Просмотр исходного кода

feat(docs): Styling & layout tweaks

Michael Bromley 7 лет назад
Родитель
Сommit
200ccc09dc

+ 2 - 2
.gitignore

@@ -397,5 +397,5 @@ docs/resources/_gen/*
 docs/static/main.js
 docs/static/main.css
 docs/public
-docs/content/docs/api/
-!docs/content/docs/api/_index.md
+docs/content/docs/configuration/*
+!docs/content/docs/configuration/_index.md

+ 146 - 43
codegen/generate-docs.ts

@@ -3,7 +3,17 @@ import klawSync from 'klaw-sync';
 import path from 'path';
 import ts from 'typescript';
 
-import { notNullOrUndefined } from '../shared/shared-utils';
+import { assertNever, notNullOrUndefined } from '../shared/shared-utils';
+
+// The absolute URL to the generated docs section
+const docsUrl = '/docs/configuration/';
+// The directory in which the markdown files will be saved
+const outputPath = path.join(__dirname, '../docs/content/docs/configuration');
+// The directories to scan for TypeScript source files
+const tsSourceDirs = [
+    '/server/src/',
+    '/shared/',
+];
 
 // tslint:disable:no-console
 interface MethodParameterInfo {
@@ -44,28 +54,33 @@ interface InterfaceInfo extends DeclarationInfo {
     members: Array<PropertyInfo | MethodInfo>;
 }
 
+interface ClassInfo extends DeclarationInfo {
+    kind: 'class';
+    members: Array<PropertyInfo | MethodInfo>;
+}
+
 interface TypeAliasInfo extends DeclarationInfo {
     kind: 'typeAlias';
     type: string;
 }
 
-type ValidDeclaration = ts.InterfaceDeclaration | ts.TypeAliasDeclaration;
+type ValidDeclaration = ts.InterfaceDeclaration | ts.TypeAliasDeclaration | ts.ClassDeclaration;
 type TypeMap = Map<string, string>;
 
-const docsPath = '/docs/api/';
-const outputPath = path.join(__dirname, '../docs/content/docs/api');
-
 /**
  * This map is used to cache types and their corresponding Hugo path. It is used to enable
  * hyperlinking from a member's "type" to the definition of that type.
  */
 const globalTypeMap: TypeMap = new Map();
 
-const tsFiles = klawSync(path.join(__dirname, '../server/src/'), {
-    nodir: true,
-    filter: item => path.extname(item.path) === '.ts',
-    traverseAll: true,
-}).map(item => item.path);
+const tsFiles = tsSourceDirs
+    .map(scanPath => klawSync( path.join(__dirname, '../', scanPath), {
+        nodir: true,
+        filter: item => path.extname(item.path) === '.ts',
+        traverseAll: true,
+    }))
+    .reduce((allFiles, files) => [...allFiles, ...files], [])
+    .map(item => item.path);
 
 deleteGeneratedDocs();
 generateDocs(tsFiles, outputPath, globalTypeMap);
@@ -133,11 +148,16 @@ function generateDocs(filePaths: string[], hugoApiDocsPath: string, typeMap: Typ
         let markdown = '';
         switch (info.kind) {
             case 'interface':
-                markdown = renderInterface(info, typeMap);
+                markdown = renderInterfaceOrClass(info, typeMap);
                 break;
             case 'typeAlias':
                 markdown = renderTypeAlias(info, typeMap);
                 break;
+            case 'class':
+                markdown = renderInterfaceOrClass(info as any, typeMap);
+                break;
+            default:
+                assertNever(info);
         }
 
         const categoryDir = path.join(hugoApiDocsPath, info.category);
@@ -162,25 +182,30 @@ function generateDocs(filePaths: string[], hugoApiDocsPath: string, typeMap: Typ
  * Maps an array of parsed SourceFiles into statements, including a reference to the original file each statement
  * came from.
  */
-function getStatementsWithSourceLocation(sourceFiles: ts.SourceFile[]): Array<{ statement: ts.Statement; sourceFile: string; sourceLine: number; }> {
+function getStatementsWithSourceLocation(
+    sourceFiles: ts.SourceFile[],
+): Array<{ statement: ts.Statement; sourceFile: string; sourceLine: number }> {
     return sourceFiles.reduce(
         (st, sf) => {
             const statementsWithSources = sf.statements.map(statement => {
-                const serverSourceRoot = '/server/src';
-                const sourceFile = sf.fileName.substring(sf.fileName.indexOf(serverSourceRoot));
+                const sourceFile = path.relative(path.join(__dirname, '..'), sf.fileName).replace(/\\/g, '/');
                 const sourceLine = sf.getLineAndCharacterOfPosition(statement.getStart()).line + 1;
-                return {statement, sourceFile, sourceLine };
+                return { statement, sourceFile, sourceLine };
             });
             return [...st, ...statementsWithSources];
         },
-        [] as Array<{ statement: ts.Statement; sourceFile: string, sourceLine: number; }>,
+        [] as Array<{ statement: ts.Statement; sourceFile: string; sourceLine: number }>,
     );
 }
 
 /**
  * Parses an InterfaceDeclaration into a simple object which can be rendered into markdown.
  */
-function parseDeclaration(statement: ts.Statement, sourceFile: string, sourceLine: number): InterfaceInfo | TypeAliasInfo | undefined {
+function parseDeclaration(
+    statement: ts.Statement,
+    sourceFile: string,
+    sourceLine: number,
+): InterfaceInfo | TypeAliasInfo | ClassInfo | undefined {
     if (!isValidDeclaration(statement)) {
         return;
     }
@@ -188,7 +213,7 @@ function parseDeclaration(statement: ts.Statement, sourceFile: string, sourceLin
     if (category === undefined) {
         return;
     }
-    const title = statement.name.getText();
+    const title = statement.name ? statement.name.getText() : 'anonymous';
     const fullText = getDeclarationFullText(statement);
     const weight = getDeclarationWeight(statement);
     const description = getDeclarationDescription(statement);
@@ -217,9 +242,15 @@ function parseDeclaration(statement: ts.Statement, sourceFile: string, sourceLin
     } else if (ts.isTypeAliasDeclaration(statement)) {
         return {
             ...info,
-            type: statement.type.getFullText().trim(),
+            type: statement.type.getText().trim(),
             kind: 'typeAlias',
         };
+    } else if (ts.isClassDeclaration(statement)) {
+        return {
+            ...info,
+            kind: 'class',
+            members: parseMembers(statement.members),
+        };
     }
 }
 
@@ -227,7 +258,7 @@ function parseDeclaration(statement: ts.Statement, sourceFile: string, sourceLin
  * Returns the declaration name plus any type parameters.
  */
 function getDeclarationFullText(declaration: ValidDeclaration): string {
-    const name = declaration.name.getText();
+    const name = declaration.name ? declaration.name.getText() : 'anonymous';
     let typeParams = '';
     if (declaration.typeParameters) {
         typeParams = '<' + declaration.typeParameters.map(tp => tp.getText()).join(', ') + '>';
@@ -238,24 +269,43 @@ function getDeclarationFullText(declaration: ValidDeclaration): string {
 /**
  * Parses an array of inteface members into a simple object which can be rendered into markdown.
  */
-function parseMembers(members: ts.NodeArray<ts.TypeElement>): Array<PropertyInfo | MethodInfo> {
+function parseMembers(
+    members: ts.NodeArray<ts.TypeElement | ts.ClassElement>,
+): Array<PropertyInfo | MethodInfo> {
     const result: Array<PropertyInfo | MethodInfo> = [];
 
     for (const member of members) {
-        if (ts.isPropertySignature(member) || ts.isMethodSignature(member)) {
-            const name = member.name.getText();
+        const modifiers = member.modifiers ? member.modifiers.map(m => m.getText()) : [];
+        const isPrivate = modifiers.includes('private');
+        if (
+            !isPrivate && (
+            ts.isPropertySignature(member) ||
+            ts.isMethodSignature(member) ||
+            ts.isPropertyDeclaration(member) ||
+            ts.isMethodDeclaration(member) ||
+            ts.isConstructorDeclaration(member)
+            )
+        ) {
+            const name = member.name ? member.name.getText() : 'constructor';
             let description = '';
             let type = '';
             let defaultValue = '';
             let parameters: MethodParameterInfo[] = [];
-            const fullText = member.getText();
+            let fullText = '';
+            if (ts.isConstructorDeclaration(member)) {
+                fullText = 'constructor';
+            } else if (ts.isMethodDeclaration(member)) {
+                fullText = member.name.getText();
+            } else {
+                fullText = member.getText();
+            }
             parseTags(member, {
                 description: tag => (description += tag.comment || ''),
                 example: tag => (description += formatExampleCode(tag.comment)),
                 default: tag => (defaultValue = tag.comment || ''),
             });
             if (member.type) {
-                type = member.type.getFullText().trim();
+                type = member.type.getText();
             }
             const memberInfo: MemberInfo = {
                 fullText,
@@ -263,10 +313,14 @@ function parseMembers(members: ts.NodeArray<ts.TypeElement>): Array<PropertyInfo
                 description,
                 type,
             };
-            if (ts.isMethodSignature(member)) {
+            if (
+                ts.isMethodSignature(member) ||
+                ts.isMethodDeclaration(member) ||
+                ts.isConstructorDeclaration(member)
+            ) {
                 parameters = member.parameters.map(p => ({
                     name: p.name.getText(),
-                    type: p.type ? p.type.getFullText() : '',
+                    type: p.type ? p.type.getText() : '',
                 }));
                 result.push({
                     ...memberInfo,
@@ -289,15 +343,15 @@ function parseMembers(members: ts.NodeArray<ts.TypeElement>): Array<PropertyInfo
 /**
  * Render the interface to a markdown string.
  */
-function renderInterface(interfaceInfo: InterfaceInfo, knownTypeMap: Map<string, string>): string {
-    const { title, weight, category, description, members } = interfaceInfo;
+function renderInterfaceOrClass(info: InterfaceInfo | ClassInfo, knownTypeMap: Map<string, string>): string {
+    const { title, weight, category, description, members } = info;
     let output = '';
     output += generateFrontMatter(title, weight);
     output += `\n\n# ${title}\n\n`;
-    output += renderGenerationInfoShortcode(interfaceInfo);
-    output += `${description}\n\n`;
+    output += renderGenerationInfoShortcode(info);
+    output += `${renderDescription(description, knownTypeMap)}\n\n`;
     output += `## Signature\n\n`;
-    output += renderInterfaceSignature(interfaceInfo);
+    output += info.kind === 'interface' ? renderInterfaceSignature(info) : renderClassSignature(info);
     output += `## Members\n\n`;
 
     for (const member of members) {
@@ -312,11 +366,16 @@ function renderInterface(interfaceInfo: InterfaceInfo, knownTypeMap: Map<string,
                     return `${p.name}: ${renderType(p.type, knownTypeMap)}`;
                 })
                 .join(', ');
-            type = `(${args}) => ${renderType(member.type, knownTypeMap)}`;
+            if (member.fullText === 'constructor') {
+                type = `(${args}) => ${title}`;
+            } else {
+                type = `(${args}) => ${renderType(member.type, knownTypeMap)}`;
+            }
+
         }
         output += `### ${member.name}\n\n`;
         output += `{{< member-info kind="${member.kind}" type="${type}" ${defaultParam}>}}\n\n`;
-        output += `${member.description}\n\n`;
+        output += `${renderDescription(member.description, knownTypeMap)}\n\n`;
     }
 
     return output;
@@ -328,9 +387,36 @@ function renderInterface(interfaceInfo: InterfaceInfo, knownTypeMap: Map<string,
 function renderInterfaceSignature(interfaceInfo: InterfaceInfo): string {
     const { fullText, members } = interfaceInfo;
     let output = '';
-    output += `\`\`\`ts\n`;
+    output += `\`\`\`TypeScript\n`;
     output += `interface ${fullText} {\n`;
-    output += members.map(member => `  ${member.fullText}`).join(`\n`) ;
+    output += members.map(member => `  ${member.fullText}`).join(`\n`);
+    output += `\n}\n`;
+    output += `\`\`\`\n`;
+
+    return output;
+}
+
+function renderClassSignature(classInfo: ClassInfo): string {
+    const { fullText, members } = classInfo;
+    let output = '';
+    output += `\`\`\`TypeScript\n`;
+    output += `class ${fullText} {\n`;
+    output += members.map(member => {
+        if (member.kind === 'method') {
+            const args = member.parameters
+                .map(p => {
+                    return `${p.name}: ${p.type}`;
+                })
+                .join(', ');
+            if (member.fullText === 'constructor') {
+                return `  constructor(${args})`;
+            } else {
+                return `  ${member.fullText}(${args}) => ${member.type};`;
+            }
+        } else {
+            return `  ${member.fullText}`;
+        }
+    }).join(`\n`);
     output += `\n}\n`;
     output += `\`\`\`\n`;
 
@@ -346,9 +432,9 @@ function renderTypeAlias(typeAliasInfo: TypeAliasInfo, knownTypeMap: Map<string,
     output += generateFrontMatter(title, weight);
     output += `\n\n# ${title}\n\n`;
     output += renderGenerationInfoShortcode(typeAliasInfo);
-    output += `${description}\n\n`;
+    output += `${renderDescription(description, knownTypeMap)}\n\n`;
     output += `## Signature\n\n`;
-    output += `\`\`\`ts\ntype ${fullText} = ${type};\n\`\`\``;
+    output += `\`\`\`TypeScript\ntype ${fullText} = ${type};\n\`\`\``;
 
     return output;
 }
@@ -388,7 +474,7 @@ function parseTags<T extends ts.Node>(
  * This function takes a string representing a type (e.g. "Array<ShippingMethod>") and turns
  * and known types (e.g. "ShippingMethod") into hyperlinks.
  */
-function renderType(type: string, knownTypeMap: Map<string, string>): string {
+function renderType(type: string, knownTypeMap: TypeMap): string {
     let typeText = type
         .trim()
         // encode HTML entities
@@ -397,17 +483,29 @@ function renderType(type: string, knownTypeMap: Map<string, string>): string {
         .replace(/\n/g, ' ');
 
     for (const [key, val] of knownTypeMap) {
-        typeText = typeText.replace(key, `<a href='${docsPath}/${val}/'>${key}</a>`);
+        const re = new RegExp(`\\b${key}\\b`, 'g');
+        typeText = typeText.replace(re, `<a href='${docsUrl}/${val}/'>${key}</a>`);
     }
     return typeText;
 }
 
+/**
+ * Replaces any `{@link Foo}` references in the description with hyperlinks.
+ */
+function renderDescription(description: string, knownTypeMap: TypeMap): string {
+    for (const [key, val] of knownTypeMap) {
+        const re = new RegExp(`{@link\\s*${key}}`, 'g');
+        description = description.replace(re, `<a href='${docsUrl}/${val}/'>${key}</a>`);
+    }
+    return description;
+}
+
 /**
  * Generates the Hugo front matter with the title of the document
  */
 function generateFrontMatter(title: string, weight: number, showToc: boolean = true): string {
     return `---
-title: "${title}"
+title: "${title.replace('-', ' ')}"
 weight: ${weight}
 date: ${new Date().toISOString()}
 showtoc: ${showToc}
@@ -435,6 +533,7 @@ function getDeclarationDescription(statement: ValidDeclaration): string {
     let description = '';
     parseTags(statement, {
         description: tag => (description += tag.comment),
+        example: tag => (description += formatExampleCode(tag.comment)),
     });
     return description;
 }
@@ -444,12 +543,16 @@ function getDeclarationDescription(statement: ValidDeclaration): string {
  * wherein the asterisks are not stripped as they should be, see https://github.com/Microsoft/TypeScript/issues/23517)
  */
 function formatExampleCode(example: string = ''): string {
-    return '\n\n' + example.replace(/\n\s+\*\s/g, '');
+    return '\n\n*Example*\n\n' + example.replace(/\n\s+\*\s/g, '\n');
 }
 
 /**
  * Type guard for the types of statement which can ge processed by the doc generator.
  */
 function isValidDeclaration(statement: ts.Statement): statement is ValidDeclaration {
-    return ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement);
+    return (
+        ts.isInterfaceDeclaration(statement) ||
+        ts.isTypeAliasDeclaration(statement) ||
+        ts.isClassDeclaration(statement)
+    );
 }

+ 53 - 0
docs/README.md

@@ -30,6 +30,59 @@ This script uses the TypeScript compiler API to traverse the server source code
 
 Currently, any `interface` which includes the JSDoc `@docCategory` tag will be extracted into a markdown file in the [content/docs/api](./content/docs/api) directory. Hugo can then build the API documentation from these markdown files. This will probably be expanded to be able to parse `class` and `type` declarations too.
 
+### Docs-specific JSDoc tags
+
+#### `@docsCategory`
+
+This is required as its presence determines whether the declaration is extracted into the docs. Its value should be a string corresponding to the API sub-section that this declaration belongs to, e.g. "payment", "shipping" etc.
+
+#### `@description`
+
+This tag specifies the text description of the declaration. It supports markdown, but should not be used for code blocks, which should be tagged with `@example` (see below). Links to other declarations can be made with the `{@link SomeOtherDeclaration}` syntax. Also applies to class/interface members.
+
+#### `@example`
+
+This tag should be used to include any code blocks. Remember to specify the language after the opening delimiter for correct highlighting. Also applies to class/interface members.
+
+#### `@docsWeight`
+
+This is optional and when present, sets the "weight" of the markdown file in the Hugo front matter. A lower value makes the resulting doc page appear higher in the menu. If not specified, a default value of `10` is used.
+
+#### `@default`
+
+This is used to specify the default value of a property, e.g. when documenting an optional configuration option.
+
+#### Example
+
+````ts
+/**
+ * @description
+ * Greets people with a friendly message. 
+ * Used by the {@link AppInitializer} during the start-up process.
+ *
+ * @example
+ * ```ts
+ * const greeter = new Greeter();
+ * console.log(greeter.greet('mike'));
+ * // -> 'Hi, mike, good to see you!'
+ * ```
+ *
+ * @docsCategory helpers
+ * @docsWeight 1
+ */
+export class Greeter {
+
+    /**
+     * @description
+     * Greets the person by name
+     */
+    greet(name: string): string {
+      return `Hi, ${name}, good to see you!`;
+    }
+}
+````
+
+
 ## A note on icons
 
 The docs site also uses the [Clarity icons](https://clarity.design/icons) to maintain consistency with the Vendure admin ui app. However, currently [this bug](https://github.com/vmware/clarity/issues/2599) makes the use of the custom-elements based icons unfeasible since it adds about 400kb to the JS bundle size. This is unacceptable for what is essentially a static HTML site.

+ 8 - 6
docs/assets/styles/_markdown.scss

@@ -4,6 +4,7 @@ $block-border-radius: 4px;
 
 .markdown {
     line-height: 1.7;
+    margin-left: 12px;
 
     > :first-child {
         margin-top: 0;
@@ -51,23 +52,24 @@ $block-border-radius: 4px;
         }
     }
 
-    code {
+    code:not([data-lang]) {
         font-family: 'Oxygen Mono', monospace;
         padding: 0 $padding-4;
-        background: $gray-100;
-        color: darken($brand-color, 30%);
+        background: $color-code-bg;
+        color: $color-code-text;
         border-radius: $block-border-radius;
+        border: 1px solid $color-code-border;
     }
 
-    pre {
+    pre:not(.chroma) {
         padding: $padding-16;
-        background: $gray-100;
+        background: $color-code-bg;
         border-radius: $block-border-radius;
         font-size: $font-size-14;
         overflow-x: auto;
 
         code {
-            color: $gray-200;
+            color: $color-code-text;
             background: none;
             padding: none;
         }

+ 13 - 17
docs/assets/styles/_shortcodes.scss

@@ -6,7 +6,7 @@
 .alert {
     border: 1px solid;
     border-radius: 2px;
-    padding: 0 12px;
+    padding: 0 18px;
 
     &.primary { border-color: $color-default; background: transparentize($color-default, 0.9); }
     &.danger { border-color: $color-danger; background: transparentize($color-danger, 0.9); }
@@ -21,35 +21,31 @@
     display: flex;
     align-items: center;
     margin-top: -16px;
+    font-size: 14px;
 
     .kind-label {
         font-size: $font-size-12;
-        background-color: #d3f2eb;
+        background-color: #eaf9f5;
+        color: #38979f;
         border-radius: 4px;
         padding: 0 6px;
-        margin-right: 6px;
+        margin-right: 12px;
     }
 
     .type, .default {
         margin-right: 12px;
-    }
-    .label{
-        display: inline-block;
-        color: $gray-700;
-    }
-
-    .type-code {
-        display: inline-block;
-        font-family: 'Oxygen Mono', monospace;
-        padding: 0 $padding-4;
-        background: $gray-100;
-        color: $gray-700;
-        border-radius: 4px;
         a:link, a:visited {
             color: darken($brand-color, 20%);
         }
     }
-
+    .type {
+        code {
+        }
+    }
+    .label{
+        display: inline-block;
+        color: $gray-600;
+    }
 }
 
 /**

+ 91 - 0
docs/assets/styles/_syntax.scss

@@ -0,0 +1,91 @@
+@import "variables";
+
+/**
+ Styles for code block syntax highlighting. Extracted from the paraiso-dark theme and then modified.
+ */
+
+pre.chroma {
+    padding: 12px;
+    font-size: 14px;
+    border-radius: 3px;
+    overflow-x: auto;
+    border: 1px solid $color-code-border;
+    position: relative;
+
+    > code::before {
+        content: attr(data-lang);
+        position: absolute;
+        right: 3px;
+        top: 0;
+        font-size: 12px;
+        color: $gray-400;
+        text-transform: uppercase;
+    }
+}
+
+/* Background */ .chroma { color: $color-code-text; background-color: $color-code-bg;
+                 }
+/* Error */ .chroma .err { color: #ef6155 }
+/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
+/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
+/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
+/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
+/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
+/* Keyword */ .chroma .k { color: #815ba4 }
+/* KeywordConstant */ .chroma .kc { color: #815ba4 }
+/* KeywordDeclaration */ .chroma .kd { color: #815ba4 }
+/* KeywordNamespace */ .chroma .kn { color: #5bc4bf }
+/* KeywordPseudo */ .chroma .kp { color: #815ba4 }
+/* KeywordReserved */ .chroma .kr { color: #01b2c4
+                      }
+/* KeywordType */ .chroma .kt { color: #ccac3d
+                  }
+/* NameAttribute */ .chroma .na { color: #06b6ef }
+/* NameClass */ .chroma .nc { color: #fec418 }
+/* NameConstant */ .chroma .no { color: #ef6155 }
+/* NameDecorator */ .chroma .nd { color: #5bc4bf }
+/* NameException */ .chroma .ne { color: #ef6155 }
+/* NameFunction */ .chroma .nf { color: #06b6ef }
+/* NameNamespace */ .chroma .nn { color: #fec418 }
+/* NameOther */ .chroma .nx { color: #427a8f
+                }
+/* NameTag */ .chroma .nt { color: #5bc4bf }
+/* NameVariable */ .chroma .nv { color: #ef6155 }
+/* Literal */ .chroma .l { color: #f99b15 }
+/* LiteralDate */ .chroma .ld { color: #48b685 }
+/* LiteralString */ .chroma .s { color: #48b685 }
+/* LiteralStringAffix */ .chroma .sa { color: #48b685 }
+/* LiteralStringBacktick */ .chroma .sb { color: #48b685 }
+/* LiteralStringDelimiter */ .chroma .dl { color: #48b685 }
+/* LiteralStringDoc */ .chroma .sd { color: #776e71 }
+/* LiteralStringDouble */ .chroma .s2 { color: #48b685 }
+/* LiteralStringEscape */ .chroma .se { color: #f99b15 }
+/* LiteralStringHeredoc */ .chroma .sh { color: #48b685 }
+/* LiteralStringInterpol */ .chroma .si { color: #f99b15 }
+/* LiteralStringOther */ .chroma .sx { color: #48b685 }
+/* LiteralStringRegex */ .chroma .sr { color: #48b685 }
+/* LiteralStringSingle */ .chroma .s1 { color: #48b685 }
+/* LiteralStringSymbol */ .chroma .ss { color: #48b685 }
+/* LiteralNumber */ .chroma .m { color: #f99b15 }
+/* LiteralNumberBin */ .chroma .mb { color: #f99b15 }
+/* LiteralNumberFloat */ .chroma .mf { color: #f99b15 }
+/* LiteralNumberHex */ .chroma .mh { color: #f99b15 }
+/* LiteralNumberInteger */ .chroma .mi { color: #f99b15 }
+/* LiteralNumberIntegerLong */ .chroma .il { color: #f99b15 }
+/* LiteralNumberOct */ .chroma .mo { color: #f99b15 }
+/* Operator */ .chroma .o { color: #1eb61c }
+/* OperatorWord */ .chroma .ow { color: #1eb61c }
+/* Comment */ .chroma .c { color: #776e71 }
+/* CommentHashbang */ .chroma .ch { color: #776e71 }
+/* CommentMultiline */ .chroma .cm { color: #776e71 }
+/* CommentSingle */ .chroma .c1 { color: #776e71 }
+/* CommentSpecial */ .chroma .cs { color: #776e71 }
+/* CommentPreproc */ .chroma .cp { color: #776e71 }
+/* CommentPreprocFile */ .chroma .cpf { color: #776e71 }
+/* GenericDeleted */ .chroma .gd { color: #ef6155 }
+/* GenericEmph */ .chroma .ge { font-style: italic }
+/* GenericHeading */ .chroma .gh { font-weight: bold }
+/* GenericInserted */ .chroma .gi { color: #48b685 }
+/* GenericPrompt */ .chroma .gp { color: #776e71; font-weight: bold }
+/* GenericStrong */ .chroma .gs { font-weight: bold }
+/* GenericSubheading */ .chroma .gu { color: #5bc4bf; font-weight: bold }

+ 3 - 0
docs/assets/styles/_variables.scss

@@ -28,6 +28,9 @@ $color-default: #0079B8;
 $color-danger: #e12200;
 $color-warning: #FF8400;
 $color-success: #2F8400;
+$color-code-bg: $gray-100;
+$color-code-border: $gray-200;
+$color-code-text: darken($brand-color, 45%);
 
 $body-background: white;
 $body-font-color: $gray-800;

+ 7 - 6
docs/assets/styles/main.scss

@@ -6,6 +6,7 @@
 @import "top-bar";
 @import "menu";
 @import "shortcodes";
+@import "syntax";
 
 html {
     font-size: $font-size-base;
@@ -35,12 +36,6 @@ body {
     }
 }
 
-footer {
-    margin-top: 100px;
-    background-color: #efefef;
-    padding: 50px;
-}
-
 h1,
 h2,
 h3,
@@ -166,6 +161,12 @@ ul.contents-list {
     }
 }
 
+.book-footer {
+    height: 200px;
+    background-color: $gray-100;
+    margin-top: 60px;
+}
+
 .book-posts {
     min-width: $body-min-width;
     max-width: $sm-breakpoint;

+ 1 - 1
docs/config.toml

@@ -2,7 +2,7 @@ baseURL = "http://example.org/"
 languageCode = "en-us"
 title = "Vendure Documenation"
 pygmentsCodeFences = true
-pygmentsStyle = "monokai"
+pygmentsUseClasses = true
 disableKinds = [
   "taxonomy",
   "taxonomyTerm"

+ 0 - 8
docs/content/docs/api/_index.md

@@ -1,8 +0,0 @@
----
-title: "API"
-weight: 10
----
-
-# Vendure API Docs
-
-All documentation in this section is auto-generated from the TypeScript source of the Vendure server. Thus it is guaranteed to be accurate and up-to-date.

+ 25 - 0
docs/content/docs/configuration/_index.md

@@ -0,0 +1,25 @@
+---
+title: "Configuration"
+weight: 9
+---
+
+# Vendure Configuration Docs
+
+All configuration is done by way of the [`VendureConfig`]({{< ref "vendure-config" >}}) object which is passed to Vendure's `bootstrap()` function.
+
+```TypeScript
+bootstrap({
+    authOptions: {
+        sessionSecret: 'BD95F861369DCD684AA668A926E86F8B',
+    },
+    port: 3000,
+    apiPath: 'api',
+    // ...
+});
+```
+
+This section contains a description of all available configuration options for Vendure.
+
+{{% alert %}}
+All documentation in this section is auto-generated from the TypeScript source of the Vendure server.
+{{% /alert %}}

+ 3 - 1
docs/layouts/docs/baseof.html

@@ -28,7 +28,9 @@
     <div class="book-page">
       {{ partial "docs/mobile-header" . }}
       {{ template "main" . }}
-      {{ partial "docs/git-footer" . }}
+      <div class="book-footer">
+
+      </div>
     </div>
 
     {{ template "toc" . }}

+ 1 - 1
docs/layouts/docs/list.html

@@ -7,7 +7,7 @@
     {{ if gt (len $list) 0 }}
     <h3>Contents:</h3>
     <ul class="contents-list">
-        {{ range sort $list "Weight" }}
+        {{ range ($list.ByParam "Title").ByParam "Weight" }}
         <li>
             <a href="{{ .RelPermalink }}">{{ .Title }}</a>
         </li>

+ 1 - 1
docs/layouts/partials/docs/menu-filetree.html

@@ -9,7 +9,7 @@
 <ul {{ if .Expanded }}class="expanded"{{ end }}>
     {{ $list := .Section.Sections }}
     {{ $list = $list | append .Section.Pages }}
-    {{ range sort $list "Weight" }}
+    {{ range ($list.ByParam "Title").ByParam "Weight" }}
         {{ if eq .Kind "section" }}
             <li class="section">
                 {{ $expanded := in $.CurrentPage .Permalink }}

+ 1 - 1
docs/layouts/shortcodes/generation-info.html

@@ -1,3 +1,3 @@
 <div class="generation-info">
-    Documentation generated from <a href="https://github.com/vendure-ecommerce/vendure/blob/master{{ .Get "sourceFile" }}#L{{ .Get "sourceLine" }}">{{  index (last 1 (split (.Get "sourceFile") "/")) 0 }}</a> on {{ dateFormat "Jan 2 2006 at 15:04" $.Page.Lastmod }}
+    Documentation generated from <a href="https://github.com/vendure-ecommerce/vendure/blob/master/{{ .Get "sourceFile" }}#L{{ .Get "sourceLine" }}">{{  index (last 1 (split (.Get "sourceFile") "/")) 0 }}</a> on {{ dateFormat "Jan 2 2006 at 15:04" $.Page.Lastmod }}
 </div>

+ 1 - 1
docs/layouts/shortcodes/member-info.html

@@ -4,7 +4,7 @@
     </div>
     <div class="type">
         <div class="label">type:</div>
-        <div class="type-code">{{ .Get "type" | safeHTML }}</div>
+        <code>{{ .Get "type" | safeHTML }}</code>
     </div>
     {{ if isset .Params "default" }}
     <div class="default">