-
Notifications
You must be signed in to change notification settings - Fork 24
Reorganize blog post structure for clarity #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,14 +1,21 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { defineConfig } from "astro/config"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import prefetch from "@astrojs/prefetch"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import sitemap from "@astrojs/sitemap"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import tailwindcss from "@tailwindcss/vite"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // https://astro.build/config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default defineConfig({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| site: "https://t3.gg", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| image: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Apply responsive image defaults to Markdown content. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| layout: "constrained", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| domains: ["t3.gg", "img.youtube.com"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vite: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| plugins: [tailwindcss()], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| plugins: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| integrations: [prefetch()], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| integrations: [prefetch(), sitemap()], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
7
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Site and image configuration look good; update integrations. The Update the integrations array to remove prefetch and optionally enable built-in prefetching: export default defineConfig({
site: "https://t3.gg",
+ prefetch: true,
image: {
layout: "constrained",
domains: ["t3.gg", "img.youtube.com"],
},
// ...
- integrations: [prefetch(), sitemap()],
+ integrations: [sitemap()],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| redirects: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "/links": "/", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "/faq": "/", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,8 @@ | |
| }, | ||
| "dependencies": { | ||
| "@astrojs/prefetch": "^0.4.1", | ||
| "@astrojs/rss": "^4.0.15", | ||
| "@astrojs/sitemap": "^3.7.0", | ||
| "date-fns": "^4.1.0" | ||
|
Comment on lines
24
to
27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat package.json | head -50Repository: T3-Content/t3.gg Length of output: 833 🏁 Script executed: test -f astro.config.mjs && cat astro.config.mjs || echo "astro.config.mjs not found"Repository: T3-Content/t3.gg Length of output: 624 🌐 Web query:
💡 Result: Astro 5 has built-in link prefetching (the old Enable it (project-wide)In import { defineConfig } from 'astro/config';
export default defineConfig({
prefetch: true,
});This injects the prefetch runtime so you can opt-in per link with Prefetch configuration optionsYou can also pass an object: export default defineConfig({
prefetch: {
defaultStrategy: 'viewport', // 'hover' | 'tap' | 'viewport' | 'load'
prefetchAll: false, // true = prefetch all internal links by default
},
});
Per-link usageOpt in: <a href="/about" data-astro-prefetch>About</a>Pick a strategy per link: <a href="/about" data-astro-prefetch="tap">About</a>Opt out (when <a href="/about" data-astro-prefetch="false">About</a>(Works for internal links only.) [1] Optional: client prerendering (experimental)If you want prefetched pages to be prerendered in supported browsers (Speculation Rules API): export default defineConfig({
prefetch: { prefetchAll: true, defaultStrategy: 'viewport' },
experimental: { clientPrerender: true },
});[3] 🌐 Web query:
💡 Result:
What to do for Astro 5: remove Sources: [1] [2] [3] Replace deprecated The Remove from package.json diff "dependencies": {
- "@astrojs/prefetch": "^0.4.1",
"@astrojs/rss": "^4.0.15",
"@astrojs/sitemap": "^3.7.0",
"date-fns": "^4.1.0"
}Update astro.config.mjs diff import { defineConfig } from "astro/config";
- import prefetch from "@astrojs/prefetch";
import sitemap from "@astrojs/sitemap";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
site: "https://t3.gg",
image: {
layout: "constrained",
domains: ["t3.gg", "img.youtube.com"],
},
vite: {
plugins: [tailwindcss()],
},
plugins: [],
- integrations: [prefetch(), sitemap()],
+ integrations: [sitemap()],
+ prefetch: true,
redirects: {
"/links": "/",
"/faq": "/",
},
});Use <a href="/about" data-astro-prefetch>About</a>
<a href="/contact" data-astro-prefetch="tap">Contact</a>🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| --- | ||
| import { Picture } from "astro:assets"; | ||
| import type { ImageMetadata } from "astro"; | ||
|
|
||
| interface Props { | ||
| src: ImageMetadata | string; | ||
| alt: string; | ||
| class?: string; | ||
| sizes?: string; | ||
| widths?: number[]; | ||
| priority?: boolean; | ||
| } | ||
|
|
||
| const { | ||
| src, | ||
| alt, | ||
| class: className, | ||
| sizes = "(min-width: 768px) 768px, 100vw", | ||
| widths = [480, 768, 1024, 1280, 1600], | ||
| priority = false, | ||
| } = Astro.props; | ||
|
|
||
| const isLocalImage = typeof src !== "string"; | ||
| const loading = priority ? "eager" : "lazy"; | ||
| --- | ||
|
|
||
| { | ||
| isLocalImage ? ( | ||
| <Picture | ||
| src={src} | ||
| alt={alt} | ||
| sizes={sizes} | ||
| widths={widths} | ||
| formats={["avif", "webp"]} | ||
| loading={loading} | ||
| decoding="async" | ||
| class={className} | ||
| /> | ||
| ) : ( | ||
| <img | ||
| src={src} | ||
| alt={alt} | ||
| loading={loading} | ||
| decoding="async" | ||
| class={className} | ||
| /> | ||
| ) | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,19 +1,38 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||
| import type { CollectionEntry } from "astro:content"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { format } from "date-fns"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import BlogImage from "./BlogImage.astro"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| export interface Props { | ||||||||||||||||||||||||||||||||||||||||||||||||
| post: { title: string; date: string }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| post: CollectionEntry<"posts">; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| import { parseISO, format } from "date-fns"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const { post } = Astro.props; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const date = parseISO(post.date); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const date = post.data.date; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const formatted = format(date, "LLLL d, yyyy"); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const coverImage = post.data.cover ?? post.data.imageURL; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const coverAlt = post.data.coverAlt ?? post.data.title; | ||||||||||||||||||||||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| <header class="not-prose mb-12 border-b border-white/10 pb-8"> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <h1 class="mb-3 text-2xl font-medium tracking-tight text-text"> | ||||||||||||||||||||||||||||||||||||||||||||||||
| {post.title} | ||||||||||||||||||||||||||||||||||||||||||||||||
| {post.data.title} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </h1> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <time datetime={date.toString()} class="text-sm text-muted">{formatted}</time> | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+12
to
22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use ISO format for the 🛠️ Suggested fix- <time datetime={date.toString()} class="text-sm text-muted">{formatted}</time>
+ <time datetime={date.toISOString()} class="text-sm text-muted">{formatted}</time>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
| {post.data.archived ? ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| <div class="mt-4 rounded-lg border border-amber-300/20 bg-amber-300/5 px-4 py-3 text-sm text-amber-100/90"> | ||||||||||||||||||||||||||||||||||||||||||||||||
| This post was archived manually by Theo. It is probably out of date or something. | ||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) : null} | ||||||||||||||||||||||||||||||||||||||||||||||||
| {coverImage ? ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| <figure class="mt-8"> | ||||||||||||||||||||||||||||||||||||||||||||||||
| <BlogImage | ||||||||||||||||||||||||||||||||||||||||||||||||
| src={coverImage} | ||||||||||||||||||||||||||||||||||||||||||||||||
| alt={coverAlt} | ||||||||||||||||||||||||||||||||||||||||||||||||
| priority={true} | ||||||||||||||||||||||||||||||||||||||||||||||||
| class="w-full rounded-xl border border-white/10" | ||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||
| </figure> | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) : null} | ||||||||||||||||||||||||||||||||||||||||||||||||
| </header> | ||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import { defineCollection, z } from "astro:content"; | ||
| import { glob } from "astro/loaders"; | ||
|
|
||
| const posts = defineCollection({ | ||
| loader: glob({ | ||
| base: "./src/content/posts", | ||
| pattern: "**/index.md", | ||
| generateId: ({ entry, data }) => { | ||
| // Prefer an explicit, canonical slug so folders can move freely | ||
| // without breaking old links. | ||
| const explicitSlug = | ||
| typeof data.slug === "string" && data.slug.trim().length > 0 | ||
| ? data.slug.trim() | ||
| : undefined; | ||
| if (explicitSlug) return explicitSlug; | ||
|
|
||
| // Fall back to the entry path (minus the index file). | ||
| return entry.replace(/\/index\.md$/, ""); | ||
| }, | ||
| }), | ||
| schema: ({ image }) => | ||
| z.object({ | ||
| title: z.string(), | ||
| description: z.string().optional(), | ||
| date: z.coerce.date(), | ||
| updated: z.coerce.date().optional(), | ||
| tags: z.array(z.string()).optional(), | ||
| // Canonical slug used for stable URLs. | ||
| slug: z.string().optional(), | ||
| // Optional legacy slugs that should redirect to the canonical slug. | ||
| slugAliases: z.array(z.string()).optional(), | ||
| draft: z.boolean().default(false), | ||
| hidden: z.boolean().default(false), | ||
| archived: z.boolean().default(false), | ||
| readMore: z.boolean().optional(), | ||
| cover: image().optional(), | ||
| coverAlt: z.string().optional(), | ||
| imageURL: z.string().url().optional(), | ||
| canonicalUrl: z.string().url().optional(), | ||
| }), | ||
| }); | ||
|
|
||
| export const collections = { | ||
| posts, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Blog Post Organization | ||
|
|
||
| This folder is organized for editing ergonomics without breaking links. | ||
|
|
||
| ## Structure | ||
|
|
||
| - Active posts: `src/content/posts/active/<year>/<slug>/index.md` | ||
| - Archived posts: `src/content/posts/archive/<year>/<slug>/index.md` | ||
|
|
||
| ## Canonical Slug (Important) | ||
|
|
||
| Each post should include a `slug` field in frontmatter: | ||
|
|
||
| ```md | ||
| --- | ||
| title: "My Post" | ||
| slug: "my-post" | ||
| date: "2026-02-02" | ||
| --- | ||
| ``` | ||
|
|
||
| The `slug` is the canonical URL segment used at `/blog/post/<slug>`. | ||
| Because the slug is explicit, you can move posts between folders freely | ||
| without breaking old links. | ||
|
|
||
| ## Optional Aliases | ||
|
|
||
| If you ever rename a slug, you can keep old URLs working: | ||
|
|
||
| ```md | ||
| slug: "new-slug" | ||
| slugAliases: | ||
| - "old-slug" | ||
| ``` | ||
|
|
||
| Aliases will redirect to the canonical slug. | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove deprecated
@astrojs/prefetchintegration.As noted in package.json,
@astrojs/prefetchis incompatible with Astro 5. Remove the import and use built-in prefetching.import { defineConfig } from "astro/config"; -import prefetch from "@astrojs/prefetch"; import sitemap from "@astrojs/sitemap";📝 Committable suggestion
🤖 Prompt for AI Agents