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.
@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 );
}