A UI Razor component for a global leaderboard modal. It shows tabs for two stats, fetches leaderboard data from the Leaderboards service, displays top entries with rank, player name and score, and highlights the local player.
@using Sandbox;
@using Sandbox.UI;
@using Sandbox.Services;
@using System;
@using System.Threading.Tasks;
@using System.Collections.Generic;
@using System.Linq;
@inherits Panel
<root class="lb-root @(IsOpen ? "open" : "")">
<div class="lb-card">
<div class="lb-header">
<div class="lb-title">GLOBAL LEADERBOARD</div>
<button class="lb-close" onclick="@Toggle">✕</button>
</div>
<div class="lb-tabs">
<button class="tab-btn @(CurrentStat == "pushes_count" ? "active" : "")" onclick="@(() => SelectStat("pushes_count"))">
PUSHES
</button>
<button class="tab-btn @(CurrentStat == "rounds_won" ? "active" : "")" onclick="@(() => SelectStat("rounds_won"))">
WINS
</button>
</div>
<div class="lb-content">
@if (IsLoading)
{
<div class="lb-status">LOADING DATA...</div>
}
else if (Entries == null || Entries.Count == 0)
{
<div class="lb-status">NO RECORD FOUND</div>
}
else
{
<div class="lb-table">
<div class="table-header">
<span class="col-rank">#</span>
<span class="col-player">PLAYER</span>
<span class="col-score">SCORE</span>
</div>
<div class="table-body">
@foreach (var entry in Entries)
{
<div class="table-row @(entry.SteamId == (Connection.Local?.SteamId ?? 0) ? "is-me" : "")">
<span class="col-rank">@GetRankBadge(entry.Rank)</span>
<span class="col-player">@entry.DisplayName</span>
<span class="col-score">@entry.Value.ToString("N0")</span>
</div>
}
</div>
</div>
}
</div>
</div>
</root>
@code {
public class EntryItem
{
public int Rank { get; set; }
public string DisplayName { get; set; }
public double Value { get; set; }
public ulong SteamId { get; set; }
}
public bool IsOpen { get; set; } = false;
public bool IsLoading { get; set; } = true;
public string CurrentStat { get; set; } = "pushes_count";
public List<EntryItem> Entries { get; set; } = new();
protected override void OnAfterTreeRender( bool firstTime )
{
base.OnAfterTreeRender( firstTime );
if ( firstTime )
{
_ = RefreshData();
}
}
public void Toggle()
{
IsOpen = !IsOpen;
if (IsOpen)
{
_ = RefreshData();
}
StateHasChanged();
}
private async Task SelectStat(string statIdent)
{
if (CurrentStat == statIdent) return;
CurrentStat = statIdent;
await RefreshData();
}
private async Task RefreshData()
{
IsLoading = true;
StateHasChanged();
try
{
var board = Leaderboards.GetFromStat("seilordstudio.one_more_push", CurrentStat);
board.SetAggregationSum();
board.MaxEntries = 20;
await board.Refresh();
if (board.Entries != null)
{
Entries = board.Entries.Select(x => new EntryItem
{
Rank = Convert.ToInt32(x.Rank),
DisplayName = x.DisplayName ?? "Player",
Value = Convert.ToDouble(x.Value),
SteamId = Convert.ToUInt64(x.SteamId)
}).ToList();
}
else
{
Entries = new();
}
}
catch (System.Exception ex)
{
Log.Warning($"Leaderboard fetch failed: {ex.Message}");
}
IsLoading = false;
StateHasChanged();
}
private string GetRankBadge(int rank)
{
return rank switch
{
1 => "🥇 1",
2 => "🥈 2",
3 => "🥉 3",
_ => rank.ToString()
};
}
}