UI/Components/Chat.razor
@using Sandbox;
@using Sandbox.UI;
@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(string author, string message, RealTimeSince timeSinceAdded);
	List<Entry> Entries = new();

	protected override void OnUpdate()
	{
		if (EscapeMenu.isOpen)
			return;
		
		if (!InputBox.IsValid())
			return;

		Panel.AcceptsFocus = false;

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

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

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

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

		if (string.IsNullOrWhiteSpace(text))
			return;

		AddText(Sandbox.Utility.Steam.PersonaName, text);
	}

	[Rpc.Broadcast]
	public void AddText(string author, string message)
	{
		message = message.Truncate(300);

		if (string.IsNullOrWhiteSpace(message))
			return;

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

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

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

		AddText("🛎️", $"{channel.DisplayName} has joined the game");
	}

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

		AddText("💨", $"{channel.DisplayName} has left the game");
	}
}