107 lines
2.8 KiB
Plaintext
107 lines
2.8 KiB
Plaintext
---
|
|
import { getCollection } from 'astro:content';
|
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
import ProjectCard from '../../components/ProjectCard.astro';
|
|
|
|
const projects = (await getCollection('projects')).sort(
|
|
(a, b) => b.data.order - a.data.order
|
|
);
|
|
|
|
const categories = ['全部', '硬件', '软件', '通信', '机器人', '其他'];
|
|
---
|
|
|
|
<BaseLayout title="项目" description="电子、软件、通信与机器人方向的项目展示">
|
|
<section class="page-head">
|
|
<h1>项目</h1>
|
|
<p class="muted">电子工程、软件、通信与机器人方向的作品与产品。</p>
|
|
</section>
|
|
|
|
{
|
|
projects.length > 0 ? (
|
|
<>
|
|
<div class="filters mono" id="filters">
|
|
{categories.map((c) => (
|
|
<button class="filter" data-cat={c}>
|
|
{c}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<div class="grid" id="grid">
|
|
{projects.map((p) => (
|
|
<div class="grid-item" data-cat={p.data.category}>
|
|
<ProjectCard
|
|
title={p.data.title}
|
|
description={p.data.description}
|
|
category={p.data.category}
|
|
tags={p.data.tags}
|
|
href={`/projects/${p.id}`}
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</>
|
|
) : (
|
|
<p class="muted">
|
|
暂无项目。在 <code>src/content/projects/</code> 新建 Markdown 文件即可添加。
|
|
</p>
|
|
)
|
|
}
|
|
</BaseLayout>
|
|
|
|
<script>
|
|
const buttons = document.querySelectorAll<HTMLButtonElement>('.filter');
|
|
const items = document.querySelectorAll<HTMLElement>('.grid-item');
|
|
buttons[0]?.classList.add('active');
|
|
buttons.forEach((btn) => {
|
|
btn.addEventListener('click', () => {
|
|
buttons.forEach((b) => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
const cat = btn.dataset.cat;
|
|
items.forEach((item) => {
|
|
item.style.display =
|
|
cat === '全部' || item.dataset.cat === cat ? '' : 'none';
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.page-head {
|
|
padding: 3rem 0 1.5rem;
|
|
}
|
|
.page-head h1 {
|
|
margin: 0 0 0.5rem;
|
|
}
|
|
.filters {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.filter {
|
|
background: var(--bg-elev);
|
|
border: 1px solid var(--border);
|
|
color: var(--text-dim);
|
|
border-radius: 999px;
|
|
padding: 0.3rem 0.85rem;
|
|
font-size: 0.8rem;
|
|
font-family: var(--font-mono);
|
|
cursor: pointer;
|
|
transition: all 0.15s ease;
|
|
}
|
|
.filter:hover {
|
|
color: var(--text);
|
|
border-color: var(--border-strong);
|
|
}
|
|
.filter.active {
|
|
color: var(--accent-strong);
|
|
border-color: var(--accent-dim);
|
|
background: rgba(57, 208, 216, 0.1);
|
|
}
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
</style>
|