diff --git a/.eslintrc b/.eslintrc index aaefbec8..974e65ab 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,7 +6,9 @@ "sourceType": "module" }, "env": { "browser": true, "node": true, "es6": true, "jest": true }, - "settings": { "react": { "version": "detect" } }, + "settings": { + "react": { "version": "detect" } + }, "overrides": [ { "files": ["**/*.ts", "**/*.tsx"], diff --git a/src/@types/GitHub.d.ts b/src/@types/GitHub.d.ts new file mode 100644 index 00000000..c15399b7 --- /dev/null +++ b/src/@types/GitHub.d.ts @@ -0,0 +1,25 @@ +export interface GitHubRepo { + name: string + url: string + owner: { + login: string + } + object: { + id: string + text: string + } +} + +export interface GitHub { + github: { + viewer: { + repositories: { + edges: [ + { + node: GitHubRepo + } + ] + } + } + } +} diff --git a/src/@types/PostMetadata.d.ts b/src/@types/PostMetadata.d.ts new file mode 100644 index 00000000..4166e3e1 --- /dev/null +++ b/src/@types/PostMetadata.d.ts @@ -0,0 +1,53 @@ +import { FluidObject } from 'gatsby-image' + +export interface PostMetadataFields { + slug: string + date: string + githubLink: string +} + +export interface PostMetadataImageExif { + iso: string + model: string + fstop: string + shutterspeed: string + focalLength: string + lensModel: string + exposure: string + gps: { + latitude: string + longitude: string + } +} + +export interface PostMetadataImage { + childImageSharp: { fluid: FluidObject } + fields: { + exif: PostMetadataImageExif + } +} + +export interface PostMetadataFrontmatter { + type?: string + title: string + description?: string + image?: PostMetadataImage + author?: string + updated?: string + tags?: string[] + linkurl?: string + style?: { + publicURL?: string + } + changelog?: string +} + +export interface PostMetadata { + id?: string + html?: string + excerpt?: string + frontmatter: PostMetadataFrontmatter + fields?: PostMetadataFields + rawMarkdownBody?: string + fileAbsolutePath?: string +} diff --git a/src/@types/SiteMetadata.d.ts b/src/@types/SiteMetadata.d.ts new file mode 100644 index 00000000..94789fb3 --- /dev/null +++ b/src/@types/SiteMetadata.d.ts @@ -0,0 +1,29 @@ +export interface MenuItem { + title: string + link: string +} + +export interface Author { + name: string + email: string + uri: string + twitter: string + github: string + facebook: string + bitcoin: string + ether: string +} + +export interface SiteMetadata { + siteTitle: string + siteTitleShort: string + siteDescription: string + siteUrl: string + author: Author + typekitID: string + menu: MenuItem[] + rss: string + jsonfeed: string + itemsPerPage: number + repoContentPath: string +} diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 5559a19d..dde94038 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -16,3 +16,14 @@ declare module '*.svg' { const src: string export default src } + +interface Window { + __LUNR__: { + readonly [language: string]: { + readonly index: lunr.Index + readonly store: { + readonly [key: string]: any + } + } + } +} diff --git a/src/components/Post/PostContent.tsx b/src/components/Post/PostContent.tsx index cdbf9bf2..3319bef5 100644 --- a/src/components/Post/PostContent.tsx +++ b/src/components/Post/PostContent.tsx @@ -1,8 +1,9 @@ import React from 'react' import Changelog from '../atoms/Changelog' +import { PostMetadata } from '../../@types/PostMetadata' // Remove lead paragraph from content -const PostContent = ({ post }: { post: any }) => { +const PostContent = ({ post }: { post: PostMetadata }) => { const separator = '' const changelog = post.frontmatter.changelog diff --git a/src/components/Post/PostLead.tsx b/src/components/Post/PostLead.tsx index 9e8cf86a..f7efd094 100644 --- a/src/components/Post/PostLead.tsx +++ b/src/components/Post/PostLead.tsx @@ -1,15 +1,10 @@ import React from 'react' import styles from './PostLead.module.scss' +import { PostMetadata } from '../../@types/PostMetadata' // Extract lead paragraph from content // Grab everything before more tag, or just first paragraph -const PostLead = ({ - post, - index -}: { - post: { html: string } - index?: boolean -}) => { +const PostLead = ({ post, index }: { post: PostMetadata; index?: boolean }) => { let lead const content = post.html const separator = '' diff --git a/src/components/Post/PostMeta.tsx b/src/components/Post/PostMeta.tsx index 1d3556c7..c51a5ca3 100644 --- a/src/components/Post/PostMeta.tsx +++ b/src/components/Post/PostMeta.tsx @@ -4,8 +4,9 @@ import slugify from 'slugify' import Time from '../atoms/Time' import { useSiteMetadata } from '../../hooks/use-site-metadata' import styles from './PostMeta.module.scss' +import { PostMetadata } from '../../@types/PostMetadata' -export default function PostMeta({ post }: { post: any }) { +export default function PostMeta({ post }: { post: PostMetadata }) { const siteMeta = useSiteMetadata() const { author, updated, tags, type } = post.frontmatter const { date } = post.fields diff --git a/src/components/Post/PostTeaser.tsx b/src/components/Post/PostTeaser.tsx index 07f85992..c61a155c 100644 --- a/src/components/Post/PostTeaser.tsx +++ b/src/components/Post/PostTeaser.tsx @@ -2,12 +2,13 @@ import React from 'react' import { Link } from 'gatsby' import Image from '../atoms/Image' import styles from './PostTeaser.module.scss' +import { PostMetadata } from '../../@types/PostMetadata' export default function PostTeaser({ post, toggleSearch }: { - post: { fields: { slug: string }; frontmatter: { image: any; title: string } } + post: PostMetadata toggleSearch?: () => void }) { const { image, title } = post.frontmatter diff --git a/src/components/Search/SearchResults.tsx b/src/components/Search/SearchResults.tsx index cb271e1a..f1d27c4e 100644 --- a/src/components/Search/SearchResults.tsx +++ b/src/components/Search/SearchResults.tsx @@ -5,7 +5,11 @@ import Container from '../atoms/Container' import PostTeaser from '../Post/PostTeaser' import SearchResultsEmpty from './SearchResultsEmpty' import styles from './SearchResults.module.scss' -import { GatsbyImageProps } from 'gatsby-image' +import { PostMetadata } from '../../@types/PostMetadata' + +export interface Results { + slug: string +} const query = graphql` query { @@ -30,48 +34,32 @@ const query = graphql` } ` -interface Page { - slug: string -} - -interface PostNode { - node: { - id: string - fields: { slug: string } - frontmatter: { - title: string - type: string - image: { childImageSharp: GatsbyImageProps } - } - } -} - -export default function SearchResults({ +function SearchResultsPure({ searchQuery, results, - toggleSearch + toggleSearch, + posts }: { + posts: [{ node: PostMetadata }] searchQuery: string - results: any + results: Results[] toggleSearch(): void }) { - const data = useStaticQuery(query) - const posts = data.allMarkdownRemark.edges - - // creating portal to break out of DOM node we're in - // and render the results in content container - return ReactDOM.createPortal( + return (
{results.length > 0 ? (
, + + ) +} + +export default function SearchResults({ + searchQuery, + results, + toggleSearch +}: { + searchQuery: string + results: Results[] + toggleSearch(): void +}) { + const data = useStaticQuery(query) + const posts = data.allMarkdownRemark.edges + + // creating portal to break out of DOM node we're in + // and render the results in content container + return ReactDOM.createPortal( + , document.getElementById('document') ) } diff --git a/src/components/Search/SearchResultsEmpty.tsx b/src/components/Search/SearchResultsEmpty.tsx index 09a3ed61..d987ae4f 100644 --- a/src/components/Search/SearchResultsEmpty.tsx +++ b/src/components/Search/SearchResultsEmpty.tsx @@ -1,12 +1,13 @@ import React from 'react' import styles from './SearchResultsEmpty.module.scss' +import { Results } from './SearchResults' const SearchResultsEmpty = ({ searchQuery, results }: { searchQuery: string - results: [] + results: Results[] }) => (
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 117b9140..7848e5d1 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -1,26 +1,12 @@ import React, { useState } from 'react' import { Helmet } from 'react-helmet' import { CSSTransition } from 'react-transition-group' -import lunr from 'lunr' import SearchInput from './SearchInput' import SearchButton from './SearchButton' import SearchResults from './SearchResults' import styles from './index.module.scss' -declare global { - interface Window { - __LUNR__: { - readonly [language: string]: { - readonly index: lunr.Index - readonly store: { - readonly [key: string]: any - } - } - } - } -} - function getSearchResults(query: string, lng: string) { if (!query || !window.__LUNR__) return [] const lunrIndex = window.__LUNR__[lng] diff --git a/src/components/Web3Donation/Alerts.tsx b/src/components/Web3Donation/Alerts.tsx index f960f005..dad4359b 100644 --- a/src/components/Web3Donation/Alerts.tsx +++ b/src/components/Web3Donation/Alerts.tsx @@ -21,7 +21,7 @@ export default function Alerts({ message }: { transactionHash: string | null - message: { text?: MessageChannel; status?: string } | null + message: { text?: string; status?: string } | null }) { const constructMessage = () => { let messageOutput diff --git a/src/components/atoms/Changelog.test.tsx b/src/components/atoms/Changelog.test.tsx index ea544f14..3651523c 100644 --- a/src/components/atoms/Changelog.test.tsx +++ b/src/components/atoms/Changelog.test.tsx @@ -2,28 +2,22 @@ import React from 'react' import testRender from '../../../jest/testRender' import { PureChangelog as Changelog } from './Changelog' +import { GitHubRepo } from '../../@types/GitHub' -const data = { - github: { - viewer: { - repositories: { - edges: [ - { - node: { - name: 'gatsby-plugin-matomo', - url: 'https://hello.com', - owner: { login: 'kremalicious' }, - object: { - text: 'hello' - } - } - } - ] +const repos: [{ node: GitHubRepo }] = [ + { + node: { + name: 'gatsby-plugin-matomo', + url: 'https://hello.com', + owner: { login: 'kremalicious' }, + object: { + id: 'hello', + text: 'hello' } } } -} +] describe('Changelog', () => { - testRender() + testRender() }) diff --git a/src/components/atoms/Changelog.tsx b/src/components/atoms/Changelog.tsx index 051d892d..ca8808ad 100644 --- a/src/components/atoms/Changelog.tsx +++ b/src/components/atoms/Changelog.tsx @@ -3,12 +3,17 @@ import { graphql, useStaticQuery } from 'gatsby' import remark from 'remark' import remarkReact from 'remark-react' import styles from './Changelog.module.scss' +import { GitHub, GitHubRepo } from '../../@types/GitHub' -export function PureChangelog({ repo, data }: { repo: string; data: any }) { - const repositoriesGitHub = data.github.viewer.repositories.edges - - const repoFilteredArray = repositoriesGitHub - .map(({ node }: { node: any }) => { +export function PureChangelog({ + repo, + repos +}: { + repo: string + repos: [{ node: GitHubRepo }] +}) { + const repoFilteredArray = repos + .map(({ node }: { node: GitHubRepo }) => { if (node.name === repo) return node }) .filter((n: any) => n) @@ -73,6 +78,7 @@ export default function Changelog({ repo }: { repo: string }) { } } ` - const data = useStaticQuery(queryGithub) - return + const data: GitHub = useStaticQuery(queryGithub) + const repos: [{ node: GitHubRepo }] = data.github.viewer.repositories.edges + return } diff --git a/src/components/atoms/Exif.tsx b/src/components/atoms/Exif.tsx index e945690c..962e445b 100644 --- a/src/components/atoms/Exif.tsx +++ b/src/components/atoms/Exif.tsx @@ -1,22 +1,9 @@ import React from 'react' import ExifMap from './ExifMap' import styles from './Exif.module.scss' +import { PostMetadataImageExif } from '../../@types/PostMetadata' -interface ExifProps { - iso: string - model: string - fstop: string - shutterspeed: string - focalLength: string - lensModel: string - exposure: string - gps: { - latitude: string - longitude: string - } -} - -export default function Exif({ exif }: { exif: ExifProps }) { +export default function Exif({ exif }: { exif: PostMetadataImageExif }) { const { iso, model, fstop, shutterspeed, focalLength, exposure, gps } = exif return ( diff --git a/src/components/atoms/SEO.tsx b/src/components/atoms/SEO.tsx index 8c5f26ea..57f58c53 100644 --- a/src/components/atoms/SEO.tsx +++ b/src/components/atoms/SEO.tsx @@ -2,6 +2,7 @@ import React from 'react' import { graphql, useStaticQuery } from 'gatsby' import { Helmet } from 'react-helmet' import { useSiteMetadata } from '../../hooks/use-site-metadata' +import { PostMetadata } from '../../@types/PostMetadata' const query = graphql` query { @@ -116,7 +117,7 @@ export default function SEO({ slug, postSEO }: { - post?: any + post?: PostMetadata slug?: string postSEO?: boolean }) { diff --git a/src/components/molecules/Featured.tsx b/src/components/molecules/Featured.tsx index 6864bbfa..8251d057 100644 --- a/src/components/molecules/Featured.tsx +++ b/src/components/molecules/Featured.tsx @@ -2,39 +2,16 @@ import React from 'react' import { Link, graphql, useStaticQuery } from 'gatsby' import Image from '../atoms/Image' import styles from './Featured.module.scss' +import { PostMetadata } from '../../@types/PostMetadata' -const query = graphql` - query { - allMarkdownRemark( - filter: { frontmatter: { featured: { eq: true } } } - sort: { fields: [fields___date], order: DESC } - ) { - edges { - node { - id - frontmatter { - title - image { - childImageSharp { - ...ImageFluidThumb - } - } - } - fields { - slug - } - } - } - } - } -` - -export default function Featured() { - const data = useStaticQuery(query) - +function FeaturedPure({ + data +}: { + data: { allMarkdownRemark: { edges: [{ node: PostMetadata }] } } +}) { return (
- {data.allMarkdownRemark.edges.map(({ node }: { node: any }) => { + {data.allMarkdownRemark.edges.map(({ node }: { node: PostMetadata }) => { const { title, image } = node.frontmatter const { slug } = node.fields @@ -50,3 +27,34 @@ export default function Featured() {
) } + +export default function Featured() { + const query = graphql` + query { + allMarkdownRemark( + filter: { frontmatter: { featured: { eq: true } } } + sort: { fields: [fields___date], order: DESC } + ) { + edges { + node { + id + frontmatter { + title + image { + childImageSharp { + ...ImageFluidThumb + } + } + } + fields { + slug + } + } + } + } + } + ` + + const data = useStaticQuery(query) + return +} diff --git a/src/components/molecules/Menu.tsx b/src/components/molecules/Menu.tsx index a12bc55d..4de1cf2e 100644 --- a/src/components/molecules/Menu.tsx +++ b/src/components/molecules/Menu.tsx @@ -4,6 +4,7 @@ import { Link } from 'gatsby' import Hamburger from '../atoms/Hamburger' import styles from './Menu.module.scss' import { useSiteMetadata } from '../../hooks/use-site-metadata' +import { MenuItem } from '../../@types/SiteMetadata' export default function Menu() { const [menuOpen, setMenuOpen] = useState(false) @@ -13,7 +14,7 @@ export default function Menu() { setMenuOpen(!menuOpen) } - const MenuItems = menu.map((item: any) => ( + const MenuItems = menu.map((item: MenuItem) => (
  • {item.title} diff --git a/src/components/molecules/RelatedPosts.tsx b/src/components/molecules/RelatedPosts.tsx index 922dac41..0d40d38f 100644 --- a/src/components/molecules/RelatedPosts.tsx +++ b/src/components/molecules/RelatedPosts.tsx @@ -2,6 +2,10 @@ import React, { useState } from 'react' import { graphql, useStaticQuery } from 'gatsby' import PostTeaser from '../Post/PostTeaser' import styles from './RelatedPosts.module.scss' +import { + PostMetadata, + PostMetadataFrontmatter +} from '../../@types/PostMetadata' const query = graphql` query { @@ -31,22 +35,26 @@ const query = graphql` } ` -function postsWithDataFilter(posts: [], key: string, valuesToFind: string[]) { - const newArray = posts.filter((post: any) => { - const frontmatterKey = post.node.frontmatter[key] +function postsWithDataFilter( + posts: [{ node: PostMetadata }], + key: keyof PostMetadataFrontmatter, + valuesToFind: string[] +) { + const newArray = posts.filter(({ node }: { node: PostMetadata }) => { + const frontmatterKey = node.frontmatter[key] as [] if ( frontmatterKey !== null && frontmatterKey.some((r: string) => valuesToFind.includes(r)) ) { - return post + return node } }) return newArray } function photosWithDataFilter(posts: []) { - const newArray = posts.filter((post: any) => { + const newArray = posts.filter((post: { node: PostMetadata }) => { const { fileAbsolutePath } = post.node if (fileAbsolutePath.includes('content/photos')) { @@ -85,7 +93,7 @@ export default function RelatedPosts({ {filteredPosts .sort(() => 0.5 - Math.random()) .slice(0, 6) - .map(({ node }: { node: any }) => ( + .map(({ node }: { node: PostMetadata }) => ( ))} diff --git a/src/hooks/use-site-metadata.ts b/src/hooks/use-site-metadata.ts index 7914ef48..db1be781 100644 --- a/src/hooks/use-site-metadata.ts +++ b/src/hooks/use-site-metadata.ts @@ -1,6 +1,7 @@ import { useStaticQuery, graphql } from 'gatsby' +import { SiteMetadata } from '../@types/SiteMetadata' -export const useSiteMetadata = () => { +export function useSiteMetadata(): SiteMetadata { const query = graphql` query { site { diff --git a/src/pages/goodies.tsx b/src/pages/goodies.tsx index d98322e9..3c228606 100644 --- a/src/pages/goodies.tsx +++ b/src/pages/goodies.tsx @@ -3,6 +3,7 @@ import { graphql, Link } from 'gatsby' import PostImage from '../components/Post/PostImage' import Page from '../templates/Page' import styles from './goodies.module.scss' +import { PostMetadata } from '../@types/PostMetadata' const page = { frontmatter: { @@ -12,16 +13,7 @@ const page = { } } -interface Post { - id: string - fields: { slug: string } - frontmatter: { - title: string - image: { childImageSharp: any } - } -} - -const GoodiesThumb = ({ post }: { post: Post }) => { +const GoodiesThumb = ({ post }: { post: PostMetadata }) => { const { title, image } = post.frontmatter const { slug } = post.fields @@ -41,7 +33,7 @@ export default function Goodies({ data, location }: { - data: { goodies: { edges: [{ node: Post }] } } + data: { goodies: { edges: [{ node: PostMetadata }] } } location: Location }) { return ( diff --git a/src/pages/photos.tsx b/src/pages/photos.tsx index 8b7fd248..4b4e3fa2 100644 --- a/src/pages/photos.tsx +++ b/src/pages/photos.tsx @@ -3,6 +3,7 @@ import { graphql, Link } from 'gatsby' import Page from '../templates/Page' import PostImage from '../components/Post/PostImage' import styles from './photos.module.scss' +import { PostMetadata } from '../@types/PostMetadata' const page = { frontmatter: { @@ -11,17 +12,7 @@ const page = { } } -interface Photo { - id: string - fields: { slug: string } - frontmatter: { - title: string - type: string - image: { childImageSharp: any } - } -} - -const PhotoThumb = ({ photo }: { photo: Photo }) => { +const PhotoThumb = ({ photo }: { photo: PostMetadata }) => { const { title, image } = photo.frontmatter const { slug } = photo.fields const { fluid } = image.childImageSharp @@ -37,21 +28,11 @@ const PhotoThumb = ({ photo }: { photo: Photo }) => { ) } -interface PhotosData { - photos: { - edges: [ - { - node: Photo - } - ] - } -} - export default function Photos({ data, location }: { - data: PhotosData + data: { photos: { edges: [{ node: PostMetadata }] } } location: Location }) { return ( diff --git a/src/templates/Page.tsx b/src/templates/Page.tsx index 95e40959..79600ad3 100644 --- a/src/templates/Page.tsx +++ b/src/templates/Page.tsx @@ -3,6 +3,7 @@ import { Helmet } from 'react-helmet' import SEO from '../components/atoms/SEO' import Layout from '../components/Layout' import styles from './Page.module.scss' +import { PostMetadata } from '../@types/PostMetadata' export default function Page({ title, @@ -14,8 +15,8 @@ export default function Page({ title: string children: any section?: string - location?: any - post?: any + location?: Location + post?: PostMetadata }) { return ( <> diff --git a/src/templates/Post.tsx b/src/templates/Post.tsx index 4919e548..6001f45e 100644 --- a/src/templates/Post.tsx +++ b/src/templates/Post.tsx @@ -13,15 +13,16 @@ import PostMeta from '../components/Post/PostMeta' import Exif from '../components/atoms/Exif' import RelatedPosts from '../components/molecules/RelatedPosts' import styles from './Post.module.scss' +import { PostMetadata } from '../@types/PostMetadata' export default function Post({ data, location }: { - data: any + data: { post: PostMetadata } location: Location }) { - const { markdownRemark: post } = data + const { post } = data const { title, image, type, linkurl, style, tags } = post.frontmatter const { slug, githubLink } = post.fields @@ -62,7 +63,7 @@ export default function Post({ export const pageQuery = graphql` query BlogPostBySlug($slug: String!) { - markdownRemark(fields: { slug: { eq: $slug } }) { + post: markdownRemark(fields: { slug: { eq: $slug } }) { html excerpt frontmatter { diff --git a/src/templates/Posts.tsx b/src/templates/Posts.tsx index 7c59cafe..d47c51d1 100644 --- a/src/templates/Posts.tsx +++ b/src/templates/Posts.tsx @@ -12,13 +12,14 @@ import Pagination from '../components/molecules/Pagination' import Featured from '../components/molecules/Featured' import styles from './Posts.module.scss' import stylesPost from './Post.module.scss' +import { PostMetadata } from '../@types/PostMetadata' export default function Posts({ data, location, pageContext }: { - data: any + data: { allMarkdownRemark: { edges: [{ node: PostMetadata }] } } location: Location pageContext: { tag: string @@ -30,7 +31,7 @@ export default function Posts({ const edges = data.allMarkdownRemark.edges const { tag, currentPageNumber, numPages, nextPage } = pageContext - const PostsList = edges.map(({ node }: { node: any }) => { + const PostsList = edges.map(({ node }: { node: PostMetadata }) => { const { type, linkurl, title, image } = node.frontmatter const { slug } = node.fields