mirror of
https://github.com/StepanovPlaton/AboutMe.git
synced 2026-04-04 12:50:49 +04:00
260 lines
8.4 KiB
Plaintext
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> |