@tiramisu-docs/kit 0.1.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.
Files changed (99) hide show
  1. package/README.md +103 -0
  2. package/components.json +14 -0
  3. package/dist/bin/mcp.d.ts +2 -0
  4. package/dist/bin/mcp.js +4 -0
  5. package/dist/config.d.ts +99 -0
  6. package/dist/config.js +36 -0
  7. package/dist/highlight.d.ts +10 -0
  8. package/dist/highlight.js +93 -0
  9. package/dist/index.d.ts +6 -0
  10. package/dist/index.js +3 -0
  11. package/dist/lib/components/index.d.ts +16 -0
  12. package/dist/lib/components/index.js +18 -0
  13. package/dist/lib/components/tiramisu/lang-icons.d.ts +4 -0
  14. package/dist/lib/components/tiramisu/lang-icons.js +77 -0
  15. package/dist/lib/components/ui/alert/index.d.ts +5 -0
  16. package/dist/lib/components/ui/alert/index.js +6 -0
  17. package/dist/lib/components/ui/badge/index.d.ts +2 -0
  18. package/dist/lib/components/ui/badge/index.js +1 -0
  19. package/dist/lib/components/ui/button/index.d.ts +4 -0
  20. package/dist/lib/components/ui/button/index.js +2 -0
  21. package/dist/lib/components/ui/card/index.d.ts +8 -0
  22. package/dist/lib/components/ui/card/index.js +10 -0
  23. package/dist/lib/components/ui/collapsible/index.d.ts +1 -0
  24. package/dist/lib/components/ui/collapsible/index.js +1 -0
  25. package/dist/lib/components/ui/dropdown-menu/index.d.ts +18 -0
  26. package/dist/lib/components/ui/dropdown-menu/index.js +18 -0
  27. package/dist/lib/components/ui/scroll-area/index.d.ts +1 -0
  28. package/dist/lib/components/ui/scroll-area/index.js +1 -0
  29. package/dist/lib/components/ui/separator/index.d.ts +1 -0
  30. package/dist/lib/components/ui/separator/index.js +1 -0
  31. package/dist/lib/components/ui/sheet/index.d.ts +3 -0
  32. package/dist/lib/components/ui/sheet/index.js +3 -0
  33. package/dist/lib/components/ui/tabs/index.d.ts +5 -0
  34. package/dist/lib/components/ui/tabs/index.js +7 -0
  35. package/dist/lib/open-links.d.ts +22 -0
  36. package/dist/lib/open-links.js +33 -0
  37. package/dist/lib/routes/docs/[...slug]/+page.d.ts +25 -0
  38. package/dist/lib/routes/docs/[...slug]/+page.js +109 -0
  39. package/dist/lib/utils.d.ts +5 -0
  40. package/dist/lib/utils.js +5 -0
  41. package/dist/mcp.d.ts +24 -0
  42. package/dist/mcp.js +155 -0
  43. package/dist/scan.d.ts +15 -0
  44. package/dist/scan.js +72 -0
  45. package/dist/seo.d.ts +63 -0
  46. package/dist/seo.js +160 -0
  47. package/dist/tiramisu-grammar.d.ts +2 -0
  48. package/dist/tiramisu-grammar.js +77 -0
  49. package/dist/types.d.ts +66 -0
  50. package/dist/types.js +1 -0
  51. package/dist/vite.d.ts +33 -0
  52. package/dist/vite.js +406 -0
  53. package/package.json +74 -0
  54. package/src/config.ts +133 -0
  55. package/src/highlight.ts +110 -0
  56. package/src/index.ts +6 -0
  57. package/src/lib/components/DocPage.svelte +430 -0
  58. package/src/lib/components/DocsLayout.svelte +145 -0
  59. package/src/lib/components/Footer.svelte +26 -0
  60. package/src/lib/components/Navbar.svelte +117 -0
  61. package/src/lib/components/PageFooter.svelte +63 -0
  62. package/src/lib/components/PrevNextNav.svelte +83 -0
  63. package/src/lib/components/SearchDialog.svelte +130 -0
  64. package/src/lib/components/Sidebar.svelte +237 -0
  65. package/src/lib/components/TableOfContents.svelte +50 -0
  66. package/src/lib/components/TopBar.svelte +407 -0
  67. package/src/lib/components/index.ts +19 -0
  68. package/src/lib/components/tiramisu/Accordion.svelte +16 -0
  69. package/src/lib/components/tiramisu/Badge.svelte +16 -0
  70. package/src/lib/components/tiramisu/Callout.svelte +26 -0
  71. package/src/lib/components/tiramisu/CodeBlock.svelte +56 -0
  72. package/src/lib/components/tiramisu/CodeTabs.svelte +123 -0
  73. package/src/lib/components/tiramisu/Demo.svelte +15 -0
  74. package/src/lib/components/tiramisu/FileTree.svelte +67 -0
  75. package/src/lib/components/tiramisu/MathBlock.svelte +26 -0
  76. package/src/lib/components/tiramisu/Mermaid.svelte +30 -0
  77. package/src/lib/components/tiramisu/NavCard.svelte +49 -0
  78. package/src/lib/components/tiramisu/Steps.svelte +60 -0
  79. package/src/lib/components/tiramisu/Tabs.svelte +87 -0
  80. package/src/lib/components/tiramisu/ZoomImage.svelte +114 -0
  81. package/src/lib/components/tiramisu/lang-icons.ts +81 -0
  82. package/src/lib/open-links.ts +50 -0
  83. package/src/lib/routes/docs/[...slug]/+page.svelte +26 -0
  84. package/src/lib/routes/docs/[...slug]/+page.ts +117 -0
  85. package/src/lib/styles/theme.css +222 -0
  86. package/src/lib/utils.ts +10 -0
  87. package/src/mcp.ts +180 -0
  88. package/src/scan.ts +92 -0
  89. package/src/seo.ts +193 -0
  90. package/src/tiramisu-grammar.ts +80 -0
  91. package/src/types.ts +71 -0
  92. package/src/virtual.d.ts +11 -0
  93. package/src/vite.ts +478 -0
  94. package/tests/config.test.ts +60 -0
  95. package/tests/mcp.test.ts +116 -0
  96. package/tests/scan.test.ts +48 -0
  97. package/tests/seo.test.ts +174 -0
  98. package/tests/vite.test.ts +283 -0
  99. package/tsconfig.json +19 -0
package/dist/vite.js ADDED
@@ -0,0 +1,406 @@
1
+ import { compileTiramisu } from "@tiramisu-docs/core";
2
+ import { execSync } from "node:child_process";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { highlightCodeBlocks } from "./highlight.js";
6
+ import { findTiramisuFiles, extractPlainText, titleCase } from "./scan.js";
7
+ /** Wrap compileTiramisu to produce Vite-friendly errors with file location */
8
+ function compileWithLocation(source, filePath) {
9
+ const dir = path.dirname(filePath);
10
+ try {
11
+ return compileTiramisu(source, {
12
+ resolveFile(src) {
13
+ const resolved = path.resolve(dir, src);
14
+ return fs.readFileSync(resolved, "utf-8");
15
+ },
16
+ });
17
+ }
18
+ catch (err) {
19
+ const isParseError = err instanceof Error && "line" in err;
20
+ if (isParseError) {
21
+ const parseErr = err;
22
+ const enhanced = new Error(parseErr.hint ?? parseErr.message);
23
+ Object.assign(enhanced, {
24
+ id: filePath,
25
+ loc: { file: filePath, line: parseErr.line, column: parseErr.column ?? 0 },
26
+ plugin: "tiramisu-docs",
27
+ });
28
+ if (parseErr.stack)
29
+ enhanced.stack = parseErr.stack;
30
+ throw enhanced;
31
+ }
32
+ throw err;
33
+ }
34
+ }
35
+ function resolveLastEdited(filePath, meta) {
36
+ if (meta.lastEdited)
37
+ return new Date(meta.lastEdited).toISOString();
38
+ try {
39
+ const stdout = execSync(`git log -1 --format=%cI "${filePath}"`, {
40
+ encoding: "utf-8",
41
+ stdio: ["pipe", "pipe", "pipe"],
42
+ }).trim();
43
+ if (stdout)
44
+ return new Date(stdout).toISOString();
45
+ }
46
+ catch { }
47
+ return fs.statSync(filePath).mtime.toISOString();
48
+ }
49
+ const VIRTUAL_MODULE_ID = "virtual:tiramisu-docs";
50
+ const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
51
+ const TIRAMISU_SVELTE_SUFFIX = ".tiramisu.svelte";
52
+ export function buildSidebarTree(docs, groupOrder = []) {
53
+ const groupMap = new Map();
54
+ function getOrCreateGroup(label) {
55
+ // Normalize lookup: case-insensitive match against existing groups
56
+ for (const [key, group] of groupMap) {
57
+ if (key.toLowerCase() === label.toLowerCase()) {
58
+ return group;
59
+ }
60
+ }
61
+ const group = { label, items: [] };
62
+ groupMap.set(label, group);
63
+ return group;
64
+ }
65
+ function getOrCreateSubgroup(parent, segment) {
66
+ const key = segment.toLowerCase();
67
+ const existing = parent.find((e) => e.type === "subgroup" && e.key === key);
68
+ if (existing)
69
+ return existing;
70
+ const sub = {
71
+ type: "subgroup",
72
+ key,
73
+ label: titleCase(segment),
74
+ items: [],
75
+ order: 999,
76
+ };
77
+ parent.push(sub);
78
+ return sub;
79
+ }
80
+ for (const doc of docs) {
81
+ const segments = doc.slug.split("/");
82
+ const item = {
83
+ type: "item",
84
+ title: doc.meta.title ?? doc.slug,
85
+ slug: doc.slug,
86
+ order: doc.meta.order ?? 999,
87
+ icon: doc.meta.icon,
88
+ };
89
+ if (segments.length === 1) {
90
+ // Root-level file: use meta.group
91
+ const groupLabel = doc.meta.group ?? "Docs";
92
+ const group = getOrCreateGroup(groupLabel);
93
+ group.items.push(item);
94
+ }
95
+ else {
96
+ // Nested file: first segment = group (static heading), deeper segments = subgroups
97
+ const groupLabel = titleCase(segments[0]);
98
+ const group = getOrCreateGroup(groupLabel);
99
+ const fileName = segments[segments.length - 1];
100
+ // Walk/create subgroups for middle segments (starting at segments[1])
101
+ let parent = group.items;
102
+ let lastSub = null;
103
+ for (let i = 1; i < segments.length - 1; i++) {
104
+ const sub = getOrCreateSubgroup(parent, segments[i]);
105
+ lastSub = sub;
106
+ parent = sub.items;
107
+ }
108
+ if (fileName === "index" && lastSub) {
109
+ // Deeper folder index → sets subgroup slug/label
110
+ lastSub.slug = item.slug;
111
+ if (item.order < lastSub.order)
112
+ lastSub.order = item.order;
113
+ if (item.title !== item.slug)
114
+ lastSub.label = item.title;
115
+ if (doc.meta.icon)
116
+ lastSub.icon = doc.meta.icon;
117
+ }
118
+ else if (fileName === "index" && !lastSub) {
119
+ // Top-level folder index (e.g. "integrations/index") → sets group label only
120
+ if (item.title !== item.slug) {
121
+ group.label = item.title;
122
+ }
123
+ if (doc.meta.icon)
124
+ group.icon = doc.meta.icon;
125
+ }
126
+ else {
127
+ parent.push(item);
128
+ }
129
+ }
130
+ }
131
+ // Sort entries recursively
132
+ function sortEntries(entries) {
133
+ for (const entry of entries) {
134
+ if (entry.type === "subgroup") {
135
+ sortEntries(entry.items);
136
+ // Derive subgroup order from its index page, or min child order
137
+ if (!entry.slug) {
138
+ const minOrder = entry.items.reduce((min, e) => {
139
+ const o = e.order;
140
+ return o < min ? o : min;
141
+ }, entry.order);
142
+ entry.order = minOrder;
143
+ }
144
+ }
145
+ }
146
+ entries.sort((a, b) => {
147
+ const ao = a.type === "item" ? a.order : a.order;
148
+ const bo = b.type === "item" ? b.order : b.order;
149
+ return ao - bo;
150
+ });
151
+ }
152
+ const sidebar = [];
153
+ for (const [, group] of groupMap) {
154
+ sortEntries(group.items);
155
+ sidebar.push({ label: group.label, items: group.items, icon: group.icon });
156
+ }
157
+ // Sort groups by groupOrder config
158
+ if (groupOrder.length > 0) {
159
+ sidebar.sort((a, b) => {
160
+ const ai = groupOrder.indexOf(a.label);
161
+ const bi = groupOrder.indexOf(b.label);
162
+ const ao = ai === -1 ? Infinity : ai;
163
+ const bo = bi === -1 ? Infinity : bi;
164
+ return ao - bo;
165
+ });
166
+ }
167
+ return sidebar;
168
+ }
169
+ export function buildSectionSidebars(docs, sections, implicitLabel) {
170
+ const allSectionPaths = flattenSectionPaths(sections);
171
+ const rootDocs = docs.filter((d) => !allSectionPaths.some((p) => d.slug === p || d.slug.startsWith(p + "/")));
172
+ const result = [];
173
+ if (rootDocs.length > 0) {
174
+ result.push({
175
+ label: implicitLabel ?? "Docs",
176
+ sidebar: buildSidebarTree(rootDocs),
177
+ });
178
+ }
179
+ for (const section of sections) {
180
+ result.push(resolveSection(docs, section));
181
+ }
182
+ return result;
183
+ }
184
+ function flattenSectionPaths(sections) {
185
+ const paths = [];
186
+ for (const s of sections) {
187
+ if (s.path)
188
+ paths.push(s.path);
189
+ if (s.children)
190
+ paths.push(...flattenSectionPaths(s.children));
191
+ }
192
+ return paths;
193
+ }
194
+ function resolveSection(docs, section) {
195
+ if (section.href) {
196
+ return { label: section.label, href: section.href, icon: section.icon };
197
+ }
198
+ if (section.children) {
199
+ return {
200
+ label: section.label,
201
+ icon: section.icon,
202
+ children: section.children.map((c) => resolveSection(docs, c)),
203
+ };
204
+ }
205
+ const sectionDocs = docs
206
+ .filter((d) => d.slug === section.path || d.slug.startsWith(section.path + "/"));
207
+ const sidebar = buildSidebarTree(sectionDocs);
208
+ return {
209
+ label: section.label,
210
+ path: section.path,
211
+ icon: section.icon,
212
+ sidebar,
213
+ };
214
+ }
215
+ export function buildLocaleData(allDocs, locales) {
216
+ const result = {};
217
+ for (const locale of locales) {
218
+ const prefix = locale.code + "/";
219
+ const docs = allDocs
220
+ .filter((d) => d.slug.startsWith(prefix))
221
+ .map((d) => ({ slug: d.slug.slice(prefix.length), meta: d.meta, headings: d.headings, lastEdited: d.lastEdited }));
222
+ result[locale.code] = { docs };
223
+ }
224
+ return result;
225
+ }
226
+ export function tiramisuPlugin(options = {}) {
227
+ const docsDir = options.docsDir ?? "src/docs";
228
+ const config = options.config;
229
+ const groupOrder = config?.sidebar?.groupOrder ?? [];
230
+ let viteRoot = process.cwd();
231
+ function resolveDocsDir() {
232
+ return path.resolve(viteRoot, docsDir);
233
+ }
234
+ function buildVirtualModule() {
235
+ const absDocsDir = resolveDocsDir();
236
+ const files = findTiramisuFiles(absDocsDir);
237
+ const docs = [];
238
+ for (const file of files) {
239
+ const source = fs.readFileSync(file, "utf-8");
240
+ const { meta, headings } = compileWithLocation(source, file);
241
+ const relativePath = path.relative(absDocsDir, file);
242
+ const slug = relativePath.replace(/\.tiramisu$/, "").replace(/\\/g, "/");
243
+ const lastEdited = resolveLastEdited(file, meta);
244
+ docs.push({ slug, meta, headings, lastEdited });
245
+ }
246
+ // Build search index with hierarchical group paths
247
+ function resolveSearchGroup(slug, meta) {
248
+ const segments = slug.split("/");
249
+ if (segments.length === 1)
250
+ return meta.group ?? "Docs";
251
+ return segments
252
+ .slice(0, -1)
253
+ .map(titleCase)
254
+ .join(" > ");
255
+ }
256
+ const searchIndex = docs.map((doc) => {
257
+ const file = path.resolve(absDocsDir, doc.slug + ".tiramisu");
258
+ const source = fs.readFileSync(file, "utf-8");
259
+ const { svelte } = compileWithLocation(source, file);
260
+ const text = extractPlainText(svelte);
261
+ return {
262
+ id: doc.slug,
263
+ title: doc.meta.title ?? doc.slug,
264
+ group: resolveSearchGroup(doc.slug, doc.meta),
265
+ slug: doc.slug,
266
+ headings: doc.headings.map((h) => h.text).join(" "),
267
+ text,
268
+ };
269
+ });
270
+ // Build dynamic imports — use .tiramisu.svelte suffix so resolveId maps them
271
+ const importsEntries = docs
272
+ .map((doc) => {
273
+ const absPath = path
274
+ .resolve(absDocsDir, doc.slug + ".tiramisu")
275
+ .replace(/\\/g, "/");
276
+ return ` "${doc.slug}": () => import("${absPath}")`;
277
+ })
278
+ .join(",\n");
279
+ if (config?.i18n) {
280
+ const localeData = buildLocaleData(docs, config.i18n.locales);
281
+ const localeBlocks = config.i18n.locales.map((locale) => {
282
+ const localeDocs = localeData[locale.code].docs;
283
+ const localeSections = config.sections
284
+ ? buildSectionSidebars(localeDocs, config.sections, config.title)
285
+ : undefined;
286
+ const localeSidebar = buildSidebarTree(localeDocs, groupOrder);
287
+ // Build locale-specific search index
288
+ const localeSearchIndex = localeDocs.map((doc) => {
289
+ const fullSlug = `${locale.code}/${doc.slug}`;
290
+ const file = path.resolve(absDocsDir, fullSlug + ".tiramisu");
291
+ const source = fs.readFileSync(file, "utf-8");
292
+ const { svelte } = compileWithLocation(source, file);
293
+ const text = extractPlainText(svelte);
294
+ return {
295
+ id: doc.slug,
296
+ title: doc.meta.title ?? doc.slug,
297
+ group: resolveSearchGroup(doc.slug, doc.meta),
298
+ slug: doc.slug,
299
+ headings: docs.find(d => d.slug === fullSlug)?.headings?.map(h => h.text).join(" ") ?? "",
300
+ text,
301
+ };
302
+ });
303
+ const localeImports = localeDocs
304
+ .map((doc) => {
305
+ const fullSlug = `${locale.code}/${doc.slug}`;
306
+ const absPath = path.resolve(absDocsDir, fullSlug + ".tiramisu").replace(/\\/g, "/");
307
+ return ` "${doc.slug}": () => import("${absPath}")`;
308
+ })
309
+ .join(",\n");
310
+ return ` "${locale.code}": {
311
+ sections: ${JSON.stringify(localeSections, null, 2)},
312
+ sidebar: ${JSON.stringify(localeSidebar, null, 2)},
313
+ docs: ${JSON.stringify(localeDocs, null, 2)},
314
+ searchIndex: ${JSON.stringify(localeSearchIndex)},
315
+ docImports: {\n${localeImports}\n },
316
+ }`;
317
+ }).join(",\n");
318
+ return [
319
+ `export const locales = {\n${localeBlocks}\n};`,
320
+ `export const defaultLocale = "${config.i18n.defaultLocale}";`,
321
+ `export const sidebar = locales["${config.i18n.defaultLocale}"].sidebar;`,
322
+ `export const sections = locales["${config.i18n.defaultLocale}"].sections;`,
323
+ `export const docs = locales["${config.i18n.defaultLocale}"].docs;`,
324
+ `export const searchIndex = locales["${config.i18n.defaultLocale}"].searchIndex;`,
325
+ `export const docImports = locales["${config.i18n.defaultLocale}"].docImports;`,
326
+ ].join("\n\n");
327
+ }
328
+ if (config?.sections) {
329
+ const resolvedSections = buildSectionSidebars(docs, config.sections, config.title);
330
+ return [
331
+ `export const locales = undefined;`,
332
+ `export const defaultLocale = undefined;`,
333
+ `export const sections = ${JSON.stringify(resolvedSections, null, 2)};`,
334
+ `export const sidebar = [];`,
335
+ `export const docs = ${JSON.stringify(docs, null, 2)};`,
336
+ `export const searchIndex = ${JSON.stringify(searchIndex)};`,
337
+ `export const docImports = {\n${importsEntries}\n};`,
338
+ ].join("\n\n");
339
+ }
340
+ else {
341
+ const sidebar = buildSidebarTree(docs, groupOrder);
342
+ return [
343
+ `export const locales = undefined;`,
344
+ `export const defaultLocale = undefined;`,
345
+ `export const sections = undefined;`,
346
+ `export const sidebar = ${JSON.stringify(sidebar, null, 2)};`,
347
+ `export const docs = ${JSON.stringify(docs, null, 2)};`,
348
+ `export const searchIndex = ${JSON.stringify(searchIndex)};`,
349
+ `export const docImports = {\n${importsEntries}\n};`,
350
+ ].join("\n\n");
351
+ }
352
+ }
353
+ return {
354
+ name: "tiramisu-docs",
355
+ enforce: "pre",
356
+ configResolved(config) {
357
+ viteRoot = config.root;
358
+ },
359
+ resolveId(id) {
360
+ if (id === VIRTUAL_MODULE_ID) {
361
+ return RESOLVED_VIRTUAL_MODULE_ID;
362
+ }
363
+ // Resolve .tiramisu imports to a virtual .svelte ID
364
+ // so the Svelte plugin processes the output
365
+ if (id.endsWith(".tiramisu")) {
366
+ const resolved = path.isAbsolute(id) ? id : path.resolve(viteRoot, id);
367
+ if (fs.existsSync(resolved)) {
368
+ return resolved + ".svelte";
369
+ }
370
+ }
371
+ return undefined;
372
+ },
373
+ async load(id) {
374
+ if (id === RESOLVED_VIRTUAL_MODULE_ID) {
375
+ return buildVirtualModule();
376
+ }
377
+ // Compile .tiramisu files to Svelte component source
378
+ // These come in as .tiramisu.svelte due to resolveId above
379
+ if (id.endsWith(TIRAMISU_SVELTE_SUFFIX)) {
380
+ const tiramisuPath = id.slice(0, -".svelte".length);
381
+ if (!fs.existsSync(tiramisuPath))
382
+ return undefined;
383
+ const source = fs.readFileSync(tiramisuPath, "utf-8");
384
+ const { svelte } = compileWithLocation(source, tiramisuPath);
385
+ return await highlightCodeBlocks(svelte);
386
+ }
387
+ return undefined;
388
+ },
389
+ handleHotUpdate(ctx) {
390
+ if (ctx.file.endsWith(".tiramisu")) {
391
+ // Invalidate the virtual module so sidebar/docs get rebuilt
392
+ const virtualMod = ctx.server.moduleGraph.getModuleById(RESOLVED_VIRTUAL_MODULE_ID);
393
+ if (virtualMod) {
394
+ ctx.server.moduleGraph.invalidateModule(virtualMod);
395
+ }
396
+ // Invalidate the compiled .svelte version too
397
+ const svelteMod = ctx.server.moduleGraph.getModuleById(ctx.file + ".svelte");
398
+ if (svelteMod) {
399
+ ctx.server.moduleGraph.invalidateModule(svelteMod);
400
+ }
401
+ ctx.server.ws.send({ type: "full-reload" });
402
+ return [];
403
+ }
404
+ },
405
+ };
406
+ }
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@tiramisu-docs/kit",
3
+ "version": "0.1.0",
4
+ "license": "Apache-2.0",
5
+ "type": "module",
6
+ "svelte": "src/index.ts",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "svelte": "./src/index.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./vite": {
16
+ "types": "./dist/vite.d.ts",
17
+ "default": "./dist/vite.js"
18
+ },
19
+ "./seo": {
20
+ "types": "./dist/seo.d.ts",
21
+ "default": "./dist/seo.js"
22
+ },
23
+ "./mcp": {
24
+ "types": "./dist/mcp.d.ts",
25
+ "default": "./dist/mcp.js"
26
+ },
27
+ "./components/*": {
28
+ "svelte": "./src/lib/components/*",
29
+ "default": "./src/lib/components/*"
30
+ },
31
+ "./styles/*": {
32
+ "default": "./src/lib/styles/*"
33
+ },
34
+ "./types": {
35
+ "types": "./dist/types.d.ts",
36
+ "default": "./dist/types.js"
37
+ },
38
+ "./utils": {
39
+ "types": "./src/lib/utils.ts",
40
+ "default": "./src/lib/utils.ts"
41
+ }
42
+ },
43
+ "scripts": {
44
+ "build": "tsc",
45
+ "prepublishOnly": "bun run build",
46
+ "test": "bun test"
47
+ },
48
+ "dependencies": {
49
+ "@timeleap/tiramisu": "^1.9.0",
50
+ "@tiramisu-docs/core": "workspace:*",
51
+ "clsx": "^2.1.1",
52
+ "iconify-icon": "^2.3.0",
53
+ "minisearch": "^7.2.0",
54
+ "katex": "^0.16.21",
55
+ "mermaid": "^11.6.0",
56
+ "shiki": "^4.0.1",
57
+ "tailwind-merge": "^3.5.0"
58
+ },
59
+ "peerDependencies": {
60
+ "@sveltejs/kit": "^2.0.0",
61
+ "svelte": "^5.0.0",
62
+ "vite": ">=6.0.0"
63
+ },
64
+ "devDependencies": {
65
+ "@internationalized/date": "^3.10.0",
66
+ "@sveltejs/kit": "^2.53.4",
67
+ "@types/node": "^20.12.11",
68
+ "svelte": "^5.0.0",
69
+ "tailwind-variants": "^3.2.2",
70
+ "tailwindcss": "^4.0.0",
71
+ "typescript": "^5.4.5",
72
+ "vite": "^7.3.1"
73
+ }
74
+ }
package/src/config.ts ADDED
@@ -0,0 +1,133 @@
1
+ export interface LogoConfig {
2
+ light: string
3
+ dark: string
4
+ }
5
+
6
+ export interface SectionConfig {
7
+ label: string
8
+ path?: string
9
+ href?: string
10
+ icon?: string
11
+ children?: SectionConfig[]
12
+ }
13
+
14
+ export interface LocaleConfig {
15
+ code: string
16
+ label: string
17
+ flag?: string
18
+ }
19
+
20
+ export interface I18nConfig {
21
+ defaultLocale: string
22
+ locales: LocaleConfig[]
23
+ fallback?: "default-language" | "404"
24
+ }
25
+
26
+ export interface ResolvedI18nConfig {
27
+ defaultLocale: string
28
+ locales: LocaleConfig[]
29
+ fallback: "default-language" | "404"
30
+ }
31
+
32
+ export interface GitHubConfig {
33
+ repo: string
34
+ branch?: string
35
+ dir?: string
36
+ }
37
+
38
+ export interface FooterSocials {
39
+ github?: string
40
+ x?: string
41
+ discord?: string
42
+ bluesky?: string
43
+ mastodon?: string
44
+ youtube?: string
45
+ linkedin?: string
46
+ }
47
+
48
+ export interface FooterConfig {
49
+ socials?: FooterSocials
50
+ copyright?: string
51
+ }
52
+
53
+ export interface InstantOgConfig {
54
+ siteId: string
55
+ template?: string
56
+ theme?: "light" | "dark"
57
+ accentColor?: string
58
+ gradientBg?: boolean
59
+ }
60
+
61
+ export interface TiramisuDocsConfig {
62
+ title?: string
63
+ description?: string
64
+ url?: string
65
+ logo?: string | LogoConfig
66
+ nav?: { label: string; href: string }[]
67
+ sidebar?: {
68
+ groupOrder?: string[]
69
+ }
70
+ sections?: SectionConfig[]
71
+ i18n?: I18nConfig
72
+ github?: GitHubConfig
73
+ mcp?: boolean | string
74
+ footer?: FooterConfig
75
+ instantOg?: InstantOgConfig
76
+ theme?: {
77
+ primary?: string
78
+ radius?: string
79
+ }
80
+ }
81
+
82
+ export interface ResolvedConfig {
83
+ title: string
84
+ description: string
85
+ url?: string
86
+ logo: LogoConfig
87
+ nav: { label: string; href: string }[]
88
+ sections?: SectionConfig[]
89
+ i18n?: ResolvedI18nConfig
90
+ github?: GitHubConfig
91
+ mcp?: boolean | string
92
+ footer?: FooterConfig
93
+ instantOg?: InstantOgConfig
94
+ sidebar: { groupOrder: string[] }
95
+ theme: { primary: string; radius: string }
96
+ }
97
+
98
+ export function defineConfig(config: TiramisuDocsConfig): TiramisuDocsConfig {
99
+ return config
100
+ }
101
+
102
+ function resolveLogo(logo?: string | LogoConfig): LogoConfig {
103
+ if (!logo) return { light: "", dark: "" }
104
+ if (typeof logo === "string") return { light: logo, dark: logo }
105
+ return logo
106
+ }
107
+
108
+ export function resolveConfig(config: TiramisuDocsConfig): ResolvedConfig {
109
+ return {
110
+ title: config.title ?? "Documentation",
111
+ description: config.description ?? "",
112
+ url: config.url?.replace(/\/+$/, ""),
113
+ logo: resolveLogo(config.logo),
114
+ nav: config.nav ?? [],
115
+ sections: config.sections,
116
+ github: config.github,
117
+ mcp: config.mcp,
118
+ footer: config.footer,
119
+ instantOg: config.instantOg,
120
+ i18n: config.i18n ? {
121
+ defaultLocale: config.i18n.defaultLocale,
122
+ locales: config.i18n.locales,
123
+ fallback: config.i18n.fallback ?? "default-language",
124
+ } : undefined,
125
+ sidebar: {
126
+ groupOrder: config.sidebar?.groupOrder ?? [],
127
+ },
128
+ theme: {
129
+ primary: config.theme?.primary ?? "hsl(262, 83%, 58%)",
130
+ radius: config.theme?.radius ?? "0.5rem",
131
+ },
132
+ }
133
+ }