UI/Chat/Chat.razor
@using Sandbox.UI
@inherits Panel

<style>
    Chat {
        position: absolute;
        bottom: 48px;
        left: 80px;
        width: 550px;
        flex-direction: column;
        gap: 12px;

        .output {
            flex-direction: column;
            max-height: 520px;
            overflow: hidden;
            padding: 12px 14px;
            background-color: rgba(0, 0, 0, 0.24);
            border-left: 2px solid rgba(120, 220, 255, 0.28);
            border-right: 2px solid rgba(120, 220, 255, 0.28);
        }

        .chat_entry {
            flex-direction: row;
            gap: 10px;
            margin-bottom: 6px;
            text-shadow: 0 2px 2px rgba(0, 0, 0, 0.85);

            .author {
                color: #5ec8ff;
                font-family: "AzeretMono-Medium";
                font-size: 22px;
            }

            .message {
                color: white;
                font-family: "AzeretMono-Medium";
                font-size: 22px;
            }
        }

        .input {
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.08s ease;
        }

        .input TextEntry {
            background-color: rgba(0, 0, 0, 0.6);
            color: white;
            font-family: "AzeretMono-Medium";
            font-size: 24px;
            padding: 14px 16px;
            border-left: 2px solid rgba(120, 220, 255, 0.35);
            border-right: 2px solid rgba(120, 220, 255, 0.35);
        }

        &.open .input {
            opacity: 1;
            pointer-events: all;
        }
    }
</style>

<root>
    @if ( _entries.Count > 0 )
    {
        <div class="output">
            @foreach ( var entry in _entries )
            {
                <div class="chat_entry">
                    <div class="author">@entry.Author:</div>
                    <div class="message">@entry.Message</div>
                </div>
            }
        </div>
    }

    <div class="input">
        <TextEntry @ref="_textEntry" onsubmit="@OnSubmit" />
    </div>
</root>

@code
{
    private TextEntry _textEntry;
    private readonly List<Entry> _entries = new();
    private bool _chatActive;

    protected override void OnAfterTreeRender( bool firstTime )
    {
        base.OnAfterTreeRender( firstTime );
        if ( !firstTime ) return;
        ChatEvent.OnChat += AddEntry;
    }

    public override void OnDeleted()
    {
        ChatEvent.OnChat -= AddEntry;
    }

    private readonly record struct Entry( string Author, string Message, RealTimeSince Age );

    private void OnSubmit()
    {
        var msg = _textEntry?.Text?.Trim();
        if ( _textEntry != null ) _textEntry.Text = string.Empty;
        if ( !string.IsNullOrWhiteSpace( msg ) )
        {
            ConsoleSystem.Run( "fp4_chat", msg );
        }

        _chatActive = false;
        _textEntry?.Blur();
    }

    public override void Tick()
    {
        base.Tick();

        if ( _textEntry == null )
            return;

        if ( Input.Pressed( "Chat" ) || Input.Pressed( "chat" ) )
        {
            _chatActive = true;
        }

        if ( _chatActive && Input.Pressed( "menu" ) )
        {
            _chatActive = false;
            _textEntry?.Blur();
        }

        if ( _chatActive && !_textEntry.HasFocus )
        {
            _textEntry.Focus();
        }

        if ( _entries.RemoveAll( x => x.Age > 20f ) > 0 )
            StateHasChanged();

        SetClass( "open", _chatActive );
    }

    public void AddEntry( string name, string message )
    {
        if ( string.IsNullOrWhiteSpace( message ) )
            return;

        _entries.Add( new Entry( name, message, 0f ) );
        StateHasChanged();
    }
}