mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
feat(config): add optional frontmatter schemas and Guides tab
This commit is contained in:
1 parent
0473a3651f
commit
b035d1ffa0
1 file changed
+57
-3
@@ -1,4 +1,5 @@
|
|||||||
import { defineConfig } from "blume";
|
import { defineConfig } from "blume";
|
||||||
|
import type { StandardSchema } from "blume/core/standard-schema.ts";
|
||||||
import { custom, filesystem } from "blume/sources";
|
import { custom, filesystem } from "blume/sources";
|
||||||
import { githubReleasesSource } from "blume/sources/github-releases.ts";
|
import { githubReleasesSource } from "blume/sources/github-releases.ts";
|
||||||
import redirects from "./redirects";
|
import redirects from "./redirects";
|
||||||
@@ -24,8 +25,12 @@ const releasesDatedByTag: typeof fetch = async (input, init) => {
|
|||||||
const releases: unknown = await res.json();
|
const releases: unknown = await res.json();
|
||||||
if (Array.isArray(releases)) {
|
if (Array.isArray(releases)) {
|
||||||
for (const release of releases) {
|
for (const release of releases) {
|
||||||
const m = typeof release?.tag_name === "string" ? release.tag_name.match(TIMEVER) : null;
|
const m =
|
||||||
if (m) release.published_at = `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}Z`;
|
typeof release?.tag_name === "string"
|
||||||
|
? release.tag_name.match(TIMEVER)
|
||||||
|
: null;
|
||||||
|
if (m)
|
||||||
|
release.published_at = `${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:${m[6]}Z`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Blume reads only `ok` and the JSON body, so the original headers (whose
|
// Blume reads only `ok` and the JSON body, so the original headers (whose
|
||||||
@@ -61,6 +66,49 @@ const plexMono = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom frontmatter, rendered as the badge row by
|
||||||
|
* components/ProblemBadges.astro. Problem pages: `topics:` is LeetCode's topic
|
||||||
|
* tags (written by apps/cli/sync.ts), `video:` the NeetCode walkthrough's
|
||||||
|
* YouTube id (apps/cli/videos.ts). Guide pages (content/guides/, created by
|
||||||
|
* sync): `list:` is the tag's LeetCode problem list. Blume rejects undeclared
|
||||||
|
* keys and takes any Standard Schema; these are hand-rolled so the docs
|
||||||
|
* workspace needs no zod. All optional — every other page carries none.
|
||||||
|
*/
|
||||||
|
const optional = <T>(
|
||||||
|
message: string,
|
||||||
|
valid: (value: unknown) => value is T,
|
||||||
|
): StandardSchema<unknown, T | undefined> => ({
|
||||||
|
"~standard": {
|
||||||
|
version: 1,
|
||||||
|
vendor: "prdlk",
|
||||||
|
validate: (value) =>
|
||||||
|
value === undefined || valid(value)
|
||||||
|
? { value }
|
||||||
|
: { issues: [{ message }] },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const topicsSchema = optional(
|
||||||
|
"expected a list of { name, slug } LeetCode topic tags",
|
||||||
|
(value): value is { name: string; slug: string }[] =>
|
||||||
|
Array.isArray(value) &&
|
||||||
|
value.every(
|
||||||
|
(t) => typeof t?.name === "string" && typeof t?.slug === "string",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const videoSchema = optional(
|
||||||
|
"expected an 11-character YouTube video id",
|
||||||
|
(value): value is string =>
|
||||||
|
typeof value === "string" && /^[\w-]{11}$/.test(value),
|
||||||
|
);
|
||||||
|
const listSchema = optional(
|
||||||
|
"expected a https://leetcode.com/problem-list/<slug>/ URL",
|
||||||
|
(value): value is string =>
|
||||||
|
typeof value === "string" &&
|
||||||
|
/^https:\/\/leetcode\.com\/problem-list\/[\w-]+\/$/.test(value),
|
||||||
|
);
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
title: "prdlk",
|
title: "prdlk",
|
||||||
description: "Documentation for my LeetCode solutions",
|
description: "Documentation for my LeetCode solutions",
|
||||||
@@ -74,6 +122,9 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
lastModified: "git",
|
lastModified: "git",
|
||||||
redirects,
|
redirects,
|
||||||
|
frontmatter: {
|
||||||
|
extend: { topics: topicsSchema, video: videoSchema, list: listSchema },
|
||||||
|
},
|
||||||
content: {
|
content: {
|
||||||
sources: [
|
sources: [
|
||||||
filesystem({ root: "content" }),
|
filesystem({ root: "content" }),
|
||||||
@@ -104,6 +155,9 @@ export default defineConfig({
|
|||||||
sidebar: {
|
sidebar: {
|
||||||
display: "flat", // "flat" | "group" | "page"
|
display: "flat", // "flat" | "group" | "page"
|
||||||
},
|
},
|
||||||
tabs: [{ label: "Changelog", path: "/changelog" }],
|
tabs: [
|
||||||
|
{ label: "Guides", path: "/guides" },
|
||||||
|
{ label: "Changelog", path: "/changelog" },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user