diff --git a/.dockerignore b/.dockerignore
index f90ce74..d755b6c 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -20,4 +20,5 @@
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
-README.md
\ No newline at end of file
+README.md
+static-pages/*
diff --git a/Foxnouns.Backend/Controllers/MetaController.cs b/Foxnouns.Backend/Controllers/MetaController.cs
index 8552164..e22fbc1 100644
--- a/Foxnouns.Backend/Controllers/MetaController.cs
+++ b/Foxnouns.Backend/Controllers/MetaController.cs
@@ -12,6 +12,7 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+using System.Text.RegularExpressions;
using Foxnouns.Backend.Dto;
using Foxnouns.Backend.Utils;
using Microsoft.AspNetCore.Mvc;
@@ -19,7 +20,7 @@ using Microsoft.AspNetCore.Mvc;
namespace Foxnouns.Backend.Controllers;
[Route("/api/v2/meta")]
-public class MetaController : ApiControllerBase
+public partial class MetaController : ApiControllerBase
{
private const string Repository = "https://codeberg.org/pronounscc/pronouns.cc";
@@ -48,7 +49,23 @@ public class MetaController : ApiControllerBase
)
);
+ [HttpGet("page/{page}")]
+ public async Task GetStaticPageAsync(string page, CancellationToken ct = default)
+ {
+ if (!PageRegex().IsMatch(page))
+ {
+ throw new ApiError.BadRequest("Invalid page name");
+ }
+
+ string path = Path.Join(Directory.GetCurrentDirectory(), "static-pages", $"{page}.md");
+ string text = await System.IO.File.ReadAllTextAsync(path, ct);
+ return Ok(text);
+ }
+
[HttpGet("/api/v2/coffee")]
public IActionResult BrewCoffee() =>
Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot);
+
+ [GeneratedRegex(@"^[a-z\-_]+$")]
+ private static partial Regex PageRegex();
}
diff --git a/Foxnouns.Backend/static-pages/.gitignore b/Foxnouns.Backend/static-pages/.gitignore
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/Foxnouns.Backend/static-pages/.gitignore
@@ -0,0 +1 @@
+*
diff --git a/Foxnouns.Frontend/src/lib/markdown.ts b/Foxnouns.Frontend/src/lib/markdown.ts
index 94a1a05..9c4ff35 100644
--- a/Foxnouns.Frontend/src/lib/markdown.ts
+++ b/Foxnouns.Frontend/src/lib/markdown.ts
@@ -7,11 +7,7 @@ const md = new MarkdownIt({
linkify: true,
}).disable(["heading", "lheading", "link", "table", "blockquote"]);
-const unsafeMd = new MarkdownIt({
- html: false,
- breaks: true,
- linkify: true,
-});
+const unsafeMd = new MarkdownIt();
export const renderMarkdown = (src: string | null) => (src ? sanitize(md.render(src)) : null);
diff --git a/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts b/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts
new file mode 100644
index 0000000..1d9e8fc
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/page/[page]/+page.server.ts
@@ -0,0 +1,14 @@
+import { baseRequest } from "$api";
+import ApiError from "$api/error";
+
+export const load = async ({ fetch, params }) => {
+ const resp = await baseRequest("GET", `/meta/page/${params.page}`, { fetch });
+ if (resp.status < 200 || resp.status > 299) {
+ const err = await resp.json();
+ if ("code" in err) throw new ApiError(err);
+ else throw new ApiError();
+ }
+
+ const pageText = await resp.text();
+ return { page: params.page, text: pageText };
+};
diff --git a/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte b/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte
new file mode 100644
index 0000000..a156d0a
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/page/[page]/+page.svelte
@@ -0,0 +1,22 @@
+
+
+
+ {title} • pronouns.cc
+
+
+
+ {@html md}
+