UI/HomePage.razor

A Blazor-style UI panel for the game's home page. Renders the main menu (PLAY, GARAGE, SESSIONS, OPTIONS, QUIT), handles keyboard/controller navigation, visual selection, and activates corresponding actions like navigation, showing server list, settings modal, and quitting the game.

@using Sandbox;
@using Sandbox.UI;
@using Sandbox.UI.Navigation;
@using Microsoft.AspNetCore.Components;

@namespace Machines.UI
@inherits Panel
@attribute [Route( "/" )]

<root class="home-page @(Input.UsingController ? "controller" : "mouse")">
    <div class="hero">
        <div class="hero-inner">
            <span class="brand-text">FACEPUNCH PRESENTS</span>
            <div class="title">
                <label>MINI</label>
                <strong>MOTORS</strong>
            </div>
        </div>
    </div>

    <div class="menu">
        <a href="/play" class="menu-item primary @Sel( 0 )" onmouseover=@(() => Select( 0 ))>
            <span class="menu-label">PLAY</span>
            @if ( _selectedIndex == 0 )
            {
                <InputHint Action="MenuSelect" class="menu-key-glyph" />
            }
        </a>
        <a href="/customize" class="menu-item @Sel( 1 )" onmouseover=@(() => Select( 1 ))>
            <span class="menu-label">GARAGE</span>
            @if ( _selectedIndex == 1 )
            {
                <InputHint Action="MenuSelect" Dark=@true class="menu-key-glyph" />
            }
        </a>
        <div class="menu-item @Sel( 2 )" onmouseover=@(() => Select( 2 )) onclick=@Sessions>
            <span class="menu-label">SESSIONS</span>
            @if ( _selectedIndex == 2 )
            {
                <InputHint Action="MenuSelect" Dark=@true class="menu-key-glyph" />
            }
        </div>
        <div class="menu-item @Sel( 3 )" onmouseover=@(() => Select( 3 )) onclick=@Options>
            <span class="menu-label">OPTIONS</span>
            @if ( _selectedIndex == 3 )
            {
                <InputHint Action="MenuSelect" Dark=@true class="menu-key-glyph" />
            }
        </div>
        <div class="menu-item @Sel( 4 )" onmouseover=@(() => Select( 4 )) onclick=@Quit>
            <span class="menu-label">QUIT</span>
            @if ( _selectedIndex == 4 )
            {
                <InputHint Action="MenuSelect" Dark=@true class="menu-key-glyph" />
            }
        </div>
    </div>

    <div class="revision">
        <RevisionCard />
    </div>

    <div class="footer">
        <div class="hint">
            <InputHint Action="MenuUp" class="hint-glyph" />
            <InputHint Action="MenuDown" class="hint-glyph" />
            <span class="hint-label">NAVIGATE</span>
        </div>
        <div class="hint">
            <InputHint Action="MenuSelect" class="hint-glyph" />
            <span class="hint-label">SELECT</span>
        </div>
    </div>
</root>

@code
{
    private const int ItemCount = 5;
    private int _selectedIndex;

    private string Sel( int index ) => _selectedIndex == index ? "selected" : "";

    private void Select( int index )
    {
        // Mouse hover only applies when not on a controller.
        if ( Input.UsingController )
            return;

        _selectedIndex = index;
    }

    public override void Tick()
    {
        base.Tick();

        // Only handle input on this page.
        if ( this.GetNavigator()?.CurrentUrl != "/home" )
            return;

        if ( Input.Pressed( "MenuUp" ) )
            Move( -1 );
        else if ( Input.Pressed( "MenuDown" ) )
            Move( +1 );

        if ( Input.Pressed( "MenuSelect" ) )
            Activate( _selectedIndex );
    }

    private void Move( int direction )
    {
        _selectedIndex = (_selectedIndex + direction + ItemCount) % ItemCount;

        if ( Input.UsingController )
        {
            Sound.Play( "element_switch" );
        }
    }

    private void Activate( int index )
    {
        switch ( index )
        {
            case 0:
                this.Navigate( "/play" );
                // Consume so it doesn't bleed into the map selector's ready-up.
                Input.Clear( "MenuSelect" );
                break;
            case 1:
                this.Navigate( "/customize" );
                Input.Clear( "MenuSelect" );
                break;
            case 2:
                Sessions();
                break;
            case 3:
                Options();
                break;
            case 4:
                Quit();
                break;
        }
    }

    private void Sessions()
    {
        Game.Overlay.ShowServerList( new Sandbox.Modals.ServerListConfig()
        {
            GamePackageFilter = Game.Ident,
        });
    }

    private void Options()
    {
        Game.Overlay.ShowSettingsModal();
    }

    private void Quit()
    {
        Game.Close();
    }

    protected override int BuildHash() => System.HashCode.Combine( _selectedIndex, Input.UsingController );
}