mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 02:53:51 +00:00
Astro upgrade to v6
This commit is contained in:
@@ -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
3172
src/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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">
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -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(),
|
||||||
0
src/src/content/blog/json-as-machine-code.keep
Normal file
0
src/src/content/blog/json-as-machine-code.keep
Normal 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
|
|
||||||
* nvramcui built in
|
|
||||||
* coreinfo built in
|
|
||||||
|
|
||||||
This configuration also includes the dGPU option rom as well for T440p's featuring the gt730m on board.
|
- **memtest86+** - Memory testing utility
|
||||||
|
- **nvramcui** - CMOS/NVRAM settings editor
|
||||||
|
- **coreinfo** - System information viewer
|
||||||
|
|
||||||
2. SeaBIOS
|
If your T440p has the optional GT730M dGPU, the GRUB2 config also includes the
|
||||||
|
necessary VGA option ROM for it.
|
||||||
|
|
||||||
3. edk2
|
### 2. SeaBIOS
|
||||||
|
|
||||||
> NOTE: Show the user how to choose the appropriate config, as well as building a custom config below.
|
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.
|
||||||
|
|
||||||
|
### 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** → Mainboard vendor: **Lenovo** → Mainboard model: **ThinkPad T440p**
|
||||||
|
- **Chipset** → Add Intel descriptor.bin, ME firmware, and GbE configuration (set paths to your blobs)
|
||||||
|
- **Chipset** → Add haswell MRC file (set path to mrc.bin)
|
||||||
|
- **Payload** → 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
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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}/`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 => ({
|
||||||
|
|||||||
@@ -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 => ({
|
||||||
|
|||||||
@@ -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`}>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user