UI/TreePanel.razor

A Razor UI panel that displays a leaderboard of tallest trees. It renders a sheet with header, loading/status note, a list of leaderboard rows (rank, name, height) with special classes for top ranks and the local player, and provides refresh and close actions.

Networking
@using System
@using Sandbox
@using Sandbox.UI
@namespace DesertPump
@inherits Panel

<root class="treepanel">

	<div class="scrim" onclick="@Close"></div>

	<div class="sheet">

		<div class="head">
			<div class="title"><i>emoji_events</i> TALLEST TREES</div>
			<div class="closebtn" onclick="@Close"><i>close</i></div>
		</div>

		@if ( Leaderboard.Fetching )
		{
			<div class="note">Loading the board...</div>
		}
		else if ( !string.IsNullOrEmpty( Leaderboard.Status ) )
		{
			<div class="note">@Leaderboard.Status</div>
		}

		<div class="rows">
			@foreach ( var row in Leaderboard.Entries )
			{
				<div class="lbrow @( row.IsMe ? "me" : "" ) @RankClass( row.Rank )">
					<div class="rank">@row.Rank</div>
					<div class="who">@row.Name</div>
					<div class="score"><span class="num">@row.Height</span><span class="unit">stages</span></div>
				</div>
			}
		</div>

		<div class="refresh" onclick="@Reload">
			<i>refresh</i> REFRESH
		</div>

	</div>

</root>

@code
{
	public Action OnClose { get; set; }

	static DesertPumpGame Game => DesertPumpGame.Current;

	protected override void OnAfterTreeRender( bool firstTime )
	{
		base.OnAfterTreeRender( firstTime );

		if ( firstTime ) Reload();
	}

	void Reload()
	{
		var name = Connection.Local?.DisplayName;
		if ( string.IsNullOrWhiteSpace( name ) ) name = "You";

		_ = Leaderboard.Refresh( Game?.TreeHeight ?? 0, name );
		StateHasChanged();
	}

	static string RankClass( int rank ) => rank switch
	{
		1 => "gold",
		2 => "silver",
		3 => "bronze",
		_ => string.Empty
	};

	void Close() => OnClose?.Invoke();

	protected override int BuildHash() => HashCode.Combine(
		Leaderboard.Entries.Count, Leaderboard.Fetching, Leaderboard.Status, Game?.TreeHeight ?? 0 );
}