add readme

This commit is contained in:
Sara Vieira
2018-01-14 16:57:25 +00:00
parent f28f8454f5
commit f49fb3d073
14 changed files with 1797 additions and 724 deletions

17
.prettierrc Normal file
View File

@@ -0,0 +1,17 @@
{
"singleQuote": true,
"trailingComma": "es5",
"useTabs": false,
"semi": false,
"overrides": [
{
"files": "*.md",
"options": {
"printWidth": 70,
"useTabs": false,
"trailingComma": "none",
"proseWrap": false
}
}
]
}

7
.travis.yml Normal file
View File

@@ -0,0 +1,7 @@
language: node_js
cache:
directories:
- node_modules
yarn: true
node_js:
- 8

35
Contributing.md Normal file
View File

@@ -0,0 +1,35 @@
# How to contribute
We love pull requests. And following this guidelines will make your pull request easier to merge.
If you want to contribute but dont know what to do, take a look at these two labels: [help wanted](https://github.com/SaraVieira/uber-cities/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) and [good first issue](https://github.com/SaraVieira/uber-cities/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
## Prerequisites
* If its your first pull request, watch [this amazing course](http://makeapullrequest.com/) by [Kent C. Dodds](https://twitter.com/kentcdodds).
* Install [EditorConfig](http://editorconfig.org/) plugin for your code editor to make sure it uses correct settings.
* Fork the repository and clone your fork.
* Install dependencies: `npm install`.
## Development workflow
Run linters:
```bash
npm lint
```
**Dont forget to add tests and update documentation for your changes.**
**Please update npm lock file (`yarn.lock`) if you add or update dependencies.**
## Other notes
* If you have commit access to repository and want to make big change or not sure about something, make a new branch and open pull request.
* Were using [Prettier](https://github.com/prettier/prettier) to format JavaScript, so dont worry much about code formatting.
* Dont commit generated files, like minified JavaScript.
* Dont change version number and change log.
## Need help?
Feel free to ask.

9
License.md Normal file
View File

@@ -0,0 +1,9 @@
# The MIT License
Copyright 2018 Sara Vieira (https://iamsaravieira.com), contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,19 +1,25 @@
# Is there Uber In ? # Is there Uber In ?
## CLI Commands [![Build Status](https://travis-ci.org/SaraVieira/uber-cities.svg)](https://travis-ci.org/SaraVieira/uber-cities)
``` bash Check if there is an uber in the town you input
# install dependencies
yarn install
# serve with hot reload at localhost:8080 Also checks for lyft, cabify and taxify
yarn dev
# build for production with minification ## Why ?
yarn build
I keep googling this on the internet and also in portugal uber's webiste is blocked
## Built With
* Preact
* Styled Components
* react-confetti
* styled-is
## Run Locally
# test the production build locally
yarn serve
``` ```
yarn
For detailed explanation on how things work, checkout the [CLI Readme](https://github.com/developit/preact-cli/blob/master/README.md). yarn dev
```

View File

@@ -5,35 +5,52 @@
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"start": "if-env NODE_ENV=production && npm run -s serve || npm run -s dev", "start": "if-env NODE_ENV=production && npm run -s serve || npm run -s dev",
"build": "preact build", "build": "preact build -p --template src/template.html",
"serve": "preact build && preact serve", "serve": "preact build && preact serve",
"dev": "preact watch", "dev": "preact watch",
"lint": "eslint src" "test": "eslint src",
"format": "prettier --write 'src/**/*.{js,css,md}'",
"posttest": "npm run format",
"precommit": "lint-staged"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "eslint-config-synacor" "extends": [
"eslint-config-synacor",
"prettier"
],
"rules": {
"react/display-name": "off",
"react/no-did-mount-set-state": "off"
}
}, },
"eslintIgnore": [ "eslintIgnore": [
"build/*" "build/*"
], ],
"devDependencies": { "devDependencies": {
"eslint": "^4.15.0", "eslint": "^4.15.0",
"eslint-config-synacor": "^1.1.0", "eslint-config-prettier": "^2.9.0",
"eslint-config-synacor": "^2.0.4",
"husky": "^0.14.3",
"if-env": "^1.0.0", "if-env": "^1.0.0",
"preact-cli": "^2.0.0", "lint-staged": "^6.0.0",
"preact-cli": "^2.1.1",
"prettier": "^1.10.2" "prettier": "^1.10.2"
}, },
"dependencies": { "dependencies": {
"axios": "^0.17.1",
"capitalize": "^1.0.0", "capitalize": "^1.0.0",
"preact": "^8.2.1", "preact": "^8.2.7",
"preact-compat": "^3.17.0", "preact-compat": "^3.17.0",
"preact-router": "^2.5.5", "preact-router": "^2.6.0",
"react-confetti": "^2.0.1", "react-confetti": "^2.0.2",
"react-sizeme": "^2.3.6", "react-sizeme": "^2.3.6",
"react-styled-flexboxgrid": "^2.1.1", "react-styled-flexboxgrid": "^2.1.1",
"styled-components": "^2.2.3", "styled-components": "^2.4.0",
"styled-is": "^1.1.0", "styled-is": "^1.1.0"
"styled-loaders": "^0.2.1" },
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
} }
} }

View File

@@ -1,6 +0,0 @@
import axios from 'axios';
export default axios.create({
baseURL: 'https://isthereuber-db.now.sh/cities',
timeout: 2000
});

View File

@@ -1,28 +1,26 @@
import { h, Component } from 'preact'; import { h, Component } from 'preact'
import { Router } from 'preact-router'; import { Router } from 'preact-router'
import Home from 'async!../routes/home'
import Home from 'async!../routes/home'; import City from 'async!../routes/city'
import City from 'async!../routes/city';
export default class App extends Component { 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
}
/** Gets fired when the route changes. render() {
* @param {Object} event "change" event from [preact-router](http://git.io/preact-router) return (
* @param {string} event.url The newly routed URL <div id="app">
*/ <Router onChange={this.handleRoute}>
handleRoute = e => { <Home path="/" />
this.currentUrl = e.url; <City path="/:city" />
}; </Router>
</div>
render() { )
return ( }
<div id="app">
<Router onChange={this.handleRoute}>
<Home path="/" />
<City path="/:city" />
</Router>
</div>
);
}
} }

View File

@@ -1,11 +1,11 @@
import uber from './uber.json'; import uber from './uber.json'
import lyft from './lyft.json'; import lyft from './lyft.json'
import cabify from './cabify.json'; import cabify from './cabify.json'
import taxify from './taxify.json'; import taxify from './taxify.json'
export default [ export default [
...uber.cities.map(u => ({ ...u, company: 'uber' })), ...uber.cities.map(u => ({ ...u, company: 'uber' })),
...lyft.cities.map(u => ({ ...u, company: 'lyft' }),), ...lyft.cities.map(u => ({ ...u, company: 'lyft' })),
...cabify.cities.map(u => ({ ...u, company: 'cabify' })), ...cabify.cities.map(u => ({ ...u, company: 'cabify' })),
...taxify.cities.map(u => ({ ...u, company: 'taxify' })) ...taxify.cities.map(u => ({ ...u, company: 'taxify' })),
]; ]

View File

@@ -1,6 +1,6 @@
import App from './components/app'; import App from './components/app'
import styled, { ThemeProvider, injectGlobal } from 'styled-components'; import styled, { ThemeProvider, injectGlobal } from 'styled-components'
import { Grid } from 'react-styled-flexboxgrid'; import { Grid } from 'react-styled-flexboxgrid'
injectGlobal` injectGlobal`
@import url('https://fonts.googleapis.com/css?family=Roboto'); @import url('https://fonts.googleapis.com/css?family=Roboto');
@@ -25,28 +25,30 @@ injectGlobal`
#app { #app {
height: 100%; height: 100%;
} }
`; `
const theme = { const theme = {
primary: '#4a0072', primary: '#4a0072',
secondary: '#e8eaf6', secondary: '#e8eaf6',
white: '#fafafa', white: '#fafafa',
black: '#3a3a3a' black: '#3a3a3a',
}; }
const Wrapper = styled.div` const Wrapper = styled.div`
background: ${props => props.theme.primary}; background: ${props => props.theme.primary};
height: 100%; height: 100%;
`; `
const System = styled(Grid)`height: 100%;`; const System = styled(Grid)`
height: 100%;
`
export default () => ( export default () => (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<Wrapper> <Wrapper>
<System> <System>
<App /> <App />
</System> </System>
</Wrapper> </Wrapper>
</ThemeProvider> </ThemeProvider>
); )

View File

@@ -1,124 +1,129 @@
import { h, Component } from 'preact'; import { h, Component } from 'preact'
import data from '../../data/index.js'; import data from '../../data/index.js'
import sizeMe from 'react-sizeme'; import sizeMe from 'react-sizeme'
import styled from 'styled-components'; import styled from 'styled-components'
import Confetti from 'react-confetti'; import Confetti from 'react-confetti'
import capitalize from 'capitalize'; import capitalize from 'capitalize'
import is from 'styled-is'; import is from 'styled-is'
const Title = styled.h1` const Title = styled.h1`
color: ${props => props.theme.secondary}; color: ${props => props.theme.secondary};
font-size: 80px; font-size: 80px;
`; `
const Subtitle = styled.h2` const Subtitle = styled.h2`
color: ${props => props.theme.secondary}; color: ${props => props.theme.secondary};
font-size: 40px; font-size: 40px;
`; `
const Wrapper = styled.div` const Wrapper = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
`; `
const Flex = styled.div` const Flex = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
a:not(:last-child) { a:not(:last-child) {
padding-right: 20px; padding-right: 20px;
} }
${is('row')` ${is('row')`
flex-direction: row; flex-direction: row;
`}; `};
`; `
const Link = styled.a` const Link = styled.a`
color: white; color: white;
z-index: 99; z-index: 99;
position: relative; position: relative;
font-size: 24px; font-size: 24px;
text-decoration: none; text-decoration: none;
`; `
const fixName = name => const fixName = name =>
name name
.split('-') .split('-')
.join(' ') .join(' ')
.toLowerCase(); .toLowerCase()
const getLink = (link, company) => { const getLink = (link, company) => {
if (company === 'taxify') { if (company === 'taxify') {
return `https://taxify.eu${link}`; return `https://taxify.eu${link}`
} }
if (company === 'cabify') { if (company === 'cabify') {
return `https://cabify.com${link}`; return `https://cabify.com${link}`
} }
if (company === 'lyft') { if (company === 'lyft') {
return `https://www.lyft.com${link}`; return `https://www.lyft.com${link}`
} }
}; }
class City extends Component { class City extends Component {
state = { state = {
cities: [] cities: [],
}; }
componentDidMount() { componentDidMount() {
const { city } = this.props; const { city } = this.props
const cities = data.filter(c => c.name.toLowerCase().includes(fixName(city))); const cities = data.filter(c =>
c.name.toLowerCase().includes(fixName(city))
)
this.setState({ cities }); this.setState({ cities })
} }
// Note: `user` comes from the URL, courtesy of our router // Note: `user` comes from the URL, courtesy of our router
render({ city, size }, { cities, loading }) { render({ city, size }, { cities, loading }) {
const uber = cities.filter(c => c.company === 'uber'); const uber = cities.filter(c => c.company === 'uber')
const other = cities.filter(c => c.company !== 'uber'); const other = cities.filter(c => c.company !== 'uber')
return ( return (
<Wrapper> <Wrapper>
<Flex> <Flex>
{uber.length ? ( {uber.length ? (
[ [
<Wrapper> <Wrapper>
<Confetti {...size} /> <Confetti {...size} />
</Wrapper>, </Wrapper>,
<Title>YES 🚘</Title> <Title>YES 🚗</Title>,
] ]
) : ( ) : (
<Title>NO 😕</Title> <Title>NO 😕</Title>
)} )}
{other.length ? ( {other.length ? (
<div> <div>
{uber.length ? {uber.length ? (
<Subtitle>There is also</Subtitle> : <Subtitle>There is also</Subtitle>
<Subtitle>But there is</Subtitle> ) : (
} <Subtitle>But there is</Subtitle>
)}
<Flex row> <Flex row>
{other.map(c => ( {other.map(c => (
<Link href={getLink(c.link, c.company)}>{capitalize(c.company)}</Link> <Link href={getLink(c.link, c.company)}>
))} {capitalize(c.company)}
</Flex> </Link>
</div> ))}
) : null} </Flex>
</Flex> </div>
</Wrapper> ) : null}
); </Flex>
} </Wrapper>
)
}
} }
export default sizeMe({ export default sizeMe({
monitorHeight: true, monitorHeight: true,
monitorWidth: true monitorWidth: true,
})(City); })(City)

View File

@@ -1,96 +1,96 @@
import { h, Component } from 'preact'; import { h, Component } from 'preact'
import { route } from 'preact-router'; import { route } from 'preact-router'
import styled from 'styled-components'; import styled from 'styled-components'
import { Row } from 'react-styled-flexboxgrid'; import { Row } from 'react-styled-flexboxgrid'
import Logo from '../../assets/logo.svg'; import Logo from '../../assets/logo.svg'
const Wrapper = styled(Row)` const Wrapper = styled(Row)`
height: 100%; height: 100%;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
text-align: center; text-align: center;
flex-direction: column; flex-direction: column;
`; `
const Title = styled.h1` const Title = styled.h1`
color: ${props => props.theme.secondary}; color: ${props => props.theme.secondary};
font-size: 80px; font-size: 80px;
margin: 0; margin: 0;
margin-top: 40px; margin-top: 40px;
@media (max-width: 1030px) { @media (max-width: 1030px) {
font-size: 55px; font-size: 55px;
} }
@media (max-width: 435px) { @media (max-width: 435px) {
font-size: 40px; font-size: 40px;
} }
`; `
const Input = styled.input` const Input = styled.input`
border: none; border: none;
border-bottom: 1px solid ${props => props.theme.secondary}; border-bottom: 1px solid ${props => props.theme.secondary};
background: transparent; background: transparent;
font-size: 80px; font-size: 80px;
height: 80px; height: 80px;
width: 300px; width: 300px;
color: ${props => props.theme.secondary}; color: ${props => props.theme.secondary};
outline: none; outline: none;
padding: 0 10px; padding: 0 10px;
font-family: 'Roboto', arial, sans-serif; font-family: 'Roboto', arial, sans-serif;
font-weight: bold; font-weight: bold;
@media (max-width: 1030px) { @media (max-width: 1030px) {
font-size: 55px; font-size: 55px;
height: 55px; height: 55px;
} }
@media (max-width: 435px) { @media (max-width: 435px) {
font-size: 40px; font-size: 40px;
height: 40px; height: 40px;
margin-top: 20px; margin-top: 20px;
} }
&:hover, &:hover,
&:active { &:active {
outline: none; outline: none;
} }
`; `
const Form = styled.form` const Form = styled.form`
display: inline; display: inline;
`; `
const fixName = name => const fixName = name =>
name name
.split(' ') .split(' ')
.join('-') .join('-')
.toLowerCase(); .toLowerCase()
export default class Home extends Component { export default class Home extends Component {
state = { state = {
value: '' value: '',
}; }
handleChange = e => this.setState({ value: fixName(e.target.value) }); handleChange = e => this.setState({ value: fixName(e.target.value) })
handleSubmit = e => { handleSubmit = e => {
const { value } = this.state; const { value } = this.state
e.preventDefault(); e.preventDefault()
route(value, true); route(value, true)
}; }
render() { render() {
return ( return (
<Wrapper> <Wrapper>
<img src={Logo} height="150" /> <img src={Logo} alt="Is There Uber In" height="150" />
<Title> <Title>
Is there Uber in Is there Uber in
<Form onSubmit={this.handleSubmit}> <Form onSubmit={this.handleSubmit}>
<Input type="text" onChange={this.handleChange} /> <Input type="text" onChange={this.handleChange} />
</Form> </Form>
? ?
</Title> </Title>
</Wrapper> </Wrapper>
); )
} }
} }

40
src/template.html Normal file
View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath %>manifest.json">
<style>
#root { opacity: 0; transition: opacity 300ms ease-in; }
body { background: #4a0072}
</style>
<% if (htmlWebpackPlugin.options.manifest.theme_color) { %>
<meta name="theme-color" content="<%= htmlWebpackPlugin.options.manifest.theme_color %>">
<% } %>
<% for (var chunk of webpack.chunks) { %>
<% if (chunk.names.length === 1 && chunk.names[0] === 'polyfills') continue; %>
<% for (var file of chunk.files) { %>
<% if (htmlWebpackPlugin.options.preload && file.match(/\.(js|css)$/)) { %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>">
<% } else if (file.match(/manifest\.json$/)) { %>
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath + file %>">
<% } %>
<% } %>
<% } %>
</head>
<body>
<%= htmlWebpackPlugin.options.ssr({
url: '/'
}) %>
<script defer src="<%= htmlWebpackPlugin.files.chunks['bundle'].entry %>"></script>
<script>window.fetch || document.write('<script src="<%= htmlWebpackPlugin.files.chunks["polyfills"].entry %>"><\/script>')</script>
</body>
</html>

1885
yarn.lock

File diff suppressed because it is too large Load Diff