UI/SpawnMenu/SpawnMenu.razor
@using Sandbox;
@using Sandbox.UI;
@namespace Sandbox
@inherits Panel
@attribute [SpawnMenuHost.SpawnMenuMode]
@attribute [Icon( "📦" )]
@attribute [Title( "#spawnmenu.tab.spawn" )]
@attribute [Order( -100 )]

<root>

    <div class="container">

        <div class="spawnmenuleft">

            <div class="tabs">

                @foreach (var t in tabs)
                {
                    var type = Game.TypeLibrary.GetType(t.GetType());

                    var c = activeTab == t ? "active" : "";

                    <div class="@c" @onclick=@(() => SwitchTab(t))>
                        <span>@type.Icon</span>
                        <span>@type.Title</span>
                    </div>
                }

            </div>

            <div class="body" @ref="TabContainer">
            </div>

        </div>

        <div class="spawnmenuright">

            <div class="tabs">

                @foreach (var t in utilityTabs)
                {
                    var type = Game.TypeLibrary.GetType(t.GetType());

                    var c = activeUtilityTab == t ? "active" : "";

                    <div class="@c" @onclick=@(() => SwitchUtilityTab(t))>
                        <span>@type.Icon</span>
                        <span>@type.Title</span>
                    </div>
                }

            </div>

            <div class="body" @ref="UtilityContainer">
            </div>

        </div>

    </div>

</root>

@code
{
    Panel activeTab;
    Panel TabContainer = default;

    Panel activeUtilityTab;
    Panel UtilityContainer = default;

    List<Panel> tabs = new List<Panel>();
    List<Panel> utilityTabs = new List<Panel>();

    public void BuildTabs()
    {
        foreach (var p in Game.TypeLibrary.GetTypes<ISpawnMenuTab>().OrderBy(x => x.Order).ThenBy(x => x.Title))
        {
            if (p.IsAbstract) continue;
            if (p.TargetType == typeof(BaseSpawnMenu)) continue;

            var panel = p.Create<Panel>();
            TabContainer.AddChild(panel);

            tabs.Add(panel);
        }

        SwitchTab( RestoreTab( tabs, "spawnmenu.tab" ) );
    }

    public void BuildUtilityTabs()
    {
        foreach (var p in Game.TypeLibrary.GetTypes<IUtilityTab>().OrderBy(x => x.Order).ThenBy(x => x.Title))
        {
            if (p.IsAbstract) continue;

            var panel = p.Create<Panel>();
            UtilityContainer.AddChild(panel);

            utilityTabs.Add(panel);
        }

        SwitchUtilityTab( RestoreTab( utilityTabs, "spawnmenu.utilitytab" ) );
    }

    Panel RestoreTab( List<Panel> panels, string cookieKey )
    {
        var saved = Game.Cookies.Get<string>( cookieKey, null );
        if ( !string.IsNullOrEmpty( saved ) )
        {
            var match = panels.FirstOrDefault( p => p.GetType().Name == saved );
            if ( match is not null ) return match;
        }
        return panels.FirstOrDefault();
    }

    protected override void OnAfterTreeRender(bool firstTime)
    {
        if (firstTime && TabContainer.IsValid())
        {
            BuildTabs();
        }

        if (firstTime && UtilityContainer.IsValid())
        {
            BuildUtilityTabs();
        }
    }

    void SwitchTab(Panel tab)
    {
        activeTab = tab;
        Game.Cookies.Set( "spawnmenu.tab", tab?.GetType().Name );
        StateHasChanged();

        foreach (var t in tabs)
        {
            t.SetClass("active", t == tab);
            t.SetClass("hidden", t != tab);
        }
    }

    void SwitchUtilityTab(Panel tab)
    {
        activeUtilityTab = tab;
        Game.Cookies.Set( "spawnmenu.utilitytab", tab?.GetType().Name );
        StateHasChanged();

        foreach (var t in utilityTabs)
        {
            t.SetClass("active", t == tab);
            t.SetClass("hidden", t != tab);
        }
    }

    // When clicking anywhere in the spawn menu, blur any focused text inputs
    // so we can close the menu by pressing the spawnmenu key.
    void OnMenuClicked()
    {
        Sandbox.UI.InputFocus.Clear();
    }
}