UI/SubtitlesList.razor

A UI Panel Razor component that displays a list of subtitle lines. It subscribes to SubtitleBus.OnSubtitle, stores recent lines with expirations, renders speaker and text, limits to 3 lines, and removes expired lines each Tick.

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

<root>
	@foreach ( var line in lines )
	{
		<div class="subtitle">
			@if ( !string.IsNullOrEmpty( line.Speaker ) )
			{
				<span class="speaker">@line.Speaker:</span>
			}
			<span class="text">@line.Text</span>
		</div>
	}
</root>

@code {
	private readonly List<(string Speaker, string Text, TimeUntil Expire)> lines = new();

	public SubtitlesList()
	{
		SubtitleBus.OnSubtitle += Add;
	}

	public override void OnDeleted()
	{
		base.OnDeleted();
		SubtitleBus.OnSubtitle -= Add;
	}

	private void Add( string speaker, string text, float duration )
	{
		lines.Add( (speaker, text, duration) );
		if ( lines.Count > 3 )
			lines.RemoveAt( 0 );
	}

	public override void Tick()
	{
		lines.RemoveAll( l => l.Expire );
	}

	protected override int BuildHash() => HashCode.Combine( lines.Count, lines.LastOrDefault().Text );
}

<style>
	SubtitlesList {
		position: absolute;
		left: 0; right: 0;
		bottom: 60px;
		flex-direction: column;
		align-items: center;

		.subtitle {
			flex-direction: row;
			padding: 6px 16px;
			margin-top: 4px;
			background-color: rgba(0,0,0,0.6);
			font-size: 26px;
			text-shadow: 2px 2px 0px black;

			.speaker { color: rgba(255,220,80,1); margin-right: 8px; }
			.text { color: white; }
		}
	}
</style>