docula 1.5.0 → 1.6.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/docula.d.ts CHANGED
@@ -215,9 +215,23 @@ declare class DoculaOptions {
215
215
  */
216
216
  autoUpdateIgnores: boolean;
217
217
  /**
218
- * File extensions to copy as assets from docs/ and changelog/ directories.
219
- * Override in docula.config to customize.
218
+ * Base URL path prefix for all generated paths (e.g., "/docs").
219
+ * When set, all asset and navigation URLs are prefixed with this path.
220
+ */
221
+ baseUrl: string;
222
+ /**
223
+ * Output subdirectory and URL segment for documentation pages.
224
+ * Set to empty string to place docs at the output root.
225
+ */
226
+ docsPath: string;
227
+ /**
228
+ * Output subdirectory and URL segment for API reference pages.
229
+ */
230
+ apiPath: string;
231
+ /**
232
+ * Output subdirectory and URL segment for changelog pages.
220
233
  */
234
+ changelogPath: string;
221
235
  /**
222
236
  * Cookie-based authentication. When set, shows a Login/Logout button
223
237
  * in the header based on whether a JWT cookie is present.
@@ -297,6 +311,13 @@ type DoculaData = {
297
311
  enableLlmsTxt?: boolean;
298
312
  hasFeed?: boolean;
299
313
  lastModified?: string;
314
+ baseUrl: string;
315
+ docsPath: string;
316
+ apiPath: string;
317
+ changelogPath: string;
318
+ docsUrl: string;
319
+ apiUrl: string;
320
+ changelogUrl: string;
300
321
  };
301
322
  type DoculaTemplates = {
302
323
  home: string;
@@ -345,6 +366,7 @@ declare class DoculaBuilder {
345
366
  buildLlmsFiles(data: DoculaData): Promise<void>;
346
367
  private generateLlmsIndexContent;
347
368
  private generateLlmsFullContent;
369
+ private buildUrlPath;
348
370
  private buildAbsoluteSiteUrl;
349
371
  private normalizePathForUrl;
350
372
  private escapeXml;
package/dist/docula.js CHANGED
@@ -907,6 +907,18 @@ var Github = class {
907
907
  // src/options.ts
908
908
  import path3 from "path";
909
909
  import process3 from "process";
910
+ function trimSlashes(value) {
911
+ let start = 0;
912
+ let end = value.length;
913
+ while (start < end && value[start] === "/") start++;
914
+ while (end > start && value[end - 1] === "/") end--;
915
+ return value.slice(start, end);
916
+ }
917
+ function trimTrailingSlashes(value) {
918
+ let end = value.length;
919
+ while (end > 0 && value[end - 1] === "/") end--;
920
+ return value.slice(0, end);
921
+ }
910
922
  var DoculaOptions = class {
911
923
  /**
912
924
  * Name of the built-in template to use (e.g., "modern", "classic")
@@ -979,9 +991,23 @@ var DoculaOptions = class {
979
991
  */
980
992
  autoUpdateIgnores = true;
981
993
  /**
982
- * File extensions to copy as assets from docs/ and changelog/ directories.
983
- * Override in docula.config to customize.
994
+ * Base URL path prefix for all generated paths (e.g., "/docs").
995
+ * When set, all asset and navigation URLs are prefixed with this path.
996
+ */
997
+ baseUrl = "";
998
+ /**
999
+ * Output subdirectory and URL segment for documentation pages.
1000
+ * Set to empty string to place docs at the output root.
1001
+ */
1002
+ docsPath = "docs";
1003
+ /**
1004
+ * Output subdirectory and URL segment for API reference pages.
984
1005
  */
1006
+ apiPath = "api";
1007
+ /**
1008
+ * Output subdirectory and URL segment for changelog pages.
1009
+ */
1010
+ changelogPath = "changelog";
985
1011
  /**
986
1012
  * Cookie-based authentication. When set, shows a Login/Logout button
987
1013
  * in the header based on whether a JWT cookie is present.
@@ -1096,6 +1122,18 @@ var DoculaOptions = class {
1096
1122
  if (options.cache && typeof options.cache === "object" && options.cache.github !== null && typeof options.cache.github === "object" && typeof options.cache.github.ttl === "number") {
1097
1123
  this.cache = options.cache;
1098
1124
  }
1125
+ if (options.baseUrl !== void 0 && typeof options.baseUrl === "string") {
1126
+ this.baseUrl = trimTrailingSlashes(options.baseUrl);
1127
+ }
1128
+ if (options.docsPath !== void 0 && typeof options.docsPath === "string") {
1129
+ this.docsPath = trimSlashes(options.docsPath);
1130
+ }
1131
+ if (options.apiPath !== void 0 && typeof options.apiPath === "string") {
1132
+ this.apiPath = trimSlashes(options.apiPath);
1133
+ }
1134
+ if (options.changelogPath !== void 0 && typeof options.changelogPath === "string") {
1135
+ this.changelogPath = trimSlashes(options.changelogPath);
1136
+ }
1099
1137
  if (options.allowedAssets && Array.isArray(options.allowedAssets)) {
1100
1138
  this.allowedAssets = options.allowedAssets;
1101
1139
  }
@@ -1207,14 +1245,28 @@ var DoculaBuilder = class {
1207
1245
  themeMode: this.options.themeMode,
1208
1246
  cookieAuth: this.options.cookieAuth,
1209
1247
  headerLinks: this.options.headerLinks,
1210
- enableLlmsTxt: this.options.enableLlmsTxt
1248
+ enableLlmsTxt: this.options.enableLlmsTxt,
1249
+ baseUrl: this.options.baseUrl,
1250
+ docsPath: this.options.docsPath,
1251
+ apiPath: this.options.apiPath,
1252
+ changelogPath: this.options.changelogPath,
1253
+ docsUrl: this.buildUrlPath(this.options.baseUrl, this.options.docsPath),
1254
+ apiUrl: this.buildUrlPath(this.options.baseUrl, this.options.apiPath),
1255
+ changelogUrl: this.buildUrlPath(
1256
+ this.options.baseUrl,
1257
+ this.options.changelogPath
1258
+ )
1211
1259
  };
1212
1260
  const readmePath = `${this.options.sitePath}/README.md`;
1213
1261
  if (doculaData.hasReadme) {
1214
1262
  currentAssetHashes["README.md"] = this.hashFile(readmePath);
1215
1263
  }
1216
1264
  if (!doculaData.openApiUrl && fs3.existsSync(`${doculaData.sitePath}/api/swagger.json`)) {
1217
- doculaData.openApiUrl = "/api/swagger.json";
1265
+ doculaData.openApiUrl = this.buildUrlPath(
1266
+ this.options.baseUrl,
1267
+ this.options.apiPath,
1268
+ "swagger.json"
1269
+ );
1218
1270
  }
1219
1271
  if (this.options.githubPath) {
1220
1272
  doculaData.github = await this.getGithubData(this.options.githubPath);
@@ -1318,15 +1370,17 @@ var DoculaBuilder = class {
1318
1370
  if (doculaData.hasApi) {
1319
1371
  this._console.step("Building API page...");
1320
1372
  await this.buildApiPage(doculaData);
1321
- this._console.fileBuilt("api/index.html");
1373
+ this._console.fileBuilt(`${this.options.apiPath}/index.html`);
1322
1374
  }
1323
1375
  if (doculaData.hasChangelog) {
1324
1376
  this._console.step("Building changelog...");
1325
1377
  await this.buildChangelogPage(doculaData);
1326
- this._console.fileBuilt("changelog/index.html");
1378
+ this._console.fileBuilt(`${this.options.changelogPath}/index.html`);
1327
1379
  await this.buildChangelogEntryPages(doculaData);
1328
1380
  for (const entry of doculaData.changelogEntries ?? []) {
1329
- this._console.fileBuilt(`changelog/${entry.slug}/index.html`);
1381
+ this._console.fileBuilt(
1382
+ `${this.options.changelogPath}/${entry.slug}/index.html`
1383
+ );
1330
1384
  }
1331
1385
  }
1332
1386
  const siteRelativePath = this.options.sitePath;
@@ -1416,7 +1470,7 @@ var DoculaBuilder = class {
1416
1470
  );
1417
1471
  this.copyContentAssets(
1418
1472
  `${doculaData.sitePath}/changelog`,
1419
- `${this.options.output}/changelog`
1473
+ `${this.options.output}/${this.options.changelogPath}`
1420
1474
  );
1421
1475
  if (doculaData.documents?.length) {
1422
1476
  this.copyDocumentSiblingAssets(doculaData);
@@ -1524,13 +1578,17 @@ var DoculaBuilder = class {
1524
1578
  const sitemapPath = `${data.output}/sitemap.xml`;
1525
1579
  const urls = [{ url: data.siteUrl }];
1526
1580
  if (data.documents?.length) {
1527
- urls.push({ url: `${data.siteUrl}/feed.xml` });
1581
+ urls.push({ url: `${data.siteUrl}${data.baseUrl}/feed.xml` });
1528
1582
  }
1529
1583
  if (data.openApiUrl && data.templates?.api) {
1530
- urls.push({ url: `${data.siteUrl}/api` });
1584
+ urls.push({
1585
+ url: `${data.siteUrl}${data.apiUrl}`
1586
+ });
1531
1587
  }
1532
1588
  if (data.hasChangelog && data.templates?.changelog) {
1533
- urls.push({ url: `${data.siteUrl}/changelog` });
1589
+ urls.push({
1590
+ url: `${data.siteUrl}${data.changelogUrl}`
1591
+ });
1534
1592
  const perPage = this.options.changelogPerPage;
1535
1593
  const totalPages = Math.max(
1536
1594
  1,
@@ -1538,12 +1596,12 @@ var DoculaBuilder = class {
1538
1596
  );
1539
1597
  for (let page = 2; page <= totalPages; page++) {
1540
1598
  urls.push({
1541
- url: `${data.siteUrl}/changelog/page/${page}`
1599
+ url: `${data.siteUrl}${data.changelogUrl}/page/${page}`
1542
1600
  });
1543
1601
  }
1544
1602
  for (const entry of data.changelogEntries ?? []) {
1545
1603
  urls.push({
1546
- url: `${data.siteUrl}/changelog/${entry.slug}`
1604
+ url: `${data.siteUrl}${data.changelogUrl}/${entry.slug}`
1547
1605
  });
1548
1606
  }
1549
1607
  }
@@ -1552,7 +1610,7 @@ var DoculaBuilder = class {
1552
1610
  if (urlPath.endsWith("index.html")) {
1553
1611
  urlPath = urlPath.slice(0, -10);
1554
1612
  }
1555
- urls.push({ url: `${data.siteUrl}${urlPath}` });
1613
+ urls.push({ url: `${data.siteUrl}${data.baseUrl}${urlPath}` });
1556
1614
  }
1557
1615
  let xml = '<?xml version="1.0" encoding="UTF-8"?>';
1558
1616
  xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
@@ -1570,8 +1628,14 @@ var DoculaBuilder = class {
1570
1628
  return;
1571
1629
  }
1572
1630
  const feedPath = `${data.output}/feed.xml`;
1573
- const channelLink = this.buildAbsoluteSiteUrl(data.siteUrl, "/");
1574
- const feedUrl = this.buildAbsoluteSiteUrl(data.siteUrl, "/feed.xml");
1631
+ const channelLink = this.buildAbsoluteSiteUrl(
1632
+ data.siteUrl,
1633
+ `${data.baseUrl}/`
1634
+ );
1635
+ const feedUrl = this.buildAbsoluteSiteUrl(
1636
+ data.siteUrl,
1637
+ `${data.baseUrl}/feed.xml`
1638
+ );
1575
1639
  let xml = '<?xml version="1.0" encoding="UTF-8"?>';
1576
1640
  xml += '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">';
1577
1641
  xml += "<channel>";
@@ -1584,7 +1648,7 @@ var DoculaBuilder = class {
1584
1648
  const itemTitle = document.navTitle || document.title || document.urlPath;
1585
1649
  const itemLink = this.buildAbsoluteSiteUrl(
1586
1650
  data.siteUrl,
1587
- this.normalizePathForUrl(document.urlPath)
1651
+ `${data.baseUrl}${this.normalizePathForUrl(document.urlPath)}`
1588
1652
  );
1589
1653
  const summary = document.description || this.summarizeMarkdown(new Writr(document.content).body);
1590
1654
  xml += "<item>";
@@ -1642,7 +1706,7 @@ var DoculaBuilder = class {
1642
1706
  lines.push(data.siteDescription);
1643
1707
  lines.push("");
1644
1708
  lines.push(
1645
- `- [Full LLM Content](${this.buildAbsoluteSiteUrl(data.siteUrl, "/llms-full.txt")})`
1709
+ `- [Full LLM Content](${this.buildAbsoluteSiteUrl(data.siteUrl, `${data.baseUrl}/llms-full.txt`)})`
1646
1710
  );
1647
1711
  lines.push("");
1648
1712
  lines.push("## Documentation");
@@ -1650,7 +1714,7 @@ var DoculaBuilder = class {
1650
1714
  for (const document of documents) {
1651
1715
  const documentUrl = this.buildAbsoluteSiteUrl(
1652
1716
  data.siteUrl,
1653
- this.normalizePathForUrl(document.urlPath)
1717
+ `${data.baseUrl}${this.normalizePathForUrl(document.urlPath)}`
1654
1718
  );
1655
1719
  const description = document.description ? ` - ${document.description}` : "";
1656
1720
  lines.push(`- [${document.navTitle}](${documentUrl})${description}`);
@@ -1662,7 +1726,7 @@ var DoculaBuilder = class {
1662
1726
  lines.push("## API Reference");
1663
1727
  if (data.hasApi) {
1664
1728
  lines.push(
1665
- `- [API Documentation](${this.buildAbsoluteSiteUrl(data.siteUrl, "/api")})`
1729
+ `- [API Documentation](${this.buildAbsoluteSiteUrl(data.siteUrl, data.apiUrl)})`
1666
1730
  );
1667
1731
  } else {
1668
1732
  lines.push("- Not available.");
@@ -1671,12 +1735,12 @@ var DoculaBuilder = class {
1671
1735
  lines.push("## Changelog");
1672
1736
  if (data.hasChangelog) {
1673
1737
  lines.push(
1674
- `- [Changelog](${this.buildAbsoluteSiteUrl(data.siteUrl, "/changelog")})`
1738
+ `- [Changelog](${this.buildAbsoluteSiteUrl(data.siteUrl, data.changelogUrl)})`
1675
1739
  );
1676
1740
  for (const entry of changelogEntries.slice(0, 20)) {
1677
1741
  const date = entry.formattedDate || entry.date || "No date";
1678
1742
  lines.push(
1679
- `- [${entry.title}](${this.buildAbsoluteSiteUrl(data.siteUrl, `/changelog/${entry.slug}`)}) (${date})`
1743
+ `- [${entry.title}](${this.buildAbsoluteSiteUrl(data.siteUrl, `${data.changelogUrl}/${entry.slug}`)}) (${date})`
1680
1744
  );
1681
1745
  }
1682
1746
  } else {
@@ -1694,7 +1758,7 @@ var DoculaBuilder = class {
1694
1758
  lines.push(data.siteDescription);
1695
1759
  lines.push("");
1696
1760
  lines.push(
1697
- `Source Index: ${this.buildAbsoluteSiteUrl(data.siteUrl, "/llms.txt")}`
1761
+ `Source Index: ${this.buildAbsoluteSiteUrl(data.siteUrl, `${data.baseUrl}/llms.txt`)}`
1698
1762
  );
1699
1763
  lines.push("");
1700
1764
  lines.push("## Documentation");
@@ -1702,7 +1766,7 @@ var DoculaBuilder = class {
1702
1766
  for (const document of documents) {
1703
1767
  const documentUrl = this.buildAbsoluteSiteUrl(
1704
1768
  data.siteUrl,
1705
- this.normalizePathForUrl(document.urlPath)
1769
+ `${data.baseUrl}${this.normalizePathForUrl(document.urlPath)}`
1706
1770
  );
1707
1771
  const markdownBody = new Writr(document.content).body.trim();
1708
1772
  lines.push("");
@@ -1720,7 +1784,9 @@ var DoculaBuilder = class {
1720
1784
  lines.push("");
1721
1785
  lines.push("## API Reference");
1722
1786
  if (data.hasApi) {
1723
- lines.push(`URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, "/api")}`);
1787
+ lines.push(
1788
+ `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, data.apiUrl)}`
1789
+ );
1724
1790
  lines.push("");
1725
1791
  const localOpenApiSpec = await this.getSafeLocalOpenApiSpec(data);
1726
1792
  if (localOpenApiSpec) {
@@ -1742,13 +1808,13 @@ var DoculaBuilder = class {
1742
1808
  lines.push("## Changelog");
1743
1809
  if (data.hasChangelog && changelogEntries.length > 0) {
1744
1810
  lines.push(
1745
- `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, "/changelog")}`
1811
+ `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, data.changelogUrl)}`
1746
1812
  );
1747
1813
  for (const entry of changelogEntries) {
1748
1814
  lines.push("");
1749
1815
  lines.push(`### ${entry.title}`);
1750
1816
  lines.push(
1751
- `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, `/changelog/${entry.slug}`)}`
1817
+ `URL: ${this.buildAbsoluteSiteUrl(data.siteUrl, `${data.changelogUrl}/${entry.slug}`)}`
1752
1818
  );
1753
1819
  if (entry.formattedDate || entry.date) {
1754
1820
  lines.push(`Date: ${entry.formattedDate || entry.date}`);
@@ -1765,6 +1831,16 @@ var DoculaBuilder = class {
1765
1831
  lines.push("");
1766
1832
  return lines.join("\n");
1767
1833
  }
1834
+ buildUrlPath(...segments) {
1835
+ const cleaned = segments.filter((s) => Boolean(s)).map((s) => {
1836
+ let start = 0;
1837
+ let end = s.length;
1838
+ while (start < end && s[start] === "/") start++;
1839
+ while (end > start && s[end - 1] === "/") end--;
1840
+ return s.slice(start, end);
1841
+ });
1842
+ return `/${cleaned.filter(Boolean).join("/")}`;
1843
+ }
1768
1844
  buildAbsoluteSiteUrl(siteUrl, urlPath) {
1769
1845
  const normalizedSiteUrl = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
1770
1846
  const normalizedPath = urlPath.startsWith("/") ? urlPath : `/${urlPath}`;
@@ -1949,7 +2025,9 @@ var DoculaBuilder = class {
1949
2025
  async buildDocsPages(data) {
1950
2026
  if (data.templates && data.documents?.length) {
1951
2027
  const documentsTemplate = `${data.templatePath}/${data.templates.docPage}`;
1952
- await fs3.promises.mkdir(`${data.output}/docs`, { recursive: true });
2028
+ const resolvedDocsPath = data.docsPath;
2029
+ const docsOutputDir = resolvedDocsPath ? `${data.output}/${resolvedDocsPath}` : `${data.output}`;
2030
+ await fs3.promises.mkdir(docsOutputDir, { recursive: true });
1953
2031
  data.sidebarItems = this.generateSidebarItems(data);
1954
2032
  const promises = data.documents.map(async (document) => {
1955
2033
  const folder = document.urlPath.split("/").slice(0, -1).join("/");
@@ -1974,7 +2052,7 @@ var DoculaBuilder = class {
1974
2052
  throw new Error("No API template or openApiUrl found");
1975
2053
  }
1976
2054
  const swaggerSource = `${data.sitePath}/api/swagger.json`;
1977
- const apiOutputPath = `${data.output}/api`;
2055
+ const apiOutputPath = `${data.output}/${data.apiPath}`;
1978
2056
  await fs3.promises.mkdir(apiOutputPath, { recursive: true });
1979
2057
  if (fs3.existsSync(swaggerSource)) {
1980
2058
  await fs3.promises.copyFile(
@@ -2016,7 +2094,7 @@ var DoculaBuilder = class {
2016
2094
  if (!data.openApiUrl || !data.templates?.api) {
2017
2095
  return;
2018
2096
  }
2019
- const apiPath = `${data.output}/api/index.html`;
2097
+ const apiPath = `${data.output}/${data.apiPath}/index.html`;
2020
2098
  const apiContent = await this.renderApiContent(data);
2021
2099
  await fs3.promises.writeFile(apiPath, apiContent, "utf8");
2022
2100
  }
@@ -2103,7 +2181,7 @@ var DoculaBuilder = class {
2103
2181
  generatedHtml: new Writr(markdownContent).renderSync({ mdx: isMdx }),
2104
2182
  preview: this.generateChangelogPreview(markdownContent, 500, isMdx),
2105
2183
  previewImage,
2106
- urlPath: `/changelog/${slug}/index.html`,
2184
+ urlPath: `/${this.options.changelogPath}/${slug}/index.html`,
2107
2185
  lastModified: fs3.statSync(filePath).mtime.toISOString().split("T")[0]
2108
2186
  };
2109
2187
  }
@@ -2200,7 +2278,7 @@ var DoculaBuilder = class {
2200
2278
  content: body,
2201
2279
  generatedHtml: new Writr(body).renderSync(),
2202
2280
  preview: this.generateChangelogPreview(body),
2203
- urlPath: `/changelog/${slug}/index.html`,
2281
+ urlPath: `/${this.options.changelogPath}/${slug}/index.html`,
2204
2282
  lastModified: dateString
2205
2283
  };
2206
2284
  }
@@ -2226,7 +2304,8 @@ var DoculaBuilder = class {
2226
2304
  for (let page = 1; page <= totalPages; page++) {
2227
2305
  const startIndex = (page - 1) * perPage;
2228
2306
  const pageEntries = allEntries.slice(startIndex, startIndex + perPage);
2229
- const outputPath = page === 1 ? `${data.output}/changelog` : `${data.output}/changelog/page/${page}`;
2307
+ const changelogOutputBase = `${data.output}/${data.changelogPath}`;
2308
+ const outputPath = page === 1 ? changelogOutputBase : `${changelogOutputBase}/page/${page}`;
2230
2309
  const indexPath = `${outputPath}/index.html`;
2231
2310
  const paginationData = {
2232
2311
  ...data,
@@ -2236,8 +2315,8 @@ var DoculaBuilder = class {
2236
2315
  hasPagination: totalPages > 1,
2237
2316
  hasNextPage: page < totalPages,
2238
2317
  hasPrevPage: page > 1,
2239
- nextPageUrl: page < totalPages ? `/changelog/page/${page + 1}/` : "",
2240
- prevPageUrl: page > 1 ? page === 2 ? "/changelog/" : `/changelog/page/${page - 1}/` : ""
2318
+ nextPageUrl: page < totalPages ? `${data.changelogUrl}/page/${page + 1}/` : "",
2319
+ prevPageUrl: page > 1 ? page === 2 ? `${data.changelogUrl}/` : `${data.changelogUrl}/page/${page - 1}/` : ""
2241
2320
  };
2242
2321
  promises.push(
2243
2322
  (async () => {
@@ -2259,7 +2338,7 @@ var DoculaBuilder = class {
2259
2338
  }
2260
2339
  const entryTemplate = `${data.templatePath}/${data.templates.changelogEntry}`;
2261
2340
  const promises = data.changelogEntries.map(async (entry) => {
2262
- const entryOutputPath = `${data.output}/changelog/${entry.slug}`;
2341
+ const entryOutputPath = `${data.output}/${data.changelogPath}/${entry.slug}`;
2263
2342
  await fs3.promises.mkdir(entryOutputPath, { recursive: true });
2264
2343
  const entryContent = await this._ecto.renderFromFile(
2265
2344
  entryTemplate,
@@ -2281,7 +2360,7 @@ var DoculaBuilder = class {
2281
2360
  for (const document of data.documents ?? []) {
2282
2361
  if (document.isRoot) {
2283
2362
  sidebarItems.unshift({
2284
- path: document.urlPath.replace("index.html", ""),
2363
+ path: `${data.baseUrl}${document.urlPath.replace("index.html", "")}`,
2285
2364
  name: document.navTitle,
2286
2365
  order: document.order
2287
2366
  });
@@ -2303,7 +2382,7 @@ var DoculaBuilder = class {
2303
2382
  }
2304
2383
  sidebarItems[sectionIndex].children ??= [];
2305
2384
  sidebarItems[sectionIndex].children.push({
2306
- path: document.urlPath.replace("index.html", ""),
2385
+ path: `${data.baseUrl}${document.urlPath.replace("index.html", "")}`,
2307
2386
  name: document.navTitle,
2308
2387
  order: document.order
2309
2388
  });
@@ -2425,13 +2504,19 @@ var DoculaBuilder = class {
2425
2504
  const isMdx = documentPath.endsWith(".mdx");
2426
2505
  const fileExtension = isMdx ? ".mdx" : ".md";
2427
2506
  const documentsFolderIndex = documentPath.lastIndexOf("/docs/");
2428
- let urlPath = documentPath.slice(documentsFolderIndex).replace(fileExtension, "/index.html");
2429
- let isRoot = urlPath.split("/").length === 3;
2430
- if (!documentPath.slice(documentsFolderIndex + 6).includes("/")) {
2431
- isRoot = true;
2432
- const filePath = documentPath.slice(documentsFolderIndex + 6);
2433
- if (filePath === "index.md" || filePath === "index.mdx") {
2434
- urlPath = documentPath.slice(documentsFolderIndex).replace(fileExtension, ".html");
2507
+ const relativePath = documentPath.slice(documentsFolderIndex + 6);
2508
+ const docsPrefix = this.options.docsPath ? `/${this.options.docsPath}` : "";
2509
+ let urlPath = `${docsPrefix}/${relativePath}`.replace(
2510
+ fileExtension,
2511
+ "/index.html"
2512
+ );
2513
+ const isRoot = !relativePath.includes("/");
2514
+ if (isRoot) {
2515
+ if (relativePath === "index.md" || relativePath === "index.mdx") {
2516
+ urlPath = `${docsPrefix}/${relativePath}`.replace(
2517
+ fileExtension,
2518
+ ".html"
2519
+ );
2435
2520
  }
2436
2521
  }
2437
2522
  if (!this.hasTableOfContents(markdownContent)) {
@@ -2801,7 +2886,11 @@ ${entry}
2801
2886
  openApiUrl: this.options.openApiUrl,
2802
2887
  themeMode: this.options.themeMode,
2803
2888
  cookieAuth: this.options.cookieAuth,
2804
- headerLinks: this.options.headerLinks
2889
+ headerLinks: this.options.headerLinks,
2890
+ baseUrl: this.options.baseUrl,
2891
+ docsPath: this.options.docsPath,
2892
+ apiPath: this.options.apiPath,
2893
+ changelogPath: this.options.changelogPath
2805
2894
  };
2806
2895
  return this._hash.toHashSync(JSON.stringify(relevant));
2807
2896
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docula",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Beautiful Website for Your Projects",
5
5
  "type": "module",
6
6
  "main": "./dist/docula.js",
@@ -3,7 +3,7 @@
3
3
 
4
4
  <head>
5
5
  {{> header }}
6
- <link rel="stylesheet" href="/css/api.css">
6
+ <link rel="stylesheet" href="{{baseUrl}}/css/api.css">
7
7
  <title>API Reference - {{ siteTitle }}</title>
8
8
  <meta name="description" content="API Reference for {{ siteTitle }}" />
9
9
  </head>
@@ -250,7 +250,7 @@
250
250
  {{> footer }}
251
251
  {{> scripts }}
252
252
 
253
- <script src="/js/api.js"></script>
253
+ <script src="{{baseUrl}}/js/api.js"></script>
254
254
  </body>
255
255
 
256
256
  </html>
@@ -12,7 +12,7 @@
12
12
  <main class="versions-container">
13
13
  <div class="versions-content">
14
14
  <div class="changelog-entry-nav">
15
- <a href="/changelog/">&larr; Back to Changelog</a>
15
+ <a href="{{changelogUrl}}/">&larr; Back to Changelog</a>
16
16
  </div>
17
17
  <div class="changelog-entry changelog-entry-single">
18
18
  <div class="changelog-entry-header">
@@ -16,7 +16,7 @@
16
16
  {{#each entries as |entry|}}
17
17
  <div class="changelog-entry">
18
18
  <div class="changelog-entry-header">
19
- <a class="changelog-entry-title" href="/changelog/{{entry.slug}}/">{{entry.title}}</a>
19
+ <a class="changelog-entry-title" href="{{changelogUrl}}/{{entry.slug}}/">{{entry.title}}</a>
20
20
  {{#if entry.tag}}
21
21
  <span class="changelog-tag changelog-tag-{{entry.tagClass}}">{{entry.tag}}</span>
22
22
  {{/if}}
@@ -3,7 +3,7 @@
3
3
 
4
4
  <head>
5
5
  {{> header }}
6
- <link rel="stylesheet" href="/css/home.css">
6
+ <link rel="stylesheet" href="{{baseUrl}}/css/home.css">
7
7
  <title>{{ siteTitle }}</title>
8
8
  </head>
9
9
 
@@ -24,7 +24,7 @@
24
24
 
25
25
  {{#if content}}
26
26
  <header class="home-hero">
27
- <img src="/logo.svg" alt="logo" />
27
+ <img src="{{baseUrl}}/logo.svg" alt="logo" />
28
28
  {{#if announcement}}
29
29
  <div class="announcement">{{{announcement}}}</div>
30
30
  {{/if}}
@@ -1 +1 @@
1
- <a href="/api" class="home-docs-button">API Reference</a>
1
+ <a href="{{apiUrl}}" class="home-docs-button">API Reference</a>
@@ -1 +1 @@
1
- <a href="/docs" class="home-docs-button">Documentation</a>
1
+ <a href="{{docsUrl}}" class="home-docs-button">Documentation</a>
@@ -1,9 +1,9 @@
1
1
  <footer>
2
2
  {{#if enableLlmsTxt}}
3
- <a href="/llms.txt" class="footer__link">llms.txt</a>
3
+ <a href="{{baseUrl}}/llms.txt" class="footer__link">llms.txt</a>
4
4
  {{/if}}
5
5
  {{#if hasFeed}}
6
- <a href="/feed.xml" class="footer__link" aria-label="RSS Feed">
6
+ <a href="{{baseUrl}}/feed.xml" class="footer__link" aria-label="RSS Feed">
7
7
  <svg class="footer__icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><circle cx="6.18" cy="17.82" r="2.18"/><path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/></svg>
8
8
  </a>
9
9
  {{/if}}
@@ -4,24 +4,24 @@
4
4
  <button class="mobile-menu-toggle" id="mobile-menu-toggle" aria-label="Toggle navigation menu">
5
5
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/></svg>
6
6
  </button>
7
- <a href="/">
8
- <img alt="{{siteTitle}}" class="logo__img" src="/logo.svg">
7
+ <a href="{{baseUrl}}/">
8
+ <img alt="{{siteTitle}}" class="logo__img" src="{{baseUrl}}/logo.svg">
9
9
  </a>
10
10
  <nav class="header-bottom__nav">
11
11
  {{#if hasDocuments}}
12
- <a class="header-bottom__item" href="/docs/" id="nav-docs">
12
+ <a class="header-bottom__item" href="{{docsUrl}}/" id="nav-docs">
13
13
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>
14
14
  <span>Documentation</span>
15
15
  </a>
16
16
  {{/if}}
17
17
  {{#if openApiUrl}}
18
- <a class="header-bottom__item" href="/api" id="nav-api">
18
+ <a class="header-bottom__item" href="{{apiUrl}}" id="nav-api">
19
19
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/></svg>
20
20
  <span>API Reference</span>
21
21
  </a>
22
22
  {{/if}}
23
23
  {{#if hasChangelog}}
24
- <a class="header-bottom__item" href="/changelog" id="nav-changelog">
24
+ <a class="header-bottom__item" href="{{changelogUrl}}" id="nav-changelog">
25
25
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z"/><path d="M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14"/><path d="M8 6v8"/></svg>
26
26
  <span>Changelog</span>
27
27
  </a>
@@ -68,19 +68,19 @@
68
68
  <aside class="mobile-sidebar" id="mobile-sidebar">
69
69
  <nav class="mobile-nav">
70
70
  {{#if hasDocuments}}
71
- <a class="mobile-nav__item" href="/docs/">
71
+ <a class="mobile-nav__item" href="{{docsUrl}}/">
72
72
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>
73
73
  <span>Documentation</span>
74
74
  </a>
75
75
  {{/if}}
76
76
  {{#if openApiUrl}}
77
- <a class="mobile-nav__item" href="/api">
77
+ <a class="mobile-nav__item" href="{{apiUrl}}">
78
78
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m16 18 6-6-6-6"/><path d="m8 6-6 6 6 6"/></svg>
79
79
  <span>API Reference</span>
80
80
  </a>
81
81
  {{/if}}
82
82
  {{#if hasChangelog}}
83
- <a class="mobile-nav__item" href="/changelog">
83
+ <a class="mobile-nav__item" href="{{changelogUrl}}">
84
84
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 6a13 13 0 0 0 8.4-2.8A1 1 0 0 1 21 4v12a1 1 0 0 1-1.6.8A13 13 0 0 0 11 14H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z"/><path d="M6 14a12 12 0 0 0 2.4 7.2 2 2 0 0 0 3.2-2.4A8 8 0 0 1 10 14"/><path d="M8 6v8"/></svg>
85
85
  <span>Changelog</span>
86
86
  </a>
@@ -1,10 +1,10 @@
1
1
  <meta charset="UTF-8">
2
2
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3
3
  <meta name="description" content="{{siteDescription}}">
4
- <link rel="stylesheet" href="/css/variables.css">
5
- <link rel="stylesheet" href="/css/styles.css">
6
- <link rel="stylesheet" href="/css/highlight/styles/base16/docula.css">
7
- <link rel="icon" href="/favicon.ico">
4
+ <link rel="stylesheet" href="{{baseUrl}}/css/variables.css">
5
+ <link rel="stylesheet" href="{{baseUrl}}/css/styles.css">
6
+ <link rel="stylesheet" href="{{baseUrl}}/css/highlight/styles/base16/docula.css">
7
+ <link rel="icon" href="{{baseUrl}}/favicon.ico">
8
8
  <script>
9
9
  (function(){
10
10
  window.__doculaThemeKey = 'docula:theme:' + ({{#if siteUrl}}'{{siteUrl}}'{{else}}location.origin{{/if}}).replace(/^https?:\/\//, '');
@@ -34,7 +34,7 @@
34
34
 
35
35
  {{#if (gt github.releases.length 6)}}
36
36
  <div>
37
- <a class="release-btn" href="/changelog">
37
+ <a class="release-btn" href="{{changelogUrl}}">
38
38
  Full Changelog
39
39
  <span>&rarr;</span>
40
40
  </a>
@@ -1,4 +1,4 @@
1
- <script src="/css/highlight/highlight.min.js"></script>
1
+ <script src="{{baseUrl}}/css/highlight/highlight.min.js"></script>
2
2
  <script>
3
3
  document.addEventListener('DOMContentLoaded', () => {
4
4
  document.querySelectorAll('pre code').forEach(el => { el.textContent = el.textContent.trimEnd(); });