Files
ChronoCCG/Chrono/Shared/Services/CardRenderingService.cs
T

75 lines
2.5 KiB
C#

using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Components;
using Model;
namespace Shared.Services;
public class CardRenderingService
{
private readonly Dictionary<string, CardData> _cardLookup;
private readonly List<string> _cardNames;
private readonly Regex _nameRegex;
public CardRenderingService()
{
var allCards = CardDatabase.Cards
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
.ToList();
_cardLookup = allCards
.GroupBy(c => c.Name, StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.First(), StringComparer.OrdinalIgnoreCase);
_cardNames = allCards
.Select(c => c.Name)
.OrderByDescending(n => n.Length)
.ToList();
var pattern = string.Join("|", _cardNames.Select(n => $@"\b{Regex.Escape(n)}\b"));
_nameRegex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
}
public RenderFragment RenderDescription(string description, Action<CardData?> onCardClick)
{
return builder =>
{
var sequence = 0;
var paragraphs = description.Split('\n', StringSplitOptions.RemoveEmptyEntries);
foreach (var paragraph in paragraphs)
{
builder.OpenElement(sequence++, "p");
var matches = _nameRegex.Matches(paragraph);
var lastIndex = 0;
foreach (Match match in matches)
{
if (match.Index > lastIndex)
builder.AddContent(sequence++, paragraph.Substring(lastIndex, match.Index - lastIndex));
var cardName = match.Value;
var card = LookupCard(cardName);
builder.OpenElement(sequence++, "button");
builder.AddAttribute(sequence++, "class", "inline-card-btn");
builder.AddAttribute(sequence++, "onclick",
EventCallback.Factory.Create(this, () => onCardClick(card)));
builder.AddContent(sequence++, cardName);
builder.CloseElement();
lastIndex = match.Index + match.Length;
}
if (lastIndex < paragraph.Length) builder.AddContent(sequence++, paragraph.Substring(lastIndex));
builder.CloseElement();
}
};
}
private CardData? LookupCard(string cardName)
{
return _cardLookup.GetValueOrDefault(cardName);
}
}