Skip to content

Commit

Permalink
feat: add modern template customization options
Browse files Browse the repository at this point in the history
  • Loading branch information
yufeih committed Apr 25, 2023
1 parent 4db0430 commit 95e801f
Show file tree
Hide file tree
Showing 19 changed files with 348 additions and 47 deletions.
73 changes: 66 additions & 7 deletions docs/docs/template.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,94 @@
# Template

Template defines the appearance of the website.
Template defines the appearance of the website. Docfx ships a default modern website template with the same look and feel as this site. Additional templates are available at the [Template Gallery](../extensions/templates.yml).

Docfx ships a default website template with the same look and feel as this site. Additional templates are available at the [Template Gallery](../extensions/templates.yml).
## Custom Template

## Create a Custom Template
Customization options varies depending on the chosen template. We recommend using the modern template which supports dark mode, more features, rich customization options and is being actively maintained. The rest of this article assumes you are using the modern template. To use the modern template, set `build.templates` property to `["default", "modern"]` in `docfx.json`:

To build your own template, create a new folder and add it to `templates` config in `docfx.json`:
```json
{
"build": {
"templates": [
"default",
"modern"
]
}
}
```

To customize the template, create a new folder next to `docfx.json` and add it to `templates` config in `docfx.json`:

```json
{
"build": {
"templates": [
"default",
"modern",
"my-template" // <-- Path to custom template
]
}
}
```

Add your custom CSS file to `styles/main.css` and JavaScript file to `styles/main.js`. Docfx loads these 2 files and use them to style the website.
Docfx loads files for the `default` and `modern` entries from the `templates` directory shipped with the `docfx` executable. On windows, this is typically `C:\Users\{name}\.nuget\packages\docfx\{version}\tools\{tfm}\any\templates` if install docfx using `dotnet tool install -g docfx`.

This is an example stylesheet that adjust the font size of article headers:
Docfx loads files for the `my-template` entries from the `my-templates` directory next to your `docfx.json` project. The `my-template/public` directory contains files that will be published to the website.

Add your custom CSS file to `my-template/public/main.css` to customize colors, show and hide elements, etc. This is an example stylesheet that adjust the font size of article headers.

```css
/* file: styles/main.css */
/* file: my-template/public/main.css */
article h1 {
font-size: 40px;
}
```

You can also use [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) to adjust the templates. There are many predefined CSS variables in [Bootstrap](https://getbootstrap.com/docs/5.3/customize/color/#colors) that can be used to customize the site:

```css
/* file: my-template/public/main.css */
body {
--bs-link-color-rgb: 66, 184, 131 !important;
--bs-link-hover-color-rgb: 64, 180, 128 !important;
}
```

The `my-template/public/main.js` file is the entry JavaScript file to customize docfx site behaviors. This is a basic setup that changes the default color mode to dark and adds some icons in the header:

```js
/* file: my-template/public/main.js */
export default {
defaultTheme: 'dark',
icons?: [
{
icon: 'github',
href: 'https://github.com/dotnet/docfx'
title: 'GitHub'
},
{
icon: 'twitter',
href: 'https://twitter.com'
title: 'Twitter'
}
]
}
```

You can also configure syntax highlighting options using the `configureHljs` option:

```js
export default {
configureHljs: (hljs) => {
// Customize hightlight.js here
},
}
```

See [this example](https://github.com/dotnet/docfx/blob/main/samples/seed/template/public/main.js) on how to enable `bicep` syntax highlighting.

More customization options are available in the [docfx options object](https://github.com/dotnet/docfx/blob/main/templates/modern/src/options.d.ts).

## Custom HTML Templates

In addition to CSS and JavaScript, you can customize how docfx generates HTML using [Mustache Templates](https://mustache.github.io/).
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions docs/template/public/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License.txt in the project root for license information. */

export default {
icons: [
{
icon: 'github',
href: 'https://github.com/dotnet/docfx',
title: 'GitHub'
}
]
}
9 changes: 9 additions & 0 deletions samples/seed/articles/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ This expression uses `\$` to display a dollar sign: $\sqrt{\$4}$

To split <span>$</span>100 in half, we calculate $100/2$

## Custom Syntax Highlighting

```bicep
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
name: 'hello'
// (...)
}
```

## Tabs

# [Linux](#tab/linux)
Expand Down
2 changes: 1 addition & 1 deletion samples/seed/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
},
"dest": "_site",
"exportViewModel": true,
"template": ["default", "modern"]
"template": ["default", "modern", "template"]
},
"pdf": {
"content": [
Expand Down
156 changes: 156 additions & 0 deletions samples/seed/template/public/bicep.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/**
Origin: https://github.com/Duncanma/highlight.js/blob/stable/src/languages/bicep.js
*/

export function bicep(hljs) {
var bounded = function (text) { return "\\b" + text + "\\b"; };
var after = function (regex) { return "(?<=" + regex + ")"; };
var notAfter = function (regex) { return "(?<!" + regex + ")"; };
var before = function (regex) { return "(?=" + regex + ")"; };
var notBefore = function (regex) { return "(?!" + regex + ")"; };
var identifierStart = "[_a-zA-Z]";
var identifierContinue = "[_a-zA-Z0-9]";
var identifier = bounded("" + identifierStart + identifierContinue + "*");
// whitespace. ideally we'd tokenize in-line block comments, but that's a lot of work. For now, ignore them.
var ws = "(?:[ \\t\\r\\n]|\\/\\*(?:\\*(?!\\/)|[^*])*\\*\\/)*";
var KEYWORDS = {
$pattern: '[A-Za-z$_][0-9A-Za-z$_]*',
keyword: [
'targetScope',
'resource',
'module',
'param',
'var',
'output',
'for',
'in',
'if',
'existing',
].join(' '),
literal: [
"true",
"false",
"null",
].join(' '),
built_in: [
'az',
'sys',
].join(' ')
};
var lineComment = {
className: 'comment',
begin: "//",
end: "$",
relevance: 0,
};
var blockComment = {
className: 'comment',
begin: "/\\*",
end: "\\*/",
relevance: 0,
};
var comments = {
variants: [lineComment, blockComment],
};
function withComments(input) {
return input.concat(comments);
}
var expression = {
keywords: KEYWORDS,
variants: [
/* placeholder filled later due to cycle*/
],
};
var escapeChar = {
begin: "\\\\(u{[0-9A-Fa-f]+}|n|r|t|\\\\|'|\\${)",
};
var stringVerbatim = {
className: 'string',
begin: "'''",
end: "'''",
};
var stringSubstitution = {
className: 'subst',
begin: "(\\${)",
end: "(})",
contains: withComments([expression]),
};
var stringLiteral = {
className: 'string',
begin: "'" + notBefore("''"),
end: "'",
contains: [
escapeChar,
stringSubstitution
],
};
var numericLiteral = {
className: "number",
begin: "[0-9]+",
};
var namedLiteral = {
className: 'literal',
begin: bounded("(true|false|null)"),
relevance: 0,
};
var identifierExpression = {
className: "variable",
begin: "" + identifier + notBefore(ws + "\\("),
};
var objectPropertyKeyIdentifier = {
className: "property",
begin: "(" + identifier + ")",
};
var objectProperty = {
variants: [
objectPropertyKeyIdentifier,
stringLiteral,
{
begin: ":" + ws,
excludeBegin: true,
end: ws + "$",
excludeEnd: true,
contains: withComments([expression]),
},
],
};
var objectLiteral = {
begin: "{",
end: "}",
contains: withComments([objectProperty]),
};
var arrayLiteral = {
begin: "\\[" + notBefore("" + ws + bounded("for")),
end: "]",
contains: withComments([expression]),
};
var functionCall = {
className: 'function',
begin: "(" + identifier + ")" + ws + "\\(",
end: "\\)",
contains: withComments([expression]),
};
var decorator = {
className: 'meta',
begin: "@" + ws + before(identifier),
end: "",
contains: withComments([functionCall]),
};
expression.variants = [
stringLiteral,
stringVerbatim,
numericLiteral,
namedLiteral,
objectLiteral,
arrayLiteral,
identifierExpression,
functionCall,
decorator,
];
return {
aliases: ['bicep'],
case_insensitive: true,
keywords: KEYWORDS,
contains: withComments([expression]),
};
}
19 changes: 19 additions & 0 deletions samples/seed/template/public/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { bicep } from './bicep.js'

export default {
icons: [
{
icon: 'github',
href: 'https://github.com/dotnet/docfx',
title: 'GitHub'
},
{
icon: 'twitter',
href: 'https://twitter.com/',
title: 'Twitter'
}
],
configureHljs: function (hljs) {
hljs.registerLanguage('bicep', bicep);
},
}
7 changes: 4 additions & 3 deletions templates/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async function buildModernTemplate() {
'.css': '.min.css',
'.js': '.min.js'
},
outdir: 'modern/styles',
outdir: 'modern/public',
entryPoints: [
'modern/src/docfx.ts',
'modern/src/search-worker.ts',
Expand Down Expand Up @@ -129,12 +129,13 @@ function serve() {
open: true,
startPath: '/test',
files: [
'modern/styles/**',
'modern/public/**',
join(project, '_site', '**')
],
server: {
routes: {
'/test/styles': 'modern/styles',
'/test/public/main.js': join(project, '_site', 'public', 'main.js'),
'/test/public': 'modern/public',
'/test': join(project, '_site')
}
}
Expand Down
19 changes: 9 additions & 10 deletions templates/modern/layout/_master.tmpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
{{!include(/^styles/.*/)}}
{{!include(/^fonts/.*/)}}
{{!include(/^public/.*/)}}
{{!include(favicon.ico)}}
{{!include(logo.svg)}}
{{!include(search-stopwords.json)}}
Expand All @@ -17,24 +16,24 @@
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
<link rel="icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}">
<link rel="stylesheet" href="{{_rel}}styles/docfx.min.css">
<link rel="stylesheet" href="{{_rel}}styles/main.css">
<link rel="stylesheet" href="{{_rel}}public/docfx.min.css">
<link rel="stylesheet" href="{{_rel}}public/main.css">
<meta name="docfx:navrel" content="{{_navRel}}">
<meta name="docfx:tocrel" content="{{_tocRel}}">
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}}
{{#_enableSearch}}<meta name="docfx:rel" content="{{_rel}}">{{/_enableSearch}}
{{#docurl}}<meta name="docfx:docurl" content="{{docurl}}">{{/docurl}}

<script>
MathJax = {
<script type="module">
import docfx from './{{_rel}}public/main.js'
window.docfx = docfx
window.MathJax = {
options: {
processHtmlClass: ['tex2jax_process', 'math']
}
};
}
</script>

<script type="text/javascript" src="{{_rel}}styles/docfx.min.js"></script>
<script type="text/javascript" src="{{_rel}}styles/main.js"></script>
<script type="text/javascript" src="{{_rel}}public/docfx.min.js"></script>
{{/redirect_url}}
</head>

Expand Down
Empty file.
1 change: 1 addition & 0 deletions templates/modern/public/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default {}
Loading

0 comments on commit 95e801f

Please sign in to comment.