Files
AboutMe/src/pages/diary.astro
2026-02-02 22:47:52 +03:00

260 lines
8.4 KiB
Plaintext

---
import { LinkPresets } from "@constants/link-presets";
import { LinkPreset } from "@/types/config";
import { siteConfig } from "@/config";
import { sortedMoments } from "@/utils/diary";
import { i18n } from "@i18n/translation";
import I18nKey from "@i18n/i18nKey";
import GridLayout from "@layouts/grid.astro";
import BackwardButton from "@components/backwardButton.astro";
const pageTitle = LinkPresets[LinkPreset.Diary].name;
const pageDescription = LinkPresets[LinkPreset.Diary].description;
// 时间格式化函数
function formatTime(dateString: string): string {
var TG = 8;
if (siteConfig.timeZone >= -12 && siteConfig.timeZone <= 12) TG = siteConfig.timeZone;
const timeGap = TG;
const now = new Date();
const date = new Date(dateString);
const diffInMinutes = Math.floor(
(now.getTime() + timeGap*60*60*1000 - date.getTime()) / (1000 * 60),
);
if (diffInMinutes < 60) {
return `${diffInMinutes}${i18n(I18nKey.diaryMinutesAgo)}`;
}
if (diffInMinutes < 1440) {
// 24小时
const hours = Math.floor(diffInMinutes / 60);
return `${hours}${i18n(I18nKey.diaryHoursAgo)}`;
}
const days = Math.floor(diffInMinutes / 1440);
return `${days}${i18n(I18nKey.diaryDaysAgo)}`;
}
---
<GridLayout title={pageTitle} description={pageDescription}>
<div class="flex w-full rounded-(--radius-large) overflow-hidden relative min-h-32">
<div class="card-base z-10 px-4 py-4 md:px-6 md:py-5 relative w-full">
<BackwardButton currentPath={Astro.url.pathname} />
<div class="relative max-w-4xl">
<!-- 页面头部 -->
<div class="moments-header mb-6">
<div class="header-content">
<div class="header-info">
<h1 class="moments-title text-xl md:text-2xl lg:text-3xl font-bold text-90 mb-1">{pageTitle}</h1>
<p class="moments-subtitle text-sm md:text-base lg:text-lg text-75">{pageDescription}</p>
</div>
<div class="header-stats">
<div class="stat-item text-center">
<span class="stat-number text-lg md:text-xl lg:text-2xl font-bold text-(--primary)">{sortedMoments.length}</span>
<span class="stat-label text-xs md:text-sm lg:text-base text-75">{i18n(I18nKey.diaryCount)}</span>
</div>
</div>
</div>
</div>
<!-- 短文列表 -->
<div class="moments-timeline">
<div class="timeline-list space-y-4">
{sortedMoments.map(moment => (
<div class="moment-item card-base p-4 md:p-6 lg:p-8 hover:shadow-lg transition-all">
<div class="moment-content">
<p class="moment-text text-sm md:text-base lg:text-lg text-90 leading-relaxed mb-3 md:mb-4">{moment.content}</p>
{moment.images && moment.images.length > 0 && (
<div class="moment-images grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 md:gap-3 lg:gap-4 mb-3 md:mb-4">
{moment.images.map((image, index) => (
<div class="image-item relative rounded-md overflow-hidden aspect-square cursor-pointer hover:scale-105 transition">
<img
src={image}
alt={i18n(I18nKey.diaryImage)}
class="w-full h-full object-cover"
loading="lazy"
/>
</div>
))}
</div>
)}
</div>
<hr class="moment-divider border-t border-(--line-divider) my-3 md:my-4" />
<div class="moment-footer flex justify-between items-center">
<div class="moment-time flex items-center gap-1.5 text-75 text-xs md:text-sm lg:text-base">
<i class="time-icon text-xs md:text-sm">🕐</i>
<time datetime={moment.date}>
{formatTime(moment.date)}
</time>
</div>
</div>
</div>
))}
</div>
</div>
<!-- 底部提示 -->
<div class="moments-tips text-center mt-6 md:mt-8 lg:mt-10 text-75 text-xs md:text-sm lg:text-base italic">
{i18n(I18nKey.diaryTips)}
</div>
</div>
</div>
</div>
</GridLayout>
<style>
.card-base {
background: var(--card-bg);
border: 1px solid var(--line-divider);
transition: all 0.3s ease;
}
.moments-header {
padding: 1rem;
border-radius: 8px;
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark, var(--primary)) 100%);
color: white;
position: relative;
overflow: hidden;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
z-index: 1;
}
.moments-title {
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.moments-subtitle {
color: rgba(255, 255, 255, 0.9);
}
.stat-number {
color: white;
}
.stat-label {
color: rgba(255, 255, 255, 0.8);
}
.image-item img {
transition: scale 0.3s ease;
}
.image-item:hover img {
scale: 1.05;
}
.action-btn {
background: none;
border: none;
cursor: pointer;
color: var(--text-muted);
}
.action-btn:hover {
color: var(--primary);
}
/* 让内容中的换行符生效(\n -> 换行) */
.moment-text {
white-space: pre-line;
}
/* 响应式设计 */
/* 桌面端 (大于1280px) */
@media (min-width: 1280px) {
.moments-header {
padding: 1.5rem;
}
.moment-item {
padding: 2rem;
}
.moment-images {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
max-width: 600px;
gap: 1rem;
}
.moment-text {
font-size: 1.1rem;
line-height: 1.8;
}
}
/* 平板竖屏 (768px - 1279px) - 优化显示 */
@media (min-width: 768px) and (max-width: 1279px) {
.moments-header {
padding: 1.25rem;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.moment-item {
padding: 1.5rem;
}
.moment-images {
grid-template-columns: repeat(3, 1fr);
gap: 0.75rem;
max-width: 500px;
}
.moment-text {
font-size: 1rem;
line-height: 1.7;
}
.moment-footer {
margin-top: 1rem;
}
}
/* 手机端 (小于768px) */
@media (max-width: 768px) {
.moments-header {
padding: 0.75rem;
}
.header-content {
flex-direction: column;
text-align: center;
gap: 0.75rem;
}
.moment-images {
grid-template-columns: repeat(2, 1fr);
}
.moment-footer {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
}
/* 优化小屏幕显示 */
@media (max-width: 512px) {
.card-base {
margin: 0 -0.5rem;
}
.moment-item {
border-radius: 8px;
}
.moments-header {
border-radius: 6px;
}
}
</style>