mirror of
https://github.com/silverstripe/doc.silverstripe.org
synced 2024-10-22 15:05:50 +00:00
Live markdown updates
This commit is contained in:
parent
4c90bad07b
commit
7d78429693
46
README.md
46
README.md
@ -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
|
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
|
## 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 build
|
||||||
gatsby serve
|
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
|
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.
|
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
|
Once your contribution has been merged into the master branch, you can run a build hook to trigger
|
||||||
a new build in Netlify.
|
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
|
## Contribution
|
||||||
|
|
||||||
To contribute an improvement to the https://docs.silverstripe.org functionality or
|
To contribute an improvement to the https://docs.silverstripe.org functionality or
|
||||||
|
@ -33,15 +33,15 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
resolve: `gatsby-source-filesystem`,
|
resolve: `gatsby-source-filesystem`,
|
||||||
options: {
|
options: {
|
||||||
name: `ss3-files`,
|
name: `watcher--ss3`,
|
||||||
path: `${__dirname}/.cache/gatsby-source-git/3`
|
path: `${__dirname}/.cache/gatsby-source-git/3/docs/en`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resolve: `gatsby-source-filesystem`,
|
resolve: `gatsby-source-filesystem`,
|
||||||
options: {
|
options: {
|
||||||
name: `ss4-files`,
|
name: `watcher--ss4`,
|
||||||
path: `${__dirname}/.cache/gatsby-source-git/4`
|
path: `${__dirname}/.cache/gatsby-source-git/4/docs/en`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -12,18 +12,37 @@ const createSlug = (filePath, version) => {
|
|||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) => {
|
exports.onCreateNode = async ({ node, getNode, getNodesByType, actions, createNodeId, createContentDigest }) => {
|
||||||
if (node.internal.type !== 'MarkdownRemark') {
|
if (node.internal.type !== 'MarkdownRemark') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { createNode } = actions;
|
const { createNode } = actions;
|
||||||
const fileNode = getNode(node.parent);
|
const fileNode = getNode(node.parent);
|
||||||
const version = fileNode.sourceInstanceName;
|
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({
|
const filePath = createFilePath({
|
||||||
node,
|
node,
|
||||||
getNode,
|
getNode,
|
||||||
basePath: `docs`
|
basePath: `docs`
|
||||||
});
|
});
|
||||||
let fileTitle = path.basename(node.fileAbsolutePath, '.md');
|
let fileTitle = path.basename(node.fileAbsolutePath, '.md');
|
||||||
const isIndex = fileTitle === 'index';
|
const isIndex = fileTitle === 'index';
|
||||||
if (isIndex) {
|
if (isIndex) {
|
||||||
@ -32,7 +51,7 @@ exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) =
|
|||||||
const docTitle = fileToTitle(fileTitle);
|
const docTitle = fileToTitle(fileTitle);
|
||||||
const slug = createSlug(filePath, version);
|
const slug = createSlug(filePath, version);
|
||||||
const parentSlug = `${path.resolve(slug, '../')}/`;
|
const parentSlug = `${path.resolve(slug, '../')}/`;
|
||||||
|
|
||||||
const docData = {
|
const docData = {
|
||||||
isIndex,
|
isIndex,
|
||||||
filePath,
|
filePath,
|
||||||
@ -55,11 +74,11 @@ exports.onCreateNode = async ({ node, getNode, actions, createContentDigest }) =
|
|||||||
};
|
};
|
||||||
const nodeData = {
|
const nodeData = {
|
||||||
...node,
|
...node,
|
||||||
id: `ss-doc-${node.id}`,
|
id: createNodeId(`SilverstripeDocument${node.id}`),
|
||||||
...docData,
|
...docData,
|
||||||
parent: node.id,
|
parent: node.id,
|
||||||
internal: docInternal,
|
internal: docInternal,
|
||||||
}
|
}
|
||||||
createNode(nodeData);
|
createNode(nodeData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { setCurrentNode } from '../utils/nodes';
|
|||||||
|
|
||||||
const Template: StatelessComponent<SingleFileQuery> = (result): ReactElement => {
|
const Template: StatelessComponent<SingleFileQuery> = (result): ReactElement => {
|
||||||
const currentNode = result.data.silverstripeDocument;
|
const currentNode = result.data.silverstripeDocument;
|
||||||
const { html } = currentNode.parent;
|
const { html } = currentNode.watchFile;
|
||||||
const { title, slug } = currentNode;
|
const { title, slug } = currentNode;
|
||||||
const { relativePath, gitRemote: { ref, webLink } } = currentNode.parent.parent;
|
const { relativePath, gitRemote: { ref, webLink } } = currentNode.parent.parent;
|
||||||
const editLink = `${webLink}/edit/${ref}/${relativePath}`;
|
const editLink = `${webLink}/edit/${ref}/${relativePath}`;
|
||||||
@ -35,9 +35,14 @@ export default Template;
|
|||||||
export const pageQuery = graphql`
|
export const pageQuery = graphql`
|
||||||
query DocsBySlug($slug: String!) {
|
query DocsBySlug($slug: String!) {
|
||||||
silverstripeDocument(slug: { eq: $slug }) {
|
silverstripeDocument(slug: { eq: $slug }) {
|
||||||
|
title
|
||||||
|
slug
|
||||||
|
id
|
||||||
|
watchFile {
|
||||||
|
html
|
||||||
|
}
|
||||||
parent {
|
parent {
|
||||||
... on MarkdownRemark {
|
... on MarkdownRemark {
|
||||||
html
|
|
||||||
parent {
|
parent {
|
||||||
... on File {
|
... on File {
|
||||||
relativePath
|
relativePath
|
||||||
@ -51,9 +56,6 @@ export const pageQuery = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
title
|
|
||||||
slug
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -7,8 +7,10 @@ export interface SingleFileQuery {
|
|||||||
export interface SinglePage {
|
export interface SinglePage {
|
||||||
title: string;
|
title: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
parent: {
|
watchFile: {
|
||||||
html: string;
|
html: string;
|
||||||
|
}
|
||||||
|
parent: {
|
||||||
parent: {
|
parent: {
|
||||||
relativePath: string;
|
relativePath: string;
|
||||||
gitRemote: {
|
gitRemote: {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const cleanApiTags = (html: string): string => {
|
const cleanApiTags = (html: string): string => {
|
||||||
return html.replace(
|
return html.replace(
|
||||||
/\[api:(.*?)\][^(]/g,
|
/\[api:(.*?)\]([^(])/g,
|
||||||
(_, query) => `<a href="${query}">${query}</a> `
|
(_, query, next) => `<a target="_blank" href="${query}">${query}</a>${next}`
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ const getCalloutClass = (type: string): string => {
|
|||||||
};
|
};
|
||||||
const cleanCalloutTags = (html: string): string => {
|
const cleanCalloutTags = (html: string): string => {
|
||||||
return html.replace(
|
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) => `
|
(_, tag, type, content) => `
|
||||||
<div class="callout-block callout-block-${getCalloutClass(type)}">
|
<div class="callout-block callout-block-${getCalloutClass(type)}">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user