Skip to content

Instantly share code, notes, and snippets.

@zaceno
Created September 11, 2018 19:12
Show Gist options
  • Save zaceno/5882691f810be89d0a0df0d58bec1d0e to your computer and use it in GitHub Desktop.
Save zaceno/5882691f810be89d0a0df0d58bec1d0e to your computer and use it in GitHub Desktop.
HAV2 Intro - example 11
<!doctype html>
<html>
<head>
<style>
.gauge {
position: relative;
padding: 0;
border: 1px #555 solid;
background-color: #aaa;
width: 200px;
height: 40px;
border-radius: 4px;
overflow: hidden;
}
.gauge-meter {
position: absolute;
padding: 0;
margin: 0;
top: 0;
left: 0;
bottom: 0;
width: 62%;
background-color: hotpink;
}
.gauge-text {
position: absolute;
margin: 0;
padding: 0;
line-height: 40px;
font-size: 25px;
text-align: center;
top: 0;
left: 0;
bottom: 0;
width: 100%;
color: #fff;
text-shadow: #000 0px -1px 1px;
z-index: 1000;
}
</style>
<script defer type="module">
import {h, app} from "https://rawgit.com/hyperapp/hyperapp/V2/src/index.js"
const DURATION = 15000 //ms = 15s
const AnimationFrame = (() => {
const effect = (props, dispatch) => {
var frameId
const onFrame = (timestamp) => {
dispatch(props.action, timestamp)
nextFrame()
}
const nextFrame = () => {
frameId = requestAnimationFrame(onFrame)
}
nextFrame()
return () => cancelAnimationFrame(frameId)
}
return props => ({effect, ...props})
})()
const Alert = (() => {
const effect = (props, dispatch) => {
alert(props.message)
}
return props => ({effect, ...props})
})()
const Start = (state, event) => {
if (state.mode !== 'stopped') return
return {
mode: 'running',
startedTime: event.timeStamp,
remainingTime: DURATION,
duration: DURATION,
}
}
const Pause = state => {
if (state.mode !== 'running') return
return {
...state,
mode: 'paused',
}
}
const Continue = (state, event) => {
if (state.mode !== 'paused') return
return {
...state,
mode: 'running',
startedTime: event.timeStamp,
duration: state.remainingTime,
}
}
const Cancel = state => {
return {
...state,
mode: 'stopped'
}
}
const UpdateTime = (state, timestamp) => {
if (state.mode !== 'running') return
if (state.remainingTime < 0) return Cancel(state)
return {
...state,
remainingTime: state.duration - (timestamp - state.startedTime)
}
}
const Gauge = (props, children) => h('div', { class: 'gauge'}, [
h('div', {
class: 'gauge-meter',
style: {
width: (
props.active
? (100 * props.fraction) + '%'
: '100%'
),
}
}),
props.active && h('p', { class: 'gauge-text'}, children)
])
const TimerControls = ({mode, timer}) => h('p', {}, [
mode === 'stopped'
? h('button', {onClick: [StartX, {timer}] }, ['START'])
: h('button', {onClick: [CancelX, {timer}] }, ['CANCEL']),
mode === 'paused'
? h('button', {onClick: [ContinueX, {timer}] }, ['CONT.'])
: h('button', {
disabled: mode === 'stopped',
onClick: [PauseX, {timer}]
}, ['PAUSE']),
])
const timerAction = (action, state, param, data) => {
const returnValue = action(state[param.timer], data)
if (!returnValue) return
return {
...state,
[param.timer]: { ...returnValue },
}
}
const StartX = (...arg) => timerAction(Start, ...arg)
const CancelX = (...arg) => timerAction(Cancel, ...arg)
const PauseX = (...arg) => timerAction(Pause, ...arg)
const ContinueX = (...arg) => timerAction(Continue, ...arg)
const UpdateTimeX = (state, param, timestamp) => {
const nextState = timerAction(UpdateTime, state, param, timestamp)
const prevMode = state[param.timer].mode
const nextMode = nextState[param.timer].mode
if (prevMode === 'running' && nextMode === 'stopped') {
return [ nextState, Alert({ message: `Timer ${param.timer === 'timer1' ? 'A' : 'B'} timed out!` }) ]
} else {
return nextState
}
}
app({
init: state => ({
timer1: {
mode: 'stopped'
},
timer2: {
mode: 'stopped'
}
}),
view: state => h('table', {}, [
h('tr', {}, [
h('td', {}, ['A']),
h('td', {}, [
h(
Gauge,
{
active: state.timer1.mode !== 'stopped',
fraction: state.timer1.remainingTime / DURATION,
},
[
Math.ceil(state.timer1.remainingTime / 1000),
' s'
]
)
]),
h('td', {}, [
h(TimerControls, {mode: state.timer1.mode, timer: 'timer1'}),
])
]),
h('tr', {}, [
h('td', {}, ['B']),
h('td', {}, [
h(
Gauge,
{
active: state.timer2.mode !== 'stopped',
fraction: state.timer2.remainingTime / DURATION,
},
[
Math.ceil(state.timer2.remainingTime / 1000),
' s'
]
)
]),
h('td', {}, [
h(TimerControls, {mode: state.timer2.mode, timer: 'timer2'}),
])
]),
]),
container: document.body,
subscriptions: state => [
state.timer1.mode === 'running' && AnimationFrame({action: [UpdateTimeX, {timer: 'timer1'}] }),
state.timer2.mode === 'running' && AnimationFrame({action: [UpdateTimeX, {timer: 'timer2'}] }),
]
})
</script>
</head>
<body></body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment