mirror of
https://github.com/LukeHagar/unicorn-utterances.git
synced 2025-12-06 04:21:55 +00:00
chore: add prettier to linting
This commit is contained in:
@@ -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
1
.gitignore
vendored
@@ -34,3 +34,4 @@ yarn-error.log*
|
||||
.vercel
|
||||
|
||||
/public/posts
|
||||
.idea/
|
||||
|
||||
5
.idea/.gitignore
generated
vendored
5
.idea/.gitignore
generated
vendored
@@ -1,5 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -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>
|
||||
12
.idea/unicorn-utterances.iml
generated
12
.idea/unicorn-utterances.iml
generated
@@ -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
6
.idea/vcs.xml
generated
@@ -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
1
.prettierrc.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
24
package-lock.json
generated
24
package-lock.json
generated
@@ -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": {
|
||||
"version": "7.27.1",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
|
||||
@@ -5433,6 +5448,15 @@
|
||||
"integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==",
|
||||
"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": {
|
||||
"version": "26.6.2",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-next": "12.0.4",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"prettier": "^2.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,19 @@ interface SEOProps {
|
||||
}
|
||||
|
||||
type MetaSEOProps = SEOProps & {
|
||||
metaDescription: string
|
||||
metaKeywords: string
|
||||
metaImage: string
|
||||
}
|
||||
metaDescription: string;
|
||||
metaKeywords: string;
|
||||
metaImage: string;
|
||||
};
|
||||
|
||||
const GoogleAnalytics = () => {
|
||||
return <>
|
||||
return (
|
||||
<>
|
||||
<link rel="preconnect" href="https://www.google.com" />
|
||||
<link rel="preconnect" href="https://marketingplatform.google.com" />
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const FacebookSEO = (props: MetaSEOProps) => {
|
||||
const {
|
||||
@@ -39,109 +41,137 @@ const FacebookSEO = (props: MetaSEOProps) => {
|
||||
unicornsData,
|
||||
publishedTime,
|
||||
editedTime,
|
||||
keywords
|
||||
keywords,
|
||||
} = props;
|
||||
return <>
|
||||
<meta property="og:url" content={siteMetadata.siteUrl + (pathName || "")}/>
|
||||
return (
|
||||
<>
|
||||
<meta
|
||||
property="og:url"
|
||||
content={siteMetadata.siteUrl + (pathName || "")}
|
||||
/>
|
||||
<meta property="og:site_name" content={siteMetadata.title} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:description"
|
||||
content={metaDescription}/>
|
||||
<meta property="og:description" content={metaDescription} />
|
||||
<meta property="og:image" content={metaImage} />
|
||||
{
|
||||
type === 'article' ?
|
||||
<meta property="og:type" content="article"/> :
|
||||
type === 'profile' ?
|
||||
<meta property="og:type" content="profile"/> :
|
||||
{type === "article" ? (
|
||||
<meta property="og:type" content="article" />
|
||||
) : type === "profile" ? (
|
||||
<meta property="og:type" content="profile" />
|
||||
) : (
|
||||
<meta property="og:type" content="blog" />
|
||||
}
|
||||
{
|
||||
type === 'profile' ?
|
||||
[
|
||||
<meta key="firstName" property="profile:firstName" content={unicornsData![0].firstName}/>,
|
||||
<meta key="lastName" property="profile:lastName" content={unicornsData![0].lastName}/>,
|
||||
<meta key="username" property="profile:username" content={unicornsData![0].id}/>
|
||||
)}
|
||||
{type === "profile"
|
||||
? [
|
||||
<meta
|
||||
key="firstName"
|
||||
property="profile:firstName"
|
||||
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
|
||||
}
|
||||
{
|
||||
type !== 'article' ? null : [
|
||||
<meta key="section" property="article:section" content="Technology"/>,
|
||||
<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}/>)
|
||||
]
|
||||
}
|
||||
: null}
|
||||
{type !== "article"
|
||||
? null
|
||||
: [
|
||||
<meta
|
||||
key="section"
|
||||
property="article:section"
|
||||
content="Technology"
|
||||
/>,
|
||||
<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 socialUnicorn = props.unicornsData!.find((uni) => uni.socials);
|
||||
const uniTwitter =
|
||||
socialUnicorn && socialUnicorn.socials && socialUnicorn.socials.twitter;
|
||||
if (uniTwitter) {
|
||||
return <meta property="twitter:creator" content={`@${uniTwitter}`}/>
|
||||
}
|
||||
return null
|
||||
return <meta property="twitter:creator" content={`@${uniTwitter}`} />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const TwitterSEO = (props: MetaSEOProps) => {
|
||||
const { metaDescription, title, metaImage, type, unicornsData } = props;
|
||||
return <>
|
||||
return (
|
||||
<>
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description"
|
||||
content={metaDescription}/>
|
||||
<meta name="twitter:description" content={metaDescription} />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content={siteMetadata.twitterHandle} />
|
||||
<meta name="twitter:image" content={metaImage} />
|
||||
{
|
||||
type === 'article' ?
|
||||
[
|
||||
unicornsData!.length === 1 ?
|
||||
<TwitterSingleAuthor key="singleAuthor" {...props}/> :
|
||||
null
|
||||
{type === "article"
|
||||
? [
|
||||
unicornsData!.length === 1 ? (
|
||||
<TwitterSingleAuthor key="singleAuthor" {...props} />
|
||||
) : null,
|
||||
]
|
||||
: null
|
||||
}
|
||||
: null}
|
||||
</>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const SEO: React.FC<SEOProps> = (
|
||||
props
|
||||
) => {
|
||||
const {
|
||||
description = "",
|
||||
children,
|
||||
title,
|
||||
keywords,
|
||||
canonical,
|
||||
} = props;
|
||||
export const SEO: React.FC<SEOProps> = (props) => {
|
||||
const { description = "", children, title, keywords, canonical } = props;
|
||||
|
||||
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 metaProps = {
|
||||
metaDescription,
|
||||
metaKeywords,
|
||||
metaImage
|
||||
}
|
||||
metaImage,
|
||||
};
|
||||
|
||||
return <Head>
|
||||
<title>{title ? `${title} | ${siteMetadata.title}` : siteMetadata.title}</title>
|
||||
return (
|
||||
<Head>
|
||||
<title>
|
||||
{title ? `${title} | ${siteMetadata.title}` : siteMetadata.title}
|
||||
</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
{canonical ? <link rel="canonical" href={canonical} /> : null}
|
||||
<meta property="name" content={siteMetadata.title} />
|
||||
<meta name="description"
|
||||
content={metaDescription}/>
|
||||
<meta property="keywords"
|
||||
content={metaKeywords}/>
|
||||
<meta name="description" content={metaDescription} />
|
||||
<meta property="keywords" content={metaKeywords} />
|
||||
<GoogleAnalytics />
|
||||
<FacebookSEO {...props} {...metaProps} />
|
||||
<TwitterSEO {...props} {...metaProps} />
|
||||
{children}
|
||||
</Head>
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AppProps } from 'next/app'
|
||||
import '../styles/index.css'
|
||||
import { AppProps } from "next/app";
|
||||
import "../styles/index.css";
|
||||
|
||||
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||
return <Component {...pageProps} />
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
render() {
|
||||
@@ -23,6 +23,6 @@ export default class MyDocument extends Document {
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import {getAllPosts} from '../api/api'
|
||||
import Post from '../types/post'
|
||||
import React from 'react'
|
||||
import Link from 'next/link';
|
||||
import { getAllPosts } from "../api/api";
|
||||
import Post from "../types/post";
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
type Props = {
|
||||
allPosts: Post[]
|
||||
}
|
||||
allPosts: Post[];
|
||||
};
|
||||
|
||||
const Index = ({ allPosts }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<ul>
|
||||
{allPosts.map(
|
||||
post =>
|
||||
{allPosts.map((post) => (
|
||||
<li key={post.slug}>
|
||||
<h2>
|
||||
<Link href={`/posts/[slug]`} as={`/posts/${post.slug}`}>
|
||||
@@ -21,13 +20,13 @@ const Index = ({allPosts}: Props) => {
|
||||
</h2>
|
||||
<p>{post.published}</p>
|
||||
</li>
|
||||
)}
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default Index
|
||||
export default Index;
|
||||
|
||||
export const getStaticProps = async () => {
|
||||
let allPosts = getAllPosts({
|
||||
@@ -35,17 +34,17 @@ export const getStaticProps = async () => {
|
||||
published: true,
|
||||
slug: true,
|
||||
author: true,
|
||||
excerpt: true
|
||||
} as const)
|
||||
excerpt: true,
|
||||
} as const);
|
||||
|
||||
// sort posts by date in descending order
|
||||
allPosts = allPosts.sort((post1, post2) => {
|
||||
const date1 = new Date(post1.published);
|
||||
const date2 = new Date(post2.published);
|
||||
return (date1 > date2 ? -1 : 1);
|
||||
})
|
||||
return date1 > date2 ? -1 : 1;
|
||||
});
|
||||
|
||||
return {
|
||||
props: { allPosts },
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
// import { useRouter } from 'next/router'
|
||||
// import ErrorPage from 'next/error'
|
||||
import {getPostBySlug, getAllPosts, postsDirectory} from '../../api/api'
|
||||
import * as React from 'react';
|
||||
import { getPostBySlug, getAllPosts, postsDirectory } from "../../api/api";
|
||||
import * as React from "react";
|
||||
|
||||
import markdownToHtml from "../../utils/markdownToHtml";
|
||||
import { useMarkdownRenderer } from "../../hooks/useMarkdownRenderer";
|
||||
import 'react-medium-image-zoom/dist/styles.css'
|
||||
import "react-medium-image-zoom/dist/styles.css";
|
||||
|
||||
type Props = {
|
||||
markdownHTML: string
|
||||
slug: string
|
||||
postsDirectory: string
|
||||
wordCount: number
|
||||
seriesPosts: any[]
|
||||
}
|
||||
markdownHTML: string;
|
||||
slug: string;
|
||||
postsDirectory: string;
|
||||
wordCount: number;
|
||||
seriesPosts: any[];
|
||||
};
|
||||
|
||||
const Post = ({markdownHTML, slug, postsDirectory, wordCount, seriesPosts}: Props) => {
|
||||
const Post = ({
|
||||
markdownHTML,
|
||||
slug,
|
||||
postsDirectory,
|
||||
wordCount,
|
||||
seriesPosts,
|
||||
}: Props) => {
|
||||
const result = useMarkdownRenderer({
|
||||
markdownHTML,
|
||||
slug,
|
||||
postsDirectory
|
||||
postsDirectory,
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -28,16 +34,16 @@ const Post = ({markdownHTML, slug, postsDirectory, wordCount, seriesPosts}: Prop
|
||||
{JSON.stringify(seriesPosts)}
|
||||
<>{result}</>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default Post
|
||||
export default Post;
|
||||
|
||||
type Params = {
|
||||
params: {
|
||||
slug: string
|
||||
}
|
||||
}
|
||||
slug: string;
|
||||
};
|
||||
};
|
||||
|
||||
const seriesPostCacheKey = {};
|
||||
|
||||
@@ -48,23 +54,28 @@ export async function getStaticProps({params}: Params) {
|
||||
content: true,
|
||||
wordCount: true,
|
||||
series: true,
|
||||
order: true
|
||||
} as const)
|
||||
order: true,
|
||||
} as const);
|
||||
|
||||
const isStr = (val: any): val is string => typeof val === 'string';
|
||||
const markdown = isStr(post.content) ? post.content : '';
|
||||
const slug = isStr(post.slug) ? post.slug : '';
|
||||
const isStr = (val: any): val is string => typeof val === "string";
|
||||
const markdown = isStr(post.content) ? post.content : "";
|
||||
const slug = isStr(post.slug) ? post.slug : "";
|
||||
|
||||
let seriesPosts: any[] = [];
|
||||
if (post.series && post.order) {
|
||||
const allPosts = getAllPosts({
|
||||
const allPosts = getAllPosts(
|
||||
{
|
||||
title: true,
|
||||
slug: true,
|
||||
series: 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);
|
||||
@@ -75,24 +86,24 @@ export async function getStaticProps({params}: Params) {
|
||||
slug: slug,
|
||||
postsDirectory,
|
||||
wordCount: post.wordCount,
|
||||
seriesPosts
|
||||
}
|
||||
}
|
||||
seriesPosts,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = getAllPosts({'slug': true})
|
||||
const posts = getAllPosts({ slug: true });
|
||||
|
||||
const paths = posts.map((post) => {
|
||||
return {
|
||||
params: {
|
||||
slug: post.slug,
|
||||
},
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
paths,
|
||||
fallback: false,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user