├── .gitignore
├── cm-night-owl.css
├── components
├── about-me.js
├── accordion-code.js
├── accordion
│ ├── above.js
│ ├── base.js
│ ├── implementations.js
│ ├── left.js
│ ├── prevent-close.js
│ ├── right.js
│ ├── single-prevent-close.js
│ ├── single.js
│ └── standard.js
├── aprocalypse.js
├── code-block.js
├── demo-layout.js
├── demo-slide.js
├── first-slide.js
├── randomly-placed.js
├── resources.js
├── shared.js
├── sob.js
├── tabs
│ ├── above.js
│ ├── base.js
│ ├── implementations.js
│ └── standard.js
└── white-layout.js
├── deck.mdx
├── package-lock.json
├── package.json
├── public
├── apropcalypse.png
├── cost-benefits.jpg
├── cry.png
├── epic-react.png
├── erased-from-existence.mp4
├── sob.png
├── standard
│ ├── 3-minutes-with-kent.png
│ ├── ama.png
│ ├── astronaut.png
│ ├── big-smile.png
│ ├── books.png
│ ├── boy.png
│ ├── dash-race-car.png
│ ├── dash-reverse.png
│ ├── dog.png
│ ├── eggheadio.png
│ ├── fem.png
│ ├── gde.png
│ ├── girl.png
│ ├── github.png
│ ├── house.png
│ ├── kcd-news.png
│ ├── medium.png
│ ├── neutral-face.png
│ ├── office.png
│ ├── racing-car-reverse.png
│ ├── smile.png
│ ├── speaking.png
│ ├── trophy.png
│ ├── twitch.png
│ ├── twitter.svg
│ ├── wave.png
│ ├── woman.png
│ ├── workshopme.png
│ └── youtube.png
├── sweat-smile.png
└── what-if.jpg
├── script.js
├── styles.css
└── theme.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/cm-night-owl.css:
--------------------------------------------------------------------------------
1 | /*
2 | Name: night-owl 1.1.1
3 | Author: Sarah Drasner (https://github.com/sdras)
4 | Original VS Code theme (https://github.com/sdras/night-owl-vscode-theme)
5 | copied from https://github.com/dawnlabs/carbon/blob/master/lib/custom/themes/night-owl.css
6 | */
7 | /* basic */
8 | .CodeMirror.cm-s-night-owl {
9 | font-family: 'Dank Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
10 | font-weight: 350;
11 | color: #abb2bf;
12 | background-color: #011627;
13 | }
14 | .cm-s-night-owl .CodeMirror-selected {
15 | background-color: #1d3b53 !important;
16 | }
17 | .cm-s-night-owl .CodeMirror-gutter,
18 | .cm-s-night-owl .CodeMirror-gutters {
19 | border: none;
20 | background-color: #011627;
21 | }
22 | .cm-s-night-owl .CodeMirror-linenumber,
23 | .cm-s-night-owl .CodeMirror-linenumbers {
24 | color: #5f7e97 !important;
25 | background-color: transparent;
26 | }
27 | .cm-s-night-owl .CodeMirror-lines {
28 | color: #abb2bf !important;
29 | background-color: transparent;
30 | }
31 | .cm-s-night-owl .CodeMirror-cursor {
32 | border-left: 2px solid #7e57c2 !important;
33 | }
34 | /* addon: edit/machingbrackets.js & addon: edit/matchtags.js */
35 | .cm-s-night-owl .CodeMirror-matchingbracket,
36 | .cm-s-night-owl .CodeMirror-matchingtag {
37 | border-bottom: 2px solid #c792ea;
38 | color: #abb2bf !important;
39 | background-color: transparent;
40 | }
41 | .cm-s-night-owl .CodeMirror-nonmatchingbracket {
42 | border-bottom: 2px solid #e06c75;
43 | color: #abb2bf !important;
44 | background-color: transparent;
45 | }
46 | /* addon: fold/foldgutter.js */
47 | .cm-s-night-owl .CodeMirror-foldmarker,
48 | .cm-s-night-owl .CodeMirror-foldgutter,
49 | .cm-s-night-owl .CodeMirror-foldgutter-open,
50 | .cm-s-night-owl .CodeMirror-foldgutter-folded {
51 | border: none;
52 | text-shadow: none;
53 | color: #5c6370 !important;
54 | background-color: transparent;
55 | }
56 | /* addon: selection/active-line.js */
57 | .cm-s-night-owl .CodeMirror-activeline-background {
58 | background-color: #01121f;
59 | }
60 | /* basic syntax */
61 | .cm-s-night-owl .cm-quote {
62 | color: #5c6370;
63 | font-style: italic;
64 | }
65 | .cm-s-night-owl .cm-negative {
66 | color: #e06c75;
67 | }
68 | .cm-s-night-owl .cm-positive {
69 | color: #e06c75;
70 | }
71 | .cm-s-night-owl .cm-strong {
72 | color: #f78c6c;
73 | font-weight: bold;
74 | }
75 | .cm-s-night-owl .cm-em {
76 | color: #c792ea;
77 | font-style: italic;
78 | }
79 | .cm-s-night-owl .cm-attribute {
80 | color: #f78c6c;
81 | }
82 | .cm-s-night-owl .cm-link {
83 | color: #ecc48d;
84 | border-bottom: solid 1px #ecc48d;
85 | }
86 | .cm-s-night-owl .cm-keyword {
87 | color: #c792ea;
88 | font-style: italic;
89 | }
90 | .cm-s-night-owl .cm-def {
91 | color: #82aaff;
92 | }
93 | .cm-s-night-owl .cm-atom {
94 | color: #f78c6c;
95 | }
96 | .cm-s-night-owl .cm-number {
97 | color: #f78c6c;
98 | }
99 | .cm-s-night-owl .cm-property {
100 | color: #fff;
101 | }
102 | .cm-s-night-owl .cm-qualifier {
103 | color: #f78c6c;
104 | }
105 | .cm-s-night-owl .cm-variable {
106 | color: #82aaff;
107 | }
108 | .cm-s-night-owl .cm-variable-2 {
109 | color: #82aaff;
110 | }
111 | .cm-s-night-owl .cm-string {
112 | color: #ecc48d;
113 | }
114 | .cm-s-night-owl .cm-string-2 {
115 | color: #addb67;
116 | }
117 | .cm-s-night-owl .cm-operator {
118 | color: #c792ea;
119 | }
120 | .cm-s-night-owl .cm-meta {
121 | color: #7fdbca;
122 | }
123 | .cm-s-night-owl .cm-comment {
124 | color: #5c6370;
125 | font-style: italic;
126 | }
127 | .cm-s-night-owl .cm-error {
128 | color: #e06c75;
129 | }
130 |
131 | .cm-s-night-owl .cm-tag {
132 | color: #addb67;
133 | }
134 |
135 | .cm-s-night-owl .cm-tag.cm-bracket {
136 | color: #7fdbca;
137 | }
138 |
--------------------------------------------------------------------------------
/components/about-me.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | const Container = styled.div`
5 | display: flex;
6 | justify-content: space-around;
7 | `
8 |
9 | const IconImage = styled.img`
10 | max-height: 70px;
11 | max-width: 70px;
12 | `
13 |
14 | function LinkedIconImage({link, name}) {
15 | return (
16 |
17 |
18 |
19 | )
20 | }
21 |
22 | const IconImageContainer = styled.div`
23 | display: flex;
24 | flex-direction: column;
25 | align-items: center;
26 | `
27 |
28 | const Family = styled.div`
29 | display: flex;
30 | `
31 |
32 | const LogoRow = styled(Container)`
33 | margin-top: 30px;
34 | margin-bottom: 30px;
35 | `
36 |
37 | class AboutMe extends React.Component {
38 | render() {
39 | return (
40 |
41 |
42 |
43 |
47 | Utah
48 |
49 |
50 |
51 |
55 |
59 |
63 |
67 |
71 |
75 |
76 | wife, 4 kids, & a dog
77 |
78 |
79 |
83 | PayPal
84 |
85 |
86 |
87 |
91 |
92 |
96 |
100 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | )
116 | }
117 | }
118 |
119 | export {AboutMe}
120 |
--------------------------------------------------------------------------------
/components/accordion-code.js:
--------------------------------------------------------------------------------
1 | export const accordionCode = `
2 | const actionTypes = {toggle_index: 'toggle_index'}
3 |
4 | function accordionReducer(openIndexes, action) {
5 | switch (action.type) {
6 | case actionTypes.toggle_index: {
7 | const closing = openIndexes.includes(action.index)
8 | return closing
9 | ? openIndexes.filter(i => i !== action.index)
10 | : [...openIndexes, action.index]
11 | }
12 | default: {
13 | throw new Error('Unhandled type in accordionReducer: ' + action.type)
14 | }
15 | }
16 | }
17 |
18 | function useAccordion({reducer = accordionReducer} = {}) {
19 | const [openIndexes, dispatch] = React.useReducer(reducer, [0])
20 | const toggleIndex = index => dispatch({type: actionTypes.toggle_index, index})
21 | return {openIndexes, toggleIndex}
22 | }
23 |
24 | export {useAccordion, accordionReducer, actionTypes}
25 | `.trim()
26 |
--------------------------------------------------------------------------------
/components/accordion/above.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {AccordionButton, AccordionItem, AccordionContents} from '../shared'
4 |
5 | function AboveAccordion({items, ...props}) {
6 | return (
7 |
8 | {({openIndexes, handleItemClick}) => (
9 |
10 | {items.map((item, index) => (
11 |
12 |
13 | {item.contents}
14 |
15 | handleItemClick(index)}
18 | >
19 | {item.title}{' '}
20 | {openIndexes.includes(index) ? '👆' : '👈'}
21 |
22 |
23 | ))}
24 |
25 | )}
26 |
27 | )
28 | }
29 |
30 | export {AboveAccordion}
31 |
--------------------------------------------------------------------------------
/components/accordion/base.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | class Accordion extends React.Component {
4 | static defaultProps = {
5 | stateReducer: (state, changes) => changes,
6 | onStateChange: () => {},
7 | }
8 | state = {openIndexes: [0]}
9 | getState(state = this.state) {
10 | return {
11 | openIndexes:
12 | this.props.openIndexes === undefined
13 | ? state.openIndexes
14 | : this.props.openIndexes,
15 | }
16 | }
17 | internalSetState(changes, callback = () => {}) {
18 | let allChanges
19 | this.setState(
20 | state => {
21 | const actualState = this.getState(state)
22 | const changesObject =
23 | typeof changes === 'function' ? changes(actualState) : changes
24 | allChanges = this.props.stateReducer(actualState, changesObject)
25 | return allChanges
26 | },
27 | () => {
28 | this.props.onStateChange(allChanges)
29 | callback()
30 | },
31 | )
32 | }
33 | handleItemClick = index => {
34 | this.internalSetState(state => {
35 | const closing = state.openIndexes.includes(index)
36 | return {
37 | type: closing ? 'closing' : 'opening',
38 | openIndexes: closing
39 | ? state.openIndexes.filter(i => i !== index)
40 | : [...state.openIndexes, index],
41 | }
42 | })
43 | }
44 | render() {
45 | return this.props.children({
46 | openIndexes: this.getState().openIndexes,
47 | handleItemClick: this.handleItemClick,
48 | })
49 | }
50 | }
51 |
52 | export {Accordion}
53 |
--------------------------------------------------------------------------------
/components/accordion/implementations.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {StandardAccordion} from './standard'
3 | import {AboveAccordion} from './above'
4 | import {RightAccordion} from './right'
5 | import {LeftAccordion} from './left'
6 | import {SingleAccordion} from './single'
7 | import {PreventCloseAccordion} from './prevent-close'
8 | import {SinglePreventCloseAccordion} from './single-prevent-close'
9 |
10 | const items = [
11 | {
12 | title: '🐴',
13 | contents: (
14 |
15 | Horses can sleep both lying down and standing up. Domestic horses have a
16 | lifespan of around 25 years. A 19th century horse named 'Old Billy' is
17 | said to have lived 62 years.
18 |
19 | ),
20 | },
21 | {
22 | title: '🦏',
23 | contents: (
24 |
25 | Rhino skin maybe thick but it can be quite sensitive to sunburns and
26 | insect bites which is why they like wallow so much – when the mud dries
27 | it acts as protection from the sunburns and insects.
28 |
29 | ),
30 | },
31 | {
32 | title: '🦄',
33 | contents: (
34 |
35 | If you’re looking to hunt a unicorn, but don’t know where to begin, try
36 | Lake Superior State University in Sault Ste. Marie, Michigan. Since
37 | 1971, the university has issued permits to unicorn questers.
38 |
39 | ),
40 | },
41 | ]
42 |
43 | function asImpl(Comp) {
44 | return () => (
45 |
53 |
54 |
55 | )
56 | }
57 |
58 | export const Standard = asImpl(StandardAccordion)
59 | export const Above = asImpl(AboveAccordion)
60 | export const Right = asImpl(RightAccordion)
61 | export const Left = asImpl(LeftAccordion)
62 | export const Single = asImpl(SingleAccordion)
63 | export const PreventClose = asImpl(PreventCloseAccordion)
64 | export const SinglePreventClose = asImpl(SinglePreventCloseAccordion)
65 |
--------------------------------------------------------------------------------
/components/accordion/left.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {css, AccordionButton, AccordionItem, AccordionContents} from '../shared'
4 |
5 | function LeftAccordion({items, ...props}) {
6 | return (
7 |
8 | {({openIndexes, handleItemClick}) => (
9 |
10 | {items.map((item, index) => (
11 |
12 |
13 | {item.contents}
14 |
15 | handleItemClick(index)}
18 | >
19 | {openIndexes.includes(index) ? '👈' : '👉'} {' '}
20 | {item.title}
21 |
22 |
23 | ))}
24 |
25 | )}
26 |
27 | )
28 | }
29 |
30 | export {LeftAccordion}
31 |
--------------------------------------------------------------------------------
/components/accordion/prevent-close.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {
4 | AccordionButton,
5 | AccordionItem,
6 | AccordionContents,
7 | preventClose,
8 | } from '../shared'
9 |
10 | function PreventCloseAccordion({items, ...props}) {
11 | return (
12 |
13 | {({openIndexes, handleItemClick}) => (
14 |
15 | {items.map((item, index) => (
16 |
17 | handleItemClick(index)}
20 | >
21 | {item.title}{' '}
22 | {openIndexes.includes(index) ? '👇' : '👈'}
23 |
24 |
25 | {item.contents}
26 |
27 |
28 | ))}
29 |
30 | )}
31 |
32 | )
33 | }
34 |
35 | export {PreventCloseAccordion}
36 |
--------------------------------------------------------------------------------
/components/accordion/right.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {css, AccordionButton, AccordionItem, AccordionContents} from '../shared'
4 |
5 | function RightAccordion({items, ...props}) {
6 | return (
7 |
8 | {({openIndexes, handleItemClick}) => (
9 |
10 | {items.map((item, index) => (
11 |
12 | handleItemClick(index)}
15 | >
16 | {openIndexes.includes(index) ? '👉' : '👈'} {' '}
17 | {item.title}
18 |
19 |
20 | {item.contents}
21 |
22 |
23 | ))}
24 |
25 | )}
26 |
27 | )
28 | }
29 |
30 | export {RightAccordion}
31 |
--------------------------------------------------------------------------------
/components/accordion/single-prevent-close.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {
4 | AccordionButton,
5 | AccordionItem,
6 | AccordionContents,
7 | single,
8 | preventClose,
9 | combineReducers,
10 | } from '../shared'
11 |
12 | function SinglePreventCloseAccordion({items, ...props}) {
13 | return (
14 |
15 | {({openIndexes, handleItemClick}) => (
16 |
17 | {items.map((item, index) => (
18 |
19 | handleItemClick(index)}
22 | >
23 | {item.title}{' '}
24 | {openIndexes.includes(index) ? '👇' : '👈'}
25 |
26 |
27 | {item.contents}
28 |
29 |
30 | ))}
31 |
32 | )}
33 |
34 | )
35 | }
36 |
37 | export {SinglePreventCloseAccordion}
38 |
--------------------------------------------------------------------------------
/components/accordion/single.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {
4 | AccordionButton,
5 | AccordionItem,
6 | AccordionContents,
7 | single,
8 | } from '../shared'
9 |
10 | function SingleAccordion({items, ...props}) {
11 | return (
12 |
13 | {({openIndexes, handleItemClick}) => (
14 |
15 | {items.map((item, index) => (
16 |
17 | handleItemClick(index)}
20 | >
21 | {item.title}{' '}
22 | {openIndexes.includes(index) ? '👇' : '👈'}
23 |
24 |
25 | {item.contents}
26 |
27 |
28 | ))}
29 |
30 | )}
31 |
32 | )
33 | }
34 |
35 | export {SingleAccordion}
36 |
--------------------------------------------------------------------------------
/components/accordion/standard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from './base'
3 | import {AccordionButton, AccordionItem, AccordionContents} from '../shared'
4 |
5 | function StandardAccordion({items, ...props}) {
6 | return (
7 |
8 | {({openIndexes, handleItemClick}) => (
9 |
10 | {items.map((item, index) => (
11 |
12 | handleItemClick(index)}
15 | >
16 | {item.title}{' '}
17 | {openIndexes.includes(index) ? '👇' : '👈'}
18 |
19 |
20 | {item.contents}
21 |
22 |
23 | ))}
24 |
25 | )}
26 |
27 | )
28 | }
29 |
30 | export {StandardAccordion}
31 |
--------------------------------------------------------------------------------
/components/aprocalypse.js:
--------------------------------------------------------------------------------
1 | export const aprocalypse = `
2 | const accordionItems = [
3 | {
4 | title: '🐴',
5 | openTitle: '🐎',
6 | contents: '...',
7 | disabled: false,
8 | },
9 | // ...
10 | ]
11 |
12 | const ui = (
13 |
28 | )
29 | `.trim()
30 |
--------------------------------------------------------------------------------
/components/code-block.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {UnControlled as CodeMirror} from 'react-codemirror2'
3 |
4 | export const CodeBlock = ({children, options = {}, style, ...props}) => (
5 |
6 |
17 |
18 | )
19 |
--------------------------------------------------------------------------------
/components/demo-layout.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | export default ({children}) => (
4 |
15 | {children}
16 |
17 | )
18 |
--------------------------------------------------------------------------------
/components/demo-slide.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Appear} from 'mdx-deck'
3 | import {CodeBlock} from './code-block'
4 |
5 | function DemoSlide({accordion, followCode, code}) {
6 | return (
7 |
8 |
11 |
12 |
13 | {code.trim()}
14 |
15 | {followCode ? (
16 |
17 |
25 | {followCode.trim()}
26 |
27 |
28 | ) : null}
29 |
30 |
31 | )
32 | }
33 |
34 | export {DemoSlide}
35 |
--------------------------------------------------------------------------------
/components/first-slide.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'styled-components'
3 |
4 | const Container = styled.div`
5 | display: flex;
6 | justify-content: space-around;
7 | align-items: center;
8 | `
9 |
10 | const IconImage = styled.img`
11 | max-height: 70px;
12 | max-width: 70px;
13 | `
14 |
15 | function LinkedIconImage({link, name}) {
16 | return (
17 |
18 |
19 |
20 | )
21 | }
22 |
23 | const IconImageContainer = styled.div`
24 | display: flex;
25 | flex-direction: column;
26 | align-items: center;
27 | `
28 |
29 | const Family = styled.div`
30 | display: flex;
31 | `
32 |
33 | const LogoRow = styled(Container)`
34 | margin-top: 30px;
35 | margin-bottom: 30px;
36 | `
37 |
38 | function FirstSlide({title, subtitle}) {
39 | return (
40 |
53 |
{title}
54 |
{subtitle}
55 |
Kent C. Dodds
56 |
57 |
58 | )
59 | }
60 |
61 | class AboutMe extends React.Component {
62 | render() {
63 | return (
64 |
88 | )
89 | }
90 | }
91 |
92 | export {FirstSlide}
93 |
--------------------------------------------------------------------------------
/components/randomly-placed.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | function RandomlyPlaced({children, style, ...props}) {
4 | return (
5 |
6 | {children ? (
7 |
15 | {children}
16 |
17 | ) : null}
18 |
19 | )
20 | }
21 |
22 | export {RandomlyPlaced}
23 |
--------------------------------------------------------------------------------
/components/resources.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import styled from 'react-emotion'
3 |
4 | const Title = styled('strong')({
5 | fontSize: 32,
6 | })
7 |
8 | const Link = styled('a')({
9 | fontSize: 24,
10 | color: '#addb67',
11 | })
12 | Link.defaultProps = {target: '_blank'}
13 |
14 | export const Resources = () => (
15 |
19 | )
20 |
--------------------------------------------------------------------------------
/components/shared.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import posed from 'react-pose'
3 | import {css as emoCSS} from 'emotion'
4 | import styled from 'react-emotion'
5 |
6 | const css = (...args) => ({className: emoCSS(...args)})
7 |
8 | const AccordionButton = styled('button')(
9 | {
10 | textAlign: 'left',
11 | minWidth: 80,
12 | cursor: 'pointer',
13 | flex: 1,
14 | paddingTop: 10,
15 | paddingBottom: 10,
16 | fontSize: 20,
17 | border: 'none',
18 | backgroundColor: 'unset',
19 | ':focus': {
20 | outline: 'none',
21 | backgroundColor: 'rgba(255, 255, 255, 0.4)',
22 | },
23 | },
24 | ({isOpen}) =>
25 | isOpen
26 | ? {
27 | backgroundColor: 'rgba(255, 255, 255, 0.2)',
28 | }
29 | : null,
30 | )
31 |
32 | const PoseAccordionContents = posed.div({
33 | open: {maxHeight: 200},
34 | closed: {maxHeight: 0},
35 | })
36 |
37 | function AccordionContents({isOpen, ...props}) {
38 | return (
39 |
44 | )
45 | }
46 |
47 | const AccordionItem = styled('div')(
48 | {
49 | display: 'grid',
50 | gridTemplate: 'auto auto',
51 | gridGap: 4,
52 | gridAutoFlow: 'row',
53 | },
54 | props => ({
55 | gridAutoFlow: props.direction === 'horizontal' ? 'column' : 'row',
56 | }),
57 | )
58 |
59 | const TabButtons = styled('div')({display: 'flex'})
60 | const TabButton = styled(AccordionButton)({
61 | textAlign: 'center',
62 | })
63 | const TabItems = styled('div')({
64 | position: 'relative',
65 | minHeight: 160,
66 | })
67 |
68 | const BelowTabItem = posed.div({
69 | open: {opacity: 1, top: 0},
70 | closed: {opacity: 0, top: 30},
71 | })
72 |
73 | const AboveTabItem = posed.div({
74 | open: {opacity: 1, bottom: 0},
75 | closed: {opacity: 0, bottom: 30},
76 | })
77 |
78 | function TabItem({position, isOpen, ...props}) {
79 | props = {
80 | pose: isOpen ? 'open' : 'closed',
81 | ...css({position: 'absolute', overflowY: 'hidden'}),
82 | ...props,
83 | }
84 | return position === 'above' ? (
85 |
86 | ) : (
87 |
88 | )
89 | }
90 |
91 | function preventClose(state, changes) {
92 | if (changes.type === 'closing' && state.openIndexes.length < 2) {
93 | return {...changes, openIndexes: state.openIndexes}
94 | }
95 | return changes
96 | }
97 |
98 | function single(state, changes) {
99 | if (changes.type === 'opening') {
100 | return {openIndexes: changes.openIndexes.slice(-1)}
101 | }
102 | return changes
103 | }
104 |
105 | function combineReducers(...reducers) {
106 | return (state, changes) => {
107 | for (let reducer of reducers) {
108 | const result = reducer(state, changes)
109 | if (result !== changes) {
110 | return result
111 | }
112 | }
113 | return changes
114 | }
115 | }
116 |
117 | export {
118 | css,
119 | AccordionButton,
120 | AccordionItem,
121 | AccordionContents,
122 | AboveTabItem,
123 | BelowTabItem,
124 | TabItem,
125 | TabItems,
126 | TabButton,
127 | TabButtons,
128 | combineReducers,
129 | preventClose,
130 | single,
131 | }
132 |
--------------------------------------------------------------------------------
/components/sob.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Appear} from 'mdx-deck'
3 | import {RandomlyPlaced} from './randomly-placed'
4 |
5 | export const Sob = ({children, style}) => (
6 |
7 |
8 | {children ? (
9 |
16 | {children}
17 |
18 | ) : null}
19 |
20 | )
21 |
22 | export const Sobbing = () => (
23 |
24 |
25 |
26 | bundle size/perf 😵
27 |
28 |
29 | maintenance overhead 😖
30 |
31 |
32 |
33 | implementation complexity 🐛
34 |
35 |
36 |
37 | API complexity 😕
38 |
39 |
40 |
41 |
42 |
43 |
63 |
64 |
65 | )
66 |
--------------------------------------------------------------------------------
/components/tabs/above.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Tabs} from './base'
3 | import {TabItem, TabItems, TabButtons, TabButton} from '../shared'
4 |
5 | function AboveTabs({items}) {
6 | return (
7 |
8 | {({openIndexes, handleItemClick}) => (
9 |
10 |
11 | {items.map((item, index) => (
12 |
17 | {items[index].contents}
18 |
19 | ))}
20 |
21 |
22 | {items.map((item, index) => (
23 | handleItemClick(index)}
27 | >
28 | {item.title}
29 |
30 | ))}
31 |
32 |
33 | )}
34 |
35 | )
36 | }
37 |
38 | export {AboveTabs}
39 |
--------------------------------------------------------------------------------
/components/tabs/base.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Accordion} from '../accordion/base'
3 | import {single, preventClose, combineReducers} from '../shared'
4 |
5 | function Tabs({stateReducer = (state, changes) => changes, ...props}) {
6 | return (
7 |
11 | )
12 | }
13 |
14 | export {Tabs}
15 |
--------------------------------------------------------------------------------
/components/tabs/implementations.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {StandardTabs} from './standard'
3 | import {AboveTabs} from './above'
4 |
5 | const items = [
6 | {
7 | title: '🐴',
8 | contents: (
9 |
10 | Horses can sleep both lying down and standing up. Domestic horses have a
11 | lifespan of around 25 years. A 19th century horse named 'Old Billy' is
12 | said to have lived 62 years.
13 |
14 | ),
15 | },
16 | {
17 | title: '🦏',
18 | contents: (
19 |
20 | Rhino skin maybe thick but it can be quite sensitive to sunburns and
21 | insect bites which is why they like wallow so much – when the mud dries
22 | it acts as protection from the sunburns and insects.
23 |
24 | ),
25 | },
26 | {
27 | title: '🦄',
28 | contents: (
29 |
30 | If you’re looking to hunt a unicorn, but don’t know where to begin, try
31 | Lake Superior State University in Sault Ste. Marie, Michigan. Since
32 | 1971, the university has issued permits to unicorn questers.
33 |
34 | ),
35 | },
36 | ]
37 |
38 | function asImpl(Comp) {
39 | return () => (
40 |
48 |
49 |
50 | )
51 | }
52 |
53 | export const Standard = asImpl(StandardTabs)
54 | export const Above = asImpl(AboveTabs)
55 |
--------------------------------------------------------------------------------
/components/tabs/standard.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Tabs} from './base'
3 | import {TabItem, TabItems, TabButtons, TabButton} from '../shared'
4 |
5 | function StandardTabs({items}) {
6 | return (
7 |
8 | {({openIndexes, handleItemClick}) => (
9 |
10 |
11 | {items.map((item, index) => (
12 | handleItemClick(index)}
16 | >
17 | {item.title}
18 |
19 | ))}
20 |
21 |
22 | {items.map((item, index) => (
23 |
28 | {items[index].contents}
29 |
30 | ))}
31 |
32 |
33 | )}
34 |
35 | )
36 | }
37 |
38 | export {StandardTabs}
39 |
--------------------------------------------------------------------------------
/components/white-layout.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Slide from 'mdx-deck/dist/Slide'
3 |
4 | export default ({children}) => (
5 |
19 | )
20 |
--------------------------------------------------------------------------------
/deck.mdx:
--------------------------------------------------------------------------------
1 | import './script.js'
2 | import {Appear, Notes} from 'mdx-deck'
3 | import {FirstSlide} from './components/first-slide'
4 | import {AboutMe} from './components/about-me'
5 | import * as Accordions from './components/accordion/implementations'
6 | import * as Tabs from './components/tabs/implementations'
7 | import {CodeBlock} from './components/code-block'
8 | import WhiteLayout from './components/white-layout'
9 | import {aprocalypse} from './components/aprocalypse'
10 | import {accordionCode} from './components/accordion-code'
11 | import {Sobbing, Sob} from './components/sob'
12 | import {RandomlyPlaced} from './components/randomly-placed'
13 | import {DemoSlide} from './components/demo-slide'
14 | import DemoLayout from './components/demo-layout'
15 | import {Resources} from './components/resources'
16 |
17 | export {default as theme} from './theme'
18 |
19 | export default WhiteLayout
20 |
21 |
25 |
26 | ---
27 |
28 | export default WhiteLayout
29 |
30 | # What this talk is
31 |
32 | - Typical lifecycle of a component (not what you're
33 | thinking)
34 | - How patterns can simplify
35 | - Composability
36 | - A challenge
37 |
38 |
39 |
40 | ---
41 |
42 | export default WhiteLayout
43 |
44 | # What this talk is _not_
45 |
46 |
47 |
48 |
49 | How to implement patterns
50 |
51 |
52 |
53 |
54 |
55 |
56 | ---
57 |
58 | # Let's get started
59 |
60 |
61 |
62 | ---
63 |
64 | export default DemoLayout
65 |
66 | `}
68 | accordion={ }
69 | />
70 |
71 |
72 |
85 |
Theme: Night Owl by Sarah Drasner
86 |
Font: Dank Mono by Phil Plückthun
87 |
88 |
89 |
90 |
91 |
92 | ```notes
93 | - Following the lifecycle of an Accordion
94 | - Make it for your use case
95 | - Props API is pretty simple
96 | - Theme/Font shoutout
97 | - New Use Case: Above
98 | ```
99 |
100 | ---
101 |
102 | export default DemoLayout
103 |
104 | `}
106 | accordion={ }
107 | />
108 |
109 | ```notes
110 | - Just a few conditional statements (position, hand, animation)
111 | - New Use Case: Right
112 | ```
113 |
114 | ---
115 |
116 | export default DemoLayout
117 |
118 | `}
120 | accordion={ }
121 | />
122 |
123 | ```notes
124 | - Refactor to use CSS Grid and use gridAutoFlow for column vs row
125 | - New Use Case: Left
126 | ```
127 |
128 | ---
129 |
130 | export default DemoLayout
131 |
132 | `}
134 | accordion={ }
135 | followCode={` `}
136 | />
137 |
138 | ```notes
139 | - Refactor the props to use position because David K. Piano said impossible states is a no-no
140 | - New Use Case: Single
141 | ```
142 |
143 | ---
144 |
145 | export default DemoLayout
146 |
147 |
154 | `}
155 | accordion={ }
156 | />
157 |
158 | ```notes
159 | - Some conditional logic in the click handler
160 | - New Use Case: Prevent Close
161 | ```
162 |
163 | ---
164 |
165 | export default DemoLayout
166 |
167 |
174 | `}
175 | accordion={ }
176 | />
177 |
178 | ```notes
179 | - Some additional conditional logic in the click handler
180 | - New Use Case: SinglePreventClose
181 | ```
182 |
183 | ---
184 |
185 | export default DemoLayout
186 |
187 |
195 | `}
196 | accordion={ }
197 | />
198 |
199 | ```notes
200 | - Luckily no changes necessary!
201 | - But this looks familiar! New Use Case: Tabs
202 | ```
203 |
204 | ---
205 |
206 | export default DemoLayout
207 |
208 |
217 | `}
218 | accordion={ }
219 | />
220 |
221 |
222 |
223 |
224 |
225 |
226 | ```notes
227 | - Write tabs UI in a different method `renderTabs`
228 | - Cry!
229 | - New Use Case: Tabs Above
230 | ```
231 |
232 | ---
233 |
234 | export default DemoLayout
235 |
236 | `}
238 | accordion={ }
239 | />
240 |
241 |
242 |
243 |
244 |
245 |
246 | ```notes
247 | - I don't want to maintain this anymore
248 | - Fork the component to make a tabs component
249 | - Sob
250 | ```
251 |
252 | ---
253 |
254 | {aprocalypse}
255 |
256 |
257 |
258 | ```notes
259 | - Datepicker with 60 props
260 | - "Configuration Props" (objects with dozens of options, basically just more props)
261 | - "render" props: boolean props to control whether something is rendered
262 | - Bundle: Code you don't need
263 | - Maintenance: Documentation, answering questions
264 | - Implementation: Remembering use cases and not breaking things. Contributors.
265 | - API: Having to learn the growing API
266 | - APROPCALYPSE
267 | ```
268 |
269 | ---
270 |
271 |
272 |
273 | ```notes
274 | (notes for next slide...)
275 | - I might have manually changed the code post-prettier :)
276 | - Don't worry about the specific implementation details.
277 | - Two major patterns that allow this:
278 | - stateReducer
279 | - render props
280 | - Inversion of control patterns
281 | ```
282 |
283 | ---
284 |
285 | export default ({children}) => (
286 | {children}
287 | )
288 |
289 | {accordionCode}
290 |
291 |
296 |
297 | ---
298 |
299 | # Demo
300 |
301 | [CodeSandbox](https://codesandbox.io/s/simply-react-accordion-lvg59)
302 |
303 | Thank you Ives ❣️
304 |
305 | ```notes
306 | - Composition allows for the same simple API
307 | ```
308 |
309 | ---
310 |
311 |
312 |
313 | ---
314 |
315 | # A word of caution
316 |
317 | What if this is all you will ever need?
318 |
319 |
331 |
332 | ---
333 |
334 | # YAGNI
335 |
336 | You Ain't Gonna Need It
337 |
338 |
339 | Optimize for deletability
340 |
341 |
342 |
350 |
351 |
352 |
353 | ```notes
354 | - Be mindful and intentional
355 | - Measure the costs and the benefits.
356 | - Just go with what you have and see how it plays out.
357 | - Optimize for deletability
358 | - Erased from existence!
359 | ```
360 |
361 | ---
362 |
363 | # Use patterns that _simplify_ your API
364 |
365 |
366 |
367 |
374 | state reducers
375 |
376 |
377 |
378 |
385 | control props
386 |
387 |
388 |
389 |
396 | hook composition
397 |
398 |
399 |
400 |
407 | compound components
408 |
409 |
410 |
411 |
424 | Let's (re)discover more!
425 |
426 |
427 |
428 |
429 | ```notes
430 | - Applying old principles (like composition and inversion of control)
431 | ```
432 |
433 | ---
434 |
435 | # Thank You
436 |
437 |
438 |
439 | [simply-react.netlify.com](https://simply-react.netlify.com)
440 |
441 |
442 | @kentcdodds
443 |
444 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simply-react",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "mdx-deck deck.mdx",
8 | "prebuild": "rimraf dist",
9 | "build": "npm run build:site && npm run build:pdf",
10 | "build:site": "mdx-deck build deck.mdx",
11 | "build:pdf": "mdx-deck pdf deck.mdx",
12 | "postbuild": "cpy --parents \"public/**\" ./dist"
13 | },
14 | "keywords": [],
15 | "author": "Kent C. Dodds (http://kentcdodds.com/)",
16 | "license": "MIT",
17 | "devDependencies": {
18 | "cpy-cli": "^2.0.0",
19 | "css-loader": "^1.0.0",
20 | "mdx-deck": "^1.6.3",
21 | "rimraf": "^2.6.2",
22 | "style-loader": "^0.22.1"
23 | },
24 | "dependencies": {
25 | "codemirror": "^5.39.2",
26 | "emotion": "^9.2.6",
27 | "react": "^16.13.1",
28 | "react-codemirror2": "^5.1.0",
29 | "react-dom": "^16.13.1",
30 | "react-emotion": "^9.2.6",
31 | "react-pose": "^2.2.1",
32 | "react-transition-group": "^2.4.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/public/apropcalypse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/apropcalypse.png
--------------------------------------------------------------------------------
/public/cost-benefits.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/cost-benefits.jpg
--------------------------------------------------------------------------------
/public/cry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/cry.png
--------------------------------------------------------------------------------
/public/epic-react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/epic-react.png
--------------------------------------------------------------------------------
/public/erased-from-existence.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/erased-from-existence.mp4
--------------------------------------------------------------------------------
/public/sob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/sob.png
--------------------------------------------------------------------------------
/public/standard/3-minutes-with-kent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/3-minutes-with-kent.png
--------------------------------------------------------------------------------
/public/standard/ama.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/ama.png
--------------------------------------------------------------------------------
/public/standard/astronaut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/astronaut.png
--------------------------------------------------------------------------------
/public/standard/big-smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/big-smile.png
--------------------------------------------------------------------------------
/public/standard/books.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/books.png
--------------------------------------------------------------------------------
/public/standard/boy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/boy.png
--------------------------------------------------------------------------------
/public/standard/dash-race-car.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/dash-race-car.png
--------------------------------------------------------------------------------
/public/standard/dash-reverse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/dash-reverse.png
--------------------------------------------------------------------------------
/public/standard/dog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/dog.png
--------------------------------------------------------------------------------
/public/standard/eggheadio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/eggheadio.png
--------------------------------------------------------------------------------
/public/standard/fem.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/fem.png
--------------------------------------------------------------------------------
/public/standard/gde.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/gde.png
--------------------------------------------------------------------------------
/public/standard/girl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/girl.png
--------------------------------------------------------------------------------
/public/standard/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/github.png
--------------------------------------------------------------------------------
/public/standard/house.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/house.png
--------------------------------------------------------------------------------
/public/standard/kcd-news.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/kcd-news.png
--------------------------------------------------------------------------------
/public/standard/medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/medium.png
--------------------------------------------------------------------------------
/public/standard/neutral-face.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/neutral-face.png
--------------------------------------------------------------------------------
/public/standard/office.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/office.png
--------------------------------------------------------------------------------
/public/standard/racing-car-reverse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/racing-car-reverse.png
--------------------------------------------------------------------------------
/public/standard/smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/smile.png
--------------------------------------------------------------------------------
/public/standard/speaking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/speaking.png
--------------------------------------------------------------------------------
/public/standard/trophy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/trophy.png
--------------------------------------------------------------------------------
/public/standard/twitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/twitch.png
--------------------------------------------------------------------------------
/public/standard/twitter.svg:
--------------------------------------------------------------------------------
1 | Twitter_Logo_Blue
--------------------------------------------------------------------------------
/public/standard/wave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/wave.png
--------------------------------------------------------------------------------
/public/standard/woman.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/woman.png
--------------------------------------------------------------------------------
/public/standard/workshopme.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/workshopme.png
--------------------------------------------------------------------------------
/public/standard/youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/standard/youtube.png
--------------------------------------------------------------------------------
/public/sweat-smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/sweat-smile.png
--------------------------------------------------------------------------------
/public/what-if.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kentcdodds/simply-react/82124c414b42c20fe98d22d695188e328e265d61/public/what-if.jpg
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | if (typeof document !== 'undefined') {
2 | require('style-loader!css-loader!codemirror/lib/codemirror.css')
3 | require('style-loader!css-loader!./cm-night-owl.css')
4 | require('style-loader!css-loader!./styles.css')
5 | require('codemirror/mode/javascript/javascript')
6 | require('codemirror/mode/jsx/jsx')
7 |
8 | // make it easier to navigate the slides via the keyboard
9 | document.body.tabIndex = '-1'
10 | window.addEventListener('keyup', e => {
11 | if (e.key === 'Escape') {
12 | document.body.focus()
13 | }
14 | })
15 | }
16 |
--------------------------------------------------------------------------------
/styles.css:
--------------------------------------------------------------------------------
1 | .zIEGn {
2 | position: relative;
3 | }
4 |
5 | .react-codemirror2 {
6 | margin-top: 18px;
7 | margin-bottom: 18px;
8 | }
9 |
10 | .react-codemirror2:first-child {
11 | margin-top: 0;
12 | }
13 |
14 | .react-codemirror2:last-child {
15 | margin-bottom: 0;
16 | }
17 |
18 | .CodeMirror {
19 | height: unset;
20 | margin-bottom: 18px;
21 | padding: 14px;
22 | }
23 |
24 | .CodeMirror pre {
25 | font-variant-ligatures: none;
26 | }
27 |
28 | pre {
29 | text-align: left;
30 | }
31 |
32 | a {
33 | color: #addb67;
34 | }
35 |
36 | * {
37 | letter-spacing: unset;
38 | }
39 |
--------------------------------------------------------------------------------
/theme.js:
--------------------------------------------------------------------------------
1 | import baseTheme from 'mdx-deck/themes'
2 |
3 | export default {
4 | ...baseTheme,
5 | colors: {
6 | ...baseTheme.colors,
7 | text: '#d6deeb',
8 | background: '#011627',
9 | link: '#addb67',
10 | },
11 | }
12 |
--------------------------------------------------------------------------------