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>
+85 -85
View File
@@ -1,27 +1,27 @@
{ {
"notes": [ "notes": [
{ {
"slug": "artificer",
"title": "Artificer", "title": "Artificer",
"category": "Role", "category": "Role"
"slug": "artificer"
}, },
{ {
"slug": "awareness", "slug": "awareness",
"title": "Awareness" "title": "Awareness"
}, },
{ {
"slug": "cache-map",
"title": "Cache Map", "title": "Cache Map",
"category": "Gear", "category": "Gear"
"slug": "cache-map"
}, },
{ {
"slug": "card-library", "slug": "card-library",
"title": "Card Library" "title": "Card Library"
}, },
{ {
"slug": "concoliator",
"title": "Concoliator", "title": "Concoliator",
"category": "Role", "category": "Role"
"slug": "concoliator"
}, },
{ {
"slug": "contents", "slug": "contents",
@@ -44,14 +44,14 @@
"title": "Dirt Roads" "title": "Dirt Roads"
}, },
{ {
"slug": "dolewood-canoe",
"title": "Dolewood Canoe", "title": "Dolewood Canoe",
"category": "Gear", "category": "Gear"
"slug": "dolewood-canoe"
}, },
{ {
"slug": "e03",
"title": "E.03", "title": "E.03",
"category": "Event", "category": "Event"
"slug": "e03"
}, },
{ {
"slug": "ecology", "slug": "ecology",
@@ -78,95 +78,95 @@
"title": "Explore Phase" "title": "Explore Phase"
}, },
{ {
"slug": "explorer",
"title": "Explorer", "title": "Explorer",
"category": "Role", "category": "Role"
"slug": "explorer"
}, },
{ {
"slug": "ferinodex",
"title": "Ferinodex", "title": "Ferinodex",
"category": "Gear", "category": "Gear"
"slug": "ferinodex"
}, },
{ {
"slug": "flora-meeples", "slug": "flora-meeples",
"title": "Flora Meeples" "title": "Flora Meeples"
}, },
{ {
"slug": "forest-1",
"title": "Forest 1", "title": "Forest 1",
"category": "Region", "category": "Region"
"slug": "forest-1"
}, },
{ {
"slug": "forest-2",
"title": "Forest 2", "title": "Forest 2",
"category": "Region", "category": "Region"
"slug": "forest-2"
}, },
{ {
"slug": "forest-3",
"title": "Forest 3", "title": "Forest 3",
"category": "Region", "category": "Region"
"slug": "forest-3"
}, },
{ {
"slug": "forest-4",
"title": "Forest 4", "title": "Forest 4",
"category": "Region", "category": "Region"
"slug": "forest-4"
}, },
{ {
"slug": "forest-5",
"title": "Forest 5", "title": "Forest 5",
"category": "Region", "category": "Region"
"slug": "forest-5"
}, },
{ {
"slug": "forest", "slug": "forest",
"title": "Forest" "title": "Forest"
}, },
{ {
"slug": "gauzeblade",
"title": "Gauzeblade", "title": "Gauzeblade",
"category": "Gear", "category": "Gear"
"slug": "gauzeblade"
}, },
{ {
"slug": "gear-cards", "slug": "gear-cards",
"title": "Gear Cards" "title": "Gear Cards"
}, },
{ {
"slug": "grass-1",
"title": "Grass 1", "title": "Grass 1",
"category": "Region", "category": "Region"
"slug": "grass-1"
}, },
{ {
"slug": "grass-2",
"title": "Grass 2", "title": "Grass 2",
"category": "Region", "category": "Region"
"slug": "grass-2"
}, },
{ {
"slug": "grass-3",
"title": "Grass 3", "title": "Grass 3",
"category": "Region", "category": "Region"
"slug": "grass-3"
}, },
{ {
"slug": "grass-4",
"title": "Grass 4", "title": "Grass 4",
"category": "Region", "category": "Region"
"slug": "grass-4"
}, },
{ {
"slug": "grass-5",
"title": "Grass 5", "title": "Grass 5",
"category": "Region", "category": "Region"
"slug": "grass-5"
}, },
{ {
"slug": "grasslands", "slug": "grasslands",
"title": "Grasslands" "title": "Grasslands"
}, },
{ {
"slug": "guide",
"title": "Guide", "title": "Guide",
"category": "Role", "category": "Role"
"slug": "guide"
}, },
{ {
"slug": "hidden-trail-map",
"title": "Hidden Trail Map", "title": "Hidden Trail Map",
"category": "Gear", "category": "Gear"
"slug": "hidden-trail-map"
}, },
{ {
"slug": "injury-cards", "slug": "injury-cards",
@@ -185,52 +185,52 @@
"title": "Market" "title": "Market"
}, },
{ {
"slug": "mountain-1",
"title": "Mountain 1", "title": "Mountain 1",
"category": "Region", "category": "Region"
"slug": "mountain-1"
}, },
{ {
"slug": "mountain-2",
"title": "Mountain 2", "title": "Mountain 2",
"category": "Region", "category": "Region"
"slug": "mountain-2"
}, },
{ {
"slug": "mountain-3",
"title": "Mountain 3", "title": "Mountain 3",
"category": "Region", "category": "Region"
"slug": "mountain-3"
}, },
{ {
"slug": "mountain-4",
"title": "Mountain 4", "title": "Mountain 4",
"category": "Region", "category": "Region"
"slug": "mountain-4"
}, },
{ {
"slug": "mountain-5",
"title": "Mountain 5", "title": "Mountain 5",
"category": "Region", "category": "Region"
"slug": "mountain-5"
}, },
{ {
"slug": "mountain", "slug": "mountain",
"title": "Mountain" "title": "Mountain"
}, },
{ {
"slug": "paratrepsis-whistle",
"title": "Paratrepsis Whistle", "title": "Paratrepsis Whistle",
"category": "Gear", "category": "Gear"
"slug": "paratrepsis-whistle"
}, },
{ {
"slug": "paved-roads", "slug": "paved-roads",
"title": "Paved Roads" "title": "Paved Roads"
}, },
{ {
"slug": "perfect-day-1",
"title": "Perfect Day 1", "title": "Perfect Day 1",
"category": "Event", "category": "Event"
"slug": "perfect-day-1"
}, },
{ {
"slug": "phonoscopic-headset",
"title": "Phonoscopic Headset", "title": "Phonoscopic Headset",
"category": "Gear", "category": "Gear"
"slug": "phonoscopic-headset"
}, },
{ {
"slug": "player-boards", "slug": "player-boards",
@@ -285,23 +285,23 @@
"title": "Round" "title": "Round"
}, },
{ {
"slug": "ruins-map",
"title": "Ruins Map", "title": "Ruins Map",
"category": "Gear", "category": "Gear"
"slug": "ruins-map"
}, },
{ {
"slug": "scout", "slug": "scout",
"title": "Scout" "title": "Scout"
}, },
{ {
"slug": "shaper",
"title": "Shaper", "title": "Shaper",
"category": "Role", "category": "Role"
"slug": "shaper"
}, },
{ {
"slug": "shepard",
"title": "Shepard", "title": "Shepard",
"category": "Role", "category": "Role"
"slug": "shepard"
}, },
{ {
"slug": "story", "slug": "story",
@@ -312,37 +312,37 @@
"title": "Supply" "title": "Supply"
}, },
{ {
"slug": "terrain-2",
"title": "Terrain 2", "title": "Terrain 2",
"category": "Terrain", "category": "Terrain"
"slug": "terrain-2"
}, },
{ {
"slug": "terrain-3",
"title": "Terrain 3", "title": "Terrain 3",
"category": "Terrain", "category": "Terrain"
"slug": "terrain-3"
}, },
{ {
"slug": "terrain-cards", "slug": "terrain-cards",
"title": "Terrain Cards" "title": "Terrain Cards"
}, },
{ {
"slug": "terrain",
"title": "Terrain", "title": "Terrain",
"category": "Terrain", "category": "Terrain"
"slug": "terrain"
}, },
{ {
"slug": "totem-of-the-irix",
"title": "Totem of the Irix", "title": "Totem of the Irix",
"category": "Gear", "category": "Gear"
"slug": "totem-of-the-irix"
}, },
{ {
"slug": "trade", "slug": "trade",
"title": "Trade" "title": "Trade"
}, },
{ {
"slug": "trader",
"title": "Trader", "title": "Trader",
"category": "Role", "category": "Role"
"slug": "trader"
}, },
{ {
"slug": "trail-markers", "slug": "trail-markers",
@@ -369,38 +369,38 @@
"title": "Victory Condition" "title": "Victory Condition"
}, },
{ {
"slug": "wasteland-1",
"title": "Wasteland 1", "title": "Wasteland 1",
"category": "Region", "category": "Region"
"slug": "wasteland-1"
}, },
{ {
"slug": "wasteland", "slug": "wasteland",
"title": "Wasteland" "title": "Wasteland"
}, },
{ {
"slug": "water-1",
"title": "Water 1", "title": "Water 1",
"category": "Region", "category": "Region"
"slug": "water-1"
}, },
{ {
"slug": "water-2",
"title": "Water 2", "title": "Water 2",
"category": "Region", "category": "Region"
"slug": "water-2"
}, },
{ {
"slug": "water-3",
"title": "Water 3", "title": "Water 3",
"category": "Region", "category": "Region"
"slug": "water-3"
}, },
{ {
"slug": "water-4",
"title": "Water 4", "title": "Water 4",
"category": "Region", "category": "Region"
"slug": "water-4"
}, },
{ {
"slug": "water-5",
"title": "Water 5", "title": "Water 5",
"category": "Region", "category": "Region"
"slug": "water-5"
}, },
{ {
"slug": "weather", "slug": "weather",