Enable clean / extension-less url (#677)

This commit is contained in:
Endilie Yacop Sucipto 2018-06-07 04:37:49 +08:00 committed by Joel Marcey
parent aee255219b
commit 31f0c27f81
14 changed files with 124 additions and 50 deletions

View file

@ -74,6 +74,8 @@ headerLinks: [
`blogSidebarCount` - Control the number of blog posts that show up in the sidebar. See the [adding a blog docs](guides-blog.md#changing-how-many-blog-posts-show-on-sidebar) for more information. `blogSidebarCount` - Control the number of blog posts that show up in the sidebar. See the [adding a blog docs](guides-blog.md#changing-how-many-blog-posts-show-on-sidebar) for more information.
`cleanUrl` - If `true`, allow URLs with no `html` extension. Example: request to URL https://docusaurus.io/docs/installation will returns the same result as https://docusaurus.io/docs/installation.html.
`cname` - The CNAME for your website. It will go into a `CNAME` file when your site it built. `cname` - The CNAME for your website. It will go into a `CNAME` file when your site it built.
`customDocsPath` - By default, Docusaurus expects your documentation to be in a directory called `docs`. This directory is at the same level as the `website` directory (i.e., not inside the `website` directory). You can specify a custom path to your documentation with this field. **Note that all of your documentation `*.md` files must still reside in a flat hierarchy. You cannot have your documents in nested directories**. `customDocsPath` - By default, Docusaurus expects your documentation to be in a directory called `docs`. This directory is at the same level as the `website` directory (i.e., not inside the `website` directory). You can specify a custom path to your documentation with this field. **Note that all of your documentation `*.md` files must still reside in a flat hierarchy. You cannot have your documents in nested directories**.
@ -250,6 +252,7 @@ const siteConfig = {
twitterUsername: 'docusaurus', twitterUsername: 'docusaurus',
twitterImage: 'img/docusaurus.png', twitterImage: 'img/docusaurus.png',
ogImage: 'img/docusaurus.png', ogImage: 'img/docusaurus.png',
cleanUrl: true,
scrollToTop: true, scrollToTop: true,
scrollToTopOptions: { scrollToTopOptions: {
zIndex: 100 zIndex: 100

View file

@ -11,6 +11,7 @@ const Container = require('./Container.js');
const MetadataBlog = require('./MetadataBlog.js'); const MetadataBlog = require('./MetadataBlog.js');
const React = require('react'); const React = require('react');
const Site = require('./Site.js'); const Site = require('./Site.js');
const utils = require('./utils.js');
// used to generate entire blog pages, i.e. collection of truncated blog posts // used to generate entire blog pages, i.e. collection of truncated blog posts
class BlogPageLayout extends React.Component { class BlogPageLayout extends React.Component {
@ -45,7 +46,10 @@ class BlogPageLayout extends React.Component {
post={post} post={post}
content={post.content} content={post.content}
truncate={true} truncate={true}
key={post.path + post.title} key={
utils.getPath(post.path, this.props.config.cleanUrl) +
post.title
}
config={this.props.config} config={this.props.config}
/> />
); );

View file

@ -8,7 +8,7 @@
const MarkdownBlock = require('./MarkdownBlock.js'); const MarkdownBlock = require('./MarkdownBlock.js');
const React = require('react'); const React = require('react');
const utils = require('./utils'); const utils = require('./utils.js');
// inner blog component for the article itself, without sidebar/header/footer // inner blog component for the article itself, without sidebar/header/footer
class BlogPost extends React.Component { class BlogPost extends React.Component {
@ -24,7 +24,12 @@ class BlogPost extends React.Component {
<a <a
className="button" className="button"
href={ href={
this.props.config.baseUrl + 'blog/' + this.props.post.path this.props.config.baseUrl +
'blog/' +
utils.getPath(
this.props.post.path,
this.props.config.cleanUrl
)
}> }>
Read More Read More
</a> </a>
@ -73,7 +78,12 @@ class BlogPost extends React.Component {
const post = this.props.post; const post = this.props.post;
return ( return (
<h1> <h1>
<a href={this.props.config.baseUrl + 'blog/' + post.path}> <a
href={
this.props.config.baseUrl +
'blog/' +
utils.getPath(post.path, this.props.config.cleanUrl)
}>
{post.title} {post.title}
</a> </a>
</h1> </h1>

View file

@ -10,11 +10,13 @@ const BlogPost = require('./BlogPost.js');
const BlogSidebar = require('./BlogSidebar.js'); const BlogSidebar = require('./BlogSidebar.js');
const Container = require('./Container.js'); const Container = require('./Container.js');
const Site = require('./Site.js'); const Site = require('./Site.js');
const utils = require('./utils.js');
// used for entire blog posts, i.e., each written blog article with sidebar with site header/footer // used for entire blog posts, i.e., each written blog article with sidebar with site header/footer
class BlogPostLayout extends React.Component { class BlogPostLayout extends React.Component {
renderSocialButtons() { renderSocialButtons() {
const post = this.props.metadata; let post = this.props.metadata;
post.path = utils.getPath(post.path, this.props.config.cleanUrl);
const fbComment = this.props.config.facebookAppId && const fbComment = this.props.config.facebookAppId &&
this.props.config.facebookComments && ( this.props.config.facebookComments && (
@ -92,10 +94,12 @@ class BlogPostLayout extends React.Component {
} }
render() { render() {
let post = this.props.metadata;
post.path = utils.getPath(post.path, this.props.config.cleanUrl);
return ( return (
<Site <Site
className="sideNavVisible" className="sideNavVisible"
url={'blog/' + this.props.metadata.path} url={'blog/' + post.path}
title={this.props.metadata.title} title={this.props.metadata.title}
language={'en'} language={'en'}
description={this.getDescription()} description={this.getDescription()}
@ -104,13 +108,13 @@ class BlogPostLayout extends React.Component {
<div className="docMainWrapper wrapper"> <div className="docMainWrapper wrapper">
<BlogSidebar <BlogSidebar
language={'en'} language={'en'}
current={this.props.metadata} current={post}
config={this.props.config} config={this.props.config}
/> />
<Container className="mainContainer documentContainer postContainer blogContainer"> <Container className="mainContainer documentContainer postContainer blogContainer">
<div className="lonePost"> <div className="lonePost">
<BlogPost <BlogPost
post={this.props.metadata} post={post}
content={this.props.children} content={this.props.children}
language={'en'} language={'en'}
config={this.props.config} config={this.props.config}

View file

@ -28,6 +28,7 @@ class DocsLayout extends React.Component {
this.props.metadata.localized_id this.props.metadata.localized_id
] || this.props.metadata.title ] || this.props.metadata.title
: this.props.metadata.title; : this.props.metadata.title;
const extension = this.props.config.cleanUrl ? '' : '.html';
return ( return (
<Site <Site
config={this.props.config} config={this.props.config}
@ -54,7 +55,7 @@ class DocsLayout extends React.Component {
{metadata.previous_id && ( {metadata.previous_id && (
<a <a
className="docs-prev button" className="docs-prev button"
href={metadata.previous_id + '.html'}> href={metadata.previous_id + extension}>
{' '} {' '}
{i18n {i18n
? translation[this.props.metadata.language][ ? translation[this.props.metadata.language][
@ -70,7 +71,7 @@ class DocsLayout extends React.Component {
{metadata.next_id && ( {metadata.next_id && (
<a <a
className="docs-next button" className="docs-next button"
href={metadata.next_id + '.html'}> href={metadata.next_id + extension}>
{i18n {i18n
? translation[this.props.metadata.language][ ? translation[this.props.metadata.language][
'localized-strings' 'localized-strings'

View file

@ -20,6 +20,7 @@ const setLanguage = require('../../server/translate.js').setLanguage;
const readMetadata = require('../../server/readMetadata.js'); const readMetadata = require('../../server/readMetadata.js');
readMetadata.generateMetadataDocs(); readMetadata.generateMetadataDocs();
const Metadata = require('../metadata.js'); const Metadata = require('../metadata.js');
const utils = require('../utils.js');
// language dropdown nav item for when translations are enabled // language dropdown nav item for when translations are enabled
class LanguageDropDown extends React.Component { class LanguageDropDown extends React.Component {
@ -169,7 +170,9 @@ class HeaderNav extends React.Component {
} }
throw new Error(errorStr); throw new Error(errorStr);
} }
href = this.props.config.baseUrl + Metadata[id].permalink; href =
this.props.config.baseUrl +
utils.getPath(Metadata[id].permalink, this.props.config.cleanUrl);
const {id: currentID, sidebar} = this.props.current; const {id: currentID, sidebar} = this.props.current;
docItemActive = currentID && currentID === id; docItemActive = currentID && currentID === id;
@ -177,14 +180,15 @@ class HeaderNav extends React.Component {
} else if (link.page) { } else if (link.page) {
// set link to page with current page's language if appropriate // set link to page with current page's language if appropriate
const language = this.props.language || ''; const language = this.props.language || '';
const extension = siteConfig.cleanUrl ? '' : '.html';
if (fs.existsSync(CWD + '/pages/en/' + link.page + '.js')) { if (fs.existsSync(CWD + '/pages/en/' + link.page + '.js')) {
href = href =
siteConfig.baseUrl + siteConfig.baseUrl +
(language ? language + '/' : '') + (language ? language + '/' : '') +
link.page + link.page +
'.html'; extension;
} else { } else {
href = siteConfig.baseUrl + link.page + '.html'; href = siteConfig.baseUrl + link.page + extension;
} }
} else if (link.href) { } else if (link.href) {
// set link to specified href // set link to specified href

View file

@ -10,6 +10,7 @@ const classNames = require('classnames');
const siteConfig = require(process.cwd() + '/siteConfig.js'); const siteConfig = require(process.cwd() + '/siteConfig.js');
const translation = require('../../server/translation.js'); const translation = require('../../server/translation.js');
const utils = require('../utils.js');
class SideNav extends React.Component { class SideNav extends React.Component {
render() { render() {
@ -81,16 +82,22 @@ class SideNav extends React.Component {
} }
return localizedString; return localizedString;
} }
// return link to doc in sidebar // return link to doc in sidebar
getLink(metadata) { getLink(metadata) {
if (metadata.permalink) { if (metadata.permalink) {
if (metadata.permalink.match(/^https?:/)) { const targetLink = utils.getPath(metadata.permalink, siteConfig.cleanUrl);
return metadata.permalink; if (targetLink.match(/^https?:/)) {
return targetLink;
} }
return siteConfig.baseUrl + metadata.permalink; return siteConfig.baseUrl + targetLink;
} }
if (metadata.path) { if (metadata.path) {
return siteConfig.baseUrl + 'blog/' + metadata.path; return (
siteConfig.baseUrl +
'blog/' +
utils.getPath(metadata.path, siteConfig.cleanUrl)
);
} }
return null; return null;
} }

View file

@ -20,8 +20,20 @@ function extractBlogPostSummary(content) {
return content.substring(0, BLOG_POST_SUMMARY_LENGTH); return content.substring(0, BLOG_POST_SUMMARY_LENGTH);
} }
function getPath(path, cleanUrl = false) {
if (cleanUrl) {
if (path.endsWith('/index.html')) {
return path.replace(/\/index.html$/, '');
} else {
return path.replace(/\.html$/, '');
}
}
return path;
}
module.exports = { module.exports = {
blogPostHasTruncateMarker, blogPostHasTruncateMarker,
extractBlogPostBeforeTruncate, extractBlogPostBeforeTruncate,
extractBlogPostSummary, extractBlogPostSummary,
getPath,
}; };

View file

@ -41,8 +41,14 @@ async function execute() {
// create the folder path for a file if it does not exist, then write the file // create the folder path for a file if it does not exist, then write the file
function writeFileAndCreateFolder(file, content) { function writeFileAndCreateFolder(file, content) {
mkdirp.sync(path.dirname(file)); mkdirp.sync(path.dirname(file));
fs.writeFileSync(file, content); fs.writeFileSync(file, content);
// build extra file for extension-less url if "cleanUrl" siteConfig is true
if (siteConfig.cleanUrl && file.indexOf('index.html') === -1) {
const extraFile = file.replace(/\.html$/, '/index.html');
mkdirp.sync(path.dirname(extraFile));
fs.writeFileSync(extraFile, content);
}
} }
const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>'; const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
@ -156,6 +162,7 @@ async function execute() {
// replace any links to markdown files to their website html links // replace any links to markdown files to their website html links
Object.keys(mdToHtml).forEach(function(key, index) { Object.keys(mdToHtml).forEach(function(key, index) {
let link = mdToHtml[key]; let link = mdToHtml[key];
link = siteConfig.cleanUrl ? link.replace(/\.html$/, '') : link;
link = link.replace('/en/', '/' + language + '/'); link = link.replace('/en/', '/' + language + '/');
link = link.replace( link = link.replace(
'/VERSION/', '/VERSION/',
@ -196,12 +203,15 @@ async function execute() {
env.translation.enabled && env.translation.enabled &&
metadata.permalink.indexOf('docs/en') !== -1 metadata.permalink.indexOf('docs/en') !== -1
) { ) {
const redirectlink = siteConfig.cleanUrl
? metadata.permalink.replace(/\.html$/, '')
: metadata.permalink;
const redirectComp = ( const redirectComp = (
<Redirect <Redirect
metadata={metadata} metadata={metadata}
language={language} language={language}
config={siteConfig} config={siteConfig}
redirect={siteConfig.baseUrl + metadata.permalink} redirect={siteConfig.baseUrl + redirectlink}
/> />
); );
const redirectStr = renderToStaticMarkupWithDoctype(redirectComp); const redirectStr = renderToStaticMarkupWithDoctype(redirectComp);

View file

@ -199,6 +199,7 @@ function execute(port) {
// replace any links to markdown files to their website html links // replace any links to markdown files to their website html links
Object.keys(mdToHtml).forEach(function(key, index) { Object.keys(mdToHtml).forEach(function(key, index) {
let link = mdToHtml[key]; let link = mdToHtml[key];
link = siteConfig.cleanUrl ? link.replace(/\.html$/, '') : link;
link = link.replace('/en/', '/' + language + '/'); link = link.replace('/en/', '/' + language + '/');
link = link.replace( link = link.replace(
'/VERSION/', '/VERSION/',
@ -271,7 +272,7 @@ function execute(port) {
}); });
// Handle all requests for blog pages and posts. // Handle all requests for blog pages and posts.
app.get(/blog\/.*html$/, (req, res) => { app.get(/^\/blog\/.*html$/, (req, res) => {
// Regenerate the blog metadata in case it has changed. Consider improving // Regenerate the blog metadata in case it has changed. Consider improving
// this to regenerate on file save rather than on page request. // this to regenerate on file save rather than on page request.
reloadMetadataBlog(); reloadMetadataBlog();
@ -305,7 +306,7 @@ function execute(port) {
// send corresponding blog page if appropriate // send corresponding blog page if appropriate
if (parts[1] === 'index.html') { if (parts[1] === 'index.html') {
res.send(blogPages['/index.html']); res.send(blogPages['/index.html']);
} else if (parts[1].endsWith('/index.html')) { } else if (parts[1].endsWith('/index.html') && blogPages[parts[1]]) {
res.send(blogPages[parts[1]]); res.send(blogPages[parts[1]]);
} else if (parts[1].match(/page([0-9]+)/)) { } else if (parts[1].match(/page([0-9]+)/)) {
if (parts[1].endsWith('/')) { if (parts[1].endsWith('/')) {
@ -314,9 +315,14 @@ function execute(port) {
res.send(blogPages[parts[1] + '/index.html']); res.send(blogPages[parts[1] + '/index.html']);
} }
} else { } else {
// else send corresponding blog post // send corresponding blog post. Ex: request to "blog/test/index.html" or
// "blog/test.html" will return html rendered version of "blog/test.md"
let file = parts[1]; let file = parts[1];
file = file.replace(/\.html$/, '.md'); if (file.endsWith('/index.html')) {
file = file.replace(/\/index.html$/, '.md');
} else {
file = file.replace(/\.html$/, '.md');
}
file = file.replace(new RegExp('/', 'g'), '-'); file = file.replace(new RegExp('/', 'g'), '-');
file = join(CWD, 'blog', file); file = join(CWD, 'blog', file);
@ -527,23 +533,35 @@ function execute(port) {
app.use(siteConfig.baseUrl, express.static(join(__dirname, '..', 'static'))); app.use(siteConfig.baseUrl, express.static(join(__dirname, '..', 'static')));
// "redirect" requests to pages ending with "/" or no extension so that, // "redirect" requests to pages ending with "/" or no extension so that,
// for example, request to "blog" returns same result as "blog/index.html" // for example, request to "blog" returns "blog/index.html" or "blog.html"
app.get(/\/[^\.]*\/?$/, (req, res) => { app.get(/\/[^\.]*\/?$/, (req, res) => {
let slash = req.path.toString().endsWith('/') ? '' : '/'; const requestFile = (url, notFoundCallback) => {
request.get( request.get(url, (error, response, body) => {
'http://localhost:' + port + req.path + slash + 'index.html', if (!error) {
(err, response, body) => {
if (!err) {
if (response) { if (response) {
res.status(response.statusCode).send(body); if (response.statusCode === 404 && notFoundCallback) {
notFoundCallback();
} else {
res.status(response.statusCode).send(body);
}
} else { } else {
console.error('No response'); console.error('No response');
} }
} else { } else {
console.error('Request failed:', err); console.error('Request failed:', error);
} }
} });
); };
let slash = req.path.toString().endsWith('/') ? '' : '/';
let requestUrl = 'http://localhost:' + port + req.path;
requestFile(requestUrl + slash + 'index.html', () => {
requestFile(
slash === '/'
? requestUrl + '.html'
: requestUrl.replace(/\/$/, '.html'),
null
);
});
}); });
// Start LiveReload server. // Start LiveReload server.

View file

@ -18,7 +18,7 @@ class Help extends React.Component {
{ {
title: <translate>Browse the docs</translate>, title: <translate>Browse the docs</translate>,
content: ( content: (
`Learn more about Docusaurus using the [official documentation](${siteConfig.baseUrl}docs/${this.props.language}/installation.html).` `Learn more about Docusaurus using the [official documentation](${siteConfig.baseUrl}docs/${this.props.language}/installation).`
), ),
}, },
{ {

View file

@ -48,7 +48,7 @@ class HomeSplash extends React.Component {
<div className="pluginRowBlock"> <div className="pluginRowBlock">
<Button <Button
href={` href={`
${siteConfig.baseUrl}docs/${this.props.language}/installation.html ${siteConfig.baseUrl}docs/${this.props.language}/installation
`}> `}>
<translate>Get Started</translate> <translate>Get Started</translate>
</Button> </Button>
@ -92,7 +92,7 @@ class Index extends React.Component {
{ {
content: ( content: (
`Save time and focus on your project's documentation. Simply `Save time and focus on your project's documentation. Simply
write docs and blog posts with [Markdown](${siteConfig.baseUrl}docs/${this.props.language}/doc-markdown.html) write docs and blog posts with [Markdown](${siteConfig.baseUrl}docs/${this.props.language}/doc-markdown)
and Docusaurus will publish a set of static html files ready and Docusaurus will publish a set of static html files ready
to serve.` to serve.`
), ),
@ -103,7 +103,7 @@ class Index extends React.Component {
}, },
{ {
content: ( content: (
`[Extend or customize](${siteConfig.baseUrl}docs/${this.props.language}/api-pages.html) `[Extend or customize](${siteConfig.baseUrl}docs/${this.props.language}/api-pages)
your project's layout by reusing React. Docusaurus can be your project's layout by reusing React. Docusaurus can be
extended while reusing the same header and footer.` extended while reusing the same header and footer.`
), ),
@ -114,7 +114,7 @@ class Index extends React.Component {
}, },
{ {
content: ( content: (
`[Localization](${siteConfig.baseUrl}docs/${this.props.language}/translation.html) `[Localization](${siteConfig.baseUrl}docs/${this.props.language}/translation)
comes pre-configured. Use [Crowdin](https://crowdin.com/) to translate your docs comes pre-configured. Use [Crowdin](https://crowdin.com/) to translate your docs
into over 70 languages.` into over 70 languages.`
), ),
@ -134,7 +134,7 @@ class Index extends React.Component {
{ {
content: ( content: (
`Support users on all versions of your project. Document `Support users on all versions of your project. Document
[versioning](${siteConfig.baseUrl}docs/${this.props.language}/versioning.html) [versioning](${siteConfig.baseUrl}docs/${this.props.language}/versioning)
helps you keep documentation in sync with project releases.` helps you keep documentation in sync with project releases.`
), ),
image: `${siteConfig.baseUrl}img/versioning.svg`, image: `${siteConfig.baseUrl}img/versioning.svg`,
@ -144,7 +144,7 @@ class Index extends React.Component {
}, },
{ {
content: ( content: (
`Make it easy for your community to [find](${siteConfig.baseUrl}docs/${this.props.language}/search.html) what they need in your documentation. `Make it easy for your community to [find](${siteConfig.baseUrl}docs/${this.props.language}/search) what they need in your documentation.
We proudly support [Algolia documentation search](https://www.algolia.com/).` We proudly support [Algolia documentation search](https://www.algolia.com/).`
), ),
image: `${siteConfig.baseUrl}img/search.svg`, image: `${siteConfig.baseUrl}img/search.svg`,
@ -161,7 +161,7 @@ class Index extends React.Component {
contents={[ contents={[
{ {
content: ( content: (
`Get [up and running](${siteConfig.baseUrl}docs/${this.props.language}/site-creation.html) `Get [up and running](${siteConfig.baseUrl}docs/${this.props.language}/site-creation)
quickly without having to worry about site design.` quickly without having to worry about site design.`
), ),
imageAlign: "right", imageAlign: "right",
@ -180,7 +180,7 @@ class Index extends React.Component {
content: ( content: (
`Make design and documentation changes by using the included `Make design and documentation changes by using the included
[live server](${siteConfig.baseUrl}docs/${this.props.language}/site-preparation#verifying-installation). [live server](${siteConfig.baseUrl}docs/${this.props.language}/site-preparation#verifying-installation).
[Publish](${siteConfig.baseUrl}docs/${this.props.language}/publishing.html) [Publish](${siteConfig.baseUrl}docs/${this.props.language}/publishing)
your site to GitHub pages or other static file hosts your site to GitHub pages or other static file hosts
manually, using a script, or with continuous integration manually, using a script, or with continuous integration
like CircleCI.` like CircleCI.`
@ -200,10 +200,10 @@ class Index extends React.Component {
{ {
content: ( content: (
`Docusaurus currently provides support to help your website `Docusaurus currently provides support to help your website
use [translations](${siteConfig.baseUrl}docs/${this.props.language}/translation.html), use [translations](${siteConfig.baseUrl}docs/${this.props.language}/translation),
[search](${siteConfig.baseUrl}docs/${this.props.language}/search.html), [search](${siteConfig.baseUrl}docs/${this.props.language}/search),
and [versioning](${siteConfig.baseUrl}docs/${this.props.language}/versioning.html), and [versioning](${siteConfig.baseUrl}docs/${this.props.language}/versioning),
along with some other special [documentation markdown features](${siteConfig.baseUrl}docs/${this.props.language}/doc-markdown.html). along with some other special [documentation markdown features](${siteConfig.baseUrl}docs/${this.props.language}/doc-markdown).
If you have ideas for useful features, feel free to If you have ideas for useful features, feel free to
contribute on [GitHub](https://github.com/facebook/docusaurus)!` contribute on [GitHub](https://github.com/facebook/docusaurus)!`
), ),
@ -223,7 +223,7 @@ class Index extends React.Component {
<div className="more-users"> <div className="more-users">
<a <a
className="button" className="button"
href={`${siteConfig.baseUrl}${this.props.language}/users.html`}> href={`${siteConfig.baseUrl}${this.props.language}/users`}>
<translate>All Docusaurus Users</translate> <translate>All Docusaurus Users</translate>
</a> </a>
</div> </div>

View file

@ -33,7 +33,7 @@ class Versions extends React.Component {
<tr> <tr>
<th>{latestVersion}</th> <th>{latestVersion}</th>
<td> <td>
<a href={`${siteConfig.baseUrl}docs/en/installation.html`}>Documentation</a> <a href={`${siteConfig.baseUrl}docs/en/installation`}>Documentation</a>
</td> </td>
<td> <td>
<a href={`https://github.com/facebook/Docusaurus/releases/tag/v${latestVersion}`}>Release Notes</a> <a href={`https://github.com/facebook/Docusaurus/releases/tag/v${latestVersion}`}>Release Notes</a>
@ -51,7 +51,7 @@ class Versions extends React.Component {
<a <a
href={`${ href={`${
siteConfig.baseUrl siteConfig.baseUrl
}docs/en/next/installation.html`} }docs/en/next/installation`}
> >
Documentation Documentation
</a> </a>
@ -75,7 +75,7 @@ class Versions extends React.Component {
<a <a
href={`${ href={`${
siteConfig.baseUrl siteConfig.baseUrl
}docs/en/${version}/installation.html`} }docs/en/${version}/installation`}
> >
Documentation Documentation
</a> </a>

View file

@ -62,6 +62,7 @@ const siteConfig = {
ogImage: 'img/docusaurus.png', ogImage: 'img/docusaurus.png',
twitterImage: 'img/docusaurus.png', twitterImage: 'img/docusaurus.png',
onPageNav: 'separate', onPageNav: 'separate',
cleanUrl: true,
scrollToTop: true, scrollToTop: true,
scrollToTopOptions: { scrollToTopOptions: {
zIndex: 100 zIndex: 100