UI/Eventlog.razor

A UI Panel component that displays a short local event log. It listens to EventlogBus.OnMessage, parses simple color tags like <color>text</>, creates labels with per-segment colors, shows up to 5 entries, and removes entries after a TimeUntil expires during Tick.

NetworkingFile Access
@using System
@using System.Linq
@using System.Collections.Generic
@using Sandbox
@using Sandbox.UI
@namespace BrickJam.UI
@inherits Panel

<root />

@code {
	public const int Limit = 5;

	public static Eventlog Instance { get; private set; }

	private readonly List<(Panel Panel, TimeUntil UntilDelete)> events = new();

	public Eventlog()
	{
		Instance = this;
		EventlogBus.OnMessage += Append;
	}

	public override void OnDeleted()
	{
		base.OnDeleted();
		EventlogBus.OnMessage -= Append;
	}

	public override void Tick()
	{
		if ( events.Count == 0 )
			return;

		var first = events[0];
		if ( first.UntilDelete )
		{
			first.Panel?.Delete();
			events.RemoveAt( 0 );
		}
	}

	/// <summary>Append a coloured log line locally. Supports <c>&lt;color&gt;text&lt;/&gt;</c> tags.</summary>
	public void Append( string input, float time = 8f )
	{
		if ( events.Count >= Limit )
		{
			events[0].Panel?.Delete();
			events.RemoveAt( 0 );
		}

		var container = AddChild<Panel>( "event" );

		var isColor = false;
		var shouldClose = false;
		var output = "";
		var color = Color.White;

		for ( var i = 0; i < input.Length; i++ )
		{
			var character = input[i];
			switch ( character )
			{
				case '<':
					if ( output != "" ) { AppendLabel( container, output, color ); output = ""; }
					if ( !isColor ) { isColor = true; break; }
					shouldClose = true;
					break;
				case '>':
					if ( isColor && !shouldClose )
					{
						color = Color.Parse( output ) ?? Color.White;
						output = ""; isColor = false; break;
					}
					if ( output == "" ) break;
					AppendLabel( container, output, color );
					output = ""; color = Color.White; shouldClose = false; isColor = false;
					break;
				case '/':
					if ( !shouldClose ) { output += character; break; }
					shouldClose = true;
					break;
				default:
					output += character;
					break;
			}

			if ( i == input.Length - 1 && output != "" )
				AppendLabel( container, output, color );
		}

		events.Add( (container, time) );
	}

	private void AppendLabel( Panel parent, string text, Color color )
	{
		var label = parent.AddChild<Label>( "label" );
		label.Text = text;
		label.Style.FontColor = color;
	}
}

<style>
	Eventlog {
		position: absolute;
		top: 30px;
		left: 0;
		flex-direction: column;
		align-items: flex-start;

		.event {
			flex-direction: row;
			gap: 4px;
			flex-wrap: wrap;
			max-width: 600px;
			background: linear-gradient(to right, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0.2) 75%, rgba(0,0,0,0) 100%);
			padding: 5px 50px 5px 10px;
			margin-bottom: 2px;

			.label {
				font-size: 22px;
				text-shadow: 2px 2px 0px black;
				color: white;
			}
		}
	}
</style>