Adds post tags
This commit is contained in:
@@ -1,13 +1,14 @@
|
|||||||
---
|
---
|
||||||
interface Props {
|
interface Props {
|
||||||
fillNotches: "left" | "right" | "both" | "none";
|
fillNotches: "left" | "right" | "both" | "none";
|
||||||
|
color?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { fillNotches = "none" } = Astro.props;
|
const { fillNotches = "none", color = "gold" } = Astro.props;
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class={`container notch-${fillNotches}`}>
|
<div class={`container notch-${fillNotches}`} style={`background-color: var(--color-${color})`}>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const blog = defineCollection({
|
|||||||
pubDate: z.coerce.date().optional(),
|
pubDate: z.coerce.date().optional(),
|
||||||
updatedDate: z.coerce.date().optional(),
|
updatedDate: z.coerce.date().optional(),
|
||||||
heroImage: image().optional(),
|
heroImage: image().optional(),
|
||||||
|
tags: z.array(z.string()).optional(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
title: "The Forge of God by Greg Bear"
|
title: "The Forge of God by Greg Bear"
|
||||||
description: "A short review"
|
description: "A short review"
|
||||||
pubDate: "Jul 18 2025"
|
pubDate: "Jul 18 2025"
|
||||||
|
tags:
|
||||||
|
- Sci-Fi
|
||||||
|
- Book Review
|
||||||
---
|
---
|
||||||
|
|
||||||
[The Forge of God](https://en.wikipedia.org/wiki/The_Forge_of_God) by [Greg Bear](https://en.wikipedia.org/wiki/Greg_Bear) is a bit of an old book to be reviewing now. It was first published in 1987 and it's 2025 now. Did I pick it up without realizing this? Was a stricken with an acute case of nostalgia? Was I trapped in an abandoned house with nothing else to read? Dear reader, I assure you that nothing so exciting happened. I simply saw it on my shelf and decided to read it. I don't need any other reason that that.
|
[The Forge of God](https://en.wikipedia.org/wiki/The_Forge_of_God) by [Greg Bear](https://en.wikipedia.org/wiki/Greg_Bear) is a bit of an old book to be reviewing now. It was first published in 1987 and it's 2025 now. Did I pick it up without realizing this? Was a stricken with an acute case of nostalgia? Was I trapped in an abandoned house with nothing else to read? Dear reader, I assure you that nothing so exciting happened. I simply saw it on my shelf and decided to read it. I don't need any other reason that that.
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
title: "I Forgot to Use AI On My Latest Project"
|
title: "I Forgot to Use AI On My Latest Project"
|
||||||
description: "I forgot to use an LLM to assist on my latest coding project. I probably set the progress of humanity back many hours. But hey, I learned something along the way. What did I learn? That I'd rather not use an LLM on this project."
|
description: "I forgot to use an LLM to assist on my latest coding project. I probably set the progress of humanity back many hours. But hey, I learned something along the way. What did I learn? That I'd rather not use an LLM on this project."
|
||||||
pubDate: "Jun 26 2025"
|
pubDate: "Jun 26 2025"
|
||||||
|
tags:
|
||||||
|
- AI
|
||||||
|
- Tech
|
||||||
|
- Coding
|
||||||
---
|
---
|
||||||
|
|
||||||
I forgot to use AI on my last project. All the tech bros are laughing at me right now. I'm sure in the time I wasted I could have launched a cloud-based passive-income app, but now I'll just have fun staying poor. I'll cry myself to sleep right after I get the satisfaction of learning something new and building something with my own mind.
|
I forgot to use AI on my last project. All the tech bros are laughing at me right now. I'm sure in the time I wasted I could have launched a cloud-based passive-income app, but now I'll just have fun staying poor. I'll cry myself to sleep right after I get the satisfaction of learning something new and building something with my own mind.
|
||||||
|
|||||||
140
src/layouts/BlogList.astro
Normal file
140
src/layouts/BlogList.astro
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
import NotchedBox from '../components/NotchedBox.astro';
|
||||||
|
import RootLayout from '../layouts/RootLayout.astro';
|
||||||
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
||||||
|
import FormattedDate from '../components/FormattedDate.astro';
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
|
||||||
|
interface Params {
|
||||||
|
selectedTag?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { selectedTag } = Astro.props;
|
||||||
|
|
||||||
|
function publishedOnly(p: CollectionEntry<'blog'>): p is (CollectionEntry<'blog'> & { data: { pubDate: Date }}) {
|
||||||
|
return p.data.pubDate !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allPosts = (await getCollection('blog', publishedOnly))
|
||||||
|
.sort(
|
||||||
|
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const tags = allPosts.flatMap(p => p.data.tags);
|
||||||
|
|
||||||
|
const posts =
|
||||||
|
selectedTag
|
||||||
|
? allPosts.filter(p => p.data.tags.includes(selectedTag))
|
||||||
|
: allPosts;
|
||||||
|
---
|
||||||
|
|
||||||
|
<RootLayout>
|
||||||
|
<style>
|
||||||
|
ul.tags {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: baseline;
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 1px 16px
|
||||||
|
.container {
|
||||||
|
background-color: var(--color-gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.posts {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
li {
|
||||||
|
/* Required since flex won't render list-elements correctly. */
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.title, .description {
|
||||||
|
color: var(--color-light-text);
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
color: var(--color-gray);
|
||||||
|
}
|
||||||
|
.entry {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover .title {
|
||||||
|
color: var(--color-accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section>
|
||||||
|
<ul class="tags">
|
||||||
|
{
|
||||||
|
tags.map(tag =>
|
||||||
|
<li>
|
||||||
|
{
|
||||||
|
tag === selectedTag
|
||||||
|
? <a href="/blog">
|
||||||
|
<NotchedBox color="gray" fillNotches={"left"}>
|
||||||
|
{tag}
|
||||||
|
|
||||||
|
</NotchedBox>
|
||||||
|
</a>
|
||||||
|
: <a href={`/blog/tag/${tag}`}>
|
||||||
|
<NotchedBox color="gray" fillNotches={"none"}>
|
||||||
|
{tag}
|
||||||
|
</NotchedBox>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<ul class="posts">
|
||||||
|
{
|
||||||
|
posts.map((post) => (
|
||||||
|
<li>
|
||||||
|
<a href={`/blog/${post.id}/`}>
|
||||||
|
<NotchedBox fillNotches="left">
|
||||||
|
<div class="entry">
|
||||||
|
{post.data.heroImage && (
|
||||||
|
<Image width={720} height={360} src={post.data.heroImage} alt="" />
|
||||||
|
)}
|
||||||
|
<h4 class="title">{post.data.title}</h4>
|
||||||
|
<p class="date">
|
||||||
|
<FormattedDate date={post.data.pubDate} />
|
||||||
|
</p>
|
||||||
|
{ post.data.description &&
|
||||||
|
<p class="description">
|
||||||
|
{post.data.description}
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</NotchedBox>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</RootLayout>
|
||||||
@@ -1,85 +1,5 @@
|
|||||||
---
|
---
|
||||||
import NotchedBox from '../../components/NotchedBox.astro';
|
import BlogList from '../../layouts/BlogList.astro';
|
||||||
import RootLayout from '../../layouts/RootLayout.astro';
|
|
||||||
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
||||||
import FormattedDate from '../../components/FormattedDate.astro';
|
|
||||||
import { Image } from 'astro:assets';
|
|
||||||
|
|
||||||
function publishedOnly(p: CollectionEntry<'blog'>): p is (CollectionEntry<'blog'> & { data: { pubDate: Date }}) {
|
|
||||||
return p.data.pubDate !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const posts = (await getCollection('blog', publishedOnly))
|
|
||||||
.sort(
|
|
||||||
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
|
||||||
);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<RootLayout>
|
<BlogList/>
|
||||||
<style>
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px;
|
|
||||||
align-items: stretch;
|
|
||||||
|
|
||||||
li {
|
|
||||||
/* Required since flex won't render list-elements correctly. */
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
.title, .description {
|
|
||||||
color: var(--color-light-text);
|
|
||||||
}
|
|
||||||
.date {
|
|
||||||
color: var(--color-gray);
|
|
||||||
}
|
|
||||||
.entry {
|
|
||||||
padding: 0.5em;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover .title {
|
|
||||||
color: var(--color-accent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<section>
|
|
||||||
<ul>
|
|
||||||
{
|
|
||||||
posts.map((post) => (
|
|
||||||
<li>
|
|
||||||
<a href={`/blog/${post.id}/`}>
|
|
||||||
<NotchedBox fillNotches="left">
|
|
||||||
<div class="entry">
|
|
||||||
{post.data.heroImage && (
|
|
||||||
<Image width={720} height={360} src={post.data.heroImage} alt="" />
|
|
||||||
)}
|
|
||||||
<h4 class="title">{post.data.title}</h4>
|
|
||||||
<p class="date">
|
|
||||||
<FormattedDate date={post.data.pubDate} />
|
|
||||||
</p>
|
|
||||||
{ post.data.description &&
|
|
||||||
<p class="description">
|
|
||||||
{post.data.description}
|
|
||||||
</p>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</NotchedBox>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</RootLayout>
|
|
||||||
|
|||||||
20
src/pages/blog/tag/[...tag].astro
Normal file
20
src/pages/blog/tag/[...tag].astro
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||||
|
import BlogList from '../../../layouts/BlogList.astro';
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const posts = await getCollection('blog');
|
||||||
|
|
||||||
|
const tags = posts.flatMap(p => p.data.tags);
|
||||||
|
|
||||||
|
return tags.map((tag) => ({
|
||||||
|
params: { tag: tag },
|
||||||
|
props: { tag: tag },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
type Props = { tag: string }
|
||||||
|
|
||||||
|
const tag = Astro.props.tag;
|
||||||
|
---
|
||||||
|
|
||||||
|
<BlogList selectedTag={tag} />
|
||||||
Reference in New Issue
Block a user