@page "/" @page "/cards" @using Chrono.Components @inject AnalyticsService AnalyticsService Chrono CCG - Card Gallery @if (selectedCard != null) { } @code { private List allCards = []; private IEnumerable filteredCards => ApplyFilters(); private string search = ""; private string categoryFilter = ""; private string immortalFilter = ""; private bool agentLink = true; private HashSet syndicateFilter = []; private string costFilter = ""; private string sortBy = "Cost"; private bool sortDescending; private bool showDetailedView; private CardData? selectedCard; private List syndicates = []; private bool HasActiveFilters => categoryFilter != "" || syndicateFilter.Count > 0 || costFilter != "" || immortalFilter != ""; protected override void OnInitialized() { allCards = CardDatabase.Cards; syndicates = allCards .Select(c => c.Faction) .Where(f => f != null) .Distinct() .OrderBy(f => f) .ToList()!; } private IEnumerable ApplyFilters() { var primarySet = allCards.Where(c => c.MatchesSearch(search) && (categoryFilter == "" || c.Category == categoryFilter) && (syndicateFilter.Count == 0 || (c.Faction != null && syndicateFilter.Contains(c.Faction))) && (costFilter == "" || c.Cost?.ToString() == costFilter) ); var sortedPrimary = sortBy switch { "Cost" => sortDescending ? primarySet.OrderByDescending(c => c.Cost) : primarySet.OrderBy(c => c.Cost), "Efficiency" => sortDescending ? primarySet.OrderByDescending(c => c.StatEfficiency) : primarySet.OrderBy(c => c.StatEfficiency), "Attack" => sortDescending ? primarySet.OrderByDescending(c => c.Attack) : primarySet.OrderBy(c => c.Attack), "Health" => sortDescending ? primarySet.OrderByDescending(c => c.Health) : primarySet.OrderBy(c => c.Health), _ => sortDescending ? primarySet.OrderByDescending(c => c.Name) : primarySet.OrderBy(c => c.Name) }; if (!agentLink) { return sortedPrimary; } var result = new List(); var seen = new HashSet(); foreach (var card in sortedPrimary) { if (seen.Contains(card.Name)) continue; // Determine the "Chain Head" (the Agent) var head = card; if (card.Category == "Immortalized" && card.ImmortalizeFrom != null) { var source = allCards.FirstOrDefault(c => c.Name == card.ImmortalizeFrom); if (source != null) head = source; } // Add the chain starting from head if (!seen.Contains(head.Name)) { result.Add(head); seen.Add(head.Name); } if (head.ImmortalizeTo != null) { foreach (var targetName in head.ImmortalizeTo) { if (seen.Contains(targetName)) continue; var linked = allCards.FirstOrDefault(c => c.Name == targetName); if (linked != null) { result.Add(linked); seen.Add(linked.Name); } } } // Ensure the original card is added if it was somehow not part of the head's chain if (!seen.Contains(card.Name)) { result.Add(card); seen.Add(card.Name); } } return result; } private void SetImmortal(string imm) { immortalFilter = immortalFilter == imm ? "" : imm; } private void ClearImmortalFilter() { immortalFilter = ""; } private void SetSyndicate(string syn) { if (syndicateFilter.Contains(syn)) { syndicateFilter.Remove(syn); } else { syndicateFilter.Add(syn); } } private void SetCategory(string cat) { categoryFilter = categoryFilter == cat ? "" : cat; _ = AnalyticsService.TrackEvent("filter_category", new { category = categoryFilter }); } private void ClearCategoryFilter() { categoryFilter = ""; _ = AnalyticsService.TrackEvent("filter_category", new { category = "All" }); } private void ClearSyndicateFilter() { syndicateFilter.Clear(); } private void ToggleAgentLink() { agentLink = !agentLink; OnToggleAgentLink(); } private void OnToggleAgentLink() { _ = AnalyticsService.TrackEvent("toggle_agent_link", new { enabled = agentLink }); } private void ClearCostFilter() { costFilter = ""; } private void ClearSearch() { search = ""; } private void SelectCard(CardData card) { selectedCard = card; _ = AnalyticsService.TrackEvent("select_item", new { item_name = card.Name, item_category = card.Category }); } private void CloseDetail() { selectedCard = null; } private void ClearFilters() { search = ""; categoryFilter = ""; syndicateFilter.Clear(); costFilter = ""; } }