mirror of
https://github.com/jxnblk/mdx-deck.git
synced 2024-11-29 13:58:02 +03:00
commit
fff120b38e
23
.babelrc
23
.babelrc
@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
presets: [
|
|
||||||
'@babel/env',
|
|
||||||
'@babel/react'
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
'@babel/plugin-proposal-class-properties',
|
|
||||||
'@babel/plugin-proposal-do-expressions',
|
|
||||||
'@babel/plugin-proposal-export-default-from',
|
|
||||||
'@babel/plugin-proposal-export-namespace-from',
|
|
||||||
'@babel/plugin-proposal-function-bind',
|
|
||||||
'@babel/plugin-proposal-function-sent',
|
|
||||||
'@babel/plugin-proposal-json-strings',
|
|
||||||
'@babel/plugin-proposal-logical-assignment-operators',
|
|
||||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
|
||||||
'@babel/plugin-proposal-numeric-separator',
|
|
||||||
'@babel/plugin-proposal-optional-chaining',
|
|
||||||
'@babel/plugin-proposal-throw-expressions',
|
|
||||||
'@babel/plugin-syntax-dynamic-import',
|
|
||||||
'@babel/plugin-syntax-import-meta',
|
|
||||||
'babel-plugin-styled-components',
|
|
||||||
]
|
|
||||||
}
|
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
dist
|
dist
|
||||||
site
|
public
|
||||||
coverage
|
coverage
|
||||||
node_modules
|
node_modules
|
||||||
yarn.lock
|
package-lock.json
|
||||||
|
11
.npmignore
11
.npmignore
@ -1,11 +0,0 @@
|
|||||||
src
|
|
||||||
site
|
|
||||||
docs
|
|
||||||
coverage
|
|
||||||
test
|
|
||||||
.babelrc
|
|
||||||
.travis.yml
|
|
||||||
CHANGELOG.md
|
|
||||||
CONTRIBUTING.md
|
|
||||||
templates
|
|
||||||
create-deck
|
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "es5"
|
||||||
|
}
|
@ -1,14 +1,12 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 10
|
- 10
|
||||||
before_deploy:
|
beforeDeploy:
|
||||||
- npm install
|
- yarn build
|
||||||
- npm run build
|
|
||||||
- cp docs/card.png site
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: pages
|
provider: pages
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
github_token: $GH_TOKEN
|
github_token: $GH_TOKEN
|
||||||
local_dir: site
|
local_dir: docs/dist
|
||||||
on:
|
on:
|
||||||
branch: master
|
branch: master
|
||||||
|
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,8 +1,18 @@
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Simplified custom mdx loader, removing unused front-matter support
|
||||||
|
- Simplified theming and default styles
|
||||||
|
- Removes default Provider component with dot indicator
|
||||||
|
- Removes timers from presentation mode (maybe)
|
||||||
|
- Uses Reach Router
|
||||||
|
- Fix for focus trap
|
||||||
|
- Removed PDF export and screenshots from core CLI - now available with the `@mdx-deck/export` package
|
||||||
|
- Removed built-in syntax highlighting
|
||||||
|
- Removed `notes` language attribute for fenced code blocks
|
||||||
|
- Refactored dev server
|
||||||
|
|
||||||
## v1.10.2 2019-03-10
|
## v1.10.2 2019-03-10
|
||||||
|
|
||||||
- Fix bad release
|
- Fix bad release
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Thanks for contributing!
|
Thanks for contributing!
|
||||||
@ -27,7 +26,6 @@ Run `npm test`
|
|||||||
- Watch Mode: `npm test -- --watch`
|
- Watch Mode: `npm test -- --watch`
|
||||||
- Coverage: `npm test -- --coverage`
|
- Coverage: `npm test -- --coverage`
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Contributor Covenant Code of Conduct
|
# Contributor Covenant Code of Conduct
|
||||||
@ -87,7 +85,7 @@ further defined and clarified by project maintainers.
|
|||||||
## Enforcement
|
## Enforcement
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
|
reported by contacting the project team at jxnblk@gmail.com. All
|
||||||
complaints will be reviewed and investigated and will result in a response that
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
is deemed necessary and appropriate to the circumstances. The project team is
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
@ -103,5 +101,3 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage], versi
|
|||||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
|
||||||
|
134
README.md
134
README.md
@ -1,4 +1,4 @@
|
|||||||
# mdx-deck
|
# MDX Deck
|
||||||
|
|
||||||
![](https://s3.amazonaws.com/jxnblk/mdx-deck.gif)
|
![](https://s3.amazonaws.com/jxnblk/mdx-deck.gif)
|
||||||
|
|
||||||
@ -15,7 +15,7 @@
|
|||||||
[npm]: https://npmjs.com/package/mdx-deck
|
[npm]: https://npmjs.com/package/mdx-deck
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm i -D mdx-deck
|
npm i -D mdx-deck@next
|
||||||
```
|
```
|
||||||
|
|
||||||
- :memo: Write presentations in markdown
|
- :memo: Write presentations in markdown
|
||||||
@ -33,21 +33,27 @@ Create an [MDX][] file and separate each slide with `---`.
|
|||||||
|
|
||||||
````mdx
|
````mdx
|
||||||
# This is the title of my deck
|
# This is the title of my deck
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# About Me
|
# About Me
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
<CodeSnippet />
|
<CodeSnippet />
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
import Demo from './components/Demo'
|
import Demo from './components/Demo'
|
||||||
|
|
||||||
<Demo />
|
## <Demo />
|
||||||
---
|
|
||||||
# The end
|
# The end
|
||||||
````
|
````
|
||||||
|
|
||||||
Add a run script to your `package.json` with the mdx-deck CLI
|
Add a run script to your `package.json` with the MDX Deck CLI
|
||||||
pointing to the `.mdx` file to start the dev server:
|
pointing to the `.mdx` file to start the dev server:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -71,14 +77,14 @@ npm start
|
|||||||
- [Build a Custom Provider Component for MDX-Deck](ks-egghead) by [Kyle Shevlin][]
|
- [Build a Custom Provider Component for MDX-Deck](ks-egghead) by [Kyle Shevlin][]
|
||||||
|
|
||||||
[egghead]: https://egghead.io/lessons/react-build-a-slide-deck-with-mdx-deck-using-markdown-react
|
[egghead]: https://egghead.io/lessons/react-build-a-slide-deck-with-mdx-deck-using-markdown-react
|
||||||
[Kent C. Dodds]: https://mobile.twitter.com/kentcdodds
|
[kent c. dodds]: https://mobile.twitter.com/kentcdodds
|
||||||
[kcd-video]: http://youtu.be/d2sQiI5NFAM?a
|
[kcd-video]: http://youtu.be/d2sQiI5NFAM?a
|
||||||
[kcd-medium]: https://blog.kentcdodds.com/mdx-deck-slide-decks-powered-by-markdown-and-react-bfc6d6af20da
|
[kcd-medium]: https://blog.kentcdodds.com/mdx-deck-slide-decks-powered-by-markdown-and-react-bfc6d6af20da
|
||||||
[hw-video]: https://www.youtube.com/watch?v=LvP2EqCiQMg&feature=youtu.be
|
[hw-video]: https://www.youtube.com/watch?v=LvP2EqCiQMg&feature=youtu.be
|
||||||
[hw-demo]: https://github.com/hswolff/mdx-deck-demo
|
[hw-demo]: https://github.com/hswolff/mdx-deck-demo
|
||||||
[Harry Wolff]: https://mobile.twitter.com/hswolff
|
[harry wolff]: https://mobile.twitter.com/hswolff
|
||||||
[ks-egghead]: https://egghead.io/lessons/javascript-build-a-custom-provider-component-for-mdx-deck
|
[ks-egghead]: https://egghead.io/lessons/javascript-build-a-custom-provider-component-for-mdx-deck
|
||||||
[Kyle Shevlin]: https://twitter.com/kyleshevlin
|
[kyle shevlin]: https://twitter.com/kyleshevlin
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@ -94,21 +100,19 @@ MDX can use Markdown syntax and render React components with JSX.
|
|||||||
|
|
||||||
### Imports
|
### Imports
|
||||||
|
|
||||||
To import components, use ES import syntax separated with empty lines from any markdown or JSX syntax.
|
To import components, use ES import syntax separated with empty lines between any markdown or JSX syntax.
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
import { Box } from 'grid-styled'
|
import { Box } from 'grid-styled'
|
||||||
|
|
||||||
<Box color='tomato'>
|
<Box color="tomato">Hello</Box>
|
||||||
Hello
|
|
||||||
</Box>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Read more about MDX syntax in the [MDX Docs][MDX].
|
Read more about MDX syntax in the [MDX Docs][mdx].
|
||||||
|
|
||||||
## Theming
|
## Theming
|
||||||
|
|
||||||
mdx-deck uses [styled-components][] for styling, making practically any part of the presentation themeable.
|
MDX Deck uses [emotion][] for styling, making practically any part of the presentation themeable.
|
||||||
|
|
||||||
### Built-in Themes
|
### Built-in Themes
|
||||||
|
|
||||||
@ -118,7 +122,7 @@ mdx-deck uses [styled-components][] for styling, making practically any part of
|
|||||||
<img src='docs/images/yellow.png' width='256' />
|
<img src='docs/images/yellow.png' width='256' />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
mdx-deck includes several built-in themes to change the look and feel of the presentation.
|
MDX Deck includes several built-in themes to change the look and feel of the presentation.
|
||||||
Export `theme` from your MDX file to enable a theme.
|
Export `theme` from your MDX file to enable a theme.
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
@ -141,15 +145,10 @@ export { default as theme } from './theme'
|
|||||||
```
|
```
|
||||||
|
|
||||||
The theme should be an object with fields for fonts, colors, and CSS for individual components.
|
The theme should be an object with fields for fonts, colors, and CSS for individual components.
|
||||||
It's recommended that all custom themes extend the default theme as a base.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// example theme.js
|
// example theme.js
|
||||||
import theme from 'mdx-deck/themes'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// extends the default theme
|
|
||||||
...theme,
|
|
||||||
// add a custom font
|
// add a custom font
|
||||||
font: 'Roboto, sans-serif',
|
font: 'Roboto, sans-serif',
|
||||||
// custom colors
|
// custom colors
|
||||||
@ -157,7 +156,7 @@ export default {
|
|||||||
text: '#f0f',
|
text: '#f0f',
|
||||||
background: 'black',
|
background: 'black',
|
||||||
link: '#0ff',
|
link: '#0ff',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -165,18 +164,20 @@ Read more about theming in the [Theming docs](docs/theming.md)
|
|||||||
|
|
||||||
### Components
|
### Components
|
||||||
|
|
||||||
mdx-deck includes built-in components to help with creating presentations, including a full screen Image component, the Appear component that allows stepping through parts of a single slide, and the Notes component for adding speaker notes.
|
MDX Deck includes built-in components to help with creating presentations, including a full screen Image component, the Appear component that allows stepping through parts of a single slide, and the Notes component for adding speaker notes.
|
||||||
|
|
||||||
Read more in the [components docs](docs/components.md).
|
Read more in the [components docs](docs/components.md).
|
||||||
|
|
||||||
### Libraries
|
### Libraries
|
||||||
|
|
||||||
These third-party libraries are great for use with mdx-deck.
|
These third-party libraries are great for use with MDX Deck.
|
||||||
|
|
||||||
- [CodeSurfer][]: React component for scrolling, zooming and highlighting code.
|
- [CodeSurfer][]: React component for scrolling, zooming and highlighting code.
|
||||||
- [mdx-code][]: Runnable code playgrounds for MDX Deck.
|
- [mdx-code][]: Runnable code playgrounds for MDX Deck.
|
||||||
- [mdx-deck-live-code][]: Live React and JS coding in slides.
|
- [mdx-deck-live-code][]: Live React and JS coding in slides.
|
||||||
|
|
||||||
|
_Note: please check with version compatibility when using these libraries._
|
||||||
|
|
||||||
[codesurfer]: https://github.com/pomber/code-surfer
|
[codesurfer]: https://github.com/pomber/code-surfer
|
||||||
[mdx-code]: https://github.com/pranaygp/mdx-code
|
[mdx-code]: https://github.com/pranaygp/mdx-code
|
||||||
[mdx-deck-live-code]: https://github.com/JReinhold/mdx-deck-live-code
|
[mdx-deck-live-code]: https://github.com/JReinhold/mdx-deck-live-code
|
||||||
@ -195,8 +196,9 @@ export default ({ children }) => (
|
|||||||
style={{
|
style={{
|
||||||
width: '100vw',
|
width: '100vw',
|
||||||
height: '100vw',
|
height: '100vw',
|
||||||
backgroundColor: 'tomato'
|
backgroundColor: 'tomato',
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -208,6 +210,7 @@ import Layout from './Layout'
|
|||||||
# No Layout
|
# No Layout
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
export default Layout
|
export default Layout
|
||||||
|
|
||||||
# Custom Layout
|
# Custom Layout
|
||||||
@ -218,69 +221,58 @@ which means you can use a nested ThemeProvider or target elements with CSS-in-JS
|
|||||||
|
|
||||||
### Built-in Layouts
|
### Built-in Layouts
|
||||||
|
|
||||||
mdx-deck includes some built-in layouts for inverting theme colors and changing the layout of a slide. Read more about [built-in layouts](docs/components.md#layouts).
|
MDX Deck includes some built-in layouts for inverting theme colors and changing the layout of a slide.
|
||||||
|
Read more about [built-in layouts](docs/components.md#layouts).
|
||||||
|
|
||||||
## Presenter Mode
|
## Presenter Mode
|
||||||
|
|
||||||
mdx-deck includes a built-in presenter mode, with a preview of the next slide and a timer.
|
MDX Deck includes a built-in _Presenter Mode_, with a preview of the next slide and a timer.
|
||||||
|
|
||||||
![presenter mode screenshot](docs/images/presenter-mode.png)
|
![presenter mode screenshot](docs/images/presenter-mode.png)
|
||||||
|
|
||||||
To use presenter mode:
|
To use presenter mode:
|
||||||
|
|
||||||
- Open two windows in the same browser, with the same URL on two different screens. (this should work in both development and exported presentations)
|
1. Open your presentation and enter _Presenter Mode_
|
||||||
- In your window, press the `Option/Alt + P` keys (or add `?mode=presenter` to the URL) to enter presenter mode.
|
2. Click on the link in the bottom to open the presentation in another tab
|
||||||
- Display the other window on the screen for the audience to see.
|
3. Move the other window to the screen for the audience to see
|
||||||
- Control the presentation from your window by using the left and right arrow keys; the other window should stay in sync
|
4. Control the presentation from your window using the left and right arrow keys – the other window should stay in sync
|
||||||
|
5. Be sure to move your cursor so that it doesn't drive anyone in the audience crazy
|
||||||
|
|
||||||
### Speaker Notes
|
### Speaker Notes
|
||||||
|
|
||||||
Notes that only show in presenter mode can be added to any slide.
|
Notes that only show in presenter mode can be added to any slide.
|
||||||
Speaker notes can be added in one of the following two ways:
|
Speaker notes can be added using the `<Notes />` component.
|
||||||
|
|
||||||
**Markdown:** Use the `notes` language attribute in a fenced code block to add speaker notes.
|
|
||||||
|
|
||||||
````mdx
|
|
||||||
# Slide Content
|
|
||||||
|
|
||||||
```notes
|
|
||||||
These are only visible in presenter mode
|
|
||||||
```
|
|
||||||
````
|
|
||||||
|
|
||||||
**Notes Component:** Use the `Notes` component to create more complex speaker notes.
|
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
import { Notes } from 'mdx-deck'
|
import { Notes } from 'mdx-deck'
|
||||||
|
|
||||||
# Slide Content
|
# Slide Content
|
||||||
|
|
||||||
<Notes>
|
<Notes>Only visible in presenter mode</Notes>
|
||||||
Only visible in presenter mode
|
|
||||||
</Notes>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Overview Mode
|
## Overview Mode
|
||||||
|
|
||||||
![Overview Mode](docs/images/overview-mode.png)
|
![Overview Mode](docs/images/overview-mode.png)
|
||||||
|
|
||||||
When editing a slide deck, toggle overview mode with `Option + O` or add `?mode=overview` to the URL.
|
When editing a slide deck, toggle overview mode with `Option + O`.
|
||||||
This shows a list of all slides on the left and a preview of the current slide on the right.
|
This shows a list of all slides on the left and a preview of the current slide on the right.
|
||||||
|
|
||||||
## Keyboard Shortcuts
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
Key | Description
|
| Key | Description |
|
||||||
----------- | -----------
|
| ----------- | -------------------------------------------- |
|
||||||
Left Arrow | Go to previous slide (or step in [Appear][])
|
| Left Arrow | Go to previous slide (or step in [Appear][]) |
|
||||||
Right Arrow | Go to next slide (or step in [Appear][])
|
| Right Arrow | Go to next slide (or step in [Appear][]) |
|
||||||
Space | Go to next slide (or step in [Appear][])
|
| Space | Go to next slide (or step in [Appear][]) |
|
||||||
Up Arrow | Hide current step in [Appear][] component without navigating slides
|
| Option + P | Toggle [Presenter Mode](#presenter-mode) |
|
||||||
Down Arrow | Show next step in [Appear][] component without navigating slides
|
| Option + O | Toggle [Overview Mode](#overview-mode) |
|
||||||
Option + P | Toggle [Presenter Mode](#presenter-mode)
|
|
||||||
Option + O | Toggle [Overview Mode](#overview-mode)
|
|
||||||
Option + G | Toggle grid view mode
|
|
||||||
|
|
||||||
[Appear]: docs/components.md#appear
|
### URL Query String
|
||||||
|
|
||||||
|
The alternative modes in MDX Deck can also be set with query strings: `?mode=presenter` or `?mode=overview`
|
||||||
|
|
||||||
|
[appear]: docs/components.md#appear
|
||||||
|
|
||||||
## Exporting
|
## Exporting
|
||||||
|
|
||||||
@ -298,15 +290,10 @@ See more exporting options in the [Exporting Documentation](docs/exporting.md)
|
|||||||
|
|
||||||
```
|
```
|
||||||
-p --port Dev server port
|
-p --port Dev server port
|
||||||
--hot-port Dev server hot reload port
|
|
||||||
-h --host Host the dev server listens to
|
-h --host Host the dev server listens to
|
||||||
--no-open Prevent from opening in default browser
|
--no-open Prevent from opening in default browser
|
||||||
-d --out-dir Output directory for exporting
|
-d --out-dir Output directory for exporting
|
||||||
--no-html Disable static HTML rendering
|
--webpack Path to custom webpack config file
|
||||||
--out-file Filename for screenshot or PDF export
|
|
||||||
--width Width in pixels
|
|
||||||
--height Height in pixels
|
|
||||||
--webpack Path to webpack config file
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
@ -317,7 +304,6 @@ See more exporting options in the [Exporting Documentation](docs/exporting.md)
|
|||||||
- [Components](docs/components.md)
|
- [Components](docs/components.md)
|
||||||
- [Exporting](docs/exporting.md)
|
- [Exporting](docs/exporting.md)
|
||||||
- [Advanced Usage](docs/advanced.md)
|
- [Advanced Usage](docs/advanced.md)
|
||||||
- [React API](docs/react.md)
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@ -332,22 +318,14 @@ See more exporting options in the [Exporting Documentation](docs/exporting.md)
|
|||||||
### Related
|
### Related
|
||||||
|
|
||||||
- [MDX][]
|
- [MDX][]
|
||||||
- [mdx-go][]
|
- [emotion][]
|
||||||
- [ok-mdx][]
|
|
||||||
- [Compositor x0][]
|
|
||||||
- [styled-components][]
|
|
||||||
- [styled-system][]
|
|
||||||
- [Spectacle][]
|
- [Spectacle][]
|
||||||
|
|
||||||
[MIT License](LICENSE.md)
|
[MIT License](LICENSE.md)
|
||||||
|
|
||||||
[MDX]: https://github.com/mdx-js/mdx
|
[mdx]: https://mdxjs.com/
|
||||||
[ok-mdx]: https://github.com/jxnblk/ok-mdx
|
[spectacle]: https://github.com/FormidableLabs/spectacle
|
||||||
[Compositor x0]: https://github.com/c8r/x0
|
[emotion]: https://emotion.sh
|
||||||
[styled-system]: https://github.com/jxnblk/styled-system
|
|
||||||
[styled-components]: https://github.com/styled-components/styled-components
|
|
||||||
[Spectacle]: https://github.com/FormidableLabs/spectacle
|
|
||||||
[mdx-go]: https://github.com/jxnblk/mdx-go
|
|
||||||
|
|
||||||
<!-- examples -->
|
<!-- examples -->
|
||||||
|
|
||||||
|
1
babel.config.js
Normal file
1
babel.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./packages/mdx-deck/babel.config')
|
202
cli.js
202
cli.js
@ -1,202 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
const path = require('path')
|
|
||||||
const meow = require('meow')
|
|
||||||
const findup = require('find-up')
|
|
||||||
const open = require('react-dev-utils/openBrowser')
|
|
||||||
const chalk = require('chalk')
|
|
||||||
const remark = {
|
|
||||||
emoji: require('remark-emoji'),
|
|
||||||
unwrapImages: require('remark-unwrap-images'),
|
|
||||||
}
|
|
||||||
const pkg = require('./package.json')
|
|
||||||
|
|
||||||
const config = require('pkg-conf').sync('mdx-deck')
|
|
||||||
const log = require('./lib/log')
|
|
||||||
|
|
||||||
const cli = meow(
|
|
||||||
`
|
|
||||||
${chalk.gray('Usage')}
|
|
||||||
|
|
||||||
$ ${chalk.magenta('mdx-deck deck.mdx')}
|
|
||||||
|
|
||||||
$ ${chalk.magenta('mdx-deck build deck.mdx')}
|
|
||||||
|
|
||||||
$ ${chalk.magenta('mdx-deck pdf deck.mdx')}
|
|
||||||
|
|
||||||
$ ${chalk.magenta('mdx-deck screenshot deck.mdx')}
|
|
||||||
|
|
||||||
${chalk.gray('Options')}
|
|
||||||
|
|
||||||
--webpack Path to webpack config file
|
|
||||||
--version Print version number
|
|
||||||
|
|
||||||
${chalk.gray('Dev server options')}
|
|
||||||
|
|
||||||
-h --host Dev server host
|
|
||||||
-p --port Dev server port
|
|
||||||
--hot-port Dev server hot reload port
|
|
||||||
--no-open Prevent from opening in default browser
|
|
||||||
|
|
||||||
${chalk.gray('Build options')}
|
|
||||||
|
|
||||||
-d --out-dir Output directory for exporting
|
|
||||||
--no-html Disable static HTML rendering
|
|
||||||
|
|
||||||
${chalk.gray('Export options')}
|
|
||||||
|
|
||||||
--out-file Filename for screenshot or PDF export
|
|
||||||
--width Width in pixels
|
|
||||||
--height Height in pixels
|
|
||||||
|
|
||||||
${chalk.gray('PDF options')}
|
|
||||||
|
|
||||||
--no-sandbox Disable Puppeteer sandbox
|
|
||||||
|
|
||||||
`,
|
|
||||||
{
|
|
||||||
description: chalk.magenta('[mdx-deck] ') + chalk.gray(pkg.description),
|
|
||||||
flags: {
|
|
||||||
port: {
|
|
||||||
type: 'string',
|
|
||||||
alias: 'p',
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
type: 'string',
|
|
||||||
alias: 'h',
|
|
||||||
},
|
|
||||||
hotPort: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
open: {
|
|
||||||
type: 'boolean',
|
|
||||||
alias: 'o',
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
outDir: {
|
|
||||||
type: 'string',
|
|
||||||
alias: 'd',
|
|
||||||
},
|
|
||||||
outFile: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
html: {
|
|
||||||
type: 'boolean',
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
webpack: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
sandbox: {
|
|
||||||
type: 'boolean',
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const [cmd, file] = cli.input
|
|
||||||
const doc = file || cmd
|
|
||||||
|
|
||||||
if (!doc) cli.showHelp(0)
|
|
||||||
|
|
||||||
const opts = Object.assign(
|
|
||||||
{
|
|
||||||
dirname: path.dirname(path.resolve(doc)),
|
|
||||||
globals: {
|
|
||||||
FILENAME: JSON.stringify(path.resolve(doc)),
|
|
||||||
},
|
|
||||||
host: 'localhost',
|
|
||||||
port: 8080,
|
|
||||||
outDir: 'dist',
|
|
||||||
},
|
|
||||||
config,
|
|
||||||
cli.flags
|
|
||||||
)
|
|
||||||
|
|
||||||
opts.outDir = path.resolve(opts.outDir)
|
|
||||||
if (opts.webpack) {
|
|
||||||
opts.webpack = require(path.resolve(opts.webpack))
|
|
||||||
} else {
|
|
||||||
const webpackConfig = findup.sync('webpack.config.js', { cwd: opts.dirname })
|
|
||||||
if (webpackConfig) opts.webpack = require(webpackConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
let dev
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case 'build':
|
|
||||||
log('building')
|
|
||||||
const build = require('./lib/build')
|
|
||||||
build(opts)
|
|
||||||
.then(res => {
|
|
||||||
log('done')
|
|
||||||
process.exit(0)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
log.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'pdf':
|
|
||||||
log('exporting to PDF')
|
|
||||||
const pdf = require('./lib/pdf')
|
|
||||||
dev = require('./lib/dev')
|
|
||||||
dev(opts)
|
|
||||||
.then(({ server }) => {
|
|
||||||
log('rendering PDF')
|
|
||||||
pdf(opts)
|
|
||||||
.then(filename => {
|
|
||||||
server.close()
|
|
||||||
log('done', filename)
|
|
||||||
process.exit(0)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
log.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
log.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'screenshot':
|
|
||||||
log('exporting to PNG')
|
|
||||||
const screenshot = require('./lib/screenshot')
|
|
||||||
dev = require('./lib/dev')
|
|
||||||
dev(opts)
|
|
||||||
.then(({ server }) => {
|
|
||||||
log('rendering screenshot')
|
|
||||||
screenshot(opts)
|
|
||||||
.then(filename => {
|
|
||||||
server.close()
|
|
||||||
log('done', filename)
|
|
||||||
process.exit(0)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
log.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
log.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'dev':
|
|
||||||
default:
|
|
||||||
log('starting dev server')
|
|
||||||
dev = require('./lib/dev')
|
|
||||||
dev(opts)
|
|
||||||
.then(res => {
|
|
||||||
const { address, port } = res.server.address()
|
|
||||||
const url = 'http://' + address + ':' + res.port
|
|
||||||
if (opts.open) open(url)
|
|
||||||
log('listening on', chalk.magenta(url))
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
log.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
@ -1,56 +1,62 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from '@emotion/styled'
|
||||||
import { space, color } from 'styled-system'
|
import { space, color } from 'styled-system'
|
||||||
|
|
||||||
const Root = styled.div([], {
|
const Root = styled.div({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center'
|
alignItems: 'center',
|
||||||
})
|
})
|
||||||
|
|
||||||
const Button = styled.button([], {
|
const Button = styled.button(
|
||||||
appearance: 'none',
|
{
|
||||||
fontFamily: 'inherit',
|
appearance: 'none',
|
||||||
fontSize: 'inherit',
|
fontFamily: 'inherit',
|
||||||
fontWeight: 'bold',
|
fontSize: 'inherit',
|
||||||
borderRadius: '4px',
|
fontWeight: 'bold',
|
||||||
border: 'none',
|
borderRadius: '4px',
|
||||||
width: '2em',
|
border: 'none',
|
||||||
'&:focus': {
|
width: '2em',
|
||||||
outline: 'none',
|
'&:focus': {
|
||||||
boxShadow: '0 0 0 2px magenta'
|
outline: 'none',
|
||||||
}
|
boxShadow: '0 0 0 2px magenta',
|
||||||
}, space, color)
|
},
|
||||||
|
},
|
||||||
|
space,
|
||||||
|
color
|
||||||
|
)
|
||||||
Button.defaultProps = {
|
Button.defaultProps = {
|
||||||
m: 0,
|
m: 0,
|
||||||
px: 3,
|
px: 3,
|
||||||
py: 2,
|
py: 2,
|
||||||
color: 'background',
|
color: 'background',
|
||||||
bg: 'text'
|
bg: 'text',
|
||||||
}
|
}
|
||||||
|
|
||||||
const Samp = styled.samp([], {
|
const Samp = styled.samp(space)
|
||||||
}, space)
|
|
||||||
|
|
||||||
|
|
||||||
export default class Counter extends React.Component {
|
export default class Counter extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
count: 0
|
count: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
inc = () => {
|
inc = () => {
|
||||||
this.setState(state => ({count: state.count + 1}))
|
this.setState(state => ({ count: state.count + 1 }))
|
||||||
}
|
}
|
||||||
|
|
||||||
dec = () => {
|
dec = () => {
|
||||||
this.setState(state => ({count: state.count - 1}))
|
this.setState(state => ({ count: state.count - 1 }))
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Root>
|
<Root>
|
||||||
<Button ml='auto' onClick={this.dec}>-</Button>
|
<Button ml="auto" onClick={this.dec}>
|
||||||
|
-
|
||||||
|
</Button>
|
||||||
<Samp mx={3}>{this.state.count}</Samp>
|
<Samp mx={3}>{this.state.count}</Samp>
|
||||||
<Button mr='auto' onClick={this.inc}>+</Button>
|
<Button mr="auto" onClick={this.inc}>
|
||||||
|
+
|
||||||
|
</Button>
|
||||||
</Root>
|
</Root>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,35 @@
|
|||||||
|
|
||||||
# Advanced Usage
|
# Advanced Usage
|
||||||
|
|
||||||
## Custom MDX components
|
## Custom MDX components
|
||||||
|
|
||||||
mdx-deck includes default components for MDX, but to provide custom components to the [MDXProvider][], add a `components` object to the `theme`.
|
MDX Deck includes default components for MDX, but to provide custom components to the [MDXProvider][], add a `components` object to the `theme`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// example theme
|
// example theme
|
||||||
import { theme } from 'mdx-deck/themes'
|
|
||||||
import Heading from './Heading'
|
import Heading from './Heading'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...theme,
|
|
||||||
components: {
|
components: {
|
||||||
h1: Heading
|
h1: Heading,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [MDX][] docs for more or take a look
|
See the [MDX][] docs for more or take a look
|
||||||
at the [default set of components](../src/components.js) as a reference.
|
at the [default set of components](../packages/components/src/mdx-components.js) as a reference.
|
||||||
|
|
||||||
## Custom Provider component
|
## Custom Provider component
|
||||||
|
|
||||||
A custom Provider component can be added to the theme to wrap the entire application.
|
A custom Provider component can be added to the theme to wrap the entire application.
|
||||||
This is useful for adding custom context providers in React.
|
This is useful for adding custom context providers in React or adding persistent UI elements to the entire deck.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// example theme.js
|
// example theme.js
|
||||||
import { theme } from 'mdx-deck/themes'
|
|
||||||
import Provider from './Provider'
|
import Provider from './Provider'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...theme,
|
|
||||||
font: 'Georgia, serif',
|
font: 'Georgia, serif',
|
||||||
Provider
|
Provider,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -43,20 +38,19 @@ which can be used to show custom page numbers or add other elements to the UI.
|
|||||||
|
|
||||||
#### Props
|
#### Props
|
||||||
|
|
||||||
|
- `slides`: (array) the components for each slide
|
||||||
- `index`: (number) the current slide index
|
- `index`: (number) the current slide index
|
||||||
- `length`: (number) the length of the slides array
|
- `mode`: (string) the current mode (one of `'normal'`, `'presenter'`, or `'overview'`)
|
||||||
- `mode`: (string) the current mode (one of `'NORMAL'`, `'PRESENTER'`, or `'OVERVIEW'`)
|
- `step`: (number) the current visible step in an Appear or Step component
|
||||||
- `notes`: (object) custom [speaker notes](#speaker-notes) for all slides
|
- Each slide includes a `meta` object with a `notes` field when the Notes component is used within a slide
|
||||||
- `step`: (number) the current visible step in an Appear component
|
|
||||||
|
|
||||||
|
|
||||||
## Combining multiple mdx files
|
## Combining multiple mdx files
|
||||||
|
|
||||||
Unlike the official `@mdx-js/loader`,
|
Unlike the official `@mdx-js/loader`,
|
||||||
the `mdx-deck/loader` exports an array of components instead of just one.
|
the `@mdx-deck/loader` exports an additional `slides` array of components instead of just the entire document.
|
||||||
Multiple MDX files can be combined into a single presentation if the filesize is getting difficult to manage.
|
Multiple MDX files can be combined into a single presentation if the filesize is getting difficult to manage.
|
||||||
|
|
||||||
First create a couple `.mdx` files like any other mdx-deck file, with `---` to separate the different slides.
|
First create a couple `.mdx` files like any other MDX Deck file, with `---` to separate the different slides.
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
# one.mdx
|
# one.mdx
|
||||||
@ -78,16 +72,13 @@ Next, create a `.js` file to import and combine the two `.mdx` files.
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
// deck.js
|
// deck.js
|
||||||
import one from './one.mdx'
|
import { slides as one } from './one.mdx'
|
||||||
import two from './two.mdx'
|
import { slides as two } from './two.mdx'
|
||||||
|
|
||||||
export default [
|
export const slides = [...one, ...two]
|
||||||
...one,
|
|
||||||
...two
|
|
||||||
]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, point the mdx-deck CLI comment in your `package.json` to the `deck.js` file.
|
Then, point the MDX Deck CLI comment in your `package.json` to the `deck.js` file.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -97,7 +88,9 @@ Then, point the mdx-deck CLI comment in your `package.json` to the `deck.js` fil
|
|||||||
|
|
||||||
## Custom webpack config
|
## Custom webpack config
|
||||||
|
|
||||||
Webpack configuration files named `webpack.config.js` will automatically be merged with the built-in configuration, using [webpack-merge](https://github.com/survivejs/webpack-merge). To use a custom filename, pass the file path to the `--webpack` flag.
|
Webpack configuration files named `webpack.config.js` will automatically be merged with the built-in configuration,
|
||||||
|
using [webpack-merge](https://github.com/survivejs/webpack-merge).
|
||||||
|
To use a custom filename, pass the file path to the `--webpack` flag.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// webpack.config.js example
|
// webpack.config.js example
|
||||||
@ -106,26 +99,23 @@ module.exports = {
|
|||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
use: [
|
use: [{ loader: 'babel-loader' }, { loader: 'react-svg-loader' }],
|
||||||
{ loader: 'babel-loader' },
|
},
|
||||||
{ loader: 'react-svg-loader' }
|
],
|
||||||
]
|
},
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Careful**: When overwriting the loader for `mdx` files, make sure to include the default loader from `mdx-deck/loader`.
|
**Careful**: When overwriting the loader for `mdx` files, make sure to include the default loader from `@mdx-deck/loader`.
|
||||||
|
|
||||||
## Custom build setups
|
## Custom build setups
|
||||||
|
|
||||||
The core mdx-deck components can also be used in any React application,
|
The core MDX Deck components can also be used in any React application,
|
||||||
such as [create-react-app][] or [next.js][].
|
such as [create-react-app][] or [next.js][].
|
||||||
|
|
||||||
See the [React API](react.md) docs for more.
|
See the [`@mdx-deck/components`](../packages/components) package for more.
|
||||||
|
|
||||||
[MDX]: https://github.com/mdx-js/mdx
|
[mdx]: https://mdxjs.com
|
||||||
[MDXProvider]: https://github.com/mdx-js/mdx/blob/master/docs/getting-started/index.md#mdxprovider
|
[mdxprovider]: https://github.com/mdx-js/mdx/blob/master/docs/getting-started/index.md#mdxprovider
|
||||||
[create-react-app]: https://github.com/facebook/create-react-app
|
[create-react-app]: https://github.com/facebook/create-react-app
|
||||||
[next.js]: https://github.com/zeit/next.js/
|
[next.js]: https://github.com/zeit/next.js/
|
||||||
|
30
docs/code.js
30
docs/code.js
@ -1,30 +0,0 @@
|
|||||||
export const a = `import React from 'react'
|
|
||||||
|
|
||||||
const Foo = props =>
|
|
||||||
<h1>Bar</h1>
|
|
||||||
|
|
||||||
export default Foo`
|
|
||||||
|
|
||||||
export const b = `import styled from 'styled-components'
|
|
||||||
import { space, color } from 'styled-system'
|
|
||||||
|
|
||||||
const Box = styled.div([], space, color)
|
|
||||||
|
|
||||||
export default Box`
|
|
||||||
|
|
||||||
export const surfer = `import { CodeSurfer } from 'mdx-deck-code-surfer'
|
|
||||||
import codeExample from './code-example'
|
|
||||||
|
|
||||||
<CodeSurfer
|
|
||||||
title='Check out my code'
|
|
||||||
code={codeExample}
|
|
||||||
steps={[
|
|
||||||
{
|
|
||||||
lines: [ 4, 5 ],
|
|
||||||
notes: 'This is lines 4 & 5 highlighted'
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
`
|
|
||||||
|
|
||||||
export default { a, b, surfer }
|
|
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
# Components
|
# Components
|
||||||
|
|
||||||
mdx-deck includes a few built-in components to help with creating presentations.
|
MDX Deck includes a few built-in components to help with creating presentations.
|
||||||
|
|
||||||
## Head
|
## Head
|
||||||
|
|
||||||
@ -13,11 +12,11 @@ import { Head } from 'mdx-deck'
|
|||||||
|
|
||||||
<Head>
|
<Head>
|
||||||
<title>My Presentation</title>
|
<title>My Presentation</title>
|
||||||
<meta name='twitter:card' content='summary_large_image' />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name='twitter:site' content='@jxnblk' />
|
<meta name="twitter:site" content="@jxnblk" />
|
||||||
<meta name='twitter:title' content='My Presentation' />
|
<meta name="twitter:title" content="My Presentation" />
|
||||||
<meta name='twitter:description' content='A really great presentation' />
|
<meta name="twitter:description" content="A really great presentation" />
|
||||||
<meta name='twitter:image' content='https://example.com/card.png' />
|
<meta name="twitter:image" content="https://example.com/card.png" />
|
||||||
</Head>
|
</Head>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -28,10 +27,11 @@ Use the `<Image />` component to render a fullscreen image (using the CSS `backg
|
|||||||
```mdx
|
```mdx
|
||||||
import { Image } from 'mdx-deck'
|
import { Image } from 'mdx-deck'
|
||||||
|
|
||||||
<Image src='kitten.png' />
|
<Image src="kitten.png" />
|
||||||
```
|
```
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
|
|
||||||
- `src` (string) image URL
|
- `src` (string) image URL
|
||||||
- `size` (string) CSS background-size
|
- `size` (string) CSS background-size
|
||||||
|
|
||||||
@ -52,31 +52,23 @@ import { Appear } from 'mdx-deck'
|
|||||||
</ul>
|
</ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Internally, the `<Appear />` component uses the `<Step />` component, which can be used to build custom components with similar behavior.
|
||||||
|
|
||||||
## Speaker Notes
|
## Speaker Notes
|
||||||
|
|
||||||
Speaker notes that only show in presenter mode can be added to any slide with either markdown syntax or with the Notes component.
|
Speaker notes that only show in presenter mode can be added to any slide with the Notes component.
|
||||||
|
|
||||||
````mdx
|
|
||||||
# Markdown speaker notes
|
|
||||||
|
|
||||||
```notes
|
|
||||||
These are only visible in presenter mode
|
|
||||||
```
|
|
||||||
````
|
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
import { Notes } from 'mdx-deck'
|
import { Notes } from 'mdx-deck'
|
||||||
|
|
||||||
# Slide Content
|
# Slide Content
|
||||||
|
|
||||||
<Notes>
|
<Notes>Only visible in presenter mode</Notes>
|
||||||
Only visible in presenter mode
|
|
||||||
</Notes>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Layouts
|
## Layouts
|
||||||
|
|
||||||
mdx-deck includes a few built-in layouts for common slide variations.
|
MDX Deck includes a few built-in layouts for common slide variations.
|
||||||
Export a layout as the `default` within a slide to wrap the contents.
|
Export a layout as the `default` within a slide to wrap the contents.
|
||||||
|
|
||||||
### Invert
|
### Invert
|
||||||
@ -123,6 +115,10 @@ export default SplitRight
|
|||||||
## Meow
|
## Meow
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Horizontal
|
||||||
|
|
||||||
|
Similar to the Split components, but renders all children side-by-side
|
||||||
|
|
||||||
### FullScreenCode
|
### FullScreenCode
|
||||||
|
|
||||||
Render fenced code blocks fullscreen.
|
Render fenced code blocks fullscreen.
|
||||||
@ -136,4 +132,3 @@ export default FullScreenCode
|
|||||||
<Button>Beep</Button>
|
<Button>Beep</Button>
|
||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
export { future as theme } from '../themes'
|
export { future as theme } from '@mdx-deck/themes'
|
||||||
import { Head, Image, Notes, Appear } from '../dist'
|
import { Head, Image, Notes, Appear } from '@mdx-deck/components'
|
||||||
import { Invert, Split, FullScreenCode, Horizontal} from '../layouts'
|
import { Invert, Split, SplitRight, FullScreenCode, Horizontal} from '@mdx-deck/layouts'
|
||||||
import Counter from './Counter'
|
import Counter from './Counter'
|
||||||
import code from './code'
|
|
||||||
|
|
||||||
<Head>
|
<Head>
|
||||||
<title>mdx-deck</title>
|
<title>mdx-deck</title>
|
||||||
@ -13,23 +12,30 @@ import code from './code'
|
|||||||
<meta name='twitter:image' content='https://jxnblk.com/mdx-deck/card.png' />
|
<meta name='twitter:image' content='https://jxnblk.com/mdx-deck/card.png' />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
# mdx-deck
|
# MDX Deck
|
||||||
|
|
||||||
MDX-based presention decks
|
MDX-based presention decks
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Presentation decks
|
# Presentation decks
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Built with [MDX][]
|
# Built with [MDX][]
|
||||||
[MDX]: https://github.com/mdx-js/mdx
|
[MDX]: https://github.com/mdx-js/mdx
|
||||||
|
|
||||||
---
|
---
|
||||||
import Box from 'superbox'
|
import { Box } from '@rebass/emotion'
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
fontSize={3}
|
fontSize={[ 6, 7 ]}
|
||||||
p={4}
|
p={4}
|
||||||
|
color='navy'
|
||||||
bg='magenta'>
|
bg='magenta'>
|
||||||
Import React components
|
Import React components
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
- Make bulleted lists
|
- Make bulleted lists
|
||||||
@ -49,10 +55,11 @@ import Box from 'superbox'
|
|||||||
<button>code example</button>
|
<button>code example</button>
|
||||||
```
|
```
|
||||||
|
|
||||||
```notes
|
<Notes>
|
||||||
- These are speaker notes
|
These are speaker notes
|
||||||
- And they won't be rendered in your slide
|
- And they won't be rendered in your slide
|
||||||
```
|
</Notes>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
@ -66,7 +73,9 @@ class extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
> “Blockquotes are essential to any good presentation”
|
> “Blockquotes are essential to any good presentation”
|
||||||
|
|
||||||
– Anonymous
|
– Anonymous
|
||||||
@ -79,6 +88,7 @@ class extends React.Component {
|
|||||||
</Notes>
|
</Notes>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Appear
|
### Appear
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
@ -89,6 +99,7 @@ class extends React.Component {
|
|||||||
<li>Four</li>
|
<li>Four</li>
|
||||||
</Appear>
|
</Appear>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Image
|
<Image
|
||||||
@ -96,9 +107,10 @@ class extends React.Component {
|
|||||||
size='contain'
|
size='contain'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
```notes
|
<Notes>
|
||||||
Testing object fit
|
Testing object fit
|
||||||
```
|
</Notes>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Real React Components
|
### Real React Components
|
||||||
@ -110,6 +122,7 @@ Testing object fit
|
|||||||
<Image src='https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=2048&q=20' />
|
<Image src='https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=2048&q=20' />
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
export default Split
|
export default Split
|
||||||
|
|
||||||
![](https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=2048&q=20)
|
![](https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=2048&q=20)
|
||||||
@ -117,6 +130,17 @@ export default Split
|
|||||||
## Split Layout
|
## Split Layout
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
export default SplitRight
|
||||||
|
|
||||||
|
![](https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=2048&q=20)
|
||||||
|
|
||||||
|
## Split Layout
|
||||||
|
|
||||||
|
(To the right)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
export default Horizontal
|
export default Horizontal
|
||||||
|
|
||||||
![](https://source.unsplash.com/random/1024x768')
|
![](https://source.unsplash.com/random/1024x768')
|
||||||
@ -157,4 +181,6 @@ Prop | Type | Description
|
|||||||
export default Invert
|
export default Invert
|
||||||
|
|
||||||
# Get started :sunglasses:
|
# Get started :sunglasses:
|
||||||
|
|
||||||
[GitHub](https://github.com/jxnblk/mdx-deck)
|
[GitHub](https://github.com/jxnblk/mdx-deck)
|
||||||
|
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Exporting
|
# Exporting
|
||||||
|
|
||||||
## Static Bundle
|
## Static Bundle
|
||||||
@ -12,26 +11,24 @@ add a `build` script to your `package.json` file.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## PDF Export
|
### PDF & Screenshots
|
||||||
|
|
||||||
Presentations can be exported as PDF using the CLI.
|
To export a deck as PDF or create a PNG screenshot, install the export CLI package:
|
||||||
This works well as a backup option for any unforeseen technical difficulties.
|
|
||||||
|
|
||||||
```json
|
```sh
|
||||||
"script": {
|
npm i @mdx-deck/export
|
||||||
"pdf": "mdx-deck pdf deck.mdx"
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Screenshots
|
Then run the following command to create a PDF:
|
||||||
|
|
||||||
A PNG image of the first slide can be exported with the `screenshot` command.
|
```sh
|
||||||
This is useful for creating open graph images for Twitter, Facebook, or Slack.
|
mdx-deck-export pdf deck.mdx
|
||||||
|
```
|
||||||
|
|
||||||
```json
|
Or export the first slide as a PNG:
|
||||||
"script": {
|
|
||||||
"screenshot": "mdx-deck screenshot deck.mdx"
|
```sh
|
||||||
}
|
mdx-deck-export png deck.mdx
|
||||||
```
|
```
|
||||||
|
|
||||||
### OG Image
|
### OG Image
|
||||||
@ -43,7 +40,6 @@ Note that the meta tag should point to a full URL, including schema and domain n
|
|||||||
import { Head } from 'mdx-deck'
|
import { Head } from 'mdx-deck'
|
||||||
|
|
||||||
<Head>
|
<Head>
|
||||||
<meta name='og:image' content='https://example.com/card.png' />
|
<meta name="og:image" content="https://example.com/card.png" />
|
||||||
</Head>
|
</Head>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
22
docs/package.json
Normal file
22
docs/package.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"name": "@mdx-deck/docs",
|
||||||
|
"version": "2.0.0-8",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "Brent Jackson <jxnblk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"start": "mdx-deck demo.mdx",
|
||||||
|
"build": "mdx-deck build demo.mdx"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/core": "^10.0.7",
|
||||||
|
"@emotion/styled": "^10.0.7",
|
||||||
|
"@mdx-deck/components": "^2.0.0-8",
|
||||||
|
"@mdx-deck/layouts": "^2.0.0-7",
|
||||||
|
"@mdx-deck/themes": "^2.0.0-7",
|
||||||
|
"@rebass/emotion": "^3.0.0",
|
||||||
|
"mdx-deck": "^2.0.0-8",
|
||||||
|
"rebass": "^3.0.1"
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
export { yellow as theme } from '../src/themes'
|
|
||||||
|
|
||||||
# Say hello to...
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Presenter mode
|
|
||||||
|
|
||||||
(press *Option + P*)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## You can see the next slide
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## And the *next* one
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## And a timer
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## And [speaker notes][] too!
|
|
||||||
|
|
||||||
[speaker notes]: https://github.com/jxnblk/mdx-deck#speaker-notes
|
|
||||||
|
|
||||||
```notes
|
|
||||||
No one will see this 🙈
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# mdx-deck
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
|
|
||||||
# React API
|
|
||||||
|
|
||||||
The core mdx-deck components can also be used in any React application, such as [create-react-app][] or [next.js][].
|
|
||||||
|
|
||||||
### Webpack Loader
|
|
||||||
|
|
||||||
mdx-deck uses a custom webpack loader to split MDX files into an array of slides. Use this loader to import mdx files in a webpack application.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// example webpack.config.js
|
|
||||||
module.exports = {
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.mdx$/,
|
|
||||||
ignore: /node_modules/,
|
|
||||||
use: [
|
|
||||||
'babel-loader',
|
|
||||||
'mdx-deck/loader'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### SlideDeck Component
|
|
||||||
|
|
||||||
```js
|
|
||||||
import React from 'react'
|
|
||||||
import { SlideDeck } from 'mdx-deck'
|
|
||||||
import slides from './deck.mdx'
|
|
||||||
import theme from './theme'
|
|
||||||
|
|
||||||
export default () =>
|
|
||||||
<SlideDeck
|
|
||||||
slides={slides}
|
|
||||||
theme={theme}
|
|
||||||
width='100vw'
|
|
||||||
height='100vh'
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
View the source for other components available for use.
|
|
||||||
|
|
||||||
[create-react-app]: https://github.com/facebook/create-react-app
|
|
||||||
[next.js]: https://github.com/zeit/next.js/
|
|
@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
# Themes
|
# Themes
|
||||||
|
|
||||||
![](images/default.png)
|
![](images/default.png)
|
||||||
Default
|
Default
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { default as theme } from 'mdx-deck/themes'
|
export { default as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -14,7 +14,8 @@ export { default as theme } from 'mdx-deck/themes'
|
|||||||
Big
|
Big
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { big as theme } from 'mdx-deck/themes'
|
export { big as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -23,7 +24,8 @@ export { big as theme } from 'mdx-deck/themes'
|
|||||||
Book
|
Book
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { book as theme } from 'mdx-deck/themes'
|
export { book as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -32,7 +34,8 @@ export { book as theme } from 'mdx-deck/themes'
|
|||||||
Code
|
Code
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { code as theme } from 'mdx-deck/themes'
|
export { code as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -41,7 +44,8 @@ export { code as theme } from 'mdx-deck/themes'
|
|||||||
Comic
|
Comic
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { comic as theme } from 'mdx-deck/themes'
|
export { comic as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -50,7 +54,8 @@ export { comic as theme } from 'mdx-deck/themes'
|
|||||||
Condensed
|
Condensed
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { condensed as theme } from 'mdx-deck/themes'
|
export { condensed as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -59,7 +64,8 @@ export { condensed as theme } from 'mdx-deck/themes'
|
|||||||
Dark
|
Dark
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { dark as theme } from 'mdx-deck/themes'
|
export { dark as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -68,7 +74,8 @@ export { dark as theme } from 'mdx-deck/themes'
|
|||||||
Future
|
Future
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { future as theme } from 'mdx-deck/themes'
|
export { future as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -77,7 +84,8 @@ export { future as theme } from 'mdx-deck/themes'
|
|||||||
Hack
|
Hack
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { hack as theme } from 'mdx-deck/themes'
|
export { hack as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -91,7 +99,8 @@ Lobster
|
|||||||
Notes
|
Notes
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { notes as theme } from 'mdx-deck/themes'
|
export { notes as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -105,7 +114,8 @@ Rye
|
|||||||
Script
|
Script
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { script as theme } from 'mdx-deck/themes'
|
export { script as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -114,7 +124,8 @@ export { script as theme } from 'mdx-deck/themes'
|
|||||||
Swiss
|
Swiss
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { swiss as theme } from 'mdx-deck/themes'
|
export { swiss as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -123,6 +134,33 @@ export { swiss as theme } from 'mdx-deck/themes'
|
|||||||
Yellow
|
Yellow
|
||||||
|
|
||||||
```mdx
|
```mdx
|
||||||
export { yellow as theme } from 'mdx-deck/themes'
|
export { yellow as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Poppins
|
||||||
|
|
||||||
|
```mdx
|
||||||
|
export { poppins as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Syntax Highlighter
|
||||||
|
|
||||||
|
```mdx
|
||||||
|
export { syntaxHighlighter as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Syntax Highlighter Prism
|
||||||
|
|
||||||
|
```mdx
|
||||||
|
export { syntaxHighlighterPrism as theme } from 'mdx-deck/themes
|
||||||
|
'
|
||||||
|
```
|
||||||
|
141
docs/theming.md
141
docs/theming.md
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
# Theming
|
# Theming
|
||||||
|
|
||||||
mdx-deck uses [styled-components][] for styling, making practically any part of the presentation themeable.
|
mdx-deck uses [emotion][] for styling, making practically any part of the presentation themeable.
|
||||||
|
|
||||||
## Built-in Themes
|
## Built-in Themes
|
||||||
|
|
||||||
@ -27,145 +26,84 @@ export { default as theme } from './theme'
|
|||||||
```
|
```
|
||||||
|
|
||||||
The theme should be an object with fields for fonts, colors, and CSS for individual components.
|
The theme should be an object with fields for fonts, colors, and CSS for individual components.
|
||||||
It's recommended that all custom themes extend the default theme as a base.
|
|
||||||
|
|
||||||
<small>Note: you need to include [all keys](#reference) in the `colors` object for the theming to work correctly. You may want to use a deep [merge](https://www.npmjs.com/search?q=merge) strategy for extending existing themes more easily.</small>
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Example theme.js
|
// Example theme.js
|
||||||
import theme from 'mdx-deck/themes'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
// extends the default theme
|
|
||||||
...theme,
|
|
||||||
// add a custom font
|
// add a custom font
|
||||||
font: 'Roboto, sans-serif',
|
font: 'Roboto, sans-serif',
|
||||||
// custom colors
|
// custom colors
|
||||||
colors: {
|
colors: {
|
||||||
...theme.colors, // include existing theme colors
|
|
||||||
text: '#f0f',
|
text: '#f0f',
|
||||||
background: 'black',
|
background: 'black',
|
||||||
link: '#0ff',
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Composing Themes
|
||||||
|
|
||||||
|
Multiple themes can be used together.
|
||||||
|
For example, this allows the use of a syntax highlighting theme,
|
||||||
|
along with a color theme, and a separate typography theme.
|
||||||
|
|
||||||
|
To compose themes together export a `themes` array instead of a single theme.
|
||||||
|
|
||||||
|
```mdx
|
||||||
|
import { syntaxHighlighter } from 'mdx-deck/themes'
|
||||||
|
import customTheme from './theme'
|
||||||
|
|
||||||
|
export const themes = [syntaxHighlighter, customTheme]
|
||||||
|
|
||||||
|
# Cool. :sunglasses:
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that themes are deep merged together and the last theme specified will override fields from themes before it.
|
||||||
|
|
||||||
### Google Fonts
|
### Google Fonts
|
||||||
|
|
||||||
To use webfonts, mdx-deck will attempt to add `<link>` tags for any font from Google Fonts.
|
Themes can specify a `googleFont` field to automatically add a `<link>` tag to the document head.
|
||||||
To load webfonts from other sources, use a custom [Provider component](advanced.md#custom-provider-component) to add custom `<link>` tags.
|
Alternatively, use the `<Head />` component to add a custom `<link>` tag.
|
||||||
|
|
||||||
### Syntax Highlighting
|
### Syntax Highlighting
|
||||||
|
|
||||||
By default fenced code blocks do not include any syntax highlighting.
|
By default fenced code blocks do not include any syntax highlighting.
|
||||||
Syntax highlighting in fenced code blocks can be enabled by providing a `prism` style object in a theme.
|
Themes can provide a set of custom MDX components, including a replacement for the default `code` component that can add syntax highlighting with libraries like [react-syntax-highlighter][].
|
||||||
The syntax highlighting is built with [react-syntax-highlighter][] and [PrismJS][].
|
|
||||||
Create a `theme.js` file and export it via the `MDX` file.
|
|
||||||
|
|
||||||
```js
|
MDX Deck includes two themes for adding syntax highlighting with [react-syntax-highlighter][]: `syntaxHighlighter` and `syntaxHighlighterPrism`.
|
||||||
export { default as theme } from './theme'
|
|
||||||
//...
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
Since MDX supports using React components inline, you can also import a syntax highlighting component directly, if you prefer.
|
||||||
// example theme.js
|
|
||||||
import { future } from 'mdx-deck/themes'
|
|
||||||
import okaidia from 'react-syntax-highlighter/styles/prism/okaidia'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...future,
|
|
||||||
prism: {
|
|
||||||
style: okaidia
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, only JavaScript and JSX are enabled for syntax highlighting to keep bundle sizes to a minimum.
|
|
||||||
To enable other languages, add a `languages` object to the `prism` object in the theme.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// example theme.js
|
|
||||||
import { future } from 'mdx-deck/themes'
|
|
||||||
import okaidia from 'react-syntax-highlighter/styles/prism/okaidia'
|
|
||||||
import prismRuby from 'react-syntax-highlighter/languages/prism/ruby'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...future,
|
|
||||||
prism: {
|
|
||||||
style: okaidia,
|
|
||||||
languages: {
|
|
||||||
ruby: prismRuby
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For lists of available syntax styles and languages, see:
|
|
||||||
|
|
||||||
- [Prism languages](https://github.com/conorhastings/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_PRISM.MD)
|
|
||||||
- [Prism styles](https://github.com/conorhastings/react-syntax-highlighter/blob/master/AVAILABLE_STYLES_PRISM.MD)
|
|
||||||
|
|
||||||
[PrismJS]: https://github.com/PrismJS/prism
|
|
||||||
[react-syntax-highlighter]: https://github.com/conorhastings/react-syntax-highlighter
|
|
||||||
|
|
||||||
### Slide Transitions
|
|
||||||
|
|
||||||
The slide transition timing function and duration can be customized with a custom theme.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// example theme
|
|
||||||
import theme from 'mdx-deck/themes'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...theme,
|
|
||||||
transitionTimingFunction: 'linear',
|
|
||||||
transitionDuration: '.1s'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Styling Elements
|
### Styling Elements
|
||||||
|
|
||||||
Each element can be styled with a theme. Add a style object (or string) to the theme to target specific elements.
|
Each element can be styled with a theme.
|
||||||
|
Add a style object (or string) to the theme to target specific elements.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// example theme
|
// example theme
|
||||||
import theme from 'mdx-deck/themes'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
...theme,
|
|
||||||
h1: {
|
h1: {
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
letterSpacing: '0.1em'
|
letterSpacing: '0.1em',
|
||||||
},
|
},
|
||||||
blockquote: {
|
blockquote: {
|
||||||
fontStyle: 'italic'
|
fontStyle: 'italic',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [reference](#reference) below for a full list of element keys.
|
See the [reference](#reference) below for a full list of element keys.
|
||||||
|
|
||||||
|
|
||||||
## Reference
|
## Reference
|
||||||
|
|
||||||
The following keys are available for theming:
|
The following keys are available for theming:
|
||||||
|
|
||||||
- `font`: base font family
|
- `font`: base font family
|
||||||
- `weights`: array of font weights for the main font
|
|
||||||
- `monospace`: font family for `<pre>` and `<code>`
|
- `monospace`: font family for `<pre>` and `<code>`
|
||||||
- `fontSizes`: array of font sizes from smallest to largest
|
|
||||||
- `colors`: object of colors used for MDX components
|
- `colors`: object of colors used for MDX components
|
||||||
- `text`: root foreground color
|
- `text`: root foreground color
|
||||||
- `background`: root background color
|
- `background`: root background color
|
||||||
- `link`
|
- `code`: text color for `<pre>` and `<code>`
|
||||||
- `heading`
|
- `codeBackground`: background color for `<pre>` and `<code>`
|
||||||
- `blockquote`
|
|
||||||
- `pre`
|
|
||||||
- `preBackground`
|
|
||||||
- `code`
|
|
||||||
- `codeBackground`
|
|
||||||
- `transitionTimingFunction`: timing function value for slide transitions
|
|
||||||
- `transitionDuration`: duration value for slide transitions. set to `0` to disable transitions
|
|
||||||
- `css`: root CSS object
|
- `css`: root CSS object
|
||||||
- `heading`: CSS for all headings
|
- `heading`: CSS for all headings
|
||||||
- `h1`: CSS for `<h1>`
|
- `h1`: CSS for `<h1>`
|
||||||
@ -174,20 +112,25 @@ The following keys are available for theming:
|
|||||||
- `h4`: CSS for `<h4>`
|
- `h4`: CSS for `<h4>`
|
||||||
- `h5`: CSS for `<h5>`
|
- `h5`: CSS for `<h5>`
|
||||||
- `h6`: CSS for `<h6>`
|
- `h6`: CSS for `<h6>`
|
||||||
- `paragraph`: CSS for `<p>`
|
- `p`: CSS for `<p>`
|
||||||
- `link`: CSS for `<a>`
|
- `a`: CSS for `<a>`
|
||||||
- `ul`: CSS for `<ul>`
|
- `ul`: CSS for `<ul>`
|
||||||
- `ol`: CSS for `<ol>`
|
- `ol`: CSS for `<ol>`
|
||||||
- `li`: CSS for `<li>`
|
- `li`: CSS for `<li>`
|
||||||
- `img`: CSS for `<img>`
|
- `img`: CSS for `<img>`
|
||||||
- `blockquote`: CSS for `<blockquote>`
|
- `blockquote`: CSS for `<blockquote>`
|
||||||
- `table`: CSS for `<table>`
|
- `table`: CSS for `<table>`
|
||||||
|
- `pre`: CSS for `<pre>`
|
||||||
|
- `code`: CSS for `<code>`
|
||||||
|
- `Slides`: CSS to apply to the wrapping Slide component
|
||||||
- `components`: object of MDX components to render markdown
|
- `components`: object of MDX components to render markdown
|
||||||
- `Provider`: component for wrapping the entire app
|
- `Provider`: component for wrapping the entire app
|
||||||
|
- `googleFont`: CSS HREF for adding a Google Font `<link>` tag
|
||||||
|
|
||||||
## Advanced Usage
|
## Advanced Usage
|
||||||
|
|
||||||
For more advanced customizations see the [Advanced Usage](advanced.md) docs.
|
For more advanced customizations see the [Advanced Usage](advanced.md) docs.
|
||||||
|
|
||||||
[styled-components]: https://github.com/styled-components/styled-components
|
[emotion]: https://emotion.sh
|
||||||
[MDX]: https://github.com/mdx-js/mdx
|
[mdx]: https://github.com/mdx-js/mdx
|
||||||
|
[react-syntax-highlighter]: https://github.com/conorhastings/react-syntax-highlighter
|
||||||
|
@ -1 +0,0 @@
|
|||||||
module.exports = require('./dist/layouts')
|
|
6
lerna.json
Normal file
6
lerna.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"packages": ["packages/*"],
|
||||||
|
"npmClient": "yarn",
|
||||||
|
"useWorkspaces": true,
|
||||||
|
"version": "2.0.0-8"
|
||||||
|
}
|
44
lib/build.js
44
lib/build.js
@ -1,44 +0,0 @@
|
|||||||
const webpack = require('webpack')
|
|
||||||
const createConfig = require('./config')
|
|
||||||
const renderHTML = require('./html')
|
|
||||||
const log = require('./log')
|
|
||||||
|
|
||||||
const build = async (opts = {}) => {
|
|
||||||
if (opts.html) {
|
|
||||||
log('rendering static html')
|
|
||||||
const { body, head, css } = await renderHTML(opts)
|
|
||||||
Object.assign(opts, {
|
|
||||||
body,
|
|
||||||
head,
|
|
||||||
css,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
log('bundling js')
|
|
||||||
const config = createConfig(opts)
|
|
||||||
|
|
||||||
config.mode = 'production'
|
|
||||||
config.output = {
|
|
||||||
path: opts.outDir
|
|
||||||
}
|
|
||||||
|
|
||||||
const compiler = webpack(config)
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
compiler.run((err, stats) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stats.compilation.errors && stats.compilation.errors.length) {
|
|
||||||
reject(stats.compilation.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(stats)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = build
|
|
153
lib/config.js
153
lib/config.js
@ -1,153 +0,0 @@
|
|||||||
const fs = require('fs')
|
|
||||||
const path = require('path')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
const HTMLPlugin = require('mini-html-webpack-plugin')
|
|
||||||
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
|
|
||||||
const merge = require('webpack-merge')
|
|
||||||
const chalk = require('chalk')
|
|
||||||
const remark = {
|
|
||||||
emoji: require('remark-emoji'),
|
|
||||||
unwrapImages: require('remark-unwrap-images'),
|
|
||||||
}
|
|
||||||
|
|
||||||
const babel = {
|
|
||||||
presets: ['@babel/preset-env', '@babel/preset-react'].map(require.resolve),
|
|
||||||
plugins: [
|
|
||||||
'@babel/plugin-proposal-class-properties',
|
|
||||||
'@babel/plugin-proposal-do-expressions',
|
|
||||||
'@babel/plugin-proposal-export-default-from',
|
|
||||||
'@babel/plugin-proposal-export-namespace-from',
|
|
||||||
'@babel/plugin-proposal-function-bind',
|
|
||||||
'@babel/plugin-proposal-function-sent',
|
|
||||||
'@babel/plugin-proposal-json-strings',
|
|
||||||
'@babel/plugin-proposal-logical-assignment-operators',
|
|
||||||
'@babel/plugin-proposal-nullish-coalescing-operator',
|
|
||||||
'@babel/plugin-proposal-numeric-separator',
|
|
||||||
'@babel/plugin-proposal-optional-chaining',
|
|
||||||
'@babel/plugin-proposal-throw-expressions',
|
|
||||||
'@babel/plugin-syntax-dynamic-import',
|
|
||||||
'@babel/plugin-syntax-import-meta',
|
|
||||||
'babel-plugin-styled-components',
|
|
||||||
].map(require.resolve),
|
|
||||||
}
|
|
||||||
|
|
||||||
const rules = [
|
|
||||||
{
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: require.resolve('babel-loader'),
|
|
||||||
options: babel,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
exclude: path.resolve(__dirname, '../node_modules'),
|
|
||||||
include: [path.resolve(__dirname, '..')],
|
|
||||||
loader: require.resolve('babel-loader'),
|
|
||||||
options: babel,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.mdx?$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: require.resolve('babel-loader'),
|
|
||||||
options: babel,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: require.resolve('./loader.js'),
|
|
||||||
options: {
|
|
||||||
mdPlugins: [remark.emoji, remark.unwrapImages],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const template = ({
|
|
||||||
head = '<title>mdx-deck</title>',
|
|
||||||
css = '',
|
|
||||||
body = '',
|
|
||||||
js,
|
|
||||||
publicPath,
|
|
||||||
}) => `<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset='utf-8'>
|
|
||||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
|
||||||
<style>*{box-sizing:border-box}body{font-family:system-ui,sans-serif;margin:0}</style>
|
|
||||||
<meta name='generator' content='mdx-deck'>
|
|
||||||
${head}${css}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id=root>${body}</div>
|
|
||||||
${HTMLPlugin.generateJSReferences(js, publicPath)}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`
|
|
||||||
|
|
||||||
const baseConfig = {
|
|
||||||
stats: 'errors-only',
|
|
||||||
mode: 'development',
|
|
||||||
module: {
|
|
||||||
rules,
|
|
||||||
},
|
|
||||||
resolve: {
|
|
||||||
extensions: ['.js', '.jsx'],
|
|
||||||
alias: {
|
|
||||||
'mdx-deck': path.resolve(__dirname, '..'),
|
|
||||||
},
|
|
||||||
modules: [
|
|
||||||
path.relative(process.cwd(), path.join(__dirname, '../node_modules')),
|
|
||||||
'node_modules',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new ProgressBarPlugin({
|
|
||||||
width: '24',
|
|
||||||
complete: '█',
|
|
||||||
incomplete: chalk.gray('░'),
|
|
||||||
format: [
|
|
||||||
chalk.magenta('[mdx-deck] :bar'),
|
|
||||||
chalk.magenta(':percent'),
|
|
||||||
chalk.gray(':elapseds :msg'),
|
|
||||||
].join(' '),
|
|
||||||
summary: false,
|
|
||||||
customSummary: () => {},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const createConfig = (opts = {}) => {
|
|
||||||
const config = merge(baseConfig, opts.webpack)
|
|
||||||
config.context = opts.dirname
|
|
||||||
|
|
||||||
config.resolve.modules.push(
|
|
||||||
opts.dirname,
|
|
||||||
path.join(opts.dirname, 'node_modules')
|
|
||||||
)
|
|
||||||
|
|
||||||
config.entry = [path.join(__dirname, '../dist/entry.js')]
|
|
||||||
|
|
||||||
const defs = Object.assign({}, opts.globals, {
|
|
||||||
OPTIONS: JSON.stringify(opts),
|
|
||||||
HOT_PORT: JSON.stringify(opts.hotPort),
|
|
||||||
HOT_HOST: JSON.stringify(opts.host),
|
|
||||||
})
|
|
||||||
|
|
||||||
config.plugins.push(
|
|
||||||
new webpack.DefinePlugin(defs),
|
|
||||||
new HTMLPlugin({ template, context: opts })
|
|
||||||
)
|
|
||||||
|
|
||||||
if (config.resolve.alias) {
|
|
||||||
const hotAlias = config.resolve.alias['webpack-hot-client/client']
|
|
||||||
if (!fs.existsSync(hotAlias)) {
|
|
||||||
const hotPath = path.dirname(require.resolve('webpack-hot-client/client'))
|
|
||||||
config.resolve.alias['webpack-hot-client/client'] = hotPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = createConfig
|
|
47
lib/dev.js
47
lib/dev.js
@ -1,47 +0,0 @@
|
|||||||
const path = require('path')
|
|
||||||
const Koa = require('koa')
|
|
||||||
const getPort = require('get-port')
|
|
||||||
const koaWebpack = require('koa-webpack')
|
|
||||||
const koaStatic = require('koa-static')
|
|
||||||
const createConfig = require('./config')
|
|
||||||
|
|
||||||
const devMiddleware = {
|
|
||||||
publicPath: '/',
|
|
||||||
clientLogLevel: 'error',
|
|
||||||
stats: 'errors-only',
|
|
||||||
logLevel: 'error',
|
|
||||||
}
|
|
||||||
|
|
||||||
const start = async (opts = {}) => {
|
|
||||||
const app = new Koa()
|
|
||||||
opts.host = opts.host || 'localhost'
|
|
||||||
opts.hotPort = opts.hotPort || await getPort()
|
|
||||||
const hotClient = {
|
|
||||||
port: opts.hotPort,
|
|
||||||
host: opts.host,
|
|
||||||
logLevel: 'error'
|
|
||||||
}
|
|
||||||
opts.dirname = opts.dirname || path.dirname(opts.entry)
|
|
||||||
const config = createConfig(opts)
|
|
||||||
config.entry.push(
|
|
||||||
path.join(__dirname, './overlay.js')
|
|
||||||
)
|
|
||||||
|
|
||||||
const middleware = await koaWebpack({
|
|
||||||
config,
|
|
||||||
devMiddleware,
|
|
||||||
hotClient
|
|
||||||
})
|
|
||||||
const port = opts.port || await getPort()
|
|
||||||
app.use(middleware)
|
|
||||||
app.use(koaStatic(opts.dirname))
|
|
||||||
|
|
||||||
const server = app.listen(port, opts.host)
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
middleware.devMiddleware.waitUntilValid(() => {
|
|
||||||
resolve({ server, app, middleware, port })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = start
|
|
64
lib/html.js
64
lib/html.js
@ -1,64 +0,0 @@
|
|||||||
const fs = require('fs')
|
|
||||||
const path = require('path')
|
|
||||||
const React = require('react')
|
|
||||||
const { renderToString, renderToStaticMarkup } = require('react-dom/server')
|
|
||||||
const { ServerStyleSheet } = require('styled-components')
|
|
||||||
const webpack = require('webpack')
|
|
||||||
const nodeExternals = require('webpack-node-externals')
|
|
||||||
const rimraf = require('rimraf')
|
|
||||||
const mkdirp = require('mkdirp')
|
|
||||||
const createConfig = require('./config')
|
|
||||||
|
|
||||||
const getApp = async opts => {
|
|
||||||
opts.tempdir = path.join(opts.outDir, 'TEMP')
|
|
||||||
|
|
||||||
if (!fs.existsSync(opts.outDir)) mkdirp.sync(opts.outDir)
|
|
||||||
if (!fs.existsSync(opts.tempdir)) mkdirp.sync(opts.tempdir)
|
|
||||||
|
|
||||||
const config = createConfig(opts)
|
|
||||||
|
|
||||||
config.output = {
|
|
||||||
path: opts.tempdir,
|
|
||||||
filename: '[name].js',
|
|
||||||
libraryTarget: 'umd',
|
|
||||||
}
|
|
||||||
config.entry = {
|
|
||||||
App: path.join(__dirname, '../dist/entry.js'),
|
|
||||||
}
|
|
||||||
config.target = 'node'
|
|
||||||
config.externals = [
|
|
||||||
nodeExternals({
|
|
||||||
whitelist: ['mdx-deck', 'mdx-deck/themes', 'mdx-deck/layouts'],
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
|
|
||||||
const compiler = webpack(config)
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
compiler.run((err, stats) => {
|
|
||||||
if (err) {
|
|
||||||
reject(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const App = require(path.resolve(opts.tempdir, './App.js')).default
|
|
||||||
rimraf(opts.tempdir, err => {
|
|
||||||
if (err) console.error(err)
|
|
||||||
})
|
|
||||||
resolve(App)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderHTML = async opts => {
|
|
||||||
const App = await getApp(opts)
|
|
||||||
const headTags = []
|
|
||||||
const sheet = new ServerStyleSheet()
|
|
||||||
const body = renderToString(
|
|
||||||
sheet.collectStyles(React.createElement(App, { headTags }))
|
|
||||||
)
|
|
||||||
const head = renderToStaticMarkup(headTags)
|
|
||||||
const css = sheet.getStyleTags()
|
|
||||||
return { body, head, css }
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = renderHTML
|
|
@ -1,43 +0,0 @@
|
|||||||
const { getOptions } = require('loader-utils')
|
|
||||||
const mdx = require('@mdx-js/mdx')
|
|
||||||
const matter = require('gray-matter')
|
|
||||||
const stringifyObject = require('stringify-object')
|
|
||||||
const normalizeNewline = require('normalize-newline')
|
|
||||||
|
|
||||||
const SLIDEREG = /\n---\n/
|
|
||||||
|
|
||||||
module.exports = async function (src) {
|
|
||||||
const callback = this.async()
|
|
||||||
const options = getOptions(this) || {}
|
|
||||||
options.skipExport = true
|
|
||||||
|
|
||||||
const { data, content } = matter(src)
|
|
||||||
|
|
||||||
const modules = []
|
|
||||||
const slides = normalizeNewline(content)
|
|
||||||
.split(SLIDEREG)
|
|
||||||
.map(str => {
|
|
||||||
const code = mdx.sync(str, options)
|
|
||||||
const lines = code.split('\n')
|
|
||||||
const tagIndex = lines.findIndex(str => /^</.test(str))
|
|
||||||
modules.push(
|
|
||||||
...lines.slice(0, tagIndex)
|
|
||||||
.filter(Boolean)
|
|
||||||
)
|
|
||||||
const jsx = lines.slice(tagIndex).join('\n')
|
|
||||||
|
|
||||||
return `({ components, ...props }) => ${jsx}`
|
|
||||||
})
|
|
||||||
.map(str => str.trim())
|
|
||||||
|
|
||||||
const code = `import React from 'react'
|
|
||||||
import { MDXTag } from '@mdx-js/tag'
|
|
||||||
${modules.join('\n')}
|
|
||||||
export const meta = ${stringifyObject(data)}
|
|
||||||
|
|
||||||
export default [
|
|
||||||
${slides.join(',\n\n')}
|
|
||||||
]`
|
|
||||||
|
|
||||||
return callback(null, code)
|
|
||||||
}
|
|
16
lib/log.js
16
lib/log.js
@ -1,16 +0,0 @@
|
|||||||
const chalk = require('chalk')
|
|
||||||
|
|
||||||
const log = (...args) => {
|
|
||||||
console.log(
|
|
||||||
chalk.magenta('[mdx-deck]'),
|
|
||||||
...args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
log.error = (...args) => {
|
|
||||||
console.log(
|
|
||||||
chalk.red('[err]'),
|
|
||||||
...args
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = log
|
|
@ -1,81 +0,0 @@
|
|||||||
const ansiHTML = require('ansi-html')
|
|
||||||
const Entities = require('html-entities').AllHtmlEntities
|
|
||||||
const entities = new Entities()
|
|
||||||
|
|
||||||
const colors = {
|
|
||||||
reset: ['transparent', 'transparent'],
|
|
||||||
black: '000000',
|
|
||||||
red: 'FF0000',
|
|
||||||
green: '00FF00',
|
|
||||||
yellow: 'FFFF00',
|
|
||||||
blue: '0000FF',
|
|
||||||
magenta: 'FF00FF',
|
|
||||||
cyan: '00FFFF',
|
|
||||||
lightgrey: 'EEEEEE',
|
|
||||||
darkgrey: '666666'
|
|
||||||
};
|
|
||||||
ansiHTML.setColors(colors)
|
|
||||||
|
|
||||||
let overlay
|
|
||||||
|
|
||||||
const style = (el, styles) => {
|
|
||||||
for (const key in styles) {
|
|
||||||
el.style[key] = styles[key]
|
|
||||||
}
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
|
|
||||||
const show = ({
|
|
||||||
title = '',
|
|
||||||
text = ''
|
|
||||||
}) => {
|
|
||||||
overlay = document.body.appendChild(
|
|
||||||
document.createElement('pre')
|
|
||||||
)
|
|
||||||
style(overlay, {
|
|
||||||
position: 'fixed',
|
|
||||||
top: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
left: 0,
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
fontFamily: 'Menlo, monospace',
|
|
||||||
fontSize: '12px',
|
|
||||||
overflow: 'auto',
|
|
||||||
lineHeight: 1.5,
|
|
||||||
padding: '8px',
|
|
||||||
margin: 0,
|
|
||||||
color: 'magenta',
|
|
||||||
backgroundColor: 'black'
|
|
||||||
})
|
|
||||||
const code = ansiHTML(entities.encode(text))
|
|
||||||
overlay.innerHTML = `<span>${title}</span>
|
|
||||||
<br />
|
|
||||||
<br />${code}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
const destroy = () => {
|
|
||||||
if (!overlay) return
|
|
||||||
document.body.removeChild(overlay)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ws = new WebSocket('ws://' + HOT_HOST + ':' + HOT_PORT)
|
|
||||||
|
|
||||||
ws.addEventListener('message', msg => {
|
|
||||||
const data = JSON.parse(msg.data)
|
|
||||||
switch (data.type) {
|
|
||||||
case 'errors':
|
|
||||||
const [ text ] = data.data.errors
|
|
||||||
console.error(data.data.errors)
|
|
||||||
show({ title: 'failed to compile', text })
|
|
||||||
break
|
|
||||||
case 'ok':
|
|
||||||
destroy()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ws.addEventListener('close', () => {
|
|
||||||
show({ title: 'disconnected' })
|
|
||||||
})
|
|
39
lib/pdf.js
39
lib/pdf.js
@ -1,39 +0,0 @@
|
|||||||
const fs = require('fs')
|
|
||||||
const path = require('path')
|
|
||||||
const mkdirp = require('mkdirp')
|
|
||||||
const puppeteer = require('puppeteer')
|
|
||||||
|
|
||||||
module.exports = async (opts = {}) => {
|
|
||||||
// This can be used to control some UI components's visibility like: Appear,...
|
|
||||||
|
|
||||||
const {
|
|
||||||
outDir,
|
|
||||||
outFile = 'presentation.pdf',
|
|
||||||
port,
|
|
||||||
width = 1280,
|
|
||||||
height = 960,
|
|
||||||
sandbox = true,
|
|
||||||
} = opts
|
|
||||||
const args = sandbox ? [] : ['--no-sandbox', '--disable-setuid-sandbox']
|
|
||||||
const browser = await puppeteer.launch({ args })
|
|
||||||
const page = await browser.newPage()
|
|
||||||
page.setUserAgent('MDX-Deck/1.7.7 Print/PDF')
|
|
||||||
const filename = path.join(outDir, outFile)
|
|
||||||
if (!fs.existsSync(outDir)) mkdirp.sync(outDir)
|
|
||||||
|
|
||||||
await page.goto('http://localhost:' + port, {
|
|
||||||
waitUntil: 'networkidle2',
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.pdf({
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
path: filename,
|
|
||||||
scale: 1,
|
|
||||||
printBackground: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
return filename
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
const fs = require('fs')
|
|
||||||
const path = require('path')
|
|
||||||
const mkdirp = require('mkdirp')
|
|
||||||
const puppeteer = require('puppeteer')
|
|
||||||
|
|
||||||
module.exports = async (opts) => {
|
|
||||||
const {
|
|
||||||
width = 1280,
|
|
||||||
height = 720,
|
|
||||||
outFile = 'card.png',
|
|
||||||
sandbox = true
|
|
||||||
} = opts
|
|
||||||
const file = path.join(opts.outDir, outFile)
|
|
||||||
|
|
||||||
if (!fs.existsSync(opts.outDir)) mkdirp.sync(opts.outDir)
|
|
||||||
|
|
||||||
const browser = await puppeteer.launch({
|
|
||||||
args: [
|
|
||||||
!sandbox && '--no-sandbox'
|
|
||||||
].filter(Boolean)
|
|
||||||
})
|
|
||||||
const page = await browser.newPage()
|
|
||||||
|
|
||||||
await page.setViewport({ width, height })
|
|
||||||
|
|
||||||
await page.goto('http://localhost:' + opts.port, {
|
|
||||||
waitUntil: 'networkidle2'
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.screenshot({
|
|
||||||
path: file,
|
|
||||||
type: 'png',
|
|
||||||
clip: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
return outFile
|
|
||||||
}
|
|
11282
package-lock.json
generated
11282
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
123
package.json
123
package.json
@ -1,110 +1,29 @@
|
|||||||
{
|
{
|
||||||
"name": "mdx-deck",
|
"private": true,
|
||||||
"version": "1.10.2",
|
"version": "2.0.0-0",
|
||||||
"description": "MDX-based presentation decks",
|
"workspaces": [
|
||||||
"main": "dist/index.js",
|
"packages/*",
|
||||||
"bin": {
|
"templates/*",
|
||||||
"mdx-deck": "./cli.js"
|
"docs"
|
||||||
},
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "npm run babel",
|
"start": "yarn workspace @mdx-deck/docs start",
|
||||||
"babel": "babel src -d dist",
|
"build": "yarn workspace @mdx-deck/docs build",
|
||||||
"watch": "babel src -d dist --watch",
|
|
||||||
"start": "./cli.js docs/index.mdx -p 8080",
|
|
||||||
"build": "./cli.js build docs/index.mdx -d site",
|
|
||||||
"pdf": "./cli.js pdf docs/index.mdx -d site",
|
|
||||||
"screenshot": "./cli.js screenshot docs/index.mdx -d docs",
|
|
||||||
"help": "./cli.js",
|
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
|
||||||
"author": "Brent Jackson",
|
|
||||||
"license": "MIT",
|
|
||||||
"repository": "github:jxnblk/mdx-deck",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/core": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-do-expressions": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-export-default-from": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-export-namespace-from": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-function-bind": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-function-sent": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-json-strings": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.0.0",
|
|
||||||
"@babel/plugin-proposal-throw-expressions": "^7.0.0",
|
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
|
||||||
"@babel/plugin-syntax-import-meta": "^7.0.0",
|
|
||||||
"@babel/preset-env": "^7.0.0",
|
|
||||||
"@babel/preset-react": "^7.0.0",
|
|
||||||
"@compositor/webfont": "^1.0.39",
|
|
||||||
"@mdx-js/mdx": "^0.15.7",
|
|
||||||
"@mdx-js/tag": "^0.15.6",
|
|
||||||
"ansi-html": "0.0.7",
|
|
||||||
"babel-loader": "^8.0.0",
|
|
||||||
"babel-plugin-styled-components": "^1.10.0",
|
|
||||||
"chalk": "^2.4.2",
|
|
||||||
"clipboardy": "^1.2.3",
|
|
||||||
"find-up": "^3.0.0",
|
|
||||||
"get-port": "^4.1.0",
|
|
||||||
"gray-matter": "^4.0.2",
|
|
||||||
"hhmmss": "^1.0.0",
|
|
||||||
"html-entities": "^1.2.1",
|
|
||||||
"koa": "^2.7.0",
|
|
||||||
"koa-static": "^5.0.0",
|
|
||||||
"koa-webpack": "^5.2.1",
|
|
||||||
"loader-utils": "^1.2.3",
|
|
||||||
"lodash.debounce": "^4.0.8",
|
|
||||||
"lodash.get": "^4.4.2",
|
|
||||||
"meow": "^5.0.0",
|
|
||||||
"mini-html-webpack-plugin": "^0.2.3",
|
|
||||||
"mkdirp": "^0.5.1",
|
|
||||||
"normalize-newline": "^3.0.0",
|
|
||||||
"pkg-conf": "^2.1.0",
|
|
||||||
"progress-bar-webpack-plugin": "^1.12.1",
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"puppeteer": "^1.12.2",
|
|
||||||
"querystring": "^0.2.0",
|
|
||||||
"react": "^16.8.2",
|
|
||||||
"react-dev-utils": "^7.0.3",
|
|
||||||
"react-dom": "^16.8.2",
|
|
||||||
"react-swipeable": "^4.3.2",
|
|
||||||
"react-syntax-highlighter": "^8.1.0",
|
|
||||||
"remark-emoji": "^2.0.2",
|
|
||||||
"remark-unwrap-images": "^0.1.0",
|
|
||||||
"rimraf": "^2.6.3",
|
|
||||||
"stringify-object": "^3.3.0",
|
|
||||||
"styled-components": "^4.1.3",
|
|
||||||
"styled-system": "^3.2.1",
|
|
||||||
"superbox": "^2.1.0",
|
|
||||||
"webpack": "^4.29.5",
|
|
||||||
"webpack-hot-client": "^4.1.1",
|
|
||||||
"webpack-merge": "^4.2.1",
|
|
||||||
"webpack-node-externals": "^1.7.2"
|
|
||||||
},
|
|
||||||
"peerDependencies": {},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/cli": "^7.0.0",
|
"@babel/core": "^7.3.4",
|
||||||
"babel-jest": "^24.1.0",
|
"@babel/preset-env": "^7.3.4",
|
||||||
|
"@babel/preset-react": "^7.0.0",
|
||||||
"husky": "^1.3.1",
|
"husky": "^1.3.1",
|
||||||
"jest": "^24.1.0",
|
"jest": "^24.3.1",
|
||||||
"jest-styled-components": "^6.3.1",
|
"lerna": "^3.13.1",
|
||||||
"lint-staged": "^7.3.0",
|
"lint-staged": "^8.1.5",
|
||||||
"mdx-deck-code-surfer": "^0.5.5",
|
"prettier": "^1.16.4"
|
||||||
"prettier": "^1.16.4",
|
|
||||||
"react-test-renderer": "^16.8.2"
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"roots": [
|
|
||||||
"<rootDir>/test/"
|
|
||||||
],
|
|
||||||
"testMatch": [
|
|
||||||
"**/test/**/*.js"
|
|
||||||
],
|
|
||||||
"testURL": "http://localhost/",
|
|
||||||
"coverageReporters": [
|
"coverageReporters": [
|
||||||
|
"lcov",
|
||||||
"html"
|
"html"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -114,15 +33,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{js,json}": [
|
"*.{md,js,json}": [
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"git add"
|
"git add"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"prettier": {
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"jsxBracketSameLine": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
packages/components/README.md
Normal file
5
packages/components/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# @mdx-deck/components
|
||||||
|
|
||||||
|
React components use in MDX Deck
|
||||||
|
|
||||||
|
https://github.com/jxnblk/mdx-deck
|
26
packages/components/package.json
Normal file
26
packages/components/package.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "@mdx-deck/components",
|
||||||
|
"version": "2.0.0-8",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"author": "Brent Jackson <jxnblk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/core": "^10.0.7",
|
||||||
|
"@emotion/styled": "^10.0.7",
|
||||||
|
"@mdx-js/tag": "^1.0.0-alpha.5",
|
||||||
|
"@reach/router": "^1.2.1",
|
||||||
|
"emotion-theming": "^10.0.7",
|
||||||
|
"hhmmss": "^1.0.0",
|
||||||
|
"lodash.merge": "^4.6.1",
|
||||||
|
"react-swipeable": "^5.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@mdx-deck/thems": "^2.0.0-0",
|
||||||
|
"@mdx-js/tag": "^0.18.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"react": "^16.8.3",
|
||||||
|
"react-dom": "^16.8.3",
|
||||||
|
"react-test-renderer": "^16.8.4"
|
||||||
|
}
|
||||||
|
}
|
21
packages/components/src/Appear.js
Normal file
21
packages/components/src/Appear.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import useSteps from './useSteps'
|
||||||
|
|
||||||
|
export const Appear = props => {
|
||||||
|
const arr = React.Children.toArray(props.children)
|
||||||
|
const step = useSteps(arr.length)
|
||||||
|
const children = arr.map((child, i) =>
|
||||||
|
i < step
|
||||||
|
? child
|
||||||
|
: React.cloneElement(child, {
|
||||||
|
style: {
|
||||||
|
...child.props.style,
|
||||||
|
visibility: 'hidden',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return <>{children}</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Appear
|
25
packages/components/src/Catch.js
Normal file
25
packages/components/src/Catch.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export class Catch extends React.Component {
|
||||||
|
state = {
|
||||||
|
err: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(err) {
|
||||||
|
this.setState({ err })
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
if (!this.state.err) return
|
||||||
|
this.setState({ err: null })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.err) {
|
||||||
|
return <pre children={this.state.err.toString()} />
|
||||||
|
}
|
||||||
|
return <>{this.props.children}</>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Catch
|
57
packages/components/src/Clock.js
Normal file
57
packages/components/src/Clock.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import React, { useState, useEffect } from 'react'
|
||||||
|
import hhmmss from 'hhmmss'
|
||||||
|
import Pre from './Pre'
|
||||||
|
|
||||||
|
const spacer = <div style={{ margin: 4 }} />
|
||||||
|
|
||||||
|
let timer
|
||||||
|
|
||||||
|
const Clock = props => {
|
||||||
|
const [time, setTime] = useState(new Date().toLocaleTimeString())
|
||||||
|
const [seconds, setSeconds] = useState(0)
|
||||||
|
const [on, setTimer] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const tick = () => {
|
||||||
|
const now = new Date()
|
||||||
|
setTime(now.toLocaleTimeString())
|
||||||
|
if (on) setSeconds(seconds + 1)
|
||||||
|
}
|
||||||
|
timer = setInterval(tick, 1000)
|
||||||
|
return () => {
|
||||||
|
clearInterval(timer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={!seconds || on}
|
||||||
|
onClick={e => {
|
||||||
|
setSeconds(0)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
{spacer}
|
||||||
|
<button
|
||||||
|
onClick={e => {
|
||||||
|
setTimer(!on)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{on ? 'Pause' : 'Start'}
|
||||||
|
</button>
|
||||||
|
{spacer}
|
||||||
|
<Pre>
|
||||||
|
{hhmmss(seconds)} | {time}
|
||||||
|
</Pre>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Clock
|
13
packages/components/src/GoogleFonts.js
Normal file
13
packages/components/src/GoogleFonts.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { createPortal } from 'react-dom'
|
||||||
|
import { withTheme } from 'emotion-theming'
|
||||||
|
|
||||||
|
const GoogleFonts = withTheme(({ theme }) => {
|
||||||
|
if (!theme.googleFont) return false
|
||||||
|
return createPortal(
|
||||||
|
<link rel="stylesheet" href={theme.googleFont} />,
|
||||||
|
document.head
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default GoogleFonts
|
@ -1,49 +1,28 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { createPortal } from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
const noop = () => {
|
export const HeadContext = React.createContext({
|
||||||
console.warn('Missing HeadProvider')
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Context = React.createContext({
|
|
||||||
tags: [],
|
tags: [],
|
||||||
push: noop
|
push: () => {
|
||||||
|
console.warn('Missing HeadProvider')
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export class HeadProvider extends React.Component {
|
export const HeadProvider = ({ tags = [], children }) => {
|
||||||
static defaultProps = {
|
const push = elements => {
|
||||||
tags: []
|
tags.push(...elements)
|
||||||
}
|
|
||||||
|
|
||||||
push = (elements) => {
|
|
||||||
this.props.tags.push(...elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const context = {
|
|
||||||
...this.props,
|
|
||||||
push: this.push
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Context.Provider value={context}>
|
|
||||||
{this.props.children}
|
|
||||||
</Context.Provider>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
const context = { push }
|
||||||
|
return <HeadContext.Provider value={context}>{children}</HeadContext.Provider>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Head extends React.Component {
|
export class Head extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
didMount: false
|
didMount: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
rehydrate = () => {
|
rehydrate = () => {
|
||||||
const children = React.Children.toArray(this.props.children)
|
const children = React.Children.toArray(this.props.children)
|
||||||
const nodes = [
|
const nodes = [...document.head.querySelectorAll('[data-head]')]
|
||||||
...document.head.querySelectorAll('[data-head]')
|
|
||||||
]
|
|
||||||
|
|
||||||
nodes.forEach(node => {
|
nodes.forEach(node => {
|
||||||
node.remove()
|
node.remove()
|
||||||
})
|
})
|
||||||
@ -59,27 +38,22 @@ export class Head extends React.Component {
|
|||||||
if (meta) meta.remove()
|
if (meta) meta.remove()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.setState({ didMount: true })
|
||||||
this.setState({
|
|
||||||
didMount: true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount() {
|
||||||
this.rehydrate()
|
this.rehydrate()
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render() {
|
||||||
const children = React.Children.toArray(this.props.children)
|
const children = React.Children.toArray(this.props.children).map(child =>
|
||||||
.map(child => React.cloneElement(child, {
|
React.cloneElement(child, {
|
||||||
'data-head': true
|
'data-head': true,
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
const { didMount } = this.state
|
if (!this.state.didMount) {
|
||||||
|
|
||||||
if (!didMount) {
|
|
||||||
return (
|
return (
|
||||||
<Context.Consumer
|
<HeadContext.Consumer
|
||||||
children={({ push }) => {
|
children={({ push }) => {
|
||||||
push(children)
|
push(children)
|
||||||
return false
|
return false
|
||||||
@ -87,10 +61,8 @@ export class Head extends React.Component {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
return createPortal(children, document.head)
|
||||||
return createPortal(
|
|
||||||
children,
|
|
||||||
document.head
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default Head
|
22
packages/components/src/Image.js
Normal file
22
packages/components/src/Image.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import styled from '@emotion/styled'
|
||||||
|
|
||||||
|
export const Image = styled.div(
|
||||||
|
{
|
||||||
|
backgroundPosition: 'center',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
},
|
||||||
|
props => ({
|
||||||
|
backgroundSize: props.size,
|
||||||
|
width: props.width,
|
||||||
|
height: props.height,
|
||||||
|
backgroundImage: `url(${props.src})`,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
Image.defaultProps = {
|
||||||
|
size: 'cover',
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Image
|
257
packages/components/src/MDXDeck.js
Normal file
257
packages/components/src/MDXDeck.js
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { Router, globalHistory, navigate, Link } from '@reach/router'
|
||||||
|
import { Swipeable } from 'react-swipeable'
|
||||||
|
import querystring from 'querystring'
|
||||||
|
import Provider from './Provider'
|
||||||
|
import Slide from './Slide'
|
||||||
|
import Presenter from './Presenter'
|
||||||
|
import Overview from './Overview'
|
||||||
|
import Print from './Print'
|
||||||
|
import GoogleFonts from './GoogleFonts'
|
||||||
|
import Catch from './Catch'
|
||||||
|
|
||||||
|
const NORMAL = 'normal'
|
||||||
|
const PRESENTER = 'presenter'
|
||||||
|
const OVERVIEW = 'overview'
|
||||||
|
const PRINT = 'print'
|
||||||
|
|
||||||
|
const STORAGE_INDEX = 'mdx-slide'
|
||||||
|
const STORAGE_STEP = 'mdx-step'
|
||||||
|
|
||||||
|
const keys = {
|
||||||
|
right: 39,
|
||||||
|
left: 37,
|
||||||
|
space: 32,
|
||||||
|
p: 80,
|
||||||
|
o: 79,
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleMode = key => state => ({
|
||||||
|
mode: state.mode === key ? NORMAL : key,
|
||||||
|
})
|
||||||
|
|
||||||
|
const BaseWrapper = props => <>{props.children}</>
|
||||||
|
|
||||||
|
const inputElements = ['INPUT', 'TEXTAREA', 'A', 'BUTTON']
|
||||||
|
|
||||||
|
export class MDXDeck extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
slides: props.slides,
|
||||||
|
step: 0,
|
||||||
|
mode: NORMAL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown = e => {
|
||||||
|
const { key, keyCode, metaKey, ctrlKey, altKey, shiftKey } = e
|
||||||
|
const { activeElement } = document
|
||||||
|
if (inputElements.includes(activeElement.tagName)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (metaKey || ctrlKey) return
|
||||||
|
const alt = altKey && !shiftKey
|
||||||
|
const shift = shiftKey && !altKey
|
||||||
|
|
||||||
|
const { pathname } = globalHistory.location
|
||||||
|
if (keyCode === keys.p && shiftKey && altKey) {
|
||||||
|
navigate('/print')
|
||||||
|
this.setState({ mode: 'print' })
|
||||||
|
}
|
||||||
|
if (pathname === '/print') return
|
||||||
|
|
||||||
|
if (alt) {
|
||||||
|
switch (keyCode) {
|
||||||
|
case keys.p:
|
||||||
|
this.setState(toggleMode(PRESENTER))
|
||||||
|
break
|
||||||
|
case keys.o:
|
||||||
|
this.setState(toggleMode(OVERVIEW))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (keyCode) {
|
||||||
|
case keys.left:
|
||||||
|
e.preventDefault()
|
||||||
|
this.previous()
|
||||||
|
break
|
||||||
|
case keys.right:
|
||||||
|
case keys.space:
|
||||||
|
e.preventDefault()
|
||||||
|
this.next()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndex = () => {
|
||||||
|
const { pathname } = globalHistory.location
|
||||||
|
return Number(pathname.split('/')[1] || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
getMeta = i => {
|
||||||
|
const { slides } = this.state
|
||||||
|
const { meta = {} } = slides[i] || {}
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
|
||||||
|
goto = i => {
|
||||||
|
const current = this.getIndex()
|
||||||
|
const reverse = i < current
|
||||||
|
navigate('/' + i)
|
||||||
|
const meta = this.getMeta(i)
|
||||||
|
this.setState({
|
||||||
|
step: reverse ? meta.steps || 0 : 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
previous = () => {
|
||||||
|
const { slides, step } = this.state
|
||||||
|
const index = this.getIndex()
|
||||||
|
const meta = this.getMeta(index)
|
||||||
|
if (meta.steps && step > 0) {
|
||||||
|
this.setState(state => ({
|
||||||
|
step: state.step - 1,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
const previous = index - 1
|
||||||
|
if (previous < 0) return
|
||||||
|
this.goto(previous)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next = () => {
|
||||||
|
const { slides, step } = this.state
|
||||||
|
const index = this.getIndex()
|
||||||
|
const meta = this.getMeta(index)
|
||||||
|
if (meta.steps && step < meta.steps) {
|
||||||
|
this.setState(state => ({
|
||||||
|
step: state.step + 1,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
const next = index + 1
|
||||||
|
if (next > slides.length - 1) return
|
||||||
|
this.goto(next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register = (index, meta) => {
|
||||||
|
const { slides } = this.state
|
||||||
|
const initialMeta = slides[index].meta || {}
|
||||||
|
slides[index].meta = { ...initialMeta, ...meta }
|
||||||
|
this.setState({ slides })
|
||||||
|
}
|
||||||
|
|
||||||
|
handleStorageChange = e => {
|
||||||
|
const { key } = e
|
||||||
|
switch (key) {
|
||||||
|
case STORAGE_INDEX:
|
||||||
|
const index = parseInt(e.newValue, 10)
|
||||||
|
this.goto(index)
|
||||||
|
break
|
||||||
|
case STORAGE_STEP:
|
||||||
|
const step = parseInt(e.newValue, 10)
|
||||||
|
this.setState({ step })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getMode = () => {
|
||||||
|
const query = querystring.parse(
|
||||||
|
globalHistory.location.search.replace(/^\?/, '')
|
||||||
|
)
|
||||||
|
this.setState(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.body.addEventListener('keydown', this.handleKeyDown)
|
||||||
|
window.addEventListener('storage', this.handleStorageChange)
|
||||||
|
this.getMode()
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.body.removeEventListener('keydown', this.handleKeyDown)
|
||||||
|
window.removeEventListener('storage', this.handleStorageChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate() {
|
||||||
|
const index = this.getIndex()
|
||||||
|
const { step, mode } = this.state
|
||||||
|
localStorage.setItem(STORAGE_INDEX, index)
|
||||||
|
localStorage.setItem(STORAGE_STEP, step)
|
||||||
|
if (mode !== NORMAL && mode !== PRINT) {
|
||||||
|
const query = '?' + querystring.stringify({ mode })
|
||||||
|
navigate(query)
|
||||||
|
} else {
|
||||||
|
const { pathname } = globalHistory.location
|
||||||
|
navigate(pathname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(err) {
|
||||||
|
console.error('componentDidCatch')
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { pathname } = globalHistory.location
|
||||||
|
const { slides } = this.state
|
||||||
|
const mode = pathname === '/print' ? PRINT : this.state.mode
|
||||||
|
const index = this.getIndex()
|
||||||
|
const meta = this.getMeta(index)
|
||||||
|
const context = {
|
||||||
|
...this.state,
|
||||||
|
register: this.register,
|
||||||
|
}
|
||||||
|
|
||||||
|
const [FirstSlide] = slides
|
||||||
|
|
||||||
|
let Wrapper = BaseWrapper
|
||||||
|
switch (mode) {
|
||||||
|
case PRESENTER:
|
||||||
|
Wrapper = Presenter
|
||||||
|
break
|
||||||
|
case OVERVIEW:
|
||||||
|
Wrapper = Overview
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Provider {...this.props} {...this.state} mode={mode} index={index}>
|
||||||
|
<Catch>
|
||||||
|
<GoogleFonts />
|
||||||
|
<Wrapper {...this.state} index={index}>
|
||||||
|
<Swipeable onSwipedRight={this.previous} onSwipedLeft={this.next}>
|
||||||
|
<Router>
|
||||||
|
<Slide path="/" index={0} {...context}>
|
||||||
|
<FirstSlide path="/" />
|
||||||
|
</Slide>
|
||||||
|
{slides.map((Component, i) => (
|
||||||
|
<Slide key={i} path={i + '/*'} index={i} {...context}>
|
||||||
|
<Component path={i + '/*'} />
|
||||||
|
</Slide>
|
||||||
|
))}
|
||||||
|
<Print path="/print" {...this.props} />
|
||||||
|
</Router>
|
||||||
|
</Swipeable>
|
||||||
|
</Wrapper>
|
||||||
|
</Catch>
|
||||||
|
</Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MDXDeck.propTypes = {
|
||||||
|
slides: PropTypes.array.isRequired,
|
||||||
|
headTags: PropTypes.array.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
MDXDeck.defaultProps = {
|
||||||
|
slides: [],
|
||||||
|
headTags: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MDXDeck
|
25
packages/components/src/Notes.js
Normal file
25
packages/components/src/Notes.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { withContext } from './context'
|
||||||
|
|
||||||
|
export const Notes = withContext(
|
||||||
|
class extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
const { context, children } = props
|
||||||
|
if (
|
||||||
|
!context ||
|
||||||
|
typeof context.index === 'undefined' ||
|
||||||
|
typeof context.register !== 'function'
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.register(context.index, { notes: children })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Notes
|
92
packages/components/src/Overview.js
Normal file
92
packages/components/src/Overview.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { Location, navigate } from '@reach/router'
|
||||||
|
import Zoom from './Zoom'
|
||||||
|
import Slide from './Slide'
|
||||||
|
import Pre from './Pre'
|
||||||
|
|
||||||
|
const getIndex = ({ pathname }) => {
|
||||||
|
return Number(pathname.split('/')[1] || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const withLocation = Component => props => (
|
||||||
|
<Location
|
||||||
|
children={({ location }) => (
|
||||||
|
<Component {...props} location={location} index={getIndex(location)} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const Overview = withLocation(props => {
|
||||||
|
const { index, slides } = props
|
||||||
|
const activeThumb = React.createRef()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const el = activeThumb.current
|
||||||
|
if (!el) return
|
||||||
|
if (typeof el.scrollIntoViewIfNeeded === 'function') {
|
||||||
|
el.scrollIntoViewIfNeeded()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
height: '100vh',
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: 'black',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 'none',
|
||||||
|
height: '100vh',
|
||||||
|
paddingLeft: 4,
|
||||||
|
paddingRight: 4,
|
||||||
|
overflowY: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{slides.map((Component, i) => (
|
||||||
|
<div
|
||||||
|
ref={i === index ? activeThumb : null}
|
||||||
|
key={i}
|
||||||
|
onClick={e => {
|
||||||
|
navigate('/' + i)
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
display: 'block',
|
||||||
|
color: 'inherit',
|
||||||
|
textDecoration: 'none',
|
||||||
|
padding: 0,
|
||||||
|
marginTop: 4,
|
||||||
|
marginBottom: 4,
|
||||||
|
cursor: 'pointer',
|
||||||
|
outline: i === index ? '4px solid #0cf' : null,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Zoom zoom={1 / 6}>
|
||||||
|
<Slide>
|
||||||
|
<Component />
|
||||||
|
</Slide>
|
||||||
|
</Zoom>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 200 / 3 + '%',
|
||||||
|
margin: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Zoom zoom={2 / 3}>{props.children}</Zoom>
|
||||||
|
<Pre>
|
||||||
|
{index} of {slides.length - 1}
|
||||||
|
</Pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default Overview
|
13
packages/components/src/Pre.js
Normal file
13
packages/components/src/Pre.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export default props => (
|
||||||
|
<pre
|
||||||
|
{...props}
|
||||||
|
style={{
|
||||||
|
fontFamily: 'Menlo, monospace',
|
||||||
|
fontSize: 18,
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
...props.style,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
87
packages/components/src/Presenter.js
Normal file
87
packages/components/src/Presenter.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { globalHistory } from '@reach/router'
|
||||||
|
import Zoom from './Zoom'
|
||||||
|
import Slide from './Slide'
|
||||||
|
import Pre from './Pre'
|
||||||
|
import Clock from './Clock'
|
||||||
|
|
||||||
|
export const Presenter = props => {
|
||||||
|
const { slides, index } = props
|
||||||
|
const Current = slides[index]
|
||||||
|
const Next = slides[index + 1]
|
||||||
|
const { notes } = Current.meta || {}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
color: 'white',
|
||||||
|
backgroundColor: 'black',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: '100vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: 'auto',
|
||||||
|
marginBottom: 'auto',
|
||||||
|
display: 'flex',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 500 / 8 + '%',
|
||||||
|
minWidth: 0,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Zoom zoom={5 / 8}>{props.children}</Zoom>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 100 / 4 + '%',
|
||||||
|
minWidth: 0,
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Zoom zoom={1 / 4}>
|
||||||
|
{Next && (
|
||||||
|
<Slide>
|
||||||
|
<Next />
|
||||||
|
</Slide>
|
||||||
|
)}
|
||||||
|
</Zoom>
|
||||||
|
<Pre>{notes}</Pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Pre>
|
||||||
|
{index} of {slides.length - 1}
|
||||||
|
</Pre>
|
||||||
|
<div style={{ margin: 'auto' }} />
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
href={globalHistory.location.origin + globalHistory.location.pathname}
|
||||||
|
style={{
|
||||||
|
color: 'inherit',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Open New Window
|
||||||
|
</a>
|
||||||
|
<div style={{ margin: 'auto' }} />
|
||||||
|
<Clock />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Presenter
|
14
packages/components/src/Print.js
Normal file
14
packages/components/src/Print.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Slide from './Slide'
|
||||||
|
|
||||||
|
export const Print = props => (
|
||||||
|
<>
|
||||||
|
{props.slides.map((Component, i) => (
|
||||||
|
<Slide key={i} index={i}>
|
||||||
|
<Component />
|
||||||
|
</Slide>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Print
|
55
packages/components/src/Provider.js
Normal file
55
packages/components/src/Provider.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { globalHistory } from '@reach/router'
|
||||||
|
import { Global } from '@emotion/core'
|
||||||
|
import { ThemeProvider } from 'emotion-theming'
|
||||||
|
import merge from 'lodash.merge'
|
||||||
|
import { HeadProvider } from './Head'
|
||||||
|
import { MDXProvider } from '@mdx-js/tag'
|
||||||
|
import defaultTheme from '@mdx-deck/themes'
|
||||||
|
import mdxComponents from './mdx-components'
|
||||||
|
|
||||||
|
const DefaultProvider = props => <>{props.children}</>
|
||||||
|
|
||||||
|
const mergeThemes = themes =>
|
||||||
|
themes.reduce(
|
||||||
|
(acc, theme) =>
|
||||||
|
typeof theme === 'function' ? theme(acc) : merge(acc, theme),
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const Provider = props => {
|
||||||
|
const { headTags, theme: baseTheme, themes = [] } = props
|
||||||
|
const theme = mergeThemes([defaultTheme, baseTheme, ...themes])
|
||||||
|
const {
|
||||||
|
Provider: UserProvider = DefaultProvider,
|
||||||
|
components: themeComponents = {},
|
||||||
|
} = theme
|
||||||
|
|
||||||
|
const allComponents = {
|
||||||
|
...mdxComponents,
|
||||||
|
...themeComponents,
|
||||||
|
}
|
||||||
|
const style =
|
||||||
|
props.mode !== 'print' ? (
|
||||||
|
<Global
|
||||||
|
styles={{
|
||||||
|
body: {
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HeadProvider tags={headTags}>
|
||||||
|
{style}
|
||||||
|
<ThemeProvider theme={theme}>
|
||||||
|
<MDXProvider components={allComponents}>
|
||||||
|
<UserProvider {...props} />
|
||||||
|
</MDXProvider>
|
||||||
|
</ThemeProvider>
|
||||||
|
</HeadProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Provider
|
60
packages/components/src/Root.js
Normal file
60
packages/components/src/Root.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import styled from '@emotion/styled'
|
||||||
|
|
||||||
|
const themed = (...tags) => props =>
|
||||||
|
tags.map(tag => props.theme[tag] && { ['& ' + tag]: props.theme[tag] })
|
||||||
|
|
||||||
|
const themedHeadings = props => ({
|
||||||
|
'& h1, & h2, & h3, & h4, & h5, & h6': props.theme.heading,
|
||||||
|
})
|
||||||
|
|
||||||
|
const themedLinks = props => ({
|
||||||
|
'& a': {
|
||||||
|
color: props.theme.colors.link,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// backwards compatibility
|
||||||
|
const themedQuote = props => ({
|
||||||
|
'& blockquote': props.theme.quote,
|
||||||
|
})
|
||||||
|
|
||||||
|
const themedCode = props => ({
|
||||||
|
'& code, & pre': {
|
||||||
|
fontFamily: props.theme.monospace,
|
||||||
|
color: props.theme.colors.code,
|
||||||
|
background: props.theme.colors.codeBackground,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Root = styled.div(
|
||||||
|
props => ({
|
||||||
|
fontFamily: props.theme.font,
|
||||||
|
color: props.theme.colors.text,
|
||||||
|
backgroundColor: props.theme.colors.background,
|
||||||
|
}),
|
||||||
|
props => props.theme.css,
|
||||||
|
themedLinks,
|
||||||
|
themedHeadings,
|
||||||
|
themedCode,
|
||||||
|
themedQuote,
|
||||||
|
themed(
|
||||||
|
'h1',
|
||||||
|
'h2',
|
||||||
|
'h3',
|
||||||
|
'h4',
|
||||||
|
'h5',
|
||||||
|
'h6',
|
||||||
|
'a',
|
||||||
|
'ul',
|
||||||
|
'ol',
|
||||||
|
'li',
|
||||||
|
'p',
|
||||||
|
'blockquote',
|
||||||
|
'img',
|
||||||
|
'table',
|
||||||
|
'pre',
|
||||||
|
'code'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Root
|
27
packages/components/src/Slide.js
Normal file
27
packages/components/src/Slide.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import Root from './Root'
|
||||||
|
import { Context } from './context'
|
||||||
|
|
||||||
|
const SlideRoot = styled.div(
|
||||||
|
{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
props => props.theme.Slide
|
||||||
|
)
|
||||||
|
|
||||||
|
export const Slide = ({ children, ...props }) => (
|
||||||
|
<Context.Provider value={props}>
|
||||||
|
<Root>
|
||||||
|
<SlideRoot>{children}</SlideRoot>
|
||||||
|
</Root>
|
||||||
|
</Context.Provider>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Slide
|
21
packages/components/src/Steps.js
Normal file
21
packages/components/src/Steps.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { withContext } from './context'
|
||||||
|
|
||||||
|
export const Steps = withContext(
|
||||||
|
class extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
const { register, index } = props.context
|
||||||
|
const { length } = props
|
||||||
|
if (typeof register !== 'function') return
|
||||||
|
register(index, { steps: length })
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const { context, render } = this.props
|
||||||
|
const { step } = context
|
||||||
|
return render({ step })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Steps
|
25
packages/components/src/Zoom.js
Normal file
25
packages/components/src/Zoom.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
|
||||||
|
const ZoomRoot = styled.div(props => ({
|
||||||
|
backgroundColor: props.theme.colors.background,
|
||||||
|
width: 100 * props.zoom + 'vw',
|
||||||
|
height: 100 * props.zoom + 'vh',
|
||||||
|
}))
|
||||||
|
|
||||||
|
const ZoomInner = styled.div([], props => ({
|
||||||
|
transformOrigin: '0 0',
|
||||||
|
transform: `scale(${props.zoom})`,
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const Zoom = ({ zoom, ...props }) => (
|
||||||
|
<ZoomRoot zoom={zoom}>
|
||||||
|
<ZoomInner zoom={zoom} {...props} />
|
||||||
|
</ZoomRoot>
|
||||||
|
)
|
||||||
|
|
||||||
|
Zoom.defaultProps = {
|
||||||
|
zoom: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Zoom
|
12
packages/components/src/__tests__/Appear.js
Normal file
12
packages/components/src/__tests__/Appear.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TestRenderer from 'react-test-renderer'
|
||||||
|
import Appear from '../Appear'
|
||||||
|
|
||||||
|
test('Appear renders', () => {
|
||||||
|
const json = TestRenderer.create(
|
||||||
|
<Appear>
|
||||||
|
<h1>Hello</h1>
|
||||||
|
</Appear>
|
||||||
|
).toJSON()
|
||||||
|
expect(json).toMatchSnapshot()
|
||||||
|
})
|
5
packages/components/src/__tests__/Clock.js
Normal file
5
packages/components/src/__tests__/Clock.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TestRenderer from 'react-test-renderer'
|
||||||
|
import Clock from '../Clock'
|
||||||
|
|
||||||
|
test.todo('Clock renders')
|
5
packages/components/src/__tests__/GoogleFonts.js
Normal file
5
packages/components/src/__tests__/GoogleFonts.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TestRenderer from 'react-test-renderer'
|
||||||
|
import GoogleFonts from '../GoogleFonts'
|
||||||
|
|
||||||
|
test.todo('GoogleFonts renders')
|
15
packages/components/src/__tests__/Head.js
Normal file
15
packages/components/src/__tests__/Head.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TestRenderer from 'react-test-renderer'
|
||||||
|
import { Head, HeadProvider } from '../Head'
|
||||||
|
|
||||||
|
test.skip('Head populates HeadProvider‘s tag prop', () => {
|
||||||
|
const tags = []
|
||||||
|
TestRenderer.create(
|
||||||
|
<HeadProvider tags={tags}>
|
||||||
|
<Head>
|
||||||
|
<title>Hello</title>
|
||||||
|
</Head>
|
||||||
|
</HeadProvider>
|
||||||
|
)
|
||||||
|
expect(tags.length).toBe(1)
|
||||||
|
})
|
8
packages/components/src/__tests__/Pre.js
Normal file
8
packages/components/src/__tests__/Pre.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TestRenderer from 'react-test-renderer'
|
||||||
|
import Pre from '../Pre'
|
||||||
|
|
||||||
|
test('Pre renders', () => {
|
||||||
|
const json = TestRenderer.create(<Pre children="hi" />).toJSON()
|
||||||
|
expect(json).toMatchSnapshot()
|
||||||
|
})
|
8
packages/components/src/__tests__/Steps.js
Normal file
8
packages/components/src/__tests__/Steps.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import TestRenderer from 'react-test-renderer'
|
||||||
|
import Steps from '../Steps'
|
||||||
|
|
||||||
|
test('Steps renders', () => {
|
||||||
|
const json = TestRenderer.create(<Steps render={() => 'hi'} />).toJSON()
|
||||||
|
expect(json).toMatchSnapshot()
|
||||||
|
})
|
@ -0,0 +1,13 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Appear renders 1`] = `
|
||||||
|
<h1
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"visibility": "hidden",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Hello
|
||||||
|
</h1>
|
||||||
|
`;
|
15
packages/components/src/__tests__/__snapshots__/Pre.js.snap
Normal file
15
packages/components/src/__tests__/__snapshots__/Pre.js.snap
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Pre renders 1`] = `
|
||||||
|
<pre
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"fontFamily": "Menlo, monospace",
|
||||||
|
"fontSize": 18,
|
||||||
|
"whiteSpace": "pre-wrap",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
hi
|
||||||
|
</pre>
|
||||||
|
`;
|
@ -0,0 +1,3 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Steps renders 1`] = `"hi"`;
|
11
packages/components/src/context.js
Normal file
11
packages/components/src/context.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React, { useContext } from 'react'
|
||||||
|
|
||||||
|
export const Context = React.createContext({})
|
||||||
|
|
||||||
|
export const withContext = Component => props => (
|
||||||
|
<Context.Consumer
|
||||||
|
children={context => <Component {...props} context={context} />}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const useDeck = () => useContext(Context)
|
8
packages/components/src/index.js
Normal file
8
packages/components/src/index.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export { MDXDeck } from './MDXDeck'
|
||||||
|
export { Head } from './Head'
|
||||||
|
export { Image } from './Image'
|
||||||
|
export { Notes } from './Notes'
|
||||||
|
export { Steps } from './Steps'
|
||||||
|
export { Appear } from './Appear'
|
||||||
|
export { withContext, useDeck } from './context'
|
||||||
|
export useSteps from './useSteps'
|
56
packages/components/src/mdx-components.js
Normal file
56
packages/components/src/mdx-components.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
|
||||||
|
export const inlineCode = styled.code(
|
||||||
|
props => ({
|
||||||
|
fontFamily: props.theme.monospace,
|
||||||
|
}),
|
||||||
|
props => props.theme.code
|
||||||
|
)
|
||||||
|
|
||||||
|
export const code = styled.pre(
|
||||||
|
props => ({
|
||||||
|
fontFamily: props.theme.monospace,
|
||||||
|
fontSize: '.75em',
|
||||||
|
}),
|
||||||
|
props => props.theme.pre
|
||||||
|
)
|
||||||
|
|
||||||
|
export const img = styled.img({
|
||||||
|
maxWidth: '100%',
|
||||||
|
height: 'auto',
|
||||||
|
objectFit: 'cover',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const TableWrap = styled.div({
|
||||||
|
overflowX: 'auto',
|
||||||
|
})
|
||||||
|
export const Table = styled.table({
|
||||||
|
width: '100%',
|
||||||
|
borderCollapse: 'separate',
|
||||||
|
borderSpacing: 0,
|
||||||
|
'& td, & th': {
|
||||||
|
textAlign: 'left',
|
||||||
|
paddingRight: '.5em',
|
||||||
|
paddingTop: '.25em',
|
||||||
|
paddingBottom: '.25em',
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
verticalAlign: 'top',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const table = props => (
|
||||||
|
<TableWrap>
|
||||||
|
<Table {...props} />
|
||||||
|
</TableWrap>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const components = {
|
||||||
|
pre: props => props.children,
|
||||||
|
code,
|
||||||
|
inlineCode,
|
||||||
|
img,
|
||||||
|
table,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default components
|
13
packages/components/src/useSteps.js
Normal file
13
packages/components/src/useSteps.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useContext, useMemo } from 'react'
|
||||||
|
import { Context } from './context'
|
||||||
|
|
||||||
|
export default length => {
|
||||||
|
const context = useContext(Context)
|
||||||
|
const { register, index, step } = context
|
||||||
|
useMemo(() => {
|
||||||
|
if (typeof register !== 'function') return
|
||||||
|
register(index, { steps: length })
|
||||||
|
}, [length])
|
||||||
|
|
||||||
|
return step
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# npm init deck
|
# npm init deck
|
||||||
|
|
||||||
Create mdx-deck presentations
|
Create mdx-deck presentations
|
@ -15,28 +15,31 @@ log.error = (...args) => {
|
|||||||
|
|
||||||
const template = 'jxnblk/mdx-deck/templates/basic'
|
const template = 'jxnblk/mdx-deck/templates/basic'
|
||||||
|
|
||||||
const cli = meow(`
|
const cli = meow(
|
||||||
|
`
|
||||||
Usage
|
Usage
|
||||||
|
|
||||||
$ npm init deck my-presentation
|
$ npm init deck my-presentation
|
||||||
|
|
||||||
$ npx create-deck my-presentation
|
$ npx create-deck my-presentation
|
||||||
|
|
||||||
`, {
|
`,
|
||||||
booleanDefault: undefined,
|
{
|
||||||
flags: {
|
booleanDefault: undefined,
|
||||||
help: {
|
flags: {
|
||||||
type: 'boolean',
|
help: {
|
||||||
alias: 'h'
|
type: 'boolean',
|
||||||
|
alias: 'h',
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
type: 'boolean',
|
||||||
|
alias: 'v',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
version: {
|
|
||||||
type: 'boolean',
|
|
||||||
alias: 'v'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
|
||||||
const [ name ] = cli.input
|
const [name] = cli.input
|
||||||
|
|
||||||
if (!name) {
|
if (!name) {
|
||||||
cli.showHelp(0)
|
cli.showHelp(0)
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "create-deck",
|
"name": "create-deck",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0-1",
|
||||||
"description": "Create mdx-deck presentations",
|
"description": "Create mdx-deck presentations",
|
||||||
"bin": {
|
"bin": {
|
||||||
"create-deck": "cli.js"
|
"create-deck": "cli.js"
|
1
packages/export/.gitignore
vendored
Normal file
1
packages/export/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
dist
|
28
packages/export/README.md
Normal file
28
packages/export/README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# MDX Deck Export CLI
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i -D @mdx-deck/export
|
||||||
|
```
|
||||||
|
|
||||||
|
Export as PDF
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdx-deck-export pdf deck.mdx
|
||||||
|
```
|
||||||
|
|
||||||
|
Export as PNG
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mdx-deck-export png deck.mdx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
```
|
||||||
|
-d --out-dir Output directory
|
||||||
|
-f --out-file Output filename
|
||||||
|
-p --port Server port
|
||||||
|
-w --width Width in pixels
|
||||||
|
-h --height Height in pixels
|
||||||
|
--no-sandbox Disable puppeteer sandbox
|
||||||
|
```
|
82
packages/export/cli.js
Executable file
82
packages/export/cli.js
Executable file
@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const path = require('path')
|
||||||
|
const meow = require('meow')
|
||||||
|
|
||||||
|
const cli = meow(
|
||||||
|
`
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
$ mdx-deck-export pdf deck.mdx
|
||||||
|
$ mdx-deck-export png deck.mdx
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
-d --out-dir Output directory
|
||||||
|
-f --out-file Output filename
|
||||||
|
-p --port Server port
|
||||||
|
-w --width Width in pixels
|
||||||
|
-h --height Height in pixels
|
||||||
|
--no-sandbox Disable puppeteer sandbox
|
||||||
|
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
flags: {
|
||||||
|
outDir: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'd',
|
||||||
|
default: 'dist',
|
||||||
|
},
|
||||||
|
outFile: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'f',
|
||||||
|
default: 'presentation.pdf',
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'p',
|
||||||
|
default: 8080,
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'w',
|
||||||
|
default: 1280,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'h',
|
||||||
|
default: 960,
|
||||||
|
},
|
||||||
|
sandbox: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const [cmd, input] = cli.input
|
||||||
|
|
||||||
|
if (!input || !cmd) {
|
||||||
|
cli.showHelp(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const opts = Object.assign({}, cli.flags, {
|
||||||
|
input,
|
||||||
|
dirname: path.dirname(path.resolve(input)),
|
||||||
|
globals: {
|
||||||
|
FILENAME: JSON.stringify(path.resolve(input)),
|
||||||
|
},
|
||||||
|
host: 'localhost',
|
||||||
|
type: cmd,
|
||||||
|
})
|
||||||
|
|
||||||
|
require('./index')(opts)
|
||||||
|
.then(filename => {
|
||||||
|
console.log(`saved ${cmd} to`, filename)
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
59
packages/export/index.js
Normal file
59
packages/export/index.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const puppeteer = require('puppeteer')
|
||||||
|
const mkdirp = require('mkdirp')
|
||||||
|
const dev = require('mdx-deck/lib/dev')
|
||||||
|
|
||||||
|
module.exports = async opts => {
|
||||||
|
const { type, outDir, outFile, port, width, height, sandbox } = opts
|
||||||
|
|
||||||
|
const args = []
|
||||||
|
if (!sandbox) {
|
||||||
|
args.push('--no-sandbox', '--disable-setuid-sandbox')
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = await dev(opts)
|
||||||
|
|
||||||
|
const browser = await puppeteer.launch({ args })
|
||||||
|
const page = await browser.newPage()
|
||||||
|
const filename = path.join(
|
||||||
|
outDir,
|
||||||
|
path.basename(outFile, path.extname(outFile)) + '.' + type
|
||||||
|
)
|
||||||
|
mkdirp.sync(outDir)
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'pdf':
|
||||||
|
await page.goto(`http://localhost:${port}/print`, {
|
||||||
|
waitUntil: 'networkidle2',
|
||||||
|
})
|
||||||
|
await page.pdf({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
path: filename,
|
||||||
|
scale: 1,
|
||||||
|
printBackground: true,
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'png':
|
||||||
|
await page.setViewport({ width, height })
|
||||||
|
await page.goto('http://localhost:' + port, {
|
||||||
|
waitUntil: 'networkidle2',
|
||||||
|
})
|
||||||
|
await page.screenshot({
|
||||||
|
path: filename,
|
||||||
|
type: 'png',
|
||||||
|
clip: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.close()
|
||||||
|
await server.close()
|
||||||
|
|
||||||
|
return filename
|
||||||
|
}
|
20
packages/export/package.json
Normal file
20
packages/export/package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "@mdx-deck/export",
|
||||||
|
"version": "2.0.0-8",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "Brent Jackson <jxnblk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"mdx-deck-export": "./cli.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"pdf": "./cli.js pdf ../../docs/demo.mdx",
|
||||||
|
"png": "./cli.js png ../../docs/demo.mdx"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mdx-deck": "^2.0.0-8",
|
||||||
|
"meow": "^5.0.0",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"puppeteer": "^1.13.0"
|
||||||
|
}
|
||||||
|
}
|
16
packages/html-plugin/README.md
Normal file
16
packages/html-plugin/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# @mdx-deck/webpack-html-plugin
|
||||||
|
|
||||||
|
Webpack plugin for generating HTML
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm i @mdx-deck/webpack-html-plugin
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// webpack.config.js
|
||||||
|
const HTMLPlugin = require('@mdx-deck/webpack-html-plugin')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: [new HTMLPlugin()],
|
||||||
|
}
|
||||||
|
```
|
93
packages/html-plugin/index.js
Normal file
93
packages/html-plugin/index.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// based on mini-html-webpack-plugin
|
||||||
|
const path = require('path')
|
||||||
|
const { RawSource } = require('webpack-sources')
|
||||||
|
|
||||||
|
class HTMLPlugin {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.options = options
|
||||||
|
this.plugin = this.plugin.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin(compilation, callback) {
|
||||||
|
const { publicPath } = compilation.options.output
|
||||||
|
const {
|
||||||
|
filename = 'index.html',
|
||||||
|
template = defaultTemplate,
|
||||||
|
context,
|
||||||
|
} = this.options
|
||||||
|
|
||||||
|
const files = getFiles(compilation.entrypoints)
|
||||||
|
const links = generateCSSReferences(files.css, publicPath)
|
||||||
|
const scripts = generateJSReferences(files.js, publicPath)
|
||||||
|
const ctx = Object.assign(
|
||||||
|
{},
|
||||||
|
files,
|
||||||
|
{
|
||||||
|
publicPath,
|
||||||
|
links,
|
||||||
|
scripts,
|
||||||
|
},
|
||||||
|
context
|
||||||
|
)
|
||||||
|
|
||||||
|
compilation.assets[filename] = new RawSource(template(ctx))
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.emit.tapAsync('MDXDeckHTMLPlugin', this.plugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFiles = entrypoints => {
|
||||||
|
const files = {}
|
||||||
|
|
||||||
|
entrypoints.forEach(entry => {
|
||||||
|
entry.getFiles().forEach(file => {
|
||||||
|
const extension = path.extname(file).replace(/\./, '')
|
||||||
|
|
||||||
|
if (!files[extension]) {
|
||||||
|
files[extension] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
files[extension].push(file)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultTemplate = ({
|
||||||
|
links,
|
||||||
|
scripts,
|
||||||
|
title = '',
|
||||||
|
body = '',
|
||||||
|
head = '',
|
||||||
|
css = '',
|
||||||
|
publicPath,
|
||||||
|
}) => `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||||
|
<style>*{box-sizing:border-box}body{margin:0;font-family:system-ui,sans-serif}</style>
|
||||||
|
<meta name='generator' content='mdx-deck'>
|
||||||
|
${head}${css}${links}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id=root>${body}</div>
|
||||||
|
${scripts}
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
|
||||||
|
const generateCSSReferences = (files = [], publicPath = '') =>
|
||||||
|
files
|
||||||
|
.map(file => `<link href='${publicPath + file}' rel='stylesheet'>`)
|
||||||
|
.join('')
|
||||||
|
|
||||||
|
const generateJSReferences = (files = [], publicPath = '') =>
|
||||||
|
files.map(file => `<script src='${publicPath + file}'></script>`).join('')
|
||||||
|
|
||||||
|
module.exports = HTMLPlugin
|
||||||
|
module.exports.template = defaultTemplate
|
10
packages/html-plugin/package.json
Normal file
10
packages/html-plugin/package.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "@mdx-deck/webpack-html-plugin",
|
||||||
|
"version": "2.0.0-1",
|
||||||
|
"author": "Brent Jackson <jxnblk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": "github:jxnblk/mdx-deck",
|
||||||
|
"dependencies": {
|
||||||
|
"webpack-sources": "^1.3.0"
|
||||||
|
}
|
||||||
|
}
|
5
packages/layouts/README.md
Normal file
5
packages/layouts/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# @mdx-deck/layouts
|
||||||
|
|
||||||
|
Layout components used in MDX Deck
|
||||||
|
|
||||||
|
https://github.com/jxnblk/mdx-deck
|
12
packages/layouts/package.json
Normal file
12
packages/layouts/package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@mdx-deck/layouts",
|
||||||
|
"version": "2.0.0-7",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"author": "Brent Jackson <jxnblk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/core": "^10.0.7",
|
||||||
|
"@emotion/styled": "^10.0.7",
|
||||||
|
"styled-system": "^4.0.1"
|
||||||
|
}
|
||||||
|
}
|
12
packages/layouts/src/Box.js
Normal file
12
packages/layouts/src/Box.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import styled from '@emotion/styled'
|
||||||
|
import { width, space, color } from 'styled-system'
|
||||||
|
|
||||||
|
export default styled.div(
|
||||||
|
{
|
||||||
|
flex: 'none',
|
||||||
|
minWidth: 0,
|
||||||
|
},
|
||||||
|
width,
|
||||||
|
space,
|
||||||
|
color
|
||||||
|
)
|
25
packages/layouts/src/Flex.js
Normal file
25
packages/layouts/src/Flex.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import styled from '@emotion/styled'
|
||||||
|
import {
|
||||||
|
alignItems,
|
||||||
|
justifyContent,
|
||||||
|
flexWrap,
|
||||||
|
flexDirection,
|
||||||
|
} from 'styled-system'
|
||||||
|
import Box from './Box'
|
||||||
|
|
||||||
|
export const Flex = styled(Box)(
|
||||||
|
{
|
||||||
|
display: 'flex',
|
||||||
|
},
|
||||||
|
alignItems,
|
||||||
|
justifyContent,
|
||||||
|
flexWrap,
|
||||||
|
flexDirection
|
||||||
|
)
|
||||||
|
|
||||||
|
Flex.defaultProps = {
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Flex
|
@ -1,9 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from '@emotion/styled'
|
||||||
|
|
||||||
const FullCode = styled.div({
|
const FullCode = styled.div({
|
||||||
width: '100vw',
|
|
||||||
height: '100vh',
|
|
||||||
textAlign: 'left',
|
textAlign: 'left',
|
||||||
'& pre': {
|
'& pre': {
|
||||||
// needed to override inline styles from syntax highlighting
|
// needed to override inline styles from syntax highlighting
|
24
packages/layouts/src/Horizontal.js
Normal file
24
packages/layouts/src/Horizontal.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Flex from './Flex'
|
||||||
|
import Box from './Box'
|
||||||
|
|
||||||
|
const Horizontal = ({ children }) => {
|
||||||
|
const kids = React.Children.toArray(children)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
css={{
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{kids.map(child => (
|
||||||
|
<Box key={child.key} width={1 / kids.length}>
|
||||||
|
{child}
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Horizontal
|
@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import styled from '@emotion/styled'
|
||||||
import styled from 'styled-components'
|
|
||||||
import { color } from 'styled-system'
|
import { color } from 'styled-system'
|
||||||
|
|
||||||
const Invert = styled.div(
|
const Invert = styled.div(
|
||||||
@ -7,6 +6,7 @@ const Invert = styled.div(
|
|||||||
width: '100vw',
|
width: '100vw',
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
'& a': {
|
'& a': {
|
||||||
@ -21,4 +21,4 @@ Invert.defaultProps = {
|
|||||||
bg: 'text',
|
bg: 'text',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default props => <Invert {...props} />
|
export default Invert
|
20
packages/layouts/src/Split.js
Normal file
20
packages/layouts/src/Split.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Flex from './Flex'
|
||||||
|
import Box from './Box'
|
||||||
|
|
||||||
|
const Split = ({ children }) => {
|
||||||
|
const [a, ...rest] = React.Children.toArray(children)
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
css={{
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box width={1 / 2}>{a}</Box>
|
||||||
|
<Box width={1 / 2}>{rest}</Box>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Split
|
21
packages/layouts/src/SplitRight.js
Normal file
21
packages/layouts/src/SplitRight.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import Flex from './Flex'
|
||||||
|
import Box from './Box'
|
||||||
|
|
||||||
|
const SplitRight = ({ children }) => {
|
||||||
|
const [a, ...rest] = React.Children.toArray(children)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
css={{
|
||||||
|
alignItems: 'center',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box width={1 / 2}>{rest}</Box>
|
||||||
|
<Box width={1 / 2}>{a}</Box>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SplitRight
|
5
packages/loader/README.md
Normal file
5
packages/loader/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# @mdx-deck/loader
|
||||||
|
|
||||||
|
Webpack loader used in MDX Deck
|
||||||
|
|
||||||
|
https://github.com/jxnblk/mdx-deck
|
18
packages/loader/index.js
Normal file
18
packages/loader/index.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const { getOptions } = require('loader-utils')
|
||||||
|
const mdx = require('@mdx-js/mdx')
|
||||||
|
const mdxPlugin = require('@mdx-deck/mdx-plugin')
|
||||||
|
|
||||||
|
module.exports = async function(src) {
|
||||||
|
const callback = this.async()
|
||||||
|
const options = getOptions(this) || {}
|
||||||
|
options.mdPlugins = options.mdPlugins || []
|
||||||
|
options.mdPlugins.push(mdxPlugin)
|
||||||
|
|
||||||
|
const result = mdx.sync(src, options)
|
||||||
|
|
||||||
|
const code = `/** @jsx mdx */
|
||||||
|
import mdx from '@mdx-js/mdx/create-element'
|
||||||
|
${result}`
|
||||||
|
|
||||||
|
return callback(null, code)
|
||||||
|
}
|
12
packages/loader/package.json
Normal file
12
packages/loader/package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@mdx-deck/loader",
|
||||||
|
"version": "2.0.0-7",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "Brent Jackson <jxnblk@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@mdx-deck/mdx-plugin": "^2.0.0-7",
|
||||||
|
"@mdx-js/mdx": "^1.0.0-alpha.5",
|
||||||
|
"loader-utils": "^1.2.3"
|
||||||
|
}
|
||||||
|
}
|
4
packages/mdx-deck/README.md
Normal file
4
packages/mdx-deck/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
# MDX Deck
|
||||||
|
|
||||||
|
https://github.com/jxnblk/mdx-deck
|
13
packages/mdx-deck/babel.config.js
Normal file
13
packages/mdx-deck/babel.config.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-env',
|
||||||
|
'@babel/preset-react',
|
||||||
|
'@emotion/babel-preset-css-prop',
|
||||||
|
].map(require.resolve),
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-proposal-class-properties',
|
||||||
|
'@babel/plugin-proposal-export-default-from',
|
||||||
|
'@babel/plugin-proposal-export-namespace-from',
|
||||||
|
'@babel/plugin-syntax-dynamic-import',
|
||||||
|
].map(require.resolve),
|
||||||
|
}
|
121
packages/mdx-deck/cli.js
Executable file
121
packages/mdx-deck/cli.js
Executable file
@ -0,0 +1,121 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
const path = require('path')
|
||||||
|
const meow = require('meow')
|
||||||
|
const findup = require('find-up')
|
||||||
|
const open = require('react-dev-utils/openBrowser')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const pkg = require('./package.json')
|
||||||
|
|
||||||
|
const config = require('pkg-conf').sync('mdx-deck')
|
||||||
|
|
||||||
|
const log = (...args) => {
|
||||||
|
console.log(chalk.green('[mdx-deck]'), ...args)
|
||||||
|
}
|
||||||
|
log.error = (...args) => {
|
||||||
|
console.log(chalk.red('[err]'), ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
const cli = meow(
|
||||||
|
`
|
||||||
|
${chalk.gray('Usage')}
|
||||||
|
|
||||||
|
$ ${chalk.green('mdx-deck deck.mdx')}
|
||||||
|
|
||||||
|
$ ${chalk.green('mdx-deck build deck.mdx')}
|
||||||
|
|
||||||
|
${chalk.gray('Options')}
|
||||||
|
|
||||||
|
-h --host Dev server host
|
||||||
|
-p --port Dev server port
|
||||||
|
--no-open Prevent from opening in default browser
|
||||||
|
--webpack Path to webpack config file
|
||||||
|
-d --out-dir Output directory for exporting
|
||||||
|
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
description: chalk.green('[mdx-deck] ') + chalk.gray(pkg.description),
|
||||||
|
flags: {
|
||||||
|
port: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'p',
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'h',
|
||||||
|
},
|
||||||
|
open: {
|
||||||
|
type: 'boolean',
|
||||||
|
alias: 'o',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
outDir: {
|
||||||
|
type: 'string',
|
||||||
|
alias: 'd',
|
||||||
|
},
|
||||||
|
webpack: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const [cmd, file] = cli.input
|
||||||
|
const doc = file || cmd
|
||||||
|
|
||||||
|
if (!doc) cli.showHelp(0)
|
||||||
|
|
||||||
|
const opts = Object.assign(
|
||||||
|
{
|
||||||
|
dirname: path.dirname(path.resolve(doc)),
|
||||||
|
globals: {
|
||||||
|
FILENAME: JSON.stringify(path.resolve(doc)),
|
||||||
|
},
|
||||||
|
host: 'localhost',
|
||||||
|
port: 8080,
|
||||||
|
outDir: 'dist',
|
||||||
|
},
|
||||||
|
config,
|
||||||
|
cli.flags
|
||||||
|
)
|
||||||
|
|
||||||
|
opts.outDir = path.resolve(opts.outDir)
|
||||||
|
if (opts.webpack) {
|
||||||
|
opts.webpack = require(path.resolve(opts.webpack))
|
||||||
|
} else {
|
||||||
|
const webpackConfig = findup.sync('webpack.config.js', { cwd: opts.dirname })
|
||||||
|
if (webpackConfig) opts.webpack = require(webpackConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dev
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case 'build':
|
||||||
|
log('building')
|
||||||
|
const build = require('./lib/build')
|
||||||
|
build(opts)
|
||||||
|
.then(res => {
|
||||||
|
log('done')
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
log.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'dev':
|
||||||
|
default:
|
||||||
|
log('starting dev server')
|
||||||
|
dev = require('./lib/dev')
|
||||||
|
dev(opts)
|
||||||
|
.then(server => {
|
||||||
|
const { address, port } = server.address()
|
||||||
|
const url = `http://localhost:${port}`
|
||||||
|
if (opts.open) open(url)
|
||||||
|
log('listening on', chalk.green(url))
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
log.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
111
packages/mdx-deck/demo.mdx
Normal file
111
packages/mdx-deck/demo.mdx
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
import { Head, Image, Notes, Appear, Steps } from '@mdx-deck/components'
|
||||||
|
|
||||||
|
export const themes = []
|
||||||
|
|
||||||
|
<Head>
|
||||||
|
<title>MDX Deck Demo</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
# Hello MDX Deck
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export default props =>
|
||||||
|
<div style={{ color: 'red' }}>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
export const Beep = props =>
|
||||||
|
<Hello>
|
||||||
|
{props.children}
|
||||||
|
</Hello>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## This is v2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What's New
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<Appear>
|
||||||
|
<li>Reach Router</li>
|
||||||
|
<li>Less opinionated styles</li>
|
||||||
|
<li>more stuff</li>
|
||||||
|
</Appear>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<Image
|
||||||
|
src='https://source.unsplash.com/random/1024x768'
|
||||||
|
size='contain'
|
||||||
|
/>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## This slide has notes
|
||||||
|
|
||||||
|
<Notes>
|
||||||
|
Hello, secret speaker notes
|
||||||
|
</Notes>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```js
|
||||||
|
const codeExample = require('./code-example')
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## More Appear
|
||||||
|
|
||||||
|
<Appear>
|
||||||
|
<div>One</div>
|
||||||
|
<div>Two</div>
|
||||||
|
<div>Three</div>
|
||||||
|
<div>Four</div>
|
||||||
|
<div>Five</div>
|
||||||
|
<div>Six</div>
|
||||||
|
</Appear>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps Components
|
||||||
|
|
||||||
|
<Steps
|
||||||
|
length={3}
|
||||||
|
render={({ step }) => (
|
||||||
|
<pre>
|
||||||
|
Step: {step}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
export default props =>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100vw',
|
||||||
|
height: '100vh',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: 'tomato'
|
||||||
|
}}>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## With a (tomato) layout
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Last Slide
|
||||||
|
|
||||||
|
|
3
packages/mdx-deck/index.js
Normal file
3
packages/mdx-deck/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from '@mdx-deck/components'
|
||||||
|
export * as themes from '@mdx-deck/themes'
|
||||||
|
export * as Layouts from '@mdx-deck/layouts'
|
1
packages/mdx-deck/layouts.js
Normal file
1
packages/mdx-deck/layouts.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from '@mdx-deck/layouts'
|
89
packages/mdx-deck/lib/build.js
Normal file
89
packages/mdx-deck/lib/build.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const React = require('react')
|
||||||
|
const { renderToString, renderToStaticMarkup } = require('react-dom/server')
|
||||||
|
const HTMLPlugin = require('@mdx-deck/webpack-html-plugin')
|
||||||
|
const createConfig = require('./config')
|
||||||
|
|
||||||
|
const getApp = async (config, opts) => {
|
||||||
|
const serverConfig = Object.assign({}, config, {
|
||||||
|
target: 'node',
|
||||||
|
output: {
|
||||||
|
path: opts.outDir,
|
||||||
|
filename: '__app.js',
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
},
|
||||||
|
externals: ['react', 'react-dom'],
|
||||||
|
})
|
||||||
|
const compiler = webpack(serverConfig)
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
compiler.run((err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (stats.compilation.errors && stats.compilation.errors.length) {
|
||||||
|
reject(stats.compilation.errors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const filename = path.resolve(opts.outDir, './__app.js')
|
||||||
|
const App = require(filename).default
|
||||||
|
resolve(App)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderHTML = async App => {
|
||||||
|
const headTags = []
|
||||||
|
const body = renderToString(
|
||||||
|
React.createElement(App, {
|
||||||
|
headTags,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const head = renderToStaticMarkup(
|
||||||
|
React.createElement(React.Fragment, null, headTags)
|
||||||
|
)
|
||||||
|
return { body, head }
|
||||||
|
}
|
||||||
|
|
||||||
|
const build = async (opts = {}) => {
|
||||||
|
const config = createConfig(opts)
|
||||||
|
|
||||||
|
const App = await getApp(config, opts)
|
||||||
|
const { body, head } = await renderHTML(App)
|
||||||
|
|
||||||
|
config.mode = 'production'
|
||||||
|
config.output = {
|
||||||
|
path: opts.outDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
config.plugins.push(
|
||||||
|
new HTMLPlugin({
|
||||||
|
context: {
|
||||||
|
head,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const compiler = webpack(config)
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
compiler.run((err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.compilation.errors && stats.compilation.errors.length) {
|
||||||
|
reject(stats.compilation.errors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(stats)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = build
|
101
packages/mdx-deck/lib/config.js
Normal file
101
packages/mdx-deck/lib/config.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const WebpackBar = require('webpackbar')
|
||||||
|
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||||
|
const merge = require('webpack-merge')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const remark = {
|
||||||
|
emoji: require('remark-emoji'),
|
||||||
|
unwrapImages: require('remark-unwrap-images'),
|
||||||
|
}
|
||||||
|
const HTMLPlugin = require('@mdx-deck/webpack-html-plugin')
|
||||||
|
const babel = require('../babel.config')
|
||||||
|
|
||||||
|
const rules = [
|
||||||
|
{
|
||||||
|
test: /\.jsx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: babel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: path.resolve(__dirname, '../node_modules'),
|
||||||
|
include: [path.resolve(__dirname, '..'), /@mdx\-deck/],
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: babel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.mdx?$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: babel,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: require.resolve('@mdx-deck/loader'),
|
||||||
|
options: {
|
||||||
|
mdPlugins: [remark.emoji, remark.unwrapImages],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ['style-loader', 'css-loader'].map(require.resolve),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const baseConfig = {
|
||||||
|
stats: 'errors-only',
|
||||||
|
mode: 'development',
|
||||||
|
module: {
|
||||||
|
rules,
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx'],
|
||||||
|
alias: {
|
||||||
|
// 'mdx-deck': path.resolve(__dirname, '..'),
|
||||||
|
'webpack-hot-middleware/client': path.resolve(
|
||||||
|
require.resolve('webpack-hot-middleware/client')
|
||||||
|
),
|
||||||
|
},
|
||||||
|
modules: [
|
||||||
|
path.relative(process.cwd(), path.join(__dirname, '../node_modules')),
|
||||||
|
'node_modules',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new WebpackBar({
|
||||||
|
name: '[mdx-deck]',
|
||||||
|
}),
|
||||||
|
new FriendlyErrorsPlugin(),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const createConfig = (opts = {}) => {
|
||||||
|
const config = merge(baseConfig, opts.webpack)
|
||||||
|
config.context = opts.dirname
|
||||||
|
|
||||||
|
config.resolve.modules.push(
|
||||||
|
opts.dirname,
|
||||||
|
path.join(opts.dirname, 'node_modules')
|
||||||
|
)
|
||||||
|
|
||||||
|
config.entry = [path.join(__dirname, './entry.js')]
|
||||||
|
|
||||||
|
const defs = Object.assign({}, opts.globals, {
|
||||||
|
OPTIONS: JSON.stringify(opts),
|
||||||
|
})
|
||||||
|
|
||||||
|
config.plugins.push(
|
||||||
|
new webpack.DefinePlugin(defs),
|
||||||
|
new HTMLPlugin({ context: opts })
|
||||||
|
)
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = createConfig
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user