Unify homepage panels and subscription actions
Some checks failed
docker-images / resolve-build-targets (push) Successful in 5s
ui-regression / playwright-regression (push) Failing after 11m59s
docker-images / build-and-push (admin) (push) Successful in 3s
docker-images / build-and-push (backend) (push) Successful in 3s
docker-images / build-and-push (frontend) (push) Successful in 58s
docker-images / submit-indexnow (push) Successful in 18s

This commit is contained in:
2026-04-04 00:05:38 +08:00
parent ad44dde886
commit 320595ee1c
5 changed files with 1005 additions and 786 deletions

View File

@@ -10,10 +10,10 @@ const { stats } = Astro.props;
<ul class="grid gap-3">
{stats.map((stat, index) => (
<li class="rounded-2xl border border-[var(--border-color)] bg-[linear-gradient(135deg,rgba(var(--primary-rgb),0.12),rgba(255,255,255,0.55))] px-4 py-4 shadow-[0_12px_32px_rgba(37,99,235,0.08)]">
<li class="terminal-panel-muted terminal-panel-accent terminal-interactive-card rounded-2xl px-4 py-4" style="--accent-rgb: var(--primary-rgb); --accent-color: var(--primary);">
<div class="flex items-center justify-between gap-4">
<div class="flex min-w-0 items-center gap-3">
<span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-transparent bg-[var(--primary)] text-[var(--terminal-bg)] shadow-[0_10px_24px_rgba(var(--primary-rgb),0.22)]">
<span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-[color:color-mix(in_oklab,var(--primary)_16%,var(--border-color))] bg-[linear-gradient(180deg,color-mix(in_oklab,var(--primary)_18%,var(--terminal-bg)),color-mix(in_oklab,var(--primary)_10%,var(--header-bg)))] text-[var(--primary)] shadow-[0_10px_24px_rgba(var(--text-rgb),0.06)]">
<span class="font-mono text-xs">{String(index + 1).padStart(2, '0')}</span>
</span>
<div class="min-w-0">
@@ -21,7 +21,7 @@ const { stats } = Astro.props;
<div class="mt-1 text-lg font-semibold text-[var(--title-color)]">{stat.value}</div>
</div>
</div>
<span class="h-10 w-px bg-[linear-gradient(180deg,transparent,rgba(var(--primary-rgb),0.3),transparent)]"></span>
<span class="h-10 w-px bg-[linear-gradient(180deg,transparent,rgba(var(--primary-rgb),0.22),transparent)]"></span>
</div>
</li>
))}

View File

@@ -155,13 +155,31 @@ const webPushAvailable = Boolean(webPushPublicKey);
<i class="fas fa-envelope-open-text"></i>
</span>
<span class="subscription-popup-channel-toggle-copy">
<span class="subscription-popup-channel-toggle-meta" aria-hidden="true">
<span class="subscription-popup-channel-toggle-tag">可选</span>
<span class="subscription-popup-channel-toggle-tag subscription-popup-channel-toggle-tag--email">
Email
</span>
</span>
<span class="subscription-popup-channel-toggle-title" data-subscription-popup-channel-toggle-label>
开启邮件订阅
添加邮件订阅
</span>
<span class="subscription-popup-channel-toggle-description">
需要时再补一个邮箱备份
<span
class="subscription-popup-channel-toggle-description"
data-subscription-popup-channel-toggle-description
>
填写邮箱后,更新也会发到你的收件箱
</span>
</span>
<span class="subscription-popup-channel-toggle-affordance" aria-hidden="true">
<span
class="subscription-popup-channel-toggle-affordance-text"
data-subscription-popup-channel-toggle-affordance
>
去填写
</span>
<i class="fas fa-chevron-right"></i>
</span>
</button>
</div>
</div>
@@ -376,6 +394,12 @@ const webPushAvailable = Boolean(webPushPublicKey);
const emailToggleLabel = emailToggleButton?.querySelector(
'[data-subscription-popup-channel-toggle-label]',
) as HTMLElement | null;
const emailToggleDescription = emailToggleButton?.querySelector(
'[data-subscription-popup-channel-toggle-description]',
) as HTMLElement | null;
const emailToggleAffordance = emailToggleButton?.querySelector(
'[data-subscription-popup-channel-toggle-affordance]',
) as HTMLElement | null;
const browserCard = root.querySelector(
'[data-subscription-popup-channel-card="browser"]',
) as HTMLElement | null;
@@ -572,7 +596,17 @@ const webPushAvailable = Boolean(webPushPublicKey);
emailInput.required = emailSelected;
if (emailToggleLabel instanceof HTMLElement) {
emailToggleLabel.textContent = emailSelected ? '收起邮件订阅' : '开启邮件订阅';
emailToggleLabel.textContent = emailSelected ? '收起邮件订阅' : '添加邮件订阅';
}
if (emailToggleDescription instanceof HTMLElement) {
emailToggleDescription.textContent = emailSelected
? '邮箱表单已经展开,填好后提交即可作为额外备份'
: '填写邮箱后,更新也会发到你的收件箱';
}
if (emailToggleAffordance instanceof HTMLElement) {
emailToggleAffordance.textContent = emailSelected ? '收起' : '去填写';
}
setToggleState(emailToggleButton, emailSelected, !browserRequired);
@@ -1210,6 +1244,43 @@ const webPushAvailable = Boolean(webPushPublicKey);
display: grid;
gap: 0.18rem;
min-width: 0;
flex: 1;
}
.subscription-popup-channel-toggle-meta {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
margin-bottom: 0.1rem;
}
.subscription-popup-channel-toggle-tag {
display: inline-flex;
align-items: center;
border-radius: 999px;
border: 1px solid color-mix(in oklab, var(--border-color) 88%, transparent);
background: color-mix(in oklab, var(--header-bg) 84%, transparent);
color: var(--text-tertiary);
padding: 0.15rem 0.45rem;
font-size: 0.66rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
white-space: nowrap;
}
.subscription-popup-channel-toggle-tag--email {
color: color-mix(in oklab, var(--secondary, var(--primary)) 62%, var(--title-color));
border-color: color-mix(
in oklab,
var(--secondary, var(--primary)) 22%,
var(--border-color)
);
background: color-mix(
in oklab,
var(--secondary, var(--primary)) 11%,
var(--terminal-bg)
);
}
.subscription-popup-channel-toggle-title {
@@ -1227,6 +1298,27 @@ const webPushAvailable = Boolean(webPushPublicKey);
line-height: 1.55;
}
.subscription-popup-channel-toggle-affordance {
display: inline-flex;
align-items: center;
gap: 0.45rem;
margin-left: auto;
align-self: center;
color: color-mix(in oklab, var(--secondary, var(--primary)) 58%, var(--title-color));
font-size: 0.78rem;
font-weight: 700;
line-height: 1;
white-space: nowrap;
transition:
color 0.2s ease,
transform 0.2s ease;
}
.subscription-popup-channel-toggle-affordance i {
font-size: 0.72rem;
transition: transform 0.2s ease;
}
.subscription-popup-channel-toggle:hover {
transform: translateY(-1px);
border-color: color-mix(in oklab, var(--primary) 22%, var(--border-color));
@@ -1234,6 +1326,10 @@ const webPushAvailable = Boolean(webPushPublicKey);
box-shadow: 0 14px 28px rgba(var(--text-rgb), 0.08);
}
.subscription-popup-channel-toggle:hover .subscription-popup-channel-toggle-affordance {
transform: translateX(1px);
}
.subscription-popup-channel-toggle.is-active {
border-color: color-mix(in oklab, var(--primary) 28%, var(--border-color));
background:
@@ -1252,6 +1348,10 @@ const webPushAvailable = Boolean(webPushPublicKey);
background: color-mix(in oklab, var(--primary) 16%, var(--terminal-bg));
}
.subscription-popup-channel-toggle.is-active .subscription-popup-channel-toggle-affordance i {
transform: rotate(90deg);
}
.subscription-popup-channel-toggle--primary {
border-color: color-mix(in oklab, var(--primary) 48%, var(--border-color));
background:

View File

@@ -10,9 +10,9 @@ const { items } = Astro.props;
<ul class="grid grid-cols-1 gap-3 sm:grid-cols-2">
{items.map((item) => (
<li class="group overflow-hidden rounded-2xl border border-[var(--border-color)] bg-[var(--terminal-bg)] shadow-[0_12px_30px_rgba(37,99,235,0.08)] transition-transform duration-200 hover:-translate-y-0.5">
<li class="terminal-panel-muted terminal-panel-accent terminal-interactive-card group overflow-hidden rounded-2xl" style="--accent-rgb: var(--primary-rgb); --accent-color: var(--primary);">
<div class="flex items-start gap-3 px-4 py-4">
<span class="mt-0.5 flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-[var(--primary)] text-white shadow-[0_10px_24px_rgba(37,99,235,0.24)]">
<span class="mt-0.5 flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-[color:color-mix(in_oklab,var(--primary)_14%,var(--border-color))] bg-[linear-gradient(180deg,color-mix(in_oklab,var(--primary)_16%,var(--terminal-bg)),color-mix(in_oklab,var(--primary)_9%,var(--header-bg)))] text-[var(--primary)] shadow-[0_10px_24px_rgba(var(--text-rgb),0.06)]">
<i class="fas fa-code text-xs"></i>
</span>
<span class="min-w-0 flex-1">

File diff suppressed because it is too large Load Diff

View File

@@ -284,6 +284,17 @@ const homeSidebarCopy = isEnglish
statsDesc: '轻量围观一下站内气氛,不必知道太多。',
aiBriefTitle: '站点便签',
};
const homeAboutSectionCopy = isEnglish
? {
techDesc: 'The main tools and frameworks currently carrying the site and its content flow.',
metricsDesc: 'Site scale and basic signals, shown with the same terminal panel language as the rest of the page.',
apiAlert: 'home / api alert',
}
: {
techDesc: '当前页面和内容背后常用的技术组合。',
metricsDesc: '用同一套终端面板看站内规模,不再突然切回普通信息块。',
apiAlert: 'home / api alert',
};
const primaryQuickLinks = [
{ icon: 'fa-file-code', text: t('nav.articles'), href: '/articles' },
{ icon: 'fa-folder', text: t('nav.categories'), href: '/categories' },
@@ -385,8 +396,14 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs);
{apiError && (
<div class="mb-8 px-4">
<div class="ml-4 p-4 rounded-lg border border-[var(--danger)]/20 bg-[var(--danger)]/10 text-[var(--danger)] text-sm">
{apiError}
<div class="terminal-panel-muted ml-4 flex items-start gap-3 border-[color:color-mix(in_oklab,var(--danger)_24%,var(--border-color))] bg-[linear-gradient(180deg,color-mix(in_oklab,var(--danger)_8%,var(--terminal-bg)),color-mix(in_oklab,var(--danger)_4%,var(--header-bg)))] px-4 py-4 text-sm text-[var(--danger)]">
<span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-[color:color-mix(in_oklab,var(--danger)_24%,var(--border-color))] bg-[color:color-mix(in_oklab,var(--danger)_12%,var(--terminal-bg))]">
<i class="fas fa-triangle-exclamation"></i>
</span>
<div class="min-w-0 space-y-1">
<p class="text-[11px] font-mono uppercase tracking-[0.2em] text-[var(--text-tertiary)]">{homeAboutSectionCopy.apiAlert}</p>
<p class="leading-7 text-[var(--danger)]">{apiError}</p>
</div>
</div>
</div>
)}
@@ -854,19 +871,54 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs);
<div id="about" class="px-4">
<CommandPrompt command={t('home.promptAbout')} />
<div class="ml-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 class="text-lg font-bold mb-3 text-[var(--title-color)]">{t('home.about')}</h3>
<p class="text-[var(--text-secondary)] mb-4">{siteSettings.ownerBio}</p>
<div class="grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1.22fr)_minmax(18rem,0.78fr)]">
<section class="terminal-panel space-y-5">
<div class="flex flex-wrap items-start justify-between gap-4">
<div class="space-y-2">
<span class="terminal-kicker w-fit">
<i class="fas fa-user-astronaut"></i>
home / profile
</span>
<div>
<h3 class="text-xl font-bold text-[var(--title-color)]">{t('home.about')}</h3>
<p class="mt-2 max-w-3xl text-sm leading-7 text-[var(--text-secondary)]">{siteSettings.ownerBio}</p>
</div>
</div>
<h3 class="text-lg font-bold mb-3 text-[var(--title-color)]">{t('home.techStack')}</h3>
<TechStackList items={techStack} />
</div>
<span class="terminal-stat-pill">
<i class="fas fa-code-branch text-[var(--primary)]"></i>
{t('common.postsCount', { count: allPosts.length })}
</span>
</div>
<div class="space-y-3">
<div class="flex items-center gap-3">
<span class="terminal-section-icon">
<i class="fas fa-layer-group"></i>
</span>
<div>
<h4 class="text-base font-semibold text-[var(--title-color)]">{t('home.techStack')}</h4>
<p class="text-sm text-[var(--text-secondary)]">{homeAboutSectionCopy.techDesc}</p>
</div>
</div>
<TechStackList items={techStack} />
</div>
</section>
<section class="terminal-panel space-y-4">
<div class="space-y-2">
<span class="terminal-kicker w-fit">
<i class="fas fa-chart-column"></i>
home / metrics
</span>
<div>
<h3 class="text-xl font-bold text-[var(--title-color)]">{t('home.systemStatus')}</h3>
<p class="mt-2 text-sm leading-7 text-[var(--text-secondary)]">{homeAboutSectionCopy.metricsDesc}</p>
</div>
</div>
<div>
<h3 class="text-lg font-bold mb-3 text-[var(--title-color)]">{t('home.systemStatus')}</h3>
<StatsList stats={systemStats} />
</div>
</section>
</div>
</div>
</div>