UI/MenuScreen.razor

A Razor UI component for the game's main menu. It shows mode picker (Classic/Arcade/Weekly), play and help buttons, a weekly level thumbnail when Weekly is selected, and an embedded leaderboard panel; it switches to a help screen when requested.

File Access
@using System
@using Sandbox
@using Sandbox.UI
@using Sandbox.Services
@namespace Breakout
@inherits Panel

@if ( Game.IsValid() && Game.State == GameState.Menu )
{
    <root>
        @if ( showingHelp )
        {
            <HelpScreen Back=@(() => { showingHelp = false; }) />
        }
        else
        {
        <div class="menu">
        <div class="brand">
            <div class="brand-inner">
            <Logo />

            <div class="modes">
                <button class="mode-pill classic @(SelectedMode == GameMode.Classic ? "active" : "")" style="@(SelectedMode == GameMode.Classic ? "background-color: #4A9BFF; color: #F6ECD4;" : "background-color: #F6ECD4; color: #2B2440;")" onclick=@(() => ModeChanged?.Invoke( GameMode.Classic ))>CLASSIC</button>
                <button class="mode-pill arcade @(SelectedMode == GameMode.Arcade ? "active" : "")" style="@(SelectedMode == GameMode.Arcade ? "background-color: #9B7BFF; color: #F6ECD4;" : "background-color: #F6ECD4; color: #2B2440;")" onclick=@(() => ModeChanged?.Invoke( GameMode.Arcade ))>ARCADE</button>
                <button class="mode-pill weekly @(SelectedMode == GameMode.Weekly ? "active" : "")" style="@(SelectedMode == GameMode.Weekly ? "background-color: #FF9E45; color: #F6ECD4;" : "background-color: #F6ECD4; color: #2B2440;")" onclick=@(() => ModeChanged?.Invoke( GameMode.Weekly ))>WEEKLY</button>
            </div>

            <div class="mode-desc">@ModeDescription</div>

            <button class="play-btn" onclick=@(() => Game.StartGame( SelectedMode ))>
                <span class="play-icon">▶</span>
                PLAY
            </button>

            <button class="help-btn" onclick=@(() => showingHelp = true)>
                <span class="play-icon">?</span>
                HELP
            </button>
                    @if (SelectedMode == GameMode.Weekly)
                    {
                        <div class="weekly-level">
                            <label class="weekly-level-label">CURRENT WEEKS LEVEL</label>
                            <img class="weekly-level-image" src="@WeeklyLevel()" />
                        </div>
                    }
            </div>
        </div>

        <div class="board-slot">
            <LeaderboardPanel MaxRows=@(5)
                Entries=@Entries
                Me=@Me
                Loading=@Loading
                ActiveFilter=@ActiveFilter
                FilterChanged=@FilterChanged
                Title=@BoardTitle
                Version=@Version />
        </div>
        </div>
        }
    </root>
}

@code
{
    // True while the help page is showing instead of the normal menu. The HELP button turns it on
    // and the BACK button turns it off.
    private bool showingHelp;

    /// <summary>
    /// The game to start when PLAY is pressed.
    /// </summary>
    [Parameter] public BreakoutGame Game { get; set; }

    /// <summary>
    /// The ranked rows for the leaderboard card.
    /// </summary>
    [Parameter] public ScoreEntry[] Entries { get; set; }

    /// <summary>
    /// The local player's own leaderboard row (null if unranked).
    /// </summary>
    [Parameter] public ScoreEntry? Me { get; set; }

    /// <summary>
    /// True while the leaderboard is loading.
    /// </summary>
    [Parameter] public bool Loading { get; set; }

    /// <summary>
    /// Which leaderboard filter tab is selected.
    /// </summary>
    [Parameter] public ScoreFilter ActiveFilter { get; set; }

    /// <summary>
    /// Called when the player picks a different leaderboard filter.
    /// </summary>
    [Parameter] public Action<ScoreFilter> FilterChanged { get; set; }

    /// <summary>
    /// The game mode currently highlighted in the picker.
    /// </summary>
    [Parameter] public GameMode SelectedMode { get; set; }

    /// <summary>
    /// Called when the player picks a different mode.
    /// </summary>
    [Parameter] public Action<GameMode> ModeChanged { get; set; }

    /// <summary>
    /// Heading text for the leaderboard card.
    /// </summary>
    [Parameter] public string BoardTitle { get; set; } = "LEADERBOARD";

    /// <summary>
    /// Bumped by the parent to force a re-render when the board data changes.
    /// </summary>
    [Parameter] public int Version { get; set; }

    private string ModeDescription => SelectedMode switch
    {
        GameMode.Arcade => "Power-ups, special blocks & multi-ball mayhem.",
        GameMode.Weekly => "A fresh scrambled board every week. Climb the weekly ranks!",
        _ => "Pure, escalating brick-breaking. No power-ups."
    };

    string WeeklyLevel()
    {
        var directior = Game.levelDirector.GetWeeklyLevel();
        if (directior == null) return null;

        return $"thumb:{directior.ResourcePath}";
    }

    protected override int BuildHash() => System.HashCode.Combine( Game?.State, Version, (int)ActiveFilter, (int)SelectedMode, Loading, Entries?.Length ?? -1, Me?.Rank ?? -1, showingHelp );
}