mirror of
https://github.com/BradNut/awesome-uses
synced 2025-09-08 17:40:31 +00:00
It's a site
This commit is contained in:
parent
8dde1405ba
commit
14c9b52729
20 changed files with 18350 additions and 1 deletions
71
.gitignore
vendored
71
.gitignore
vendored
|
|
@ -1,2 +1,71 @@
|
||||||
.idea
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# gatsby files
|
||||||
|
.cache/
|
||||||
|
public
|
||||||
|
|
||||||
|
# Mac files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
yarn-error.log
|
||||||
|
.pnp/
|
||||||
|
.pnp.js
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
haters/
|
||||||
|
|
|
||||||
3
README.md
Normal file
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
## /uses website
|
||||||
|
|
||||||
|
Add yourself [here](./src/data.js)
|
||||||
6
gatsby-browser.js
Normal file
6
gatsby-browser.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { FilterProvider } from './src/context/FilterContext';
|
||||||
|
|
||||||
|
export const wrapRootElement = ({ element }) => (
|
||||||
|
<FilterProvider>{element}</FilterProvider>
|
||||||
|
)
|
||||||
30
gatsby-config.js
Normal file
30
gatsby-config.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
module.exports = {
|
||||||
|
siteMetadata: {
|
||||||
|
title: `/uses`,
|
||||||
|
description: `A list of /uses pages detailing developer setups.`,
|
||||||
|
author: `@wesbos`,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
resolve: `gatsby-source-filesystem`,
|
||||||
|
options: {
|
||||||
|
name: `images`,
|
||||||
|
path: `${__dirname}/src/images`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
`gatsby-transformer-sharp`,
|
||||||
|
`gatsby-plugin-sharp`,
|
||||||
|
{
|
||||||
|
resolve: `gatsby-plugin-manifest`,
|
||||||
|
options: {
|
||||||
|
name: `gatsby-starter-default`,
|
||||||
|
short_name: `starter`,
|
||||||
|
start_url: `/`,
|
||||||
|
background_color: `#663399`,
|
||||||
|
theme_color: `#663399`,
|
||||||
|
display: `minimal-ui`,
|
||||||
|
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
60
gatsby-node.js
Normal file
60
gatsby-node.js
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import people from './src/data.js';
|
||||||
|
import { tags, countries } from './src/util/stats';
|
||||||
|
|
||||||
|
function sourceNodes({ actions, createNodeId, createContentDigest }) {
|
||||||
|
// Add People to the GraphQL API, we randomize the data on each build so no one gets their feelings hurt
|
||||||
|
people
|
||||||
|
.sort(() => Math.random() - 0.5)
|
||||||
|
.forEach(person => {
|
||||||
|
const nodeMeta = {
|
||||||
|
id: createNodeId(`person-${person.name}`),
|
||||||
|
parent: null,
|
||||||
|
children: [],
|
||||||
|
internal: {
|
||||||
|
type: `Person`,
|
||||||
|
mediaType: `text/html`,
|
||||||
|
content: JSON.stringify(person),
|
||||||
|
contentDigest: createContentDigest(person),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.createNode({ ...person, ...nodeMeta });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add tags to GraphQL API
|
||||||
|
tags().forEach(tag => {
|
||||||
|
const nodeMeta = {
|
||||||
|
id: createNodeId(`tag-${tag.name}`),
|
||||||
|
parent: null,
|
||||||
|
children: [],
|
||||||
|
internal: {
|
||||||
|
type: `Tag`,
|
||||||
|
mediaType: `text/html`,
|
||||||
|
content: JSON.stringify(tag),
|
||||||
|
contentDigest: createContentDigest(tag),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.createNode({ ...tag, ...nodeMeta });
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(countries());
|
||||||
|
// Add Countries to GraphQL API
|
||||||
|
countries().forEach(country => {
|
||||||
|
const nodeMeta = {
|
||||||
|
id: createNodeId(`country-${country.name}`),
|
||||||
|
parent: null,
|
||||||
|
children: [],
|
||||||
|
internal: {
|
||||||
|
type: `Country`,
|
||||||
|
mediaType: `text/html`,
|
||||||
|
content: JSON.stringify(country),
|
||||||
|
contentDigest: createContentDigest(country),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
actions.createNode({ ...country, ...nodeMeta });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { sourceNodes };
|
||||||
17250
package-lock.json
generated
Normal file
17250
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
50
package.json
Normal file
50
package.json
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"name": "uses",
|
||||||
|
"description": "What do you uses",
|
||||||
|
"version": "7.7.7",
|
||||||
|
"author": "Wes Bos",
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"wesbos"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"country-emoji": "^1.5.0",
|
||||||
|
"esm": "^3.2.25",
|
||||||
|
"gatsby": "^2.18.12",
|
||||||
|
"gatsby-image": "^2.2.34",
|
||||||
|
"gatsby-plugin-manifest": "^2.2.31",
|
||||||
|
"gatsby-plugin-offline": "^3.0.27",
|
||||||
|
"gatsby-plugin-react-helmet": "^3.1.16",
|
||||||
|
"gatsby-plugin-sharp": "^2.3.5",
|
||||||
|
"gatsby-source-filesystem": "^2.1.40",
|
||||||
|
"gatsby-transformer-sharp": "^2.3.7",
|
||||||
|
"normalize.css": "^8.0.1",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react": "^16.12.0",
|
||||||
|
"react-dom": "^16.12.0",
|
||||||
|
"react-helmet": "^5.2.1",
|
||||||
|
"styled-components": "^4.4.1"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "npx --node-arg '-r esm' gatsby build",
|
||||||
|
"develop": "npx --node-arg '-r esm' gatsby develop",
|
||||||
|
"start": "npm run develop",
|
||||||
|
"serve": "npx --node-arg '-r esm' gatsby serve",
|
||||||
|
"clean": "gatsby clean"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-eslint": "^9.0.0",
|
||||||
|
"eslint": "^5.16.0",
|
||||||
|
"eslint-config-airbnb": "^17.1.1",
|
||||||
|
"eslint-config-prettier": "^4.3.0",
|
||||||
|
"eslint-config-wesbos": "0.0.19",
|
||||||
|
"eslint-plugin-html": "^5.0.5",
|
||||||
|
"eslint-plugin-import": "^2.19.1",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||||
|
"eslint-plugin-prettier": "^3.1.2",
|
||||||
|
"eslint-plugin-react": "^7.17.0",
|
||||||
|
"eslint-plugin-react-hooks": "^1.7.0",
|
||||||
|
"prettier": "^1.19.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/components/Person.js
Normal file
69
src/components/Person.js
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { name } from 'country-emoji';
|
||||||
|
import iphone from '../../public/icons/iphone.png';
|
||||||
|
import android from '../../public/icons/android.png';
|
||||||
|
import windows from '../../public/icons/windows.svg';
|
||||||
|
import apple from '../../public/icons/apple.svg';
|
||||||
|
|
||||||
|
const icons = { iphone, android, windows, apple };
|
||||||
|
export default function Person({ person, currentTag }) {
|
||||||
|
const url = new URL(person.url);
|
||||||
|
const img = `https://logo.clearbit.com/${url.host}`;
|
||||||
|
return (
|
||||||
|
<div className="person">
|
||||||
|
<div className="personInner">
|
||||||
|
<img width="50" src={img} alt={person.name} />
|
||||||
|
<h3>
|
||||||
|
<a href={person.url} target="_blank" rel="noopener noreferrer">
|
||||||
|
{person.name} {person.emoji}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
<a
|
||||||
|
className="displayLink"
|
||||||
|
href={person.url}
|
||||||
|
>{`${url.host}${url.pathname}`}</a>
|
||||||
|
<p>{person.description}</p>
|
||||||
|
|
||||||
|
<ul className="tags">
|
||||||
|
{person.tags.map(tag => (
|
||||||
|
<li
|
||||||
|
key={tag}
|
||||||
|
className={`tag ${tag === currentTag ? 'currentTag' : ''}`}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="deets">
|
||||||
|
<span className="country" title={name(person.country)}>
|
||||||
|
{person.country}
|
||||||
|
</span>
|
||||||
|
{person.computer && (
|
||||||
|
<span title={`Computer: ${person.computer}`}>
|
||||||
|
<img
|
||||||
|
height="40"
|
||||||
|
src={icons[person.computer]}
|
||||||
|
alt={person.computer}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{person.phone && (
|
||||||
|
<span title={`Uses an ${person.phone}`}>
|
||||||
|
<img height="50" src={icons[person.phone]} alt={person.phone} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{person.twitter && (
|
||||||
|
<span>
|
||||||
|
<a href={`https://twitter.com/${person.twitter}`}>
|
||||||
|
<span className="at">@</span>
|
||||||
|
{person.twitter.replace('@', '')}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{person.github && <span>{person.github}</span>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
51
src/components/Topics.js
Normal file
51
src/components/Topics.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import FilterContext from '../context/FilterContext';
|
||||||
|
|
||||||
|
export default function Topics() {
|
||||||
|
const { countries, tags, currentTag, setCurrentTag } = useContext(
|
||||||
|
FilterContext
|
||||||
|
);
|
||||||
|
console.log(countries);
|
||||||
|
return (
|
||||||
|
<div className="tags">
|
||||||
|
{tags.map(tag => (
|
||||||
|
<label
|
||||||
|
className={`tag ${tag.name === currentTag ? 'currentTag' : ''}`}
|
||||||
|
htmlFor={`filter-${tag.name}`}
|
||||||
|
key={`filter-${tag.name}`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="tag"
|
||||||
|
id={`filter-${tag.name}`}
|
||||||
|
value={tag.name}
|
||||||
|
checked={tag.name === currentTag}
|
||||||
|
onChange={e => setCurrentTag(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
{tag.name}
|
||||||
|
<span className="count">{tag.count}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{countries.map(tag => (
|
||||||
|
<label
|
||||||
|
className={`tag ${tag.emoji === currentTag ? 'currentTag' : ''}`}
|
||||||
|
htmlFor={`filter-${tag.name}`}
|
||||||
|
key={`filter-${tag.name}`}
|
||||||
|
title={tag.name}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="tag"
|
||||||
|
id={`filter-${tag.name}`}
|
||||||
|
value={tag.emoji}
|
||||||
|
checked={tag.emoji === currentTag}
|
||||||
|
onChange={e => setCurrentTag(e.currentTarget.value)}
|
||||||
|
/>
|
||||||
|
<span className="emoji">{tag.emoji}</span>
|
||||||
|
<span className="count">{tag.count}</span>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
src/components/header.js
Normal file
26
src/components/header.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { Link } from 'gatsby';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const Header = ({ siteTitle }) => (
|
||||||
|
<header className="header">
|
||||||
|
<div>
|
||||||
|
<h1>
|
||||||
|
<Link to="/">/uses</Link>
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
A list of <code>/uses</code> pages detailing developer setups.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
|
||||||
|
Header.propTypes = {
|
||||||
|
siteTitle: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
Header.defaultProps = {
|
||||||
|
siteTitle: ``,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
32
src/components/image.js
Normal file
32
src/components/image.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from "react"
|
||||||
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
import Img from "gatsby-image"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This component is built using `gatsby-image` to automatically serve optimized
|
||||||
|
* images with lazy loading and reduced file sizes. The image is loaded using a
|
||||||
|
* `useStaticQuery`, which allows us to load the image from directly within this
|
||||||
|
* component, rather than having to pass the image data down from pages.
|
||||||
|
*
|
||||||
|
* For more information, see the docs:
|
||||||
|
* - `gatsby-image`: https://gatsby.dev/gatsby-image
|
||||||
|
* - `useStaticQuery`: https://www.gatsbyjs.org/docs/use-static-query/
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Image = () => {
|
||||||
|
const data = useStaticQuery(graphql`
|
||||||
|
query {
|
||||||
|
placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
|
||||||
|
childImageSharp {
|
||||||
|
fluid(maxWidth: 300) {
|
||||||
|
...GatsbyImageSharpFluid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Image
|
||||||
184
src/components/layout.css
Normal file
184
src/components/layout.css
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
html {
|
||||||
|
--purple: #1e1f5c;
|
||||||
|
--blue: #203447;
|
||||||
|
--lightblue: #1f4662;
|
||||||
|
--blue2: #1C2F40;
|
||||||
|
--yellow: #ffc600;
|
||||||
|
--pink: #EB4471;
|
||||||
|
--vape: #d7d7d7;
|
||||||
|
background: var(--blue);
|
||||||
|
color: var(--vape);
|
||||||
|
font-family: 'Fira Mono';
|
||||||
|
font-weight: 100;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background: var(--yellow);
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,h2,h3,h4,h5,h6 {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1 a {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--yellow);
|
||||||
|
text-decoration-color: var(--pink);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site {
|
||||||
|
max-width: 1900px;
|
||||||
|
margin: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h1 {
|
||||||
|
font-size: 6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 3rem;
|
||||||
|
max-width: 1900px;
|
||||||
|
padding: 0 3rem;
|
||||||
|
margin: 5rem auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.people {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||||
|
grid-gap: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person {
|
||||||
|
border: 1px solid var(--vape);
|
||||||
|
border-radius: 5.34334px;
|
||||||
|
box-shadow: 10px -10px 0 var(--blue2);
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 1fr auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.personInner {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person .tag {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name.last {
|
||||||
|
font-size: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deets {
|
||||||
|
display: flex;
|
||||||
|
border-block-start: 1px solid var(--vape);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deets > * {
|
||||||
|
flex: 1;
|
||||||
|
border-inline-start: 1px solid var(--vape);
|
||||||
|
text-align: center;
|
||||||
|
padding: 1rem;
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deets a {
|
||||||
|
color: var(--vape);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deets .at {
|
||||||
|
color: var(--yellow);
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deets :first-child {
|
||||||
|
border-inline-start: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deets .country {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
.deets .phone {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayLink {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--vape);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.displayLink:hover {
|
||||||
|
color: var(--pink);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
background: var(--pink);
|
||||||
|
margin: 2px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 1.7rem;
|
||||||
|
padding: 5px;
|
||||||
|
color: hsla(0, 100%, 100%, 0.8);
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag input { display: none; }
|
||||||
|
|
||||||
|
.tag.currentTag {
|
||||||
|
background: var(--yellow);
|
||||||
|
color: hsla(0, 100%, 0%, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag .emoji {
|
||||||
|
text-shadow: 0 0 1px 2px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag .count {
|
||||||
|
background: var(--blue);
|
||||||
|
font-size: 1rem;
|
||||||
|
color: white;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
46
src/components/layout.js
Normal file
46
src/components/layout.js
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* Layout component that queries for data
|
||||||
|
* with Gatsby's useStaticQuery component
|
||||||
|
*
|
||||||
|
* See: https://www.gatsbyjs.org/docs/use-static-query/
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useStaticQuery, graphql } from 'gatsby';
|
||||||
|
|
||||||
|
import Header from './header';
|
||||||
|
import 'normalize.css';
|
||||||
|
import './layout.css';
|
||||||
|
|
||||||
|
const Layout = ({ children }) => {
|
||||||
|
const data = useStaticQuery(graphql`
|
||||||
|
query SiteTitleQuery {
|
||||||
|
site {
|
||||||
|
siteMetadata {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header siteTitle={data.site.siteMetadata.title} />
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
<footer>
|
||||||
|
© {new Date().getFullYear() - Math.floor(Math.random() * 777)} Made by{' '}
|
||||||
|
<a href="https://wesbos.com">Wes Bos</a> with{' '}
|
||||||
|
<a href="https://www.gatsbyjs.org">Gatsby</a>. Icons from icons8.com.
|
||||||
|
</footer>
|
||||||
|
</main>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Layout.propTypes = {
|
||||||
|
children: PropTypes.node.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
41
src/context/FilterContext.js
Normal file
41
src/context/FilterContext.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import React, { createContext, useState } from 'react';
|
||||||
|
import { useStaticQuery, graphql } from 'gatsby';
|
||||||
|
|
||||||
|
const FilterContext = createContext();
|
||||||
|
|
||||||
|
const FilterProvider = function({ children }) {
|
||||||
|
const [currentTag, setCurrentTag] = useState('all');
|
||||||
|
|
||||||
|
const { allTag, allCountry } = useStaticQuery(graphql`
|
||||||
|
query FilterQuery {
|
||||||
|
allTag {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allCountry {
|
||||||
|
nodes {
|
||||||
|
count
|
||||||
|
emoji
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
return (
|
||||||
|
<FilterContext.Provider
|
||||||
|
value={{
|
||||||
|
tags: allTag.nodes,
|
||||||
|
countries: allCountry.nodes,
|
||||||
|
currentTag,
|
||||||
|
setCurrentTag,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</FilterContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FilterContext;
|
||||||
|
export { FilterProvider };
|
||||||
323
src/data.js
Normal file
323
src/data.js
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
// Add yourself. Insert an object at any point - it doesn't matter if you go before someone else as results are randomized.
|
||||||
|
|
||||||
|
// please remove the comments before You PR
|
||||||
|
const pages = [
|
||||||
|
{
|
||||||
|
name: 'Wes Bos',
|
||||||
|
// Short description
|
||||||
|
description:
|
||||||
|
'Maker of this site. Web Developer, Tutorial Maker, Podcaster, BBQ Lover',
|
||||||
|
// URL to your /uses page
|
||||||
|
url: 'https://wesbos.com/uses',
|
||||||
|
twitter: '@wesbos',
|
||||||
|
// An emoji that describes you
|
||||||
|
emoji: '🔥',
|
||||||
|
// emoji of your country's flag
|
||||||
|
country: '🇨🇦',
|
||||||
|
// ONE of: apple, windows or linux
|
||||||
|
computer: 'apple',
|
||||||
|
// iphone or android
|
||||||
|
phone: 'iphone',
|
||||||
|
// Tags - You can add your own, but please keep it to one word. "Social vape entrepreneur influencer denver" isn't a tag.
|
||||||
|
|
||||||
|
// Dev Tags: Engineer, Developer, Designer, Front End, Back End, Full Stack,
|
||||||
|
// Other: Tags: Entrepreneur, Teacher, Podcaster, YouTuber, Blogger, Speaker,
|
||||||
|
// Language Tags: JavaScript, PHP, Rails, Ruby, TypeScript...
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'Entrepreneur',
|
||||||
|
'Teacher',
|
||||||
|
'YouTuber',
|
||||||
|
'JavaScript',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Troy Forster',
|
||||||
|
description: 'Consulting Technology Director and CTO for Hire',
|
||||||
|
url: 'https://tforster.com/uses',
|
||||||
|
twitter: '@tforster',
|
||||||
|
emoji: '',
|
||||||
|
country: '🇨🇦',
|
||||||
|
computer: 'windows',
|
||||||
|
phone: 'android',
|
||||||
|
tags: [
|
||||||
|
'Engineer',
|
||||||
|
'Back End',
|
||||||
|
'Front End',
|
||||||
|
'Consultant',
|
||||||
|
'Entrepreneur',
|
||||||
|
'JavaScript',
|
||||||
|
'C#',
|
||||||
|
'PHP',
|
||||||
|
'Serverless',
|
||||||
|
'SOA',
|
||||||
|
'Enterprise',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Kent C. Dodds',
|
||||||
|
description: 'JavaScript Software Engineer, speaker, and trainer',
|
||||||
|
url: 'https://kentcdodds.com/uses',
|
||||||
|
emoji: '🙌',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'android',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'Entrepreneur',
|
||||||
|
'Teacher',
|
||||||
|
'YouTuber',
|
||||||
|
'JavaScript',
|
||||||
|
'Testing',
|
||||||
|
'React',
|
||||||
|
'Speaker',
|
||||||
|
'Blogger',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Glenn Reyes',
|
||||||
|
description:
|
||||||
|
'Independent Software Engineer, trainer & speaker. Into sports & music.',
|
||||||
|
url: 'https://glennreyes.com/uses',
|
||||||
|
emoji: '💃',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Front End',
|
||||||
|
'Entrepreneur',
|
||||||
|
'Teacher',
|
||||||
|
'JavaScript',
|
||||||
|
'React',
|
||||||
|
'GraphQL',
|
||||||
|
'TypeScript',
|
||||||
|
'Speaker',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Adam Jahnke',
|
||||||
|
description:
|
||||||
|
'Caffiend, motorcyclist, climber, recovering perfectionist. I love to make the complex simple.',
|
||||||
|
url: 'https://adamyonk.com/uses',
|
||||||
|
emoji: '⤫',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: ['Engineer', 'Full Stack', 'JavaScript', 'Ruby'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Andrew Healey',
|
||||||
|
description: 'Software Engineer, Writer, Learner!',
|
||||||
|
url: 'https://healeycodes.com/uses',
|
||||||
|
emoji: '🦉',
|
||||||
|
country: '🇬🇧',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: ['Software Engineer', 'Full Stack', 'JavaScript', 'Python', 'Writer'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Scott Tolinski',
|
||||||
|
description: 'Web Developer, Tutorial Maker, Podcaster, Bboy',
|
||||||
|
url: 'https://kit.com/leveluptutorials/podcasting-screencasting-gear',
|
||||||
|
emoji: '💪🏻',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: ['Developer', 'FrontEnd', 'Entrepreneur', 'Teacher', 'JavaScript'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Josiah Wiebe',
|
||||||
|
description: 'Designer & developer, lifelong learner.',
|
||||||
|
url: 'https://jwie.be/uses/',
|
||||||
|
emoji: '🚴',
|
||||||
|
country: '🇨🇦',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Full Stack',
|
||||||
|
'Developer',
|
||||||
|
'Designer',
|
||||||
|
'Python',
|
||||||
|
'JavaScript',
|
||||||
|
'TypeScript',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Benjamin Lannon',
|
||||||
|
description: 'Web Developer, Open Source Contributor, Livestreamer',
|
||||||
|
url: 'https://lannonbr.com/uses/',
|
||||||
|
emoji: '🎤',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'Blogger',
|
||||||
|
'Teacher',
|
||||||
|
'JavaScript',
|
||||||
|
'GraphQL',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nuno Maduro',
|
||||||
|
description: 'Software engineer, Open Source contributor, Speaker',
|
||||||
|
url: 'https://nunomaduro.com/uses/',
|
||||||
|
emoji: '🏄♂️',
|
||||||
|
country: '🇵🇹',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Engineer',
|
||||||
|
'Developer',
|
||||||
|
'Speaker',
|
||||||
|
'PHP',
|
||||||
|
'JavaScript',
|
||||||
|
'TypeScript',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Adrian Marin',
|
||||||
|
description:
|
||||||
|
'Product-Minded Software Engineer, Digital nomad, no-nonsense enjoyer of life, friends and family.',
|
||||||
|
url: 'https://adrianthedev.com/uses',
|
||||||
|
twitter: '@adrianthedev',
|
||||||
|
emoji: '🥑',
|
||||||
|
country: '🇷🇴',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: ['Developer', 'Full Stack', 'Entrepreneur', 'Rails', 'TypeScript'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Jahir Fiquitiva',
|
||||||
|
description: 'Passionate and Creative Full Stack Developer',
|
||||||
|
url: 'https://jahir.dev/uses',
|
||||||
|
twitter: '@jahirfiquitiva',
|
||||||
|
emoji: '💎',
|
||||||
|
country: '🇨🇴',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'JavaScript',
|
||||||
|
'Kotlin',
|
||||||
|
'Python',
|
||||||
|
'Kotlin',
|
||||||
|
'React',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Brad Garropy',
|
||||||
|
description:
|
||||||
|
'Self taught frontender at Adobe, into lifting and country music.',
|
||||||
|
url: 'https://bradgarropy.com/uses',
|
||||||
|
twitter: '@bradgarropy',
|
||||||
|
emoji: '🤠',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'windows',
|
||||||
|
phone: 'android',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Front End',
|
||||||
|
'Full Stack',
|
||||||
|
'Streamer',
|
||||||
|
'YouTuber',
|
||||||
|
'Blogger',
|
||||||
|
'JavaScript',
|
||||||
|
'Python',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Josh Barker',
|
||||||
|
description:
|
||||||
|
'Front end engineer at Red Ventures. Soccer enthusiast. Lover of stories.',
|
||||||
|
url: 'https://joshuabarker.com/uses',
|
||||||
|
twitter: '@joshuafbarker',
|
||||||
|
emoji: '⚽️',
|
||||||
|
country: '🇺🇸',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: ['Developer', 'Front End', 'JavaScript'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Aaron Dunphy',
|
||||||
|
description: 'Full Stack Developer, Coffee Lover and Photo Taker',
|
||||||
|
url: 'https://aarondunphy.com/uses',
|
||||||
|
twitter: '@aaronjohndunphy',
|
||||||
|
emoji: '📷',
|
||||||
|
country: '🇬🇧',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'Back End',
|
||||||
|
'Laravel',
|
||||||
|
'PHP',
|
||||||
|
'JavaScript',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Mohamed Benhida',
|
||||||
|
description: 'Web Developer, Open source contributor.',
|
||||||
|
url: 'http://mohamedbenhida.com/uses',
|
||||||
|
twitter: '@simo_benhida',
|
||||||
|
emoji: '🔥',
|
||||||
|
country: '🇲🇦',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'iphone',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'Entrepreneur',
|
||||||
|
'Teacher',
|
||||||
|
'Back End',
|
||||||
|
'Laravel',
|
||||||
|
'Vuejs',
|
||||||
|
'Tailwindcss',
|
||||||
|
'PHP',
|
||||||
|
'JavaScript',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Andrew McCombe',
|
||||||
|
// Short description
|
||||||
|
description:
|
||||||
|
'Experienced full stack web developer with a passion for testing.',
|
||||||
|
url: 'https://www.euperia.com/uses',
|
||||||
|
twitter: '@euperia',
|
||||||
|
emoji: '🏁',
|
||||||
|
country: '🇬🇧',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'android',
|
||||||
|
tags: [
|
||||||
|
'Developer',
|
||||||
|
'Full Stack',
|
||||||
|
'Back End',
|
||||||
|
'Laravel',
|
||||||
|
'PHP',
|
||||||
|
'JavaScript',
|
||||||
|
'Vue',
|
||||||
|
'LAMP',
|
||||||
|
'ElasticSearch',
|
||||||
|
'AWS',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Smakosh',
|
||||||
|
description: 'Full stack JavaScript Developer, blogger and speaker.',
|
||||||
|
url: 'https://smakosh.com/the-tech-tools-I-use',
|
||||||
|
twitter: '@smakosh',
|
||||||
|
emoji: '👌',
|
||||||
|
country: '🇲🇦',
|
||||||
|
computer: 'apple',
|
||||||
|
phone: 'android & iphone',
|
||||||
|
tags: ['Developer', 'Full Stack', 'Entrepreneur', 'Blogger', 'JavaScript'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default pages;
|
||||||
BIN
src/images/gatsby-astronaut.png
Normal file
BIN
src/images/gatsby-astronaut.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 163 KiB |
BIN
src/images/gatsby-icon.png
Normal file
BIN
src/images/gatsby-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
11
src/pages/404.js
Normal file
11
src/pages/404.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Layout from '../components/layout';
|
||||||
|
|
||||||
|
const NotFoundPage = () => (
|
||||||
|
<Layout>
|
||||||
|
<p>WHAT R U DOING HERE</p>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default NotFoundPage;
|
||||||
47
src/pages/index.js
Normal file
47
src/pages/index.js
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
import { useStaticQuery, graphql } from 'gatsby';
|
||||||
|
import FilterContext from '../context/FilterContext';
|
||||||
|
|
||||||
|
import Layout from '../components/layout';
|
||||||
|
import Person from '../components/Person';
|
||||||
|
import Topics from '../components/Topics';
|
||||||
|
|
||||||
|
function IndexPage() {
|
||||||
|
const { currentTag } = useContext(FilterContext);
|
||||||
|
const { allPerson } = useStaticQuery(graphql`
|
||||||
|
query People {
|
||||||
|
allPerson {
|
||||||
|
nodes {
|
||||||
|
computer
|
||||||
|
country
|
||||||
|
description
|
||||||
|
emoji
|
||||||
|
id
|
||||||
|
name
|
||||||
|
phone
|
||||||
|
tags
|
||||||
|
twitter
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
const people = allPerson.nodes.filter(
|
||||||
|
person =>
|
||||||
|
currentTag === 'all' ||
|
||||||
|
person.tags.includes(currentTag) ||
|
||||||
|
currentTag === person.country
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<Topics />
|
||||||
|
<div className="people">
|
||||||
|
{people.map(person => (
|
||||||
|
<Person key={person.name} person={person} currentTag={currentTag} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IndexPage;
|
||||||
51
src/util/stats.js
Normal file
51
src/util/stats.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { name } from 'country-emoji';
|
||||||
|
import people from '../data.js';
|
||||||
|
|
||||||
|
function merge(prop) {
|
||||||
|
return function(acc, obj) {
|
||||||
|
return [...obj[prop], ...acc];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function countInstances(acc, tag) {
|
||||||
|
acc[tag] = acc[tag] ? acc[tag] + 1 : 1;
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function countries() {
|
||||||
|
const data = people
|
||||||
|
.map(person => ({
|
||||||
|
name: name(person.country),
|
||||||
|
emoji: person.country,
|
||||||
|
}))
|
||||||
|
.reduce((acc, country) => {
|
||||||
|
if (acc[country.name]) {
|
||||||
|
// exists, update
|
||||||
|
acc[country.name].count = acc[country.name].count + 1;
|
||||||
|
} else {
|
||||||
|
acc[country.name] = {
|
||||||
|
...country,
|
||||||
|
count: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const sorted = Object.entries(data)
|
||||||
|
.map(([, country]) => country)
|
||||||
|
.sort((a, b) => b.count - a.count);
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tags() {
|
||||||
|
const allTags = people.reduce(merge('tags'), []);
|
||||||
|
const counts = allTags.reduce(countInstances, {});
|
||||||
|
// sort and filter for any tags that only have 1
|
||||||
|
const tags = Object.entries(counts)
|
||||||
|
.sort(([, countA], [, countB]) => countB - countA)
|
||||||
|
.filter(([, count]) => count > 1)
|
||||||
|
.map(([name, count]) => ({ name, count }));
|
||||||
|
|
||||||
|
return [{ name: 'all', count: people.length }, ...tags];
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue