Astro upgrade to v6

This commit is contained in:
2026-03-30 09:53:51 -07:00
parent 95081b8b77
commit b2cd74385f
15 changed files with 1556 additions and 1758 deletions

View File

@@ -8,36 +8,36 @@
"preview": "astro preview" "preview": "astro preview"
}, },
"devDependencies": { "devDependencies": {
"@astrojs/react": "^4.4.0", "@astrojs/react": "^5.0.2",
"@astrojs/tailwind": "^6.0.2", "@astrojs/tailwind": "^6.0.2",
"@tailwindcss/typography": "^0.5.16", "@tailwindcss/typography": "^0.5.19",
"@types/react": "^18.3.20", "@types/react": "^18.3.28",
"@types/react-dom": "^18.3.6", "@types/react-dom": "^18.3.7",
"astro": "^5.14.1", "astro": "^6.1.2",
"tailwindcss": "^3.4.17" "tailwindcss": "^3.4.19"
}, },
"dependencies": { "dependencies": {
"@astrojs/mdx": "^4.3.6", "@astrojs/mdx": "^5.0.3",
"@astrojs/node": "^9.4.4", "@astrojs/node": "^10.0.4",
"@astrojs/rss": "^4.0.12", "@astrojs/rss": "^4.0.18",
"@astrojs/sitemap": "^3.6.0", "@astrojs/sitemap": "^3.7.2",
"@giscus/react": "^3.1.0", "@giscus/react": "^3.1.0",
"@pilcrowjs/object-parser": "^0.0.4", "@pilcrowjs/object-parser": "^0.0.4",
"@react-hook/intersection-observer": "^3.1.2", "@react-hook/intersection-observer": "^3.1.2",
"@rehype-pretty/transformers": "^0.13.2", "@rehype-pretty/transformers": "^0.13.2",
"arctic": "^3.6.0", "arctic": "^3.7.0",
"lucide-react": "^0.468.0", "lucide-react": "^0.468.0",
"marked": "^15.0.8", "marked": "^15.0.12",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-icons": "^5.5.0", "react-icons": "^5.6.0",
"react-responsive": "^10.0.1", "react-responsive": "^10.0.1",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-pretty-code": "^0.14.1", "rehype-pretty-code": "^0.14.3",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"schema-dts": "^1.1.5", "schema-dts": "^1.1.5",
"shiki": "^3.12.2", "shiki": "^3.23.0",
"typewriter-effect": "^2.21.0", "typewriter-effect": "^2.22.0",
"unist-util-visit": "^5.0.0" "unist-util-visit": "^5.1.0"
} }
} }

3172
src/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
import React from "react"; import React from "react";
type BlogPost = { type BlogPost = {
slug: string; id: string;
data: { data: {
title: string; title: string;
author: string; author: string;
@@ -30,9 +30,9 @@ export const BlogPostList = ({ posts }: BlogPostListProps) => {
<div className="w-full max-w-6xl mx-auto"> <div className="w-full max-w-6xl mx-auto">
<ul className="space-y-6 md:space-y-10"> <ul className="space-y-6 md:space-y-10">
{posts.map((post) => ( {posts.map((post) => (
<li key={post.slug} className="group px-4 md:px-0"> <li key={post.id} className="group px-4 md:px-0">
<a <a
href={`/blog/${post.slug}`} href={`/blog/${post.id}`}
className="block" className="block"
> >
<article className="flex flex-col md:flex-row gap-4 md:gap-8 pb-6 md:pb-10 border-b border-foreground/20 last:border-b-0 p-2 md:p-4 rounded-lg group-hover:outline group-hover:outline-2 group-hover:outline-purple transition-all duration-200"> <article className="flex flex-col md:flex-row gap-4 md:gap-8 pb-6 md:pb-10 border-b border-foreground/20 last:border-b-0 p-2 md:p-4 rounded-lg group-hover:outline group-hover:outline-2 group-hover:outline-purple transition-all duration-200">

View File

@@ -11,7 +11,7 @@ export function ProjectCard({ project }: ProjectCardProps) {
return ( return (
<article className="group relative h-full"> <article className="group relative h-full">
<a <a
href={`/projects/${project.slug}`} href={`/projects/${project.id}`}
className="block rounded-lg border-2 border-foreground/20 className="block rounded-lg border-2 border-foreground/20
hover:border-blue transition-all duration-300 hover:border-blue transition-all duration-300
bg-background overflow-hidden h-full flex flex-col" bg-background overflow-hidden h-full flex flex-col"

View File

@@ -23,7 +23,7 @@ export function ProjectList({ projects }: ProjectListProps) {
</h2> </h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 auto-rows-fr justify-items-center"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 auto-rows-fr justify-items-center">
{latestProjects.map(project => ( {latestProjects.map(project => (
<div key={project.slug} className="w-full max-w-md"> <div key={project.id} className="w-full max-w-md">
<ProjectCard project={project} /> <ProjectCard project={project} />
</div> </div>
))} ))}
@@ -37,7 +37,7 @@ export function ProjectList({ projects }: ProjectListProps) {
</h2> </h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 auto-rows-fr justify-items-center"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 auto-rows-fr justify-items-center">
{otherProjects.map(project => ( {otherProjects.map(project => (
<div key={project.slug} className="w-full max-w-md"> <div key={project.id} className="w-full max-w-md">
<ProjectCard project={project} /> <ProjectCard project={project} />
</div> </div>
))} ))}

View File

@@ -1,7 +1,9 @@
import { defineCollection, z } from "astro:content"; import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
export const collections = { export const collections = {
blog: defineCollection({ blog: defineCollection({
loader: glob({ pattern: "**/*.mdx", base: "./src/content/blog" }),
schema: z.object({ schema: z.object({
title: z.string(), title: z.string(),
description: z.string(), description: z.string(),
@@ -16,6 +18,7 @@ export const collections = {
}), }),
}), }),
projects: defineCollection({ projects: defineCollection({
loader: glob({ pattern: "**/*.mdx", base: "./src/content/projects" }),
schema: z.object({ schema: z.object({
title: z.string(), title: z.string(),
description: z.string(), description: z.string(),

View File

@@ -25,6 +25,7 @@ import Advertisement from '@/content/blog/components/thinkpad-t440p-coreboot-gui
Don't pipe anyone's scripts to **sh** blindly, including mine - <a href="https://github.com/timmypidashev/scripts" target="_blank" rel="noopener noreferrer">audit the source</a>. Don't pipe anyone's scripts to **sh** blindly, including mine - <a href="https://github.com/timmypidashev/scripts" target="_blank" rel="noopener noreferrer">audit the source</a>.
## Getting Started ## Getting Started
The Thinkpad T440p is a powerful and versatile laptop that can be further enhanced by installing coreboot, The Thinkpad T440p is a powerful and versatile laptop that can be further enhanced by installing coreboot,
an open-source BIOS replacement. This guide will walk you through the process of corebooting your T440p, an open-source BIOS replacement. This guide will walk you through the process of corebooting your T440p,
including flashing the BIOS chip and installing the necessary software. including flashing the BIOS chip and installing the necessary software.
@@ -202,22 +203,64 @@ Configuring coreboot is really where most of your time will be spent. To help ou
I've created several handy configs that should suit most use cases, and can be easily I've created several handy configs that should suit most use cases, and can be easily
tweaked to your liking. Here is a list of whats available: tweaked to your liking. Here is a list of whats available:
1. GRUB2 ### 1. GRUB2 (Recommended)
This configuration features GRUB2 as the bootloader, and contains 3 secondary payloads, GRUB2 is the recommended payload for most users. It boots Linux directly without needing a
which the user can opt in/out of: separate bootloader installation on disk. This configuration includes three secondary payloads:
* memtest built in - **memtest86+** - Memory testing utility
* nvramcui built in - **nvramcui** - CMOS/NVRAM settings editor
* coreinfo built in - **coreinfo** - System information viewer
This configuration also includes the dGPU option rom as well for T440p's featuring the gt730m on board. If your T440p has the optional GT730M dGPU, the GRUB2 config also includes the
necessary VGA option ROM for it.
2. SeaBIOS ### 2. SeaBIOS
3. edk2 SeaBIOS provides a traditional BIOS interface, making it the most compatible option.
Choose this if you need to boot operating systems that expect a legacy BIOS, such
as Windows or BSD.
> NOTE: Show the user how to choose the appropriate config, as well as building a custom config below. ### 3. edk2 (UEFI)
edk2 provides a UEFI firmware interface. Choose this if you prefer UEFI boot or
need UEFI-specific features.
---
If using the interactive script, it will prompt you to choose a payload and apply
a preset configuration automatically. You can also choose to open the full
configuration menu (`make nconfig`) to customize further.
For manual configuration, first copy the extracted blobs into place:
<CommandSequence
commands={[
"mkdir -p ~/t440p-coreboot/coreboot/3rdparty/blobs/mainboard/lenovo/haswell",
"mkdir -p ~/t440p-coreboot/coreboot/3rdparty/blobs/cpu/intel/haswell",
"cp ~/t440p-coreboot/ifd.bin ~/t440p-coreboot/coreboot/3rdparty/blobs/mainboard/lenovo/haswell/descriptor.bin",
"cp ~/t440p-coreboot/me.bin ~/t440p-coreboot/coreboot/3rdparty/blobs/mainboard/lenovo/haswell/me.bin",
"cp ~/t440p-coreboot/gbe.bin ~/t440p-coreboot/coreboot/3rdparty/blobs/mainboard/lenovo/haswell/gbe.bin",
"cp ~/t440p-coreboot/mrc.bin ~/t440p-coreboot/coreboot/3rdparty/blobs/cpu/intel/haswell/mrc.bin"
]}
description="Copy firmware blobs into the coreboot source tree"
client:load
/>
Then open the configuration menu:
<Command
description="Open coreboot configuration"
command="cd ~/t440p-coreboot/coreboot && make nconfig"
client:load
/>
Key settings to configure:
- **Mainboard** &rarr; Mainboard vendor: **Lenovo** &rarr; Mainboard model: **ThinkPad T440p**
- **Chipset** &rarr; Add Intel descriptor.bin, ME firmware, and GbE configuration (set paths to your blobs)
- **Chipset** &rarr; Add haswell MRC file (set path to mrc.bin)
- **Payload** &rarr; Choose your preferred payload (GRUB2, SeaBIOS, or edk2)
## Building and Flashing ## Building and Flashing
@@ -239,7 +282,7 @@ Once the coreboot build has completed, split the built ROM for the 8MB(bottom) c
commands={[ commands={[
"cd ~/t440p-coreboot/coreboot/build", "cd ~/t440p-coreboot/coreboot/build",
"dd if=coreboot.rom of=bottom.rom bs=1M count=8", "dd if=coreboot.rom of=bottom.rom bs=1M count=8",
"dd if=coreboot.rom of=top.rom bs=1M skin=8" "dd if=coreboot.rom of=top.rom bs=1M skip=8"
]} ]}
description="Split the built ROM for both EEPROM chips" description="Split the built ROM for both EEPROM chips"
client:load client:load

View File

@@ -41,7 +41,7 @@ export function getArticleSchema(post: CollectionEntry<"blog">) {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "Article", "@type": "Article",
headline: post.data.title, headline: post.data.title,
url: `${import.meta.env.SITE}/blog/${post.slug}/`, url: `${import.meta.env.SITE}/blog/${post.id}/`,
description: post.data.excerpt, description: post.data.excerpt,
datePublished: post.data.date.toString(), datePublished: post.data.date.toString(),
publisher: { publisher: {

View File

@@ -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 ContentLayout from "@/layouts/content.astro"; import ContentLayout from "@/layouts/content.astro";
import { getArticleSchema } from "@/lib/structuredData"; import { getArticleSchema } from "@/lib/structuredData";
@@ -11,9 +11,9 @@ const { slug } = Astro.params;
// Fetch blog posts // Fetch blog posts
const posts = await getCollection("blog"); const posts = await getCollection("blog");
const post = posts.find(post => post.slug === slug); const post = posts.find(post => post.id === slug);
if (!post || post.data.isDraft === true) { if (!post || (!import.meta.env.DEV && post.data.isDraft === true)) {
return new Response(null, { return new Response(null, {
status: 404, status: 404,
statusText: "Not found" statusText: "Not found"
@@ -21,7 +21,7 @@ if (!post || post.data.isDraft === true) {
} }
// Dynamically render the content // Dynamically render the content
const { Content } = await post.render(); const { Content } = await render(post);
// Format the date // Format the date
const formattedDate = new Date(post.data.date).toLocaleDateString("en-US", { const formattedDate = new Date(post.data.date).toLocaleDateString("en-US", {
@@ -46,7 +46,7 @@ const breadcrumbsStructuredData = {
"@type": "ListItem", "@type": "ListItem",
position: 2, position: 2,
name: post.data.title, name: post.data.title,
item: `${import.meta.env.SITE}/blog/${post.slug}/`, item: `${import.meta.env.SITE}/blog/${post.id}/`,
}, },
], ],
}; };

View File

@@ -5,7 +5,7 @@ import { BlogHeader } from "@/components/blog/header";
import { BlogPostList } from "@/components/blog/post-list"; import { BlogPostList } from "@/components/blog/post-list";
const posts = (await getCollection("blog", ({ data }) => { const posts = (await getCollection("blog", ({ data }) => {
return data.isDraft !== true; return import.meta.env.DEV || data.isDraft !== true;
})).sort((a, b) => { })).sort((a, b) => {
return b.data.date.valueOf() - a.data.date.valueOf() return b.data.date.valueOf() - a.data.date.valueOf()
}).map(post => ({ }).map(post => ({

View File

@@ -5,7 +5,7 @@ import ContentLayout from "@/layouts/content.astro";
import TagList from "@/components/blog/tag-list"; import TagList from "@/components/blog/tag-list";
const posts = (await getCollection("blog", ({ data }) => { const posts = (await getCollection("blog", ({ data }) => {
return data.isDraft !== true; return import.meta.env.DEV || data.isDraft !== true;
})).sort((a, b) => { })).sort((a, b) => {
return b.data.date.valueOf() - a.data.date.valueOf() return b.data.date.valueOf() - a.data.date.valueOf()
}).map(post => ({ }).map(post => ({

View File

@@ -1,7 +1,7 @@
--- ---
export const prerender = true; export const prerender = true;
import { getCollection } from "astro:content"; import { getCollection, render } from "astro:content";
import ContentLayout from "@/layouts/content.astro"; import ContentLayout from "@/layouts/content.astro";
import { Comments } from "@/components/blog/comments"; import { Comments } from "@/components/blog/comments";
@@ -9,13 +9,13 @@ import { Comments } from "@/components/blog/comments";
export async function getStaticPaths() { export async function getStaticPaths() {
const projects = await getCollection("projects"); const projects = await getCollection("projects");
return projects.map(project => ({ return projects.map(project => ({
params: { slug: project.slug }, params: { slug: project.id },
props: { project }, props: { project },
})); }));
} }
const { project } = Astro.props; const { project } = Astro.props;
const { Content } = await project.render(); const { Content } = await render(project);
--- ---
<ContentLayout title={`${project.data.title} | Timothy Pidashev`}> <ContentLayout title={`${project.data.title} | Timothy Pidashev`}>

View File

@@ -16,11 +16,11 @@ export async function GET(context: APIContext) {
title: post.data.title, title: post.data.title,
pubDate: post.data.date, pubDate: post.data.date,
description: post.data.description, description: post.data.description,
link: `/blog/${post.slug}/`, link: `/blog/${post.id}/`,
author: post.data.author, author: post.data.author,
categories: post.data.tags, categories: post.data.tags,
enclosure: post.data.image ? { enclosure: post.data.image ? {
url: new URL(`blog/${post.slug}/thumbnail.png`, context.site).toString(), url: new URL(`blog/${post.id}/thumbnail.png`, context.site).toString(),
type: 'image/jpeg', type: 'image/jpeg',
length: 0 length: 0
} : undefined } : undefined