|
1 | | -@using Microsoft.AspNetCore.Components.Authorization |
| 1 | +@inject IJSRuntime JS |
2 | 2 | @inherits LayoutComponentBase |
| 3 | +@implements IDisposable |
| 4 | +@using MESS.Blazor.Components.Navigator |
| 5 | +@using Microsoft.AspNetCore.Components.Authorization |
| 6 | +@inject NavigationManager Navigation |
| 7 | +@inject AuthenticationStateProvider AuthProvider |
3 | 8 |
|
4 | 9 | <HeadContent> |
5 | 10 | <script src="darkmode.js"></script> |
6 | 11 | </HeadContent> |
7 | 12 |
|
8 | | -<div class="page"> |
9 | | - <main> |
10 | | - <article class="content px-4 mx-auto"> |
11 | | - <AuthorizeView Roles="Technician, Administrator"> |
12 | | - <NavLink class="btn btn-outline-secondary text-decoration-none" href="/WorkInstructionManager" Match="NavLinkMatch.All"> |
13 | | - Phoebe |
14 | | - </NavLink> |
15 | | - <NavLink class="btn btn-outline-secondary text-decoration-none" href="/production-log" Match="NavLinkMatch.All"> |
16 | | - Production Log |
17 | | - </NavLink> |
18 | | - </AuthorizeView> |
19 | | - <div class="mt-sm-3"> |
20 | | - @Body |
21 | | - </div> |
22 | | - <DarkModeButton></DarkModeButton> |
23 | | - </article> |
24 | | - </main> |
25 | | -</div> |
| 13 | +<!-- Fixed Top Bar with Left and Right Buttons --> |
| 14 | +<div class="position-fixed top-0 start-0 end-0 d-flex justify-content-between align-items-center px-3 custom-top-bar" |
| 15 | + style="z-index: 1050; height: 50px;"> |
26 | 16 |
|
27 | | -<div id="blazor-error-ui" data-nosnippet> |
28 | | - An unhandled error has occurred. |
29 | | - <a href="." class="reload">Reload</a> |
30 | | - <span class="dismiss">🗙</span> |
| 17 | + <!-- Left-side button --> |
| 18 | + <div class="d-flex align-items-center"> |
| 19 | + <AuthorizeView Roles="Technician, Administrator"> |
| 20 | + @if (ShowSidebarToggle) |
| 21 | + { |
| 22 | + <button class="btn btn-outline-secondary" |
| 23 | + @onclick="ToggleSidebar" |
| 24 | + style="width: 32px; height: 32px; padding: 0; font-size: 1.1rem; display: flex; align-items: center; justify-content: center; border-radius: 0.25rem;"> |
| 25 | + ☰ |
| 26 | + </button> |
| 27 | + } |
| 28 | + </AuthorizeView> |
| 29 | + </div> |
| 30 | + |
| 31 | + <!-- Right-side button --> |
| 32 | + <div class="d-flex align-items-center"> |
| 33 | + @if (ShowDarkModeToggle) |
| 34 | + { |
| 35 | + <button class="btn btn-outline-secondary" |
| 36 | + @onclick="ToggleDarkMode" |
| 37 | + title="Toggle Dark Mode" |
| 38 | + style="width: 36px; height: 32px; font-size: 1.3rem; display: flex; align-items: center; justify-content: center; border-radius: 0.25rem;"> |
| 39 | + @(isDarkMode ? "\u2600\ufe0f" : "\ud83c\udf19") |
| 40 | + </button> |
| 41 | + } |
| 42 | + </div> |
31 | 43 | </div> |
32 | 44 |
|
| 45 | +<!-- Sidebar --> |
| 46 | +<AuthorizeView Roles="Technician, Administrator"> |
| 47 | + <NavigationMenu IsOpen="@isSidebarOpen" OnToggle="ToggleSidebar" /> |
| 48 | +</AuthorizeView> |
| 49 | + |
| 50 | +<!-- Main Content --> |
| 51 | +<main class="content px-4 mx-auto" |
| 52 | + style=" |
| 53 | + margin-left:@(isSidebarOpen ? "250px" : "0"); |
| 54 | + padding-top: 36px; |
| 55 | + transition: margin-left 0.3s ease;"> |
| 56 | + @Body |
| 57 | +</main> |
| 58 | + |
| 59 | +<!-- Fluent Providers --> |
33 | 60 | <FluentToastProvider /> |
34 | 61 | <FluentDialogProvider /> |
35 | 62 | <FluentTooltipProvider /> |
36 | 63 | <FluentMessageBarProvider /> |
37 | 64 | <FluentMenuProvider /> |
38 | 65 |
|
| 66 | +<!-- Error UI --> |
| 67 | +<div id="blazor-error-ui" data-nosnippet> |
| 68 | + An unhandled error has occurred. |
| 69 | + <a href="." class="reload">Reload</a> |
| 70 | + <span class="dismiss">🗙</span> |
| 71 | +</div> |
| 72 | + |
| 73 | +@code { |
| 74 | + private bool isSidebarOpen = false; |
| 75 | + private bool ShowSidebarToggle = true; |
| 76 | + private bool ShowDarkModeToggle = true; |
| 77 | + private bool isDarkMode = false; |
| 78 | + |
| 79 | + /// <summary> |
| 80 | + /// Called by the framework when parameters are set. |
| 81 | + /// Checks the current page and determines whether the sidebar toggle and dark mode toggle should be shown. |
| 82 | + /// </summary> |
| 83 | + protected override void OnParametersSet() |
| 84 | + { |
| 85 | + var relativeUri = Navigation.ToBaseRelativePath(Navigation.Uri).TrimEnd('/'); |
| 86 | + |
| 87 | + // Hide toggle button on the WorkInstructionManager page |
| 88 | + ShowSidebarToggle = !relativeUri.Equals("WorkInstructionManager", StringComparison.OrdinalIgnoreCase); |
| 89 | + |
| 90 | + // Also hide dark mode toggle on WorkInstructionManager page |
| 91 | + ShowDarkModeToggle = ShowSidebarToggle; |
| 92 | + } |
| 93 | + |
| 94 | + /// <summary> |
| 95 | + /// Toggles the sidebar open/closed state. |
| 96 | + /// Also invokes the SidebarToggleRequested callback if assigned. |
| 97 | + /// </summary> |
| 98 | + private async Task ToggleSidebar() |
| 99 | + { |
| 100 | + isSidebarOpen = !isSidebarOpen; |
| 101 | + |
| 102 | + if (SidebarToggleRequested.HasDelegate) |
| 103 | + { |
| 104 | + await SidebarToggleRequested.InvokeAsync(null); |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + /// <summary> |
| 109 | + /// Toggles dark mode by invoking the JS function and updates the icon. |
| 110 | + /// </summary> |
| 111 | + private async Task ToggleDarkMode() |
| 112 | + { |
| 113 | + isDarkMode = !isDarkMode; |
| 114 | + await JS.InvokeVoidAsync("toggleDarkMode", isDarkMode); |
| 115 | + } |
39 | 116 |
|
40 | | -@code |
41 | | -{ |
| 117 | + /// <summary> |
| 118 | + /// Performs any necessary cleanup when the component is disposed. |
| 119 | + /// </summary> |
| 120 | + public void Dispose() |
| 121 | + { |
| 122 | + // Cleanup if needed |
| 123 | + } |
42 | 124 |
|
| 125 | + /// <summary> |
| 126 | + /// Event callback for notifying external components when the sidebar toggle is requested. |
| 127 | + /// </summary> |
| 128 | + [Parameter] |
| 129 | + public EventCallback SidebarToggleRequested { get; set; } |
43 | 130 | } |
0 commit comments