Skip to content

Commit

Permalink
feat: custom pages (#994)
Browse files Browse the repository at this point in the history
  • Loading branch information
endiliey authored Sep 28, 2018
1 parent 7d4d9fe commit 8691a25
Show file tree
Hide file tree
Showing 25 changed files with 256 additions and 121 deletions.
66 changes: 32 additions & 34 deletions v2/lib/commands/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,42 +83,40 @@ module.exports = async function start(siteDir, cliOptions = {}) {
const compiler = webpack(config);

// webpack-serve
setTimeout(async () => {
await serve(
{},
{
compiler,
open: true,
devMiddleware: {
logLevel: 'silent',
},
hotClient: {
port: hotPort,
logLevel: 'error',
},
await serve(
{},
{
compiler,
open: true,
devMiddleware: {
logLevel: 'silent',
},
hotClient: {
port: hotPort,
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)));
}
},
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);
// enable HTTP range requests
app.use(range);

// rewrite request to `/` since dev is only a SPA
app.use(
convert(
history({
rewrites: [{from: /\.html$/, to: '/'}],
}),
),
);
},
// rewrite request to `/` since dev is only a SPA
app.use(
convert(
history({
rewrites: [{from: /\.html$/, to: '/'}],
}),
),
);
},
);
}, 1000);
},
);
};
2 changes: 1 addition & 1 deletion v2/lib/load/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ module.exports = async function load(siteDir) {

// pages
const pagesDir = path.resolve(siteDir, 'pages');
const pagesMetadatas = await loadPages(pagesDir);
const pagesMetadatas = await loadPages({pagesDir, env, siteConfig});
await generate(
'pagesMetadatas.js',
`export default ${JSON.stringify(pagesMetadatas, null, 2)};`,
Expand Down
55 changes: 48 additions & 7 deletions v2/lib/load/pages.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,57 @@
const globby = require('globby');
const {encodePath, fileToPath} = require('./utils');
const path = require('path');
const {encodePath, fileToPath, idx} = require('./utils');

async function loadPages(pagesDir) {
async function loadPages({pagesDir, env, siteConfig}) {
const pagesFiles = await globby(['**/*.js'], {
cwd: pagesDir,
});

const pagesMetadatas = await Promise.all(
pagesFiles.map(async source => ({
path: encodePath(fileToPath(source)),
source,
})),
const {baseUrl} = siteConfig;

/* Prepare metadata container */
const pagesMetadatas = [];

/* Translation */
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']);

await Promise.all(
pagesFiles.map(async relativeSource => {
const source = path.join(pagesDir, relativeSource);
const pathName = encodePath(fileToPath(relativeSource));
if (translationEnabled && enabledLangTags.length > 0) {
enabledLangTags.forEach(langTag => {
/* default lang should also be available. E.g: /en/users and /users is the same */
if (langTag === defaultLangTag) {
pagesMetadatas.push({
permalink: pathName.replace(/^\//, baseUrl),
language: langTag,
source,
});
}

const metadata = {
permalink: pathName.replace(/^\//, `${baseUrl}${langTag}/`),
language: langTag,
source,
};
pagesMetadatas.push(metadata);
});

// for defaultLanguage
} else {
const metadata = {
permalink: pathName.replace(/^\//, baseUrl),
source,
};
pagesMetadatas.push(metadata);
}
}),
);
return pagesMetadatas;
}
Expand Down
18 changes: 14 additions & 4 deletions v2/lib/load/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,23 @@ async function genRoutesConfig({docsMetadatas = {}, pagesMetadatas = []}) {
}`;
}

function genPagesRoute({path: pagesPath, source}) {
function genPagesRoute(metadata) {
const {permalink, source} = metadata;
return `
{
path: ${JSON.stringify(pagesPath)},
path: ${JSON.stringify(permalink)},
exact: true,
component: Loadable({
loader: () => import('@pages/${source}'),
loading: Loading
loader: () => import(${JSON.stringify(source)}),
loading: Loading,
render(loaded, props) {
let Content = loaded.default;
return (
<Pages {...props} metadata={${JSON.stringify(metadata)}}>
<Content {...props} metadata={${JSON.stringify(metadata)}} />
</Pages>
);
}
})
}`;
}
Expand All @@ -47,6 +56,7 @@ async function genRoutesConfig({docsMetadatas = {}, pagesMetadatas = []}) {
`import Loadable from 'react-loadable';\n` +
`import Loading from '@theme/Loading';\n` +
`import Docs from '@theme/Docs';\n` +
`import Pages from '@theme/Pages';\n` +
`import NotFound from '@theme/NotFound';\n` +
`const routes = [${docsRoutes},${pagesMetadatas
.map(genPagesRoute)
Expand Down
2 changes: 1 addition & 1 deletion v2/lib/load/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = function loadConfig(siteDir) {
? customThemePath
: path.resolve(__dirname, '../theme');

const themeComponents = ['Docs', 'Loading', 'NotFound', 'Markdown'];
const themeComponents = ['Docs', 'Pages', 'Loading', 'NotFound', 'Markdown'];
themeComponents.forEach(component => {
if (!require.resolve(path.join(themePath, component))) {
throw new Error(
Expand Down
4 changes: 4 additions & 0 deletions v2/lib/theme/Docs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@ export default class Docs extends React.Component {
docsSidebars,
metadata,
} = this.props;
const {language, version} = metadata;
return (
<Layout {...this.props}>
<Helmet>
<title>{(metadata && metadata.title) || siteConfig.title}</title>
{language && <html lang={language} />}
{language && <meta name="docsearch:language" content={language} />}
{version && <meta name="docsearch:version" content={version} />}
</Helmet>
<div>{this.renderSidebar(metadata, docsSidebars, docsMetadatas)}</div>
<div>
Expand Down
19 changes: 11 additions & 8 deletions v2/lib/theme/Layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ 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(
const {
children,
pagesMetadatas = [],
docsMetadatas = {},
location,
} = this.props;
const docsFlatMetadatas = Object.values(docsMetadatas);
const routeLinks = [...pagesMetadatas, ...docsFlatMetadatas].map(
data =>
data.path !== location.pathname && (
<li key={data.path}>
<Link to={data.path}>{data.path}</Link>
data.permalink !== location.pathname && (
<li key={data.permalink}>
<Link to={data.permalink}>{data.permalink}</Link>
</li>
),
);
Expand Down
21 changes: 21 additions & 0 deletions v2/lib/theme/Pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable */
import React from 'react';
import {Link} from 'react-router-dom';
import Helmet from 'react-helmet';
import Layout from '@theme/Layout'; // eslint-disable-line

export default class Pages extends React.Component {
render() {
const {metadata, children, siteConfig} = this.props;
const {language} = metadata;
return (
<Layout {...this.props}>
<Helmet defaultTitle={siteConfig.title}>
{language && <html lang={language} />}
{language && <meta name="docsearch:language" content={language} />}
</Helmet>
{children}
</Layout>
);
}
}
8 changes: 4 additions & 4 deletions v2/lib/webpack/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ module.exports = function createServerConfig(props) {
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);
const docsFlatMetadatas = Object.values(docsMetadatas);
const paths = [...docsFlatMetadatas, ...pagesMetadatas].map(
data => data.permalink,
);
config.plugin('siteGenerator').use(staticSiteGenerator, [
{
entry: 'main',
Expand Down
5 changes: 2 additions & 3 deletions v2/test/__fixtures__/simple-site/pages/hello/world.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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}>
<div>
<Helmet>
<title>World</title>
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
</Helmet>
<div>Hello World </div>
</Layout>
</div>
);
}
}
5 changes: 2 additions & 3 deletions v2/test/__fixtures__/simple-site/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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}>
<div>
<Helmet>
<title>Home</title>
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
</Helmet>
<div>Home ... </div>
</Layout>
</div>
);
}
}
5 changes: 2 additions & 3 deletions v2/test/__fixtures__/translated-site/pages/hello/world.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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}>
<div>
<Helmet>
<title>World</title>
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
</Helmet>
<div>Hello World </div>
</Layout>
</div>
);
}
}
5 changes: 2 additions & 3 deletions v2/test/__fixtures__/translated-site/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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}>
<div>
<Helmet>
<title>Home</title>
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
</Helmet>
<div>Home ... </div>
</Layout>
</div>
);
}
}
5 changes: 2 additions & 3 deletions v2/test/__fixtures__/transversioned-site/pages/hello/world.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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}>
<div>
<Helmet>
<title>World</title>
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
</Helmet>
<div>Hello World </div>
</Layout>
</div>
);
}
}
5 changes: 2 additions & 3 deletions v2/test/__fixtures__/transversioned-site/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
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}>
<div>
<Helmet>
<title>Home</title>
<link rel="stylesheet" type="text/css" href="/css/basic.css" />
</Helmet>
<div>Home ... </div>
</Layout>
</div>
);
}
}
Loading

0 comments on commit 8691a25

Please sign in to comment.