mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-06 05:37:16 +02:00
commit
adbae6b2ba
181 changed files with 16758 additions and 1 deletions
|
@ -1,3 +1,4 @@
|
|||
static/**/*.js
|
||||
build
|
||||
node_modules
|
||||
v2
|
||||
|
|
|
@ -6,3 +6,4 @@ yarn.lock
|
|||
website
|
||||
docs
|
||||
docusaurus-init
|
||||
v2
|
||||
|
|
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
@ -0,0 +1 @@
|
|||
v2
|
|
@ -41,7 +41,8 @@
|
|||
"jest": {
|
||||
"testPathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"__fixtures__"
|
||||
"__fixtures__",
|
||||
"v2"
|
||||
],
|
||||
"testURL": "http://localhost/"
|
||||
},
|
||||
|
|
3
v2/.babelrc
Normal file
3
v2/.babelrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"presets": ["env", "react"]
|
||||
}
|
4
v2/.eslintignore
Normal file
4
v2/.eslintignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
generated
|
||||
__fixtures__
|
||||
dist
|
||||
website
|
23
v2/.eslintrc.js
Normal file
23
v2/.eslintrc.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const OFF = 0;
|
||||
const WARNING = 1;
|
||||
const ERROR = 2;
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
jest: true,
|
||||
node: true,
|
||||
},
|
||||
extends: ['airbnb', 'prettier'],
|
||||
rules: {
|
||||
'no-console': OFF,
|
||||
'func-names': OFF,
|
||||
'react/jsx-filename-extension': OFF,
|
||||
'react/jsx-one-expression-per-line': OFF,
|
||||
'react/prop-types': OFF,
|
||||
'react/destructuring-assignment': OFF, // too many lines
|
||||
'import/no-unresolved': WARNING, // because it couldn't resolve webpack alias
|
||||
'react/prefer-stateless-function': WARNING,
|
||||
},
|
||||
};
|
10
v2/.gitignore
vendored
Normal file
10
v2/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
.DS_Store
|
||||
.vscode
|
||||
.idea
|
||||
.eslintcache
|
||||
node_modules
|
||||
dist
|
||||
yarn-error.log
|
||||
generated
|
||||
website/node_modules
|
||||
build
|
3
v2/.prettierignore
Normal file
3
v2/.prettierignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
generated
|
||||
__fixtures__
|
||||
dist
|
8
v2/.prettierrc
Normal file
8
v2/.prettierrc
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"bracketSpacing": false,
|
||||
"jsxBracketSameLine": true,
|
||||
"parser": "flow",
|
||||
"printWidth": 80,
|
||||
"proseWrap": "never",
|
||||
"singleQuote": true
|
||||
}
|
13
v2/README.md
Normal file
13
v2/README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Munseo
|
||||
|
||||
## Development Server
|
||||
|
||||
```bash
|
||||
yarn start # open http://localhost:3000/
|
||||
```
|
||||
|
||||
## Production Build
|
||||
|
||||
```bash
|
||||
yarn build # check website/build
|
||||
```
|
73
v2/bin/munseo.js
Normal file
73
v2/bin/munseo.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const chalk = require('chalk');
|
||||
const semver = require('semver');
|
||||
const path = require('path');
|
||||
const program = require('commander');
|
||||
const {build, eject, init, start} = require('../lib');
|
||||
const requiredVersion = require('../package.json').engines.node;
|
||||
|
||||
if (!semver.satisfies(process.version, requiredVersion)) {
|
||||
console.log(
|
||||
chalk.red(`\nMinimum node version not met :)`) +
|
||||
chalk.yellow(
|
||||
`\nYou are using Node ${
|
||||
process.version
|
||||
}, Requirement: Node ${requiredVersion}.\n`
|
||||
)
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function wrapCommand(fn) {
|
||||
return (...args) =>
|
||||
fn(...args).catch(err => {
|
||||
console.error(chalk.red(err.stack));
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
|
||||
program
|
||||
.version(require('../package.json').version)
|
||||
.usage('<command> [options]');
|
||||
|
||||
program
|
||||
.command('build [siteDir]')
|
||||
.description('Build website')
|
||||
.option(
|
||||
'-sic, --skip-image-compression <skipImageCompression>',
|
||||
'Skip compression of image assets (default: false)'
|
||||
)
|
||||
.action((siteDir = '.', {skipImageCompression}) => {
|
||||
wrapCommand(build)(path.resolve(siteDir), {skipImageCompression});
|
||||
});
|
||||
|
||||
program
|
||||
.command('eject [siteDir]')
|
||||
.description('copy the default theme into website folder for customization.')
|
||||
.action((siteDir = '.') => {
|
||||
wrapCommand(eject)(path.resolve(siteDir));
|
||||
});
|
||||
|
||||
program
|
||||
.command('init [projectDir]')
|
||||
.description('Initialize website')
|
||||
.action((projectDir = '.') => {
|
||||
wrapCommand(init)(path.resolve(projectDir));
|
||||
});
|
||||
|
||||
program
|
||||
.command('start [siteDir]')
|
||||
.description('Start development server')
|
||||
.option('-p, --port <port>', 'use specified port (default: 3000)')
|
||||
.option('-h, --host <host>', 'use specified host (default: localhost')
|
||||
.option('-nw, --no-watch <noWatch>', 'disable live reload (default: false)')
|
||||
.action((siteDir = '.', {port, noWatch}) => {
|
||||
wrapCommand(start)(path.resolve(siteDir), {port, noWatch});
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
if (!process.argv.slice(2).length) {
|
||||
program.outputHelp();
|
||||
}
|
26
v2/docs/docusaurus.md
Normal file
26
v2/docs/docusaurus.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
id: docusaurus
|
||||
title: docusaurus
|
||||
---
|
||||
|
||||
<h1 align="center">
|
||||
<p align="center">Docusaurus</p>
|
||||
<a href="https://docusaurus.io"><img src="/img/slash-introducing.png" alt="Docusaurus"></a>
|
||||
</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/docusaurus"><a href="#backers" alt="sponsors on Open Collective"><img src="https://opencollective.com/Docusaurus/backers/badge.svg" /></a> <a href="#sponsors" alt="Sponsors on Open Collective"><img src="https://opencollective.com/Docusaurus/sponsors/badge.svg" /></a> <img src="https://img.shields.io/npm/v/docusaurus.svg?style=flat" alt="npm version"></a>
|
||||
<a href="https://circleci.com/gh/facebook/Docusaurus"><img src="https://circleci.com/gh/facebook/Docusaurus.svg?style=shield" alt="CircleCI Status"></a>
|
||||
<a href="CONTRIBUTING.md#pull-requests"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome"></a>
|
||||
<a href="https://discord.gg/docusaurus"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg" alt="Chat"></a>
|
||||
<a href="https://github.com/prettier/prettier"><img alt="code style: prettier" src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/facebook/jest"><img src="https://img.shields.io/badge/tested_with-jest-99424f.svg" alt="Tested with Jest"></a>
|
||||
</p>
|
||||
|
||||
## Introduction
|
||||
|
||||
Docusaurus is a project for easily building, deploying, and maintaining open source project websites.
|
||||
|
||||
* **Simple to Start** Docusaurus is built to be easy to [get up and running](https://docusaurus.io/docs/en/installation.html) in as little time possible. We've built Docusaurus to handle the website build process so you can focus on your project.
|
||||
* **Localizable** Docusaurus ships with [localization support](https://docusaurus.io/docs/en/translation.html) via CrowdIn. Empower and grow your international community by translating your documentation.
|
||||
* **Customizable** While Docusaurus ships with the key pages and sections you need to get started, including a home page, a docs section, a [blog](https://docusaurus.io/docs/en/blog.html), and additional support pages, it is also [customizable](https://docusaurus.io/docs/en/custom-pages.html) as well to ensure you have a site that is [uniquely yours](https://docusaurus.io/docs/en/api-pages.html).
|
51
v2/docs/foo/bar.md
Normal file
51
v2/docs/foo/bar.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
id: bar
|
||||
title: My Title
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Experience real-time editing with Remarkable!
|
||||
|
||||
Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results.
|
||||
|
||||
***
|
||||
|
||||
# h1 Heading
|
||||
## h2 Heading
|
||||
### h3 Heading
|
||||
#### h4 Heading
|
||||
##### h5 Heading
|
||||
###### h6 Heading
|
||||
|
||||
|
||||
## Horizontal Rules
|
||||
|
||||
This is horizontal rule
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## Emphasis
|
||||
|
||||
**This is bold text**
|
||||
|
||||
__This is bold text__
|
||||
|
||||
*This is italic text*
|
||||
|
||||
_This is italic text_
|
||||
|
||||
~~Deleted text~~
|
||||
|
||||
Superscript: 19^th^
|
||||
|
||||
Subscript: H~2~O
|
||||
|
||||
++Inserted text++
|
||||
|
||||
==Marked text==
|
74
v2/docs/foo/baz.md
Normal file
74
v2/docs/foo/baz.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: baz
|
||||
title: Test Markdown
|
||||
---
|
||||
|
||||
## Images
|
||||
|
||||

|
||||
|
||||
Like links, Images also have a footnote style syntax
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
With a reference later in the document defining the URL location:
|
||||
|
||||
## Links
|
||||
|
||||
[link text](http://dev.nodeca.com)
|
||||
|
||||
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
|
||||
|
||||
Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
|
||||
|
||||
|
||||
|
||||
## Footnotes
|
||||
|
||||
Footnote 1 link[^first].
|
||||
|
||||
Footnote 2 link[^second].
|
||||
|
||||
Inline footnote^[Text of inline footnote] definition.
|
||||
|
||||
Duplicated footnote reference[^second].
|
||||
|
||||
[^first]: Footnote **can have markup**
|
||||
|
||||
and multiple paragraphs.
|
||||
|
||||
[^second]: Footnote text.
|
||||
|
||||
|
||||
## Definition lists
|
||||
|
||||
Term 1
|
||||
|
||||
: Definition 1
|
||||
with lazy continuation.
|
||||
|
||||
Term 2 with *inline markup*
|
||||
|
||||
: Definition 2
|
||||
|
||||
{ some code, part of Definition 2 }
|
||||
|
||||
Third paragraph of definition 2.
|
||||
|
||||
_Compact style:_
|
||||
|
||||
Term 1
|
||||
~ Definition 1
|
||||
|
||||
Term 2
|
||||
~ Definition 2a
|
||||
~ Definition 2b
|
||||
|
||||
|
||||
## Abbreviations
|
||||
|
||||
This is HTML abbreviation example.
|
||||
|
||||
It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
|
||||
|
||||
*[HTML]: Hyper Text Markup Language
|
52
v2/docs/hello.md
Normal file
52
v2/docs/hello.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
id: hello
|
||||
title: Hello, World !
|
||||
---
|
||||
|
||||
## Relative links
|
||||
|
||||
Replace this
|
||||
[highlight](highlight.md) [docusaurus](docusaurus.md)
|
||||
|
||||
Can't replace this
|
||||
[file](file.md)
|
||||
|
||||
Do not replace below
|
||||
|
||||
```
|
||||
[highlight](highlight.md) [docusaurus](docusaurus.md)
|
||||
```
|
||||
|
||||
## Blockquotes
|
||||
|
||||
> Blockquotes can also be nested...
|
||||
>> ...by using additional greater-than signs right next to each other...
|
||||
> > > ...or with spaces between arrows.
|
||||
|
||||
|
||||
## Lists
|
||||
|
||||
Unordered
|
||||
|
||||
+ Create a list by starting a line with `+`, `-`, or `*`
|
||||
+ Sub-lists are made by indenting 2 spaces:
|
||||
- Marker character change forces new list start:
|
||||
* Ac tristique libero volutpat at
|
||||
+ Facilisis in pretium nisl aliquet
|
||||
- Nulla volutpat aliquam velit
|
||||
+ Very easy!
|
||||
|
||||
Ordered
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. Consectetur adipiscing elit
|
||||
3. Integer molestie lorem at massa
|
||||
|
||||
|
||||
1. You can use sequential numbers...
|
||||
1. ...or keep all the numbers as `1.`
|
||||
|
||||
Start numbering with offset:
|
||||
|
||||
57. foo
|
||||
1. bar
|
44
v2/docs/highlight.md
Normal file
44
v2/docs/highlight.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
id: highlight
|
||||
title: Syntax highlighting demo
|
||||
---
|
||||
|
||||
```cpp
|
||||
#include<bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
cout << "Hello world\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main()
|
||||
{
|
||||
int n, i;
|
||||
bool isPrime = true;
|
||||
|
||||
cout << "Enter a positive integer: ";
|
||||
cin >> n;
|
||||
|
||||
for(i = 2; i <= n / 2; ++i)
|
||||
{
|
||||
if(n % i == 0)
|
||||
{
|
||||
isPrime = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isPrime)
|
||||
cout << "This is a prime number";
|
||||
else
|
||||
cout << "This is not a prime number";
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
77
v2/lib/commands/build.js
Normal file
77
v2/lib/commands/build.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const fs = require('fs-extra');
|
||||
const globby = require('globby');
|
||||
const load = require('../load');
|
||||
const createServerConfig = require('../webpack/server');
|
||||
const createClientConfig = require('../webpack/client');
|
||||
const {applyConfigureWebpack} = require('../webpack/utils');
|
||||
|
||||
function compile(config) {
|
||||
return new Promise((resolve, reject) => {
|
||||
webpack(config, (err, stats) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
if (stats.hasErrors()) {
|
||||
stats.toJson().errors.forEach(e => {
|
||||
console.error(e);
|
||||
});
|
||||
reject(new Error(`Failed to compile with errors.`));
|
||||
}
|
||||
if (stats.hasWarnings()) {
|
||||
stats.toJson().warnings.forEach(warning => {
|
||||
console.warn(warning);
|
||||
});
|
||||
}
|
||||
resolve(stats.toJson({modules: false}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = async function build(siteDir, cliOptions = {}) {
|
||||
process.env.NODE_ENV = 'production';
|
||||
console.log('Build command invoked ...');
|
||||
console.log(cliOptions);
|
||||
|
||||
const props = await load(siteDir);
|
||||
|
||||
let serverConfig = createServerConfig(props).toConfig();
|
||||
let clientConfig = createClientConfig(props).toConfig();
|
||||
|
||||
// apply user webpack config
|
||||
const {
|
||||
siteConfig: {configureWebpack}
|
||||
} = props;
|
||||
clientConfig = applyConfigureWebpack(configureWebpack, clientConfig, false);
|
||||
serverConfig = applyConfigureWebpack(configureWebpack, serverConfig, true);
|
||||
|
||||
// Build the client bundles first.
|
||||
// We cannot run them in parallel because the server need to pickup the correct client bundle name
|
||||
await compile(clientConfig);
|
||||
|
||||
// Build the server bundles (render the static HTML and pick client bundle)
|
||||
await compile(serverConfig);
|
||||
|
||||
// copy static files
|
||||
const {outDir} = props;
|
||||
const staticDir = path.resolve(siteDir, 'static');
|
||||
const staticFiles = await globby(['**'], {
|
||||
cwd: staticDir
|
||||
});
|
||||
await Promise.all(
|
||||
staticFiles.map(async source => {
|
||||
const fromPath = path.resolve(staticDir, source);
|
||||
const toPath = path.resolve(outDir, source);
|
||||
return fs.copy(fromPath, toPath);
|
||||
})
|
||||
);
|
||||
|
||||
const relativeDir = path.relative(process.cwd(), outDir);
|
||||
console.log(
|
||||
`\n${chalk.green('Success!')} Generated static files in ${chalk.cyan(
|
||||
relativeDir
|
||||
)}.\n`
|
||||
);
|
||||
};
|
16
v2/lib/commands/eject.js
Normal file
16
v2/lib/commands/eject.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const fs = require('fs-extra');
|
||||
const chalk = require('chalk');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = async function eject(siteDir) {
|
||||
const defaultTheme = path.resolve(__dirname, '..', 'theme');
|
||||
const customTheme = path.resolve(siteDir, 'theme');
|
||||
await fs.copy(defaultTheme, customTheme);
|
||||
|
||||
const relativeDir = path.relative(process.cwd(), customTheme);
|
||||
console.log(
|
||||
`\n${chalk.green('Success!')} Copied default theme files to ${chalk.cyan(
|
||||
relativeDir
|
||||
)}.\n`
|
||||
);
|
||||
};
|
7
v2/lib/commands/init.js
Normal file
7
v2/lib/commands/init.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
module.exports = async function init(projectDir, cliOptions = {}) {
|
||||
console.log('Init command invoked ...');
|
||||
console.log(projectDir);
|
||||
console.log(cliOptions);
|
||||
|
||||
// TODO
|
||||
};
|
124
v2/lib/commands/start.js
Normal file
124
v2/lib/commands/start.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
const chalk = require('chalk');
|
||||
const webpack = require('webpack');
|
||||
const chokidar = require('chokidar');
|
||||
const convert = require('koa-connect');
|
||||
const range = require('koa-range');
|
||||
const mount = require('koa-mount');
|
||||
const serveStatic = require('koa-static');
|
||||
const history = require('connect-history-api-fallback');
|
||||
const portfinder = require('portfinder');
|
||||
const serve = require('webpack-serve');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const load = require('../load');
|
||||
const createClientConfig = require('../webpack/client');
|
||||
const {applyConfigureWebpack} = require('../webpack/utils');
|
||||
|
||||
function getHost(reqHost) {
|
||||
return reqHost || 'localhost';
|
||||
}
|
||||
|
||||
async function getPort(reqPort) {
|
||||
portfinder.basePort = parseInt(reqPort, 10) || 3000;
|
||||
const port = await portfinder.getPortPromise();
|
||||
return port;
|
||||
}
|
||||
|
||||
module.exports = async function start(siteDir, cliOptions = {}) {
|
||||
console.log('Start command invoked ...');
|
||||
console.log(cliOptions);
|
||||
|
||||
// Process all related files as a prop
|
||||
const props = await load(siteDir);
|
||||
|
||||
// Reload files processing
|
||||
if (!cliOptions.noWatch) {
|
||||
const reload = () => {
|
||||
load(siteDir).catch(err => {
|
||||
console.error(chalk.red(err.stack));
|
||||
});
|
||||
};
|
||||
const docsRelativeDir = props.siteConfig.customDocsPath;
|
||||
const fsWatcher = chokidar.watch(
|
||||
[`../${docsRelativeDir}/**/*.md`, 'blog/**/*.md', 'siteConfig.js'],
|
||||
{
|
||||
cwd: siteDir,
|
||||
ignoreInitial: true
|
||||
}
|
||||
);
|
||||
fsWatcher.on('add', reload);
|
||||
fsWatcher.on('change', reload);
|
||||
fsWatcher.on('unlink', reload);
|
||||
fsWatcher.on('addDir', reload);
|
||||
fsWatcher.on('unlinkDir', reload);
|
||||
}
|
||||
|
||||
const port = await getPort(cliOptions.port);
|
||||
const hotPort = await getPort(port + 1);
|
||||
const host = getHost(cliOptions.host);
|
||||
const {baseUrl} = props;
|
||||
|
||||
// create compiler from generated webpack config
|
||||
let config = createClientConfig(props);
|
||||
|
||||
const {siteConfig} = props;
|
||||
config.plugin('html-webpack-plugin').use(HtmlWebpackPlugin, [
|
||||
{
|
||||
inject: false,
|
||||
hash: true,
|
||||
template: path.resolve(__dirname, '../core/devTemplate.ejs'),
|
||||
filename: 'index.html',
|
||||
title: siteConfig.title
|
||||
}
|
||||
]);
|
||||
config = config.toConfig();
|
||||
|
||||
// apply user webpack config
|
||||
const {
|
||||
siteConfig: {configureWebpack}
|
||||
} = props;
|
||||
config = applyConfigureWebpack(configureWebpack, config, false);
|
||||
|
||||
const compiler = webpack(config);
|
||||
|
||||
// webpack-serve
|
||||
setTimeout(async () => {
|
||||
await serve(
|
||||
{},
|
||||
{
|
||||
compiler,
|
||||
open: true,
|
||||
devMiddleware: {
|
||||
logLevel: 'silent'
|
||||
},
|
||||
hotClient: {
|
||||
port: hotPort,
|
||||
logLevel: 'error'
|
||||
},
|
||||
logLevel: 'error',
|
||||
port,
|
||||
host,
|
||||
add: app => {
|
||||
// serve static files
|
||||
const staticDir = path.resolve(siteDir, 'static');
|
||||
if (fs.existsSync(staticDir)) {
|
||||
app.use(mount(baseUrl, serveStatic(staticDir)));
|
||||
}
|
||||
|
||||
// enable HTTP range requests
|
||||
app.use(range);
|
||||
|
||||
// rewrite request to `/` since dev is only a SPA
|
||||
app.use(
|
||||
convert(
|
||||
history({
|
||||
rewrites: [{from: /\.html$/, to: '/'}]
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}, 1000);
|
||||
};
|
15
v2/lib/core/App.js
Normal file
15
v2/lib/core/App.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {renderRoutes} from 'react-router-config';
|
||||
|
||||
import routes from '@generated/routes'; // eslint-disable-line
|
||||
import docsMetadatas from '@generated/docsMetadatas'; // eslint-disable-line
|
||||
import docsSidebars from '@generated/docsSidebars'; // eslint-disable-line
|
||||
import pagesMetadatas from '@generated/pagesMetadatas'; // eslint-disable-line
|
||||
import siteConfig from '@generated/siteConfig'; //eslint-disable-line
|
||||
|
||||
export default () =>
|
||||
renderRoutes(routes, {
|
||||
docsMetadatas,
|
||||
docsSidebars,
|
||||
pagesMetadatas,
|
||||
siteConfig
|
||||
});
|
19
v2/lib/core/clientEntry.js
Normal file
19
v2/lib/core/clientEntry.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import {BrowserRouter} from 'react-router-dom';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import App from './App';
|
||||
import prerender from './prerender';
|
||||
import routes from '@generated/routes'; // eslint-disable-line
|
||||
|
||||
// Client side render (e.g: running in browser) to become single-page application (SPA)
|
||||
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
||||
prerender(routes, window.location.pathname).then(() => {
|
||||
ReactDOM.render(
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>,
|
||||
document.getElementById('app')
|
||||
);
|
||||
});
|
||||
}
|
12
v2/lib/core/devTemplate.ejs
Normal file
12
v2/lib/core/devTemplate.ejs
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>
|
||||
</body>
|
||||
</html>
|
18
v2/lib/core/prerender.js
Normal file
18
v2/lib/core/prerender.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import {matchRoutes} from 'react-router-config';
|
||||
|
||||
/**
|
||||
* This helps us to make sure all the async component for that particular route
|
||||
* is loaded before rendering. This is to avoid loading screens on first page load
|
||||
*/
|
||||
export default function prerender(routeConfig, providedLocation) {
|
||||
const matches = matchRoutes(routeConfig, providedLocation);
|
||||
return Promise.all(
|
||||
matches.map(match => {
|
||||
const {component} = match.route;
|
||||
if (component && component.preload) {
|
||||
return component.preload();
|
||||
}
|
||||
return undefined;
|
||||
})
|
||||
);
|
||||
}
|
59
v2/lib/core/serverEntry.js
Normal file
59
v2/lib/core/serverEntry.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
import React from 'react';
|
||||
import {StaticRouter} from 'react-router-dom';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
import App from './App';
|
||||
import prerender from './prerender';
|
||||
import routes from '@generated/routes'; // eslint-disable-line
|
||||
import webpackClientStats from '@build/client.stats.json'; //eslint-disable-line
|
||||
|
||||
// Renderer for static-site-generator-webpack-plugin (async rendering via promises)
|
||||
export default function render(locals) {
|
||||
return prerender(routes, locals.path).then(() => {
|
||||
const context = {};
|
||||
const appHtml = ReactDOMServer.renderToString(
|
||||
<StaticRouter location={locals.path} context={context}>
|
||||
<App />
|
||||
</StaticRouter>
|
||||
);
|
||||
|
||||
const helmet = Helmet.renderStatic();
|
||||
const htmlAttributes = helmet.htmlAttributes.toString();
|
||||
const bodyAttributes = helmet.bodyAttributes.toString();
|
||||
const metaStrings = [
|
||||
helmet.title.toString(),
|
||||
helmet.meta.toString(),
|
||||
helmet.link.toString()
|
||||
];
|
||||
const metaHtml = metaStrings.filter(Boolean).join('\n ');
|
||||
|
||||
const assets = webpackClientStats.assetsByChunkName.main;
|
||||
const jsFiles = assets.filter(value => value.match(/\.js$/));
|
||||
const cssFiles = assets.filter(value => value.match(/\.css$/));
|
||||
const {baseUrl} = locals;
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html${htmlAttributes ? ` ${htmlAttributes}` : ''}>
|
||||
<head>
|
||||
${metaHtml}
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
${cssFiles.map(
|
||||
cssFile =>
|
||||
`<link rel="stylesheet" type="text/css" href="${baseUrl}${cssFile}" />`
|
||||
)}
|
||||
</head>
|
||||
<body${bodyAttributes ? ` ${bodyAttributes}` : ''}>
|
||||
<div id="app">${appHtml}</div>
|
||||
${jsFiles.map(
|
||||
jsFile =>
|
||||
`<script type="text/javascript" src="${baseUrl}${jsFile}"></script>`
|
||||
)}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
return html;
|
||||
});
|
||||
}
|
11
v2/lib/index.js
Normal file
11
v2/lib/index.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
const build = require('./commands/build');
|
||||
const init = require('./commands/init');
|
||||
const start = require('./commands/start');
|
||||
const eject = require('./commands/eject');
|
||||
|
||||
module.exports = {
|
||||
build,
|
||||
eject,
|
||||
init,
|
||||
start
|
||||
};
|
67
v2/lib/load/config.js
Normal file
67
v2/lib/load/config.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function loadConfig(siteDir, deleteCache = true) {
|
||||
const configPath = path.resolve(siteDir, 'siteConfig.js');
|
||||
if (deleteCache) {
|
||||
delete require.cache[configPath];
|
||||
}
|
||||
let config = {};
|
||||
if (fs.existsSync(configPath)) {
|
||||
config = require(configPath); // eslint-disable-line
|
||||
}
|
||||
|
||||
const requiredFields = [
|
||||
'title',
|
||||
'tagline',
|
||||
'organizationName',
|
||||
'projectName',
|
||||
'baseUrl'
|
||||
];
|
||||
const optionalFields = [
|
||||
'customDocsPath',
|
||||
'defaultLanguage',
|
||||
'highlight',
|
||||
'markdownPlugins',
|
||||
'configureWebpack',
|
||||
'chainWebpack',
|
||||
'docsUrl',
|
||||
'customFields'
|
||||
];
|
||||
const missingFields = requiredFields.filter(field => !config[field]);
|
||||
if (missingFields && missingFields.length > 0) {
|
||||
throw new Error(
|
||||
`${missingFields.join(', ')} fields are missing in siteConfig.js`
|
||||
);
|
||||
}
|
||||
|
||||
/* Fill default value */
|
||||
const defaultConfig = {
|
||||
customDocsPath: 'docs',
|
||||
docsUrl: 'docs'
|
||||
};
|
||||
Object.keys(defaultConfig).forEach(field => {
|
||||
if (!config[field]) {
|
||||
config[field] = defaultConfig[field];
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
User's own array of custom fields,
|
||||
e.g: if they want to include some field so they can access it later from `props.siteConfig`
|
||||
*/
|
||||
const {customFields = []} = config;
|
||||
|
||||
/* We don't allow useless/ not meaningful field */
|
||||
const allowedFields = [...requiredFields, ...optionalFields, ...customFields];
|
||||
const uselessFields = Object.keys(config).filter(
|
||||
field => !allowedFields.includes(field)
|
||||
);
|
||||
if (uselessFields && uselessFields.length > 0) {
|
||||
throw new Error(
|
||||
`${uselessFields.join(', ')} fields are useless in siteConfig.js`
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
129
v2/lib/load/docs/index.js
Normal file
129
v2/lib/load/docs/index.js
Normal file
|
@ -0,0 +1,129 @@
|
|||
const path = require('path');
|
||||
const globby = require('globby');
|
||||
const createOrder = require('./order');
|
||||
const loadSidebars = require('./sidebars');
|
||||
const processMetadata = require('./metadata');
|
||||
const {getSubFolder, idx} = require('../utils');
|
||||
|
||||
async function loadDocs({siteDir, docsDir, env, siteConfig}) {
|
||||
// @tested - load all sidebars including versioned sidebars
|
||||
const docsSidebars = loadSidebars({siteDir, env});
|
||||
|
||||
// @tested - build the docs ordering such as next, previous, category and sidebar
|
||||
const order = createOrder(docsSidebars);
|
||||
|
||||
/* Settle versions & translations from environment */
|
||||
const translationEnabled = idx(env, ['translation', 'enabled']);
|
||||
const enabledLanguages =
|
||||
translationEnabled && idx(env, ['translation', 'enabledLanguages']);
|
||||
const enabledLangTags =
|
||||
(enabledLanguages && enabledLanguages.map(lang => lang.tag)) || [];
|
||||
const defaultLangTag = idx(env, ['translation', 'defaultLanguage', 'tag']);
|
||||
const versioningEnabled = idx(env, ['versioning', 'enabled']);
|
||||
const versions =
|
||||
(versioningEnabled && idx(env, ['versioning', 'versions'])) || [];
|
||||
|
||||
/* Prepare metadata container */
|
||||
const docsMetadatas = {};
|
||||
|
||||
/* metadata for default docs files */
|
||||
const docsFiles = await globby(['**/*.md'], {
|
||||
cwd: docsDir
|
||||
});
|
||||
await Promise.all(
|
||||
docsFiles.map(async source => {
|
||||
/*
|
||||
Do not allow reserved version/ translated folder name in 'docs'
|
||||
e.g: 'docs/version-1.0.0/' should not be allowed as it can cause unwanted bug
|
||||
*/
|
||||
const subFolder = getSubFolder(path.resolve(docsDir, source), docsDir);
|
||||
const versionsFolders = versions.map(version => `version-${version}`);
|
||||
if ([...enabledLangTags, ...versionsFolders].includes(subFolder)) {
|
||||
throw new Error(`You cannot have a folder named 'docs/${subFolder}/'`);
|
||||
}
|
||||
|
||||
const metadata = await processMetadata(
|
||||
source,
|
||||
docsDir,
|
||||
env,
|
||||
order,
|
||||
siteConfig
|
||||
);
|
||||
docsMetadatas[metadata.id] = metadata;
|
||||
})
|
||||
);
|
||||
|
||||
/* metadata for non-default-language docs */
|
||||
if (translationEnabled) {
|
||||
const translatedDir = path.join(siteDir, 'translated_docs');
|
||||
const translatedFiles = await globby(['**/*.md'], {
|
||||
cwd: translatedDir
|
||||
});
|
||||
await Promise.all(
|
||||
translatedFiles.map(async source => {
|
||||
/*
|
||||
Do not process disabled & default languages folder in `translated_docs`
|
||||
e.g: 'translated_docs/ja/**' should not be processed if lang 'ja' is disabled
|
||||
*/
|
||||
const translatedFilePath = path.resolve(translatedDir, source);
|
||||
const detectedLangTag = getSubFolder(translatedFilePath, translatedDir);
|
||||
if (
|
||||
detectedLangTag === defaultLangTag ||
|
||||
!enabledLangTags.includes(detectedLangTag)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const metadata = await processMetadata(
|
||||
source,
|
||||
translatedDir,
|
||||
env,
|
||||
order,
|
||||
siteConfig
|
||||
);
|
||||
docsMetadatas[metadata.id] = metadata;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/* metadata for versioned docs */
|
||||
if (versioningEnabled) {
|
||||
const versionedDir = path.join(siteDir, 'versioned_docs');
|
||||
const versionedFiles = await globby(['**/*.md'], {
|
||||
cwd: versionedDir
|
||||
});
|
||||
await Promise.all(
|
||||
versionedFiles.map(async source => {
|
||||
const metadata = await processMetadata(
|
||||
source,
|
||||
versionedDir,
|
||||
env,
|
||||
order,
|
||||
siteConfig
|
||||
);
|
||||
docsMetadatas[metadata.id] = metadata;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/* Get the titles of the previous and next ids so that we can use them */
|
||||
Object.keys(docsMetadatas).forEach(currentID => {
|
||||
const previousID = idx(docsMetadatas, [currentID, 'previous']);
|
||||
if (previousID) {
|
||||
const previousTitle = idx(docsMetadatas, [previousID, 'title']);
|
||||
docsMetadatas[currentID].previous_title = previousTitle || 'Previous';
|
||||
}
|
||||
const nextID = idx(docsMetadatas, [currentID, 'next']);
|
||||
if (nextID) {
|
||||
const nextTitle = idx(docsMetadatas, [nextID, 'title']);
|
||||
docsMetadatas[currentID].next_title = nextTitle || 'Next';
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
docsSidebars,
|
||||
docsMetadatas
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = loadDocs;
|
170
v2/lib/load/docs/metadata.js
Normal file
170
v2/lib/load/docs/metadata.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const {getSubFolder, idx, parse} = require('../utils');
|
||||
|
||||
function getLanguage(filepath, refDir, env) {
|
||||
const translationEnabled = idx(env, ['translation', 'enabled']);
|
||||
if (translationEnabled) {
|
||||
const detectedLangTag = getSubFolder(filepath, refDir);
|
||||
const enabledLanguages = idx(env, ['translation', 'enabledLanguages']);
|
||||
const langTags =
|
||||
(enabledLanguages && enabledLanguages.map(lang => lang.tag)) || [];
|
||||
if (langTags.includes(detectedLangTag)) {
|
||||
return detectedLangTag;
|
||||
}
|
||||
const defaultLanguage = idx(env, ['translation', 'defaultLanguage']);
|
||||
if (defaultLanguage && defaultLanguage.tag) {
|
||||
return defaultLanguage.tag;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getVersion(filepath, refDir, env) {
|
||||
const versioningEnabled = idx(env, ['versioning', 'enabled']);
|
||||
if (versioningEnabled) {
|
||||
const subFolder = getSubFolder(filepath, refDir);
|
||||
if (subFolder) {
|
||||
const detectedVersion = subFolder.replace(/^version-/, '');
|
||||
const versions = idx(env, ['versioning', 'versions']) || [];
|
||||
if (versions.includes(detectedVersion)) {
|
||||
return detectedVersion;
|
||||
}
|
||||
}
|
||||
return 'next';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
module.exports = async function processMetadata(
|
||||
source,
|
||||
refDir,
|
||||
env,
|
||||
order,
|
||||
siteConfig
|
||||
) {
|
||||
const filepath = path.resolve(refDir, source);
|
||||
const fileString = await fs.readFile(filepath, 'utf-8');
|
||||
const {metadata} = parse(fileString);
|
||||
|
||||
/* default id is the file name */
|
||||
if (!metadata.id) {
|
||||
metadata.id = path.basename(source, path.extname(source));
|
||||
}
|
||||
if (metadata.id.includes('/')) {
|
||||
throw new Error('Document id cannot include "/".');
|
||||
}
|
||||
|
||||
/* default title is the id */
|
||||
if (!metadata.title) {
|
||||
metadata.title = metadata.id;
|
||||
}
|
||||
|
||||
/* language */
|
||||
const language = getLanguage(filepath, refDir, env);
|
||||
metadata.language = language;
|
||||
const langPart = (language && `${language}/`) || '';
|
||||
|
||||
/* version */
|
||||
const defaultLangTag = idx(env, ['translation', 'defaultLanguage', 'tag']);
|
||||
let versionRefDir = refDir;
|
||||
if (language && language !== defaultLangTag) {
|
||||
versionRefDir = path.join(refDir, language);
|
||||
}
|
||||
const version = getVersion(filepath, versionRefDir, env);
|
||||
metadata.version = version;
|
||||
const latestVersion = idx(env, ['versioning', 'latestVersion']);
|
||||
const versionPart =
|
||||
(version && version !== latestVersion && `${version}/`) || '';
|
||||
|
||||
/*
|
||||
Convert temporarily metadata.id to the form of dirname/id without version/lang prefix
|
||||
ex: file `versioned_docs/version-1.0.0/en/foo/bar.md` with id `version-1.0.0-bar` => `foo/bar`
|
||||
*/
|
||||
if (language) {
|
||||
metadata.id = metadata.id.replace(new RegExp(`^${language}-`), '');
|
||||
}
|
||||
|
||||
if (version) {
|
||||
metadata.id = metadata.id.replace(new RegExp(`^version-${version}-`), '');
|
||||
}
|
||||
|
||||
const dirName = path.dirname(source);
|
||||
if (dirName !== '.') {
|
||||
let prefix = dirName;
|
||||
if (language) {
|
||||
prefix = prefix.replace(new RegExp(`^${language}`), '');
|
||||
}
|
||||
prefix = prefix.replace(/^\//, '');
|
||||
if (version) {
|
||||
prefix = prefix.replace(new RegExp(`^version-${version}`), '');
|
||||
}
|
||||
prefix = prefix.replace(/^\//, '');
|
||||
if (prefix) {
|
||||
metadata.id = `${prefix}/${metadata.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The docs file source
|
||||
e.g: `@docs/hello.md` or `@versioned_docs/version-1.0.0/hello.md`
|
||||
*/
|
||||
if (language && language !== defaultLangTag) {
|
||||
metadata.source = `@translated_docs/${source}`;
|
||||
} else if (version && version !== 'next') {
|
||||
metadata.source = `@versioned_docs/${source}`;
|
||||
} else {
|
||||
metadata.source = `@docs/${source}`;
|
||||
}
|
||||
|
||||
/* Build the permalink */
|
||||
const {baseUrl, docsUrl} = siteConfig;
|
||||
|
||||
/*
|
||||
if user has own custom permalink defined in frontmatter
|
||||
e.g: :baseUrl:docsUrl/:langPart/:versionPart/endiliey/:id
|
||||
*/
|
||||
if (metadata.permalink) {
|
||||
metadata.permalink = path.resolve(
|
||||
metadata.permalink
|
||||
.replace(/:baseUrl/, baseUrl)
|
||||
.replace(/:docsUrl/, docsUrl)
|
||||
.replace(/:langPart/, langPart)
|
||||
.replace(/:versionPart/, versionPart)
|
||||
.replace(/:id/, metadata.id)
|
||||
);
|
||||
} else {
|
||||
metadata.permalink = `${baseUrl}${docsUrl}/${langPart}${versionPart}${
|
||||
metadata.id
|
||||
}`;
|
||||
}
|
||||
|
||||
/* if version */
|
||||
if (version && version !== 'next') {
|
||||
metadata.id = `version-${version}-${metadata.id}`;
|
||||
}
|
||||
|
||||
/* save localized id before adding language on it */
|
||||
metadata.localized_id = metadata.id;
|
||||
|
||||
/* if language */
|
||||
if (language) {
|
||||
metadata.id = `${language}-${metadata.id}`;
|
||||
}
|
||||
|
||||
/* Determine order */
|
||||
const id = metadata.localized_id;
|
||||
if (order[id]) {
|
||||
metadata.sidebar = order[id].sidebar;
|
||||
metadata.category = order[id].category;
|
||||
if (order[id].next) {
|
||||
metadata.next_id = order[id].next;
|
||||
metadata.next = (language ? `${language}-` : '') + order[id].next;
|
||||
}
|
||||
if (order[id].previous) {
|
||||
metadata.previous_id = order[id].previous;
|
||||
metadata.previous = (language ? `${language}-` : '') + order[id].previous;
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
};
|
36
v2/lib/load/docs/order.js
Normal file
36
v2/lib/load/docs/order.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
// build the docs meta such as next, previous, category and sidebar
|
||||
module.exports = function createOrder(allSidebars = {}) {
|
||||
const order = {};
|
||||
if (!allSidebars) {
|
||||
return order;
|
||||
}
|
||||
Object.keys(allSidebars).forEach(sidebar => {
|
||||
const categories = allSidebars[sidebar];
|
||||
|
||||
let ids = [];
|
||||
const categoryOrder = [];
|
||||
Object.keys(categories).forEach(category => {
|
||||
ids = ids.concat(categories[category]);
|
||||
// eslint-disable-next-line
|
||||
for (let i = 0; i < categories[category].length; i++) {
|
||||
categoryOrder.push(category);
|
||||
}
|
||||
});
|
||||
|
||||
// eslint-disable-next-line
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
const id = ids[i];
|
||||
let previous;
|
||||
let next;
|
||||
if (i > 0) previous = ids[i - 1];
|
||||
if (i < ids.length - 1) next = ids[i + 1];
|
||||
order[id] = {
|
||||
previous,
|
||||
next,
|
||||
sidebar,
|
||||
category: categoryOrder[i]
|
||||
};
|
||||
}
|
||||
});
|
||||
return order;
|
||||
};
|
35
v2/lib/load/docs/sidebars.js
Normal file
35
v2/lib/load/docs/sidebars.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const {idx} = require('../utils');
|
||||
|
||||
module.exports = function loadSidebars({siteDir, env}) {
|
||||
let allSidebars = {};
|
||||
|
||||
// current sidebars
|
||||
const sidebarsJSONFile = path.join(siteDir, 'sidebars.json');
|
||||
if (fs.existsSync(sidebarsJSONFile)) {
|
||||
allSidebars = require(sidebarsJSONFile); // eslint-disable-line
|
||||
}
|
||||
|
||||
// versioned sidebars
|
||||
if (idx(env, ['versioning', 'enabled'])) {
|
||||
const versions = idx(env, ['versioning', 'versions']);
|
||||
if (Array.isArray(versions)) {
|
||||
versions.forEach(version => {
|
||||
const versionedSidebarsJSONFile = path.join(
|
||||
siteDir,
|
||||
'versioned_sidebars',
|
||||
`version-${version}-sidebars.json`
|
||||
);
|
||||
if (fs.existsSync(versionedSidebarsJSONFile)) {
|
||||
const sidebar = require(versionedSidebarsJSONFile); // eslint-disable-line
|
||||
Object.assign(allSidebars, sidebar);
|
||||
} else {
|
||||
const missingFile = path.relative(siteDir, versionedSidebarsJSONFile);
|
||||
throw new Error(`Failed to load ${missingFile}. It does not exist.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return allSidebars;
|
||||
};
|
60
v2/lib/load/env.js
Normal file
60
v2/lib/load/env.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const {idx} = require('./utils');
|
||||
|
||||
module.exports = function loadEnv({siteDir, siteConfig}) {
|
||||
// Translation
|
||||
const translation = {
|
||||
enabled: false,
|
||||
enabledLanguages: [],
|
||||
defaultLanguage: {}
|
||||
};
|
||||
|
||||
const languagesFile = path.join(siteDir, 'languages.js');
|
||||
if (fs.existsSync(languagesFile)) {
|
||||
const languages = require(languagesFile); // eslint-disable-line
|
||||
|
||||
/* Enabled languages */
|
||||
const enabledLanguages = languages.filter(lang => lang.enabled);
|
||||
if (!enabledLanguages || enabledLanguages.length === 0) {
|
||||
throw new Error(`Please at least enable one language in 'languages.js'`);
|
||||
}
|
||||
translation.enabledLanguages = enabledLanguages;
|
||||
|
||||
/* Default Language */
|
||||
const {defaultLanguage: defaultLanguageTag} = siteConfig;
|
||||
const defaultLanguage = enabledLanguages.find(
|
||||
lang => lang.tag === defaultLanguageTag
|
||||
);
|
||||
if (!defaultLanguage) {
|
||||
throw new Error(
|
||||
`Please set a default language in 'siteConfig.js' which is enabled in 'languages.js'`
|
||||
);
|
||||
}
|
||||
translation.defaultLanguage = defaultLanguage;
|
||||
|
||||
translation.enabled = true;
|
||||
}
|
||||
|
||||
// Versioning
|
||||
const versioning = {
|
||||
enabled: false,
|
||||
latestVersion: null,
|
||||
defaultVersion: null,
|
||||
versions: []
|
||||
};
|
||||
|
||||
const versionsJSONFile = path.join(siteDir, 'versions.json');
|
||||
if (fs.existsSync(versionsJSONFile)) {
|
||||
versioning.enabled = true;
|
||||
versioning.versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8'));
|
||||
versioning.latestVersion = idx(versioning, ['versions', 0]);
|
||||
const {defaultVersionShown} = siteConfig;
|
||||
versioning.defaultVersion = defaultVersionShown || versioning.latestVersion;
|
||||
}
|
||||
|
||||
return {
|
||||
translation,
|
||||
versioning
|
||||
};
|
||||
};
|
90
v2/lib/load/index.js
Normal file
90
v2/lib/load/index.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
const path = require('path');
|
||||
const loadConfig = require('./config');
|
||||
const loadDocs = require('./docs');
|
||||
const loadEnv = require('./env');
|
||||
const loadPages = require('./pages');
|
||||
const loadTheme = require('./theme');
|
||||
const {generate} = require('./utils');
|
||||
const genRoutesConfig = require('./routes');
|
||||
|
||||
module.exports = async function load(siteDir) {
|
||||
// @tested - siteConfig
|
||||
const siteConfig = loadConfig(siteDir);
|
||||
await generate(
|
||||
'siteConfig.js',
|
||||
`export default ${JSON.stringify(siteConfig, null, 2)};`
|
||||
);
|
||||
|
||||
// @tested - env
|
||||
const env = loadEnv({siteDir, siteConfig});
|
||||
|
||||
// docs
|
||||
const docsDir = path.resolve(siteDir, '..', siteConfig.customDocsPath);
|
||||
const {docsMetadatas, docsSidebars} = await loadDocs({
|
||||
siteDir,
|
||||
docsDir,
|
||||
env,
|
||||
siteConfig
|
||||
});
|
||||
await generate(
|
||||
'docsMetadatas.js',
|
||||
`export default ${JSON.stringify(docsMetadatas, null, 2)};`
|
||||
);
|
||||
await generate(
|
||||
'docsSidebars.js',
|
||||
`export default ${JSON.stringify(docsSidebars, null, 2)};`
|
||||
);
|
||||
|
||||
/* Create source to metadata mapping */
|
||||
const sourceToMetadata = {};
|
||||
Object.values(docsMetadatas).forEach(
|
||||
({source, version, permalink, language}) => {
|
||||
sourceToMetadata[source] = {
|
||||
version,
|
||||
permalink,
|
||||
language
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// pages
|
||||
const pagesDir = path.resolve(siteDir, 'pages');
|
||||
const pagesMetadatas = await loadPages(pagesDir);
|
||||
await generate(
|
||||
'pagesMetadatas.js',
|
||||
`export default ${JSON.stringify(pagesMetadatas, null, 2)};`
|
||||
);
|
||||
|
||||
// resolve outDir
|
||||
const outDir = path.resolve(siteDir, 'build');
|
||||
|
||||
// resolve the theme
|
||||
const themePath = loadTheme(siteDir);
|
||||
|
||||
const {baseUrl} = siteConfig;
|
||||
const versionedDir = path.join(siteDir, 'versioned_docs');
|
||||
const translatedDir = path.join(siteDir, 'translated_docs');
|
||||
|
||||
const props = {
|
||||
siteConfig,
|
||||
siteDir,
|
||||
docsDir,
|
||||
docsMetadatas,
|
||||
docsSidebars,
|
||||
env,
|
||||
pagesDir,
|
||||
pagesMetadatas,
|
||||
outDir,
|
||||
themePath,
|
||||
baseUrl,
|
||||
sourceToMetadata,
|
||||
versionedDir,
|
||||
translatedDir
|
||||
};
|
||||
|
||||
// Generate React Router Config
|
||||
const routesConfig = await genRoutesConfig(props);
|
||||
await generate('routes.js', routesConfig);
|
||||
|
||||
return props;
|
||||
};
|
18
v2/lib/load/pages.js
Normal file
18
v2/lib/load/pages.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const globby = require('globby');
|
||||
const {encodePath, fileToPath} = require('./utils');
|
||||
|
||||
async function loadPages(pagesDir) {
|
||||
const pagesFiles = await globby(['**/*.js'], {
|
||||
cwd: pagesDir
|
||||
});
|
||||
|
||||
const pagesMetadatas = await Promise.all(
|
||||
pagesFiles.map(async source => ({
|
||||
path: encodePath(fileToPath(source)),
|
||||
source
|
||||
}))
|
||||
);
|
||||
return pagesMetadatas;
|
||||
}
|
||||
|
||||
module.exports = loadPages;
|
58
v2/lib/load/routes.js
Normal file
58
v2/lib/load/routes.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
async function genRoutesConfig({docsMetadatas = {}, pagesMetadatas = []}) {
|
||||
function genDocsRoute(metadata) {
|
||||
const {permalink, source} = metadata;
|
||||
return `
|
||||
{
|
||||
path: ${JSON.stringify(permalink)},
|
||||
exact: true,
|
||||
component: Loadable({
|
||||
loader: () => import(${JSON.stringify(source)}),
|
||||
loading: Loading,
|
||||
render(loaded, props) {
|
||||
let Content = loaded.default;
|
||||
return (
|
||||
<Docs {...props} metadata={${JSON.stringify(metadata)}}>
|
||||
<Content />
|
||||
</Docs>
|
||||
);
|
||||
}
|
||||
})
|
||||
}`;
|
||||
}
|
||||
|
||||
function genPagesRoute({path: pagesPath, source}) {
|
||||
return `
|
||||
{
|
||||
path: ${JSON.stringify(pagesPath)},
|
||||
exact: true,
|
||||
component: Loadable({
|
||||
loader: () => import('@pages/${source}'),
|
||||
loading: Loading
|
||||
})
|
||||
}`;
|
||||
}
|
||||
|
||||
const notFoundRoute = `,
|
||||
{
|
||||
path: '*',
|
||||
component: NotFound
|
||||
}`;
|
||||
|
||||
const docsRoutes = Object.values(docsMetadatas)
|
||||
.map(genDocsRoute)
|
||||
.join(',');
|
||||
|
||||
return (
|
||||
`import React from 'react';\n` +
|
||||
`import Loadable from 'react-loadable';\n` +
|
||||
`import Loading from '@theme/Loading';\n` +
|
||||
`import Docs from '@theme/Docs';\n` +
|
||||
`import NotFound from '@theme/NotFound';\n` +
|
||||
`const routes = [${docsRoutes},${pagesMetadatas
|
||||
.map(genPagesRoute)
|
||||
.join(',')}${notFoundRoute}\n];\n` +
|
||||
`export default routes;\n`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = genRoutesConfig;
|
20
v2/lib/load/theme.js
Normal file
20
v2/lib/load/theme.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function loadConfig(siteDir) {
|
||||
const customThemePath = path.resolve(siteDir, 'theme');
|
||||
const themePath = fs.existsSync(customThemePath)
|
||||
? customThemePath
|
||||
: path.resolve(__dirname, '../theme');
|
||||
|
||||
const themeComponents = ['Docs', 'Loading', 'NotFound', 'Markdown'];
|
||||
themeComponents.forEach(component => {
|
||||
if (!require.resolve(path.join(themePath, component))) {
|
||||
throw new Error(
|
||||
`Failed to load ${themePath}/${component}. It does not exist.`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return themePath;
|
||||
};
|
81
v2/lib/load/utils.js
Normal file
81
v2/lib/load/utils.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
const path = require('path');
|
||||
const fm = require('front-matter');
|
||||
const escapeStringRegexp = require('escape-string-regexp');
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const genPath = path.resolve(__dirname, '../core/generated');
|
||||
fs.ensureDirSync(genPath);
|
||||
|
||||
const genCache = new Map();
|
||||
async function generate(file, content) {
|
||||
const cached = genCache.get(file);
|
||||
if (cached !== content) {
|
||||
await fs.writeFile(path.join(genPath, file), content);
|
||||
genCache.set(file, content);
|
||||
}
|
||||
}
|
||||
|
||||
const indexRE = /(^|.*\/)index\.(md|js)$/i;
|
||||
const extRE = /\.(md|js)$/;
|
||||
|
||||
function fileToPath(file) {
|
||||
if (indexRE.test(file)) {
|
||||
return file.replace(indexRE, '/$1');
|
||||
}
|
||||
return `/${file.replace(extRE, '').replace(/\\/g, '/')}`;
|
||||
}
|
||||
|
||||
function encodePath(userpath) {
|
||||
return userpath
|
||||
.split('/')
|
||||
.map(item => encodeURIComponent(item))
|
||||
.join('/');
|
||||
}
|
||||
|
||||
function fileToComponentName(file) {
|
||||
const ext = extRE.exec(file)[1];
|
||||
let str = file.replace(extRE, '');
|
||||
str = str.replace(/([A-Z])/g, ' $1');
|
||||
str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase();
|
||||
str = str.charAt(0).toUpperCase() + str.slice(1);
|
||||
str = str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase());
|
||||
return ext ? ext.toUpperCase() + str : str;
|
||||
}
|
||||
|
||||
function idx(target, keyPaths) {
|
||||
return (
|
||||
target &&
|
||||
(Array.isArray(keyPaths)
|
||||
? keyPaths.reduce((obj, key) => obj && obj[key], target)
|
||||
: target[keyPaths])
|
||||
);
|
||||
}
|
||||
|
||||
function getSubFolder(file, refDir) {
|
||||
const separator = escapeStringRegexp(path.sep);
|
||||
const baseDir = escapeStringRegexp(path.basename(refDir));
|
||||
const regexSubFolder = new RegExp(
|
||||
`${baseDir}${separator}(.*?)${separator}.*`
|
||||
);
|
||||
const match = regexSubFolder.exec(file);
|
||||
return match && match[1];
|
||||
}
|
||||
|
||||
function parse(fileString) {
|
||||
if (!fm.test(fileString)) {
|
||||
return {metadata: null, content: fileString};
|
||||
}
|
||||
const {attributes: metadata, body: content} = fm(fileString);
|
||||
|
||||
return {metadata, content};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
encodePath,
|
||||
generate,
|
||||
fileToPath,
|
||||
fileToComponentName,
|
||||
getSubFolder,
|
||||
idx,
|
||||
parse
|
||||
};
|
80
v2/lib/theme/Docs/index.js
Normal file
80
v2/lib/theme/Docs/index.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
/* eslint-disable */
|
||||
import React from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import Helmet from 'react-helmet';
|
||||
import styles from './styles.css';
|
||||
import Layout from '@theme/Layout'; // eslint-disable-line
|
||||
|
||||
export default class Docs extends React.Component {
|
||||
renderSidebar(metadata, docsSidebars, docsMetadatas) {
|
||||
const {sidebar, language, id: thisID} = metadata;
|
||||
if (!sidebar || !docsSidebars) {
|
||||
return null;
|
||||
}
|
||||
const thisSidebar = docsSidebars[sidebar];
|
||||
return (
|
||||
thisSidebar &&
|
||||
Object.keys(thisSidebar).map(categoryName => {
|
||||
return (
|
||||
<div className="navGroup" key={categoryName}>
|
||||
<h3 className="navGroupCategoryTitle">{categoryName}</h3>
|
||||
<ul>
|
||||
{thisSidebar[categoryName].map(rawLinkID => {
|
||||
const linkID = (language ? `${language}-` : '') + rawLinkID;
|
||||
const linkMetadata = docsMetadatas[linkID];
|
||||
if (!linkMetadata) {
|
||||
throw new Error(
|
||||
`Improper sidebars.json file, document with id '${linkID}' not found.`
|
||||
);
|
||||
}
|
||||
const linkClassName =
|
||||
linkID === thisID ? 'navListItemActive' : 'navListItem';
|
||||
return (
|
||||
<li className={linkClassName} key={linkID}>
|
||||
<Link className="navItem" to={linkMetadata.permalink}>
|
||||
{linkMetadata.sidebar_label || linkMetadata.title}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
route,
|
||||
siteConfig,
|
||||
docsMetadatas,
|
||||
docsSidebars,
|
||||
metadata
|
||||
} = this.props;
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>{(metadata && metadata.title) || siteConfig.title}</title>
|
||||
</Helmet>
|
||||
<div>{this.renderSidebar(metadata, docsSidebars, docsMetadatas)}</div>
|
||||
<div>
|
||||
{metadata.previous &&
|
||||
docsMetadatas[metadata.previous] && (
|
||||
<Link to={docsMetadatas[metadata.previous].permalink}>
|
||||
<span>← {metadata.previous_title}</span>
|
||||
</Link>
|
||||
)}
|
||||
{' ⚫️ '}
|
||||
{metadata.next &&
|
||||
docsMetadatas[metadata.next] && (
|
||||
<Link to={docsMetadatas[metadata.next].permalink}>
|
||||
<span>{metadata.next_title} →</span>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.mainContainer}>{this.props.children}</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
10
v2/lib/theme/Docs/styles.css
Normal file
10
v2/lib/theme/Docs/styles.css
Normal file
|
@ -0,0 +1,10 @@
|
|||
.mainContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 30px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
justify-content: center;
|
||||
}
|
29
v2/lib/theme/Layout/index.js
Normal file
29
v2/lib/theme/Layout/index.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import styles from './styles.css';
|
||||
|
||||
/* eslint-disable react/prefer-stateless-function */
|
||||
export default class Layout extends React.Component {
|
||||
render() {
|
||||
const {children, pagesMetadatas, docsMetadatas = {}, location} = this.props;
|
||||
const docsLinks = Object.values(docsMetadatas).map(data => ({
|
||||
path: `${data.permalink}`
|
||||
}));
|
||||
const routeLinks = [...pagesMetadatas, ...docsLinks].map(
|
||||
data =>
|
||||
data.path !== location.pathname && (
|
||||
<li key={data.path}>
|
||||
<Link to={data.path}>{data.path}</Link>
|
||||
</li>
|
||||
)
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
{children}
|
||||
<div className={styles.footer}>
|
||||
<ul className={styles.routeLinks}>{routeLinks}</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
39
v2/lib/theme/Layout/styles.css
Normal file
39
v2/lib/theme/Layout/styles.css
Normal file
|
@ -0,0 +1,39 @@
|
|||
.footer {
|
||||
color: #777;
|
||||
margin-top: 30px;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.routeLinks {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.routeLinks li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.routeLinks li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.routeLinks li a.selected,
|
||||
.routeLinks li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.routeLinks li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
11
v2/lib/theme/Loading.js
Normal file
11
v2/lib/theme/Loading.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
export default props => {
|
||||
if (props.error) {
|
||||
return <div align="center">Error</div>;
|
||||
}
|
||||
if (props.pastDelay) {
|
||||
return <div align="center">Loading...</div>;
|
||||
}
|
||||
return null;
|
||||
};
|
22
v2/lib/theme/Markdown/anchors.js
Normal file
22
v2/lib/theme/Markdown/anchors.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import toSlug from './toSlug';
|
||||
|
||||
function anchors(md) {
|
||||
const originalRender = md.renderer.rules.heading_open;
|
||||
|
||||
// eslint-disable-next-line
|
||||
md.renderer.rules.heading_open = function(tokens, idx, options, env) {
|
||||
const textToken = tokens[idx + 1];
|
||||
|
||||
if (textToken.content) {
|
||||
const anchor = toSlug(textToken.content, env);
|
||||
|
||||
return `<h${
|
||||
tokens[idx].hLevel
|
||||
}><a class="anchor" aria-hidden="true" id="${anchor}"></a><a href="#${anchor}" aria-hidden="true" class="hash-link"><svg class="hash-link-icon" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>`;
|
||||
}
|
||||
|
||||
return originalRender(tokens, idx, options, env);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = anchors;
|
22
v2/lib/theme/Markdown/highlight.js
Normal file
22
v2/lib/theme/Markdown/highlight.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
const hljs = require('highlight.js');
|
||||
const chalk = require('chalk');
|
||||
const escapeHtml = require('escape-html');
|
||||
|
||||
export default (str, rawLang) => {
|
||||
if (rawLang === 'text' || !rawLang) {
|
||||
return escapeHtml(str);
|
||||
}
|
||||
const lang = rawLang.toLowerCase();
|
||||
try {
|
||||
if (hljs.getLanguage(lang)) {
|
||||
return hljs.highlight(lang, str).value;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
chalk.yellow(
|
||||
`Highlight.js syntax highlighting for language "${lang}" is not supported.`
|
||||
)
|
||||
);
|
||||
}
|
||||
return hljs.highlightAuto(str).value;
|
||||
};
|
94
v2/lib/theme/Markdown/index.js
Normal file
94
v2/lib/theme/Markdown/index.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
/* eslint-disable */
|
||||
|
||||
import React from 'react';
|
||||
import Markdown from 'remarkable';
|
||||
import Helmet from 'react-helmet';
|
||||
import highlight from './highlight';
|
||||
import anchors from './anchors';
|
||||
|
||||
class MarkdownBlock extends React.Component {
|
||||
content() {
|
||||
if (this.props.source) {
|
||||
return (
|
||||
<span
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: this.renderMarkdown(this.props.source)
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return React.Children.map(this.props.children, child => {
|
||||
if (typeof child === 'string') {
|
||||
return (
|
||||
<span
|
||||
dangerouslySetInnerHTML={{__html: this.renderMarkdown(child)}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return child;
|
||||
});
|
||||
}
|
||||
|
||||
renderMarkdown(source) {
|
||||
const alias = {
|
||||
js: 'jsx'
|
||||
};
|
||||
const {siteConfig} = this.props;
|
||||
const md = new Markdown({
|
||||
langPrefix: 'hljs css language-',
|
||||
highlight: highlight,
|
||||
html: true,
|
||||
linkify: true
|
||||
});
|
||||
|
||||
// Register anchors plugin
|
||||
md.use(anchors);
|
||||
|
||||
// Allow client sites to register their own plugins
|
||||
if (siteConfig.markdownPlugins) {
|
||||
siteConfig.markdownPlugins.forEach(plugin => {
|
||||
md.use(plugin);
|
||||
});
|
||||
}
|
||||
|
||||
const html = md.render(source);
|
||||
|
||||
// Ensure fenced code blocks use Highlight.js hljs class
|
||||
// https://github.com/jonschlinkert/remarkable/issues/224
|
||||
return html.replace(/<pre><code>/g, '<pre><code class="hljs">');
|
||||
}
|
||||
|
||||
render() {
|
||||
const {siteConfig} = this.props;
|
||||
const highlight = Object.assign(
|
||||
{},
|
||||
{
|
||||
version: '9.12.0',
|
||||
theme: 'default'
|
||||
},
|
||||
siteConfig.highlight
|
||||
);
|
||||
|
||||
// Use user-provided themeUrl if it exists, else construct one from version and theme.
|
||||
const highlightThemeURL = highlight.themeUrl
|
||||
? highlight.themeUrl
|
||||
: `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${
|
||||
highlight.version
|
||||
}/styles/${highlight.theme}.min.css`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Helmet>
|
||||
<link rel="stylesheet" type="text/css" href={highlightThemeURL} />
|
||||
</Helmet>
|
||||
{this.content()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MarkdownBlock.defaultProps = {
|
||||
siteConfig: {}
|
||||
};
|
||||
|
||||
export default MarkdownBlock;
|
68
v2/lib/theme/Markdown/toSlug.js
Normal file
68
v2/lib/theme/Markdown/toSlug.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* eslint-disable */
|
||||
|
||||
const letters =
|
||||
'\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC';
|
||||
const numbers =
|
||||
'\u0030-\u0039\u00B2\u00B3\u00B9\u00BC-\u00BE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19';
|
||||
const exceptAlphanum = new RegExp(`[^${[letters, numbers].join('')}]`, 'g');
|
||||
|
||||
/**
|
||||
* Converts a string to a slug, that can be used in heading anchors
|
||||
*
|
||||
* @param {string} string
|
||||
* @param {Object} [context={}] - an optional context to track used slugs and
|
||||
* ensure that new slug will be unique
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
module.exports = (string, context = {}) => {
|
||||
// var accents = "àáäâèéëêìíïîòóöôùúüûñç";
|
||||
const accents =
|
||||
'\u00e0\u00e1\u00e4\u00e2\u00e8' +
|
||||
'\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef' +
|
||||
'\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9' +
|
||||
'\u00fa\u00fc\u00fb\u00f1\u00e7';
|
||||
|
||||
const without = 'aaaaeeeeiiiioooouuuunc';
|
||||
|
||||
let slug = string
|
||||
.toString()
|
||||
// Handle uppercase characters
|
||||
.toLowerCase()
|
||||
// Handle accentuated characters
|
||||
.replace(new RegExp(`[${accents}]`, 'g'), c =>
|
||||
without.charAt(accents.indexOf(c))
|
||||
)
|
||||
// Replace `.`, `(` and `?` with blank string like Github does
|
||||
.replace(/\.|\(|\?/g, '')
|
||||
// Dash special characters
|
||||
.replace(exceptAlphanum, '-')
|
||||
// Compress multiple dash
|
||||
.replace(/-+/g, '-')
|
||||
// Trim dashes
|
||||
.replace(/^-|-$/g, '');
|
||||
|
||||
// Add trailing `-` if string contains ` ...` in the end like Github does
|
||||
if (/\s[.]{1,}/.test(string)) {
|
||||
slug += '-';
|
||||
}
|
||||
|
||||
if (!context.slugStats) {
|
||||
context.slugStats = {};
|
||||
}
|
||||
|
||||
if (typeof context.slugStats[slug] === 'number') {
|
||||
// search for an index, that will not clash with an existing headings
|
||||
while (
|
||||
typeof context.slugStats[`${slug}-${++context.slugStats[slug]}`] ===
|
||||
'number'
|
||||
);
|
||||
slug += `-${context.slugStats[slug]}`;
|
||||
}
|
||||
|
||||
// we are tracking both original anchors and suffixed to avoid future name
|
||||
// clashing with headings with numbers e.g. `#Foo 1` may clash with the second `#Foo`
|
||||
context.slugStats[slug] = 0;
|
||||
|
||||
return slug;
|
||||
};
|
18
v2/lib/theme/NotFound.js
Normal file
18
v2/lib/theme/NotFound.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import React from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class NotFound extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout>
|
||||
<div>404 Page Not Found</div>
|
||||
<div>
|
||||
<img
|
||||
alt="Not found"
|
||||
src="https://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX3889253.jpg"
|
||||
/>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
133
v2/lib/webpack/base.js
Normal file
133
v2/lib/webpack/base.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
const Config = require('webpack-chain');
|
||||
const CSSExtractPlugin = require('mini-css-extract-plugin');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const path = require('path');
|
||||
|
||||
const mdLoader = require.resolve('./loader/markdown');
|
||||
|
||||
module.exports = function createBaseConfig(props, isServer) {
|
||||
const {
|
||||
siteConfig,
|
||||
outDir,
|
||||
themePath,
|
||||
docsDir,
|
||||
pagesDir,
|
||||
siteDir,
|
||||
sourceToMetadata,
|
||||
versionedDir,
|
||||
translatedDir,
|
||||
baseUrl
|
||||
} = props;
|
||||
|
||||
const config = new Config();
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
config
|
||||
.mode(isProd ? 'production' : 'development')
|
||||
.output.path(outDir)
|
||||
.filename(isProd ? '[name].[chunkhash].js' : '[name].js')
|
||||
.publicPath(isProd ? baseUrl : '/');
|
||||
|
||||
if (!isProd) {
|
||||
config.devtool('cheap-module-eval-source-map');
|
||||
}
|
||||
|
||||
config.resolve
|
||||
.set('symlinks', true)
|
||||
.alias.set('@theme', themePath)
|
||||
.set('@site', siteDir)
|
||||
.set('@versioned_docs', versionedDir)
|
||||
.set('@translated_docs', translatedDir)
|
||||
.set('@docs', docsDir)
|
||||
.set('@pages', pagesDir)
|
||||
.set('@build', outDir)
|
||||
.set('@generated', path.resolve(__dirname, '../core/generated'))
|
||||
.set('@core', path.resolve(__dirname, '../core'))
|
||||
.end();
|
||||
|
||||
function applyBabel(rule) {
|
||||
rule
|
||||
.use('babel')
|
||||
.loader('babel-loader')
|
||||
.options({
|
||||
babelrc: false,
|
||||
presets: ['env', 'react'],
|
||||
plugins: [isServer ? 'dynamic-import-node' : 'syntax-dynamic-import']
|
||||
});
|
||||
}
|
||||
|
||||
const jsRule = config.module
|
||||
.rule('js')
|
||||
.test(/\.js$/)
|
||||
.exclude.add(filepath => {
|
||||
// Always transpile lib directory
|
||||
if (filepath.startsWith(path.join(__dirname, '..'))) {
|
||||
return false;
|
||||
}
|
||||
// Don't transpile node_modules
|
||||
return /node_modules/.test(filepath);
|
||||
})
|
||||
.end();
|
||||
|
||||
applyBabel(jsRule);
|
||||
|
||||
const mdRule = config.module.rule('markdown').test(/\.md$/);
|
||||
|
||||
applyBabel(mdRule);
|
||||
|
||||
mdRule
|
||||
.use('markdown-loader')
|
||||
.loader(mdLoader)
|
||||
.options({
|
||||
siteConfig,
|
||||
versionedDir,
|
||||
translatedDir,
|
||||
docsDir,
|
||||
sourceToMetadata
|
||||
});
|
||||
|
||||
const cssRule = config.module.rule('css').test(/\.css$/);
|
||||
if (!isServer) {
|
||||
if (isProd) {
|
||||
cssRule.use('extract-css-loader').loader(CSSExtractPlugin.loader);
|
||||
} else {
|
||||
cssRule.use('style-loader').loader('style-loader');
|
||||
}
|
||||
}
|
||||
|
||||
cssRule
|
||||
.use('css-loader')
|
||||
.loader(isServer ? 'css-loader/locals' : 'css-loader')
|
||||
.options({
|
||||
modules: true,
|
||||
importLoaders: 1,
|
||||
localIdentName: `[local]_[hash:base64:8]`,
|
||||
sourceMap: !isProd,
|
||||
minimize: true
|
||||
});
|
||||
|
||||
// mini-css-extract plugin
|
||||
config.plugin('extract-css').use(CSSExtractPlugin, [
|
||||
{
|
||||
filename: isProd ? '[name].[chunkhash].css' : '[name].css',
|
||||
chunkFilename: isProd ? '[id].[chunkhash].css' : '[id].css'
|
||||
}
|
||||
]);
|
||||
|
||||
if (isProd) {
|
||||
config.optimization.minimizer([
|
||||
new UglifyJsPlugin({
|
||||
cache: true,
|
||||
uglifyOptions: {
|
||||
warnings: false,
|
||||
compress: false,
|
||||
ecma: 6,
|
||||
mangle: true
|
||||
},
|
||||
sourceMap: true
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
30
v2/lib/webpack/client.js
Normal file
30
v2/lib/webpack/client.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
const path = require('path');
|
||||
const webpackNiceLog = require('webpack-nicelog');
|
||||
const {StatsWriterPlugin} = require('webpack-stats-plugin');
|
||||
const cleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
const createBaseConfig = require('./base');
|
||||
const {applyChainWebpack} = require('./utils');
|
||||
|
||||
module.exports = function createClientConfig(props) {
|
||||
const config = createBaseConfig(props);
|
||||
config.entry('main').add(path.resolve(__dirname, '../core/clientEntry.js'));
|
||||
|
||||
// remove/clean build folders before building bundles
|
||||
const {outDir} = props;
|
||||
config
|
||||
.plugin('clean')
|
||||
.use(cleanWebpackPlugin, [outDir, {verbose: false, allowExternal: true}]);
|
||||
|
||||
// write webpack stats object so we can pickup correct client bundle path in server.
|
||||
config
|
||||
.plugin('stats')
|
||||
.use(StatsWriterPlugin, [{filename: 'client.stats.json'}]);
|
||||
|
||||
// show compilation progress bar and build time
|
||||
config.plugin('niceLog').use(webpackNiceLog, [{name: 'Client'}]);
|
||||
|
||||
// user extended webpack-chain config
|
||||
applyChainWebpack(props.siteConfig.chainWebpack, config, false);
|
||||
|
||||
return config;
|
||||
};
|
78
v2/lib/webpack/loader/markdown.js
Normal file
78
v2/lib/webpack/loader/markdown.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
const {getOptions} = require('loader-utils');
|
||||
const fm = require('front-matter');
|
||||
|
||||
module.exports = function(fileString) {
|
||||
const options = getOptions(this);
|
||||
const {
|
||||
siteConfig,
|
||||
versionedDir,
|
||||
docsDir,
|
||||
translatedDir,
|
||||
sourceToMetadata
|
||||
} = options;
|
||||
|
||||
/* Extract content of markdown (without frontmatter) */
|
||||
const {body} = fm(fileString);
|
||||
|
||||
/* Determine the source dir. e.g: @docs, @translated_docs/ko and @versioned_docs/version-1.0.0 */
|
||||
let sourceDir;
|
||||
let thisSource = this.resourcePath;
|
||||
if (thisSource.startsWith(translatedDir)) {
|
||||
thisSource = thisSource.replace(translatedDir, '@translated_docs');
|
||||
const {language, version} = sourceToMetadata[thisSource] || {};
|
||||
if (language && version && version !== 'next') {
|
||||
sourceDir = `@translated_docs/${language}/version-${version}`;
|
||||
} else if (language && (!version || version === 'next')) {
|
||||
sourceDir = `@translated_docs/${language}`;
|
||||
}
|
||||
} else if (thisSource.startsWith(versionedDir)) {
|
||||
thisSource = thisSource.replace(versionedDir, '@versioned_docs');
|
||||
const {version} = sourceToMetadata[thisSource] || {};
|
||||
if (version) {
|
||||
sourceDir = `@versioned_docs/version-${version}`;
|
||||
}
|
||||
} else if (thisSource.startsWith(docsDir)) {
|
||||
sourceDir = `@docs`;
|
||||
}
|
||||
|
||||
/* Replace internal markdown linking (except in fenced blocks) */
|
||||
let content = body;
|
||||
if (sourceDir) {
|
||||
let fencedBlock = false;
|
||||
const lines = body.split('\n').map(line => {
|
||||
if (line.trim().startsWith('```')) {
|
||||
fencedBlock = !fencedBlock;
|
||||
}
|
||||
if (fencedBlock) return line;
|
||||
|
||||
let modifiedLine = line;
|
||||
const mdLinks = [];
|
||||
const mdRegex = /(?:\]\()(?:\.\/)?([^'")\]\s>]+\.md)/g;
|
||||
let match = mdRegex.exec(content);
|
||||
while (match !== null) {
|
||||
mdLinks.push(match[1]);
|
||||
match = mdRegex.exec(content);
|
||||
}
|
||||
mdLinks.forEach(mdLink => {
|
||||
const targetSource = `${sourceDir}/${mdLink}`;
|
||||
const {permalink} = sourceToMetadata[targetSource] || {};
|
||||
if (permalink) {
|
||||
modifiedLine = modifiedLine.replace(mdLink, permalink);
|
||||
}
|
||||
});
|
||||
return modifiedLine;
|
||||
});
|
||||
content = lines.join('\n');
|
||||
}
|
||||
|
||||
/* Return a React component */
|
||||
return (
|
||||
`import React from 'react';\n` +
|
||||
`import Markdown from '@theme/Markdown'\n` +
|
||||
`export default () => (
|
||||
<Markdown siteConfig={${JSON.stringify(siteConfig)}}>
|
||||
{${JSON.stringify(content)}}
|
||||
</Markdown>
|
||||
);`
|
||||
);
|
||||
};
|
43
v2/lib/webpack/server.js
Normal file
43
v2/lib/webpack/server.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
const path = require('path');
|
||||
const staticSiteGenerator = require('static-site-generator-webpack-plugin');
|
||||
const webpackNiceLog = require('webpack-nicelog');
|
||||
const createBaseConfig = require('./base');
|
||||
const {applyChainWebpack} = require('./utils');
|
||||
|
||||
module.exports = function createServerConfig(props) {
|
||||
const config = createBaseConfig(props, true);
|
||||
|
||||
config.entry('main').add(path.resolve(__dirname, '../core/serverEntry.js'));
|
||||
config.target('node');
|
||||
config.output.filename('server.bundle.js').libraryTarget('commonjs2');
|
||||
|
||||
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
|
||||
config.output.globalObject('this');
|
||||
|
||||
const {siteConfig, docsMetadatas, pagesMetadatas} = props;
|
||||
|
||||
// static site generator webpack plugin
|
||||
const docsLinks = Object.values(docsMetadatas).map(data => ({
|
||||
path: `${data.permalink}`
|
||||
}));
|
||||
const paths = [...docsLinks, ...pagesMetadatas].map(data => data.path);
|
||||
config.plugin('siteGenerator').use(staticSiteGenerator, [
|
||||
{
|
||||
entry: 'main',
|
||||
locals: {
|
||||
baseUrl: siteConfig.baseUrl
|
||||
},
|
||||
paths
|
||||
}
|
||||
]);
|
||||
|
||||
// show compilation progress bar and build time
|
||||
config
|
||||
.plugin('niceLog')
|
||||
.use(webpackNiceLog, [{name: 'Server', color: 'yellow'}]);
|
||||
|
||||
// user extended webpack-chain config
|
||||
applyChainWebpack(props.siteConfig.chainWebpack, config, true);
|
||||
|
||||
return config;
|
||||
};
|
27
v2/lib/webpack/utils.js
Normal file
27
v2/lib/webpack/utils.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
const merge = require('webpack-merge');
|
||||
|
||||
// Modify the generated webpack config with normal webpack config
|
||||
function applyConfigureWebpack(userConfig, config, isServer) {
|
||||
if (typeof userConfig === 'object') {
|
||||
return merge(config, userConfig);
|
||||
}
|
||||
if (typeof userConfig === 'function') {
|
||||
const res = userConfig(config, isServer);
|
||||
if (res && typeof res === 'object') {
|
||||
return merge(config, res);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
// Modify the generated webpack config with webpack-chain API
|
||||
function applyChainWebpack(userChainWebpack, config, isServer) {
|
||||
if (userChainWebpack) {
|
||||
userChainWebpack(config, isServer);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
applyConfigureWebpack,
|
||||
applyChainWebpack
|
||||
};
|
94
v2/package.json
Normal file
94
v2/package.json
Normal file
|
@ -0,0 +1,94 @@
|
|||
{
|
||||
"name": "munseo",
|
||||
"version": "0.0.1",
|
||||
"description": "📝⚡️ Transform your document (문서) to a website",
|
||||
"main": "lib/index.js",
|
||||
"bin": {
|
||||
"munseo": "bin/munseo.js"
|
||||
},
|
||||
"scripts": {
|
||||
"munseo": "node bin/munseo",
|
||||
"start": "node bin/munseo start website",
|
||||
"build": "node bin/munseo build website",
|
||||
"eject": "node bin/munseo eject website",
|
||||
"prettier": "prettier --config .prettierrc --write \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"",
|
||||
"lint": "eslint --cache \"lib/**/*.js\" \"bin/**/*.js\" \"test/**/*.js\"",
|
||||
"test": "jest --config test/jest.config.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/endiliey/munseo.git"
|
||||
},
|
||||
"keywords": [
|
||||
"blog",
|
||||
"generator",
|
||||
"react"
|
||||
],
|
||||
"author": "endiliey",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/endiliey/munseo/issues"
|
||||
},
|
||||
"homepage": "https://github.com/endiliey/munseo#readme",
|
||||
"devDependencies": {
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb": "17.0.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-react": "^7.9.1",
|
||||
"jest": "^23.4.2",
|
||||
"prettier": "^1.13.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-dynamic-import-node": "^2.0.0",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"chalk": "^2.4.1",
|
||||
"chokidar": "^2.0.4",
|
||||
"classnames": "^2.2.6",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"commander": "^2.16.0",
|
||||
"connect-history-api-fallback": "^1.5.0",
|
||||
"css-loader": "^1.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"front-matter": "^2.3.0",
|
||||
"fs-extra": "^7.0.0",
|
||||
"globby": "^8.0.1",
|
||||
"highlight.js": "^9.12.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"koa-connect": "^2.0.1",
|
||||
"koa-mount": "^3.0.0",
|
||||
"koa-range": "^0.3.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"loader-utils": "^1.1.0",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"portfinder": "^1.0.13",
|
||||
"prismjs": "^1.15.0",
|
||||
"react": "^16.4.1",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-loadable": "^5.5.0",
|
||||
"react-router-config": "^1.0.0-beta.4",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"react-youtube": "^7.6.0",
|
||||
"remarkable": "^1.7.1",
|
||||
"semver": "^5.5.0",
|
||||
"static-site-generator-webpack-plugin": "endiliey/static-site-generator-webpack-plugin#master",
|
||||
"style-loader": "^0.22.1",
|
||||
"uglifyjs-webpack-plugin": "^1.3.0",
|
||||
"webpack": "^4.16.3",
|
||||
"webpack-chain": "^4.8.0",
|
||||
"webpack-merge": "^4.1.4",
|
||||
"webpack-nicelog": "^2.2.1",
|
||||
"webpack-serve": "^2.0.2",
|
||||
"webpack-stats-plugin": "^0.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
}
|
3
v2/test/__fixtures__/custom-site/pages/bar/baz.js
Normal file
3
v2/test/__fixtures__/custom-site/pages/bar/baz.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import React from 'react';
|
||||
|
||||
export default () => <div>Baz</div>;
|
3
v2/test/__fixtures__/custom-site/pages/foo.js
Normal file
3
v2/test/__fixtures__/custom-site/pages/foo.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import React from 'react';
|
||||
|
||||
export default () => <div>Foo</div>;
|
3
v2/test/__fixtures__/custom-site/pages/foo/index.js
Normal file
3
v2/test/__fixtures__/custom-site/pages/foo/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import React from 'react';
|
||||
|
||||
export default () => <div>Foo in subfolder</div>;
|
3
v2/test/__fixtures__/custom-site/pages/index.js
Normal file
3
v2/test/__fixtures__/custom-site/pages/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import React from 'react';
|
||||
|
||||
export default () => <div>Index</div>;
|
7
v2/test/__fixtures__/custom-site/siteConfig.js
Normal file
7
v2/test/__fixtures__/custom-site/siteConfig.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
title: 'Sakura',
|
||||
tagline: 'This is not an ordinary site',
|
||||
organizationName: 'endiliey',
|
||||
projectName: 'sakura',
|
||||
baseUrl: '/sakura/'
|
||||
};
|
66
v2/test/__fixtures__/docs/foo/bar.md
Normal file
66
v2/test/__fixtures__/docs/foo/bar.md
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: bar
|
||||
title: Bar
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Experience real-time editing with Remarkable!
|
||||
|
||||
Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results.
|
||||
|
||||
***
|
||||
|
||||
# h1 Heading
|
||||
## h2 Heading
|
||||
### h3 Heading
|
||||
#### h4 Heading
|
||||
##### h5 Heading
|
||||
###### h6 Heading
|
||||
|
||||
|
||||
## Horizontal Rules
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## Typographic replacements
|
||||
|
||||
Enable typographer option to see result.
|
||||
|
||||
(c) (C) (r) (R) (tm) (TM) (p) (P) +-
|
||||
|
||||
test.. test... test..... test?..... test!....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
Remarkable -- awesome
|
||||
|
||||
"Smartypants, double quotes"
|
||||
|
||||
'Smartypants, single quotes'
|
||||
|
||||
|
||||
## Emphasis
|
||||
|
||||
**This is bold text**
|
||||
|
||||
__This is bold text__
|
||||
|
||||
*This is italic text*
|
||||
|
||||
_This is italic text_
|
||||
|
||||
~~Deleted text~~
|
||||
|
||||
Superscript: 19^th^
|
||||
|
||||
Subscript: H~2~O
|
||||
|
||||
++Inserted text++
|
||||
|
||||
==Marked text==
|
74
v2/test/__fixtures__/docs/foo/baz.md
Normal file
74
v2/test/__fixtures__/docs/foo/baz.md
Normal file
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: baz
|
||||
title: baz
|
||||
---
|
||||
|
||||
## Images
|
||||
|
||||
Like links, Images also have a footnote style syntax
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
With a reference later in the document defining the URL location:
|
||||
|
||||
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## Links
|
||||
|
||||
[link text](http://dev.nodeca.com)
|
||||
|
||||
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
|
||||
|
||||
Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
|
||||
|
||||
|
||||
|
||||
## Footnotes
|
||||
|
||||
Footnote 1 link[^first].
|
||||
|
||||
Footnote 2 link[^second].
|
||||
|
||||
Inline footnote^[Text of inline footnote] definition.
|
||||
|
||||
Duplicated footnote reference[^second].
|
||||
|
||||
[^first]: Footnote **can have markup**
|
||||
|
||||
and multiple paragraphs.
|
||||
|
||||
[^second]: Footnote text.
|
||||
|
||||
|
||||
## Definition lists
|
||||
|
||||
Term 1
|
||||
|
||||
: Definition 1
|
||||
with lazy continuation.
|
||||
|
||||
Term 2 with *inline markup*
|
||||
|
||||
: Definition 2
|
||||
|
||||
{ some code, part of Definition 2 }
|
||||
|
||||
Third paragraph of definition 2.
|
||||
|
||||
_Compact style:_
|
||||
|
||||
Term 1
|
||||
~ Definition 1
|
||||
|
||||
Term 2
|
||||
~ Definition 2a
|
||||
~ Definition 2b
|
||||
|
||||
|
||||
## Abbreviations
|
||||
|
||||
This is HTML abbreviation example.
|
||||
|
||||
It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
|
||||
|
||||
*[HTML]: Hyper Text Markup Language
|
54
v2/test/__fixtures__/docs/hello.md
Normal file
54
v2/test/__fixtures__/docs/hello.md
Normal file
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
id: hello
|
||||
title: Hello, World !
|
||||
---
|
||||
|
||||
Hi, Endilie here :)
|
||||
|
||||
## Relative links
|
||||
|
||||
Replace this
|
||||
[foo](foo/bar.md)
|
||||
|
||||
Can't replace this
|
||||
[file](file.md)
|
||||
|
||||
Do not replace below
|
||||
|
||||
```
|
||||
[hello](hello.md)
|
||||
```
|
||||
|
||||
## Blockquotes
|
||||
|
||||
> Blockquotes can also be nested...
|
||||
>> ...by using additional greater-than signs right next to each other...
|
||||
> > > ...or with spaces between arrows.
|
||||
|
||||
|
||||
## Lists
|
||||
|
||||
Unordered
|
||||
|
||||
+ Create a list by starting a line with `+`, `-`, or `*`
|
||||
+ Sub-lists are made by indenting 2 spaces:
|
||||
- Marker character change forces new list start:
|
||||
* Ac tristique libero volutpat at
|
||||
+ Facilisis in pretium nisl aliquet
|
||||
- Nulla volutpat aliquam velit
|
||||
+ Very easy!
|
||||
|
||||
Ordered
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. Consectetur adipiscing elit
|
||||
3. Integer molestie lorem at massa
|
||||
|
||||
|
||||
1. You can use sequential numbers...
|
||||
1. ...or keep all the numbers as `1.`
|
||||
|
||||
Start numbering with offset:
|
||||
|
||||
57. foo
|
||||
1. bar
|
7
v2/test/__fixtures__/docs/permalink.md
Normal file
7
v2/test/__fixtures__/docs/permalink.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
id: permalink
|
||||
title: Permalink
|
||||
permalink: :baseUrl:docsUrl/:langPart/:versionPart/endiliey/:id
|
||||
---
|
||||
|
||||
This has a different permalink
|
17
v2/test/__fixtures__/simple-site/pages/hello/world.js
Normal file
17
v2/test/__fixtures__/simple-site/pages/hello/world.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class World extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>World</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
|
||||
</Helmet>
|
||||
<div>Hello World </div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
17
v2/test/__fixtures__/simple-site/pages/index.js
Normal file
17
v2/test/__fixtures__/simple-site/pages/index.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class Home extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>Home</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
|
||||
</Helmet>
|
||||
<div>Home ... </div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
11
v2/test/__fixtures__/simple-site/sidebars.json
Normal file
11
v2/test/__fixtures__/simple-site/sidebars.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz"
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
7
v2/test/__fixtures__/simple-site/siteConfig.js
Normal file
7
v2/test/__fixtures__/simple-site/siteConfig.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
title: 'Hello',
|
||||
tagline: 'Hello World',
|
||||
organizationName: 'endiliey',
|
||||
projectName: 'hello',
|
||||
baseUrl: '/'
|
||||
};
|
378
v2/test/__fixtures__/simple-site/static/css/basic.css
Normal file
378
v2/test/__fixtures__/simple-site/static/css/basic.css
Normal file
|
@ -0,0 +1,378 @@
|
|||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="checkbox"] {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
label[for='toggle-all'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
left: -12px;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
border: none; /* Mobile Safari */
|
||||
}
|
||||
|
||||
.toggle-all:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 13px 17px 12px 17px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none; /* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
white-space: pre-line;
|
||||
word-break: break-all;
|
||||
padding: 15px 60px 15px 15px;
|
||||
margin-left: 45px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a.selected,
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
BIN
v2/test/__fixtures__/simple-site/static/img/sakura.png
Normal file
BIN
v2/test/__fixtures__/simple-site/static/img/sakura.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
178
v2/test/__fixtures__/translated-site/languages.js
Normal file
178
v2/test/__fixtures__/translated-site/languages.js
Normal file
|
@ -0,0 +1,178 @@
|
|||
const languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: 'English',
|
||||
tag: 'en',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: '日本語',
|
||||
tag: 'ja',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'العربية',
|
||||
tag: 'ar',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Bosanski',
|
||||
tag: 'bs-BA',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Català',
|
||||
tag: 'ca',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Čeština',
|
||||
tag: 'cs',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Dansk',
|
||||
tag: 'da',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Deutsch',
|
||||
tag: 'de',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Ελληνικά',
|
||||
tag: 'el',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Español',
|
||||
tag: 'es-ES',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'فارسی',
|
||||
tag: 'fa-IR',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Suomi',
|
||||
tag: 'fi',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Français',
|
||||
tag: 'fr',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'עִברִית',
|
||||
tag: 'he',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Magyar',
|
||||
tag: 'hu',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Bahasa Indonesia',
|
||||
tag: 'id-ID',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Italiano',
|
||||
tag: 'it',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Afrikaans',
|
||||
tag: 'af',
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
name: '한국어',
|
||||
tag: 'ko',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'मराठी',
|
||||
tag: 'mr-IN',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Nederlands',
|
||||
tag: 'nl',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Norsk',
|
||||
tag: 'no-NO',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Polskie',
|
||||
tag: 'pl',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Português',
|
||||
tag: 'pt-PT',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Português (Brasil)',
|
||||
tag: 'pt-BR',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Română',
|
||||
tag: 'ro',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Русский',
|
||||
tag: 'ru',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Slovenský',
|
||||
tag: 'sk-SK',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Српски језик (Ћирилица)',
|
||||
tag: 'sr',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Svenska',
|
||||
tag: 'sv-SE',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Türkçe',
|
||||
tag: 'tr',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Українська',
|
||||
tag: 'uk',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Tiếng Việt',
|
||||
tag: 'vi',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: '简体中文',
|
||||
tag: 'zh-CN',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: '繁體中文',
|
||||
tag: 'zh-TW',
|
||||
},
|
||||
];
|
||||
module.exports = languages;
|
17
v2/test/__fixtures__/translated-site/pages/hello/world.js
Normal file
17
v2/test/__fixtures__/translated-site/pages/hello/world.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class World extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>World</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
|
||||
</Helmet>
|
||||
<div>Hello World </div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
17
v2/test/__fixtures__/translated-site/pages/index.js
Normal file
17
v2/test/__fixtures__/translated-site/pages/index.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class Home extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>Home</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
|
||||
</Helmet>
|
||||
<div>Home ... </div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
11
v2/test/__fixtures__/translated-site/sidebars.json
Normal file
11
v2/test/__fixtures__/translated-site/sidebars.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz"
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
8
v2/test/__fixtures__/translated-site/siteConfig.js
Normal file
8
v2/test/__fixtures__/translated-site/siteConfig.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
title: 'Hello',
|
||||
tagline: 'Hello World',
|
||||
organizationName: 'endiliey',
|
||||
projectName: 'hello',
|
||||
baseUrl: '/',
|
||||
defaultLanguage: 'en'
|
||||
};
|
378
v2/test/__fixtures__/translated-site/static/css/basic.css
Normal file
378
v2/test/__fixtures__/translated-site/static/css/basic.css
Normal file
|
@ -0,0 +1,378 @@
|
|||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="checkbox"] {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
label[for='toggle-all'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
left: -12px;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
border: none; /* Mobile Safari */
|
||||
}
|
||||
|
||||
.toggle-all:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 13px 17px 12px 17px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none; /* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
white-space: pre-line;
|
||||
word-break: break-all;
|
||||
padding: 15px 60px 15px 15px;
|
||||
margin-left: 45px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a.selected,
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
BIN
v2/test/__fixtures__/translated-site/static/img/sakura.png
Normal file
BIN
v2/test/__fixtures__/translated-site/static/img/sakura.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: bar
|
||||
title: Bar
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Remarkable로 실시간 편집을 경험하십시오!
|
||||
|
||||
깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다.
|
||||
|
||||
***
|
||||
|
||||
# h1 제목
|
||||
## h2 제목
|
||||
### h3 제목
|
||||
#### h4 헤딩
|
||||
##### h5 제목
|
||||
###### h6 제목
|
||||
|
||||
|
||||
## 수평 규칙
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## 활자체 대체
|
||||
|
||||
입력기 옵션을 사용하면 결과를 볼 수 있습니다.
|
||||
|
||||
(p) (P) + - (r) (t)
|
||||
|
||||
테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! ....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
놀라운 - 굉장한
|
||||
|
||||
"Smartypants, 큰 따옴표"
|
||||
|
||||
'Smartypants, 작은 따옴표'
|
||||
|
||||
|
||||
## 강조
|
||||
|
||||
** 이것은 굵은 글씨입니다 **
|
||||
|
||||
__ 이것은 굵은 글씨입니다 __
|
||||
|
||||
* 이탤릭체 텍스트 *
|
||||
|
||||
_ 이탤릭체 텍스트 _
|
||||
|
||||
~~ 삭제 된 텍스트 ~~
|
||||
|
||||
위 첨자 : 19 ^ th ^
|
||||
|
||||
아래 첨자 : H ~ 2 ~ O
|
||||
|
||||
++ 삽입 된 텍스트 ++
|
||||
|
||||
== 표시된 텍스트 ==
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: baz
|
||||
title: baz
|
||||
---
|
||||
|
||||
## 이미지
|
||||
|
||||
링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다.
|
||||
|
||||
! [Alt text] [id]
|
||||
|
||||
나중에 URL 위치를 정의하는 문서에서 참조로 :
|
||||
|
||||
[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## 링크
|
||||
|
||||
[링크 텍스트] (http://dev.nodeca.com)
|
||||
|
||||
[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!")
|
||||
|
||||
자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정)
|
||||
|
||||
|
||||
|
||||
## 각주
|
||||
|
||||
각주 1 링크 [^ 첫 번째].
|
||||
|
||||
각주 2 링크 [^ 초].
|
||||
|
||||
인라인 각주 ^ [인라인 각주의 텍스트] 정의.
|
||||
|
||||
중복 된 각주 참조 [^ 초].
|
||||
|
||||
[^ first] : 각주 **는 마크 업을 가질 수 있습니다 **
|
||||
|
||||
및 여러 단락.
|
||||
|
||||
[^ 초] : 각주 텍스트.
|
||||
|
||||
|
||||
## 정의 목록
|
||||
|
||||
1 학기
|
||||
|
||||
정의 1
|
||||
게으른 연속.
|
||||
|
||||
* 인라인 마크 업과 함께 2 학기 *
|
||||
|
||||
: 정의 2
|
||||
|
||||
{일부 코드, 정의 2의 일부}
|
||||
|
||||
정의의 세 번째 단락 2.
|
||||
|
||||
_ 컴팩트 스타일 : _
|
||||
|
||||
1 학기
|
||||
~ 정의 1
|
||||
|
||||
2 학기
|
||||
~ 정의 2a
|
||||
~ 정의 2b
|
||||
|
||||
|
||||
## 약어
|
||||
|
||||
이것은 HTML 약어입니다.
|
||||
|
||||
그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다.
|
||||
|
||||
* [HTML] : 하이퍼 텍스트 마크 업 언어
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
id: hello
|
||||
title: Hello, World !
|
||||
---
|
||||
|
||||
안녕하세요, 여기 엔 틸리에 :)
|
||||
|
||||
## Blockquotes
|
||||
|
||||
> Blockquotes는 또한 중첩 될 수 있습니다 ...
|
||||
>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ...
|
||||
>>> ... 또는 화살표 사이에 공백이 있어야합니다.
|
||||
|
||||
|
||||
## 목록
|
||||
|
||||
정렬되지 않은
|
||||
|
||||
+`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다.
|
||||
+ 하위 목록은 2 칸을 들여서 만들어집니다 :
|
||||
- 마커 문자 변경으로 새로운 목록 시작 :
|
||||
* AC tristique libero volutpat at
|
||||
+ Preisium nisl aliquet에 대한 + 시설
|
||||
- Nulla volutpat aliquam velit
|
||||
+ 매우 쉽습니다!
|
||||
|
||||
주문 됨
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. 컨소시엄 adipiscing 엘리트
|
||||
3. massa에서의 정수 lorem
|
||||
|
||||
|
||||
1. 일련 번호를 사용할 수 있습니다 ...
|
||||
1. ... 또는 모든 숫자를 '1'로 유지하십시오.
|
||||
|
||||
오프셋을 사용하여 번호 매기기 시작 :
|
||||
|
||||
57. foo
|
||||
1. 막대기
|
178
v2/test/__fixtures__/transversioned-site/languages.js
Normal file
178
v2/test/__fixtures__/transversioned-site/languages.js
Normal file
|
@ -0,0 +1,178 @@
|
|||
const languages = [
|
||||
{
|
||||
enabled: true,
|
||||
name: 'English',
|
||||
tag: 'en',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: '日本語',
|
||||
tag: 'ja',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'العربية',
|
||||
tag: 'ar',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Bosanski',
|
||||
tag: 'bs-BA',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Català',
|
||||
tag: 'ca',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Čeština',
|
||||
tag: 'cs',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Dansk',
|
||||
tag: 'da',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Deutsch',
|
||||
tag: 'de',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Ελληνικά',
|
||||
tag: 'el',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Español',
|
||||
tag: 'es-ES',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'فارسی',
|
||||
tag: 'fa-IR',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Suomi',
|
||||
tag: 'fi',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Français',
|
||||
tag: 'fr',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'עִברִית',
|
||||
tag: 'he',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Magyar',
|
||||
tag: 'hu',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Bahasa Indonesia',
|
||||
tag: 'id-ID',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Italiano',
|
||||
tag: 'it',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Afrikaans',
|
||||
tag: 'af',
|
||||
},
|
||||
{
|
||||
enabled: true,
|
||||
name: '한국어',
|
||||
tag: 'ko',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'मराठी',
|
||||
tag: 'mr-IN',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Nederlands',
|
||||
tag: 'nl',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Norsk',
|
||||
tag: 'no-NO',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Polskie',
|
||||
tag: 'pl',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Português',
|
||||
tag: 'pt-PT',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Português (Brasil)',
|
||||
tag: 'pt-BR',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Română',
|
||||
tag: 'ro',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Русский',
|
||||
tag: 'ru',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Slovenský',
|
||||
tag: 'sk-SK',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Српски језик (Ћирилица)',
|
||||
tag: 'sr',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Svenska',
|
||||
tag: 'sv-SE',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Türkçe',
|
||||
tag: 'tr',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Українська',
|
||||
tag: 'uk',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: 'Tiếng Việt',
|
||||
tag: 'vi',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: '简体中文',
|
||||
tag: 'zh-CN',
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
name: '繁體中文',
|
||||
tag: 'zh-TW',
|
||||
},
|
||||
];
|
||||
module.exports = languages;
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class World extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>World</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
|
||||
</Helmet>
|
||||
<div>Hello World </div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
17
v2/test/__fixtures__/transversioned-site/pages/index.js
Normal file
17
v2/test/__fixtures__/transversioned-site/pages/index.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default class Home extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Layout {...this.props}>
|
||||
<Helmet>
|
||||
<title>Home</title>
|
||||
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
|
||||
</Helmet>
|
||||
<div>Home ... </div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
11
v2/test/__fixtures__/transversioned-site/sidebars.json
Normal file
11
v2/test/__fixtures__/transversioned-site/sidebars.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"docs": {
|
||||
"Test": [
|
||||
"foo/bar",
|
||||
"foo/baz"
|
||||
],
|
||||
"Guides": [
|
||||
"hello"
|
||||
]
|
||||
}
|
||||
}
|
8
v2/test/__fixtures__/transversioned-site/siteConfig.js
Normal file
8
v2/test/__fixtures__/transversioned-site/siteConfig.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
title: 'Hello',
|
||||
tagline: 'Hello World',
|
||||
organizationName: 'endiliey',
|
||||
projectName: 'hello',
|
||||
baseUrl: '/',
|
||||
defaultLanguage: 'en'
|
||||
};
|
378
v2/test/__fixtures__/transversioned-site/static/css/basic.css
Normal file
378
v2/test/__fixtures__/transversioned-site/static/css/basic.css
Normal file
|
@ -0,0 +1,378 @@
|
|||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: none;
|
||||
font-size: 100%;
|
||||
vertical-align: baseline;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
body {
|
||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
line-height: 1.4em;
|
||||
background: #f5f5f5;
|
||||
color: #4d4d4d;
|
||||
min-width: 230px;
|
||||
max-width: 550px;
|
||||
margin: 0 auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
button,
|
||||
input[type="checkbox"] {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todoapp {
|
||||
background: #fff;
|
||||
margin: 130px 0 40px 0;
|
||||
position: relative;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.todoapp input::-webkit-input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::-moz-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp input::input-placeholder {
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
color: #e6e6e6;
|
||||
}
|
||||
|
||||
.todoapp h1 {
|
||||
position: absolute;
|
||||
top: -155px;
|
||||
width: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: rgba(175, 47, 47, 0.15);
|
||||
-webkit-text-rendering: optimizeLegibility;
|
||||
-moz-text-rendering: optimizeLegibility;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.new-todo,
|
||||
.edit {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
font-family: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: 1.4em;
|
||||
border: 0;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
padding: 6px;
|
||||
border: 1px solid #999;
|
||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.new-todo {
|
||||
padding: 16px 16px 16px 60px;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.003);
|
||||
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
|
||||
}
|
||||
|
||||
.main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
label[for='toggle-all'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
left: -12px;
|
||||
width: 60px;
|
||||
height: 34px;
|
||||
text-align: center;
|
||||
border: none; /* Mobile Safari */
|
||||
}
|
||||
|
||||
.toggle-all:before {
|
||||
content: '❯';
|
||||
font-size: 22px;
|
||||
color: #e6e6e6;
|
||||
padding: 10px 27px 10px 27px;
|
||||
}
|
||||
|
||||
.toggle-all:checked:before {
|
||||
color: #737373;
|
||||
}
|
||||
|
||||
.todo-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.todo-list li {
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #ededed;
|
||||
}
|
||||
|
||||
.todo-list li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing {
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.todo-list li.editing .edit {
|
||||
display: block;
|
||||
width: 506px;
|
||||
padding: 13px 17px 12px 17px;
|
||||
margin: 0 0 0 43px;
|
||||
}
|
||||
|
||||
.todo-list li.editing .view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
||||
height: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
border: none; /* Mobile Safari */
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li .toggle:checked:after {
|
||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
|
||||
}
|
||||
|
||||
.todo-list li label {
|
||||
white-space: pre-line;
|
||||
word-break: break-all;
|
||||
padding: 15px 60px 15px 15px;
|
||||
margin-left: 45px;
|
||||
display: block;
|
||||
line-height: 1.2;
|
||||
transition: color 0.4s;
|
||||
}
|
||||
|
||||
.todo-list li.completed label {
|
||||
color: #d9d9d9;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.todo-list li .destroy {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 10px;
|
||||
bottom: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: auto 0;
|
||||
font-size: 30px;
|
||||
color: #cc9a9a;
|
||||
margin-bottom: 11px;
|
||||
transition: color 0.2s ease-out;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:hover {
|
||||
color: #af5b5e;
|
||||
}
|
||||
|
||||
.todo-list li .destroy:after {
|
||||
content: '×';
|
||||
}
|
||||
|
||||
.todo-list li:hover .destroy {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.todo-list li .edit {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.todo-list li.editing:last-child {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: #777;
|
||||
padding: 10px 15px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e6e6e6;
|
||||
}
|
||||
|
||||
.footer:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
||||
0 8px 0 -3px #f6f6f6,
|
||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
||||
0 16px 0 -6px #f6f6f6,
|
||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.todo-count {
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.todo-count strong {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.filters li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.filters li a {
|
||||
color: inherit;
|
||||
margin: 3px;
|
||||
padding: 3px 7px;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.filters li a.selected,
|
||||
.filters li a:hover {
|
||||
border-color: rgba(175, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.filters li a.selected {
|
||||
border-color: rgba(175, 47, 47, 0.2);
|
||||
}
|
||||
|
||||
.clear-completed,
|
||||
html .clear-completed:active {
|
||||
float: right;
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.clear-completed:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin: 65px auto 0;
|
||||
color: #bfbfbf;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info p {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.info a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.info a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Hack to remove background from Mobile Safari.
|
||||
Can't use it globally since it destroys checkboxes in Firefox
|
||||
*/
|
||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||
.toggle-all,
|
||||
.todo-list li .toggle {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.todo-list li .toggle {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.toggle-all {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.footer {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
BIN
v2/test/__fixtures__/transversioned-site/static/img/sakura.png
Normal file
BIN
v2/test/__fixtures__/transversioned-site/static/img/sakura.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: bar
|
||||
title: Bar
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Remarkable로 실시간 편집을 경험하십시오!
|
||||
|
||||
깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다.
|
||||
|
||||
***
|
||||
|
||||
# h1 제목
|
||||
## h2 제목
|
||||
### h3 제목
|
||||
#### h4 헤딩
|
||||
##### h5 제목
|
||||
###### h6 제목
|
||||
|
||||
|
||||
## 수평 규칙
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## 활자체 대체
|
||||
|
||||
입력기 옵션을 사용하면 결과를 볼 수 있습니다.
|
||||
|
||||
(p) (P) + - (r) (t)
|
||||
|
||||
테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! ....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
놀라운 - 굉장한
|
||||
|
||||
"Smartypants, 큰 따옴표"
|
||||
|
||||
'Smartypants, 작은 따옴표'
|
||||
|
||||
|
||||
## 강조
|
||||
|
||||
** 이것은 굵은 글씨입니다 **
|
||||
|
||||
__ 이것은 굵은 글씨입니다 __
|
||||
|
||||
* 이탤릭체 텍스트 *
|
||||
|
||||
_ 이탤릭체 텍스트 _
|
||||
|
||||
~~ 삭제 된 텍스트 ~~
|
||||
|
||||
위 첨자 : 19 ^ th ^
|
||||
|
||||
아래 첨자 : H ~ 2 ~ O
|
||||
|
||||
++ 삽입 된 텍스트 ++
|
||||
|
||||
== 표시된 텍스트 ==
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: baz
|
||||
title: baz
|
||||
---
|
||||
|
||||
## 이미지
|
||||
|
||||
링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다.
|
||||
|
||||
! [Alt text] [id]
|
||||
|
||||
나중에 URL 위치를 정의하는 문서에서 참조로 :
|
||||
|
||||
[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## 링크
|
||||
|
||||
[링크 텍스트] (http://dev.nodeca.com)
|
||||
|
||||
[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!")
|
||||
|
||||
자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정)
|
||||
|
||||
|
||||
|
||||
## 각주
|
||||
|
||||
각주 1 링크 [^ 첫 번째].
|
||||
|
||||
각주 2 링크 [^ 초].
|
||||
|
||||
인라인 각주 ^ [인라인 각주의 텍스트] 정의.
|
||||
|
||||
중복 된 각주 참조 [^ 초].
|
||||
|
||||
[^ first] : 각주 **는 마크 업을 가질 수 있습니다 **
|
||||
|
||||
및 여러 단락.
|
||||
|
||||
[^ 초] : 각주 텍스트.
|
||||
|
||||
|
||||
## 정의 목록
|
||||
|
||||
1 학기
|
||||
|
||||
정의 1
|
||||
게으른 연속.
|
||||
|
||||
* 인라인 마크 업과 함께 2 학기 *
|
||||
|
||||
: 정의 2
|
||||
|
||||
{일부 코드, 정의 2의 일부}
|
||||
|
||||
정의의 세 번째 단락 2.
|
||||
|
||||
_ 컴팩트 스타일 : _
|
||||
|
||||
1 학기
|
||||
~ 정의 1
|
||||
|
||||
2 학기
|
||||
~ 정의 2a
|
||||
~ 정의 2b
|
||||
|
||||
|
||||
## 약어
|
||||
|
||||
이것은 HTML 약어입니다.
|
||||
|
||||
그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다.
|
||||
|
||||
* [HTML] : 하이퍼 텍스트 마크 업 언어
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
id: hello
|
||||
title: Hello, World !
|
||||
---
|
||||
|
||||
안녕하세요, 여기 엔 틸리에 :)
|
||||
|
||||
## 상대 링크
|
||||
|
||||
이것 바꾸기
|
||||
[foo](foo/bar.md)
|
||||
|
||||
이것을 대체 할 수 없습니다.
|
||||
[파일] (file.md)
|
||||
|
||||
아래를 교체하지 마십시오.
|
||||
|
||||
```
|
||||
[hello] (hello.md)
|
||||
```
|
||||
|
||||
## Blockquotes
|
||||
|
||||
> Blockquotes는 또한 중첩 될 수 있습니다 ...
|
||||
>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ...
|
||||
>>> ... 또는 화살표 사이에 공백이 있어야합니다.
|
||||
|
||||
|
||||
## 목록
|
||||
|
||||
정렬되지 않은
|
||||
|
||||
+`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다.
|
||||
+ 하위 목록은 2 칸을 들여서 만들어집니다 :
|
||||
- 마커 문자 변경으로 새로운 목록 시작 :
|
||||
* AC tristique libero volutpat at
|
||||
+ Preisium nisl aliquet에 대한 + 시설
|
||||
- Nulla volutpat aliquam velit
|
||||
+ 매우 쉽습니다!
|
||||
|
||||
주문 됨
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. 컨소시엄 adipiscing 엘리트
|
||||
3. massa에서의 정수 lorem
|
||||
|
||||
|
||||
1. 일련 번호를 사용할 수 있습니다 ...
|
||||
1. ... 또는 모든 숫자를 '1'로 유지하십시오.
|
||||
|
||||
오프셋을 사용하여 번호 매기기 시작 :
|
||||
|
||||
57. foo
|
||||
1. 막대기
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: version-1.0.0-bar
|
||||
title: Bar
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Remarkable로 실시간 편집을 경험하십시오!
|
||||
|
||||
깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다.
|
||||
|
||||
***
|
||||
|
||||
# h1 제목
|
||||
## h2 제목
|
||||
### h3 제목
|
||||
#### h4 헤딩
|
||||
##### h5 제목
|
||||
###### h6 제목
|
||||
|
||||
|
||||
## 수평 규칙
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## 활자체 대체
|
||||
|
||||
입력기 옵션을 사용하면 결과를 볼 수 있습니다.
|
||||
|
||||
(p) (P) + - (r) (t)
|
||||
|
||||
테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! ....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
놀라운 - 굉장한
|
||||
|
||||
"Smartypants, 큰 따옴표"
|
||||
|
||||
'Smartypants, 작은 따옴표'
|
||||
|
||||
|
||||
## 강조
|
||||
|
||||
** 이것은 굵은 글씨입니다 **
|
||||
|
||||
__ 이것은 굵은 글씨입니다 __
|
||||
|
||||
* 이탤릭체 텍스트 *
|
||||
|
||||
_ 이탤릭체 텍스트 _
|
||||
|
||||
~~ 삭제 된 텍스트 ~~
|
||||
|
||||
위 첨자 : 19 ^ th ^
|
||||
|
||||
아래 첨자 : H ~ 2 ~ O
|
||||
|
||||
++ 삽입 된 텍스트 ++
|
||||
|
||||
== 표시된 텍스트 ==
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: version-1.0.0-baz
|
||||
title: baz
|
||||
---
|
||||
|
||||
## 이미지
|
||||
|
||||
링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다.
|
||||
|
||||
! [Alt text] [id]
|
||||
|
||||
나중에 URL 위치를 정의하는 문서에서 참조로 :
|
||||
|
||||
[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## 링크
|
||||
|
||||
[링크 텍스트] (http://dev.nodeca.com)
|
||||
|
||||
[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!")
|
||||
|
||||
자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정)
|
||||
|
||||
|
||||
|
||||
## 각주
|
||||
|
||||
각주 1 링크 [^ 첫 번째].
|
||||
|
||||
각주 2 링크 [^ 초].
|
||||
|
||||
인라인 각주 ^ [인라인 각주의 텍스트] 정의.
|
||||
|
||||
중복 된 각주 참조 [^ 초].
|
||||
|
||||
[^ first] : 각주 **는 마크 업을 가질 수 있습니다 **
|
||||
|
||||
및 여러 단락.
|
||||
|
||||
[^ 초] : 각주 텍스트.
|
||||
|
||||
|
||||
## 정의 목록
|
||||
|
||||
1 학기
|
||||
|
||||
정의 1
|
||||
게으른 연속.
|
||||
|
||||
* 인라인 마크 업과 함께 2 학기 *
|
||||
|
||||
: 정의 2
|
||||
|
||||
{일부 코드, 정의 2의 일부}
|
||||
|
||||
정의의 세 번째 단락 2.
|
||||
|
||||
_ 컴팩트 스타일 : _
|
||||
|
||||
1 학기
|
||||
~ 정의 1
|
||||
|
||||
2 학기
|
||||
~ 정의 2a
|
||||
~ 정의 2b
|
||||
|
||||
|
||||
## 약어
|
||||
|
||||
이것은 HTML 약어입니다.
|
||||
|
||||
그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다.
|
||||
|
||||
* [HTML] : 하이퍼 텍스트 마크 업 언어
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
id: version-1.0.0-hello
|
||||
title: Hello, World !
|
||||
---
|
||||
|
||||
안녕하세요, 여기 엔 틸리에 :)
|
||||
|
||||
## 상대 링크
|
||||
|
||||
이것 바꾸기
|
||||
[foo](foo/bar.md)
|
||||
|
||||
이것을 대체 할 수 없습니다.
|
||||
[파일] (file.md)
|
||||
|
||||
아래를 교체하지 마십시오.
|
||||
|
||||
```
|
||||
[hello] (hello.md)
|
||||
```
|
||||
|
||||
## Blockquotes
|
||||
|
||||
> Blockquotes는 또한 중첩 될 수 있습니다 ...
|
||||
>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ...
|
||||
>>> ... 또는 화살표 사이에 공백이 있어야합니다.
|
||||
|
||||
|
||||
## 목록
|
||||
|
||||
정렬되지 않은
|
||||
|
||||
+`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다.
|
||||
+ 하위 목록은 2 칸을 들여서 만들어집니다 :
|
||||
- 마커 문자 변경으로 새로운 목록 시작 :
|
||||
* AC tristique libero volutpat at
|
||||
+ Preisium nisl aliquet에 대한 + 시설
|
||||
- Nulla volutpat aliquam velit
|
||||
+ 매우 쉽습니다!
|
||||
|
||||
주문 됨
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. 컨소시엄 adipiscing 엘리트
|
||||
3. massa에서의 정수 lorem
|
||||
|
||||
|
||||
1. 일련 번호를 사용할 수 있습니다 ...
|
||||
1. ... 또는 모든 숫자를 '1'로 유지하십시오.
|
||||
|
||||
오프셋을 사용하여 번호 매기기 시작 :
|
||||
|
||||
57. foo
|
||||
1. 막대기
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: version-1.0.1-bar
|
||||
title: Bar
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Remarkable로 실시간 편집을 경험하십시오!
|
||||
|
||||
깨끗한 슬레이트로 시작하려면`clear` 링크를 클릭하고 결과를 공유하거나 저장하려면`permalink`를 가져옵니다.
|
||||
|
||||
***
|
||||
|
||||
# h1 제목
|
||||
## h2 제목
|
||||
### h3 제목
|
||||
#### h4 헤딩
|
||||
##### h5 제목
|
||||
###### h6 제목
|
||||
|
||||
|
||||
## 수평 규칙
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## 활자체 대체
|
||||
|
||||
입력기 옵션을 사용하면 결과를 볼 수 있습니다.
|
||||
|
||||
(p) (P) + - (r) (t)
|
||||
|
||||
테스트 .. 테스트 ... 테스트 ..... 테스트? ..... 테스트! ....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
놀라운 - 굉장한
|
||||
|
||||
"Smartypants, 큰 따옴표"
|
||||
|
||||
'Smartypants, 작은 따옴표'
|
||||
|
||||
|
||||
## 강조
|
||||
|
||||
** 이것은 굵은 글씨입니다 **
|
||||
|
||||
__ 이것은 굵은 글씨입니다 __
|
||||
|
||||
* 이탤릭체 텍스트 *
|
||||
|
||||
_ 이탤릭체 텍스트 _
|
||||
|
||||
~~ 삭제 된 텍스트 ~~
|
||||
|
||||
위 첨자 : 19 ^ th ^
|
||||
|
||||
아래 첨자 : H ~ 2 ~ O
|
||||
|
||||
++ 삽입 된 텍스트 ++
|
||||
|
||||
== 표시된 텍스트 ==
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: version-1.0.1-baz
|
||||
title: baz
|
||||
---
|
||||
|
||||
## 이미지
|
||||
|
||||
링크와 마찬가지로 이미지에도 각주 스타일 구문이 있습니다.
|
||||
|
||||
! [Alt text] [id]
|
||||
|
||||
나중에 URL 위치를 정의하는 문서에서 참조로 :
|
||||
|
||||
[id] : https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## 링크
|
||||
|
||||
[링크 텍스트] (http://dev.nodeca.com)
|
||||
|
||||
[제목 링크] (http://nodeca.github.io/pica/demo/ "제목 텍스트!")
|
||||
|
||||
자동 변환 된 링크 https://github.com/nodeca/pica (linkify를 사용하도록 설정)
|
||||
|
||||
|
||||
|
||||
## 각주
|
||||
|
||||
각주 1 링크 [^ 첫 번째].
|
||||
|
||||
각주 2 링크 [^ 초].
|
||||
|
||||
인라인 각주 ^ [인라인 각주의 텍스트] 정의.
|
||||
|
||||
중복 된 각주 참조 [^ 초].
|
||||
|
||||
[^ first] : 각주 **는 마크 업을 가질 수 있습니다 **
|
||||
|
||||
및 여러 단락.
|
||||
|
||||
[^ 초] : 각주 텍스트.
|
||||
|
||||
|
||||
## 정의 목록
|
||||
|
||||
1 학기
|
||||
|
||||
정의 1
|
||||
게으른 연속.
|
||||
|
||||
* 인라인 마크 업과 함께 2 학기 *
|
||||
|
||||
: 정의 2
|
||||
|
||||
{일부 코드, 정의 2의 일부}
|
||||
|
||||
정의의 세 번째 단락 2.
|
||||
|
||||
_ 컴팩트 스타일 : _
|
||||
|
||||
1 학기
|
||||
~ 정의 1
|
||||
|
||||
2 학기
|
||||
~ 정의 2a
|
||||
~ 정의 2b
|
||||
|
||||
|
||||
## 약어
|
||||
|
||||
이것은 HTML 약어입니다.
|
||||
|
||||
그것은 "HTML"을 변환하지만 "xxxHTMLyyy"와 같이 부분적인 항목을 그대로 유지합니다.
|
||||
|
||||
* [HTML] : 하이퍼 텍스트 마크 업 언어
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
id: version-1.0.1-hello
|
||||
title: Hello, World !
|
||||
---
|
||||
|
||||
안녕하세요, 여기 엔 틸리에 :)
|
||||
|
||||
## 상대 링크
|
||||
|
||||
이것 바꾸기
|
||||
[foo](foo/bar.md)
|
||||
|
||||
이것을 대체 할 수 없습니다.
|
||||
[파일] (file.md)
|
||||
|
||||
아래를 교체하지 마십시오.
|
||||
|
||||
```
|
||||
[hello] (hello.md)
|
||||
```
|
||||
|
||||
## Blockquotes
|
||||
|
||||
> Blockquotes는 또한 중첩 될 수 있습니다 ...
|
||||
>> ... 서로 옆에 큰 더 큰 부호를 사용하여 ...
|
||||
>>> ... 또는 화살표 사이에 공백이 있어야합니다.
|
||||
|
||||
|
||||
## 목록
|
||||
|
||||
정렬되지 않은
|
||||
|
||||
+`+`,`-` 또는`*`를 사용하여 행을 시작하여 목록을 만듭니다.
|
||||
+ 하위 목록은 2 칸을 들여서 만들어집니다 :
|
||||
- 마커 문자 변경으로 새로운 목록 시작 :
|
||||
* AC tristique libero volutpat at
|
||||
+ Preisium nisl aliquet에 대한 + 시설
|
||||
- Nulla volutpat aliquam velit
|
||||
+ 매우 쉽습니다!
|
||||
|
||||
주문 됨
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. 컨소시엄 adipiscing 엘리트
|
||||
3. massa에서의 정수 lorem
|
||||
|
||||
|
||||
1. 일련 번호를 사용할 수 있습니다 ...
|
||||
1. ... 또는 모든 숫자를 '1'로 유지하십시오.
|
||||
|
||||
오프셋을 사용하여 번호 매기기 시작 :
|
||||
|
||||
57. foo
|
||||
1. 막대기
|
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
id: version-1.0.0-bar
|
||||
title: Bar
|
||||
---
|
||||
|
||||
# Remarkable
|
||||
|
||||
> Experience real-time editing with Remarkable!
|
||||
|
||||
Click the `clear` link to start with a clean slate, or get the `permalink` to share or save your results.
|
||||
|
||||
***
|
||||
|
||||
# h1 Heading
|
||||
## h2 Heading
|
||||
### h3 Heading
|
||||
#### h4 Heading
|
||||
##### h5 Heading
|
||||
###### h6 Heading
|
||||
|
||||
|
||||
## Horizontal Rules
|
||||
|
||||
___
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
|
||||
## Typographic replacements
|
||||
|
||||
Enable typographer option to see result.
|
||||
|
||||
(c) (C) (r) (R) (tm) (TM) (p) (P) +-
|
||||
|
||||
test.. test... test..... test?..... test!....
|
||||
|
||||
!!!!!! ???? ,,
|
||||
|
||||
Remarkable -- awesome
|
||||
|
||||
"Smartypants, double quotes"
|
||||
|
||||
'Smartypants, single quotes'
|
||||
|
||||
|
||||
## Emphasis
|
||||
|
||||
**This is bold text**
|
||||
|
||||
__This is bold text__
|
||||
|
||||
*This is italic text*
|
||||
|
||||
_This is italic text_
|
||||
|
||||
~~Deleted text~~
|
||||
|
||||
Superscript: 19^th^
|
||||
|
||||
Subscript: H~2~O
|
||||
|
||||
++Inserted text++
|
||||
|
||||
==Marked text==
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
id: version-1.0.0-baz
|
||||
title: Baz
|
||||
---
|
||||
|
||||
## Images
|
||||
|
||||
Like links, Images also have a footnote style syntax
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
With a reference later in the document defining the URL location:
|
||||
|
||||
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
|
||||
## Links
|
||||
|
||||
[link text](http://dev.nodeca.com)
|
||||
|
||||
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
|
||||
|
||||
Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
|
||||
|
||||
|
||||
|
||||
## Footnotes
|
||||
|
||||
Footnote 1 link[^first].
|
||||
|
||||
Footnote 2 link[^second].
|
||||
|
||||
Inline footnote^[Text of inline footnote] definition.
|
||||
|
||||
Duplicated footnote reference[^second].
|
||||
|
||||
[^first]: Footnote **can have markup**
|
||||
|
||||
and multiple paragraphs.
|
||||
|
||||
[^second]: Footnote text.
|
||||
|
||||
|
||||
## Definition lists
|
||||
|
||||
Term 1
|
||||
|
||||
: Definition 1
|
||||
with lazy continuation.
|
||||
|
||||
Term 2 with *inline markup*
|
||||
|
||||
: Definition 2
|
||||
|
||||
{ some code, part of Definition 2 }
|
||||
|
||||
Third paragraph of definition 2.
|
||||
|
||||
_Compact style:_
|
||||
|
||||
Term 1
|
||||
~ Definition 1
|
||||
|
||||
Term 2
|
||||
~ Definition 2a
|
||||
~ Definition 2b
|
||||
|
||||
|
||||
## Abbreviations
|
||||
|
||||
This is HTML abbreviation example.
|
||||
|
||||
It converts "HTML", but keep intact partial entries like "xxxHTMLyyy" and so on.
|
||||
|
||||
*[HTML]: Hyper Text Markup Language
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue