feat: dox++
This commit is contained in:
parent
c68bb3b6f7
commit
95e18b9978
|
@ -49,24 +49,28 @@ export const hooks = {
|
|||
|
||||
/**
|
||||
* Define CLI commands.
|
||||
* @param {[Command](https://github.com/tj/commander.js/tree/master#declaring-program-variable)} program The [Commander.js](https://github.com/tj/commander.js) program.
|
||||
*/
|
||||
'@flecks/core.commands': (program) => ({
|
||||
// So this could be invoked like:
|
||||
// npx flecks something -t --blow-up blah
|
||||
something: {
|
||||
action: (...args) => {
|
||||
// Run the command...
|
||||
'@flecks/core.commands': (program, flecks) => {
|
||||
const {Argument} = flecks.fleck('@flecks/core/server');
|
||||
return {
|
||||
// So this could be invoked like:
|
||||
// npx flecks something -t --blow-up blah
|
||||
something: {
|
||||
action: (...args) => {
|
||||
// Run the command...
|
||||
},
|
||||
args: [
|
||||
new Argument('<somearg>', 'some argument'),
|
||||
],
|
||||
description: 'This command does tests and also blows up',
|
||||
options: [
|
||||
'-t, --test', 'Do a test',
|
||||
'-b, --blow-up', 'Blow up instead of running the command',
|
||||
],
|
||||
},
|
||||
args: [
|
||||
'<somearg>',
|
||||
],
|
||||
description: 'This command does tests and also blows up',
|
||||
options: [
|
||||
'-t, --test', 'Do a test',
|
||||
'-b, --blow-up', 'Blow up instead of running the command',
|
||||
],
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Define configuration.
|
||||
|
|
|
@ -16,6 +16,8 @@ const debug = D('@flecks/core/commands');
|
|||
const debugSilly = debug.extend('silly');
|
||||
const flecksRoot = normalize(FLECKS_CORE_ROOT);
|
||||
|
||||
export {Argument};
|
||||
|
||||
export const processCode = (child) => new Promise((resolve, reject) => {
|
||||
child.on('error', reject);
|
||||
child.on('exit', (code) => {
|
||||
|
|
|
@ -19,6 +19,7 @@ defaultOptions.sorted = true;
|
|||
export {dump as dumpYml, load as loadYml} from 'js-yaml';
|
||||
|
||||
export {
|
||||
Argument,
|
||||
default as commands,
|
||||
processCode,
|
||||
spawnWith,
|
||||
|
|
|
@ -21,15 +21,27 @@
|
|||
"build",
|
||||
"server.js",
|
||||
"server.js.map",
|
||||
"src"
|
||||
"src",
|
||||
"website"
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.17.2",
|
||||
"@babel/traverse": "^7.17.0",
|
||||
"@babel/types": "^7.17.0",
|
||||
"@docusaurus/core": "3.0.1",
|
||||
"@docusaurus/module-type-aliases": "3.0.1",
|
||||
"@docusaurus/preset-classic": "3.0.1",
|
||||
"@docusaurus/types": "3.0.1",
|
||||
"@flecks/core": "^2.0.3",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
"comment-parser": "^1.3.0",
|
||||
"glob": "^7.2.0"
|
||||
"glob": "^7.2.0",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"remark-html": "^16.0.1",
|
||||
"rimraf": "^5.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flecks/fleck": "^2.0.3"
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import {mkdir, writeFile} from 'fs/promises';
|
||||
import {join} from 'path';
|
||||
|
||||
import {D} from '@flecks/core';
|
||||
|
||||
import {
|
||||
generateBuildConfigsPage,
|
||||
generateConfigPage,
|
||||
generateHookPage,
|
||||
generateTodoPage,
|
||||
} from './generate';
|
||||
import {parseFlecks} from './parser';
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
const debug = D('@flecks/dox/commands');
|
||||
|
||||
export default (program, flecks) => {
|
||||
const commands = {};
|
||||
commands.dox = {
|
||||
description: 'generate documentation for this project',
|
||||
action: async () => {
|
||||
debug('Parsing flecks...');
|
||||
const state = await parseFlecks(flecks);
|
||||
debug('parsed');
|
||||
debug('Generating hooks page...');
|
||||
const hookPage = generateHookPage(state.hooks, flecks);
|
||||
debug('generated');
|
||||
debug('Generating TODO page...');
|
||||
const todoPage = generateTodoPage(state.todos, flecks);
|
||||
debug('generated');
|
||||
debug('Generating build configs page...');
|
||||
const buildConfigsPage = generateBuildConfigsPage(state.buildConfigs);
|
||||
debug('generated');
|
||||
debug('Generating config page...');
|
||||
const configPage = generateConfigPage(state.configs);
|
||||
debug('generated');
|
||||
const output = join(FLECKS_CORE_ROOT, 'dox');
|
||||
await mkdir(output, {recursive: true});
|
||||
/* eslint-disable no-console */
|
||||
console.log('');
|
||||
console.group('Output:');
|
||||
debug('Writing hooks page...');
|
||||
await writeFile(join(output, 'hooks.md'), hookPage);
|
||||
console.log('hooks.md');
|
||||
debug('Writing TODO page...');
|
||||
await writeFile(join(output, 'TODO.md'), todoPage);
|
||||
console.log('TODO.md');
|
||||
debug('Writing build configs page...');
|
||||
await writeFile(join(output, 'build-configs.md'), buildConfigsPage);
|
||||
console.log('build-configs.md');
|
||||
debug('Writing config page...');
|
||||
await writeFile(join(output, 'config.md'), configPage);
|
||||
console.log('config.md');
|
||||
console.groupEnd();
|
||||
console.log('');
|
||||
/* eslint-enable no-console */
|
||||
},
|
||||
};
|
||||
return commands;
|
||||
};
|
86
packages/dox/src/server/commands.js
Normal file
86
packages/dox/src/server/commands.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
import {
|
||||
access,
|
||||
cp,
|
||||
mkdir,
|
||||
rename,
|
||||
rmdir,
|
||||
} from 'fs/promises';
|
||||
import {dirname, join} from 'path';
|
||||
|
||||
import {
|
||||
generate,
|
||||
resolveSiteDir,
|
||||
spawn,
|
||||
} from './docusaurus';
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
export default (program, flecks) => {
|
||||
const {Argument} = flecks.fleck('@flecks/core/server');
|
||||
const commands = {};
|
||||
const siteDirArgument = new Argument('[siteDir]', 'Docusaurus directory', 'website');
|
||||
siteDirArgument.defaultValue = 'website';
|
||||
commands.docusaurus = {
|
||||
description: 'create a documentation website for this project',
|
||||
action: async (subcommand, siteDir) => {
|
||||
const resolvedSiteDir = resolveSiteDir(siteDir);
|
||||
let siteDirExisted = false;
|
||||
try {
|
||||
const result = await mkdir(resolvedSiteDir);
|
||||
if (undefined === result) {
|
||||
await rmdir(resolvedSiteDir);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
siteDirExisted = true;
|
||||
}
|
||||
switch (subcommand) {
|
||||
case 'build':
|
||||
if (!siteDirExisted) {
|
||||
throw new Error(`There's no website directory at ${resolvedSiteDir} to build!`);
|
||||
}
|
||||
await generate(flecks, resolvedSiteDir);
|
||||
spawn('build', resolvedSiteDir);
|
||||
break;
|
||||
case 'create': {
|
||||
if (siteDirExisted) {
|
||||
throw new Error(`A website directory at ${resolvedSiteDir} already exists!`);
|
||||
}
|
||||
const templateDirectory = dirname(
|
||||
__non_webpack_require__.resolve('@flecks/dox/website/sidebars.js'),
|
||||
);
|
||||
await cp(templateDirectory, resolvedSiteDir, {recursive: true});
|
||||
// Copy the docusaurus config if it doesn't already exist.
|
||||
try {
|
||||
await access(join(FLECKS_CORE_ROOT, 'build', 'docusaurus.config.js'));
|
||||
}
|
||||
catch (error) {
|
||||
await rename(
|
||||
join(resolvedSiteDir, 'docusaurus.config.js'),
|
||||
join(FLECKS_CORE_ROOT, 'build', 'docusaurus.config.js'),
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`website directory created at ${resolvedSiteDir}!`);
|
||||
break;
|
||||
}
|
||||
case 'start':
|
||||
if (!siteDirExisted) {
|
||||
throw new Error(`There's no website directory at ${resolvedSiteDir} to start!`);
|
||||
}
|
||||
await generate(flecks, resolvedSiteDir);
|
||||
spawn('start', resolvedSiteDir);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
args: [
|
||||
new Argument('subcommand', 'Docusaurus command to run').choices(['build', 'create', 'start']),
|
||||
siteDirArgument,
|
||||
],
|
||||
};
|
||||
return commands;
|
||||
};
|
124
packages/dox/src/server/docusaurus.js
Normal file
124
packages/dox/src/server/docusaurus.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
import {mkdir, writeFile} from 'fs/promises';
|
||||
import {isAbsolute, join, resolve} from 'path';
|
||||
|
||||
import {spawnWith} from '@flecks/core/server';
|
||||
import {themes as prismThemes} from 'prism-react-renderer';
|
||||
import {rimraf} from 'rimraf';
|
||||
|
||||
import {
|
||||
generateBuildConfigsPage,
|
||||
generateConfigPage,
|
||||
generateHookPage,
|
||||
generateTodoPage,
|
||||
} from './generate';
|
||||
import {parseFlecks} from './parser';
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
export function configDefaults() {
|
||||
/** @type {import('@docusaurus/types').Config} */
|
||||
const config = {
|
||||
tagline: 'built with flecks',
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en'],
|
||||
},
|
||||
presets: [
|
||||
['classic', {
|
||||
docs: {
|
||||
sidebarPath: './sidebars.js',
|
||||
},
|
||||
pages: {
|
||||
path: 'pages',
|
||||
},
|
||||
}],
|
||||
],
|
||||
themeConfig: {
|
||||
// navbar: {
|
||||
// title: 'flecks',
|
||||
// logo: {
|
||||
// alt: 'flecks logo',
|
||||
// src: 'img/flecks.svg',
|
||||
// },
|
||||
// items: [
|
||||
// ],
|
||||
// },
|
||||
footer: {
|
||||
style: 'dark',
|
||||
copyright: 'Built with flecks and Docusaurus.',
|
||||
},
|
||||
prism: {
|
||||
theme: prismThemes.github,
|
||||
darkTheme: prismThemes.dracula,
|
||||
},
|
||||
},
|
||||
};
|
||||
return config;
|
||||
}
|
||||
|
||||
export function resolveSiteDir(siteDir) {
|
||||
return isAbsolute(siteDir)
|
||||
? siteDir
|
||||
: resolve(FLECKS_CORE_ROOT, siteDir);
|
||||
}
|
||||
|
||||
export async function generate(flecks, siteDir) {
|
||||
// Generate "docs".
|
||||
const docsDirectory = join(siteDir, 'docs', 'flecks');
|
||||
await rimraf(docsDirectory);
|
||||
const generatedDirectory = join(docsDirectory, '@flecks', 'dox');
|
||||
await mkdir(generatedDirectory, {recursive: true});
|
||||
const state = await parseFlecks(flecks);
|
||||
const hookPage = generateHookPage(state.hooks, flecks);
|
||||
const todoPage = generateTodoPage(state.todos, flecks);
|
||||
const buildConfigsPage = generateBuildConfigsPage(state.buildConfigs);
|
||||
const configPage = generateConfigPage(state.configs);
|
||||
await writeFile(join(generatedDirectory, 'hooks.md'), hookPage);
|
||||
await writeFile(join(generatedDirectory, 'TODO.md'), todoPage);
|
||||
await writeFile(join(generatedDirectory, 'build-configs.md'), buildConfigsPage);
|
||||
await writeFile(join(generatedDirectory, 'config.mdx'), configPage);
|
||||
}
|
||||
|
||||
export function spawn(subcommand, siteDir) {
|
||||
const args = [];
|
||||
switch (subcommand) {
|
||||
case 'start':
|
||||
args.push('start', '--no-open');
|
||||
break;
|
||||
case 'build':
|
||||
args.push('build', '--out-dir', join(FLECKS_CORE_ROOT, 'dist', 'dox'));
|
||||
break;
|
||||
default: {
|
||||
const docusaurusCall = `npx docusaurus <subcommand> --config ${join(FLECKS_CORE_ROOT, 'build', 'docusaurus.config.js')}`;
|
||||
throw new Error(`@flecks/dox only supports the 'build' and 'start' subcommands. You can run docusaurus yourself with:\n\n${docusaurusCall}`);
|
||||
}
|
||||
}
|
||||
args.push('--config', join(FLECKS_CORE_ROOT, 'build', 'docusaurus.config.js'));
|
||||
const cacheDirectory = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'dox');
|
||||
// Spawn `docusaurus`.
|
||||
const cmd = [
|
||||
// `npx` doesn't propagate signals!
|
||||
// 'npx', 'docusaurus',
|
||||
join(FLECKS_CORE_ROOT, 'node_modules', '.bin', 'docusaurus'),
|
||||
...args,
|
||||
siteDir,
|
||||
];
|
||||
const child = spawnWith(
|
||||
cmd,
|
||||
{
|
||||
env: {
|
||||
// Override docusaurus generation directory for cleanliness.
|
||||
DOCUSAURUS_GENERATED_FILES_DIR_NAME: join(cacheDirectory, '.docusaurus'),
|
||||
},
|
||||
},
|
||||
);
|
||||
// Clean up on exit.
|
||||
process.on('exit', () => {
|
||||
child.kill();
|
||||
});
|
||||
return child;
|
||||
}
|
|
@ -8,7 +8,7 @@ const makeFilenameRewriter = (filenameRewriters) => (filename, line, column) =>
|
|||
|
||||
export const generateBuildConfigsPage = (buildConfigs) => {
|
||||
const source = [];
|
||||
source.push('# Build configuration files');
|
||||
source.push('# Build configuration');
|
||||
source.push('');
|
||||
source.push('This page documents all the build configuration files in this project.');
|
||||
source.push('');
|
||||
|
@ -27,38 +27,36 @@ export const generateBuildConfigsPage = (buildConfigs) => {
|
|||
|
||||
export const generateConfigPage = (configs) => {
|
||||
const source = [];
|
||||
source.push('# Configuration');
|
||||
source.push("import CodeBlock from '@theme/CodeBlock';");
|
||||
source.push('');
|
||||
source.push('This page documents all the configuration in this project.');
|
||||
source.push('# Fleck configuration');
|
||||
source.push('');
|
||||
source.push('<style>td > .theme-code-block \\{ margin: 0; \\}</style>');
|
||||
source.push('');
|
||||
source.push('This page documents all configurable flecks in this project.');
|
||||
source.push('');
|
||||
Object.entries(configs)
|
||||
.sort(([l], [r]) => (l < r ? -1 : 1))
|
||||
.forEach(([fleck, configs]) => {
|
||||
// source.push(`## \`${fleck}\``);
|
||||
source.push('```javascript');
|
||||
source.push(`'${fleck}': {`);
|
||||
source.push(`## \`${fleck}\``);
|
||||
source.push('|Name|Default|Description|');
|
||||
source.push('|-|-|-|');
|
||||
configs.forEach(({comment, config, defaultValue}) => {
|
||||
comment.split('\n').forEach((line) => {
|
||||
source.push(` // ${line}`);
|
||||
});
|
||||
const value = defaultValue
|
||||
.split('\n')
|
||||
.map((line, i, array) => {
|
||||
let output = '';
|
||||
if (array.length - 1 === i) {
|
||||
output += ' ';
|
||||
}
|
||||
else if (0 !== i) {
|
||||
output += ' ';
|
||||
}
|
||||
output += line.trim();
|
||||
return output;
|
||||
})
|
||||
.join('\n');
|
||||
source.push(` ${config}: ${value}`);
|
||||
// Leading and trailing empty cell to make table rendering easier.
|
||||
const row = ['', config];
|
||||
let code = defaultValue.replace(/`/g, '\\`');
|
||||
// Multiline code. Fix indentation.
|
||||
if (defaultValue.includes('\n')) {
|
||||
const defaultValueLines = code.split('\n');
|
||||
const [first, ...rest] = defaultValueLines;
|
||||
const indent = (rest[0].length - rest[0].trimStart().length) - 2;
|
||||
code = [first, ...rest.map((line) => line.substring(indent))].join('\\n');
|
||||
}
|
||||
row.push(`<CodeBlock language="javascript">{\`${code}\`}</CodeBlock>`);
|
||||
row.push(comment, '');
|
||||
source.push(row.join('|'));
|
||||
});
|
||||
source.push('}');
|
||||
source.push('```');
|
||||
source.push('');
|
||||
});
|
||||
return source.join('\n');
|
||||
};
|
||||
|
@ -74,27 +72,22 @@ export const generateHookPage = (hooks, flecks) => {
|
|||
Object.entries(hooks)
|
||||
.sort(([lhook], [rhook]) => (lhook < rhook ? -1 : 1))
|
||||
.forEach(([hook, {implementations = [], invocations = [], specification}]) => {
|
||||
source.push(`## \`${hook}\``);
|
||||
source.push('');
|
||||
const {description, example, params} = specification || {
|
||||
params: [],
|
||||
};
|
||||
source.push(`## \`${hook}\``);
|
||||
source.push('');
|
||||
if (description) {
|
||||
description.split('\n').forEach((line) => {
|
||||
source.push(`> ${line}`);
|
||||
});
|
||||
source.push(...description.split('\n'));
|
||||
source.push('');
|
||||
}
|
||||
if (params.length > 0) {
|
||||
source.push('<details>');
|
||||
source.push('<summary>Parameters</summary>');
|
||||
source.push('<ul>');
|
||||
params.forEach(({description, name, type}) => {
|
||||
source.push(`<li><strong><code>{${type}}</code></strong> <code>${name}</code>`);
|
||||
source.push(`<blockquote>${description}</blockquote></li>`);
|
||||
source.push(`### <code>${name}: ${type}</code>`);
|
||||
source.push('');
|
||||
source.push(`<p>${description.trim()}</p>`);
|
||||
source.push('');
|
||||
});
|
||||
source.push('</ul>');
|
||||
source.push('</details>');
|
||||
source.push('');
|
||||
}
|
||||
if (implementations.length > 0) {
|
||||
|
@ -137,7 +130,7 @@ export const generateTodoPage = (todos, flecks) => {
|
|||
const {filenameRewriters} = flecks.get('@flecks/dox/server');
|
||||
const rewriteFilename = makeFilenameRewriter(filenameRewriters);
|
||||
const source = [];
|
||||
source.push('# TODO');
|
||||
source.push('# TODO list');
|
||||
source.push('');
|
||||
source.push('This page documents all the TODO items in this project.');
|
||||
source.push('');
|
|
@ -1,5 +1,7 @@
|
|||
import commands from './commands';
|
||||
|
||||
export {configDefaults} from './docusaurus';
|
||||
|
||||
export const hooks = {
|
||||
'@flecks/core.commands': commands,
|
||||
'@flecks/core.config': () => ({
|
|
@ -23,8 +23,6 @@ import {require as R} from '@flecks/core/server';
|
|||
import {parse as parseComment} from 'comment-parser';
|
||||
import glob from 'glob';
|
||||
|
||||
const flecksCorePath = dirname(__non_webpack_require__.resolve('@flecks/core/package.json'));
|
||||
|
||||
class ParserState {
|
||||
|
||||
constructor() {
|
||||
|
@ -170,7 +168,10 @@ const FlecksInvocations = (state, filename) => ({
|
|||
|| (
|
||||
(
|
||||
isThisExpression(path.node.callee.object)
|
||||
&& (filename === join(flecksCorePath, 'src', 'flecks.js'))
|
||||
&& (
|
||||
(filename === '@flecks/core/src/flecks.js')
|
||||
|| (filename === '@flecks/core/src/server/flecks.js')
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
2
packages/dox/website/docs/.gitignore
vendored
Normal file
2
packages/dox/website/docs/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# This ignores the automatically-generated `flecks` subfolder.
|
||||
/flecks
|
9
packages/dox/website/docs/introduction.mdx
Normal file
9
packages/dox/website/docs/introduction.mdx
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
description: This project was built with flecks and is totally awesome!
|
||||
slug: /
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
⚡️ Welcome to your documentation website! From here, you will want to consult the
|
||||
[Docusaurus](https://docusaurus.io/) documentation to learn how to build this website out!
|
21
packages/dox/website/docusaurus.config.js
Normal file
21
packages/dox/website/docusaurus.config.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
// @ts-check
|
||||
// `@type` JSDoc annotations allow editor autocompletion and type checking
|
||||
// (when paired with `@ts-check`).
|
||||
// There are various equivalent ways to declare your Docusaurus config.
|
||||
// See: https://docusaurus.io/docs/api/docusaurus-config
|
||||
|
||||
// For some reason we get a webpack warning if we use import here...
|
||||
const {configDefaults} = require('@flecks/dox/server'); // eslint-disable-line import/no-extraneous-dependencies
|
||||
|
||||
export default async function flecksDocusaurus() {
|
||||
const defaults = configDefaults();
|
||||
/** @type {import('@docusaurus/types').Config} */
|
||||
const config = {
|
||||
...defaults,
|
||||
title: 'My documentation website',
|
||||
tagline: 'built with flecks',
|
||||
url: 'http://localhost',
|
||||
baseUrl: '/',
|
||||
};
|
||||
return config;
|
||||
}
|
41
packages/dox/website/pages/index.jsx
Normal file
41
packages/dox/website/pages/index.jsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import clsx from 'clsx';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
import Heading from '@theme/Heading';
|
||||
import styles from './index.module.css';
|
||||
|
||||
function HomepageHeader() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<header className={clsx('hero hero--primary', styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<Heading as="h1" className="hero__title">
|
||||
{siteConfig.title}
|
||||
</Heading>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Link
|
||||
className="button button--secondary button--lg"
|
||||
to="/docs"
|
||||
>
|
||||
Your documentation here
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
return (
|
||||
<Layout
|
||||
title={`Hello from ${siteConfig.title}`}
|
||||
description="Description will go into a meta tag in <head />"
|
||||
>
|
||||
<HomepageHeader />
|
||||
</Layout>
|
||||
);
|
||||
}
|
23
packages/dox/website/pages/index.module.css
Normal file
23
packages/dox/website/pages/index.module.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* CSS files with the .module.css suffix will be treated as CSS modules
|
||||
* and scoped locally.
|
||||
*/
|
||||
|
||||
.heroBanner {
|
||||
padding: 4rem 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.heroBanner {
|
||||
padding: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
5
packages/dox/website/sidebars.js
Normal file
5
packages/dox/website/sidebars.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export default {
|
||||
sidebar: [
|
||||
'introduction',
|
||||
],
|
||||
};
|
Loading…
Reference in New Issue
Block a user