1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
---
import { getCollection, type CollectionEntry } from 'astro:content';
import BaseLayout from '../../layouts/BaseLayout.astro';
import '../../styles/post.css';
import '../../styles/sitemap.css';
const allPosts = await getCollection('posts');
allPosts.sort((a: CollectionEntry<'posts'>, b: CollectionEntry<'posts'>) => b.data.date.localeCompare(a.data.date));
function formatDate(dateStr: string): string {
const [year, month, day] = dateStr.split('-').map(Number);
const d = new Date(year, month - 1, day);
return d.toLocaleDateString('en-US', { month: 'long', day: '2-digit', year: 'numeric' });
}
---
<BaseLayout title="Posts">
<div class="org-article-title">
<h1></h1>
<a href="/posts/feed.xml">RSS Feed</a>
</div>
<div id="tag-filter-container"></div>
<div id="content" class="content">
<ul class="org-ul" id="posts-list">
{allPosts.map((post: CollectionEntry<'posts'>) => (
<li data-tags={post.data.tags.join(',')}>
<p><a href={`/posts/${post.slug}`}>{post.data.title}</a></p>
<div class="sitemap_date"><p>{formatDate(post.data.date)}</p></div>
<div class="sitemap_tag"><p>{post.data.tags.join(',')}</p></div>
</li>
))}
</ul>
</div>
<script is:inline>
(function () {
const list = document.getElementById('posts-list');
const filterContainer = document.getElementById('tag-filter-container');
if (!list || !filterContainer) return;
const items = Array.from(list.querySelectorAll('li[data-tags]'));
// Collect unique tags
const tagSet = new Set();
items.forEach(item => {
const tags = item.getAttribute('data-tags') || '';
tags.split(',').filter(Boolean).forEach(t => tagSet.add(t.trim()));
});
if (tagSet.size === 0) return;
// Track which tags are enabled
const enabledTags = new Set(tagSet);
function applyFilter() {
items.forEach(item => {
const itemTags = (item.getAttribute('data-tags') || '')
.split(',')
.filter(Boolean)
.map(t => t.trim());
const visible = itemTags.some(t => enabledTags.has(t)) || itemTags.length === 0;
item.style.display = visible ? '' : 'none';
});
}
// Create filter buttons
tagSet.forEach(tag => {
const btn = document.createElement('span');
btn.textContent = tag;
btn.className = 'tag-filter-item';
btn.dataset.tag = tag;
btn.addEventListener('click', () => {
if (enabledTags.has(tag)) {
enabledTags.delete(tag);
btn.classList.add('disabled');
} else {
enabledTags.add(tag);
btn.classList.remove('disabled');
}
applyFilter();
});
filterContainer.appendChild(btn);
});
})();
</script>
</BaseLayout>
|