Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
aladinet committed Jun 15, 2020
0 parents commit 5fff598
Show file tree
Hide file tree
Showing 25 changed files with 355 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"env": {
"test": {
"presets": [
["preact-cli/babel", { "modules": "commonjs" }]
]
}
}
}
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
/build
/*.log
*.lock
.env
.env.build
2 changes: 2 additions & 0 deletions .nowignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
README.md
yarn.lock
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
![Preact Logo](https://github.com/vercel/vercel/blob/master/packages/frameworks/logos/preact.svg)

# Preact Example

This directory is a brief example of a [Preact](https://preactjs.com/) app that can be deployed with Vercel and zero configuration.

## Deploy Your Own

Deploy your own Preact project with Vercel.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/vercel/tree/master/examples/preact)

_Live Example: https://preact.now-examples.now.sh_

### How We Created This Example

To get started with Preact for deployment with Vercel, you can use the [Preact CLI](https://github.com/preactjs/preact-cli) to initialize the project:

```shell
$ preact create default my-project
```

### Deploying From Your Terminal

You can deploy your new Preact project with a single command from your terminal using [Vercel CLI](https://vercel.com/download):

```shell
$ vercel
```
60 changes: 60 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"private": true,
"name": "preact",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "per-env",
"start:production": "npm run -s serve",
"start:development": "npm run -s dev",
"build": "preact build",
"serve": "preact build && preact serve",
"dev": "preact watch --port $PORT",
"lint": "eslint src",
"test": "jest"
},
"devDependencies": {
"eslint": "^4.9.0",
"eslint-config-synacor": "^2.0.2",
"identity-obj-proxy": "^3.0.0",
"per-env": "^1.0.2",
"jest": "^21.2.1",
"preact-cli": "^2.1.0",
"preact-render-spy": "^1.2.1"
},
"dependencies": {
"preact": "^8.2.6",
"preact-compat": "^3.17.0",
"preact-render-to-string": "^4.1.0",
"preact-router": "^2.5.7"
},
"jest": {
"verbose": true,
"setupFiles": [
"<rootDir>/tests/__mocks__/browserMocks.js"
],
"testRegex": "(/(__tests__|tests)/.*|(\\.|/)(test|spec))\\.jsx?$",
"testPathIgnorePatterns": [
"/node_modules/",
"<rootDir>/tests/__mocks__/*"
],
"testURL": "http://localhost:8080",
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"node_modules"
],
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tests/__mocks__/fileMock.js",
"\\.(css|less|scss)$": "identity-obj-proxy",
"^./style$": "identity-obj-proxy",
"^preact$": "<rootDir>/node_modules/preact/dist/preact.min.js",
"^react$": "preact-compat",
"^react-dom$": "preact-compat",
"^create-react-class$": "preact-compat/lib/create-react-class",
"^react-addons-css-transition-group$": "preact-css-transition-group"
}
}
}
Binary file added src/assets/favicon.ico
Binary file not shown.
Binary file added src/assets/icons/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/mstile-150x150.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions src/components/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { h, Component } from 'preact';
import { Router } from 'preact-router';

import Header from './header';

// Code-splitting is automated for routes
import Home from '../routes/home';
import Profile from '../routes/profile';

export default class App extends Component {
/** Gets fired when the route changes.
* @param {Object} event "change" event from [preact-router](http://git.io/preact-router)
* @param {string} event.url The newly routed URL
*/
handleRoute = e => {
this.currentUrl = e.url;
};

render() {
return (
<div id="app">
<Header />
<Router onChange={this.handleRoute}>
<Home path="/" />
<Profile path="/profile/" user="me" />
<Profile path="/profile/:user" />
</Router>
</div>
);
}
}
22 changes: 22 additions & 0 deletions src/components/header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { h } from 'preact';
import { Link } from 'preact-router/match';
import style from './style';

const Header = () => (
<header class={style.header}>
<h1>Preact App</h1>
<nav>
<Link activeClassName={style.active} href="/">
Home
</Link>
<Link activeClassName={style.active} href="/profile">
Me
</Link>
<Link activeClassName={style.active} href="/profile/john">
John
</Link>
</nav>
</header>
);

export default Header;
48 changes: 48 additions & 0 deletions src/components/header/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.header {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 56px;
padding: 0;
background: #673AB7;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
z-index: 50;
}

.header h1 {
float: left;
margin: 0;
padding: 0 15px;
font-size: 24px;
line-height: 56px;
font-weight: 400;
color: #FFF;
}

.header nav {
float: right;
font-size: 100%;
}

.header nav a {
display: inline-block;
height: 56px;
line-height: 56px;
padding: 0 15px;
min-width: 50px;
text-align: center;
background: rgba(255,255,255,0);
text-decoration: none;
color: #FFF;
will-change: background-color;
}

.header nav a:hover,
.header nav a:active {
background: rgba(0,0,0,0.2);
}

.header nav a.active {
background: rgba(0,0,0,0.4);
}
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import './style';
import App from './components/app';

export default App;
21 changes: 21 additions & 0 deletions src/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "preact",
"short_name": "preact",
"start_url": "/",
"display": "standalone",
"orientation": "portrait",
"background_color": "#fff",
"theme_color": "#673ab8",
"icons": [
{
"src": "/assets/icons/android-chrome-192x192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/assets/icons/android-chrome-512x512.png",
"type": "image/png",
"sizes": "512x512"
}
]
}
11 changes: 11 additions & 0 deletions src/routes/home/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { h } from 'preact';
import style from './style';

const Home = () => (
<div class={style.home}>
<h1>Home</h1>
<p>This is the Home component.</p>
</div>
);

export default Home;
5 changes: 5 additions & 0 deletions src/routes/home/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.home {
padding: 56px 20px;
min-height: 100%;
width: 100%;
}
46 changes: 46 additions & 0 deletions src/routes/profile/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { h, Component } from 'preact';
import style from './style';

export default class Profile extends Component {
state = {
time: Date.now(),
count: 10,
};

// update the current time
updateTime = () => {
this.setState({ time: Date.now() });
};

increment = () => {
this.setState({ count: this.state.count + 1 });
};

// gets called when this route is navigated to
componentDidMount() {
// start a timer for the clock:
this.timer = setInterval(this.updateTime, 1000);
}

// gets called just before navigating away from the route
componentWillUnmount() {
clearInterval(this.timer);
}

// Note: `user` comes from the URL, courtesy of our router
render({ user }, { time, count }) {
return (
<div class={style.profile}>
<h1>Profile: {user}</h1>
<p>This is the user profile for a user named {user}.</p>

<div>Current time: {new Date(time).toLocaleString()}</div>

<p>
<button onClick={this.increment}>Click Me</button> Clicked {count}{' '}
times.
</p>
</div>
);
}
}
5 changes: 5 additions & 0 deletions src/routes/profile/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.profile {
padding: 56px 20px;
min-height: 100%;
width: 100%;
}
20 changes: 20 additions & 0 deletions src/style/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
background: #FAFAFA;
font-family: 'Helvetica Neue', arial, sans-serif;
font-weight: 400;
color: #444;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

* {
box-sizing: border-box;
}

#app {
height: 100%;
}
21 changes: 21 additions & 0 deletions tests/__mocks__/browserMocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Mock Browser API's which are not supported by JSDOM, e.g. ServiceWorker, LocalStorage
/**
* An example how to mock localStorage is given below 👇
*/

/*
// Mocks localStorage
const localStorageMock = (function() {
let store = {};
return {
getItem: (key) => store[key] || null,
setItem: (key, value) => store[key] = value.toString(),
clear: () => store = {}
};
})();
Object.defineProperty(window, 'localStorage', {
value: localStorageMock
}); */
3 changes: 3 additions & 0 deletions tests/__mocks__/fileMocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// This fixed an error related to the CSS and loading gif breaking my Jest test
// See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
module.exports = 'test-file-stub';
12 changes: 12 additions & 0 deletions tests/header.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Header from '../src/components/header';
import { Link } from 'preact-router/match';
// See: https://github.com/mzgoddard/preact-render-spy
import { shallow } from 'preact-render-spy';

describe('Initial Test of the Header', () => {
test('Header renders 3 nav items', () => {
const context = shallow(<Header />);
expect(context.find('h1').text()).toBe('Preact App');
expect(context.find(<Link />).length).toBe(3);
});
});

0 comments on commit 5fff598

Please sign in to comment.