Vibe Google Analytics
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
@namespace Shared.Components
|
||||
@using Chrono.Model
|
||||
|
||||
@if (Card != null)
|
||||
{
|
||||
@@ -11,7 +10,7 @@
|
||||
{
|
||||
<div class="detail-image">
|
||||
<img src="@Card.ImagePath" alt="@Card.Name"
|
||||
onerror="this.style.display='none';this.parentElement.style.display='none'" />
|
||||
onerror="this.style.display='none';this.parentElement.style.display='none'"/>
|
||||
</div>
|
||||
}
|
||||
<div class="detail-info">
|
||||
@@ -61,7 +60,7 @@
|
||||
<span class="field-value">@Card.Set</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@if (Card.Artist != null)
|
||||
{
|
||||
<div class="detail-field">
|
||||
@@ -69,7 +68,7 @@
|
||||
<span class="field-value">@Card.Artist</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@if (Card.Rarity != null)
|
||||
{
|
||||
<div class="detail-field">
|
||||
@@ -105,7 +104,8 @@
|
||||
var target = LookupCard(targetName);
|
||||
if (target != null)
|
||||
{
|
||||
<button class="inline-card-btn" @onclick="() => SelectCard(target)">@targetName</button>
|
||||
<button class="inline-card-btn"
|
||||
@onclick="() => SelectCard(target)">@targetName</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -125,7 +125,8 @@
|
||||
var fromCard = LookupCard(Card.ImmortalizeFrom);
|
||||
if (fromCard != null)
|
||||
{
|
||||
<button class="inline-card-btn" @onclick="() => SelectCard(fromCard)">@Card.ImmortalizeFrom</button>
|
||||
<button class="inline-card-btn"
|
||||
@onclick="() => SelectCard(fromCard)">@Card.ImmortalizeFrom</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -148,9 +149,15 @@
|
||||
|
||||
private bool HasImage => Card?.ImageFile is { Length: > 0 } && Card.ImageFile != "placeholder.png";
|
||||
|
||||
private async Task Close() => await OnClose.InvokeAsync();
|
||||
private async Task Close()
|
||||
{
|
||||
await OnClose.InvokeAsync();
|
||||
}
|
||||
|
||||
private async Task SelectCard(CardData card) => await OnSelectCard.InvokeAsync(card);
|
||||
private async Task SelectCard(CardData card)
|
||||
{
|
||||
await OnSelectCard.InvokeAsync(card);
|
||||
}
|
||||
|
||||
private RenderFragment RenderCardDescription(string description)
|
||||
{
|
||||
@@ -163,4 +170,5 @@
|
||||
return CardDatabase.Cards.FirstOrDefault(c =>
|
||||
string.Equals(c.Name, cardName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,8 +10,12 @@
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.card-detail {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@namespace Shared.Components
|
||||
@using Chrono.Model
|
||||
|
||||
<div class="deck-card-row">
|
||||
@foreach (var group in Cards.GroupBy(x => x))
|
||||
@@ -29,10 +28,13 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired] public List<string> Cards { get; set; } = [];
|
||||
[Parameter][EditorRequired] public List<string> Cards { get; set; } = [];
|
||||
[Parameter] public EventCallback<CardData?> OnSelectCard { get; set; }
|
||||
|
||||
private async Task SelectCard(CardData? card) => await OnSelectCard.InvokeAsync(card);
|
||||
private async Task SelectCard(CardData? card)
|
||||
{
|
||||
await OnSelectCard.InvokeAsync(card);
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, CardData> CardLookup = CardDatabase.Cards
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
|
||||
@@ -43,4 +45,5 @@
|
||||
{
|
||||
return CardLookup.GetValueOrDefault(cardName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="mana-curve">
|
||||
@foreach (var entry in Distribution)
|
||||
{
|
||||
var height = MaxCount > 0 ? (entry.Count * 100 / MaxCount) : 0;
|
||||
var height = MaxCount > 0 ? entry.Count * 100 / MaxCount : 0;
|
||||
<div class="mana-bar-container">
|
||||
<div class="mana-bar-label">@entry.Count</div>
|
||||
<div class="mana-bar" style="height: @($"{Math.Max(height, 5)}%")"></div>
|
||||
@@ -13,7 +13,7 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired] public List<(int Cost, int Count)> Distribution { get; set; } = [];
|
||||
[Parameter][EditorRequired] public List<(int Cost, int Count)> Distribution { get; set; } = [];
|
||||
[Parameter] public int MaxCostLabel { get; set; } = 10;
|
||||
|
||||
private int MaxCount => Distribution.Count > 0 ? Distribution.Max(x => x.Count) : 0;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
@implements IDisposable
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject AnalyticsService AnalyticsService
|
||||
|
||||
@code {
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
NavigationManager.LocationChanged += OnLocationChanged;
|
||||
}
|
||||
|
||||
private async void OnLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
await TrackPageView(e.Location);
|
||||
}
|
||||
|
||||
private async Task TrackPageView(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
var relativePath = NavigationManager.ToBaseRelativePath(url);
|
||||
if (!relativePath.StartsWith("/"))
|
||||
{
|
||||
relativePath = "/" + relativePath;
|
||||
}
|
||||
|
||||
await AnalyticsService.TrackPageView(relativePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore errors during tracking
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
NavigationManager.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Lifeblood",
|
||||
Category = "Faction",
|
||||
Content = "Concepts:\r\n- Wide Boards\r\n- Overpower",
|
||||
Content = "Concepts:\r\n\r\n- Wide Boards\r\n- Overpower",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Faction" },
|
||||
@@ -164,7 +164,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Phasetide",
|
||||
Category = "Faction",
|
||||
Content = "Concepts:\r\n- Healing\r\n-",
|
||||
Content = "Concepts:\r\n\r\n- Healing\r\n-",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Faction" },
|
||||
@@ -174,7 +174,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Silence",
|
||||
Category = "Faction",
|
||||
Content = "Concepts:\r\n- Activatable Agents\r\n-",
|
||||
Content = "Concepts:\r\n\r\n- Activatable Agents\r\n-",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Faction" },
|
||||
@@ -184,7 +184,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Singularity",
|
||||
Category = "Faction",
|
||||
Content = "Concepts:\r\n- Discard",
|
||||
Content = "Concepts:\r\n\r\n- Discard",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Faction" },
|
||||
@@ -194,7 +194,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Splintergleam",
|
||||
Category = "Faction",
|
||||
Content = "# Self Damage\r\n\r\nCan hurt it's own units for power. Has [[Bleed]] to make reoccurring damage on units very easy.\r\n\r\n# Core Damage \r\n\r\nCan hurt both cores easily. Has [[Breakdown]] to take advantage of having an injured core for more damage.",
|
||||
Content = "# Self Damage\r\n\r\nCan hurt it's own units for power. Has [[Bleed]] to make reoccurring damage on units very easy.\r\n\r\n# Core Damage\r\n\r\nCan hurt both cores easily. Has [[Breakdown]] to take advantage of having an injured core for more damage.",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Faction" },
|
||||
@@ -204,7 +204,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Sungrace",
|
||||
Category = "Faction",
|
||||
Content = "# Energy Reserves\r\n\r\nCare about always having banked energy. Spells can refund themselves when using [[Energy Reserves]], or get stronger is you [[Overflow]] your energy reserve.\r\n\r\nConcepts:\r\n- Ramp\r\n- Using and Replenishing Reserved Energy\r\n-",
|
||||
Content = "# Energy Reserves\r\n\r\nCare about always having banked energy. Spells can refund themselves when using [[Energy Reserves]], or get stronger is\r\nyou [[Overflow]] your energy reserve.\r\n\r\nConcepts:\r\n\r\n- Ramp\r\n- Using and Replenishing Reserved Energy\r\n-",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Faction" },
|
||||
@@ -479,7 +479,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Onboarding Track",
|
||||
Category = "Pass",
|
||||
Content = "| Tier | Reward |\r\n| ---- | -------------------------------- |\r\n| 1 | Sprouts Record |\r\n| 2 | 120 Core Charges |\r\n| 3 | Burn Precon |\r\n| 4 | 120 Core Charges, 25 Flux |\r\n| 5 | Profile Pictures |\r\n| 6 | Emotes |\r\n| 7 | 120 Core Charges |\r\n| 8 | Profile Pictures |\r\n| 9 | 60 Core Charges, 50 Flux |\r\n| 10 | 240 Core Charges, 1 Draft Ticket |\r\n\r\n| Core Charges | Flux |\r\n| ------------ | ---- |\r\n| 660 | 75 |",
|
||||
Content = "| Tier | Reward |\r\n|------|----------------------------------|\r\n| 1 | Sprouts Record |\r\n| 2 | 120 Core Charges |\r\n| 3 | Burn Precon |\r\n| 4 | 120 Core Charges, 25 Flux |\r\n| 5 | Profile Pictures |\r\n| 6 | Emotes |\r\n| 7 | 120 Core Charges |\r\n| 8 | Profile Pictures |\r\n| 9 | 60 Core Charges, 50 Flux |\r\n| 10 | 240 Core Charges, 1 Draft Ticket |\r\n\r\n| Core Charges | Flux |\r\n|--------------|------|\r\n| 660 | 75 |",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "expPer", "30" },
|
||||
@@ -491,7 +491,7 @@ public static class DocDatabase
|
||||
{
|
||||
Title = "Daily Wins",
|
||||
Category = "Quest",
|
||||
Content = "1: 30cc 30xp \n2: 20cc 25xp \n3: 20cc 20xp \n4: 10cc 20xp \n5: 10cc 15xp \n6-12 are all simply 5xp. \n\nSo the daily total win reward for 12 wins is 90cc/145xp.",
|
||||
Content = "1: 30cc 30xp\n2: 20cc 25xp\n3: 20cc 20xp\n4: 10cc 20xp\n5: 10cc 15xp\n6-12 are all simply 5xp.\n\nSo the daily total win reward for 12 wins is 90cc/145xp.",
|
||||
Frontmatter = new()
|
||||
{
|
||||
{ "category", "Quest" },
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<NavigationTracker/>
|
||||
<article class="content px-4">
|
||||
<TelerikRootComponent>
|
||||
@Body
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<PageTitle>Chrono CCG - Agents</PageTitle>
|
||||
|
||||
<HeadContent>
|
||||
<meta name="description" content="View and compare all Chrono CCG agents. Analyze stats, factions, and efficiency to build the perfect deck." />
|
||||
<meta name="description"
|
||||
content="View and compare all Chrono CCG agents. Analyze stats, factions, and efficiency to build the perfect deck."/>
|
||||
</HeadContent>
|
||||
|
||||
<div class="agents-page">
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
<PageTitle>Chrono CCG - @(deck?.Name ?? "Deck Details")</PageTitle>
|
||||
|
||||
<HeadContent>
|
||||
<meta name="description" content="@(deck != null ? $"View details for the {deck.Name} deck. {deck.Cards.Count} cards, {deck.Factions.Count} factions." : "Deck details and card list.")" />
|
||||
<meta name="description"
|
||||
content="@(deck != null ? $"View details for the {deck.Name} deck. {deck.Cards.Count} cards, {deck.Factions.Count} factions." : "Deck details and card list.")"/>
|
||||
</HeadContent>
|
||||
|
||||
<div class="deck-detail-page">
|
||||
@@ -23,7 +24,8 @@
|
||||
<article class="deck-article">
|
||||
<header class="deck-header">
|
||||
<h1>@deck.Name</h1>
|
||||
<b>Deck Code:</b> <pre>@deck.DeckCode</pre>
|
||||
<b>Deck Code:</b>
|
||||
<pre>@deck.DeckCode</pre>
|
||||
@if (deck.Factions.Count > 0)
|
||||
{
|
||||
<div class="deck-factions">
|
||||
@@ -44,14 +46,14 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<ManaCurve Distribution="GetManaDistribution()" MaxCostLabel="10" />
|
||||
<ManaCurve Distribution="GetManaDistribution()" MaxCostLabel="10"/>
|
||||
</header>
|
||||
|
||||
@if (deck.Keycards.Count > 0)
|
||||
{
|
||||
<section class="deck-section">
|
||||
<h2><i class="bi bi-star-fill" style="color: var(--gold);"></i> Keycards</h2>
|
||||
<CardGrid Cards="deck.Keycards" OnSelectCard="SelectCard" />
|
||||
<CardGrid Cards="deck.Keycards" OnSelectCard="SelectCard"/>
|
||||
</section>
|
||||
}
|
||||
|
||||
@@ -59,13 +61,13 @@
|
||||
{
|
||||
<section class="deck-section">
|
||||
<h2><i class="bi bi-shuffle"></i> Divers</h2>
|
||||
<CardGrid Cards="deck.Divers" OnSelectCard="SelectCard" />
|
||||
<CardGrid Cards="deck.Divers" OnSelectCard="SelectCard"/>
|
||||
</section>
|
||||
}
|
||||
|
||||
<section class="deck-section">
|
||||
<h2><i class="bi bi-collection-fill"></i> Cards</h2>
|
||||
<CardGrid Cards="deck.Cards" OnSelectCard="SelectCard" />
|
||||
<CardGrid Cards="deck.Cards" OnSelectCard="SelectCard"/>
|
||||
</section>
|
||||
|
||||
@if (deck.Description != null)
|
||||
@@ -81,10 +83,10 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<CardDetailModal Card="selectedCard"
|
||||
OnClose="CloseDetail"
|
||||
OnSelectCard="SelectCard"
|
||||
DescriptionRenderer="@(desc => CardRenderer.RenderDescription(desc, SelectCard))" />
|
||||
<CardDetailModal Card="selectedCard"
|
||||
OnClose="CloseDetail"
|
||||
OnSelectCard="SelectCard"
|
||||
DescriptionRenderer="@(desc => CardRenderer.RenderDescription(desc, SelectCard))"/>
|
||||
|
||||
@code {
|
||||
[Parameter] public string Name { get; set; } = "";
|
||||
@@ -124,7 +126,7 @@
|
||||
{
|
||||
if (deck == null) return [];
|
||||
var counts = new Dictionary<int, int>();
|
||||
for (int i = 0; i <= 10; i++) counts[i] = 0;
|
||||
for (var i = 0; i <= 10; i++) counts[i] = 0;
|
||||
|
||||
foreach (var cardName in deck.Cards)
|
||||
{
|
||||
@@ -139,4 +141,5 @@
|
||||
|
||||
return counts.OrderBy(x => x.Key).Select(x => (x.Key, x.Value)).ToList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<PageTitle>Chrono CCG - Decks</PageTitle>
|
||||
|
||||
<HeadContent>
|
||||
<meta name="description" content="Explore community and official Chrono CCG decks. Find the best strategies and card combinations." />
|
||||
<meta name="description"
|
||||
content="Explore community and official Chrono CCG decks. Find the best strategies and card combinations."/>
|
||||
</HeadContent>
|
||||
|
||||
<div class="decks-page">
|
||||
@@ -13,7 +14,8 @@
|
||||
<div class="decks-header-row">
|
||||
<p class="text-secondary">@decks.Count deck@(decks.Count != 1 ? "s" : "")</p>
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="showPrecons" @bind="showPrecons" @bind:after="RefreshDecks">
|
||||
<input class="form-check-input" type="checkbox" id="showPrecons" @bind="showPrecons"
|
||||
@bind:after="RefreshDecks">
|
||||
<label class="form-check-label" for="showPrecons">Show Precons</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,11 +36,11 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<div class="deck-card-factions">
|
||||
<span class="faction-badge">@deck.DeckType</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="deck-card-meta">
|
||||
<span>@deck.Cards.Distinct().Count() unique, @deck.Cards.Count total</span>
|
||||
@if (deck.Keycards.Count > 0)
|
||||
@@ -70,7 +72,7 @@
|
||||
|
||||
@code {
|
||||
private List<DeckData> decks = [];
|
||||
private bool showPrecons = false;
|
||||
private bool showPrecons;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
@@ -81,10 +83,10 @@
|
||||
{
|
||||
decks = DeckDatabase.Decks
|
||||
.Where(d => d.IsVisible)
|
||||
.Where(d =>
|
||||
showPrecons
|
||||
? d.DeckType is "precon" or "store" :
|
||||
d.DeckType is "custom")
|
||||
.Where(d =>
|
||||
showPrecons
|
||||
? d.DeckType is "precon" or "store"
|
||||
: d.DeckType is "custom")
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,17 +13,19 @@
|
||||
<aside class="docs-sidebar">
|
||||
<div class="search-box">
|
||||
<i class="bi bi-search"></i>
|
||||
<input type="text" placeholder="Search docs..." @bind="searchQuery" @bind:event="oninput" />
|
||||
<input type="text" placeholder="Search docs..." @bind="searchQuery" @bind:event="oninput"/>
|
||||
</div>
|
||||
|
||||
<div class="category-list">
|
||||
<div class="category-item @(selectedCategory == null ? "active" : "")" @onclick="() => SelectCategory(null)">
|
||||
<div class="category-item @(selectedCategory == null ? "active" : "")"
|
||||
@onclick="() => SelectCategory(null)">
|
||||
All Pages
|
||||
</div>
|
||||
@foreach (var category in categories)
|
||||
{
|
||||
var cat = category;
|
||||
<div class="category-item @(selectedCategory == cat ? "active" : "")" @onclick="() => SelectCategory(cat)">
|
||||
<div class="category-item @(selectedCategory == cat ? "active" : "")"
|
||||
@onclick="() => SelectCategory(cat)">
|
||||
@cat
|
||||
</div>
|
||||
}
|
||||
@@ -134,20 +136,24 @@
|
||||
return doc.Frontmatter.TryGetValue(key, out var val) && !string.IsNullOrWhiteSpace(val) ? val : null;
|
||||
}
|
||||
|
||||
private static string GetLabel(string key) => key switch
|
||||
private static string GetLabel(string key)
|
||||
{
|
||||
"category" => "Category",
|
||||
"description" => "Description",
|
||||
"essencePrice" => "Essence Price",
|
||||
"crytalPrice" => "Crystal Price",
|
||||
"coreChargesPrice" => "Core Charges Price",
|
||||
"pricePerPack" => "Price per Pack",
|
||||
"codeCharges" => "Code Charges",
|
||||
"coreCharges" => "Core Charges",
|
||||
"currency" => "Currency",
|
||||
"faction" => "Faction",
|
||||
"exp" => "EXP Reward",
|
||||
"see" => "See Also",
|
||||
_ => string.Concat(key.Select((c, i) => i > 0 && char.IsUpper(c) ? " " + c : c.ToString())),
|
||||
};
|
||||
return key switch
|
||||
{
|
||||
"category" => "Category",
|
||||
"description" => "Description",
|
||||
"essencePrice" => "Essence Price",
|
||||
"crytalPrice" => "Crystal Price",
|
||||
"coreChargesPrice" => "Core Charges Price",
|
||||
"pricePerPack" => "Price per Pack",
|
||||
"codeCharges" => "Code Charges",
|
||||
"coreCharges" => "Core Charges",
|
||||
"currency" => "Currency",
|
||||
"faction" => "Faction",
|
||||
"exp" => "EXP Reward",
|
||||
"see" => "See Also",
|
||||
_ => string.Concat(key.Select((c, i) => i > 0 && char.IsUpper(c) ? " " + c : c.ToString()))
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Shared.Services;
|
||||
|
||||
public class AnalyticsService
|
||||
{
|
||||
private readonly IJSRuntime _jsRuntime;
|
||||
|
||||
public AnalyticsService(IJSRuntime jsRuntime)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
public async ValueTask TrackPageView(string path)
|
||||
{
|
||||
await _jsRuntime.InvokeVoidAsync("trackPageView", path);
|
||||
}
|
||||
|
||||
public async ValueTask TrackEvent(string eventName, object? eventData = null)
|
||||
{
|
||||
if (eventData != null)
|
||||
await _jsRuntime.InvokeVoidAsync("gtag", "event", eventName, eventData);
|
||||
else
|
||||
await _jsRuntime.InvokeVoidAsync("gtag", "event", eventName);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Text.RegularExpressions;
|
||||
using Chrono.Model;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Shared.Services;
|
||||
|
||||
public class CardRenderingService
|
||||
{
|
||||
private readonly List<string> _cardNames;
|
||||
private readonly Dictionary<string, CardData> _cardLookup;
|
||||
private readonly List<string> _cardNames;
|
||||
private readonly Regex _nameRegex;
|
||||
|
||||
public CardRenderingService()
|
||||
@@ -33,7 +33,7 @@ public class CardRenderingService
|
||||
{
|
||||
return builder =>
|
||||
{
|
||||
int sequence = 0;
|
||||
var sequence = 0;
|
||||
var paragraphs = description.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var paragraph in paragraphs)
|
||||
@@ -41,31 +41,27 @@ public class CardRenderingService
|
||||
builder.OpenElement(sequence++, "p");
|
||||
|
||||
var matches = _nameRegex.Matches(paragraph);
|
||||
int lastIndex = 0;
|
||||
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.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));
|
||||
}
|
||||
if (lastIndex < paragraph.Length) builder.AddContent(sequence++, paragraph.Substring(lastIndex));
|
||||
|
||||
builder.CloseElement();
|
||||
}
|
||||
@@ -76,4 +72,4 @@ public class CardRenderingService
|
||||
{
|
||||
return _cardLookup.GetValueOrDefault(cardName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user