Vibed deck viewer

This commit is contained in:
2026-06-18 13:30:46 -04:00
parent c3c8aa1403
commit 111bc36fd4
12 changed files with 1062 additions and 34 deletions
+155 -2
View File
@@ -30,7 +30,7 @@ foreach (var file in mdFiles)
if (endIndex < 0)
continue;
var frontmatter = content[3..endIndex].Trim();
var frontmatter = content[3..endIndex].Trim().Replace("\r\n", "\n").Replace("\r", "\n");
var yaml = ParseYaml(frontmatter);
var name = Path.GetFileNameWithoutExtension(file);
@@ -117,6 +117,75 @@ writer.WriteLine(" ];");
writer.WriteLine("}");
Console.WriteLine($"Generated {cards.Count} cards in {generatedFile}");
// ── Decks ──
var decksDir = Path.Combine(docsDir, "Decks");
var deckFiles = Directory.Exists(decksDir) ? Directory.GetFiles(decksDir, "*.md") : [];
var decks = new List<DeckData>();
foreach (var file in deckFiles)
{
var content = Encoding.UTF8.GetString(File.ReadAllBytes(file));
if (!content.StartsWith("---")) continue;
var endIndex = content.IndexOf("---", 3, StringComparison.Ordinal);
if (endIndex < 0) continue;
var frontmatter = content[3..endIndex].Trim().Replace("\r\n", "\n").Replace("\r", "\n");
var yaml = ParseYaml(frontmatter);
var name = Path.GetFileNameWithoutExtension(file);
var isVisible = yaml.GetValueOrDefault("isVisible") == "true";
var deck = new DeckData
{
Name = name,
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"),
Factions = ParseList(yaml, "factions").Select(s => StripWikiLink(s) ?? "").Where(s => s != "").ToList(),
IsVisible = isVisible,
};
decks.Add(deck);
}
Console.WriteLine($"Parsed {decks.Count} deck files");
// Generate Decks.g.cs
var deckGeneratedFile = Path.Combine(repoRoot, "Chrono", "Web", "Generated", "Decks.g.cs");
Directory.CreateDirectory(Path.GetDirectoryName(deckGeneratedFile)!);
using var deckWriter = new StreamWriter(deckGeneratedFile, false, Encoding.UTF8);
deckWriter.WriteLine("// <auto-generated/>");
deckWriter.WriteLine("#nullable enable");
deckWriter.WriteLine();
deckWriter.WriteLine("namespace Chrono.Model;");
deckWriter.WriteLine();
deckWriter.WriteLine("public static class DeckDatabase");
deckWriter.WriteLine("{");
deckWriter.WriteLine(" public static readonly System.Collections.Generic.List<DeckData> Decks =");
deckWriter.WriteLine(" [");
for (var i = 0; i < decks.Count; i++)
{
var d = decks[i];
deckWriter.WriteLine(" new()");
deckWriter.WriteLine(" {");
WriteProp(deckWriter, "Name", d.Name, 3);
WriteListProp(deckWriter, "Cards", d.Cards, 3);
WriteListProp(deckWriter, "Keycards", d.Keycards, 3);
WriteListProp(deckWriter, "Divers", d.Divers, 3);
WriteStrProp(deckWriter, "Description", d.Description, 3);
WriteListProp(deckWriter, "Factions", d.Factions, 3);
deckWriter.WriteLine($" IsVisible = {(d.IsVisible ? "true" : "false")},");
var comma = i < decks.Count - 1 ? "," : "";
deckWriter.WriteLine($" }}{comma}");
}
deckWriter.WriteLine(" ];");
deckWriter.WriteLine("}");
Console.WriteLine($"Generated {decks.Count} decks in {deckGeneratedFile}");
return 0;
// --- Helpers ---
@@ -181,10 +250,48 @@ static Dictionary<string, string> ParseYaml(string yaml)
var lines = yaml.Split('\n');
string? currentKey = null;
var listBuffer = new List<string>();
var inBlockScalar = false;
string? blockScalarKey = null;
var blockScalarLines = new List<string>();
string? quoteKey = null;
var quoteLines = new List<string>();
foreach (var line in lines)
{
var trimmed = line.Trim();
if (inBlockScalar)
{
if (line.Length == 0 || line[0] == ' ' || line[0] == '\t')
{
blockScalarLines.Add(trimmed);
continue;
}
if (blockScalarKey != null)
dict[blockScalarKey] = string.Join("\n", blockScalarLines);
inBlockScalar = false;
blockScalarKey = null;
blockScalarLines.Clear();
}
if (quoteKey != null)
{
if (line.Length == 0 || line[0] == ' ' || line[0] == '\t')
{
quoteLines.Add(trimmed);
if (trimmed.EndsWith("\""))
{
dict[quoteKey] = string.Join("\n", quoteLines.Select(UnescapeYaml)).TrimEnd('"');
quoteKey = null;
quoteLines.Clear();
}
continue;
}
dict[quoteKey] = string.Join("\n", quoteLines.Select(UnescapeYaml));
quoteKey = null;
quoteLines.Clear();
}
if (trimmed.Length == 0) continue;
if (trimmed.StartsWith("- "))
@@ -205,16 +312,62 @@ static Dictionary<string, string> ParseYaml(string yaml)
currentKey = trimmed[..colonIndex].Trim();
var value = trimmed[(colonIndex + 1)..].Trim();
if (value.Length == 0) continue;
if (value is "|" or "|-")
{
inBlockScalar = true;
blockScalarKey = currentKey;
blockScalarLines.Clear();
continue;
}
if (value.StartsWith("\"") && !value.EndsWith("\""))
{
quoteKey = currentKey;
quoteLines.Clear();
quoteLines.Add(value.TrimStart('"'));
continue;
}
dict[currentKey] = value;
}
if (listBuffer.Count > 0 && currentKey != null)
dict[currentKey] = string.Join("\n", listBuffer);
if (inBlockScalar && blockScalarKey != null)
dict[blockScalarKey] = string.Join("\n", blockScalarLines);
if (quoteKey != null)
dict[quoteKey] = string.Join("\n", quoteLines.Select(UnescapeYaml));
return dict;
}
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;
default: sb.Append(s[i]); break;
}
}
else
{
sb.Append(s[i]);
}
}
return sb.ToString();
}
static void WriteProp(StreamWriter w, string name, string value, int indent)
{
w.WriteLine($"{new string(' ', indent * 4)}{name} = {ToLiteral(value)},");