diff --git a/jest.config.js b/jest.config.js index 8684337..5e7dd45 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,7 @@ module.exports = { // Coverage collectCoverage: true, - collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.test.{ts,tsx}', '!src/gatsby-types.d.ts'], + collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.types.{ts,tsx}', '!src/**/*.test.{ts,tsx}', '!src/gatsby-types.d.ts'], coverageDirectory: 'reports/coverage', coveragePathIgnorePatterns: ['/node_modules/'], coverageProvider: 'babel', diff --git a/src/components/dark-mode-switch/dark-mode-switch.tsx b/src/components/dark-mode-switch/dark-mode-switch.tsx new file mode 100644 index 0000000..4518a5d --- /dev/null +++ b/src/components/dark-mode-switch/dark-mode-switch.tsx @@ -0,0 +1,31 @@ +import React, { useCallback, useState } from 'react'; +import type { FunctionComponent, ReactElement } from 'react'; + +import { FiSun, FiMoon } from 'react-icons/fi'; + +const DarkModeSwitch: FunctionComponent = (): ReactElement => { + const [darkMode, setDarkMode] = useState(false); + + const toggleDarkMode = useCallback(() => { + setDarkMode(!darkMode); + document.documentElement.classList.toggle('dark'); + }, [darkMode]); + + return ( + <> + {darkMode === true ? ( + + ) : ( + + )} + + ); +}; + +export { DarkModeSwitch }; diff --git a/src/components/document-head/document-head.tsx b/src/components/document-head/document-head.tsx new file mode 100644 index 0000000..439ccad --- /dev/null +++ b/src/components/document-head/document-head.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import type { FunctionComponent, PropsWithChildren } from 'react'; + +const DocumentHead: FunctionComponent = ({ children }) => { + return ( + <> + + + + + + + {children} + + ); +}; + +export { DocumentHead }; diff --git a/src/components/seo/__snapshots__/seo-blog-posting.test.tsx.snap b/src/components/document-head/seo/__snapshots__/seo-blog-posting.test.tsx.snap similarity index 96% rename from src/components/seo/__snapshots__/seo-blog-posting.test.tsx.snap rename to src/components/document-head/seo/__snapshots__/seo-blog-posting.test.tsx.snap index afcfb5d..9edcd87 100644 --- a/src/components/seo/__snapshots__/seo-blog-posting.test.tsx.snap +++ b/src/components/document-head/seo/__snapshots__/seo-blog-posting.test.tsx.snap @@ -2,16 +2,9 @@ exports[` should render 1`] = ` [ - , Hosting a static website on Amazon S3 , - , should render 1`] = ` [ - , Broken Robot , - , { +jest.mock('../../site-metadata/use-site-metadata', () => { return { useSiteMetadata: jest.fn().mockImplementation(() => { return { diff --git a/src/components/seo/seo-blog-posting.tsx b/src/components/document-head/seo/seo-blog-posting.tsx similarity index 76% rename from src/components/seo/seo-blog-posting.tsx rename to src/components/document-head/seo/seo-blog-posting.tsx index d47e469..f22c034 100644 --- a/src/components/seo/seo-blog-posting.tsx +++ b/src/components/document-head/seo/seo-blog-posting.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import type { FunctionComponent, PropsWithChildren } from 'react'; +import type { FunctionComponent } from 'react'; -import { useSiteMetadata } from '../site-metadata/use-site-metadata'; +import { useSiteMetadata } from '../../site-metadata/use-site-metadata'; import { MetaOgArticle } from './meta-og-article/meta-og-article'; import { MetaTwitter } from './meta-twitter/meta-twitter'; @@ -15,28 +15,14 @@ type SeoBlogPostingProps = { tags: string[]; }; -const SeoBlogPosting: FunctionComponent> = ({ - title, - description, - pathname, - published, - tags, - children -}) => { +const SeoBlogPosting: FunctionComponent = ({ title, description, pathname, published, tags }) => { const { title: siteName, siteUrl, author } = useSiteMetadata(); const url = `${siteUrl}${pathname}`; return ( <> - - {title} - - > url={url} author={author} /> - - {children} ); }; diff --git a/src/components/seo/seo-web-page.test.tsx b/src/components/document-head/seo/seo-web-page.test.tsx similarity index 96% rename from src/components/seo/seo-web-page.test.tsx rename to src/components/document-head/seo/seo-web-page.test.tsx index fb5b616..de88bff 100644 --- a/src/components/seo/seo-web-page.test.tsx +++ b/src/components/document-head/seo/seo-web-page.test.tsx @@ -5,7 +5,7 @@ import { create } from 'react-test-renderer'; import { SeoWebPage } from './seo-web-page'; import type { SeoWebPageProps } from './seo-web-page'; -jest.mock('../site-metadata/use-site-metadata', () => { +jest.mock('../../site-metadata/use-site-metadata', () => { return { useSiteMetadata: jest.fn().mockImplementation(() => { return { diff --git a/src/components/seo/seo-web-page.tsx b/src/components/document-head/seo/seo-web-page.tsx similarity index 71% rename from src/components/seo/seo-web-page.tsx rename to src/components/document-head/seo/seo-web-page.tsx index 092d0fa..c2c942d 100644 --- a/src/components/seo/seo-web-page.tsx +++ b/src/components/document-head/seo/seo-web-page.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import type { FunctionComponent, PropsWithChildren } from 'react'; +import type { FunctionComponent } from 'react'; -import { useSiteMetadata } from '../site-metadata/use-site-metadata'; +import { useSiteMetadata } from '../../site-metadata/use-site-metadata'; import { MetaOgWebsite } from './meta-og-website/meta-og-website'; import { MetaTwitter } from './meta-twitter/meta-twitter'; @@ -13,26 +13,14 @@ type SeoWebPageProps = { pathname: string; }; -const SeoWebPage: FunctionComponent> = ({ - title, - description, - pathname, - children -}) => { +const SeoWebPage: FunctionComponent = ({ title, description, pathname }) => { const { title: siteName, siteUrl, author } = useSiteMetadata(); const url = `${siteUrl}${pathname}`; return ( <> - - {title} - - > = ({ url={url} author={author} /> - - {children} ); }; diff --git a/src/components/layout/__snapshots__/layout.test.tsx.snap b/src/components/layout/__snapshots__/layout.test.tsx.snap index 8ccb530..7b3aeba 100644 --- a/src/components/layout/__snapshots__/layout.test.tsx.snap +++ b/src/components/layout/__snapshots__/layout.test.tsx.snap @@ -53,6 +53,77 @@ exports[` should render 1`] = ` About me + + + + + + + + + + +
diff --git a/src/components/layout/header/__snapshots__/header.test.tsx.snap b/src/components/layout/header/__snapshots__/header.test.tsx.snap index aaeae33..577062c 100644 --- a/src/components/layout/header/__snapshots__/header.test.tsx.snap +++ b/src/components/layout/header/__snapshots__/header.test.tsx.snap @@ -50,6 +50,77 @@ exports[`
should render 1`] = ` About me + + + + + + + + + + +
diff --git a/src/components/layout/header/header.tsx b/src/components/layout/header/header.tsx index e03a2be..f8fe3eb 100644 --- a/src/components/layout/header/header.tsx +++ b/src/components/layout/header/header.tsx @@ -1,6 +1,7 @@ import React from 'react'; import type { FunctionComponent, ReactElement } from 'react'; +import { DarkModeSwitch } from '../../dark-mode-switch/dark-mode-switch'; import { InternalLink } from '../../internal-link/internal-link'; type HeaderProps = { @@ -19,6 +20,8 @@ const Header: FunctionComponent = ({ title }): ReactElement => { Home Blog About me + + diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 25a93ff..fb6e32b 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -4,7 +4,8 @@ import type { FunctionComponent } from 'react'; import { Link } from 'gatsby'; import type { HeadFC, PageProps } from 'gatsby'; -import { SeoWebPage } from '../components/seo/seo-web-page'; +import { DocumentHead } from '../components/document-head/document-head'; +import { SeoWebPage } from '../components/document-head/seo/seo-web-page'; const NotFoundPage: FunctionComponent = () => { return ( @@ -33,10 +34,14 @@ const NotFoundPage: FunctionComponent = () => { export default NotFoundPage; -export const Head: HeadFC = ({ location }) => ( - -); +export const Head: HeadFC = ({ location }) => { + return ( + + + + ); +}; diff --git a/src/pages/about-me/index.tsx b/src/pages/about-me/index.tsx index f55a4ad..f9f3922 100644 --- a/src/pages/about-me/index.tsx +++ b/src/pages/about-me/index.tsx @@ -4,10 +4,11 @@ import type { FunctionComponent, ReactElement } from 'react'; import type { HeadFC } from 'gatsby'; import { StaticImage } from 'gatsby-plugin-image'; +import { DocumentHead } from '../../components/document-head/document-head'; +import { SeoWebPage } from '../../components/document-head/seo/seo-web-page'; import { ExternalLink } from '../../components/external-link/external-link'; import { InternalLink } from '../../components/internal-link/internal-link'; import { Layout } from '../../components/layout/layout'; -import { SeoWebPage } from '../../components/seo/seo-web-page'; const AboutMePage: FunctionComponent = (): ReactElement => { return ( @@ -99,10 +100,14 @@ const AboutMePage: FunctionComponent = (): ReactElement => { export default AboutMePage; -export const Head: HeadFC = ({ location }) => ( - -); +export const Head: HeadFC = ({ location }) => { + return ( + + + + ); +}; diff --git a/src/pages/blog/index.tsx b/src/pages/blog/index.tsx index 018b6a8..c54bc68 100644 --- a/src/pages/blog/index.tsx +++ b/src/pages/blog/index.tsx @@ -5,8 +5,9 @@ import type { HeadFC } from 'gatsby'; import { BlogPostList } from '../../components/blog-post-list'; import { useBlogPosts } from '../../components/blog-posts/use-blog-posts'; +import { DocumentHead } from '../../components/document-head/document-head'; +import { SeoWebPage } from '../../components/document-head/seo/seo-web-page'; import { Layout } from '../../components/layout/layout'; -import { SeoWebPage } from '../../components/seo/seo-web-page'; const BlogPage: FunctionComponent = (): ReactElement => { const blogPosts = useBlogPosts(); @@ -40,10 +41,14 @@ const BlogPage: FunctionComponent = (): ReactElement => { export default BlogPage; -export const Head: HeadFC = ({ location }) => ( - -); +export const Head: HeadFC = ({ location }) => { + return ( + + + + ); +}; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a45dba7..4f7aa0e 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -5,9 +5,10 @@ import type { HeadFC, PageProps } from 'gatsby'; import { BlogPostList } from '../components/blog-post-list'; import { useRecentBlogPosts } from '../components/blog-posts/use-recent-blog-posts'; +import { DocumentHead } from '../components/document-head/document-head'; +import { SeoWebPage } from '../components/document-head/seo/seo-web-page'; import { InternalLink } from '../components/internal-link/internal-link'; import { Layout } from '../components/layout/layout'; -import { SeoWebPage } from '../components/seo/seo-web-page'; import { useSiteMetadata } from '../components/site-metadata/use-site-metadata'; const IndexPage: FunctionComponent = (): ReactElement => { @@ -54,10 +55,12 @@ export const Head: HeadFC = ({ location }) => { const { title, description } = useSiteMetadata(); return ( - + + + ); }; diff --git a/src/styles/global.css b/src/styles/global.css index b5c61c9..40d0778 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1,3 +1,13 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + :root { + color-scheme: light; + } + + :root.dark { + color-scheme: dark; + } +} diff --git a/src/templates/blog-post.tsx b/src/templates/blog-post.tsx index f48cec0..4bd8bc5 100644 --- a/src/templates/blog-post.tsx +++ b/src/templates/blog-post.tsx @@ -3,8 +3,9 @@ import type { FunctionComponent, ReactElement } from 'react'; import type { HeadFC, PageProps } from 'gatsby'; +import { DocumentHead } from '../components/document-head/document-head'; +import { SeoBlogPosting } from '../components/document-head/seo/seo-blog-posting'; import { Layout } from '../components/layout/layout'; -import { SeoBlogPosting } from '../components/seo/seo-blog-posting'; type PageContext = { id: string; @@ -42,15 +43,19 @@ const BlogPostTemplate: FunctionComponent> = ({ pag ); }; -const Head: HeadFC = ({ location, pageContext: { title, excerpt, published, tags } }) => ( - -); +const Head: HeadFC = ({ location, pageContext: { title, excerpt, published, tags } }) => { + return ( + + + + ); +}; export default BlogPostTemplate; diff --git a/tailwind.config.js b/tailwind.config.js index 7e10f60..c299845 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -7,5 +7,6 @@ module.exports = { theme: { extend: {} }, + darkMode: 'class', plugins: [require('@tailwindcss/typography')] };