Skip to content

brillout/docpress

Repository files navigation

DocPress

Documentation website builder.

Used for:

  • https://vike.dev
  • https://telefunc.com

Don't use this: this package isn't meant for others to use. It's only meant to be used by Vike and Telefunc. That said, feel free to fork this project.

GitHub Pages Integration

  1. Change DNS settings of domain name to add following A records:
    A     @     185.199.108.153
    A     @     185.199.109.153
    A     @     185.199.110.153
    A     @     185.199.111.153
    
    See also: GitHub Docs.
  2. Add GitHub workflow: .github/workflows/website.yml.
  3. Configure GitHub Settings > Pages

Algolia DocSearch: Custom Crawler Configs

vike-crawler.js
new Crawler({
  appId: "YOUR_APP_ID",
  apiKey: "YOUR_API_KEY",
  rateLimit: 8,
  maxDepth: 10,
  startUrls: ["https://vike.dev"],
  renderJavaScript: false,
  sitemaps: [],
  ignoreCanonicalTo: false,
  discoveryPatterns: ["https://vike.dev/**"],
  schedule: "at 13:29 on Tuesday",
  safetyChecks: { beforeIndexPublishing: { maxLostRecordsPercentage: 10 } },
  actions: [
    {
      indexName: "YOUR_INDEX_NAME",
      pathsToMatch: ["https://vike.dev/**"],
      recordExtractor: ({ $, helpers, url }) => {
        const seeAlsoSection = $("#see-also");
        if (seeAlsoSection.length) {
          seeAlsoSection.remove();
          seeAlsoSection.nextAll().remove();
        }

        const category = $('meta[name="algolia:category"]').attr("content") || "";
        const category_order = parseInt($('meta[name="algolia:category:order"]').attr("content") || "99999999999", 10);

        const records = helpers.docsearch({
          recordProps: {
            lvl0: { selectors: "", defaultValue: category.toUpperCase() },
            lvl1: url.toString() === "https://vike.dev/" ? "head > title" : ".page-content h1",
            lvl2: ".page-content h2",
            lvl3: ".page-content h3",
            lvl4: ".page-content h4",
            lvl5: ".page-content h5",
            lvl6: ".page-content h6",
            content: [".page-content p, .page-content li, .page-content pre"],
            category: { defaultValue: category || "" },
            category_order: { defaultValue: "" },
            pageRank: -1 * category_order,
          },
          indexHeadings: true,
          aggregateContent: true,
          recordVersion: "v3",
        });

        records.forEach((record) => {
          if ( record.content === null && (record.type === "lvl2" || record.type === "lvl3" || record.type === "lvl4")) {
            if (record.anchor) {
              const content =
                $(`#${record.anchor}`).next().text().trim() || null;
              record.content = content;
            }
          }

          record.category_order = category_order;

          record.is_available = Boolean($('meta[name="algolia:category:hide"]').length === 0);
        });

        return records;
      },
    },
  ],
  initialIndexSettings: {
    vike: {
      attributesForFaceting: [
        "filterOnly(is_available)",
        "category",
        "lang",
        "type",
      ],
      attributesToRetrieve: [
        "anchor",
        "category",
        "category_order",
        "content",
        "hierarchy",
        "type",
        "url",
        "url_without_anchor",
      ],
      attributesToHighlight: ["content", "hierarchy"],
      attributesToSnippet: ["content:10"],
      camelCaseAttributes: ["content", "hierarchy"],
      searchableAttributes: [
        "unordered(hierarchy.lvl1)",
        "unordered(hierarchy.lvl2)",
        "unordered(hierarchy.lvl3)",
        "unordered(hierarchy.lvl4)",
        "unordered(content)",
      ],
      distinct: true,
      attributeForDistinct: "url",
      customRanking: [
        "desc(weight.pageRank)",
        "desc(weight.level)",
        "asc(weight.position)",
      ],
      ranking: [
        "typo",
        "words",
        "filters",
        "asc(category_order)",
        "attribute",
        "proximity",
        "exact",
        "custom",
      ],
      disableExactOnAttributes: ["hierarchy.lvl2"],
      highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
      highlightPostTag: "</span>",
      allowTyposOnNumericTokens: false,
      minProximity: 1,
      ignorePlurals: true,
      advancedSyntax: true,
      attributeCriteriaComputedByMinProximity: true,
      removeWordsIfNoResults: "allOptional",
    },
  },
});

diff default-crawler.js vike-crawler.js

diff default-crawler.js vike-crawler.js
--- a/default-crawler.js
+++ b/vike-crawler.js
 new Crawler({
   appId: "YOUR_APP_ID",
   apiKey: "YOUR_API_KEY",
-  indexPrefix: "crawler_",
   rateLimit: 8,
   maxDepth: 10,
-  startUrls: ["https://YOUR_WEBSITE_URL"],
+  startUrls: ["https://vike.dev"],
   renderJavaScript: false,
   sitemaps: [],
   ignoreCanonicalTo: false,
-  discoveryPatterns: ["https://YOUR_WEBSITE_URL/**"],
+  discoveryPatterns: ["https://vike.dev/**"],
+  schedule: "at 13:29 on Tuesday",
+  safetyChecks: { beforeIndexPublishing: { maxLostRecordsPercentage: 10 } },
   actions: [
     {
       indexName: "YOUR_INDEX_NAME",
-      pathsToMatch: ["https://YOUR_WEBSITE_URL/**"],
-      recordExtractor: ({ helpers }) => {
-        return helpers.docsearch({
+      pathsToMatch: ["https://vike.dev/**"],
+      recordExtractor: ({ $, helpers, url }) => {
+        $("#see-also").next("ul").remove();
+        $("#see-also").remove();
+
+        const lvl0 = $('meta[name="algolia:category"]').attr("content").toUpperCase();
+
+        const category_order = Number($('meta[name="algolia:category:order"]').attr("content") || "99999999999");
+
+        const records = helpers.docsearch({
           recordProps: {
-            lvl1: ["header h1", "article h1", "main h1", "h1", "head > title"],
-            content: ["article p, article li", "main p, main li", "p, li"],
-            lvl0: {
-              selectors: "",
-              defaultValue: "Documentation",
-            },
-            lvl2: ["article h2", "main h2", "h2"],
-            lvl3: ["article h3", "main h3", "h3"],
-            lvl4: ["article h4", "main h4", "h4"],
-            lvl5: ["article h5", "main h5", "h5"],
-            lvl6: ["article h6", "main h6", "h6"],
+            lvl0: { selectors: "", defaultValue: lvl0 },
+            lvl1: url.toString() === "https://vike.dev/" ? "head > title" : ".page-content h1",
+            lvl2: ".page-content h2",
+            lvl3: ".page-content h3",
+            lvl4: ".page-content h4",
+            lvl5: ".page-content h5",
+            lvl6: ".page-content h6",
+            content: [".page-content p, .page-content li, .page-content pre"],
+            category: { defaultValue: $('meta[name="algolia:category"]').attr("content") || "" },
+            pageRank: -1 * category_order,
           },
+          indexHeadings: true,
           aggregateContent: true,
           recordVersion: "v3",
         });
+
+        records.forEach((record) => {
+          if ( record.content === null && (record.type === "lvl2" || record.type === "lvl3" || record.type === "lvl4")) {
+            if (record.anchor) {
+              const content =
+                $(`#${record.anchor}`).next().text().trim() || null;
+              record.content = content;
+            }
+          }
+
+          record.category_order = category_order;
+
+          record.is_available = Boolean($('meta[name="algolia:category:hide"]').length === 0);
+        });
+
+        return records;
       },
     },
   ],
   initialIndexSettings: {
-    YOUR_INDEX_NAME: {
-      attributesForFaceting: ["type", "lang"],
+    vike: {
+      attributesForFaceting: ["filterOnly(is_available)", "type", "lang"],
       attributesToRetrieve: [
         "hierarchy",
         "content",
         "url",
         "url_without_anchor",
         "type",
+        "category",
+        "category_order",
       ],
       attributesToHighlight: ["hierarchy", "content"],
       attributesToSnippet: ["content:10"],
-        "unordered(hierarchy.lvl0)",
         "unordered(hierarchy.lvl1)",
         "unordered(hierarchy.lvl2)",
         "unordered(hierarchy.lvl3)",
         "unordered(hierarchy.lvl4)",
-        "unordered(hierarchy.lvl5)",
-        "unordered(hierarchy.lvl6)",
         "content",
       ],
       distinct: true,
       attributeForDistinct: "url",
       customRanking: [
+        "asc(category_order)",
         "desc(weight.pageRank)",
         "desc(weight.level)",
         "asc(weight.position)",
       ],
       ranking: [
+        "typo",
         "words",
         "filters",
-        "typo",
         "attribute",
         "proximity",
         "exact",
         "custom",
       ],
+      disableExactOnAttributes: ["hierarchy.lvl2"],
       highlightPreTag: '<span class="algolia-docsearch-suggestion--highlight">',
       highlightPostTag: "</span>",
-      minWordSizefor1Typo: 3,
-      minWordSizefor2Typos: 7,
       allowTyposOnNumericTokens: false,
       minProximity: 1,
       ignorePlurals: true,
       advancedSyntax: true,
       attributeCriteriaComputedByMinProximity: true,
       removeWordsIfNoResults: "allOptional",
     },
   },
 });

Detype

DocPress automatically converts ts code blocks to js (using detype), while showing a JS↔TS toggle to users.

Custom meta and comments:

  • Use ts-only meta to skip transforming typescript code.

  • Use hide-menu meta to hide the copy button.

  • To transform typescript code with invalid syntax (e.g. for code diffs), use custom magic comments:

    • Use // @docpress-replace dummyVarName varName above the affected line.
    • Use // @docpress-uncomment at the beginning of the affected line.
    const hello: string = 'world' // [!code --]
    // @docpress-replace dummyhello hello
    const dummyhello: string[] = ['hello', 'world'] // [!code ++]
    
    // @docpress-uncomment function greeting() { // [!code --]
    function greeting(name: string) { // [!code ++]
      // ...
    }

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors