Skip to content

Instantly share code, notes, and snippets.

@selfup
Created October 20, 2017 12:49
Show Gist options
  • Save selfup/7f2d912f37f8d0190594b72aa47bbdb7 to your computer and use it in GitHub Desktop.
Save selfup/7f2d912f37f8d0190594b72aa47bbdb7 to your computer and use it in GitHub Desktop.
import { app } from 'hyperapp'
import { main, nav, section, h1, button, a, p, span } from '@hyperapp/html'
const Route = props => {
const match = props.exact
? location.pathname === props.path
: location.pathname.match(props.path)
return props.render
? match && props.render({ path: props.path })
: match && section(props.view)
}
const Redirect = props => {
// You can resolve the skipped render by triggering the update on the next tick
// but you do see a flash of guarded content
props.when && history.replaceState(null, null, props.to)
// props.when && setTimeout(() => history.replaceState(null, null, props.to), 0)
}
const Home = [h1('Home Page')]
const Login = [h1('Login Page')]
const Todos = [h1('Todos Page')]
const Todo = [h1('Todo Page')]
app({
state: {},
actions: {
update: () => {
console.log('Updating state path to', location.pathname)
return { path: location.pathname }
},
auth: () => ({ user: 'Joe Bloggs' }),
deauth: () => ({ user: null }),
rerender: () => ({ rand: Math.random() }),
},
view: (state, actions) =>
main([
nav([
a({ href: '/' }, 'Home'),
a({ href: '/login' }, 'Login'),
a({ href: '/todos' }, 'Todos'),
a({ href: '/todos/1' }, 'Todo'),
button({ onclick: actions.auth }, 'AUTH'),
button({ onclick: actions.deauth }, 'DEAUTH'),
state.user && p(`Logged in as ${state.user}`),
]),
Route({ exact: true, path: '/', view: Home }),
Route({ exact: true, path: '/login', view: Login }),
Route({
path: '/todos',
render: () => [
Redirect({ to: '/login', when: !state.user }),
span([
p(`
You shouldnt see me if you arent authed.
Redirect should have called history.replaceState which calls update.
You can see that the window pathname ${location.pathname} and state path ${state.path} are equal.
But you will not see the represented in the view until you call another action.
Or use setTimout on the update, or remove skipRender from hyperapp core.
`),
button(
{ onclick: actions.rerender },
'Trigger a re-render (random action)'
),
]),
Route({ exact: true, path: '/todos', view: Todos }),
Route({ path: '/todos/1', view: Todo }),
],
}),
]),
init: (state, actions) => {
// Calling pushstate triggers a state update
var pushState = history.pushState
history.pushState = function() {
pushState.apply(history, arguments)
actions.update()
}
// Calling replaceState triggers a state update
var replaceState = history.replaceState
history.replaceState = function() {
replaceState.apply(history, arguments)
actions.update()
}
// Listen to clicks on links and call pushstate
addEventListener('click', e => {
const link = e.target.tagName === 'A'
const path = e.target.getAttribute('href')
if (link && path && path.startsWith('/')) {
history.pushState(null, null, path)
e.preventDefault()
}
})
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment