├── src
├── app
│ ├── routes
│ │ ├── Home
│ │ │ ├── index.js
│ │ │ ├── defaultQuery.js
│ │ │ └── Home.js
│ │ └── NotFound
│ │ │ ├── index.js
│ │ │ └── NotFound.js
│ ├── .DS_Store
│ ├── components
│ │ └── App
│ │ │ ├── index.js
│ │ │ └── App.js
│ ├── styles
│ │ └── main.css
│ └── assets
│ │ └── logo.svg
├── .DS_Store
├── server
│ ├── types
│ │ ├── TalkPrepared.graphql
│ │ ├── Contributor.graphql
│ │ ├── Job.graphql
│ │ ├── Project.graphql
│ │ ├── Repo.graphql
│ │ ├── Talk.graphql
│ │ ├── index.js
│ │ ├── SpeakerInfo.graphql
│ │ └── Query.graphql
│ ├── data
│ │ ├── countries.js
│ │ ├── basic.js
│ │ ├── main.js
│ │ ├── github.js
│ │ ├── resume.json
│ │ ├── speaker-info.js
│ │ ├── projects.js
│ │ └── talks.js
│ ├── middleware
│ │ ├── webpack.js
│ │ └── render.js
│ └── index.js
└── client
│ └── index.js
├── .vscode
└── settings.json
├── .travis.yml
├── .babelrc
├── README.md
├── .eslintrc
├── .gitignore
├── .editorconfig
├── webpack
├── common.js
├── webpack.server.babel.js
└── webpack.client.babel.js
├── LICENSE
├── yarn-error.log
└── package.json
/src/app/routes/Home/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Home'
2 |
--------------------------------------------------------------------------------
/src/app/routes/NotFound/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './NotFound'
2 |
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SaraVieira/graphql-portfolio/HEAD/src/.DS_Store
--------------------------------------------------------------------------------
/src/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SaraVieira/graphql-portfolio/HEAD/src/app/.DS_Store
--------------------------------------------------------------------------------
/src/app/components/App/index.js:
--------------------------------------------------------------------------------
1 | import '../../styles/main.css'
2 | export { default } from './App'
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "git.ignoreLimitWarning": true,
3 | "prettier.trailingComma": "none"
4 | }
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 7
4 | - 6
5 | - 8
6 | script: npm run lint && npm run build
7 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "transform-object-rest-spread"
4 | ],
5 | "presets": [
6 | "env"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Licensed under the MIT LICENSE
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "prettier-standard/lib/base",
4 | "standard-react",
5 | "prettier"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/src/server/types/TalkPrepared.graphql:
--------------------------------------------------------------------------------
1 | type TalksPrepared {
2 | # Talk Name
3 | name: String,
4 | # Talk Description
5 | description: String
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | node_modules
3 | stats.json
4 | .vscode
5 |
6 | # Ignore Mac DS_Store files
7 | .DS_Store
8 |
9 | # Ignore IntelliJ generated files
10 | .idea
11 |
--------------------------------------------------------------------------------
/src/app/styles/main.css:
--------------------------------------------------------------------------------
1 | body,
2 | html,
3 | #root {
4 | padding: 0;
5 | margin: 0;
6 | height: 100%;
7 | }
8 |
9 | .variable-editor {
10 | display: none;
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/routes/NotFound/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const NotFound = () => (
4 |
5 |
Page not found
6 |
7 | )
8 |
9 | export default NotFound
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/src/server/data/countries.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | 'Portugal',
3 | 'Spain',
4 | 'Germany',
5 | 'Netherlands',
6 | 'Poland',
7 | 'Austria',
8 | 'United Kingdom',
9 | 'France',
10 | 'Switzerland'
11 | ]
12 |
--------------------------------------------------------------------------------
/src/server/types/Contributor.graphql:
--------------------------------------------------------------------------------
1 | # List of amazing people who helped this project
2 | type Contributor {
3 | # Name of the Amazing Person that contributed
4 | name: String
5 | # Their Github URL
6 | url: String
7 | }
8 |
--------------------------------------------------------------------------------
/src/server/types/Job.graphql:
--------------------------------------------------------------------------------
1 | # Jobs I have had or still have
2 | type Job {
3 | # Name of the Company
4 | company: String
5 | # Title I had there
6 | title: String!
7 | # Where this job was located
8 | location: String
9 | # Started Date
10 | started: String
11 | # End date
12 | finished: String
13 | }
14 |
--------------------------------------------------------------------------------
/src/server/types/Project.graphql:
--------------------------------------------------------------------------------
1 | # Dumb and maybe not so dumb Projects/Packages I have done over the years
2 | type Project {
3 | # Name
4 | name: String!
5 | # Description
6 | description: String
7 | # The repo of this
8 | github: String
9 | # The website of this if there is one
10 | website: String
11 | }
12 |
--------------------------------------------------------------------------------
/src/server/types/Repo.graphql:
--------------------------------------------------------------------------------
1 | # All my github repos
2 | type Repo {
3 | # Repo Name
4 | name: String
5 | # Link to repo
6 | url: String
7 | # Repo description
8 | description: String
9 | # Language used
10 | language: String
11 | # Number of stars
12 | stars: Int
13 | # Is it forked?
14 | fork: Boolean!
15 | # Owner of the repo
16 | owner: String
17 | }
18 |
--------------------------------------------------------------------------------
/src/server/types/Talk.graphql:
--------------------------------------------------------------------------------
1 | type Talk {
2 | # Talk name
3 | name: String
4 | # The awesome event that hosted this talk
5 | event: String
6 | # The Date
7 | date: String
8 | # Video link if there is one
9 | video: String
10 | # Slides link if there is one
11 | slides: String
12 | # Have I already done this talk?
13 | done: Boolean,
14 | # Where is this ?
15 | location: String
16 | }
17 |
--------------------------------------------------------------------------------
/src/server/middleware/webpack.js:
--------------------------------------------------------------------------------
1 | import devMiddleware from 'webpack-dev-middleware'
2 | import hotMiddleware from 'webpack-hot-middleware'
3 | import webpack from 'webpack'
4 |
5 | import config from '../../../webpack/webpack.client.babel'
6 |
7 | const compiler = webpack(config)
8 |
9 | export const webpackDevMiddleware = devMiddleware(compiler, {
10 | stats: 'minimal'
11 | })
12 | export const webpackHotMiddleware = hotMiddleware(compiler)
13 |
--------------------------------------------------------------------------------
/src/client/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BrowserRouter as Router } from 'react-router-dom'
3 | import { render } from 'react-dom'
4 | import App from '../app/components/App'
5 | import * as OfflinePluginRuntime from 'offline-plugin/runtime'
6 |
7 | render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | )
13 |
14 | if (module.hot) {
15 | module.hot.accept()
16 | }
17 | OfflinePluginRuntime.install()
18 |
--------------------------------------------------------------------------------
/src/server/data/basic.js:
--------------------------------------------------------------------------------
1 | const distanceInWordsToNow = require('date-fns/distance_in_words_to_now')
2 |
3 | module.exports = {
4 | name: 'Sara Vieira',
5 | company: 'YLD',
6 | email: 'hey@iamsaravieira.com',
7 | age: distanceInWordsToNow(new Date(1991, 11, 29)),
8 | twitter: 'https://twitter.com/NikkitaFTW',
9 | github: 'https://github.com/SaraVieira/',
10 | instagram: 'https://www.instagram.com/niikkitaftw/',
11 | medium: 'https://medium.com/@nikkitaftw'
12 | }
13 |
--------------------------------------------------------------------------------
/src/app/components/App/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Route, Switch } from 'react-router-dom'
3 |
4 | import Home from '../../routes/Home'
5 | import NotFound from '../../routes/NotFound'
6 |
7 | const App = () => {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 | )
16 | }
17 |
18 | export default App
19 |
--------------------------------------------------------------------------------
/src/server/types/index.js:
--------------------------------------------------------------------------------
1 | import Job from './Job.graphql'
2 | import Repo from './Repo.graphql'
3 | import Talk from './Talk.graphql'
4 | import Query from './Query.graphql'
5 | import Contributor from './Contributor.graphql'
6 | import Project from './Project.graphql'
7 | import SpeakerInfo from './SpeakerInfo.graphql'
8 | import TalkPrepared from './TalkPrepared.graphql'
9 |
10 | export {
11 | Job,
12 | Repo,
13 | Talk,
14 | Query,
15 | Contributor,
16 | Project,
17 | SpeakerInfo,
18 | TalkPrepared
19 | }
20 |
--------------------------------------------------------------------------------
/src/server/types/SpeakerInfo.graphql:
--------------------------------------------------------------------------------
1 | # Speaker Info for talks (this part is mostly for me 😝)
2 | type SpeakerInfo {
3 | # My Name
4 | name: String
5 | # My Email
6 | email: String
7 | # My Twitter handler
8 | twitter: String
9 | # My GitHub name
10 | github: String
11 | # Shirt size I want
12 | shirtSize: String
13 | # Country flying from
14 | country: String,
15 | # My Bio
16 | bio: String
17 | # My Photo
18 | photo: String
19 | # Talks
20 | talks: [TalksPrepared]
21 | # Recored Talks
22 | videos: [String]
23 | }
24 |
--------------------------------------------------------------------------------
/src/app/routes/Home/defaultQuery.js:
--------------------------------------------------------------------------------
1 | const defaultQuery = `
2 | # Yellow
3 | # My name is Sara and I am Front End Developer from Portugal
4 | # I made this GraphQL API as my page because everyone loves GraphQL
5 | # Also it's waaay easier to update like this.
6 | # Check out the Docs and here is a sample query
7 |
8 | {
9 | name,
10 | age,
11 | email,
12 | github,
13 | twitter,
14 | employed,
15 | talks,
16 | projects,
17 | jobs,
18 | repos,
19 | contributors
20 | }
21 | `
22 | export default defaultQuery
23 |
--------------------------------------------------------------------------------
/src/server/types/Query.graphql:
--------------------------------------------------------------------------------
1 | # Fun right!?
2 | type Query {
3 | # My Name
4 | name: String!
5 | # My Age
6 | age: String!
7 | # My Email
8 | email: String!
9 | # The company I work for as of now
10 | company: String!
11 | # My Twitter handler
12 | twitter: String!
13 | # My GitHub name
14 | github: String!
15 | # Am I employed?
16 | employed: Boolean!
17 | jobs: [Job]
18 | repos: [Repo]
19 | talks: [Talk]
20 | contributors: [Contributor]
21 | projects: [Project]
22 | countries: [String],
23 | speakerInfo: SpeakerInfo,
24 | # Have fun
25 | randomCurseWord: String
26 | }
27 |
--------------------------------------------------------------------------------
/src/server/data/main.js:
--------------------------------------------------------------------------------
1 | const curseWords = require('curse-words-common')
2 | const uniqueRandomArray = require('unique-random-array')
3 | const jobs = require('./resume.json')
4 | const { repos, contributors } = require('./github')
5 | const talks = require('./talks')
6 | const projects = require('./projects')
7 | const countries = require('./countries')
8 | const speakerInfo = require('./speaker-info')
9 | const basic = require('./basic')
10 |
11 | const rand = uniqueRandomArray(curseWords)
12 |
13 | module.exports = {
14 | ...basic,
15 | randomCurseWord: rand(),
16 | jobs,
17 | repos,
18 | talks,
19 | projects,
20 | contributors,
21 | countries,
22 | speakerInfo
23 | }
24 |
--------------------------------------------------------------------------------
/src/app/routes/Home/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import GraphiQL from 'graphiql'
3 | import fetch from 'isomorphic-fetch'
4 | import Logo from '../../assets/logo.svg'
5 | import defaultQuery from './defaultQuery'
6 | import 'graphiql-material-theme'
7 |
8 | const graphQLFetcher = graphQLParams =>
9 | fetch('/graphql', {
10 | method: 'post',
11 | headers: { 'Content-Type': 'application/json' },
12 | body: JSON.stringify(graphQLParams)
13 | }).then(response => response.json())
14 |
15 | const Home = () => (
16 |
20 |
21 |
22 |
23 |
24 | )
25 |
26 | export default Home
27 |
--------------------------------------------------------------------------------
/src/server/data/github.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios')
2 |
3 | export const repos = axios(
4 | 'https://api.github.com/users/SaraVieira/repos?type=all&per_page=100'
5 | )
6 | .then(repos =>
7 | repos.data.map(repo => ({
8 | name: repo.name,
9 | url: repo.html_url,
10 | description: repo.description,
11 | language: repo.language,
12 | stars: repo.stargazers_count,
13 | fork: repo.fork,
14 | owner: repo.owner.login
15 | }))
16 | )
17 | .then(repos => repos.filter(r => !r.fork))
18 | .then(repos => repos.sort((a, b) => b.stars - a.stars))
19 |
20 | export const contributors = axios(
21 | 'https://api.github.com/repos/SaraVieira/graphql-portfolio/contributors'
22 | ).then(contributors =>
23 | contributors.data.map(contributor => ({
24 | name: contributor.login,
25 | url: contributor.html_url
26 | }))
27 | )
28 |
--------------------------------------------------------------------------------
/src/server/data/resume.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "company": "YLD",
4 | "title": "Full-stack Developer",
5 | "location": "Lisboa/London",
6 | "started": "Sep 2017",
7 | "finished": ""
8 | },
9 | {
10 | "company": "Mindera",
11 | "title": "Front End Developer",
12 | "location": "Porto",
13 | "started": "Apr 2016",
14 | "finished": "Sep 2017"
15 | },
16 | {
17 | "company": "Porto Tech Center (Africa Internet Group)",
18 | "title": "Front End Developer",
19 | "location": "Porto, Portugal",
20 | "started": "Feb 2015",
21 | "finished": "Apr 2016"
22 | },
23 | {
24 | "company": "Pixelmatters",
25 | "title": "Front-End Developer",
26 | "location": "Porto",
27 | "started": "Aug 2014",
28 | "finished": "Dec 2014"
29 | },
30 | {
31 | "company": "Ideoma Design",
32 | "title": "Developer / Wordpress",
33 | "location": "Vila Nova de Gaia",
34 | "started": "Jan 2014",
35 | "finished": "Jul 2014"
36 | }
37 | ]
38 |
--------------------------------------------------------------------------------
/webpack/common.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import webpack from 'webpack'
3 |
4 | const isProduction = process.env.NODE_ENV === 'production'
5 |
6 | export const babelLoaderOptions = {
7 | cacheDirectory: !isProduction,
8 | plugins: [
9 | 'transform-object-rest-spread',
10 | ...(isProduction && ['transform-react-remove-prop-types'])
11 | ]
12 | }
13 |
14 | export const cssLoaderOptions = {
15 | minimize: isProduction
16 | }
17 |
18 | export const urlLoaderOptions = {
19 | limit: 10000,
20 | name: `media/[name]${isProduction ? '.[hash:8]' : ''}.[ext]`
21 | }
22 |
23 | export default {
24 | output: {
25 | path: path.resolve(__dirname, '../build'),
26 | publicPath: '/'
27 | },
28 | plugins: [
29 | new webpack.DefinePlugin({
30 | 'process.env': {
31 | NODE_ENV: JSON.stringify(process.env.NODE_ENV)
32 | }
33 | }),
34 | ...(isProduction && [
35 | new webpack.optimize.UglifyJsPlugin({ comments: false })
36 | ])
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Richard Käll (richardkall.se)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/server/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable global-require, no-console */
2 | import path from 'path'
3 | import compression from 'compression'
4 | import express from 'express'
5 | import format from 'date-fns/format'
6 | import graphqlHTTP from 'express-graphql'
7 | import morgan from 'morgan'
8 | import { makeExecutableSchema } from 'graphql-tools'
9 |
10 | import data from './data/main'
11 | import renderMiddleware from './middleware/render'
12 |
13 | // Schemas
14 | import {
15 | Job,
16 | Repo,
17 | Talk,
18 | Query,
19 | Contributor,
20 | Project,
21 | SpeakerInfo,
22 | TalkPrepared
23 | } from './types'
24 |
25 | const isProduction = process.env.NODE_ENV === 'production'
26 | const port = process.env.PORT || 3000
27 | const app = express()
28 |
29 | const typeDefs = Query.concat(
30 | Job,
31 | Project,
32 | Repo,
33 | Talk,
34 | Contributor,
35 | SpeakerInfo,
36 | TalkPrepared
37 | )
38 |
39 | const resolvers = {
40 | Query: {
41 | name: () => data.name,
42 | age: () => data.age,
43 | email: () => data.email,
44 | company: () => data.company,
45 | twitter: () => data.twitter,
46 | github: () => data.github,
47 | employed: () => true,
48 | jobs: () => data.jobs,
49 | repos: () => data.repos,
50 | randomCurseWord: () => data.randomCurseWord,
51 | contributors: () => data.contributors,
52 | countries: () => data.countries,
53 | talks: () =>
54 | data.talks.map(talk => ({
55 | ...talk,
56 | date: format(talk.date, 'DD/MM/YY')
57 | })),
58 | projects: () => data.projects,
59 | speakerInfo: () => data.speakerInfo
60 | }
61 | }
62 |
63 | const schema = makeExecutableSchema({ typeDefs, resolvers })
64 |
65 | if (isProduction) {
66 | app.use(compression())
67 | } else {
68 | const {
69 | webpackDevMiddleware,
70 | webpackHotMiddleware
71 | } = require('./middleware/webpack')
72 |
73 | app.use(webpackDevMiddleware)
74 | app.use(webpackHotMiddleware)
75 | }
76 |
77 | app.use(
78 | '/graphql',
79 | graphqlHTTP({
80 | schema,
81 | graphiql: false
82 | })
83 | )
84 |
85 | app.use(morgan(isProduction ? 'combined' : 'dev'))
86 | app.use(express.static(path.resolve(__dirname, '../build')))
87 | app.use(renderMiddleware)
88 |
89 | app.listen(port, console.log(`Server running on port ${port}`))
90 |
--------------------------------------------------------------------------------
/src/server/data/speaker-info.js:
--------------------------------------------------------------------------------
1 | import basic from './basic'
2 | import talks from './talks'
3 |
4 | module.exports = {
5 | name: basic.name,
6 | email: basic.email,
7 | twitter: basic.twitter,
8 | github: basic.github,
9 | shirtSize: "Men's M",
10 | country: 'Portugal',
11 | bio:
12 | 'Front-End Developer at @YLDio, open sorcerer, Blogger , Drummer and horror movie fan girl 🐈🎃🇵🇹🌈',
13 | photo: 'https://avatars0.githubusercontent.com/u/1051509?s=460&v=4',
14 | talks: [
15 | {
16 | name: 'We need to talk about Preact',
17 | description:
18 | "I know many of you have heard about Preact and may have even played around with it but have you seen it's true potential? In this talk we are going to have the needed discussion about Preact and why it's awesome."
19 | },
20 | {
21 | name: 'The Dream of Styleguide Driven Development',
22 | description:
23 | 'React is awesome! We probably all here agree on that. You have heard of all types of driven development but react emerged a new type, styleguide driven development became a reality with components. This type of development focuses on Developer/Designer collaboration and on assertive components. With the use of React, CSS Modules, Flow and Snapshot testing we were able to almost remove style regressions. In this talk you get a glimpse of you can start styleguide driven development and how you can sell this dream to your project managers. '
24 | },
25 | {
26 | name: "Let's manage our local state with GraphQL.",
27 | description:
28 | "Apollo has given us freedom and happiness when it comes to managing our data coming from the server but we still had to write code and sometimes a lot of it to manage our local state? Well, what if we managed it with queries too? Sounds too awesome right? Let's learn how to do this with apollo-link-state"
29 | },
30 | {
31 | name: 'The Lonely and Dark Road to Styling in React',
32 | description: `CSS is hard !I made a living out of it being hard but when React was introduced we had a whole new level of fighting over CSS, there are so many ways to approach it and so many tradeoffs one can do when choosing the better approach that a talk that will go over these options is more than necessary.
33 | Let's walk this road thogheter and I promise it will all be fine and you will leave with an ideia of type of styling is better for each project.
34 | Hint: There is no perfect way ....`
35 | }
36 | ],
37 | videos: talks.map(talk => talk.video && talk.video)
38 | }
39 |
--------------------------------------------------------------------------------
/src/server/middleware/render.js:
--------------------------------------------------------------------------------
1 | /* global VENDOR_BUNDLE: true, CLIENT_BUNDLE: true */
2 | function render(req, res) {
3 | const context = {}
4 |
5 | if (context.url) {
6 | return res.redirect(302, context.url)
7 | }
8 |
9 | return res.status(context.status || 200).send(`
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Sara Vieira
29 |
30 |
31 |
32 |
33 |
37 |
38 |
39 |
54 |
55 |
56 | `)
57 | }
58 |
59 | export default render
60 |
--------------------------------------------------------------------------------
/webpack/webpack.server.babel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-unresolved, global-require */
2 | import nodeExternals from 'webpack-node-externals'
3 | import webpack from 'webpack'
4 |
5 | import common, {
6 | babelLoaderOptions,
7 | cssLoaderOptions,
8 | urlLoaderOptions
9 | } from './common'
10 |
11 | const isProduction = process.env.NODE_ENV === 'production'
12 |
13 | export default {
14 | name: 'server',
15 | entry: './src/server',
16 | target: 'node',
17 | node: {
18 | __dirname: false
19 | },
20 | output: {
21 | ...common.output,
22 | filename: 'server.js',
23 | libraryTarget: 'commonjs2'
24 | },
25 | module: {
26 | rules: [
27 | {
28 | test: /\.css$/,
29 | use: [
30 | {
31 | loader: 'style-loader'
32 | },
33 | {
34 | loader: 'css-loader',
35 | options: cssLoaderOptions
36 | }
37 | ]
38 | },
39 | {
40 | test: /\.js$/,
41 | exclude: /node_modules/,
42 | use: [
43 | {
44 | loader: 'babel-loader',
45 | options: {
46 | ...babelLoaderOptions,
47 | presets: [
48 | [
49 | 'env',
50 | {
51 | targets: {
52 | node: true
53 | },
54 | modules: false
55 | }
56 | ],
57 | 'react'
58 | ]
59 | }
60 | }
61 | ]
62 | },
63 | {
64 | test: /\.flow$/,
65 | use: 'null-loader'
66 | },
67 | {
68 | test: /\.graphql$/,
69 | use: 'raw-loader'
70 | },
71 | {
72 | include: /\.(png|jpeg|jpg|svg)$/,
73 | use: [
74 | {
75 | loader: 'url-loader',
76 | options: {
77 | ...urlLoaderOptions,
78 | emitFile: false
79 | }
80 | }
81 | ]
82 | }
83 | ]
84 | },
85 | plugins: [
86 | ...common.plugins,
87 | new webpack.DefinePlugin({
88 | CLIENT_BUNDLE: JSON.stringify(
89 | isProduction
90 | ? require('../build/assets.json').client.js
91 | : '/js/client.js'
92 | ),
93 | VENDOR_BUNDLE: JSON.stringify(
94 | isProduction
95 | ? require('../build/assets.json').vendor.js
96 | : '/js/vendor.js'
97 | ),
98 | 'process.env': {
99 | PORT: JSON.stringify(process.env.PORT)
100 | }
101 | })
102 | ],
103 | externals: [nodeExternals()],
104 | bail: isProduction
105 | }
106 |
--------------------------------------------------------------------------------
/webpack/webpack.client.babel.js:
--------------------------------------------------------------------------------
1 | import AssetsPlugin from 'assets-webpack-plugin'
2 | import WebpackMd5Hash from 'webpack-md5-hash'
3 | import webpack from 'webpack'
4 | import OfflinePlugin from 'offline-plugin'
5 | import common, {
6 | babelLoaderOptions,
7 | cssLoaderOptions,
8 | urlLoaderOptions
9 | } from './common'
10 |
11 | const isProduction = process.env.NODE_ENV === 'production'
12 |
13 | export default {
14 | name: 'client',
15 | entry: {
16 | client: [
17 | ...(!isProduction && ['webpack-hot-middleware/client']),
18 | './src/client'
19 | ]
20 | },
21 | output: {
22 | ...common.output,
23 | filename: `js/[name]${isProduction ? '.[chunkhash:8]' : ''}.js`
24 | },
25 | module: {
26 | rules: [
27 | {
28 | test: /\.css$/,
29 | use: [
30 | {
31 | loader: 'style-loader'
32 | },
33 | {
34 | loader: 'css-loader',
35 | options: cssLoaderOptions
36 | },
37 | {
38 | loader: 'postcss-loader',
39 | options: {
40 | plugins() {
41 | return [
42 | require('postcss-import')({
43 | path: ['src/app/styles']
44 | }),
45 | require('postcss-cssnext')({ apply: false }), // eslint-disable-line global-require
46 | require('postcss-apply')
47 | ]
48 | }
49 | }
50 | }
51 | ]
52 | },
53 | {
54 | test: /\.flow$/,
55 | use: 'null-loader'
56 | },
57 | {
58 | test: /\.js$/,
59 | exclude: /node_modules/,
60 | use: [
61 | {
62 | loader: 'babel-loader',
63 | options: {
64 | ...babelLoaderOptions,
65 | presets: [
66 | [
67 | 'env',
68 | {
69 | targets: {
70 | browsers: '> 1%, Last 2 versions'
71 | },
72 | modules: false
73 | }
74 | ],
75 | 'react'
76 | ]
77 | }
78 | }
79 | ]
80 | },
81 | {
82 | include: /\.(png|jpeg|jpg|svg)$/,
83 | use: [
84 | {
85 | loader: 'url-loader',
86 | options: urlLoaderOptions
87 | }
88 | ]
89 | }
90 | ]
91 | },
92 | plugins: [
93 | ...common.plugins,
94 | ...(isProduction
95 | ? [
96 | new AssetsPlugin({
97 | filename: 'assets.json',
98 | path: common.output.path
99 | })
100 | ]
101 | : [new webpack.HotModuleReplacementPlugin()]),
102 | new webpack.optimize.CommonsChunkPlugin({
103 | name: 'vendor',
104 | minChunks: ({ resource }) => /node_modules/.test(resource)
105 | }),
106 | new WebpackMd5Hash(),
107 | new OfflinePlugin()
108 | ],
109 | bail: isProduction
110 | }
111 |
--------------------------------------------------------------------------------
/yarn-error.log:
--------------------------------------------------------------------------------
1 | Arguments:
2 | /usr/local/bin/node /usr/local/Cellar/yarn/1.2.1/libexec/bin/yarn.js
3 |
4 | PATH:
5 | /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/flyingunicornaway/Library/Android/sdk/tools:/Users/flyingunicornaway/Library/Android/sdk/platform-tools
6 |
7 | Yarn version:
8 | 1.2.1
9 |
10 | Node version:
11 | 8.8.1
12 |
13 | Platform:
14 | darwin x64
15 |
16 | npm manifest:
17 | {
18 | "name": "react-starter",
19 | "version": "0.0.0",
20 | "private": true,
21 | "engines": {
22 | "node": ">=4"
23 | },
24 | "scripts": {
25 | "analyze": "webpack --config webpack/webpack.client.babel.js --profile --json > stats.json",
26 | "build": "npm run build:client && npm run build:server",
27 | "build:client": "webpack --progress --config webpack/webpack.client.babel.js",
28 | "build:server": "webpack --progress --config webpack/webpack.server.babel.js",
29 | "dev": "npm run build:server && node build/server",
30 | "lint": "eslint --ignore-path .gitignore .",
31 | "prebuild": "rimraf build/*",
32 | "start": "node build/server"
33 | },
34 | "devDependencies": {
35 | "eslint": "^4.10.0",
36 | "eslint-config-standard": "^10.2.1",
37 | "eslint-plugin-import": "^2.8.0",
38 | "eslint-plugin-node": "^5.2.1",
39 | "eslint-plugin-promise": "^3.6.0",
40 | "eslint-plugin-react": "7.4.0",
41 | "eslint-plugin-standard": "^3.0.1",
42 | "svg-inline-loader": "^0.8.0"
43 | },
44 | "dependencies": {
45 | "assets-webpack-plugin": "3.5.1",
46 | "axios": "^0.17.0",
47 | "babel-cli": "6.26.0",
48 | "babel-loader": "7.1.2",
49 | "babel-plugin-transform-object-rest-spread": "6.26.0",
50 | "babel-plugin-transform-react-remove-prop-types": "0.3.2",
51 | "babel-preset-env": "1.6.1",
52 | "babel-preset-react": "6.24.1",
53 | "compression": "1.7.1",
54 | "css-loader": "0.28.7",
55 | "date-fns": "^1.29.0",
56 | "eslint-plugin-react": "7.4.0",
57 | "express": "^4.16.2",
58 | "express-graphql": "^0.6.11",
59 | "extract-text-webpack-plugin": "3.0.2",
60 | "file-loader": "1.1.5",
61 | "graphql": "^0.11.7",
62 | "graphql-playground": "^1.1.0",
63 | "morgan": "1.9.0",
64 | "postcss-cssnext": "3.0.2",
65 | "postcss-loader": "2.0.8",
66 | "react": "16.0.0",
67 | "react-dom": "16.0.0",
68 | "react-router-dom": "4.2.2",
69 | "rimraf": "2.6.2",
70 | "url-loader": "0.6.2",
71 | "webpack": "3.8.1",
72 | "webpack-dev-middleware": "1.12.0",
73 | "webpack-hot-middleware": "2.20.0",
74 | "webpack-md5-hash": "0.0.5",
75 | "webpack-node-externals": "1.6.0"
76 | }
77 | }
78 |
79 | yarn manifest:
80 | No manifest
81 |
82 | Lockfile:
83 | No lockfile
84 |
85 | Trace:
86 | Error: https://registry.yarnpkg.com/assets-webpack-plugin: ETIMEDOUT
87 | at Timeout._onTimeout (/usr/local/Cellar/yarn/1.2.1/libexec/lib/cli.js:123675:19)
88 | at ontimeout (timers.js:471:11)
89 | at tryOnTimeout (timers.js:306:5)
90 | at Timer.listOnTimeout (timers.js:266:5)
91 |
--------------------------------------------------------------------------------
/src/server/data/projects.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | name: 'Isthereuber.in',
4 | description:
5 | 'A website that tells you if there is uber or other drive sharing apps in the city you type in',
6 | github: 'https://github.com/SaraVieira/uber-cities',
7 | website: 'https://isthereuber.in'
8 | },
9 | {
10 | name: 'Webpack.wtf',
11 | description: 'A simple website for all of us to share our webpack pains',
12 | github: 'https://github.com/SaraVieira/webpack.wtf',
13 | website: 'https://webpack.wtf'
14 | },
15 | {
16 | name: 'WutTheLint?',
17 | description: 'The proof that we have way too many linters',
18 | github: 'https://github.com/SaraVieira/wutthelint',
19 | website: 'https://wutthelint.now.sh'
20 | },
21 | {
22 | name: 'postcss-caralho',
23 | description:
24 | 'PostCSS plugin for that changes curse words after ! to !important because why not ?',
25 | github: 'https://github.com/SaraVieira/postcss-caralho'
26 | },
27 | {
28 | name: 'PreactCasts',
29 | description: 'ScreenCasts to help you get started with preact',
30 | website:
31 | 'https://www.youtube.com/watch?v=lF5TQwbYr9Q&list=PL1O2bxLvC8EPw09PKUl3smGrujiZbQFG9'
32 | },
33 | {
34 | name: 'Caninameit',
35 | description:
36 | 'A cli tool to help you see a npm name is already taken because this a problem now 😱',
37 | github: 'https://github.com/SaraVieira/caninameit'
38 | },
39 | {
40 | name: 'styled-loaders',
41 | description: 'Loaders Built with Preact and Styled Components',
42 | github: 'https://github.com/SaraVieira/styled-loaders',
43 | website: 'https://styled-loaders.now.sh/'
44 | },
45 | {
46 | name: 'vscode-preact-preact-router-snippets',
47 | description: 'Useful Preact Ecosystem snippets for Visual Studio Code',
48 | github:
49 | 'https://github.com/SaraVieira/vscode-preact-preact-router-snippets',
50 | website:
51 | 'https://marketplace.visualstudio.com/items?itemName=saravieira.preact-preact-router-snippets'
52 | },
53 | {
54 | name: 'randomoji',
55 | description: 'GET A RANDOM EMOJI',
56 | github: 'https://github.com/SaraVieira/randomoji'
57 | },
58 | {
59 | name: 'preact-cli-plugin-flow',
60 | description: 'Use flow with the Preact CLI',
61 | github: 'https://github.com/SaraVieira/preact-cli-plugin-flow'
62 | },
63 | {
64 | name: 'Eslint Config Flying Rocket 🚀',
65 | description:
66 | 'An ESLint Shareable Config for the style I use and you may like too 🍕',
67 | github: 'https://github.com/SaraVieira/eslint-config-flying-rocket'
68 | },
69 | {
70 | name: 'preact-cli-lodash',
71 | description: 'Minify build when using lodash and preact-cli',
72 | github: 'https://github.com/SaraVieira/preact-cli-lodash'
73 | },
74 | {
75 | name: 'preact-cli-postcss',
76 | description:
77 | 'Removes default postcss config and instead will use postcss.config.js',
78 | github: 'https://github.com/SaraVieira/preact-cli-postcss'
79 | },
80 | {
81 | name: 'isthereuber-db',
82 | description: 'DB of cities with uber',
83 | github: 'https://github.com/SaraVieira/isthereuber-db',
84 | website: 'https://isthereuber-db.now.sh/cities'
85 | }
86 | ]
87 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "GraphQL-portfolio",
3 | "version": "1.0.0",
4 | "engines": {
5 | "node": ">=4"
6 | },
7 | "scripts": {
8 | "analyze": "webpack --config webpack/webpack.client.babel.js --profile --json > stats.json",
9 | "build": "npm run build:client && npm run build:server",
10 | "now-build": "NODE_ENV=production npm run build:client -- -p && NODE_ENV=production npm run build:server -- -p",
11 | "build:client": "webpack --progress --config webpack/webpack.client.babel.js",
12 | "build:server": "webpack --progress --config webpack/webpack.server.babel.js",
13 | "pretty": "prettier-standard {src,webpack}/**/*.js --single-quote",
14 | "dev": "npm run build:server && node build/server",
15 | "lint": "eslint --ignore-path .gitignore .",
16 | "prebuild": "rimraf build/*",
17 | "start": "node build/server",
18 | "precommit": "lint-staged"
19 | },
20 | "lint-staged": {
21 | "*.js": [
22 | "npm run pretty",
23 | "git add"
24 | ]
25 | },
26 | "devDependencies": {
27 | "eslint": "^4.10.0",
28 | "eslint-config-prettier": "^2.7.0",
29 | "eslint-config-prettier-standard": "^1.0.1",
30 | "eslint-config-standard": "^10.2.1",
31 | "eslint-config-standard-react": "^5.0.0",
32 | "eslint-plugin-import": "^2.8.0",
33 | "eslint-plugin-node": "^5.2.1",
34 | "eslint-plugin-prettier": "^2.3.1",
35 | "eslint-plugin-promise": "^3.6.0",
36 | "eslint-plugin-react": "7.4.0",
37 | "eslint-plugin-standard": "^3.0.1",
38 | "husky": "^0.14.3",
39 | "lint-staged": "^4.3.0",
40 | "nodemon": "^1.12.1",
41 | "null-loader": "^0.1.1",
42 | "offline-plugin": "^4.8.4",
43 | "postcss-apply": "^0.8.0",
44 | "postcss-import": "^11.0.0",
45 | "prettier": "^1.7.4",
46 | "prettier-standard": "^7.0.3",
47 | "raw-loader": "^0.5.1"
48 | },
49 | "dependencies": {
50 | "assets-webpack-plugin": "3.5.1",
51 | "axios": "^0.17.0",
52 | "babel-cli": "6.26.0",
53 | "babel-loader": "7.1.2",
54 | "babel-plugin-transform-object-rest-spread": "6.26.0",
55 | "babel-plugin-transform-react-remove-prop-types": "0.3.2",
56 | "babel-preset-env": "1.6.1",
57 | "babel-preset-react": "6.24.1",
58 | "compression": "1.7.1",
59 | "css-loader": "0.28.7",
60 | "curse-words-common": "^1.1.0",
61 | "date-fns": "^1.29.0",
62 | "eslint-plugin-react": "7.4.0",
63 | "express": "^4.16.2",
64 | "express-graphql": "^0.6.11",
65 | "file-loader": "1.1.5",
66 | "graphiql": "^0.11.10",
67 | "graphiql-material-theme": "^1.0.3",
68 | "graphql": "^0.11.7",
69 | "graphql-tools": "^2.7.2",
70 | "isomorphic-fetch": "^2.2.1",
71 | "morgan": "1.9.0",
72 | "normalize.css": "^7.0.0",
73 | "postcss-cssnext": "3.0.2",
74 | "postcss-loader": "2.0.8",
75 | "react": "16.0.0",
76 | "react-dom": "16.0.0",
77 | "react-router-dom": "4.2.2",
78 | "rimraf": "2.6.2",
79 | "style-jsx": "^0.0.0",
80 | "style-loader": "^0.19.0",
81 | "unique-random-array": "^1.0.0",
82 | "url-loader": "0.6.2",
83 | "webpack": "3.8.1",
84 | "webpack-dev-middleware": "1.12.0",
85 | "webpack-hot-middleware": "2.20.0",
86 | "webpack-md5-hash": "0.0.5",
87 | "webpack-node-externals": "1.6.0"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/server/data/talks.js:
--------------------------------------------------------------------------------
1 | const isPast = require('date-fns/is_past')
2 |
3 | const talks = [
4 | {
5 | name: 'CSS Hates You',
6 | event: 'Mtalks',
7 | date: new Date(2017, 5, 14),
8 | done: !!isPast(new Date(2017, 5, 14)),
9 | video: 'https://youtu.be/gwW36kV9TV4?t=10s',
10 | slides:
11 | 'https://github.com/SaraVieira/talks/blob/master/CSS%20Hates%20You.pptx',
12 | location: 'Porto, Portugal'
13 | },
14 | {
15 | name: "There's a whole new world offline",
16 | event: 'Require("lx")',
17 | date: new Date(2017, 6, 6),
18 | done: !!isPast(new Date(2017, 6, 6)),
19 | video: 'https://www.youtube.com/watch?v=ZvA41uuyujA',
20 | slides:
21 | 'https://docs.google.com/presentation/d/1vQ9xAijI8NjbQkFESu0LwVYEcpCxqQhcjC7ESzddMTE/edit#slide=id.p',
22 | location: 'Lisbon, Portugal'
23 | },
24 | {
25 | name: 'CSS Hates You',
26 | event: 'Formidable & Friends Birthday Bash!',
27 | date: new Date(2017, 10, 9),
28 | done: !!isPast(new Date(2017, 10, 9)),
29 | slides:
30 | 'https://drive.google.com/open?id=1lwjwVFpC_hnxZE7aUiuetgzHoEG87cxrzQ4oItdCAo4',
31 | location: 'London, UK'
32 | },
33 | {
34 | name: 'We need to talk about Preact',
35 | event: 'JS Roundabout',
36 | date: new Date(2017, 10, 8),
37 | done: !!isPast(new Date(2017, 10, 8)),
38 | slides:
39 | 'https://drive.google.com/open?id=1BJRGOBNySWpN7NRkr1kQVI1ul7EG9SCo5t4NSnFJrSM',
40 | video: 'https://www.youtube.com/watch?v=Bb3Vyj0KTd4',
41 | location: 'London, UK'
42 | },
43 | {
44 | name: 'We need to talk about Preact',
45 | event: 'React Day Berlin',
46 | date: new Date(2017, 11, 2),
47 | done: !!isPast(new Date(2017, 11, 2)),
48 | video: 'https://www.youtube.com/watch?v=jqXRSvXWYf8',
49 | slides:
50 | 'https://drive.google.com/open?id=1BJRGOBNySWpN7NRkr1kQVI1ul7EG9SCo5t4NSnFJrSM',
51 | location: 'Berlin, Germany'
52 | },
53 | {
54 | name: 'We need to talk about Preact',
55 | event: 'EnterJS',
56 | date: new Date(2018, 20, 5),
57 | done: !!isPast(new Date(2018, 20, 5)),
58 | location: 'Darmstadt, Germany'
59 | },
60 | {
61 | name: 'We need to talk about Preact',
62 | event: 'React Vienna',
63 | date: new Date(2017, 0, 18),
64 | done: !!isPast(new Date(2017, 0, 18)),
65 | video: 'https://www.youtube.com/watch?v=bYdeMvr5Aus',
66 | slides:
67 | 'https://drive.google.com/open?id=1BJRGOBNySWpN7NRkr1kQVI1ul7EG9SCo5t4NSnFJrSM',
68 | location: 'Vienna, Autria'
69 | },
70 | {
71 | name: "Your brain doesn't have a --fix flag",
72 | event: 'Agent Conf',
73 | date: new Date(2018, 0, 25),
74 | done: !!isPast(new Date(2018, 0, 25)),
75 | location: 'Dornbirn, Austria',
76 | slides: 'https://brain-fix.now.sh'
77 | },
78 | {
79 | name: "Your brain doesn't have a --fix flag",
80 | event: 'Front End NE',
81 | date: new Date(2018, 3, 5),
82 | done: !!isPast(new Date(2018, 3, 5)),
83 | location: 'Newcastle, UK',
84 | slides: 'https://brain-fix.now.sh'
85 | },
86 | {
87 | name: 'Testing React Applications',
88 | event: 'React Finland',
89 | date: new Date(2018, 3, 25),
90 | done: !!isPast(new Date(2018, 3, 25)),
91 | location: 'Helsinki, Finland'
92 | },
93 | {
94 | event: 'React Fest',
95 | name: 'The lonely and dark road to Styling in React',
96 | date: new Date(2018, 2, 9),
97 | done: !!isPast(new Date(2018, 2, 9)),
98 | location: 'London, UK'
99 | },
100 |
101 | {
102 | event: 'JSHeroes',
103 | date: new Date(2018, 3, 18),
104 | done: !!isPast(new Date(2018, 3, 18)),
105 | location: 'Cluj-Napoca, Romania'
106 | },
107 | {
108 | event: 'Graphql Europe',
109 | date: new Date(2018, 5, 15),
110 | done: !!isPast(new Date(2018, 5, 15)),
111 | location: 'Berlin, Germany'
112 | },
113 | {
114 | event: 'Front End United',
115 | date: new Date(2018, 4, 31),
116 | done: !!isPast(new Date(2018, 4, 31)),
117 | location: 'Utrecht, Netherlands'
118 | },
119 | {
120 | name: 'Styleguide Driven Development',
121 | event: 'React Girls London',
122 | date: new Date(2017, 8, 26),
123 | done: !!isPast(new Date(2017, 8, 26)),
124 | slides: 'https://github.com/SaraVieira/styleguide-driven-development',
125 | location: 'London, UK'
126 | },
127 | {
128 | name: 'Styleguide Driven Development',
129 | event: 'React Alicante',
130 | date: new Date(2017, 9, 30),
131 | done: !!isPast(new Date(2017, 9, 30)),
132 | slides: 'https://github.com/SaraVieira/styleguide-driven-development',
133 | video: 'https://www.youtube.com/watch?v=JjXnmhNW8Cs',
134 | location: 'Alicante, Spain'
135 | },
136 | {
137 | name: "The Hitchhiker's Guide to the Webpack",
138 | event: 'Codemotion Amsterdam',
139 | date: new Date(2016, 4, 16),
140 | done: !!isPast(new Date(2016, 4, 16)),
141 | video: 'https://www.youtube.com/watch?v=Zor8E6_ZoVA',
142 | slides:
143 | 'https://github.com/SaraVieira/talks/blob/master/Codemotion%20Amsterdam.pptx',
144 | location: 'Amsterdam, Netherlands'
145 | },
146 | {
147 | name: 'CSS3 Layouts: Flexbox vs CSS Grid',
148 | event: 'Codemotion Milan',
149 | date: new Date(2015, 10, 20),
150 | done: !!isPast(new Date(2015, 10, 20)),
151 | video: 'https://www.youtube.com/watch?v=b-in0QpvDiQ',
152 | slides:
153 | 'https://github.com/SaraVieira/talks/blob/master/Codemotion%20Amsterdam.pptx',
154 | location: 'Milan, Italy'
155 | },
156 | {
157 | name: 'CSS as a programming language',
158 | event: 'Front Trends',
159 | date: new Date(2014, 4, 20),
160 | done: !!isPast(new Date(2014, 4, 20)),
161 | video: 'https://vimeo.com/105956446',
162 | slides:
163 | 'https://github.com/SaraVieira/talks/tree/master/css-as-programming-language',
164 | location: 'Warsaw, Poland'
165 | },
166 | {
167 | name: 'Front-end Tools and Workflows',
168 | event: 'QCon London 2015',
169 | date: new Date(2015, 5, 20),
170 | done: !!isPast(new Date(2015, 5, 20)),
171 | video: 'https://www.infoq.com/presentations/front-end-tools-workflows',
172 | location: 'London, UK'
173 | }
174 | ]
175 |
176 | module.exports = talks.sort((a, b) => (a.date > b.date ? -1 : 1))
177 |
--------------------------------------------------------------------------------
/src/app/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------