diff --git a/app/app.vue b/app/app.vue
index eebac735..562f772f 100644
--- a/app/app.vue
+++ b/app/app.vue
@@ -20,6 +20,7 @@
diff --git a/app/components/layout/TheSiteFooter.server.vue b/app/components/layout/TheSiteFooter.server.vue
index 5cd01437..639a8586 100644
--- a/app/components/layout/TheSiteFooter.server.vue
+++ b/app/components/layout/TheSiteFooter.server.vue
@@ -1,46 +1,5 @@
diff --git a/app/pages/blog/[article].vue b/app/pages/blog/[article].vue
index 7b7bb3f6..c58fea54 100644
--- a/app/pages/blog/[article].vue
+++ b/app/pages/blog/[article].vue
@@ -101,6 +101,38 @@ defineOgImageComponent('DefaultImage', {
if (import.meta.server) {
useRoute().meta.description = page.value.description
+
+ const articleSchema = {
+ '@context': 'https://schema.org',
+ '@type': 'Article',
+ 'headline': page.value.title,
+ 'description': page.value.description,
+ 'datePublished': page.value.date,
+ 'author': {
+ '@type': 'Person',
+ 'name': 'Daniel Roe',
+ 'url': 'https://roe.dev',
+ },
+ 'publisher': {
+ '@type': 'Person',
+ 'name': 'Daniel Roe',
+ 'url': 'https://roe.dev',
+ },
+ 'mainEntityOfPage': {
+ '@type': 'WebPage',
+ '@id': `https://roe.dev${path.value}`,
+ },
+ 'keywords': page.value.tags?.join(', '),
+ }
+
+ useHead({
+ script: [
+ {
+ type: 'application/ld+json',
+ innerHTML: JSON.stringify(articleSchema),
+ },
+ ],
+ })
}
const blueskyUri = shallowRef(page.value.bluesky)
diff --git a/app/utils/data.ts b/app/utils/data.ts
new file mode 100644
index 00000000..dd3c16a8
--- /dev/null
+++ b/app/utils/data.ts
@@ -0,0 +1,42 @@
+export const links = [
+ {
+ name: 'GitHub',
+ icon: 'i-ri:github-fill',
+ link: 'https://github.com/danielroe/',
+ },
+ {
+ name: 'Bluesky',
+ icon: 'i-tabler-brand-bluesky',
+ link: 'https://bsky.app/profile/danielroe.dev',
+ },
+ {
+ name: 'LinkedIn',
+ icon: 'i-ri:linkedin-fill',
+ link: 'https://www.linkedin.com/in/daniel-roe/',
+ },
+ {
+ name: 'Mastodon',
+ icon: 'i-ri:mastodon-fill',
+ link: 'https://mastodon.roe.dev/@daniel',
+ },
+ {
+ name: 'Instagram',
+ icon: 'i-ri:instagram-fill',
+ link: 'https://www.instagram.com/daniel.c.roe',
+ },
+ {
+ name: 'Twitch',
+ icon: 'i-ri-twitch-fill',
+ link: 'https://twitch.tv/danielroe',
+ },
+ {
+ name: 'YouTube',
+ icon: 'i-ri-youtube-fill',
+ link: 'https://www.youtube.com/@danielroe',
+ },
+ {
+ name: 'RSS',
+ icon: 'i-ri:rss-fill',
+ link: '/rss.xml',
+ },
+]
diff --git a/budget.json b/budget.json
index e2093b1c..e54b7b32 100644
--- a/budget.json
+++ b/budget.json
@@ -4,7 +4,7 @@
"resourceSizes": [
{
"resourceType": "document",
- "budget": 11.8
+ "budget": 12
},
{
"resourceType": "script",
diff --git a/public/site.webmanifest b/public/site.webmanifest
index fa99de77..ce41c3c0 100644
--- a/public/site.webmanifest
+++ b/public/site.webmanifest
@@ -1,6 +1,6 @@
{
- "name": "",
- "short_name": "",
+ "name": "Daniel Roe",
+ "short_name": "Daniel Roe",
"icons": [
{
"src": "/android-chrome-192x192.png",
diff --git a/test/unit/bundle.spec.ts b/test/unit/bundle.spec.ts
index e74836b1..e1f3045d 100644
--- a/test/unit/bundle.spec.ts
+++ b/test/unit/bundle.spec.ts
@@ -78,7 +78,7 @@ describe('project sizes', () => {
stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
expect
.soft(roundToKilobytes(stats.server.totalBytes))
- .toMatchInlineSnapshot(`"939k"`)
+ .toMatchInlineSnapshot(`"942k"`)
const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect