preact-router example

by Jason Miller

HTML

<script src="https://unpkg.com/preact"></script>
<script src="https://npmcdn.com/preact-router"></script>

SCSS

body {
	padding-top: 60px;
	font: 14px/1.21 'Helvetica Neue',arial;
}

.modal {
  position: fixed;
  left: 0;
  top: 0;
  width: 400px;
  padding: 20px;
  background: #fff;
  box-shadow: 0 20px 50px rgba(0,0,0,0.4);
  z-index: 999;
  max-height: 50vh;
  overflow: auto;
  
  &::before {
    position: fixed;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
    background: rgba(0,0,0,0.5);
    z-index: -1;
  }
}

header {
	position: fixed;
	left: 0;
	top: 0;
	width: 100%;
	height: 56px;
	background: #2f9c76;
	line-height: 56px;
	box-shadow: 0 0 5px rgba(0,0,0,0.5);
	
	nav {
		display: inline-block;
		padding: 0 10px;
	}
	nav a {
		display: inline-block;
		padding: 0 10px;
		color: #FFF;
		font-size: 18px;
		font-weight: 300;
		letter-spacing: 0.05em;
		text-decoration: none;
		cursor: pointer;
		&:hover {
			background-color: rgba(255,255,255,0.2);
		}
	}
}

input {
	background: #FFF;
	border: 2px solid #ccc;
	line-height: 1.3 !important;
	padding: 5px 10px;
	font: inherit;
	font-size: 100%;
	border-radius: 5px;
	outline: none;
	&:focus { border-color: #0f7c56; }
}

section {
	display: block;
	margin: 20px auto;
	padding: 50px;
	max-width: 300px;
	background: #FAFAFA;
	box-shadow: 0 1px 5px rgba(0,0,0,0.3);
	border-radius: 3px;
}

Babel + JSX

const { h, Component, render } = preact; /** @jsx h */
const { Router, route } = preactRouter;

history.replaceState(0,0,'/');  // jsfiddle url defaults to `/_display`

function search(query) {
	route(`/profile?q=${encodeURIComponent(query)}`);
}

/** Stateless app */
const App = () => (
	<div class="app">
		<Header />
		<Router>
			<Home path="/" />
			<Profile path="/profile/:user?" />
			<Error type="404" default />
		</Router>
	</div>
);

/** demo header nav+search */
const Header = () => (
	<header>
		<nav>
			<a href="/">Home</a>
			<a href="/profile">Profile</a>
			<a href="/profile/john">John</a>
			<a href="/asdf">Error</a>
		</nav>
		<input type="search" placeholder="Search..." onSearch={e => search(e.target.value)} />
	</header>
);

/** our index route */
class Home extends Component {
	setText = e => {
		this.setState({ text: e.target.value });
	};
	render({ }, { text='Some Text' }) {
		return (
			<section class="home">
				<input value={text} onInput={this.setText} />
				<div>In caps: {text.toUpperCase()}</div>
			</section>
		);
	}
}

/** handles /profile and /profile/:user */
const Profile = ({ user, ...props }) => (
	<section class="profile">
		<h2>Profile: {user || 'you'}</h2>
		<p>This is some text about {user || 'you'}.</p>
		<pre>{ JSON.stringify({ user, ...props },0,'  ') }</pre>
	</section>
);

/** fall-back route (handles unroutable URLs) */
const Error = ({ type, url }) => (
	<section class="error">
		<h2>Error {type}</h2>
		<p>It looks like we hit a snag.</p>
		<pre>{url}</pre>
	</section>
);

render(<App />, document.body);