Skip to content

Commit baedb52

Browse files
authored
🤖 metadata (#469)
1 parent 3274ddb commit baedb52

23 files changed

+181
-313
lines changed

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20
1+
22

package-lock.json

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "bradgarropy.com",
3-
"version": "8.7.2",
3+
"version": "8.8.0",
44
"description": "🏠 my home on the web",
55
"type": "module",
66
"keywords": [
@@ -97,7 +97,7 @@
9797
"@testing-library/jest-dom": "^6.1.5",
9898
"@testing-library/react": "^16.2.0",
9999
"@testing-library/user-event": "^14.4.3",
100-
"@types/node": "^20.10.4",
100+
"@types/node": "^22.15.0",
101101
"@types/react": "^19.0.1",
102102
"@types/react-dom": "^19.0.2",
103103
"@vitejs/plugin-react": "^4.2.1",

src/components/Meta/Meta.test.tsx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import {render} from "@testing-library/react"
2+
import {expect, test} from "vitest"
3+
4+
import Meta from "~/components/Meta"
5+
import {createImageUrl} from "~/utils/cloudinary"
6+
7+
test("shows default meta", () => {
8+
render(<Meta />)
9+
10+
expect(document.title).toEqual("🏠 my home on the web")
11+
12+
const ogUrl = document.querySelector('meta[property="og:url"]')
13+
const ogType = document.querySelector('meta[property="og:type"]')
14+
const ogTitle = document.querySelector('meta[property="og:title"]')
15+
const ogImage = document.querySelector('meta[property="og:image"]')
16+
const twitterCard = document.querySelector('meta[property="twitter:card"]')
17+
const twitterSite = document.querySelector('meta[property="twitter:site"]')
18+
19+
const twitterTitle = document.querySelector(
20+
'meta[property="twitter:title"]',
21+
)
22+
23+
const twitterImage = document.querySelector(
24+
'meta[property="twitter:image"]',
25+
)
26+
27+
expect(ogUrl?.getAttribute("content")).toEqual("https://bradgarropy.com")
28+
expect(ogType?.getAttribute("content")).toEqual("website")
29+
expect(ogTitle?.getAttribute("content")).toEqual("🏠 my home on the web")
30+
31+
expect(ogImage?.getAttribute("content")).toEqual(
32+
createImageUrl("/social/facebook.png"),
33+
)
34+
35+
expect(twitterCard?.getAttribute("content")).toEqual("summary")
36+
expect(twitterSite?.getAttribute("content")).toEqual("@bradgarropy")
37+
38+
expect(twitterTitle?.getAttribute("content")).toEqual(
39+
"🏠 my home on the web",
40+
)
41+
42+
expect(twitterImage?.getAttribute("content")).toEqual(
43+
createImageUrl("/social/twitter.png"),
44+
)
45+
})
46+
47+
test("shows custom meta", () => {
48+
render(
49+
<Meta
50+
title="custom meta"
51+
facebookImage={createImageUrl("/facebookCustomMeta.png")}
52+
twitterCard="summary_large_image"
53+
twitterImage={createImageUrl("/twitterCustomMeta.png")}
54+
/>,
55+
)
56+
57+
expect(document.title).toEqual("custom meta")
58+
59+
const ogUrl = document.querySelector('meta[property="og:url"]')
60+
const ogType = document.querySelector('meta[property="og:type"]')
61+
const ogTitle = document.querySelector('meta[property="og:title"]')
62+
const ogImage = document.querySelector('meta[property="og:image"]')
63+
const twitterCard = document.querySelector('meta[property="twitter:card"]')
64+
const twitterSite = document.querySelector('meta[property="twitter:site"]')
65+
66+
const twitterTitle = document.querySelector(
67+
'meta[property="twitter:title"]',
68+
)
69+
70+
const twitterImage = document.querySelector(
71+
'meta[property="twitter:image"]',
72+
)
73+
74+
expect(ogUrl?.getAttribute("content")).toEqual("https://bradgarropy.com")
75+
expect(ogType?.getAttribute("content")).toEqual("website")
76+
expect(ogTitle?.getAttribute("content")).toEqual("custom meta")
77+
78+
expect(ogImage?.getAttribute("content")).toEqual(
79+
createImageUrl("/facebookCustomMeta.png"),
80+
)
81+
82+
expect(twitterCard?.getAttribute("content")).toEqual("summary_large_image")
83+
expect(twitterSite?.getAttribute("content")).toEqual("@bradgarropy")
84+
expect(twitterTitle?.getAttribute("content")).toEqual("custom meta")
85+
86+
expect(twitterImage?.getAttribute("content")).toEqual(
87+
createImageUrl("/twitterCustomMeta.png"),
88+
)
89+
})

src/components/Meta/Meta.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type {FC} from "react"
2+
3+
import {createImageUrl} from "~/utils/cloudinary"
4+
5+
type MetaProps = {
6+
title?: string
7+
twitterCard?: "summary" | "summary_large_image"
8+
facebookImage?: string
9+
twitterImage?: string
10+
}
11+
12+
const Meta: FC<MetaProps> = ({
13+
title = "🏠 my home on the web",
14+
twitterCard = "summary",
15+
facebookImage = createImageUrl("/social/facebook.png"),
16+
twitterImage = createImageUrl("/social/twitter.png"),
17+
}) => {
18+
return (
19+
<>
20+
<title>{title}</title>
21+
22+
<meta property="og:url" content="https://bradgarropy.com" />
23+
<meta property="og:type" content="website" />
24+
<meta property="og:title" content={title} />
25+
<meta property="og:image" content={facebookImage} />
26+
<meta property="twitter:card" content={twitterCard} />
27+
<meta property="twitter:site" content="@bradgarropy" />
28+
<meta property="twitter:title" content={title} />
29+
<meta property="twitter:image" content={twitterImage} />
30+
</>
31+
)
32+
}
33+
34+
export default Meta

src/components/Meta/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {default} from "./Meta"

src/root.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type {LinksFunction, LoaderFunctionArgs} from "@remix-run/node"
2-
import type {MetaFunction} from "@remix-run/react"
32
import {
43
Links,
54
Meta,
@@ -15,7 +14,6 @@ import {AppProvider} from "~/context/App"
1514
import {ThemeProvider} from "~/context/Theme"
1615
import styles from "~/styles/tailwind.css?url"
1716
import {createImageUrl} from "~/utils/cloudinary"
18-
import {getMeta} from "~/utils/meta"
1917
import {getTheme} from "~/utils/session.server"
2018

2119
import pkg from "../package.json"
@@ -27,11 +25,6 @@ export const loader = async ({request}: LoaderFunctionArgs) => {
2725
return {measurementId, theme}
2826
}
2927

30-
export const meta: MetaFunction = () => {
31-
const meta = getMeta()
32-
return meta
33-
}
34-
3528
export const links: LinksFunction = () => {
3629
const links = [
3730
{

src/routes/$.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import type {MetaFunction} from "@remix-run/node"
21
import {useLoaderData} from "@remix-run/react"
32

43
import FourOhFour from "~/components/FourOhFour"
54
import Layout from "~/components/Layout"
6-
import {getMeta} from "~/utils/meta"
5+
import Meta from "~/components/Meta"
76
import {getLatestPost} from "~/utils/posts"
87
import {getLatestVideos} from "~/utils/videos"
98

@@ -19,19 +18,12 @@ export const loader = async () => {
1918
}
2019
}
2120

22-
export const meta: MetaFunction = () => {
23-
const meta = getMeta({
24-
title: "🤷🏼‍♂️ not found",
25-
})
26-
27-
return meta
28-
}
29-
3021
const NotFoundRoute = () => {
3122
const {latestPost, latestVideos} = useLoaderData<typeof loader>()
3223

3324
return (
3425
<Layout>
26+
<Meta title="🤷🏼‍♂️ not found" />
3527
<FourOhFour post={latestPost} videos={latestVideos} />
3628
</Layout>
3729
)

src/routes/_index.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import type {MetaFunction} from "@remix-run/node"
21
import {useLoaderData} from "@remix-run/react"
32

43
import Home from "~/components/Home"
54
import Layout from "~/components/Layout"
6-
import {getMeta} from "~/utils/meta"
5+
import Meta from "~/components/Meta"
76
import {getPosts} from "~/utils/posts"
87
import {getFeaturedProjects} from "~/utils/projects"
98
import {getLatestVideos} from "~/utils/videos"
@@ -20,17 +19,13 @@ export const loader = async () => {
2019
}
2120
}
2221

23-
export const meta: MetaFunction = () => {
24-
const meta = getMeta({title: "🏠 my home on the web"})
25-
return meta
26-
}
27-
2822
const IndexRoute = () => {
2923
const {latestPosts, latestVideos, featuredProjects} =
3024
useLoaderData<typeof loader>()
3125

3226
return (
3327
<Layout>
28+
<Meta />
3429
<Home
3530
latestPosts={latestPosts}
3631
latestVideos={latestVideos}

src/routes/blog.$slug.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import type {LoaderFunctionArgs, MetaFunction} from "@remix-run/node"
1+
import type {LoaderFunctionArgs} from "@remix-run/node"
22
import {useLoaderData} from "@remix-run/react"
33

44
import Layout from "~/components/Layout"
5+
import Meta from "~/components/Meta"
56
import Newsletter from "~/components/Newsletter"
67
import Post from "~/components/Post"
78
import PostList from "~/components/PostList"
89
import Section from "~/components/Section"
910
import type {PostFrontmatter} from "~/types/post"
10-
import {getMeta} from "~/utils/meta"
1111
import {getPostBySlug, getRelatedPosts} from "~/utils/posts"
1212

1313
export const loader = async ({params}: LoaderFunctionArgs) => {
@@ -18,19 +18,13 @@ export const loader = async ({params}: LoaderFunctionArgs) => {
1818
return {post, relatedPosts}
1919
}
2020

21-
export const meta: MetaFunction<typeof loader> = ({data}) => {
22-
const meta = getMeta({
23-
title: data?.post.frontmatter.title,
24-
})
25-
26-
return meta
27-
}
28-
2921
const BlogRoute = () => {
3022
const {post, relatedPosts} = useLoaderData<typeof loader>()
3123

3224
return (
3325
<Layout>
26+
<Meta title={post.frontmatter.title} />
27+
3428
<div className="flex flex-col gap-y-28">
3529
<Post post={post} />
3630

src/routes/blog._index.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,18 @@
1-
import type {MetaFunction} from "@remix-run/node"
21
import {useLoaderData} from "@remix-run/react"
32
import {useState} from "react"
43

54
import Layout from "~/components/Layout"
5+
import Meta from "~/components/Meta"
66
import PostList from "~/components/PostList"
77
import PostSearchBar from "~/components/PostSearchBar"
88
import type {PostFrontmatter} from "~/types/post"
9-
import {getMeta} from "~/utils/meta"
109
import {getPosts} from "~/utils/posts"
1110

1211
export const loader = async () => {
1312
const allPosts = getPosts()
1413
return {allPosts}
1514
}
1615

17-
export const meta: MetaFunction = () => {
18-
const meta = getMeta({
19-
title: "✍🏼 blog",
20-
})
21-
22-
return meta
23-
}
24-
2516
const BlogRoute = () => {
2617
const {allPosts} = useLoaderData<typeof loader>()
2718
const [posts, setPosts] = useState(allPosts)
@@ -32,6 +23,8 @@ const BlogRoute = () => {
3223

3324
return (
3425
<Layout>
26+
<Meta title="✍🏼 blog" />
27+
3528
<div>
3629
<PostSearchBar posts={allPosts} onSearch={onSearch} />
3730
<PostList posts={posts} />

0 commit comments

Comments
 (0)