refact: convert components to use React.FC type + type improvements

This commit is contained in:
Phi
2019-09-17 17:06:43 -04:00
committed by Jean-Philippe Sirois
parent d61c218657
commit 1d88367645
23 changed files with 89 additions and 74 deletions
Vendored
+4
View File
@@ -0,0 +1,4 @@
declare module "*.svg" {
const content: any;
export default content;
}
+1
View File
@@ -28,6 +28,7 @@
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"" "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\""
}, },
"dependencies": { "dependencies": {
"@reach/router": "^1.2.1",
"gatsby": "^2.13.51", "gatsby": "^2.13.51",
"gatsby-image": "^2.2.8", "gatsby-image": "^2.2.8",
"gatsby-plugin-layout": "^1.1.2", "gatsby-plugin-layout": "^1.1.2",
+2 -6
View File
@@ -1,8 +1,4 @@
import React, { useMemo, useState } from "react" import React, { FC, useMemo, useState } from "react"
interface ISidebarProviderProps {
children: React.ReactNode
}
export interface ISidebarContextInterface { export interface ISidebarContextInterface {
current: number current: number
@@ -13,7 +9,7 @@ export const SidebarContext = React.createContext<ISidebarContextInterface | nul
null null
) )
export function SidebarProvider({ children }: ISidebarProviderProps) { export const SidebarProvider: FC = ({ children }) => {
const [current, setCurrent] = useState(0) const [current, setCurrent] = useState(0)
const memoizedContextValue = useMemo( const memoizedContextValue = useMemo(
+6 -7
View File
@@ -1,23 +1,22 @@
import React, { createContext, useMemo } from "react" import React, { createContext, FC, useMemo } from "react"
import { ThemeProvider as BaseThemeProvider } from "styled-components" import { ThemeProvider as BaseThemeProvider } from "styled-components"
import { darkTheme, lightTheme } from "./design/themes" import { darkTheme, lightTheme } from "./design/themes"
import { useLocalStorage } from "./hooks/useLocalStorage" import { useLocalStorage } from "./hooks/useLocalStorage"
interface IThemeProviderProps {
// TODO: type this properly, BaseThemeProvider doesn't like React.ReactNode
children: any
}
export interface IThemeContext { export interface IThemeContext {
theme: "dark" | "light" theme: "dark" | "light"
setTheme: () => void setTheme: () => void
toggleTheme: () => void toggleTheme: () => void
} }
interface IScopedDownChildren {
children: JSX.Element
}
export const ThemeContext = createContext<IThemeContext | null>(null) export const ThemeContext = createContext<IThemeContext | null>(null)
const ThemeProvider = ({ children }: IThemeProviderProps) => { const ThemeProvider: FC<IScopedDownChildren> = ({ children }) => {
const [theme, setTheme] = useLocalStorage("theme", "light") const [theme, setTheme] = useLocalStorage("theme", "light")
const themeObject = useMemo( const themeObject = useMemo(
+3 -3
View File
@@ -1,9 +1,9 @@
import React, { PropsWithChildren } from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
export function Container({ export const Container: FC = ({
children, children,
...restProps ...restProps
}: PropsWithChildren<{}>): JSX.Element { }) => {
return <SC.ContainerWrapper {...restProps}>{children}</SC.ContainerWrapper> return <SC.ContainerWrapper {...restProps}>{children}</SC.ContainerWrapper>
} }
+2 -2
View File
@@ -1,7 +1,7 @@
import React, { PropsWithChildren } from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
export function DiscordButton({ children }: PropsWithChildren<{}>) { export const DiscordButton: FC = ({ children }) => {
return ( return (
<SC.DiscordButtonWrapper> <SC.DiscordButtonWrapper>
<SC.StyledDiscordLogo /> {children} <SC.StyledDiscordLogo /> {children}
+2 -2
View File
@@ -1,8 +1,8 @@
import React from "react" import React, { FC } from "react"
import { Container } from "../Container" import { Container } from "../Container"
import * as SC from "./styles" import * as SC from "./styles"
export function Footer() { export const Footer: FC = () => {
return ( return (
<SC.FooterWrapper> <SC.FooterWrapper>
<Container> <Container>
+7 -3
View File
@@ -1,5 +1,5 @@
import { Link } from "gatsby" import { Link } from "gatsby"
import React, { PropsWithChildren, useLayoutEffect, useState } from "react" import React, { FC, useLayoutEffect, useState } from "react"
import { DiscordButton } from "../DiscordButton" import { DiscordButton } from "../DiscordButton"
import { WavesBottom, WavesTop } from "../Waves" import { WavesBottom, WavesTop } from "../Waves"
import * as SC from "./styles" import * as SC from "./styles"
@@ -8,7 +8,11 @@ interface IHeaderProps {
isHome: boolean isHome: boolean
} }
function MenuItem({ children, to }: PropsWithChildren<{ to: string }>) { interface IMenuItemProps {
to: string
}
const MenuItem: FC<IMenuItemProps> = ({ children, to }) => {
return ( return (
<SC.MenuItem <SC.MenuItem
to={to} to={to}
@@ -21,7 +25,7 @@ function MenuItem({ children, to }: PropsWithChildren<{ to: string }>) {
) )
} }
export function Header({ isHome }: IHeaderProps) { export const Header: FC<IHeaderProps> = ({ isHome }) => {
// Hack to force Particle.js to rerender // Hack to force Particle.js to rerender
const [noop, setNoop] = useState(0) const [noop, setNoop] = useState(0)
useLayoutEffect(() => { useLayoutEffect(() => {
+5 -4
View File
@@ -5,7 +5,8 @@
* See: https://www.gatsbyjs.org/docs/use-static-query/ * See: https://www.gatsbyjs.org/docs/use-static-query/
*/ */
import React, { Fragment, PropsWithChildren } from "react" import { RouteComponentProps } from '@reach/router'
import React, { FC, Fragment } from "react"
import { GlobalStyles } from "../../globalStyles" import { GlobalStyles } from "../../globalStyles"
import { ThemeProvider } from "../../ThemeProvider" import { ThemeProvider } from "../../ThemeProvider"
@@ -15,11 +16,11 @@ import { Header } from "../Header"
import { WavesBottom } from "../Waves" import { WavesBottom } from "../Waves"
import * as SC from "./styles" import * as SC from "./styles"
export function Layout({ export const Layout: FC<RouteComponentProps> = ({
children, children,
location, location,
}: PropsWithChildren<{ location: Location }>) { }) => {
const isHome = location.pathname === "/" const isHome = location ? location.pathname === "/" : false
return ( return (
<ThemeProvider> <ThemeProvider>
+4 -4
View File
@@ -3,7 +3,7 @@ import "prismjs/components/prism-markup-templating"
import "prismjs/components/prism-php" import "prismjs/components/prism-php"
import "prismjs/components/prism-python" import "prismjs/components/prism-python"
import "prismjs/plugins/line-numbers/prism-line-numbers.css" import "prismjs/plugins/line-numbers/prism-line-numbers.css"
import React from "react" import React, { FC, useEffect } from "react"
import * as SC from "./styles" import * as SC from "./styles"
interface IMarkdownProps { interface IMarkdownProps {
@@ -14,11 +14,11 @@ interface IMarkdownProps {
This component is used as a wrapper around Markdown generated content, This component is used as a wrapper around Markdown generated content,
mainly to provide styles to the html generated. mainly to provide styles to the html generated.
*/ */
export function Markdown({ export const Markdown: FC<IMarkdownProps> = ({
content, content,
...restProps ...restProps
}: IMarkdownProps): JSX.Element { }) => {
React.useEffect(() => { useEffect(() => {
Prism.highlightAll() Prism.highlightAll()
}, []) }, [])
return ( return (
+2 -2
View File
@@ -1,11 +1,11 @@
import React from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
interface IMobileHeaderProps { interface IMobileHeaderProps {
openMenu: () => void openMenu: () => void
} }
export function MobileHeader({ openMenu }: IMobileHeaderProps) { export const MobileHeader: FC<IMobileHeaderProps> = ({ openMenu }) => {
return ( return (
<SC.MobileHeaderWrapper> <SC.MobileHeaderWrapper>
<SC.LogoWrapper> <SC.LogoWrapper>
+6 -2
View File
@@ -1,15 +1,19 @@
import React from "react" import React, { FC } from "react"
import ChevronUp from "../../icons/chevron-up.svg" import ChevronUp from "../../icons/chevron-up.svg"
import { IFileOrFolder } from "../../types" import { IFileOrFolder } from "../../types"
import { humanize, traversePaths } from "../../utils" import { humanize, traversePaths } from "../../utils"
import * as SC from "./styles" import * as SC from "./styles"
interface ILinkProps {
item: IFileOrFolder
}
interface IResourceBreadcrumbProps { interface IResourceBreadcrumbProps {
relativePath: any relativePath: any
} }
function Link({ item }: { item: IFileOrFolder }) { const Link: FC<ILinkProps> = ({ item }) => {
return <SC.StyledLink to={item.path}>{humanize(item.title)}</SC.StyledLink> return <SC.StyledLink to={item.path}>{humanize(item.title)}</SC.StyledLink>
} }
+11 -11
View File
@@ -1,4 +1,4 @@
import React, { Fragment } from "react" import React, { FC, Fragment } from "react"
import ChevronUp from "../../icons/chevron-up.svg" import ChevronUp from "../../icons/chevron-up.svg"
import { ResourceBreadcrumb } from "../ResourceBreadcrumb" import { ResourceBreadcrumb } from "../ResourceBreadcrumb"
@@ -6,13 +6,13 @@ import { StackedAvatars } from "../StackedAvatars"
import * as SC from "./styles" import * as SC from "./styles"
interface IResourceHeaderProps { interface IResourceHeaderProps {
relativePath: any relativePath: string
title: any title: string
authors: any authors: string[]
createdAt: any createdAt: string
timeToRead: any timeToRead: number
recommendedReading: any recommendedReading: string[]
externalResources: any externalResources: string[]
} }
function ExtraLink({ function ExtraLink({
@@ -43,7 +43,7 @@ function ExtraLink({
) )
} }
export function ResourceHeader({ export const ResourceHeader: FC<IResourceHeaderProps> = ({
relativePath, relativePath,
title, title,
authors, authors,
@@ -51,7 +51,7 @@ export function ResourceHeader({
timeToRead, timeToRead,
recommendedReading, recommendedReading,
externalResources, externalResources,
}: IResourceHeaderProps) { }) => {
const date = new Date(createdAt) const date = new Date(createdAt)
const month = date.toLocaleString("default", { month: "long" }) const month = date.toLocaleString("default", { month: "long" })
const day = date.getDate() const day = date.getDate()
@@ -67,7 +67,7 @@ export function ResourceHeader({
<SC.Top> <SC.Top>
<SC.Meta> <SC.Meta>
<StackedAvatars authors={authors} /> {authors.length} contributor <StackedAvatars authors={authors} /> {authors.length} contributor
{authors.lenght > 1 && "s"} {authors.length > 1 && "s"}
</SC.Meta> </SC.Meta>
<SC.Meta>{dateToHuman}</SC.Meta> <SC.Meta>{dateToHuman}</SC.Meta>
<SC.Meta> <SC.Meta>
+2 -2
View File
@@ -5,7 +5,7 @@
* See: https://www.gatsbyjs.org/docs/use-static-query/ * See: https://www.gatsbyjs.org/docs/use-static-query/
*/ */
import React, { PropsWithChildren, useState } from "react" import React, { FC, useState } from "react"
import { GlobalStyles } from "../../globalStyles" import { GlobalStyles } from "../../globalStyles"
import { SidebarProvider } from "../../SidebarProvider" import { SidebarProvider } from "../../SidebarProvider"
@@ -14,7 +14,7 @@ import { MobileHeader } from "../MobileHeader"
import { ResourcesSidebar } from "../ResourcesSidebar" import { ResourcesSidebar } from "../ResourcesSidebar"
import * as SC from "./styles" import * as SC from "./styles"
export function ResourcesLayout({ children }: PropsWithChildren<{}>) { export const ResourcesLayout: FC = ({ children }) => {
const [activeMobileMenu, setActiveMobileMenu] = useState(false) const [activeMobileMenu, setActiveMobileMenu] = useState(false)
function openMenu() { function openMenu() {
+7 -5
View File
@@ -1,12 +1,14 @@
import React, { PropsWithChildren } from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
export function ResourcesLink({ interface IResourcesLinkProps {
to: string
}
export const ResourcesLink: FC<IResourcesLinkProps> = ({
children, children,
to, to,
}: PropsWithChildren<{ }) => {
to: string
}>) {
if (!to.match(/^(https?:\/\/)/)) { if (!to.match(/^(https?:\/\/)/)) {
return ( return (
<SC.ResourcesLinkInternal to={to}>{children}</SC.ResourcesLinkInternal> <SC.ResourcesLinkInternal to={to}>{children}</SC.ResourcesLinkInternal>
+2 -2
View File
@@ -1,5 +1,5 @@
import { graphql, useStaticQuery } from "gatsby" import { graphql, useStaticQuery } from "gatsby"
import React, { memo } from "react" import React, { FC, HTMLAttributes, memo } from "react"
import "react-perfect-scrollbar/dist/css/styles.css" import "react-perfect-scrollbar/dist/css/styles.css"
import { IAllResourcesQuery, IFileOrFolder, IFolder } from "../../types" import { IAllResourcesQuery, IFileOrFolder, IFolder } from "../../types"
import { humanize } from "../../utils" import { humanize } from "../../utils"
@@ -51,7 +51,7 @@ const Language = memo(({ item }: { item: IFolder; index: number }) => {
) )
}) })
export function ResourcesList(props: React.HTMLAttributes<HTMLDivElement>) { export const ResourcesList: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
const resources = useStaticQuery<IAllResourcesQuery>(ALL_RESOURCES) const resources = useStaticQuery<IAllResourcesQuery>(ALL_RESOURCES)
const tree = useBuildTree(resources) const tree = useBuildTree(resources)
+7 -3
View File
@@ -1,5 +1,5 @@
import { graphql, Link, useStaticQuery } from "gatsby" import { graphql, Link, useStaticQuery } from "gatsby"
import React, { memo, PropsWithChildren, useState } from "react" import React, { FC, HTMLAttributes, memo, useState } from "react"
import Scrollbar from "react-perfect-scrollbar" import Scrollbar from "react-perfect-scrollbar"
import "react-perfect-scrollbar/dist/css/styles.css" import "react-perfect-scrollbar/dist/css/styles.css"
import TriangleDown from "../../icons/triangle-down.svg" import TriangleDown from "../../icons/triangle-down.svg"
@@ -83,7 +83,11 @@ const FirstLevelFolder = memo(
} }
) )
function MenuItem({ children, to }: PropsWithChildren<{ to: string }>) { interface IMenuItemProps {
to: string
}
const MenuItem: FC<IMenuItemProps> = ({ children, to }) => {
return ( return (
<SC.MenuItem to={to} activeClassName="active"> <SC.MenuItem to={to} activeClassName="active">
{children} {children}
@@ -91,7 +95,7 @@ function MenuItem({ children, to }: PropsWithChildren<{ to: string }>) {
) )
} }
export function ResourcesSidebar(props: React.HTMLAttributes<HTMLDivElement>) { export const ResourcesSidebar: FC<HTMLAttributes<HTMLDivElement>> = (props) => {
const resources = useStaticQuery<IAllResourcesQuery>(ALL_RESOURCES) const resources = useStaticQuery<IAllResourcesQuery>(ALL_RESOURCES)
const tree = useBuildTree(resources) const tree = useBuildTree(resources)
@@ -1,14 +1,14 @@
import React, { PropsWithChildren } from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
export interface IResourcesSidebarSectionProps { export interface IResourcesSidebarSectionProps {
readonly title: string readonly title: string
} }
export function ResourcesSidebarSection({ export const ResourcesSidebarSection: FC<IResourcesSidebarSectionProps> = ({
title, title,
children, children,
}: PropsWithChildren<IResourcesSidebarSectionProps>) { }) => {
return ( return (
<div> <div>
<SC.SidebarTitle>{title}</SC.SidebarTitle> <SC.SidebarTitle>{title}</SC.SidebarTitle>
+3 -3
View File
@@ -1,5 +1,5 @@
import { graphql, useStaticQuery } from "gatsby" import { graphql, useStaticQuery } from "gatsby"
import React from "react" import React, { FC } from "react"
import Helmet from "react-helmet" import Helmet from "react-helmet"
interface ISEOProps { interface ISEOProps {
@@ -10,13 +10,13 @@ interface ISEOProps {
readonly title: string readonly title: string
} }
export function SEO({ export const SEO: FC<ISEOProps> = ({
description, description,
lang = "en", lang = "en",
meta = [], meta = [],
keywords = [], keywords = [],
title, title,
}: ISEOProps) { }) => {
const { site } = useStaticQuery( const { site } = useStaticQuery(
graphql` graphql`
query { query {
+3 -3
View File
@@ -1,12 +1,12 @@
import React from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
interface IStackedAvatarsProps { interface IStackedAvatarsProps {
authors: any authors: any[]
} }
export function StackedAvatars({ authors }: IStackedAvatarsProps) { export const StackedAvatars: FC<IStackedAvatarsProps> = ({ authors }) => {
return ( return (
<SC.StackedAvatarsWrapper count={authors.length}> <SC.StackedAvatarsWrapper count={authors.length}>
{authors.map((author, index) => ( {authors.map((author, index) => (
+2 -2
View File
@@ -1,8 +1,8 @@
import React from "react" import React, { FC } from "react"
import useTheme from "../../hooks/useTheme" import useTheme from "../../hooks/useTheme"
import * as SC from "./styles" import * as SC from "./styles"
export function ThemeToggler() { export const ThemeToggler: FC = () => {
const { theme, toggleTheme } = useTheme() const { theme, toggleTheme } = useTheme()
return ( return (
+3 -3
View File
@@ -1,10 +1,10 @@
import React from "react" import React, { FC } from "react"
import * as SC from "./styles" import * as SC from "./styles"
export function WavesTop() { export const WavesTop: FC = () => {
return <SC.StyledWavesTop /> return <SC.StyledWavesTop />
} }
export function WavesBottom() { export const WavesBottom: FC = () => {
return <SC.StyledWavesBottom /> return <SC.StyledWavesBottom />
} }
+2 -2
View File
@@ -1,11 +1,11 @@
import { graphql } from "gatsby" import { graphql } from "gatsby"
import React, { Fragment } from "react" import React, { FC, Fragment } from "react"
import { Markdown } from "../components/Markdown" import { Markdown } from "../components/Markdown"
import { ResourceHeader } from "../components/ResourceHeader" import { ResourceHeader } from "../components/ResourceHeader"
import { SEO } from "../components/SEO" import { SEO } from "../components/SEO"
// @todo maybe find alternative type for data // @todo maybe find alternative type for data
function LanguagePost({ data }: any) { const LanguagePost: FC<any> = ({ data }) => {
const { relativePath } = data.file const { relativePath } = data.file
const { html, fields, frontmatter, timeToRead } = data.file.post const { html, fields, frontmatter, timeToRead } = data.file.post