├── .gitignore
├── LICENSE
├── README.md
├── dochameleon-init
├── README.md
├── initialize.js
├── package-lock.json
└── package.json
├── docs
├── README.md
├── assets
│ └── img
│ │ └── progressive.png
├── blog
│ ├── 2018
│ │ ├── 01
│ │ │ ├── 10
│ │ │ │ └── staging-step.html
│ │ │ └── 08
│ │ │ │ └── why-dochameleon.html
│ │ ├── 02
│ │ │ └── 02
│ │ │ │ └── dochameleon-io-live.html
│ │ └── 03
│ │ │ └── 09
│ │ │ └── everybody-should-have-an-website.html
│ ├── atom.xml
│ ├── feed.xml
│ ├── index.html
│ └── page1
│ │ └── index.html
├── docs
│ ├── assets
│ │ └── img
│ │ │ └── progressive.png
│ ├── guide_analytics.html
│ ├── guide_color_scheme.html
│ ├── guide_configuration.html
│ ├── guide_core.html
│ ├── guide_github.html
│ ├── guide_i18n.html
│ ├── guide_installation.html
│ ├── guide_progressive.html
│ ├── guide_react.html
│ ├── guide_search.html
│ ├── guide_site_creation.html
│ ├── guide_site_publishing.html
│ └── guide_theme.html
├── en
│ ├── README.md
│ ├── blog
│ │ ├── 2018
│ │ │ ├── 01
│ │ │ │ ├── 10
│ │ │ │ │ └── staging-step.html
│ │ │ │ └── 08
│ │ │ │ │ └── why-dochameleon.html
│ │ │ ├── 02
│ │ │ │ └── 02
│ │ │ │ │ └── dochameleon-io-live.html
│ │ │ └── 03
│ │ │ │ └── 09
│ │ │ │ └── everybody-should-have-an-website.html
│ │ ├── index.html
│ │ └── page1
│ │ │ └── index.html
│ ├── docs
│ │ ├── assets
│ │ │ └── img
│ │ │ │ └── progressive.png
│ │ ├── guide_analytics.html
│ │ ├── guide_color_scheme.html
│ │ ├── guide_configuration.html
│ │ ├── guide_core.html
│ │ ├── guide_github.html
│ │ ├── guide_i18n.html
│ │ ├── guide_installation.html
│ │ ├── guide_progressive.html
│ │ ├── guide_react.html
│ │ ├── guide_search.html
│ │ ├── guide_site_creation.html
│ │ ├── guide_site_publishing.html
│ │ └── guide_theme.html
│ ├── help.html
│ ├── index.html
│ ├── languages.html
│ ├── readme.html
│ └── users.html
├── help.html
├── img
│ ├── algolia.svg
│ ├── dochameleon.png
│ ├── f-r.png
│ ├── favicon.ico
│ ├── favicon.png
│ ├── fsts.png
│ ├── github.png
│ ├── github_pages.png
│ ├── language.svg
│ ├── markdown.png
│ ├── octocat.jpg
│ ├── progressive.png
│ ├── react.svg
│ ├── setup.png
│ └── translation.svg
├── index.html
├── languages.html
├── readme.html
├── sitemap.xml
├── users.html
└── zh
│ ├── README.md
│ ├── blog
│ ├── 2018
│ │ ├── 01
│ │ │ ├── 10
│ │ │ │ └── staging-step.html
│ │ │ └── 08
│ │ │ │ └── why-dochameleon.html
│ │ ├── 02
│ │ │ └── 02
│ │ │ │ └── dochameleon-io-live.html
│ │ └── 03
│ │ │ └── 09
│ │ │ └── everybody-should-have-an-website.html
│ ├── index.html
│ └── page1
│ │ └── index.html
│ ├── docs
│ ├── assets
│ │ └── img
│ │ │ └── progressive.png
│ ├── guide_analytics.html
│ ├── guide_color_scheme.html
│ ├── guide_configuration.html
│ ├── guide_core.html
│ ├── guide_github.html
│ ├── guide_i18n.html
│ ├── guide_installation.html
│ ├── guide_progressive.html
│ ├── guide_react.html
│ ├── guide_search.html
│ ├── guide_site_creation.html
│ ├── guide_site_publishing.html
│ └── guide_theme.html
│ ├── help.html
│ ├── index.html
│ ├── languages.html
│ ├── readme.html
│ └── users.html
├── examples
└── basics
│ ├── blog
│ ├── 2018-01-08-why-dochameleon.md
│ └── 2018-01-10-staging-step.md
│ ├── components
│ ├── Callout.js
│ ├── Features.js
│ ├── Footer.js
│ ├── HelpDetails.js
│ ├── HomeSplash.js
│ ├── Showcase.js
│ ├── callouts.json
│ ├── features.json
│ ├── headerLinks.json
│ ├── help.json
│ └── users.json
│ ├── docs
│ ├── guide_configuration.md
│ ├── guide_customize_color.md
│ ├── guide_customize_core.md
│ ├── guide_customize_progressive.md
│ ├── guide_customize_react.md
│ ├── guide_customize_theme.md
│ ├── guide_installation.md
│ ├── guide_search.md
│ ├── guide_site_creation.md
│ ├── guide_site_publishing.md
│ └── sidebars.json
│ ├── gitignore
│ ├── pages
│ ├── help.js
│ ├── index.js
│ ├── languages.js
│ └── users.js
│ ├── siteConfig.js
│ ├── static
│ └── img
│ │ ├── f-r.png
│ │ └── fsts.png
│ └── theme
│ └── pages.js
├── lib
├── build-files.js
├── copy-examples.js
├── core
│ ├── Analytics.js
│ ├── Assets.js
│ ├── Blog.js
│ ├── Docs.js
│ ├── Extractor.js
│ ├── I18n.js
│ ├── Pages.js
│ ├── Parser.js
│ ├── Search.js
│ ├── components
│ │ ├── AnalyticsScript.js
│ │ ├── Breadcrumb.js
│ │ ├── Button.js
│ │ ├── CollapseIcon.js
│ │ ├── Footer.js
│ │ ├── Head.js
│ │ ├── HeaderNav.js
│ │ ├── HeaderNavItem.js
│ │ ├── MarkdownBlock.js
│ │ ├── Page.js
│ │ ├── README.md
│ │ ├── SearchBox.js
│ │ ├── SideNav.js
│ │ ├── SideNavCategory.js
│ │ ├── SideNavItem.js
│ │ ├── blog
│ │ │ ├── BlogPageLayout.js
│ │ │ ├── BlogPost.js
│ │ │ ├── BlogPostLayout.js
│ │ │ ├── BlogSidebar.js
│ │ │ └── social.js
│ │ ├── docs
│ │ │ ├── Doc.js
│ │ │ ├── DocsLayout.js
│ │ │ └── DocsSidebar.js
│ │ ├── headerLinks.json
│ │ └── toSlug.js
│ ├── dfs.js
│ ├── generate.js
│ ├── pages
│ │ ├── README.md
│ │ └── readme.js
│ ├── server.js
│ ├── site.js
│ └── theme
│ │ ├── blog.js
│ │ ├── color.js
│ │ ├── main.js
│ │ ├── markdown.js
│ │ ├── reset.js
│ │ └── search.js
├── publish-gh-pages.js
├── start-server.js
└── static
│ └── img
│ ├── algolia.svg
│ ├── dochameleon.png
│ ├── favicon.ico
│ ├── favicon.png
│ ├── github.png
│ ├── language.svg
│ ├── markdown.png
│ ├── octocat.jpg
│ ├── progressive.png
│ ├── react.svg
│ ├── setup.png
│ └── translation.svg
├── package-lock.json
├── package.json
└── website
├── .gitignore
├── analyticsConfig.js
├── blog
├── 2018-01-08-why-dochameleon.md
├── 2018-01-10-staging-step.md
├── 2018-02-02-dochameleon-io-live.md
└── 2018-03-09-everybody-should-have-an-website.md
├── components
├── Callout.js
├── Features.js
├── Footer.js
├── HelpDetails.js
├── HomeSplash.js
├── Showcase.js
├── callouts.json
├── features.json
├── headerLinks.json
├── help.json
└── users.json
├── docs
├── guide_analytics.md
├── guide_configuration.md
├── guide_customize_color.md
├── guide_customize_core.md
├── guide_customize_progressive.md
├── guide_customize_react.md
├── guide_customize_theme.md
├── guide_github.md
├── guide_i18n.md
├── guide_installation.md
├── guide_search.md
├── guide_site_creation.md
├── guide_site_publishing.md
└── sidebars.json
├── i18n
└── zh
│ ├── blog.js
│ ├── docs.js
│ ├── docs
│ └── guide_installation.md
│ ├── features.js
│ ├── langConfig.js
│ ├── languages.js
│ ├── menu.js
│ ├── project.js
│ └── translate.js
├── package.json
├── pages
├── help.js
├── index.js
├── languages.js
└── users.js
├── siteConfig.js
├── static
└── img
│ ├── f-r.png
│ ├── fsts.png
│ └── github_pages.png
└── theme
└── pages.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | website/build/
5 | website/node_modules
6 | website/package-lock.json
7 | website/yarn.lock
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Richard Zhang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dochameleon
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://badge.fury.io/js/dochameleon)
5 | [](https://www.npmjs.com/package/dochameleon)
6 | []()
7 |
8 | A Progressive Static Website Generator, built for Open Source documentation.
9 |
10 | Start your website in less than 1 minute.
11 |
12 | ```bash
13 | > npm install -g dochameleon-init
14 | > dochameleon-init
15 | > cd website
16 | > npm run start
17 | ```
18 |
19 | Or, [install without script](https://dochameleon.io/docs/guide_installation.html#manual-installation)
20 |
21 | Progressive Customization
22 |
23 |
24 |
25 | 1. [Just write markdown for documentation and blogging](http://dochameleon.io/docs/guide_site_creation.html)
26 | 2. [Change color scheme](http://dochameleon.io/docs/guide_color_scheme.html)
27 | 3. [Customize styling theme](http://dochameleon.io/docs/guide_theme.html)
28 | 4. [Write your own page](http://dochameleon.io/docs/guide_react.html)
29 | 5. [Replace core components](http://dochameleon.io/docs/guide_core.html)
30 |
31 | Check [Dochameleon Site](http://dochameleon.io/) for its own documentation.
32 |
--------------------------------------------------------------------------------
/dochameleon-init/README.md:
--------------------------------------------------------------------------------
1 | ## `dochameleon-init`
2 |
3 | An initialization script for [Dochameleon](https://dochameleon.io).
4 |
5 | ### What does it do?
6 |
7 | Dochameleon was a fork from Docusausurs
8 |
9 | 1. Go into the root of your GitHub repo directory where you will be creating the docs.
10 | 1. `yarn global add dochameleon-init` or `npm install --global dochameleon-init`
11 | 1. `dochameleon-init`
12 |
13 | Find out more in the [official docs](https://dochameleon.io/docs/guide_installation.html).
14 |
--------------------------------------------------------------------------------
/dochameleon-init/initialize.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const shell = require("shelljs");
4 | const chalk = require("chalk");
5 | const fs = require("fs");
6 | const path = require("path");
7 |
8 | const CWD = process.cwd();
9 | const join = path.join;
10 |
11 | const log = console.log;
12 | const error = console.error;
13 |
14 | let useYarn = !!(shell.which("yarn"));
15 |
16 | let file = join(CWD, "website");
17 | if (fs.existsSync(file)) {
18 | error(chalk.yellow("/website folder already exists.\n"));
19 | log(
20 | "Dochameleon setup at 'website' folder. You will need to remove existing 'website' folder from root directory to let Dochameleon do its work."
21 | );
22 | process.exit(1);
23 | }
24 |
25 | shell.cd(CWD);
26 | shell.mkdir("website");
27 | log(chalk.green("Website folder created!\n"));
28 |
29 | shell.cd("website");
30 | log(chalk.yellow("Installing latest version of Dochameleon in website.\n"));
31 |
32 | const content = { scripts: { examples: "dochameleon-examples" } };
33 | fs.writeFileSync(
34 | CWD + "/website/package.json",
35 | JSON.stringify(content, null, 2) + "\n"
36 | );
37 |
38 | shell.exec(
39 | useYarn
40 | ? "yarn add dochameleon --dev"
41 | : "npm install dochameleon --save-dev"
42 | );
43 | log(chalk.green("Dochameleon installed in website folder!\n"));
44 |
45 | shell.exec(
46 | useYarn
47 | ? "yarn run examples"
48 | : "npm run examples"
49 | );
50 |
--------------------------------------------------------------------------------
/dochameleon-init/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dochameleon-init",
3 | "description": "Initialization script for Dochameleon",
4 | "version": "0.0.1",
5 | "license": "MIT",
6 | "preferGlobal": true,
7 | "keywords": [
8 | "documentation",
9 | "websites",
10 | "open source",
11 | "docusaurus",
12 | "dochameleon"
13 | ],
14 | "bin": {
15 | "dochameleon-init": "initialize.js"
16 | },
17 | "dependencies": {
18 | "chalk": "^2.1.0",
19 | "inquirer": "^5.1.0",
20 | "shelljs": "^0.7.8"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Dochameleon
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://badge.fury.io/js/dochameleon)
5 | [](https://www.npmjs.com/package/dochameleon)
6 | []()
7 |
8 | A Progressive Static Website Generator, built for Open Source documentation.
9 |
10 | Start your website in less than 1 minute.
11 |
12 | ```bash
13 | > npm install -g dochameleon-init
14 | > dochameleon-init
15 | > cd website
16 | > npm run start
17 | ```
18 |
19 | Or, [install without script](https://dochameleon.io/docs/guide_installation.html#manual-installation)
20 |
21 | Progressive Customization
22 |
23 |
24 |
25 | 1. [Just write markdown for documentation and blogging](http://dochameleon.io/docs/guide_site_creation.html)
26 | 2. [Change color scheme](http://dochameleon.io/docs/guide_color_scheme.html)
27 | 3. [Customize styling theme](http://dochameleon.io/docs/guide_theme.html)
28 | 4. [Write your own page](http://dochameleon.io/docs/guide_react.html)
29 | 5. [Replace core components](http://dochameleon.io/docs/guide_core.html)
30 |
31 | Check [Dochameleon Site](http://dochameleon.io/) for its own documentation.
32 |
--------------------------------------------------------------------------------
/docs/assets/img/progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/assets/img/progressive.png
--------------------------------------------------------------------------------
/docs/blog/atom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | https://richardzcode.github.io/blog
4 | Dochameleon Blog
5 | 2018-03-09T14:00:00Z
6 | Feed for Node.js
7 |
8 | The best place to stay up-to-date with the latest Dochameleon news and events.
9 | Copyright © 2018 Richard Zhang
10 |
11 |
12 | https://richardzcode.github.io/blog/2018/03/09/everybody-should-have-an-website.html
13 |
14 |
15 | 2018-03-09T14:00:00Z
16 |
19 |
20 | Richard Zhang
21 |
22 |
23 |
24 |
25 | https://richardzcode.github.io/blog/2018/02/02/dochameleon-io-live.html
26 |
27 |
28 | 2018-02-02T14:00:00Z
29 |
34 |
35 | Richard Zhang
36 |
37 |
38 |
39 |
40 | https://richardzcode.github.io/blog/2018/01/10/staging-step.html
41 |
42 |
43 | 2018-01-10T14:00:00Z
44 |
47 |
48 | Richard Zhang
49 |
50 |
51 |
52 |
53 | https://richardzcode.github.io/blog/2018/01/08/why-dochameleon.html
54 |
55 |
56 | 2018-01-08T14:00:00Z
57 |
62 |
63 | Richard Zhang
64 |
65 |
66 |
--------------------------------------------------------------------------------
/docs/blog/feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Dochameleon Blog
5 | https://richardzcode.github.io/blog
6 | The best place to stay up-to-date with the latest Dochameleon news and events.
7 | Fri, 09 Mar 2018 14:00:00 GMT
8 | http://blogs.law.harvard.edu/tech/rss
9 | Feed for Node.js
10 | Copyright © 2018 Richard Zhang
11 | -
12 |
13 | https://richardzcode.github.io/blog/2018/03/09/everybody-should-have-an-website.html
14 | https://richardzcode.github.io/blog/2018/03/09/everybody-should-have-an-website.html
15 | Fri, 09 Mar 2018 14:00:00 GMT
16 |
19 |
20 | -
21 |
22 | https://richardzcode.github.io/blog/2018/02/02/dochameleon-io-live.html
23 | https://richardzcode.github.io/blog/2018/02/02/dochameleon-io-live.html
24 | Fri, 02 Feb 2018 14:00:00 GMT
25 |
30 |
31 | -
32 |
33 | https://richardzcode.github.io/blog/2018/01/10/staging-step.html
34 | https://richardzcode.github.io/blog/2018/01/10/staging-step.html
35 | Wed, 10 Jan 2018 14:00:00 GMT
36 |
39 |
40 | -
41 |
42 | https://richardzcode.github.io/blog/2018/01/08/why-dochameleon.html
43 | https://richardzcode.github.io/blog/2018/01/08/why-dochameleon.html
44 | Mon, 08 Jan 2018 14:00:00 GMT
45 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/docs/docs/assets/img/progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/docs/assets/img/progressive.png
--------------------------------------------------------------------------------
/docs/en/README.md:
--------------------------------------------------------------------------------
1 | # Dochameleon
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://badge.fury.io/js/dochameleon)
5 | [](https://www.npmjs.com/package/dochameleon)
6 | []()
7 |
8 | A Progressive Static Website Generator, built for Open Source documentation.
9 |
10 | Start your website in less than 1 minute.
11 |
12 | ```bash
13 | > npm install -g dochameleon-init
14 | > dochameleon-init
15 | > cd website
16 | > npm run start
17 | ```
18 |
19 | Or, [install without script](https://dochameleon.io/docs/guide_installation.html#manual-installation)
20 |
21 | Progressive Customization
22 |
23 |
24 |
25 | 1. [Just write markdown for documentation and blogging](http://dochameleon.io/docs/guide_site_creation.html)
26 | 2. [Change color scheme](http://dochameleon.io/docs/guide_color_scheme.html)
27 | 3. [Customize styling theme](http://dochameleon.io/docs/guide_theme.html)
28 | 4. [Write your own page](http://dochameleon.io/docs/guide_react.html)
29 | 5. [Replace core components](http://dochameleon.io/docs/guide_core.html)
30 |
31 | Check [Dochameleon Site](http://dochameleon.io/) for its own documentation.
32 |
--------------------------------------------------------------------------------
/docs/en/docs/assets/img/progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/en/docs/assets/img/progressive.png
--------------------------------------------------------------------------------
/docs/img/algolia.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/docs/img/dochameleon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/dochameleon.png
--------------------------------------------------------------------------------
/docs/img/f-r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/f-r.png
--------------------------------------------------------------------------------
/docs/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/favicon.ico
--------------------------------------------------------------------------------
/docs/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/favicon.png
--------------------------------------------------------------------------------
/docs/img/fsts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/fsts.png
--------------------------------------------------------------------------------
/docs/img/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/github.png
--------------------------------------------------------------------------------
/docs/img/github_pages.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/github_pages.png
--------------------------------------------------------------------------------
/docs/img/language.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/docs/img/markdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/markdown.png
--------------------------------------------------------------------------------
/docs/img/octocat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/octocat.jpg
--------------------------------------------------------------------------------
/docs/img/progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/progressive.png
--------------------------------------------------------------------------------
/docs/img/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/docs/img/setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/img/setup.png
--------------------------------------------------------------------------------
/docs/img/translation.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/docs/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | https://richardzcode.github.io/help.html weekly 0.5
4 | https://richardzcode.github.io/index.html weekly 0.5
5 | https://richardzcode.github.io/languages.html weekly 0.5
6 | https://richardzcode.github.io/readme.html weekly 0.5
7 | https://richardzcode.github.io/README.md weekly 0.5
8 | https://richardzcode.github.io/users.html weekly 0.5
9 | https://richardzcode.github.io/blog/2018/03/09/everybody-should-have-an-website.html weekly 0.3
10 | https://richardzcode.github.io/blog/2018/02/02/dochameleon-io-live.html weekly 0.3
11 | https://richardzcode.github.io/blog/2018/01/10/staging-step.html weekly 0.3
12 | https://richardzcode.github.io/blog/2018/01/08/why-dochameleon.html weekly 0.3
13 | https://richardzcode.github.io/docs/guide_analytics.html weekly 0.3
14 | https://richardzcode.github.io/docs/guide_configuration.html weekly 0.3
15 | https://richardzcode.github.io/docs/guide_color_scheme.html weekly 0.3
16 | https://richardzcode.github.io/docs/guide_core.html weekly 0.3
17 | https://richardzcode.github.io/docs/guide_progressive.html weekly 0.3
18 | https://richardzcode.github.io/docs/guide_react.html weekly 0.3
19 | https://richardzcode.github.io/docs/guide_theme.html weekly 0.3
20 | https://richardzcode.github.io/docs/guide_github.html weekly 0.3
21 | https://richardzcode.github.io/docs/guide_i18n.html weekly 0.3
22 | https://richardzcode.github.io/docs/guide_installation.html weekly 0.3
23 | https://richardzcode.github.io/docs/guide_search.html weekly 0.3
24 | https://richardzcode.github.io/docs/guide_site_creation.html weekly 0.3
25 | https://richardzcode.github.io/docs/guide_site_publishing.html weekly 0.3
26 |
--------------------------------------------------------------------------------
/docs/zh/README.md:
--------------------------------------------------------------------------------
1 | # Dochameleon
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://badge.fury.io/js/dochameleon)
5 | [](https://www.npmjs.com/package/dochameleon)
6 | []()
7 |
8 | A Progressive Static Website Generator, built for Open Source documentation.
9 |
10 | Start your website in less than 1 minute.
11 |
12 | ```bash
13 | > npm install -g dochameleon-init
14 | > dochameleon-init
15 | > cd website
16 | > npm run start
17 | ```
18 |
19 | Or, [install without script](https://dochameleon.io/docs/guide_installation.html#manual-installation)
20 |
21 | Progressive Customization
22 |
23 |
24 |
25 | 1. [Just write markdown for documentation and blogging](http://dochameleon.io/docs/guide_site_creation.html)
26 | 2. [Change color scheme](http://dochameleon.io/docs/guide_color_scheme.html)
27 | 3. [Customize styling theme](http://dochameleon.io/docs/guide_theme.html)
28 | 4. [Write your own page](http://dochameleon.io/docs/guide_react.html)
29 | 5. [Replace core components](http://dochameleon.io/docs/guide_core.html)
30 |
31 | Check [Dochameleon Site](http://dochameleon.io/) for its own documentation.
32 |
--------------------------------------------------------------------------------
/docs/zh/docs/assets/img/progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/docs/zh/docs/assets/img/progressive.png
--------------------------------------------------------------------------------
/examples/basics/blog/2018-01-08-why-dochameleon.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Why Dochameleon
3 | author: Richard Zhang
4 | authorGitHub: richardzcode
5 | ---
6 |
7 | It is not hard to guess where the idea of Dochameleon is from.
8 |
9 | With [Docusaurus](https://github.com/facebook/Docusaurus) built and maintained by awesome team from Facebook, why do I want to build another one?
10 |
11 | One personal reason is I am so excited about Docusaurus. Can't stop checking around, rewrite, restruct source code. So only way to satisfy is to create a new project.
12 |
13 |
14 |
15 | Here are some technical reasons,
16 |
17 | 1. Dev server and site generation are written separately. Inconsistency is inevitable.
18 | 2. Pages can not share building blocks.
19 | 3. Big CSS file makes styling hard.
20 |
21 | At the same time some features are removed. I feel they are a bit too opinionated with complexity, may not suited for all open source projects.
22 |
23 | 1. Search with [algolia](https://www.algolia.com/).
24 | 2. Multi-Language with [crowdin](https://crowdin.com/).
25 | 3. Project version support.
26 |
27 | For example, at the end of the day multi-language and versioning are grouped by file hierarchies. One options is to just take pull requests on GitHub.
28 |
--------------------------------------------------------------------------------
/examples/basics/blog/2018-01-10-staging-step.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Staging Step
3 | author: Richard Zhang
4 | authorGitHub: richardzcode
5 | ---
6 |
7 | The basic idea of Dochameleon is to generate a static web server by using [Server-Side-Rendering](https://reactjs.org/docs/react-dom-server.html). Contents are combined from core library and specific project.
8 |
9 | Combining from two sources can be tricky. So there is a staging step. Which in essence copies files from the two sources into one place, for SSR to generate from, and for developers to inspect on.
10 |
11 | The one place can be found at `node_modules/dochameleon/lib/stage`, contains a file structure like this:
12 |
13 | ```bash
14 | node_modules/dochameleon/lib/stage/
15 | ├── Blog.js
16 | ├── Docs.js
17 | ├── Pages.js
18 | ├── blog
19 | │ └── 2018-01-08-why-dochameleon.md
20 | │ └── 2018-01-10-stage-step.md
21 | ├── components
22 | │ ├── Button.js
23 | │ ├── CollapseIcon.js
24 | │ ├── FeatureCallout.js
25 | │ ├── FeatureCallouts.js
26 | │ ├── Features.js
27 | │ ├── Footer.js
28 | │ ├── Head.js
29 | │ ├── HeaderNav.js
30 | │ ├── HelpDetails.js
31 | │ ├── HomeSplash.js
32 | │ ├── MarkdownBlock.js
33 | │ ├── Page.js
34 | │ ├── Showcase.js
35 | │ ├── SideNav.js
36 | │ ├── blog
37 | │ ├── docs
38 | │ ├── featureCallouts.json
39 | │ ├── features.json
40 | │ ├── help.json
41 | │ └── users.json
42 | ├── dfs.js
43 | ├── docs
44 | │ ├── doc1.md
45 | │ ├── doc2.md
46 | │ ├── doc3.md
47 | │ ├── exampledoc4.md
48 | │ ├── exampledoc5.md
49 | │ └── sidebars.json
50 | ├── pages
51 | │ ├── help.js
52 | │ ├── index.js
53 | │ └── users.js
54 | ├── parse
55 | │ ├── Markdown.js
56 | │ └── toSlug.js
57 | ├── static
58 | │ ├── css
59 | │ └── img
60 | └── theme
61 | ├── blog.js
62 | ├── main.js
63 | ├── markdown.js
64 | └── pages.js
65 | ```
66 |
--------------------------------------------------------------------------------
/examples/basics/components/Callout.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Div, A, Img, Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('./MarkdownBlock');
5 |
6 | class FeatureCallout extends React.Component {
7 | render() {
8 | const { site, lang, callout } = this.props;
9 | const { theme } = site;
10 | const title = site.i18n.translate(callout.title, lang);
11 | const content = callout['content.token']
12 | ? [].concat(site.i18n.translate(callout['content.token'], lang, callout.content)).join('')
13 | : [].concat(callout.content).join('');
14 | return (
15 |
16 | {callout.imgFirst && (
17 |
18 |
19 |
})
23 |
24 |
25 | )}
26 |
27 | {callout.doc
28 | ? {title}
32 | : {title}
33 | }
34 | {content}
35 |
36 | {!callout.imgFirst && (
37 |
38 |
39 |
})
40 |
41 |
42 | )}
43 |
44 | )
45 | }
46 | }
47 |
48 | module.exports = FeatureCallout;
49 |
--------------------------------------------------------------------------------
/examples/basics/components/Features.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H3, Div, Img, Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('./MarkdownBlock.js');
5 | const features = require('./features.json');
6 |
7 | const header = features.header
8 | ? [].concat(features.header).join('')
9 | : '';
10 | const footer = features.footer
11 | ? [].concat(features.footer).join('')
12 | : '';
13 |
14 | const Features = (props) => {
15 | const { site, lang } = props;
16 | const { theme } = site;
17 | const sectionComps = features.features.map((feature, idx) => {
18 | const content = feature['content.token']
19 | ? [].concat(site.i18n.translate(feature['content.token'], lang, feature.content)).join('')
20 | : [].concat(feature.content).join('');
21 | return (
22 |
23 |
24 |
25 |
})
26 |
27 |
{site.i18n.translate(feature.title, lang)}
28 |
{content}
29 |
30 |
31 | )
32 | });
33 |
34 | return (
35 |
36 | {header && {header}}
37 | {sectionComps}
38 | {footer && {footer}}
39 |
40 | )
41 | }
42 |
43 | module.exports = Features;
44 |
--------------------------------------------------------------------------------
/examples/basics/components/Footer.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | class Footer extends React.Component {
4 | render() {
5 | const { site, lang } = this.props;
6 | const { theme } = site;
7 | const currentYear = new Date().getFullYear();
8 | return (
9 |
58 | );
59 | }
60 | }
61 |
62 | module.exports = Footer;
63 |
--------------------------------------------------------------------------------
/examples/basics/components/HelpDetails.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H3, Div, Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('./MarkdownBlock.js');
5 | const help = require('./help.json');
6 |
7 | const HelpDetails = (props) => {
8 | const { site, lang } = props;
9 | const { theme } = site;
10 | const sectionComps = help.map((help_item, idx) => {
11 | return (
12 |
13 |
14 |
{help_item.title}
15 | {help_item.content}
16 |
17 |
18 | )
19 | });
20 | return {sectionComps}
21 | }
22 |
23 | module.exports = HelpDetails;
24 |
--------------------------------------------------------------------------------
/examples/basics/components/HomeSplash.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H2, Div } = require('fluid-react');
3 |
4 | const Button = require('./Button.js');
5 |
6 | class HomeSplash extends React.Component {
7 | render() {
8 | const { site, lang } = this.props;
9 | const tagline = site.i18n.translate('tagline', lang, site.config.tagline);
10 | return (
11 |
12 |
13 | {site.config.title}
14 |
{tagline}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | module.exports = HomeSplash;
27 |
--------------------------------------------------------------------------------
/examples/basics/components/Showcase.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H3, H5, Div, P, Row, Col } = require('fluid-react');
3 |
4 | const users = require('./users.json');
5 |
6 | const Showcase = props => {
7 | if (users.length === 0) { return null; }
8 |
9 | const { site, lang } = props;
10 | const { theme } = site;
11 | const userComps = users
12 | .filter(user => !props.pinned || user.pinned)
13 | .map((user, i) => {
14 | let img_src = user.img;
15 | if (!img_src.startsWith('http')) { img_src = site.url(img_src); }
16 | return (
17 |
18 |
19 |
20 |
21 |
22 | );
23 | });
24 |
25 | return (
26 |
27 |
28 | {site.i18n.translate('Who\'s Using This?', lang)}
29 |
30 | {site.i18n.translate('This project is used by all these people', lang)}
31 |
32 |
33 | {userComps}
34 |
35 |
36 | );
37 | };
38 |
39 | module.exports = Showcase;
40 |
--------------------------------------------------------------------------------
/examples/basics/components/callouts.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Quick Setup",
4 | "doc": "guide_installation",
5 | "content.token": "quick_setup.content",
6 | "content": [
7 | "Get up and running quickly. Have your own website in just a few minutes",
8 | "\n",
9 | "\n```bash",
10 | "\n> npm install -g dochameleon-init",
11 | "\n> dochameleon-init",
12 | "\n> cd website",
13 | "\n> npm run start",
14 | "\n```"
15 | ],
16 | "img": "img/setup.png",
17 | "imgFirst": false
18 | },
19 | {
20 | "title": "Develop and Deploy",
21 | "doc": "guide_site_publishing",
22 | "content.token": "develop_deploy.content",
23 | "content": [
24 | "Develop using included live server; ",
25 | "Deploy to GitHub or any static file web hosts"
26 | ],
27 | "img": "img/octocat.jpg",
28 | "imgStyle": { "maxWidth": "50%" },
29 | "imgFirst": true
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/examples/basics/components/features.json:
--------------------------------------------------------------------------------
1 | {
2 | "header": "",
3 | "footer": "",
4 | "features": [
5 | {
6 | "title": "Powered by Markdown",
7 | "content.token": "markdown.content",
8 | "content": [
9 | "Write docs and blog posts with ",
10 | "[Markdown](https://guides.github.com/features/mastering-markdown/). ",
11 | "Dochameleon converts them into HTML files."
12 | ],
13 | "img": "img/markdown.png"
14 | },
15 | {
16 | "title": "Built Using React",
17 | "content.token": "react.content",
18 | "content": [
19 | "Build [React](https://reactjs.org/) Components ",
20 | "to extend or customize your project."
21 | ],
22 | "img": "img/react.svg"
23 | },
24 | {
25 | "title": "Progressive Customization",
26 | "content.token": "customization.content",
27 | "content": "Works out-of-box, able to customize to the extend of replacing core components",
28 | "img": "img/progressive.png"
29 | }
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/examples/basics/components/headerLinks.json:
--------------------------------------------------------------------------------
1 | [
2 | { "type": "page", "value": "readme", "label": "README" },
3 | { "type": "doc", "value": "guide_installation", "label": "Docs" },
4 | { "type": "blog", "label": "Blog" },
5 | {
6 | "type": "url",
7 | "value": "https://github.com/richardzcode/Dochameleon",
8 | "img": "img/github.png",
9 | "label": "GitHub"
10 | }
11 | ]
12 |
--------------------------------------------------------------------------------
/examples/basics/components/help.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Browse Docs",
4 | "content": "Learn more using the documentation on this site."
5 | },
6 | {
7 | "title": "Join the community",
8 | "content": "Ask questions about the documentation and project"
9 | },
10 | {
11 | "title": "Stay up to date",
12 | "content": "Find out what's new with this project"
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/examples/basics/components/users.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "fsts-js",
4 | "img": "img/fsts.png",
5 | "link": "https://richardzcode.github.io/fsts-js/index.html",
6 | "pinned": true
7 | },
8 | {
9 | "caption": "Fluid React",
10 | "img": "img/f-r.png",
11 | "link": "https://richardzcode.github.io/fluid-react/index.html",
12 | "pinned": true
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_configuration.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_configuration
3 | title: Site Configuration
4 | sidebar_label: Site Configuration
5 | ---
6 |
7 | ```bash
8 | website/
9 | └── siteConfig.js
10 | ```
11 |
12 | Site configurations are defined in `website/siteConfig.js`, here is an example:
13 |
14 | ```
15 | const currentYear = new Date().getFullYear();
16 |
17 | const siteConfig = {
18 | projectName: 'Dochameleon',
19 | title: 'Dochameleon',
20 | tagline: 'Open Source Documentation Site Generator',
21 | copyright: 'Copyright © ' + currentYear + ' Richard Zhang',
22 |
23 | rootUrl: 'https://richardzcode.github.io',
24 | baseUrl: '/Dochameleon',
25 |
26 | icon: 'img/dochameleon.png',
27 | favicon: 'img/favicon.png',
28 |
29 | css: [],
30 | js: [
31 | 'https://buttons.github.io/buttons.js',
32 | ],
33 |
34 | headerLinks: [
35 | {doc: 'guide_installation', label: 'Docs'},
36 | {url: 'https://github.com/richardzcode/Dochameleon', label: 'GitHub'},
37 | {page: 'help', label: 'Help'},
38 | {blog: true, label: 'Blog'},
39 | ]
40 | };
41 | ```
42 |
43 | Dochameleon itself does not have css file. Theming is through CSS-in-JS. Extra css and js files can be specified in siteConfig.js
44 |
45 | `headerLinks` defines what displayed on main menu. Menu items can be one of the four types: doc, blog, page, url
46 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_customize_color.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_color_scheme
3 | title: Color Scheme
4 | sidebar_label: Color Scheme
5 | ---
6 |
7 | Changing colors probably is the simplest way to differenciate a website.
8 |
9 | Dochameleon does not have CSS file. All styles are defined in Javascript, which enables easy style customization. Changing color scheme is a perfect example.
10 |
11 | The core library has a [theme](https://github.com/richardzcode/Dochameleon/tree/master/lib/core/theme) folder which defines UI style. Custom website also have a `theme` folder. At runtime the two folder will be combined together, with the custom file replace core file if names are same.
12 |
13 | Copy [color.js](https://github.com/richardzcode/Dochameleon/tree/master/lib/core/theme/color.js) into website folder `/theme`, then change `primary` and `secondary` color. So it becomes:
14 |
15 | ```
16 | const color = {
17 | primary: '#283e4a',
18 | secondary: '#337ab7',
19 | tertiary: '#e0e0e0',
20 | font: '#393939',
21 | fontSecondary: '#000'
22 | };
23 |
24 | color.title = color.primary;
25 | color.content = color.font;
26 | color.contentSecondary = color.fontSecondary;
27 | color.clickable = color.primary;
28 |
29 | color.nav = {
30 | primary: color.primary,
31 | secondary: color.secondary,
32 | tertiary: color.tertiary,
33 | font: '#fff',
34 | fontSecondary: 'rgba(255, 255, 255, 0.8)',
35 | fontTertiary: 'rgba(255, 255, 255, 0.6)'
36 | };
37 |
38 | color.footer = '#808080';
39 |
40 | module.exports = color;
41 | ```
42 |
43 | run dev server again, `npm run start`. See what happens.
44 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_customize_core.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_core
3 | title: Core Component
4 | sidebar_label: Core Component
5 | ---
6 |
7 | Like mentioned in [Customization - React Component](./guide_react.html), Dochameleon merges custom and core components together at runtime. This makes further customization possible.
8 |
9 | Let's say you don't like sidebar at the left side for docs. Just copy `components/docs/DocsLayout.js` from core library to `website/components/docs`, then modify render function to switch the order of sidebar and content.
10 |
11 | ```
12 | return (
13 |
14 |
15 |
16 | {content}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | ```
26 |
27 | Now `npm run start` see the sidebar is on the right side.
28 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_customize_progressive.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_progressive
3 | title: Progressive
4 | sidebar_label: Progressive Customization
5 | ---
6 |
7 | Website created by Dochameleon works out-of-box. You can just write Markdown documents and blogs.
8 |
9 | Depend on needs, you can customize the website progressively, from simply changing color to completely replace the core component rendering.
10 |
11 | 
12 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_customize_react.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_react
3 | title: React Component
4 | sidebar_label: React Component
5 | ---
6 |
7 | Write web pages in React, then Dochameleon will convert them into static HTML files.
8 |
9 | ### Pages
10 |
11 | Write web pages in `website/pages` folder. Each file exports an React component which will be rendered as one page.
12 |
13 | ### Components
14 |
15 | You may write custom React components in `website/components` folder, and use them in pages.
16 |
17 | Core library has React components too. At runtime, Dochameleon merges the two sets together.
18 |
19 | Take a look at example site `components` folder. It has number of components. Among them, `Footer.js` will overwrite the core Footer. Try remove it, and run `npm run start`, you'll notice default footer is different.
20 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_customize_theme.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_theme
3 | title: UI Theme
4 | sidebar_label: UI Theme
5 | ---
6 |
7 | Like mentioned in [Customization - Color Scheme](./guide_color_scheme.html), Dochameleon defines UI style in `/theme` folder, in Javascript.
8 |
9 | ### Core and Custom Theme
10 |
11 | Core theme located at `lib/core/theme` folder of the core library. Custom theme located at `website/theme` folder. Each file exports an object that defines a set of UI styles.
12 |
13 | Two steps happening at runtime.
14 |
15 | First step, files in the two folder will be merged together. If custom theme file has same name as core theme file then it will overwrite the core file.
16 |
17 | Second step, Dochameleon reads all theme files and merge all objects into one final object. This is the theme object, contains defination of all UI styles.
18 |
19 | ### Customization
20 |
21 | Customization is simply write theme files in `website/theme` folder.
22 |
23 | Create a file `website/theme/custom.js`
24 | ```
25 | const custom = {
26 | button: {
27 | margin: '4px',
28 | border: '1px solid blue',
29 | borderRadius: '3px',
30 | color: 'blue',
31 | display: 'inline-block',
32 | fontSize: '14px',
33 | fontWeight: '400',
34 | lineHeight: '1.2em',
35 | padding: '10px',
36 | textTransform: 'uppercase',
37 | textDecoration: 'none',
38 | transition: 'background 0.3s, color 0.3s'
39 | }
40 | }
41 |
42 | module.exports = custom;
43 | ```
44 |
45 | run dev server again, `npm run start`. See how buttons look like now.
46 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_installation
3 | title: Installation
4 | sidebar_label: Installation
5 | ---
6 |
7 |
8 |
9 | ### Install via script
10 |
11 | The easiest way to install Dochameleon is by using script `dochameleon-init`
12 |
13 | First install the script
14 |
15 | ```
16 | npm install --global dochameleon-init
17 | ```
18 |
19 | Then, go to the folder that your'd like to create the documentation website, run
20 |
21 | ```
22 | dochameleon-init
23 | cd website
24 | npm run start
25 | ```
26 |
27 | The init script does three things: create `website` folder; npm install `dochameleon` package; copy a basic example website to start from.
28 |
29 |
30 | ### Manual installation
31 |
32 | If you do not want `dochameleon-init`, rather create website manually.
33 |
34 | - Create and go into the `website` folder
35 | - Create package.json with content,
36 | ```
37 | {
38 | "scripts": {
39 | "examples": "dochameleon-examples"
40 | }
41 | }
42 | ```
43 | - Install Dochameleon, run
44 | ```
45 | npm install dochameleon
46 | ```
47 |
48 | - Init with basic example, run
49 | ```
50 | npm run examples
51 | ```
52 |
53 | ### Run Local Dev Server
54 |
55 | Once installation completed, a website with example content is ready to go. Just run
56 |
57 | ```
58 | npm run start
59 | ```
60 |
61 | ### File Structure
62 |
63 | Once installation successful, here is the file structure you'll have under the `website` folder
64 |
65 | ```bash
66 | website/
67 | ├── blog/
68 | │ ├── 2018-01-08-why-dochameleon.md
69 | │ └── 2018-01-10-staging-step.md
70 | ├── components/
71 | ├── docs/
72 | │ ├── doc1.md
73 | │ ├── doc2.md
74 | │ ├── doc3.md
75 | │ └── sidebars.json
76 | ├── pages/
77 | │ ├── help.js
78 | │ ├── index.js
79 | │ └── users.js
80 | ├── siteConfig.js
81 | ├── static/
82 | └── theme/
83 | ```
84 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_search.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_search
3 | title: Search
4 | sidebar_label: Search
5 | ---
6 |
7 | Dochameleon support search by [Algolia](https://www.algolia.com). Algolia is super easy to setup, and its community plan is free.
8 |
9 | ### Configure
10 |
11 | After setup Algolia for your project. Add `searchConfig.js` along with `siteConfig.js`
12 |
13 | ```bash
14 | website/
15 | └── searchConfig.js
16 | ```
17 |
18 | Content similiar to this:
19 | ```
20 | const searchConfig = {
21 | application_id: ...,
22 | search_api_key: ...,
23 | api_key: ...,
24 | js: 'https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js'
25 | }
26 |
27 | module.exports = searchConfig;
28 | ```
29 |
30 | Make sure searchConfig.js is in your `.gitignore`. You want to keep api_key safe.
31 |
32 | ### Add to Menu
33 |
34 | Modify `siteConfig.js`, add this entry to headerLinks:
35 | ```
36 | {type: 'search'},
37 | ```
38 |
39 | ### Indexing
40 |
41 | Indexing happens at site generation time. When you run `npm run build`, the latest docs are pushed to Algolia.
42 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_site_creation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_site_creation
3 | title: Site Creation
4 | sidebar_label: Site Creation
5 | ---
6 |
7 |
8 |
9 | ### Docs
10 |
11 | ```bash
12 | website/
13 | └── docs/
14 | ├── doc1.md
15 | ├── doc2.md
16 | ├── doc3.md
17 | └── sidebars.json
18 | ```
19 | Write documentation under `website/docs` folder, with Markdown.
20 |
21 | At beginning of each doc file, add metadata like this:
22 |
23 | ```
24 | ---
25 | id: doc1
26 | title: Latin-ish
27 | sidebar_label: Example Page
28 | ---
29 | ```
30 |
31 | #### Sidebar
32 |
33 | Sidebar menu is defined in `sidebars.json`
34 |
35 | ### Blog
36 |
37 | ```bash
38 | website/
39 | └── blog/
40 | ├── 2018-01-08-why-dochameleon.md
41 | └── 2018-01-10-staging-step.md
42 | ```
43 | Write blog posts under `website/blog` folder, with Markdown.
44 |
45 | File name must have the format of `yyyy-mm-dd-blog-file-name.md`
46 |
47 | At begging of each blog post, add metadata like this:
48 |
49 | ```
50 | ---
51 | title: Why Dochameleon
52 | author: Richard Zhang
53 | authorUrl: https://github.com/richardzcode
54 | authorImage: https://github.com/richardzcode.png
55 | ---
56 | ```
57 |
58 | authorUrl and authorImage can be set by name/id of GitHub, Facebook, or Twitter, for example:
59 |
60 | ```
61 | authorGitHub: richardzcode
62 | ```
63 |
64 | or
65 |
66 | ```
67 | authorFBID: ...
68 | ```
69 |
70 | or
71 |
72 | ```
73 | authorTwitter: ...
74 | ```
75 |
76 | ### Pages
77 |
78 | ```bash
79 | website/
80 | ├── components/
81 | ├── pages/
82 | │ ├── help.js
83 | │ ├── index.js
84 | │ └── users.js
85 | └── theme/
86 | ```
87 | Create web pages under `website/pages` folder, by writing React.
88 |
89 | Create components under `website/components`, for pages to import.
90 |
91 | Write theme files under `website/theme`, to define styles.
92 |
93 | ### Static Files
94 |
95 | ```bash
96 | website/
97 | └── static/
98 | ```
99 |
100 | Put static files under `website/static` folder. They will go to `${rootUrl}${baseUrl}/`
101 |
102 | You may refer to static files in docs as `/static/...`, for example `[Logo]( /static/img/logo.png)`
103 |
--------------------------------------------------------------------------------
/examples/basics/docs/guide_site_publishing.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_site_publishing
3 | title: Site Publishing
4 | sidebar_label: Site Publishing
5 | ---
6 |
7 | Dochameleon converts Markdown and React source files into static HTML files. Then you put them on any of the web hosting solution, GitHub, Amazon S3, etc.
8 |
9 | ### Build
10 |
11 | ```
12 | npm run build
13 | ```
14 |
15 | Then all HTML files will be generated into `website/build` folder.
16 |
17 | ### Hosting
18 |
19 | Now you may get all of the files inside `website/build` and copy over to web hosting.
20 |
21 | ### GitHub Pages
22 |
23 | [GitHub Pages](https://pages.github.com/) is a very natural hosting choice for open source projects. To publish to GitHub Pages,
24 |
25 | 1. Follow steps to create your GitHub Pages. Select "master branch /docs folder" as `Source`
26 |
27 | 2. Copy `website/build/{projectName}` folder to your project `/docs` folder.
28 | 3. Commit and push your git repo.
29 |
30 | That's it!
31 |
--------------------------------------------------------------------------------
/examples/basics/docs/sidebars.json:
--------------------------------------------------------------------------------
1 | {
2 | "docs": {
3 | "Getting Started": [
4 | "guide_installation",
5 | "guide_configuration",
6 | "guide_site_creation",
7 | "guide_site_publishing"
8 | ],
9 | "Customization": [
10 | "guide_progressive",
11 | "guide_color_scheme",
12 | "guide_theme",
13 | "guide_react",
14 | "guide_core"
15 | ],
16 | "More": ["guide_search"]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/basics/gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | build/
4 | yarn.lock
5 | **/node_modules
6 | searchConfig.js
7 |
--------------------------------------------------------------------------------
/examples/basics/pages/help.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const HelpDetails = require('../components/HelpDetails.js');
4 |
5 | class Help extends React.Component {
6 | render() {
7 | const { site, lang } = this.props;
8 | const { theme } = site;
9 | return (
10 |
11 |
12 |
Need help?
13 |
This project is maintained by a dedicated group of people.
14 |
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | module.exports = Help;
22 |
--------------------------------------------------------------------------------
/examples/basics/pages/index.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const HomeSplash = require('../components/HomeSplash.js');
4 | const Features = require('../components/Features.js');
5 | const Callout = require('../components/Callout.js');
6 | const Showcase = require('../components/Showcase.js');
7 |
8 | const callouts = require('../components/callouts.json');
9 |
10 | class Index extends React.Component {
11 | render() {
12 | const { site, lang } = this.props;
13 | const { theme } = site;
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | module.exports = Index;
33 |
--------------------------------------------------------------------------------
/examples/basics/pages/languages.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('../components/MarkdownBlock.js');
5 |
6 | const no_languages_content = `
7 | To have multi-language, write translations under \`website/i18n/$lang_code$\`
8 |
9 | [Example](https://github.com/richardzcode/Dochameleon/tree/master/website/i18n)
10 | `;
11 |
12 | class Languages extends React.Component {
13 | render() {
14 | const { site, lang } = this.props;
15 | const { theme } = site;
16 | const langs = site.i18n.langs();
17 | const languages = langs && langs.length > 0
18 | ? langs.map((language, i) => {
19 | return (
20 |
21 |
22 | {site.i18n.translate(language, lang)}
23 |
24 |
25 | );
26 | })
27 | : {no_languages_content}
28 |
29 | return (
30 |
31 |
32 |
33 | {languages}
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | module.exports = Languages;
42 |
--------------------------------------------------------------------------------
/examples/basics/pages/users.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { JS} = require('fsts');
3 |
4 | const Showcase = require('../components/Showcase.js');
5 |
6 | const user_json = 'https://github.com/richardzcode/Dochameleon/blob/master/website/components/users.json';
7 |
8 | class Users extends React.Component {
9 | render() {
10 | const { site, lang } = this.props;
11 | const { theme } = site;
12 |
13 | const cta = site.i18n.translate('Create pull request to add your logo', lang);
14 | return (
15 |
21 | );
22 | }
23 | }
24 |
25 | module.exports = Users;
26 |
--------------------------------------------------------------------------------
/examples/basics/siteConfig.js:
--------------------------------------------------------------------------------
1 | const currentYear = new Date().getFullYear();
2 |
3 | const siteConfig = {
4 | projectName: 'test-site',
5 | title: 'Test Site',
6 | tagline: 'A website for testing',
7 | copyright: 'Copyright © ' + currentYear + ' Richard Zhang',
8 |
9 | rootUrl: 'https://richardzcode.github.io',
10 | baseUrl: '/test-site',
11 |
12 | icon: 'img/dochameleon.png',
13 | favicon: 'img/favicon.png',
14 |
15 | js: [
16 | 'https://buttons.github.io/buttons.js'
17 | ]
18 | };
19 |
20 | module.exports = siteConfig;
21 |
--------------------------------------------------------------------------------
/examples/basics/static/img/f-r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/examples/basics/static/img/f-r.png
--------------------------------------------------------------------------------
/examples/basics/static/img/fsts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/examples/basics/static/img/fsts.png
--------------------------------------------------------------------------------
/examples/basics/theme/pages.js:
--------------------------------------------------------------------------------
1 | const color = require('./color.js');
2 |
3 | const pages = {
4 | block: {
5 | padding: '30px 10px'
6 | },
7 | blockEven: {
8 | padding: '30px 10px',
9 | background: '#e9e9e9'
10 | },
11 | homeSplash: {
12 | padding: '2em 10px',
13 | textAlign: 'center'
14 | },
15 | promoSection: {
16 | display: 'flex',
17 | flexFlow: 'row wrap',
18 | justifyContent: 'center',
19 | fontSize: '125%',
20 | lineHeight: '1.6em',
21 | position: 'relative',
22 | zIndex: '99'
23 | },
24 | featureImageContainer: {
25 | textAlign: 'center'
26 | },
27 | featureImage: {
28 | maxHeight: '80px'
29 | },
30 | calloutTitle: {
31 | textAlign: 'left',
32 | textDecoration: 'none',
33 | color: color.title,
34 | fontWeight: '300',
35 | fontSize: '180%',
36 | lineHeight: '1em'
37 | },
38 | calloutImageContainer: {
39 | textAlign: 'center'
40 | },
41 | calloutImage: {
42 | maxWidth: '80%'
43 | },
44 | showcaseBox: {
45 | display: 'block',
46 | padding: '20px',
47 | width: '80px',
48 | textAlign: 'center'
49 | },
50 | showcaseImage: {
51 | maxWidth: '100%',
52 | maxHeight: '80px'
53 | },
54 | helpTitle: {
55 | textAlign: 'left',
56 | color: color.title,
57 | fontWeight: '300',
58 | fontSize: '200%',
59 | lineHeight: '1em'
60 | },
61 | helpSection: {
62 | padding: '20px'
63 | },
64 | helpSectionTitle: {
65 | textAlign: 'left',
66 | color: color.title,
67 | fontWeight: '300',
68 | fontSize: '150%',
69 | lineHeight: '1em'
70 | }
71 | };
72 |
73 | module.exports = pages;
74 |
--------------------------------------------------------------------------------
/lib/build-files.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('babel-register')({
4 | babelrc: false,
5 | only: [__dirname, process.cwd() + '/core'],
6 | presets: ['react', 'env'],
7 | });
8 |
9 | // initial check that required files are present
10 | const chalk = require('chalk');
11 | const fs = require('fs');
12 | const CWD = process.cwd();
13 |
14 | if (!fs.existsSync(CWD + '/siteConfig.js')) {
15 | console.error(
16 | chalk.red('Error: No siteConfig.js file found in website folder!')
17 | );
18 | process.exit(1);
19 | }
20 |
21 | // generate all static html files
22 | const generate = require('./core/generate.js');
23 | generate();
24 | console.log("Site built successfully. Generated files in 'build' folder.");
25 |
--------------------------------------------------------------------------------
/lib/copy-examples.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require('fs-extra');
4 | const glob = require('glob');
5 | const path = require('path');
6 | const chalk = require('chalk');
7 |
8 | const join = path.join;
9 | const CWD = process.cwd();
10 |
11 | // add scripts to package.json file
12 | const package_json = join(CWD, 'package.json');
13 | if (fs.existsSync(package_json)) {
14 | const content = JSON.parse(
15 | fs.readFileSync(package_json, 'utf8')
16 | );
17 |
18 | if (!content.scripts) { content.scripts = {}; }
19 |
20 | content.scripts = Object.assign(
21 | {},
22 | content.scripts,
23 | {
24 | 'start': 'dochameleon-start',
25 | 'build': 'dochameleon-build',
26 | 'publish-gh-pages': 'dochameleon-publish',
27 | 'examples': 'dochameleon-examples'
28 | }
29 | );
30 |
31 | fs.writeFileSync(
32 | package_json,
33 | JSON.stringify(content, null, 2) + '\n'
34 | );
35 |
36 | console.log(
37 | `${chalk.green('Wrote dochameleon scripts to package.json file.')}\n`
38 | );
39 | }
40 |
41 | const exampleRoot = join(__dirname, '..', 'examples', 'basics');
42 |
43 | // docs
44 | const docsFrom = join(exampleRoot, 'docs');
45 | const docsTo = join(CWD, 'docs');
46 | if (fs.existsSync(docsTo)) {
47 | console.log(
48 | `${chalk.yellow('Example docs already exist!')}
49 | Rename or remove ${chalk.yellow(docsTo)} to regenerate example docs.\n`
50 | );
51 | } else {
52 | fs.copySync(docsFrom, docsTo);
53 | }
54 |
55 | // blog
56 | const blogFrom = join(exampleRoot, 'blog');
57 | const blogTo = join(CWD, 'blog');
58 | if (fs.existsSync(blogTo)) {
59 | console.log(
60 | `${chalk.yellow('Example blog posts already exist!')}
61 | Rename or remove ${chalk.yellow(blogTo)} to regenerate example blog posts.\n`
62 | );
63 | } else {
64 | fs.copySync(blogFrom, blogTo);
65 | }
66 |
67 | // .gitignore
68 | const gitignoreFrom = join(exampleRoot, 'gitignore');
69 | const gitignoreTo = join(CWD, '.gitignore');
70 | if (fs.existsSync(gitignoreTo)) {
71 | console.log(
72 | `${chalk.yellow('.gitignore already exists')} in ${chalk.yellow(CWD)}
73 | Rename or remove the file to regenerate an example version.\n`
74 | );
75 | } else {
76 | fs.copySync(gitignoreFrom, gitignoreTo);
77 | }
78 |
79 | // copy other files
80 | glob.sync(exampleRoot + '/**/*')
81 | .forEach(file => {
82 | if (fs.lstatSync(file).isDirectory()) { return; }
83 |
84 | const file_name = path.basename(file);
85 | if (file_name === 'gitignore') { return; }
86 |
87 | const folder = path.basename(path.dirname(file));
88 | if (folder === 'blog' || folder === 'docs') { return; }
89 |
90 | const targetFile = path.resolve(file).replace(exampleRoot, CWD);
91 | try {
92 | fs.copySync(file, targetFile, { overwrite: false, errorOnExist: true });
93 | } catch (e) {
94 | console.log(
95 | `${chalk.yellow(file_name + ' already exists')}
96 | Rename or remove the file to regenerate an example version.\n`
97 | );
98 | }
99 | });
100 |
101 | const file_structure = `
102 | website/
103 | ├── blog/
104 | │ ├── 2018-01-08-why-dochameleon.md
105 | │ └── 2018-01-10-staging-step.md
106 | ├── components/
107 | ├── docs/
108 | │ ├── doc1.md
109 | │ ├── doc2.md
110 | │ ├── doc3.md
111 | │ └── sidebars.json
112 | ├── pages/
113 | │ ├── help.js
114 | │ ├── index.js
115 | │ └── users.js
116 | ├── siteConfig.js
117 | ├── static/
118 | └── theme/
119 | `
120 |
121 | const site_config = chalk.yellow('website/siteConfig.js');
122 |
123 | const guide = `
124 | ${chalk.green('Website created')} in ${chalk.green('/website')}
125 |
126 | Default website file structure:
127 | ${chalk.green.dim(file_structure)}
128 |
129 | Go to ${chalk.yellow('/website/docs')} to write docs with Markdown.
130 | Go to ${chalk.yellow('/website/blog')} to write blog posts with Markdown.
131 | Go to ${chalk.yellow('/website/pages')} to write customized pages with React.
132 | Go to ${chalk.yellow('/website/components')} to write React components.
133 |
134 | Set ${chalk.green('docsDir')} in ${site_config} to change path to docs.
135 | Set ${chalk.green('blogDir')} in ${site_config} to change path to blog posts.
136 |
137 | Modify ${site_config} for project settings.
138 | `
139 | console.log(guide);
140 |
--------------------------------------------------------------------------------
/lib/core/Analytics.js:
--------------------------------------------------------------------------------
1 | class Analytics {
2 | constructor(site) {
3 | this.config = site.analyticsConfig
4 | if (!this.config) { return; }
5 |
6 | const { js } = this.config;
7 | if (js) { // add js to config js
8 | site.config.js = (site.config.js || []).concat(js);
9 | }
10 | }
11 | }
12 |
13 | module.exports = Analytics;
14 |
--------------------------------------------------------------------------------
/lib/core/Assets.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const chalk = require('chalk');
3 | const createSitemap = require('sitemap').createSitemap;
4 |
5 | const dfs = require('./dfs.js');
6 |
7 | const join = path.join;
8 |
9 | class Assets {
10 | constructor(site, rootPath) {
11 | this.site = site;
12 | this.rootPath = rootPath;
13 | }
14 |
15 | sitemap() {
16 | let urls = [];
17 |
18 | this.site.pages.files()
19 | .forEach(file => {
20 | const url = file.split('/pages')[1]
21 | .replace(/\.js$/, '.html');
22 | urls.push({url, changefreq: 'weekly', priority: 0.5});
23 | });
24 |
25 | this.site.blog.metadatas
26 | .forEach(metadata => {
27 | const url = metadata.permalink();
28 | urls.push({url, changefreq: 'weekly', priority: 0.3});
29 | });
30 |
31 | this.site.docs.metadatas
32 | .forEach(metadata => {
33 | const url = metadata.permalink();
34 | urls.push({url, changefreq: 'weekly', priority: 0.3});
35 | });
36 |
37 | const sitemap = createSitemap({
38 | hostname: this.site.rootUrl,
39 | cacheTime: 600 * 1000, // 600 sec - cache purge period
40 | urls: urls,
41 | });
42 |
43 | return new Promise((resolve, reject) => {
44 | sitemap.toXML((err, xml) => {
45 | if (err) {
46 | reject('An error has occured.');
47 | } else {
48 | resolve(xml);
49 | }
50 | });
51 | });
52 | }
53 |
54 | staticFiles() {
55 | return dfs.files(join(this.rootPath, '**'));
56 | }
57 | };
58 |
59 | module.exports = Assets;
60 |
--------------------------------------------------------------------------------
/lib/core/Blog.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const Feed = require('feed');
3 | const React = require('react');
4 | const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
5 |
6 | const dfs = require('./dfs.js');
7 | const Extractor = require('./Extractor.js');
8 | const BlogPageLayout = require('./components/blog/BlogPageLayout.js');
9 | const BlogPostLayout = require('./components/blog/BlogPostLayout.js');
10 |
11 | const join = path.join;
12 |
13 | const extractor = new Extractor();
14 |
15 | const dtToString = dt => {
16 | const year = dt.getFullYear();
17 | const month = [
18 | 'January',
19 | 'February',
20 | 'March',
21 | 'April',
22 | 'May',
23 | 'June',
24 | 'July',
25 | 'August',
26 | 'September',
27 | 'October',
28 | 'November',
29 | 'December',
30 | ][dt.getMonth()];
31 | const day = dt.getDate();
32 |
33 | return month + ' ' + day + ', ' + year;
34 | }
35 |
36 | class Blog {
37 | constructor(site, rootPath) {
38 | this.site = site;
39 | this.rootPath = rootPath;
40 |
41 | this.loadMetadatas();
42 | }
43 |
44 | isEmpty() {
45 | return this.metadatas.length === 0;
46 | }
47 |
48 | findByPath(path) {
49 | const found = this.metadatas
50 | .filter(metadata => metadata.path === path);
51 | return found.length > 0? found[0] : null;
52 | }
53 |
54 | files() {
55 | return dfs.files(join(this.rootPath, '**/*.*'), ['.md', '.markdown']);
56 | }
57 |
58 | loadMetadatas() {
59 | this.metadatas = this.files()
60 | .sort()
61 | .reverse()
62 | .map(file => this._parseFile(file));
63 | }
64 |
65 | feed(type) {
66 | type = type || 'rss';
67 |
68 | const site = this.site;
69 | const rootUrl = site.urlWithRoot('blog');
70 | const metadatas = this.metadatas;
71 | const feed = new Feed({
72 | title: site.config.title + ' Blog',
73 | description: 'The best place to stay up-to-date with the latest ' +
74 | site.config.title + ' news and events.',
75 | id: rootUrl,
76 | link: rootUrl,
77 | image: site.headerIcon,
78 | copyright: site.config.copyright,
79 | updated: metadatas.length > 0? new Date(metadatas[0].date) : new Date(),
80 | });
81 |
82 | metadatas.forEach(post => {
83 | feed.addItem({
84 | title: post.title,
85 | link: rootUrl + '/' + post.path,
86 | author: [{
87 | name: post.author,
88 | link: post.authorURL,
89 | }],
90 | date: new Date(post.date),
91 | description: post.brief,
92 | });
93 | });
94 |
95 | return type === 'rss' ? feed.rss2() : feed.atom1();
96 | }
97 |
98 | renderPage(pageNumber, pageSize, lang) {
99 | pageNumber = pageNumber || 1;
100 | pageSize = pageSize || 10;
101 |
102 | const site = this.site;
103 | const from = (pageNumber - 1) * pageSize;
104 | const to = from + pageSize;
105 | const posts = this.metadatas.slice(from, to);
106 | const previous = pageNumber > 1
107 | ? site.url('/blog/page' + (pageNumber - 1) + '/index.html', lang)
108 | : null;
109 | const next = to < (this.metadatas.length - 1)
110 | ? site.url('/blog/page' + (pageNumber + 1) + '/index.html', lang)
111 | : null;
112 | const blogPageComp = (
113 |
120 | );
121 | return renderToStaticMarkup(blogPageComp);
122 | }
123 |
124 | render(post, lang) {
125 | if (typeof post === 'string') { post = this.findByPath(post); }
126 | if (!post) { return ''; }
127 |
128 | const site = this.site;
129 | const recent = this.metadatas.slice(0, 10);
130 | const blogPostComp =
131 | return renderToStaticMarkup(blogPostComp);
132 | }
133 |
134 | _parseFile(file) {
135 | const metadata = extractor.extractMetadata(dfs.read(file));
136 | // From 2015-08-13-blog-post-name-0.5.md to 2015/08/13/blog-post-name-0-5.html
137 | metadata.path = path.basename(file)
138 | .replace('-', '/')
139 | .replace('-', '/')
140 | .replace('-', '/')
141 | .replace(/\.md$/, '.html');
142 |
143 | const site = this.site;
144 | metadata.permalink = function(lang) { return site.blogUrl(this.path, lang); }
145 |
146 | metadata.id = metadata.title;
147 |
148 | // Extract, YYYY, MM, DD from the file name
149 | const dtStr = path.basename(file)
150 | .replace(/([0-9]+\-[0-9]+\-[0-9]+)\-.+/, (match, $1) => $1 + 'T06:00:00.000');
151 | metadata.date = new Date(dtStr);
152 | metadata.dtStr = dtToString(metadata.date);
153 |
154 | // brief
155 | const splitBrief = metadata.content.split('');
156 | metadata.brief = splitBrief.length > 1
157 | ? splitBrief[0].trim()
158 | : metadata.content.trim().substring(0, 250).trim();
159 |
160 | return metadata;
161 | }
162 | }
163 |
164 | module.exports = Blog;
165 |
--------------------------------------------------------------------------------
/lib/core/Docs.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const React = require('react');
3 | const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
4 |
5 | const dfs = require('./dfs.js');
6 | const Extractor = require('./Extractor.js');
7 | const DocsLayout = require('./components/docs/DocsLayout.js');
8 |
9 | const join = path.join;
10 |
11 | const extractor = new Extractor();
12 |
13 | class Docs {
14 | constructor(site, rootPath) {
15 | this.site = site;
16 | this.rootPath = rootPath;
17 |
18 | this.sidebars_json = join(rootPath, 'sidebars.json');
19 | this.loadSidebars();
20 | this.loadMetadatas();
21 | }
22 |
23 | files() {
24 | return dfs.files(join(this.rootPath, '**'), ['.md', '.markdown']);
25 | }
26 |
27 | find(id) {
28 | if (!id) { return null; }
29 | const found = this.metadatas
30 | .filter(metadata => metadata.id === id);
31 | return found.length > 0? found[0] : null;
32 | }
33 |
34 | findByUri(uri) {
35 | const found = this.metadatas
36 | .filter(metadata => metadata.permalink() === uri);
37 | return found.length > 0? found[0] : null;
38 | }
39 |
40 | loadSidebars() {
41 | this.sidebars = {};
42 | if (dfs.exists(this.sidebars_json)) {
43 | this.sidebars = require(this.sidebars_json);
44 | }
45 |
46 | this.sidebar_items = [];
47 | Object.keys(this.sidebars)
48 | .forEach(key => {
49 | const sidebar = this.sidebars[key];
50 | Object.keys(sidebar)
51 | .forEach(category => {
52 | const doc_ids = sidebar[category];
53 | doc_ids.forEach(id => {
54 | const entry = {
55 | id: id,
56 | sidebar: sidebar,
57 | category: category
58 | };
59 | const last = this.sidebar_items.length > 0
60 | ? this.sidebar_items[this.sidebar_items.length-1]
61 | : null;
62 | if (last) {
63 | entry.previous = last.id;
64 | last.next = id;
65 | }
66 | this.sidebar_items.push(entry);
67 | });
68 | });
69 | });
70 | }
71 |
72 | loadMetadatas() {
73 | this.metadatas = this.files()
74 | .map(file => this.processMetadata(file))
75 | .filter(metadata => !!metadata);
76 |
77 | this.metadatas.forEach(metadata => {
78 | const previous = this.find(metadata.previous);
79 | if (previous) {
80 | metadata.previous_title = previous.title || 'Previous';
81 | metadata.previous_sidebar_label = previous.sidebar_label || 'Previous';
82 | }
83 | const next = this.find(metadata.next);
84 | if (next) {
85 | metadata.next_title = next.title || 'Next';
86 | metadata.next_sidebar_label = next.sidebar_label || 'Next';
87 | }
88 | });
89 | }
90 |
91 | processMetadata(file) {
92 | const file_content = dfs.read(file);
93 | const metadata = extractor.extractMetadata(file_content);
94 |
95 | metadata.source = path.basename(file);
96 | if (!metadata.id) {
97 | metadata.id = path.basename(file, path.extname(file));
98 | }
99 | if (metadata.id.includes('/')) {
100 | throw new Error('Document id cannot include "/".');
101 | }
102 | if (!metadata.title) { metadata.title = metadata.id; }
103 |
104 | metadata.path = metadata.id + '.html';
105 |
106 | const site = this.site;
107 | metadata.permalink = function(lang) { return site.docUrl(this.id, lang); }
108 |
109 | const found = this.sidebar_items
110 | .filter(item => item.id === metadata.id);
111 | if (found.length > 0) {
112 | const item = found[0];
113 | metadata.sidebar = item.sidebar;
114 | metadata.category = item.category;
115 |
116 | if (item.next) { metadata.next = item.next; }
117 | if (item.previous) { metadata.previous = item.previous; }
118 | }
119 |
120 | return metadata;
121 | }
122 |
123 | render(metadata, lang) {
124 | if (typeof metadata === 'string') { metadata = this.find(metadata); }
125 | if (!metadata) { return null; }
126 |
127 | const site = this.site;
128 | if (lang) {
129 | const doc = site.i18n.translateDoc(metadata.id, lang);
130 | if (doc) { metadata = doc; }
131 | }
132 | const content = this._replaceDocLinksWithFull(metadata.content);
133 |
134 | return renderToStaticMarkup(
135 |
136 | {content}
137 |
138 | );
139 | }
140 |
141 | _replaceDocLinksWithFull(content) {
142 | this.metadatas
143 | .map(metadata => ({
144 | source: metadata.source,
145 | url: this.site.docUrl(metadata.id)
146 | }))
147 | .forEach(entry => {
148 | content = content.replace(
149 | new RegExp('\\]\\((\\./)?' + entry.source, 'g'),
150 | '](' + entry.url
151 | );
152 | });
153 | return content;
154 | }
155 | }
156 |
157 | module.exports = Docs;
158 |
--------------------------------------------------------------------------------
/lib/core/Extractor.js:
--------------------------------------------------------------------------------
1 | class Extractor {
2 | extractMetadata(file_content) {
3 | const { header, content } = this.splitHeader(file_content);
4 | const metadata = { content: content };
5 | metadata.brief = this.extractBrief(content);
6 | header.split('\n')
7 | .forEach(line => {
8 | const parts = line.split(':');
9 | const key = parts[0].trim();
10 | let value = parts.slice(1).join(':').trim();
11 | try {
12 | value = JSON.parse(value);
13 | } catch(e) {}
14 | metadata[key] = value;
15 | });
16 | return metadata;
17 | }
18 |
19 | splitHeader(content) {
20 | const lines = content.split(/\r?\n/);
21 | if (lines[0] !== '---') { return { header: '', content: content }; }
22 |
23 | for (var i = 1; i < lines.length - 1; i++) {
24 | if (lines[i] === '---') {
25 | return {
26 | header: lines.slice(1, i + 1).join('\n'),
27 | content: lines.slice(i + 1).join('\n'),
28 | };
29 | }
30 | }
31 |
32 | return { header: '', content: content };
33 | }
34 |
35 | extractBrief(content) {
36 | if (!content) { return ''; }
37 |
38 | const splitBrief = content.split('');
39 | if (splitBrief.length > 1) {
40 | return splitBrief[0].replace(/<.+>/g, '').trim();
41 | }
42 |
43 | const lines = this.linesForBriefExtraction(content);
44 | let len = lines[0].length;
45 | let i = 1;
46 | for (; i < lines.length; i++) {
47 | len += lines[i].length;
48 | if (len > 128) { break; }
49 | }
50 |
51 | return lines.slice(0, i).join('\n').trim();
52 | }
53 |
54 | linesForBriefExtraction(content) {
55 | const lines = content.replace(/<.+>/g, '')
56 | .split(/\r?\n/);
57 | const result = [];
58 |
59 | let isCode = false;
60 | for (var i = 0; i < lines.length; i++) {
61 | const codeBoundary = lines[i].match(/```/);
62 | if (codeBoundary) {
63 | if (!isCode) { result.push('...'); }
64 | isCode = !isCode;
65 | continue;
66 | }
67 | if (isCode) { continue; }
68 |
69 | result.push(lines[i]);
70 | }
71 |
72 | return result;
73 | }
74 | }
75 |
76 | module.exports = Extractor;
77 |
--------------------------------------------------------------------------------
/lib/core/I18n.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const dfs = require('./dfs.js');
4 |
5 | const join = path.join;
6 |
7 | class I18n {
8 | constructor(site, rootPath) {
9 | this.site = site;
10 | this.rootPath = rootPath;
11 |
12 | this.loadLanguages();
13 | }
14 |
15 | hasTranslation() {
16 | return this.languages && Object.keys(this.languages).length > 0;
17 | }
18 |
19 | langs() {
20 | return this.languages
21 | ? Object.keys(this.languages)
22 | : [];
23 | }
24 |
25 | translate(phrase, lang, defVal) {
26 | let val = defVal || phrase;
27 | if (!phrase || !lang) { return val; }
28 | if (typeof phrase !== 'string') { return val; }
29 |
30 | const language = this.languages[lang];
31 | if (!language) { return val; }
32 |
33 | phrase = phrase.trim();
34 | if (!phrase) { return val; }
35 |
36 | return language.dictionary[phrase] || val;
37 | }
38 |
39 | translateDoc(id, lang) {
40 | if (!id) { return null; }
41 |
42 | const language = this.languages[lang];
43 | if (!language) { return null; }
44 |
45 | return language.docs[id] || null;
46 | }
47 |
48 | renderElement(el, lang) {
49 | if (!el) { return el; }
50 | if (typeof el === 'string') { return this.translate(el, lang); }
51 | return el;
52 | }
53 |
54 | loadLanguages() {
55 | this.languages = {};
56 |
57 | console.log('check i18n directories from ' + this.rootPath);
58 | dfs.directories(join(this.rootPath, '*'))
59 | .forEach(dir => {
60 | console.log(dir);
61 | //TODO: parse out lang then call loadLanguage(lang)
62 | const match = dir.replace(this.rootPath, '')
63 | .match(/.([a-zA-Z]{2})$/);
64 | if (match) { this.loadLanguage(match[1]); }
65 | });
66 |
67 | // Default language pages also needed to be generated, if i18n is on.
68 | const defLang = this.site.config.defaultLanguage || 'en';
69 | if (this.langs().length > 0 && !this.languages[defLang]) {
70 | this.languages[defLang] = {
71 | dictionary: {},
72 | docs: {}
73 | };
74 | }
75 | }
76 |
77 | loadLanguage(lang) {
78 | console.log('load language ' + lang);
79 | const langRoot = join(this.rootPath, lang);
80 | const langDocsRoot = join(langRoot, 'docs');
81 |
82 | const configFile = join(langRoot, 'langConfig.js');
83 | const language = {
84 | config: dfs.exists(configFile)? require(configFile) : { label: lang },
85 | dictionary: {},
86 | docs: {}
87 | };
88 | this.languages[lang] = language;
89 |
90 | // load translated docs
91 | const site = this.site;
92 | const docPaths = [];
93 | dfs.files(join(langDocsRoot, '**'), ['.md', '.markdown'])
94 | .forEach(file => {
95 | docPaths.push(file); // to be excluded from loading vocabularies
96 | const doc = site.docs.processMetadata(file);
97 | if (doc && doc.id) {
98 | language.docs[doc.id] = Object.assign({}, site.docs.find(doc.id), doc);
99 | }
100 | });
101 |
102 | // load vocabularies
103 | dfs.files(join(langRoot, '**'))
104 | .filter(file => !docPaths.includes(file))
105 | .filter(file => !file.endsWith('langConfig.js'))
106 | .forEach(file => {
107 | //TODO: load vocabularies from file
108 | const set = require(file);
109 | Object.assign(language.dictionary, set);
110 | });
111 | }
112 | }
113 |
114 | module.exports = I18n;
115 |
--------------------------------------------------------------------------------
/lib/core/Pages.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const React = require('react');
3 | const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
4 |
5 | const dfs = require('./dfs.js');
6 | const Page = require('./components/Page.js');
7 |
8 | const join = path.join;
9 |
10 | class Pages {
11 | constructor(site, rootPath) {
12 | this.site = site;
13 | this.rootPath = rootPath;
14 | }
15 |
16 | files() {
17 | return dfs.files(join(this.rootPath, '**'));
18 | }
19 |
20 | render(uri, lang) {
21 | let file = join(this.rootPath, uri);
22 | if (dfs.exists(file)) { return dfs.read(file); }
23 |
24 | file = file.replace(/\.html$/, '.js');
25 | if (!dfs.exists(file)) { return ''; }
26 |
27 | const site = this.site;
28 | const ReactComp = require(file);
29 | return renderToStaticMarkup(
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | module.exports = Pages;
38 |
--------------------------------------------------------------------------------
/lib/core/Search.js:
--------------------------------------------------------------------------------
1 | const algoliasearch = require('algoliasearch');
2 |
3 | class Search {
4 | constructor(site) {
5 | this.config = site.searchConfig
6 | if (!this.config) { return; }
7 |
8 | const { application_id, api_key, js } = this.config;
9 | if (!application_id || !api_key) { return; }
10 |
11 | this.client = algoliasearch(application_id, api_key);
12 |
13 | if (js) { // add js to config js
14 | site.config.js = (site.config.js || []).concat(js);
15 | }
16 | }
17 |
18 | getDocIndex() {
19 | if (!this.client) { return null; }
20 | if (!this.docIndex) {
21 | const index = this.client.initIndex('docs');
22 | const setting = {
23 | searchableAttributes: ['title', 'category', 'content']
24 | };
25 | index.setSettings(setting, function(err, content) {
26 | if (err) {
27 | console.log('set settings error', err);
28 | } else {
29 | console.log('set settings success', content);
30 | }
31 | });
32 | this.docIndex = index;
33 | }
34 | return this.docIndex;
35 | }
36 |
37 | addDoc(doc) {
38 | if (!this.client) { return; }
39 | if (!doc) { return; }
40 |
41 | const index = this.getDocIndex();
42 | const obj = {
43 | objectID: doc.id,
44 | title: doc.title,
45 | category: doc.category,
46 | permalink: doc.permalink(),
47 | brief: doc.brief,
48 | content: doc.content
49 | };
50 | index.addObject(obj, function(err, content) {
51 | if (err) {
52 | console.log('search not able to add doc ' + doc.id);
53 | } else {
54 | console.log('search successfully added doc ' + doc.id);
55 | }
56 | });
57 | }
58 | }
59 |
60 | module.exports = Search;
61 |
--------------------------------------------------------------------------------
/lib/core/components/AnalyticsScript.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const gascript = `
4 | window.dataLayer = window.dataLayer || [];
5 | function gtag(){dataLayer.push(arguments);}
6 | gtag('js', new Date());
7 |
8 | gtag('config', '$tracking_id$');
9 | `;
10 |
11 | class AnalyticsScript extends React.Component {
12 | render() {
13 | const { site } = this.props;
14 | const { analyticsConfig } = site;
15 | if (!analyticsConfig || !analyticsConfig.tracking_id) { return null; }
16 |
17 | const ga = gascript.replace('$tracking_id$', analyticsConfig.tracking_id);
18 | return (
19 |
20 | );
21 | }
22 | }
23 |
24 | module.exports = AnalyticsScript;
25 |
--------------------------------------------------------------------------------
/lib/core/components/Breadcrumb.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const CollapseIcon = require('./CollapseIcon.js');
4 |
5 | const Breadcrumb = (props) => {
6 | const { site, current, lang } = props;
7 | if (!current) { return null; }
8 |
9 | const { theme } = site;
10 | return (
11 |
12 |
13 | ›
14 | {site.i18n.translate(current.sidebar_label || current.title, lang)}
15 |
16 | );
17 | };
18 |
19 | module.exports = Breadcrumb;
20 |
--------------------------------------------------------------------------------
/lib/core/components/Button.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | class Button extends React.Component {
4 | render() {
5 | const { site, lang, style, href, target } = this.props;
6 | const theme = site.theme;
7 | const buttonStyle = Object.assign({}, theme.button, style);
8 | return (
9 |
10 | {site.i18n.renderElement(this.props.children, lang)}
11 |
12 | )
13 | }
14 | }
15 |
16 | Button.defaultProps = {
17 | target: '_self',
18 | };
19 |
20 | module.exports = Button;
21 |
--------------------------------------------------------------------------------
/lib/core/components/CollapseIcon.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const open = {
4 | box: {
5 | position: 'relative',
6 | height: '10px',
7 | width: '10px',
8 | display: 'inline-block',
9 | margin: '2px',
10 | marginRight: '12px'
11 | },
12 | upper: {
13 | position: 'absolute',
14 | top: '0',
15 | left: '2px',
16 | background: 'transparent',
17 | borderWidth: '0 5px 5px',
18 | borderStyle: 'solid',
19 | borderColor: 'transparent #2E8555',
20 | height: '0',
21 | opacity: '1',
22 | width: '5px',
23 | zIndex: '10'
24 | },
25 | lower: {
26 | position: 'absolute',
27 | top: '100%',
28 | left: '2px',
29 | background: 'transparent',
30 | borderWidth: '0 5px 5px',
31 | borderStyle: 'solid',
32 | borderColor: 'transparent #2E8555',
33 | height: '0',
34 | opacity: '1',
35 | width: '5px',
36 | zIndex: '10',
37 | transform: 'rotate(180deg)'
38 | },
39 | forward: {
40 | position: 'absolute',
41 | top: '0',
42 | left: '8px',
43 | width: '3px',
44 | height: '6px',
45 | border: '5px solid #2E8555',
46 | borderWidth: '5px 0',
47 | transform: 'rotate(45deg)',
48 | zIndex: '1'
49 | },
50 | backward: {
51 | position: 'absolute',
52 | top: '0',
53 | left: '8px',
54 | width: '3px',
55 | height: '6px',
56 | border: '5px solid #2E8555',
57 | borderWidth: '5px 0',
58 | transform: 'rotate(-45deg)',
59 | zIndex: '1'
60 | }
61 | };
62 |
63 | const close = {
64 | box: {
65 | position: 'relative',
66 | height: '10px',
67 | width: '10px',
68 | display: 'inline-block',
69 | margin: '2px',
70 | marginRight: '12px'
71 | },
72 | upper: {
73 | position: 'absolute',
74 | height: '0',
75 | width: '0'
76 | },
77 | lower: {
78 | position: 'absolute',
79 | height: '0',
80 | width: '0'
81 | },
82 | forward: {
83 | position: 'absolute',
84 | top: '0',
85 | left: '8px',
86 | width: '3px',
87 | height: '0',
88 | border: '5px solid #2E8555',
89 | borderWidth: '8px 0',
90 | transform: 'rotate(45deg)',
91 | zIndex: '1'
92 | },
93 | backward: {
94 | position: 'absolute',
95 | top: '0',
96 | left: '8px',
97 | width: '3px',
98 | height: '0',
99 | border: '5px solid #2E8555',
100 | borderWidth: '8px 0',
101 | transform: 'rotate(-45deg)',
102 | zIndex: '1'
103 | }
104 | };
105 |
106 | class CollapseIcon extends React.Component {
107 | render() {
108 | const { targetId } = this.props;
109 | const script = `
110 | var open = document.getElementById('collapse_open');
111 | var close = document.getElementById('collapse_close');
112 | open.onclick=function() {
113 | open.style.display = 'none';
114 | close.style.display = 'inline-block';
115 | var targetId = open.getAttribute('target_id');
116 | var targetEl = document.getElementById(targetId);
117 | if (targetEl) { targetEl.style.display = ''; }
118 | };
119 | close.onclick=function() {
120 | close.style.display = 'none';
121 | open.style.display = 'inline-block';
122 | var targetId = open.getAttribute('target_id');
123 | var targetEl = document.getElementById(targetId);
124 | if (targetEl) { targetEl.style.display = 'none'; }
125 | };
126 | `;
127 | const open_box_style = Object.assign({}, open.box, {display: 'none'});
128 | return (
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | )
145 | }
146 | }
147 |
148 | module.exports = CollapseIcon;
149 |
--------------------------------------------------------------------------------
/lib/core/components/Footer.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | class Footer extends React.Component {
4 | render() {
5 | const theme = this.props.site.theme;
6 | const currentYear = new Date().getFullYear();
7 | return (
8 |
15 | );
16 | }
17 | }
18 |
19 | module.exports = Footer;
20 |
--------------------------------------------------------------------------------
/lib/core/components/Head.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const async_script = '';
4 |
5 | class Head extends React.Component {
6 | render() {
7 | const { site, title, url, description, ogImage, redirect } = this.props;
8 | const { config } = site;
9 |
10 | const keywords = config.keywords || 'Open Source Documentation Dochameleon';
11 | const author = config.author || 'Dochameleon.io';
12 | let img_src = site.icon? site.urlWithRoot(site.icon) : '';
13 | if (config.ogImage) { img_src = site.urlWithRoot(config.ogImage); }
14 | if (ogImage) { img_src = site.urlWithRoot(ogImage); }
15 |
16 | return (
17 |
18 |
19 |
20 | {title}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | { img_src && }
31 | {config.noIndex && }
32 | {redirect && (
33 |
43 | )}
44 | {!site.blog.isEmpty() && (
45 |
51 | )}
52 |
53 | {
54 | config.css &&
55 | config.css.map((source, idx) => (
56 |
57 | ))
58 | }
59 | {
60 | config.js &&
61 | config.js.map((source, idx) => {
62 | const src = (typeof source === 'string')? source : source.src;
63 | return source.async
64 | ?
65 | :
66 | })
67 | }
68 |
69 | );
70 | }
71 | }
72 |
73 | module.exports = Head;
74 |
--------------------------------------------------------------------------------
/lib/core/components/HeaderNav.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Div, Ul, A, Row, Col } = require('fluid-react');
3 | const path = require('path');
4 |
5 | const dfs = require('../dfs.js');
6 | const HeaderNavItem = require('./HeaderNavItem.js');
7 | const headerLinks = dfs.exists(path.join(__dirname, 'headerLinks.json'))
8 | ? require('./headerLinks.json')
9 | : [];
10 |
11 | class HeaderNav extends React.Component {
12 | render() {
13 | const { site, lang } = this.props;
14 | const { config, theme } = site;
15 |
16 | const home_url = site.url('/', lang);
17 | const title = site.i18n.translate(config.title, lang);
18 | return (
19 |
20 |
21 |
22 | {site.icon &&
}
23 | {!site.config.noHeaderTitle && {title}
}
24 |
25 |
26 |
27 |
28 | {headerLinks.map((link, index) => (
29 |
35 | ))}
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
43 | module.exports = HeaderNav;
44 |
--------------------------------------------------------------------------------
/lib/core/components/HeaderNavItem.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Li, A } = require('fluid-react');
3 |
4 | const SearchBox = require('./SearchBox.js');
5 |
6 | const HeaderNavItem = (props) => {
7 | const { site, lang, link } = props;
8 | const { theme } = site;
9 |
10 | if (link.type === 'search') {
11 | return site.searchConfig && site.searchConfig.application_id
12 | ?
13 | : null
14 | }
15 |
16 | let href = link.value;
17 | switch(link.type) {
18 | case 'doc':
19 | let doc_id = link.value;
20 | if (!doc_id && site.docs.metadatas.length > 0) {
21 | doc_id = site.docs.metadatas[0].id;
22 | }
23 | href = site.docUrl(doc_id, lang);
24 | break;
25 | case 'page':
26 | href = site.pageUrl(link.value, lang);
27 | break;
28 | case 'blog':
29 | href = site.url('/blog/', lang);
30 | break;
31 | }
32 | const label = site.i18n.translate(link.label, lang);
33 |
34 | return (
35 |
36 |
37 | {link.img
38 | ?
39 | : label
40 | }
41 |
42 |
43 | )
44 | };
45 |
46 | module.exports = HeaderNavItem;
47 |
--------------------------------------------------------------------------------
/lib/core/components/MarkdownBlock.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const MarkdownBlock = props => {
4 | const { site, lang } = props;
5 | const html = site.parser.markdownToHtml(props.children, lang);
6 | return
7 | }
8 |
9 | module.exports = MarkdownBlock;
10 |
--------------------------------------------------------------------------------
/lib/core/components/Page.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Div } = require('fluid-react');
3 | const { JS } = require('fsts');
4 |
5 | const Head = require('./Head.js');
6 | const HeaderNav = require('./HeaderNav.js');
7 | const Footer = require('./Footer.js');
8 | const AnalyticsScript = require('./AnalyticsScript.js');
9 |
10 | class Page extends React.Component {
11 | render() {
12 | const { site, lang, title } = this.props;
13 | const { config, theme } = site;
14 |
15 | const tagline = site.i18n.translate(config.tagline, lang);
16 | const configTitle = site.i18n.translate(config.title, lang);
17 | const pageTitle = title
18 | ? [site.i18n.translate(title), configTitle].join(' . ')
19 | : [configTitle, tagline].join(' . ');
20 | const description = this.props.description || tagline;
21 | const url = this.props.url || site.url('index.html');
22 |
23 | let resetCss = '';
24 | if (theme.reset) {
25 | resetCss = Object.keys(theme.reset)
26 | .map(key => key + JS.styleToCss(theme.reset[key]))
27 | .join('');
28 | }
29 |
30 | const render_children = React.Children.map(this.props.children, child => {
31 | return React.cloneElement(child, { lang: lang });
32 | });
33 |
34 | return (
35 |
36 |
37 |
38 |
39 |
40 | { !config.noHeaderNav && }
41 |
42 | {render_children}
43 |
44 |
45 |
46 |
47 | );
48 | }
49 | }
50 |
51 | module.exports = Page;
52 |
--------------------------------------------------------------------------------
/lib/core/components/README.md:
--------------------------------------------------------------------------------
1 | ### Test README
2 |
--------------------------------------------------------------------------------
/lib/core/components/SearchBox.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Div, Ul, Input, Img } = require('fluid-react');
3 |
4 | const searchJs = `
5 | var client = algoliasearch('$application_id$', '$search_api_key$');
6 | var index = client.initIndex('$index_name$');
7 |
8 | var itemStyle = $itemStyle$;
9 | var footerStyle = $footerStyle$;
10 | var logoSrc = '$logoSrc$';
11 |
12 | var elWithStyle = function(tag, style) {
13 | const el = document.createElement(tag);
14 | if (style) {
15 | Object.keys(style)
16 | .filter(key => !['title', 'description', 'search_by', 'logo'].includes(key))
17 | .forEach(key => el.style[key] = style[key]);
18 | }
19 | return el;
20 | };
21 |
22 | var init = function() {
23 | box.addEventListener('keyup', function(evt) {
24 | if (evt.key === 'Escape') {
25 | box.value = '';
26 | list.style.display = 'none';
27 | } else {
28 | search();
29 | }
30 | });
31 | }
32 |
33 | var search = function() {
34 | var term = box.value.trim();
35 | if (!term) {
36 | list.style.display = 'none';
37 | return;
38 | }
39 |
40 | index.search({ query: term }, function(err, content) {
41 | if (err) { return console.log(err); }
42 |
43 | while (list.children.length > 0) { list.removeChild(list.children[0]); }
44 |
45 | if (content.nbHits === 0) {
46 | list.style.display = 'none';
47 | return;
48 | }
49 |
50 | list.style.display = 'block';
51 | content.hits.forEach(hit => {
52 | const item = elWithStyle('li', itemStyle);
53 | list.appendChild(item);
54 |
55 | const title = elWithStyle('a', itemStyle.title);
56 | title.href = hit.permalink;
57 | title.innerHTML = hit.title;
58 | item.appendChild(title);
59 |
60 | const description = elWithStyle('div', itemStyle.description);
61 | description.innerHTML = hit.brief;
62 | item.appendChild(description);
63 | });
64 |
65 | const footer = elWithStyle('li', footerStyle);
66 | list.appendChild(footer);
67 | const search_by = elWithStyle('span', footerStyle.search_by);
68 | search_by.innerHTML = 'search by';
69 | footer.appendChild(search_by);
70 | const logo = elWithStyle('img', footerStyle.logo);
71 | logo.src = logoSrc;
72 | footer.appendChild(logo);
73 | });
74 | }
75 |
76 | var box = document.getElementById('doc_search');
77 | var list = document.getElementById('doc_search_list');
78 |
79 | box.addEventListener('focus', search);
80 |
81 | init();
82 | `
83 |
84 | class SearchBox extends React.Component {
85 | render() {
86 | const { site } = this.props;
87 | const { searchConfig } = site;
88 | const theme = site.theme.search;
89 | const itemStyle = theme.item || {};
90 | const footerStyle = theme.footer || {};
91 | const js = searchJs.replace('$application_id$', searchConfig.application_id)
92 | .replace('$search_api_key$', searchConfig.search_api_key)
93 | .replace('$index_name$', 'docs')
94 | .replace('$itemStyle$', JSON.stringify(itemStyle))
95 | .replace('$footerStyle$', JSON.stringify(footerStyle))
96 | .replace('$logoSrc$', site.url('img/algolia.svg'));
97 | return (
98 |
103 | )
104 | }
105 | }
106 |
107 | module.exports = SearchBox;
108 |
--------------------------------------------------------------------------------
/lib/core/components/SideNav.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const Breadcrumb = require('./Breadcrumb.js');
4 | const SideNavCategory = require('./SideNavCategory.js');
5 |
6 | class SideNav extends React.Component {
7 | render() {
8 | const { site, sidebar, current, lang } = this.props;
9 | const { theme } = site;
10 |
11 | return (
12 |
13 |
14 |
26 |
27 | );
28 | }
29 | }
30 |
31 | module.exports = SideNav;
32 |
--------------------------------------------------------------------------------
/lib/core/components/SideNavCategory.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const SideNavItem = require('./SideNavItem.js');
4 |
5 | const SideNavCategory = (props) => {
6 | const { site, name, items, current, lang } = props;
7 | const { theme } = site;
8 | return (
9 |
10 |
{site.i18n.translate(name, lang)}
11 |
12 | {items.map(item => (
13 |
20 | ))}
21 |
22 |
23 | );
24 | };
25 |
26 | module.exports = SideNavCategory;
27 |
--------------------------------------------------------------------------------
/lib/core/components/SideNavItem.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const SideNavItem = (props) => {
4 | const { site, item, current, lang } = props;
5 | const { theme } = site;
6 | const active = current && current.id === item.id;
7 | let linkStyle = theme.sideNavItemLink;
8 | if (current && current.id === item.id) {
9 | linkStyle = Object.assign({}, linkStyle, theme.sideNavItemLinkActive);
10 | }
11 | return (
12 |
13 |
14 | {site.i18n.translate(item.sidebar_label || item.title, lang)}
15 |
16 |
17 | );
18 | };
19 |
20 | module.exports = SideNavItem;
21 |
--------------------------------------------------------------------------------
/lib/core/components/blog/BlogPageLayout.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Row, Col } = require('fluid-react');
3 |
4 | const Page = require('../Page.js');
5 | const BlogPost = require('./BlogPost.js');
6 | const BlogSidebar = require('./BlogSidebar.js');
7 |
8 | class BlogPageLayout extends React.Component {
9 | render() {
10 | const { site, posts, previous, next, lang } = this.props;
11 | const { theme } = site;
12 | const postComps = posts.map(post => (
13 |
20 | ));
21 | return (
22 |
23 |
24 |
25 |
26 |
27 |
28 | {postComps}
29 |
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | module.exports = BlogPageLayout;
42 |
--------------------------------------------------------------------------------
/lib/core/components/blog/BlogPost.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const social = require('./social.js');
4 | const MarkdownBlock = require('../MarkdownBlock.js');
5 |
6 | const Author = props => {
7 | const { site, post, lang } = props;
8 | if (!post.author) { return null; }
9 |
10 | let author = {};
11 | if (post.authorGitHub) {
12 | Object.assign(author, social.gitHubUser(post.authorGitHub));
13 | }
14 | if (post.authorFBID) {
15 | Object.assign(author, social.facebookUser(post.authorFBID));
16 | }
17 | if (post.authorTwitter) {
18 | Object.assign(author, social.twitterUser(post.authorTwitter));
19 | }
20 | author.name = post.author;
21 | author.title = post.authorTitle;
22 | if (post.authorUrl) { author.url = post.authorUrl }
23 | if (post.authorImage) { author.image = post.authorImage }
24 |
25 | const theme = site.theme.blog;
26 | return (
27 |
28 |
34 | {author.image &&
35 |
36 |

37 |
38 | }
39 |
40 | );
41 | }
42 |
43 | const PostHeader = props => {
44 | const { site, post, url, lang } = props;
45 | const theme = site.theme.blog;
46 | return (
47 |
48 |
53 | {post.dtStr}
54 |
55 |
56 | );
57 | }
58 |
59 | const PostContent = props => {
60 | const { post, site, truncate, url, lang } = props;
61 | const theme = site.theme.blog;
62 | if (!truncate) { return {post.content} }
63 |
64 | return (
65 |
66 | {post.brief}
67 | {post.brief !== post.content && (
68 |
71 | )}
72 |
73 | )
74 | }
75 |
76 | class BlogPost extends React.Component {
77 | render() {
78 | const { site, post, truncate, lang } = this.props;
79 | const theme = site.theme.blog;
80 | return (
81 |
85 | );
86 | }
87 | }
88 |
89 | module.exports = BlogPost;
90 |
--------------------------------------------------------------------------------
/lib/core/components/blog/BlogPostLayout.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Row, Col } = require('fluid-react');
3 |
4 | const Page = require('../Page.js');
5 | const Button = require('../Button.js');
6 | const BlogPost = require('./BlogPost.js');
7 | const BlogSidebar = require('./BlogSidebar.js');
8 |
9 | class BlogPostLayout extends React.Component {
10 | render() {
11 | const { site, post, recent, lang } = this.props;
12 | const { theme } = site;
13 | const url = site.urlWithRoot(site.blogUrl(post.path, lang));
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 | }
34 |
35 | module.exports = BlogPostLayout;
36 |
--------------------------------------------------------------------------------
/lib/core/components/blog/BlogSidebar.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const SideNav = require('../SideNav.js');
4 |
5 | class BlogSidebar extends React.Component {
6 | render() {
7 | const { site, metadatas, current, lang } = this.props;
8 | const sidebar = {
9 | 'Recent Posts': metadatas
10 | };
11 | return
12 | }
13 | }
14 |
15 | module.exports = BlogSidebar;
16 |
--------------------------------------------------------------------------------
/lib/core/components/blog/social.js:
--------------------------------------------------------------------------------
1 | const gitHubUser = username => {
2 | return {
3 | url: 'https://github.com/' + username,
4 | image: 'https://github.com/' + username + '.png'
5 | }
6 | }
7 |
8 | const facebookUser = FBID => {
9 | return {
10 | url: 'https://www.facebook.com/' + FBID,
11 | image: 'https://graph.facebook.com/' + FBID + '/picture/?height=200&width=200'
12 | }
13 | }
14 |
15 | const twitterUser = screenName => {
16 | return {
17 | url: 'https://twitter.com/' + screenName,
18 | image: 'https://twitter.com/' + screenName + '/profile_image?size=original'
19 | }
20 | }
21 |
22 | module.exports = {
23 | gitHubUser,
24 | facebookUser,
25 | twitterUser
26 | }
27 |
--------------------------------------------------------------------------------
/lib/core/components/docs/Doc.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const MarkdownBlock = require('../MarkdownBlock.js');
4 |
5 | class Doc extends React.Component {
6 | render() {
7 | const { site, lang, title } = this.props;
8 | const { theme } = site;
9 |
10 | return (
11 |
12 | { title && (
13 |
14 | {site.i18n.translate(title, lang)}
15 |
16 | )
17 | }
18 |
19 | {this.props.children}
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | module.exports = Doc;
27 |
--------------------------------------------------------------------------------
/lib/core/components/docs/DocsLayout.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Row, Col } = require('fluid-react');
3 |
4 | const Page = require('../Page.js');
5 | const Button = require('../Button.js');
6 | const Doc = require('./Doc.js');
7 | const DocsSidebar = require('./DocsSidebar.js');
8 |
9 | const PrevNext = props => {
10 | const { site, metadata, lang } = props;
11 | const { theme } = site;
12 | if (!metadata.previous && !metadata.next) { return null; }
13 |
14 | return (
15 |
16 | {metadata.previous && (
17 |
20 | )}
21 |
22 | {metadata.next && (
23 |
26 | )}
27 |
28 | )
29 | }
30 |
31 | class DocsLayout extends React.Component {
32 | render() {
33 | const { site, metadata, lang } = this.props;
34 | const { theme } = site;
35 | const { title, brief } = metadata;
36 | const content = this.props.children;
37 | const url = site.urlWithRoot(site.docUrl(metadata.id));
38 |
39 | return (
40 |
41 |
42 | { metadata.sidebar
43 | ? (
44 |
45 |
46 |
47 |
48 |
49 | {content}
50 |
51 |
52 |
53 | )
54 | : (
55 |
56 | {content}
57 |
58 |
59 | )
60 | }
61 |
62 |
63 | );
64 | }
65 | }
66 | module.exports = DocsLayout;
67 |
--------------------------------------------------------------------------------
/lib/core/components/docs/DocsSidebar.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const SideNav = require('../SideNav.js');
4 |
5 | class DocsSidebar extends React.Component {
6 | render() {
7 | const { site, metadata, lang } = this.props;
8 | const { sidebar } = metadata;
9 | if (!sidebar) { return null; }
10 |
11 | const expand_sidebar = {};
12 | Object.keys(sidebar)
13 | .forEach(category => {
14 | expand_sidebar[category] = sidebar[category]
15 | .map(item => site.docs.find(item))
16 | .filter(metadata => !!metadata);
17 | });
18 |
19 | return (
20 |
26 | );
27 | }
28 | }
29 |
30 | module.exports = DocsSidebar;
31 |
--------------------------------------------------------------------------------
/lib/core/components/headerLinks.json:
--------------------------------------------------------------------------------
1 | [
2 | { "type": "doc", "label": "Docs" },
3 | { "type": "blog", "label": "Blog" },
4 | { "type": "search" }
5 | ]
6 |
--------------------------------------------------------------------------------
/lib/core/components/toSlug.js:
--------------------------------------------------------------------------------
1 | module.exports = string => {
2 | // var accents = "àáäâèéëêìíïîòóöôùúüûñç";
3 | const accents =
4 | '\u00e0\u00e1\u00e4\u00e2\u00e8' +
5 | '\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef' +
6 | '\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9' +
7 | '\u00fa\u00fc\u00fb\u00f1\u00e7';
8 |
9 | const without = 'aaaaeeeeiiiioooouuuunc';
10 |
11 | let slug = string
12 | .toString()
13 | .toLowerCase()
14 | // Handle accentuated characters
15 | .replace(new RegExp('[' + accents + ']', 'g'), c => {
16 | return without.charAt(accents.indexOf(c));
17 | })
18 | // Replace `.`, `(` and `?` with blank string like Github does
19 | .replace(/\.|\(|\?/g, '')
20 | .replace(/[^a-z0-9]/g, '-')
21 | .replace(/-+/g, '-')
22 | .replace(/^-|-$/g, '');
23 |
24 | // Add trailing `-` if string contains ` ...` in the end like Github does
25 | if (/\s[.]{1,}/.test(string)) {
26 | slug += '-';
27 | }
28 |
29 | return slug;
30 | };
31 |
--------------------------------------------------------------------------------
/lib/core/dfs.js:
--------------------------------------------------------------------------------
1 | /** Dochameleon File System */
2 |
3 | const fs = require('fs-extra');
4 | const glob = require('glob');
5 | const path = require('path');
6 |
7 | function directories(pattern) {
8 | return glob.sync(pattern, { dot: true })
9 | .filter(file => fs.lstatSync(file).isDirectory());
10 | }
11 |
12 | function files(pattern, ext) {
13 | return glob.sync(pattern, { dot: true })
14 | .filter(file => {
15 | if (fs.lstatSync(file).isDirectory()) { return false; }
16 | if (!ext) { return true; }
17 | let file_ext = path.extname(file);
18 | if (typeof ext === 'string') { return ext === file_ext; }
19 | return ext.includes(file_ext);
20 | });
21 | }
22 |
23 | function exists(file) {
24 | return fs.existsSync(file);
25 | }
26 |
27 | function read(file) {
28 | if (!fs.existsSync(file)) { return ''; }
29 |
30 | return fs.readFileSync(file, { encoding: 'utf8' });
31 | }
32 |
33 | function remove(file) {
34 | fs.removeSync(file);
35 | }
36 |
37 | function write(file, content) {
38 | fs.mkdirsSync(file.replace(new RegExp('/[^/]*$'), ''));
39 | fs.writeFileSync(file, content);
40 | }
41 |
42 | function copy(src, dest) {
43 | fs.mkdirsSync(dest.replace(new RegExp('/[^/]*$'), ''));
44 | fs.copySync(src, dest);
45 | }
46 |
47 | module.exports = {
48 | directories,
49 | files,
50 | exists,
51 | read,
52 | remove,
53 | write,
54 | copy
55 | }
56 |
--------------------------------------------------------------------------------
/lib/core/generate.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const join = path.join;
4 |
5 | const dfs = require('./dfs.js');
6 | const Site = require('./site.js');
7 |
8 | function generate(buildDir, site, lang) {
9 | const targetDir = join(buildDir, lang || '');
10 | // docs
11 | site.docs.metadatas.forEach(metadata => {
12 | dfs.write(
13 | join(targetDir, 'docs', metadata.path),
14 | site.docs.render(metadata, lang)
15 | );
16 | });
17 |
18 | // copy docs assets if they exist
19 | const stage_docs_assets = join(site.stageRoot, 'docs', 'assets');
20 | if (dfs.exists(stage_docs_assets)) {
21 | dfs.copy(stage_docs_assets, join(targetDir, 'docs', 'assets'));
22 | }
23 |
24 | // blog
25 | site.blog.metadatas.forEach(metadata => {
26 | dfs.write(
27 | join(targetDir, 'blog', metadata.path),
28 | site.blog.render(metadata, lang)
29 | );
30 | });
31 |
32 | // blog index
33 | const pageSize = 10;
34 | for (var i = 0; i < site.blog.metadatas.length; i += pageSize) {
35 | const pageNumber = Math.floor(i / pageSize) + 1;
36 | const content = site.blog.renderPage(pageNumber, pageSize, lang);
37 | dfs.write(
38 | join(targetDir, 'blog', 'page' + pageNumber, 'index.html'),
39 | content
40 | );
41 | if (pageNumber === 1) {
42 | dfs.write(
43 | join(targetDir, 'blog', 'index.html'),
44 | content
45 | );
46 | }
47 | }
48 |
49 | // copy blog assets if they exist
50 | const stage_blog_assets = join(site.stageRoot, 'blog', 'assets');
51 | if (dfs.exists(stage_blog_assets)) {
52 | dfs.copy(stage_blog_assets, join(targetDir, 'blog', 'assets'));
53 | }
54 |
55 | // pages
56 | site.pages.files()
57 | .forEach(file => {
58 | if (file.match(/\.js$/)) {
59 | const uri = file.replace(site.pages.rootPath, '')
60 | .replace(/\.js$/, '.html');
61 | dfs.write(join(targetDir, uri), site.pages.render(uri, lang));
62 | return;
63 | }
64 |
65 | const targetFile = join(targetDir, file.split('pages')[1]);
66 | dfs.copy(file, targetFile);
67 | });
68 | }
69 |
70 | function execute() {
71 | const CWD = process.cwd();
72 |
73 | const siteConfig = require(CWD + '/siteConfig.js');
74 | const site = new Site(siteConfig);
75 |
76 | console.log('generate.js triggered...');
77 |
78 | const buildDir = siteConfig.buildDir
79 | ? join(CWD, siteConfig.buildDir)
80 | : join(CWD, 'build', siteConfig.projectName);
81 | console.log('destination folder: ' + buildDir);
82 |
83 | dfs.remove(buildDir);
84 |
85 | generate(buildDir, site);
86 | const languages = site.i18n.langs();
87 | if (languages) {
88 | languages.forEach(language => generate(buildDir, site, language));
89 | }
90 |
91 | // put back docs assets if building to GitHub repo docs folder,
92 | // i.e. dir ends with '/docs'
93 | if (buildDir.match(/[\\/]docs[\\/]?$/)) {
94 | const stage_docs_assets = join(site.stageRoot, 'docs', 'assets');
95 | if (dfs.exists(stage_docs_assets)) {
96 | dfs.copy(stage_docs_assets, join(buildDir, 'assets'));
97 | }
98 | }
99 |
100 | // blog feed
101 | if (site.blog.metadatas.length > 0) {
102 | dfs.write(
103 | join(buildDir, 'blog', 'feed.xml'),
104 | site.blog.feed('rss')
105 | );
106 | dfs.write(
107 | join(buildDir, 'blog', 'atom.xml'),
108 | site.blog.feed('atom')
109 | );
110 | }
111 |
112 | // create sitemap
113 | site.assets.sitemap(siteConfig)
114 | .then(xml => dfs.write(join(buildDir, 'sitemap.xml'), xml));
115 |
116 | // copy all static files
117 | site.assets.staticFiles()
118 | .forEach(file => {
119 | let parts = file.split('/static/');
120 | let targetFile = join(buildDir, parts[1]);
121 | dfs.copy(file, targetFile);
122 | });
123 |
124 | // Search Indexing
125 | site.docs.metadatas.forEach(metadata => {
126 | site.search.addDoc(metadata);
127 | });
128 |
129 | // Generate CNAME file if a custom domain is specified in siteConfig
130 | if (siteConfig.cname) {
131 | dfs.write(join(buildDir, 'CNAME'), siteConfig.cname);
132 | }
133 | }
134 |
135 | module.exports = execute;
136 |
--------------------------------------------------------------------------------
/lib/core/pages/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | Dochameleon generates readme.html from README.md. By default it looks up from `../README.md`. You may also copy your file into `website/pages` folder.
4 |
5 | If wanted to have README as index file, copy `pages/readme.js` from core library to your `website/pages/index.js`
6 |
--------------------------------------------------------------------------------
/lib/core/pages/readme.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const path = require('path');
3 |
4 | const dfs = require('../dfs.js');
5 |
6 | const Doc = require('../components/docs/Doc.js');
7 |
8 | const join = path.join;
9 |
10 | class ReadMe extends React.Component {
11 | render() {
12 | const { site, lang } = this.props;
13 |
14 | let readme_path = join(__dirname, './README.md');
15 | const doc = site.docs.processMetadata(readme_path);
16 | return (
17 |
18 |
19 | {doc.content}
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | module.exports = ReadMe;
27 |
--------------------------------------------------------------------------------
/lib/core/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const request = require('request');
3 | const path = require('path');
4 |
5 | const Site = require('./site.js');
6 |
7 | function execute(port) {
8 | const CWD = process.cwd();
9 | const join = path.join;
10 |
11 | const siteConfig = require(join(CWD, 'siteConfig.js'));
12 | const site = new Site(siteConfig);
13 |
14 | const app = express();
15 |
16 | app.get(/docs\/.*html$/, (req, res, next) => {
17 | let uri = req.path.toString();
18 | let lang = '';
19 | const i18nMatch = uri.match(/\/([a-zA-Z]{2})(\/docs\/.+)/);
20 | if (i18nMatch) {
21 | lang = i18nMatch[1];
22 | uri = i18nMatch[2];
23 | }
24 |
25 | const metadata = site.docs.findByUri(uri);
26 | if (metadata) {
27 | res.send(site.docs.render(metadata, lang));
28 | } else {
29 | next();
30 | }
31 | });
32 |
33 | app.get('/sitemap.xml', function(req, res) {
34 | site.assets.sitemap(siteConfig)
35 | .then(xml => {
36 | res.set('Content-Type', 'application/xml');
37 | res.send(xml);
38 | })
39 | .catch(err => {
40 | res.send(err);
41 | });
42 | });
43 |
44 | app.get(/blog\/.*xml$/, (req, res) => {
45 | const type = req.path.toString().match(/atom\.xml$/) ? 'atom' : 'rss';
46 | res.set('Content-Type', 'application/rss+xml');
47 | res.send(site.blog.feed(type));
48 | });
49 |
50 | app.get(/blog\/.*html$/, (req, res, next) => {
51 | let uri = req.path.toString();
52 | let lang = '';
53 | const i18nMatch = uri.match(/\/([a-zA-Z]{2})\/blog\/(.+)/);
54 | if (i18nMatch) {
55 | lang = i18nMatch[1];
56 | uri = i18nMatch[2];
57 | } else {
58 | uri = uri.split('/blog/')[1];
59 | }
60 |
61 | if (uri === 'index.html') {
62 | res.send(site.blog.renderPage(1, 10, lang));
63 | } else {
64 | res.send(site.blog.render(uri, lang));
65 | }
66 | });
67 |
68 | app.get('*.html', (req, res, next) => {
69 | let uri = req.path.toString().replace(siteConfig.baseUrl, '');
70 | if (uri.startsWith('/')) { uri = uri.substring(1); }
71 |
72 | let lang = '';
73 | const i18nMatch = uri.match(/^([a-zA-Z]{2})(\/.+)/);
74 | if (i18nMatch) {
75 | lang = i18nMatch[1];
76 | uri = i18nMatch[2];
77 | }
78 |
79 | const html = site.pages.render(uri, lang);
80 | if (html) {
81 | res.send(html);
82 | } else {
83 | next();
84 | }
85 | });
86 |
87 | // serve static assets from these locations
88 | app.use(
89 | site.url('/docs/assets'),
90 | express.static(join(site.stageRoot, 'docs', 'assets'))
91 | );
92 | app.use(
93 | site.url('/[a-zA-Z]{2}/docs/assets'),
94 | express.static(join(site.stageRoot, 'docs', 'assets'))
95 | );
96 | app.use(
97 | site.url('/blog/assets'),
98 | express.static(join(site.stageRoot, 'blog', 'assets'))
99 | );
100 | app.use(
101 | site.url('/[a-zA-Z]{2}/blog/assets'),
102 | express.static(join(site.stageRoot, 'blog', 'assets'))
103 | );
104 | app.use(
105 | site.url(''),
106 | express.static(join(site.stageRoot, 'static'))
107 | );
108 |
109 | // "redirect" requests to pages ending with "/" or no extension so that
110 | // request to "...blog" returns same result as "...blog/index.html"
111 | app.get(/\/[^\.]*\/?$/, (req, res) => {
112 | let path = req.path.toString();
113 | if (!path.endsWith('/')) { path = path + '/'; }
114 | request.get(
115 | 'http://localhost:' + port + path + 'index.html',
116 | (err, response, body) => {
117 | if (!err) { res.send(body); }
118 | }
119 | );
120 | });
121 |
122 | app.listen(port);
123 | console.log('Open http://localhost:' + port + '/');
124 | }
125 |
126 | module.exports = execute;
127 |
--------------------------------------------------------------------------------
/lib/core/theme/blog.js:
--------------------------------------------------------------------------------
1 | const color = require('./color.js');
2 |
3 | const BlogTheme = { blog: {
4 | post: {
5 | padding: '20px'
6 | },
7 | title: {
8 | color: color.title,
9 | fontWeight: 300,
10 | fontSize: '200%',
11 | lineHeight: '1em'
12 | },
13 | titleLink: {
14 | color: color.title
15 | },
16 | authorBlock: {
17 | display: 'flex'
18 | },
19 | authorName: {
20 | paddingTop: '5px'
21 | },
22 | authorNameLink: {
23 | color: color.title
24 | },
25 | authorImgContainer: {
26 | marginLeft: '0.5em',
27 | width: '30px',
28 | height: '30px',
29 | borderRadius: '50%',
30 | overflow: 'hidden'
31 | },
32 | readMore: {
33 | marginTop: '0.5em'
34 | }
35 | }};
36 |
37 | module.exports = BlogTheme;
38 |
--------------------------------------------------------------------------------
/lib/core/theme/color.js:
--------------------------------------------------------------------------------
1 | const color = {
2 | primary: '#2E8555',
3 | secondary: '#205C3B',
4 | tertiary: '#e0e0e0',
5 | font: '#393939',
6 | fontSecondary: '#000'
7 | };
8 |
9 | color.title = color.primary;
10 | color.content = color.font;
11 | color.contentSecondary = color.fontSecondary;
12 | color.clickable = color.primary;
13 |
14 | color.nav = {
15 | primary: color.primary,
16 | secondary: color.secondary,
17 | tertiary: color.tertiary,
18 | font: '#fff',
19 | fontSecondary: 'rgba(255, 255, 255, 0.8)',
20 | fontTertiary: 'rgba(255, 255, 255, 0.6)',
21 | };
22 |
23 | color.footer = '#808080';
24 |
25 | module.exports = color;
26 |
--------------------------------------------------------------------------------
/lib/core/theme/markdown.js:
--------------------------------------------------------------------------------
1 | const color = require('./color.js');
2 |
3 | const MarkdownTheme = { md: {
4 | h1: {
5 | textAlign: 'left',
6 | marginTop: '0.5em',
7 | color: color.title,
8 | fontWeight: 300,
9 | fontSize: '200%',
10 | lineHeight: '1.2em'
11 | },
12 | h2: {
13 | textAlign: 'left',
14 | marginTop: '0.5em',
15 | color: color.title,
16 | fontWeight: 300,
17 | fontSize: '180%',
18 | lineHeight: '1.2em'
19 | },
20 | h3: {
21 | textAlign: 'left',
22 | marginTop: '0.5em',
23 | color: color.title,
24 | fontWeight: 300,
25 | fontSize: '150%',
26 | lineHeight: '1.2em'
27 | },
28 | h4: {
29 | textAlign: 'left',
30 | marginTop: '0.5em',
31 | color: color.content,
32 | fontWeight: 300,
33 | fontSize: '120%',
34 | lineHeight: '1.2em'
35 | },
36 | h5: {
37 | textAlign: 'left',
38 | marginTop: '0.5em',
39 | color: color.content,
40 | fontWeight: 300,
41 | fontSize: '100%',
42 | lineHeight: '1.2em'
43 | },
44 | h6: {
45 | textAlign: 'left',
46 | marginTop: '0.5em',
47 | color: color.contentSecondary,
48 | fontWeight: 300,
49 | fontSize: '100%',
50 | lineHeight: '1.2em'
51 | },
52 | p: {
53 | lineHeight: '1.5em',
54 | color: color.content,
55 | paddingTop: '10px',
56 | wordWrap: 'break-word'
57 | },
58 | ul: {
59 | padding: '5px 20px'
60 | },
61 | ol: {
62 | padding: '5px 20px'
63 | },
64 | li_p: {
65 | lineHeight: '1.5em',
66 | color: color.content,
67 | wordWrap: 'break-word'
68 | },
69 | fence: {
70 | fontFamily: `
71 | "SFMono-Regular",
72 | source-code-pro,
73 | Menlo,
74 | Monaco,
75 | Consolas,
76 | "Roboto Mono",
77 | "Droid Sans Mono",
78 | "Liberation Mono",
79 | Consolas,
80 | "Courier New",
81 | Courier,
82 | monospace`,
83 | display: 'block',
84 | margin: '20px 0',
85 | padding: '0.5em',
86 | borderLeft: '4px solid ' + color.primary,
87 | borderRadius: '0.3em',
88 | fontSize: '0.8em',
89 | wordBreak: 'break-word',
90 | overflowX: 'auto',
91 | lineHeight: '1.5em'
92 | },
93 | code: {
94 | padding: '0.2em 0.4em',
95 | background: color.tertiary,
96 | fontSize: '85%',
97 | borderRadius: '3px'
98 | },
99 | anchor: {
100 | display: 'block',
101 | position: 'relative',
102 | top: '-100px'
103 | },
104 | table: {
105 | display: 'block',
106 | width: '100%',
107 | overflow: 'auto',
108 | marginTop: '10px',
109 | marginBottom: '10px',
110 | borderSpacing: '0',
111 | borderCollapse: 'collapse',
112 | boxSizing: 'borderBox',
113 | wordWrap: 'break-word'
114 | },
115 | tr: {},
116 | th: {
117 | padding: '5px 10px',
118 | border: '1px solid #dfe2e5',
119 | verticalAlign: 'top',
120 | fontWeight: '600'
121 | },
122 | td: {
123 | padding: '5px 10px',
124 | border: '1px solid #dfe2e5',
125 | verticalAlign: 'top'
126 | }
127 | }}
128 |
129 | MarkdownTheme.md.fence_bash = Object.assign({}, MarkdownTheme.md.fence, {
130 | background: color.nav.primary,
131 | color: color.nav.fontSecondary
132 | });
133 |
134 | module.exports = MarkdownTheme;
135 |
--------------------------------------------------------------------------------
/lib/core/theme/reset.js:
--------------------------------------------------------------------------------
1 | const color = require('./color.js');
2 |
3 | const reset = {}
4 |
5 | reset['html, body, div, span, applet, object, iframe,' +
6 | 'h1, h2, h3, h4, h5, h6, p, blockquote, pre,' +
7 | 'a, abbr, acronym, address, big, cite, code,' +
8 | 'del, dfn, em, img, ins, kbd, q, s, samp,' +
9 | 'small, strike, strong, sub, sup, tt, var,' +
10 | 'b, u, i, center,' +
11 | 'dl, dt, dd, ol, ul, li,' +
12 | 'fieldset, form, label, legend,' +
13 | 'table, caption, tbody, tfoot, thead, tr, th, td,' +
14 | 'article, aside, canvas, details, embed,' +
15 | 'figure, figcaption, footer, header, hgroup,' +
16 | 'menu, nav, output, ruby, section, summary,' +
17 | 'time, mark, audio, video'] = {
18 | margin: '0',
19 | padding: '0',
20 | border: '0'
21 | };
22 |
23 | reset['article, aside, details, figcaption, figure,' +
24 | 'footer, header, hgroup, menu, nav, section'] = {
25 | display: 'block'
26 | };
27 |
28 | reset['body'] = {
29 | lineHeight: '1',
30 | '-webkit-font-smoothing': 'antialiased',
31 | '-moz-osx-font-smoothing': 'antialiased'
32 | };
33 |
34 | reset['blockquote, q'] = {
35 | quotes: 'none'
36 | };
37 |
38 | reset['blockquote:before, blockquote:after,' +
39 | 'q:before, q:after'] = {
40 | content: '',
41 | content: 'none'
42 | };
43 |
44 | reset['table'] = {
45 | borderCollapse: 'collapse',
46 | borderSpacing: '0'
47 | };
48 |
49 | reset['p'] = {
50 | lineHeight: '1.4'
51 | };
52 |
53 | reset['img'] = {
54 | maxWidth: '100%',
55 | height: 'auto'
56 | };
57 |
58 | reset['article p img, article iframe'] = {
59 | maxWidth: '100%',
60 | display: 'inline-block',
61 | marginLeft: 'auto',
62 | marginRight: 'auto'
63 | };
64 |
65 | reset['a'] = {
66 | color: color.clickable,
67 | textDecoration: 'none'
68 | };
69 |
70 | reset['a.hash-link'] = {
71 | float: 'left',
72 | paddingRight: '4px',
73 | marginTop: '4px',
74 | marginLeft: '-20px',
75 | lineHeight: '1.2',
76 | opacity: '0',
77 | transition: 'opacity 0.3s'
78 | };
79 |
80 | reset['h1:hover .hash-link,' +
81 | 'h2:hover .hash-link,' +
82 | 'h3:hover .hash-link,' +
83 | 'h4:hover .hash-link'] = {
84 | opacity: '0.5',
85 | transition: 'none'
86 | };
87 |
88 | reset['a.hash-link:hover'] = {
89 | opacity: '1!important',
90 | transition: 'none'
91 | };
92 |
93 | reset['blockquote'] = {
94 | padding: '15px 30px 15px 15px',
95 | margin: '20px 0',
96 | backgroundColor: 'rgba(204, 122, 111, 0.1)',
97 | borderLeft: '5px solid rgba(191, 87, 73, 0.2)'
98 | };
99 |
100 | reset['ul, ol'] = {
101 | padding: '10px 20px'
102 | };
103 |
104 | reset['input::-webkit-input-placeholder'] = {
105 | color: '#e5e5e5'
106 | };
107 |
108 | reset['input::-moz-placeholder'] = {
109 | color: '#e5e5e5'
110 | };
111 |
112 | reset['input::placeholder'] = {
113 | color: '#e5e5e5'
114 | };
115 |
116 | const resetTheme = { reset };
117 |
118 | module.exports = resetTheme;
119 |
--------------------------------------------------------------------------------
/lib/core/theme/search.js:
--------------------------------------------------------------------------------
1 | const color = require('./color.js');
2 |
3 | const SearchTheme = { search: {
4 | container: {
5 | position: 'relative'
6 | },
7 | input: {
8 | lineHeight: '1.5em',
9 | background: '#eee',
10 | padding: '0 0.5em',
11 | margin: '0 10px',
12 | fontSize: '0.8em',
13 | verticalAlign: 'middle',
14 | boxSizing: 'border-box',
15 | borderStyle: 'solid',
16 | borderColor: color.nav.primary,
17 | borderRadius: '1em',
18 | width: '12em',
19 | '@media (max-width: 767px)': {
20 | width: '8em',
21 | borderColor: color.nav.secondary
22 | }
23 | },
24 | list: {
25 | display: 'none',
26 | position: 'absolute',
27 | right: '1em',
28 | top: '1.5em',
29 | minWidth: '25em',
30 | maxWidth: '30em',
31 | maxHeight: '25em',
32 | whiteSpace: 'pre-wrap',
33 | overflow: 'auto',
34 | background: '#fff',
35 | opacity: '0.9',
36 | listStyle: 'none',
37 | textAlign: 'left',
38 | borderRadius: '5px',
39 | borderBottom: '1px solid',
40 | borderColor: color.nav.primary,
41 | boxSizing: 'border-box',
42 | padding: '0',
43 | '@media (max-width: 575px)': {
44 | right: '0.5em',
45 | minWidth: '20em',
46 | maxWidth: '25em'
47 | }
48 | },
49 | item: {
50 | padding: '0',
51 | title: {
52 | padding: '1em 1em 0.5em 1em',
53 | color: color.primary,
54 | display: 'block',
55 | textDecoration: 'underline'
56 | },
57 | description: {
58 | padding: '0 1em 0 2em',
59 | color: color.secondary,
60 | whiteSpace: 'pre-wrap',
61 | fontSize: '0.7em'
62 | }
63 | },
64 | footer: {
65 | padding: '1em',
66 | textAlign: 'right',
67 | search_by: {
68 | marginRight: '0.5em'
69 | },
70 | logo: {
71 | width: '4em',
72 | verticalAlign: 'middle'
73 | }
74 | }
75 | }}
76 |
77 | module.exports = SearchTheme;
78 |
--------------------------------------------------------------------------------
/lib/start-server.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | require('babel-register')({
4 | babelrc: false,
5 | only: [__dirname, process.cwd() + '/core'],
6 | presets: ['react', 'env'],
7 | });
8 |
9 | const chalk = require('chalk');
10 | const fs = require('fs');
11 | const commander = require('commander');
12 | const tcpPortUsed = require('tcp-port-used');
13 |
14 | const CWD = process.cwd();
15 |
16 | if (!fs.existsSync(CWD + '/siteConfig.js')) {
17 | console.error(
18 | chalk.red('Error: No siteConfig.js file found in website folder!')
19 | );
20 | process.exit(1);
21 | }
22 |
23 | commander.option('--port ', 'Specify port number').parse(process.argv);
24 | const port = parseInt(commander.port, 10) || 3000;
25 |
26 | tcpPortUsed
27 | .check(port, 'localhost')
28 | .then(function(inUse) {
29 | if (inUse) {
30 | console.error(chalk.red('Port ' + port + ' is in use'));
31 | process.exit(1);
32 | } else {
33 | console.log('Starting Dochameleon server on port ' + port + '...');
34 | const server = require('./core/server.js');
35 | server(port);
36 | }
37 | })
38 | .catch(function(ex) {
39 | setTimeout(function() {
40 | throw ex;
41 | }, 0);
42 | });
43 |
--------------------------------------------------------------------------------
/lib/static/img/algolia.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/lib/static/img/dochameleon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/dochameleon.png
--------------------------------------------------------------------------------
/lib/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/favicon.ico
--------------------------------------------------------------------------------
/lib/static/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/favicon.png
--------------------------------------------------------------------------------
/lib/static/img/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/github.png
--------------------------------------------------------------------------------
/lib/static/img/language.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/lib/static/img/markdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/markdown.png
--------------------------------------------------------------------------------
/lib/static/img/octocat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/octocat.jpg
--------------------------------------------------------------------------------
/lib/static/img/progressive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/progressive.png
--------------------------------------------------------------------------------
/lib/static/img/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
22 |
--------------------------------------------------------------------------------
/lib/static/img/setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/lib/static/img/setup.png
--------------------------------------------------------------------------------
/lib/static/img/translation.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dochameleon",
3 | "description": "Simpler but more flexible Docusaurus",
4 | "version": "0.0.51",
5 | "license": "MIT",
6 | "keywords": [
7 | "documentation",
8 | "websites",
9 | "open source",
10 | "dochameleon",
11 | "docusaurus"
12 | ],
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/richardzcode/Dochameleon.git"
16 | },
17 | "scripts": {
18 | "ci-check": "yarn prettier:diff",
19 | "format:source": "prettier --config .prettierrc --write \"lib/**/*.js\"",
20 | "format:examples": "prettier --config .prettierrc --write \"examples/**/*.js\"",
21 | "nit:source": "prettier --config .prettierrc --list-different \"lib/**/*.js\"",
22 | "nit:examples": "prettier --config .prettierrc --list-different \"examples/**/*.js\"",
23 | "prettier": "yarn format:source && yarn format:examples",
24 | "prettier:diff": "yarn nit:source && yarn nit:examples",
25 | "test": "jest"
26 | },
27 | "dependencies": {
28 | "algoliasearch": "^3.27.1",
29 | "babel-preset-env": "^1.7.0",
30 | "babel-preset-react": "^6.24.1",
31 | "babel-register": "^6.24.1",
32 | "babel-traverse": "^6.25.0",
33 | "babylon": "^6.17.4",
34 | "chalk": "^2.4.1",
35 | "commander": "^2.15.1",
36 | "express": "^4.16.3",
37 | "feed": "^1.1.1",
38 | "fluid-react": "0.0.41",
39 | "fs-extra": "^5.0.0",
40 | "fsts": "0.0.40",
41 | "glob": "^7.1.2",
42 | "react": "^16.4.0",
43 | "react-dom": "^16.4.0",
44 | "react-dom-factories": "^1.0.1",
45 | "remarkable": "^1.7.1",
46 | "request": "^2.87.0",
47 | "shelljs": "^0.7.8",
48 | "sitemap": "^1.13.0",
49 | "tcp-port-used": "^0.1.2"
50 | },
51 | "bin": {
52 | "dochameleon-start": "./lib/start-server.js",
53 | "dochameleon-build": "./lib/build-files.js",
54 | "dochameleon-publish": "./lib/publish-gh-pages.js",
55 | "dochameleon-examples": "./lib/copy-examples.js"
56 | },
57 | "devDependencies": {
58 | "jest": "^21.2.1",
59 | "prettier": "^1.13.3",
60 | "rimraf": "^2.6.2"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | build/
4 | yarn.lock
5 | **/node_modules
6 | searchConfig.js
7 |
--------------------------------------------------------------------------------
/website/analyticsConfig.js:
--------------------------------------------------------------------------------
1 | const analyticsConfig = {
2 | tracking_id: 'UA-113485999-1',
3 | js: { src: 'https://www.googletagmanager.com/gtag/js', async: true }
4 | }
5 |
6 | module.exports = analyticsConfig;
7 |
--------------------------------------------------------------------------------
/website/blog/2018-01-08-why-dochameleon.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Why Dochameleon
3 | author: Richard Zhang
4 | authorGitHub: richardzcode
5 | ---
6 |
7 | It is not hard to guess where the idea of Dochameleon is from.
8 |
9 | With [Docusaurus](https://github.com/facebook/Docusaurus) built and maintained by awesome team from Facebook, why do I want to build another one?
10 |
11 | One personal reason is I am so excited about Docusaurus. Can't stop checking around, rewrite, restruct source code. So only way to satisfy is to create a new project.
12 |
13 |
14 |
15 | Here are some technical reasons,
16 |
17 | 1. Dev server and site generation are written separately. Inconsistency is inevitable.
18 | 2. Pages can not share building blocks.
19 | 3. Big CSS file makes styling hard.
20 |
21 | At the same time some features are removed. I feel they are a bit too opinionated with complexity, may not suited for all open source projects.
22 |
23 | 1. Search with [algolia](https://www.algolia.com/).
24 | 2. Multi-Language with [crowdin](https://crowdin.com/).
25 | 3. Project version support.
26 |
27 | For example, at the end of the day multi-language and versioning are grouped by file hierarchies. One options is to just take pull requests on GitHub.
28 |
--------------------------------------------------------------------------------
/website/blog/2018-01-10-staging-step.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Staging Step
3 | author: Richard Zhang
4 | authorGitHub: richardzcode
5 | ---
6 |
7 | The basic idea of Dochameleon is to generate a static web server by using [Server-Side-Rendering](https://reactjs.org/docs/react-dom-server.html). Contents are combined from core library and specific project.
8 |
9 | Combining from two sources can be tricky. So there is a staging step. Which in essence copies files from the two sources into one place, for SSR to generate from, and for developers to inspect on.
10 |
11 | The one place can be found at `node_modules/dochameleon/lib/stage`, contains a file structure like this:
12 |
13 | ```bash
14 | node_modules/dochameleon/lib/stage/
15 | ├── Blog.js
16 | ├── Docs.js
17 | ├── Pages.js
18 | ├── blog
19 | │ └── 2018-01-08-why-dochameleon.md
20 | │ └── 2018-01-10-stage-step.md
21 | ├── components
22 | │ ├── Button.js
23 | │ ├── CollapseIcon.js
24 | │ ├── FeatureCallout.js
25 | │ ├── FeatureCallouts.js
26 | │ ├── Features.js
27 | │ ├── Footer.js
28 | │ ├── Head.js
29 | │ ├── HeaderNav.js
30 | │ ├── HelpDetails.js
31 | │ ├── HomeSplash.js
32 | │ ├── MarkdownBlock.js
33 | │ ├── Page.js
34 | │ ├── Showcase.js
35 | │ ├── SideNav.js
36 | │ ├── blog
37 | │ ├── docs
38 | │ ├── featureCallouts.json
39 | │ ├── features.json
40 | │ ├── help.json
41 | │ └── users.json
42 | ├── dfs.js
43 | ├── docs
44 | │ ├── doc1.md
45 | │ ├── doc2.md
46 | │ ├── doc3.md
47 | │ ├── exampledoc4.md
48 | │ ├── exampledoc5.md
49 | │ └── sidebars.json
50 | ├── pages
51 | │ ├── help.js
52 | │ ├── index.js
53 | │ └── users.js
54 | ├── parse
55 | │ ├── Markdown.js
56 | │ └── toSlug.js
57 | ├── static
58 | │ ├── css
59 | │ └── img
60 | └── theme
61 | ├── blog.js
62 | ├── main.js
63 | ├── markdown.js
64 | └── pages.js
65 | ```
66 |
--------------------------------------------------------------------------------
/website/blog/2018-02-02-dochameleon-io-live.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Dochameleon.io is Live
3 | author: Richard Zhang
4 | authorGitHub: richardzcode
5 | ---
6 |
7 | Initially building [Dochameleon](https://dochameleon.io) was purely for fun. Writing code is like playing video game to me. [Docusaurus](https://github.com/facebook/Docusaurus) was like a new game release.
8 |
9 | So just play.
10 |
11 | Since Dochameleon is my own project I have the luxury to cut down, rewrite, in any way I feel right. Build the core first, then add features like search and analytics. I started to think this is actually useful. In some areas it is even better than the awesome Docusaurus built by Facebook folks. (disclaimer: just some areas, not the whole project)
12 |
13 | Why not put it online.
14 |
15 | Register a domain with AWS Route 53; Create a CloudFront distribution in order to serve SSL certificate of its own domain instead of GitHub.
16 |
17 | https://dochameleon.io is live!
18 |
--------------------------------------------------------------------------------
/website/blog/2018-03-09-everybody-should-have-an-website.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Everybody Should Have an Website
3 | author: Richard Zhang
4 | authorGitHub: richardzcode
5 | ---
6 |
7 | Everybody has social networks apps, probably more than one. But not a lot of people own websites.
8 |
9 | The assumption is building an website is hard and probably requires some cost. Even [Wordpress](https://wordpress.org) famous 5 minutes installation doesn't cut it.
10 |
11 | Actually it is easy, and requires no money, or very little depending on your needs.
12 |
13 | This formula is generally true for many use cases:
14 |
15 | ```
16 | Website = Hosting + Domain + Static Content
17 | ```
18 |
19 | ## Hosting
20 |
21 | [GitHub](https://github.com) hosting is free. If you don't know Git. Just follow instructions on GitHub. They made everything simple and clear.
22 |
23 | [Netlify](https://netlify.com) also has free personal plan. It is not just hosting. You may end up have Netlify for everything.
24 |
25 | Of course there are [Amazon S3](https://aws.amazon.com/s3/) and alike.
26 |
27 | ## Domain
28 |
29 | Domain registration is the part that needs some money. Price is different per providers. I use [Amazon AWS](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/registrar.html). As of today, $12 for a '.com' domain for one year.
30 |
31 | On the other hand, to get a domain like '_your_name_.github.io' or '_your_name_.netlify.com' is free. So this is really depend on how personalized do you want.
32 |
33 | ## Content Creation
34 |
35 | People are afraid of learning HTML/CSS/Javascript.
36 |
37 | But you don't have to. Just learn [Markdown](https://guides.github.com/features/mastering-markdown/), the guide is only one page. It is easier than MS Word.
38 |
39 | ## Content Generation
40 |
41 | There are tools to convert your content to HTML.
42 |
43 | [Jekyll](https://jekyllrb.com/) is built for transforming your plain text into static websites and blogs.
44 |
45 | [Hugo](https://gohugo.io) is another popular choice.
46 |
47 | If you know VueJs, try [NUXT](https://nuxtjs.org/).
48 |
49 | If you know React, try [Docusaurus](https://docusaurus.io) or [Dochameleon](https://dochameleon.io). You still just write Markdown for content, but have the chance to extend with ReactJs.
50 |
51 | There are so many, these are only the ones I have experience or interested in.
52 |
53 | ## Security
54 |
55 | To make your site secure require some learning and maybe some money. However for most personal websites for just sharing contents. This may not be necessary.
56 |
57 | ## Conclusion
58 |
59 | Social networks are boring. Have an internet handle for your personalities. The cost is less than one day of time, and zero amount of money.
60 |
--------------------------------------------------------------------------------
/website/components/Callout.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Div, A, Img, Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('./MarkdownBlock');
5 |
6 | class FeatureCallout extends React.Component {
7 | render() {
8 | const { site, lang, callout } = this.props;
9 | const { theme } = site;
10 | const title = site.i18n.translate(callout.title, lang);
11 | const content = callout['content.token']
12 | ? [].concat(site.i18n.translate(callout['content.token'], lang, callout.content)).join('')
13 | : [].concat(callout.content).join('');
14 | return (
15 |
16 | {callout.imgFirst && (
17 |
18 |
19 |
})
23 |
24 |
25 | )}
26 |
27 | {callout.doc
28 | ? {title}
32 | : {title}
33 | }
34 | {content}
35 |
36 | {!callout.imgFirst && (
37 |
38 |
39 |
})
40 |
41 |
42 | )}
43 |
44 | )
45 | }
46 | }
47 |
48 | module.exports = FeatureCallout;
49 |
--------------------------------------------------------------------------------
/website/components/Features.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H3, Div, Img, Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('./MarkdownBlock.js');
5 | const features = require('./features.json');
6 |
7 | const header = features.header
8 | ? [].concat(features.header).join('')
9 | : '';
10 | const footer = features.footer
11 | ? [].concat(features.footer).join('')
12 | : '';
13 |
14 | const Features = (props) => {
15 | const { site, lang } = props;
16 | const { theme } = site;
17 | const sectionComps = features.features.map((feature, idx) => {
18 | const content = feature['content.token']
19 | ? [].concat(site.i18n.translate(feature['content.token'], lang, feature.content)).join('')
20 | : [].concat(feature.content).join('');
21 | return (
22 |
23 |
24 |
25 |
})
26 |
27 |
{site.i18n.translate(feature.title, lang)}
28 |
{content}
29 |
30 |
31 | )
32 | });
33 |
34 | return (
35 |
36 | {header && {header}}
37 | {sectionComps}
38 | {footer && {footer}}
39 |
40 | )
41 | }
42 |
43 | module.exports = Features;
44 |
--------------------------------------------------------------------------------
/website/components/Footer.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | class Footer extends React.Component {
4 | render() {
5 | const { site, lang } = this.props;
6 | const { theme } = site;
7 | const currentYear = new Date().getFullYear();
8 | return (
9 |
61 | );
62 | }
63 | }
64 |
65 | module.exports = Footer;
66 |
--------------------------------------------------------------------------------
/website/components/HelpDetails.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H3, Div, Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('./MarkdownBlock.js');
5 | const help = require('./help.json');
6 |
7 | const HelpDetails = (props) => {
8 | const { site, lang } = props;
9 | const { theme } = site;
10 | const sectionComps = help.map((help_item, idx) => {
11 | return (
12 |
13 |
14 |
{help_item.title}
15 | {help_item.content}
16 |
17 |
18 | )
19 | });
20 | return {sectionComps}
21 | }
22 |
23 | module.exports = HelpDetails;
24 |
--------------------------------------------------------------------------------
/website/components/HomeSplash.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H2, Div } = require('fluid-react');
3 |
4 | const Button = require('./Button.js');
5 |
6 | class HomeSplash extends React.Component {
7 | render() {
8 | const { site, lang } = this.props;
9 | const tagline = site.i18n.translate('tagline', lang, site.config.tagline);
10 | return (
11 |
12 |
13 | {site.config.title}
14 |
{tagline}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | module.exports = HomeSplash;
27 |
--------------------------------------------------------------------------------
/website/components/Showcase.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { H3, H5, Div, P, Row, Col } = require('fluid-react');
3 |
4 | const users = require('./users.json');
5 |
6 | const Showcase = props => {
7 | if (users.length === 0) { return null; }
8 |
9 | const { site, lang } = props;
10 | const { theme } = site;
11 | const userComps = users
12 | .filter(user => !props.pinned || user.pinned)
13 | .map((user, i) => {
14 | let img_src = user.img;
15 | if (!img_src.startsWith('http')) { img_src = site.url(img_src); }
16 | return (
17 |
18 |
19 |
20 |
21 |
22 | );
23 | });
24 |
25 | return (
26 |
27 |
28 | {site.i18n.translate('Who\'s Using This?', lang)}
29 |
30 | {site.i18n.translate('This project is used by all these people', lang)}
31 |
32 |
33 | {userComps}
34 |
35 |
36 | );
37 | };
38 |
39 | module.exports = Showcase;
40 |
--------------------------------------------------------------------------------
/website/components/callouts.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Quick Setup",
4 | "doc": "guide_installation",
5 | "content.token": "quick_setup.content",
6 | "content": [
7 | "Get up and running quickly. Have your own website in just a few minutes",
8 | "\n",
9 | "\n```bash",
10 | "\n> npm install -g dochameleon-init",
11 | "\n> dochameleon-init",
12 | "\n> cd website",
13 | "\n> npm run start",
14 | "\n```"
15 | ],
16 | "img": "img/setup.png",
17 | "imgFirst": false
18 | },
19 | {
20 | "title": "Develop and Deploy",
21 | "doc": "guide_site_publishing",
22 | "content.token": "develop_deploy.content",
23 | "content": [
24 | "Develop using included live server; ",
25 | "Deploy to GitHub or any static file web hosts"
26 | ],
27 | "img": "img/octocat.jpg",
28 | "imgStyle": { "maxWidth": "40%" },
29 | "imgFirst": true
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/website/components/features.json:
--------------------------------------------------------------------------------
1 | {
2 | "header": "",
3 | "footer": "",
4 | "features": [
5 | {
6 | "title": "Powered by Markdown",
7 | "content.token": "markdown.content",
8 | "content": [
9 | "Write docs and blog posts with ",
10 | "[Markdown](https://guides.github.com/features/mastering-markdown/). ",
11 | "Dochameleon converts them into HTML files."
12 | ],
13 | "img": "img/markdown.png"
14 | },
15 | {
16 | "title": "Built Using React",
17 | "content.token": "react.content",
18 | "content": [
19 | "Build [React](https://reactjs.org/) Components ",
20 | "to extend or customize your project."
21 | ],
22 | "img": "img/react.svg"
23 | },
24 | {
25 | "title": "Progressive Customization",
26 | "content.token": "customization.content",
27 | "content": "Works out-of-box, able to customize to the extend of replacing core components",
28 | "img": "img/progressive.png"
29 | }
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/website/components/headerLinks.json:
--------------------------------------------------------------------------------
1 | [
2 | { "type": "doc", "value": "guide_installation", "label": "Docs" },
3 | { "type": "page", "value": "help", "label": "Help" },
4 | { "type": "blog", "label": "Blog" },
5 | {
6 | "type": "page",
7 | "value": "languages",
8 | "img": "img/translation.svg",
9 | "label": "Languages"
10 | },
11 | {
12 | "type": "url",
13 | "value": "https://github.com/richardzcode/Dochameleon",
14 | "img": "img/github.png",
15 | "label": "GitHub"
16 | },
17 | { "type": "search" }
18 | ]
19 |
--------------------------------------------------------------------------------
/website/components/help.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "Browse Docs",
4 | "content": "Learn more using the [documentation](docs/guide_installation.html)."
5 | },
6 | {
7 | "title": "Join the community",
8 | "content": "Ask questions at [Gitter](https://gitter.im/Dochameleon/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link)."
9 | },
10 | {
11 | "title": "Stay up to date",
12 | "content": "Find out what's [new](https://github.com/richardzcode/Dochameleon)."
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/website/components/users.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "fsts-js",
4 | "img": "img/fsts.png",
5 | "link": "https://richardzcode.github.io/fsts-js/index.html",
6 | "pinned": true
7 | },
8 | {
9 | "caption": "Fluid React",
10 | "img": "img/f-r.png",
11 | "link": "https://richardzcode.github.io/fluid-react/index.html",
12 | "pinned": true
13 | }
14 | ]
15 |
--------------------------------------------------------------------------------
/website/docs/guide_analytics.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_analytics
3 | title: Analytics
4 | sidebar_label: Analytics
5 | ---
6 |
7 | Dochameleon support [Google Analytics](https://developers.google.com/analytics/).
8 |
9 | After setup Google Analytics for your project. Add `analyticsConfig.js` along with `siteConfig.js`
10 |
11 | ```bash
12 | website/
13 | └── analyticsConfig.js
14 | ```
15 |
16 | Content similiar to this, remember to replace tracker_id:
17 | ```
18 | const analyticsConfig = {
19 | tracking_id: 'UA-XXXX-Y',
20 | js: { src: 'https://www.googletagmanager.com/gtag/js', async: true }
21 | }
22 |
23 | module.exports = analyticsConfig;
24 | ```
25 |
26 | Then build and publish. Check results at [Google Analytics](https://analytics.google.com)
27 |
--------------------------------------------------------------------------------
/website/docs/guide_configuration.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_configuration
3 | title: Site Configuration
4 | sidebar_label: Site Configuration
5 | ---
6 |
7 |
8 |
9 | ### Config File
10 |
11 | ```bash
12 | website/
13 | └── siteConfig.js
14 | ```
15 |
16 | Site configurations are defined in `website/siteConfig.js`, here is an example:
17 |
18 | ```
19 | const currentYear = new Date().getFullYear();
20 |
21 | const siteConfig = {
22 | projectName: 'Dochameleon',
23 | title: 'Dochameleon',
24 | tagline: 'Open Source Documentation Site Generator',
25 | copyright: 'Copyright © ' + currentYear + ' Richard Zhang',
26 |
27 | rootUrl: 'https://richardzcode.github.io',
28 | baseUrl: '/Dochameleon',
29 |
30 | icon: 'img/dochameleon.png',
31 | favicon: 'img/favicon.png',
32 |
33 | css: [],
34 | js: [
35 | 'https://buttons.github.io/buttons.js',
36 | ]
37 | };
38 | ```
39 |
40 | Dochameleon itself does not have css file. Theming is through CSS-in-JS. Extra css and js files can be specified in siteConfig.js
41 |
42 | ### Header Links
43 |
44 | `website/components/headerLinks.json` defines what displayed on main menu. Create this file to replace default header links.
45 |
46 | Menu item types:
47 |
48 | * doc
49 | * blog
50 | * page
51 | * url
52 | * search
53 |
54 | Example:
55 |
56 | ```
57 | [
58 | { "type": "doc", "value": "guide_installation", "label": "Docs" },
59 | { "type": "page", "value": "help", "label": "Help" },
60 | { "type": "blog", "label": "Blog" },
61 | {
62 | "type": "page",
63 | "value": "languages",
64 | "img": "img/translation.svg",
65 | "label": "Languages"
66 | },
67 | {
68 | "type": "url",
69 | "value": "https://github.com/richardzcode/Dochameleon",
70 | "img": "img/github.png",
71 | "label": "GitHub"
72 | },
73 | { "type": "search" }
74 | ]
75 | ```
76 |
--------------------------------------------------------------------------------
/website/docs/guide_customize_color.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_color_scheme
3 | title: Color Scheme
4 | sidebar_label: Color Scheme
5 | ---
6 |
7 | Changing colors probably is the simplest way to differenciate a website.
8 |
9 | Dochameleon does not have CSS file. All styles are defined in Javascript, which enables easy style customization. Changing color scheme is a perfect example.
10 |
11 | The core library has a [theme](https://github.com/richardzcode/Dochameleon/tree/master/lib/core/theme) folder which defines UI style. Custom website also have a `theme` folder. At runtime the two folder will be combined together, with the custom file replace core file if names are same.
12 |
13 | Copy [color.js](https://github.com/richardzcode/Dochameleon/tree/master/lib/core/theme/color.js) into website folder `/theme`, then change `primary` and `secondary` color. So it becomes:
14 |
15 | ```
16 | const color = {
17 | primary: '#283e4a',
18 | secondary: '#337ab7',
19 | tertiary: '#e0e0e0',
20 | font: '#393939',
21 | fontSecondary: '#000'
22 | };
23 |
24 | color.title = color.primary;
25 | color.content = color.font;
26 | color.contentSecondary = color.fontSecondary;
27 | color.clickable = color.primary;
28 |
29 | color.nav = {
30 | primary: color.primary,
31 | secondary: color.secondary,
32 | tertiary: color.tertiary,
33 | font: '#fff',
34 | fontSecondary: 'rgba(255, 255, 255, 0.8)',
35 | fontTertiary: 'rgba(255, 255, 255, 0.6)'
36 | };
37 |
38 | color.footer = '#808080';
39 |
40 | module.exports = color;
41 | ```
42 |
43 | run dev server again, `npm run start`. See what happens.
44 |
--------------------------------------------------------------------------------
/website/docs/guide_customize_core.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_core
3 | title: Core Component
4 | sidebar_label: Core Component
5 | ---
6 |
7 | Like mentioned in [Customization - React Component](./guide_react.html), Dochameleon merges custom and core components together at runtime. This makes further customization possible.
8 |
9 | Let's say you don't like sidebar at the left side for docs. Just copy `components/docs/DocsLayout.js` from core library to `website/components/docs`, then modify render function to switch the order of sidebar and content.
10 |
11 | ```
12 | return (
13 |
14 |
15 |
16 | {content}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | );
25 | ```
26 |
27 | Now `npm run start` see the sidebar is on the right side.
28 |
--------------------------------------------------------------------------------
/website/docs/guide_customize_progressive.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_progressive
3 | title: Progressive
4 | sidebar_label: Progressive Customization
5 | ---
6 |
7 | Website created by Dochameleon works out-of-box. You can just write Markdown documents and blogs.
8 |
9 | Depend on needs, you can customize the website progressively, from simply changing color to completely replace the core component rendering.
10 |
11 | 
12 |
--------------------------------------------------------------------------------
/website/docs/guide_customize_react.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_react
3 | title: React Component
4 | sidebar_label: React Component
5 | ---
6 |
7 | Write web pages in React, then Dochameleon will convert them into static HTML files.
8 |
9 | ### Pages
10 |
11 | Write web pages in `website/pages` folder. Each file exports an React component which will be rendered as one page.
12 |
13 | ### Components
14 |
15 | You may write custom React components in `website/components` folder, and use them in pages.
16 |
17 | Core library has React components too. At runtime, Dochameleon merges the two sets together.
18 |
19 | Take a look at example site `components` folder. It has number of components. Among them, `Footer.js` will overwrite the core Footer. Try remove it, and run `npm run start`, you'll notice default footer is different.
20 |
--------------------------------------------------------------------------------
/website/docs/guide_customize_theme.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_theme
3 | title: UI Theme
4 | sidebar_label: UI Theme
5 | ---
6 |
7 | Like mentioned in [Customization - Color Scheme](./guide_color_scheme.html), Dochameleon defines UI style in `/theme` folder, in Javascript.
8 |
9 | ### Core and Custom Theme
10 |
11 | Core theme located at `lib/core/theme` folder of the core library. Custom theme located at `website/theme` folder. Each file exports an object that defines a set of UI styles.
12 |
13 | Two steps happening at runtime.
14 |
15 | First step, files in the two folder will be merged together. If custom theme file has same name as core theme file then it will overwrite the core file.
16 |
17 | Second step, Dochameleon reads all theme files and merge all objects into one final object. This is the theme object, contains defination of all UI styles.
18 |
19 | ### Customization
20 |
21 | Customization is simply write theme files in `website/theme` folder.
22 |
23 | Create a file `website/theme/custom.js`
24 | ```
25 | const custom = {
26 | button: {
27 | margin: '4px',
28 | border: '1px solid blue',
29 | borderRadius: '3px',
30 | color: 'blue',
31 | display: 'inline-block',
32 | fontSize: '14px',
33 | fontWeight: '400',
34 | lineHeight: '1.2em',
35 | padding: '10px',
36 | textTransform: 'uppercase',
37 | textDecoration: 'none',
38 | transition: 'background 0.3s, color 0.3s'
39 | }
40 | }
41 |
42 | module.exports = custom;
43 | ```
44 |
45 | run dev server again, `npm run start`. See how buttons look like now.
46 |
--------------------------------------------------------------------------------
/website/docs/guide_github.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_github
3 | title: Project on GitHub
4 | sidebar_label: Project on GitHub
5 | ---
6 |
7 |
8 |
9 | Dochameleon is aware of GitHub conventions. Follow this steps to quickly create website for your GitHub project.
10 |
11 | ### Installation
12 |
13 | Just make sure run `dochameleon-init` at your project repo root.
14 |
15 | ```
16 | > cd $path_to_project$
17 | > dochameleon-init
18 | > cd website
19 | > npm run start
20 | ```
21 |
22 | ### Configuration
23 |
24 | Modify `siteConfig.js` with your project information, particularly:
25 |
26 | * projectName
27 | * title
28 | * copyright
29 | * rootUrl
30 | * baseUrl
31 | * icon
32 | * favicon
33 |
34 | ### Docs
35 |
36 | By default Dochameleon loads docs from `website/docs`. You may copy files over, or just change the config. For example, by GitHub convention it is the `docs` folder under your repo. Add this line to your `website/siteConfig.js`
37 |
38 | ```
39 | docsDir: '../docs'
40 | ```
41 |
42 | **Caution:** Do not set docsDir and buildDir to the same path, since building process would remove and add files.
43 |
44 | ### Assets
45 |
46 | In case you have assets like images, put them under `docs/assets` folder of your repo. Dochameleon will keep them so the references still work as usual.
47 |
48 | ### Home Page
49 |
50 | You may want to make README.md as home page instead of the default one.
51 |
52 | The library actually has already created a `readme.html` page with your README.md. You may just copy this source code
53 |
54 | ```
55 | cp node_modules/dochameleon/lib/core/pages/readme.js pages/index.js
56 | ```
57 |
58 | Now `npm run start`.
59 |
--------------------------------------------------------------------------------
/website/docs/guide_i18n.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_i18n
3 | title: Multi-Language
4 | sidebar_label: Multi-Language
5 | ---
6 |
7 |
8 |
9 | For multi-language support, just create folder `website/i18n` then have language folders below it. Language code follow [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) standard.
10 |
11 | ### Configure
12 |
13 | Create `i18n` folder along with `siteConfig.js`, then language folders below it.
14 |
15 | ```bash
16 | website/
17 | └── i18n/
18 | ├── zh/
19 | └── fr/
20 | ```
21 |
22 | ### Dictionary
23 |
24 | Under each language folder, create as many js file as you want, each exports an object of vocabulary map. Dochameleon will merge all objects into one big dictionary object to be used for translation.
25 |
26 | For example:
27 |
28 | `website/i18n/zh/blog.js`
29 | ```
30 | const blog = {
31 | 'Why Dochameleon': '为什么Dochameleon',
32 | 'Staging Step': '准备步骤',
33 | 'Dochameleon.io is Live': 'Dochameleon.io上线了',
34 | 'Pages': '网页',
35 | 'Static Files': '静态文件',
36 | 'Configure Source Folders': '配置源文件路径'
37 | };
38 |
39 | module.exports = blog;
40 | ```
41 |
42 | ### Docs Translation
43 |
44 | A dictionary is not enough to translate a full document. Create `docs` folder under language folder and have translated documentation. Make sure to have same document id in metadata section of the file.
45 |
46 | For example look at [here](https://github.com/richardzcode/Dochameleon/tree/master/website/i18n/zh/docs)
47 |
48 | ### {lang} Parameter and Translation
49 |
50 | A {lang} parameter is passed down to all components for rendering. When developing your own component, make sure to get and pass down {lang} parameter as well.
51 |
52 | When render, call `site.i18n.translate(token, lang)` to get translation.
53 |
--------------------------------------------------------------------------------
/website/docs/guide_installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_installation
3 | title: Installation
4 | sidebar_label: Installation
5 | ---
6 |
7 |
8 |
9 | ### Install via script
10 |
11 | The easiest way to install Dochameleon is by using script `dochameleon-init`
12 |
13 | First install the script
14 |
15 | ```
16 | npm install --global dochameleon-init
17 | ```
18 |
19 | Then, go to the folder that your'd like to create the documentation website, run
20 |
21 | ```
22 | dochameleon-init
23 | cd website
24 | npm run start
25 | ```
26 |
27 | Now check http://localhost:3000, the website is up running!
28 |
29 | The init script does three things:
30 | * create `website` folder;
31 | * npm install `dochameleon` package;
32 | * copy a basic example website to start from.
33 |
34 |
35 | ### Manual installation
36 |
37 | If you do not want `dochameleon-init`, rather create website manually.
38 |
39 | - Create and go into the `website` folder
40 | - Create package.json with content,
41 | ```
42 | {
43 | "scripts": {
44 | "examples": "dochameleon-examples"
45 | }
46 | }
47 | ```
48 | - Install Dochameleon, run
49 | ```
50 | npm install dochameleon
51 | ```
52 |
53 | - Init with basic example, run
54 | ```
55 | npm run examples
56 | ```
57 |
58 | ### Run Local Dev Server
59 |
60 | Once installation completed, a website with example content is ready to go. Just run
61 |
62 | ```
63 | npm run start
64 | ```
65 |
66 | ### File Structure
67 |
68 | Once installation successful, here is the file structure you'll have under the `website` folder
69 |
70 | ```bash
71 | website/
72 | ├── blog/
73 | │ ├── 2018-01-08-why-dochameleon.md
74 | │ └── 2018-01-10-staging-step.md
75 | ├── components/
76 | ├── docs/
77 | │ ├── doc1.md
78 | │ ├── doc2.md
79 | │ ├── doc3.md
80 | │ └── sidebars.json
81 | ├── pages/
82 | │ ├── help.js
83 | │ ├── index.js
84 | │ └── users.js
85 | ├── siteConfig.js
86 | ├── static/
87 | └── theme/
88 | ```
89 |
--------------------------------------------------------------------------------
/website/docs/guide_search.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_search
3 | title: Search
4 | sidebar_label: Search
5 | ---
6 |
7 |
8 |
9 | Dochameleon support search by [Algolia](https://www.algolia.com). Algolia is super easy to setup, and its community plan is free.
10 |
11 | ### Configure
12 |
13 | After setup Algolia for your project. Add `searchConfig.js` along with `siteConfig.js`
14 |
15 | ```bash
16 | website/
17 | └── searchConfig.js
18 | ```
19 |
20 | Content similiar to this:
21 | ```
22 | const searchConfig = {
23 | application_id: ...,
24 | search_api_key: ...,
25 | api_key: ...,
26 | js: 'https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js'
27 | }
28 |
29 | module.exports = searchConfig;
30 | ```
31 |
32 | Make sure searchConfig.js is in your `.gitignore`. You want to keep api_key safe.
33 |
34 | ### Add to Menu
35 |
36 | Modify `siteConfig.js`, add this entry to headerLinks:
37 | ```
38 | {type: 'search'},
39 | ```
40 |
41 | ### Indexing
42 |
43 | Indexing happens at site generation time. When you run `npm run build`, the latest docs are pushed to Algolia.
44 |
--------------------------------------------------------------------------------
/website/docs/guide_site_creation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_site_creation
3 | title: Site Creation
4 | sidebar_label: Site Creation
5 | ---
6 |
7 |
8 |
9 | ### Docs
10 |
11 | ```bash
12 | website/
13 | └── docs/
14 | ├── doc1.md
15 | ├── doc2.md
16 | ├── doc3.md
17 | └── sidebars.json
18 | ```
19 | Write documentation under `website/docs` folder, with Markdown.
20 |
21 | At beginning of each doc file, add metadata like this:
22 |
23 | ```
24 | ---
25 | id: doc1
26 | title: Latin-ish
27 | sidebar_label: Example Page
28 | ---
29 | ```
30 |
31 | #### Sidebar
32 |
33 | Sidebar menu is defined in `sidebars.json`
34 |
35 | ### Blog
36 |
37 | ```bash
38 | website/
39 | └── blog/
40 | ├── 2018-01-08-why-dochameleon.md
41 | └── 2018-01-10-staging-step.md
42 | ```
43 | Write blog posts under `website/blog` folder, with Markdown.
44 |
45 | File name must have the format of `yyyy-mm-dd-blog-file-name.md`
46 |
47 | At begging of each blog post, add metadata like this:
48 |
49 | ```
50 | ---
51 | title: Why Dochameleon
52 | author: Richard Zhang
53 | authorUrl: https://github.com/richardzcode
54 | authorImage: https://github.com/richardzcode.png
55 | ---
56 | ```
57 |
58 | authorUrl and authorImage can be set by name/id of GitHub, Facebook, or Twitter, for example:
59 |
60 | ```
61 | authorGitHub: richardzcode
62 | ```
63 |
64 | or
65 |
66 | ```
67 | authorFBID: ...
68 | ```
69 |
70 | or
71 |
72 | ```
73 | authorTwitter: ...
74 | ```
75 |
76 | ### Pages
77 |
78 | ```bash
79 | website/
80 | ├── components/
81 | ├── pages/
82 | │ ├── help.js
83 | │ ├── index.js
84 | │ └── users.js
85 | └── theme/
86 | ```
87 | Create web pages under `website/pages` folder, by writing React.
88 |
89 | Create components under `website/components`, for pages to import.
90 |
91 | Write theme files under `website/theme`, to define styles.
92 |
93 | ### Static Files
94 |
95 | ```bash
96 | website/
97 | └── static/
98 | ```
99 |
100 | Put static files under `website/static` folder. They will go to `${rootUrl}${baseUrl}/`
101 |
102 | You may refer to static files in docs as `/static/...`, for example `[Logo]( /static/img/logo.png)`
103 |
104 | ### Configure Source Folders
105 |
106 | By default Dochameleon looks up sources under `website` which is the current commandline directory. All source folders are configurable. For example you may want to change 'docs' folder to GitHub repo '/docs'.
107 |
108 | Set source folders in `siteConfig.js`
109 |
110 | ```
111 | ...
112 |
113 | const siteConfig = {
114 | projectName: 'Dochameleon',
115 | title: 'Dochameleon',
116 | tagline: 'Open Source Documentation Site Generator',
117 | copyright: 'Copyright © ' + currentYear + ' Richard Zhang',
118 |
119 | docsDir: '../docs',
120 | pagesDir: ...,
121 | blogDir: ...,
122 | componentsDir: ...,
123 | staticDir: ...,
124 | themeDir: ...,
125 |
126 | ...
127 | ```
128 |
--------------------------------------------------------------------------------
/website/docs/guide_site_publishing.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_site_publishing
3 | title: Site Publishing
4 | sidebar_label: Site Publishing
5 | ---
6 |
7 |
8 |
9 | Dochameleon converts Markdown and React source files into static HTML files. Then you put them on any of the web hosting solution, GitHub, Amazon S3, etc.
10 |
11 | ### Build
12 |
13 | ```
14 | npm run build
15 | ```
16 |
17 | Then all HTML files will be generated into `website/build` folder.
18 |
19 | ### Hosting
20 |
21 | Now you may get all of the files inside `website/build` and copy over to web hosting.
22 |
23 | #### GitHub Pages
24 |
25 | [GitHub Pages](https://pages.github.com/) is a very natural hosting choice for open source projects. To publish to GitHub Pages,
26 |
27 | 1. Follow steps to create your GitHub Pages. Select "master branch /docs folder" as `Source`
28 |
29 | 2. Copy `website/build/{projectName}` folder to your project `/docs` folder.
30 | 3. Commit and push your git repo.
31 |
32 | That's it!
33 |
34 | ##### Skip copy step
35 |
36 | By default build command generates HTML files into `website/build/{projectName}` folder. You may configure the destination to another place. For example, to GitHub project 'docs' folder so no copy needed before publish.
37 |
38 | ```
39 | ...
40 |
41 | const siteConfig = {
42 | projectName: 'Dochameleon',
43 | title: 'Dochameleon',
44 | tagline: 'Open Source Documentation Site Generator',
45 | copyright: 'Copyright © ' + currentYear + ' Richard Zhang',
46 |
47 | buildDir: '../docs',
48 |
49 | ...
50 | ```
51 |
52 | **Caution:** During build Dochameleon will remove files in buildDir. Make sure `../docs` doesn't have files you needed for other purposes.
53 |
--------------------------------------------------------------------------------
/website/docs/sidebars.json:
--------------------------------------------------------------------------------
1 | {
2 | "docs": {
3 | "Getting Started": [
4 | "guide_installation",
5 | "guide_configuration",
6 | "guide_site_creation",
7 | "guide_site_publishing",
8 | "guide_github"
9 | ],
10 | "Customization": [
11 | "guide_progressive",
12 | "guide_color_scheme",
13 | "guide_theme",
14 | "guide_react",
15 | "guide_core"
16 | ],
17 | "Advanced": [
18 | "guide_search",
19 | "guide_analytics",
20 | "guide_i18n"
21 | ]
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/website/i18n/zh/blog.js:
--------------------------------------------------------------------------------
1 | const blog = {
2 | 'Why Dochameleon': '为什么Dochameleon',
3 | 'Staging Step': '准备步骤',
4 | 'Dochameleon.io is Live': 'Dochameleon.io上线了',
5 | 'Pages': '网页',
6 | 'Static Files': '静态文件',
7 | 'Configure Source Folders': '配置源文件路径'
8 | };
9 |
10 | module.exports = blog;
11 |
--------------------------------------------------------------------------------
/website/i18n/zh/docs.js:
--------------------------------------------------------------------------------
1 | const docs = {
2 | 'Configuration': '配置',
3 | 'Home Page': '主页'
4 | };
5 |
6 | module.exports = docs;
7 |
--------------------------------------------------------------------------------
/website/i18n/zh/docs/guide_installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: guide_installation
3 | title: 安装指南
4 | sidebar_label: 安装指南
5 | ---
6 |
7 |
8 |
9 | ### 用脚本安装
10 |
11 | 安装Dochameleon最简单的方式,运用脚本`dochameleon-init`
12 |
13 | 首先安装脚本
14 |
15 | ```
16 | npm install --global dochameleon-init
17 | ```
18 |
19 | 然后,进入想要创建文档网站的文件夹,运行
20 |
21 | ```
22 | dochameleon-init
23 | cd website
24 | npm run start
25 | ```
26 |
27 | 脚本完成三件任务
28 | * 创建`website`文件夹
29 | * npm安装`dochameleon`包
30 | * 拷贝样板网站
31 |
32 |
33 | ### 手工安装
34 |
35 | 如果你不想使用脚本,更愿意手工创建网站
36 | - 创建并进入`website`文件夹
37 | - 编写package.json,内容如下,
38 |
39 | ```
40 | {
41 | "scripts": {
42 | "examples": "dochameleon-examples"
43 | }
44 | }
45 | ```
46 | - 安装Dochameleon, 运行
47 | ```
48 | npm install dochameleon
49 | ```
50 |
51 | - 初始化基本样板, 运行
52 | ```
53 | npm run examples
54 | ```
55 |
56 | ### 运行本地开发服务器
57 |
58 | 安装完成之后,一个样板网站已经可以使用了。运行
59 |
60 | ```
61 | npm run start
62 | ```
63 |
64 | ### 文件结构
65 |
66 | 安装成功之后,`website`下文件结构是这样的,
67 |
68 | ```bash
69 | website/
70 | ├── blog/
71 | │ ├── 2018-01-08-why-dochameleon.md
72 | │ └── 2018-01-10-staging-step.md
73 | ├── components/
74 | ├── docs/
75 | │ ├── doc1.md
76 | │ ├── doc2.md
77 | │ ├── doc3.md
78 | │ └── sidebars.json
79 | ├── pages/
80 | │ ├── help.js
81 | │ ├── index.js
82 | │ └── users.js
83 | ├── siteConfig.js
84 | ├── static/
85 | └── theme/
86 | ```
87 |
--------------------------------------------------------------------------------
/website/i18n/zh/features.js:
--------------------------------------------------------------------------------
1 | const features = {
2 | 'Powered by Markdown': 'Markdown编辑',
3 | 'Built Using React': '使用React构建',
4 | 'Progressive Customization': '渐进式定制',
5 | 'Quick Setup': '快速安装',
6 | 'Develop and Deploy': '开发与发布',
7 | 'markdown.content': [
8 | '用[Markdown](https://guides.github.com/features/mastering-markdown/)编辑文档和博客。',
9 | 'Dochameleon转化文章为HTML文件'
10 | ],
11 | 'react.content': '编写自己的[React](https://reactjs.org/)构件,为你的项目延伸和定制网站',
12 | 'customization.content': '安装即可用,不同层级定制直至更换核心构件。',
13 | 'quick_setup.content': [
14 | '快速安装,几分钟搞定',
15 | '\n',
16 | '\n```bash',
17 | '\n> npm install -g dochameleon-init',
18 | '\n> dochameleon-init',
19 | '\n> cd website',
20 | '\n> npm run start',
21 | '\n```'
22 | ],
23 | 'develop_deploy.content': [
24 | '自带本地服务器帮助开发;',
25 | '发布到GitHub,或任何静态网站托管服务'
26 | ],
27 | 'Who\'s Using This?': '谁在使用',
28 | 'This project is used by all these people': '这个项目被用在这些项目中'
29 | }
30 |
31 | module.exports = features;
32 |
--------------------------------------------------------------------------------
/website/i18n/zh/langConfig.js:
--------------------------------------------------------------------------------
1 | const langConfig = {
2 | label: '中文'
3 | };
4 |
5 | module.exports = langConfig;
6 |
--------------------------------------------------------------------------------
/website/i18n/zh/languages.js:
--------------------------------------------------------------------------------
1 | const languages = {
2 | 'en': '英文',
3 | 'zh': '中文'
4 | };
5 |
6 | module.exports = languages;
7 |
--------------------------------------------------------------------------------
/website/i18n/zh/menu.js:
--------------------------------------------------------------------------------
1 | const menu = {
2 | 'Docs': '文档',
3 | 'Help': '帮助',
4 | 'Blog': '博客',
5 | 'Getting Started': '从哪开始',
6 | 'Installation': '安装指南',
7 | 'Site Configuration': '配置网站',
8 | 'Site Creation': '充实网站',
9 | 'Site Publishing': '发布网站',
10 | 'Project on GitHub': 'GitHub上的项目',
11 | 'Customization': '定制',
12 | 'Customize': '定制',
13 | 'Progressive Customization': '渐进式定制',
14 | 'Progressive': '渐进式',
15 | 'Color Scheme': '色调',
16 | 'UI Theme': '主题',
17 | 'React Component': 'React构件',
18 | 'Core Component': '核心构件',
19 | 'More': '更多',
20 | 'Advanced': '更多',
21 | 'Search': '搜索',
22 | 'Analytics': '分析',
23 | 'Multi-Language': '多种语言',
24 | 'Recent Posts': '最新文章',
25 | 'Read More': '阅读更多',
26 | 'Community': '社区',
27 | 'Guides': '开发指南',
28 | 'User Showcase': '用户列表',
29 | 'Twitter': '推特'
30 | };
31 |
32 | module.exports = menu;
33 |
--------------------------------------------------------------------------------
/website/i18n/zh/project.js:
--------------------------------------------------------------------------------
1 | const project = {
2 | tagline: '开源文档静态网站生成工具'
3 | };
4 |
5 | module.exports = project;
6 |
--------------------------------------------------------------------------------
/website/i18n/zh/translate.js:
--------------------------------------------------------------------------------
1 | const translate = {
2 | 'Create pull request to add your logo':
3 | '创建一个pull request加入你的网站图标'
4 | };
5 |
6 | module.exports = translate;
7 |
--------------------------------------------------------------------------------
/website/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "examples": "dochameleon-examples",
4 | "start": "dochameleon-start",
5 | "build": "dochameleon-build",
6 | "publish-gh-pages": "dochameleon-publish"
7 | },
8 | "devDependencies": {
9 | "dochameleon": "file:../dochameleon-0.0.44.tgz"
10 | },
11 | "dependencies": {}
12 | }
13 |
--------------------------------------------------------------------------------
/website/pages/help.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const HelpDetails = require('../components/HelpDetails.js');
4 |
5 | class Help extends React.Component {
6 | render() {
7 | const { site, lang } = this.props;
8 | const { theme } = site;
9 | return (
10 |
11 |
12 |
Need help?
13 |
This project is maintained by a dedicated group of people.
14 |
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | module.exports = Help;
22 |
--------------------------------------------------------------------------------
/website/pages/index.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 |
3 | const HomeSplash = require('../components/HomeSplash.js');
4 | const Features = require('../components/Features.js');
5 | const Callout = require('../components/Callout.js');
6 | const Showcase = require('../components/Showcase.js');
7 |
8 | const callouts = require('../components/callouts.json');
9 |
10 | class Index extends React.Component {
11 | render() {
12 | const { site, lang } = this.props;
13 | const { theme } = site;
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | module.exports = Index;
33 |
--------------------------------------------------------------------------------
/website/pages/languages.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { Row, Col } = require('fluid-react');
3 |
4 | const MarkdownBlock = require('../components/MarkdownBlock.js');
5 |
6 | const no_languages_content = `
7 | To have multi-language, write translations under \`website/i18n/$lang_code$\`
8 |
9 | [Example](https://github.com/richardzcode/Dochameleon/tree/master/website/i18n)
10 | `;
11 |
12 | class Languages extends React.Component {
13 | render() {
14 | const { site, lang } = this.props;
15 | const { theme } = site;
16 | const langs = site.i18n.langs();
17 | const languages = langs && langs.length > 0
18 | ? langs.map((language, i) => {
19 | return (
20 |
21 |
22 | {site.i18n.translate(language, lang)}
23 |
24 |
25 | );
26 | })
27 | : {no_languages_content}
28 |
29 | return (
30 |
31 |
32 |
33 | {languages}
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
41 | module.exports = Languages;
42 |
--------------------------------------------------------------------------------
/website/pages/users.js:
--------------------------------------------------------------------------------
1 | const React = require('react');
2 | const { JS} = require('fsts');
3 |
4 | const Showcase = require('../components/Showcase.js');
5 |
6 | const user_json = 'https://github.com/richardzcode/Dochameleon/blob/master/website/components/users.json';
7 |
8 | class Users extends React.Component {
9 | render() {
10 | const { site, lang } = this.props;
11 | const { theme } = site;
12 |
13 | const cta = site.i18n.translate('Create pull request to add your logo', lang);
14 | return (
15 |
21 | );
22 | }
23 | }
24 |
25 | module.exports = Users;
26 |
--------------------------------------------------------------------------------
/website/siteConfig.js:
--------------------------------------------------------------------------------
1 | const currentYear = new Date().getFullYear();
2 |
3 | const siteConfig = {
4 | projectName: 'Dochameleon',
5 | title: 'Dochameleon',
6 | tagline: 'Open Source Documentation Site Generator',
7 | copyright: 'Copyright © ' + currentYear + ' Richard Zhang',
8 |
9 | rootUrl: 'https://richardzcode.github.io',
10 | baseUrl: '',
11 |
12 | icon: 'img/dochameleon.png',
13 | favicon: 'img/favicon.png',
14 |
15 | js: [
16 | { src: 'https://buttons.github.io/buttons.js', async: true }
17 | ],
18 |
19 | repoDir: '../',
20 | buildDir: '../docs'
21 | };
22 |
23 | module.exports = siteConfig;
24 |
--------------------------------------------------------------------------------
/website/static/img/f-r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/website/static/img/f-r.png
--------------------------------------------------------------------------------
/website/static/img/fsts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/website/static/img/fsts.png
--------------------------------------------------------------------------------
/website/static/img/github_pages.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richardzcode/Dochameleon/18d221ab16288ae04e9bc6ae8feb735d0825b9cc/website/static/img/github_pages.png
--------------------------------------------------------------------------------
/website/theme/pages.js:
--------------------------------------------------------------------------------
1 | const color = require('./color.js');
2 |
3 | const pages = {
4 | block: {
5 | padding: '30px 10px'
6 | },
7 | blockEven: {
8 | padding: '30px 10px',
9 | background: '#e9e9e9'
10 | },
11 | homeSplash: {
12 | padding: '2em 10px',
13 | textAlign: 'center'
14 | },
15 | promoSection: {
16 | display: 'flex',
17 | flexFlow: 'row wrap',
18 | justifyContent: 'center',
19 | fontSize: '125%',
20 | lineHeight: '1.6em',
21 | position: 'relative',
22 | zIndex: '99'
23 | },
24 | featureImageContainer: {
25 | textAlign: 'center'
26 | },
27 | featureImage: {
28 | maxHeight: '80px'
29 | },
30 | calloutTitle: {
31 | textAlign: 'left',
32 | textDecoration: 'none',
33 | color: color.title,
34 | fontWeight: '300',
35 | fontSize: '180%',
36 | lineHeight: '1em'
37 | },
38 | calloutImageContainer: {
39 | textAlign: 'center'
40 | },
41 | calloutImage: {
42 | maxWidth: '80%'
43 | },
44 | showcaseBox: {
45 | display: 'block',
46 | padding: '20px',
47 | width: '80px',
48 | textAlign: 'center'
49 | },
50 | showcaseImage: {
51 | maxWidth: '100%',
52 | maxHeight: '80px'
53 | },
54 | helpTitle: {
55 | textAlign: 'left',
56 | color: color.title,
57 | fontWeight: '300',
58 | fontSize: '200%',
59 | lineHeight: '1em'
60 | },
61 | helpSection: {
62 | padding: '20px'
63 | },
64 | helpSectionTitle: {
65 | textAlign: 'left',
66 | color: color.title,
67 | fontWeight: '300',
68 | fontSize: '150%',
69 | lineHeight: '1em'
70 | }
71 | };
72 |
73 | module.exports = pages;
74 |
--------------------------------------------------------------------------------