@namespace Chrono.Components @if (Card != null) {
@if (HasImage) {
@Card.Name
}

@Card.Name

@Card.Category @if (Card.Cost.HasValue) { @Card.Cost } @if (Card.Attack.HasValue) { @Card.Attack } @if (Card.Health.HasValue) { @Card.Health } @if (Card.Speed != null) { @Card.Speed }
@if (Card.Faction != null) {
Faction @Card.Faction
} @if (Card.Description != null) {
@RenderDescription(Card.Description)
} @if (Card.Set != null) {
Set @Card.Set
} @if (Card.Archetypes is { Count: > 0 }) {
Archetypes @string.Join(", ", Card.Archetypes)
} @if (Card.ImmortalizeWhen != null) {
Immortalize When @Card.ImmortalizeWhen
} @if (Card.HasImmortalize) {
Immortalizes To @foreach (var name in Card.ImmortalizeTo!) { var targetName = name; var target = LookupCard(targetName); if (target != null) { } else { @targetName } }
} @if (Card.ImmortalizeFrom != null) {
Immortalizes From @{ var fromCard = LookupCard(Card.ImmortalizeFrom); if (fromCard != null) { } else { @Card.ImmortalizeFrom } }
} @if (ShowNotes && Card.IsAgent) {
Personal Note @if (isSaving) { Saving... }
}
} @code { [Parameter] public CardData? Card { get; set; } [Parameter] public EventCallback OnClose { get; set; } [Parameter] public EventCallback OnNavigate { get; set; } [Parameter] public bool ShowNotes { get; set; } [Inject] private HttpClient Http { get; set; } = default!; private bool HasImage => Card?.ImageFile is { Length: > 0 } && Card.ImageFile != "placeholder.png"; private string currentNote = ""; private bool isSaving; protected override void OnParametersSet() { if (Card != null && Card.IsAgent) { currentNote = ""; _ = LoadNote(); } } private async Task LoadNote() { if (Card == null || !Card.IsAgent) return; try { var note = await Http.GetFromJsonAsync($"api/notes/{Uri.EscapeDataString(Card.Name)}"); currentNote = note?.Note ?? ""; } catch { currentNote = ""; } } private async Task SaveNote() { if (Card == null || !Card.IsAgent) return; isSaving = true; try { await Http.PostAsJsonAsync("api/notes", new CardNote { CardName = Card.Name, Note = currentNote }); } catch { } finally { isSaving = false; } } private void HandleClose() { _ = OnClose.InvokeAsync(); } private void HandleBackdropClick() { _ = OnClose.InvokeAsync(); } private void Navigate(CardData card) { _ = OnNavigate.InvokeAsync(card); } private static CardData? LookupCard(string cardName) { return CardDatabase.Cards.FirstOrDefault(c => string.Equals(c.Name, cardName, StringComparison.OrdinalIgnoreCase)); } private RenderFragment RenderDescription(string description) => builder => { var cardNames = CardDatabase.Cards .Select(c => c.Name) .Where(n => !string.IsNullOrWhiteSpace(n)) .OrderByDescending(n => n.Length) .ToList(); int seq = 0; var remaining = description; while (!string.IsNullOrEmpty(remaining)) { int bestIdx = -1; string? bestName = null; foreach (var name in cardNames) { int idx = remaining.IndexOf(name, StringComparison.OrdinalIgnoreCase); if (idx != -1 && (bestIdx == -1 || idx < bestIdx)) { bestIdx = idx; bestName = name; } } if (bestIdx != -1 && bestName != null) { if (bestIdx > 0) builder.AddContent(seq++, remaining[..bestIdx]); var card = LookupCard(bestName); if (card != null) { builder.OpenElement(seq++, "button"); builder.AddAttribute(seq++, "class", "inline-card-btn"); builder.AddAttribute(seq++, "onclick", EventCallback.Factory.Create(this, () => Navigate(card))); builder.AddContent(seq++, bestName); builder.CloseElement(); } else { builder.AddContent(seq++, bestName); } remaining = remaining[(bestIdx + bestName.Length)..]; } else { builder.AddContent(seq++, remaining); remaining = ""; } } }; }