chore: add prettier to linting

This commit is contained in:
Corbin Crutchley
2021-11-30 07:34:07 -08:00
parent 602da1951f
commit 31ca6cae33
14 changed files with 352 additions and 312 deletions

View File

@@ -1,3 +1,7 @@
{ {
"extends": ["next/core-web-vitals", "prettier"] "plugins": ["prettier"],
"extends": ["next/core-web-vitals", "prettier"],
"rules": {
"prettier/prettier": "error"
}
} }

1
.gitignore vendored
View File

@@ -34,3 +34,4 @@ yarn-error.log*
.vercel .vercel
/public/posts /public/posts
.idea/

5
.idea/.gitignore generated vendored
View File

@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/unicorn-utterances.iml" filepath="$PROJECT_DIR$/.idea/unicorn-utterances.iml" />
</modules>
</component>
</project>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
.prettierrc.json Normal file
View File

@@ -0,0 +1 @@
{}

24
package-lock.json generated
View File

@@ -2362,6 +2362,15 @@
} }
} }
}, },
"eslint-plugin-prettier": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz",
"integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==",
"dev": true,
"requires": {
"prettier-linter-helpers": "^1.0.0"
}
},
"eslint-plugin-react": { "eslint-plugin-react": {
"version": "7.27.1", "version": "7.27.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.27.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.27.1.tgz",
@@ -2554,6 +2563,12 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
}, },
"fast-diff": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
"integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
"dev": true
},
"fast-glob": { "fast-glob": {
"version": "3.2.7", "version": "3.2.7",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
@@ -5433,6 +5448,15 @@
"integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==", "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
"dev": true "dev": true
}, },
"prettier-linter-helpers": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
"integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
"dev": true,
"requires": {
"fast-diff": "^1.1.2"
}
},
"pretty-format": { "pretty-format": {
"version": "26.6.2", "version": "26.6.2",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",

View File

@@ -49,6 +49,7 @@
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-next": "12.0.4", "eslint-config-next": "12.0.4",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"prettier": "^2.5.0" "prettier": "^2.5.0"
} }
} }

View File

@@ -17,17 +17,19 @@ interface SEOProps {
} }
type MetaSEOProps = SEOProps & { type MetaSEOProps = SEOProps & {
metaDescription: string metaDescription: string;
metaKeywords: string metaKeywords: string;
metaImage: string metaImage: string;
} };
const GoogleAnalytics = () => { const GoogleAnalytics = () => {
return <> return (
<>
<link rel="preconnect" href="https://www.google.com" /> <link rel="preconnect" href="https://www.google.com" />
<link rel="preconnect" href="https://marketingplatform.google.com" /> <link rel="preconnect" href="https://marketingplatform.google.com" />
</> </>
} );
};
const FacebookSEO = (props: MetaSEOProps) => { const FacebookSEO = (props: MetaSEOProps) => {
const { const {
@@ -39,109 +41,137 @@ const FacebookSEO = (props: MetaSEOProps) => {
unicornsData, unicornsData,
publishedTime, publishedTime,
editedTime, editedTime,
keywords keywords,
} = props; } = props;
return <> return (
<meta property="og:url" content={siteMetadata.siteUrl + (pathName || "")}/> <>
<meta
property="og:url"
content={siteMetadata.siteUrl + (pathName || "")}
/>
<meta property="og:site_name" content={siteMetadata.title} /> <meta property="og:site_name" content={siteMetadata.title} />
<meta property="og:title" content={title} /> <meta property="og:title" content={title} />
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:description" <meta property="og:description" content={metaDescription} />
content={metaDescription}/>
<meta property="og:image" content={metaImage} /> <meta property="og:image" content={metaImage} />
{ {type === "article" ? (
type === 'article' ? <meta property="og:type" content="article" />
<meta property="og:type" content="article"/> : ) : type === "profile" ? (
type === 'profile' ? <meta property="og:type" content="profile" />
<meta property="og:type" content="profile"/> : ) : (
<meta property="og:type" content="blog" /> <meta property="og:type" content="blog" />
} )}
{ {type === "profile"
type === 'profile' ? ? [
[ <meta
<meta key="firstName" property="profile:firstName" content={unicornsData![0].firstName}/>, key="firstName"
<meta key="lastName" property="profile:lastName" content={unicornsData![0].lastName}/>, property="profile:firstName"
<meta key="username" property="profile:username" content={unicornsData![0].id}/> content={unicornsData![0].firstName}
/>,
<meta
key="lastName"
property="profile:lastName"
content={unicornsData![0].lastName}
/>,
<meta
key="username"
property="profile:username"
content={unicornsData![0].id}
/>,
] ]
: null : null}
} {type !== "article"
{ ? null
type !== 'article' ? null : [ : [
<meta key="section" property="article:section" content="Technology"/>, <meta
<meta key="author" property="article:author" content={unicornsData!.map((uni) => uni.name).join(',')}/>, key="section"
publishedTime ? <meta key="published_time" property="article:published_time" content={publishedTime}/> : null, property="article:section"
editedTime ? <meta key="modified_time" property="article:modified_time" content={editedTime}/> : null, content="Technology"
...keywords!.map(keyword => <meta key={keyword} property="article:tag" content={keyword}/>) />,
] <meta
} key="author"
property="article:author"
content={unicornsData!.map((uni) => uni.name).join(",")}
/>,
publishedTime ? (
<meta
key="published_time"
property="article:published_time"
content={publishedTime}
/>
) : null,
editedTime ? (
<meta
key="modified_time"
property="article:modified_time"
content={editedTime}
/>
) : null,
...keywords!.map((keyword) => (
<meta key={keyword} property="article:tag" content={keyword} />
)),
]}
</> </>
} );
};
const TwitterSingleAuthor = (props: MetaSEOProps) => { const TwitterSingleAuthor = (props: MetaSEOProps) => {
const socialUnicorn = props.unicornsData!.find((uni) => uni.socials); const socialUnicorn = props.unicornsData!.find((uni) => uni.socials);
const uniTwitter = const uniTwitter =
socialUnicorn && socialUnicorn.socials && socialUnicorn.socials.twitter; socialUnicorn && socialUnicorn.socials && socialUnicorn.socials.twitter;
if (uniTwitter) { if (uniTwitter) {
return <meta property="twitter:creator" content={`@${uniTwitter}`}/> return <meta property="twitter:creator" content={`@${uniTwitter}`} />;
}
return null
} }
return null;
};
const TwitterSEO = (props: MetaSEOProps) => { const TwitterSEO = (props: MetaSEOProps) => {
const { metaDescription, title, metaImage, type, unicornsData } = props; const { metaDescription, title, metaImage, type, unicornsData } = props;
return <> return (
<>
<meta name="twitter:title" content={title} /> <meta name="twitter:title" content={title} />
<meta name="twitter:description" <meta name="twitter:description" content={metaDescription} />
content={metaDescription}/>
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content={siteMetadata.twitterHandle} /> <meta name="twitter:site" content={siteMetadata.twitterHandle} />
<meta name="twitter:image" content={metaImage} /> <meta name="twitter:image" content={metaImage} />
{ {type === "article"
type === 'article' ? ? [
[ unicornsData!.length === 1 ? (
unicornsData!.length === 1 ? <TwitterSingleAuthor key="singleAuthor" {...props} />
<TwitterSingleAuthor key="singleAuthor" {...props}/> : ) : null,
null
] ]
: null : null}
}
</> </>
} );
};
export const SEO: React.FC<SEOProps> = ( export const SEO: React.FC<SEOProps> = (props) => {
props const { description = "", children, title, keywords, canonical } = props;
) => {
const {
description = "",
children,
title,
keywords,
canonical,
} = props;
const metaDescription = description || siteMetadata.description; const metaDescription = description || siteMetadata.description;
const metaKeywords = keywords ? keywords.join(',') : siteMetadata.keywords; const metaKeywords = keywords ? keywords.join(",") : siteMetadata.keywords;
const metaImage = `${siteUrl}/share-banner.png`; const metaImage = `${siteUrl}/share-banner.png`;
const metaProps = { const metaProps = {
metaDescription, metaDescription,
metaKeywords, metaKeywords,
metaImage metaImage,
} };
return <Head> return (
<title>{title ? `${title} | ${siteMetadata.title}` : siteMetadata.title}</title> <Head>
<title>
{title ? `${title} | ${siteMetadata.title}` : siteMetadata.title}
</title>
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
{canonical ? <link rel="canonical" href={canonical} /> : null} {canonical ? <link rel="canonical" href={canonical} /> : null}
<meta property="name" content={siteMetadata.title} /> <meta property="name" content={siteMetadata.title} />
<meta name="description" <meta name="description" content={metaDescription} />
content={metaDescription}/> <meta property="keywords" content={metaKeywords} />
<meta property="keywords"
content={metaKeywords}/>
<GoogleAnalytics /> <GoogleAnalytics />
<FacebookSEO {...props} {...metaProps} /> <FacebookSEO {...props} {...metaProps} />
<TwitterSEO {...props} {...metaProps} /> <TwitterSEO {...props} {...metaProps} />
{children} {children}
</Head> </Head>
} );
};

View File

@@ -1,6 +1,6 @@
import { AppProps } from 'next/app' import { AppProps } from "next/app";
import '../styles/index.css' import "../styles/index.css";
export default function MyApp({ Component, pageProps }: AppProps) { export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} /> return <Component {...pageProps} />;
} }

View File

@@ -1,4 +1,4 @@
import Document, { Html, Head, Main, NextScript } from 'next/document' import Document, { Html, Head, Main, NextScript } from "next/document";
export default class MyDocument extends Document { export default class MyDocument extends Document {
render() { render() {
@@ -23,6 +23,6 @@ export default class MyDocument extends Document {
<NextScript /> <NextScript />
</body> </body>
</Html> </Html>
) );
} }
} }

View File

@@ -1,18 +1,17 @@
import {getAllPosts} from '../api/api' import { getAllPosts } from "../api/api";
import Post from '../types/post' import Post from "../types/post";
import React from 'react' import React from "react";
import Link from 'next/link'; import Link from "next/link";
type Props = { type Props = {
allPosts: Post[] allPosts: Post[];
} };
const Index = ({ allPosts }: Props) => { const Index = ({ allPosts }: Props) => {
return ( return (
<> <>
<ul> <ul>
{allPosts.map( {allPosts.map((post) => (
post =>
<li key={post.slug}> <li key={post.slug}>
<h2> <h2>
<Link href={`/posts/[slug]`} as={`/posts/${post.slug}`}> <Link href={`/posts/[slug]`} as={`/posts/${post.slug}`}>
@@ -21,13 +20,13 @@ const Index = ({allPosts}: Props) => {
</h2> </h2>
<p>{post.published}</p> <p>{post.published}</p>
</li> </li>
)} ))}
</ul> </ul>
</> </>
) );
} };
export default Index export default Index;
export const getStaticProps = async () => { export const getStaticProps = async () => {
let allPosts = getAllPosts({ let allPosts = getAllPosts({
@@ -35,17 +34,17 @@ export const getStaticProps = async () => {
published: true, published: true,
slug: true, slug: true,
author: true, author: true,
excerpt: true excerpt: true,
} as const) } as const);
// sort posts by date in descending order // sort posts by date in descending order
allPosts = allPosts.sort((post1, post2) => { allPosts = allPosts.sort((post1, post2) => {
const date1 = new Date(post1.published); const date1 = new Date(post1.published);
const date2 = new Date(post2.published); const date2 = new Date(post2.published);
return (date1 > date2 ? -1 : 1); return date1 > date2 ? -1 : 1;
}) });
return { return {
props: { allPosts }, props: { allPosts },
} };
} };

View File

@@ -1,25 +1,31 @@
// import { useRouter } from 'next/router' // import { useRouter } from 'next/router'
// import ErrorPage from 'next/error' // import ErrorPage from 'next/error'
import {getPostBySlug, getAllPosts, postsDirectory} from '../../api/api' import { getPostBySlug, getAllPosts, postsDirectory } from "../../api/api";
import * as React from 'react'; import * as React from "react";
import markdownToHtml from "../../utils/markdownToHtml"; import markdownToHtml from "../../utils/markdownToHtml";
import { useMarkdownRenderer } from "../../hooks/useMarkdownRenderer"; import { useMarkdownRenderer } from "../../hooks/useMarkdownRenderer";
import 'react-medium-image-zoom/dist/styles.css' import "react-medium-image-zoom/dist/styles.css";
type Props = { type Props = {
markdownHTML: string markdownHTML: string;
slug: string slug: string;
postsDirectory: string postsDirectory: string;
wordCount: number wordCount: number;
seriesPosts: any[] seriesPosts: any[];
} };
const Post = ({markdownHTML, slug, postsDirectory, wordCount, seriesPosts}: Props) => { const Post = ({
markdownHTML,
slug,
postsDirectory,
wordCount,
seriesPosts,
}: Props) => {
const result = useMarkdownRenderer({ const result = useMarkdownRenderer({
markdownHTML, markdownHTML,
slug, slug,
postsDirectory postsDirectory,
}); });
return ( return (
@@ -28,16 +34,16 @@ const Post = ({markdownHTML, slug, postsDirectory, wordCount, seriesPosts}: Prop
{JSON.stringify(seriesPosts)} {JSON.stringify(seriesPosts)}
<>{result}</> <>{result}</>
</> </>
) );
} };
export default Post export default Post;
type Params = { type Params = {
params: { params: {
slug: string slug: string;
} };
} };
const seriesPostCacheKey = {}; const seriesPostCacheKey = {};
@@ -48,23 +54,28 @@ export async function getStaticProps({params}: Params) {
content: true, content: true,
wordCount: true, wordCount: true,
series: true, series: true,
order: true order: true,
} as const) } as const);
const isStr = (val: any): val is string => typeof val === 'string'; const isStr = (val: any): val is string => typeof val === "string";
const markdown = isStr(post.content) ? post.content : ''; const markdown = isStr(post.content) ? post.content : "";
const slug = isStr(post.slug) ? post.slug : ''; const slug = isStr(post.slug) ? post.slug : "";
let seriesPosts: any[] = []; let seriesPosts: any[] = [];
if (post.series && post.order) { if (post.series && post.order) {
const allPosts = getAllPosts({ const allPosts = getAllPosts(
{
title: true, title: true,
slug: true, slug: true,
series: true, series: true,
order: true, order: true,
} as const, seriesPostCacheKey) } as const,
seriesPostCacheKey
);
seriesPosts = allPosts.filter(filterPost => filterPost.series === post.series).sort(sortPost => Number(sortPost.order) - Number(post.order)); seriesPosts = allPosts
.filter((filterPost) => filterPost.series === post.series)
.sort((sortPost) => Number(sortPost.order) - Number(post.order));
} }
const markdownHTML = await markdownToHtml(slug, markdown); const markdownHTML = await markdownToHtml(slug, markdown);
@@ -75,24 +86,24 @@ export async function getStaticProps({params}: Params) {
slug: slug, slug: slug,
postsDirectory, postsDirectory,
wordCount: post.wordCount, wordCount: post.wordCount,
seriesPosts seriesPosts,
} },
} };
} }
export async function getStaticPaths() { export async function getStaticPaths() {
const posts = getAllPosts({'slug': true}) const posts = getAllPosts({ slug: true });
const paths = posts.map((post) => { const paths = posts.map((post) => {
return { return {
params: { params: {
slug: post.slug, slug: post.slug,
}, },
} };
}); });
return { return {
paths, paths,
fallback: false, fallback: false,
} };
} }