refact: clean up (#12)

refact: clean up
This commit is contained in:
Jean-Philippe Sirois
2019-07-27 18:05:48 -04:00
committed by GitHub
24 changed files with 253 additions and 317 deletions
+6 -9
View File
@@ -1,12 +1,9 @@
import React from "react"
import React, { PropsWithChildren } from "react"
import * as SC from "./styles"
interface ContainerProps {
children: React.ReactNode
export function Container({
children,
...restProps
}: PropsWithChildren<{}>): JSX.Element {
return <SC.ContainerWrapper {...restProps}>{children}</SC.ContainerWrapper>
}
const Container = ({ children, ...restProps }: ContainerProps): JSX.Element => (
<SC.ContainerWrapper {...restProps}>{children}</SC.ContainerWrapper>
)
export default Container
+9 -17
View File
@@ -8,13 +8,11 @@
import React, { PropsWithChildren } from "react"
import { useStaticQuery, graphql } from "gatsby"
import Container from "../Container"
import DocsSidebar from "../DocsSidebar"
import { Main, MainContent } from "./styles"
import Scrollbar from "react-perfect-scrollbar"
import "react-perfect-scrollbar/dist/css/styles.css"
import { DocsSidebar } from "../DocsSidebar"
import { Footer } from "../Footer"
import * as SC from "./styles"
const DocsLayout = ({ children }: PropsWithChildren<{}>) => {
export function DocsLayout({ children }: PropsWithChildren<{}>) {
const data = useStaticQuery(graphql`
query {
site {
@@ -27,20 +25,14 @@ const DocsLayout = ({ children }: PropsWithChildren<{}>) => {
return (
<div>
<Main>
<SC.Main>
<DocsSidebar />
<MainContent>
<SC.MainContent>
<h1>{data.site.siteMetadata.title}</h1>
{children}
</MainContent>
</Main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</SC.MainContent>
</SC.Main>
<Footer />
</div>
)
}
export default DocsLayout
-41
View File
@@ -1,41 +0,0 @@
// TODO: refactor this into styled components
html {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/**
* If you already use line highlighting
*/
/* Adjust the position of the line numbers */
.gatsby-highlight pre[class*="language-"].line-numbers {
padding-left: 2.8em;
}
/**
* If you only want to use line numbering
*/
.gatsby-highlight {
background-color: #fdf6e3;
border-radius: 0.3em;
margin: 0.5em 0;
padding: 1em;
overflow: auto;
}
.gatsby-highlight pre[class*="language-"].line-numbers {
padding: 0;
padding-left: 2.8em;
overflow: initial;
}
+10 -92
View File
@@ -1,99 +1,25 @@
import * as R from "ramda"
import React, { useState } from "react"
import Tree from "react-treeview"
import { useStaticQuery, graphql } from "gatsby"
import useBuildTree from "./useBuildTree"
import * as SC from "./styles"
interface IFile {
export interface IFile {
title: string
type: "file"
path: string
}
interface IFolder {
export interface IFolder {
title: string
type: "folder"
path: string
children: IFileOrFolder[]
}
type IFileOrFolder = IFile | IFolder
export type IFileOrFolder = IFile | IFolder
const traverse = (
[head, ...tail]: string[],
basePath = "/docs"
): IFileOrFolder => {
const path = basePath + "/" + head
const isFile = !tail.length
if (isFile) {
// probably not more than one dot
const [name] = head.split(".")
return {
title: name,
type: "file",
path,
}
}
return {
title: head,
type: "folder",
path,
children: [traverse(tail, path)],
}
}
const generateFolder = ({
title,
path,
targets,
}: {
title: IFolder["title"]
path: IFile["path"]
targets: IFolder[]
}): IFolder => {
const children = join(R.chain(target => target.children, targets))
return {
title,
type: "folder",
path,
children,
}
}
const generateFile = ({
title,
path,
}: {
title: IFile["title"]
path: IFile["path"]
}): IFile => {
return {
title,
path,
type: "file",
}
}
const join = ([head, ...tail]: IFileOrFolder[]): IFileOrFolder[] => {
if (!head) return []
const [similarFs, remaining] = R.partition(
obj => obj.title === head.title && obj.type === head.type,
tail
)
const targets = [head, ...similarFs]
const { title, path } = head
const current =
head.type === "folder"
? generateFolder({ title, path, targets: targets as IFolder[] })
: generateFile({ title, path })
return [current, ...join(remaining)]
}
interface IFileQuery {
export interface IFileQuery {
node: {
relativePath: string
childMarkdownRemark: {
@@ -105,7 +31,7 @@ interface IFileQuery {
}
}
interface IAllDocsQuery {
export interface IAllDocsQuery {
allFile: {
edges: IFileQuery[]
}
@@ -129,7 +55,7 @@ const ALL_DOCS = graphql`
}
`
const plantTree = (item: IFileOrFolder) => {
function plantTree(item: IFileOrFolder) {
if (item.type === "file") {
return (
<SC.PageLink to={item.path} activeClassName="active">
@@ -158,21 +84,13 @@ function Folder({ item }: { item: IFolder }) {
)
}
const DocsSidebar = () => {
export function DocsSidebar() {
const docs = useStaticQuery<IAllDocsQuery>(ALL_DOCS)
const objects = docs.allFile.edges.map(({ node: file }: IFileQuery) =>
traverse(file.relativePath.split("/"))
)
const results = join(objects)
console.log(results)
const tree = useBuildTree(docs)
return (
<SC.DocsSidebarWrapper>
{results.map(node => plantTree(node))}
{tree.map(node => plantTree(node))}
</SC.DocsSidebarWrapper>
)
}
export default DocsSidebar
@@ -0,0 +1,90 @@
import * as R from "ramda"
import {
IFileOrFolder,
IFile,
IFolder,
IAllDocsQuery,
IFileQuery,
} from "./index"
function traverse(
[head, ...tail]: string[],
basePath = "/docs"
): IFileOrFolder {
const path = basePath + "/" + head
const isFile = !tail.length
if (isFile) {
// probably not more than one dot
const [name] = head.split(".")
return {
title: name,
type: "file",
path,
}
}
return {
title: head,
type: "folder",
path,
children: [traverse(tail, path)],
}
}
function generateFolder({
title,
path,
targets,
}: {
title: IFolder["title"]
path: IFile["path"]
targets: IFolder[]
}): IFolder {
const children = join(R.chain(target => target.children, targets))
return {
title,
type: "folder",
path,
children,
}
}
function generateFile({
title,
path,
}: {
title: IFile["title"]
path: IFile["path"]
}): IFile {
return {
title,
type: "file",
path,
}
}
function join([head, ...tail]: IFileOrFolder[]): IFileOrFolder[] {
if (!head) return []
const [similarFs, remaining] = R.partition(
obj => obj.title === head.title && obj.type === head.type,
tail
)
const targets = [head, ...similarFs]
const { title, path } = head
const current =
head.type === "folder"
? generateFolder({ title, path, targets: targets as IFolder[] })
: generateFile({ title, path })
return [current, ...join(remaining)]
}
export default function useBuildTree(docs: IAllDocsQuery) {
const objects = docs.allFile.edges.map(({ node: file }: IFileQuery) =>
traverse(file.relativePath.split("/"))
)
return join(objects)
}
+5 -7
View File
@@ -1,20 +1,18 @@
import React from "react"
import { SidebarTitle } from "./style"
import React, { PropsWithChildren } from "react"
import * as SC from "./styles"
export interface DocsSidebarSectionProps {
readonly title: string
}
const DocsSidebarSection = ({
export function DocsSidebarSection({
title,
children,
}: React.PropsWithChildren<DocsSidebarSectionProps>) => {
}: PropsWithChildren<DocsSidebarSectionProps>) {
return (
<div>
<SidebarTitle>{title}</SidebarTitle>
<SC.SidebarTitle>{title}</SC.SidebarTitle>
{children}
</div>
)
}
export default DocsSidebarSection
@@ -1,5 +1,5 @@
import styled from "styled-components";
import styled from "styled-components"
export const SidebarTitle = styled.h3`
text-transform: uppercase;
`;
`
+15
View File
@@ -0,0 +1,15 @@
import React from "react"
import * as SC from "./styles"
import { Container } from "../Container"
export function Footer() {
return (
<SC.FooterWrapper>
<Container>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</Container>
</SC.FooterWrapper>
)
}
+4
View File
@@ -0,0 +1,4 @@
import { Link } from "gatsby"
import styled from "styled-components"
export const FooterWrapper = styled.footer``
+10 -18
View File
@@ -8,15 +8,15 @@
import React, { PropsWithChildren } from "react"
import { useStaticQuery, graphql } from "gatsby"
import Container from "../Container"
import Navbar from "../Navbar"
import Sidebar from "../Sidebar"
import { Container } from "../Container"
import { Footer } from "../Footer"
import { Sidebar } from "../Sidebar"
import "./layout.scss"
import { Main, MainContent } from "./styles"
import * as SC from "./styles"
import Scrollbar from "react-perfect-scrollbar"
import "react-perfect-scrollbar/dist/css/styles.css"
const Layout = ({ children }: PropsWithChildren<{}>) => {
export function Layout({ children }: PropsWithChildren<{}>) {
const data = useStaticQuery(graphql`
query {
site {
@@ -30,23 +30,15 @@ const Layout = ({ children }: PropsWithChildren<{}>) => {
return (
<Scrollbar>
<Container>
<Main>
<SC.Main>
<Sidebar />
<MainContent>
<SC.MainContent>
<h1>{data.site.siteMetadata.title}</h1>
{children}
</MainContent>
</Main>
</SC.MainContent>
</SC.Main>
</Container>
<footer>
<Container>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</Container>
</footer>
<Footer />
</Scrollbar>
)
}
export default Layout
+1
View File
@@ -6,6 +6,7 @@ html {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-43
View File
@@ -1,43 +0,0 @@
import { Link } from "gatsby";
import * as React from "react";
import icon from "./icon.png";
import { HeaderWrapper } from "./styles";
// @todo maybe find alternative type for data
const Navbar = ({ siteTitle }: any) => (
<HeaderWrapper>
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `1.45rem 1.0875rem`,
}}
>
<div style={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
{/* <img src={icon} style={{ width: "70px" }} /> */}
<h1 style={{ margin: 0 }}>
<Link
to="/"
style={{
color: `white`,
textDecoration: `none`,
}}
>
{siteTitle}
</Link>
</h1>
</div>
</div>
</HeaderWrapper>
)
Navbar.propTypes = {
siteTitle: String
}
Navbar.defaultProps = {
siteTitle: ``,
}
export default Navbar;
-6
View File
@@ -1,6 +0,0 @@
import styled from "styled-components";
export const HeaderWrapper = styled.header`
background: #ba1a2e;
marginBottom: 1.45rem;
`;
+23 -9
View File
@@ -3,13 +3,20 @@ import Helmet from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"
interface SEOProps {
readonly description: string;
readonly lang: string;
readonly meta: object[];
readonly title: string;
readonly description?: string
readonly lang?: string
readonly meta?: any[]
readonly keywords?: string[]
readonly title: string
}
const SEO = ({ description = "", lang = "en", meta = [], title }: SEOProps) => {
export function SEO({
description,
lang = "en",
meta = [],
keywords = [],
title,
}: SEOProps) {
const { site } = useStaticQuery(
graphql`
query {
@@ -66,9 +73,16 @@ const SEO = ({ description = "", lang = "en", meta = [], title }: SEOProps) => {
name: `twitter:description`,
content: metaDescription,
},
]}
]
.concat(
keywords.length > 0
? {
name: `keywords`,
content: keywords.join(`, `),
}
: []
)
.concat(meta)}
/>
)
};
export default SEO
}
+3 -5
View File
@@ -1,9 +1,9 @@
import React from "react"
import React, { PropsWithChildren } from "react"
import logo from "../../images/tph-logo.png"
import * as SC from "./styles"
import ArrowRight from "../../icons/arrow-right.svg"
function MenuItem({ children, to }: { children: React.ReactNode; to: string }) {
function MenuItem({ children, to }: PropsWithChildren<{ to: string }>) {
return (
<SC.MenuItem to={to}>
{children} <ArrowRight />
@@ -11,7 +11,7 @@ function MenuItem({ children, to }: { children: React.ReactNode; to: string }) {
)
}
const Sidebar = () => {
export function Sidebar() {
return (
<SC.SidebarWrapper>
<SC.Logo src={logo} />
@@ -27,5 +27,3 @@ const Sidebar = () => {
</SC.SidebarWrapper>
)
}
export default Sidebar
+12 -12
View File
@@ -31,8 +31,8 @@ called `getMembers` that retrieves all the members in a discord server. When we
function we see the following result.
```js
const members = getMembers("The Programmers Hangout");
console.log(members); // Promise {<pending>}
const members = getMembers("The Programmers Hangout")
console.log(members) // Promise {<pending>}
```
Normally, we would have expected to see an array of all the members but it takes time to
@@ -44,8 +44,8 @@ to access the actual members like so.
```js
getMembers("The Programmers Hangout").then(members => {
console.log(members); // (32k) [{...}, {...}, {...}]
});
console.log(members) // (32k) [{...}, {...}, {...}]
})
```
This way we are able to make sure that we only try to `console.log` when the `getMembers` function has resolved and ready to be used.
@@ -63,10 +63,10 @@ You may have tried doing something like this before.
```js
// Incorrect code, don't copy!
let results;
let results
getWeather("Los Angeles").then(weather => {
results = weather;
});
results = weather
})
console.log(results) // undefined
```
@@ -81,8 +81,8 @@ In order to fix this problem we need to move the `console.log` inside the `.then
```js
getWeather("Los Angeles").then(weather => {
console.log(weather); // Sunny, probably
});
console.log(weather) // Sunny, probably
})
```
## Real World Example
@@ -94,12 +94,12 @@ You can try it in your browser if you want to test it out.
function getCharacters() {
return fetch(`https://rickandmortyapi.com/api/character`)
.then(response => response.json())
.then(response => response.results);
.then(response => response.results)
}
getCharacters().then(characters => {
console.log(characters); // (20) [{...}, {...}, {...}]
});
console.log(characters) // (20) [{...}, {...}, {...}]
})
```
Let's break down what's happening in this function
@@ -15,9 +15,9 @@ function doAsync(number) {
return new Promise(function(resolve, reject) {
doDatabase().then(function(dbResult) {
otherDbFunction(dbResult).then(function(secondResult) {
resolve(secondResult + 10);
resolve(secondResult + 10)
})
})
});
})
}
```
@@ -29,9 +29,9 @@ already returns a promise, you can just return the original thing.
function doAsync(number) {
return doDatabase().then(function(dbResult) {
otherDbFunction(dbResult).then(function(secondResult) {
return secondResult + 10;
return secondResult + 10
})
})
});
}
```
@@ -40,11 +40,13 @@ is that they allow you do chain them sequentially.
```js
function doAsync(number) {
return doDatabase().then(function(dbResult) {
return doDatabase()
.then(function(dbResult) {
return otherDbFunction(dbResult)
}).then(function(secondResult) {
return secondResult + 10;
});
})
.then(function(secondResult) {
return secondResult + 10
})
}
```
@@ -56,17 +58,18 @@ function doAsync(number) {
return doDatabase()
.then(otherDbFunction)
.then(function(secondResult) {
return secondResult + 10;
});
return secondResult + 10
})
}
```
And you don't need those returns if you just have ES6 arrow functions
```js
const doAsync = number => doDatabase()
const doAsync = number =>
doDatabase()
.then(otherDbFunction)
.then(secondResult => secondResult + 10);
.then(secondResult => secondResult + 10)
```
Wow, that last one looks a lot cleaner to me than the first. Keeping that in mind, maybe we could be making some of our other functions cleaner as well
@@ -13,7 +13,6 @@ There are multiple benefits to using a singleton class
- You're always going to pull the same instance of the class
- It's only instantiated once
- Use `$this` in a static-like context
-
By using a singleton instead of a static class we expose a cleaner class to use and we can use regular instance properties instead of static properties.
+5 -3
View File
@@ -1,14 +1,16 @@
import React from "react"
import Layout from "../components/Layout"
import SEO from "../components/SEO"
import { Layout } from "../components/Layout"
import { SEO } from "../components/SEO"
const NotFoundPage = () => (
function NotFoundPage() {
return (
<Layout>
<SEO title="404: Not found" />
<h1>NOT FOUND</h1>
<p>You just hit a route that doesn&#39;t exist... the sadness.</p>
</Layout>
)
}
export default NotFoundPage
+5 -3
View File
@@ -1,13 +1,15 @@
import React from "react"
import DocsLayout from "../components/DocsLayout"
import SEO from "../components/SEO"
import { DocsLayout } from "../components/DocsLayout"
import { SEO } from "../components/SEO"
const DocsPage = () => (
function DocsPage() {
return (
<DocsLayout>
<SEO title="Docs" />
the docs
</DocsLayout>
)
}
export default DocsPage
-1
View File
@@ -1 +0,0 @@
# Hello
+6 -5
View File
@@ -1,19 +1,20 @@
import React from "react"
import { Link } from "gatsby"
import Layout from "../components/Layout"
import SEO from "../components/SEO"
import { Layout } from "../components/Layout"
import { SEO } from "../components/SEO"
const IndexPage = () => (
function IndexPage() {
return (
<Layout>
<SEO title="Home" />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
</div>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}></div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
}
export default IndexPage
+3 -3
View File
@@ -1,10 +1,10 @@
import React from "react"
import { graphql } from "gatsby"
import SEO from "../components/SEO"
import DocsLayout from "../components/DocsLayout"
import { SEO } from "../components/SEO"
import { DocsLayout } from "../components/DocsLayout"
// @todo maybe find alternative type for data
const LanguagePost = ({ data }: any) => {
function LanguagePost({ data }: any) {
const { html, frontmatter } = data.file.post
console.log(data)
return (
+1
View File
@@ -1 +1,2 @@
declare module "*.svg"
declare module "*.png"