UI/SpawnMenu/UndoHistoryPage.razor
@using Sandbox;
@using Sandbox.UI;
@inherits UtilityPage
@namespace Sandbox
@attribute [Icon( "undo" )]
@attribute [Title( "#spawnmenu.utility.undo" )]
@attribute [Group( "#spawnmenu.utility.group.utilities" )]
@attribute [Order( 1 )]

<root class="page">
    @if ( Loading )
    {
        <div class="undo-empty">#spawnmenu.utility.undo_loading</div>
    }
    else if ( History.Count == 0 )
    {
        <div class="undo-empty">#spawnmenu.utility.undo_empty</div>
    }
    else
    {
        <div class="undo-help">#spawnmenu.utility.undo_help</div>

        @foreach ( var item in History )
        {
            var entry = item;
            <div class="control-row action undo-entry" @onclick=@(() => Undo( entry ))>
                <div class="undo-icon @(string.IsNullOrWhiteSpace( entry.Icon ) ? "material-icon" : "")">@(string.IsNullOrWhiteSpace( entry.Icon ) ? "undo" : entry.Icon)</div>
                <div class="undo-info">
                    <label class="undo-name">@DisplayName( entry )</label>
                    <label class="undo-count">@ObjectCountText( entry.ObjectCount )</label>
                </div>
                <i class="undo-action">undo</i>
            </div>
        }
    }
</root>

@code
{
    List<UndoSystem.HistoryItem> History = [];
    bool Loading = true;

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

        if ( !firstTime ) return;

        UndoSystem.HistoryUpdated += OnHistoryUpdated;
        Refresh();
    }

    protected override void OnVisibilityChanged()
    {
        base.OnVisibilityChanged();

        if ( IsVisible )
            Refresh();
    }

    public override void OnDeleted()
    {
        UndoSystem.HistoryUpdated -= OnHistoryUpdated;
        base.OnDeleted();
    }

    void Refresh()
    {
        Loading = true;
        StateHasChanged();
        UndoSystem.RequestHistory();
    }

    void OnHistoryUpdated( IReadOnlyList<UndoSystem.HistoryItem> history )
    {
        History = history?.ToList() ?? [];
        Loading = false;
        StateHasChanged();
    }

    void Undo( UndoSystem.HistoryItem entry )
    {
        if ( entry is null ) return;

        Loading = true;
        StateHasChanged();
        UndoSystem.UndoEntry( entry.Id );
    }

    static string DisplayName( UndoSystem.HistoryItem entry )
        => string.IsNullOrWhiteSpace( entry.Name ) ? "Action" : entry.Name;

    static string ObjectCountText( int count )
        => count == 1
            ? Game.Language.GetPhrase( "spawnmenu.utility.undo_one_object" )
            : Game.Language.GetPhrase( "spawnmenu.utility.undo_many_objects", new() { { "count", count } } );
}