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 ?
## CLI Commands
[![Build Status](https://travis-ci.org/SaraVieira/uber-cities.svg)](https://travis-ci.org/SaraVieira/uber-cities)
``` bash
# install dependencies
yarn install
Check if there is an uber in the town you input
# serve with hot reload at localhost:8080
yarn dev
Also checks for lyft, cabify and taxify
# build for production with minification
yarn build
## Why ?
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
```
For detailed explanation on how things work, checkout the [CLI Readme](https://github.com/developit/preact-cli/blob/master/README.md).
yarn
yarn dev
```

View File

@@ -5,35 +5,52 @@
"license": "MIT",
"scripts": {
"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",
"dev": "preact watch",
"lint": "eslint src"
"test": "eslint src",
"format": "prettier --write 'src/**/*.{js,css,md}'",
"posttest": "npm run format",
"precommit": "lint-staged"
},
"eslintConfig": {
"extends": "eslint-config-synacor"
"extends": [
"eslint-config-synacor",
"prettier"
],
"rules": {
"react/display-name": "off",
"react/no-did-mount-set-state": "off"
}
},
"eslintIgnore": [
"build/*"
],
"devDependencies": {
"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",
"preact-cli": "^2.0.0",
"lint-staged": "^6.0.0",
"preact-cli": "^2.1.1",
"prettier": "^1.10.2"
},
"dependencies": {
"axios": "^0.17.1",
"capitalize": "^1.0.0",
"preact": "^8.2.1",
"preact": "^8.2.7",
"preact-compat": "^3.17.0",
"preact-router": "^2.5.5",
"react-confetti": "^2.0.1",
"preact-router": "^2.6.0",
"react-confetti": "^2.0.2",
"react-sizeme": "^2.3.6",
"react-styled-flexboxgrid": "^2.1.1",
"styled-components": "^2.2.3",
"styled-is": "^1.1.0",
"styled-loaders": "^0.2.1"
"styled-components": "^2.4.0",
"styled-is": "^1.1.0"
},
"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 { Router } from 'preact-router';
import { h, Component } from 'preact'
import { Router } from 'preact-router'
import Home from 'async!../routes/home';
import City from 'async!../routes/city';
import Home from 'async!../routes/home'
import City from 'async!../routes/city'
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.
* @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">
<Router onChange={this.handleRoute}>
<Home path="/" />
<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 lyft from './lyft.json';
import cabify from './cabify.json';
import taxify from './taxify.json';
import uber from './uber.json'
import lyft from './lyft.json'
import cabify from './cabify.json'
import taxify from './taxify.json'
export default [
...uber.cities.map(u => ({ ...u, company: 'uber' })),
...lyft.cities.map(u => ({ ...u, company: 'lyft' }),),
...cabify.cities.map(u => ({ ...u, company: 'cabify' })),
...taxify.cities.map(u => ({ ...u, company: 'taxify' }))
];
...uber.cities.map(u => ({ ...u, company: 'uber' })),
...lyft.cities.map(u => ({ ...u, company: 'lyft' })),
...cabify.cities.map(u => ({ ...u, company: 'cabify' })),
...taxify.cities.map(u => ({ ...u, company: 'taxify' })),
]

View File

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

View File

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

View File

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