mirror of
https://github.com/r-freeman/portfolio.git
synced 2024-11-24 02:45:41 +00:00
Add og meta tags
All checks were successful
Build And Publish / BuildAndPublish (push) Successful in 2m45s
All checks were successful
Build And Publish / BuildAndPublish (push) Successful in 2m45s
This commit is contained in:
parent
18161a50e8
commit
412927d663
@ -4,15 +4,22 @@ import Image from 'next/image'
|
|||||||
import {Container} from '@/components/common/Container'
|
import {Container} from '@/components/common/Container'
|
||||||
import {MailIcon} from '@/components/icons/MailIcon'
|
import {MailIcon} from '@/components/icons/MailIcon'
|
||||||
import {GitHubIcon, LinkedInIcon} from '@/components/icons/SocialIcons'
|
import {GitHubIcon, LinkedInIcon} from '@/components/icons/SocialIcons'
|
||||||
|
import {metadata as _metadata} from '@/lib/generateMetadata'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import me from '@/public/images/me.jpg'
|
import me from '@/public/images/me.jpg'
|
||||||
import awsCCPBadge from '@/public/images/aws-certified-cloud-practitioner-badge.png'
|
import awsCCPBadge from '@/public/images/aws-certified-cloud-practitioner-badge.png'
|
||||||
|
|
||||||
export const metadata = {
|
const meta = {
|
||||||
title: 'About - Ryan Freeman',
|
title: 'About',
|
||||||
description: 'I’m Ryan. I live in Dublin, Ireland where I work as a software engineer.'
|
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({
|
function SocialLink({
|
||||||
className,
|
className,
|
||||||
href,
|
href,
|
||||||
@ -55,14 +62,11 @@ export default async function About() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="lg:order-first lg:row-span-2">
|
<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">
|
<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">
|
||||||
I’m Ryan. I live in Dublin, Ireland where I work as a software engineer.
|
{meta.heading}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="mt-6 space-y-7 text-base text-zinc-600 dark:text-zinc-400">
|
<div className="mt-6 space-y-7 text-base text-zinc-600 dark:text-zinc-400">
|
||||||
<p>
|
<p>
|
||||||
I've always had an affinity for technology, and loved making things for as long as I can
|
{meta.description}
|
||||||
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.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
In terms of my experience to date, I have a strong foundation in both front-end and back-end
|
In terms of my experience to date, I have a strong foundation in both front-end and back-end
|
||||||
|
@ -29,11 +29,11 @@ export async function GET(request: Request) {
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
textAlign: 'center',
|
textAlign: 'left',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
lineHeight: '1',
|
lineHeight: '1.1',
|
||||||
padding: '0 128px'
|
padding: '0 64px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -6,7 +6,10 @@ import {Footer} from '@/components/common/Footer'
|
|||||||
import '@/styles/tailwind.css'
|
import '@/styles/tailwind.css'
|
||||||
|
|
||||||
export const metadata = {
|
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.',
|
description: 'Full-stack software engineer who enjoys building cloud-native applications.',
|
||||||
metadataBase: new URL('https://ryanfreeman.dev'),
|
metadataBase: new URL('https://ryanfreeman.dev'),
|
||||||
alternates: {
|
alternates: {
|
||||||
|
19
app/page.tsx
19
app/page.tsx
@ -8,6 +8,18 @@ import {GitHubIcon, LinkedInIcon} from '@/components/icons/SocialIcons'
|
|||||||
import {getAllArticles} from '@/lib/getAllArticles'
|
import {getAllArticles} from '@/lib/getAllArticles'
|
||||||
import {formatDate} from '@/lib/formatDate'
|
import {formatDate} from '@/lib/formatDate'
|
||||||
import type {Article} from '@/types'
|
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) {
|
function Article(article: Article) {
|
||||||
return (
|
return (
|
||||||
@ -41,13 +53,10 @@ export default async function Home() {
|
|||||||
<Container className="mt-9">
|
<Container className="mt-9">
|
||||||
<div className="max-w-2xl">
|
<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">
|
<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>
|
</h1>
|
||||||
<p className="mt-6 text-base text-zinc-600 dark:text-zinc-400">
|
<p className="mt-6 text-base text-zinc-600 dark:text-zinc-400">
|
||||||
Hi. I'm Ryan, a software engineer based in Dublin, Ireland. I'm currently working in the
|
{meta.description}
|
||||||
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.
|
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-6 flex gap-6">
|
<div className="mt-6 flex gap-6">
|
||||||
<SocialLink
|
<SocialLink
|
||||||
|
@ -4,13 +4,18 @@ import {SimpleLayout} from '@/components/layouts/SimpleLayout'
|
|||||||
import {Card} from '@/components/ui/Card'
|
import {Card} from '@/components/ui/Card'
|
||||||
import {getPinnedRepos} from '@/lib/github'
|
import {getPinnedRepos} from '@/lib/github'
|
||||||
import {numberFormat} from '@/lib/numberFormat'
|
import {numberFormat} from '@/lib/numberFormat'
|
||||||
import React from 'react';
|
import {metadata as _metadata} from '@/lib/generateMetadata'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
export const metadata = {
|
const meta = {
|
||||||
title: 'Projects - Ryan Freeman',
|
title: 'Projects',
|
||||||
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.'
|
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 const revalidate = 0
|
||||||
|
|
||||||
export default async function Projects() {
|
export default async function Projects() {
|
||||||
@ -18,8 +23,8 @@ export default async function Projects() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleLayout
|
<SimpleLayout
|
||||||
heading="Things I've made and projects I've worked on."
|
heading={meta.heading}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
gradient="bg-gradient-to-r from-sky-400 to-blue-500">
|
gradient="bg-gradient-to-r from-sky-400 to-blue-500">
|
||||||
<ul
|
<ul
|
||||||
role="list"
|
role="list"
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import {SimpleLayout} from '@/components/layouts/SimpleLayout'
|
import {SimpleLayout} from '@/components/layouts/SimpleLayout'
|
||||||
import {Card} from '@/components/ui/Card'
|
import {Card} from '@/components/ui/Card'
|
||||||
import React from 'react';
|
import React from 'react'
|
||||||
|
import {metadata as _metadata} from '@/lib/generateMetadata'
|
||||||
|
|
||||||
export const metadata = {
|
const meta = {
|
||||||
title: 'Reading - Ryan Freeman',
|
title: 'Reading',
|
||||||
description: 'Take a look at my curated reading list.'
|
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 = {
|
type Book = {
|
||||||
title: string
|
title: string
|
||||||
author: string
|
author: string
|
||||||
@ -69,8 +74,8 @@ export default async function Reading() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleLayout
|
<SimpleLayout
|
||||||
heading="Books I'm reading at the moment"
|
heading={meta.heading}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
gradient="bg-gradient-to-r from-sky-400 to-blue-500">
|
gradient="bg-gradient-to-r from-sky-400 to-blue-500">
|
||||||
<ul
|
<ul
|
||||||
role="list"
|
role="list"
|
||||||
|
@ -9,31 +9,17 @@ import {ShieldIcon} from '@/components/icons/ShieldIcon'
|
|||||||
import {EmailIcon} from '@/components/icons/EmailIcon'
|
import {EmailIcon} from '@/components/icons/EmailIcon'
|
||||||
import {RocketIcon} from '@/components/icons/RocketIcon'
|
import {RocketIcon} from '@/components/icons/RocketIcon'
|
||||||
import {ShoppingBagIcon} from '@/components/icons/ShoppingBagIcon'
|
import {ShoppingBagIcon} from '@/components/icons/ShoppingBagIcon'
|
||||||
|
import {metadata as _metadata} from '@/lib/generateMetadata'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Services - Ryan Freeman',
|
title: 'Services',
|
||||||
heading: 'I offer a wide range of digital services to elevate and transform your business',
|
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. ' +
|
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.',
|
'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 = {
|
export const metadata = _metadata({...meta, heading: meta.heading})
|
||||||
...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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Services = {
|
type Services = {
|
||||||
title: string
|
title: string
|
||||||
@ -99,8 +85,8 @@ export default function Services() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleLayout
|
<SimpleLayout
|
||||||
heading={metadata.heading}
|
heading={meta.heading}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
gradient="bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400">
|
gradient="bg-gradient-to-r from-pink-300 via-purple-300 to-indigo-400">
|
||||||
<ul
|
<ul
|
||||||
role="list"
|
role="list"
|
||||||
|
@ -2,12 +2,17 @@ import React, {ReactNode} from 'react'
|
|||||||
import {SimpleLayout} from '@/components/layouts/SimpleLayout'
|
import {SimpleLayout} from '@/components/layouts/SimpleLayout'
|
||||||
import {Card} from '@/components/ui/Card'
|
import {Card} from '@/components/ui/Card'
|
||||||
import {Section} from '@/components/ui/Section'
|
import {Section} from '@/components/ui/Section'
|
||||||
|
import {metadata as _metadata} from '@/lib/generateMetadata'
|
||||||
|
|
||||||
export const metadata = {
|
const meta = {
|
||||||
title: 'Uses - Ryan Freeman',
|
title: 'Uses',
|
||||||
description: 'Software I use, equipment that makes my job easier, and other things I recommend.'
|
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. Here’s 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 }) {
|
function ToolsSection({children, title}: { children: ReactNode, title: string }) {
|
||||||
return (
|
return (
|
||||||
<Section title={title}>
|
<Section title={title}>
|
||||||
@ -32,8 +37,8 @@ function Tool({title, href, children}: { title: string, href: string, children:
|
|||||||
export default function Uses() {
|
export default function Uses() {
|
||||||
return (
|
return (
|
||||||
<SimpleLayout
|
<SimpleLayout
|
||||||
heading="Software I use, equipment that makes my job easier, and other things I recommend."
|
heading={meta.heading}
|
||||||
description="I get asked a lot about the things I use to build software and stay productive. Here’s a big list of all of my favourite gear."
|
description={meta.description}
|
||||||
gradient="bg-gradient-to-r from-orange-400 to-rose-400">
|
gradient="bg-gradient-to-r from-orange-400 to-rose-400">
|
||||||
<div className="space-y-20">
|
<div className="space-y-20">
|
||||||
<ToolsSection title="Workstation">
|
<ToolsSection title="Workstation">
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
||||||
import {createSlug} from '../../../lib/createSlug'
|
import {createSlug} from '../../../lib/createSlug'
|
||||||
|
import {metadata as _metadata} from '../../../lib/generateMetadata'
|
||||||
|
|
||||||
export const metadata = {
|
export const meta = {
|
||||||
authors: 'Ryan Freeman',
|
authors: 'Ryan Freeman',
|
||||||
title: 'A personal journey in software engineering',
|
title: 'A personal journey in software engineering',
|
||||||
date: '2022-12-04',
|
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.'
|
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
|
export default (props) => <ArticleLayout
|
||||||
title={metadata.title}
|
title={meta.title}
|
||||||
date={metadata.date}
|
date={meta.date}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
slug={createSlug(metadata.title)}
|
slug={createSlug(meta.title)}
|
||||||
{...props} />
|
{...props} />
|
||||||
|
|
||||||
Hello there!
|
Hello there!
|
||||||
|
@ -2,6 +2,7 @@ import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
|||||||
import {createSlug} from '../../../lib/createSlug'
|
import {createSlug} from '../../../lib/createSlug'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import ogMetaTags from './open-graph-meta-tags.png'
|
import ogMetaTags from './open-graph-meta-tags.png'
|
||||||
|
import {metadata as _metadata} from '../../../lib/generateMetadata'
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
authors: 'Ryan Freeman',
|
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.'
|
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 = {
|
export const metadata = _metadata({title: meta.title, heading: meta.title, description: meta.description, type: 'article'})
|
||||||
...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 default (props) => <ArticleLayout
|
export default (props) => <ArticleLayout
|
||||||
title={metadata.title}
|
title={meta.title}
|
||||||
date={metadata.date}
|
date={meta.date}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
slug={createSlug(metadata.title)}
|
slug={createSlug(meta.title)}
|
||||||
{...props} />
|
{...props} />
|
||||||
|
|
||||||
In this post I\'ll talk about how I created dynamic, eye-catching Open Graph images with Next.js for this website.
|
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=""/>
|
<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
|
## Conclusion
|
||||||
|
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
||||||
import {createSlug} from '../../../lib/createSlug'
|
import {createSlug} from '../../../lib/createSlug'
|
||||||
|
import {metadata as _metadata} from '../../../lib/generateMetadata'
|
||||||
import raspberryPi from './vishnu-mohanan-rZKdS0wI8Ks-unsplash.jpg'
|
import raspberryPi from './vishnu-mohanan-rZKdS0wI8Ks-unsplash.jpg'
|
||||||
import casaOS from './casaos.png'
|
import casaOS from './casaos.png'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
|
|
||||||
export const metadata = {
|
export const meta = {
|
||||||
authors: 'Ryan Freeman',
|
authors: 'Ryan Freeman',
|
||||||
title: 'Migrating from Vercel to Raspberry Pi 5',
|
title: 'Migrating from Vercel to Raspberry Pi 5',
|
||||||
date: '2024-08-23',
|
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.'
|
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
|
export default (props) => <ArticleLayout
|
||||||
title={metadata.title}
|
title={meta.title}
|
||||||
date={metadata.date}
|
date={meta.date}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
slug={createSlug(metadata.title)}
|
slug={createSlug(meta.title)}
|
||||||
{...props} />
|
{...props} />
|
||||||
|
|
||||||
<Image src={raspberryPi} alt=""/>
|
<Image src={raspberryPi} alt=""/>
|
||||||
|
@ -4,31 +4,17 @@ import {Card} from '@/components/ui/Card'
|
|||||||
import {Views} from '@/components/ui/Views'
|
import {Views} from '@/components/ui/Views'
|
||||||
import {formatDate} from '@/lib/formatDate'
|
import {formatDate} from '@/lib/formatDate'
|
||||||
import {getAllArticles} from '@/lib/getAllArticles'
|
import {getAllArticles} from '@/lib/getAllArticles'
|
||||||
|
import {metadata as _metadata} from '@/lib/generateMetadata'
|
||||||
import type {Article} from '@/types'
|
import type {Article} from '@/types'
|
||||||
|
|
||||||
const meta = {
|
const meta = {
|
||||||
title: 'Writing - Ryan Freeman',
|
title: 'Writing',
|
||||||
heading: 'Writing on software engineering, and everything in between.',
|
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 = {
|
export const metadata = _metadata({...meta, heading: meta.heading})
|
||||||
...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'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Article({article}: { article: Article }) {
|
function Article({article}: { article: Article }) {
|
||||||
return (
|
return (
|
||||||
@ -57,8 +43,8 @@ export default async function Writing() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleLayout
|
<SimpleLayout
|
||||||
heading={metadata.heading}
|
heading={meta.heading}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
gradient="bg-gradient-to-r from-pink-500 to-violet-500"
|
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">
|
<div className="mx-auto grid max-w-xl grid-cols-1 gap-y-20 lg:max-w-none">
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
||||||
import {createSlug} from '../../../lib/createSlug'
|
import {createSlug} from '../../../lib/createSlug'
|
||||||
|
import {metadata as _metadata} from '../../../lib/generateMetadata'
|
||||||
import locks from './mariia-shalabaieva-zVC8A0CrTZ0-unsplash.jpg'
|
import locks from './mariia-shalabaieva-zVC8A0CrTZ0-unsplash.jpg'
|
||||||
import namecheap from './namecheap-change-nameservers.png'
|
import namecheap from './namecheap-change-nameservers.png'
|
||||||
import nginx from './nginx-proxy-manager.png'
|
import nginx from './nginx-proxy-manager.png'
|
||||||
import starshipTroopers from './starship-troopers.gif'
|
import starshipTroopers from './starship-troopers.gif'
|
||||||
|
|
||||||
export const metadata = {
|
export const meta = {
|
||||||
authors: 'Ryan Freeman',
|
authors: 'Ryan Freeman',
|
||||||
title: 'Secure your websites with Let\'s Encrypt, NPM and Cloudflare',
|
title: 'Secure your websites with Let\'s Encrypt, NPM and Cloudflare',
|
||||||
date: '2024-09-21',
|
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.'
|
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
|
export default (props) => <ArticleLayout
|
||||||
title={metadata.title}
|
title={meta.title}
|
||||||
date={metadata.date}
|
date={meta.date}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
slug={createSlug(metadata.title)}
|
slug={createSlug(meta.title)}
|
||||||
{...props} />
|
{...props} />
|
||||||
|
|
||||||
<Image src={locks} alt=""/>
|
<Image src={locks} alt=""/>
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
import {ArticleLayout} from '../../../components/layouts/ArticleLayout'
|
||||||
import {createSlug} from '../../../lib/createSlug'
|
import {createSlug} from '../../../lib/createSlug'
|
||||||
|
import {metadata as _metadata} from '../../../lib/generateMetadata'
|
||||||
import steamLibrary from './024a06f7b503c5ae8f9442ac521e06b9c9bc21e8.png'
|
import steamLibrary from './024a06f7b503c5ae8f9442ac521e06b9c9bc21e8.png'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
|
|
||||||
export const metadata = {
|
export const meta = {
|
||||||
authors: 'Ryan Freeman',
|
authors: 'Ryan Freeman',
|
||||||
title: 'Using Tailscale to bypass Steam Families restrictions',
|
title: 'Using Tailscale to bypass Steam Families restrictions',
|
||||||
date: '2024-09-14',
|
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.'
|
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
|
export default (props) => <ArticleLayout
|
||||||
title={metadata.title}
|
title={meta.title}
|
||||||
date={metadata.date}
|
date={meta.date}
|
||||||
description={metadata.description}
|
description={meta.description}
|
||||||
slug={createSlug(metadata.title)}
|
slug={createSlug(meta.title)}
|
||||||
{...props} />
|
{...props} />
|
||||||
|
|
||||||
<Image src={steamLibrary} alt=""/>
|
<Image src={steamLibrary} alt=""/>
|
||||||
|
27
lib/generateMetadata.ts
Normal file
27
lib/generateMetadata.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,12 @@ import glob from 'fast-glob'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
|
|
||||||
async function importArticle(articleFilename: string) {
|
async function importArticle(articleFilename: string) {
|
||||||
let {metadata, default: component} = await import(
|
let {meta, default: component} = await import(
|
||||||
`/app/writing/${articleFilename}`
|
`/app/writing/${articleFilename}`
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
slug: articleFilename.replace(/(\/page)?\.mdx$/, ''),
|
slug: articleFilename.replace(/(\/page)?\.mdx$/, ''),
|
||||||
...metadata,
|
...meta,
|
||||||
component,
|
component,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,17 +23,3 @@ export type Repo = {
|
|||||||
color: string
|
color: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Metric = {
|
|
||||||
title: string
|
|
||||||
value: number | string
|
|
||||||
group: string
|
|
||||||
href: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetricGroup = [
|
|
||||||
{
|
|
||||||
groupName: string,
|
|
||||||
groupItems: Metric[]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
Loading…
Reference in New Issue
Block a user