Add og meta tags
All checks were successful
Build And Publish / BuildAndPublish (push) Successful in 2m45s

This commit is contained in:
Ryan Freeman 2024-10-11 22:01:19 +01:00 committed by r-freeman
parent 18161a50e8
commit 412927d663
17 changed files with 147 additions and 134 deletions

View File

@ -4,15 +4,22 @@ import Image from 'next/image'
import {Container} from '@/components/common/Container'
import {MailIcon} from '@/components/icons/MailIcon'
import {GitHubIcon, LinkedInIcon} from '@/components/icons/SocialIcons'
import {metadata as _metadata} from '@/lib/generateMetadata'
import clsx from 'clsx'
import me from '@/public/images/me.jpg'
import awsCCPBadge from '@/public/images/aws-certified-cloud-practitioner-badge.png'
export const metadata = {
title: 'About - Ryan Freeman',
description: 'Im Ryan. I live in Dublin, Ireland where I work as a software engineer.'
const meta = {
title: 'About',
heading: 'I\'m Ryan. I live in Dublin, Ireland where I work as a software engineer.',
description: 'I\'ve always had an affinity for technology, and loved making things for as long as I can remember. ' +
'My first computer was an Amstrad CPC 464 way back in the 90s, which is ancient by modern standards. ' +
'My passion for tinkering continued through my teens and into adulthood where I eventually found my way into software engineering.',
type: 'website'
}
export const metadata = _metadata({...meta, heading: meta.heading})
function SocialLink({
className,
href,
@ -55,14 +62,11 @@ export default async function About() {
</div>
<div className="lg:order-first lg:row-span-2">
<h1 className="text-4xl font-bold tracking-tight text-zinc-800 sm:text-5xl bg-clip-text dark:text-transparent bg-gradient-to-r from-blue-400 to-emerald-400">
Im Ryan. I live in Dublin, Ireland where I work as a software engineer.
{meta.heading}
</h1>
<div className="mt-6 space-y-7 text-base text-zinc-600 dark:text-zinc-400">
<p>
I&apos;ve always had an affinity for technology, and loved making things for as long as I can
remember. My first computer was an Amstrad CPC 464 way back in the 90s, which is ancient by modern
standards. My passion for tinkering continued through my teens and into adulthood where I
eventually found my way into software engineering.
{meta.description}
</p>
<p>
In terms of my experience to date, I have a strong foundation in both front-end and back-end

View File

@ -29,11 +29,11 @@ export async function GET(request: Request) {
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
textAlign: 'left',
alignItems: 'center',
justifyContent: 'center',
lineHeight: '1',
padding: '0 128px'
lineHeight: '1.1',
padding: '0 64px'
}}
>
<div

View File

@ -6,7 +6,10 @@ import {Footer} from '@/components/common/Footer'
import '@/styles/tailwind.css'
export const metadata = {
title: 'Ryan Freeman - Full-stack software engineer from Dublin, Ireland.',
title: {
default: 'Ryan Freeman - Full-stack software engineer based in Dublin, Ireland.',
template: '%s - Ryan Freeman'
},
description: 'Full-stack software engineer who enjoys building cloud-native applications.',
metadataBase: new URL('https://ryanfreeman.dev'),
alternates: {

View File

@ -8,6 +8,18 @@ import {GitHubIcon, LinkedInIcon} from '@/components/icons/SocialIcons'
import {getAllArticles} from '@/lib/getAllArticles'
import {formatDate} from '@/lib/formatDate'
import type {Article} from '@/types'
import {metadata as _metadata} from '@/lib/generateMetadata'
const meta = {
title: 'Ryan Freeman - Full-stack software engineer based in Dublin, Ireland.',
heading: 'Full-stack software engineer who enjoys building cloud-native applications.',
description: 'Hi. I\'m Ryan, a software engineer based in Dublin, Ireland. I\'m currently working in the aviation industry for Aer Lingus. ' +
'I am passionate about personal growth and progressing in my career. ' +
'This is my personal website where you can learn more about me, read articles I\'ve written and see projects I\'ve worked on.',
type: 'website'
}
export const metadata = _metadata({...meta, heading: meta.heading})
function Article(article: Article) {
return (
@ -41,13 +53,10 @@ export default async function Home() {
<Container className="mt-9">
<div className="max-w-2xl">
<h1 className="text-4xl font-bold tracking-tight text-zinc-800 sm:text-5xl bg-clip-text dark:text-transparent bg-gradient-to-r from-pink-500 via-red-500 to-yellow-500">
Full-stack software engineer who enjoys building cloud-native applications.
{meta.heading}
</h1>
<p className="mt-6 text-base text-zinc-600 dark:text-zinc-400">
Hi. I&apos;m Ryan, a software engineer based in Dublin, Ireland. I&apos;m currently working in the
aviation industry for Aer Lingus. I am passionate about personal growth and progressing in my career. This
is my personal website where you can learn more about me, read articles I&apos;ve written and see projects
I&apos;ve worked on.
{meta.description}
</p>
<div className="mt-6 flex gap-6">
<SocialLink

View File

@ -4,13 +4,18 @@ import {SimpleLayout} from '@/components/layouts/SimpleLayout'
import {Card} from '@/components/ui/Card'
import {getPinnedRepos} from '@/lib/github'
import {numberFormat} from '@/lib/numberFormat'
import React from 'react';
import {metadata as _metadata} from '@/lib/generateMetadata'
import React from 'react'
export const metadata = {
title: 'Projects - Ryan Freeman',
description: 'Here\'s a selection of academic and personal projects that I have worked on. Many of them are open-source, so if you see something that piques your interest, check out the code and contribute if you have ideas for how it can be improved.'
const meta = {
title: 'Projects',
heading: 'Things I\'ve made and projects I\'ve worked on.',
description: 'Here\'s a selection of academic and personal projects that I have worked on. Many of them are open-source, so if you see something that piques your interest, check out the code and contribute if you have ideas for how it can be improved.',
type: 'website'
}
export const metadata = _metadata({...meta, heading: meta.heading})
export const revalidate = 0
export default async function Projects() {
@ -18,8 +23,8 @@ export default async function Projects() {
return (
<SimpleLayout
heading="Things I've made and projects I've worked on."
description={metadata.description}
heading={meta.heading}
description={meta.description}
gradient="bg-gradient-to-r from-sky-400 to-blue-500">
<ul
role="list"

View File

@ -1,12 +1,17 @@
import {SimpleLayout} from '@/components/layouts/SimpleLayout'
import {Card} from '@/components/ui/Card'
import React from 'react';
import React from 'react'
import {metadata as _metadata} from '@/lib/generateMetadata'
export const metadata = {
title: 'Reading - Ryan Freeman',
description: 'Take a look at my curated reading list.'
const meta = {
title: 'Reading',
heading: 'Books I\'m reading at the moment',
description: 'Take a look at my curated reading list.',
type: 'website'
}
export const metadata = _metadata({...meta, heading: meta.heading})
type Book = {
title: string
author: string
@ -69,8 +74,8 @@ export default async function Reading() {
return (
<SimpleLayout
heading="Books I'm reading at the moment"
description={metadata.description}
heading={meta.heading}
description={meta.description}
gradient="bg-gradient-to-r from-sky-400 to-blue-500">
<ul
role="list"

View File

@ -9,31 +9,17 @@ import {ShieldIcon} from '@/components/icons/ShieldIcon'
import {EmailIcon} from '@/components/icons/EmailIcon'
import {RocketIcon} from '@/components/icons/RocketIcon'
import {ShoppingBagIcon} from '@/components/icons/ShoppingBagIcon'
import {metadata as _metadata} from '@/lib/generateMetadata'
const meta = {
title: 'Services - Ryan Freeman',
title: 'Services',
heading: 'I offer a wide range of digital services to elevate and transform your business',
description: 'Whether you need a WordPress website, React app, AWS support or odd coding jobs, I\'m here to help. ' +
'As an experienced software engineer, I produce high-quality software that will deliver immediate value for you and your customers.',
type: 'website'
}
export const metadata = {
...meta,
openGraph: {
title: meta.title,
description: meta.description,
images: [
{
url: `/api/og-image?text=${meta.heading}`,
width: 1200,
height: 600,
alt: meta.heading,
type: 'image/png'
}
],
type: 'website'
}
}
export const metadata = _metadata({...meta, heading: meta.heading})
type Services = {
title: string
@ -99,8 +85,8 @@ export default function Services() {
return (
<SimpleLayout
heading={metadata.heading}
description={metadata.description}
heading={meta.heading}
description={meta.description}
gradient="bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400">
<ul
role="list"

View File

@ -2,12 +2,17 @@ import React, {ReactNode} from 'react'
import {SimpleLayout} from '@/components/layouts/SimpleLayout'
import {Card} from '@/components/ui/Card'
import {Section} from '@/components/ui/Section'
import {metadata as _metadata} from '@/lib/generateMetadata'
export const metadata = {
title: 'Uses - Ryan Freeman',
description: 'Software I use, equipment that makes my job easier, and other things I recommend.'
const meta = {
title: 'Uses',
heading: 'Software I use, equipment that makes my job easier, and other things I recommend.',
description: 'I get asked a lot about the things I use to build software and stay productive. Heres a big list of all of my favourite gear.',
type: 'website'
}
export const metadata = _metadata({...meta, heading: meta.heading})
function ToolsSection({children, title}: { children: ReactNode, title: string }) {
return (
<Section title={title}>
@ -32,8 +37,8 @@ function Tool({title, href, children}: { title: string, href: string, children:
export default function Uses() {
return (
<SimpleLayout
heading="Software I use, equipment that makes my job easier, and other things I recommend."
description="I get asked a lot about the things I use to build software and stay productive. Heres a big list of all of my favourite gear."
heading={meta.heading}
description={meta.description}
gradient="bg-gradient-to-r from-orange-400 to-rose-400">
<div className="space-y-20">
<ToolsSection title="Workstation">

View File

@ -1,18 +1,21 @@
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
import {createSlug} from '../../../lib/createSlug'
import {metadata as _metadata} from '../../../lib/generateMetadata'
export const metadata = {
export const meta = {
authors: 'Ryan Freeman',
title: 'A personal journey in software engineering',
date: '2022-12-04',
description: 'Hello there! If you\'re reading this, you\'ve likely stumbled upon my website — welcome! My name is Ryan Freeman, and I\'m a full-stack developer with a passion for creating intuitive and dynamic web applications.'
}
export const metadata = _metadata({title: meta.title, heading: meta.title, description: meta.description, type: 'article'})
export default (props) => <ArticleLayout
title={metadata.title}
date={metadata.date}
description={metadata.description}
slug={createSlug(metadata.title)}
title={meta.title}
date={meta.date}
description={meta.description}
slug={createSlug(meta.title)}
{...props} />
Hello there!

View File

@ -2,6 +2,7 @@ import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
import {createSlug} from '../../../lib/createSlug'
import Image from 'next/image'
import ogMetaTags from './open-graph-meta-tags.png'
import {metadata as _metadata} from '../../../lib/generateMetadata'
export const meta = {
authors: 'Ryan Freeman',
@ -10,29 +11,13 @@ export const meta = {
description: 'In this post I\'ll talk about how I created dynamic, eye-catching Open Graph images with Next.js for this website.'
}
export const metadata = {
...meta,
openGraph: {
title: meta.title,
description: meta.description,
images: [
{
url: `/api/og-image?text=${meta.title}`,
width: 1200,
height: 600,
alt: meta.title,
type: 'image/png'
}
],
type: 'website'
}
}
export const metadata = _metadata({title: meta.title, heading: meta.title, description: meta.description, type: 'article'})
export default (props) => <ArticleLayout
title={metadata.title}
date={metadata.date}
description={metadata.description}
slug={createSlug(metadata.title)}
title={meta.title}
date={meta.date}
description={meta.description}
slug={createSlug(meta.title)}
{...props} />
In this post I\'ll talk about how I created dynamic, eye-catching Open Graph images with Next.js for this website.
@ -138,7 +123,7 @@ By exporting the `metadata` object, I was able to specify the Open Graph meta ta
<Image src={ogMetaTags} alt=""/>
Lastly, I can verify everything is working correctly by loading the page in the browser.
Lastly, I can verify everything is working correctly by loading the Services page in the browser and examining the Open Graph meta tags.
## Conclusion

View File

@ -1,21 +1,24 @@
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
import {createSlug} from '../../../lib/createSlug'
import {metadata as _metadata} from '../../../lib/generateMetadata'
import raspberryPi from './vishnu-mohanan-rZKdS0wI8Ks-unsplash.jpg'
import casaOS from './casaos.png'
import Image from 'next/image'
export const metadata = {
export const meta = {
authors: 'Ryan Freeman',
title: 'Migrating from Vercel to Raspberry Pi 5',
date: '2024-08-23',
description: 'Recently, I decided to migrate this website from Vercel to a self-hosted environment using a Raspberry Pi 5. This transition was driven by several motivations, such as lowering costs and having greater control over the software and hardware that I run.'
}
export const metadata = _metadata({title: meta.title, heading: meta.title, description: meta.description, type: 'article'})
export default (props) => <ArticleLayout
title={metadata.title}
date={metadata.date}
description={metadata.description}
slug={createSlug(metadata.title)}
title={meta.title}
date={meta.date}
description={meta.description}
slug={createSlug(meta.title)}
{...props} />
<Image src={raspberryPi} alt=""/>

View File

@ -4,31 +4,17 @@ import {Card} from '@/components/ui/Card'
import {Views} from '@/components/ui/Views'
import {formatDate} from '@/lib/formatDate'
import {getAllArticles} from '@/lib/getAllArticles'
import {metadata as _metadata} from '@/lib/generateMetadata'
import type {Article} from '@/types'
const meta = {
title: 'Writing - Ryan Freeman',
title: 'Writing',
heading: 'Writing on software engineering, and everything in between.',
description: 'All of my long-form thoughts on software engineering, and more, displayed in chronological order.'
description: 'All of my long-form thoughts on software engineering, and more, displayed in chronological order.',
type: 'website'
}
export const metadata = {
...meta,
openGraph: {
title: meta.title,
description: meta.description,
images: [
{
url: `/api/og-image?text=${meta.heading}`,
width: 1200,
height: 600,
alt: meta.heading,
type: 'image/png'
}
],
type: 'website'
}
}
export const metadata = _metadata({...meta, heading: meta.heading})
function Article({article}: { article: Article }) {
return (
@ -57,8 +43,8 @@ export default async function Writing() {
return (
<SimpleLayout
heading={metadata.heading}
description={metadata.description}
heading={meta.heading}
description={meta.description}
gradient="bg-gradient-to-r from-pink-500 to-violet-500"
>
<div className="mx-auto grid max-w-xl grid-cols-1 gap-y-20 lg:max-w-none">

View File

@ -1,23 +1,26 @@
import Image from 'next/image'
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
import {createSlug} from '../../../lib/createSlug'
import {metadata as _metadata} from '../../../lib/generateMetadata'
import locks from './mariia-shalabaieva-zVC8A0CrTZ0-unsplash.jpg'
import namecheap from './namecheap-change-nameservers.png'
import nginx from './nginx-proxy-manager.png'
import starshipTroopers from './starship-troopers.gif'
export const metadata = {
export const meta = {
authors: 'Ryan Freeman',
title: 'Secure your websites with Let\'s Encrypt, NPM and Cloudflare',
date: '2024-09-21',
description: 'SSL/TLS is the encryption standard or protocol which encrypts the session between a website (server) and the browser (client). This protects us from potential man-in-the-middle attacks whereby an attacker could eavesdrop on the session and see all the traffic and data exchanged in the clear.'
}
export const metadata = _metadata({title: meta.title, heading: meta.title, description: meta.description, type: 'article'})
export default (props) => <ArticleLayout
title={metadata.title}
date={metadata.date}
description={metadata.description}
slug={createSlug(metadata.title)}
title={meta.title}
date={meta.date}
description={meta.description}
slug={createSlug(meta.title)}
{...props} />
<Image src={locks} alt=""/>

View File

@ -1,20 +1,23 @@
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
import {createSlug} from '../../../lib/createSlug'
import {metadata as _metadata} from '../../../lib/generateMetadata'
import steamLibrary from './024a06f7b503c5ae8f9442ac521e06b9c9bc21e8.png'
import Image from 'next/image'
export const metadata = {
export const meta = {
authors: 'Ryan Freeman',
title: 'Using Tailscale to bypass Steam Families restrictions',
date: '2024-09-14',
description: 'This past week, Steam launched Steam Families, which allows Steam account owners to share their game library with up to six members of their family.'
}
export const metadata = _metadata({title: meta.title, heading: meta.title, description: meta.description, type: 'article'})
export default (props) => <ArticleLayout
title={metadata.title}
date={metadata.date}
description={metadata.description}
slug={createSlug(metadata.title)}
title={meta.title}
date={meta.date}
description={meta.description}
slug={createSlug(meta.title)}
{...props} />
<Image src={steamLibrary} alt=""/>

27
lib/generateMetadata.ts Normal file
View File

@ -0,0 +1,27 @@
type Meta = {
title: string
heading: string
description: string
type: string
[name: string]: string | Object
}
export const metadata = (meta: Meta) => {
return {
...meta,
openGraph: {
title: meta.title,
description: meta.description,
images: [
{
url: `/api/og-image?text=${meta.heading}`,
width: 1200,
height: 600,
alt: meta.heading,
type: 'image/png'
}
],
type: meta.type
}
}
}

View File

@ -2,12 +2,12 @@ import glob from 'fast-glob'
import * as path from 'path'
async function importArticle(articleFilename: string) {
let {metadata, default: component} = await import(
let {meta, default: component} = await import(
`/app/writing/${articleFilename}`
)
return {
slug: articleFilename.replace(/(\/page)?\.mdx$/, ''),
...metadata,
...meta,
component,
}
}

View File

@ -23,17 +23,3 @@ export type Repo = {
color: string
}
}
export type Metric = {
title: string
value: number | string
group: string
href: string
}
export type MetricGroup = [
{
groupName: string,
groupItems: Metric[]
}
]