From 50dcc8e55c32056694350794684c23bd26218b15 Mon Sep 17 00:00:00 2001 From: 6d486f49 Date: Thu, 18 Jun 2026 21:07:28 -0400 Subject: [PATCH] ... --- Chrono/Build/Program.cs | 40 +++++--- Chrono/Deploy/Program.cs | 8 +- Chrono/Model/CardData.cs | 10 ++ Chrono/Model/CardNote.cs | 2 +- Chrono/Model/DeckData.cs | 12 ++- Chrono/Server/AppDbContext.cs | 4 +- Chrono/Server/Controllers/NotesController.cs | 16 +--- Chrono/Server/Program.cs | 19 +--- Chrono/Server/Server.csproj | 42 ++++---- Chrono/Tests/PlaywrightTests.cs | 10 +- Chrono/Tests/TelerikLicenseTests.cs | 6 +- Chrono/Tests/Tests.csproj | 4 +- Chrono/Web/Generated/Decks.g.cs | 24 +++++ Chrono/Web/Layout/NavMenu.razor | 4 +- Chrono/Web/Pages/Agents.razor | 4 +- Chrono/Web/Pages/Cards.razor | 79 +++++++++++++-- Chrono/Web/Pages/Cards.razor.css | 95 +++++++++++++++++++ Chrono/Web/Pages/DeckDetail.razor | 48 +++++++--- Chrono/Web/Pages/DeckDetail.razor.css | 59 ++++++++++-- Chrono/Web/Pages/Decks.razor | 3 +- Chrono/Web/Pages/Home.razor | 7 +- Chrono/Web/Pages/Home.razor.css | 76 ++++++++++++--- Chrono/Web/wwwroot/css/app.css | 10 +- Chrono/Web/wwwroot/index.html | 2 +- Chrono/Web/wwwroot/sample-data/weather.json | 27 ------ .../frontmatter-markdown-links/main.js | 1 + chrono.docs/.obsidian/workspace.json | 2 +- chrono.docs/Decks/Big Energy.md | 24 +++++ chrono.tasks/Docker.md | 43 +++++---- 29 files changed, 502 insertions(+), 179 deletions(-) delete mode 100644 Chrono/Web/wwwroot/sample-data/weather.json diff --git a/Chrono/Build/Program.cs b/Chrono/Build/Program.cs index 086396a..6946b46 100644 --- a/Chrono/Build/Program.cs +++ b/Chrono/Build/Program.cs @@ -142,9 +142,10 @@ foreach (var file in deckFiles) Cards = ParseList(yaml, "cards").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(), Keycards = ParseList(yaml, "keycards").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(), Divers = ParseList(yaml, "divers").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(), - Description = StripWikiLinks(NullIfNa(yaml.GetValueOrDefault("description")))?.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n\n", "\n").Replace("\n\n", "\n"), + Description = StripWikiLinks(NullIfNa(yaml.GetValueOrDefault("description")))?.Replace("\r\n", "\n") + .Replace("\r", "\n").Replace("\n\n", "\n").Replace("\n\n", "\n"), Factions = ParseList(yaml, "factions").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(), - IsVisible = isVisible, + IsVisible = isVisible }; decks.Add(deck); @@ -267,6 +268,7 @@ static Dictionary ParseYaml(string yaml) blockScalarLines.Add(trimmed); continue; } + if (blockScalarKey != null) dict[blockScalarKey] = string.Join("\n", blockScalarLines); inBlockScalar = false; @@ -285,8 +287,10 @@ static Dictionary ParseYaml(string yaml) quoteKey = null; quoteLines.Clear(); } + continue; } + dict[quoteKey] = string.Join("\n", quoteLines.Select(UnescapeYaml)); quoteKey = null; quoteLines.Clear(); @@ -347,24 +351,34 @@ static string UnescapeYaml(string s) { var sb = new StringBuilder(); for (var i = 0; i < s.Length; i++) - { if (s[i] == '\\' && i + 1 < s.Length) - { switch (s[i + 1]) { - case 'r': sb.Append('\r'); i++; break; - case 'n': sb.Append('\n'); i++; break; - case 't': sb.Append('\t'); i++; break; - case '\\': sb.Append('\\'); i++; break; - case '"': sb.Append('"'); i++; break; + case 'r': + sb.Append('\r'); + i++; + break; + case 'n': + sb.Append('\n'); + i++; + break; + case 't': + sb.Append('\t'); + i++; + break; + case '\\': + sb.Append('\\'); + i++; + break; + case '"': + sb.Append('"'); + i++; + break; default: sb.Append(s[i]); break; } - } else - { sb.Append(s[i]); - } - } + return sb.ToString(); } diff --git a/Chrono/Deploy/Program.cs b/Chrono/Deploy/Program.cs index 9eb0877..30dcfe2 100644 --- a/Chrono/Deploy/Program.cs +++ b/Chrono/Deploy/Program.cs @@ -4,7 +4,8 @@ var deployDir = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", ". var webDir = Path.GetFullPath(Path.Combine(deployDir, "..", "Web")); var webProject = Path.Combine(webDir, "Web.csproj"); var publishDir = Path.Combine(Path.GetTempPath(), "chrono-deploy", Guid.NewGuid().ToString()); -var deploymentToken = Environment.GetEnvironmentVariable("Chrono_DeployToken") ?? throw new InvalidOperationException("Chrono_DeployToken environment variable not set."); +var deploymentToken = Environment.GetEnvironmentVariable("Chrono_DeployToken") ?? + throw new InvalidOperationException("Chrono_DeployToken environment variable not set."); var deployEnv = Environment.GetEnvironmentVariable("Chrono_DeployEnv") ?? "preview"; // 1. Publish @@ -20,7 +21,8 @@ if (!Directory.Exists(wwwroot)) // 2. Deploy Console.WriteLine("Deploying to Azure Static Web Apps..."); -Run("swa.cmd", $"deploy \"{wwwroot}\" --deployment-token \"{deploymentToken}\" --app-location \"{webDir}\" --env \"{deployEnv}\""); +Run("swa.cmd", + $"deploy \"{wwwroot}\" --deployment-token \"{deploymentToken}\" --app-location \"{webDir}\" --env \"{deployEnv}\""); Console.WriteLine("Deploy successful!"); return 0; @@ -29,5 +31,5 @@ static void Run(string fileName, string arguments) { var process = Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = false })!; process.WaitForExit(); - if (process.ExitCode != 0) { Environment.Exit(process.ExitCode); } + if (process.ExitCode != 0) Environment.Exit(process.ExitCode); } \ No newline at end of file diff --git a/Chrono/Model/CardData.cs b/Chrono/Model/CardData.cs index 3839760..3f4e39a 100644 --- a/Chrono/Model/CardData.cs +++ b/Chrono/Model/CardData.cs @@ -31,4 +31,14 @@ public class CardData public bool HasImmortalize => ImmortalizeTo is { Count: > 0 }; public bool IsImmortalized => ImmortalizeFrom != null; public string ImagePath => $"cards/{ImageFile ?? "placeholder.png"}"; + + public bool MatchesSearch(string query) + { + if (string.IsNullOrWhiteSpace(query)) return true; + var q = query.Trim().ToLowerInvariant(); + return Name.ToLowerInvariant().Contains(q) || + (Description?.ToLowerInvariant().Contains(q) ?? false) || + (Faction?.ToLowerInvariant().Contains(q) ?? false) || + Archetypes.Any(a => a.ToLowerInvariant().Contains(q)); + } } \ No newline at end of file diff --git a/Chrono/Model/CardNote.cs b/Chrono/Model/CardNote.cs index e6680f9..abae3f2 100644 --- a/Chrono/Model/CardNote.cs +++ b/Chrono/Model/CardNote.cs @@ -4,4 +4,4 @@ public class CardNote { public string CardName { get; set; } = ""; public string Note { get; set; } = ""; -} +} \ No newline at end of file diff --git a/Chrono/Model/DeckData.cs b/Chrono/Model/DeckData.cs index 45c090d..eb556b0 100644 --- a/Chrono/Model/DeckData.cs +++ b/Chrono/Model/DeckData.cs @@ -9,4 +9,14 @@ public class DeckData public string? Description { get; init; } public List Factions { get; init; } = []; public bool IsVisible { get; init; } -} + + public bool IsValid => Cards.Count == 40 && Divers.Count <= 2; + + public string ValidationMessage => (Cards.Count, Divers.Count) switch + { + (< 40, _) => $"Deck needs {40 - Cards.Count} more cards.", + (> 40, _) => $"Deck has {Cards.Count - 40} too many cards.", + (_, > 2) => "Deck can only have 2 Divers.", + _ => "Deck is valid." + }; +} \ No newline at end of file diff --git a/Chrono/Server/AppDbContext.cs b/Chrono/Server/AppDbContext.cs index bf9287d..eb89b90 100644 --- a/Chrono/Server/AppDbContext.cs +++ b/Chrono/Server/AppDbContext.cs @@ -1,5 +1,5 @@ -using Microsoft.EntityFrameworkCore; using Chrono.Model; +using Microsoft.EntityFrameworkCore; namespace Server; @@ -15,4 +15,4 @@ public class AppDbContext : DbContext { modelBuilder.Entity().HasKey(n => n.CardName); } -} +} \ No newline at end of file diff --git a/Chrono/Server/Controllers/NotesController.cs b/Chrono/Server/Controllers/NotesController.cs index 212e4fa..39009c3 100644 --- a/Chrono/Server/Controllers/NotesController.cs +++ b/Chrono/Server/Controllers/NotesController.cs @@ -1,6 +1,5 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Chrono.Model; +using Microsoft.AspNetCore.Mvc; namespace Server.Controllers; @@ -21,10 +20,7 @@ public class NotesController : ControllerBase try { var note = await _context.CardNotes.FindAsync(cardName); - if (note == null) - { - return Ok(new CardNote { CardName = cardName, Note = "" }); - } + if (note == null) return Ok(new CardNote { CardName = cardName, Note = "" }); return Ok(note); } catch (Exception ex) @@ -41,13 +37,9 @@ public class NotesController : ControllerBase { var existing = await _context.CardNotes.FindAsync(note.CardName); if (existing == null) - { _context.CardNotes.Add(note); - } else - { existing.Note = note.Note; - } await _context.SaveChangesAsync(); } @@ -55,7 +47,7 @@ public class NotesController : ControllerBase { Console.WriteLine($"[WARNING] Could not save note to database: {ex.Message}"); } - + return Ok(note); } -} +} \ No newline at end of file diff --git a/Chrono/Server/Program.cs b/Chrono/Server/Program.cs index e795637..adcf379 100644 --- a/Chrono/Server/Program.cs +++ b/Chrono/Server/Program.cs @@ -11,10 +11,7 @@ builder.Services.AddRazorPages(); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); builder.Services.AddDbContext(options => { - if (!string.IsNullOrEmpty(connectionString)) - { - options.UseNpgsql(connectionString); - } + if (!string.IsNullOrEmpty(connectionString)) options.UseNpgsql(connectionString); }); var app = builder.Build(); @@ -25,26 +22,20 @@ using (var scope = app.Services.CreateScope()) try { var db = scope.ServiceProvider.GetRequiredService(); - if (!string.IsNullOrEmpty(connectionString)) - { - db.Database.Migrate(); - } + if (!string.IsNullOrEmpty(connectionString)) db.Database.Migrate(); } catch (Exception ex) { - Console.WriteLine($"[WARNING] Database migration failed: {ex.Message}. The application will continue without a database connection."); + Console.WriteLine( + $"[WARNING] Database migration failed: {ex.Message}. The application will continue without a database connection."); } } // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) -{ app.UseWebAssemblyDebugging(); -} else -{ app.UseExceptionHandler("/Error"); -} app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); @@ -55,4 +46,4 @@ app.MapRazorPages(); app.MapControllers(); app.MapFallbackToFile("index.html"); -app.Run(); +app.Run(); \ No newline at end of file diff --git a/Chrono/Server/Server.csproj b/Chrono/Server/Server.csproj index 3d91b74..51974a9 100644 --- a/Chrono/Server/Server.csproj +++ b/Chrono/Server/Server.csproj @@ -1,27 +1,27 @@ - - - - + + + + - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + - - net10.0 - enable - enable - + + net10.0 + enable + enable + diff --git a/Chrono/Tests/PlaywrightTests.cs b/Chrono/Tests/PlaywrightTests.cs index 9705b26..1927f87 100644 --- a/Chrono/Tests/PlaywrightTests.cs +++ b/Chrono/Tests/PlaywrightTests.cs @@ -1,5 +1,4 @@ using Microsoft.Playwright.NUnit; -using Microsoft.Playwright; namespace Tests; @@ -25,7 +24,7 @@ public class PlaywrightTests : PageTest await Expect(noteInput).ToBeVisibleAsync(); // 5. Type a unique note - string uniqueNote = "Test note " + Guid.NewGuid().ToString(); + var uniqueNote = "Test note " + Guid.NewGuid(); await noteInput.FillAsync(uniqueNote); // 6. Blur to trigger save @@ -33,10 +32,7 @@ public class PlaywrightTests : PageTest // 7. Wait for saving indicator to disappear (if it appeared) var savingIndicator = Page.Locator(".saving-indicator"); - if (await savingIndicator.IsVisibleAsync()) - { - await Expect(savingIndicator).Not.ToBeVisibleAsync(); - } + if (await savingIndicator.IsVisibleAsync()) await Expect(savingIndicator).Not.ToBeVisibleAsync(); // 8. Close the detail view by clicking the backdrop await Page.Locator(".modal-backdrop").ClickAsync(); @@ -48,4 +44,4 @@ public class PlaywrightTests : PageTest // 10. Verify the note is still there await Expect(noteInput).ToHaveValueAsync(uniqueNote); } -} +} \ No newline at end of file diff --git a/Chrono/Tests/TelerikLicenseTests.cs b/Chrono/Tests/TelerikLicenseTests.cs index 6bfb9f4..5da349d 100644 --- a/Chrono/Tests/TelerikLicenseTests.cs +++ b/Chrono/Tests/TelerikLicenseTests.cs @@ -1,5 +1,5 @@ -using Microsoft.Playwright.NUnit; using Microsoft.Playwright; +using Microsoft.Playwright.NUnit; namespace Tests; @@ -25,7 +25,7 @@ public class TelerikLicenseTests : PageTest await Expect(licenseWarning).Not.ToBeVisibleAsync(); // 4. Also verify that no "Trial" banner is visible - var trialBanner = Page.GetByText("Telerik UI for Blazor Trial", new() { Exact = false }); + var trialBanner = Page.GetByText("Telerik UI for Blazor Trial", new PageGetByTextOptions { Exact = false }); await Expect(trialBanner).Not.ToBeVisibleAsync(); } -} +} \ No newline at end of file diff --git a/Chrono/Tests/Tests.csproj b/Chrono/Tests/Tests.csproj index 7606a27..4b7497c 100644 --- a/Chrono/Tests/Tests.csproj +++ b/Chrono/Tests/Tests.csproj @@ -11,14 +11,14 @@ - + - + diff --git a/Chrono/Web/Generated/Decks.g.cs b/Chrono/Web/Generated/Decks.g.cs index 23c415f..fd3c4b3 100644 --- a/Chrono/Web/Generated/Decks.g.cs +++ b/Chrono/Web/Generated/Decks.g.cs @@ -12,19 +12,43 @@ public static class DeckDatabase Name = "Big Energy", Cards = [ "Brilliant Martyr", + "Brilliant Martyr", + "Brilliant Martyr", + "Kinetic Absorber", + "Kinetic Absorber", "Kinetic Absorber", "Hidden Locus", + "Hidden Locus", + "Hidden Locus", + "Suncursed Conduit", + "Suncursed Conduit", "Suncursed Conduit", "Swashbuckling Diehard", + "Swashbuckling Diehard", + "Swashbuckling Diehard", + "Debris Collector", + "Debris Collector", "Debris Collector", "Paradox Flow", + "Paradox Flow", + "Starfueled Medics", + "Starfueled Medics", "Starfueled Medics", "Lumbering Starseeker", + "Lumbering Starseeker", + "Novathermal Mining", + "Novathermal Mining", "Novathermal Mining", "Radiant Channeling", + "Radiant Channeling", + "Radiant Channeling", + "Supernova", + "Supernova", "Supernova", "Gunnery Captain", "Lightsteel Colossus", + "Lightsteel Colossus", + "Devourer Spawn", "Devourer Spawn", "Army of the Sun", ], diff --git a/Chrono/Web/Layout/NavMenu.razor b/Chrono/Web/Layout/NavMenu.razor index 34e76b0..1189715 100644 --- a/Chrono/Web/Layout/NavMenu.razor +++ b/Chrono/Web/Layout/NavMenu.razor @@ -1,6 +1,8 @@