This commit is contained in:
2026-06-10 21:57:37 -04:00
parent 97ec82dd7f
commit e471875dc3
10 changed files with 532 additions and 554 deletions
+10
View File
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+92
View File
@@ -0,0 +1,92 @@
using System.Text.RegularExpressions;
var exeDir = AppContext.BaseDirectory;
var solutionDir = FindContainingDir(exeDir, "ET.sln")
?? throw new InvalidOperationException("Cannot find ET.sln");
var srcDir = Path.GetFullPath(Path.Combine(solutionDir, "..", "docs", "Notes"));
var dstDir = Path.GetFullPath(Path.Combine(solutionDir, "Web", "wwwroot", "docs", "notes"));
Console.WriteLine($"Source: {srcDir}");
Console.WriteLine($"Destination: {dstDir}");
if (!Directory.Exists(srcDir))
{
Console.Error.WriteLine($"Source directory not found: {srcDir}");
return 1;
}
Directory.CreateDirectory(dstDir);
foreach (var file in Directory.GetFiles(dstDir))
File.Delete(file);
var entries = new List<object>();
foreach (var file in Directory.EnumerateFiles(srcDir, "*.md"))
{
var name = Path.GetFileNameWithoutExtension(file);
var slug = Slugify(name);
File.Copy(file, Path.Combine(dstDir, $"{slug}.md"), overwrite: true);
string? category = null;
var content = File.ReadAllText(file);
var fmMatch = Regex.Match(content, @"^---\s*\n(.*?)\n---", RegexOptions.Singleline);
if (fmMatch.Success)
{
var catMatch = Regex.Match(fmMatch.Groups[1].Value, @"(?m)^category:\s*(.+)$");
if (catMatch.Success)
category = catMatch.Groups[1].Value.Trim().Trim('"');
}
var entry = new Dictionary<string, object?>
{
["slug"] = slug,
["title"] = name
};
if (category != null)
entry["category"] = category;
entries.Add(entry);
}
var index = new Dictionary<string, object> { ["notes"] = entries };
var json = System.Text.Json.JsonSerializer.Serialize(index, new System.Text.Json.JsonSerializerOptions
{
WriteIndented = true
});
var indexPath = Path.Combine(Path.GetDirectoryName(dstDir)!, "notes-index.json");
File.WriteAllText(indexPath, json);
Console.WriteLine($"Copied {entries.Count} notes.");
Console.WriteLine($"Index written to: {indexPath}");
return 0;
static string Slugify(string name)
{
var slug = name.ToLowerInvariant()
.Replace("'", "")
.Replace(".", "")
.Replace("(", "")
.Replace(")", "");
slug = Regex.Replace(slug, @"[^a-z0-9 -]", "");
slug = Regex.Replace(slug, @"\s+", "-");
slug = Regex.Replace(slug, @"-+", "-");
return slug.Trim('-');
}
static string? FindContainingDir(string startDir, string markerFile)
{
var dir = new DirectoryInfo(startDir);
while (dir != null)
{
if (File.Exists(Path.Combine(dir.FullName, markerFile)))
return dir.FullName;
dir = dir.Parent;
}
return null;
}
+6
View File
@@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Web\Web.csproj", "{6E375519-4DF8-455B-9AEC-0C84C31106E9}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Web\Web.csproj", "{6E375519-4DF8-455B-9AEC-0C84C31106E9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "Console\Console.csproj", "{A5946F7D-E8CE-4ACE-8D79-0F5FF0CB11C0}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -12,5 +14,9 @@ Global
{6E375519-4DF8-455B-9AEC-0C84C31106E9}.Debug|Any CPU.Build.0 = Debug|Any CPU {6E375519-4DF8-455B-9AEC-0C84C31106E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E375519-4DF8-455B-9AEC-0C84C31106E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {6E375519-4DF8-455B-9AEC-0C84C31106E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E375519-4DF8-455B-9AEC-0C84C31106E9}.Release|Any CPU.Build.0 = Release|Any CPU {6E375519-4DF8-455B-9AEC-0C84C31106E9}.Release|Any CPU.Build.0 = Release|Any CPU
{A5946F7D-E8CE-4ACE-8D79-0F5FF0CB11C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5946F7D-E8CE-4ACE-8D79-0F5FF0CB11C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5946F7D-E8CE-4ACE-8D79-0F5FF0CB11C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5946F7D-E8CE-4ACE-8D79-0F5FF0CB11C0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
-6
View File
@@ -2,14 +2,8 @@
<div class="page"> <div class="page">
<div class="sidebar"> <div class="sidebar">
<NavMenu/> <NavMenu/>
</div> </div>
<main> <main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
<article class="content px-4"> <article class="content px-4">
@Body @Body
</article> </article>
-10
View File
@@ -16,16 +16,6 @@
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
</NavLink>
</div>
@if (groupedNotes == null) @if (groupedNotes == null)
{ {
-19
View File
@@ -1,19 +0,0 @@
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
-60
View File
@@ -1,60 +0,0 @@
@page "/weather"
@inject HttpClient Http
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p>
<em>Loading...</em>
</p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
}
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
-35
View File
@@ -1,35 +0,0 @@
$src = Resolve-Path "$PSScriptRoot\..\..\docs\Notes"
$dst = "$PSScriptRoot\wwwroot\docs\notes"
if (Test-Path $dst) { Remove-Item "$dst\*" -Force -ErrorAction SilentlyContinue }
New-Item -ItemType Directory -Path $dst -Force | Out-Null
$entries = @()
Get-ChildItem -Path $src -Filter "*.md" | ForEach-Object {
$base = $_.BaseName
$slug = $base.ToLowerInvariant()
$slug = $slug -replace "'", ""
$slug = $slug -replace "\.", ""
$slug = $slug -replace "[^a-z0-9 -]", ""
$slug = $slug -replace "\s+", "-"
$slug = $slug -replace "-+", "-"
$slug = $slug.Trim('-')
Copy-Item $_.FullName (Join-Path $dst "$slug.md")
$category = $null
$content = Get-Content $_.FullName -Raw
if ($content -match '(?s)^---\s*\n(.*?)\n---') {
$frontmatter = $Matches[1]
if ($frontmatter -match '(?m)^category:\s*(.+)$') {
$category = $Matches[1].Trim().Trim('"')
}
}
$entry = @{ slug = $slug; title = $base }
if ($category) { $entry.category = $category }
$entries += $entry
}
$indexPath = "$PSScriptRoot\wwwroot\docs\notes-index.json"
$index = @{ notes = $entries } | ConvertTo-Json
Set-Content -Path $indexPath -Value $index -Encoding UTF8
+1 -1
View File
@@ -14,7 +14,7 @@
</ItemGroup> </ItemGroup>
<Target Name="SyncDocsNotes" BeforeTargets="BeforeBuild"> <Target Name="SyncDocsNotes" BeforeTargets="BeforeBuild">
<Exec Command="powershell -NoProfile -ExecutionPolicy Bypass -File &quot;$(MSBuildProjectDirectory)\SyncDocs.ps1&quot;"/> <Exec Command="dotnet run --project &quot;$(MSBuildProjectDirectory)\..\Console\Console.csproj&quot;"/>
</Target> </Target>
</Project> </Project>
+421 -421
View File
@@ -1,422 +1,422 @@
{ {
"notes": [ "notes": [
{ {
"title": "Artificer", "slug": "artificer",
"category": "Role", "title": "Artificer",
"slug": "artificer" "category": "Role"
}, },
{ {
"slug": "awareness", "slug": "awareness",
"title": "Awareness" "title": "Awareness"
}, },
{ {
"title": "Cache Map", "slug": "cache-map",
"category": "Gear", "title": "Cache Map",
"slug": "cache-map" "category": "Gear"
}, },
{ {
"slug": "card-library", "slug": "card-library",
"title": "Card Library" "title": "Card Library"
}, },
{ {
"title": "Concoliator", "slug": "concoliator",
"category": "Role", "title": "Concoliator",
"slug": "concoliator" "category": "Role"
}, },
{ {
"slug": "contents", "slug": "contents",
"title": "Contents" "title": "Contents"
}, },
{ {
"slug": "crisis-markers", "slug": "crisis-markers",
"title": "Crisis Markers" "title": "Crisis Markers"
}, },
{ {
"slug": "crisis-resolution", "slug": "crisis-resolution",
"title": "Crisis Resolution" "title": "Crisis Resolution"
}, },
{ {
"slug": "crisis", "slug": "crisis",
"title": "Crisis" "title": "Crisis"
}, },
{ {
"slug": "dirt-roads", "slug": "dirt-roads",
"title": "Dirt Roads" "title": "Dirt Roads"
}, },
{ {
"title": "Dolewood Canoe", "slug": "dolewood-canoe",
"category": "Gear", "title": "Dolewood Canoe",
"slug": "dolewood-canoe" "category": "Gear"
}, },
{ {
"title": "E.03", "slug": "e03",
"category": "Event", "title": "E.03",
"slug": "e03" "category": "Event"
}, },
{ {
"slug": "ecology", "slug": "ecology",
"title": "Ecology" "title": "Ecology"
}, },
{ {
"slug": "endeavor-tokens", "slug": "endeavor-tokens",
"title": "Endeavor Tokens" "title": "Endeavor Tokens"
}, },
{ {
"slug": "energy-tokens", "slug": "energy-tokens",
"title": "Energy Tokens" "title": "Energy Tokens"
}, },
{ {
"slug": "event-cards", "slug": "event-cards",
"title": "Event Cards" "title": "Event Cards"
}, },
{ {
"slug": "events", "slug": "events",
"title": "Events" "title": "Events"
}, },
{ {
"slug": "explore-phase", "slug": "explore-phase",
"title": "Explore Phase" "title": "Explore Phase"
}, },
{ {
"title": "Explorer", "slug": "explorer",
"category": "Role", "title": "Explorer",
"slug": "explorer" "category": "Role"
}, },
{ {
"title": "Ferinodex", "slug": "ferinodex",
"category": "Gear", "title": "Ferinodex",
"slug": "ferinodex" "category": "Gear"
}, },
{ {
"slug": "flora-meeples", "slug": "flora-meeples",
"title": "Flora Meeples" "title": "Flora Meeples"
}, },
{ {
"title": "Forest 1", "slug": "forest-1",
"category": "Region", "title": "Forest 1",
"slug": "forest-1" "category": "Region"
}, },
{ {
"title": "Forest 2", "slug": "forest-2",
"category": "Region", "title": "Forest 2",
"slug": "forest-2" "category": "Region"
}, },
{ {
"title": "Forest 3", "slug": "forest-3",
"category": "Region", "title": "Forest 3",
"slug": "forest-3" "category": "Region"
}, },
{ {
"title": "Forest 4", "slug": "forest-4",
"category": "Region", "title": "Forest 4",
"slug": "forest-4" "category": "Region"
}, },
{ {
"title": "Forest 5", "slug": "forest-5",
"category": "Region", "title": "Forest 5",
"slug": "forest-5" "category": "Region"
}, },
{ {
"slug": "forest", "slug": "forest",
"title": "Forest" "title": "Forest"
}, },
{ {
"title": "Gauzeblade", "slug": "gauzeblade",
"category": "Gear", "title": "Gauzeblade",
"slug": "gauzeblade" "category": "Gear"
}, },
{ {
"slug": "gear-cards", "slug": "gear-cards",
"title": "Gear Cards" "title": "Gear Cards"
}, },
{ {
"title": "Grass 1", "slug": "grass-1",
"category": "Region", "title": "Grass 1",
"slug": "grass-1" "category": "Region"
}, },
{ {
"title": "Grass 2", "slug": "grass-2",
"category": "Region", "title": "Grass 2",
"slug": "grass-2" "category": "Region"
}, },
{ {
"title": "Grass 3", "slug": "grass-3",
"category": "Region", "title": "Grass 3",
"slug": "grass-3" "category": "Region"
}, },
{ {
"title": "Grass 4", "slug": "grass-4",
"category": "Region", "title": "Grass 4",
"slug": "grass-4" "category": "Region"
}, },
{ {
"title": "Grass 5", "slug": "grass-5",
"category": "Region", "title": "Grass 5",
"slug": "grass-5" "category": "Region"
}, },
{ {
"slug": "grasslands", "slug": "grasslands",
"title": "Grasslands" "title": "Grasslands"
}, },
{ {
"title": "Guide", "slug": "guide",
"category": "Role", "title": "Guide",
"slug": "guide" "category": "Role"
}, },
{ {
"title": "Hidden Trail Map", "slug": "hidden-trail-map",
"category": "Gear", "title": "Hidden Trail Map",
"slug": "hidden-trail-map" "category": "Gear"
}, },
{ {
"slug": "injury-cards", "slug": "injury-cards",
"title": "Injury Cards" "title": "Injury Cards"
}, },
{ {
"slug": "lake", "slug": "lake",
"title": "Lake" "title": "Lake"
}, },
{ {
"slug": "losing-the-game", "slug": "losing-the-game",
"title": "Losing the Game" "title": "Losing the Game"
}, },
{ {
"slug": "market", "slug": "market",
"title": "Market" "title": "Market"
}, },
{ {
"title": "Mountain 1", "slug": "mountain-1",
"category": "Region", "title": "Mountain 1",
"slug": "mountain-1" "category": "Region"
}, },
{ {
"title": "Mountain 2", "slug": "mountain-2",
"category": "Region", "title": "Mountain 2",
"slug": "mountain-2" "category": "Region"
}, },
{ {
"title": "Mountain 3", "slug": "mountain-3",
"category": "Region", "title": "Mountain 3",
"slug": "mountain-3" "category": "Region"
}, },
{ {
"title": "Mountain 4", "slug": "mountain-4",
"category": "Region", "title": "Mountain 4",
"slug": "mountain-4" "category": "Region"
}, },
{ {
"title": "Mountain 5", "slug": "mountain-5",
"category": "Region", "title": "Mountain 5",
"slug": "mountain-5" "category": "Region"
}, },
{ {
"slug": "mountain", "slug": "mountain",
"title": "Mountain" "title": "Mountain"
}, },
{ {
"title": "Paratrepsis Whistle", "slug": "paratrepsis-whistle",
"category": "Gear", "title": "Paratrepsis Whistle",
"slug": "paratrepsis-whistle" "category": "Gear"
}, },
{ {
"slug": "paved-roads", "slug": "paved-roads",
"title": "Paved Roads" "title": "Paved Roads"
}, },
{ {
"title": "Perfect Day 1", "slug": "perfect-day-1",
"category": "Event", "title": "Perfect Day 1",
"slug": "perfect-day-1" "category": "Event"
}, },
{ {
"title": "Phonoscopic Headset", "slug": "phonoscopic-headset",
"category": "Gear", "title": "Phonoscopic Headset",
"slug": "phonoscopic-headset" "category": "Gear"
}, },
{ {
"slug": "player-boards", "slug": "player-boards",
"title": "Player Boards" "title": "Player Boards"
}, },
{ {
"slug": "player-meeples", "slug": "player-meeples",
"title": "Player Meeples" "title": "Player Meeples"
}, },
{ {
"slug": "predator-meeples", "slug": "predator-meeples",
"title": "Predator Meeples" "title": "Predator Meeples"
}, },
{ {
"slug": "prepare-phase", "slug": "prepare-phase",
"title": "Prepare Phase" "title": "Prepare Phase"
}, },
{ {
"slug": "press-on", "slug": "press-on",
"title": "Press On" "title": "Press On"
}, },
{ {
"slug": "prey-meeples", "slug": "prey-meeples",
"title": "Prey Meeples" "title": "Prey Meeples"
}, },
{ {
"slug": "progress", "slug": "progress",
"title": "Progress" "title": "Progress"
}, },
{ {
"slug": "ranger-badges", "slug": "ranger-badges",
"title": "Ranger Badges" "title": "Ranger Badges"
}, },
{ {
"slug": "ranger-meeples", "slug": "ranger-meeples",
"title": "Ranger Meeples" "title": "Ranger Meeples"
}, },
{ {
"slug": "research-station", "slug": "research-station",
"title": "Research Station" "title": "Research Station"
}, },
{ {
"slug": "rest", "slug": "rest",
"title": "Rest" "title": "Rest"
}, },
{ {
"slug": "role-cards", "slug": "role-cards",
"title": "Role Cards" "title": "Role Cards"
}, },
{ {
"slug": "round", "slug": "round",
"title": "Round" "title": "Round"
}, },
{ {
"title": "Ruins Map", "slug": "ruins-map",
"category": "Gear", "title": "Ruins Map",
"slug": "ruins-map" "category": "Gear"
}, },
{ {
"slug": "scout", "slug": "scout",
"title": "Scout" "title": "Scout"
}, },
{ {
"title": "Shaper", "slug": "shaper",
"category": "Role", "title": "Shaper",
"slug": "shaper" "category": "Role"
}, },
{ {
"title": "Shepard", "slug": "shepard",
"category": "Role", "title": "Shepard",
"slug": "shepard" "category": "Role"
}, },
{ {
"slug": "story", "slug": "story",
"title": "Story" "title": "Story"
}, },
{ {
"slug": "supply", "slug": "supply",
"title": "Supply" "title": "Supply"
}, },
{ {
"title": "Terrain 2", "slug": "terrain-2",
"category": "Terrain", "title": "Terrain 2",
"slug": "terrain-2" "category": "Terrain"
}, },
{ {
"title": "Terrain 3", "slug": "terrain-3",
"category": "Terrain", "title": "Terrain 3",
"slug": "terrain-3" "category": "Terrain"
}, },
{ {
"slug": "terrain-cards", "slug": "terrain-cards",
"title": "Terrain Cards" "title": "Terrain Cards"
}, },
{ {
"title": "Terrain", "slug": "terrain",
"category": "Terrain", "title": "Terrain",
"slug": "terrain" "category": "Terrain"
}, },
{ {
"title": "Totem of the Irix", "slug": "totem-of-the-irix",
"category": "Gear", "title": "Totem of the Irix",
"slug": "totem-of-the-irix" "category": "Gear"
}, },
{ {
"slug": "trade", "slug": "trade",
"title": "Trade" "title": "Trade"
}, },
{ {
"title": "Trader", "slug": "trader",
"category": "Role", "title": "Trader",
"slug": "trader" "category": "Role"
}, },
{ {
"slug": "trail-markers", "slug": "trail-markers",
"title": "Trail Markers" "title": "Trail Markers"
}, },
{ {
"slug": "travel-phase", "slug": "travel-phase",
"title": "Travel Phase" "title": "Travel Phase"
}, },
{ {
"slug": "traverse", "slug": "traverse",
"title": "Traverse" "title": "Traverse"
}, },
{ {
"slug": "unmaintained-roads", "slug": "unmaintained-roads",
"title": "Unmaintained Roads" "title": "Unmaintained Roads"
}, },
{ {
"slug": "valley", "slug": "valley",
"title": "Valley" "title": "Valley"
}, },
{ {
"slug": "victory-condition", "slug": "victory-condition",
"title": "Victory Condition" "title": "Victory Condition"
}, },
{ {
"title": "Wasteland 1", "slug": "wasteland-1",
"category": "Region", "title": "Wasteland 1",
"slug": "wasteland-1" "category": "Region"
}, },
{ {
"slug": "wasteland", "slug": "wasteland",
"title": "Wasteland" "title": "Wasteland"
}, },
{ {
"title": "Water 1", "slug": "water-1",
"category": "Region", "title": "Water 1",
"slug": "water-1" "category": "Region"
}, },
{ {
"title": "Water 2", "slug": "water-2",
"category": "Region", "title": "Water 2",
"slug": "water-2" "category": "Region"
}, },
{ {
"title": "Water 3", "slug": "water-3",
"category": "Region", "title": "Water 3",
"slug": "water-3" "category": "Region"
}, },
{ {
"title": "Water 4", "slug": "water-4",
"category": "Region", "title": "Water 4",
"slug": "water-4" "category": "Region"
}, },
{ {
"title": "Water 5", "slug": "water-5",
"category": "Region", "title": "Water 5",
"slug": "water-5" "category": "Region"
}, },
{ {
"slug": "weather", "slug": "weather",
"title": "Weather" "title": "Weather"
}, },
{ {
"slug": "white-sky", "slug": "white-sky",
"title": "White Sky" "title": "White Sky"
}, },
{ {
"slug": "xp-cubes", "slug": "xp-cubes",
"title": "XP Cubes" "title": "XP Cubes"
}, },
{ {
"slug": "xp", "slug": "xp",
"title": "XP" "title": "XP"
} }
] ]
} }