diff --git a/README.md b/README.md
index 1363d84c6..9e9d35bfb 100644
--- a/README.md
+++ b/README.md
@@ -12,11 +12,7 @@ $ greenwood
```
Fun! But naturally you'll want to make your own pages. So create a folder called _src/pages/_ and create a page called _index.md_.
-```shell
----
-label: 'hello'
----
-
+```md
# Helloworld
```
@@ -47,39 +43,77 @@ Your project will generally have a structure like this:
> Customize
### Creating A Page
-Here's a an example of a page
+
+Pages should be placed in your `src/pages/` directory. Page filenames will become the page's generated path. e.g.
+
+Here's a an example of a `src/pages/mypage.md`
+```md
+### Hello World
+
+This is an example page built by Greenwood. Make your own in _src/pages_!
+```
+
+Will accessible at http://localhost:8000/mypage
+
+You can nest directories in your `src/pages` directory which will also be used for the final URL.
+
+e.g. a markdown file at `src/pages/myblog/mycategory/index.md` will be accessible at http://localhost:8000/myblog/mycategory
+
+Another example a markdown file at `src/pages/myblog/mycategory/mypage.md` will be accessible at http://localhost:8000/myblog/mycategory/mypage
+
+You can also create [custom templates](#front-matter-template) to style and layout each page. As well as [customize the overall app template](#app-template)
+
+## Advanced Markdown
+
+You can add front-matter variables to the top, such as label, template, imports, as well as render components and html within each md file.
+
+### Front-Matter Label
+
+By default, a randomly generated export name will be created. `label` front-matter variable is completely optional.
+
+`label` front-matter variable will set the name of the exported md built web component element, within a default page template.
+
+e.g. example below would output `` with a child of `` element containing the markdown
+
+
```md
---
label: 'hello'
-template: 'page'
---
-
### Hello World
-This is an example page built by Greenwood. Make your own in _src/pages_!
+This is an example page built by Greenwood. Make your own in src/pages!
+
```
-And a page template
-```javascript
-import { html, LitElement } from 'lit-element';
-
-class index extends LitElement {
- render() {
- return html`
-
Greenwood
-
- This is the home page built by Greenwood. Make your own pages in src/pages/index.js!
-
- `;
- }
-}
-
-customElements.define('home-page', index);
+### Front-Matter Template
+
+You can also have your md file compiled within a custom page template. By default, each md file is automatically placed in a default(included) `page-template.js` component and exported with a generated/set label name.
+
+e.g. example below `` (all template element labels are prepended with `eve-`).
+
+You can add custom templates by specifying the `template` front-matter variable.
+
+The `template` variable string value will be appended with `-template.js` and is expected to be the an accessibile filename from within your `src/templates` directory.
+
+e.g. `template: 'guides'` will use a `src/template/guides-template.js` file.
+
+[See Page Template section](#page-template) below for an example `page-template.js` file.
+
+```md
+---
+label: 'hello'
+template: 'guides'
+---
+### Hello World
+
+This is an example page built by Greenwood. Make your own in src/pages!
+
```
-## Advanced Markdown
+### Front-Matter Render
-You can also render custom html such as a custom style or even a component within your markdown page using `imports` in your front-matter variables at top, as well as utilizing the `render` code block e.g.
+You can also render custom html such as a custom style or even a component within your markdown page using `imports` in your front-matter variables, as well as utilizing the `render` code block e.g.
````md
---
@@ -99,6 +133,7 @@ This is an example page built by Greenwood. Make your own in src/pages!
```
````
+
## API
Here are some of the features and capabiliites of Greenwood.
diff --git a/package.json b/package.json
index 312b27ffa..618fce207 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"redux": "^4.0.1",
"redux-thunk": "^2.3.0",
"rimraf": "^2.6.3",
- "wc-markdown-loader": "^0.0.6",
+ "wc-markdown-loader": "^0.0.8",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1",
diff --git a/packages/cli/config/webpack.config.common.js b/packages/cli/config/webpack.config.common.js
index f571976c5..23a413647 100644
--- a/packages/cli/config/webpack.config.common.js
+++ b/packages/cli/config/webpack.config.common.js
@@ -25,7 +25,7 @@ const mapUserWorkspaceDirectory = (userPath) => {
);
};
-module.exports = (context) => {
+module.exports = (context, graph) => {
// dynamically map all the user's workspace directories for resolution by webpack
// this essentially helps us keep watch over changes from the user, and greenwood's build pipeline
const mappedUserDirectoriesForWebpack = getUserWorkspaceDirectories(context.userWorkspace).map(mapUserWorkspaceDirectory);
@@ -63,10 +63,10 @@ module.exports = (context) => {
}
}, {
test: /\.md$/,
- loaders: [
- 'babel-loader',
- 'wc-markdown-loader'
- ]
+ loader: 'wc-markdown-loader',
+ options: {
+ graph
+ }
}, {
test: /\.css$/,
loaders: [
diff --git a/packages/cli/config/webpack.config.develop.js b/packages/cli/config/webpack.config.develop.js
index f103fe374..31151c93e 100644
--- a/packages/cli/config/webpack.config.develop.js
+++ b/packages/cli/config/webpack.config.develop.js
@@ -24,8 +24,8 @@ const rebuild = async() => {
}
};
-module.exports = (context) => {
- const configWithContext = commonConfig(context);
+module.exports = ({ context, graph }) => {
+ const configWithContext = commonConfig(context, graph);
const publicPath = configWithContext.output.publicPath;
return webpackMerge(configWithContext, {
diff --git a/packages/cli/config/webpack.config.prod.js b/packages/cli/config/webpack.config.prod.js
index 62b6fc448..7aebb5391 100644
--- a/packages/cli/config/webpack.config.prod.js
+++ b/packages/cli/config/webpack.config.prod.js
@@ -3,8 +3,8 @@ const path = require('path');
const webpackMerge = require('webpack-merge');
const commonConfig = require(path.join(__dirname, '..', './config/webpack.config.common.js'));
-module.exports = (context) => {
- const configWithContext = commonConfig(context);
+module.exports = ({ context, graph }) => {
+ const configWithContext = commonConfig(context, graph);
return webpackMerge(configWithContext, {
diff --git a/packages/cli/lib/graph.js b/packages/cli/lib/graph.js
index 0e865a534..c98cc1e62 100644
--- a/packages/cli/lib/graph.js
+++ b/packages/cli/lib/graph.js
@@ -47,12 +47,12 @@ const createGraphFromPages = async (pagesDir) => {
// determine if this is an index file, if so set route to '/'
let route = fileRoute === '/index' ? '/' : fileRoute;
-
+
// check if additional nested directories
if (seperatorIndex > 0) {
// get all remaining nested page directories
completeNestedPath = subDir.substring(0, seperatorIndex);
-
+
// set route to the nested pages path and file name(without extension)
route = completeNestedPath + route;
mdFile = `./${completeNestedPath}${fileRoute}.md`;
@@ -62,6 +62,9 @@ const createGraphFromPages = async (pagesDir) => {
relativeExpectedPath = `'../${fileName}/${fileName}.js'`;
}
+ // generate a random element name
+ label = label || generateRandomElementLabel(6);
+
/*
* Variable Definitions
*----------------------
@@ -73,6 +76,7 @@ const createGraphFromPages = async (pagesDir) => {
* fileName: file name without extension/path, so that it can be copied to scratch dir with same name
* relativeExpectedPath: relative import path for generated component within a list.js file to later be
* imported into app.js root component
+ * elementLabel: the element name for the generated md page e.g.
*/
pages.push({ mdFile, label, route, template, filePath, fileName, relativeExpectedPath });
@@ -97,6 +101,19 @@ const createGraphFromPages = async (pagesDir) => {
});
};
+const generateRandomElementLabel = (size) => {
+
+ const letters = 'abcedfghijklmnopqrstuvwxyz';
+ let short = [], rand = 0;
+
+ for (let n = 0; n < size; n = n + 1) {
+ rand = Math.floor(Math.random() * 25);
+ short.push(letters.substr(rand, 1));
+ }
+
+ return short.join('');
+};
+
module.exports = generateGraph = async (compilation) => {
return new Promise(async (resolve, reject) => {
diff --git a/packages/cli/tasks/build.js b/packages/cli/tasks/build.js
index 896797216..ccd1628dd 100644
--- a/packages/cli/tasks/build.js
+++ b/packages/cli/tasks/build.js
@@ -18,8 +18,8 @@ module.exports = runProductionBuild = async(compilation) => {
};
// eslint-disable-next-line no-unused-vars
-const runWebpack = async ({ context }) => {
- const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.prod.js'))(context);
+const runWebpack = async (compilation) => {
+ const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.prod.js'))(compilation);
return new Promise(async (resolve, reject) => {
diff --git a/packages/cli/tasks/develop.js b/packages/cli/tasks/develop.js
index 7598b8151..39884855d 100644
--- a/packages/cli/tasks/develop.js
+++ b/packages/cli/tasks/develop.js
@@ -2,11 +2,11 @@ const path = require('path');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
-module.exports = runDevServer = async ({ context }) => {
+module.exports = runDevServer = async (compilation) => {
return new Promise(async (resolve, reject) => {
try {
- const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.develop.js'))(context);
+ const webpackConfig = require(path.join(__dirname, '..', './config/webpack.config.develop.js'))(compilation);
const devServerConfig = webpackConfig.devServer;
let compiler = webpack(webpackConfig);
diff --git a/packages/cli/templates/hello.md b/packages/cli/templates/hello.md
index 0dd4055b3..bc93e10f2 100644
--- a/packages/cli/templates/hello.md
+++ b/packages/cli/templates/hello.md
@@ -1,9 +1,7 @@
---
-path: '/hello'
label: 'hello'
template: 'page'
---
-
### Hello World
This is an example page built by Greenwood. Make your own in _src/pages_!
\ No newline at end of file
diff --git a/packages/cli/templates/index.md b/packages/cli/templates/index.md
index d9cdffcc8..f0176789c 100644
--- a/packages/cli/templates/index.md
+++ b/packages/cli/templates/index.md
@@ -1,9 +1,7 @@
---
-path: '/'
label: 'index'
template: 'page'
---
-
### Greenwood
This is the home page built by Greenwood. Make your own pages in src/pages/index.js!
\ No newline at end of file
diff --git a/test/cli.spec.js b/test/cli.spec.js
index 5b8e67a2b..8c9e9ac2b 100644
--- a/test/cli.spec.js
+++ b/test/cli.spec.js
@@ -102,6 +102,7 @@ describe('building greenwood with a user workspace w/custom nested pages directo
await setup.run(['./packages/cli/index.js', 'build']);
blogPageHtmlPath = path.join(CONTEXT.publicDir, 'blog', '20190326', 'index.html');
+ customFMPageHtmlPath = path.join(CONTEXT.publicDir, 'customfm', 'index.html');
});
it('should output one JS bundle', async() => {
@@ -126,18 +127,50 @@ describe('building greenwood with a user workspace w/custom nested pages directo
});
it('should have the expected heading text within the blog page in the blog directory', async() => {
- const heading = dom.window.document.querySelector('h3.wc-md-blog').textContent;
+ const heading = dom.window.document.querySelector('h3').textContent;
expect(heading).to.equal(defaultHeading);
});
it('should have the expected paragraph text within the blog page in the blog directory', async() => {
- let paragraph = dom.window.document.querySelector('p.wc-md-blog').textContent;
+ let paragraph = dom.window.document.querySelector('p').textContent;
expect(paragraph).to.equal(defaultBody);
});
});
+ describe('a custom front-matter override page directory', () => {
+ const defaultPageHeading = 'Custom FM Page';
+ const defaultPageBody = 'This is a custom fm page built by Greenwood.';
+ let dom;
+
+ beforeEach(async() => {
+ dom = await JSDOM.fromFile(customFMPageHtmlPath);
+ });
+
+ it('should contain a customfm folder with an index html file', () => {
+ expect(fs.existsSync(customFMPageHtmlPath)).to.be.true;
+ });
+
+ it('should have the expected heading text within the customfm page in the customfm directory', async() => {
+ const heading = dom.window.document.querySelector('h3').textContent;
+
+ expect(heading).to.equal(defaultPageHeading);
+ });
+
+ it('should have the expected paragraph text within the customfm page in the customfm directory', async() => {
+ let paragraph = dom.window.document.querySelector('p').textContent;
+
+ expect(paragraph).to.equal(defaultPageBody);
+ });
+
+ it('should have the expected blog-template\'s blog-content class', async() => {
+ let layout = dom.window.document.querySelector('.blog-content');
+
+ expect(layout).to.not.equal(null);
+ });
+ });
+
after(async() => {
await fs.remove(CONTEXT.userSrc);
await fs.remove(CONTEXT.publicDir);
@@ -146,15 +179,10 @@ describe('building greenwood with a user workspace w/custom nested pages directo
});
-// // TODO - https://github.com/ProjectEvergreen/greenwood/issues/32
-// // describe('building greenwood with a user workspace w/custom app-template override', () => {
-
-// // });
-
-// // TODO - https://github.com/ProjectEvergreen/greenwood/issues/30
-// // describe('building greenwood with a user workspace w/custom page-template override', () => {
+// TODO - https://github.com/ProjectEvergreen/greenwood/issues/32
+// describe('building greenwood with a user workspace w/custom app-template override', () => {
-// // });
+// });
describe('building greenwood with error handling for app and page templates', () => {
before(async () => {
diff --git a/test/fixtures/mock-app/src/pages/blog/20190326/index.md b/test/fixtures/mock-app/src/pages/blog/20190326/index.md
index 9b8432f3f..1a5462435 100644
--- a/test/fixtures/mock-app/src/pages/blog/20190326/index.md
+++ b/test/fixtures/mock-app/src/pages/blog/20190326/index.md
@@ -1,6 +1,4 @@
---
-label: 'blog'
-template: 'page'
imports:
header: '../../../components/header/header.js'
CSS: '../../../styles/theme.css'
diff --git a/test/fixtures/mock-app/src/pages/customfm.md b/test/fixtures/mock-app/src/pages/customfm.md
new file mode 100644
index 000000000..93b9e9c90
--- /dev/null
+++ b/test/fixtures/mock-app/src/pages/customfm.md
@@ -0,0 +1,8 @@
+---
+label: 'customfm'
+template: 'blog'
+---
+
+### Custom FM Page
+
+This is a custom fm page built by Greenwood.
\ No newline at end of file
diff --git a/test/fixtures/mock-app/src/pages/hello.md b/test/fixtures/mock-app/src/pages/hello.md
index 3cd0df422..be938bfb3 100644
--- a/test/fixtures/mock-app/src/pages/hello.md
+++ b/test/fixtures/mock-app/src/pages/hello.md
@@ -1,6 +1,4 @@
---
-label: 'hello'
-template: 'page'
imports:
CSS: '../styles/theme.css'
---
diff --git a/test/fixtures/mock-app/src/pages/index.md b/test/fixtures/mock-app/src/pages/index.md
index b0e8a01f4..ab29f0c49 100644
--- a/test/fixtures/mock-app/src/pages/index.md
+++ b/test/fixtures/mock-app/src/pages/index.md
@@ -1,6 +1,4 @@
---
-label: 'index'
-template: 'page'
imports:
CSS: '../styles/theme.css'
---
diff --git a/test/fixtures/mock-app/src/templates/blog-template.js b/test/fixtures/mock-app/src/templates/blog-template.js
new file mode 100644
index 000000000..3d8c4f5a8
--- /dev/null
+++ b/test/fixtures/mock-app/src/templates/blog-template.js
@@ -0,0 +1,17 @@
+import { html, LitElement } from 'lit-element';
+
+MDIMPORT;
+
+class PageTemplate extends LitElement {
+ render() {
+ return html`
+
+ `;
+ }
+}
+
+customElements.define('page-template', PageTemplate);
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index f947e1d02..72fe22602 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9431,16 +9431,18 @@ wbuf@^1.1.0, wbuf@^1.7.3:
dependencies:
minimalistic-assert "^1.0.0"
-wc-markdown-loader@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/wc-markdown-loader/-/wc-markdown-loader-0.0.6.tgz#a6d01f6d46a55e9522e6a240f7392417c4656445"
- integrity sha512-ZAJPuHjvzGYaaq2p9u1fCLOiTO0cy9q3pV+knko4+Wfaz1o7WHo8MOcN085f3Bg0399f18Kwb69nRVkmzV3RCg==
+wc-markdown-loader@^0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/wc-markdown-loader/-/wc-markdown-loader-0.0.8.tgz#00d0f4f8b5346cd32fa6138dde42f2d859faaea5"
+ integrity sha512-5iwsUkrmfZdiACt/y9ujwetvXK/k1VtM6U7HshDOIws4NkunC4Cmhae47ViBUqRnnFRinKcO+wzIP/DyBqBuOg==
dependencies:
camelize "^1.0.0"
except "^0.1.3"
front-matter "^3.0.1"
+ loader-utils "^1.2.3"
node-prismjs "^0.1.0"
remarkable "^1.7.1"
+ schema-utils "^1.0.0"
webidl-conversions@^4.0.2:
version "4.0.2"