File size: 5,297 Bytes
96dd062
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<script lang="ts">
import { onMount } from "svelte";

import I18nKey from "@/i18n/i18nKey";
import { i18n } from "@/i18n/translation";
import { getPostUrlBySlug } from "@/utils/url-utils";

export let tags: string[] = [];
export let categories: string[] = [];
export let sortedPosts: Post[] = [];

const params = new URLSearchParams(window.location.search);
tags = params.has("tag") ? params.getAll("tag") : [];
categories = params.has("category") ? params.getAll("category") : [];
const uncategorized = params.get("uncategorized");

interface Post {
	id: string;
	data: {
		title: string;
		tags: string[];
		category?: string | null;
		published: Date;
	};
}

interface Group {
	year: number;
	posts: Post[];
}

let groups: Group[] = [];

function formatDate(date: Date) {
	const month = (date.getMonth() + 1).toString().padStart(2, "0");
	const day = date.getDate().toString().padStart(2, "0");
	return `${month}-${day}`;
}

function formatTag(tagList: string[]) {
	return tagList.map((t) => `#${t}`).join(" ");
}

onMount(async () => {
	let filteredPosts: Post[] = sortedPosts;

	if (tags.length > 0) {
		filteredPosts = filteredPosts.filter(
			(post) =>
				Array.isArray(post.data.tags) &&
				post.data.tags.some((tag) => tags.includes(tag)),
		);
	}

	if (categories.length > 0) {
		filteredPosts = filteredPosts.filter(
			(post) => post.data.category && categories.includes(post.data.category),
		);
	}

	if (uncategorized) {
		filteredPosts = filteredPosts.filter((post) => !post.data.category);
	}

	// 按发布时间倒序排序,确保不受置顶影响
	filteredPosts = filteredPosts
		.slice()
		.sort((a, b) => b.data.published.getTime() - a.data.published.getTime());

	const grouped = filteredPosts.reduce(
		(acc, post) => {
			const year = post.data.published.getFullYear();
			if (!acc[year]) {
				acc[year] = [];
			}
			acc[year].push(post);
			return acc;
		},
		{} as Record<number, Post[]>,
	);

	const groupedPostsArray = Object.keys(grouped).map((yearStr) => ({
		year: Number.parseInt(yearStr, 10),
		posts: grouped[Number.parseInt(yearStr, 10)],
	}));

	groupedPostsArray.sort((a, b) => b.year - a.year);

	groups = groupedPostsArray;
});
</script>

<div class="card-base px-8 py-6">

    {#each groups as group}

        <div>

            <div class="flex flex-row w-full items-center h-15">

                <div class="w-[15%] md:w-[10%] transition text-2xl font-bold text-right text-75">

                    {group.year}

                </div>

                <div class="w-[15%] md:w-[10%]">

                    <div

                            class="h-3 w-3 bg-none rounded-full outline outline-(--primary) mx-auto

                  -outline-offset-2 z-50 outline-3"

                    ></div>

                </div>

                <div class="w-[70%] md:w-[80%] transition text-left text-50">

                    {group.posts.length} {i18n(group.posts.length === 1 ? I18nKey.postCount : I18nKey.postsCount)}

                </div>

            </div>



            {#each group.posts as post}

                <a

                        href={getPostUrlBySlug(post.id)}

                        aria-label={post.data.title}

                        class="group btn-plain block! h-10 w-full rounded-lg hover:text-[initial]"

                >

                    <div class="flex flex-row justify-start items-center h-full">

                        <!-- date -->

                        <div class="w-[15%] md:w-[10%] transition text-sm text-right text-50">

                            {formatDate(post.data.published)}

                        </div>



                        <!-- dot and line -->

                        <div class="w-[15%] md:w-[10%] relative dash-line h-full flex items-center">

                            <div

                                    class="transition-all mx-auto w-1 h-1 rounded group-hover:h-5

                       bg-[oklch(0.5_0.05_var(--hue))] group-hover:bg-(--primary)

                       outline outline-4 z-50

                       outline-(--card-bg)

                       group-hover:outline-(--btn-plain-bg-hover)

                       group-active:outline-(--btn-plain-bg-active)"

                            ></div>

                        </div>



                        <!-- post title -->

                        <div

                                class="w-[70%] md:max-w-[65%] md:w-[65%] text-left font-bold

                     group-hover:translate-x-1 transition-all group-hover:text-(--primary)

                     text-75 pr-8 whitespace-nowrap text-ellipsis overflow-hidden"

                        >

                            {post.data.title}

                        </div>



                        <!-- tag list -->

                        <div

                                class="hidden md:block md:w-[15%] text-left text-sm transition

                     whitespace-nowrap text-ellipsis overflow-hidden text-30"

                        >

                            {formatTag(post.data.tags)}

                        </div>

                    </div>

                </a>

            {/each}

        </div>

    {/each}

</div>