Allow filtering of projects
All checks were successful
Build and Deploy to Web Server / deploy (push) Successful in 15m24s

This commit is contained in:
2025-08-25 11:18:39 +09:30
parent 025914083c
commit 982589927f
2 changed files with 80 additions and 4 deletions

View File

@@ -14,9 +14,16 @@ interface Props {
project: CollectionEntry<"projects">; project: CollectionEntry<"projects">;
textOn?: "left" | "right"; textOn?: "left" | "right";
quality?: number; quality?: number;
class?: string;
} }
const { project, textOn = "left", quality = "80" } = Astro.props; const {
project,
textOn = "left",
quality = "80",
class: className,
...attrs
} = Astro.props;
const images = getAllProjectImages(project); const images = getAllProjectImages(project);
@@ -124,7 +131,10 @@ const projectHasBody = project.body && project.body.trim().length > 0;
const link = `/projects/${slugify(project.data.type)}/${slugify(project.data.slug)}/`; const link = `/projects/${slugify(project.data.type)}/${slugify(project.data.slug)}/`;
--- ---
<div class="grid grid-cols-1 text-left md:grid-cols-2"> <div
class:list={["grid grid-cols-1 text-left md:grid-cols-2", className]}
{...attrs}
>
<div <div
class:list={[ class:list={[
"order-1 flex flex-col items-start justify-center py-4", "order-1 flex flex-col items-start justify-center py-4",

View File

@@ -1,14 +1,19 @@
--- ---
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
import SectionTitle from "../components/SectionTitle.astro"; import { slugify } from "@lib/utils";
import MainLayout from "../layouts/MainLayout.astro";
import SectionTitle from "@components/SectionTitle.astro";
import MainLayout from "@layouts/MainLayout.astro";
import Token from "@components/Token.astro";
import ProjectCard from "@components/ProjectCard.astro"; import ProjectCard from "@components/ProjectCard.astro";
const projects = (await getCollection("projects")).sort( const projects = (await getCollection("projects")).sort(
(a, b) => b.data.date.valueOf() - a.data.date.valueOf() (a, b) => b.data.date.valueOf() - a.data.date.valueOf()
); );
const types = [...new Set(projects.map((project) => project.data.type))];
--- ---
<MainLayout title="Projects"> <MainLayout title="Projects">
@@ -16,6 +21,22 @@ const projects = (await getCollection("projects")).sort(
<section id="projects" class="bg-white dark:bg-gray-950"> <section id="projects" class="bg-white dark:bg-gray-950">
<div class="mx-auto max-w-4xl px-8 py-16 text-center"> <div class="mx-auto max-w-4xl px-8 py-16 text-center">
<SectionTitle>Recent Projects</SectionTitle> <SectionTitle>Recent Projects</SectionTitle>
<div id="filter-tokens" class="my-8 space-x-2">
<Token
class="filter-token !text-primary ring-primary bg-white ring-2 hover:cursor-pointer"
data-type="all">All</Token
>
{
types.map((type) => (
<Token
class="filter-token hover:cursor-pointer"
data-type={slugify(type)}
>
{type}
</Token>
))
}
</div>
<div class="space-y-16 md:space-y-8"> <div class="space-y-16 md:space-y-8">
{ {
projects.map((project, index) => { projects.map((project, index) => {
@@ -23,6 +44,8 @@ const projects = (await getCollection("projects")).sort(
<ProjectCard <ProjectCard
project={project} project={project}
textOn={index % 2 === 0 ? "left" : "right"} textOn={index % 2 === 0 ? "left" : "right"}
data-type={slugify(project.data.type)}
class="project"
/> />
); );
}) })
@@ -32,3 +55,46 @@ const projects = (await getCollection("projects")).sort(
</section> </section>
</div> </div>
</MainLayout> </MainLayout>
<script>
function setUpFilters() {
const tokensContainer = document.querySelector("#filter-tokens");
if (!tokensContainer) return;
const tokens =
tokensContainer.querySelectorAll<HTMLElement>(".filter-token");
const projects = document.querySelectorAll<HTMLElement>(".project");
tokensContainer.addEventListener("click", (e) => {
const token = (e.target as Element).closest<HTMLElement>(".filter-token");
if (!token) return;
tokens.forEach((t) =>
t.classList.remove(
"bg-white",
"!text-primary",
"ring-primary",
"ring-2"
)
);
token.classList.add(
"bg-white",
"!text-primary",
"ring-primary",
"ring-2"
);
const type = token.dataset.type;
projects.forEach((project) => {
const match = type === "all" || project.dataset.type === type;
project.classList.toggle("hidden", !match);
});
});
}
setUpFilters();
document.addEventListener("astro:page-load", setUpFilters);
</script>