From 4e4279798196ed99860d03caa014f9ed70ebdc46 Mon Sep 17 00:00:00 2001 From: biss Date: Sat, 18 Jul 2026 11:39:53 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=BE=80=E5=B9=B4=E4=BB=8A=E6=97=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/OnThisDay.astro | 133 +++++++++++++ src/data/on-this-day.ts | 103 ++++++++++ src/data/photo-topics/events.ts | 11 +- src/data/photo-topics/graduation-day.ts | 10 +- src/data/photo-types.ts | 1 + src/data/timeline.ts | 9 +- src/pages/index.astro | 3 + src/styles/global.css | 244 ++++++++++++++++++++++++ 8 files changed, 508 insertions(+), 6 deletions(-) create mode 100644 src/components/OnThisDay.astro create mode 100644 src/data/on-this-day.ts diff --git a/src/components/OnThisDay.astro b/src/components/OnThisDay.astro new file mode 100644 index 0000000..70581d9 --- /dev/null +++ b/src/components/OnThisDay.astro @@ -0,0 +1,133 @@ +
+
+ + +
+
+
+

ON THIS DAY · 那年今日

+

今天,记忆翻到了这一页

+
+

正在寻找同月同日的班级记忆……

+
+ +
+ + + + +
+
+
+ + diff --git a/src/data/on-this-day.ts b/src/data/on-this-day.ts new file mode 100644 index 0000000..44777d2 --- /dev/null +++ b/src/data/on-this-day.ts @@ -0,0 +1,103 @@ +import { articles } from "./articles"; +import { photoTopics } from "./photos"; +import { timeline } from "./timeline"; + +export type MemoryKind = "event" | "photo" | "article"; + +export interface OnThisDayMemory { + id: string; + date: string; + monthDay: string; + year: number; + kind: MemoryKind; + kindLabel: string; + title: string; + text: string; + href: string; + image?: string; + external?: boolean; +} + +const kindLabels: Record = { + event: "班级事件", + photo: "旧照片", + article: "旧文章" +}; + +const toIsoDate = (year: number, month: number, day: number) => + `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`; + +const getTimelineDates = (label: string) => { + const match = label.match(/(\d{4})年(\d{1,2})月([^日]+)日/); + if (!match) return []; + + const [, yearText, monthText, dayText] = match; + return dayText + .split(/[、,,]/) + .map((value) => Number(value.match(/\d+/)?.[0])) + .filter((value) => Number.isInteger(value) && value >= 1 && value <= 31) + .map((day) => toIsoDate(Number(yearText), Number(monthText), day)); +}; + +const createMemory = ( + memory: Omit +): OnThisDayMemory => ({ + ...memory, + monthDay: memory.date.slice(5), + year: Number(memory.date.slice(0, 4)), + kindLabel: kindLabels[memory.kind] +}); + +const eventMemories = timeline.flatMap((moment, momentIndex) => + getTimelineDates(moment.date).map((date) => + createMemory({ + id: `event-${momentIndex}-${date}`, + date, + kind: "event", + title: moment.title, + text: moment.text, + href: "href" in moment && typeof moment.href === "string" ? moment.href : "/timeline/" + }) + ) +); + +const photoMemories = photoTopics.flatMap((topic) => + topic.photos.flatMap((photo, photoIndex) => + photo.date + ? [ + createMemory({ + id: `photo-${topic.slug}-${photoIndex}-${photo.date}`, + date: photo.date, + kind: "photo", + title: photo.title, + text: photo.caption, + href: `/gallery/${topic.slug}/`, + image: photo.image + }) + ] + : [] + ) +); + +const articleMemories = articles.map((article, articleIndex) => + createMemory({ + id: `article-${articleIndex}-${article.date}`, + date: article.date, + kind: "article", + title: article.title, + text: article.excerpt, + href: article.sourceUrl, + image: article.cover, + external: true + }) +); + +const kindOrder: Record = { + event: 0, + photo: 1, + article: 2 +}; + +export const onThisDayMemories = [...eventMemories, ...photoMemories, ...articleMemories].sort( + (left, right) => right.year - left.year || kindOrder[left.kind] - kindOrder[right.kind] +); diff --git a/src/data/photo-topics/events.ts b/src/data/photo-topics/events.ts index 840cf1e..a7db67d 100644 --- a/src/data/photo-topics/events.ts +++ b/src/data/photo-topics/events.ts @@ -10,7 +10,8 @@ export const eventsTopic: PhotoTopic = { { title: "高一下学期表彰大会", caption: "排练时觉得麻烦,回头看全是可爱。", - image: "https://pic.biss.click/image/50e233d6-dd88-4a10-bb2d-a42ace27cdec.jpg" + image: "https://pic.biss.click/image/50e233d6-dd88-4a10-bb2d-a42ace27cdec.jpg", + date: "2022-07-08" }, { title: "集体出游", @@ -20,13 +21,17 @@ export const eventsTopic: PhotoTopic = { { title: "百日誓师大会", caption: "高三的第一次全体活动,大家都很随意地在听讲,虽然最后还是没能坚持到最后。", - image: "https://pic.biss.click/image/45bfbe79-bd7b-40f3-9670-1b34cc0957b2.png" + image: "https://pic.biss.click/image/45bfbe79-bd7b-40f3-9670-1b34cc0957b2.png", + date: "2024-02-28" }, wechatPhoto(117, "考前舞台", "紧张的日子里,也需要一次大声唱出来。"), wechatPhoto(121, "看台上的我们", "一片红色校服,聚成高三最后的集体活动。"), wechatPhoto(129, "操场热身", "阳光很好,口号和动作都比平时更有力量。"), wechatPhoto(132, "坐在一起", "台上发生什么已经模糊,身边的人还记得。"), - wechatPhoto(176, "元旦歌咏", "整齐站上舞台,是青春里难得的郑重。"), + { + ...wechatPhoto(176, "元旦歌咏", "整齐站上舞台,是青春里难得的郑重。"), + date: "2021-12-31" + }, wechatPhoto(178, "领奖时刻", "证书会褪色,但被认可的那一刻不会。"), wechatPhoto(180, "操场挑战", "跨过栏架,也跨过一个个觉得做不到的瞬间。"), wechatPhoto(181, "百日倒计时", "数字揭开的那一刻,高考忽然变得很近。"), diff --git a/src/data/photo-topics/graduation-day.ts b/src/data/photo-topics/graduation-day.ts index 1817493..c44f891 100644 --- a/src/data/photo-topics/graduation-day.ts +++ b/src/data/photo-topics/graduation-day.ts @@ -32,13 +32,19 @@ export const graduationDayTopic: PhotoTopic = { caption: "那一刻大家都在笑,但心里都知道要分别了。", image: "https://pic.biss.click/image/f8d180c1-4827-4bfd-9550-4bfad4b97640.jpg" }, - wechatPhoto(145, "壮行合影", "红色班服、彩色气球,和出发前最完整的一次站在一起。"), + { + ...wechatPhoto(145, "壮行合影", "红色班服、彩色气球,和出发前最完整的一次站在一起。"), + date: "2024-06-06" + }, wechatPhoto(146, "气球升起之前", "所有人挤进镜头,等一个一起松手的瞬间。"), wechatPhoto(150, "飞向夏天", "气球越过教学楼,属于高中的倒计时也到了最后。"), wechatPhoto(151, "人群里的告别", "欢呼、拥抱和一句句被现场声音盖住的话。"), wechatPhoto(152, "穿过祝福", "从熟悉的人群中走过,前面就是新的路。"), wechatPhoto(153, "鲜花与笑脸", "最后一程依然有人在身旁鼓掌。"), - wechatPhoto(81, "毕业典礼合影", "红色幕布前,老师和同学一起留下毕业的证据。"), + { + ...wechatPhoto(81, "毕业典礼合影", "红色幕布前,老师和同学一起留下毕业的证据。"), + date: "2024-06-09" + }, wechatPhoto(84, "典礼现场", "从看台望向舞台,礼堂装下了整届人的夏天。"), wechatPhoto(85, "把花送给老师", "镜头拼在一起,也拼出那天的感谢。"), wechatPhoto(88, "走过红毯", "熟悉的老师站在两侧,目送这一届学生离开。"), diff --git a/src/data/photo-types.ts b/src/data/photo-types.ts index 27449b5..3df2047 100644 --- a/src/data/photo-types.ts +++ b/src/data/photo-types.ts @@ -2,6 +2,7 @@ export interface PhotoItem { title: string; caption: string; image: string; + date?: string; } export interface PhotoTopic { diff --git a/src/data/timeline.ts b/src/data/timeline.ts index f071066..041f165 100644 --- a/src/data/timeline.ts +++ b/src/data/timeline.ts @@ -3,7 +3,14 @@ export const timelineIntro = { text: "把三年里的班级大事按时间放在这里。军训、分班、网课、百日誓师、高考和毕业,都成为了后来回头看时很亮的节点。" }; -export const timeline = [ +export interface TimelineMoment { + date: string; + title: string; + text: string; + href?: string; +} + +export const timeline: TimelineMoment[] = [ { date: "2021年8月", title: "进入高中", diff --git a/src/pages/index.astro b/src/pages/index.astro index 44f26f9..ea81d9c 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,5 +1,6 @@ --- import BaseLayout from "../layouts/BaseLayout.astro"; +import OnThisDay from "../components/OnThisDay.astro"; import { galleryIntro, photoTopics } from "../data/photos"; import { featuredMessage, messages, messagesIntro } from "../data/messages"; import { people, peopleIntro } from "../data/people"; @@ -41,6 +42,8 @@ const previewPeople = people.slice(0, 6);
+ +
diff --git a/src/styles/global.css b/src/styles/global.css index 4d78cd4..97354a6 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -198,6 +198,225 @@ h1 { font-size: 14px; } +.on-this-day-band { + position: relative; + overflow: hidden; + background: + radial-gradient(circle at 8% 14%, rgba(232, 168, 76, 0.2), transparent 24%), + linear-gradient(135deg, #f6f0df, #fffdf7 48%, #eef4e9); +} + +.on-this-day-band::after { + content: ""; + position: absolute; + right: -80px; + bottom: -110px; + width: 280px; + height: 280px; + border: 1px solid rgba(55, 109, 90, 0.12); + border-radius: 50%; + box-shadow: + 0 0 0 34px rgba(55, 109, 90, 0.035), + 0 0 0 68px rgba(55, 109, 90, 0.025); + pointer-events: none; +} + +.on-this-day-shell { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: 150px minmax(0, 1fr); + gap: clamp(28px, 5vw, 64px); + align-items: start; +} + +.memory-date-card { + position: sticky; + top: 26px; + overflow: hidden; + border: 1px solid rgba(55, 109, 90, 0.2); + border-radius: 14px; + background: #fffdf7; + box-shadow: 0 18px 42px rgba(39, 55, 52, 0.11); + text-align: center; +} + +.memory-date-card span, +.memory-date-card small { + display: block; +} + +.memory-date-card span { + padding: 8px 12px; + background: var(--green); + color: #fffdf7; + font-size: 14px; + font-weight: 800; +} + +.memory-date-card strong { + display: block; + padding: 12px 12px 2px; + color: var(--ink); + font-family: Georgia, "Times New Roman", serif; + font-size: 62px; + line-height: 1; +} + +.memory-date-card small { + padding: 8px 12px 13px; + color: var(--muted); + font-size: 11px; + letter-spacing: 0.08em; +} + +.on-this-day-heading { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(240px, 0.8fr); + gap: clamp(20px, 4vw, 52px); + align-items: end; + margin-bottom: 30px; +} + +.on-this-day-heading .eyebrow { + color: var(--coral); +} + +.on-this-day-heading p:last-child { + margin: 0; + color: var(--muted); +} + +.memory-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px; +} + +.memory-card { + min-height: 190px; + display: grid; + grid-template-columns: 150px minmax(0, 1fr); + overflow: hidden; + border: 1px solid rgba(31, 43, 42, 0.12); + border-radius: 12px; + background: rgba(255, 255, 255, 0.82); + box-shadow: 0 8px 28px rgba(39, 55, 52, 0.06); + transition: transform 180ms ease, border-color 180ms ease, box-shadow 180ms ease; +} + +.memory-card:hover { + transform: translateY(-3px); + border-color: rgba(55, 109, 90, 0.34); + box-shadow: 0 16px 38px rgba(39, 55, 52, 0.12); +} + +.memory-card > img, +.memory-card-visual { + width: 100%; + height: 100%; + min-height: 190px; + object-fit: cover; +} + +.memory-card-visual { + display: grid; + place-items: center; + color: rgba(255, 253, 247, 0.9); + background: linear-gradient(135deg, rgba(55, 109, 90, 0.94), rgba(69, 111, 148, 0.88)); + font-family: STKaiti, KaiTi, serif; + font-size: 48px; +} + +.memory-card-copy { + min-width: 0; + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 20px; +} + +.memory-card-meta { + color: var(--coral); + font-size: 12px; + font-weight: 800; + letter-spacing: 0.04em; +} + +.memory-card-copy > strong { + margin-top: 7px; + font-size: 19px; + line-height: 1.35; +} + +.memory-card-text { + display: -webkit-box; + overflow: hidden; + margin-top: 8px; + color: var(--muted); + font-size: 13px; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.memory-card-action { + margin-top: auto; + padding-top: 14px; + color: var(--green); + font-size: 12px; + font-weight: 800; +} + +.memory-empty { + min-height: 190px; + display: grid; + grid-template-columns: auto minmax(0, 1fr); + gap: 22px; + align-items: center; + padding: clamp(24px, 4vw, 38px); + border: 1px dashed rgba(55, 109, 90, 0.3); + border-radius: 14px; + background: rgba(255, 255, 255, 0.56); +} + +.memory-empty[hidden], +.memory-grid[hidden] { + display: none; +} + +.memory-empty-mark { + color: var(--sun); + font-size: 48px; +} + +.memory-empty h3 { + margin: 0; + font-size: 22px; +} + +.memory-empty p, +.memory-noscript { + margin: 6px 0 0; + color: var(--muted); +} + +.memory-empty-links { + display: flex; + flex-wrap: wrap; + gap: 9px; + margin-top: 18px; +} + +.memory-empty-links a { + padding: 7px 12px; + border: 1px solid var(--line); + border-radius: 999px; + background: #fff; + color: var(--green); + font-size: 13px; + font-weight: 800; +} + main { overflow: hidden; } @@ -2227,6 +2446,8 @@ h2 { .stats, .section-title, + .on-this-day-shell, + .on-this-day-heading, .message-wall, .twikoo-sticky-wall .tk-comments, .twikoo-sticky-wall .tk-comments-container, @@ -2428,6 +2649,16 @@ h2 { padding-inline: 14px; } + .memory-card { + grid-template-columns: 1fr; + } + + .memory-card > img, + .memory-card-visual { + height: 190px; + min-height: 0; + } + .hero-actions { display: grid; } @@ -2442,6 +2673,19 @@ h2 { min-height: auto; } + .memory-date-card { + position: static; + width: 104px; + } + + .memory-date-card strong { + font-size: 48px; + } + + .memory-grid { + grid-template-columns: 1fr; + } + .photo-card, .photo-card:nth-child(2), .photo-card:nth-child(4) { From 85a21e23585e3a043766e718e79e193b68156b47 Mon Sep 17 00:00:00 2001 From: biss Date: Sat, 18 Jul 2026 11:51:56 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E6=94=B91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/OnThisDay.astro | 252 ++++++++++++++++++++++++-------- src/styles/global.css | 257 ++++++++++++++++++++++++++------- 2 files changed, 392 insertions(+), 117 deletions(-) diff --git a/src/components/OnThisDay.astro b/src/components/OnThisDay.astro index 70581d9..dabf21a 100644 --- a/src/components/OnThisDay.astro +++ b/src/components/OnThisDay.astro @@ -1,16 +1,26 @@
-