1
1
mirror of https://github.com/jxnblk/mdx-deck.git synced 2024-10-26 07:37:23 +03:00

Adjust steps implementation and presenter mode

This commit is contained in:
Brent Jackson 2020-01-17 17:23:49 -05:00
parent 12ac79128a
commit e87f63c01a
12 changed files with 209 additions and 27 deletions

View File

@ -9,7 +9,7 @@
"scripts": {
"__start": "yarn workspace @mdx-deck/docs start",
"start": "yarn workspace @mdx-deck/lite start",
"build": "yarn workspace @mdx-deck/docs build",
"build": "yarn workspace @mdx-deck/lite build",
"export": "./packages/export/cli.js http://localhost:8000/print -o docs/public/deck.pdf",
"cypress:open": "cypress open",
"cypress:run": "cypress run",

View File

@ -3,7 +3,15 @@
Lightweight alternative to core mdx-deck
- No steps
- ~~No steps~~
- No print mode
- No export
- No layouts
---
- [ ] presenter styles
- [ ] overview styles
- [ ] timer
- [ ] clock
- [ ] local images

View File

@ -18,6 +18,7 @@
"@mdx-js/mdx": "^1.5.3",
"gatsby-page-utils": "^0.0.37",
"gatsby-plugin-react-helmet": "^3.1.18",
"hhmmss": "^1.0.0",
"react-helmet": "^5.2.1",
"remark-emoji": "^2.0.2",
"remark-images": "^1.0.0",

View File

@ -0,0 +1,17 @@
import React from 'react'
export default props => {
const [time, setTime] = React.useState(new Date().toLocaleTimeString())
React.useEffect(() => {
const timer = setInterval(() => {
const now = new Date()
setTime(now.toLocaleTimeString())
}, 1000)
return () => {
clearInterval(timer)
}
}, [])
return time
}

View File

@ -1,5 +1,7 @@
/** @jsx jsx */
import { jsx } from 'theme-ui'
import React from 'react'
import useSteps from './use-steps'
const createComponent = key => {
const Component = () => false
@ -41,3 +43,50 @@ export const Invert = props =>
color='background'
bg='text'
/>
export const Counter = ({ length = 4 }) => {
const step = useSteps(length)
return (
<pre>
{step} / {length}
</pre>
)
}
export const StepList = props => {
const list = React.Children.toArray(props.children)
.find(child => /^(ul|ol)$/.test(child.props.originalType))
// if (!list) return <div>{props.children}</div>
const items = React.Children.toArray(list && list.props.children)
const step = useSteps(items.length)
if (!list) return false
const children = items.map((item, i) => React.cloneElement(item, {
style: {
visibility: i < step ? 'visible' : 'hidden'
}
}))
return React.cloneElement(list, { children })
}
export const Appear = ({
target,
...props
}) => {
const children = React.Children.toArray(props.children)
const step = useSteps(children.length)
const styled = children.map((child, i) =>
React.cloneElement(child, {
style: {
visibility: i < step ? 'visible' : 'hidden',
}
})
)
return <React.Fragment>{styled}</React.Fragment>
}

View File

@ -1,11 +1,13 @@
/** @jsx jsx */
import { jsx } from 'theme-ui'
import { jsx, Box, Flex } from 'theme-ui'
import React from 'react'
import { Context, useDeck } from './context'
import modes from './modes'
import Header from './header'
import Footer from './footer'
import Slide from './slide'
import Clock from './clock'
import Timer from './timer'
const Main = ({
width = '100vw',
@ -16,7 +18,7 @@ const Main = ({
const outer = useDeck()
const context = {
...outer,
isMain: !preview,
main: !preview,
}
return (
@ -52,42 +54,62 @@ const Presenter = props => {
sx={{
display: 'flex',
height: '100vh',
bg: 'backdrop',
}}>
<div
sx={{
width: '60%',
height: '100vh',
padding: 3,
}}>
<Main
{...props}
width='100%'
height='100vh'>
height='100%'>
<Slide>
{props.slide}
</Slide>
</Main>
</div>
<div
<Flex
sx={{
flexDirection: 'column',
width: '40%',
height: '100vh',
padding: 3,
py: 3,
pr: 3,
overflowY: 'auto',
outline: '1px solid cyan',
}}>
<Slide
width='100%'
height='100vh'
zoom={1/2}
sx={{
outline: '1px solid tomato',
}}>
{next}
</Slide>
<div>
<div
sx={{
py: 3,
flex: '1 1 auto',
}}>
{props.notes}
</div>
</div>
<Flex
sx={{
fontFamily: '"Roboto Mono", Menlo, monospace',
}}>
<Box>
{props.index} / {props.slides.length - 1}
</Box>
<Box mx='auto' />
<Box>
<Timer />
{' '}
<Clock />
</Box>
</Flex>
</Flex>
</div>
)
}

View File

@ -10,16 +10,6 @@ import Container from './container'
import Slide from './slide'
import baseTheme from './theme'
/**
* - [ ] presenter styles
* - [ ] overview styles
* - [ ] timer/clock
* - [ ] Ditch layouts?
* - [ ] themes
* - [ ] base theme
* - [ ] test local images
*/
const getIndex = props => {
if (!props.location) return 0
const paths = props.location.pathname.split('/')
@ -29,7 +19,8 @@ const getIndex = props => {
export default props => {
const slides = split(props)
const index = getIndex(props)
// const index = getIndex(props)
const [index, setIndex] = React.useState(getIndex(props))
const { slug } = props.pageContext || {}
const slide = slides[index]
@ -45,6 +36,10 @@ export default props => {
lastIndex.current = index
}, [index])
// steps
const [step, setStep] = React.useState(0)
const [steps, setSteps] = React.useState(0)
const context = {
slides,
slug,
@ -56,23 +51,46 @@ export default props => {
setMode,
toggleMode,
notes: slide.notes,
step,
setStep,
steps,
setSteps,
}
/*
context.setIndex = fn => {
const n = typeof fn === 'function' ? fn(index) : fn
props.navigate('/' + n)
}
*/
context.previous = () => {
context.setIndex(n => n > 0 ? n - 1 : n)
if (steps && step > 0) {
setStep(n => n - 1)
} else {
setIndex(n => n > 0 ? n - 1 : n)
setStep(0)
setSteps(0)
}
}
context.next = () => {
context.setIndex(n => n < slides.length - 1 ? n + 1 : n)
if (step < steps) {
setStep(n => n + 1)
} else {
setIndex(n => n < slides.length - 1 ? n + 1 : n)
setStep(0)
setSteps(0)
}
}
React.useEffect(() => {
props.navigate('/' + index, {
replace: true,
})
}, [index])
const theme = merge(baseTheme, props.theme || {})
console.log(context)
// console.log(context)
return (
<Context.Provider value={context}>

View File

@ -18,6 +18,8 @@ export default ({
justifyContent: 'center',
overflow: 'hidden',
position: 'relative',
color: 'text',
bg: 'background',
variant: 'styles.Slide',
width,
height,

View File

@ -3,6 +3,7 @@ export default {
colors: {
text: '#fff',
background: '#000',
backdrop: '#111',
},
styles: {
root: {

View File

@ -0,0 +1,39 @@
/** @jsx jsx */
import { jsx } from 'theme-ui'
import React from 'react'
import hhmmss from 'hhmmss'
export default props => {
const [seconds, setSeconds] = React.useState(0)
const [active, setActive] = React.useState(false)
React.useEffect(() => {
const timer = setInterval(() => {
if (!active) return
setSeconds(n => n + 1)
}, 1000)
return () => {
clearInterval(timer)
}
}, [active])
return (
<button
onClick={e => {
setActive(!active)
if (active) setSeconds(0)
}}
title={active ? 'Stop Timer' : 'Start Timer'}
sx={{
appearance: 'none',
fontFamily: '"Roboto Mono", Menlo, monospace',
fontSize: 'inherit',
color: 'white',
bg: 'black',
border: 0,
padding: 2,
}}>
{hhmmss(seconds)}
</button>
)
}

View File

@ -0,0 +1,17 @@
import React from 'react'
import { useDeck } from './context'
export const useSteps = length => {
const context = useDeck()
React.useEffect(() => {
if (!context.main) return
context.setSteps(length)
if (context.direction < 0) context.setStep(length)
}, [length])
if (!context.main) return length
return context.step
}
export default useSteps

View File

@ -21,8 +21,12 @@ These are top-secret speaker notes. Shhhh!
### What's New
<StepList>
- Simplified API
- No steps
- Refactored internals
</StepList>
---
@ -36,6 +40,10 @@ Stand clear of the closing doors
---
<Counter />
---
```jsx
import React from 'react'