Live markdown updates

This commit is contained in:
Aaron Carlino 2019-11-19 13:55:33 +13:00
parent 4c90bad07b
commit 7d78429693
7 changed files with 76 additions and 29 deletions

View File

@ -28,18 +28,17 @@ To set up a local instance of [doc.silverstripe.org](https://github.com/silverst
```
git clone https://github.com/silverstripe/doc.silverstripe.org path/to/ssdocs
```
will clone this repository into `path/to/ssdocs`.
* From within `path/to/ssdocs`, run the command
```
gatsby develop
```
to instantiate a development server. This will consume all of the markdown files in both major release
branches and allow you to browse the documentation site on `http://localhost:8000` by default
(see the [Gatsby docs](https://www.gatsbyjs.org/docs/) for instructions on customising the port).
## Building
To test a static build of the site
To test a static build of the site, first create a production environment file.
```
cp .env.development .env.production
```
Then, run the build.
```
gatsby build
gatsby serve
@ -48,15 +47,40 @@ gatsby serve
These commands will give you an exact representation of how the site will run on a production server, with
statically generated html files and server-side rendering.
## Deploying
## Developing
From within `path/to/ssdocs`, run the command
```
gatsby develop
```
to instantiate a development server. This will consume all of the markdown files in both major release
branches and allow you to browse the documentation site on `http://localhost:8000` by default
(see the [Gatsby docs](https://www.gatsbyjs.org/docs/) for instructions on customising the port).
## Authoring
You can make changes directly to the source markdown files and get live updates in the development
server without having to rebuild the app or even refresh the browser. The clones of the `silverstripe/framework`
repositories are in the `.cache/gatsby-source-git` folder in the root of this project. There are subfolders
for `3/` and `4/`, respective to their branch names. You can edit the files in `docs/en` from there.
Just don't forget to merge your changes upstream once you're done. Building the gatsby app will not preserve
your content changes, since the remote repositories are the source of truth.
## Deploying content changes
Once your contribution has been merged into the master branch, you can run a build hook to trigger
a new build in Netlify.
```
(build hook coming soon)
curl -X POST -d {} https://api.netlify.com/build_hooks/5dd225fffdc558cbf6a23490
```
## Deploying app changes
Once your change is merged in to the `master` branch of this repository, it will be deployed live within minutes.
## Contribution
To contribute an improvement to the https://docs.silverstripe.org functionality or

View File

@ -33,15 +33,15 @@ module.exports = {
{
resolve: `gatsby-source-filesystem`,
options: {
name: `ss3-files`,
path: `${__dirname}/.cache/gatsby-source-git/3`
name: `watcher--ss3`,
path: `${__dirname}/.cache/gatsby-source-git/3/docs/en`
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `ss4-files`,
path: `${__dirname}/.cache/gatsby-source-git/4`
name: `watcher--ss4`,
path: `${__dirname}/.cache/gatsby-source-git/4/docs/en`
}
},
{

View File

@ -12,18 +12,37 @@ const createSlug = (filePath, version) => {
.toLowerCase()
};
exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) => {
exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNodeId, createContentDigest }) => {
if (node.internal.type !== 'MarkdownRemark') {
return;
}
const { createNode } = actions;
const fileNode = getNode(node.parent);
const version = fileNode.sourceInstanceName;
// The gatsby-source-filesystem plugins are registered to collect from the same path
// that the git source writes to, so we get the watch task (hot reload on content changes)
// But we don't want duplicate document pages for each source plugin, so
// we bail out if we already have the file. However, we need to ensure
// the file is injected into the template as a dependency, so when the content changes,
// the pages get refreshed on the fly.
if (version.match(/^watcher--/)) {
const existing = getNodesByType('SilverstripeDocument')
.find(n => n.fileAbsolutePath === node.fileAbsolutePath);
if (existing) {
// Pair the document with its watched file so we can inject it into the template
// as a dependency.
existing.watchFile___NODE = node.id;
return;
}
}
const filePath = createFilePath({
node,
getNode,
basePath: `docs`
});
});
let fileTitle = path.basename(node.fileAbsolutePath, '.md');
const isIndex = fileTitle === 'index';
if (isIndex) {
@ -32,7 +51,7 @@ exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) =
const docTitle = fileToTitle(fileTitle);
const slug = createSlug(filePath, version);
const parentSlug = `${path.resolve(slug, '../')}/`;
const docData = {
isIndex,
filePath,
@ -55,11 +74,11 @@ exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) =
};
const nodeData = {
...node,
id: `ss-doc-${node.id}`,
id: createNodeId(`SilverstripeDocument${node.id}`),
...docData,
parent: node.id,
internal: docInternal,
}
}
createNode(nodeData);
};

View File

@ -7,7 +7,7 @@ import { setCurrentNode } from '../utils/nodes';
const Template: StatelessComponent<SingleFileQuery> = (result): ReactElement => {
const currentNode = result.data.silverstripeDocument;
const { html } = currentNode.parent;
const { html } = currentNode.watchFile;
const { title, slug } = currentNode;
const { relativePath, gitRemote: { ref, webLink } } = currentNode.parent.parent;
const editLink = `${webLink}/edit/${ref}/${relativePath}`;
@ -35,9 +35,14 @@ export default Template;
export const pageQuery = graphql`
query DocsBySlug($slug: String!) {
silverstripeDocument(slug: { eq: $slug }) {
title
slug
id
watchFile {
html
}
parent {
... on MarkdownRemark {
html
parent {
... on File {
relativePath
@ -51,9 +56,6 @@ export const pageQuery = graphql`
}
}
title
slug
}
}
`

View File

@ -7,8 +7,10 @@ export interface SingleFileQuery {
export interface SinglePage {
title: string;
slug: string;
parent: {
watchFile: {
html: string;
}
parent: {
parent: {
relativePath: string;
gitRemote: {

View File

@ -1,7 +1,7 @@
const cleanApiTags = (html: string): string => {
return html.replace(
/\[api:(.*?)\][^(]/g,
(_, query) => `<a href="${query}">${query}</a> `
/\[api:(.*?)\]([^(])/g,
(_, query, next) => `<a target="_blank" href="${query}">${query}</a>${next}`
)
};

View File

@ -14,7 +14,7 @@ const getCalloutClass = (type: string): string => {
};
const cleanCalloutTags = (html: string): string => {
return html.replace(
/(?:<p>\s*)?(\[(hint|warning|info|alert|notice|note)\])(.*?)(\[\/(hint|warning|info|alert|notice|note)\])(?:<\/p>)?/gs,
/(?:<p>\s*)(\[(hint|warning|info|alert|notice|note)\])(.*?)(\[\/(hint|warning|info|alert|notice|note)\])(?:\s*<\/p>)/gs,
(_, tag, type, content) => `
<div class="callout-block callout-block-${getCalloutClass(type)}">
<div class="content">