@ox-content/vite-plugin 2.6.0 → 2.7.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/dist/index.cjs CHANGED
@@ -9372,6 +9372,7 @@ function resolveTheme(config) {
9372
9372
  header: merged.header ?? defaultTheme.header,
9373
9373
  footer: merged.footer ?? defaultTheme.footer,
9374
9374
  socialLinks: merged.socialLinks ?? defaultTheme.socialLinks,
9375
+ sidebar: merged.sidebar ?? [],
9375
9376
  embed: merged.embed ?? {},
9376
9377
  css: merged.css ?? "",
9377
9378
  js: merged.js ?? ""
@@ -9381,6 +9382,7 @@ function resolveTheme(config) {
9381
9382
  * Converts resolved theme to the format expected by Rust NAPI.
9382
9383
  */
9383
9384
  function themeToNapi(theme) {
9385
+ const socialLinks = socialLinksToNapi(theme.socialLinks);
9384
9386
  return {
9385
9387
  colors: theme.colors.primary ? {
9386
9388
  primary: theme.colors.primary,
@@ -9426,16 +9428,30 @@ function themeToNapi(theme) {
9426
9428
  message: theme.footer.message,
9427
9429
  copyright: theme.footer.copyright
9428
9430
  } : void 0,
9429
- socialLinks: theme.socialLinks.github || theme.socialLinks.twitter || theme.socialLinks.discord ? {
9430
- github: theme.socialLinks.github,
9431
- twitter: theme.socialLinks.twitter,
9432
- discord: theme.socialLinks.discord
9433
- } : void 0,
9431
+ socialLinks,
9434
9432
  embed: Object.keys(theme.embed).length > 0 ? theme.embed : void 0,
9435
9433
  css: theme.css || void 0,
9436
9434
  js: theme.js || void 0
9437
9435
  };
9438
9436
  }
9437
+ function socialLinksToNapi(links) {
9438
+ if (Array.isArray(links)) {
9439
+ const items = links.map((item) => {
9440
+ return {
9441
+ icon: typeof item.icon === "string" ? item.icon : void 0,
9442
+ iconSvg: typeof item.icon === "object" ? item.icon.svg : void 0,
9443
+ link: item.link,
9444
+ ariaLabel: item.ariaLabel
9445
+ };
9446
+ });
9447
+ return items.length > 0 ? { links: items } : void 0;
9448
+ }
9449
+ return links.github || links.twitter || links.discord ? {
9450
+ github: links.github,
9451
+ twitter: links.twitter,
9452
+ discord: links.discord
9453
+ } : void 0;
9454
+ }
9439
9455
  //#endregion
9440
9456
  //#region src/ssg.ts
9441
9457
  /**
@@ -10791,7 +10807,8 @@ function resolveSsgOptions(ssg) {
10791
10807
  extension: ".html",
10792
10808
  clean: false,
10793
10809
  bare: false,
10794
- generateOgImage: false
10810
+ generateOgImage: false,
10811
+ lastUpdated: false
10795
10812
  };
10796
10813
  if (ssg === true || ssg === void 0) return {
10797
10814
  enabled: true,
@@ -10799,6 +10816,7 @@ function resolveSsgOptions(ssg) {
10799
10816
  clean: false,
10800
10817
  bare: false,
10801
10818
  generateOgImage: false,
10819
+ lastUpdated: false,
10802
10820
  theme: resolveTheme(void 0)
10803
10821
  };
10804
10822
  return {
@@ -10809,6 +10827,7 @@ function resolveSsgOptions(ssg) {
10809
10827
  siteName: ssg.siteName,
10810
10828
  ogImage: ssg.ogImage,
10811
10829
  generateOgImage: ssg.generateOgImage ?? false,
10830
+ lastUpdated: ssg.lastUpdated ?? false,
10812
10831
  siteUrl: ssg.siteUrl,
10813
10832
  theme: resolveTheme(ssg.theme)
10814
10833
  };
@@ -10862,13 +10881,17 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
10862
10881
  text: entry.text,
10863
10882
  slug: entry.slug
10864
10883
  }));
10884
+ const toRustNavItem = (item) => ({
10885
+ title: item.title,
10886
+ path: item.path,
10887
+ href: item.href,
10888
+ children: item.children?.map(toRustNavItem),
10889
+ collapsed: item.collapsed
10890
+ });
10865
10891
  const navGroupsForRust = navGroups.map((group) => ({
10866
10892
  title: group.title,
10867
- items: group.items.map((item) => ({
10868
- title: item.title,
10869
- path: item.path,
10870
- href: item.href
10871
- }))
10893
+ collapsed: group.collapsed,
10894
+ items: group.items.map(toRustNavItem)
10872
10895
  }));
10873
10896
  const themeForRust = theme ? themeToNapi(theme) : void 0;
10874
10897
  const entryPageForRust = pageData.entryPage ? {
@@ -10907,6 +10930,7 @@ async function generateHtmlPage(pageData, navGroups, siteName, base, ogImage, th
10907
10930
  description: pageData.description,
10908
10931
  content: pageData.content,
10909
10932
  toc: tocForRust,
10933
+ lastUpdated: pageData.lastUpdated,
10910
10934
  path: pageData.path,
10911
10935
  entryPage: entryPageForRust
10912
10936
  }, navGroupsForRust, {
@@ -11194,6 +11218,63 @@ function buildNavItems(markdownFiles, srcDir, base, extension) {
11194
11218
  });
11195
11219
  return result;
11196
11220
  }
11221
+ function isSafeSidebarLink(link) {
11222
+ const trimmed = link.trim();
11223
+ if (trimmed.startsWith("//")) return false;
11224
+ return !/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || /^(https?:|mailto:)/i.test(trimmed);
11225
+ }
11226
+ function sidebarPath(link) {
11227
+ if (!link || !isSafeSidebarLink(link)) return "";
11228
+ if (/^(https?:|mailto:|#)/i.test(link.trim())) return "";
11229
+ const bare = link.trim().split("#", 1)[0].split("?", 1)[0].replace(/^\/+/, "").replace(/\/$/, "").replace(/\.(md|markdown)$/i, "");
11230
+ if (!bare || bare === "index") return "/";
11231
+ return bare.replace(/\/index$/, "");
11232
+ }
11233
+ function sidebarHref(link, base, extension) {
11234
+ if (!link) return "#";
11235
+ const trimmed = link.trim();
11236
+ if (!isSafeSidebarLink(trimmed)) return "#";
11237
+ if (/^(https?:|mailto:|#)/i.test(trimmed)) return trimmed;
11238
+ const hash = trimmed.includes("#") ? `#${trimmed.split("#").slice(1).join("#")}` : "";
11239
+ const withoutExt = trimmed.split("#", 1)[0].replace(/^\/+/, "").replace(/\/$/, "").replace(/\.(md|markdown)$/i, "");
11240
+ return `${base}${!withoutExt || withoutExt === "index" ? "index" : `${withoutExt.replace(/\/index$/, "")}/index`}${extension}${hash}`;
11241
+ }
11242
+ /**
11243
+ * Builds navigation items from an explicit theme sidebar tree.
11244
+ */
11245
+ function buildThemeNavItems(sidebar, base, extension) {
11246
+ const toNavItem = (item) => {
11247
+ const navItem = {
11248
+ title: item.text ?? item.link ?? "Untitled",
11249
+ path: sidebarPath(item.link),
11250
+ href: sidebarHref(item.link, base, extension)
11251
+ };
11252
+ if (item.items?.length) navItem.children = item.items.map(toNavItem);
11253
+ if (item.collapsed !== void 0) navItem.collapsed = item.collapsed;
11254
+ return navItem;
11255
+ };
11256
+ const groups = [];
11257
+ let looseItems = [];
11258
+ const flushLooseItems = () => {
11259
+ if (looseItems.length > 0) {
11260
+ groups.push({
11261
+ title: "Guide",
11262
+ items: looseItems
11263
+ });
11264
+ looseItems = [];
11265
+ }
11266
+ };
11267
+ for (const item of sidebar) if (item.items?.length && !item.link) {
11268
+ flushLooseItems();
11269
+ groups.push({
11270
+ title: item.text ?? "Guide",
11271
+ items: item.items.map(toNavItem),
11272
+ collapsed: item.collapsed
11273
+ });
11274
+ } else looseItems.push(toNavItem(item));
11275
+ flushLooseItems();
11276
+ return groups;
11277
+ }
11197
11278
  /**
11198
11279
  * Builds all markdown files to static HTML.
11199
11280
  */
@@ -11216,7 +11297,7 @@ async function buildSsg(options, root) {
11216
11297
  });
11217
11298
  } catch {}
11218
11299
  const markdownFiles = await collectMarkdownFiles$1(srcDir);
11219
- const navItems = buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension);
11300
+ const navItems = ssgOptions.theme?.sidebar.length ? buildThemeNavItems(ssgOptions.theme.sidebar, base, ssgOptions.extension) : buildNavItems(markdownFiles, srcDir, base, ssgOptions.extension);
11220
11301
  let siteName = ssgOptions.siteName ?? "Documentation";
11221
11302
  if (!ssgOptions.siteName) try {
11222
11303
  const pkgPath = path.join(root, "package.json");
@@ -11228,6 +11309,7 @@ async function buildSsg(options, root) {
11228
11309
  const ogImageUrlMap = /* @__PURE__ */ new Map();
11229
11310
  const shouldGenerateOgImages = (options.ogImage || ssgOptions.generateOgImage) && !ssgOptions.bare;
11230
11311
  const pageResults = [];
11312
+ const napi = ssgOptions.lastUpdated ? await require_mermaid.importNapiModule() : void 0;
11231
11313
  for (const inputPath of markdownFiles) try {
11232
11314
  const result = await transformMarkdown(await fs_promises.readFile(inputPath, "utf-8"), inputPath, options, {
11233
11315
  convertMdLinks: true,
@@ -11255,6 +11337,7 @@ async function buildSsg(options, root) {
11255
11337
  transformedHtml,
11256
11338
  title,
11257
11339
  description,
11340
+ lastUpdated: napi?.getGitLastUpdated(inputPath, root) ?? void 0,
11258
11341
  frontmatter: result.frontmatter,
11259
11342
  toc: result.toc
11260
11343
  });
@@ -11300,7 +11383,7 @@ async function buildSsg(options, root) {
11300
11383
  ogImageUrlMap.clear();
11301
11384
  }
11302
11385
  for (const pageResult of pageResults) try {
11303
- const { inputPath, transformedHtml, title, description, frontmatter, toc } = pageResult;
11386
+ const { inputPath, transformedHtml, title, description, lastUpdated, frontmatter, toc } = pageResult;
11304
11387
  let pageOgImage = ssgOptions.ogImage;
11305
11388
  if (shouldGenerateOgImages && ogImageUrlMap.has(inputPath)) pageOgImage = ogImageUrlMap.get(inputPath);
11306
11389
  let entryPage;
@@ -11315,6 +11398,7 @@ async function buildSsg(options, root) {
11315
11398
  description,
11316
11399
  content: transformedHtml,
11317
11400
  toc,
11401
+ lastUpdated,
11318
11402
  frontmatter,
11319
11403
  path: getUrlPath$1(inputPath, srcDir),
11320
11404
  href: getHref(inputPath, srcDir, base, ssgOptions.extension),
@@ -13223,6 +13307,7 @@ function renderPage(page, options) {
13223
13307
  description: page.description,
13224
13308
  html: page.html,
13225
13309
  toc: page.toc,
13310
+ lastUpdated: page.lastUpdated,
13226
13311
  path: page.path,
13227
13312
  url: page.url,
13228
13313
  frontmatter: page.frontmatter,
@@ -13237,6 +13322,7 @@ function renderPage(page, options) {
13237
13322
  description: p.description,
13238
13323
  html: p.html,
13239
13324
  toc: p.toc,
13325
+ lastUpdated: p.lastUpdated,
13240
13326
  path: p.path,
13241
13327
  url: p.url,
13242
13328
  frontmatter: p.frontmatter,