Search code examples
c#blazorblazor-server-sidemudblazor

How to create/detect specific Phone Design or Layout for a Blazor Server-Side App


Ok so I am supposed to design a website that will be used to administer courses and their appointments for students. While the Admin Pages and such will be accesed from a PC, the Page which Students can use to sign up for appointments will most likeley be accessed from phne and PC a lot of the time. I do like my current PC layout and Ive done a redesign for a Phone Layout. Now the thing is that I want to be able to detect when a User is accesing the Site via Phone so I can switch to my Phone Design. I dont think that my current code is Important for this question, since its not all to code specific. However, if any of you think that some Code exaples are required just tell me and Ill gladly add some. I just wanna be a bit carefull since it is company internal stuff.

So to give a rough Idea: The PC layout has the courses stored in cards that appear next to one another. When the User selects a course card, its appointments are displayed a smaller cards below the Courses. But when I would acces this Layout with a phone the Cards are pressed together, whilst also overflowing.

The Phone Layout makes use of MudBlazors Carusel meaning that It only shows one Course Card at a time and one gets to the next Course by sliding it to the side.

Now at first I though "hey I can just use css @media to detect screen size and then adapdt my visuals", but I realized that that wont work. Specifically Im working with MudBlazor which is kind of dificult to work with when one wants to make extensive styling choices. That lead me down the road of the Phone Layout using different components then the PC Layout.

Now I could be lazy and just use the Carusel for the PC layout as well, but I would be really interested if there would be a way for me the detect the screen size/device of the user and based on that select how id like it to be rendered.

So maybe something like this

@page "/courses"

@if(_isPhoneOrSmallScreen)
{
    <CoursePagePhoneLayout/>
}
else
{
    <CoursePagePCLayout/>
}


@code
{
    private bool _isPhoneOrSmallScreen = false;

    protected override void OnInitialized()
    {
        _isPhoneOrSmallScreen = DetectScreenOrPhone();
    }
    
    private bool DetectScreenOrPhone()
    {
        //some implementation
    }
}

This is just an idea/example and not actual code of mine

Edit:

Ive just stumbled across MudHidden and Im taking a look into that


Solution

  • I think that MudHidden should work for your use-case and I see that you've already discovered it.

    In the same doc page it also shows how you can listen to browser sized events using MudBlazor's IBrowserViewportService. This should allow you to fine tune what is considered a small screen within a component instead of using MudBlazor's fixed breakpoint values.

    e.g.

    @using MudBlazor.Services
    @implements IBrowserViewportObserver
    @implements IAsyncDisposable
    
    <h2>IsPhoneOrSmallScreen: @_isPhoneOrSmallScreen</h2>
    <div>
        Resize the window and see width and height change:<br />
        Browser window is <b>@(_width) x @(_height)px</b>
    </div>
    <MudDivider Class="my-4"/>
    
    @if(_isPhoneOrSmallScreen){
        <h2>In a carousel</h2>
        <MudCarousel Class="mud-width-full" Style="height:200px;" TData="object">
            <MudCarouselItem Color="@Color.Primary">
                <div class="d-flex" style="height:100%">
                    <MudIcon Class="mx-auto my-auto" Icon="@Icons.Custom.Brands.MudBlazor" Size="@Size.Large" />
                </div>
            </MudCarouselItem>
            <MudCarouselItem Color="@Color.Secondary">
                <div class="d-flex" style="height:100%">
                    <MudIcon Class="mx-auto my-auto" Icon="@Icons.Custom.Brands.MudBlazor" Size="@Size.Large" />
                </div>
            </MudCarouselItem>
            <MudCarouselItem >
                <div class="d-flex" style="height:100%">
                    <MudIcon Class="mx-auto my-auto" Icon="@Icons.Custom.Brands.MudBlazor" Color="@Color.Primary" Size="@Size.Large" />
                </div>
            </MudCarouselItem>
        </MudCarousel>
    }else{
        <h2>In a card</h2>
        <MudCard Class="pa-5">
            <div class="d-flex" style="height:100%">
                <MudIcon Class="mx-auto my-auto" Icon="@Icons.Custom.Brands.MudBlazor" Size="@Size.Large" />
            </div>
        </MudCard>
    }
    
    @code {
        [Inject]
        private IBrowserViewportService BrowserViewportService { get; set; }
    
        private int _width = 0;
        private int _height = 0;
        private bool _isPhoneOrSmallScreen => _width < 600;
        
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await BrowserViewportService.SubscribeAsync(this, fireImmediately: true);
            }
    
            await base.OnAfterRenderAsync(firstRender);
        }
    
        public async ValueTask DisposeAsync() => await BrowserViewportService.UnsubscribeAsync(this);
    
        Guid IBrowserViewportObserver.Id { get; } = Guid.NewGuid();
    
        ResizeOptions IBrowserViewportObserver.ResizeOptions { get; } = new()
        {
            ReportRate = 50,
            NotifyOnBreakpointOnly = false
        };
    
        Task IBrowserViewportObserver.NotifyBrowserViewportChangeAsync(BrowserViewportEventArgs browserViewportEventArgs)
        {
            _width = browserViewportEventArgs.BrowserWindowSize.Width;
            _height = browserViewportEventArgs.BrowserWindowSize.Height;
    
            return InvokeAsync(StateHasChanged);
        }
    }
    

    Demo 👉 MudBlazor Snippet

    enter image description here