livemark 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/actions/config/define.d.ts +67 -3
- package/build/actions/config/define.js +3 -3
- package/build/actions/config/load.js +23 -2
- package/build/components/Layout.js +9 -7
- package/build/components/SidebarSections.js +7 -7
- package/build/content/article.js +3 -3
- package/build/helpers/resolve-base.d.ts +6 -0
- package/build/helpers/resolve-base.js +13 -0
- package/build/helpers/resolve-base.unit.d.ts +1 -0
- package/build/helpers/resolve-base.unit.js +49 -0
- package/build/helpers/section.d.ts +10 -2
- package/build/helpers/section.js +19 -3
- package/build/helpers/section.unit.js +32 -2
- package/build/models/config.d.ts +29 -11
- package/build/models/config.js +9 -11
- package/build/models/section.d.ts +7 -5
- package/build/models/section.js +4 -4
- package/package.json +1 -1
- package/source/actions/config/define.ts +4 -6
- package/source/actions/config/load.ts +26 -6
- package/source/components/Layout.tsx +11 -11
- package/source/components/SidebarSections.tsx +8 -5
- package/source/content/article.ts +2 -2
- package/source/helpers/resolve-base.ts +11 -0
- package/source/helpers/resolve-base.unit.ts +61 -0
- package/source/helpers/section.ts +18 -3
- package/source/helpers/section.unit.ts +43 -1
- package/source/models/config.ts +32 -14
- package/source/models/section.ts +7 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vite-plus/test";
|
|
2
|
-
import { matchSection, partitionBySection } from "./section.js";
|
|
2
|
+
import { customSectionActive, matchSection, partitionBySection, } from "./section.js";
|
|
3
3
|
describe("matchSection", () => {
|
|
4
4
|
const sections = [
|
|
5
5
|
{ title: "Docs", prefix: "/" },
|
|
@@ -59,4 +59,34 @@ describe("partitionBySection", () => {
|
|
|
59
59
|
]);
|
|
60
60
|
});
|
|
61
61
|
});
|
|
62
|
-
|
|
62
|
+
describe("customSectionActive", () => {
|
|
63
|
+
it("should not match an absolute http url", () => {
|
|
64
|
+
expect(customSectionActive("https://x.com/y", "/y/")).toBe(false);
|
|
65
|
+
expect(customSectionActive("http://x.com/y", "/y/")).toBe(false);
|
|
66
|
+
});
|
|
67
|
+
it("should not match a protocol-relative url", () => {
|
|
68
|
+
expect(customSectionActive("//cdn.x.com/y", "/y/")).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
it("should not match a hash url", () => {
|
|
71
|
+
expect(customSectionActive("#section", "/section/")).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
it("should match the exact path", () => {
|
|
74
|
+
expect(customSectionActive("/about", "/about/")).toBe(true);
|
|
75
|
+
expect(customSectionActive("/about/", "/about/")).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
it("should match a descendant path", () => {
|
|
78
|
+
expect(customSectionActive("/about", "/about/team/")).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
it("should not match a sibling path with shared prefix", () => {
|
|
81
|
+
expect(customSectionActive("/about", "/aboutus/")).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
it("should match exact root only", () => {
|
|
84
|
+
expect(customSectionActive("/", "/")).toBe(true);
|
|
85
|
+
expect(customSectionActive("/", "/about/")).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it("should ignore query and hash on the url", () => {
|
|
88
|
+
expect(customSectionActive("/about?x=1", "/about/")).toBe(true);
|
|
89
|
+
expect(customSectionActive("/about#top", "/about/team/")).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdGlvbi51bml0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc291cmNlL2hlbHBlcnMvc2VjdGlvbi51bml0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBQ3JELE9BQU8sRUFDTCxtQkFBbUIsRUFDbkIsWUFBWSxFQUNaLGtCQUFrQixHQUNuQixNQUFNLGNBQWMsQ0FBQTtBQUVyQixRQUFRLENBQUMsY0FBYyxFQUFFLEdBQUcsRUFBRTtJQUM1QixNQUFNLFFBQVEsR0FBRztRQUNmLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFO1FBQzlCLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFO1FBQ2pDLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFO0tBQzVDLENBQUE7SUFFRCxFQUFFLENBQUMsdUNBQXVDLEVBQUUsR0FBRyxFQUFFO1FBQy9DLE1BQU0sQ0FBQyxZQUFZLENBQUMsa0JBQWtCLEVBQUUsUUFBUSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQzVFLENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLDBEQUEwRCxFQUFFLEdBQUcsRUFBRTtRQUNsRSxNQUFNLENBQUMsWUFBWSxDQUFDLGFBQWEsRUFBRSxRQUFRLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDbEUsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsdUNBQXVDLEVBQUUsR0FBRyxFQUFFO1FBQy9DLE1BQU0sQ0FBQyxZQUFZLENBQUMsbUJBQW1CLEVBQUUsUUFBUSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FB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QUFFLENBQUMsb0RBQW9ELEVBQUUsR0FBRyxFQUFFO1FBQzVELE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDaEUsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsOEJBQThCLEVBQUUsR0FBRyxFQUFFO1FBQ3RDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDaEQsTUFBTSxDQUFDLG1CQUFtQixDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUN6RCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyx5Q0FBeUMsRUFBRSxHQUFHLEVBQUU7UUFDakQsTUFBTSxDQUFDLG1CQUFtQixDQUFDLFlBQVksRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUMvRCxNQUFNLENBQUMsbUJBQW1CLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO0lBQ3RFLENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFDLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBkZXNjcmliZSwgZXhwZWN0LCBpdCB9IGZyb20gXCJ2aXRlLXBsdXMvdGVzdFwiXG5pbXBvcnQge1xuICBjdXN0b21TZWN0aW9uQWN0aXZlLFxuICBtYXRjaFNlY3Rpb24sXG4gIHBhcnRpdGlvbkJ5U2VjdGlvbixcbn0gZnJvbSBcIi4vc2VjdGlvbi50c1wiXG5cbmRlc2NyaWJlKFwibWF0Y2hTZWN0aW9uXCIsICgpID0+IHtcbiAgY29uc3Qgc2VjdGlvbnMgPSBbXG4gICAgeyB0aXRsZTogXCJEb2NzXCIsIHByZWZpeDogXCIvXCIgfSxcbiAgICB7IHRpdGxlOiBcIkFQSVwiLCBwcmVmaXg6IFwiL2FwaS9cIiB9LFxuICAgIHsgdGl0bGU6IFwiQVBJIEF1dGhcIiwgcHJlZml4OiBcIi9hcGkvYXV0aC9cIiB9LFxuICBdXG5cbiAgaXQoXCJzaG91bGQgbWF0Y2ggdGhlIG1vc3Qgc3BlY2lmaWMgcHJlZml4XCIsICgpID0+IHtcbiAgICBleHBlY3QobWF0Y2hTZWN0aW9uKFwiL2FwaS9hdXRoL2xvZ2luL1wiLCBzZWN0aW9ucyk/LnRpdGxlKS50b0JlKFwiQVBJIEF1dGhcIilcbiAgfSlcblxuICBpdChcInNob3VsZCBtYXRjaCBhIGxlc3Mgc3BlY2lmaWMgcHJlZml4IHdoZW4gbm8gZGVlcGVyIG1hdGNoXCIsICgpID0+IHtcbiAgICBleHBlY3QobWF0Y2hTZWN0aW9uKFwiL2FwaS91c2Vycy9cIiwgc2VjdGlvbnMpPy50aXRsZSkudG9CZShcIkFQSVwiKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIG1hdGNoIHJvb3Qgc2VjdGlvbiBhcyBmYWxsYmFja1wiLCAoKSA9PiB7XG4gICAgZXhwZWN0KG1hdGNoU2VjdGlvbihcIi9nZXR0aW5nLXN0YXJ0ZWQvXCIsIHNlY3Rpb25zKT8udGl0bGUpLnRvQmUoXCJEb2NzXCIpXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgcmV0dXJuIHVuZGVmaW5lZCB3aGVuIG5vIHNlY3Rpb24gbWF0Y2hlc1wiLCAoKSA9PiB7XG4gICAgY29uc3QgbmFycm93ID0gW3sgdGl0bGU6IFwiQVBJXCIsIHByZWZpeDogXCIvYXBpL1wiIH1dXG4gICAgZXhwZWN0KG1hdGNoU2VjdGlvbihcIi9nZXR0aW5nLXN0YXJ0ZWQvXCIsIG5hcnJvdykpLnRvQmVVbmRlZmluZWQoKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIG1hdGNoIGEgc2luZ2xlIHJvb3Qgc2VjdGlvbiBmb3IgYWxsIGFydGljbGVzXCIsICgpID0+IHtcbiAgICBjb25zdCByb290ID0gW3sgdGl0bGU6IFwiRG9jc1wiLCBwcmVmaXg6IFwiL1wiIH1dXG4gICAgZXhwZWN0KG1hdGNoU2VjdGlvbihcIi9hbnl0aGluZy9kZWVwL3BhdGgvXCIsIHJvb3QpPy50aXRsZSkudG9CZShcIkRvY3NcIilcbiAgfSlcbn0pXG5cbmRlc2NyaWJlKFwicGFydGl0aW9uQnlTZWN0aW9uXCIsICgpID0+IHtcbiAgY29uc3Qgc2VjdGlvbnMgPSBbXG4gICAgeyB0aXRsZTogXCJEb2NzXCIsIHByZWZpeDogXCIvXCIgfSxcbiAgICB7IHRpdGxlOiBcIkFQSVwiLCBwcmVmaXg6IFwiL2FwaS9cIiB9LFxuICBdXG5cbiAgY29uc3QgYXJ0aWNsZXMgPSBbXG4gICAgeyBwYXRoOiBcIi9nZXR0aW5nLXN0YXJ0ZWQvXCIgfSxcbiAgICB7IHBhdGg6IFwiL2d1aWRlL1wiIH0sXG4gICAgeyBwYXRoOiBcIi9hcGkvdXNlcnMvXCIgfSxcbiAgICB7IHBhdGg6IFwiL2FwaS9hdXRoL1wiIH0sXG4gIF1cblxuICBpdChcInNob3VsZCBzcGxpdCBhcnRpY2xlcyBpbnRvIHNlY3Rpb24gYnVja2V0c1wiLCAoKSA9PiB7XG4gICAgY29uc3QgcmVzdWx0ID0gcGFydGl0aW9uQnlTZWN0aW9uKGFydGljbGVzLCBzZWN0aW9ucylcbiAgICBleHBlY3QocmVzdWx0LmdldChcIi9cIik/Lm1hcChhID0+IGEucGF0aCkpLnRvRXF1YWwoW1xuICAgICAgXCIvZ2V0dGluZy1zdGFydGVkL1wiLFxuICAgICAgXCIvZ3VpZGUvXCIsXG4gICAgXSlcbiAgICBleHBlY3QocmVzdWx0LmdldChcIi9hcGkvXCIpPy5tYXAoYSA9PiBhLnBhdGgpKS50b0VxdWFsKFtcbiAgICAgIFwiL2FwaS91c2Vycy9cIixcbiAgICAgIFwiL2FwaS9hdXRoL1wiLFxuICAgIF0pXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgcHV0IHVubWF0Y2hlZCBhcnRpY2xlcyBpbiBfX2RlZmF1bHRfXyBidWNrZXRcIiwgKCkgPT4ge1xuICAgIGNvbnN0IG5hcnJvdyA9IFt7IHRpdGxlOiBcIkFQSVwiLCBwcmVmaXg6IFwiL2FwaS9cIiB9XVxuICAgIGNvbnN0IHJlc3VsdCA9IHBhcnRpdGlvbkJ5U2VjdGlvbihhcnRpY2xlcywgbmFycm93KVxuICAgIGV4cGVjdChyZXN1bHQuZ2V0KFwiX19kZWZhdWx0X19cIik/Lm1hcChhID0+IGEucGF0aCkpLnRvRXF1YWwoW1xuICAgICAgXCIvZ2V0dGluZy1zdGFydGVkL1wiLFxuICAgICAgXCIvZ3VpZGUvXCIsXG4gICAgXSlcbiAgICBleHBlY3QocmVzdWx0LmdldChcIi9hcGkvXCIpPy5tYXAoYSA9PiBhLnBhdGgpKS50b0VxdWFsKFtcbiAgICAgIFwiL2FwaS91c2Vycy9cIixcbiAgICAgIFwiL2FwaS9hdXRoL1wiLFxuICAgIF0pXG4gIH0pXG59KVxuXG5kZXNjcmliZShcImN1c3RvbVNlY3Rpb25BY3RpdmVcIiwgKCkgPT4ge1xuICBpdChcInNob3VsZCBub3QgbWF0Y2ggYW4gYWJzb2x1dGUgaHR0cCB1cmxcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChjdXN0b21TZWN0aW9uQWN0aXZlKFwiaHR0cHM6Ly94LmNvbS95XCIsIFwiL3kvXCIpKS50b0JlKGZhbHNlKVxuICAgIGV4cGVjdChjdXN0b21TZWN0aW9uQWN0aXZlKFwiaHR0cDovL3guY29tL3lcIiwgXCIveS9cIikpLnRvQmUoZmFsc2UpXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgbm90IG1hdGNoIGEgcHJvdG9jb2wtcmVsYXRpdmUgdXJsXCIsICgpID0+IHtcbiAgICBleHBlY3QoY3VzdG9tU2VjdGlvbkFjdGl2ZShcIi8vY2RuLnguY29tL3lcIiwgXCIveS9cIikpLnRvQmUoZmFsc2UpXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgbm90IG1hdGNoIGEgaGFzaCB1cmxcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChjdXN0b21TZWN0aW9uQWN0aXZlKFwiI3NlY3Rpb25cIiwgXCIvc2VjdGlvbi9cIikpLnRvQmUoZmFsc2UpXG4gIH0pXG5cbiAgaXQoXCJzaG91bGQgbWF0Y2ggdGhlIGV4YWN0IHBhdGhcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChjdXN0b21TZWN0aW9uQWN0aXZlKFwiL2Fib3V0XCIsIFwiL2Fib3V0L1wiKSkudG9CZSh0cnVlKVxuICAgIGV4cGVjdChjdXN0b21TZWN0aW9uQWN0aXZlKFwiL2Fib3V0L1wiLCBcIi9hYm91dC9cIikpLnRvQmUodHJ1ZSlcbiAgfSlcblxuICBpdChcInNob3VsZCBtYXRjaCBhIGRlc2NlbmRhbnQgcGF0aFwiLCAoKSA9PiB7XG4gICAgZXhwZWN0KGN1c3RvbVNlY3Rpb25BY3RpdmUoXCIvYWJvdXRcIiwgXCIvYWJvdXQvdGVhbS9cIikpLnRvQmUodHJ1ZSlcbiAgfSlcblxuICBpdChcInNob3VsZCBub3QgbWF0Y2ggYSBzaWJsaW5nIHBhdGggd2l0aCBzaGFyZWQgcHJlZml4XCIsICgpID0+IHtcbiAgICBleHBlY3QoY3VzdG9tU2VjdGlvbkFjdGl2ZShcIi9hYm91dFwiLCBcIi9hYm91dHVzL1wiKSkudG9CZShmYWxzZSlcbiAgfSlcblxuICBpdChcInNob3VsZCBtYXRjaCBleGFjdCByb290IG9ubHlcIiwgKCkgPT4ge1xuICAgIGV4cGVjdChjdXN0b21TZWN0aW9uQWN0aXZlKFwiL1wiLCBcIi9cIikpLnRvQmUodHJ1ZSlcbiAgICBleHBlY3QoY3VzdG9tU2VjdGlvbkFjdGl2ZShcIi9cIiwgXCIvYWJvdXQvXCIpKS50b0JlKGZhbHNlKVxuICB9KVxuXG4gIGl0KFwic2hvdWxkIGlnbm9yZSBxdWVyeSBhbmQgaGFzaCBvbiB0aGUgdXJsXCIsICgpID0+IHtcbiAgICBleHBlY3QoY3VzdG9tU2VjdGlvbkFjdGl2ZShcIi9hYm91dD94PTFcIiwgXCIvYWJvdXQvXCIpKS50b0JlKHRydWUpXG4gICAgZXhwZWN0KGN1c3RvbVNlY3Rpb25BY3RpdmUoXCIvYWJvdXQjdG9wXCIsIFwiL2Fib3V0L3RlYW0vXCIpKS50b0JlKHRydWUpXG4gIH0pXG59KVxuIl19
|
package/build/models/config.d.ts
CHANGED
|
@@ -7,15 +7,27 @@ import type { ConfigEnv, UserConfig as ViteUserConfig } from "vite";
|
|
|
7
7
|
* merge, etc. Use this for deployment-target tweaks (e.g. CF Workers
|
|
8
8
|
* via `environments.ssr.resolve.conditions: ["workerd", ...]`). */
|
|
9
9
|
export type ViteOverride = ViteUserConfig | ((env: ConfigEnv) => ViteUserConfig | Promise<ViteUserConfig>);
|
|
10
|
+
/** Sub-path mount. String form is used as-is; function form is called
|
|
11
|
+
* with Vite's `command` (`"serve"` in dev, `"build"` in production) so
|
|
12
|
+
* the user can branch (typical case: serve at `/` in dev but at
|
|
13
|
+
* `/repo/` in production for GitHub Pages). The build pipeline
|
|
14
|
+
* resolves it to a string before any runtime sees it. */
|
|
15
|
+
export type Base = string | ((command: "build" | "serve") => string | undefined);
|
|
10
16
|
/**
|
|
11
17
|
* User-provided configuration for Livemark.
|
|
18
|
+
*
|
|
19
|
+
* `vite` and `base` are lifted from `unknown` to their public types so
|
|
20
|
+
* `defineConfig` shows the right shape in editors. Use this type for
|
|
21
|
+
* the input to `defineConfig` — it keeps defaulted fields optional
|
|
22
|
+
* (because zod input ≠ output for fields with `.default()`).
|
|
12
23
|
*/
|
|
13
|
-
export type UserConfig = Omit<z.
|
|
24
|
+
export type UserConfig = Omit<z.input<typeof UserConfig>, "vite" | "base"> & {
|
|
14
25
|
vite?: ViteOverride;
|
|
26
|
+
base?: Base;
|
|
15
27
|
};
|
|
16
28
|
export declare const UserConfig: z.ZodObject<{
|
|
17
29
|
site: z.ZodOptional<z.ZodString>;
|
|
18
|
-
base: z.
|
|
30
|
+
base: z.ZodOptional<z.ZodUnknown>;
|
|
19
31
|
favicon: z.ZodOptional<z.ZodString>;
|
|
20
32
|
logo: z.ZodOptional<z.ZodString>;
|
|
21
33
|
title: z.ZodDefault<z.ZodString>;
|
|
@@ -137,7 +149,7 @@ export declare const UserConfig: z.ZodObject<{
|
|
|
137
149
|
header: "header";
|
|
138
150
|
sidebar: "sidebar";
|
|
139
151
|
}>>;
|
|
140
|
-
type: z.ZodLiteral<"
|
|
152
|
+
type: z.ZodLiteral<"custom">;
|
|
141
153
|
url: z.ZodString;
|
|
142
154
|
}, z.core.$strip>], "type">>>>;
|
|
143
155
|
patches: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -164,11 +176,12 @@ export declare const UserConfig: z.ZodObject<{
|
|
|
164
176
|
}, z.core.$strip>>>;
|
|
165
177
|
vite: z.ZodOptional<z.ZodUnknown>;
|
|
166
178
|
}, z.core.$strip>;
|
|
167
|
-
/** Website configuration injected at build time via Vite define
|
|
179
|
+
/** Website configuration injected at build time via Vite define.
|
|
180
|
+
* `base` is strictly a string here — the build pipeline has already
|
|
181
|
+
* resolved any function form via `resolveBase()`. */
|
|
168
182
|
export type WebsiteConfig = z.infer<typeof WebsiteConfig>;
|
|
169
183
|
export declare const WebsiteConfig: z.ZodObject<{
|
|
170
184
|
site: z.ZodOptional<z.ZodString>;
|
|
171
|
-
base: z.ZodPipe<z.ZodOptional<z.ZodString>, z.ZodTransform<string | undefined, string | undefined>>;
|
|
172
185
|
favicon: z.ZodOptional<z.ZodString>;
|
|
173
186
|
logo: z.ZodOptional<z.ZodString>;
|
|
174
187
|
title: z.ZodDefault<z.ZodString>;
|
|
@@ -219,9 +232,10 @@ export declare const WebsiteConfig: z.ZodObject<{
|
|
|
219
232
|
header: "header";
|
|
220
233
|
sidebar: "sidebar";
|
|
221
234
|
}>>;
|
|
222
|
-
type: z.ZodLiteral<"
|
|
235
|
+
type: z.ZodLiteral<"custom">;
|
|
223
236
|
url: z.ZodString;
|
|
224
237
|
}, z.core.$strip>], "type">>>>;
|
|
238
|
+
base: z.ZodOptional<z.ZodString>;
|
|
225
239
|
}, z.core.$strip>;
|
|
226
240
|
/**
|
|
227
241
|
* System-computed configuration derived from the config file location.
|
|
@@ -234,14 +248,18 @@ export declare const SystemConfig: z.ZodObject<{
|
|
|
234
248
|
/**
|
|
235
249
|
* Fully resolved Livemark configuration.
|
|
236
250
|
*
|
|
237
|
-
* `vite` stays `unknown`
|
|
251
|
+
* `vite` stays `unknown` because that's what the runtime schema
|
|
238
252
|
* produces — consumer-facing typing happens via {@link UserConfig} so
|
|
239
|
-
* `defineConfig` shows the right shape in editors.
|
|
253
|
+
* `defineConfig` shows the right shape in editors. `base` is lifted to
|
|
254
|
+
* `string | undefined` because `loadConfig()` resolves any function
|
|
255
|
+
* form via `resolveBase()` before returning.
|
|
240
256
|
*/
|
|
241
|
-
export type Config = z.infer<typeof Config
|
|
257
|
+
export type Config = Omit<z.infer<typeof Config>, "base"> & {
|
|
258
|
+
base?: string;
|
|
259
|
+
};
|
|
242
260
|
export declare const Config: z.ZodObject<{
|
|
243
261
|
site: z.ZodOptional<z.ZodString>;
|
|
244
|
-
base: z.
|
|
262
|
+
base: z.ZodOptional<z.ZodUnknown>;
|
|
245
263
|
favicon: z.ZodOptional<z.ZodString>;
|
|
246
264
|
logo: z.ZodOptional<z.ZodString>;
|
|
247
265
|
title: z.ZodDefault<z.ZodString>;
|
|
@@ -363,7 +381,7 @@ export declare const Config: z.ZodObject<{
|
|
|
363
381
|
header: "header";
|
|
364
382
|
sidebar: "sidebar";
|
|
365
383
|
}>>;
|
|
366
|
-
type: z.ZodLiteral<"
|
|
384
|
+
type: z.ZodLiteral<"custom">;
|
|
367
385
|
url: z.ZodString;
|
|
368
386
|
}, z.core.$strip>], "type">>>>;
|
|
369
387
|
patches: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
package/build/models/config.js
CHANGED
|
@@ -5,15 +5,12 @@ import { Section } from "./section.js";
|
|
|
5
5
|
import { CodeThemeDark, CodeThemeLight } from "./theme.js";
|
|
6
6
|
export const UserConfig = z.object({
|
|
7
7
|
site: z.string().optional(),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const trimmed = v.replace(/^\/|\/$/g, "");
|
|
15
|
-
return trimmed ? `/${trimmed}` : undefined;
|
|
16
|
-
}),
|
|
8
|
+
// Stored as `unknown` in the schema (zod can't type a function and
|
|
9
|
+
// string union meaningfully); the public TypeScript surface above
|
|
10
|
+
// lifts it back to `Base` for editor support. The build pipeline
|
|
11
|
+
// resolves it via `resolveBase()` before any runtime consumer sees
|
|
12
|
+
// it, so the runtime `WebsiteConfig.base` is strictly `string`.
|
|
13
|
+
base: z.unknown().optional(),
|
|
17
14
|
favicon: z.string().optional(),
|
|
18
15
|
logo: z.string().optional(),
|
|
19
16
|
title: z.string().default("Livemark"),
|
|
@@ -34,15 +31,16 @@ export const WebsiteConfig = UserConfig.pick({
|
|
|
34
31
|
title: true,
|
|
35
32
|
description: true,
|
|
36
33
|
site: true,
|
|
37
|
-
base: true,
|
|
38
34
|
favicon: true,
|
|
39
35
|
logo: true,
|
|
40
36
|
links: true,
|
|
41
37
|
sections: true,
|
|
38
|
+
}).extend({
|
|
39
|
+
base: z.string().optional(),
|
|
42
40
|
});
|
|
43
41
|
export const SystemConfig = z.object({
|
|
44
42
|
root: z.string(),
|
|
45
43
|
configPath: z.string(),
|
|
46
44
|
});
|
|
47
45
|
export const Config = UserConfig.merge(SystemConfig);
|
|
48
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
46
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc291cmNlL21vZGVscy9jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQTtBQUV2QixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQ2hDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUN0QyxPQUFPLEVBQUUsYUFBYSxFQUFFLGNBQWMsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQStCMUQsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDakMsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDM0IsbUVBQW1FO0lBQ25FLGtFQUFrRTtJQUNsRSxpRUFBaUU7SUFDakUsbUVBQW1FO0lBQ25FLGdFQUFnRTtJQUNoRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM1QixPQUFPLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM5QixJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMzQixLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUM7SUFDckMsV0FBVyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMseUJBQXlCLENBQUM7SUFDMUQsT0FBTyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztJQUN0RSxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDOUQsY0FBYyxFQUFFLGNBQWMsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLENBQUM7SUFDMUQsYUFBYSxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLENBQUM7SUFDeEQsS0FBSyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFO0lBQy9CLFFBQVEsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLFFBQVEsRUFBRTtJQUNyQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLEVBQUU7SUFDbEMsc0VBQXNFO0lBQ3RFLG1FQUFtRTtJQUNuRSxrRUFBa0U7SUFDbEUsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDN0IsQ0FBQyxDQUFBO0FBTUYsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUM7SUFDM0MsS0FBSyxFQUFFLElBQUk7SUFDWCxXQUFXLEVBQUUsSUFBSTtJQUNqQixJQUFJLEVBQUUsSUFBSTtJQUNWLE9BQU8sRUFBRSxJQUFJO0lBQ2IsSUFBSSxFQUFFLElBQUk7SUFDVixLQUFLLEVBQUUsSUFBSTtJQUNYLFFBQVEsRUFBRSxJQUFJO0NBQ2YsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNSLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0NBQzVCLENBQUMsQ0FBQTtBQU1GLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ25DLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2hCLFVBQVUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0NBQ3ZCLENBQUMsQ0FBQTtBQWNGLE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIlxuaW1wb3J0IHR5cGUgeyBDb25maWdFbnYsIFVzZXJDb25maWcgYXMgVml0ZVVzZXJDb25maWcgfSBmcm9tIFwidml0ZVwiXG5pbXBvcnQgeyBMaW5rIH0gZnJvbSBcIi4vbGluay50c1wiXG5pbXBvcnQgeyBQYXRjaCB9IGZyb20gXCIuL3BhdGNoLnRzXCJcbmltcG9ydCB7IFNlY3Rpb24gfSBmcm9tIFwiLi9zZWN0aW9uLnRzXCJcbmltcG9ydCB7IENvZGVUaGVtZURhcmssIENvZGVUaGVtZUxpZ2h0IH0gZnJvbSBcIi4vdGhlbWUudHNcIlxuXG4vKiogRXNjYXBlIGhhdGNoIGZvciBhcmJpdHJhcnkgVml0ZSBjb25maWcg4oCUIGFjY2VwdHMgZWl0aGVyIGEgY29uZmlnXG4gKiAgb2JqZWN0IChzaW1wbGUgb3ZlcnJpZGVzKSBvciBhIGZ1bmN0aW9uIGZvcm0gKGAoZW52KSA9PiBjb25maWdgLFxuICogIG1hdGNoaW5nIFZpdGUncyBvd24gYGRlZmluZUNvbmZpZ2ApLiBNZXJnZWQgb24gdG9wIG9mIGxpdmVtYXJrJ3NcbiAqICBkZWZhdWx0cyB2aWEgYG1lcmdlQ29uZmlnYCwgc28gcGx1Z2luIGFycmF5cyBjb25jYXRlbmF0ZSwgZGVmaW5lc1xuICogIG1lcmdlLCBldGMuIFVzZSB0aGlzIGZvciBkZXBsb3ltZW50LXRhcmdldCB0d2Vha3MgKGUuZy4gQ0YgV29ya2Vyc1xuICogIHZpYSBgZW52aXJvbm1lbnRzLnNzci5yZXNvbHZlLmNvbmRpdGlvbnM6IFtcIndvcmtlcmRcIiwgLi4uXWApLiAqL1xuZXhwb3J0IHR5cGUgVml0ZU92ZXJyaWRlID1cbiAgfCBWaXRlVXNlckNvbmZpZ1xuICB8ICgoZW52OiBDb25maWdFbnYpID0+IFZpdGVVc2VyQ29uZmlnIHwgUHJvbWlzZTxWaXRlVXNlckNvbmZpZz4pXG5cbi8qKiBTdWItcGF0aCBtb3VudC4gU3RyaW5nIGZvcm0gaXMgdXNlZCBhcy1pczsgZnVuY3Rpb24gZm9ybSBpcyBjYWxsZWRcbiAqICB3aXRoIFZpdGUncyBgY29tbWFuZGAgKGBcInNlcnZlXCJgIGluIGRldiwgYFwiYnVpbGRcImAgaW4gcHJvZHVjdGlvbikgc29cbiAqICB0aGUgdXNlciBjYW4gYnJhbmNoICh0eXBpY2FsIGNhc2U6IHNlcnZlIGF0IGAvYCBpbiBkZXYgYnV0IGF0XG4gKiAgYC9yZXBvL2AgaW4gcHJvZHVjdGlvbiBmb3IgR2l0SHViIFBhZ2VzKS4gVGhlIGJ1aWxkIHBpcGVsaW5lXG4gKiAgcmVzb2x2ZXMgaXQgdG8gYSBzdHJpbmcgYmVmb3JlIGFueSBydW50aW1lIHNlZXMgaXQuICovXG5leHBvcnQgdHlwZSBCYXNlID0gc3RyaW5nIHwgKChjb21tYW5kOiBcImJ1aWxkXCIgfCBcInNlcnZlXCIpID0+IHN0cmluZyB8IHVuZGVmaW5lZClcblxuLyoqXG4gKiBVc2VyLXByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gZm9yIExpdmVtYXJrLlxuICpcbiAqIGB2aXRlYCBhbmQgYGJhc2VgIGFyZSBsaWZ0ZWQgZnJvbSBgdW5rbm93bmAgdG8gdGhlaXIgcHVibGljIHR5cGVzIHNvXG4gKiBgZGVmaW5lQ29uZmlnYCBzaG93cyB0aGUgcmlnaHQgc2hhcGUgaW4gZWRpdG9ycy4gVXNlIHRoaXMgdHlwZSBmb3JcbiAqIHRoZSBpbnB1dCB0byBgZGVmaW5lQ29uZmlnYCDigJQgaXQga2VlcHMgZGVmYXVsdGVkIGZpZWxkcyBvcHRpb25hbFxuICogKGJlY2F1c2Ugem9kIGlucHV0IOKJoCBvdXRwdXQgZm9yIGZpZWxkcyB3aXRoIGAuZGVmYXVsdCgpYCkuXG4gKi9cbmV4cG9ydCB0eXBlIFVzZXJDb25maWcgPSBPbWl0PHouaW5wdXQ8dHlwZW9mIFVzZXJDb25maWc+LCBcInZpdGVcIiB8IFwiYmFzZVwiPiAmIHtcbiAgdml0ZT86IFZpdGVPdmVycmlkZVxuICBiYXNlPzogQmFzZVxufVxuZXhwb3J0IGNvbnN0IFVzZXJDb25maWcgPSB6Lm9iamVjdCh7XG4gIHNpdGU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgLy8gU3RvcmVkIGFzIGB1bmtub3duYCBpbiB0aGUgc2NoZW1hICh6b2QgY2FuJ3QgdHlwZSBhIGZ1bmN0aW9uIGFuZFxuICAvLyBzdHJpbmcgdW5pb24gbWVhbmluZ2Z1bGx5KTsgdGhlIHB1YmxpYyBUeXBlU2NyaXB0IHN1cmZhY2UgYWJvdmVcbiAgLy8gbGlmdHMgaXQgYmFjayB0byBgQmFzZWAgZm9yIGVkaXRvciBzdXBwb3J0LiBUaGUgYnVpbGQgcGlwZWxpbmVcbiAgLy8gcmVzb2x2ZXMgaXQgdmlhIGByZXNvbHZlQmFzZSgpYCBiZWZvcmUgYW55IHJ1bnRpbWUgY29uc3VtZXIgc2Vlc1xuICAvLyBpdCwgc28gdGhlIHJ1bnRpbWUgYFdlYnNpdGVDb25maWcuYmFzZWAgaXMgc3RyaWN0bHkgYHN0cmluZ2AuXG4gIGJhc2U6IHoudW5rbm93bigpLm9wdGlvbmFsKCksXG4gIGZhdmljb246IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgbG9nbzogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICB0aXRsZTogei5zdHJpbmcoKS5kZWZhdWx0KFwiTGl2ZW1hcmtcIiksXG4gIGRlc2NyaXB0aW9uOiB6LnN0cmluZygpLmRlZmF1bHQoXCJNYXJrZG93biBzaXRlIGdlbmVyYXRvclwiKSxcbiAgaW5jbHVkZTogei51bmlvbihbei5zdHJpbmcoKSwgei5hcnJheSh6LnN0cmluZygpKV0pLmRlZmF1bHQoXCIqKi8qLm1kXCIpLFxuICBleGNsdWRlOiB6LnVuaW9uKFt6LnN0cmluZygpLCB6LmFycmF5KHouc3RyaW5nKCkpXSkub3B0aW9uYWwoKSxcbiAgY29kZVRoZW1lTGlnaHQ6IENvZGVUaGVtZUxpZ2h0LmRlZmF1bHQoXCJjYXRwcHVjY2luLWxhdHRlXCIpLFxuICBjb2RlVGhlbWVEYXJrOiBDb2RlVGhlbWVEYXJrLmRlZmF1bHQoXCJjYXRwcHVjY2luLW1vY2hhXCIpLFxuICBsaW5rczogei5hcnJheShMaW5rKS5vcHRpb25hbCgpLFxuICBzZWN0aW9uczogei5hcnJheShTZWN0aW9uKS5vcHRpb25hbCgpLFxuICBwYXRjaGVzOiB6LmFycmF5KFBhdGNoKS5vcHRpb25hbCgpLFxuICAvLyBTdG9yZWQgYXMgYHVua25vd25gIGluIHRoZSBzY2hlbWEgKHpvZCBjYW4ndCB0eXBlIGEgVml0ZSBVc2VyQ29uZmlnXG4gIC8vIG9yIGEgZnVuY3Rpb24gcmV0dXJuaW5nIG9uZSBtZWFuaW5nZnVsbHkpOyB0aGUgcHVibGljIFR5cGVTY3JpcHRcbiAgLy8gc3VyZmFjZSBhYm92ZSBsaWZ0cyBpdCBiYWNrIHRvIFZpdGVPdmVycmlkZSBmb3IgZWRpdG9yIHN1cHBvcnQuXG4gIHZpdGU6IHoudW5rbm93bigpLm9wdGlvbmFsKCksXG59KVxuXG4vKiogV2Vic2l0ZSBjb25maWd1cmF0aW9uIGluamVjdGVkIGF0IGJ1aWxkIHRpbWUgdmlhIFZpdGUgZGVmaW5lLlxuICogIGBiYXNlYCBpcyBzdHJpY3RseSBhIHN0cmluZyBoZXJlIOKAlCB0aGUgYnVpbGQgcGlwZWxpbmUgaGFzIGFscmVhZHlcbiAqICByZXNvbHZlZCBhbnkgZnVuY3Rpb24gZm9ybSB2aWEgYHJlc29sdmVCYXNlKClgLiAqL1xuZXhwb3J0IHR5cGUgV2Vic2l0ZUNvbmZpZyA9IHouaW5mZXI8dHlwZW9mIFdlYnNpdGVDb25maWc+XG5leHBvcnQgY29uc3QgV2Vic2l0ZUNvbmZpZyA9IFVzZXJDb25maWcucGljayh7XG4gIHRpdGxlOiB0cnVlLFxuICBkZXNjcmlwdGlvbjogdHJ1ZSxcbiAgc2l0ZTogdHJ1ZSxcbiAgZmF2aWNvbjogdHJ1ZSxcbiAgbG9nbzogdHJ1ZSxcbiAgbGlua3M6IHRydWUsXG4gIHNlY3Rpb25zOiB0cnVlLFxufSkuZXh0ZW5kKHtcbiAgYmFzZTogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxufSlcblxuLyoqXG4gKiBTeXN0ZW0tY29tcHV0ZWQgY29uZmlndXJhdGlvbiBkZXJpdmVkIGZyb20gdGhlIGNvbmZpZyBmaWxlIGxvY2F0aW9uLlxuICovXG5leHBvcnQgdHlwZSBTeXN0ZW1Db25maWcgPSB6LmluZmVyPHR5cGVvZiBTeXN0ZW1Db25maWc+XG5leHBvcnQgY29uc3QgU3lzdGVtQ29uZmlnID0gei5vYmplY3Qoe1xuICByb290OiB6LnN0cmluZygpLFxuICBjb25maWdQYXRoOiB6LnN0cmluZygpLFxufSlcblxuLyoqXG4gKiBGdWxseSByZXNvbHZlZCBMaXZlbWFyayBjb25maWd1cmF0aW9uLlxuICpcbiAqIGB2aXRlYCBzdGF5cyBgdW5rbm93bmAgYmVjYXVzZSB0aGF0J3Mgd2hhdCB0aGUgcnVudGltZSBzY2hlbWFcbiAqIHByb2R1Y2VzIOKAlCBjb25zdW1lci1mYWNpbmcgdHlwaW5nIGhhcHBlbnMgdmlhIHtAbGluayBVc2VyQ29uZmlnfSBzb1xuICogYGRlZmluZUNvbmZpZ2Agc2hvd3MgdGhlIHJpZ2h0IHNoYXBlIGluIGVkaXRvcnMuIGBiYXNlYCBpcyBsaWZ0ZWQgdG9cbiAqIGBzdHJpbmcgfCB1bmRlZmluZWRgIGJlY2F1c2UgYGxvYWRDb25maWcoKWAgcmVzb2x2ZXMgYW55IGZ1bmN0aW9uXG4gKiBmb3JtIHZpYSBgcmVzb2x2ZUJhc2UoKWAgYmVmb3JlIHJldHVybmluZy5cbiAqL1xuZXhwb3J0IHR5cGUgQ29uZmlnID0gT21pdDx6LmluZmVyPHR5cGVvZiBDb25maWc+LCBcImJhc2VcIj4gJiB7XG4gIGJhc2U/OiBzdHJpbmdcbn1cbmV4cG9ydCBjb25zdCBDb25maWcgPSBVc2VyQ29uZmlnLm1lcmdlKFN5c3RlbUNvbmZpZylcbiJdfQ==
|
|
@@ -37,16 +37,18 @@ export declare const ChangelogSection: z.ZodObject<{
|
|
|
37
37
|
source: z.ZodString;
|
|
38
38
|
version: z.ZodOptional<z.ZodBoolean>;
|
|
39
39
|
}, z.core.$strip>;
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
/** Custom section: renders as a link to an arbitrary URL — absolute
|
|
41
|
+
* (`https://…`) or internal (`/changelog`). Internal URLs participate
|
|
42
|
+
* in active-state highlighting like routed sections. */
|
|
43
|
+
export type CustomSection = z.infer<typeof CustomSection>;
|
|
44
|
+
export declare const CustomSection: z.ZodObject<{
|
|
43
45
|
icon: z.ZodOptional<z.ZodString>;
|
|
44
46
|
title: z.ZodString;
|
|
45
47
|
position: z.ZodDefault<z.ZodEnum<{
|
|
46
48
|
header: "header";
|
|
47
49
|
sidebar: "sidebar";
|
|
48
50
|
}>>;
|
|
49
|
-
type: z.ZodLiteral<"
|
|
51
|
+
type: z.ZodLiteral<"custom">;
|
|
50
52
|
url: z.ZodString;
|
|
51
53
|
}, z.core.$strip>;
|
|
52
54
|
/**
|
|
@@ -91,6 +93,6 @@ export declare const Section: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodD
|
|
|
91
93
|
header: "header";
|
|
92
94
|
sidebar: "sidebar";
|
|
93
95
|
}>>;
|
|
94
|
-
type: z.ZodLiteral<"
|
|
96
|
+
type: z.ZodLiteral<"custom">;
|
|
95
97
|
url: z.ZodString;
|
|
96
98
|
}, z.core.$strip>], "type">>;
|
package/build/models/section.js
CHANGED
|
@@ -18,8 +18,8 @@ export const ChangelogSection = BaseSection.extend({
|
|
|
18
18
|
source: z.string(),
|
|
19
19
|
version: z.boolean().optional(),
|
|
20
20
|
});
|
|
21
|
-
export const
|
|
22
|
-
type: z.literal("
|
|
21
|
+
export const CustomSection = BaseSection.extend({
|
|
22
|
+
type: z.literal("custom"),
|
|
23
23
|
url: z.string(),
|
|
24
24
|
});
|
|
25
25
|
export const Section = z.preprocess(input => {
|
|
@@ -32,6 +32,6 @@ export const Section = z.preprocess(input => {
|
|
|
32
32
|
ArticleSection,
|
|
33
33
|
BlogSection,
|
|
34
34
|
ChangelogSection,
|
|
35
|
-
|
|
35
|
+
CustomSection,
|
|
36
36
|
]));
|
|
37
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NvdXJjZS9tb2RlbHMvc2VjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFBO0FBRXZCLE1BQU0sV0FBVyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDM0IsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDM0IsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDakIsUUFBUSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO0NBQzFELENBQUMsQ0FBQTtBQUlGLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDO0lBQy9DLElBQUksRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztJQUMxQixNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTtDQUNuQixDQUFDLENBQUE7QUFJRixNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQztJQUM1QyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDdkIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7Q0FDbkIsQ0FBQyxDQUFBO0FBSUYsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQztJQUNqRCxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUM7SUFDNUIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDbEIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDbEIsT0FBTyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDaEMsQ0FBQyxDQUFBO0FBTUYsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLFdBQVcsQ0FBQyxNQUFNLENBQUM7SUFDOUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDO0lBQ3pCLEdBQUcsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0NBQ2hCLENBQUMsQ0FBQTtBQVFGLE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUMsVUFBVSxDQUNqQyxLQUFLLENBQUMsRUFBRTtJQUNOLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3hFLE9BQU8sS0FBSyxDQUFBO0lBQ2QsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLEtBQWdDLENBQUE7SUFDL0MsT0FBTyxNQUFNLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxNQUFNLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFBO0FBQ25FLENBQUMsRUFDRCxDQUFDLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFO0lBQzNCLGNBQWM7SUFDZCxXQUFXO0lBQ1gsZ0JBQWdCO0lBQ2hCLGFBQWE7Q0FDZCxDQUFDLENBQ0gsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHogfSBmcm9tIFwiem9kXCJcblxuY29uc3QgQmFzZVNlY3Rpb24gPSB6Lm9iamVjdCh7XG4gIGljb246IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgdGl0bGU6IHouc3RyaW5nKCksXG4gIHBvc2l0aW9uOiB6LmVudW0oW1wiaGVhZGVyXCIsIFwic2lkZWJhclwiXSkuZGVmYXVsdChcImhlYWRlclwiKSxcbn0pXG5cbi8qKiBEZWZhdWx0IHNlY3Rpb246IHJlbmRlcnMgYXJ0aWNsZXMuICovXG5leHBvcnQgdHlwZSBBcnRpY2xlU2VjdGlvbiA9IHouaW5mZXI8dHlwZW9mIEFydGljbGVTZWN0aW9uPlxuZXhwb3J0IGNvbnN0IEFydGljbGVTZWN0aW9uID0gQmFzZVNlY3Rpb24uZXh0ZW5kKHtcbiAgdHlwZTogei5saXRlcmFsKFwiYXJ0aWNsZVwiKSxcbiAgcHJlZml4OiB6LnN0cmluZygpLFxufSlcblxuLyoqIEJsb2cgc2VjdGlvbjogZGF0ZS1zb3J0ZWQgcG9zdHMgd2l0aCB0YWdzIGFuZCBpbmRleC4gKi9cbmV4cG9ydCB0eXBlIEJsb2dTZWN0aW9uID0gei5pbmZlcjx0eXBlb2YgQmxvZ1NlY3Rpb24+XG5leHBvcnQgY29uc3QgQmxvZ1NlY3Rpb24gPSBCYXNlU2VjdGlvbi5leHRlbmQoe1xuICB0eXBlOiB6LmxpdGVyYWwoXCJibG9nXCIpLFxuICBwcmVmaXg6IHouc3RyaW5nKCksXG59KVxuXG4vKiogQ2hhbmdlbG9nIHNlY3Rpb246IHNpbmdsZSBmaWxlIG9yIEdpdEh1YiByZWxlYXNlcywgc3BsaXQgcGVyIHZlcnNpb24uICovXG5leHBvcnQgdHlwZSBDaGFuZ2Vsb2dTZWN0aW9uID0gei5pbmZlcjx0eXBlb2YgQ2hhbmdlbG9nU2VjdGlvbj5cbmV4cG9ydCBjb25zdCBDaGFuZ2Vsb2dTZWN0aW9uID0gQmFzZVNlY3Rpb24uZXh0ZW5kKHtcbiAgdHlwZTogei5saXRlcmFsKFwiY2hhbmdlbG9nXCIpLFxuICBwcmVmaXg6IHouc3RyaW5nKCksXG4gIHNvdXJjZTogei5zdHJpbmcoKSxcbiAgdmVyc2lvbjogei5ib29sZWFuKCkub3B0aW9uYWwoKSxcbn0pXG5cbi8qKiBDdXN0b20gc2VjdGlvbjogcmVuZGVycyBhcyBhIGxpbmsgdG8gYW4gYXJiaXRyYXJ5IFVSTCDigJQgYWJzb2x1dGVcbiAqICAoYGh0dHBzOi8v4oCmYCkgb3IgaW50ZXJuYWwgKGAvY2hhbmdlbG9nYCkuIEludGVybmFsIFVSTHMgcGFydGljaXBhdGVcbiAqICBpbiBhY3RpdmUtc3RhdGUgaGlnaGxpZ2h0aW5nIGxpa2Ugcm91dGVkIHNlY3Rpb25zLiAqL1xuZXhwb3J0IHR5cGUgQ3VzdG9tU2VjdGlvbiA9IHouaW5mZXI8dHlwZW9mIEN1c3RvbVNlY3Rpb24+XG5leHBvcnQgY29uc3QgQ3VzdG9tU2VjdGlvbiA9IEJhc2VTZWN0aW9uLmV4dGVuZCh7XG4gIHR5cGU6IHoubGl0ZXJhbChcImN1c3RvbVwiKSxcbiAgdXJsOiB6LnN0cmluZygpLFxufSlcblxuLyoqXG4gKiBBIHNpdGUgc2VjdGlvbi4gRGlzY3JpbWluYXRlZCBvbiBgdHlwZWAuXG4gKiBXaGVuIGB0eXBlYCBpcyBvbWl0dGVkLCBpdCBkZWZhdWx0cyB0byBcImFydGljbGVcIiBzbyBwbGFpblxuICogYHsgdGl0bGUsIHByZWZpeCB9YCBlbnRyaWVzIGtlZXAgd29ya2luZy5cbiAqL1xuZXhwb3J0IHR5cGUgU2VjdGlvbiA9IHouaW5mZXI8dHlwZW9mIFNlY3Rpb24+XG5leHBvcnQgY29uc3QgU2VjdGlvbiA9IHoucHJlcHJvY2VzcyhcbiAgaW5wdXQgPT4ge1xuICAgIGlmIChpbnB1dCA9PT0gbnVsbCB8fCB0eXBlb2YgaW5wdXQgIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShpbnB1dCkpIHtcbiAgICAgIHJldHVybiBpbnB1dFxuICAgIH1cbiAgICBjb25zdCByZWNvcmQgPSBpbnB1dCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuICAgIHJldHVybiBcInR5cGVcIiBpbiByZWNvcmQgPyByZWNvcmQgOiB7IC4uLnJlY29yZCwgdHlwZTogXCJhcnRpY2xlXCIgfVxuICB9LFxuICB6LmRpc2NyaW1pbmF0ZWRVbmlvbihcInR5cGVcIiwgW1xuICAgIEFydGljbGVTZWN0aW9uLFxuICAgIEJsb2dTZWN0aW9uLFxuICAgIENoYW5nZWxvZ1NlY3Rpb24sXG4gICAgQ3VzdG9tU2VjdGlvbixcbiAgXSksXG4pXG4iXX0=
|
package/package.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { UserConfig } from "../../models/config.ts"
|
|
1
|
+
import { UserConfig as UserConfigSchema } from "../../models/config.ts"
|
|
2
|
+
import type { UserConfig } from "../../models/config.ts"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Validate and fill defaults for a partial config object.
|
|
6
6
|
*/
|
|
7
|
-
export function defineConfig(
|
|
8
|
-
|
|
9
|
-
): z.output<typeof UserConfig> {
|
|
10
|
-
return UserConfig.parse(input)
|
|
7
|
+
export function defineConfig(input: UserConfig) {
|
|
8
|
+
return UserConfigSchema.parse(input)
|
|
11
9
|
}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { existsSync } from "node:fs"
|
|
2
2
|
import { dirname, resolve } from "node:path"
|
|
3
3
|
import { pathToFileURL } from "node:url"
|
|
4
|
-
import type {
|
|
5
|
-
import
|
|
6
|
-
import { UserConfig } from "../../models/config.ts"
|
|
4
|
+
import type { Config, UserConfig } from "../../models/config.ts"
|
|
5
|
+
import { resolveBase } from "../../helpers/resolve-base.ts"
|
|
7
6
|
import { defineConfig } from "./define.ts"
|
|
8
7
|
|
|
8
|
+
/** Map livemark CLI verbs to the Vite-equivalent `command` string used by
|
|
9
|
+
* `resolveBase()`. `preview` serves the production build's artifacts so
|
|
10
|
+
* it uses the build-mode base. Default to `"build"` for safety when no
|
|
11
|
+
* recognised verb is in argv (the common path is `livemark <verb> ...`). */
|
|
12
|
+
const COMMAND_BY_VERB: Record<string, "build" | "serve"> = {
|
|
13
|
+
start: "serve",
|
|
14
|
+
build: "build",
|
|
15
|
+
preview: "build",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function detectCommand() {
|
|
19
|
+
for (const arg of process.argv.slice(2)) {
|
|
20
|
+
if (arg in COMMAND_BY_VERB) return COMMAND_BY_VERB[arg]!
|
|
21
|
+
}
|
|
22
|
+
return "build" as const
|
|
23
|
+
}
|
|
24
|
+
|
|
9
25
|
/**
|
|
10
26
|
* Load and validate a config file, checking --config/-c CLI arg, then cwd.
|
|
11
27
|
*
|
|
@@ -23,15 +39,19 @@ export async function loadConfig(path?: string): Promise<Config> {
|
|
|
23
39
|
const cliPath = configIndex !== -1 ? process.argv[configIndex + 1] : undefined
|
|
24
40
|
const explicit = path ?? cliPath
|
|
25
41
|
const resolved = resolve(explicit ?? "livemark.config.ts")
|
|
26
|
-
let input:
|
|
42
|
+
let input: UserConfig = {}
|
|
27
43
|
if (existsSync(resolved)) {
|
|
28
44
|
// Cache-bust the ESM import so dev-server restart reloads edits on disk.
|
|
29
45
|
const url = `${pathToFileURL(resolved).href}?t=${Date.now()}`
|
|
30
46
|
const module: Record<string, unknown> = await import(url)
|
|
31
|
-
input = (module.default as
|
|
47
|
+
input = (module.default as UserConfig) ?? {}
|
|
32
48
|
} else if (explicit) {
|
|
33
49
|
throw new Error(`Config file not found: ${resolved}`)
|
|
34
50
|
}
|
|
35
51
|
const validated = defineConfig(input)
|
|
36
|
-
|
|
52
|
+
// Resolve the function form of `base` once, here, using the livemark
|
|
53
|
+
// CLI verb. Downstream consumers (Vite plugin, content-collections,
|
|
54
|
+
// runtime) get a plain string|undefined and never see the function.
|
|
55
|
+
const base = resolveBase(validated.base, detectCommand())
|
|
56
|
+
return { ...validated, base, root: dirname(resolved), configPath: resolved }
|
|
37
57
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "../content/article.ts"
|
|
10
10
|
import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
|
|
11
11
|
import { prefixUrl } from "../helpers/prefix-url.ts"
|
|
12
|
-
import { sectionIcon } from "../helpers/section.ts"
|
|
12
|
+
import { customSectionActive, sectionIcon } from "../helpers/section.ts"
|
|
13
13
|
import {
|
|
14
14
|
SidebarInset,
|
|
15
15
|
SidebarProvider,
|
|
@@ -69,17 +69,20 @@ export function Layout(props: {
|
|
|
69
69
|
sections
|
|
70
70
|
.filter(section => section.position === "header")
|
|
71
71
|
.map(section => {
|
|
72
|
-
|
|
72
|
+
const icon = sectionIcon(section)
|
|
73
|
+
if (section.type === "custom") {
|
|
74
|
+
const isActive = customSectionActive(section.url, pathname)
|
|
73
75
|
return (
|
|
74
76
|
<a
|
|
75
77
|
key={section.url}
|
|
76
78
|
href={prefixUrl(section.url, config.base)}
|
|
77
|
-
className=
|
|
79
|
+
className={`inline-flex items-center gap-1.5 text-foreground ${
|
|
80
|
+
isActive
|
|
81
|
+
? "font-medium border-b-2 border-foreground pb-0.5 -mb-0.5"
|
|
82
|
+
: "opacity-80 hover:opacity-100 transition-opacity"
|
|
83
|
+
}`}
|
|
78
84
|
>
|
|
79
|
-
<DynamicIcon
|
|
80
|
-
name={sectionIcon(section)}
|
|
81
|
-
className="size-3.5"
|
|
82
|
-
/>
|
|
85
|
+
{icon && <DynamicIcon name={icon} className="size-3.5" />}
|
|
83
86
|
<span>{section.title}</span>
|
|
84
87
|
</a>
|
|
85
88
|
)
|
|
@@ -107,10 +110,7 @@ export function Layout(props: {
|
|
|
107
110
|
: "opacity-80 hover:opacity-100 transition-opacity"
|
|
108
111
|
}`}
|
|
109
112
|
>
|
|
110
|
-
<DynamicIcon
|
|
111
|
-
name={sectionIcon(section)}
|
|
112
|
-
className="size-3.5"
|
|
113
|
-
/>
|
|
113
|
+
{icon && <DynamicIcon name={icon} className="size-3.5" />}
|
|
114
114
|
<span>
|
|
115
115
|
{section.title}
|
|
116
116
|
{latestVersion && (
|
|
@@ -3,7 +3,7 @@ import { Link, useLocation, useMatch } from "@tanstack/react-router"
|
|
|
3
3
|
import { currentSection, sectionFirstArticle } from "../content/article.ts"
|
|
4
4
|
import { DynamicIcon } from "../helpers/dynamic-icon.tsx"
|
|
5
5
|
import { prefixUrl } from "../helpers/prefix-url.ts"
|
|
6
|
-
import { sectionIcon } from "../helpers/section.ts"
|
|
6
|
+
import { customSectionActive, sectionIcon } from "../helpers/section.ts"
|
|
7
7
|
import {
|
|
8
8
|
SidebarGroup,
|
|
9
9
|
SidebarGroupContent,
|
|
@@ -40,17 +40,20 @@ export function SidebarSections() {
|
|
|
40
40
|
<SidebarMenu>
|
|
41
41
|
{sections.map(s => {
|
|
42
42
|
const mobileOnly = s.position !== "sidebar"
|
|
43
|
-
|
|
43
|
+
const icon = sectionIcon(s)
|
|
44
|
+
if (s.type === "custom") {
|
|
45
|
+
const active = customSectionActive(s.url, pathname)
|
|
44
46
|
return (
|
|
45
47
|
<SidebarMenuItem
|
|
46
48
|
key={s.url}
|
|
47
49
|
className={mobileOnly ? "md:hidden" : undefined}
|
|
48
50
|
>
|
|
49
51
|
<SidebarMenuButton
|
|
50
|
-
|
|
52
|
+
isActive={active}
|
|
53
|
+
className={active ? "" : "opacity-75"}
|
|
51
54
|
render={<a href={prefixUrl(s.url, config.base)} />}
|
|
52
55
|
>
|
|
53
|
-
<DynamicIcon name={
|
|
56
|
+
{icon && <DynamicIcon name={icon} className="size-4" />}
|
|
54
57
|
<span>{s.title}</span>
|
|
55
58
|
</SidebarMenuButton>
|
|
56
59
|
</SidebarMenuItem>
|
|
@@ -76,7 +79,7 @@ export function SidebarSections() {
|
|
|
76
79
|
/>
|
|
77
80
|
}
|
|
78
81
|
>
|
|
79
|
-
<DynamicIcon name={
|
|
82
|
+
{icon && <DynamicIcon name={icon} className="size-4" />}
|
|
80
83
|
<span>{s.title}</span>
|
|
81
84
|
</SidebarMenuButton>
|
|
82
85
|
</SidebarMenuItem>
|
|
@@ -33,9 +33,9 @@ function orderKey(order?: number) {
|
|
|
33
33
|
|
|
34
34
|
const configSections = config.sections
|
|
35
35
|
|
|
36
|
-
/** Route-bound sections (everything except `
|
|
36
|
+
/** Route-bound sections (everything except `custom`). Custom sections
|
|
37
37
|
* are pure links — they have no `prefix` and don't claim a URL space. */
|
|
38
|
-
const routedSections = configSections?.filter(s => s.type !== "
|
|
38
|
+
const routedSections = configSections?.filter(s => s.type !== "custom") ?? []
|
|
39
39
|
|
|
40
40
|
/** Per-section article tree, keyed by section prefix */
|
|
41
41
|
export const sectionArticleTrees = new Map<string, ArticleNode[]>()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Resolve a base config field — accepts a string, a function of the
|
|
2
|
+
* form `(command) => string | undefined` (where `command` matches
|
|
3
|
+
* Vite's `ConfigEnv.command`), or undefined. Normalizes the result to
|
|
4
|
+
* either `undefined` (no base) or a leading-slash, no-trailing-slash
|
|
5
|
+
* string (e.g. `"repo"` and `"/repo/"` both → `"/repo"`). */
|
|
6
|
+
export function resolveBase(input: unknown, command: "build" | "serve") {
|
|
7
|
+
const raw = typeof input === "function" ? input(command) : input
|
|
8
|
+
if (typeof raw !== "string" || !raw) return undefined
|
|
9
|
+
const trimmed = raw.replace(/^\/|\/$/g, "")
|
|
10
|
+
return trimmed ? `/${trimmed}` : undefined
|
|
11
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { describe, expect, it } from "vite-plus/test"
|
|
2
|
+
import { resolveBase } from "./resolve-base.ts"
|
|
3
|
+
|
|
4
|
+
describe("resolveBase", () => {
|
|
5
|
+
it("should return undefined for undefined input", () => {
|
|
6
|
+
expect(resolveBase(undefined, "build")).toBeUndefined()
|
|
7
|
+
expect(resolveBase(undefined, "serve")).toBeUndefined()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it("should return undefined for empty or root-only string", () => {
|
|
11
|
+
expect(resolveBase("", "build")).toBeUndefined()
|
|
12
|
+
expect(resolveBase("/", "build")).toBeUndefined()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it("should normalize a string without slashes", () => {
|
|
16
|
+
expect(resolveBase("repo", "build")).toBe("/repo")
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it("should normalize a string with leading slash", () => {
|
|
20
|
+
expect(resolveBase("/repo", "build")).toBe("/repo")
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it("should normalize a string with trailing slash", () => {
|
|
24
|
+
expect(resolveBase("repo/", "build")).toBe("/repo")
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it("should normalize a string with both slashes", () => {
|
|
28
|
+
expect(resolveBase("/repo/", "build")).toBe("/repo")
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it("should preserve multi-segment paths", () => {
|
|
32
|
+
expect(resolveBase("/a/b/", "build")).toBe("/a/b")
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("should call a function with command=build", () => {
|
|
36
|
+
const fn = (cmd: "build" | "serve") => (cmd === "build" ? "prod" : "dev")
|
|
37
|
+
expect(resolveBase(fn, "build")).toBe("/prod")
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it("should call a function with command=serve", () => {
|
|
41
|
+
const fn = (cmd: "build" | "serve") => (cmd === "build" ? "prod" : "dev")
|
|
42
|
+
expect(resolveBase(fn, "serve")).toBe("/dev")
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it("should handle a function returning undefined", () => {
|
|
46
|
+
const fn = (cmd: "build" | "serve") =>
|
|
47
|
+
cmd === "serve" ? undefined : "prod"
|
|
48
|
+
expect(resolveBase(fn, "serve")).toBeUndefined()
|
|
49
|
+
expect(resolveBase(fn, "build")).toBe("/prod")
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it("should handle a function returning empty string", () => {
|
|
53
|
+
const fn = () => ""
|
|
54
|
+
expect(resolveBase(fn, "build")).toBeUndefined()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it("should normalize the function-returned string", () => {
|
|
58
|
+
const fn = () => "/repo/"
|
|
59
|
+
expect(resolveBase(fn, "build")).toBe("/repo")
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import type { Section } from "../models/section.ts"
|
|
2
2
|
|
|
3
|
-
const DEFAULT_ICONS: Record<Section["type"], string
|
|
3
|
+
const DEFAULT_ICONS: Partial<Record<Section["type"], string>> = {
|
|
4
4
|
article: "book-open",
|
|
5
5
|
blog: "rss",
|
|
6
6
|
changelog: "history",
|
|
7
|
-
external: "external-link",
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
/** Return the section's icon, falling back to a type-based default
|
|
9
|
+
/** Return the section's icon, falling back to a type-based default.
|
|
10
|
+
* Custom sections have no default — the user opts in via `icon`. */
|
|
11
11
|
export function sectionIcon(section: Pick<Section, "icon" | "type">) {
|
|
12
12
|
return section.icon ?? DEFAULT_ICONS[section.type]
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/** Whether a custom section's URL should highlight as active for the
|
|
16
|
+
* current pathname. Only `/`-leading internal paths participate;
|
|
17
|
+
* protocol-absolute (`https://…`, `//cdn…`) URLs never highlight.
|
|
18
|
+
* Match semantics mirror routed sections — exact path or any
|
|
19
|
+
* descendant. A URL of `/` only highlights the home page itself
|
|
20
|
+
* (otherwise it would always match). */
|
|
21
|
+
export function customSectionActive(url: string, pathname: string) {
|
|
22
|
+
if (!url.startsWith("/") || url.startsWith("//")) return false
|
|
23
|
+
const stripped = url.split(/[?#]/)[0] ?? ""
|
|
24
|
+
const target = `/${stripped.replace(/^\/|\/$/g, "")}/`
|
|
25
|
+
const current = `/${pathname.replace(/^\/|\/$/g, "")}/`
|
|
26
|
+
if (target === "/") return current === "/"
|
|
27
|
+
return current === target || current.startsWith(target)
|
|
28
|
+
}
|
|
29
|
+
|
|
15
30
|
/** Find the section whose prefix is the longest prefix of the article path */
|
|
16
31
|
export function matchSection<S extends { prefix: string }>(
|
|
17
32
|
articlePath: string,
|