Initial commit.
commit
9e324a1f94
|
@ -0,0 +1,11 @@
|
||||||
|
###
|
||||||
|
|
||||||
|
.git*
|
||||||
|
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
docker-compose.yml
|
||||||
|
|
||||||
|
*.md
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
extends: airbnb
|
||||||
|
|
||||||
|
parser: babel-eslint
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- babel
|
||||||
|
- json
|
||||||
|
|
||||||
|
env:
|
||||||
|
browser: true
|
||||||
|
node: true
|
||||||
|
es6: true
|
||||||
|
|
||||||
|
rules:
|
||||||
|
no-underscore-dangle: 'off'
|
||||||
|
no-plusplus:
|
||||||
|
- error
|
||||||
|
- allowForLoopAfterthoughts: true
|
||||||
|
react/no-array-index-key: 0
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directory
|
||||||
|
# Deployed apps should consider commenting this line out:
|
||||||
|
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Webpack output
|
||||||
|
/dist
|
|
@ -0,0 +1,16 @@
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 6
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- npm install codecov.io coveralls
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js
|
||||||
|
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
|
@ -0,0 +1,4 @@
|
||||||
|
FROM icedream/caddy
|
||||||
|
|
||||||
|
WORKDIR /data
|
||||||
|
COPY ./dist/ /data
|
|
@ -0,0 +1,29 @@
|
||||||
|
node("docker && linux && amd64") {
|
||||||
|
checkout scm
|
||||||
|
|
||||||
|
docker.image("node:8.2.1").inside {
|
||||||
|
// Install dependencies
|
||||||
|
sh "npm install"
|
||||||
|
|
||||||
|
// Build website with npm
|
||||||
|
sh "npm run build"
|
||||||
|
archive "dist/**"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build docker image to be deployed
|
||||||
|
def image = docker.build("docker.dreamnetwork.oss:5000/icedream/carl-kittelberger-website:${env.BRANCH_NAME ?: "latest"}", "-f Dockerfile.dist .")
|
||||||
|
|
||||||
|
// @NOTE - https://issues.jenkins-ci.org/browse/JENKINS-42152?focusedCommentId=307976&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-307976
|
||||||
|
image.push()
|
||||||
|
if (env.BRANCH_NAME) {
|
||||||
|
switch(env.BRANCH_NAME) {
|
||||||
|
case "master":
|
||||||
|
image.push("latest")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
image.push()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
image.push("${sh(script: "git describe --tags --always", returnStdout: true).trim()}")
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
# VIzon countdown website
|
||||||
|
|
||||||
|
Source code for vizon-countdown.icedream.pw.
|
|
@ -0,0 +1,37 @@
|
||||||
|
module.exports = {
|
||||||
|
type: 'react-app',
|
||||||
|
|
||||||
|
babel: {
|
||||||
|
loose: false,
|
||||||
|
presets: [
|
||||||
|
'babel-preset-env',
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'babel-plugin-transform-class-properties',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
webpack: {
|
||||||
|
autoprefixer: '> 1%, last 2 versions, Firefox ESR, ios >= 8',
|
||||||
|
|
||||||
|
extra: {
|
||||||
|
resolve: {
|
||||||
|
extensions: [
|
||||||
|
'.jsx',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
publicPath: '',
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
babel: {
|
||||||
|
test: /\.jsx?/,
|
||||||
|
},
|
||||||
|
'sass-css': {
|
||||||
|
modules: true,
|
||||||
|
localIdentName: '[name]__[local]__[hash:base64:5]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,54 @@
|
||||||
|
{
|
||||||
|
"name": "vizon-countdown-website",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Website for a countdown to the next draw on VIzon",
|
||||||
|
"private": true,
|
||||||
|
"main": "src/index.jsx",
|
||||||
|
"scripts": {
|
||||||
|
"build": "nwb build-react-app ./src",
|
||||||
|
"clean": "nwb clean-app",
|
||||||
|
"start": "nwb serve-react-app ./src",
|
||||||
|
"test": "nwb test-react",
|
||||||
|
"test:coverage": "nwb test-react --coverage",
|
||||||
|
"test:watch": "nwb test-react --server",
|
||||||
|
"lint": "eslint ."
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "ssh://git@git.icedream.tech:2222/icedream/vizon-countdown-website.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"website",
|
||||||
|
"vizon",
|
||||||
|
"rizon",
|
||||||
|
"draw",
|
||||||
|
"countdown"
|
||||||
|
],
|
||||||
|
"author": "Carl Kittelberger <icedream@icedream.pw>",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-eslint": "^7.2.3",
|
||||||
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
|
"babel-preset-env": "^1.6.0",
|
||||||
|
"eslint": "^4.4.1",
|
||||||
|
"eslint-config-airbnb": "^15.1.0",
|
||||||
|
"eslint-plugin-babel": "^4.1.2",
|
||||||
|
"eslint-plugin-import": "^2.7.0",
|
||||||
|
"eslint-plugin-json": "^1.2.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.0.2",
|
||||||
|
"eslint-plugin-react": "^7.2.1",
|
||||||
|
"file-loader": "^0.11.2",
|
||||||
|
"nwb": "^0.18.10",
|
||||||
|
"nwb-sass": "^0.8.1",
|
||||||
|
"svg-inline-loader": "^0.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"moment": "^2.18.1",
|
||||||
|
"normalize-scss": "^7.0.0",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
|
"react": "^15.6.1",
|
||||||
|
"react-dom": "^15.6.1",
|
||||||
|
"react-helmet": "^5.1.3",
|
||||||
|
"react-router": "^4.1.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import moment from 'moment';
|
||||||
|
import Countdown from './Countdown';
|
||||||
|
import Header from './Header';
|
||||||
|
import ProgressCircle from './ProgressCircle';
|
||||||
|
import getUpcomingDate from './getUpcomingDate';
|
||||||
|
|
||||||
|
import style from './App.sass';
|
||||||
|
|
||||||
|
class App extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
getNow: PropTypes.func,
|
||||||
|
weekdays: PropTypes.arrayOf(PropTypes.string),
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
getNow: () => moment(),
|
||||||
|
weekdays: [
|
||||||
|
'tuesday',
|
||||||
|
'thursday',
|
||||||
|
'saturday',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.interval = setInterval(this.updateUpcomingDate.bind(this), 1000);
|
||||||
|
this.updateUpcomingDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateUpcomingDate() {
|
||||||
|
const { getNow, weekdays } = this.props;
|
||||||
|
const now = getNow();
|
||||||
|
return moment.min(
|
||||||
|
...weekdays.map(weekday => getUpcomingDate(now, weekday)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUpcomingDate() {
|
||||||
|
this.setState({ nextUpcomingDate: this.calculateUpcomingDate() });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { nextUpcomingDate } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={style.app}>
|
||||||
|
<Header>
|
||||||
|
VIzon countdown
|
||||||
|
</Header>
|
||||||
|
|
||||||
|
<div className={style.content}>
|
||||||
|
<div className={style.contentContainer}>
|
||||||
|
<p>
|
||||||
|
The next VIzon draw is on {nextUpcomingDate.format('dddd')}, {nextUpcomingDate.format('L LT')}.
|
||||||
|
</p>
|
||||||
|
<Countdown date={nextUpcomingDate} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
|
@ -0,0 +1,19 @@
|
||||||
|
.app
|
||||||
|
background-color: #f8f8f8
|
||||||
|
min-height: 100vh
|
||||||
|
font-size: 24px
|
||||||
|
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
|
justify-content: stretch
|
||||||
|
align-items: center
|
||||||
|
|
||||||
|
.content
|
||||||
|
color: #222
|
||||||
|
line-height: 1.5
|
||||||
|
width: 100%
|
||||||
|
max-width: 1024px
|
||||||
|
padding: 1em 0
|
||||||
|
box-sizing: content-box
|
||||||
|
flex-grow: 1
|
||||||
|
text-align: center
|
|
@ -0,0 +1,97 @@
|
||||||
|
import React from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import DigitBlock from './DigitBlock';
|
||||||
|
import ProgressCircle from './ProgressCircle';
|
||||||
|
|
||||||
|
import style from './Countdown.sass';
|
||||||
|
|
||||||
|
export default class Countdown extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
date: PropTypes.object.isRequired,
|
||||||
|
locale: PropTypes.string,
|
||||||
|
minimumIntegerDigits: PropTypes.number,
|
||||||
|
useGrouping: PropTypes.bool,
|
||||||
|
getNow: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
locale: undefined,
|
||||||
|
minimumIntegerDigits: 2,
|
||||||
|
useGrouping: false,
|
||||||
|
getNow: () => moment(),
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.tick();
|
||||||
|
this.interval = setInterval(this.tick.bind(this), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
calculateDiff() {
|
||||||
|
const { getNow, date } = this.props;
|
||||||
|
return date.diff(getNow());
|
||||||
|
}
|
||||||
|
|
||||||
|
tick() {
|
||||||
|
this.setState({ duration: this.calculateDiff() });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.state) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { duration } = this.state;
|
||||||
|
|
||||||
|
const durationMoment = moment.duration(duration);
|
||||||
|
|
||||||
|
const days = durationMoment.days();
|
||||||
|
const hours = durationMoment.hours();
|
||||||
|
const minutes = durationMoment.minutes();
|
||||||
|
const seconds = durationMoment.seconds();
|
||||||
|
|
||||||
|
const size = 160; // @HACK
|
||||||
|
|
||||||
|
const { locale, minimumIntegerDigits, useGrouping } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={style.countdown}>
|
||||||
|
<ProgressCircle size={size} max={3} progress={days} stroke="rgb(60, 90, 128)">
|
||||||
|
<DigitBlock suffix="d">
|
||||||
|
{days.toLocaleString(locale, {
|
||||||
|
minimumIntegerDigits,
|
||||||
|
useGrouping,
|
||||||
|
})}
|
||||||
|
</DigitBlock>
|
||||||
|
</ProgressCircle>
|
||||||
|
<ProgressCircle size={size} max={24} progress={hours} stroke="rgb(60, 144, 60)">
|
||||||
|
<DigitBlock suffix="h">
|
||||||
|
{hours.toLocaleString(locale, {
|
||||||
|
minimumIntegerDigits,
|
||||||
|
useGrouping,
|
||||||
|
})}
|
||||||
|
</DigitBlock>
|
||||||
|
</ProgressCircle>
|
||||||
|
<ProgressCircle size={size} max={60} progress={minutes} stroke="rgb(160, 154, 40)">
|
||||||
|
<DigitBlock suffix="m">
|
||||||
|
{minutes.toLocaleString(locale, {
|
||||||
|
minimumIntegerDigits,
|
||||||
|
useGrouping,
|
||||||
|
})}
|
||||||
|
</DigitBlock>
|
||||||
|
</ProgressCircle>
|
||||||
|
<ProgressCircle size={size} max={60} progress={seconds} stroke="rgb(155, 50, 70)">
|
||||||
|
<DigitBlock suffix="s">
|
||||||
|
{durationMoment.seconds().toLocaleString(locale, {
|
||||||
|
minimumIntegerDigits,
|
||||||
|
useGrouping,
|
||||||
|
})}
|
||||||
|
</DigitBlock>
|
||||||
|
</ProgressCircle>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
.countdown
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
flex-wrap: wrap
|
||||||
|
font-family: monospace
|
||||||
|
justify-content: space-around
|
||||||
|
|
||||||
|
&> *:not(:first-child)
|
||||||
|
margin-left: 0.25em
|
|
@ -0,0 +1,22 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import style from './DigitBlock.sass';
|
||||||
|
|
||||||
|
const DigitBlock = ({ children, suffix }) => (
|
||||||
|
<div className={style.digitBlock}>
|
||||||
|
<span>{children}</span>
|
||||||
|
<span className={style.digitBlockSuffix}>{suffix}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
DigitBlock.defaultProps = {
|
||||||
|
suffix: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
DigitBlock.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
suffix: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DigitBlock;
|
|
@ -0,0 +1,10 @@
|
||||||
|
.digitBlock
|
||||||
|
font-size: 2em
|
||||||
|
display: inline-block
|
||||||
|
white-space: pre
|
||||||
|
|
||||||
|
&Suffix
|
||||||
|
font-size: 0.5em
|
||||||
|
text-transform: uppercase
|
||||||
|
font-weight: bold
|
||||||
|
color: #888
|
|
@ -0,0 +1,23 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import style from './Header.sass';
|
||||||
|
|
||||||
|
export default function Header({ className, children }) {
|
||||||
|
return (
|
||||||
|
<header className={[style.header, className].join(' ')}>
|
||||||
|
{children}
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Header.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
className: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Header.defaultProps = {
|
||||||
|
children: null,
|
||||||
|
className: null,
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
.header
|
||||||
|
background-color: #222
|
||||||
|
color: #f8f8f8
|
||||||
|
font-weight: bold
|
||||||
|
font-size: 1.5em
|
||||||
|
text-align: center
|
||||||
|
box-shadow: 0px 4px 4vh 4px rgba(34,34,34,0.9)
|
||||||
|
z-index: 2
|
||||||
|
padding: 12px 0
|
||||||
|
width: 100%
|
|
@ -0,0 +1,81 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import style from './ProgressCircle.sass';
|
||||||
|
|
||||||
|
const ProgressCircle = ({
|
||||||
|
children,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
progress,
|
||||||
|
size,
|
||||||
|
strokeWidth,
|
||||||
|
backStroke,
|
||||||
|
stroke,
|
||||||
|
}) => {
|
||||||
|
const width = size;
|
||||||
|
const height = size;
|
||||||
|
|
||||||
|
const viewBox = [0, 0, width, height].join(' ');
|
||||||
|
|
||||||
|
const cx = width / 2;
|
||||||
|
const cy = height / 2;
|
||||||
|
|
||||||
|
const r = (size / 2) - (strokeWidth / 2);
|
||||||
|
|
||||||
|
const strokeLength = 2 * Math.PI * r;
|
||||||
|
|
||||||
|
const finalProgress = (progress - min) / (max - min);
|
||||||
|
|
||||||
|
const strokeDasharray = strokeLength;
|
||||||
|
const strokeDashoffset = strokeLength * (1 - finalProgress);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={style.progressCircleContainer}
|
||||||
|
style={{
|
||||||
|
width: `${width}px`,
|
||||||
|
height: `${height}px`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg className={style.progressCircle} {...{ width, height, viewBox }}>
|
||||||
|
<circle
|
||||||
|
fill="none"
|
||||||
|
stroke={backStroke}
|
||||||
|
{...{ cx, cy, r, strokeWidth }}
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
className={style.progressValue}
|
||||||
|
fill="none"
|
||||||
|
{...{ cx, cy, r, stroke, strokeWidth, strokeDashoffset, strokeDasharray }}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span className={style.progressCircleLabel}>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProgressCircle.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
size: PropTypes.number.isRequired,
|
||||||
|
progress: PropTypes.number,
|
||||||
|
strokeWidth: PropTypes.number,
|
||||||
|
min: PropTypes.number,
|
||||||
|
max: PropTypes.number,
|
||||||
|
backStroke: PropTypes.string,
|
||||||
|
stroke: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
ProgressCircle.defaultProps = {
|
||||||
|
stroke: '#444',
|
||||||
|
backStroke: '#eee',
|
||||||
|
strokeWidth: 10,
|
||||||
|
progress: 0.5,
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
|
children: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProgressCircle;
|
|
@ -0,0 +1,18 @@
|
||||||
|
.progressCircle
|
||||||
|
transform: rotate(-90deg)
|
||||||
|
position: absolute
|
||||||
|
left: 0
|
||||||
|
top: 0
|
||||||
|
|
||||||
|
.progressValue
|
||||||
|
transition: stroke-dashoffset 1s linear
|
||||||
|
|
||||||
|
.progressCircleContainer
|
||||||
|
position: relative
|
||||||
|
display: inline-flex
|
||||||
|
flex-direction: column
|
||||||
|
justify-content: space-around
|
||||||
|
|
||||||
|
.progressCircleLabel
|
||||||
|
flex-basis: auto
|
||||||
|
text-align: center
|
|
@ -0,0 +1,16 @@
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
export default function getUpcomingDate(now, weekday: String) {
|
||||||
|
let wanted = moment()
|
||||||
|
.isoWeekday(weekday)
|
||||||
|
.second(0)
|
||||||
|
.minute(0)
|
||||||
|
.hour(0);
|
||||||
|
|
||||||
|
if (wanted.isBefore(now)) {
|
||||||
|
// we want the date from the upcoming week
|
||||||
|
wanted = wanted.add(1, 'weeks');
|
||||||
|
}
|
||||||
|
|
||||||
|
return wanted;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<title>my-app</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { render } from 'react-dom';
|
||||||
|
|
||||||
|
import './index.sass';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
render(<App />, document.querySelector('#app'));
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import "~normalize-scss/sass/normalize"
|
||||||
|
|
||||||
|
body
|
||||||
|
font-family: sans-serif
|
||||||
|
margin: 0
|
||||||
|
padding: 0
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_2_1_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 841.9 595.3" enable-background="new 0 0 841.9 595.3" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path fill="#61DAFB" d="M666.3,296.5c0-32.5-40.7-63.3-103.1-82.4c14.4-63.6,8-114.2-20.2-130.4c-6.5-3.8-14.1-5.6-22.4-5.6v22.3
|
||||||
|
c4.6,0,8.3,0.9,11.4,2.6c13.6,7.8,19.5,37.5,14.9,75.7c-1.1,9.4-2.9,19.3-5.1,29.4c-19.6-4.8-41-8.5-63.5-10.9
|
||||||
|
c-13.5-18.5-27.5-35.3-41.6-50c32.6-30.3,63.2-46.9,84-46.9l0-22.3c0,0,0,0,0,0c-27.5,0-63.5,19.6-99.9,53.6
|
||||||
|
c-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7,0,51.4,16.5,84,46.6c-14,14.7-28,31.4-41.3,49.9c-22.6,2.4-44,6.1-63.6,11
|
||||||
|
c-2.3-10-4-19.7-5.2-29c-4.7-38.2,1.1-67.9,14.6-75.8c3-1.8,6.9-2.6,11.5-2.6l0-22.3c0,0,0,0,0,0c-8.4,0-16,1.8-22.6,5.6
|
||||||
|
c-28.1,16.2-34.4,66.7-19.9,130.1c-62.2,19.2-102.7,49.9-102.7,82.3c0,32.5,40.7,63.3,103.1,82.4c-14.4,63.6-8,114.2,20.2,130.4
|
||||||
|
c6.5,3.8,14.1,5.6,22.5,5.6c27.5,0,63.5-19.6,99.9-53.6c36.4,33.8,72.4,53.2,99.9,53.2c8.4,0,16-1.8,22.6-5.6
|
||||||
|
c28.1-16.2,34.4-66.7,19.9-130.1C625.8,359.7,666.3,328.9,666.3,296.5z M536.1,229.8c-3.7,12.9-8.3,26.2-13.5,39.5
|
||||||
|
c-4.1-8-8.4-16-13.1-24c-4.6-8-9.5-15.8-14.4-23.4C509.3,224,523,226.6,536.1,229.8z M490.3,336.3c-7.8,13.5-15.8,26.3-24.1,38.2
|
||||||
|
c-14.9,1.3-30,2-45.2,2c-15.1,0-30.2-0.7-45-1.9c-8.3-11.9-16.4-24.6-24.2-38c-7.6-13.1-14.5-26.4-20.8-39.8
|
||||||
|
c6.2-13.4,13.2-26.8,20.7-39.9c7.8-13.5,15.8-26.3,24.1-38.2c14.9-1.3,30-2,45.2-2c15.1,0,30.2,0.7,45,1.9
|
||||||
|
c8.3,11.9,16.4,24.6,24.2,38c7.6,13.1,14.5,26.4,20.8,39.8C504.7,309.8,497.8,323.2,490.3,336.3z M522.6,323.3
|
||||||
|
c5.4,13.4,10,26.8,13.8,39.8c-13.1,3.2-26.9,5.9-41.2,8c4.9-7.7,9.8-15.6,14.4-23.7C514.2,339.4,518.5,331.3,522.6,323.3z
|
||||||
|
M421.2,430c-9.3-9.6-18.6-20.3-27.8-32c9,0.4,18.2,0.7,27.5,0.7c9.4,0,18.7-0.2,27.8-0.7C439.7,409.7,430.4,420.4,421.2,430z
|
||||||
|
M346.8,371.1c-14.2-2.1-27.9-4.7-41-7.9c3.7-12.9,8.3-26.2,13.5-39.5c4.1,8,8.4,16,13.1,24C337.1,355.7,341.9,363.5,346.8,371.1z
|
||||||
|
M420.7,163c9.3,9.6,18.6,20.3,27.8,32c-9-0.4-18.2-0.7-27.5-0.7c-9.4,0-18.7,0.2-27.8,0.7C402.2,183.3,411.5,172.6,420.7,163z
|
||||||
|
M346.7,221.9c-4.9,7.7-9.8,15.6-14.4,23.7c-4.6,8-8.9,16-13,24c-5.4-13.4-10-26.8-13.8-39.8C318.6,226.7,332.4,224,346.7,221.9z
|
||||||
|
M256.2,347.1c-35.4-15.1-58.3-34.9-58.3-50.6c0-15.7,22.9-35.6,58.3-50.6c8.6-3.7,18-7,27.7-10.1c5.7,19.6,13.2,40,22.5,60.9
|
||||||
|
c-9.2,20.8-16.6,41.1-22.2,60.6C274.3,354.2,264.9,350.8,256.2,347.1z M310,490c-13.6-7.8-19.5-37.5-14.9-75.7
|
||||||
|
c1.1-9.4,2.9-19.3,5.1-29.4c19.6,4.8,41,8.5,63.5,10.9c13.5,18.5,27.5,35.3,41.6,50c-32.6,30.3-63.2,46.9-84,46.9
|
||||||
|
C316.8,492.6,313,491.7,310,490z M547.2,413.8c4.7,38.2-1.1,67.9-14.6,75.8c-3,1.8-6.9,2.6-11.5,2.6c-20.7,0-51.4-16.5-84-46.6
|
||||||
|
c14-14.7,28-31.4,41.3-49.9c22.6-2.4,44-6.1,63.6-11C544.3,394.8,546.1,404.5,547.2,413.8z M585.7,347.1c-8.6,3.7-18,7-27.7,10.1
|
||||||
|
c-5.7-19.6-13.2-40-22.5-60.9c9.2-20.8,16.6-41.1,22.2-60.6c9.9,3.1,19.3,6.5,28.1,10.2c35.4,15.1,58.3,34.9,58.3,50.6
|
||||||
|
C644,312.2,621.1,332.1,585.7,347.1z"/>
|
||||||
|
<polygon fill="#61DAFB" points="320.8,78.4 320.8,78.4 320.8,78.4 "/>
|
||||||
|
<circle fill="#61DAFB" cx="420.9" cy="296.5" r="45.7"/>
|
||||||
|
<polygon fill="#61DAFB" points="520.5,78.1 520.5,78.1 520.5,78.1 "/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
Loading…
Reference in New Issue