@nu-appdev/northwestern-starlight-theme 1.3.2 → 1.5.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/CHANGELOG.md +39 -1
- package/README.md +8 -12
- package/config.ts +308 -0
- package/dist/config.d.ts +82 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/expressive-code.d.ts +21 -0
- package/dist/expressive-code.d.ts.map +1 -0
- package/dist/index.d.ts +123 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/mermaid.d.ts +97 -0
- package/dist/mermaid.d.ts.map +1 -0
- package/dist/src/config-schema.d.ts +141 -0
- package/dist/src/config-schema.d.ts.map +1 -0
- package/dist/src/rehype-table-scroll.d.ts +10 -0
- package/dist/src/rehype-table-scroll.d.ts.map +1 -0
- package/expressive-code.ts +35 -0
- package/index.ts +105 -18
- package/mermaid.ts +22 -12
- package/package.json +22 -7
- package/src/config-schema.ts +250 -0
- package/src/og/endpoint.ts +63 -0
- package/src/og/render.ts +260 -0
- package/src/og/route-middleware.ts +125 -0
- package/src/rehype-table-scroll.ts +7 -0
- package/src/styles/content.css +18 -17
- package/src/styles/typography.css +2 -2
- package/src/virtual.d.ts +6 -0
- package/expressive-code.mjs +0 -18
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { AstroIntegration } from "astro";
|
|
2
|
+
import type { AstroMermaidOptions } from "astro-mermaid";
|
|
3
|
+
/**
|
|
4
|
+
* Configuration options for the Northwestern Mermaid integration.
|
|
5
|
+
*
|
|
6
|
+
* Extends `astro-mermaid` options with a `toolbar` toggle that controls
|
|
7
|
+
* the hover toolbar (fullscreen, download, copy) on rendered diagrams.
|
|
8
|
+
*
|
|
9
|
+
* @see {@link northwesternMermaid} for the integration factory
|
|
10
|
+
*/
|
|
11
|
+
export interface NorthwesternMermaidOptions extends AstroMermaidOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Show the hover toolbar (fullscreen, download SVG, copy source) on diagrams.
|
|
14
|
+
*
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
toolbar?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Theme mode for Mermaid color palette generation.
|
|
21
|
+
*
|
|
22
|
+
* Maps to the `data-theme` attribute on `<html>`: `"light"` for the default
|
|
23
|
+
* palette, `"dark"` for the inverted palette with lighter primary colors
|
|
24
|
+
* and darker canvas backgrounds.
|
|
25
|
+
*/
|
|
26
|
+
export type NorthwesternMermaidMode = "light" | "dark";
|
|
27
|
+
/**
|
|
28
|
+
* Generate a complete `astro-mermaid` config with Northwestern-branded colors
|
|
29
|
+
* for the given theme mode.
|
|
30
|
+
*
|
|
31
|
+
* Builds a Mermaid `themeVariables` object from the Northwestern brand palette,
|
|
32
|
+
* deriving all node, edge, label, chart, and diagram-specific colors from a
|
|
33
|
+
* small set of brand primaries via `khroma` color manipulation.
|
|
34
|
+
*
|
|
35
|
+
* @param mode - `"light"` or `"dark"`. Controls canvas, text, and primary color values.
|
|
36
|
+
* @returns A complete `AstroMermaidOptions` object ready to pass to `astro-mermaid`.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { createNorthwesternMermaidConfig } from "@nu-appdev/northwestern-starlight-theme/mermaid";
|
|
41
|
+
*
|
|
42
|
+
* const darkConfig = createNorthwesternMermaidConfig("dark");
|
|
43
|
+
* // darkConfig.mermaidConfig.themeVariables contains all colors
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function createNorthwesternMermaidConfig(mode: NorthwesternMermaidMode): AstroMermaidOptions;
|
|
47
|
+
/**
|
|
48
|
+
* Pre-built light-mode Mermaid config with Northwestern brand colors.
|
|
49
|
+
*
|
|
50
|
+
* Used as the default when Mermaid is auto-detected. Override individual
|
|
51
|
+
* `themeVariables` by passing a `mermaid` object to {@link northwesternTheme}
|
|
52
|
+
* in `index.ts`, or use {@link createNorthwesternMermaidConfig} for full control.
|
|
53
|
+
*/
|
|
54
|
+
export declare const defaultMermaidConfig: AstroMermaidOptions;
|
|
55
|
+
/**
|
|
56
|
+
* Pre-built dark-mode Mermaid config with Northwestern brand colors.
|
|
57
|
+
*
|
|
58
|
+
* Applied at runtime when the user switches to dark mode. The toolbar script
|
|
59
|
+
* re-renders diagrams with this config via `window.__NU_MERMAID_CONFIGS__.dark`.
|
|
60
|
+
*/
|
|
61
|
+
export declare const darkMermaidConfig: AstroMermaidOptions;
|
|
62
|
+
/**
|
|
63
|
+
* Create an Astro integration that registers Northwestern-branded Mermaid diagrams.
|
|
64
|
+
*
|
|
65
|
+
* Wraps `astro-mermaid` with Northwestern color palettes for both light and dark
|
|
66
|
+
* modes, and injects the toolbar script (fullscreen viewer, download, copy).
|
|
67
|
+
*
|
|
68
|
+
* **Note:** `defineNorthwesternConfig` handles Mermaid integration ordering.
|
|
69
|
+
* This function is only needed for manual setups.
|
|
70
|
+
*
|
|
71
|
+
* **Must be added before `starlight()` in the `integrations` array.** The
|
|
72
|
+
* `astro-mermaid` remark plugin needs to register before Starlight's rehype
|
|
73
|
+
* processing, and Astro processes integrations in order. Placing it after
|
|
74
|
+
* `starlight()` causes Mermaid code blocks to be treated as plain code.
|
|
75
|
+
*
|
|
76
|
+
* @param options - Merged with Northwestern defaults. Set `toolbar: false` to
|
|
77
|
+
* disable the hover toolbar.
|
|
78
|
+
* @returns An Astro integration to add to `integrations` in your Astro config.
|
|
79
|
+
*
|
|
80
|
+
* @example Manual setup
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { northwesternMermaid } from "@nu-appdev/northwestern-starlight-theme/mermaid";
|
|
83
|
+
* import northwesternTheme from "@nu-appdev/northwestern-starlight-theme";
|
|
84
|
+
*
|
|
85
|
+
* export default defineConfig({
|
|
86
|
+
* integrations: [
|
|
87
|
+
* northwesternMermaid(), // Must come before starlight()
|
|
88
|
+
* starlight({
|
|
89
|
+
* plugins: [northwesternTheme()],
|
|
90
|
+
* title: "My Docs",
|
|
91
|
+
* }),
|
|
92
|
+
* ],
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function northwesternMermaid(options?: NorthwesternMermaidOptions): AstroIntegration;
|
|
97
|
+
//# sourceMappingURL=mermaid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../mermaid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAIzD;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA2B,SAAQ,mBAAmB;IACnE;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,CAAC;AAwUvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB,CAmBlG;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAA8D,CAAC;AAElG;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,mBAA6D,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,gBAAgB,CAqD9F"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Non-empty string helper used when reading titles from mixed Starlight config shapes.
|
|
4
|
+
*
|
|
5
|
+
* Trims surrounding whitespace and rejects empty strings after trimming.
|
|
6
|
+
*/
|
|
7
|
+
export declare const nonEmptyStringSchema: z.ZodString;
|
|
8
|
+
/**
|
|
9
|
+
* Top-level configuration for the Northwestern Starlight theme plugin.
|
|
10
|
+
*
|
|
11
|
+
* With `defineNorthwesternConfig`, pass this object as the `theme` key.
|
|
12
|
+
* With `northwesternTheme()` directly, pass it as the function argument.
|
|
13
|
+
*/
|
|
14
|
+
export declare const northwesternThemeConfigSchema: z.ZodObject<{
|
|
15
|
+
/**
|
|
16
|
+
* Homepage hero layout configuration.
|
|
17
|
+
*/
|
|
18
|
+
homepage: z.ZodOptional<z.ZodObject<{
|
|
19
|
+
layout: z.ZodOptional<z.ZodEnum<{
|
|
20
|
+
centered: "centered";
|
|
21
|
+
split: "split";
|
|
22
|
+
}>>;
|
|
23
|
+
showTitle: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
imageWidth: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, z.core.$strict>>;
|
|
26
|
+
/**
|
|
27
|
+
* Mermaid diagram support.
|
|
28
|
+
*
|
|
29
|
+
* - `true`: auto-detect Mermaid packages and enable support when available
|
|
30
|
+
* - `false`: disable Mermaid integration entirely
|
|
31
|
+
* - `object`: merge custom Mermaid options with Northwestern defaults
|
|
32
|
+
*/
|
|
33
|
+
mermaid: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
34
|
+
/**
|
|
35
|
+
* Open Graph image generation.
|
|
36
|
+
*
|
|
37
|
+
* Generates a branded 1200x630 image for each docs page when `site`
|
|
38
|
+
* is configured in `astro.config.ts`.
|
|
39
|
+
*/
|
|
40
|
+
ogImage: z.ZodOptional<z.ZodBoolean>;
|
|
41
|
+
}, z.core.$strict>;
|
|
42
|
+
/**
|
|
43
|
+
* Configuration options for the standalone Northwestern Mermaid integration.
|
|
44
|
+
*
|
|
45
|
+
* This intentionally validates only the Northwestern-owned wrapper surface and
|
|
46
|
+
* allows additional upstream `astro-mermaid` options to pass through unchanged.
|
|
47
|
+
*/
|
|
48
|
+
export declare const northwesternMermaidOptionsSchema: z.ZodObject<{
|
|
49
|
+
/**
|
|
50
|
+
* Show the hover toolbar on rendered diagrams.
|
|
51
|
+
*
|
|
52
|
+
* The toolbar provides fullscreen, download, and copy-source actions.
|
|
53
|
+
*/
|
|
54
|
+
toolbar: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
}, z.core.$loose>;
|
|
56
|
+
/**
|
|
57
|
+
* Configuration options for `defineNorthwesternConfig()`.
|
|
58
|
+
*
|
|
59
|
+
* This schema validates the Northwestern-owned wrapper surface while allowing
|
|
60
|
+
* the rest of Astro's top-level config to pass through untouched.
|
|
61
|
+
*/
|
|
62
|
+
export declare const northwesternConfigOptionsSchema: z.ZodObject<{
|
|
63
|
+
/**
|
|
64
|
+
* Full Starlight configuration object.
|
|
65
|
+
*
|
|
66
|
+
* This is forwarded to `starlight()` after Northwestern defaults and
|
|
67
|
+
* helper-managed integration ordering are applied.
|
|
68
|
+
*/
|
|
69
|
+
starlight: z.ZodObject<{}, z.core.$loose>;
|
|
70
|
+
/**
|
|
71
|
+
* Northwestern theme plugin options.
|
|
72
|
+
*/
|
|
73
|
+
theme: z.ZodOptional<z.ZodObject<{
|
|
74
|
+
/**
|
|
75
|
+
* Homepage hero layout configuration.
|
|
76
|
+
*/
|
|
77
|
+
homepage: z.ZodOptional<z.ZodObject<{
|
|
78
|
+
layout: z.ZodOptional<z.ZodEnum<{
|
|
79
|
+
centered: "centered";
|
|
80
|
+
split: "split";
|
|
81
|
+
}>>;
|
|
82
|
+
showTitle: z.ZodOptional<z.ZodBoolean>;
|
|
83
|
+
imageWidth: z.ZodOptional<z.ZodString>;
|
|
84
|
+
}, z.core.$strict>>;
|
|
85
|
+
/**
|
|
86
|
+
* Mermaid diagram support.
|
|
87
|
+
*
|
|
88
|
+
* - `true`: auto-detect Mermaid packages and enable support when available
|
|
89
|
+
* - `false`: disable Mermaid integration entirely
|
|
90
|
+
* - `object`: merge custom Mermaid options with Northwestern defaults
|
|
91
|
+
*/
|
|
92
|
+
mermaid: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
93
|
+
/**
|
|
94
|
+
* Open Graph image generation.
|
|
95
|
+
*
|
|
96
|
+
* Generates a branded 1200x630 image for each docs page when `site`
|
|
97
|
+
* is configured in `astro.config.ts`.
|
|
98
|
+
*/
|
|
99
|
+
ogImage: z.ZodOptional<z.ZodBoolean>;
|
|
100
|
+
}, z.core.$strict>>;
|
|
101
|
+
/**
|
|
102
|
+
* Mermaid diagram support.
|
|
103
|
+
*
|
|
104
|
+
* - `true`: add Northwestern Mermaid with defaults
|
|
105
|
+
* - `false`: disable Mermaid
|
|
106
|
+
* - `object`: add Northwestern Mermaid with custom options
|
|
107
|
+
*/
|
|
108
|
+
mermaid: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
109
|
+
/**
|
|
110
|
+
* Show the hover toolbar on rendered diagrams.
|
|
111
|
+
*
|
|
112
|
+
* The toolbar provides fullscreen, download, and copy-source actions.
|
|
113
|
+
*/
|
|
114
|
+
toolbar: z.ZodOptional<z.ZodBoolean>;
|
|
115
|
+
}, z.core.$loose>]>>;
|
|
116
|
+
/**
|
|
117
|
+
* Additional Starlight plugins to register after the Northwestern theme.
|
|
118
|
+
*/
|
|
119
|
+
plugins: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
120
|
+
/**
|
|
121
|
+
* Escape hatch for advanced integration ordering.
|
|
122
|
+
*
|
|
123
|
+
* Use `before` for integrations that must run before Mermaid/Starlight,
|
|
124
|
+
* and `after` for integrations that should be appended after Starlight.
|
|
125
|
+
*/
|
|
126
|
+
integrations: z.ZodOptional<z.ZodObject<{
|
|
127
|
+
/**
|
|
128
|
+
* Integrations added before Mermaid and Starlight.
|
|
129
|
+
*/
|
|
130
|
+
before: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
131
|
+
/**
|
|
132
|
+
* Integrations added after Starlight.
|
|
133
|
+
*/
|
|
134
|
+
after: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
|
|
135
|
+
}, z.core.$strict>>;
|
|
136
|
+
}, z.core.$loose>;
|
|
137
|
+
/**
|
|
138
|
+
* Validate a public config object and throw a friendly package-scoped error on failure.
|
|
139
|
+
*/
|
|
140
|
+
export declare function validateSchema<T>(schema: z.ZodType<T>, value: unknown, scope: string): T;
|
|
141
|
+
//# sourceMappingURL=config-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../src/config-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,aAIoD,CAAC;AA6DtF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B;IAElC;;OAEG;;;;;;;;;IAKH;;;;;;OAMG;;IASH;;;;;OAKG;;kBAOL,CAAC;AAEP;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC;IAErC;;;;OAIG;;iBAQL,CAAC;AAEP;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B;IAEpC;;;;;OAKG;;IAKH;;OAEG;;QA9EH;;WAEG;;;;;;;;;QAKH;;;;;;WAMG;;QASH;;;;;WAKG;;;IAwDH;;;;;;OAMG;;QA7CH;;;;WAIG;;;IA+CH;;OAEG;;IAKH;;;;;OAKG;;QAGK;;WAEG;;QAKH;;WAEG;;;iBAYb,CAAC;AA2BP;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAQxF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rehype plugin that wraps `<table>` elements in a scrollable container at build time.
|
|
3
|
+
*
|
|
4
|
+
* Inserts a `<div class="nu-table-scroll">` around each table with `tabindex="0"`,
|
|
5
|
+
* `role="region"`, and `aria-label` for keyboard scrollability. Runs during the
|
|
6
|
+
* Astro build so the HTML arrives with the wrapper already in place.
|
|
7
|
+
*/
|
|
8
|
+
import type { Root } from "hast";
|
|
9
|
+
export default function rehypeTableScroll(): (tree: Root) => void;
|
|
10
|
+
//# sourceMappingURL=rehype-table-scroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rehype-table-scroll.d.ts","sourceRoot":"","sources":["../../src/rehype-table-scroll.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAkB,IAAI,EAAE,MAAM,MAAM,CAAC;AAgCjD,MAAM,CAAC,OAAO,UAAU,iBAAiB,KAC7B,MAAM,IAAI,UACrB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { StarlightExpressiveCodeOptions } from "@astrojs/starlight/expressive-code";
|
|
2
|
+
import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pre-configured Expressive Code options for the Northwestern Starlight theme.
|
|
6
|
+
*
|
|
7
|
+
* Adds the line-numbers plugin and sets sensible defaults. Pass your own
|
|
8
|
+
* options to merge with the Northwestern defaults.
|
|
9
|
+
*
|
|
10
|
+
* **Note:** `defineNorthwesternConfig` includes these options.
|
|
11
|
+
* This helper is only needed for manual setups using `northwesternTheme()` directly.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* // ec.config.mjs (manual setup only)
|
|
16
|
+
* import { defineEcConfig } from "@astrojs/starlight/expressive-code";
|
|
17
|
+
* import { northwesternExpressiveCode } from "@nu-appdev/northwestern-starlight-theme/expressive-code";
|
|
18
|
+
*
|
|
19
|
+
* export default defineEcConfig(northwesternExpressiveCode());
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function northwesternExpressiveCode(
|
|
23
|
+
config: StarlightExpressiveCodeOptions = {},
|
|
24
|
+
): StarlightExpressiveCodeOptions {
|
|
25
|
+
const { defaultProps, plugins, ...rest } = config;
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
...rest,
|
|
29
|
+
plugins: [pluginLineNumbers(), ...(plugins ?? [])],
|
|
30
|
+
defaultProps: {
|
|
31
|
+
showLineNumbers: false,
|
|
32
|
+
...(defaultProps ?? {}),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
package/index.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { copyFileSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
3
4
|
import { dirname, join } from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import type { StarlightPlugin } from "@astrojs/starlight/types";
|
|
6
|
-
import
|
|
7
|
+
import { nonEmptyStringSchema, northwesternThemeConfigSchema, validateSchema } from "./src/config-schema";
|
|
8
|
+
import rehypeTableScroll from "./src/rehype-table-scroll";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Configuration for the homepage hero section.
|
|
@@ -53,21 +55,16 @@ export interface NorthwesternHomepageConfig {
|
|
|
53
55
|
/**
|
|
54
56
|
* Top-level configuration for the Northwestern Starlight theme plugin.
|
|
55
57
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
+
* With `defineNorthwesternConfig`, pass these as the `theme` key.
|
|
59
|
+
* With `northwesternTheme()` directly, pass them as the function argument.
|
|
60
|
+
* All properties are optional.
|
|
58
61
|
*
|
|
59
62
|
* @example
|
|
60
63
|
* ```ts
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* integrations: [
|
|
66
|
-
* starlight({
|
|
67
|
-
* plugins: [northwesternTheme({ homepage: { layout: "split" } })],
|
|
68
|
-
* }),
|
|
69
|
-
* ],
|
|
70
|
-
* });
|
|
64
|
+
* defineNorthwesternConfig({
|
|
65
|
+
* starlight: { title: "My Docs" },
|
|
66
|
+
* theme: { homepage: { layout: "split" } },
|
|
67
|
+
* })
|
|
71
68
|
* ```
|
|
72
69
|
*
|
|
73
70
|
* @see {@link NorthwesternHomepageConfig} for homepage hero options
|
|
@@ -86,12 +83,35 @@ export interface NorthwesternThemeConfig {
|
|
|
86
83
|
* - `true` (default) — auto-detect: enables Mermaid if `astro-mermaid` and `mermaid`
|
|
87
84
|
* are installed, skips silently if they are not
|
|
88
85
|
* - `false` — disables Mermaid entirely
|
|
89
|
-
* - `object` — enables Mermaid with custom
|
|
90
|
-
* merged with Northwestern defaults
|
|
86
|
+
* - `object` — enables Mermaid with custom Mermaid config merged with Northwestern defaults
|
|
91
87
|
*
|
|
92
88
|
* @default true
|
|
93
89
|
*/
|
|
94
90
|
mermaid?: boolean | Record<string, unknown>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Open Graph image generation.
|
|
94
|
+
*
|
|
95
|
+
* Generates branded OG images (1200x630 PNG) for every docs page with the
|
|
96
|
+
* page title and description on a Northwestern purple background.
|
|
97
|
+
*
|
|
98
|
+
* Requires `site` to be set in `astro.config.ts` for absolute image URLs.
|
|
99
|
+
*
|
|
100
|
+
* @default true
|
|
101
|
+
*/
|
|
102
|
+
ogImage?: boolean;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getSiteTitle(title: unknown): string {
|
|
106
|
+
const parsedTitle = nonEmptyStringSchema.safeParse(title);
|
|
107
|
+
if (parsedTitle.success) return parsedTitle.data;
|
|
108
|
+
if (title && typeof title === "object") {
|
|
109
|
+
for (const value of Object.values(title as Record<string, unknown>)) {
|
|
110
|
+
const parsedValue = nonEmptyStringSchema.safeParse(value);
|
|
111
|
+
if (parsedValue.success) return parsedValue.data;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return "";
|
|
95
115
|
}
|
|
96
116
|
|
|
97
117
|
/**
|
|
@@ -116,10 +136,14 @@ const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
|
|
|
116
136
|
* component overrides (Hero, ThemeToggle, EditLink), and optional Mermaid diagram
|
|
117
137
|
* support with branded color schemes.
|
|
118
138
|
*
|
|
139
|
+
* **Recommended:** Use {@link https://github.com/NUAppDev/northwestern-starlight-theme | defineNorthwesternConfig}
|
|
140
|
+
* from `@nu-appdev/northwestern-starlight-theme/config` instead. It handles
|
|
141
|
+
* integration ordering, Mermaid, and Expressive Code (line numbers, GitHub themes).
|
|
142
|
+
*
|
|
119
143
|
* @param config - Theme configuration. All properties optional.
|
|
120
144
|
* @returns A Starlight plugin to pass to `plugins` in your Starlight config.
|
|
121
145
|
*
|
|
122
|
-
* @example
|
|
146
|
+
* @example Manual setup
|
|
123
147
|
* ```ts
|
|
124
148
|
* starlight({ plugins: [northwesternTheme()] })
|
|
125
149
|
* ```
|
|
@@ -137,19 +161,35 @@ const RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
|
|
|
137
161
|
* ```
|
|
138
162
|
*/
|
|
139
163
|
export default function northwesternTheme(config: NorthwesternThemeConfig = {}): StarlightPlugin {
|
|
140
|
-
const {
|
|
164
|
+
const {
|
|
165
|
+
homepage = {},
|
|
166
|
+
mermaid = true,
|
|
167
|
+
ogImage = true,
|
|
168
|
+
} = validateSchema(northwesternThemeConfigSchema, config, "theme config");
|
|
141
169
|
const themeConfig = {
|
|
142
170
|
homepage: {
|
|
143
171
|
layout: homepage.layout ?? "centered",
|
|
144
172
|
showTitle: homepage.showTitle ?? true,
|
|
145
173
|
imageWidth: homepage.imageWidth ?? "500px",
|
|
146
174
|
},
|
|
175
|
+
ogImage: {
|
|
176
|
+
enabled: false, // set to true in config:setup when ogImage is enabled
|
|
177
|
+
siteTitle: "",
|
|
178
|
+
logoPath: "",
|
|
179
|
+
resvgWasmPath: "",
|
|
180
|
+
},
|
|
147
181
|
};
|
|
148
182
|
|
|
149
183
|
return {
|
|
150
184
|
name: "northwestern-starlight-theme",
|
|
151
185
|
hooks: {
|
|
152
|
-
async "config:setup"({
|
|
186
|
+
async "config:setup"({
|
|
187
|
+
config: starlightConfig,
|
|
188
|
+
updateConfig,
|
|
189
|
+
addIntegration,
|
|
190
|
+
addRouteMiddleware,
|
|
191
|
+
logger,
|
|
192
|
+
}) {
|
|
153
193
|
// Apply default favicon if consumer hasn't set one
|
|
154
194
|
const consumerSetFavicon =
|
|
155
195
|
starlightConfig.favicon &&
|
|
@@ -244,6 +284,53 @@ export default function northwesternTheme(config: NorthwesternThemeConfig = {}):
|
|
|
244
284
|
}
|
|
245
285
|
}
|
|
246
286
|
|
|
287
|
+
// OG image generation (bundled via satori + @resvg/resvg-wasm)
|
|
288
|
+
if (ogImage) {
|
|
289
|
+
const siteTitle = getSiteTitle(starlightConfig.title);
|
|
290
|
+
|
|
291
|
+
if (!siteTitle) {
|
|
292
|
+
logger.warn(
|
|
293
|
+
"Open Graph image generation was disabled because Starlight `title` is empty.\n" +
|
|
294
|
+
" Set `title` in starlight({...}) so OG images and structured data have a site name.",
|
|
295
|
+
);
|
|
296
|
+
} else {
|
|
297
|
+
themeConfig.ogImage.logoPath = faviconPath;
|
|
298
|
+
themeConfig.ogImage.siteTitle = siteTitle;
|
|
299
|
+
|
|
300
|
+
addRouteMiddleware({
|
|
301
|
+
entrypoint: "@nu-appdev/northwestern-starlight-theme/src/og/route-middleware",
|
|
302
|
+
order: "post",
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
addIntegration({
|
|
306
|
+
name: "northwestern-theme-og-image",
|
|
307
|
+
hooks: {
|
|
308
|
+
"astro:config:setup": ({ config: astroConfig, injectRoute }) => {
|
|
309
|
+
if (!astroConfig.site) {
|
|
310
|
+
logger.warn(
|
|
311
|
+
"Open Graph image generation was disabled because `site` is not set.\n" +
|
|
312
|
+
" Set `site` in astro.config.ts to enable absolute OG image URLs.",
|
|
313
|
+
);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
themeConfig.ogImage.enabled = true;
|
|
318
|
+
const require = createRequire(import.meta.url);
|
|
319
|
+
themeConfig.ogImage.resvgWasmPath = require.resolve(
|
|
320
|
+
"@resvg/resvg-wasm/index_bg.wasm",
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
injectRoute({
|
|
324
|
+
pattern: "/og/[...slug]",
|
|
325
|
+
entrypoint: "@nu-appdev/northwestern-starlight-theme/src/og/endpoint.ts",
|
|
326
|
+
});
|
|
327
|
+
logger.info("OG image generation enabled");
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
247
334
|
updateConfig({
|
|
248
335
|
...(consumerSetFavicon ? {} : { favicon: "/favicon.png" }),
|
|
249
336
|
components: {
|
package/mermaid.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AstroIntegration } from "astro";
|
|
2
|
-
import
|
|
2
|
+
import type { AstroMermaidOptions } from "astro-mermaid";
|
|
3
3
|
import { darken, isDark, lighten, mix, transparentize } from "khroma";
|
|
4
|
+
import { northwesternMermaidOptionsSchema, validateSchema } from "./src/config-schema";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Configuration options for the Northwestern Mermaid integration.
|
|
@@ -417,6 +418,9 @@ export const darkMermaidConfig: AstroMermaidOptions = createNorthwesternMermaidC
|
|
|
417
418
|
* Wraps `astro-mermaid` with Northwestern color palettes for both light and dark
|
|
418
419
|
* modes, and injects the toolbar script (fullscreen viewer, download, copy).
|
|
419
420
|
*
|
|
421
|
+
* **Note:** `defineNorthwesternConfig` handles Mermaid integration ordering.
|
|
422
|
+
* This function is only needed for manual setups.
|
|
423
|
+
*
|
|
420
424
|
* **Must be added before `starlight()` in the `integrations` array.** The
|
|
421
425
|
* `astro-mermaid` remark plugin needs to register before Starlight's rehype
|
|
422
426
|
* processing, and Astro processes integrations in order. Placing it after
|
|
@@ -426,7 +430,7 @@ export const darkMermaidConfig: AstroMermaidOptions = createNorthwesternMermaidC
|
|
|
426
430
|
* disable the hover toolbar.
|
|
427
431
|
* @returns An Astro integration to add to `integrations` in your Astro config.
|
|
428
432
|
*
|
|
429
|
-
* @example
|
|
433
|
+
* @example Manual setup
|
|
430
434
|
* ```ts
|
|
431
435
|
* import { northwesternMermaid } from "@nu-appdev/northwestern-starlight-theme/mermaid";
|
|
432
436
|
* import northwesternTheme from "@nu-appdev/northwestern-starlight-theme";
|
|
@@ -443,7 +447,11 @@ export const darkMermaidConfig: AstroMermaidOptions = createNorthwesternMermaidC
|
|
|
443
447
|
* ```
|
|
444
448
|
*/
|
|
445
449
|
export function northwesternMermaid(options: NorthwesternMermaidOptions = {}): AstroIntegration {
|
|
446
|
-
const { toolbar = true, ...overrides } =
|
|
450
|
+
const { toolbar = true, ...overrides } = validateSchema(
|
|
451
|
+
northwesternMermaidOptionsSchema,
|
|
452
|
+
options,
|
|
453
|
+
"Mermaid config",
|
|
454
|
+
);
|
|
447
455
|
const lightConfig = createNorthwesternMermaidConfig("light");
|
|
448
456
|
const darkConfig = createNorthwesternMermaidConfig("dark");
|
|
449
457
|
|
|
@@ -463,19 +471,21 @@ export function northwesternMermaid(options: NorthwesternMermaidOptions = {}): A
|
|
|
463
471
|
|
|
464
472
|
const mergedLightMermaidConfig = mergeWithOverrides(lightConfig.mermaidConfig as Record<string, unknown>);
|
|
465
473
|
const mergedDarkMermaidConfig = mergeWithOverrides(darkConfig.mermaidConfig as Record<string, unknown>);
|
|
466
|
-
|
|
467
|
-
const mermaidIntegration = mermaid({
|
|
468
|
-
...lightConfig,
|
|
469
|
-
...overrides,
|
|
470
|
-
enableLog: false,
|
|
471
|
-
mermaidConfig: mergedLightMermaidConfig,
|
|
472
|
-
});
|
|
474
|
+
const mermaidModulePromise = import("astro-mermaid");
|
|
473
475
|
|
|
474
476
|
return {
|
|
475
477
|
name: "northwestern-mermaid",
|
|
476
478
|
hooks: {
|
|
477
|
-
"astro:config:setup"(params) {
|
|
478
|
-
|
|
479
|
+
async "astro:config:setup"(params) {
|
|
480
|
+
const { default: mermaid } = await mermaidModulePromise;
|
|
481
|
+
const mermaidIntegration = mermaid({
|
|
482
|
+
...lightConfig,
|
|
483
|
+
...overrides,
|
|
484
|
+
enableLog: false,
|
|
485
|
+
mermaidConfig: mergedLightMermaidConfig,
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
await mermaidIntegration.hooks["astro:config:setup"]?.(params);
|
|
479
489
|
|
|
480
490
|
params.injectScript(
|
|
481
491
|
"page",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nu-appdev/northwestern-starlight-theme",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A Northwestern-branded theme for Astro Starlight",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Danny Foster <danny@northwestern.edu>",
|
|
@@ -28,14 +28,19 @@
|
|
|
28
28
|
},
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
|
-
"types": "./index.ts",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
32
|
"import": "./index.ts"
|
|
33
33
|
},
|
|
34
34
|
"./expressive-code": {
|
|
35
|
-
"
|
|
35
|
+
"types": "./dist/expressive-code.d.ts",
|
|
36
|
+
"import": "./expressive-code.ts"
|
|
37
|
+
},
|
|
38
|
+
"./config": {
|
|
39
|
+
"types": "./dist/config.d.ts",
|
|
40
|
+
"import": "./config.ts"
|
|
36
41
|
},
|
|
37
42
|
"./mermaid": {
|
|
38
|
-
"types": "./mermaid.ts",
|
|
43
|
+
"types": "./dist/mermaid.d.ts",
|
|
39
44
|
"import": "./mermaid.ts"
|
|
40
45
|
},
|
|
41
46
|
"./components": {
|
|
@@ -44,19 +49,25 @@
|
|
|
44
49
|
},
|
|
45
50
|
"./src/styles/components/*": "./src/styles/components/*",
|
|
46
51
|
"./src/components/*": "./src/components/*",
|
|
52
|
+
"./src/og/*": "./src/og/*",
|
|
47
53
|
"./src/scripts/*": "./src/scripts/*",
|
|
48
54
|
"./src/styles/*": "./src/styles/*"
|
|
49
55
|
},
|
|
50
56
|
"files": [
|
|
51
57
|
"CHANGELOG.md",
|
|
52
|
-
"
|
|
58
|
+
"dist/",
|
|
59
|
+
"config.ts",
|
|
60
|
+
"expressive-code.ts",
|
|
53
61
|
"index.ts",
|
|
54
62
|
"mermaid.ts",
|
|
55
63
|
"src/"
|
|
56
64
|
],
|
|
57
65
|
"dependencies": {
|
|
58
66
|
"@expressive-code/plugin-line-numbers": "^0.41.7",
|
|
59
|
-
"
|
|
67
|
+
"@resvg/resvg-wasm": "^2.6.2",
|
|
68
|
+
"khroma": "^2.1.0",
|
|
69
|
+
"satori": "^0.26.0",
|
|
70
|
+
"zod": "^4.3.6"
|
|
60
71
|
},
|
|
61
72
|
"peerDependencies": {
|
|
62
73
|
"@astrojs/starlight": ">=0.32.0",
|
|
@@ -73,6 +84,10 @@
|
|
|
73
84
|
}
|
|
74
85
|
},
|
|
75
86
|
"devDependencies": {
|
|
76
|
-
"@types/hast": "^3.0.4"
|
|
87
|
+
"@types/hast": "^3.0.4",
|
|
88
|
+
"typescript": "^6.0.2"
|
|
89
|
+
},
|
|
90
|
+
"scripts": {
|
|
91
|
+
"build": "tsc -p tsconfig.build.json --noCheck"
|
|
77
92
|
}
|
|
78
93
|
}
|