Allow filtering of projects
All checks were successful
Build and Deploy to Web Server / deploy (push) Successful in 15m24s
All checks were successful
Build and Deploy to Web Server / deploy (push) Successful in 15m24s
This commit is contained in:
@@ -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",
|
||||||
|
@@ -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>
|
||||||
|
Reference in New Issue
Block a user