update website
31
README.md
@@ -29,7 +29,7 @@ mdxc example.mdx
|
||||
|
||||
Other ways to use MDX include:
|
||||
|
||||
- Use it with [Sitepack](#sitepack) to build static websites
|
||||
- Use it with [create-react-app](#create-react-app) to build static websites
|
||||
- Use it with [Webpack](#webpack-with-mdx-loader)
|
||||
- Use the [API](#api) directly
|
||||
|
||||
@@ -306,22 +306,26 @@ Options:
|
||||
-u, --unwrapped don't wrap the content in a React component
|
||||
```
|
||||
|
||||
### Sitepack
|
||||
### create-react-app
|
||||
|
||||
**MDXC was originally created as a plugin for Sitepack.**
|
||||
MDX can be used with unejected create-react-app projects! To start, you'll need to add a `.babelrc` file to the root level of your project:
|
||||
|
||||
[Sitepack](http://github.com/jamesknelson/sitepack) is a wrapper around Webpack. It gives you a way to add pages to your website using plain-old `require()`, it handles the nasty parts of Webpack configuration for you, and it does all this while performing the magic required to build a static HTML version of each of your pages. As it happens, the MDXC website is built with Sitepack.
|
||||
|
||||
If your plan is to use MDX to write an actual *website* (you know, with pages and links and no "login" button), then Sitepack is worth giving a try. It's documentation is still in its infancy, but you can get around this by using the **sitepack-react-starter-kit** which supports MDX out of the box.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/jamesknelson/sitepack-react-starter-kit.git
|
||||
cd sitepack-react-starter-kit
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
{
|
||||
"presets": ["babel-preset-react-app"]
|
||||
}
|
||||
```
|
||||
|
||||
Once you've cloned, installed and started sitepack, open your browser at <http://localhost:4000> and start editing the `md` files in the `content` directory -- changes will be reflected live! When you're ready to release, build your site with `npm run build`.
|
||||
Then, you can import a component from any Markdown file by prepending the filename with `!babel-loader!mdx-loader!`. For example:
|
||||
|
||||
```
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import DocumentComponent from '!babel-loader!mdx-loader!../pages/index.md'
|
||||
```
|
||||
|
||||
You can also import documents dynamically using the proposed `import()` syntax.
|
||||
|
||||
For an example of a statically rendered site using create-react-site and MDX, see [the source](https://github.com/jamesknelson/junctions/tree/master/site) for the [Junctions router site](https://junctions.js.org/tutorial/#Markdown-Components).
|
||||
|
||||
### Webpack with mdx-loader
|
||||
|
||||
@@ -470,6 +474,7 @@ module.exports = function mdxLoader(content) {
|
||||
## MDX in the wild
|
||||
|
||||
- [junctions](https://junctions.js.org), a router for React ([website source](https://github.com/jamesknelson/junctions/tree/master/docs))
|
||||
- [React Armory](https://reactarmory.com)
|
||||
- *create a PR to add your own site!*
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
70
package.json
@@ -1,62 +1,18 @@
|
||||
{
|
||||
"name": "mdxc",
|
||||
"version": "1.0.0",
|
||||
"description": "A tool to convert Markdown into React components",
|
||||
"author": "James K Nelson <james@jamesknelson.com>",
|
||||
"license": "MIT",
|
||||
"main": "lib/mdxc.js",
|
||||
"bin": {
|
||||
"mdxc": "./bin/mdxc.js"
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"cross-env": "^5.0.5",
|
||||
"lerna": "^2.1.2",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf lib",
|
||||
"build:watch": "cross-env BABEL_ENV=commonjs babel --watch --source-maps=inline -d lib/ source/",
|
||||
"build": "cross-env BABEL_ENV=commonjs babel source --out-dir lib",
|
||||
"prepublish": "npm run clean && npm run build",
|
||||
"test": "npm run build && mocha test/*.test.js",
|
||||
"site:start": "sitepack start -c site/sitepack.config.js",
|
||||
"site:clean": "rimraf site/build",
|
||||
"site:build": "npm run site:clean && sitepack build -c site/sitepack.config.js -o site/build",
|
||||
"site:publish": "npm run site:build && cp ./CNAME site/build && cd site/build && git init && git commit --allow-empty -m 'update site' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'update site' && git push git@github.com:jamesknelson/mdxc gh-pages --force",
|
||||
"site:view": "sitepack view -d site/build"
|
||||
"build": "lerna run --parallel build",
|
||||
"build:watch": "lerna run --parallel build:watch",
|
||||
"test": "lerna run --parallel test",
|
||||
"test:watch": "lerna run --parallel test:watch"
|
||||
},
|
||||
"keywords": [
|
||||
"markdown",
|
||||
"jsx",
|
||||
"mdx"
|
||||
],
|
||||
"devDependencies": {
|
||||
"armo-breadboard": "0.2.2",
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-plugin-transform-class-properties": "^6.22.0",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.22.0",
|
||||
"babel-preset-latest": "^6.22.0",
|
||||
"babel-preset-react": "^6.23.0",
|
||||
"classnames": "^2.2.5",
|
||||
"cross-env": "^3.1.4",
|
||||
"exenv": "^1.2.2",
|
||||
"less": "^2.7.2",
|
||||
"less-loader": "^4.0.2",
|
||||
"loader-utils": "^1.1.0",
|
||||
"markdown-it-testgen": "^0.1.4",
|
||||
"mocha": "^3.2.0",
|
||||
"prismjs": "^1.6.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"react": "^15.4.2",
|
||||
"react-dom": "^15.4.2",
|
||||
"react-textarea-autosize": "^4.1.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"sitepack": "^1.0.0-beta.12",
|
||||
"sitepack-react": "1.0.0-beta.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-core": "^6.24.0",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"babel-plugin-transform-react-jsx": "^6.23.0",
|
||||
"commander": "^2.9.0",
|
||||
"front-matter": "^2.1.2",
|
||||
"markdown-it": "^8.2.2",
|
||||
"parsimmon": "^1.2.0",
|
||||
"slugify": "^1.1.0"
|
||||
}
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"site"
|
||||
]
|
||||
}
|
||||
|
||||
3
site/.babelrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["babel-preset-react-app"]
|
||||
}
|
||||
21
site/.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Your Application component is the top-level component of your React
|
||||
* application. It is used by both `main.js` and `renderToString.js`.
|
||||
*
|
||||
* The `<Router>` component that is provided by sitepack-react will
|
||||
* use the `history` object to select the current page from the `site` object.
|
||||
*
|
||||
* As the `site` object contains a tree of Pages, the selected Page will
|
||||
* likely have a number of ancestors. The Router will iterate through these
|
||||
* ancestors, rendering any `wrapper` component that is specified.
|
||||
*
|
||||
* For example, if the current Page is a direct child of the root page, the
|
||||
* Router will render a tree of components that looks like so:
|
||||
*
|
||||
* +-------------------------+
|
||||
* | Root Page Wrapper |
|
||||
* | +---------------------+ |
|
||||
* | | Contet Page Wrapper | |
|
||||
* | +---------------------+ |
|
||||
* +-------------------------+
|
||||
*
|
||||
* The Root Page Wrapper will be rendered for every page, so it is a good
|
||||
* place to put your site's header/footer.
|
||||
*
|
||||
* If you'd like to make navigation menus specific to one section, a Wrapper
|
||||
* is a good place to put them.
|
||||
*
|
||||
* Finally, the Wrapper for the selected page can render content-specific
|
||||
* elements like titles, metadata and loading spinners.
|
||||
*/
|
||||
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { Router } from 'sitepack-react'
|
||||
|
||||
const Application = ({ site, history }) =>
|
||||
<Router site={site} history={history} />
|
||||
|
||||
export default Application
|
||||
@@ -1,13 +0,0 @@
|
||||
export default {
|
||||
wrapper: 'SiteWrapper',
|
||||
title: "MDXC",
|
||||
metaTitle: "MDXC: Use React Components from Markdown",
|
||||
metaDescription: "MDXC is a tool to convert Markdown into React Components, making it possible to import and use React Components within your Markdown!",
|
||||
content: require('./home.md'),
|
||||
children: [
|
||||
require('../../examples/props.mdx'),
|
||||
require('../../examples/import.mdx'),
|
||||
require('../../examples/basics.mdx'),
|
||||
require('../../examples/factories.mdx'),
|
||||
]
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* Sitepack uses the function exported by this file to create the Site object
|
||||
* that is passed to your `<Application>` element in `main.js` and
|
||||
* `renderToString.js`
|
||||
*
|
||||
* The Site object is created by passing your site's root Page to `createSite`.
|
||||
* To get your root Page object, just `require()` it.
|
||||
*
|
||||
* The resultant `Site` object has two properties:
|
||||
*
|
||||
* - `rootPage`, the Page which sits at the root of your site
|
||||
* - `pages`, an object which contains all Pages within your site
|
||||
*
|
||||
* Actually, all of the pages in `pages` are also available under `rootPage` --
|
||||
* they're just located under the `children` or `content` of another page.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Because Sites and Pages are just JavaScript objects, they can be passed to
|
||||
* functions like any other JavaScript object. Functions that take a `Site` and
|
||||
* return a new `Site` are called **Transforms**.
|
||||
*
|
||||
* You can pass a transform to `createSite` as its second argument. Of course,
|
||||
* you'll often want to perform more than one transform on a Site. You can do
|
||||
* this with the `createSiteTransformer` function, which combines multiple
|
||||
* transforms into a single transform that runs through its arguments in order.
|
||||
*
|
||||
* Sitepack provides a number of useful transforms that allow you to add and
|
||||
* modify your Page's options.
|
||||
*/
|
||||
|
||||
import './global.less'
|
||||
import React from 'react'
|
||||
import { createSite, createSiteTransformer, Transforms } from 'sitepack'
|
||||
import { sitepackReactTransform } from 'sitepack-react'
|
||||
|
||||
export default ({ environment }) => {
|
||||
const siteTransformer = createSiteTransformer(
|
||||
// Use `MDXWrapper` by default for any files ending with `.md` or `.mdx`.
|
||||
Transforms.addDefaultsByPattern({
|
||||
test: /\.mdx?$/,
|
||||
options: {
|
||||
wrapper: 'MDXWrapper',
|
||||
},
|
||||
}),
|
||||
|
||||
// Add metadata used by the elements provided by `sitepack-react`,
|
||||
// including `<Router>`, `<Link>` and `<PageContentLoader>`.
|
||||
sitepackReactTransform(),
|
||||
|
||||
Transforms.consume([
|
||||
'description',
|
||||
'author',
|
||||
'banner',
|
||||
]),
|
||||
|
||||
// Convert `wrapper` strings into React components by requiring a
|
||||
// file based on the string.
|
||||
Transforms.consumeByMap(
|
||||
'wrapper',
|
||||
wrapper => wrapper && require('./wrappers/'+wrapper+'.js').default
|
||||
),
|
||||
)
|
||||
|
||||
// Create a Site object whose root page will be the Page described by
|
||||
// `../content/index.page.js`.
|
||||
//
|
||||
// This Site object will be passed through each of the transforms
|
||||
// defined above, from top to bottom.
|
||||
const site = createSite(require('./content/index.page.js'), siteTransformer)
|
||||
|
||||
return site
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* You can add any global CSS to this file, but prefer component-specific CSS
|
||||
* files where possible.
|
||||
*/
|
||||
|
||||
@import '~prismjs/themes/prism-tomorrow.css';
|
||||
|
||||
@import url('https://fonts.googleapis.com/css?family=Inconsolata|Roboto:400,700');
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#app, #app > div {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
pre, code { font-family: Inconsolata, monospace; line-height: 1.5 }
|
||||
pre { background: rgb(45, 45, 45); padding: 10px; border-radius: 3px; color: rgb(205, 205, 205); }
|
||||
pre code { font-size: 12px; white-space: pre-wrap; }
|
||||
code { font-size: 16px; }
|
||||
h1 { font-family: Inconsolata, monospace; margin: 40px 0 10px 0; font-size: 200%; }
|
||||
h2 { font-family: Inconsolata, monospace; margin: 30px 0 0 0; font-size: 150%; color: rgb(81, 81, 81); }
|
||||
h2 code { font-size: 100%; font-weight: 100; }
|
||||
h2 + p { margin-top: 10px; }
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
}
|
||||
img + em {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
li { margin: 4px 0; }
|
||||
|
||||
h1, h2, h3 { position: relative; }
|
||||
|
||||
p { margin: 1em 0; }
|
||||
|
||||
th {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
table td,
|
||||
table th {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
a { color: #a00; text-decoration: none }
|
||||
@@ -1,42 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title><%= page.title %></title>
|
||||
|
||||
<meta property="og:site_name" content="MDXC" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:creator" content="James K Nelson" />
|
||||
|
||||
<% if (page.metaDescription) { %>
|
||||
<meta name="description" content="<%- page.metaDescription %>" />
|
||||
<meta property="og:description" content="<%- page.metaDescription %>" />
|
||||
<meta name="twitter:description" content="<%- page.metaDescription %>" />
|
||||
|
||||
<meta property="og:title" content="<%- page.metaTitle || page.title %>" />
|
||||
<meta name="twitter:title" content="<%- page.metaTitle || page.title %>" />
|
||||
<% } %>
|
||||
<% if (page.metaImage) { %>
|
||||
<meta property="og:image" content="<%- page.metaImage %>" />
|
||||
<meta name="twitter:image" content="<%- page.metaImage %>" />
|
||||
<% } %>
|
||||
|
||||
<% files.css.forEach(function(file) { %>
|
||||
<link rel="stylesheet" type="text/css" href="<%- file %>">
|
||||
<% }); %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<%= content %>
|
||||
</div>
|
||||
|
||||
<!-- Place this tag in your head or just before your close body tag. -->
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
|
||||
<% files.js.forEach(function(file) { %>
|
||||
<script type="text/javascript" src="<%- file %>"></script>
|
||||
<% }); %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +0,0 @@
|
||||
const url = require('url')
|
||||
const path = require('path')
|
||||
const loaderUtils = require('loader-utils')
|
||||
const frontMatter = require('front-matter')
|
||||
const { loadPageWithContent } = require('sitepack/lib/loaderUtils')
|
||||
|
||||
|
||||
module.exports = function rawPageLoader(content) {
|
||||
const loaderOptions = loaderUtils.getOptions(this) || {};
|
||||
const data = frontMatter(content);
|
||||
return loadPageWithContent(this, loaderOptions, data.attributes, 'module.exports = '+JSON.stringify(data.body))
|
||||
}
|
||||
39
site/main.js
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* This file is used to tell Sitepack how to load your app once the page's
|
||||
* JavaScript has been loaded.
|
||||
*
|
||||
* Sitepack will call the default export, passing in an object with `history`
|
||||
* and `site` keys. These two arguments are also passed to the function
|
||||
* exported by `renderToString.js`, allowing re-use of the `Application`
|
||||
* component between both files.
|
||||
*
|
||||
* - `history` is a History object, produced by the history package. It
|
||||
* contains the URL for your application, and can be used with routers
|
||||
* like react-router and junctions.
|
||||
*
|
||||
* See https://github.com/mjackson/history for more details.
|
||||
*
|
||||
* - `site` contains a Site object. This object has two properties:
|
||||
*
|
||||
* + `rootPage` points to the root Page for your site
|
||||
* + `pages` contains an object with all pages in your site, keyed by
|
||||
* page ID.
|
||||
*
|
||||
* The `main` function also receives a string specifying the current
|
||||
* environment, which will either be "production" or "development".
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import Application from './Application'
|
||||
|
||||
export default function main({ environment, history, site }) {
|
||||
ReactDOM.render(
|
||||
React.createElement(Application, {
|
||||
environment: environment,
|
||||
history: history,
|
||||
site: site,
|
||||
}),
|
||||
document.getElementById('app')
|
||||
)
|
||||
}
|
||||
28
site/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "site",
|
||||
"version": "0.4.4",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"junctions": "^0.4.6",
|
||||
"junctions-static": "^0.4.6",
|
||||
"prismjs": "^1.6.0",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-junctions": "^0.4.4",
|
||||
"react-scripts": "1.0.17",
|
||||
"react-textarea-autosize": "^4.1.0",
|
||||
"rimraf": "^2.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf build",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build && junctions-static build -m build/static/js/main.*.js -r create-react-app",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"publish": "npm run clean && npm run build && cp ../CNAME ./build && cd build && git init && git commit --allow-empty -m 'update docs' && git checkout -b gh-pages && touch .nojekyll && git add . && git commit -am 'update docs' && git push git@github.com:jamesknelson/mdxc gh-pages --force",
|
||||
"view": "junctions-static view -p 3000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"raw-loader": "^0.5.1"
|
||||
}
|
||||
}
|
||||
BIN
site/public/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
site/public/android-chrome-384x384.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
site/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
9
site/public/browserconfig.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
site/public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 537 B |
BIN
site/public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 827 B |
BIN
site/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
46
site/public/index.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<meta property="og:site_name" content="MDXC" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:creator" content="james_k_nelson" />
|
||||
<meta property="og:image" content="https://mdxc.reactarmory.com/logo.png?2" />
|
||||
<meta name="twitter:image" content="https://mdxc.reactarmory.com/logo.png?2" />
|
||||
<meta property="og:title" content="%socialTitle%" />
|
||||
<meta name="twitter:title" content="%socialTitle%" />
|
||||
<meta name="description" content="%socialDescription%" />
|
||||
<meta property="og:description" content="%socialDescription%" />
|
||||
<meta name="twitter:description" content="%socialDescription%" />
|
||||
|
||||
<title>%PAGE_TITLE%</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
|
||||
<script async defer src="https://buttons.github.io/buttons.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
site/public/logo-white.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
site/public/logo.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
site/public/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
47
site/public/safari-pinned-tab.svg
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="500.000000pt" height="500.000000pt" viewBox="0 0 500.000000 500.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,500.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M915 3500 l-330 -5 -67 -110 c-78 -127 -181 -304 -228 -390 -18 -33
|
||||
-49 -89 -68 -125 -19 -36 -71 -135 -114 -222 l-80 -156 88 -174 c108 -214 247
|
||||
-464 372 -668 51 -85 96 -157 98 -159 6 -6 3763 -9 3786 -3 34 8 295 452 485
|
||||
827 l92 180 -26 50 c-61 121 -187 360 -213 404 -15 27 -43 75 -60 107 -41 74
|
||||
-237 402 -256 428 -13 19 -49 19 -1581 20 -863 1 -1716 -1 -1898 -4z m1913
|
||||
-405 c19 -49 42 -109 52 -131 11 -23 22 -53 25 -66 11 -41 52 -78 88 -78 47 1
|
||||
69 24 130 140 94 178 123 225 138 223 48 -6 149 -47 149 -61 0 -5 -29 -63 -66
|
||||
-128 -120 -219 -244 -474 -244 -503 0 -28 128 -290 259 -526 68 -125 71 -113
|
||||
-38 -151 l-64 -23 -16 22 c-19 26 -28 41 -88 155 -83 156 -90 167 -119 184
|
||||
-24 13 -35 14 -62 5 -42 -15 -48 -26 -130 -232 l-48 -120 -38 3 c-20 2 -59 13
|
||||
-86 25 l-49 22 26 65 c60 151 163 400 194 465 18 39 33 86 33 105 0 21 -24 89
|
||||
-61 170 -67 151 -193 462 -193 478 0 6 21 17 48 26 120 38 119 38 160 -69z
|
||||
m1146 44 c142 -38 212 -151 229 -367 l5 -53 -95 3 -95 3 -3 72 c-5 130 -44
|
||||
191 -129 200 -98 11 -164 -27 -187 -109 -15 -50 -21 -658 -8 -740 19 -118 80
|
||||
-179 175 -174 73 4 126 58 140 141 6 34 8 63 13 168 1 15 12 17 94 17 l93 0
|
||||
-2 -62 c-13 -305 -130 -432 -384 -415 -176 11 -274 108 -312 307 -12 62 -16
|
||||
571 -5 668 17 161 81 276 177 319 84 38 202 47 294 22z m-2938 2 c6 -1 17 -34
|
||||
24 -73 7 -40 14 -82 16 -93 2 -11 7 -33 10 -50 3 -16 14 -75 24 -130 11 -55
|
||||
22 -116 25 -135 3 -19 15 -82 26 -140 25 -134 58 -308 64 -339 2 -13 6 -25 8
|
||||
-28 4 -3 16 61 22 112 1 9 8 46 20 105 3 14 12 63 21 110 8 47 39 213 67 370
|
||||
l53 285 54 5 c30 3 89 3 130 0 l76 -5 -1 -650 0 -650 -92 -3 -93 -3 -1 508
|
||||
c-1 535 -1 530 -37 323 -7 -36 -23 -126 -36 -200 -14 -75 -28 -151 -31 -170
|
||||
-3 -19 -8 -42 -10 -50 -2 -8 -7 -35 -10 -60 -4 -25 -11 -64 -16 -88 -5 -23
|
||||
-12 -59 -15 -80 -3 -20 -7 -44 -9 -52 -3 -8 -7 -33 -10 -55 -12 -77 -9 -75
|
||||
-86 -75 -48 0 -69 4 -70 13 0 6 -2 22 -5 34 -2 12 -17 97 -34 190 -17 92 -35
|
||||
188 -40 213 -5 25 -12 61 -14 80 -3 19 -15 85 -26 145 -12 61 -23 124 -26 140
|
||||
-2 17 -6 39 -8 50 -3 11 -8 41 -12 68 -3 26 -9 47 -13 47 -3 0 -6 -215 -5
|
||||
-477 0 -263 -2 -484 -4 -490 -3 -9 -31 -13 -93 -13 l-89 0 0 113 c-1 246 -1
|
||||
1124 -1 1159 l1 37 83 3 c70 3 110 2 163 -1z m1202 -6 c160 -15 242 -81 275
|
||||
-221 19 -84 20 -704 1 -802 -17 -92 -47 -153 -93 -195 -78 -71 -131 -83 -376
|
||||
-85 l-181 -2 0 655 0 654 106 3 c119 3 178 2 268 -7z"/>
|
||||
<path d="M2083 3002 l-33 -3 0 -516 0 -515 94 4 c77 4 99 9 126 28 65 47 68
|
||||
60 69 470 1 243 -2 382 -9 411 -20 77 -58 108 -144 116 -28 2 -55 5 -61 6 -5
|
||||
1 -25 1 -42 -1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
19
site/public/site.webmanifest
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* This file is used to tell Sitepack how to render the HTML content for each
|
||||
* Page which is statically rendered.
|
||||
*
|
||||
* Sitepack will call the default export, passing in an object with `history`
|
||||
* and `site` keys. These two arguments are also passed to the function
|
||||
* exported by `main.js`, allowing re-use of the `Application` component
|
||||
* between both files.
|
||||
*
|
||||
* - `history` is a History object, produced by the history package. It
|
||||
* contains the URL for your application, and can be used with routers
|
||||
* like react-router and junctions.
|
||||
*
|
||||
* See https://github.com/mjackson/history for more details.
|
||||
*
|
||||
* - `site` contains a Site object. This object has two properties:
|
||||
*
|
||||
* + `rootPage` points to the root Page for your site
|
||||
* + `pages` contains an object with all pages in your site, keyed by
|
||||
* page ID.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOMServer from 'react-dom/server'
|
||||
import Application from './Application'
|
||||
|
||||
export default function renderToString({ history, site }) {
|
||||
return ReactDOMServer.renderToString(
|
||||
React.createElement(Application, {
|
||||
environment: 'static',
|
||||
history: history,
|
||||
site: site,
|
||||
})
|
||||
)
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
export default ({ environment }) => ({
|
||||
|
||||
/**
|
||||
* Specify the Webpack loaders that Sitepack will use. This follows the same
|
||||
* format as the `rules` option in Webpack 2's configuration file.
|
||||
*
|
||||
* Read more at https://webpack.js.org/configuration/module/#module-rules
|
||||
*/
|
||||
rules: [
|
||||
|
||||
/**
|
||||
* Run any JavaScript other than `.page.js` files through babel to enable
|
||||
* ES6 and JSX support. Babel can be configured using the `.babelrc` file
|
||||
* in the project's root directory.
|
||||
*/
|
||||
{ test: /\.js$/,
|
||||
exclude: /node_modules|\.page\.js$/,
|
||||
loader: 'babel'
|
||||
},
|
||||
|
||||
/**
|
||||
* The `sitepack-page` loader converts a plain-old JavaScript object
|
||||
* into the `Page` object that Sitepack uses internally. We also run
|
||||
* `.page.js` through babel, but do so separately from standard
|
||||
* `.js` files.
|
||||
*/
|
||||
{ test: /\.page\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
'sitepack-page',
|
||||
'babel'
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* MDX is a tool that converts Markdown files to React components. This
|
||||
* loader uses MDX to create Page objects for Markdown files.
|
||||
*/
|
||||
{ test: /\.mdx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'sitepack-raw-page',
|
||||
options: {
|
||||
eager: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows you to `require()` images. Images under 4kb will be inlined with
|
||||
* a data URL, while larger images will be given their own files.
|
||||
*/
|
||||
{ test: /\.(gif|jpe?g|png|ico)$/,
|
||||
loader: 'url',
|
||||
options: { limit: 4000 },
|
||||
},
|
||||
|
||||
/**
|
||||
* The `sitepack-css` loader handles hot reloading of CSS during
|
||||
* development, and also extracts your CSS into a separate file in a
|
||||
* production build.
|
||||
*/
|
||||
{ test: /\.css$/,
|
||||
loader: 'sitepack-css',
|
||||
},
|
||||
|
||||
/**
|
||||
* You can use CSS preprocessor like SASS, LESS or PostCSS by chaining
|
||||
* them with the `sitepack-css` loader.
|
||||
*/
|
||||
{ test: /\.less$/,
|
||||
use: [
|
||||
'sitepack-css',
|
||||
'less'
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* This section is used to configure the paths to various files and
|
||||
* directories that Sitepack requires.
|
||||
*/
|
||||
paths: {
|
||||
/**
|
||||
* The file containing a template for your generated HTML files.
|
||||
*/
|
||||
html: './index.html.ejs',
|
||||
|
||||
/**
|
||||
* The file that exports the function to be called once your app has loaded.
|
||||
*/
|
||||
main: './main.js',
|
||||
|
||||
/**
|
||||
* The directory whose contents will be copied into your build directory.
|
||||
*/
|
||||
public: './public',
|
||||
|
||||
/**
|
||||
* The directory where any custom loaders for this website are stored.
|
||||
*/
|
||||
loaders: './loaders',
|
||||
|
||||
/**
|
||||
* The file that exports the function that will be used to render a string
|
||||
* with the HTML content for each page.
|
||||
*/
|
||||
renderToString: './renderToString.js',
|
||||
|
||||
/**
|
||||
* The file that exports the function responsible for creating your Site
|
||||
* object, and loading the root Page.
|
||||
*/
|
||||
site: './createSite.js',
|
||||
},
|
||||
|
||||
/**
|
||||
* You can specify a list of node modules whose contents should be included
|
||||
* in a separate `vendor.js` bundle, instead of the main `entry.js` bundle.
|
||||
*
|
||||
* Separating vendor files into a separate bundle will reduce the size
|
||||
* of your application bundle, increasing loading speed when you change
|
||||
* your site's content.
|
||||
*/
|
||||
vendor: [
|
||||
'react',
|
||||
'react-dom'
|
||||
],
|
||||
})
|
||||
148
site/src/components/App.css
Normal file
@@ -0,0 +1,148 @@
|
||||
.App {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.App-nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 25px;
|
||||
left: 0;
|
||||
width: 150px;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.App-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 150px;
|
||||
right: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.App-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 150px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 639px) {
|
||||
.App h1 {
|
||||
margin-top: 15px
|
||||
}
|
||||
|
||||
.App-nav {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
bottom: auto;
|
||||
height: auto;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.App-content {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.App-footer {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 15px 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.App-footer {
|
||||
background-color: #181818;
|
||||
}
|
||||
.App-footer a {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-family: Inconsolata, sans-serif;
|
||||
text-decoration: underline;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
|
||||
.App-github-ribbon {
|
||||
width: 12.1em;
|
||||
height: 12.1em;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
text-indent: -999999px;
|
||||
}
|
||||
.App-github-ribbon:before, .App-github-ribbon:after {
|
||||
/* The right and left classes determine the side we attach our banner to */
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 15.38em;
|
||||
height: 1.54em;
|
||||
|
||||
top: 3.23em;
|
||||
right: -3.23em;
|
||||
|
||||
box-sizing: content-box;
|
||||
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.App-github-ribbon::before {
|
||||
content: "";
|
||||
|
||||
/* Add a bit of padding to give some substance outside the "stitching" */
|
||||
padding: .38em 0;
|
||||
|
||||
/* Set the base colour */
|
||||
background-color: #a00;
|
||||
|
||||
/* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15)));
|
||||
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
|
||||
/* Add a drop shadow */
|
||||
box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
|
||||
|
||||
pointer-events: auto;
|
||||
}
|
||||
.App-github-ribbon::after {
|
||||
/* Set the text from the title attribute */
|
||||
content: attr(title);
|
||||
|
||||
/* Set the text properties */
|
||||
color: #fff;
|
||||
font: 700 1em "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
line-height: 1.54em;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 -.08em rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
text-indent: 0;
|
||||
|
||||
/* Set the layout properties */
|
||||
padding: .15em 0;
|
||||
margin: .15em 0;
|
||||
|
||||
/* Add "stitching" effect */
|
||||
border-width: .08em 0;
|
||||
border-style: dotted;
|
||||
border-color: #fff;
|
||||
border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
94
site/src/components/App.js
Normal file
@@ -0,0 +1,94 @@
|
||||
import React from 'react'
|
||||
import { createJunctionTemplate, createPageTemplate, JunctionActiveChild } from 'react-junctions'
|
||||
import { MDXWrapper } from './MDXWrapper'
|
||||
import { Navbar } from './Navbar'
|
||||
import './App.css'
|
||||
|
||||
|
||||
export const App = ({ env, junction }) =>
|
||||
<div className='App'>
|
||||
<a
|
||||
className='App-github-ribbon'
|
||||
href="https://github.com/jamesknelson/mdxc"
|
||||
title="Fork me on GitHub">
|
||||
Fork me on GitHub
|
||||
</a>
|
||||
|
||||
<Navbar
|
||||
env={env}
|
||||
className='App-nav'
|
||||
/>
|
||||
|
||||
<main className='App-content'>
|
||||
<JunctionActiveChild
|
||||
env={env}
|
||||
junction={junction}
|
||||
notFoundElement={
|
||||
<div className='App-notfound'>
|
||||
<h1>404</h1>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</main>
|
||||
|
||||
<footer className='App-footer'>
|
||||
<a className='App-footer-author' href='https://twitter.com/james_k_nelson'>By @james_k_nelson</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
|
||||
export const AppJunctionTemplate = createJunctionTemplate({
|
||||
children: {
|
||||
'/': createPageTemplate({
|
||||
title: 'MDXC',
|
||||
component: MDXWrapper,
|
||||
getContent: () => import('!raw-loader!../pages/index.md'),
|
||||
meta: {
|
||||
socialTitle: 'Junctions',
|
||||
socialDescription: 'A batteries-included router for React.',
|
||||
},
|
||||
}),
|
||||
|
||||
'/examples/basics': createPageTemplate({
|
||||
title: 'MDXC: Basics',
|
||||
component: MDXWrapper,
|
||||
getContent: () => import('!raw-loader!../pages/basics.md'),
|
||||
meta: {
|
||||
socialTitle: 'MDXC: Basics',
|
||||
socialDescription: "Learn how JSX interacts with standard Markdown in documents compiled with MDXC.",
|
||||
},
|
||||
}),
|
||||
|
||||
'/examples/factories': createPageTemplate({
|
||||
title: 'MDXC: Factories',
|
||||
component: MDXWrapper,
|
||||
getContent: () => import('!raw-loader!../pages/factories.md'),
|
||||
meta: {
|
||||
socialTitle: 'MDXC: Factories',
|
||||
socialDescription: "Learn how to configure your Markdown with custom React Components instead of standard HTML elements",
|
||||
},
|
||||
}),
|
||||
|
||||
'/examples/import': createPageTemplate({
|
||||
title: 'MDXC: Import',
|
||||
component: MDXWrapper,
|
||||
getContent: () => import('!raw-loader!../pages/import.md'),
|
||||
meta: {
|
||||
socialTitle: 'MDXC: Import',
|
||||
socialDescription: "Learn how to extend your Markdown documents with React Components using MDXC.",
|
||||
},
|
||||
}),
|
||||
|
||||
'/examples/props': createPageTemplate({
|
||||
title: 'MDXC: Props',
|
||||
component: MDXWrapper,
|
||||
getContent: () => import('!raw-loader!../pages/props.md'),
|
||||
meta: {
|
||||
socialTitle: 'MDXC: Props',
|
||||
socialDescription: "Learn how to substitute data into your Markdown documents using React and MDXC.",
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
component: App,
|
||||
})
|
||||
@@ -24,13 +24,6 @@ function highlight(str, lang) {
|
||||
|
||||
|
||||
export default class HighlightedCodeBlock extends PureComponent {
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
language: PropTypes.string,
|
||||
source: PropTypes.string,
|
||||
}
|
||||
|
||||
render() {
|
||||
const language = this.props.language
|
||||
const className = this.props.className + ' language-'+(language === 'mdx' ? 'markdown' : language)
|
||||
27
site/src/components/MDXWrapper.css
Normal file
@@ -0,0 +1,27 @@
|
||||
.MDXWrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.MDXWrapper-heading-hash {
|
||||
transition: opacity 200ms ease-out;
|
||||
opacity: 0;
|
||||
color: #aaa;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.MDXWrapper-heading:hover .MDXWrapper-heading-hash {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 639px) {
|
||||
.MDXWrapper {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
113
site/src/components/MDXWrapper.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import './MDXWrapper.css'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { Link } from 'react-junctions'
|
||||
import { MDXBreadboard } from 'mdx-breadboard'
|
||||
import fullscreenMDXBreadboardTheme from './fullscreenMDXBreadboardTheme'
|
||||
import defaultMDXBreadboardTheme from './defaultMDXBreadboardTheme'
|
||||
import createClassNamePrefixer from '../utils/createClassNamePrefixer'
|
||||
|
||||
|
||||
function ThemedMDXBreadboard({ defaultSource, ...other }) {
|
||||
return (
|
||||
<MDXBreadboard
|
||||
{...other}
|
||||
defaultSource={defaultSource}
|
||||
theme={defaultMDXBreadboardTheme}
|
||||
require={breadboardRequire}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function breadboardRequire(name) {
|
||||
switch (name) {
|
||||
case 'react':
|
||||
return require('react')
|
||||
|
||||
case 'mdx-breadboard':
|
||||
return { MDXBreadboard: ThemedMDXBreadboard }
|
||||
|
||||
case './Warning':
|
||||
return require('./Warning')
|
||||
|
||||
default:
|
||||
console.warn('Breadboard tried to import unknown module ', name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function createHeadingFactory(type, env) {
|
||||
return ({ id, ...other }, ...children) => {
|
||||
// Change MDX's heading ids by removing anything in parens, and removing
|
||||
// any <> characters, as otherwise the API Reference's ids can get a
|
||||
// little weird.
|
||||
let simpleId = id.replace(/\(.*/, '').replace(/[<>]/g, '')
|
||||
|
||||
return React.createElement(
|
||||
type,
|
||||
{
|
||||
id: simpleId,
|
||||
className: 'MDXWrapper-heading',
|
||||
...other,
|
||||
},
|
||||
...children,
|
||||
|
||||
// Append a hash link to each heading, which will be hidden via
|
||||
// CSS until he mouse hovers over the heading.
|
||||
<Link env={env} className='MDXWrapper-heading-hash' href={'#'+simpleId}>#</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class MDXWrapper extends Component {
|
||||
factories = {
|
||||
a: (props, ...children) =>
|
||||
React.createElement(Link, {
|
||||
...props,
|
||||
env: this.props.env
|
||||
}, ...children),
|
||||
|
||||
h1: createHeadingFactory('h1', this.props.env),
|
||||
h2: createHeadingFactory('h2', this.props.env),
|
||||
h3: createHeadingFactory('h3', this.props.env),
|
||||
h4: createHeadingFactory('h4', this.props.env),
|
||||
h5: createHeadingFactory('h5', this.props.env),
|
||||
h6: createHeadingFactory('h6', this.props.env),
|
||||
}
|
||||
|
||||
render() {
|
||||
let { env, page } = this.props
|
||||
|
||||
return (
|
||||
<div className='MDXWrapper'>
|
||||
<LoadingIndicator isLoading={page.contentStatus === 'busy'} />
|
||||
|
||||
{ page.contentStatus === 'ready' &&
|
||||
<div className='MDXWrapper-ready'>
|
||||
<MDXBreadboard
|
||||
key={page.url}
|
||||
defaultMode='view'
|
||||
defaultSource={page.content}
|
||||
theme={fullscreenMDXBreadboardTheme}
|
||||
require={breadboardRequire}
|
||||
factories={this.factories}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{ page.contentStatus === 'error' &&
|
||||
<div className='MDXWrapper-error'>
|
||||
<h1>Gosh darn it.</h1>
|
||||
<p>Something went wrong while loading the page.</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const LoadingIndicator = ({ isLoading }) =>
|
||||
<div className={`
|
||||
MDXWrapper-LoadingIndicator
|
||||
MDXWrapper-LoadingIndicator-${isLoading ? 'loading' : 'done'}
|
||||
`} />
|
||||
69
site/src/components/Navbar.css
Normal file
@@ -0,0 +1,69 @@
|
||||
.Navbar-link {
|
||||
display: block;
|
||||
margin: 5px 0 5px 12px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 639px) {
|
||||
.Navbar-link {
|
||||
display: inline-block;
|
||||
margin: 0 0 5px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.Navbar {
|
||||
background-color: #181818;
|
||||
}
|
||||
.Navbar a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.Navbar-brand {
|
||||
display: block;
|
||||
width: 125px;
|
||||
margin: 25px auto 0;
|
||||
}
|
||||
.Navbar-brand > img {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.Navbar-brand-active > img {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.Navbar-description {
|
||||
font-size: 13px;
|
||||
font-family: Inconsolata, sans-serif;
|
||||
text-align: center;
|
||||
margin: 0 12px 25px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.Navbar-heading {
|
||||
display: block;
|
||||
margin: 15px 12px 5px;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: bold;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.Navbar-link {
|
||||
font-size: 14px;
|
||||
font-family: Roboto, sans-serif;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.Navbar-link-active {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-shadow: 0 0 2px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.Navbar-github-stars {
|
||||
margin-left: 12px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.Navbar-github-stars > a {
|
||||
color: #181818;
|
||||
}
|
||||
37
site/src/components/Navbar.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-junctions'
|
||||
import './Navbar.css'
|
||||
|
||||
|
||||
export const Navbar = ({ className='', env }) =>
|
||||
<nav className={'Navbar '+className}>
|
||||
<Link
|
||||
env={env}
|
||||
href='/'
|
||||
className='Navbar-brand'
|
||||
activeClassName='Navbar-brand-active'
|
||||
exact>
|
||||
<img src='/logo-white.png' />
|
||||
</Link>
|
||||
<p className='Navbar-description'>React Components within Markdown</p>
|
||||
<span className='Navbar-heading'>Examples</span>
|
||||
<NavLink env={env} href='/examples/basics'>Basics</NavLink>
|
||||
<NavLink env={env} href='/examples/import'>Imports</NavLink>
|
||||
<NavLink env={env} href='/examples/props'>Props</NavLink>
|
||||
<NavLink env={env} href='/examples/factories'>Factories</NavLink>
|
||||
|
||||
<div className={'Navbar-github-stars'}>
|
||||
<a className='github-button' href='https://github.com/jamesknelson/mdxc' data-icon='octicon-star' data-show-count='true' aria-label='Star jamesknelson/mdxc on GitHub'>Star</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
const NavLink = ({ children, className='', env, href }) =>
|
||||
<Link
|
||||
activeClassName='Navbar-link-active'
|
||||
className={'Navbar-link '+className}
|
||||
env={env}
|
||||
href={href}
|
||||
exact>
|
||||
{children}
|
||||
</Link>
|
||||
16
site/src/components/Warning.css
Normal file
@@ -0,0 +1,16 @@
|
||||
.Warning {
|
||||
border: 1px solid #a00;
|
||||
border-radius: 5px;
|
||||
margin: 12px 0;
|
||||
padding: 8px 10px 10px;
|
||||
|
||||
color: #500;
|
||||
background-color: #ffeeee;
|
||||
}
|
||||
|
||||
.Warning h5 {
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
color: #a00;
|
||||
}
|
||||
13
site/src/components/Warning.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import './Warning.css'
|
||||
import React from 'react'
|
||||
|
||||
export default function Warning({ children }) {
|
||||
return (
|
||||
<section className='Warning'>
|
||||
<h5>Warning</h5>
|
||||
<div className='Warning-content'>
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
106
site/src/components/defaultMDXBreadboardTheme.css
Normal file
@@ -0,0 +1,106 @@
|
||||
.defaultMDXBreadboardTheme {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.defaultMDXBreadboardTheme-single,
|
||||
.defaultMDXBreadboardTheme-static {
|
||||
max-width: 530px;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-modes {
|
||||
opacity: 0;
|
||||
transition: opacity ease-out 300ms;
|
||||
}
|
||||
.defaultMDXBreadboardTheme-loaded .defaultMDXBreadboardTheme-modes {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-editor {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
resize: none;
|
||||
border: none;
|
||||
|
||||
margin-right: 15px;
|
||||
|
||||
padding: 15px;
|
||||
color: rgb(210, 210, 210);
|
||||
background-color: #2d2d2d;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.defaultMDXBreadboardTheme-editor-static {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-transformed {
|
||||
margin: 0 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-editor,
|
||||
.defaultMDXBreadboardTheme-output {
|
||||
font-family: Inconsolata, monospace;
|
||||
line-height: 18px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-preview {
|
||||
padding: 0 15px;
|
||||
box-shadow: 0 0 10px #e0e0e0 inset;
|
||||
border-radius: 3px;
|
||||
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
// First div is the mount element, second is the wrapper
|
||||
.defaultMDXBreadboardTheme-preview > div > div > * {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-mode {
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
.defaultMDXBreadboardTheme-mode:not(:last-child) {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme-modes, .defaultMDXBreadboardTheme-wrapper {
|
||||
display: inline-block;
|
||||
background: rgba(96, 96, 96, 0.9);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
padding: 0 7px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.defaultMDXBreadboardTheme > nav {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 24px;
|
||||
right: 30px;
|
||||
left: 0;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
color: #bbb;
|
||||
z-index: 2;
|
||||
text-align: right;
|
||||
}
|
||||
.defaultMDXBreadboardTheme > nav > span {
|
||||
cursor: pointer;
|
||||
}
|
||||
.defaultMDXBreadboardTheme > nav > span.active {
|
||||
color: #eee;
|
||||
}
|
||||
.defaultMDXBreadboardTheme-single > nav {
|
||||
max-width: 500px;
|
||||
}
|
||||
.defaultMDXBreadboardTheme-active {
|
||||
color: #fff !important;
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
import './defaultMDXBreadboardTheme.less'
|
||||
import ExecutionEnvironment from 'exenv'
|
||||
import './defaultMDXBreadboardTheme.css'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import Textarea from 'react-textarea-autosize'
|
||||
import { MDXBreadboard } from 'armo-breadboard'
|
||||
import HighlightedCodeBlock from './HighlightedCodeBlock'
|
||||
import createClassNamePrefixer from '../utils/createClassNamePrefixer'
|
||||
import HighlightedCodeBlock from '../controls/HighlightedCodeBlock'
|
||||
|
||||
|
||||
const cx = createClassNamePrefixer('defaultMDXBreadboardTheme')
|
||||
|
||||
|
||||
export default {
|
||||
let defaultMDXBreadboardTheme = {
|
||||
maxSinglePaneWidth: 800,
|
||||
|
||||
|
||||
renderBreadboard: function(props) {
|
||||
const {
|
||||
consoleMessages,
|
||||
@@ -32,7 +30,7 @@ export default {
|
||||
onToggleWrapped,
|
||||
} = props
|
||||
|
||||
const isStatic = !ExecutionEnvironment.canUseDOM
|
||||
const isStatic = process.env.IS_STATIC
|
||||
const singleMode = Object.values(modes).reduce((acc, x) => acc + x || 0, 0) === 1 || isStatic
|
||||
|
||||
const sourceLayout = {
|
||||
@@ -104,7 +102,7 @@ export default {
|
||||
if (renderBreadboard) {
|
||||
return (
|
||||
<div style={{ maxWidth: 'none', width: '100%' }}>
|
||||
{renderBreadboard({theme: defaultMDXBreadboardtheme})}
|
||||
{renderBreadboard({theme: defaultMDXBreadboardTheme})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -116,7 +114,7 @@ export default {
|
||||
renderEditor: function({ layout, value, onChange }) {
|
||||
return (
|
||||
<Textarea
|
||||
className={cx('editor', { 'editor-static': !ExecutionEnvironment.canUseDOM })}
|
||||
className={cx('editor', { 'editor-static': process.env.IS_STATIC })}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
style={layout}
|
||||
@@ -124,3 +122,6 @@ export default {
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export default defaultMDXBreadboardTheme
|
||||
197
site/src/components/fullscreenMDXBreadboardTheme.css
Normal file
@@ -0,0 +1,197 @@
|
||||
@keyframes fullscreenMDXBreadboardTheme-progress {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -35px -35px;
|
||||
}
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-secondary {
|
||||
display: none;
|
||||
position: relative;
|
||||
flex-basis: 600px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-editor-wrapper {
|
||||
background-color: #2d2d2d;
|
||||
padding-top: 12px;
|
||||
display: none;
|
||||
position: relative;
|
||||
flex-basis: 600px;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
min-height: 100%;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-expand {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-default-primary,
|
||||
.fullscreenMDXBreadboardTheme-loaded .fullscreenMDXBreadboardTheme-secondary,
|
||||
.fullscreenMDXBreadboardTheme-loaded .fullscreenMDXBreadboardTheme-editor-wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme > nav {
|
||||
position: fixed;
|
||||
left: 155px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 965px) {
|
||||
.fullscreenMDXBreadboardTheme > nav {
|
||||
left: 50%;
|
||||
padding-left: 78px;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-default-secondary {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width : 639px) {
|
||||
.fullscreenMDXBreadboardTheme > nav {
|
||||
left: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-loading-bar, {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
height: 4px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-image: linear-gradient(-45deg, rgba(255,255,255,0.2) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.2) 75%, transparent 75%, transparent);
|
||||
background-color: #990000;
|
||||
background-size: 35px 35px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2) inset;
|
||||
transition: transform ease-in 300ms;
|
||||
animation: fullscreenMDXBreadboardTheme-progress 2s cubic-bezier(.4,.45,.6,.55) infinite;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-loaded .fullscreenMDXBreadboardTheme-loading-bar {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-modes {
|
||||
opacity: 0;
|
||||
transition: opacity ease-out 300ms;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-loaded .fullscreenMDXBreadboardTheme-modes {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-editor {
|
||||
background-color: #2d2d2d;
|
||||
flex-grow: 1;
|
||||
min-height: 100%;
|
||||
cursor: text;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-editor-textarea {
|
||||
resize: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
background-color: #2d2d2d;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
padding: 15px;
|
||||
color: rgb(210, 210, 210);
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-editor-server {
|
||||
height: auto !important;
|
||||
min-height: 100%;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-transformed {
|
||||
margin: 0 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-editor-textarea,
|
||||
.fullscreenMDXBreadboardTheme-output {
|
||||
font-family: Inconsolata, monospace;
|
||||
line-height: 18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-transformed {
|
||||
padding-top: 22px !important;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-preview {
|
||||
padding: 15px;
|
||||
background-color: white;
|
||||
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
// First div is the mount element, second is the wrapper
|
||||
.fullscreenMDXBreadboardTheme-preview > div > div > * {
|
||||
max-width: 500px;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-preview > div > div > .defaultMDXBreadboardTheme {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-error {
|
||||
background-color: black;
|
||||
color: #ddd;
|
||||
padding: 15px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-error pre {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-error-title {
|
||||
color: #E36049;
|
||||
display: block;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-mode {
|
||||
&:not(:last-child) {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme-modes, .fullscreenMDXBreadboardTheme-wrapper {
|
||||
display: inline-block;
|
||||
background: rgba(96, 96, 96, 0.7);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
padding: 0 7px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme > nav {
|
||||
top: 0;
|
||||
height: 24px;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
color: #bbb;
|
||||
z-index: 2;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme > nav > span {
|
||||
cursor: pointer;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme > nav > span.active {
|
||||
color: #eee;
|
||||
}
|
||||
.fullscreenMDXBreadboardTheme-active {
|
||||
color: #fff !important;
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
import './fullscreenMDXBreadboardTheme.less'
|
||||
import ExecutionEnvironment from 'exenv'
|
||||
import './fullscreenMDXBreadboardTheme.css'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { MDXBreadboard } from 'armo-breadboard'
|
||||
import Textarea from 'react-textarea-autosize'
|
||||
import defaultMDXBreadboardTheme from './defaultMDXBreadboardTheme'
|
||||
import HighlightedCodeBlock from './HighlightedCodeBlock'
|
||||
import createClassNamePrefixer from '../utils/createClassNamePrefixer'
|
||||
import HighlightedCodeBlock from '../controls/HighlightedCodeBlock'
|
||||
|
||||
|
||||
const cx = createClassNamePrefixer('fullscreenMDXBreadboardTheme')
|
||||
@@ -18,7 +16,7 @@ class Editor extends Component {
|
||||
|
||||
render() {
|
||||
const props = this.props
|
||||
const isServer = !ExecutionEnvironment.canUseDOM
|
||||
const isServer = process.env.IS_STATIC
|
||||
|
||||
return (
|
||||
<div className={cx('editor')} onClick={this.handleClick} style={props.layout}>
|
||||
@@ -61,7 +59,7 @@ export default {
|
||||
const singleMode = Object.values(modes).reduce((acc, x) => acc + x || 0, 0) === 1
|
||||
|
||||
return (
|
||||
<div className={cx.root(null, ExecutionEnvironment.canUseDOM ? 'loaded' : 'static')}>
|
||||
<div className={cx.root(null, process.env.IS_STATIC ? 'static' : 'loaded')}>
|
||||
<div className={cx('loading-bar')} />
|
||||
<nav>
|
||||
<span className={cx('modes')}>
|
||||
70
site/src/index.css
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* You can add any global CSS to this file, but prefer component-specific CSS
|
||||
* files where possible.
|
||||
*/
|
||||
|
||||
@import '~prismjs/themes/prism-tomorrow.css';
|
||||
|
||||
@import url('https://fonts.googleapis.com/css?family=Inconsolata|Roboto:400,700');
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#app, #app > div {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
pre, code { font-family: Inconsolata, monospace; line-height: 1.5 }
|
||||
pre { background: rgb(45, 45, 45); padding: 10px; border-radius: 3px; color: rgb(205, 205, 205); }
|
||||
pre code { font-size: 12px; white-space: pre-wrap; }
|
||||
code { font-size: 16px; }
|
||||
h1 { font-family: Inconsolata, monospace; margin: 40px 0 10px 0; font-size: 200%; }
|
||||
h2 { font-family: Inconsolata, monospace; margin: 30px 0 0 0; font-size: 150%; color: rgb(81, 81, 81); }
|
||||
h2 code { font-size: 100%; font-weight: 100; }
|
||||
h2 + p { margin-top: 10px; }
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
}
|
||||
img + em {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
li { margin: 4px 0; }
|
||||
|
||||
h1, h2, h3 { position: relative; }
|
||||
|
||||
p { margin: 1em 0; }
|
||||
|
||||
th {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
table td,
|
||||
table th {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
a { color: #a00; text-decoration: none }
|
||||
50
site/src/index.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { JunctionNavigation } from 'react-junctions'
|
||||
import { AppJunctionTemplate } from './components/App'
|
||||
import './index.css'
|
||||
|
||||
|
||||
process.env.IS_STATIC = process.env.NODE_ENV === 'production'
|
||||
|
||||
|
||||
function main() {
|
||||
// `main` is never called in the static build.
|
||||
process.env.IS_STATIC = false
|
||||
|
||||
// The `<JunctionNavigation>` component re-renders the app each time
|
||||
// the browser's location changes.
|
||||
//
|
||||
// It renders the `component` property of the template defined in App.js,
|
||||
// passing in a `junction` prop with the app's navigatin state.
|
||||
let content =
|
||||
<JunctionNavigation
|
||||
root={AppJunctionTemplate}
|
||||
waitForInitialContent
|
||||
/>
|
||||
|
||||
// React requires us to call "hydrate" if the content already exists in
|
||||
// the DOM, which is the case for statically rendered pages.
|
||||
let node = document.getElementById('root')
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
ReactDOM.hydrate(content, node)
|
||||
}
|
||||
else {
|
||||
ReactDOM.render(content, node)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// When building the static version of the app, we don't want to run the
|
||||
// `main` function, as there is no DOM to render to.
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
main()
|
||||
}
|
||||
|
||||
|
||||
// Make the `root` template and `main` function available to junctions-static,
|
||||
// so it knows what to render and how to start the app.
|
||||
window.JunctionsStaticApp = {
|
||||
root: AppJunctionTemplate,
|
||||
main: main
|
||||
}
|
||||
62
site/src/pages/basics.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Basics
|
||||
======
|
||||
|
||||
This example describes how JSX interacts with standard Markdown in a document compiled with MDXC. For more info on Markdown itself, check out the [original description by Daring Fireball](https://daringfireball.net/projects/markdown/).
|
||||
|
||||
|
||||
|
||||
Tags
|
||||
----
|
||||
|
||||
The syntax of MDX is almost identical to Markdown, with the main difference being that tags in MDX represent JSX instead of HTML.
|
||||
|
||||
MDX, like JSX, requires all tags to be closed. This means that unclosed tags like <br> are just treated as plain text.
|
||||
|
||||
Properly closed tags will result in React elements. For example, `<br />` will create a line <br /> break.
|
||||
|
||||
And when you mix up <strong>closed and <strong>unclosed</strong> tags, MDX will treat the *last* possible opening tag as JSX, while treating earlier opening tags as text. So in this paragraph, the first `<strong>` will be text, while the latter will become a React element.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
Because an MDX file compiles to a React Component, you'll need to name your attributes the React way. This means using `className` instead of `class`, `htmlFor` instead of `for`, etc.
|
||||
|
||||
And for <span style={{color: 'red', fontStyle: 'italic'}}>style</span>, you'll need to pass in objects. Like this:
|
||||
|
||||
```jsx
|
||||
<span style={{color: 'red', fontStyle: 'italic'}}>
|
||||
style
|
||||
</span>
|
||||
```
|
||||
|
||||
Children
|
||||
--------
|
||||
|
||||
The content of a pair of JSX tags will be used as the React element's `children`.
|
||||
|
||||
For tags which are "inline" -- i.e. within a paragraph of text, the tag's content is treated as Markdown. This means you can use <span fontStyle={{backgroundColor: 'lightgreen'}}>`backticks`, **asterisks**, etc.</span> within a span block. They can also contain other tags, so if you really wanted, you could embed a JSX <select><option>select</option></select> control in your paragraph. Importantly, {braces} are treated as text -- not JSX.
|
||||
|
||||
<div>
|
||||
Tag "blocks" -- where a paragraph starts and ends with the same tag -- are treated a little differently. In a tag block, the content is treated as it would be in a JSX document. This means that `backticks`, **asterisks**, etc. are plain text. And {"{braces}"} can actually be used to substitute values into your text.
|
||||
|
||||
<div>
|
||||
<div>
|
||||
Indentation is also ignored, allowing you to copy and paste large blocks of code
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<markdown>
|
||||
# `<markdown>` tags
|
||||
|
||||
But sometimes, you want to be able to write a tag block's content in Markdown. In those cases, you can use the special `<markdown>` tag to switch back to markdown mode, where {braces} are text and `backticks` are your friend.
|
||||
</markdown>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
119
site/src/pages/factories.md
Normal file
@@ -0,0 +1,119 @@
|
||||
Factories
|
||||
=========
|
||||
|
||||
Components produced by MDXC can be configured to render custom components instead of standard HTML elements. This allows for tighter integration between your document components and React. For example:
|
||||
|
||||
- You add `#` anchors to your titles
|
||||
- You could replace your code blocks with live examples
|
||||
- You can replace `<a>` tags with react-router `<Link>` elements
|
||||
|
||||
To configure how HTML elements should be rendered, you pass factory functions to the special `factories` prop of your document components. For example, you could confuse your users by reversing how your headings are rendered:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```jsx
|
||||
<Document
|
||||
factories={{
|
||||
h1: (props, children) => React.createFactory('h6'),
|
||||
h2: (props, children) => React.createFactory('h5'),
|
||||
h3: (props, children) => React.createFactory('h4'),
|
||||
h4: (props, children) => React.createFactory('h3'),
|
||||
h5: (props, children) => React.createFactory('h2'),
|
||||
h6: (props, children) => React.createFactory('h1'),
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Factory functions are expected to take two arguments (`props` and `children`), and return a React element -- just like the functions returned by [React.createFactory](https://facebook.github.io/react/docs/react-api.html#createfactory).
|
||||
|
||||
Each available key of the `factories` object corresponds to a HTML tag, with one exception --- `codeBlock` corresponds to a fenced block of code, and by default is rendered with `<pre><code>`.
|
||||
|
||||
|
||||
|
||||
Heading anchors
|
||||
---------------
|
||||
|
||||
The MDXC website uses `h1`, `h2` and `h3` factories to add `#` anchors to titles. Hover over one of the titles to try it out.
|
||||
|
||||
```jsx
|
||||
function headingFactory(type, props, ...children) {
|
||||
// Render the same props and children that were passed in, but prepend a
|
||||
// link to this title with the text '#'.
|
||||
return React.createElement(
|
||||
type,
|
||||
props,
|
||||
<a href={'#'+props.id}>#</a>,
|
||||
...children
|
||||
)
|
||||
}
|
||||
|
||||
<Document
|
||||
factories={{
|
||||
h1: (props, children) => headingFactory('h1', props, children),
|
||||
h2: (props, children) => headingFactory('h2', props, children),
|
||||
h3: (props, children) => headingFactory('h3', props, children),
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Live examples
|
||||
-------------
|
||||
|
||||
The `mdx-breadboard` package uses a `codeBlock` factory to provide live examples for code blocks fenced with the `mdx` language.
|
||||
|
||||
```jsx
|
||||
<Document
|
||||
factories={{
|
||||
codeBlock: (props, children) => {
|
||||
const language = props.className.replace(/^language-/, '')
|
||||
if (language.slice(0, 3) === 'mdx') {
|
||||
return <MDXBreadboard defaultSource={children} />
|
||||
}
|
||||
else {
|
||||
return <pre {...props}><code dangerouslySetInnerHTML={{ __html: children }} /</pre>
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
The MDXC website website uses `mdx-breadboard`, so you can use it test out MDX!
|
||||
|
||||
```mdx
|
||||
*So this will render a live MDX code example*
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
HTML5 History Links
|
||||
-------------------
|
||||
|
||||
Navigation libraries like [react-router](https://reacttraining.com/react-router/web/api/Link) and [junctions](https://junctions.js.org/api/react-junctions/Link) often provide a Link component that supports `pushState`. To tell your document component to use this instead of a standard `<a>` tag, you can specify the `a` factory. Make sure to pass `<Link>` a `to` prop instead of a `href` prop.
|
||||
|
||||
```jsx
|
||||
import { Link } from 'react-router'
|
||||
|
||||
<Document
|
||||
factories={{
|
||||
a: ({ href, ...other }, ...children) =>
|
||||
React.createElement(Link, {
|
||||
to: href,
|
||||
...other
|
||||
}, ...children)
|
||||
}}
|
||||
/>
|
||||
```
|
||||
35
site/src/pages/import.md
Normal file
@@ -0,0 +1,35 @@
|
||||
import { MDXBreadboard } from 'mdx-breadboard'
|
||||
import Warning from './Warning'
|
||||
|
||||
Imports
|
||||
=======
|
||||
|
||||
MDX is a tool for creating *simple* React components with Markdown; it is limited in functionality by design. When you want to do something complex, you'll need to delegate to an old fashioned React component. And to access external components, you'll need to use `import`.
|
||||
|
||||
If you're familiar with the JavaScript `import` statement then you already know how to use `import` in MDX; the syntax is identical.
|
||||
|
||||
The only difference between MDX and ES2015 `import` is MDX imports **must** appear before the first empty line, and must not contain any leading whitespace.
|
||||
|
||||
So for example, this MDX document starts with a valid `import` statement:
|
||||
|
||||
<MDXBreadboard defaultSource={`
|
||||
import { MDXBreadboard } from 'mdx-breadboard'
|
||||
|
||||
*The import statement at the top of this example will be extracted from your content.*
|
||||
`} />
|
||||
|
||||
<Warning>
|
||||
Import statements cannot have leading space!
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
Import statements must appear at the top of the file. Any leading empty lines will cause the import to be treated as text.
|
||||
</Warning>
|
||||
|
||||
Finally, all import statements must follow the form `import ... from "..."` or `import ... from '...'`. For example, the following *is not* an MDX import statement, as it does not contain any quotes:
|
||||
|
||||
<MDXBreadboard defaultSource={`
|
||||
import a moose from tasmania
|
||||
|
||||
*The line at the top of this example will be part of your content.*
|
||||
`} />
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MDXBreadboard } from 'armo-breadboard'
|
||||
import { MDXBreadboard } from 'mdx-breadboard'
|
||||
|
||||
MDXC
|
||||
====
|
||||
@@ -6,7 +6,7 @@ MDXC
|
||||
MDXC is a tool to convert Markdown into React Components. It lets you `import` and use other Components within your Markdown. Like so:
|
||||
|
||||
<MDXBreadboard defaultMode='view' defaultSource={`
|
||||
import { MDXBreadboard } from 'armo-breadboard'
|
||||
import { MDXBreadboard } from 'mdx-breadboard'
|
||||
_Turtles?_
|
||||
<MDXBreadboard defaultSource='**Turtles!**' />
|
||||
`} />
|
||||
@@ -35,7 +35,7 @@ This website is built with MDXC. In fact, once the page has loaded you can edit
|
||||
Usage
|
||||
-----
|
||||
|
||||
To start using MDX documents, you can either use the supplied command-line tool, or you can configure Webpack with mdx-loader.
|
||||
To start using MDX documents, you can either use the supplied command-line tool, you can use create-react-app, or you can configure Webpack with mdx-loader.
|
||||
|
||||
|
||||
### Command Line
|
||||
@@ -54,7 +54,24 @@ mdxc example.mdx
|
||||
> mdxc --help
|
||||
```
|
||||
|
||||
### With create-react-app
|
||||
|
||||
MDX can be used with unejected create-react-app projects! To start, you'll need to add a `.babelrc` file to the root level of your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"presets": ["babel-preset-react-app"]
|
||||
}
|
||||
```
|
||||
|
||||
Then, you can import a component from any Markdown file by prepending the filename with `!babel-loader!mdx-loader!`. For example:
|
||||
|
||||
```js
|
||||
/* eslint-disable import/no-webpack-loader-syntax */
|
||||
import DocumentComponent from '!babel-loader!mdx-loader!../pages/index.md'
|
||||
```
|
||||
|
||||
You can also import documents dynamically using the proposed `import()` syntax. For an example of a statically rendered site using create-react-site and MDX, see [the source](https://github.com/jamesknelson/junctions/tree/master/site) for the [Junctions router site](https://junctions.js.org/tutorial/#Markdown-Components).
|
||||
|
||||
|
||||
|
||||
@@ -150,6 +167,7 @@ MDX in the wild
|
||||
---------------
|
||||
|
||||
- [Junctions](https://junctions.js.org), a tool for handling navigation history within React applications
|
||||
- [React Armory](https://reactarmory.com)
|
||||
- *Add your site via PR!*
|
||||
|
||||
|
||||
53
site/src/pages/props.md
Normal file
@@ -0,0 +1,53 @@
|
||||
prop value
|
||||
prop onChange
|
||||
|
||||
<h1>Hello{value ? ', '+value : ''}!</h1>
|
||||
|
||||
<input
|
||||
placeholder='What is your name?'
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
|
||||
React components wouldn't be React components without props. So as you may suspect, MDX components can have props too!
|
||||
|
||||
Declaring props
|
||||
---------------
|
||||
|
||||
To add a prop to an MDX component, declare it at the top of your file like so:
|
||||
|
||||
```
|
||||
prop firstName
|
||||
```
|
||||
|
||||
`prop` statements cannot have any leading whitespace, and must appear before any other content or empty lines. The only exception is that they *may* be intermixed with import statements. So this is ok:
|
||||
|
||||
```
|
||||
import Welcomer from './components/Welcomer'
|
||||
prop firstName
|
||||
```
|
||||
|
||||
Prop definitions can be mixed with imports
|
||||
|
||||
Using props
|
||||
-----------
|
||||
|
||||
Once you've declared a prop, you can use it within a tag's attributes, or within curly braces in a JSX block. Bare in mind that you *cannot* use a prop within curly braces in *inline* JSX.
|
||||
|
||||
So, this is OK:
|
||||
|
||||
```jsx
|
||||
Hello, <span children={firstName} />
|
||||
```
|
||||
|
||||
As is this:
|
||||
|
||||
```jsx
|
||||
<blockqoute>I'm afraid I can't do that, {firstName}.</blockquote>
|
||||
```
|
||||
|
||||
But this will just print the braces as text:
|
||||
|
||||
```markdown
|
||||
Hello <span>{firstName}</span>.
|
||||
```
|
||||
@@ -13,7 +13,5 @@ function prefixedClassNames(prefix, ...args) {
|
||||
export default function createClassNamePrefixer(prefix) {
|
||||
const prefixer = (...args) => prefixedClassNames(prefix, ...args)
|
||||
prefixer.root = (raw, ...args) => prefix + ' ' + prefixedClassNames(prefix, ...args) + ' ' + (raw || '')
|
||||
prefixer.child = (name, ...args) => prefixedClassNames(prefix+'_'+name, ...args)
|
||||
prefixer.childRoot = (name, ...args) => prefix+'_'+name + ' ' + prefixedClassNames(prefix+'_'+name, ...args)
|
||||
return prefixer
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
.defaultMDXBreadboardTheme {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&-single,
|
||||
&-static {
|
||||
max-width: 530px;
|
||||
}
|
||||
|
||||
&-modes {
|
||||
opacity: 0;
|
||||
transition: opacity ease-out 300ms;
|
||||
}
|
||||
&-loaded &-modes {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-editor {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
resize: none;
|
||||
border: none;
|
||||
|
||||
margin-right: 15px;
|
||||
|
||||
padding: 15px;
|
||||
color: rgb(210, 210, 210);
|
||||
background-color: #2d2d2d;
|
||||
border-radius: 3px;
|
||||
}
|
||||
&-editor-static {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
&-transformed {
|
||||
margin: 0 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&-editor,
|
||||
&-output {
|
||||
font-family: Inconsolata, monospace;
|
||||
line-height: 18px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&-preview {
|
||||
padding: 0 15px;
|
||||
box-shadow: 0 0 10px #e0e0e0 inset;
|
||||
border-radius: 3px;
|
||||
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
|
||||
// First div is the mount element, second is the wrapper
|
||||
> div > div > * {
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
&-mode {
|
||||
&:not(:last-child) {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
&-modes, &-wrapper {
|
||||
display: inline-block;
|
||||
background: rgba(96, 96, 96, 0.9);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
padding: 0 7px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
> nav {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 24px;
|
||||
right: 30px;
|
||||
left: 0;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
color: #bbb;
|
||||
z-index: 2;
|
||||
text-align: right;
|
||||
|
||||
> span {
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-single > nav {
|
||||
max-width: 500px;
|
||||
}
|
||||
&-active {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
@keyframes fullscreenMDXBreadboardTheme-progress {
|
||||
0% {
|
||||
background-position: 0 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -35px -35px;
|
||||
}
|
||||
}
|
||||
|
||||
.fullscreenMDXBreadboardTheme {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
|
||||
&-secondary {
|
||||
display: none;
|
||||
position: relative;
|
||||
flex-basis: 600px;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
&-editor-wrapper {
|
||||
background-color: #2d2d2d;
|
||||
padding-top: 12px;
|
||||
display: none;
|
||||
position: relative;
|
||||
flex-basis: 600px;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
min-height: 100%;
|
||||
}
|
||||
&-expand {
|
||||
flex-grow: 1;
|
||||
}
|
||||
&-default-primary,
|
||||
&-loaded &-secondary,
|
||||
&-loaded &-editor-wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
> nav {
|
||||
position: fixed;
|
||||
left: 155px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 965px) {
|
||||
> nav {
|
||||
left: 50%;
|
||||
padding-left: 78px;
|
||||
}
|
||||
|
||||
&-default-secondary {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width : 639px) {
|
||||
> nav {
|
||||
left: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-loading-bar, {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
height: 4px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-image: linear-gradient(-45deg, rgba(255,255,255,0.2) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.2) 75%, transparent 75%, transparent);
|
||||
background-color: #990000;
|
||||
background-size: 35px 35px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2) inset;
|
||||
transition: transform ease-in 300ms;
|
||||
animation: fullscreenMDXBreadboardTheme-progress 2s cubic-bezier(.4,.45,.6,.55) infinite;
|
||||
}
|
||||
&-loaded &-loading-bar {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
&-modes {
|
||||
opacity: 0;
|
||||
transition: opacity ease-out 300ms;
|
||||
}
|
||||
&-loaded &-modes {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&-editor {
|
||||
background-color: #2d2d2d;
|
||||
flex-grow: 1;
|
||||
min-height: 100%;
|
||||
cursor: text;
|
||||
|
||||
&-textarea {
|
||||
resize: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
background-color: #2d2d2d;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
padding: 15px;
|
||||
color: rgb(210, 210, 210);
|
||||
}
|
||||
&-server {
|
||||
height: auto !important;
|
||||
min-height: 100%;
|
||||
cursor: wait;
|
||||
}
|
||||
}
|
||||
|
||||
&-transformed {
|
||||
margin: 0 !important;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&-editor-textarea,
|
||||
&-output {
|
||||
font-family: Inconsolata, monospace;
|
||||
line-height: 18px;
|
||||
font-size: 15px;
|
||||
}
|
||||
&-transformed {
|
||||
padding-top: 22px !important;
|
||||
}
|
||||
|
||||
&-preview {
|
||||
padding: 15px;
|
||||
background-color: white;
|
||||
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
line-height: 24px;
|
||||
font-size: 16px;
|
||||
|
||||
// First div is the mount element, second is the wrapper
|
||||
> div > div > * {
|
||||
max-width: 500px;
|
||||
}
|
||||
> div > div > .defaultMDXBreadboardTheme {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-error {
|
||||
background-color: black;
|
||||
color: #ddd;
|
||||
padding: 15px;
|
||||
border-radius: 3px;
|
||||
|
||||
pre {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&-title {
|
||||
color: #E36049;
|
||||
display: block;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&-mode {
|
||||
&:not(:last-child) {
|
||||
border-right: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
padding: 0 7px;
|
||||
}
|
||||
|
||||
&-modes, &-wrapper {
|
||||
display: inline-block;
|
||||
background: rgba(96, 96, 96, 0.7);
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
padding: 0 7px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
> nav {
|
||||
top: 0;
|
||||
height: 24px;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
font-family: 'Roboto', Helvetica, Tahoma, sans-serif;
|
||||
color: #bbb;
|
||||
z-index: 2;
|
||||
|
||||
> span {
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-active {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import './MDXWrapper.less'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { Link } from 'sitepack-react'
|
||||
import { MDXBreadboard } from 'armo-breadboard'
|
||||
import fullscreenMDXBreadboardTheme from '../themes/fullscreenMDXBreadboardTheme'
|
||||
import defaultMDXBreadboardTheme from '../themes/defaultMDXBreadboardTheme'
|
||||
import createClassNamePrefixer from '../utils/createClassNamePrefixer'
|
||||
|
||||
|
||||
const cx = createClassNamePrefixer('MDXWrapper')
|
||||
|
||||
|
||||
function ThemedMDXBreadboard({ defaultSource, ...other }) {
|
||||
return (
|
||||
<MDXBreadboard
|
||||
{...other}
|
||||
defaultSource={defaultSource}
|
||||
theme={defaultMDXBreadboardTheme}
|
||||
require={breadboardRequire}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function breadboardRequire(name) {
|
||||
switch (name) {
|
||||
case 'react':
|
||||
return require('react')
|
||||
|
||||
case 'armo-breadboard':
|
||||
return { MDXBreadboard: ThemedMDXBreadboard }
|
||||
|
||||
case './components/Warning':
|
||||
return require('../../examples/components/Warning')
|
||||
|
||||
default:
|
||||
console.warn('Breadboard tried to import unknown module ', name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function headingFactory(type, props, ...children) {
|
||||
// Render the same props and children that were passed in, but append a
|
||||
// link to this title with the text '#'.
|
||||
return React.createElement(
|
||||
type,
|
||||
{
|
||||
...props,
|
||||
className: cx('hash-heading'),
|
||||
},
|
||||
...children,
|
||||
<a href={'#'+props.id} className={cx('hash')}>#</a>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default class MDXWrapper extends Component {
|
||||
static propTypes = {
|
||||
page: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { page, hash } = this.props
|
||||
|
||||
// TODO:
|
||||
// - scroll to hash on load
|
||||
|
||||
return (
|
||||
<div className={cx.root()}>
|
||||
<MDXBreadboard
|
||||
key={page.id}
|
||||
defaultMode='view'
|
||||
defaultSource={page.content}
|
||||
theme={fullscreenMDXBreadboardTheme}
|
||||
require={breadboardRequire}
|
||||
factories={{
|
||||
h1: (props, children) => headingFactory('h1', props, children),
|
||||
h2: (props, children) => headingFactory('h2', props, children),
|
||||
h3: (props, children) => headingFactory('h3', props, children),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
.MDXWrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
|
||||
@media only screen and (max-width : 639px) {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&-hash {
|
||||
transition: opacity 200ms ease-out;
|
||||
opacity: 0;
|
||||
color: #aaa;
|
||||
margin-left: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
&-hash-heading:hover &-hash {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import './SiteWrapper.less'
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { Link } from 'sitepack-react'
|
||||
import createClassNamePrefixer from '../utils/createClassNamePrefixer'
|
||||
|
||||
|
||||
const cx = createClassNamePrefixer('SiteWrapper')
|
||||
|
||||
const logoLinkTheme = ({ renderLink, active, children }) =>
|
||||
renderLink({ className: cx('logo', { 'logo-active': active }) }, children)
|
||||
|
||||
const exampleLinkTheme = ({ renderLink, active, children }) =>
|
||||
renderLink({ className: cx('link', { 'link-active': active }) }, children)
|
||||
|
||||
|
||||
export default class SiteWrapper extends Component {
|
||||
static propTypes = {
|
||||
page: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, page, hash } = this.props
|
||||
|
||||
return (
|
||||
<div className={cx.root()}>
|
||||
<a className={cx('github-ribbon')} href="https://github.com/jamesknelson/mdxc" title="Fork me on GitHub">Fork me on GitHub</a>
|
||||
<nav>
|
||||
<Link page='/site/content/index.page.js' theme={logoLinkTheme} exact>
|
||||
<img src={require('../../media/logo-white.png')} />
|
||||
</Link>
|
||||
<p className={cx('description')}>React Components within Markdown</p>
|
||||
<span className={cx('heading')}>Examples</span>
|
||||
<Link page='/examples/basics.mdx' theme={exampleLinkTheme}>Basics</Link>
|
||||
<Link page='/examples/import.mdx' theme={exampleLinkTheme}>Imports</Link>
|
||||
<Link page='/examples/props.mdx' theme={exampleLinkTheme}>Props</Link>
|
||||
<Link page='/examples/factories.mdx' theme={exampleLinkTheme}>Factories</Link>
|
||||
|
||||
<div className={cx('github-stars')}>
|
||||
<a className="github-button" href="https://github.com/jamesknelson/mdxc" data-icon="octicon-star" data-show-count="true" aria-label="Star jamesknelson/mdxc on GitHub">Star</a>
|
||||
</div>
|
||||
</nav>
|
||||
<main className={cx('main')}>
|
||||
{
|
||||
/* `children` will be `undefined` on 404 */
|
||||
children || '404'
|
||||
}
|
||||
</main>
|
||||
<footer>
|
||||
<a className={cx('author')} href='http://jamesknelson.com'>By James K Nelson</a>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
.SiteWrapper {
|
||||
height: 100%;
|
||||
|
||||
> nav {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 25px;
|
||||
left: 0;
|
||||
width: 150px;
|
||||
overflow: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
> main {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 150px;
|
||||
right: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
&-link {
|
||||
display: block;
|
||||
margin: 5px 0 5px 12px;
|
||||
}
|
||||
|
||||
> footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 150px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 639px) {
|
||||
h1 {
|
||||
margin-top: 15px
|
||||
}
|
||||
|
||||
> nav {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
bottom: auto;
|
||||
height: auto;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
> main {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
&-link {
|
||||
display: inline-block;
|
||||
margin: 0 0 5px 10px;
|
||||
}
|
||||
|
||||
> footer {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding: 15px 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
> nav {
|
||||
background-color: #181818;
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&-logo {
|
||||
display: block;
|
||||
width: 125px;
|
||||
margin: 25px auto 0;
|
||||
|
||||
> img {
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&-active > img {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
&-description {
|
||||
font-size: 13px;
|
||||
font-family: Inconsolata, sans-serif;
|
||||
text-align: center;
|
||||
margin: 0 12px 25px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
&-heading {
|
||||
display: block;
|
||||
margin: 15px 12px 5px;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: bold;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
&-link {
|
||||
font-size: 14px;
|
||||
font-family: Roboto, sans-serif;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
|
||||
&-active {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-shadow: 0 0 2px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
> footer {
|
||||
background-color: #181818;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-family: Inconsolata, sans-serif;
|
||||
text-decoration: underline;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
&-github-stars {
|
||||
margin-left: 12px;
|
||||
margin-top: 15px;
|
||||
|
||||
> a {
|
||||
color: #181818;
|
||||
}
|
||||
}
|
||||
|
||||
&-github-ribbon {
|
||||
width: 12.1em;
|
||||
height: 12.1em;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
text-indent: -999999px;
|
||||
|
||||
&:before, &:after {
|
||||
/* The right and left classes determine the side we attach our banner to */
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 15.38em;
|
||||
height: 1.54em;
|
||||
|
||||
top: 3.23em;
|
||||
right: -3.23em;
|
||||
|
||||
box-sizing: content-box;
|
||||
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
|
||||
/* Add a bit of padding to give some substance outside the "stitching" */
|
||||
padding: .38em 0;
|
||||
|
||||
/* Set the base colour */
|
||||
background-color: #a00;
|
||||
|
||||
/* Set a gradient: transparent black at the top to almost-transparent black at the bottom */
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15)));
|
||||
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15));
|
||||
|
||||
/* Add a drop shadow */
|
||||
box-shadow: 0 .15em .23em 0 rgba(0, 0, 0, 0.5);
|
||||
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&:after {
|
||||
/* Set the text from the title attribute */
|
||||
content: attr(title);
|
||||
|
||||
/* Set the text properties */
|
||||
color: #fff;
|
||||
font: 700 1em "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
line-height: 1.54em;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 -.08em rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
text-indent: 0;
|
||||
|
||||
/* Set the layout properties */
|
||||
padding: .15em 0;
|
||||
margin: .15em 0;
|
||||
|
||||
/* Add "stitching" effect */
|
||||
border-width: .08em 0;
|
||||
border-style: dotted;
|
||||
border-color: #fff;
|
||||
border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||