@dominikcz/greg 0.9.27

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.
Files changed (183) hide show
  1. package/README.md +397 -0
  2. package/bin/greg.js +241 -0
  3. package/bin/init.js +351 -0
  4. package/bin/templates/docs/getting-started.md +47 -0
  5. package/bin/templates/docs/index.md +11 -0
  6. package/bin/templates/greg.config.js +39 -0
  7. package/bin/templates/greg.config.ts +38 -0
  8. package/bin/templates/index.html +16 -0
  9. package/bin/templates/src/App.svelte +5 -0
  10. package/bin/templates/src/app.css +20 -0
  11. package/bin/templates/src/main.js +9 -0
  12. package/bin/templates/svelte.config.js +1 -0
  13. package/bin/templates/tsconfig.json +21 -0
  14. package/bin/templates/vite.config.js +23 -0
  15. package/docs/__partials/markdown/examples/basic.md +4 -0
  16. package/docs/__partials/markdown/examples/diff.md +10 -0
  17. package/docs/__partials/markdown/examples/focus.md +5 -0
  18. package/docs/__partials/markdown/examples/language-title.md +3 -0
  19. package/docs/__partials/markdown/examples/line-highlighting.md +5 -0
  20. package/docs/__partials/markdown/examples/line-numbers.md +5 -0
  21. package/docs/__partials/note.md +4 -0
  22. package/docs/guide/__shared-warning.md +4 -0
  23. package/docs/guide/asset-handling.md +88 -0
  24. package/docs/guide/deploying.md +162 -0
  25. package/docs/guide/getting-started.md +334 -0
  26. package/docs/guide/index.md +23 -0
  27. package/docs/guide/localization.md +290 -0
  28. package/docs/guide/markdown/code.md +95 -0
  29. package/docs/guide/markdown/components-and-mermaid.md +43 -0
  30. package/docs/guide/markdown/containers.md +110 -0
  31. package/docs/guide/markdown/header-anchors.md +34 -0
  32. package/docs/guide/markdown/includes.md +84 -0
  33. package/docs/guide/markdown/index.md +20 -0
  34. package/docs/guide/markdown/inline-attributes.md +21 -0
  35. package/docs/guide/markdown/links-and-toc.md +64 -0
  36. package/docs/guide/markdown/math.md +54 -0
  37. package/docs/guide/markdown/syntax-highlighting.md +75 -0
  38. package/docs/guide/routing.md +150 -0
  39. package/docs/guide/using-svelte.md +88 -0
  40. package/docs/guide/versioning.md +281 -0
  41. package/docs/incompatibilities.md +48 -0
  42. package/docs/index.md +43 -0
  43. package/docs/reference/badge.md +100 -0
  44. package/docs/reference/carbon-ads.md +46 -0
  45. package/docs/reference/code-group.md +126 -0
  46. package/docs/reference/home-page.md +232 -0
  47. package/docs/reference/index.md +18 -0
  48. package/docs/reference/markdowndocs.md +275 -0
  49. package/docs/reference/outline.md +79 -0
  50. package/docs/reference/search.md +263 -0
  51. package/docs/reference/steps.md +200 -0
  52. package/docs/reference/team-page.md +189 -0
  53. package/docs/reference/theme.md +150 -0
  54. package/fakeDocsGenerator/generate_docs.js +310 -0
  55. package/package.json +92 -0
  56. package/scripts/build-versions.js +609 -0
  57. package/scripts/generate-static.js +79 -0
  58. package/scripts/render-markdown.js +420 -0
  59. package/src/lib/MarkdownDocs/AiChat.svelte +936 -0
  60. package/src/lib/MarkdownDocs/BackToTop.svelte +68 -0
  61. package/src/lib/MarkdownDocs/Breadcrumb.svelte +68 -0
  62. package/src/lib/MarkdownDocs/DocsNavigation.svelte +149 -0
  63. package/src/lib/MarkdownDocs/DocsSiteHeader.svelte +758 -0
  64. package/src/lib/MarkdownDocs/DocsVersionSwitcher.svelte +103 -0
  65. package/src/lib/MarkdownDocs/MarkdownDocs.svelte +2115 -0
  66. package/src/lib/MarkdownDocs/MarkdownRenderer.svelte +487 -0
  67. package/src/lib/MarkdownDocs/Outline.svelte +238 -0
  68. package/src/lib/MarkdownDocs/PrevNext.svelte +115 -0
  69. package/src/lib/MarkdownDocs/SearchModal.svelte +1241 -0
  70. package/src/lib/MarkdownDocs/TreeView.svelte +32 -0
  71. package/src/lib/MarkdownDocs/TreeViewItem.svelte +219 -0
  72. package/src/lib/MarkdownDocs/VersionOutdatedNotice.svelte +72 -0
  73. package/src/lib/MarkdownDocs/__tests__/codeDirectives.test.js +54 -0
  74. package/src/lib/MarkdownDocs/__tests__/common.test.js +41 -0
  75. package/src/lib/MarkdownDocs/__tests__/docsExamplesLint.test.js +77 -0
  76. package/src/lib/MarkdownDocs/__tests__/fixtures/docs/markdown/__partial-basic.md +3 -0
  77. package/src/lib/MarkdownDocs/__tests__/fixtures/docs/markdown/snippet.js +9 -0
  78. package/src/lib/MarkdownDocs/__tests__/fixtures/includes/part.md +11 -0
  79. package/src/lib/MarkdownDocs/__tests__/fixtures/includes/wrapper.md +5 -0
  80. package/src/lib/MarkdownDocs/__tests__/fixtures/snippets/sample.js +8 -0
  81. package/src/lib/MarkdownDocs/__tests__/fixtures/snippets/sample.md +5 -0
  82. package/src/lib/MarkdownDocs/__tests__/helpers.js +67 -0
  83. package/src/lib/MarkdownDocs/__tests__/localeUtils.test.js +204 -0
  84. package/src/lib/MarkdownDocs/__tests__/markdown.test.js +704 -0
  85. package/src/lib/MarkdownDocs/__tests__/markdownRendererRuntime.test.js +65 -0
  86. package/src/lib/MarkdownDocs/__tests__/searchIndexBuilder.test.js +117 -0
  87. package/src/lib/MarkdownDocs/__tests__/sqliteStore.test.js +202 -0
  88. package/src/lib/MarkdownDocs/__tests__/useRouter.test.js +16 -0
  89. package/src/lib/MarkdownDocs/ai/adapters/customAdapter.js +14 -0
  90. package/src/lib/MarkdownDocs/ai/adapters/customAdapter.ts +43 -0
  91. package/src/lib/MarkdownDocs/ai/adapters/ollamaAdapter.js +81 -0
  92. package/src/lib/MarkdownDocs/ai/adapters/ollamaAdapter.ts +116 -0
  93. package/src/lib/MarkdownDocs/ai/adapters/openaiAdapter.js +92 -0
  94. package/src/lib/MarkdownDocs/ai/adapters/openaiAdapter.ts +137 -0
  95. package/src/lib/MarkdownDocs/ai/aiProvider.ts +31 -0
  96. package/src/lib/MarkdownDocs/ai/characters.js +52 -0
  97. package/src/lib/MarkdownDocs/ai/characters.ts +69 -0
  98. package/src/lib/MarkdownDocs/ai/chunkStore.ts +25 -0
  99. package/src/lib/MarkdownDocs/ai/chunker.js +85 -0
  100. package/src/lib/MarkdownDocs/ai/chunker.ts +135 -0
  101. package/src/lib/MarkdownDocs/ai/docLinker.js +26 -0
  102. package/src/lib/MarkdownDocs/ai/docLinker.ts +36 -0
  103. package/src/lib/MarkdownDocs/ai/promptBuilder.js +33 -0
  104. package/src/lib/MarkdownDocs/ai/promptBuilder.ts +53 -0
  105. package/src/lib/MarkdownDocs/ai/ragPipeline.js +54 -0
  106. package/src/lib/MarkdownDocs/ai/ragPipeline.ts +106 -0
  107. package/src/lib/MarkdownDocs/ai/stores/memoryStore.js +88 -0
  108. package/src/lib/MarkdownDocs/ai/stores/memoryStore.ts +112 -0
  109. package/src/lib/MarkdownDocs/ai/stores/sqliteStore.ts +372 -0
  110. package/src/lib/MarkdownDocs/ai/types.ts +71 -0
  111. package/src/lib/MarkdownDocs/aiServer.js +288 -0
  112. package/src/lib/MarkdownDocs/codeDirectives.js +191 -0
  113. package/src/lib/MarkdownDocs/codeFenceInfo.js +45 -0
  114. package/src/lib/MarkdownDocs/codeGroup.ts +46 -0
  115. package/src/lib/MarkdownDocs/common.ts +47 -0
  116. package/src/lib/MarkdownDocs/docsUtils.js +281 -0
  117. package/src/lib/MarkdownDocs/index.plugins.js +22 -0
  118. package/src/lib/MarkdownDocs/layouts/LayoutDoc.svelte +8 -0
  119. package/src/lib/MarkdownDocs/layouts/LayoutHome.svelte +58 -0
  120. package/src/lib/MarkdownDocs/layouts/LayoutPage.svelte +9 -0
  121. package/src/lib/MarkdownDocs/loadGregConfig.js +82 -0
  122. package/src/lib/MarkdownDocs/localeUtils.ts +682 -0
  123. package/src/lib/MarkdownDocs/markdownRendererRuntime.ts +314 -0
  124. package/src/lib/MarkdownDocs/mermaidThemes.js +319 -0
  125. package/src/lib/MarkdownDocs/navigationUtils.js +22 -0
  126. package/src/lib/MarkdownDocs/rehypeCodeGroup.js +326 -0
  127. package/src/lib/MarkdownDocs/rehypeCodeTitle.js +96 -0
  128. package/src/lib/MarkdownDocs/rehypeToc.js +170 -0
  129. package/src/lib/MarkdownDocs/remarkCodeMeta.js +22 -0
  130. package/src/lib/MarkdownDocs/remarkContainers.js +329 -0
  131. package/src/lib/MarkdownDocs/remarkCustomAnchors.js +42 -0
  132. package/src/lib/MarkdownDocs/remarkEscapeSvelte.js +33 -0
  133. package/src/lib/MarkdownDocs/remarkGlobalComponents.js +65 -0
  134. package/src/lib/MarkdownDocs/remarkImports.js +461 -0
  135. package/src/lib/MarkdownDocs/remarkImportsBrowser.js +349 -0
  136. package/src/lib/MarkdownDocs/remarkInlineAttrs.js +95 -0
  137. package/src/lib/MarkdownDocs/remarkMathToHtml.js +138 -0
  138. package/src/lib/MarkdownDocs/searchIndexBuilder.js +497 -0
  139. package/src/lib/MarkdownDocs/searchServer.js +263 -0
  140. package/src/lib/MarkdownDocs/treeViewTypes.ts +11 -0
  141. package/src/lib/MarkdownDocs/useRouter.svelte.ts +114 -0
  142. package/src/lib/MarkdownDocs/useSplitter.svelte.ts +33 -0
  143. package/src/lib/MarkdownDocs/versioningDefaults.js +20 -0
  144. package/src/lib/MarkdownDocs/vitePluginAiServer.js +204 -0
  145. package/src/lib/MarkdownDocs/vitePluginCopyDocs.js +153 -0
  146. package/src/lib/MarkdownDocs/vitePluginFrontmatter.js +109 -0
  147. package/src/lib/MarkdownDocs/vitePluginGregConfig.js +108 -0
  148. package/src/lib/MarkdownDocs/vitePluginSearchIndex.js +57 -0
  149. package/src/lib/MarkdownDocs/vitePluginSearchServer.js +190 -0
  150. package/src/lib/components/Badge.svelte +59 -0
  151. package/src/lib/components/Button.svelte +138 -0
  152. package/src/lib/components/CarbonAds.svelte +99 -0
  153. package/src/lib/components/CodeGroup.svelte +102 -0
  154. package/src/lib/components/Feature.svelte +209 -0
  155. package/src/lib/components/Features.svelte +123 -0
  156. package/src/lib/components/Hero.svelte +399 -0
  157. package/src/lib/components/Image.svelte +128 -0
  158. package/src/lib/components/Link.svelte +105 -0
  159. package/src/lib/components/SocialLink.svelte +84 -0
  160. package/src/lib/components/SocialLinks.svelte +33 -0
  161. package/src/lib/components/Steps.svelte +143 -0
  162. package/src/lib/components/TeamMember.svelte +273 -0
  163. package/src/lib/components/TeamMembers.svelte +81 -0
  164. package/src/lib/components/TeamPage.svelte +65 -0
  165. package/src/lib/components/TeamPageSection.svelte +108 -0
  166. package/src/lib/components/TeamPageTitle.svelte +89 -0
  167. package/src/lib/components/index.js +24 -0
  168. package/src/lib/portal/context.js +12 -0
  169. package/src/lib/portal/index.js +3 -0
  170. package/src/lib/portal/portal.svelte +14 -0
  171. package/src/lib/portal/slot.svelte +8 -0
  172. package/src/lib/scss/__code.scss +128 -0
  173. package/src/lib/scss/__containers.scss +99 -0
  174. package/src/lib/scss/__markdown.scss +447 -0
  175. package/src/lib/scss/__scrollbar.scss +60 -0
  176. package/src/lib/scss/__steps.scss +100 -0
  177. package/src/lib/scss/__theme.scss +238 -0
  178. package/src/lib/scss/__toc.scss +55 -0
  179. package/src/lib/scss/__utilities.scss +7 -0
  180. package/src/lib/scss/greg.scss +9 -0
  181. package/src/lib/spinner/spinner.svelte +42 -0
  182. package/svelte.config.js +146 -0
  183. package/types/index.d.ts +456 -0
@@ -0,0 +1,314 @@
1
+ import remarkParse from "remark-parse";
2
+ import remarkGfm from "remark-gfm";
3
+ import remarkRehype from "remark-rehype";
4
+ import rehypeStringify from "rehype-stringify";
5
+ import rehypeSlug from "rehype-slug";
6
+ import rehypeAutolinkHeadings from "rehype-autolink-headings";
7
+
8
+ import { rehypeTocPlaceholder } from "./rehypeToc.js";
9
+ import { remarkContainers, rehypeContainers } from "./remarkContainers.js";
10
+ import rehypeCodeGroup from "./rehypeCodeGroup.js";
11
+ import rehypeCodeTitle from "./rehypeCodeTitle.js";
12
+ import { remarkCodeMeta } from "./remarkCodeMeta.js";
13
+ import { remarkCustomAnchors } from "./remarkCustomAnchors.js";
14
+ import { remarkInlineAttrs } from "./remarkInlineAttrs.js";
15
+ import { remarkImportsBrowser } from "./remarkImportsBrowser.js";
16
+
17
+ import Badge from "../components/Badge.svelte";
18
+ import Button from "../components/Button.svelte";
19
+ import Image from "../components/Image.svelte";
20
+ import Link from "../components/Link.svelte";
21
+ import CodeGroup from "../components/CodeGroup.svelte";
22
+ import Hero from "../components/Hero.svelte";
23
+ import Features from "../components/Features.svelte";
24
+ import TeamMembers from "../components/TeamMembers.svelte";
25
+
26
+ export type PluginEntry = {
27
+ name: string;
28
+ plugin: any;
29
+ options?: Record<string, any>;
30
+ };
31
+
32
+ export type PropsBuilder = (el: HTMLElement) => Record<string, any>;
33
+
34
+ export type ComponentHydrationEntry = {
35
+ component: any;
36
+ buildProps: PropsBuilder;
37
+ selector?: string;
38
+ };
39
+
40
+ export type RenderHandlerContext = {
41
+ mermaidThemeConfig: Record<string, unknown>;
42
+ };
43
+
44
+ export type RenderHandler = {
45
+ name: string;
46
+ run: (
47
+ root: HTMLElement,
48
+ context: RenderHandlerContext,
49
+ ) => void | Promise<void>;
50
+ };
51
+
52
+ const HEADER_AUTOLINK_OPTIONS = {
53
+ behavior: "prepend",
54
+ properties: {
55
+ class: "header-anchor",
56
+ ariaHidden: "true",
57
+ tabIndex: -1,
58
+ },
59
+ content: { type: "text", value: "#" },
60
+ };
61
+
62
+ export function buildPropsFromAttributes(
63
+ el: HTMLElement,
64
+ ): Record<string, string> {
65
+ const props: Record<string, string> = {};
66
+ for (const attr of Array.from(el.attributes)) {
67
+ props[attr.name] = attr.value;
68
+ }
69
+ // If Badge / Button has text children but no text prop, pass textContent.
70
+ if (!props.text && el.textContent?.trim()) {
71
+ props.text = el.textContent.trim();
72
+ }
73
+ return props;
74
+ }
75
+
76
+ export function parseCodeGroupProps(el: HTMLElement) {
77
+ const tabsRaw = el.getAttribute("data-codegroup-tabs") ?? "[]";
78
+ let tabs: string[] = [];
79
+ try {
80
+ const parsed = JSON.parse(tabsRaw);
81
+ if (Array.isArray(parsed)) {
82
+ tabs = parsed.map((value) => String(value));
83
+ }
84
+ } catch {
85
+ tabs = [];
86
+ }
87
+
88
+ const blocks = Array.from(el.querySelectorAll(":scope > .rcg-block")).map(
89
+ (block) => (block as HTMLElement).innerHTML,
90
+ );
91
+
92
+ if (!tabs.length) {
93
+ tabs = blocks.map((_value, index) => `Tab ${index + 1}`);
94
+ }
95
+
96
+ const initialActive = Number(el.getAttribute("data-codegroup-active") ?? "0");
97
+
98
+ return {
99
+ tabs,
100
+ blocks,
101
+ initialActive: Number.isFinite(initialActive) ? initialActive : 0,
102
+ };
103
+ }
104
+
105
+ function parseJsonAttribute<T>(
106
+ el: HTMLElement,
107
+ attribute: string,
108
+ fallback: T,
109
+ ): T {
110
+ const raw = el.getAttribute(attribute);
111
+ if (!raw) return fallback;
112
+ try {
113
+ return JSON.parse(raw) as T;
114
+ } catch {
115
+ return fallback;
116
+ }
117
+ }
118
+
119
+ function parseHeroProps(el: HTMLElement) {
120
+ const props = buildPropsFromAttributes(el);
121
+ const {
122
+ ["data-hydrate"]: _dataHydrate,
123
+ ["data-hero-image"]: _heroImage,
124
+ ["data-hero-actions"]: _heroActions,
125
+ ...plainProps
126
+ } = props;
127
+ const image = parseJsonAttribute(el, "data-hero-image", undefined);
128
+ const actions = parseJsonAttribute(el, "data-hero-actions", [] as any[]);
129
+ return {
130
+ ...plainProps,
131
+ ...(image ? { image } : {}),
132
+ actions,
133
+ };
134
+ }
135
+
136
+ function parseFeaturesProps(el: HTMLElement) {
137
+ const features = parseJsonAttribute(el, "data-features", [] as any[]);
138
+ return { features };
139
+ }
140
+
141
+ function parseTeamMembersProps(el: HTMLElement) {
142
+ const props = buildPropsFromAttributes(el);
143
+ const {
144
+ ["data-hydrate"]: _dataHydrate,
145
+ ["data-members"]: _members,
146
+ ["members"]: _membersLegacy,
147
+ ...plainProps
148
+ } = props;
149
+ const members = parseJsonAttribute(
150
+ el,
151
+ "data-members",
152
+ parseJsonAttribute(el, "members", [] as any[]),
153
+ );
154
+ return {
155
+ ...plainProps,
156
+ members,
157
+ };
158
+ }
159
+
160
+ export const COMPONENT_REGISTRY: Record<string, ComponentHydrationEntry> = {
161
+ badge: {
162
+ component: Badge,
163
+ buildProps: buildPropsFromAttributes,
164
+ },
165
+ button: {
166
+ component: Button,
167
+ buildProps: buildPropsFromAttributes,
168
+ },
169
+ image: {
170
+ component: Image,
171
+ buildProps: buildPropsFromAttributes,
172
+ },
173
+ link: {
174
+ component: Link,
175
+ buildProps: buildPropsFromAttributes,
176
+ },
177
+ codegroup: {
178
+ component: CodeGroup,
179
+ buildProps: parseCodeGroupProps,
180
+ },
181
+ hero: {
182
+ component: Hero,
183
+ buildProps: parseHeroProps,
184
+ selector: "hero, [data-hydrate=hero]",
185
+ },
186
+ features: {
187
+ component: Features,
188
+ buildProps: parseFeaturesProps,
189
+ selector: "features, [data-hydrate=features]",
190
+ },
191
+ teammembers: {
192
+ component: TeamMembers,
193
+ buildProps: parseTeamMembersProps,
194
+ selector: "teammembers, [data-hydrate=teammembers]",
195
+ },
196
+ };
197
+
198
+ export function getRuntimeRenderHandlers(deps: {
199
+ hydrateComponents: (root: HTMLElement) => void;
200
+ initMermaid: (
201
+ root: HTMLElement,
202
+ themeConfig: Record<string, unknown>,
203
+ ) => void | Promise<void>;
204
+ }): RenderHandler[] {
205
+ return [
206
+ {
207
+ name: "hydrate-components",
208
+ run: (root) => deps.hydrateComponents(root),
209
+ },
210
+ {
211
+ name: "init-mermaid",
212
+ run: (root, context) =>
213
+ deps.initMermaid(root, context.mermaidThemeConfig),
214
+ },
215
+ ];
216
+ }
217
+
218
+ export function getThemeChangeRenderHandlers(deps: {
219
+ rerenderMermaid: (
220
+ root: HTMLElement,
221
+ themeConfig: Record<string, unknown>,
222
+ ) => void | Promise<void>;
223
+ }): RenderHandler[] {
224
+ return [
225
+ {
226
+ name: "rerender-mermaid",
227
+ run: (root, context) =>
228
+ deps.rerenderMermaid(root, context.mermaidThemeConfig),
229
+ },
230
+ ];
231
+ }
232
+
233
+ export async function runRenderHandlers(
234
+ root: HTMLElement,
235
+ handlers: RenderHandler[],
236
+ context: RenderHandlerContext,
237
+ ) {
238
+ for (const handler of handlers) {
239
+ try {
240
+ await handler.run(root, context);
241
+ } catch {
242
+ // Individual handler failures should not block other handlers.
243
+ continue;
244
+ }
245
+ }
246
+ }
247
+
248
+ export function getRemarkPluginEntries(
249
+ currentBaseUrl: string,
250
+ currentDocsPrefix: string,
251
+ ): PluginEntry[] {
252
+ return [
253
+ { name: "remark-parse", plugin: remarkParse },
254
+ { name: "remark-gfm", plugin: remarkGfm },
255
+ { name: "remark-inline-attrs", plugin: remarkInlineAttrs },
256
+ {
257
+ name: "remark-imports-browser",
258
+ plugin: remarkImportsBrowser,
259
+ options: {
260
+ baseUrl: currentBaseUrl,
261
+ docsPrefix: currentDocsPrefix,
262
+ },
263
+ },
264
+ { name: "remark-code-meta", plugin: remarkCodeMeta },
265
+ { name: "remark-containers", plugin: remarkContainers },
266
+ {
267
+ name: "remark-custom-anchors",
268
+ plugin: remarkCustomAnchors,
269
+ },
270
+ {
271
+ name: "remark-rehype",
272
+ plugin: remarkRehype,
273
+ options: { allowDangerousHtml: true },
274
+ },
275
+ ];
276
+ }
277
+
278
+ export function getRehypePluginEntries(deps: {
279
+ rehypeStepsWrapper: any;
280
+ rehypeMermaid: any;
281
+ rehypeShiki: any;
282
+ }): PluginEntry[] {
283
+ return [
284
+ { name: "rehype-slug", plugin: rehypeSlug },
285
+ {
286
+ name: "rehype-autolink-headings",
287
+ plugin: rehypeAutolinkHeadings,
288
+ options: HEADER_AUTOLINK_OPTIONS,
289
+ },
290
+ { name: "rehype-steps-wrapper", plugin: deps.rehypeStepsWrapper },
291
+ { name: "rehype-mermaid", plugin: deps.rehypeMermaid },
292
+ { name: "rehype-shiki", plugin: deps.rehypeShiki },
293
+ { name: "rehype-containers", plugin: rehypeContainers },
294
+ { name: "rehype-code-group", plugin: rehypeCodeGroup },
295
+ { name: "rehype-code-title", plugin: rehypeCodeTitle },
296
+ { name: "rehype-toc-placeholder", plugin: rehypeTocPlaceholder },
297
+ {
298
+ name: "rehype-stringify",
299
+ plugin: rehypeStringify,
300
+ options: { allowDangerousHtml: true },
301
+ },
302
+ ];
303
+ }
304
+
305
+ export function applyPluginEntries(processor: any, entries: PluginEntry[]) {
306
+ for (const entry of entries) {
307
+ if (entry.options) {
308
+ processor.use(entry.plugin, entry.options);
309
+ continue;
310
+ }
311
+ processor.use(entry.plugin);
312
+ }
313
+ return processor;
314
+ }
@@ -0,0 +1,319 @@
1
+ /**
2
+ * mermaidThemes.js
3
+ *
4
+ * Built-in Mermaid diagram theme definitions.
5
+ * Each entry maps to a `MermaidConfig` object accepted by `mermaid.initialize()`.
6
+ *
7
+ * Colours inside `themeCSS` use CSS custom-property tokens (--mmd-*)
8
+ * defined in greg.scss, so diagrams react to Greg's light/dark
9
+ * mode via the CSS cascade — no JS re-render required for colour changes.
10
+ *
11
+ * `themeVariables` are baked into the SVG at render-time.
12
+ * MarkdownRenderer swaps between `material` (light) and `material-dark`
13
+ * when `colorTheme` changes, triggering a full SVG re-render so that
14
+ * background and internal mermaid colour math are also correct.
15
+ *
16
+ * Material theme design inspired by https://github.com/gotoailab/modern_mermaid
17
+ */
18
+
19
+ // ── Shared Material themeCSS ─────────────────────────────────────────────────
20
+ // Used by both `material` (light) and `material-dark`.
21
+ // All colour values are CSS variable references resolved at paint-time.
22
+
23
+ const MATERIAL_CSS = `
24
+ /* ── Flowchart nodes ──────────────────────────────────── */
25
+ .node rect, .node circle, .node polygon {
26
+ fill: var(--mmd-node-bg) !important;
27
+ stroke: none !important;
28
+ rx: 4px !important; ry: 4px !important;
29
+ filter: var(--mmd-shadow-sm);
30
+ }
31
+ .node .label {
32
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
33
+ font-weight: 500;
34
+ fill: var(--mmd-text) !important;
35
+ font-size: 14px;
36
+ }
37
+ .edgePath .path {
38
+ stroke: var(--mmd-line) !important; stroke-width: 2px !important;
39
+ stroke-linecap: round;
40
+ }
41
+ .arrowheadPath { fill: var(--mmd-line) !important; stroke: var(--mmd-line) !important; }
42
+ .edgeLabel {
43
+ background-color: var(--mmd-node-bg) !important;
44
+ color: var(--mmd-text) !important;
45
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
46
+ font-weight: 500; font-size: 13px;
47
+ }
48
+
49
+ /* ── Sequence diagram ─────────────────────────────────── */
50
+ .actor rect, g.actor rect, rect.actor {
51
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
52
+ rx: 4px !important; ry: 4px !important;
53
+ filter: var(--mmd-shadow-sm) !important;
54
+ }
55
+ .actor { fill: var(--mmd-node-bg) !important; stroke: none !important; }
56
+ g.actor { filter: var(--mmd-shadow-sm); }
57
+ .actor text {
58
+ fill: var(--mmd-text) !important;
59
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 500;
60
+ }
61
+ .actor-line {
62
+ stroke: var(--mmd-actor-line) !important; stroke-width: 2px !important;
63
+ stroke-dasharray: 4 4 !important;
64
+ }
65
+ .activation0, .activation1, .activation2,
66
+ rect.activation0, rect.activation1, rect.activation2 {
67
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
68
+ filter: var(--mmd-shadow-sm) !important;
69
+ }
70
+ .messageLine0, .messageLine1 {
71
+ stroke: var(--mmd-line) !important; stroke-width: 2px !important;
72
+ }
73
+ .messageText {
74
+ fill: var(--mmd-text) !important;
75
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
76
+ font-weight: 500; font-size: 13px;
77
+ }
78
+ #arrowhead path, .arrowheadPath {
79
+ fill: var(--mmd-line) !important; stroke: var(--mmd-line) !important;
80
+ }
81
+
82
+ /* Note boxes */
83
+ .note, rect.note, g.note rect {
84
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
85
+ rx: 4px !important; ry: 4px !important;
86
+ filter: var(--mmd-shadow-md) !important;
87
+ }
88
+ .noteText, text.noteText {
89
+ fill: var(--mmd-text) !important;
90
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 500;
91
+ }
92
+
93
+ /* Loop / Alt / Opt boxes */
94
+ .labelBox {
95
+ fill: var(--mmd-node-bg) !important; stroke: var(--mmd-border) !important;
96
+ stroke-width: 1px !important; rx: 4px !important; ry: 4px !important;
97
+ }
98
+ .labelText, .loopText, text.labelText, text.loopText {
99
+ fill: var(--mmd-text) !important;
100
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 500;
101
+ }
102
+ .loopLine { stroke: var(--mmd-actor-line) !important; stroke-width: 2px !important; }
103
+
104
+ /* ── Cluster / Subgraph ───────────────────────────────── */
105
+ .cluster rect {
106
+ fill: var(--mmd-node-bg) !important; stroke: var(--mmd-border) !important;
107
+ stroke-width: 1px !important; rx: 8px !important; ry: 8px !important;
108
+ filter: var(--mmd-shadow-sm);
109
+ }
110
+ .cluster text {
111
+ fill: var(--mmd-text-sub) !important;
112
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
113
+ font-weight: 500; text-transform: uppercase; letter-spacing: 1px; font-size: 12px;
114
+ }
115
+
116
+ /* ── Class diagram ────────────────────────────────────── */
117
+ .classGroup rect, g.classGroup rect,
118
+ g[id*="classid"] rect, g[id^="classid"] rect,
119
+ svg[aria-roledescription="classDiagram"] g.classGroup rect {
120
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
121
+ rx: 4px !important; ry: 4px !important;
122
+ filter: var(--mmd-shadow-sm) !important;
123
+ }
124
+ .classLabel .label, .classLabel text, .class-label text {
125
+ fill: var(--mmd-text) !important;
126
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 500;
127
+ }
128
+ .relationshipLine, .relation { stroke: var(--mmd-line) !important; stroke-width: 2px !important; }
129
+ .divider { stroke: var(--mmd-border) !important; stroke-width: 1px !important; }
130
+
131
+ /* ── State diagram ────────────────────────────────────── */
132
+ g[id*="state-"] rect, g[id^="state-"] rect, g.stateGroup rect,
133
+ .statediagram-state rect, .statediagram-state .state-inner, g[class*="state"] rect,
134
+ svg[aria-roledescription="statediagram"] g rect:not(circle):not([id*="start"]):not([id*="end"]) {
135
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
136
+ rx: 4px !important; ry: 4px !important;
137
+ filter: var(--mmd-shadow-sm) !important;
138
+ }
139
+ .start-state circle, .end-state circle, circle[id*="start"], circle[id*="end"] {
140
+ fill: var(--mmd-accent-1) !important; stroke: none !important;
141
+ filter: var(--mmd-shadow-acc1);
142
+ }
143
+ .statediagram-state circle { stroke: none !important; }
144
+ .stateLabel text, .statediagram-state text, .state-note text {
145
+ fill: var(--mmd-text) !important;
146
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 500;
147
+ }
148
+ .transition, path.transition { stroke: var(--mmd-line) !important; stroke-width: 2px !important; }
149
+ g.stateGroup.statediagram-cluster rect {
150
+ fill: var(--mmd-node-bg) !important; stroke: var(--mmd-border) !important;
151
+ stroke-width: 1px !important; rx: 8px !important; ry: 8px !important;
152
+ }
153
+
154
+ /* ── ER diagram ───────────────────────────────────────── */
155
+ .er.entityBox, .entityBox, g[id*="entity-"] rect, g[id^="entity"] rect,
156
+ svg[aria-roledescription="er"] .entityBox, svg[aria-roledescription="er"] g rect {
157
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
158
+ rx: 4px !important; ry: 4px !important;
159
+ filter: var(--mmd-shadow-sm) !important;
160
+ }
161
+ .er .attributeBoxEven, .er .attributeBoxOdd {
162
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
163
+ }
164
+
165
+ /* ── Gantt chart ──────────────────────────────────────── */
166
+ .titleText, text.titleText {
167
+ fill: var(--mmd-text) !important;
168
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
169
+ font-weight: 500; text-transform: uppercase; letter-spacing: 1.25px;
170
+ }
171
+ .sectionTitle, text.sectionTitle {
172
+ fill: var(--mmd-text-sub) !important;
173
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 500;
174
+ }
175
+ .taskText, .taskTextOutsideRight, .taskTextOutsideLeft, text.taskText {
176
+ fill: var(--mmd-text) !important;
177
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 400;
178
+ }
179
+ .task0, .task1, .task2, .task3, rect.task, rect[class*="task"],
180
+ svg[aria-roledescription="gantt"] rect.task, g.task rect {
181
+ stroke: none !important; rx: 4px !important;
182
+ filter: var(--mmd-shadow-sm) !important;
183
+ }
184
+ .taskText0, .taskText1, .taskText2, .taskText3 { fill: var(--mmd-text) !important; }
185
+ .grid .tick line { stroke: var(--mmd-border) !important; }
186
+ .grid path { stroke: none !important; }
187
+
188
+ /* ── Pie chart ────────────────────────────────────────── */
189
+ .pieCircle, circle.pieCircle { stroke: none !important; }
190
+ .pieTitleText, text.pieTitleText {
191
+ fill: var(--mmd-text) !important;
192
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
193
+ font-weight: 500; text-transform: uppercase; letter-spacing: 1.25px;
194
+ }
195
+ .legendText, text.legendText, text.legend {
196
+ fill: var(--mmd-text) !important;
197
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif; font-weight: 400;
198
+ }
199
+ .slice, path.slice, svg[aria-roledescription="pie"] path {
200
+ stroke: var(--mmd-canvas) !important; stroke-width: 2px !important;
201
+ filter: var(--mmd-shadow-sm) !important;
202
+ }
203
+ .pieChart .slice0 { fill: var(--mmd-accent-1) !important; }
204
+ .pieChart .slice1 { fill: var(--mmd-accent-2) !important; }
205
+ .pieChart .slice2 { fill: var(--mmd-accent-3) !important; }
206
+ .pieChart .slice3 { fill: var(--mmd-accent-4) !important; }
207
+ .pieChart .slice4 { fill: var(--mmd-accent-5) !important; }
208
+ .pieChart .slice5 { fill: var(--mmd-accent-6) !important; }
209
+
210
+ /* ── Journey diagram ──────────────────────────────────── */
211
+ .section0, .section1, .section2 {
212
+ fill: var(--mmd-node-bg) !important; stroke: none !important;
213
+ rx: 4px !important; filter: var(--mmd-shadow-sm);
214
+ }
215
+ .journey-section rect { rx: 4px !important; }
216
+
217
+ /* ── XYChart ──────────────────────────────────────────── */
218
+ .line-plot-0 path { stroke: var(--mmd-accent-1) !important; stroke-width: 3px !important; stroke-linecap: round; }
219
+ .line-plot-1 path { stroke: var(--mmd-accent-2) !important; stroke-width: 3px !important; stroke-linecap: round; }
220
+ .line-plot-2 path { stroke: var(--mmd-accent-3) !important; stroke-width: 3px !important; stroke-linecap: round; }
221
+ .bar-plot-0 rect { fill: var(--mmd-accent-1) !important; stroke: none !important; rx: 4px !important; filter: var(--mmd-shadow-sm); }
222
+ .bar-plot-1 rect { fill: var(--mmd-accent-2) !important; stroke: none !important; rx: 4px !important; filter: var(--mmd-shadow-sm); }
223
+ .bar-plot-2 rect { fill: var(--mmd-accent-3) !important; stroke: none !important; rx: 4px !important; filter: var(--mmd-shadow-sm); }
224
+ .ticks path { stroke: var(--mmd-border) !important; }
225
+ .chart-title text {
226
+ fill: var(--mmd-text) !important; font-weight: 500 !important; font-size: 18px !important;
227
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
228
+ text-transform: uppercase; letter-spacing: 1.25px;
229
+ }
230
+ .left-axis .label text, .bottom-axis .label text {
231
+ fill: var(--mmd-text-sub) !important; font-size: 13px !important;
232
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
233
+ }
234
+ .left-axis .title text, .bottom-axis .title text {
235
+ fill: var(--mmd-text) !important; font-size: 14px !important; font-weight: 500;
236
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
237
+ }
238
+ .legend text {
239
+ fill: var(--mmd-text) !important; font-size: 13px !important;
240
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
241
+ }
242
+
243
+ /* ── Global text fallback ─────────────────────────────── */
244
+ text {
245
+ fill: var(--mmd-text) !important;
246
+ font-family: "Roboto","Noto Sans SC",-apple-system,sans-serif;
247
+ }
248
+ `;
249
+
250
+ // ── Theme registry ────────────────────────────────────────────────────────────
251
+
252
+ /** @type {Record<string, import('mermaid').MermaidConfig>} */
253
+ export const MERMAID_THEMES = {
254
+ /**
255
+ * Material Design – light variant.
256
+ * White card surfaces, Roboto typography.
257
+ * Colours resolved from --mmd-* CSS tokens at paint-time.
258
+ */
259
+ material: {
260
+ theme: 'base',
261
+ themeVariables: {
262
+ background: '#ffffff',
263
+ primaryColor: '#ffffff',
264
+ primaryTextColor: 'rgba(0, 0, 0, 0.87)',
265
+ primaryBorderColor: '#e0e0e0',
266
+ lineColor: '#757575',
267
+ secondaryColor: '#ffffff',
268
+ tertiaryColor: '#ffffff',
269
+ fontFamily: '"Roboto", "Noto Sans SC", -apple-system, sans-serif',
270
+ fontSize: '14px',
271
+ },
272
+ themeCSS: MATERIAL_CSS,
273
+ },
274
+
275
+ /**
276
+ * Material Design – dark variant.
277
+ * Deep-navy surfaces (#2d2d44), elevated accent palette.
278
+ * themeCSS is identical to `material`; colours adapt automatically via
279
+ * --mmd-* tokens redefined under .greg[data-theme="dark"].
280
+ */
281
+ 'material-dark': {
282
+ theme: 'base',
283
+ themeVariables: {
284
+ darkMode: true,
285
+ background: '#1e1e2e',
286
+ primaryColor: '#2d2d44',
287
+ primaryTextColor: 'rgba(255, 255, 255, 0.87)',
288
+ primaryBorderColor: '#3e3e5a',
289
+ lineColor: '#9090b8',
290
+ secondaryColor: '#2d2d44',
291
+ tertiaryColor: '#2d2d44',
292
+ fontFamily: '"Roboto", "Noto Sans SC", -apple-system, sans-serif',
293
+ fontSize: '14px',
294
+ },
295
+ themeCSS: MATERIAL_CSS,
296
+ },
297
+ };
298
+
299
+ /** The theme key used when no explicit theme is requested. */
300
+ export const DEFAULT_MERMAID_THEME = 'material';
301
+
302
+ /**
303
+ * Returns the best available theme key for the requested colour scheme.
304
+ *
305
+ * When `colorTheme === 'dark'`, tries `baseTheme + '-dark'` first.
306
+ * Falls back to `baseTheme` if the dark variant is not present in `themes`.
307
+ *
308
+ * @param {string} baseTheme - e.g. 'material'
309
+ * @param {'light'|'dark'|undefined} colorTheme
310
+ * @param {Record<string,unknown>} themes - the merged theme map
311
+ * @returns {string}
312
+ */
313
+ export function getColorSchemeTheme(baseTheme, colorTheme, themes) {
314
+ if (colorTheme === 'dark') {
315
+ const darkKey = `${baseTheme}-dark`;
316
+ if (darkKey in themes) return darkKey;
317
+ }
318
+ return baseTheme;
319
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Toggle a section on any section-row click and navigate to section index
3
+ * when the section has an index page.
4
+ */
5
+ export function handleSectionClick(item, key, toggleSection, navigate) {
6
+ const EXTERNAL_RE = /^(?:[a-z][a-z\d+\-.]*:|\/\/)/i;
7
+
8
+ toggleSection(key);
9
+ if (item?.type === 'md' && item?.link) {
10
+ if (item.target === '_blank') {
11
+ window.open(item.link, '_blank', 'noopener,noreferrer');
12
+ return;
13
+ }
14
+
15
+ if (EXTERNAL_RE.test(item.link)) {
16
+ window.location.assign(item.link);
17
+ return;
18
+ }
19
+
20
+ navigate(item.link);
21
+ }
22
+ }