Examples/TwitchChatExample/TwitchChatEntry.razor
@using System.Collections.Generic;
@using System.Linq;
@using Sandbox;
@using Sandbox.UI;
@namespace TwitchAPI.Examples

<root>
    <div class="username">
        <div class="badges">
            @foreach (var badge in ChatMessage.User.Badges)
            {
                <div class="badge @badge" />
            }
        </div>
        @if (HasAvatarImages)
        {
            <img class="avatar" [email protected]() />
        }
        <label class="name" style="color: @ChatMessage.User.Color.Hex">@ChatMessage.Username</label>
        <label>:</label>
    </div>
    <div class="message">
        @foreach (var fragment in Fragments)
        {
            if (fragment.Emote is not null)
            {
                <img class="emote" src="@fragment.Emote" />
            }
            else
            {
                <label>@fragment.Text</label>
            }
        }
    </div>
</root>

@code
{
    public TwitchChatMessage ChatMessage { get; set; }
    public float Lifetime { get; set; } = 10f;
    public float FadeTime { get; set; } = 0.5f;
    public bool HasAvatarImages { get; set; } = false;
    List<MessageFragment> Fragments { get; set; } = new();

    TimeSince TimeSinceCreated = 0f;

    record MessageFragment(string Text, string Emote);

    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        Fragments.Clear();
        var text = ChatMessage.Message;
        var emotes = ChatMessage.Emotes;
        var currentEmote = emotes.FirstOrDefault();
        var currentIndex = 0;
        while (currentEmote is not null)
        {
            var textPrior = text.Substring(currentIndex, currentEmote.StartingCharacter - currentIndex);
            if (!string.IsNullOrWhiteSpace(textPrior))
            {
                foreach (var word in textPrior.Split(' '))
                {
                    if (string.IsNullOrWhiteSpace(word)) continue;
                    Fragments.Add(new MessageFragment(word, null));
                }
            }

            var emoteText = text.Substring(currentEmote.StartingCharacter, currentEmote.EndingCharacter - currentEmote.StartingCharacter + 1);
            Fragments.Add(new MessageFragment(emoteText, currentEmote.GetImageUrl()));

            currentIndex = currentEmote.EndingCharacter + 1;
            currentEmote = emotes.FirstOrDefault(e => e.StartingCharacter >= currentIndex);
        }

        var textAfter = text.Substring(currentIndex);
        if (!string.IsNullOrWhiteSpace(textAfter))
        {
            foreach (var word in textAfter.Split(' '))
            {
                if (string.IsNullOrWhiteSpace(word)) continue;
                Fragments.Add(new MessageFragment(word, null));
            }
        }
    }

    public override void Tick()
    {
        if (TimeSinceCreated >= Lifetime)
        {
            var opacity = 1f - ((TimeSinceCreated - Lifetime) / FadeTime);
            if (opacity <= 0f)
            {
                Delete();
            }
            else
            {
                Style.Opacity = opacity;
            }
        }
    }
}