MudBlazor / Templates

Ready to use Blazor Templates in different styles and layout with all the basic setup already done for MudBlazor.
MIT License
719 stars 156 forks source link

Unable to toggle drawer containing `MudNavMenu` when on `/Account` (SSR) pages. #478

Closed bitbound closed 1 day ago

bitbound commented 1 day ago

Out-of-the-box, it's not possible to toggle the drawer containing the MudNavMenu when you're on any of the account pages (using SSR). This is particularly problematic on mobile, since you're no longer able to navigate.

I see that the templates are using 0phois/MudBlazor.StaticInput for the SSR pages, but they don't have a component for MudIconButton or MudNavMenu. So I'm not sure if this issue belongs here as a bug, or in that repo as a feature request.

ScarletKuro commented 1 day ago

Works fine for me. You can see that I have MudNavMenu with MudNavLinks and that I'm on auth (/Account) pages and the navigation does work. I tested before everything: WASM, Server, Auth with per-page and global interactivity.

works

bitbound commented 1 day ago

Sorry, I wasn't clear. It's the MudIconButton that toggles the drawer.

https://github.com/user-attachments/assets/8314719d-66e8-4f43-88c7-1dc67248c2f0

ScarletKuro commented 1 day ago

Sorry, I wasn't clear. It's the MudIconButton that toggles the drawer.

That's the key part, the drawer and the nav menu are very different things.

This is expected for now and has been explained multiple times. When you are on static SSR pages, there is no interactivity, which means that any C# code will not execute. Our drawer functions only when there is interactivity, as the open state is managed by the C# code. I don't think 0phois/MudBlazor.StaticInput can do anything either.

There are only three ways to handle this:

  1. Use a drawer that is purely written in HTML and CSS.
  2. Theoretically, you could use JavaScript to change the class of the drawer from open to closed, but if I remember correctly, there could be other side effects.
  3. Create a Pull Request for a mini drawer in mobile view, featuring just a tiny sidebar with icons only. That's what we had in plans, but currently there is no ETA.
bitbound commented 1 day ago

This is expected for now and has been explained multiple times.

I wouldn't have created this issue had I seen anywhere that this is a known incompletion. I searched the issues and documentation, but didn't see anything specifically for this. Maybe I missed something, but I did look.

When you are on static SSR pages, there is no interactivity, which means that any C# code will not execute.

I understand how interactivity and render modes work. I understand why this isn't working.

This works in the default Blazor templates (again, don't need to explain the technical reasons why it works in them). So a reasonable person, even one who understands the technical reasons why it's not working, would expect them to work in these templates as well. A reasonable person would either consider this a bug or an oversight.

If you're frustrated from having to explain this (maybe I'm mistaken, but I kinda get that feeling), I suggest one or more of the following:

Anyhow, thank you for your work on MudBlazor. I've really been enjoying it for my own open-source stuff. Have a good day!

ScarletKuro commented 1 day ago

wouldn't have created this issue had I seen anywhere that this is a known incompletion. I searched the issues and documentation, but didn't see anything specifically for this. Maybe I missed something, but I did look.

https://github.com/MudBlazor/Templates/issues/461
https://github.com/MudBlazor/MudBlazor/issues/9523
https://github.com/MudBlazor/MudBlazor/issues/9743
+Discord
+General GitHub discussion about WebApp.

I'm not frustrated, and I apologize if it sounds passively aggressive. The reason we keep mentioning that this has been discussed multiple times is that, when .NET 8 was in its release candidate stage, we publicly stated in all channels that we would not support static SSR. MudBlazor was developed way before static SSR was introduced, and adopting it would require extensive rewriting. This also goes against our principle of not using JavaScript unless absolutely necessary. At this point, MudBlazor would essentially just wrap some JavaScript libraries into Blazor components, which was not our initial intention. This template represents what we could squeeze out from MudBlazor with static SSR, it's not perfect, but it's significantly better than what we had in the 1.0.0 template version.

I suggest one or more of the following:

  • Add a section to the README that lists features, such as this one, that are incomplete or non-functioning.
  • Add a pinned issue containing known bugs and incomplete features.
  • Add comments in the template code next to the incomplete or non-functioning components.

Thank you for the feedback. I will work on improving the documentation.

bitbound commented 8 hours ago

For anyone who arrives here and would like an example of a potential solution, here's what I did. This assumes you're using the default value for MudDrawer.Breakpoint. It's working for me, minus the missing backdrop. It will handle both desktop and mobile views, and it handles transitions between the breakpoint when resizing the window.

I'm sure edge cases will pop up at some point. 😄

MainLayout.razor:


@inject NavigationManager NavManager

@* other content *@

      @* Added id to toggle button. *@
      <MudIconButton id="nav-drawer-toggle-button"
                     Icon="@Icons.Material.Filled.Menu"
                     Color="Color.Inherit"
                     Edge="Edge.Start"
                     OnClick="@(_ => DrawerToggle())" />

@* other content *@

    @* Added id to drawer. *@
    <MudDrawer @bind-Open="_drawerOpen"
               id="nav-drawer"
               ClipMode="DrawerClipMode.Always"
               Elevation="2">

@* other content *@

  @*  Add JavaScript if we're on an Identity page. *@
  @if (_isIdentityPage)
  {
    <script src="/Components/Layout/MainLayout.razor.js"></script>
  }

@code {
  private bool _isIdentityPage;

 // other content

  protected override async Task OnInitializedAsync()
  {
    _isIdentityPage =
      Uri.TryCreate(NavManager.Uri, UriKind.Absolute, out var currentUri) &&
      currentUri.PathAndQuery.StartsWith("/Account");

     // other content
  }
}

MainLayout.razor.js (new file in same folder as MainLayout.razor):

/** @type {HTMLButtonElement} */
const toggleButton = document.getElementById("nav-drawer-toggle-button");
const navDrawer = document.getElementById("nav-drawer");
const drawerParent = navDrawer.parentElement;
const desktopQuery = window.matchMedia("(min-width: 960px)");

desktopQuery.addEventListener("change", ev => {
  const isOpen = navDrawer.classList.contains("mud-drawer--open");
  const hasBreakpoint = navDrawer.classList.contains("mud-drawer-md");

  if (ev.matches) {
    navDrawer.classList.add("mud-drawer-md");
    navDrawer.classList.remove("mud-drawer--closed");
    navDrawer.classList.add("mud-drawer--open");
    drawerParent.classList.remove("mud-drawer-closed-responsive-md-left");
    drawerParent.classList.add("mud-drawer-open-responsive-md-left");
  }
});

toggleButton.addEventListener("click", () => {
  const isDesktopWidth = desktopQuery.matches;
  const hasBreakpoint = navDrawer.classList.contains("mud-drawer-md");

  if (!isDesktopWidth && hasBreakpoint) {
      navDrawer.classList.remove("mud-drawer-md");
    return;
  }

  if (isDesktopWidth && !hasBreakpoint) {
    navDrawer.classList.add("mud-drawer-md");
  }

  navDrawer.classList.toggle("mud-drawer--open");
  navDrawer.classList.toggle("mud-drawer--closed");
  drawerParent.classList.toggle("mud-drawer-closed-responsive-md-left");
  drawerParent.classList.toggle("mud-drawer-open-responsive-md-left");
});

https://github.com/user-attachments/assets/a57528a8-7b05-4fa4-8e9f-008dc45a6da2