mordoc 1.0.1 → 1.0.3

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/bin/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  // Entry point for the Mordoc CLI. This file is intentionally plain JS (not TS)
4
4
  // so it can be executed directly by Node without a build step.
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;CACrB;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0GjF"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,mBAAmB;IAClC,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;CACrB;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6GjF"}
package/dist/cli/build.js CHANGED
@@ -144,11 +144,42 @@ export async function runBuildCommand(options) {
144
144
  await fs.rm(ssrOutDir, { recursive: true, force: true });
145
145
  console.log('\n→ verifying output...');
146
146
  await verifyBuildOutput(data, clientOutDir);
147
+ console.log('\n→ writing sitemap and robots.txt...');
148
+ await writeSitemapAndRobots(data, clientOutDir);
147
149
  console.log('\n→ building search index...');
148
150
  await runPagefindIndexer(data, clientOutDir);
149
151
  console.log('\n✔ build complete');
150
152
  console.log(` output → ${clientOutDir}\n`);
151
153
  }
154
+ /**
155
+ * Writes `sitemap.xml` and `robots.txt` into the client output directory.
156
+ *
157
+ * Every page discovered by the pipeline gets a `<loc>` entry — the sitemap
158
+ * is filesystem-driven, not sidenav-driven, so orphaned pages are included.
159
+ * Both files reference `site.baseUrl`, which is validated to be a full URL
160
+ * with no trailing slash.
161
+ */
162
+ async function writeSitemapAndRobots(data, clientOutDir) {
163
+ const { baseUrl } = data.site;
164
+ // XML spec requires & to be encoded as &amp; in attribute/text content.
165
+ // routePaths are always slash-only ASCII paths so this is academic, but correct.
166
+ const escapeXml = (v) => v.replace(/&/g, '&amp;');
167
+ const urlEntries = data.pages
168
+ .map((page) => ` <url>\n <loc>${escapeXml(baseUrl + page.entry.routePath)}</loc>\n </url>`)
169
+ .join('\n');
170
+ const sitemap = '<?xml version="1.0" encoding="UTF-8"?>\n' +
171
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' +
172
+ urlEntries + '\n' +
173
+ '</urlset>\n';
174
+ await fs.writeFile(path.join(clientOutDir, 'sitemap.xml'), sitemap, 'utf-8');
175
+ console.log(` sitemap.xml (${data.pages.length} URL${data.pages.length === 1 ? '' : 's'})`);
176
+ const robots = 'User-agent: *\n' +
177
+ 'Allow: /\n' +
178
+ '\n' +
179
+ `Sitemap: ${baseUrl}/sitemap.xml\n`;
180
+ await fs.writeFile(path.join(clientOutDir, 'robots.txt'), robots, 'utf-8');
181
+ console.log(' robots.txt');
182
+ }
152
183
  /**
153
184
  * Defensive post-build checks.
154
185
  *
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,MAAM,sBAAsB,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAwB3D,SAAS,UAAU,CAAC,WAAmB;IACrC,OAAO;QACL,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;QAC5C,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,CAAC;KACpE,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA4B;IAChE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;IAChC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW,IAAI,CAAC,CAAC;IAE3C,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,MAAM,uBAAuB,CAAC,CAAC;IAE9D,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,oEAAoE;IACpE,iEAAiE;IACjE,iEAAiE;IACjE,mEAAmE;IACnE,iEAAiE;IACjE,mEAAmE;IACnE,wBAAwB;IACxB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAE/D,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAC3C,MAAM,SAAS,CAAC;QACd,UAAU,EAAE,KAAK;QACjB,IAAI,EAAE,OAAO;QACb,SAAS;QACT,OAAO,EAAE;YACP,KAAK,EAAE;YACP,gBAAgB,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;SACxC;QACD,KAAK,EAAE;YACL,MAAM,EAAE,YAAY;YACpB,kEAAkE;YAClE,6DAA6D;YAC7D,4BAA4B;YAC5B,WAAW,EAAE,KAAK;YAClB,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACxC,MAAM,SAAS,CAAC;QACd,UAAU,EAAE,KAAK;QACjB,IAAI,EAAE,OAAO;QACb,8DAA8D;QAC9D,gEAAgE;QAChE,+DAA+D;QAC/D,qDAAqD;QACrD,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE;YACP,KAAK,EAAE;YACP,gBAAgB,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;SACxC;QACD,KAAK,EAAE;YACL,MAAM,EAAE,SAAS;YACjB,WAAW,EAAE,KAAK;YAClB,GAAG,EAAE,kBAAkB;SACxB;KACF,CAAC,CAAC;IAEH,oDAAoD;IACpD,EAAE;IACF,gEAAgE;IAChE,mEAAmE;IACnE,iEAAiE;IACjE,mEAAmE;IACnE,kEAAkE;IAClE,mEAAmE;IACnE,qEAAqE;IACrE,EAAE;IACF,oEAAoE;IACpE,qEAAqE;IACrE,sEAAsE;IACtE,8DAA8D;IAC9D,uDAAuD;IACvD,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EACpC,qBAAqB,EACrB,OAAO,CACR,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACtD,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAC;IAEhD,uEAAuE;IACvE,kEAAkE;IAClE,kEAAkE;IAClE,oEAAoE;IACpE,gCAAgC;IAChC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,iBAAiB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAE5C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,MAAM,kBAAkB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAE7C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,cAAc,YAAY,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,iBAAiB,CAC9B,IAA6C,EAC7C,YAAoB;IAEpB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;QACvC,MAAM,YAAY,GAChB,SAAS,KAAK,GAAG;YACf,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,0BAA0B,YAAY,eAAe,SAAS,6BAA6B,CAC5F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACnD,IAAI,oBAAoB,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;QACnF,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,sEAAsE;gBACpE,0EAA0E;gBAC1E,8EAA8E,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ssg-runner.d.ts","sourceRoot":"","sources":["../../src/cli/ssg-runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,sBAAsB,CAAC;AAalE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAgED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCrE"}
1
+ {"version":3,"file":"ssg-runner.d.ts","sourceRoot":"","sources":["../../src/cli/ssg-runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,sBAAsB,CAAC;AAclE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAmHD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCrE"}
@@ -20,21 +20,62 @@ function escapeHtml(value) {
20
20
  *
21
21
  * Title format matches `Content.tsx`'s `document.title` assignment so
22
22
  * dev and prod are consistent: `Page Title — Site Name`.
23
- * `<meta name="description">` is omitted when frontmatter has no description.
24
- * `<link rel="icon">` is omitted when no favicon asset is configured.
23
+ *
24
+ * Always emits:
25
+ * - `<title>`, `<meta name="description">` (if available), `<link rel="icon">` (if configured)
26
+ * - `<link rel="canonical">` and `og:url` using `site.baseUrl + routePath`
27
+ * - `og:title`, `og:description` (falls back to site description when page has none)
28
+ *
29
+ * Emits conditionally from `site.metadata`:
30
+ * - `og:type` and `og:image` if declared
31
+ * - Full Twitter Card block (`twitter:card`, `twitter:site`, `twitter:title`,
32
+ * `twitter:description`, `twitter:image`) when `twitterCard` is declared — without
33
+ * `twitter:card` the other twitter tags have no effect, so the whole block is gated on it.
25
34
  */
26
- function buildHeadHtml(page, siteName, faviconUrl) {
35
+ function buildHeadHtml(page, site, faviconUrl, routePath) {
27
36
  const pageTitle = page.frontmatter.title;
28
37
  const title = pageTitle
29
- ? `${escapeHtml(pageTitle)} — ${escapeHtml(siteName)}`
30
- : escapeHtml(siteName);
38
+ ? `${escapeHtml(pageTitle)} — ${escapeHtml(site.name)}`
39
+ : escapeHtml(site.name);
40
+ // Page description with fallback to site description for social tags only.
41
+ const pageDescription = page.frontmatter.description;
42
+ const socialDescription = pageDescription ?? site.description;
43
+ const canonicalUrl = `${site.baseUrl}${routePath}`;
44
+ const meta = site.metadata;
31
45
  const parts = [`<title>${title}</title>`];
32
- if (page.frontmatter.description) {
33
- parts.push(`<meta name="description" content="${escapeHtml(page.frontmatter.description)}">`);
46
+ if (pageDescription) {
47
+ parts.push(`<meta name="description" content="${escapeHtml(pageDescription)}">`);
34
48
  }
35
49
  if (faviconUrl) {
36
50
  parts.push(`<link rel="icon" href="${escapeHtml(faviconUrl)}">`);
37
51
  }
52
+ parts.push(`<link rel="canonical" href="${escapeHtml(canonicalUrl)}">`);
53
+ // OpenGraph
54
+ parts.push(`<meta property="og:url" content="${escapeHtml(canonicalUrl)}">`);
55
+ parts.push(`<meta property="og:title" content="${escapeHtml(title)}">`);
56
+ if (socialDescription) {
57
+ parts.push(`<meta property="og:description" content="${escapeHtml(socialDescription)}">`);
58
+ }
59
+ if (meta?.ogType) {
60
+ parts.push(`<meta property="og:type" content="${escapeHtml(meta.ogType)}">`);
61
+ }
62
+ if (meta?.ogImage) {
63
+ parts.push(`<meta property="og:image" content="${escapeHtml(site.baseUrl + meta.ogImage)}">`);
64
+ }
65
+ // Twitter Card — the full block is only useful when twitter:card is present.
66
+ if (meta?.twitterCard) {
67
+ parts.push(`<meta name="twitter:card" content="${escapeHtml(meta.twitterCard)}">`);
68
+ if (meta.twitterSite) {
69
+ parts.push(`<meta name="twitter:site" content="${escapeHtml(meta.twitterSite)}">`);
70
+ }
71
+ parts.push(`<meta name="twitter:title" content="${escapeHtml(title)}">`);
72
+ if (socialDescription) {
73
+ parts.push(`<meta name="twitter:description" content="${escapeHtml(socialDescription)}">`);
74
+ }
75
+ if (meta.ogImage) {
76
+ parts.push(`<meta name="twitter:image" content="${escapeHtml(site.baseUrl + meta.ogImage)}">`);
77
+ }
78
+ }
38
79
  return parts.join('\n ');
39
80
  }
40
81
  /**
@@ -111,7 +152,7 @@ export async function runSsg(options) {
111
152
  const request = new Request(`http://localhost${routePath}`);
112
153
  const { html: appHtml } = await ssrModule.render(request, shellData);
113
154
  const pageLang = detectCurrentLang(routePath, data.language, data.site.defaultLanguage);
114
- const headHtml = buildHeadHtml(page, data.site.name, data.assets.favicon);
155
+ const headHtml = buildHeadHtml(page, data.site, data.assets.favicon, routePath);
115
156
  // lang is a plain ASCII code — string-form replace is safe (no $-patterns)
116
157
  const withLang = template.replace(SSR_LANG_MARKER, pageLang);
117
158
  const withHead = withLang.replace(SSR_HEAD_MARKER, () => headHtml);
@@ -1 +1 @@
1
- {"version":3,"file":"ssg-runner.js","sourceRoot":"","sources":["../../src/cli/ssg-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ssg-runner.js","sourceRoot":"","sources":["../../src/cli/ssg-runner.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"site-loader.d.ts","sourceRoot":"","sources":["../../src/config/site-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAgDnD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAsB7E"}
1
+ {"version":3,"file":"site-loader.d.ts","sourceRoot":"","sources":["../../src/config/site-loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAkEnD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAsB7E"}
@@ -37,6 +37,21 @@ function validateSiteConfig(raw) {
37
37
  if (baseUrl.endsWith('/')) {
38
38
  throw new Error(`site.json: "baseUrl" must not end with a trailing slash. Got: "${baseUrl}"`);
39
39
  }
40
+ const meta = obj['metadata'];
41
+ if (meta !== undefined) {
42
+ if (typeof meta !== 'object' || meta === null || Array.isArray(meta)) {
43
+ throw new Error('site.json: "metadata" must be an object.');
44
+ }
45
+ const metaObj = meta;
46
+ if (metaObj['ogImage'] !== undefined) {
47
+ if (typeof metaObj['ogImage'] !== 'string') {
48
+ throw new Error('site.json: "metadata.ogImage" must be a string.');
49
+ }
50
+ if (!metaObj['ogImage'].startsWith('/')) {
51
+ throw new Error(`site.json: "metadata.ogImage" must be a root-relative path starting with "/" (e.g. "/images/og-cover.png"). Got: "${metaObj['ogImage']}"`);
52
+ }
53
+ }
54
+ }
40
55
  return raw;
41
56
  }
42
57
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"site-loader.js","sourceRoot":"","sources":["../../src/config/site-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,wEAAwE;AACxE,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAErD,iFAAiF;AACjF,MAAM,eAAe,GAAyB;IAC5C,MAAM;IACN,aAAa;IACb,SAAS;IACT,iBAAiB;CAClB,CAAC;AAEF;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAY;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,+CAA+C,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAW,CAAC;IACzC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mDAAmD,OAAO,GAAG,CAAC,CAAC;IACjF,CAAC;IAED,kFAAkF;IAClF,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,kEAAkE,OAAO,GAAG,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,GAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAErD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,0DAA0D,CAAC,CAAC;QAChH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,iBAAiB,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"site-loader.js","sourceRoot":"","sources":["../../src/config/site-loader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "name": "mordoc",
3
- "version": "1.0.1",
3
+ "repoitory": {
4
+ "type": "git",
5
+ "url": "https://github.com/shiva-varanasi/mordoc.git"
6
+ },
7
+ "version": "1.0.3",
4
8
  "description": "A modern documentation site generator powered by Vite, React, and Markdoc.",
5
9
  "type": "module",
6
10
  "files": [
@@ -31,7 +31,7 @@
31
31
  position: sticky;
32
32
  top: var(--header-total);
33
33
  align-self: flex-start;
34
- width: var(--sidebar-width);
34
+ width: var(--sidenav-width);
35
35
  height: calc(100svh - var(--header-total));
36
36
  overflow-y: auto;
37
37
  flex-shrink: 0;
@@ -234,32 +234,61 @@
234
234
 
235
235
  .prose :global(ul),
236
236
  .prose :global(ol) {
237
- margin: 0 0 16px 16px;
238
- padding: 0;
237
+ margin: 1rem 0;
238
+ padding-left: 1.5rem;
239
239
  font-size: 16px;
240
240
  line-height: 1.7;
241
241
  color: var(--color-content-fg);
242
242
  }
243
243
 
244
244
  .prose :global(ul) {
245
- list-style: disc inside;
245
+ list-style: disc;
246
+ list-style-position: outside;
246
247
  }
247
248
 
248
249
  .prose :global(ol) {
249
- list-style: decimal inside;
250
+ list-style: decimal;
251
+ list-style-position: outside;
252
+ }
253
+
254
+ .prose :global(ul ul) {
255
+ list-style-type: circle;
256
+ }
257
+
258
+ .prose :global(ul ul ul) {
259
+ list-style-type: square;
260
+ }
261
+
262
+ .prose :global(ol ol) {
263
+ list-style-type: lower-alpha;
264
+ }
265
+
266
+ .prose :global(ol ol ol) {
267
+ list-style-type: lower-roman;
250
268
  }
251
269
 
252
270
  .prose :global(li) {
271
+ margin-bottom: 0.5rem;
272
+ line-height: 1.7;
273
+ }
274
+
275
+ .prose :global(li:last-child) {
253
276
  margin-bottom: 0;
254
277
  }
255
278
 
256
- .prose :global(li + li) {
257
- margin-top: 8px;
279
+ /* Markdoc loose lists wrap item text in <p> — override global .prose p margins */
280
+ .prose :global(li > p) {
281
+ margin-top: 0;
282
+ margin-bottom: 0.5rem;
283
+ }
284
+
285
+ .prose :global(li > p:last-child) {
286
+ margin-bottom: 0;
258
287
  }
259
288
 
260
289
  .prose :global(li > ul),
261
290
  .prose :global(li > ol) {
262
- margin-top: 8px;
291
+ margin-top: 0.5rem;
263
292
  margin-bottom: 0;
264
293
  }
265
294
 
@@ -316,7 +345,7 @@
316
345
  border-radius: var(--radius-sm);
317
346
  font-family: var(--font-mono);
318
347
  font-size: 0.875em;
319
- font-weight: 500;
348
+ font-weight: 400;
320
349
  }
321
350
 
322
351
  /* Reset inline-code styles for code inside a pre — the CodeBlock component owns that styling */
@@ -334,14 +363,14 @@
334
363
  width: 100%;
335
364
  margin: 1.25rem 0;
336
365
  border-collapse: collapse;
337
- font-size: 0.9rem;
366
+ font-size: 1rem;
338
367
  }
339
368
 
340
369
  .prose :global(th) {
341
370
  padding: 0.625rem 0.875rem;
342
371
  text-align: left;
343
372
  font-weight: 600;
344
- font-size: 0.8125rem;
373
+ font-size: 1rem;
345
374
  color: var(--color-fg);
346
375
  border-bottom: 1px solid var(--color-border);
347
376
  }
package/src/app/index.css CHANGED
@@ -27,14 +27,13 @@
27
27
  --accent-muted: color-mix(in oklch, var(--accent) 20%, white);
28
28
  --accent-emphasis: var(--accent);
29
29
  --accent-strong: color-mix(in oklch, var(--accent) 80%, black);
30
- --accent-on: white;
31
30
 
32
31
  /* Layout — shared across multiple components */
33
32
  --header-height: 4rem;
34
33
  --topnav-height: 0px;
35
34
  --header-total: calc(var(--header-height) + var(--topnav-height));
36
- --sidebar-width: 16rem;
37
- --sidebar-width-icon: 3.5rem;
35
+ --sidenav-width: 16rem;
36
+ --sidenav-width-icon: 3.5rem;
38
37
  --toc-width: 16rem;
39
38
  --content-max-width: 48rem;
40
39
  --page-gutter: 2.5rem;
@@ -1,3 +1,9 @@
1
+ /* ── Button tokens ────────────────────────────────────────────── */
2
+
3
+ :root {
4
+ --button-primary-fg: white;
5
+ }
6
+
1
7
  /* ── Button ───────────────────────────────────────────────────── */
2
8
 
3
9
  .button {
@@ -21,7 +27,7 @@
21
27
 
22
28
  .primary {
23
29
  background: var(--accent);
24
- color: var(--accent-on);
30
+ color: var(--button-primary-fg);
25
31
  border-color: var(--accent);
26
32
  }
27
33
 
package/src/app/main.tsx CHANGED
@@ -9,9 +9,10 @@ import pagesIndex from 'virtual:mordoc/pages-index';
9
9
  import translations from 'virtual:mordoc/translations';
10
10
  import type { ShellData } from '../types/pipeline.js';
11
11
  import './index.css';
12
- import 'virtual:mordoc/theme';
13
12
  import { MordocDataContext } from './data-context.js';
14
13
  import { createAppRouter } from './routes.js';
14
+ // theme.css must be last so user overrides win over component-level :root tokens
15
+ import 'virtual:mordoc/theme';
15
16
 
16
17
  /**
17
18
  * Browser entry. Assembles `ShellData` from the eager virtual modules
@@ -66,27 +66,3 @@
66
66
  font-size: 0.875em;
67
67
  font-weight: 500;
68
68
  }
69
-
70
- /* ── Go home button ─────────────────────────────────────────── */
71
-
72
- .homeButton {
73
- display: inline-flex;
74
- align-items: center;
75
- padding: 0.5rem 1.125rem;
76
- background: var(--accent-emphasis);
77
- color: var(--accent-on);
78
- border-radius: var(--radius-md);
79
- font-size: 0.9375rem;
80
- font-weight: 500;
81
- text-decoration: none;
82
- transition: background 150ms ease;
83
- }
84
-
85
- .homeButton:hover {
86
- background: var(--accent-strong);
87
- }
88
-
89
- .homeButton:focus-visible {
90
- outline: 2px solid var(--accent-emphasis);
91
- outline-offset: 2px;
92
- }
@@ -10,7 +10,8 @@
10
10
  * rendering this component.
11
11
  */
12
12
 
13
- import { Link, useLocation } from 'react-router';
13
+ import { useLocation } from 'react-router';
14
+ import { Button } from '../landing/button/Button.js';
14
15
  import { Footer } from '../footer/Footer.js';
15
16
  import styles from './NotFound.module.css';
16
17
 
@@ -25,7 +26,7 @@ export function NotFound() {
25
26
  <p className={styles.description}>
26
27
  No page exists at <code className={styles.path}>{location.pathname}</code>.
27
28
  </p>
28
- <Link to="/" className={styles.homeButton}>Go home</Link>
29
+ <Button path="/">Go home</Button>
29
30
  </div>
30
31
  </div>
31
32
  <Footer />
@@ -2,30 +2,30 @@
2
2
  SIDENAV TOKENS
3
3
  ============================================================ */
4
4
  :root {
5
- --sidebar-bg: #FAFAFA;
6
- --sidebar-fg: #383838;
7
- --sidebar-fg-muted: #666666;
8
- --sidebar-border: #E5E5E5;
9
- --sidebar-accent: #EFEFEF;
10
- --sidebar-accent-fg: #1C1C1C;
11
- --sidebar-group-label-fg: rgba(56, 56, 56, 0.7);
12
- --sidebar-gap-y: 4px;
13
- --sidebar-item-h: 36px;
14
- --sidebar-group-h: 36px;
15
- --sidebar-pad-x: 8px;
16
- --sidebar-pad-y: 16px;
17
- --sidebar-item-pad-x: 8px;
18
- --sidebar-item-pad-y: 6px;
5
+ --sidenav-bg: #FAFAFA;
6
+ --sidenav-fg: #383838;
7
+ --sidenav-fg-muted: #666666;
8
+ --sidenav-border: #E5E5E5;
9
+ --sidenav-accent: #EFEFEF;
10
+ --sidenav-accent-fg: #1C1C1C;
11
+ --sidenav-group-label-fg: rgba(56, 56, 56, 0.7);
12
+ --sidenav-gap-y: 4px;
13
+ --sidenav-item-h: 36px;
14
+ --sidenav-group-h: 36px;
15
+ --sidenav-pad-x: 8px;
16
+ --sidenav-pad-y: 16px;
17
+ --sidenav-item-pad-x: 8px;
18
+ --sidenav-item-pad-y: 6px;
19
19
  }
20
20
 
21
21
  :global(.dark) {
22
- --sidebar-bg: #0F0F0F;
23
- --sidebar-fg: #D6D6D6;
24
- --sidebar-fg-muted: #9E9E9E;
25
- --sidebar-border: #292929;
26
- --sidebar-accent: #1F1F1F;
27
- --sidebar-accent-fg: #EBEBEB;
28
- --sidebar-group-label-fg: rgba(214, 214, 214, 0.7);
22
+ --sidenav-bg: #0F0F0F;
23
+ --sidenav-fg: #D6D6D6;
24
+ --sidenav-fg-muted: #9E9E9E;
25
+ --sidenav-border: #292929;
26
+ --sidenav-accent: #1F1F1F;
27
+ --sidenav-accent-fg: #EBEBEB;
28
+ --sidenav-group-label-fg: rgba(214, 214, 214, 0.7);
29
29
  }
30
30
 
31
31
  /* ============================================================
@@ -34,7 +34,7 @@
34
34
  ============================================================ */
35
35
 
36
36
  .sidenav {
37
- padding: var(--sidebar-pad-y) var(--sidebar-pad-x);
37
+ padding: var(--sidenav-pad-y) var(--sidenav-pad-x);
38
38
  }
39
39
 
40
40
  /* ── Menu list ───────────────────────────────────────────────── */
@@ -64,8 +64,8 @@
64
64
  align-items: center;
65
65
  justify-content: space-between;
66
66
  width: 100%;
67
- min-height: var(--sidebar-group-h);
68
- padding: var(--sidebar-item-pad-y) var(--sidebar-item-pad-x);
67
+ min-height: var(--sidenav-group-h);
68
+ padding: var(--sidenav-item-pad-y) var(--sidenav-item-pad-x);
69
69
  margin-top: 10px;
70
70
  border-radius: var(--radius-md);
71
71
  background: none;
@@ -74,7 +74,7 @@
74
74
  font-weight: 500;
75
75
  line-height: 1.25;
76
76
  letter-spacing: 0;
77
- color: var(--sidebar-group-label-fg);
77
+ color: var(--sidenav-group-label-fg);
78
78
  font-family: var(--font-sans);
79
79
  cursor: pointer;
80
80
  text-align: left;
@@ -86,7 +86,7 @@
86
86
  }
87
87
 
88
88
  .groupLabelTrigger:hover {
89
- background: var(--sidebar-accent);
89
+ background: var(--sidenav-accent);
90
90
  }
91
91
 
92
92
  .groupLabelText {
@@ -103,13 +103,13 @@
103
103
  justify-content: space-between;
104
104
  gap: 8px;
105
105
  width: 100%;
106
- min-height: var(--sidebar-group-h);
107
- padding: var(--sidebar-item-pad-y) var(--sidebar-item-pad-x);
106
+ min-height: var(--sidenav-group-h);
107
+ padding: var(--sidenav-item-pad-y) var(--sidenav-item-pad-x);
108
108
  border-radius: var(--radius-md);
109
109
  font-size: 14px;
110
110
  font-weight: 500;
111
111
  line-height: 1.25;
112
- color: var(--sidebar-fg);
112
+ color: var(--sidenav-fg);
113
113
  text-decoration: none;
114
114
  cursor: pointer;
115
115
  margin-top: 10px;
@@ -121,7 +121,7 @@
121
121
  }
122
122
 
123
123
  .linkedGroupLabel:hover {
124
- background: var(--sidebar-accent);
124
+ background: var(--sidenav-accent);
125
125
  }
126
126
 
127
127
  .linkedGroupLabel.linkActive {
@@ -138,19 +138,19 @@
138
138
  display: flex;
139
139
  align-items: center;
140
140
  width: 100%;
141
- min-height: var(--sidebar-group-h);
142
- padding: var(--sidebar-item-pad-y) var(--sidebar-item-pad-x);
141
+ min-height: var(--sidenav-group-h);
142
+ padding: var(--sidenav-item-pad-y) var(--sidenav-item-pad-x);
143
143
  border-radius: var(--radius-md);
144
144
  font-size: 14px;
145
145
  font-weight: 500;
146
146
  line-height: 1.25;
147
- color: var(--sidebar-fg);
147
+ color: var(--sidenav-fg);
148
148
  text-decoration: none;
149
149
  transition: color 150ms ease, background-color 150ms ease;
150
150
  }
151
151
 
152
152
  .topLink:hover {
153
- background: var(--sidebar-accent);
153
+ background: var(--sidenav-accent);
154
154
  }
155
155
 
156
156
  .topLink.topLinkActive {
@@ -168,25 +168,25 @@
168
168
  display: flex;
169
169
  align-items: center;
170
170
  width: 100%;
171
- min-height: var(--sidebar-item-h);
172
- padding: var(--sidebar-item-pad-y) 8px var(--sidebar-item-pad-y) 24px;
171
+ min-height: var(--sidenav-item-h);
172
+ padding: var(--sidenav-item-pad-y) 8px var(--sidenav-item-pad-y) 8px;
173
173
  border-radius: var(--radius-md);
174
174
  font-size: 14px;
175
- font-weight: 400;
175
+ font-weight: 500;
176
176
  line-height: 1.4;
177
- color: var(--sidebar-fg);
177
+ color: var(--sidenav-fg);
178
178
  text-decoration: none;
179
179
  transition: color 150ms ease, background-color 150ms ease;
180
180
  }
181
181
 
182
182
  .navLink:hover {
183
- background: var(--sidebar-accent);
183
+ background: var(--sidenav-accent);
184
184
  }
185
185
 
186
186
  .navLink.navLinkActive {
187
187
  background: var(--accent-subtle);
188
188
  color: var(--accent-emphasis);
189
- font-weight: 500;
189
+ font-weight: 600;
190
190
  }
191
191
 
192
192
  /* ============================================================
@@ -195,6 +195,7 @@
195
195
 
196
196
  .groupContent {
197
197
  padding-top: 4px;
198
+ padding-left: 16px;
198
199
  }
199
200
 
200
201
  /* ============================================================
@@ -203,7 +204,7 @@
203
204
 
204
205
  .chevron {
205
206
  flex-shrink: 0;
206
- color: var(--sidebar-fg-muted);
207
+ color: var(--sidenav-fg-muted);
207
208
  transition: transform 200ms ease;
208
209
  }
209
210
 
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useEffect } from 'react';
2
2
  import { NavLink, useLocation, useNavigate } from 'react-router';
3
3
  import { useMordocData } from '../data-context.js';
4
4
  import { detectCurrentLang, buildLangPrefix, stripLangPrefix, resolveLabel } from '../lang-utils.js';
@@ -51,6 +51,10 @@ function SidenavNode({ item, depth }: { item: SidenavItem; depth: number }) {
51
51
  const isLabelActive = item.path ? location.pathname === item.path : false;
52
52
  const [open, setOpen] = useState(isGroupActive || isLabelActive);
53
53
 
54
+ useEffect(() => {
55
+ if (isGroupActive || isLabelActive) setOpen(true);
56
+ }, [isGroupActive, isLabelActive]);
57
+
54
58
  // Leaf item — path only, no children
55
59
  if (item.path && !item.children) {
56
60
  const isTop = depth === 0;