ui/PanelComponents/Chat.razor
@using Sandbox;
@using Sandbox.UI;
@namespace SS1
@inherits PanelComponent
@implements Component.INetworkListener

<root>

	<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="InputBox" onsubmit="@ChatFinished"></TextEntry>
	</div>
	
</root>

@code
{
	TextEntry InputBox;

	public record Entry( ulong steamid, string author, string message, RealTimeSince timeSinceAdded );
	List<Entry> Entries = new();

	protected override void OnUpdate()
	{
		if (InputBox is null)
			return;

		Panel.AcceptsFocus = false;

		if ( Input.Pressed( "chat" ) )
		{
			InputBox.Focus();
		}

		if ( Entries.RemoveAll( x => x.timeSinceAdded > 20f ) > 0 )
		{
			StateHasChanged();
		}

		SetClass( "open", InputBox.HasFocus );
	}

	void ChatFinished()
	{
		var text = InputBox.Text;
		InputBox.Text = "";

		if (string.IsNullOrWhiteSpace(text))
			return;

		AddText( text );
	}

	public void AddText( string message )
	{
		message = message.Truncate( 300 );

		if (string.IsNullOrWhiteSpace(message))
			return;

		var author = Rpc.Caller.DisplayName;
		var steamid = Rpc.Caller.SteamId;

		Log.Info($"{author}: {message}");

		Entries.Add(new Entry(steamid, author, message, 0.0f));
		StateHasChanged();
	}

	public void AddSystemText(string message)
	{
		message = message.Truncate(300);

		if (string.IsNullOrWhiteSpace(message))
			return;

		Entries.Add(new Entry(0, "ℹ️", message, 0.0f));
		StateHasChanged();
	}

	void Component.INetworkListener.OnConnected( Connection channel )
	{
		if ( IsProxy ) return;

		AddSystemText( $"{channel.DisplayName} has joined the game" );
	}

	void Component.INetworkListener.OnDisconnected( Connection channel )
	{
		if ( IsProxy ) return;

		AddSystemText( $"{channel.DisplayName} has left the game" );
	}

	protected override int BuildHash()
	{
		return HashCode.Combine(
			Manager.Instance.NumPlayers
		);
	}
}