mirror of
https://github.com/mikkelsvartveit/astro-personal-website.git
synced 2025-12-22 19:22:37 +00:00
Upgrade to Astro 5
This commit is contained in:
parent
ff787453ab
commit
c5a44e7fab
16 changed files with 2578 additions and 2018 deletions
|
|
@ -7,7 +7,7 @@ import cloudflare from "@astrojs/cloudflare";
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [tailwind(), svelte(), mdx()],
|
integrations: [tailwind(), svelte(), mdx()],
|
||||||
output: "hybrid",
|
output: "static",
|
||||||
adapter: cloudflare({
|
adapter: cloudflare({
|
||||||
imageService: "compile",
|
imageService: "compile",
|
||||||
platformProxy: {
|
platformProxy: {
|
||||||
|
|
@ -19,8 +19,5 @@ export default defineConfig({
|
||||||
external: ["node:async_hooks"],
|
external: ["node:async_hooks"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
experimental: {
|
|
||||||
actions: true,
|
|
||||||
},
|
|
||||||
site: "https://mikkelsvartveit.com",
|
site: "https://mikkelsvartveit.com",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
18
package.json
18
package.json
|
|
@ -10,20 +10,20 @@
|
||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "^10.4.2",
|
"@astrojs/cloudflare": "^12.1.0",
|
||||||
"@astrojs/mdx": "^3.1.3",
|
"@astrojs/mdx": "^4.0.3",
|
||||||
"@astrojs/svelte": "^5.7.0",
|
"@astrojs/svelte": "^7.0.2",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.4",
|
||||||
"astro": "^4.12.2",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
|
"astro": "^5.1.1",
|
||||||
"sharp": "^0.32.6",
|
"sharp": "^0.32.6",
|
||||||
"svelte": "^4.2.18",
|
"svelte": "^5.15.0",
|
||||||
"tailwindcss": "^3.4.7"
|
"tailwindcss": "^3.4.17"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.13",
|
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.0.3",
|
||||||
"prettier-plugin-astro": "^0.12.3",
|
"prettier-plugin-astro": "^0.12.3",
|
||||||
"prettier-plugin-svelte": "^3.2.6",
|
"prettier-plugin-svelte": "^3.3.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.14"
|
"prettier-plugin-tailwindcss": "^0.5.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4373
pnpm-lock.yaml
4373
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +1,9 @@
|
||||||
import { defineAction, z, getApiContext } from "astro:actions";
|
import { defineAction } from "astro:actions";
|
||||||
|
|
||||||
export const server = {
|
export const server = {
|
||||||
registerView: defineAction({
|
dummy: defineAction({
|
||||||
input: z.object({ articleSlug: z.string() }),
|
handler: async () => {
|
||||||
handler: async ({ articleSlug }) => {
|
return 0;
|
||||||
const context = getApiContext();
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const { ViewCountKV } = context.locals.runtime.env;
|
|
||||||
|
|
||||||
let viewCount = (await ViewCountKV.get(articleSlug)) || 0;
|
|
||||||
await ViewCountKV.put(articleSlug, ++viewCount);
|
|
||||||
|
|
||||||
return viewCount;
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
29
src/components/ArticleViewCounter.astro
Normal file
29
src/components/ArticleViewCounter.astro
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
|
const { articleSlug } = Astro.props;
|
||||||
|
|
||||||
|
const { ViewCountKV } = Astro.locals.runtime.env;
|
||||||
|
|
||||||
|
let counter = await ViewCountKV.get(articleSlug);
|
||||||
|
|
||||||
|
await ViewCountKV.put(articleSlug, ++counter);
|
||||||
|
---
|
||||||
|
|
||||||
|
<span class="inline-flex items-center space-x-1">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="12">
|
||||||
|
<!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
|
||||||
|
<style>
|
||||||
|
svg {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<path
|
||||||
|
d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z"
|
||||||
|
>
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<span>{counter}</span>
|
||||||
|
</span>
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { actions } from "astro:actions";
|
|
||||||
import { onMount } from "svelte";
|
|
||||||
import { expoIn } from "svelte/easing";
|
|
||||||
import { fade } from "svelte/transition";
|
|
||||||
|
|
||||||
export let articleSlug: string;
|
|
||||||
|
|
||||||
let counter: number | null = null;
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
const readCount = await actions.registerView({ articleSlug });
|
|
||||||
|
|
||||||
counter = readCount;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{#if counter !== null}
|
|
||||||
<span
|
|
||||||
class="inline-flex items-center space-x-1"
|
|
||||||
transition:fade={{ duration: 200, easing: expoIn }}
|
|
||||||
>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" height="12">
|
|
||||||
<!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
|
|
||||||
<style>
|
|
||||||
svg {
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<path
|
|
||||||
d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM144 256a144 144 0 1 1 288 0 144 144 0 1 1 -288 0zm144-64c0 35.3-28.7 64-64 64c-7.1 0-13.9-1.2-20.3-3.3c-5.5-1.8-11.9 1.6-11.7 7.4c.3 6.9 1.3 13.8 3.2 20.7c13.7 51.2 66.4 81.6 117.6 67.9s81.6-66.4 67.9-117.6c-11.1-41.5-47.8-69.4-88.6-71.1c-5.8-.2-9.2 6.1-7.4 11.7c2.1 6.4 3.3 13.2 3.3 20.3z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<span>{counter}</span>
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
28
src/content.config.ts
Normal file
28
src/content.config.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineCollection, z } from "astro:content";
|
||||||
|
import { glob } from "astro/loaders";
|
||||||
|
|
||||||
|
const blog = defineCollection({
|
||||||
|
loader: glob({ pattern: "*.md*", base: "./src/content/blog" }),
|
||||||
|
schema: ({ image }) =>
|
||||||
|
z.object({
|
||||||
|
intro: z.string(),
|
||||||
|
image: image(),
|
||||||
|
date: z.date(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const programming = defineCollection({
|
||||||
|
loader: glob({ pattern: "*.md*", base: "./src/content/programming" }),
|
||||||
|
schema: ({ image }) =>
|
||||||
|
z.object({
|
||||||
|
title: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
image: image(),
|
||||||
|
date: z.date(),
|
||||||
|
technologies: z.array(z.string()),
|
||||||
|
website: z.string().optional(),
|
||||||
|
repository: z.string().optional(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = { blog, programming };
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import { z, defineCollection } from "astro:content";
|
|
||||||
|
|
||||||
const programmingCollection = defineCollection({
|
|
||||||
type: "content",
|
|
||||||
schema: ({ image }) =>
|
|
||||||
z.object({
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
image: image(),
|
|
||||||
technologies: z.array(z.string()),
|
|
||||||
website: z.string().url(),
|
|
||||||
repository: z.string().url().optional(),
|
|
||||||
date: z.date(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const blogCollection = defineCollection({
|
|
||||||
type: "content",
|
|
||||||
schema: ({ image }) =>
|
|
||||||
z.object({
|
|
||||||
image: image(),
|
|
||||||
intro: z.string(),
|
|
||||||
date: z.date(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const collections = {
|
|
||||||
programming: programmingCollection,
|
|
||||||
blog: blogCollection,
|
|
||||||
};
|
|
||||||
12
src/env.d.ts
vendored
12
src/env.d.ts
vendored
|
|
@ -1,3 +1,13 @@
|
||||||
/// <reference path="../.astro/actions.d.ts" />
|
|
||||||
/// <reference path="../.astro/types.d.ts" />
|
/// <reference path="../.astro/types.d.ts" />
|
||||||
/// <reference types="astro/client" />
|
/// <reference types="astro/client" />
|
||||||
|
|
||||||
|
type KVNamespace = import("@cloudflare/workers-types").KVNamespace;
|
||||||
|
type ENV = {
|
||||||
|
ViewCountKV: KVNamespace;
|
||||||
|
};
|
||||||
|
|
||||||
|
// use a default runtime configuration (advanced mode).
|
||||||
|
type Runtime = import("@astrojs/cloudflare").Runtime<ENV>;
|
||||||
|
declare namespace App {
|
||||||
|
interface Locals extends Runtime {}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,26 @@
|
||||||
---
|
---
|
||||||
|
import { getCollection, render } from "astro:content";
|
||||||
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
||||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||||
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
||||||
import type { GetStaticPaths } from "astro";
|
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
import ProseLayout from "@layouts/ProseLayout.astro";
|
import ProseLayout from "@layouts/ProseLayout.astro";
|
||||||
import ArticleViewCounter from "@components/ArticleViewCounter.svelte";
|
import ArticleViewCounter from "@components/ArticleViewCounter.astro";
|
||||||
import HeadContent from "@components/HeadContent.astro";
|
import HeadContent from "@components/HeadContent.astro";
|
||||||
|
import type { GetStaticPaths } from "astro";
|
||||||
|
|
||||||
export const getStaticPaths = (async () => {
|
export const getStaticPaths = (async () => {
|
||||||
const blogCollection = await getCollection("blog");
|
const blogCollection = await getCollection("blog");
|
||||||
return blogCollection.map((entry) => ({
|
return blogCollection.map((entry) => ({
|
||||||
params: {
|
params: {
|
||||||
article: entry.slug,
|
article: entry.id,
|
||||||
},
|
},
|
||||||
props: { entry },
|
props: { entry },
|
||||||
}));
|
}));
|
||||||
}) satisfies GetStaticPaths;
|
}) satisfies GetStaticPaths;
|
||||||
|
|
||||||
const project = Astro.props.entry;
|
const blogPost = Astro.props.entry;
|
||||||
const { Content, headings } = await project.render();
|
const { Content, headings } = await render(blogPost);
|
||||||
const { date, intro, image } = project.data;
|
const { date, intro, image } = blogPost.data;
|
||||||
const title = headings[0].text;
|
const title = headings[0].text;
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ const title = headings[0].text;
|
||||||
|
|
||||||
<span class="px-2">⋅</span>
|
<span class="px-2">⋅</span>
|
||||||
|
|
||||||
<ArticleViewCounter articleSlug={project.slug} client:only="svelte" />
|
<ArticleViewCounter server:defer articleSlug={blogPost.id} />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ProseLayout>
|
<ProseLayout>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
|
import { getCollection, render } from "astro:content";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import Paragraph from "@components/Paragraph.astro";
|
import Paragraph from "@components/Paragraph.astro";
|
||||||
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
||||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||||
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
||||||
import { getCollection } from "astro:content";
|
|
||||||
import Head from "@components/HeadContent.astro";
|
import Head from "@components/HeadContent.astro";
|
||||||
|
|
||||||
const articles = await getCollection("blog");
|
const articles = await getCollection("blog");
|
||||||
|
|
@ -31,13 +31,13 @@ const articles = await getCollection("blog");
|
||||||
articles
|
articles
|
||||||
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
|
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
|
||||||
.map(async (article) => {
|
.map(async (article) => {
|
||||||
const { slug, data } = article;
|
const { id, data } = article;
|
||||||
const { image, intro } = data;
|
const { image, intro } = data;
|
||||||
const { headings } = await article.render();
|
const { headings } = await render(article);
|
||||||
const title = headings[0].text;
|
const title = headings[0].text;
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
href={`/articles/${slug}`}
|
href={`/articles/${id}`}
|
||||||
class="group mx-auto my-8 grid max-w-xs grid-cols-1 overflow-hidden rounded-lg bg-white shadow duration-100 hover:translate-x-1 hover:shadow-md sm:max-w-none sm:grid-cols-3"
|
class="group mx-auto my-8 grid max-w-xs grid-cols-1 overflow-hidden rounded-lg bg-white shadow duration-100 hover:translate-x-1 hover:shadow-md sm:max-w-none sm:grid-cols-3"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection, render } from "astro:content";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||||
import Link from "@components/Link.astro";
|
import Link from "@components/Link.astro";
|
||||||
|
|
@ -11,8 +11,8 @@ const articles = await getCollection("blog");
|
||||||
const latestArticle = articles.sort(
|
const latestArticle = articles.sort(
|
||||||
(p2, p1) => p1.data.date.getTime() - p2.data.date.getTime()
|
(p2, p1) => p1.data.date.getTime() - p2.data.date.getTime()
|
||||||
)[0];
|
)[0];
|
||||||
const latestArticleSlug = latestArticle.slug;
|
const latestArticleSlug = latestArticle.id;
|
||||||
const latestArticleTitle = (await latestArticle.render()).headings[0].text;
|
const latestArticleTitle = (await render(latestArticle)).headings[0].text;
|
||||||
const latestArticleImage = latestArticle.data.image;
|
const latestArticleImage = latestArticle.data.image;
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
import type { GetStaticPaths } from "astro";
|
import type { GetStaticPaths } from "astro";
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import { getFileNameFromPath } from "./index.astro";
|
import { getFileNameFromPath } from "./index.astro";
|
||||||
import RootLayout from "@layouts/RootLayout.astro";
|
|
||||||
import HeadContent from "@components/HeadContent.astro";
|
import HeadContent from "@components/HeadContent.astro";
|
||||||
|
|
||||||
export const getStaticPaths = (async () => {
|
export const getStaticPaths: GetStaticPaths = (async () => {
|
||||||
const photos = await Astro.glob("../../assets/photos/*");
|
const photos = await Astro.glob("../../assets/photos/*");
|
||||||
|
|
||||||
return photos.map((photo: any) => ({
|
return photos.map((photo: any) => ({
|
||||||
|
|
@ -18,7 +17,7 @@ export const getStaticPaths = (async () => {
|
||||||
}));
|
}));
|
||||||
}) satisfies GetStaticPaths;
|
}) satisfies GetStaticPaths;
|
||||||
|
|
||||||
const { photo } = Astro.props;
|
const photo = Astro.props.photo as any;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,20 @@ import type { GetStaticPaths } from "astro";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
import ProseLayout from "@layouts/ProseLayout.astro";
|
import ProseLayout from "@layouts/ProseLayout.astro";
|
||||||
import HeadContent from "@components/HeadContent.astro";
|
import HeadContent from "@components/HeadContent.astro";
|
||||||
|
import { render } from "astro:content";
|
||||||
|
|
||||||
export const getStaticPaths = (async () => {
|
export const getStaticPaths = (async () => {
|
||||||
const programmingEntries = await getCollection("programming");
|
const programmingEntries = await getCollection("programming");
|
||||||
return programmingEntries.map((entry) => ({
|
return programmingEntries.map((entry) => ({
|
||||||
params: {
|
params: {
|
||||||
project: entry.slug,
|
project: entry.id,
|
||||||
},
|
},
|
||||||
props: { entry },
|
props: { entry },
|
||||||
}));
|
}));
|
||||||
}) satisfies GetStaticPaths;
|
}) satisfies GetStaticPaths;
|
||||||
|
|
||||||
const project = Astro.props.entry;
|
const project = Astro.props.entry;
|
||||||
const { Content } = await project.render();
|
const { Content } = await render(project);
|
||||||
const { title, description, image, date, technologies, website, repository } =
|
const { title, description, image, date, technologies, website, repository } =
|
||||||
project.data;
|
project.data;
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ const projects = await getCollection("programming");
|
||||||
{
|
{
|
||||||
projects
|
projects
|
||||||
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
|
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
|
||||||
.map(({ data, slug }) => (
|
.map(({ data, id }) => (
|
||||||
<a
|
<a
|
||||||
href={`/programming/${slug}`}
|
href={`/programming/${id}`}
|
||||||
class="mx-auto overflow-hidden rounded-lg bg-white pb-8 shadow-md duration-100 hover:-translate-y-1 hover:shadow-lg"
|
class="mx-auto overflow-hidden rounded-lg bg-white pb-8 shadow-md duration-100 hover:-translate-y-1 hover:shadow-lg"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"extends": "astro/tsconfigs/strict",
|
"extends": "astro/tsconfigs/strict",
|
||||||
|
"include": [".astro/types.d.ts", "**/*"],
|
||||||
|
"exclude": ["dist"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue