diff --git a/.env.example b/.env.example
new file mode 100644
index 00000000..f35353df
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,10 @@
+NUXT_GITHUB_TOKEN=
+NUXT_GITHUB_CLIENT_SECRET=
+NUXT_PUBLIC_GITHUB_CLIENT_ID=
+NUXT_GITHUB_INVITE_TOKEN=
+NUXT_PRIVATE_KEY=
+NUXT_PUBLIC_KEY=
+NUXT_RESEND_API_KEY=
+
+DEVTO_TOKEN=
+NUXT_SOCIAL_NETWORKS_BLUESKY_PASSWORD=
diff --git a/budget.json b/budget.json
index cf038eeb..56057214 100644
--- a/budget.json
+++ b/budget.json
@@ -12,11 +12,11 @@
},
{
"resourceType": "stylesheet",
- "budget": 7
+ "budget": 7.1
},
{
"resourceType": "other",
- "budget": 7.6
+ "budget": 7.8
}
],
"resourceCounts": [
diff --git a/nuxt.config.ts b/nuxt.config.ts
index 6b390201..56336dfe 100644
--- a/nuxt.config.ts
+++ b/nuxt.config.ts
@@ -85,8 +85,11 @@ export default defineNuxtConfig({
social: {
networks: {
+ bluesky: {
+ identifier: 'danielroe.dev',
+ },
mastodon: {
- identifier: '@daniel@roe.dev',
+ identifier: 'daniel@roe.dev',
},
},
},
@@ -171,6 +174,7 @@ export default defineNuxtConfig({
domains: [
'avatars.githubusercontent.com',
's3.nl-ams.scw.cloud',
+ 'cdn.bsky.social',
'https://avatars.githubusercontent.com',
],
screens: {
diff --git a/package.json b/package.json
index bac43b99..92a62ba8 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"*.{css,vue}": "stylelint"
},
"dependencies": {
+ "@atproto/api": "^0.4.1",
"@iconify-json/ri": "^1.1.10",
"@iconify-json/svg-spinners": "^1.1.1",
"@nuxt/content": "2.7.0",
@@ -42,7 +43,7 @@
"jose": "4.14.4",
"knitwork": "^1.0.0",
"magic-regexp": "0.7.0",
- "magic-string": "^0.30.0",
+ "magic-string": "^0.30.1",
"masto": "^5.11.4",
"mlly": "^1.4.0",
"nuxt": "3.6.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1b1b7ce6..6c5ecef3 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,6 +17,9 @@ patchedDependencies:
path: patches/h3@1.7.1.patch
dependencies:
+ '@atproto/api':
+ specifier: ^0.4.1
+ version: 0.4.1
'@iconify-json/ri':
specifier: ^1.1.10
version: 1.1.10
@@ -75,7 +78,7 @@ dependencies:
specifier: 0.7.0
version: 0.7.0
magic-string:
- specifier: ^0.30.0
+ specifier: ^0.30.1
version: 0.30.1
masto:
specifier: ^5.11.4
@@ -235,6 +238,61 @@ packages:
/@antfu/utils@0.7.5:
resolution: {integrity: sha512-dlR6LdS+0SzOAPx/TPRhnoi7hE251OVeT2Snw0RguNbBSbjUHdWr0l3vcUUDg26rEysT89kCbtw1lVorBXLLCg==}
+ /@atproto/api@0.4.1:
+ resolution: {integrity: sha512-aQ+yLFk1PF9FQKB0yCwdTwXaPIwZuvfPbvB1fZlHHv2+3o8ryeCTrMrrw7T9gZ7gyRqI27J9EYcimJbks7SHgw==}
+ dependencies:
+ '@atproto/common-web': 0.2.0
+ '@atproto/uri': 0.1.0
+ '@atproto/xrpc': 0.2.0
+ tlds: 1.240.0
+ typed-emitter: 2.1.0
+ dev: false
+
+ /@atproto/common-web@0.2.0:
+ resolution: {integrity: sha512-ugKrT8CWf6PDsZ29VOhOCs5K4z9BAFIV7SxPXA+MHC7pINqQ+wyjIq+DtUI8kmUSce1dTqc/lMN1akf/W5whVQ==}
+ dependencies:
+ graphemer: 1.4.0
+ multiformats: 9.9.0
+ uint8arrays: 3.0.0
+ zod: 3.21.4
+ dev: false
+
+ /@atproto/identifier@0.2.0:
+ resolution: {integrity: sha512-5zzlozQEWPMDzyl0D0zSpuNbnc1gtBg/Ov5wbcfieZzbjxgJ/eJHXEBlmxNE1uN91QqpGX5FCEE36jX8tKl9Ag==}
+ dependencies:
+ '@atproto/common-web': 0.2.0
+ dev: false
+
+ /@atproto/lexicon@0.2.0:
+ resolution: {integrity: sha512-0OpLZ4o4pbRj2e19h2fO69781wPmL0S8WJaXey3y9FLjV19lj18IEbnlE/OQG8qZNDyGmgezs00L/o7qNCJorw==}
+ dependencies:
+ '@atproto/common-web': 0.2.0
+ '@atproto/identifier': 0.2.0
+ '@atproto/nsid': 0.1.0
+ '@atproto/uri': 0.1.0
+ iso-datestring-validator: 2.2.2
+ multiformats: 9.9.0
+ zod: 3.21.4
+ dev: false
+
+ /@atproto/nsid@0.1.0:
+ resolution: {integrity: sha512-Pp+tHrGtPVHUi3ainR5yPgHbuqxrZrT0vAMbsNonL+NpWRB82szZSWNThPAgUz4v73Fav6y0WcTIXHzRv2D2Yg==}
+ dev: false
+
+ /@atproto/uri@0.1.0:
+ resolution: {integrity: sha512-ZaiOYHsakB98HrXfqiF6m7xgahSn9yXxKnPm0EaN0Breax6jtTl+lblWtduonAmyWVLJJAQJbvF+ud0i/3+wBw==}
+ dependencies:
+ '@atproto/identifier': 0.2.0
+ '@atproto/nsid': 0.1.0
+ dev: false
+
+ /@atproto/xrpc@0.2.0:
+ resolution: {integrity: sha512-xsyJDPG0aVfNmBvjvVkjD4YdETCkOC/xhW+4BIzKucKIH8YftcE78ANZg5rdfXjIAnsQNPP2nDf13EKcfFHpKw==}
+ dependencies:
+ '@atproto/lexicon': 0.2.0
+ zod: 3.21.4
+ dev: false
+
/@babel/code-frame@7.22.5:
resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==}
engines: {node: '>=6.9.0'}
@@ -6594,6 +6652,10 @@ packages:
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+ /iso-datestring-validator@2.2.2:
+ resolution: {integrity: sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==}
+ dev: false
+
/isomorphic-ws@5.0.0(ws@8.13.0):
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
@@ -7783,6 +7845,10 @@ packages:
/muggle-string@0.3.1:
resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==}
+ /multiformats@9.9.0:
+ resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==}
+ dev: false
+
/nanoid@3.3.6:
resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -9590,7 +9656,6 @@ packages:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
dependencies:
tslib: 2.6.0
- dev: true
/sade@1.8.1:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
@@ -10458,6 +10523,11 @@ packages:
engines: {node: '>=12'}
dev: true
+ /tlds@1.240.0:
+ resolution: {integrity: sha512-1OYJQenswGZSOdRw7Bql5Qu7uf75b+F3HFBXbqnG/ifHa0fev1XcG+3pJf3pA/KC6RtHQzfKgIf1vkMlMG7mtQ==}
+ hasBin: true
+ dev: false
+
/to-buffer@1.1.1:
resolution: {integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==}
dev: true
@@ -10640,6 +10710,12 @@ packages:
is-typed-array: 1.1.10
dev: true
+ /typed-emitter@2.1.0:
+ resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
+ optionalDependencies:
+ rxjs: 7.8.1
+ dev: false
+
/typescript@5.1.6:
resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
engines: {node: '>=14.17'}
@@ -10648,6 +10724,12 @@ packages:
/ufo@1.1.2:
resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==}
+ /uint8arrays@3.0.0:
+ resolution: {integrity: sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==}
+ dependencies:
+ multiformats: 9.9.0
+ dev: false
+
/ultrahtml@1.3.0:
resolution: {integrity: sha512-xmXvE8tC8t4PVqy0/g1fe7H9USY/Brr425q4dD/0QbQMQit7siCtb06+SCqE4GfU24nwsZz8Th1g7L7mm1lL5g==}
@@ -11792,6 +11874,10 @@ packages:
compress-commons: 4.1.1
readable-stream: 3.6.2
+ /zod@3.21.4:
+ resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
+ dev: false
+
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: false
diff --git a/src/components/FeedPost.vue b/src/components/FeedPost.vue
index d983956e..529c3edb 100644
--- a/src/components/FeedPost.vue
+++ b/src/components/FeedPost.vue
@@ -1,6 +1,10 @@
-
-
diff --git a/src/components/TheSocialFeed.server.vue b/src/components/TheSocialFeed.server.vue
new file mode 100644
index 00000000..6795b1fc
--- /dev/null
+++ b/src/components/TheSocialFeed.server.vue
@@ -0,0 +1,36 @@
+
+
') + } + + text.prepend('
') + text.append('
') + + return { + network: 'bluesky' as const, + accountLink: `https://staging.bsky.app/profile/${p.post.author.handle}`, + avatar: p.post.author.avatar, + handle: p.post.author.displayName, + createdAt: post.createdAt, + permalink: + `https://staging.bsky.app/profile/${p.post.author.handle}/post` + + p.post.uri.match(/(\/[^/]+)$/)?.[1], + html: text.toString(), + media: embed?.images?.map(i => ({ + url: i.fullsize, + alt: i.alt, + })), + } + }) + ) + }) +}) diff --git a/src/modules/runtime/server/_social/mastodon.get.ts b/src/modules/runtime/server/_social/mastodon.get.ts index 9f802d0a..09811be1 100644 --- a/src/modules/runtime/server/_social/mastodon.get.ts +++ b/src/modules/runtime/server/_social/mastodon.get.ts @@ -2,7 +2,7 @@ import { createClient } from 'masto' import { parseURL, withProtocol } from 'ufo' export default defineLazyEventHandler(async () => { - const acct = 'daniel@roe.dev' + const acct = useRuntimeConfig().social.networks.mastodon.identifier const data = await $fetch<{ subject: string; aliases: string[] }>( '.well-known/webfinger', @@ -27,8 +27,20 @@ export default defineLazyEventHandler(async () => { return Promise.all( posts .filter(p => p.content && !p.inReplyToId) - // .slice(0, 1) .map(p => ({ + network: 'mastodon' as const, + accountLink: `https://elk.zone/${host}/@${p.account.acct}`, + avatar: p.account.avatar, + handle: p.account.displayName.replace( + /:([a-z-]+):/g, + (string, shortcode) => { + const emoji = p.account.emojis.find( + e => e.shortcode === shortcode + ) + if (!emoji) return string + return `