UI/Scoreboard.razor
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent

<root>
    <div class="body">
        <div class="title">
            <label class="big">sandbox</label>

            @if ( !string.IsNullOrEmpty( _mapTitle ) )
            {
                <label class="small">Playing on @(_mapTitle)</label>
            }
        </div>

        <div class="table">
            <div class="col">
                <div class="header row">
                    <div class="avatar-spacer"></div>
                    <div class="name"></div>
                    <div class="stat">Kills</div>
                    <div class="stat">Deaths</div>
                    <div class="stat">Ping</div>
                    <div class="mute-spacer"></div>
                </div>

                @foreach ( var connection in Connection.All.OrderByDescending( x => PlayerData.For( x )?.Kills ?? 0 ).ThenBy( x => x.DisplayName ) )
                {
                    <ScoreboardRow Connection="@connection" />
                }
            </div>
        </div>
    </div>
</root>

@code
{
    string _mapTitle = null;

    protected override void OnTreeFirstBuilt()
    {
        base.OnTreeFirstBuilt();
        FetchMap();
    }

    async void FetchMap()
    {
        var ident = Networking.MapName;

        var pkg = await Package.FetchAsync( ident, false );
        if ( pkg is not null )
        {
            _mapTitle = pkg.Title;
        }
    }

    protected override void OnUpdate()
    {
	    var host = Game.ActiveScene.Get<SpawnMenuHost>();
	    if ( host?.Panel?.HasClass( "open" ) ?? false )
	    {
		    Input.Clear( "Score" );
	    }

	    SetClass( "visible", Input.Down( "Score" ) );
    }

    /// <summary>
    /// update every second
    /// </summary>
    protected override int BuildHash() => System.HashCode.Combine( RealTime.Now.CeilToInt() );
}