From e3139eea2f8e59ffa9566ae8e9438500f9fbdfa1 Mon Sep 17 00:00:00 2001 From: Joel Marcey Date: Fri, 7 Jul 2017 10:28:29 -0700 Subject: [PATCH] Initial commit --- LICENSE | 30 + PATENTS | 33 + README.md | 156 ++ examples/core/Footer.js | 121 ++ examples/example-blog/2016-03-11-blog-post.md | 18 + .../example-blog/2017-04-10-blog-post-two.md | 18 + examples/example-docs/en/doc1.md | 163 ++ examples/example-docs/en/doc2.md | 12 + examples/example-docs/en/doc3.md | 17 + examples/example-docs/en/exampledoc4.md | 10 + examples/example-docs/en/exampledoc5.md | 10 + examples/i18n/en.json | 59 + examples/languages.js | 183 ++ examples/pages/en/help.js | 58 + examples/pages/en/index.js | 192 ++ examples/pages/en/users.js | 58 + examples/siteConfig.js | 100 + examples/static/img/docusaurus.svg | 1 + examples/static/img/favicon.png | Bin 0 -> 984 bytes examples/static/img/favicon/favicon.ico | Bin 0 -> 9662 bytes examples/static/img/oss_logo.png | Bin 0 -> 4370 bytes lib/build-files.js | 18 + lib/copy-examples.js | 15 + lib/core/BlogPageLayout.js | 66 + lib/core/BlogPost.js | 107 + lib/core/BlogPostLayout.js | 46 + lib/core/BlogSidebar.js | 41 + lib/core/CompLibrary.js | 18 + lib/core/Container.js | 47 + lib/core/Doc.js | 43 + lib/core/DocsLayout.js | 82 + lib/core/DocsSidebar.js | 42 + lib/core/Footer.js | 111 + lib/core/GridBlock.js | 83 + lib/core/Head.js | 50 + lib/core/Header.js | 28 + lib/core/Marked.js | 1060 ++++++++++ lib/core/Prism.js | 569 +++++ lib/core/Site.js | 114 + lib/core/nav/HeaderNav.js | 144 ++ lib/core/nav/SideNav.js | 103 + lib/core/toSlug.js | 48 + lib/core/unindent.js | 27 + lib/publish-gh-pages.js | 71 + lib/server/generate.js | 268 +++ lib/server/readCategories.js | 105 + lib/server/readMetadata.js | 181 ++ lib/server/server.js | 343 +++ lib/server/translation.js | 99 + lib/start-server.js | 18 + lib/static/css/main.css | 1876 +++++++++++++++++ lib/static/img/language.svg | 3 + package.json | 32 + 53 files changed, 7097 insertions(+) create mode 100644 LICENSE create mode 100644 PATENTS create mode 100644 README.md create mode 100644 examples/core/Footer.js create mode 100755 examples/example-blog/2016-03-11-blog-post.md create mode 100644 examples/example-blog/2017-04-10-blog-post-two.md create mode 100644 examples/example-docs/en/doc1.md create mode 100644 examples/example-docs/en/doc2.md create mode 100644 examples/example-docs/en/doc3.md create mode 100644 examples/example-docs/en/exampledoc4.md create mode 100644 examples/example-docs/en/exampledoc5.md create mode 100644 examples/i18n/en.json create mode 100644 examples/languages.js create mode 100755 examples/pages/en/help.js create mode 100755 examples/pages/en/index.js create mode 100644 examples/pages/en/users.js create mode 100644 examples/siteConfig.js create mode 100644 examples/static/img/docusaurus.svg create mode 100644 examples/static/img/favicon.png create mode 100644 examples/static/img/favicon/favicon.ico create mode 100644 examples/static/img/oss_logo.png create mode 100644 lib/build-files.js create mode 100644 lib/copy-examples.js create mode 100644 lib/core/BlogPageLayout.js create mode 100644 lib/core/BlogPost.js create mode 100644 lib/core/BlogPostLayout.js create mode 100644 lib/core/BlogSidebar.js create mode 100644 lib/core/CompLibrary.js create mode 100644 lib/core/Container.js create mode 100644 lib/core/Doc.js create mode 100644 lib/core/DocsLayout.js create mode 100644 lib/core/DocsSidebar.js create mode 100644 lib/core/Footer.js create mode 100755 lib/core/GridBlock.js create mode 100644 lib/core/Head.js create mode 100644 lib/core/Header.js create mode 100644 lib/core/Marked.js create mode 100644 lib/core/Prism.js create mode 100644 lib/core/Site.js create mode 100644 lib/core/nav/HeaderNav.js create mode 100644 lib/core/nav/SideNav.js create mode 100644 lib/core/toSlug.js create mode 100644 lib/core/unindent.js create mode 100644 lib/publish-gh-pages.js create mode 100644 lib/server/generate.js create mode 100644 lib/server/readCategories.js create mode 100644 lib/server/readMetadata.js create mode 100644 lib/server/server.js create mode 100644 lib/server/translation.js create mode 100644 lib/start-server.js create mode 100644 lib/static/css/main.css create mode 100644 lib/static/img/language.svg create mode 100644 package.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..774c15f329 --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +BSD License + +For Docusaurus software + +Copyright (c) 2017-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/PATENTS b/PATENTS new file mode 100644 index 0000000000..d4602119b8 --- /dev/null +++ b/PATENTS @@ -0,0 +1,33 @@ +Additional Grant of Patent Rights Version 2 + +"Software" means the Docusaurus software contributed by Facebook, Inc. + +Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software +("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable +(subject to the termination provision below) license under any Necessary +Claims, to make, have made, use, sell, offer to sell, import, and otherwise +transfer the Software. For avoidance of doubt, no license is granted under +Facebook’s rights in any patent claims that are infringed by (i) modifications +to the Software made by you or any third party or (ii) the Software in +combination with any software or other technology. + +The license granted hereunder will terminate, automatically and without notice, +if you (or any of your subsidiaries, corporate affiliates or agents) initiate +directly or indirectly, or take a direct financial interest in, any Patent +Assertion: (i) against Facebook or any of its subsidiaries or corporate +affiliates, (ii) against any party if such Patent Assertion arises in whole or +in part from any software, technology, product or service of Facebook or any of +its subsidiaries or corporate affiliates, or (iii) against any party relating +to the Software. Notwithstanding the foregoing, if Facebook or any of its +subsidiaries or corporate affiliates files a lawsuit alleging patent +infringement against you in the first instance, and you respond by filing a +patent infringement counterclaim in that lawsuit against that party that is +unrelated to the Software, the license granted hereunder will not terminate +under section (i) of this paragraph due to such counterclaim. + +A "Necessary Claim" is a claim of a patent owned by Facebook that is +necessarily infringed by the Software standing alone. + +A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, +or contributory infringement or inducement to infringe any patent, including a +cross-claim or counterclaim. diff --git a/README.md b/README.md new file mode 100644 index 0000000000..19543f155a --- /dev/null +++ b/README.md @@ -0,0 +1,156 @@ +# Docusaurus + +## Getting Started + +In your project repo, make sure you have a `docs` folder containing all of your documentation files written in markdown. Create a `website` folder inside which you will install and run docusaurus. If you wish, you can also include a `blog` folder in your project repo at the same level as the `docs` folder for blog posts. + +Install Docusaurus using `npm`: + +``` +cd website +npm install --save-dev docusaurus +``` + +In your `package.json` file, add the following scripts for docusaurus: + +```json +"scripts": { + "start": "docusaurus-start", + "build": "docusaurus-build", + "publish-gh-pages": "docusaurus-publish", + "examples": "docusaurus-examples" +} +``` + +To create example files for configuration, run `examples` using npm: + +``` +npm run examples +``` + +This will create the following files in your website folder: + +``` +core/Footer.js +example-docs/en/doc1.md +example-docs/en/doc2.md +example-docs/en/doc3.md +example-docs/en/exampledoc4.md +example-docs/en/exampledoc5.md +example-blog/2016-03-11-blog-post.md +example-blog/2017-04-10-blog-post-two.md +i18n/en.js +pages/en/help.js +pages/en/index.js +pages/en/users.js +static/img/... +languages.js +siteConfig.js +``` + +`examples` will not overwrite any existing files of the same name in your website folder. + +## Configuration + +The provided example files contain configurations for an example project `deltice/test-site` and with the documents in `example-docs/` and blog posts in `example-blog/`. These are provided for your reference to help you configure your project. + +### Document and Blog Front Matters + +Documentation should contain front matter that follows this example: +``` +--- +id: doc1 +title: Document Title +layout: docs1 +category: Sidebar Category 1 +permalink: docs/en/doc1.html +previous: doc0 +next: doc2 + +--- +``` + +Blog posts should be written as markdown files with the following front matter: +``` +--- +title: Blog Post Title +author: Author Name +authorURL: http://twitter.com/author +authorFBID: 21315325 +--- +``` +In the blog post you should include a line ``. This will determine under which point text will be ignored when generating the preview of your blog post. Blog posts should have the file name format: `yyyy-mm-dd-your-file-name.md`. + +### Language Configurations + +If you wish to support websites for other languages, the `languages.js` file provides a list of what languages you wish to enable. Files in the `i18n` folder will provide localized versions of various strings. + +If you only wish to have an English version of your site, the `i18n` folder and the `languages.js` file are not necessary to run Docusaurus and should be deleted. + +### Site Configurations + +Configure the siteConfig.js file which has comments guiding you through what needs to be done and how each configuration affects your website. + +Customize core/Footer.js which will serve as the footer for each page on your website. + +Include your own top-level pages as React components in `pages/`. These components should just be the body sections of the pages you want, and they will be included with the header and footer that the rest of Docusaurus uses. Examples are provided for your reference. Currently, if you want to add other React components to your pages, you must include all of it inside that file due to how `require` paths are set-up. You may also include `.html` files directly, but this is not recommended, and these will just be served as is and will not have any of the header/footer/styles shared by the rest of Docusaurus. + +All images and other static assets you wish to include should be placed inside the `static` folder. Any `.css` files provided in `static` will be concatenated to the standard styles provided by Docusaurus and used site-wide. + +Files placed in `static/` will be accessible in the following way: `static/img/image.png` will be accessible at `img/image.png`. + +## Using Docusaurus + +### Run the Server + +To run your website locally run the script: + +``` +npm run start +``` + +This will start a server hosting your website locally at `localhost:3000`. This server will ignore any occurences `siteConfig.baseUrl` in URLs, e.g. `localhost:3000/your-site/index.html` will be the same as `localhost:3000/index.html`. Any changes to configured files will be reflected by refreshing the page, i.e. the server does not need to be restarted to show changes. + + +### Build Static Pages + +To create a static build of your website, run the script: + +``` +npm run build +``` + +This will generate `.html` files from all of your docs and other pages included in `pages/`. This allows you to check whether or not all your files are being generated correctly. The build folder is inside Docusaurus's directory inside `node_modules`. + +### Publishing Your Website + +Use CircleCI to publish your website whenever your project repo is updated. Configure your circle.yml file in your project repo to run commands to publish to GitHub Pages. An example is shown here: + +```yaml +machine: + node: + version: 6.10.3 + npm: + version: 3.10.10 + +test: + override: + - "true" + +deployment: + website: + branch: master + commands: + - git config --global user.email "test-site-bot@users.noreply.github.com" + - git config --global user.name "Website Deployment Script" + - echo "machine github.com login test-site-bot password $GITHUB_TOKEN" > ~/.netrc + - cd website && npm install && GIT_USER=test-site-bot npm run publish-gh-pages +``` + +Note that in this case a GitHub user `test-site-bot` is created to use just for publishing. Make sure to give your Git user push permissions for your project and to set a GITHUB_TOKEN environment variable in Circle if you choose to publish this way. + +If you wish to manually publish your website with the `publish-gh-pages` script, run the following example command with the appropriate variables for your project: + +``` +DEPLOY_USER=deltice GIT_USER=test-site-bot CIRCLE_PROJECT_USERNAME=deltice CIRCLE_PROJECT_REPONAME=test-site CIRCLE_BRANCH=master npm run publish-gh-pages +``` diff --git a/examples/core/Footer.js b/examples/core/Footer.js new file mode 100644 index 0000000000..9ff597552c --- /dev/null +++ b/examples/core/Footer.js @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require("react"); + +const githubButton = ( + + Star + +); + +class Footer extends React.Component { + render() { + const currentYear = new Date().getFullYear(); + return ( + + ); + } +} + +module.exports = Footer; diff --git a/examples/example-blog/2016-03-11-blog-post.md b/examples/example-blog/2016-03-11-blog-post.md new file mode 100755 index 0000000000..eb9597895c --- /dev/null +++ b/examples/example-blog/2016-03-11-blog-post.md @@ -0,0 +1,18 @@ +--- +title: Blog Title +author: Blog Author +authorURL: http://twitter.com/ +authorFBID: 0 +--- + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus elementum massa eget nulla aliquet sagittis. Proin odio tortor, vulputate ut odio in, ultrices ultricies augue. Cras ornare ultrices lorem malesuada iaculis. Etiam sit amet libero tempor, pulvinar mauris sed, sollicitudin sapien. + + + +Mauris vestibulum ullamcorper nibh, ut semper purus pulvinar ut. Donec volutpat orci sit amet mauris malesuada, non pulvinar augue aliquam. Vestibulum ultricies at urna ut suscipit. Morbi iaculis, erat at imperdiet semper, ipsum nulla sodales erat, eget tincidunt justo dui quis justo. Pellentesque dictum bibendum diam at aliquet. Sed pulvinar, dolor quis finibus ornare, eros odio facilisis erat, eu rhoncus nunc dui sed ex. Nunc gravida dui massa, sed ornare arcu tincidunt sit amet. Maecenas efficitur sapien neque, a laoreet libero feugiat ut. + +Nulla facilisi. Maecenas sodales nec purus eget posuere. Sed sapien quam, pretium a risus in, porttitor dapibus erat. Sed sit amet fringilla ipsum, eget iaculis augue. Integer sollicitudin tortor quis ultricies aliquam. Suspendisse fringilla nunc in tellus cursus, at placerat tellus scelerisque. Sed tempus elit a sollicitudin rhoncus. Nulla facilisi. Morbi nec dolor dolor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras et aliquet lectus. Pellentesque sit amet eros nisi. Quisque ac sapien in sapien congue accumsan. Nullam in posuere ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin lacinia leo a nibh fringilla pharetra. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin venenatis lectus dui, vel ultrices ante bibendum hendrerit. Aenean egestas feugiat dui id hendrerit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur in tellus laoreet, eleifend nunc id, viverra leo. Proin vulputate non dolor vel vulputate. Curabitur pretium lobortis felis, sit amet finibus lorem suscipit ut. Sed non mollis risus. Duis sagittis, mi in euismod tincidunt, nunc mauris vestibulum urna, at euismod est elit quis erat. Phasellus accumsan vitae neque eu placerat. In elementum arcu nec tellus imperdiet, eget maximus nulla sodales. Curabitur eu sapien eget nisl sodales fermentum. + +Phasellus pulvinar ex id commodo imperdiet. Praesent odio nibh, sollicitudin sit amet faucibus id, placerat at metus. Donec vitae eros vitae tortor hendrerit finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque vitae purus dolor. Duis suscipit ac nulla et finibus. Phasellus ac sem sed dui dictum gravida. Phasellus eleifend vestibulum facilisis. Integer pharetra nec enim vitae mattis. Duis auctor, lectus quis condimentum bibendum, nunc dolor aliquam massa, id bibendum orci velit quis magna. Ut volutpat nulla nunc, sed interdum magna condimentum non. Sed urna metus, scelerisque vitae consectetur a, feugiat quis magna. Donec dignissim ornare nisl, eget tempor risus malesuada quis. \ No newline at end of file diff --git a/examples/example-blog/2017-04-10-blog-post-two.md b/examples/example-blog/2017-04-10-blog-post-two.md new file mode 100644 index 0000000000..35aeaece6d --- /dev/null +++ b/examples/example-blog/2017-04-10-blog-post-two.md @@ -0,0 +1,18 @@ +--- +title: New Blog Post +author: Blog Author +authorURL: http://twitter.com/ +authorFBID: 0 +--- + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus elementum massa eget nulla aliquet sagittis. Proin odio tortor, vulputate ut odio in, ultrices ultricies augue. Cras ornare ultrices lorem malesuada iaculis. Etiam sit amet libero tempor, pulvinar mauris sed, sollicitudin sapien. + + + +Mauris vestibulum ullamcorper nibh, ut semper purus pulvinar ut. Donec volutpat orci sit amet mauris malesuada, non pulvinar augue aliquam. Vestibulum ultricies at urna ut suscipit. Morbi iaculis, erat at imperdiet semper, ipsum nulla sodales erat, eget tincidunt justo dui quis justo. Pellentesque dictum bibendum diam at aliquet. Sed pulvinar, dolor quis finibus ornare, eros odio facilisis erat, eu rhoncus nunc dui sed ex. Nunc gravida dui massa, sed ornare arcu tincidunt sit amet. Maecenas efficitur sapien neque, a laoreet libero feugiat ut. + +Nulla facilisi. Maecenas sodales nec purus eget posuere. Sed sapien quam, pretium a risus in, porttitor dapibus erat. Sed sit amet fringilla ipsum, eget iaculis augue. Integer sollicitudin tortor quis ultricies aliquam. Suspendisse fringilla nunc in tellus cursus, at placerat tellus scelerisque. Sed tempus elit a sollicitudin rhoncus. Nulla facilisi. Morbi nec dolor dolor. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras et aliquet lectus. Pellentesque sit amet eros nisi. Quisque ac sapien in sapien congue accumsan. Nullam in posuere ante. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin lacinia leo a nibh fringilla pharetra. + +Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin venenatis lectus dui, vel ultrices ante bibendum hendrerit. Aenean egestas feugiat dui id hendrerit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur in tellus laoreet, eleifend nunc id, viverra leo. Proin vulputate non dolor vel vulputate. Curabitur pretium lobortis felis, sit amet finibus lorem suscipit ut. Sed non mollis risus. Duis sagittis, mi in euismod tincidunt, nunc mauris vestibulum urna, at euismod est elit quis erat. Phasellus accumsan vitae neque eu placerat. In elementum arcu nec tellus imperdiet, eget maximus nulla sodales. Curabitur eu sapien eget nisl sodales fermentum. + +Phasellus pulvinar ex id commodo imperdiet. Praesent odio nibh, sollicitudin sit amet faucibus id, placerat at metus. Donec vitae eros vitae tortor hendrerit finibus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque vitae purus dolor. Duis suscipit ac nulla et finibus. Phasellus ac sem sed dui dictum gravida. Phasellus eleifend vestibulum facilisis. Integer pharetra nec enim vitae mattis. Duis auctor, lectus quis condimentum bibendum, nunc dolor aliquam massa, id bibendum orci velit quis magna. Ut volutpat nulla nunc, sed interdum magna condimentum non. Sed urna metus, scelerisque vitae consectetur a, feugiat quis magna. Donec dignissim ornare nisl, eget tempor risus malesuada quis. \ No newline at end of file diff --git a/examples/example-docs/en/doc1.md b/examples/example-docs/en/doc1.md new file mode 100644 index 0000000000..8f2fd96029 --- /dev/null +++ b/examples/example-docs/en/doc1.md @@ -0,0 +1,163 @@ +--- +id: doc1 +title: Docusaurus +layout: docs +category: Docusaurus +permalink: docs/en/doc1.html +next: doc2 +--- + +## Getting Started + +In your project repo, make sure you have a `docs` folder containing all of your documentation files written in markdown. Create a `website` folder inside which you will install and run docusaurus. If you wish, you can also include a `blog` folder in your project repo at the same level as the `docs` folder for blog posts. + +Install Docusaurus using `npm`: + +``` +cd website +npm install --save-dev docusaurus +``` + +In your `package.json` file, add the following scripts for docusaurus: + +```json +"scripts": { + "start": "docusaurus-start", + "build": "docusaurus-build", + "publish-gh-pages": "docusaurus-publish", + "examples": "docusaurus-examples" +} +``` + +To create example files for configuration, run `examples` using npm: + +``` +npm run examples +``` + +This will create the following files in your website folder: + +``` +core/Footer.js +example-docs/en/doc1.md +example-docs/en/doc2.md +example-docs/en/doc3.md +example-docs/en/exampledoc4.md +example-docs/en/exampledoc5.md +example-blog/2016-03-11-blog-post.md +example-blog/2017-04-10-blog-post-two.md +i18n/en.js +pages/en/help.js +pages/en/index.js +pages/en/users.js +static/img/... +languages.js +siteConfig.js +``` + +`examples` will not overwrite any existing files of the same name in your website folder. + +## Configuration + +The provided example files contain configurations for an example project `deltice/test-site` and with the documents in `example-docs/` and blog posts in `example-blog/`. These are provided for your reference to help you configure your project. + +### Document and Blog Front Matters + +Documentation should contain front matter that follows this example: +``` +--- +id: doc1 +title: Document Title +layout: docs1 +category: Sidebar Category 1 +permalink: docs/en/doc1.html +previous: doc0 +next: doc2 + +--- +``` + +Blog posts should be written as markdown files with the following front matter: +``` +--- +title: Blog Post Title +author: Author Name +authorURL: http://twitter.com/author +authorFBID: 21315325 +--- +``` +In the blog post you should include a line ``. This will determine under which point text will be ignored when generating the preview of your blog post. Blog posts should have the file name format: `yyyy-mm-dd-your-file-name.md`. + +### Language Configurations + +If you wish to support websites for other languages, the `languages.js` file provides a list of what languages you wish to enable. Files in the `i18n` folder will provide localized versions of various strings. + +If you only wish to have an English version of your site, the `i18n` folder and the `languages.js` file are not necessary to run Docusaurus and should be deleted. + +### Site Configurations + +Configure the siteConfig.js file which has comments guiding you through what needs to be done and how each configuration affects your website. + +Customize core/Footer.js which will serve as the footer for each page on your website. + +Include your own top-level pages as React components in `pages/`. These components should just be the body sections of the pages you want, and they will be included with the header and footer that the rest of Docusaurus uses. Examples are provided for your reference. Currently, if you want to add other React components to your pages, you must include all of it inside that file due to how `require` paths are set-up. You may also include `.html` files directly, but this is not recommended, and these will just be served as is and will not have any of the header/footer/styles shared by the rest of Docusaurus. + +All images and other static assets you wish to include should be placed inside the `static` folder. Any `.css` files provided in `static` will be concatenated to the standard styles provided by Docusaurus and used site-wide. + +Files placed in `static/` will be accessible in the following way: `static/img/image.png` will be accessible at `img/image.png`. + +## Using Docusaurus + +### Run the Server + +To run your website locally run the script: + +``` +npm run start +``` + +This will start a server hosting your website locally at `localhost:3000`. This server will ignore any occurences `siteConfig.baseUrl` in URLs, e.g. `localhost:3000/your-site/index.html` will be the same as `localhost:3000/index.html`. Any changes to configured files will be reflected by refreshing the page, i.e. the server does not need to be restarted to show changes. + + +### Build Static Pages + +To create a static build of your website, run the script: + +``` +npm run build +``` + +This will generate `.html` files from all of your docs and other pages included in `pages/`. This allows you to check whether or not all your files are being generated correctly. The build folder is inside Docusaurus's directory inside `node_modules`. + +### Publishing Your Website + +Use CircleCI to publish your website whenever your project repo is updated. Configure your circle.yml file in your project repo to run commands to publish to GitHub Pages. An example is shown here: + +```yaml +machine: + node: + version: 6.10.3 + npm: + version: 3.10.10 + +test: + override: + - "true" + +deployment: + website: + branch: master + commands: + - git config --global user.email "test-site-bot@users.noreply.github.com" + - git config --global user.name "Website Deployment Script" + - echo "machine github.com login test-site-bot password $GITHUB_TOKEN" > ~/.netrc + - cd website && npm install && GIT_USER=test-site-bot npm run publish-gh-pages +``` + +Note that in this case a GitHub user `test-site-bot` is created to use just for publishing. Make sure to give your Git user push permissions for your project and to set a GITHUB_TOKEN environment variable in Circle if you choose to publish this way. + +If you wish to manually publish your website with the `publish-gh-pages` script, run the following example command with the appropriate variables for your project: + +``` +DEPLOY_USER=deltice GIT_USER=test-site-bot CIRCLE_PROJECT_USERNAME=deltice CIRCLE_PROJECT_REPONAME=test-site CIRCLE_BRANCH=master npm run publish-gh-pages +``` diff --git a/examples/example-docs/en/doc2.md b/examples/example-docs/en/doc2.md new file mode 100644 index 0000000000..ecf294ae9d --- /dev/null +++ b/examples/example-docs/en/doc2.md @@ -0,0 +1,12 @@ +--- +id: doc2 +title: document number 2 +layout: docs +category: First Category +permalink: docs/en/doc2.html +previous: doc1 +next: doc3 +--- + +This is a link to [another document.](/docs/en/doc3.md) +This is a link to an [external page.](http://www.example.com) diff --git a/examples/example-docs/en/doc3.md b/examples/example-docs/en/doc3.md new file mode 100644 index 0000000000..1a5a1c384f --- /dev/null +++ b/examples/example-docs/en/doc3.md @@ -0,0 +1,17 @@ +--- +id: doc3 +title: This is document number 3 +layout: docs +category: Second Category +permalink: docs/en/doc3.html +previous: doc2 +--- +Lorem ipsum dolor sit amet, consectetur adipiscing elit. In ac euismod odio, eu consequat dui. Nullam molestie consectetur risus id imperdiet. Proin sodales ornare turpis, non mollis massa ultricies id. Nam at nibh scelerisque, feugiat ante non, dapibus tortor. Vivamus volutpat diam quis tellus elementum bibendum. Praesent semper gravida velit quis aliquam. Etiam in cursus neque. Nam lectus ligula, malesuada et mauris a, bibendum faucibus mi. Phasellus ut interdum felis. Phasellus in odio pulvinar, porttitor urna eget, fringilla lectus. Aliquam sollicitudin est eros. Mauris consectetur quam vitae mauris interdum hendrerit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +Duis et egestas libero, imperdiet faucibus ipsum. Sed posuere eget urna vel feugiat. Vivamus a arcu sagittis, fermentum urna dapibus, congue lectus. Fusce vulputate porttitor nisl, ac cursus elit volutpat vitae. Nullam vitae ipsum egestas, convallis quam non, porta nibh. Morbi gravida erat nec neque bibendum, eu pellentesque velit posuere. Fusce aliquam erat eu massa eleifend tristique. + +Sed consequat sollicitudin ipsum eget tempus. Integer a aliquet velit. In justo nibh, pellentesque non suscipit eget, gravida vel lacus. Donec odio ante, malesuada in massa quis, pharetra tristique ligula. Donec eros est, tristique eget finibus quis, semper non nisl. Vivamus et elit nec enim ornare placerat. Sed posuere odio a elit cursus sagittis. + +Phasellus feugiat purus eu tortor ultrices finibus. Ut libero nibh, lobortis et libero nec, dapibus posuere eros. Sed sagittis euismod justo at consectetur. Nulla finibus libero placerat, cursus sapien at, eleifend ligula. Vivamus elit nisl, hendrerit ac nibh eu, ultrices tempus dui. Nam tellus neque, commodo non rhoncus eu, gravida in risus. Nullam id iaculis tortor. + +Nullam at odio in sem varius tempor sit amet vel lorem. Etiam eu hendrerit nisl. Fusce nibh mauris, vulputate sit amet ex vitae, congue rhoncus nisl. Sed eget tellus purus. Nullam tempus commodo erat ut tristique. Cras accumsan massa sit amet justo consequat eleifend. Integer scelerisque vitae tellus id consectetur. diff --git a/examples/example-docs/en/exampledoc4.md b/examples/example-docs/en/exampledoc4.md new file mode 100644 index 0000000000..344d059b54 --- /dev/null +++ b/examples/example-docs/en/exampledoc4.md @@ -0,0 +1,10 @@ +--- +id: doc4 +title: Other Document +layout: docs-other +category: First Category +permalink: docs/en/doc4.html +next: doc5 +--- + +this is another document \ No newline at end of file diff --git a/examples/example-docs/en/exampledoc5.md b/examples/example-docs/en/exampledoc5.md new file mode 100644 index 0000000000..48bc2939cd --- /dev/null +++ b/examples/example-docs/en/exampledoc5.md @@ -0,0 +1,10 @@ +--- +id: doc5 +title: Fifth Document +layout: docs-other +category: First Category +permalink: docs/en/doc5.html +previous: doc4 +--- + +Another one \ No newline at end of file diff --git a/examples/i18n/en.json b/examples/i18n/en.json new file mode 100644 index 0000000000..f7b3e9735e --- /dev/null +++ b/examples/i18n/en.json @@ -0,0 +1,59 @@ +{ + "localized-strings": { + "doc1": "Docusaurus", + "doc2": "The Second in a Series of Documents", + "doc3": "The Third in a Series of Documents", + "doc4": "Separate Sidebar Document 1", + "doc5": "Separate Sidebar Document 2", + "Docusaurus": "Docusaurus Guide", + "First Category": "Example Category 1", + "Second Category": "Example Category 2", + "previous": "Previous", + "next": "Continue Reading", + "Docs": "Docs", + "API": "API", + "GitHub": "GitHub", + "Help": "Help", + "Blog": "Blog" + }, + "tagline": "Tagline", + "pages-strings": { + "index": { + "My Tagline": "My Tagline", + "Try It Out": "Try It Out", + "Example Link": "Example Link", + "Example Link 2": "Example Link 2", + "This is the content of my feature": "This is the content of my feature", + "The content of my second feature": "The content of my second feature", + "These are features of this project": "These are features of this project", + "Talk about learning how to use this": "Talk about learning how to use this", + "Talk about trying this out": "Talk about trying this out", + "This is another description of how this project is useful": "This is another description of how this project is useful", + "This project is used by all these people": "This project is used by all these people", + "More \"Docusaurus\" Users": "More \"Docusaurus\" Users", + "Feature One": "Feature One", + "Feature Two": "Feature Two", + "Feature Callout": "Feature Callout", + "Learn How": "Learn How", + "Try it Out": "Try it Out", + "Description": "Description", + "Who's Using This?": "Who's Using This?" + }, + "help": { + "Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)": "Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)", + "Browse Docs": "Browse Docs", + "Ask questions about the documentation and project": "Ask questions about the documentation and project", + "Join the community": "Join the community", + "Find out what's new with this project": "Find out what's new with this project", + "Stay up to date": "Stay up to date", + "Need help?": "Need help?", + "This project is maintained by a dedicated group of people.": "This project is maintained by a dedicated group of people." + }, + "users": { + "Who's Using This?": "Who's Using This?", + "This project is used by many folks": "This project is used by many folks", + "Are you using this project?": "Are you using this project?", + "Add your company": "Add your company" + } + } +} diff --git a/examples/languages.js b/examples/languages.js new file mode 100644 index 0000000000..23d179c2da --- /dev/null +++ b/examples/languages.js @@ -0,0 +1,183 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const languages = [ + { + enabled: false, + name: "日本語", + tag: "ja" + }, + { + enabled: true, + name: "English", + tag: "en" + }, + { + enabled: false, + name: "العربية", + tag: "ar" + }, + { + enabled: false, + name: "Bosanski", + tag: "bs-BA" + }, + { + enabled: false, + name: "Català", + tag: "ca" + }, + { + enabled: false, + name: "Čeština", + tag: "cs" + }, + { + enabled: false, + name: "Dansk", + tag: "da" + }, + { + enabled: false, + name: "Deutsch", + tag: "de" + }, + { + enabled: false, + name: "Ελληνικά", + tag: "el" + }, + { + enabled: false, + name: "Español", + tag: "es-ES" + }, + { + enabled: false, + name: "فارسی", + tag: "fa-IR" + }, + { + enabled: false, + name: "Suomi", + tag: "fi" + }, + { + enabled: false, + name: "Français", + tag: "fr" + }, + { + enabled: false, + name: "עִברִית", + tag: "he" + }, + { + enabled: false, + name: "Magyar", + tag: "hu" + }, + { + enabled: false, + name: "Bahasa Indonesia", + tag: "id-ID" + }, + { + enabled: false, + name: "Italiano", + tag: "it" + }, + { + enabled: false, + name: "Afrikaans", + tag: "af" + }, + { + enabled: false, + name: "한국어", + tag: "ko" + }, + { + enabled: false, + name: "मराठी", + tag: "mr-IN" + }, + { + enabled: false, + name: "Nederlands", + tag: "nl" + }, + { + enabled: false, + name: "Norsk", + tag: "no-NO" + }, + { + enabled: false, + name: "Polskie", + tag: "pl" + }, + { + enabled: false, + name: "Português", + tag: "pt-PT" + }, + { + enabled: false, + name: "Português (Brasil)", + tag: "pt-BR" + }, + { + enabled: false, + name: "Română", + tag: "ro" + }, + { + enabled: false, + name: "Русский", + tag: "ru" + }, + { + enabled: false, + name: "Slovenský", + tag: "sk-SK" + }, + { + enabled: false, + name: "Српски језик (Ћирилица)", + tag: "sr" + }, + { + enabled: false, + name: "Svenska", + tag: "sv-SE" + }, + { + enabled: false, + name: "Türkçe", + tag: "tr" + }, + { + enabled: false, + name: "Українська", + tag: "uk" + }, + { + enabled: false, + name: "Tiếng Việt", + tag: "vi" + }, + { + enabled: false, + name: "中文", + tag: "zh-Hans" + }, + { enabled: false, name: "繁體中文", tag: "zh-Hant" } +]; +module.exports = languages; diff --git a/examples/pages/en/help.js b/examples/pages/en/help.js new file mode 100755 index 0000000000..354660daad --- /dev/null +++ b/examples/pages/en/help.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require("react"); + +const CompLibrary = require("../../core/CompLibrary.js"); +const Container = CompLibrary.Container; +const GridBlock = CompLibrary.GridBlock; + +const siteConfig = require(process.cwd() + "/siteConfig.js"); + +class Help extends React.Component { + render() { + const supportLinks = [ + { + content: + "Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)\n", + title: "Browse Docs" + }, + { + content: "Ask questions about the documentation and project\n", + title: "Join the community" + }, + { + content: "Find out what's new with this project\n", + title: "Stay up to date" + } + ]; + + return ( +
+
+ +
+
+

Need help?

+
+

This project is maintained by a dedicated group of people.

+ +
+
+
+
+ ); + } +} + +Help.defaultProps = { + language: "en" +}; + +module.exports = Help; diff --git a/examples/pages/en/index.js b/examples/pages/en/index.js new file mode 100755 index 0000000000..ac8b86af8f --- /dev/null +++ b/examples/pages/en/index.js @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require("react"); + +const CompLibrary = require("../../core/CompLibrary.js"); +const Marked = CompLibrary.Marked; /* Used to read markdown */ +const Container = CompLibrary.Container; +const GridBlock = CompLibrary.GridBlock; + +const siteConfig = require(process.cwd() + "/siteConfig.js"); + +class Button extends React.Component { + render() { + return ( +
+ + {this.props.children} + +
+ ); + } +} + +Button.defaultProps = { + target: "_self" +}; + +class HomeSplash extends React.Component { + render() { + return ( +
+
+
+
+ +
+
+

+ {siteConfig.title} + My Tagline +

+
+
+
+ + + +
+
+
+
+
+
+
+ ); + } +} + +class Index extends React.Component { + render() { + let language = this.props.language || "en"; + const showcase = siteConfig.users + .filter(user => { + return user.pinned; + }) + .map(user => { + return ( + + + + ); + }); + + return ( +
+ +
+ + + + +
+

Feature Callout

+ These are features of this project +
+ + + + + + + + + + + + + +
+

+ {"Who's Using This?"} +

+

This project is used by all these people

+
+ {showcase} +
+ +
+
+
+ ); + } +} + +module.exports = Index; diff --git a/examples/pages/en/users.js b/examples/pages/en/users.js new file mode 100644 index 0000000000..683b77e1d4 --- /dev/null +++ b/examples/pages/en/users.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require("react"); + +const CompLibrary = require("../../core/CompLibrary.js"); +const Container = CompLibrary.Container; + +// const siteConfig = require(process.cwd() + "/siteConfig.js"); + +class Users extends React.Component { + render() { + const showcase = siteConfig.users.map(user => { + return ( + + + + ); + }); + + return ( +
+
+ +
+
+

Who's Using This?

+

This project is used by many folks

+
+
+ {showcase} +
+

Are you using this project?

+ + Add your company + +
+
+
+
+ ); + } +} + +Users.defaultProps = { + language: "en" +}; + +module.exports = Users; diff --git a/examples/siteConfig.js b/examples/siteConfig.js new file mode 100644 index 0000000000..d8fdaf3373 --- /dev/null +++ b/examples/siteConfig.js @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const fs = require("fs"); + +/* List of projects/orgs using your project for the users page */ +const users = [ + { + caption: "User1", + image: "/test-site/img/docusaurus.svg", + infoLink: "https://www.example.com", + pinned: true + } +]; + +const siteConfig = { + title: "Test Site" /* title for your website */, + url: "https://deltice.github.io" /* your github url */, + baseUrl: "/test-site/" /* base url for your project */, + projectName: "test-site", + repo: "deltice/test-site" /* repo for your project */, + users, + /* base url for editing docs, usage example: editUrl + 'en/doc1.md' */ + editUrl: "https://github.com/deltice/test-site/edit/master/docs/", + /* header links for links on this site, 'LANGUAGE' will be replaced by whatever + language the page is for, ex: 'en' */ + headerLinksInternal: [ + { + section: "docs", + href: "/test-site/docs/LANGUAGE/doc1.html", + text: "Docs" + }, + { section: "api", href: "/test-site/docs/LANGUAGE/doc4.html", text: "API" }, + { section: "help", href: "/test-site/LANGUAGE/help.html", text: "Help" }, + { section: "blog", href: "/test-site/blog", text: "Blog" } + ], + /* header links for links outside the site */ + headerLinksExternal: [ + { + section: "github", + href: "https://github.com/deltice/test-site", + text: "GitHub" + } + ], + /* path to images for header/footer */ + headerIcon: "img/docusaurus.svg", + footerIcon: "img/docusaurus.svg", + favicon: "img/favicon.png", + /* default link for docsSidebar */ + docsSidebarDefaults: { + layout: "docs", + root: "/test-site/docs/en/doc1.html", + title: "Docs" + }, + /* colors for website */ + colors: { + primaryColor: "#2E8555", + secondaryColor: "#205C3B", + prismColor: + "rgba(46, 133, 85, 0.03)" /* primaryColor in rgba form, with 0.03 alpha */ + }, + tagline: "My Tagline", + recruitingLink: "https://crowdin.com/project/test-site" /* translation site "help translate" link */, + /* remove this section to disable search bar */ + algolia: { + apiKey: "0f9f28b9ab9efae89810921a351753b5", /* use your search-only api key */ + indexName: "github" + }, + /* remove this to disable google analytics tracking */ + /* gaTrackingId: "" */ +}; + +let languages; +if (fs.existsSync("./languages.js")) { + languages = require("./languages.js"); + siteConfig["en"] = require("./i18n/en.json"); +} else { + languages = [ + { + enabled: true, + name: "English", + tag: "en" + } + ]; +} + +const enabledLanguages = languages.filter(lang => lang.enabled); + +siteConfig["languages"] = enabledLanguages; + +/* INJECT LOCALIZED FILES BEGIN */ +/* INJECT LOCALIZED FILES END */ + +module.exports = siteConfig; diff --git a/examples/static/img/docusaurus.svg b/examples/static/img/docusaurus.svg new file mode 100644 index 0000000000..f80b2217c7 --- /dev/null +++ b/examples/static/img/docusaurus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/static/img/favicon.png b/examples/static/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..122f0a56c5bbaf730e8bd9357a9df215ac7c55d8 GIT binary patch literal 984 zcmV;}11J26P) zK~z}7?UqYy8&wpBzj=7ZuP`2CJIIU&xAlQP~ z1DgU83#2Y9!~!-5RV;`gC9OyzO4HCdZfPvi*tH!eu^Y#6JRT1lvuP8liM>JczdZMx zqhI%a=iUn~{ZDilhzqiC1AztLYha`qjipD((M4JODe`V4v43>`(avaR#ntWFC@vP? zGRtNdNCD}+8W0{K=Th(4-kLtBk3JAD7Gi~~x4*d^0>VITF9yUN;x6Dl;G(DBqv?bC z3)|$lwTSkTr{9wWj_!2__mu3EgIH_=IYAKY+ZmP}axOiQjspJx^NsF6PaQhr`lr{Is>P}o2m%a$I6NUc z)rq^0b7kQPykXlzq&bEEmk$)GVm*KA8Q9-CG1L@l2mmy0-S3U!U8aW z#c?21hw-Fjmkik{hj-{vG^?g;lnfVetr=5L1SWwMU=f%z%cgVYvzg^ezVZ-gxv5;r z+%(%Q({cjOHDd|@x`B@YACLfKPsDRi@hH*yy7?c#fg^#@(!J7U#jC8Q#!~KP891$I z$}!&|-@K};Mk!mGFWoKqfKvQIeA=v-(!iSoZpkJM19Y6|sLp;dd#XOJeqg!Lt9Z%W zG9&AW^@V&ae|qEY##4Q-_bn9W3V-M4^Zh-q^ej1ijuAiskQ|bly_(&0b-6Yxg~}oj zZ`8m#@H5~NW%0G4_lN#;_#G!4K}V(iNPD@QE3exgvmr`i06-9gHa((GCdZP8u}A?| zfNCReK_?=U+5v4LbT(v{?Q*!bRl8%9jQf^h8FrsNj7ax`MYT$8Ht|DZWo>4y1GoT; z1F<^TyE5=e@0s2w^&$P`#CM7D)xTClmTAR-c3@airOe1jBQ^xQ+ZET0S}Zx1yp_3< zc@_8^_+YmN&TD~He zpm;#>fZ~Bg_W%P0pMW6v0PF{Afd>2+EFB_6u9OQIt;R03UfoC6;Ik>>Q*lk-wE%iO zp}H2xVe}gG9M}ck0{4NqrJ*7gZ!SLOKkOI5@8;F!TC_#MQP2$r06o)GenVRb>;W8D zD7%D?X>1yA1l$Eq5VsTRW$HmsrRS9N3?s%OWBc;_<(-zbmVl$&(ZE;mE#7y%#2I|A zjo-_M>|5-COg^&(FNdS(h@d$ui+4JY<>iuXB~8$FQ>Yet7={@`-z|XVq!8%A6-L7h zXZkW*Y%kgxgc{+N^ei+dvs3NASiGq?kdm6xkA7(0j)3{J)2Vr>-$2K0(qh|eJI>~? z-S8XD2h9u3$sbZ()UcW`^k4Z~-O_qL$X%C>Yh{0s&$y<|G zCsYX+NEa_@0BVSO|fZ7K>{)>%F;*p%GZWfJqXZcL@?De$k)Ai@j7tLK0p!gt{(Z0RSsF{(nin5TT zbJ+E|s}=jQ!|}4C!H{Fkx3jWj3D0quz)=(*-Q>TAA@q0g#NjT*< zo54cbdUP(b+3Z>8tIhz`XTrJ5*^o?gVtZOqT0HjOL_d@xFZ8<$#hQtnhjPAvjzQ>b zMGoCqu(2SR<^mx zQ9ivLybZR2#mFl$tYV4>{+}KYV}`&XcNx`SM2s8NRL4q0*@x*G|M}pk#B}IqDy#5^ zC~EHqe|^p*DKP-P)25nQ>Zu)vYOH;HddW$j$IE=W#veIjrC0@-)Nj934ol@YWKnwr Oa;S{rb}D0*y!;b<+O}B$ literal 0 HcmV?d00001 diff --git a/examples/static/img/oss_logo.png b/examples/static/img/oss_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8183e289b139e5d03ff9870d3e6bfbcd968a5edd GIT binary patch literal 4370 zcmeH~_ct317sq4PRxxVNP(i6tp;qn04neJ|)z}oZVwKoxOKok;YRiLaOQ}6u)NUy; zs)UNsB9-9vob&z_?|JVJ_uPBV{hWL5_k4f3sTO92%nZB?004j)2Gz3!04NZbwLKlx zW&R?6PZt27{BB`_(7$Xi{vZEW;D1qpBoiCXOMm|fu{5&+@U?V-slyL1&e1G3i`%ZM zO&xk1`DZ83h5diEidP>;&>78rwbCD3v6g!kNfo&DPK7bO_*!NW=YzEm+PD581dZVC zS9Q;Jk6$!t9(RkkjBz{vRt|^|MuV^oBNM` zO>W=1msz(-LPu>kACG=)emyK1Mq$kS{>6|FyV>WzCiPW=6?={4VtMqUuyL+CQMKKP zBC z_y9kKZ}S^2WoZSgrIX%Y7WT=7FkAdi&4nAin(F7!>bLlI zad%;`0_VCtII?k~c^oGAL;pGA1>8)hau$C?TS<@g{mgZC>m~Ds$S;;Nfm%jvh(Bv^ zWc2q_D#;wWq^}D6aJ{x`>DMhNb4=vj^~Ghat$)|ma18(-9c9${cv9cG_1nZ)I!$C@ z;b>;^?~41=@^+NP&B?`~$TO;N_rR3RWJ3#X`J1C5ZtLL>Tyy6w*{}XBDSn`g`z$k6 zRI+(=N|QoXlHK<5;^BE^vg7rLS(J5$>v-X-9+$&ehY#wC=rxk8+wPHQ@)^}~L^yTM z*gX5EoEY&j zM)x*O%t`~gIb^PRvIFUNE8C5{{WoEg>%8IogXg?v+~OcXJ@bO_kI{MX&b^=Ur8ap5 zLzM^H@qeToAlRnp9(SCP*{X88)`ma!r}+~8Ax+NjO?m)IE9p;)cX*rg^E?eD(xI}nUoX9T@c zTDjin?b!Li&vyO~&&v-&PFK1<*u%mJTJvstb`#z}2|2X$-pohBc(|dhhlh`0N9;5I zKIAIoeGXccKA%27c(qGVCvJk-&#@$PBD`rzXwl4CZ?E0<-E8i{14^l>bx$LDi1r7 z%0;l%=_~J|NK@5)W1(Yz(7%-$Uym%kQ{xRK#N!A#FEU@2x63!9qwKU zVXJ)dP*#QDI642NLU5Zv(vgdLzzMWYn8yXq$hp4BIvbiB{YflNlG}Yegy~!&t>Ig5 zm67BZ1kGoHW~eGj{EixxQci8B)!xK?T|Uy3wX|*Q;mr;L*ib-vo204mC5PZ0OQxd~ zw|_SWVU-i`1Y067GfD*%*+nf?-Y_Z_)feI(=7@$3TmB56G>VHfEvY0v$|}*pf^^q13O# zD;1VxwP#o-@SZU~W52|?``W{l_>EbGmIO8G*;|z8;SX#$z**tbgk6YA8B%QyUx6EQLD3G>p-2h|r=;Ru|X z6m6gaAXz+uV4^J+cAv$w;Rd!KESa}MRF=ck_-gB#hBS#UtM5tKVuh(masF_5_@d1F zkw>jZM~kBBXBs1V<`?2`$7vob?P18X7~~Z&g|w*DG|T{uE!V`ghZgp1e2ln8t2nD# zl%A@`_gz+C2lw!Jg5O#cA}%TACin+S_kp?PW`=kUmba?62TFN=i2SV+uF5aP<7&9YaQ$G)=(#(-@_2j^ z_a>asZZ&Kd>lf%hz2ZSTG(HS>fi=X4dgs1}pn^gW>@14Pk;xn#y)dLJ6_0pUBssR^ zcp_TP;GY3+tK(1l8QX1-n53OmY7~(p0N+m$!%S?mMv-Z#(7LKqTXnhf8*Tk?oTf@) zTOf00EEI9#cyV98Qm4Hv#i1CKYT0m7434vF|JCsr2+wm(e{b1aCxGF3v!=({#V_qQ zv)NL_uDBYs9w~uxhF2=2R)IEQC6?L#kY*(oOunSJ;I>U#!U0EWJFf`%ZJh*+sX?IG zJ6%9q+6=*sv0JEvu+OHJ1h!#bm%kC#K{zFvTh{WYQi1s>r(N^if`5S57&O3wb@C6X z3)tBi8w4<4+1`sfB>g7YRX;f$uG;Ru^4iNuM!&PLO}MY=#^ki3mrZ|NkQAn($L4NM+QOgfP5ES7HcrN79&3;BPjl(%C9=VK z>GgLpML$ZVfp$`9!usvKs^-Od3(op8jS{rx;~Gtjy;o$%ecB7peBabb6fs3O)`CQh zbK}*&No+KVNclVAy)5PA+Sg|rmm))_)@rsBKZps`32zXFKZ_!sd<*1eqLDnC#N{R? zn9k12IZs6IdbJb3zL_+P&B~CjH{$({?P7;O^{K^gS1l{bP3FBI;9rdYaWs>8yf~l5 z3|m*L%7pD_kA(c>BU1sBM3ZEwzS zesj$`-(d5N=A&k7&Iyb7c6-$6;ep;pRqrPd?VT1%TF?wP9+(48H+*|mO9K-%ifA6K z>K=l?Tvn7v3^J<$#rpky29Pu$CvGdVB0`{J8HM|%pFX}6d993VlJC1XaxYzs*|lU>SdQGd-GTElbov>rBf*lJdBvr6wJ#nIa9nAhNQrlQjnK!6JI z#RNLSVZXyLSJj1|M+7|B96yL&afRx=9TcH9wDxvVEJB@zJ$XF&340D+m zp(0N^2YY%2RCv;&mFhU*PbK(0gDvMq{gq1un})l2iQI)ZtuB9$vnRb{%2=JNA8Zea zdYR;^$IO>)F`T;Uc(eFbjVlNH&f`3ek9DGViCYFu*tN%~of0*SZ1fU}jj1!BV?kr) z`_ZoPRqS~MuZplsP_mA?O#QP#sQx}EQLdh-dATJV-sC!z-e=vqdz=Un8(v%G{UCLo zQyoyx9e|i-h}k7%83`I_!+Tui|GfsA=JT%v+?*fe{60Ua?RvBh>7uLXOZLv(7@UTD z3|=4(OMX+tR(fREd#He?df1?~a~Q)O?GpPf_Yg75nMeCCh`kPrJ|)S#ReK65 zf>F*+y2wb+`(q~`S%qxApf2(u1q1O{KpeT(uUd z-&P9KIE*azsj;=*^^97PATOLUrZD7jOo(yP@n_#}u%fgR6srfxoA-8qV{jUx8{@m& z@743!eYtYPZyAgYN2^t_v*=t8Sv`8SxnA#W32Oj9Cer( z#e0t|wp%dy+1~*iN)FF+gHS!BKdd}Uh5y6=YhK-ni|E@u!iPJphfKeD+Q4HLHX9-k zp-9e^2ab#78{}*KeFwg@4-2%;#zekf1wAsDBE@pYQfkvN6|NANtMfxywcGSlwmMwb z03ty+WrY%5Sjiu|Tuj4|*2zwGUSSAk=3kygG+lD6+5443Zmtz@FAgQ)oS-a3iZ&ze zKDyg4y;M3u0$iHPY-KR2XBKl)EF?rM-fGd=T*r`)O!$hbIV)UJooQ{3#;akv1Ln=4 z;e?g4?tV?vS;_D_l;b)?6wet2i}t{Kp4t?nnneH6lC$j#)QCBF?|c(p*j(ZSBL9Y5-Lkzf&{=ZfX!zA{ z1B{6l&@@FtiDOyvnjSa0#Gg;a4YjJ!cR3_JlqN0gf%hC1SBRrRF@`$7oeEQ$*N33t zXS5l2iCjQhj0<+Oft-XUWN=s1iLDlCVPz;c>FSR=aThcj0#Q63lfI`C^sKQd= 0) { + url += 'page' + (page + 1) + '/'; + } + return url + '#content'; + }, + + render() { + const perPage = this.props.metadata.perPage; + const page = this.props.metadata.page; + return ( + +
+ + +
+ {MetadataBlog + .slice(page * perPage, (page + 1) * perPage) + .map(post => { + return ( + + ); + })} +
+ {page > 0 && + + ← Prev + } + {MetadataBlog.length > (page + 1) * perPage && + + Next → + } +
+
+
+
+
+ ); + }, +}); + +module.exports = BlogPageLayout; diff --git a/lib/core/BlogPost.js b/lib/core/BlogPost.js new file mode 100644 index 0000000000..3f92f32024 --- /dev/null +++ b/lib/core/BlogPost.js @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const Marked = require('./Marked.js'); +const React = require('react'); + +class BlogPost extends React.Component { + renderContent() { + let content = this.props.content; + if (this.props.truncate) { + content = content.split('')[0]; + return ( + + ); + } + return {content}; + } + + renderAuthorPhoto() { + const post = this.props.post; + if (post.authorFBID) { + return ( +
+ + + +
+ ); + } else { + return null; + } + } + + renderTitle() { + const post = this.props.post; + return ( +

+ {post.title} +

+ ); + } + + renderPostHeader() { + const post = this.props.post; + const match = post.path.match(/([0-9]+)\/([0-9]+)\/([0-9]+)/); + // Because JavaScript sucks at date handling :( + const year = match[1]; + const month = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ][parseInt(match[2], 10) - 1]; + const day = parseInt(match[3], 10); + + return ( +
+ {this.renderAuthorPhoto()} +

+ {post.author} +

+ {this.renderTitle()} +

+ {month} {day}, {year} +

+
+ ); + } + + render() { + return ( +
+ {this.renderPostHeader()} + {this.renderContent()} +
+ ); + } +} + +module.exports = BlogPost; diff --git a/lib/core/BlogPostLayout.js b/lib/core/BlogPostLayout.js new file mode 100644 index 0000000000..dab0433f20 --- /dev/null +++ b/lib/core/BlogPostLayout.js @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const BlogPost = require('./BlogPost.js'); +const BlogSidebar = require('./BlogSidebar.js'); +const Container = require('./Container.js'); +const Site = require('./Site.js'); + +class BlogPostLayout extends React.Component { + render() { + return ( + +
+ + +
+ +
+
+
+
+ ); + } +} + +module.exports = BlogPostLayout; diff --git a/lib/core/BlogSidebar.js b/lib/core/BlogSidebar.js new file mode 100644 index 0000000000..c4311dfba3 --- /dev/null +++ b/lib/core/BlogSidebar.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const Container = require('./Container.js'); +const SideNav = require('./nav/SideNav.js'); + +const MetadataBlog = require('./MetadataBlog.js'); + +class BlogSidebar extends React.Component { + render() { + const contents = [{ + name: 'Recent Posts', + links: MetadataBlog, + }]; + const title = this.props.current && this.props.current.title; + const current = { + id: title || '', + category: 'Recent Posts', + }; + return ( + + + + ); + } +} + +module.exports = BlogSidebar; diff --git a/lib/core/CompLibrary.js b/lib/core/CompLibrary.js new file mode 100644 index 0000000000..1e6f3bee71 --- /dev/null +++ b/lib/core/CompLibrary.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const Marked = require('./Marked.js'); +const Container = require('./Container.js'); +const GridBlock = require('./GridBlock.js'); + +module.exports = { + Marked: Marked, + Container: Container, + GridBlock: GridBlock +} diff --git a/lib/core/Container.js b/lib/core/Container.js new file mode 100644 index 0000000000..6dca6d8ca1 --- /dev/null +++ b/lib/core/Container.js @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const classNames = require('classnames'); + +class Container extends React.Component { + render() { + const containerClasses = classNames('container', this.props.className, { + 'darkBackground': this.props.background === 'dark', + 'highlightBackground': this.props.background === 'highlight', + 'lightBackground': this.props.background === 'light', + 'paddingAll': this.props.padding.indexOf('all') >= 0, + 'paddingBottom': this.props.padding.indexOf('bottom') >= 0, + 'paddingLeft': this.props.padding.indexOf('left') >= 0, + 'paddingRight': this.props.padding.indexOf('right') >= 0, + 'paddingTop': this.props.padding.indexOf('top') >= 0, + }); + let wrappedChildren; + + if (this.props.wrapper) { + wrappedChildren = +
{this.props.children}
; + } else { + wrappedChildren = this.props.children; + } + return ( +
+ {wrappedChildren} +
+ ); + } +} + +Container.defaultProps = { + background: 'transparent', + padding: [], + wrapper: true, +}; + +module.exports = Container; diff --git a/lib/core/Doc.js b/lib/core/Doc.js new file mode 100644 index 0000000000..97022dfd9c --- /dev/null +++ b/lib/core/Doc.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const Marked = require('./Marked.js'); + +class Doc extends React.Component { + render() { + let editLink = ( + + Edit this Doc + + ); + return ( +
+
+ {editLink} +

{this.props.title}

+
+
+ {this.props.content} +
+
+ ); + } +} + +module.exports = Doc; diff --git a/lib/core/DocsLayout.js b/lib/core/DocsLayout.js new file mode 100644 index 0000000000..ba846a5448 --- /dev/null +++ b/lib/core/DocsLayout.js @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const Container = require('./Container.js'); +const Doc = require('./Doc.js'); +const DocsSidebar = require('./DocsSidebar.js'); +const Site = require('./Site.js'); + +class DocsLayout extends React.Component { + render() { + const metadata = this.props.metadata; + const content = this.props.children; + const i18n = this.props.config[this.props.metadata.language]; + return ( + + + + ); + } +} +module.exports = DocsLayout; diff --git a/lib/core/DocsSidebar.js b/lib/core/DocsSidebar.js new file mode 100644 index 0000000000..9c6024d4b1 --- /dev/null +++ b/lib/core/DocsSidebar.js @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const Metadata = require('./metadata.js'); +const React = require('react'); +const Container = require('./Container.js'); +const SideNav = require('./nav/SideNav.js'); +const siteConfig = require(process.cwd() + '/siteConfig.js'); + +class DocsSidebar extends React.Component { + render() { + let layout = this.props.metadata.layout; + let docsCategories = require('./' + layout + 'Categories.js'); + return ( + + + + ); + } +} + +DocsSidebar.propTypes = { + layout: React.PropTypes.string, + root: React.PropTypes.string, + title: React.PropTypes.string, +}; + +DocsSidebar.defaultProps = siteConfig.docsSidebarDefaults; + +module.exports = DocsSidebar; diff --git a/lib/core/Footer.js b/lib/core/Footer.js new file mode 100644 index 0000000000..4036f0def2 --- /dev/null +++ b/lib/core/Footer.js @@ -0,0 +1,111 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); + +const githubButton = ( + + Star + +); + +class Footer extends React.Component { + render() { + const currentYear = new Date().getFullYear(); + return ( + + ); + } +} + + + +module.exports = Footer; diff --git a/lib/core/GridBlock.js b/lib/core/GridBlock.js new file mode 100755 index 0000000000..30820def69 --- /dev/null +++ b/lib/core/GridBlock.js @@ -0,0 +1,83 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const classNames = require('classnames'); + +const Marked = require('./Marked.js'); + +class GridBlock extends React.Component { + renderBlock(block) { + const blockClasses = classNames('blockElement', this.props.className, { + 'alignCenter': this.props.align === 'center', + 'alignRight': this.props.align === 'right', + 'fourByGridBlock': this.props.layout === 'fourColumn', + 'imageAlignBottom': (block.image && block.imageAlign === 'bottom'), + 'imageAlignSide': (block.image && (block.imageAlign === 'left' || + block.imageAlign === 'right')), + 'imageAlignTop': (block.image && block.imageAlign === 'top'), + 'threeByGridBlock': this.props.layout === 'threeColumn', + 'twoByGridBlock': this.props.layout === 'twoColumn', + }); + + const topLeftImage = (block.imageAlign === 'top' || + block.imageAlign === 'left') && + this.renderBlockImage(block.image); + + const bottomRightImage = (block.imageAlign === 'bottom' || + block.imageAlign === 'right') && + this.renderBlockImage(block.image); + + return ( +
+ {topLeftImage} +
+ {this.renderBlockTitle(block.title)} + {block.content} +
+ {bottomRightImage} +
+ ); + } + + renderBlockImage(image) { + if (image) { + return ( +
+ ); + } else { + return null; + } + } + + renderBlockTitle(title) { + if (title) { + return

{title}

; + } else { + return null; + } + } + + render() { + return ( +
+ {this.props.contents.map(this.renderBlock, this)} +
+ ); + } +} + +GridBlock.defaultProps = { + align: 'left', + contents: [], + imagealign: 'top', + layout: 'twoColumn', +}; + +module.exports = GridBlock; diff --git a/lib/core/Head.js b/lib/core/Head.js new file mode 100644 index 0000000000..41c0849730 --- /dev/null +++ b/lib/core/Head.js @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); + +class Head extends React.Component { + render() { + /* + + + + + + + + + + + + */ + + return ( + + + + {this.props.title} + + + + + + + + {this.props.config.algolia && + + } + + + + ); + } +} + +module.exports = Head; diff --git a/lib/core/Header.js b/lib/core/Header.js new file mode 100644 index 0000000000..dbe789265b --- /dev/null +++ b/lib/core/Header.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const toSlug = require('./toSlug.js'); + +const Header = React.createClass({ + render() { + const slug = toSlug(this.props.toSlug || this.props.children); + const Heading = 'h' + this.props.level; + + return ( + + + {this.props.children} + {' '}# + + ); + }, +}); + +module.exports = Header; diff --git a/lib/core/Marked.js b/lib/core/Marked.js new file mode 100644 index 0000000000..e6c35a3f43 --- /dev/null +++ b/lib/core/Marked.js @@ -0,0 +1,1060 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const Prism = require('./Prism.js'); +const Header = require('./Header.js'); + +/** + * Block-Level Grammar + */ + +const block = { + newline: /^\n+/, + code: /^( {4}[^\n]+\n*)+/, + fences: noop, + hr: /^( *[-*_]){3,} *(?:\n+|$)/, + heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, + nptable: noop, + lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, + blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, + list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, + def: /^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, + table: noop, + paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, + text: /^[^\n]+/, +}; + +block.bullet = /(?:[*+-]|\d+\.)/; +block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; +block.item = replace(block.item, 'gm')(/bull/g, block.bullet)(); + +block.list = replace(block.list)(/bull/g, block.bullet)('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)(); + +block._tag = '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' + + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' + + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b'; + +block.html = replace(block.html)('comment', //)('closed', /<(tag)[\s\S]+?<\/\1>/)('closing', /])*?>/)(/tag/g, block._tag)(); + +block.paragraph = replace(block.paragraph)('hr', block.hr)('heading', block.heading)('lheading', block.lheading)('blockquote', block.blockquote)('tag', '<' + block._tag)('def', block.def)(); + +/** + * Normal Block Grammar + */ + +block.normal = merge({}, block); + +/** + * GFM Block Grammar + */ + +block.gfm = merge({}, block.normal, { + fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/, + paragraph: /^/, +}); + +block.gfm.paragraph = replace(block.paragraph)('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')(); + +/** + * GFM + Tables Block Grammar + */ + +block.tables = merge({}, block.gfm, { + nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, + table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/, +}); + +/** + * Block Lexer + */ + +function Lexer(options) { + this.tokens = []; + this.tokens.links = {}; + this.options = options || marked.defaults; + this.rules = block.normal; + + if (this.options.gfm) { + if (this.options.tables) { + this.rules = block.tables; + } else { + this.rules = block.gfm; + } + } +} + +/** + * Expose Block Rules + */ + +Lexer.rules = block; + +/** + * Static Lex Method + */ + +Lexer.lex = function(src, options) { + const lexer = new Lexer(options); + return lexer.lex(src); +}; + +/** + * Preprocessing + */ + +Lexer.prototype.lex = function(src) { + src = src + .replace(/\r\n|\r/g, '\n') + .replace(/\t/g, ' ') + .replace(/\u00a0/g, ' ') + .replace(/\u2424/g, '\n'); + + return this.token(src, true); +}; + +/** + * Lexing + */ + +Lexer.prototype.token = function(_src, top) { + let src = _src.replace(/^ +$/gm, ''); + let next; + let loose; + let cap; + let bull; + let b; + let item; + let space; + let i; + let l; + + while (src) { + // newline + if (cap = this.rules.newline.exec(src)) { + src = src.substring(cap[0].length); + if (cap[0].length > 1) { + this.tokens.push({ + type: 'space', + }); + } + } + + // code + if (cap = this.rules.code.exec(src)) { + src = src.substring(cap[0].length); + cap = cap[0].replace(/^ {4}/gm, ''); + this.tokens.push({ + type: 'code', + text: !this.options.pedantic + ? cap.replace(/\n+$/, '') + : cap, + }); + continue; + } + + // fences (gfm) + if (cap = this.rules.fences.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'code', + lang: cap[2], + text: cap[3], + }); + continue; + } + + // heading + if (cap = this.rules.heading.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'heading', + depth: cap[1].length, + text: cap[2], + }); + continue; + } + + // table no leading pipe (gfm) + if (top && (cap = this.rules.nptable.exec(src))) { + src = src.substring(cap[0].length); + + item = { + type: 'table', + header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3].replace(/\n$/, '').split('\n'), + }; + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = item.cells[i].split(/ *\| */); + } + + this.tokens.push(item); + + continue; + } + + // lheading + if (cap = this.rules.lheading.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'heading', + depth: cap[2] === '=' ? 1 : 2, + text: cap[1], + }); + continue; + } + + // hr + if (cap = this.rules.hr.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'hr', + }); + continue; + } + + // blockquote + if (cap = this.rules.blockquote.exec(src)) { + src = src.substring(cap[0].length); + + this.tokens.push({ + type: 'blockquote_start', + }); + + cap = cap[0].replace(/^ *> ?/gm, ''); + + // Pass `top` to keep the current + // "toplevel" state. This is exactly + // how markdown.pl works. + this.token(cap, top); + + this.tokens.push({ + type: 'blockquote_end', + }); + + continue; + } + + // list + if (cap = this.rules.list.exec(src)) { + src = src.substring(cap[0].length); + bull = cap[2]; + + this.tokens.push({ + type: 'list_start', + ordered: bull.length > 1, + }); + + // Get each top-level item. + cap = cap[0].match(this.rules.item); + + next = false; + l = cap.length; + i = 0; + + for (; i < l; i++) { + item = cap[i]; + + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) +/, ''); + + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { // eslint-disable-line + space -= item.length; + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (this.options.smartLists && i !== l - 1) { + b = block.bullet.exec(cap[i + 1])[0]; + if (bull !== b && !(bull.length > 1 && b.length > 1)) { + src = cap.slice(i + 1).join('\n') + src; + i = l - 1; + } + } + + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item[item.length - 1] === '\n'; + if (!loose) {loose = next;} + } + + this.tokens.push({ + type: loose + ? 'loose_item_start' + : 'list_item_start', + }); + + // Recurse. + this.token(item, false); + + this.tokens.push({ + type: 'list_item_end', + }); + } + + this.tokens.push({ + type: 'list_end', + }); + + continue; + } + + // html + if (cap = this.rules.html.exec(src)) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: this.options.sanitize + ? 'paragraph' + : 'html', + pre: cap[1] === 'pre' || cap[1] === 'script', + text: cap[0], + }); + continue; + } + + // def + if (top && (cap = this.rules.def.exec(src))) { + src = src.substring(cap[0].length); + this.tokens.links[cap[1].toLowerCase()] = { + href: cap[2], + title: cap[3], + }; + continue; + } + + // table (gfm) + if (top && (cap = this.rules.table.exec(src))) { + src = src.substring(cap[0].length); + + item = { + type: 'table', + header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n'), + }; + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = item.cells[i] + .replace(/^ *\| *| *\| *$/g, '') + .split(/ *\| */); + } + + this.tokens.push(item); + + continue; + } + + // top-level paragraph + if (top && (cap = this.rules.paragraph.exec(src))) { + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'paragraph', + text: cap[1][cap[1].length - 1] === '\n' + ? cap[1].slice(0, -1) + : cap[1], + }); + continue; + } + + // text + if (cap = this.rules.text.exec(src)) { + // Top-level should never reach here. + src = src.substring(cap[0].length); + this.tokens.push({ + type: 'text', + text: cap[0], + }); + continue; + } + + if (src) { + throw new + Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return this.tokens; +}; + +/** + * Inline-Level Grammar + */ + +const inline = { + escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, + autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, + url: noop, + tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, + link: /^!?\[(inside)\]\(href\)/, + reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, + nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, + strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, + em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, + code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/, + br: /^ {2,}\n(?!\s*$)/, + del: noop, + text: /^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; + +inline.link = replace(inline.link)('inside', inline._inside)('href', inline._href)(); + +inline.reflink = replace(inline.reflink)('inside', inline._inside)(); + +/** + * Normal Inline Grammar + */ + +inline.normal = merge({}, inline); + +/** + * Pedantic Inline Grammar + */ + +inline.pedantic = merge({}, inline.normal, { + strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, +}); + +/** + * GFM Inline Grammar + */ + +inline.gfm = merge({}, inline.normal, { + escape: replace(inline.escape)('])', '~|])')(), + url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/, + del: /^~~(?=\S)([\s\S]*?\S)~~/, + text: replace(inline.text)(']|', '~]|')('|', '|https?://|')(), +}); + +/** + * GFM + Line Breaks Inline Grammar + */ + +inline.breaks = merge({}, inline.gfm, { + br: replace(inline.br)('{2,}', '*')(), + text: replace(inline.gfm.text)('{2,}', '*')(), +}); + +/** + * Inline Lexer & Compiler + */ + +function InlineLexer(links, options) { + this.options = options || marked.defaults; + this.links = links; + this.rules = inline.normal; + + if (!this.links) { + throw new + Error('Tokens array requires a `links` property.'); + } + + if (this.options.gfm) { + if (this.options.breaks) { + this.rules = inline.breaks; + } else { + this.rules = inline.gfm; + } + } else if (this.options.pedantic) { + this.rules = inline.pedantic; + } +} + +/** + * Expose Inline Rules + */ + +InlineLexer.rules = inline; + +/** + * Static Lexing/Compiling Method + */ + +InlineLexer.output = function(src, links, options) { + const inline = new InlineLexer(links, options); + return inline.output(src); +}; + +/** + * Lexing/Compiling + */ + +InlineLexer.prototype.output = function(src) { + const out = []; + let link; + let text; + let href; + let cap; + + while (src) { + // escape + if (cap = this.rules.escape.exec(src)) { + src = src.substring(cap[0].length); + out.push(cap[1]); + continue; + } + + // autolink + if (cap = this.rules.autolink.exec(src)) { + src = src.substring(cap[0].length); + if (cap[2] === '@') { + text = cap[1][6] === ':' + ? cap[1].substring(7) + : cap[1]; + href = 'mailto:' + text; + } else { + text = cap[1]; + href = text; + } + out.push(React.DOM.a({href: this.sanitizeUrl(href)}, text)); + continue; + } + + // url (gfm) + if (cap = this.rules.url.exec(src)) { + src = src.substring(cap[0].length); + text = cap[1]; + href = text; + out.push(React.DOM.a({href: this.sanitizeUrl(href)}, text)); + continue; + } + + // tag + if (cap = this.rules.tag.exec(src)) { + src = src.substring(cap[0].length); + // TODO(alpert): Don't escape if sanitize is false + out.push(cap[0]); + continue; + } + + // link + if (cap = this.rules.link.exec(src)) { + src = src.substring(cap[0].length); + out.push(this.outputLink(cap, { + href: cap[2], + title: cap[3], + })); + continue; + } + + // reflink, nolink + if ((cap = this.rules.reflink.exec(src)) + || (cap = this.rules.nolink.exec(src))) { + src = src.substring(cap[0].length); + link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = this.links[link.toLowerCase()]; + if (!link || !link.href) { + out.push.apply(out, this.output(cap[0][0])); + src = cap[0].substring(1) + src; + continue; + } + out.push(this.outputLink(cap, link)); + continue; + } + + // strong + if (cap = this.rules.strong.exec(src)) { + src = src.substring(cap[0].length); + out.push(React.DOM.strong(null, this.output(cap[2] || cap[1]))); + continue; + } + + // em + if (cap = this.rules.em.exec(src)) { + src = src.substring(cap[0].length); + out.push(React.DOM.em(null, this.output(cap[2] || cap[1]))); + continue; + } + + // code + if (cap = this.rules.code.exec(src)) { + src = src.substring(cap[0].length); + out.push(React.DOM.code(null, cap[2])); + continue; + } + + // br + if (cap = this.rules.br.exec(src)) { + src = src.substring(cap[0].length); + out.push(React.DOM.br(null, null)); + continue; + } + + // del (gfm) + if (cap = this.rules.del.exec(src)) { + src = src.substring(cap[0].length); + out.push(React.DOM.del(null, this.output(cap[1]))); + continue; + } + + // text + if (cap = this.rules.text.exec(src)) { + src = src.substring(cap[0].length); + out.push(this.smartypants(cap[0])); + continue; + } + + if (src) { + throw new + Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return out; +}; + +/** + * Sanitize a URL for a link or image + */ + +InlineLexer.prototype.sanitizeUrl = function(url) { + if (this.options.sanitize) { + try { + const prot = decodeURIComponent(url) + .replace(/[^A-Za-z0-9:]/g, '') + .toLowerCase(); + if (prot.indexOf('javascript:') === 0) { // eslint-disable-line + return '#'; + } + } catch (e) { + return '#'; + } + } + return url; +}; + +/** + * Compile Link + */ + +InlineLexer.prototype.outputLink = function(cap, link) { + if (cap[0][0] !== '!') { + const shouldOpenInNewWindow = + link.href.charAt(0) !== '/' + && link.href.charAt(0) !== '#'; + + return React.DOM.a({ + href: this.sanitizeUrl(link.href), + title: link.title, + target: shouldOpenInNewWindow ? '_blank' : '', + }, this.output(cap[1])); + } else { + return React.DOM.img({ + src: this.sanitizeUrl(link.href), + alt: cap[1], + title: link.title, + }, null); + } +}; + +/** + * Smartypants Transformations + */ + +InlineLexer.prototype.smartypants = function(text) { + if (!this.options.smartypants) {return text;} + return text + .replace(/--/g, '\u2014') + .replace(/'([^']*)'/g, '\u2018$1\u2019') + .replace(/"([^"]*)"/g, '\u201C$1\u201D') + .replace(/\.{3}/g, '\u2026'); +}; + +/** + * Parsing & Compiling + */ + +function Parser(options) { + this.tokens = []; + this.token = null; + this.options = options || marked.defaults; +} + +/** + * Static Parse Method + */ + +Parser.parse = function(src, options) { + const parser = new Parser(options); + return parser.parse(src); +}; + +/** + * Parse Loop + */ + +Parser.prototype.parse = function(src) { + this.inline = new InlineLexer(src.links, this.options); + this.tokens = src.reverse(); + + const out = []; + while (this.next()) { + out.push(this.tok()); + } + + return out; +}; + +/** + * Next Token + */ + +Parser.prototype.next = function() { + return this.token = this.tokens.pop(); +}; + +/** + * Preview Next Token + */ + +Parser.prototype.peek = function() { + return this.tokens[this.tokens.length - 1] || 0; +}; + +/** + * Parse Text Tokens + */ + +Parser.prototype.parseText = function() { + let body = this.token.text; + + while (this.peek().type === 'text') { + body += '\n' + this.next().text; + } + + return this.inline.output(body); +}; + +/** + * Parse Current Token + */ + +Parser.prototype.tok = function() { // eslint-disable-line + switch (this.token.type) { + case 'space': { + return []; + } + case 'hr': { + return React.DOM.hr(null, null); + } + case 'heading': { + return ( +
+ {this.inline.output(this.token.text)} +
+ ); + } + case 'code': { + return {this.token.text}; + } + case 'table': { + const table = []; + const body = []; + let row = []; + let heading; + let i; + let cells; + let j; + + // header + for (i = 0; i < this.token.header.length; i++) { + heading = this.inline.output(this.token.header[i]); + row.push(React.DOM.th( + this.token.align[i] + ? {style: {textAlign: this.token.align[i]}} + : null, + heading + )); + } + table.push(React.DOM.thead(null, React.DOM.tr(null, row))); + + // body + for (i = 0; i < this.token.cells.length; i++) { + row = []; + cells = this.token.cells[i]; + for (j = 0; j < cells.length; j++) { + row.push(React.DOM.td( + this.token.align[j] + ? {style: {textAlign: this.token.align[j]}} + : null, + this.inline.output(cells[j]) + )); + } + body.push(React.DOM.tr(null, row)); + } + table.push(React.DOM.thead(null, body)); + + return React.DOM.table(null, table); + } + case 'blockquote_start': { + const body = []; + + while (this.next().type !== 'blockquote_end') { + body.push(this.tok()); + } + + return React.DOM.blockquote(null, body); + } + case 'list_start': { + const type = this.token.ordered ? 'ol' : 'ul'; + const body = []; + + while (this.next().type !== 'list_end') { + body.push(this.tok()); + } + + return React.DOM[type](null, body); + } + case 'list_item_start': { + const body = []; + + while (this.next().type !== 'list_item_end') { + body.push(this.token.type === 'text' + ? this.parseText() + : this.tok()); + } + + return React.DOM.li(null, body); + } + case 'loose_item_start': { + const body = []; + + while (this.next().type !== 'list_item_end') { + body.push(this.tok()); + } + + return React.DOM.li(null, body); + } + case 'html': { + return React.DOM.div({ + dangerouslySetInnerHTML: { + __html: this.token.text, + }, + }); + } + case 'paragraph': { + return this.options.paragraphFn + ? this.options.paragraphFn.call(null, this.inline.output(this.token.text)) + : React.DOM.p(null, this.inline.output(this.token.text)); + } + case 'text': { + return this.options.paragraphFn + ? this.options.paragraphFn.call(null, this.parseText()) + : React.DOM.p(null, this.parseText()); + } + } +}; + +/** + * Helpers + */ + +function replace(regex, opt) { + regex = regex.source; + opt = opt || ''; + return function self(name, val) { + if (!name) {return new RegExp(regex, opt);} + val = val.source || val; + val = val.replace(/(^|[^\[])\^/g, '$1'); + regex = regex.replace(name, val); + return self; + }; +} + +function noop() {} +noop.exec = noop; + +function merge(obj) { + let i = 1; + let target; + let key; + + for (; i < arguments.length; i++) { + target = arguments[i]; + for (key in target) { + if (Object.prototype.hasOwnProperty.call(target, key)) { + obj[key] = target[key]; + } + } + } + + return obj; +} + +/** + * Marked + */ + +function marked(src, opt, callback) { + if (callback || typeof opt === 'function') { + if (!callback) { + callback = opt; + opt = null; + } + + if (opt) {opt = merge({}, marked.defaults, opt);} + + const highlight = opt.highlight; + let tokens; + let pending; + let i = 0; + + try { + tokens = Lexer.lex(src, opt); + } catch (e) { + return callback(e); + } + + pending = tokens.length; + + const done = function(hi) { + let out, err; + + if (hi !== true) { + delete opt.highlight; + } + + try { + out = Parser.parse(tokens, opt); + } catch (e) { + err = e; + } + + opt.highlight = highlight; + + return err + ? callback(err) + : callback(null, out); + }; + + if (!highlight || highlight.length < 3) { + return done(true); + } + + if (!pending) {return done();} + + for (; i < tokens.length; i++) { + (function(token) { + if (token.type !== 'code') { + return --pending || done(); + } + return highlight(token.text, token.lang, (err, code) => { + if (code == null || code === token.text) { + return --pending || done(); + } + token.text = code; + token.escaped = true; + --pending || done(); + return undefined; + }); + })(tokens[i]); + } + + return undefined; + } + try { + if (opt) {opt = merge({}, marked.defaults, opt);} + return Parser.parse(Lexer.lex(src, opt), opt); + } catch (e) { + e.message += '\nPlease report this to https://github.com/chjj/marked.'; + if ((opt || marked.defaults).silent) { + return [React.DOM.p(null, 'An error occurred:'), + React.DOM.pre(null, e.message)]; + } + throw e; + } +} + +/** + * Options + */ + +marked.options = +marked.setOptions = function(opt) { + merge(marked.defaults, opt); + return marked; +}; + +marked.defaults = { + gfm: true, + tables: true, + breaks: false, + pedantic: false, + sanitize: false, + smartLists: false, + silent: false, + highlight: null, + langPrefix: 'lang-', + smartypants: false, + paragraphFn: null, +}; + +/** + * Expose + */ + +marked.Parser = Parser; +marked.parser = Parser.parse; + +marked.Lexer = Lexer; +marked.lexer = Lexer.lex; + +marked.InlineLexer = InlineLexer; +marked.inlineLexer = InlineLexer.output; + +marked.parse = marked; + +class Marked extends React.Component { + render() { + return
{marked(this.props.children, this.props)}
; + } +} + +module.exports = Marked; diff --git a/lib/core/Prism.js b/lib/core/Prism.js new file mode 100644 index 0000000000..d5f5781f31 --- /dev/null +++ b/lib/core/Prism.js @@ -0,0 +1,569 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const unindent = require('./unindent.js'); + +/* http://prismjs.com/download.html?themes=prism&languages=markup+clike+javascript+jsx */ +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * MIT license https://www.opensource.org/licenses/mit-license.php/ + * @author Lea Verou https://lea.verou.me + */ + +// Private helper vars +const lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i; + +const _ = Prism = { + util: { + encode(tokens) { + if (tokens instanceof Token) { + return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); + } else if (_.util.type(tokens) === 'Array') { + return tokens.map(_.util.encode); + } else { + return tokens.replace(/&/g, '&').replace(/ { return _.util.clone(v); }); + } + + return o; + }, + }, + + languages: { + extend(id, redef) { + const lang = _.util.clone(_.languages[id]); + + for (const key in redef) { + lang[key] = redef[key]; + } + + return lang; + }, + + /** + * Insert a token before another token in a language literal + * As this needs to recreate the object (we cannot actually insert before keys in object literals), + * we cannot just provide an object, we need an object and a key. + * @param inside The key (or language id) of the parent + * @param before The key to insert before. If not provided, the function appends instead. + * @param insert Object with the key/value pairs to insert + * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted. + */ + insertBefore(inside, before, insert, root) { + root = root || _.languages; + const grammar = root[inside]; + + if (arguments.length == 2) { + insert = arguments[1]; + + for (var newToken in insert) { + if (insert.hasOwnProperty(newToken)) { + grammar[newToken] = insert[newToken]; + } + } + + return grammar; + } + + const ret = {}; + + for (const token in grammar) { + + if (grammar.hasOwnProperty(token)) { + + if (token == before) { + + for (var newToken in insert) { + + if (insert.hasOwnProperty(newToken)) { + ret[newToken] = insert[newToken]; + } + } + } + + ret[token] = grammar[token]; + } + } + + // Update references in other language definitions + _.languages.DFS(_.languages, function(key, value) { + if (value === root[inside] && key != inside) { + this[key] = ret; + } + }); + + return root[inside] = ret; + }, + + // Traverse a language definition with Depth First Search + DFS(o, callback, type) { + for (const i in o) { + if (o.hasOwnProperty(i)) { + callback.call(o, i, o[i], type || i); + + if (_.util.type(o[i]) === 'Object') { + _.languages.DFS(o[i], callback); + } else if (_.util.type(o[i]) === 'Array') { + _.languages.DFS(o[i], callback, i); + } + } + } + }, + }, + + highlightAll(async, callback) { + const elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'); + + for (let i = 0, element; element = elements[i++];) { + _.highlightElement(element, async === true, callback); + } + }, + + highlightElement(element, async, callback) { + // Find language + let language, grammar, parent = element; + + while (parent && !lang.test(parent.className)) { + parent = parent.parentNode; + } + + if (parent) { + language = (parent.className.match(lang) || [, ''])[1]; + grammar = _.languages[language]; + } + + // Set language on the element, if not present + element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + + // Set language on the parent, for styling + parent = element.parentNode; + + if (/pre/i.test(parent.nodeName)) { + parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; + } + + if (!grammar) { + return; + } + + let code = element.textContent; + + if (!code) { + return; + } + + code = code.replace(/^(?:\r?\n|\r)/, ''); + + const env = { + element, + language, + grammar, + code, + }; + + _.hooks.run('before-highlight', env); + + if (async && _self.Worker) { + const worker = new Worker(_.filename); + + worker.onmessage = function(evt) { + env.highlightedCode = Token.stringify(JSON.parse(evt.data), language); + + _.hooks.run('before-insert', env); + + env.element.innerHTML = env.highlightedCode; + + callback && callback.call(env.element); + _.hooks.run('after-highlight', env); + }; + + worker.postMessage(JSON.stringify({ + language: env.language, + code: env.code, + })); + } else { + env.highlightedCode = _.highlight(env.code, env.grammar, env.language); + + _.hooks.run('before-insert', env); + + env.element.innerHTML = env.highlightedCode; + + callback && callback.call(element); + + _.hooks.run('after-highlight', env); + } + }, + + highlight(text, grammar, language) { + const tokens = _.tokenize(text, grammar); + return Token.stringify(_.util.encode(tokens), language); + }, + + tokenize(text, grammar, language) { + const Token = _.Token; + + const strarr = [text]; + + const rest = grammar.rest; + + if (rest) { + for (var token in rest) { + grammar[token] = rest[token]; + } + + delete grammar.rest; + } + + tokenloop: for (var token in grammar) { + if (!grammar.hasOwnProperty(token) || !grammar[token]) { + continue; + } + + let patterns = grammar[token]; + patterns = (_.util.type(patterns) === 'Array') ? patterns : [patterns]; + + for (let j = 0; j < patterns.length; ++j) { + let pattern = patterns[j], + inside = pattern.inside, + lookbehind = !!pattern.lookbehind, + lookbehindLength = 0, + alias = pattern.alias; + + pattern = pattern.pattern || pattern; + + for (let i = 0; i < strarr.length; i++) { // Don't cache length as it changes during the loop + + const str = strarr[i]; + + if (strarr.length > text.length) { + // Something went terribly wrong, ABORT, ABORT! + break tokenloop; + } + + if (str instanceof Token) { + continue; + } + + pattern.lastIndex = 0; + + var match = pattern.exec(str); + + if (match) { + if (lookbehind) { + lookbehindLength = match[1].length; + } + + var from = match.index - 1 + lookbehindLength, + match = match[0].slice(lookbehindLength), + len = match.length, + to = from + len, + before = str.slice(0, from + 1), + after = str.slice(to + 1); + + const args = [i, 1]; + + if (before) { + args.push(before); + } + + const wrapped = new Token(token, inside ? _.tokenize(match, inside) : match, alias); + + args.push(wrapped); + + if (after) { + args.push(after); + } + + Array.prototype.splice.apply(strarr, args); + } + } + } + } + + return strarr; + }, + + hooks: { + all: {}, + + add(name, callback) { + const hooks = _.hooks.all; + + hooks[name] = hooks[name] || []; + + hooks[name].push(callback); + }, + + run(name, env) { + const callbacks = _.hooks.all[name]; + + if (!callbacks || !callbacks.length) { + return; + } + + for (let i = 0, callback; callback = callbacks[i++];) { + callback(env); + } + }, + }, +}; + +const Token = _.Token = function(type, content, alias) { + this.type = type; + this.content = content; + this.alias = alias; +}; + +Token.reactify = function(o, language, parent, key) { + if (typeof o == 'string') { + return o; + } + + if (_.util.type(o) === 'Array') { + return o.map((element, i) => { + return Token.reactify(element, language, o, i); + }); + } + + const env = { + type: o.type, + content: Token.reactify(o.content, language, parent), + tag: 'span', + classes: ['token', o.type], + attributes: {key}, + language, + parent, + }; + + if (env.type == 'comment') { + env.attributes.spellCheck = true; + } + + if (o.alias) { + const aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias]; + Array.prototype.push.apply(env.classes, aliases); + } + + _.hooks.run('wrap', env); + + env.attributes.className = env.classes.join(' '); + + return React.DOM[env.tag](env.attributes, env.content); +}; + +Prism.languages.markup = { + 'comment': //, + 'prolog': /<\?[\w\W]+?\?>/, + 'doctype': //, + 'cdata': //i, + 'tag': { + pattern: /<\/?[^\s>\/]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i, + inside: { + 'tag': { + pattern: /^<\/?[^\s>\/]+/i, + inside: { + 'punctuation': /^<\/?/, + 'namespace': /^[^\s>\/:]+:/, + }, + }, + 'attr-value': { + pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i, + inside: { + 'punctuation': /[=>"']/, + }, + }, + 'punctuation': /\/?>/, + 'attr-name': { + pattern: /[^\s>\/]+/, + inside: { + 'namespace': /^[^\s>\/:]+:/, + }, + }, + + }, + }, + 'entity': /&#?[\da-z]{1,8};/i, +}; + +// Plugin to make entity title show the real entity, idea by Roman Komarov +Prism.hooks.add('wrap', env => { + + if (env.type === 'entity') { + env.attributes['title'] = env.content.replace(/&/, '&'); + } +}); + +Prism.languages.clike = { + 'comment': [ + { + pattern: /(^|[^\\])\/\*[\w\W]*?\*\//, + lookbehind: true, + }, + { + pattern: /(^|[^\\:])\/\/.*/, + lookbehind: true, + }, + ], + 'string': /("|')(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, + 'class-name': { + pattern: /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i, + lookbehind: true, + inside: { + punctuation: /(\.|\\)/, + }, + }, + 'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, + 'boolean': /\b(true|false)\b/, + 'function': /[a-z0-9_]+(?=\()/i, + 'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/, + 'operator': /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/, + 'punctuation': /[{}[\];(),.:]/, +}; + +Prism.languages.javascript = Prism.languages.extend('clike', { + 'keyword': /\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/, + 'number': /\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/, + 'function': /(?!\d)[a-z0-9_$]+(?=\()/i, +}); + +Prism.languages.insertBefore('javascript', 'keyword', { + 'regex': { + pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/, + lookbehind: true, + }, +}); + +Prism.languages.insertBefore('javascript', 'class-name', { + 'template-string': { + pattern: /`(?:\\`|\\?[^`])*`/, + inside: { + 'interpolation': { + pattern: /\$\{[^}]+\}/, + inside: { + 'interpolation-punctuation': { + pattern: /^\$\{|\}$/, + alias: 'punctuation', + }, + rest: Prism.languages.javascript, + }, + }, + 'string': /[\s\S]+/, + }, + }, +}); + +if (Prism.languages.markup) { + Prism.languages.insertBefore('markup', 'tag', { + 'script': { + pattern: /[\w\W]*?<\/script>/i, + inside: { + 'tag': { + pattern: /|<\/script>/i, + inside: Prism.languages.markup.tag.inside, + }, + rest: Prism.languages.javascript, + }, + alias: 'language-javascript', + }, + }); +} + +(function(Prism) { + + const javascript = Prism.util.clone(Prism.languages.javascript); + + Prism.languages.jsx = Prism.languages.extend('markup', javascript); + Prism.languages.jsx.tag.pattern = /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+|(\{[\w\W]*?\})))?\s*)*\/?>/i; + + Prism.languages.jsx.tag.inside['attr-value'].pattern = /=[^\{](?:('|")[\w\W]*?(\1)|[^\s>]+)/i; + + Prism.languages.insertBefore('inside', 'attr-value', { + 'script': { + pattern: /=(\{[\w\W]*?\})/i, + inside: { + 'function' : Prism.languages.javascript.function, + 'punctuation': /[={}[\];(),.:]/, + 'keyword': Prism.languages.javascript.keyword, + }, + 'alias': 'language-javascript', + }, + }, Prism.languages.jsx.tag); + +}(Prism)); + +const PrismComponent = React.createClass({ + statics: { + _, + }, + getDefaultProps() { + return { + language: 'javascript', + }; + }, + render() { + const lines = []; + if (this.props.line) { + this.props.line.split(',').forEach(range => { + const parts = range.split('-'); + if (parts.length === 1) { + lines.push(parts[0].trim()); + } else { + const start = parseInt(parts[0].trim(), 10); + const end = parseInt(parts[1].trim(), 10); + for (let ii = start; ii <= end; ii++) { + lines.push(ii); + } + } + }); + } + const grammar = _.languages[this.props.language]; + return ( +
+        {Token.reactify(_.tokenize(this.props.children, grammar))}
+        {lines.map((line, ii) => {
+          return (
+            
+ ); + })} +
+ ); + }, +}); + +module.exports = PrismComponent; diff --git a/lib/core/Site.js b/lib/core/Site.js new file mode 100644 index 0000000000..b5edb8b45e --- /dev/null +++ b/lib/core/Site.js @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const React = require('react'); +const HeaderNav = require('./nav/HeaderNav.js'); +const Head = require('./Head.js'); +const Footer = require(process.cwd() + '/core/Footer.js'); + +class Site extends React.Component { + /* + goes in body after navPusher + +
+