@@ -25,7 +25,6 @@ export default function RootLayout({
)
}
-export const runtime = 'edge'
export const metadata = {
metadataBase: new URL('https://maxleiter.com'),
title: {
diff --git a/app/lib/get-posts.ts b/app/lib/get-posts.ts
index 4ef82329..48ef9cc9 100644
--- a/app/lib/get-posts.ts
+++ b/app/lib/get-posts.ts
@@ -1,31 +1,73 @@
import matter from 'gray-matter'
-import path from 'path'
+import { Octokit } from '@octokit/rest'
import type { Post } from './types'
-import fs from 'fs/promises'
import { cache } from 'react'
// import supabase from '@lib/supabase/private'
-export const getPosts = cache(async () => {
- const posts = await fs.readdir('./posts/')
+const octokit = new Octokit({
+ auth: process.env.GITHUB_TOKEN,
+ request: {
+ fetch,
+ },
+})
+
+type GithubFile = {
+ type: 'file' | 'dir' | 'submodule' | 'symlink'
+ size: number
+ name: string
+ path: string
+ content?: string | undefined
+ sha: string
+ url: string
+ git_url: string | null
+ html_url: string | null
+ download_url: string | null
+ _links: any
+}
+
+const getPosts = cache(async () => {
+ const repoOwner = 'maxleiter'
+ const repoName = 'maxleiter.com'
+ const postsDir = 'posts'
+
+ const { data: files } = (await octokit.repos.getContent({
+ owner: repoOwner,
+ repo: repoName,
+ path: postsDir,
+ })) as { data: GithubFile[] }
const postsWithMetadata = await Promise.all(
- posts
+ files
.filter(
- (file) => path.extname(file) === '.md' || path.extname(file) === '.mdx'
+ (file) =>
+ file.type === 'file' &&
+ (file.path.endsWith('.md') || file.path.endsWith('.mdx'))
)
.map(async (file) => {
- const filePath = `./posts/${file}`
- const postContent = await fs.readFile(filePath, 'utf8')
+ const { data: fileContent } = (await octokit.repos.getContent({
+ owner: repoOwner,
+ repo: repoName,
+ path: file.path,
+ })) as { data: GithubFile }
+
+ if (!fileContent.content) {
+ return null
+ }
+
+ const postContent = Buffer.from(fileContent.content, 'base64').toString(
+ 'utf8'
+ )
const { data, content } = matter(postContent)
if (data.published === false) {
return null
}
- const withoutLeadingChars = filePath.substring(2).replace('.mdx', '.md')
+
+ const withoutLeadingChars = file.path.replace('.mdx', '.md')
const fetchUrl =
process.env.NODE_ENV === 'production'
- ? `https://api.github.com/repos/maxleiter/maxleiter.com/commits?path=${withoutLeadingChars}&page=1&per_page=1`
+ ? `https://api.github.com/repos/${repoOwner}/${repoName}/commits?path=${withoutLeadingChars}&page=1&per_page=1`
: `http://localhost:3000/mock-commit-response.json`
const commitInfoResponse = await fetch(fetchUrl, {
@@ -68,7 +110,7 @@ export const getPosts = cache(async () => {
return filtered
})
-export async function getPost(slug: string) {
+export const getPost = async (slug: string) => {
const posts = await getPosts()
return posts.find((post) => post.slug === slug)
}
diff --git a/app/opengraph-image.tsx b/app/opengraph-image.tsx
index a23cb733..654ee4d1 100644
--- a/app/opengraph-image.tsx
+++ b/app/opengraph-image.tsx
@@ -5,9 +5,7 @@ export const size = { width: 1200, height: 600 }
export const alt = ''
export const contentType = 'image/png'
-export const config = {
- runtime: 'edge',
-}
+export const runtime = 'edge'
// eslint-disable-next-line import/no-anonymous-default-export
export default async function (): Promise {
diff --git a/app/page.tsx b/app/page.tsx
index 34141950..cb036115 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -11,6 +11,8 @@ import Posts from '@components/posts-list'
const PROJECT_COUNT = 3
+export const revalidate = 10800
+
export default async function HomePage() {
const projects = await getProjects()
@@ -59,5 +61,3 @@ export default async function HomePage() {
>
)
}
-
-export const dynamic = 'force-static'
diff --git a/app/styles/global.css b/app/styles/global.css
index 44c7bbab..b81e2b98 100644
--- a/app/styles/global.css
+++ b/app/styles/global.css
@@ -89,6 +89,7 @@ body {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 110%;
font-size: 16px;
line-height: 1.55em;
}
diff --git a/package.json b/package.json
index b6ec5b79..2bccda0b 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"@next/bundle-analyzer": "13.3.4",
"@next/eslint-plugin-next": "13.3.4",
"@next/mdx": "13.3.5-canary.8",
+ "@octokit/rest": "^19.0.7",
"@supabase/supabase-js": "2.21.0",
"@vercel/analytics": "^1.0.1",
"@vercel/og": "^0.5.4",
diff --git a/pages/api/og.tsx b/pages/api/og.tsx
index 795ab311..dd4f123d 100644
--- a/pages/api/og.tsx
+++ b/pages/api/og.tsx
@@ -1,8 +1,7 @@
import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'
-export const config = {
- runtime: 'edge',
-}
+export const runtime = 'edge'
+
const font = fetch(new URL('./fonts/Inter-Medium.ttf', import.meta.url)).then(
(res) => res.arrayBuffer()
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 31246427..25b7471a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -7,6 +7,7 @@ specifiers:
'@next/bundle-analyzer': 13.3.4
'@next/eslint-plugin-next': 13.3.4
'@next/mdx': 13.3.5-canary.8
+ '@octokit/rest': ^19.0.7
'@supabase/supabase-js': 2.21.0
'@types/marked': 4.3.0
'@types/mdx': ^2.0.5
@@ -72,6 +73,7 @@ dependencies:
'@next/bundle-analyzer': 13.3.4
'@next/eslint-plugin-next': 13.3.4
'@next/mdx': 13.3.5-canary.8_msthxdjvrhmdkfpqqalumiidgq
+ '@octokit/rest': 19.0.7
'@supabase/supabase-js': 2.21.0
'@vercel/analytics': 1.0.1
'@vercel/og': 0.5.4
@@ -763,6 +765,122 @@ packages:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
+ /@octokit/auth-token/3.0.3:
+ resolution: {integrity: sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/types': 9.2.1
+ dev: false
+
+ /@octokit/core/4.2.0:
+ resolution: {integrity: sha512-AgvDRUg3COpR82P7PBdGZF/NNqGmtMq2NiPqeSsDIeCfYFOZ9gddqWNQHnFdEUf+YwOj4aZYmJnlPp7OXmDIDg==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/auth-token': 3.0.3
+ '@octokit/graphql': 5.0.5
+ '@octokit/request': 6.2.3
+ '@octokit/request-error': 3.0.3
+ '@octokit/types': 9.2.1
+ before-after-hook: 2.2.3
+ universal-user-agent: 6.0.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /@octokit/endpoint/7.0.5:
+ resolution: {integrity: sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/types': 9.2.1
+ is-plain-object: 5.0.0
+ universal-user-agent: 6.0.0
+ dev: false
+
+ /@octokit/graphql/5.0.5:
+ resolution: {integrity: sha512-Qwfvh3xdqKtIznjX9lz2D458r7dJPP8l6r4GQkIdWQouZwHQK0mVT88uwiU2bdTU2OtT1uOlKpRciUWldpG0yQ==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/request': 6.2.3
+ '@octokit/types': 9.2.1
+ universal-user-agent: 6.0.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /@octokit/openapi-types/17.1.1:
+ resolution: {integrity: sha512-/X7Gh/qWiWaooJmUnYD48SYy72fyrk2ceisOSe89JojK7r0j8YrTwYpDi76kI+c6QiqX1KSgdoBTMJvktsDkYw==}
+ dev: false
+
+ /@octokit/plugin-paginate-rest/6.0.0_@octokit+core@4.2.0:
+ resolution: {integrity: sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ '@octokit/core': '>=4'
+ dependencies:
+ '@octokit/core': 4.2.0
+ '@octokit/types': 9.2.1
+ dev: false
+
+ /@octokit/plugin-request-log/1.0.4_@octokit+core@4.2.0:
+ resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==}
+ peerDependencies:
+ '@octokit/core': '>=3'
+ dependencies:
+ '@octokit/core': 4.2.0
+ dev: false
+
+ /@octokit/plugin-rest-endpoint-methods/7.0.1_@octokit+core@4.2.0:
+ resolution: {integrity: sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==}
+ engines: {node: '>= 14'}
+ peerDependencies:
+ '@octokit/core': '>=3'
+ dependencies:
+ '@octokit/core': 4.2.0
+ '@octokit/types': 9.2.1
+ deprecation: 2.3.1
+ dev: false
+
+ /@octokit/request-error/3.0.3:
+ resolution: {integrity: sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/types': 9.2.1
+ deprecation: 2.3.1
+ once: 1.4.0
+ dev: false
+
+ /@octokit/request/6.2.3:
+ resolution: {integrity: sha512-TNAodj5yNzrrZ/VxP+H5HiYaZep0H3GU0O7PaF+fhDrt8FPrnkei9Aal/txsN/1P7V3CPiThG0tIvpPDYUsyAA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/endpoint': 7.0.5
+ '@octokit/request-error': 3.0.3
+ '@octokit/types': 9.2.1
+ is-plain-object: 5.0.0
+ node-fetch: 2.6.7
+ universal-user-agent: 6.0.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /@octokit/rest/19.0.7:
+ resolution: {integrity: sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==}
+ engines: {node: '>= 14'}
+ dependencies:
+ '@octokit/core': 4.2.0
+ '@octokit/plugin-paginate-rest': 6.0.0_@octokit+core@4.2.0
+ '@octokit/plugin-request-log': 1.0.4_@octokit+core@4.2.0
+ '@octokit/plugin-rest-endpoint-methods': 7.0.1_@octokit+core@4.2.0
+ transitivePeerDependencies:
+ - encoding
+ dev: false
+
+ /@octokit/types/9.2.1:
+ resolution: {integrity: sha512-Vx4keMiD/CAiwVFasLcH0xBSVbKIHebIZke9i7ZbUWGNN4vJFWSYH6Nvga7UY9NIJCGa6x3QG849XTbi5wYmkA==}
+ dependencies:
+ '@octokit/openapi-types': 17.1.1
+ dev: false
+
/@pkgr/utils/2.3.1:
resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -1336,6 +1454,10 @@ packages:
engines: {node: '>= 0.4'}
dev: false
+ /before-after-hook/2.2.3:
+ resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==}
+ dev: false
+
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@@ -1815,6 +1937,10 @@ packages:
engines: {node: '>= 0.8'}
dev: false
+ /deprecation/2.3.1:
+ resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
+ dev: false
+
/dequal/2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
@@ -3256,6 +3382,11 @@ packages:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
+ /is-plain-object/5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
/is-reference/3.0.1:
resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==}
dependencies:
@@ -6020,6 +6151,10 @@ packages:
unist-util-is: 5.2.1
unist-util-visit-parents: 5.1.3
+ /universal-user-agent/6.0.0:
+ resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==}
+ dev: false
+
/universalify/2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
engines: {node: '>= 10.0.0'}