feat(sidebar): redesign sidebar UI with three user states (light theme)

Replace the dark sidebar theme with a light-themed three-state UI
matching the design references:

- guest  : pink "login" pill in user row, no status pill on VIP card,
           "Activate VIP Membership" button shown
- member : "VIP membership not activated" subtitle, no status pill,
           "Activate VIP Membership" button shown
- vip    : pink "VIP Member" pill with diamond icon, "Activated" pill
           in VIP card header, no Activate button

Decompose into BackBar, UserHeader, VipBenefitsCard, and VoicePackageCard
under src/app/sidebar/components/. Delete obsolete GuestPanel,
UserInfoCard, and VipCta.

Lift VIP_BENEFITS to a shared src/data/constants/vip-benefits.ts so the
sidebar and subscription page render identical benefit copy.

Add five sidebar tokens (--color-card-surface, --color-voice-gradient-*
--border-card, --shadow-card, --color-pill-bg) to src/tokens/colors.css.

Includes barrelsby regeneration for src/app/sidebar/components and
side-effect barrel updates under src/stores/{auth,chat,sidebar,user},
plus package-lock.json from npm install (required for lint/typecheck).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-16 10:25:04 +08:00
parent 0548a08cbb
commit e44cc7e2f3
22 changed files with 10240 additions and 559 deletions
@@ -1,302 +1,24 @@
/* ============================================================
* 侧边栏主屏幕(浅色主题)
* ============================================================ */
.shell {
display: flex;
flex-direction: column;
background: var(--color-sidebar-background, #0d0b14);
color: var(--color-text-primary, #ffffff);
background: var(--color-page-background, #ffffff);
color: var(--color-auth-text-primary, #333333);
min-height: 100dvh;
padding: var(--spacing-xxl, 24px) var(--spacing-lg, 16px);
padding: 0 var(--spacing-lg, 16px) var(--spacing-xxl, 24px);
box-sizing: border-box;
}
.backRow {
.userSlot {
padding: var(--spacing-md, 12px) 0;
}
.backLink {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs, 4px);
color: var(--color-text-primary, #ffffff);
text-decoration: none;
font-size: var(--font-size-lg, 16px);
font-weight: 400;
background: none;
border: 0;
padding: 0;
cursor: pointer;
.cardSlot {
padding: var(--spacing-sm, 8px) 0;
}
.backLink:hover {
opacity: 0.7;
}
.backIcon {
color: var(--color-text-primary, #ffffff);
flex-shrink: 0;
}
.backText {
color: var(--color-text-primary, #ffffff);
font-size: var(--font-size-lg, 16px);
font-weight: 400;
}
.settingsArea {
padding: 0;
display: flex;
flex-direction: column;
align-items: stretch;
gap: var(--spacing-lg, 16px);
}
/* 让 SettingsSection 适配深色侧边栏背景(覆盖 _components/core 里的硬编码浅色) */
.settingsArea :global(section) > h3 {
color: var(--color-text-secondary, #9e9e9e);
}
.settingsArea :global(ul) {
background: var(--color-bubble-background, #1a1625);
}
.settingsArea :global(li) {
background: transparent;
}
.settingsArea :global(button) {
color: var(--color-text-primary, #ffffff);
}
.settingsArea :global(button) span {
color: var(--color-text-primary, #ffffff);
}
.settingsArea :global(svg) {
color: var(--color-text-primary, #ffffff);
}
/* ============================================================
* 用户信息区
* ============================================================ */
.profileArea {
padding: 0;
display: flex;
flex-direction: column;
align-items: stretch;
gap: var(--spacing-lg, 16px);
width: 100%;
margin-top: var(--spacing-md, 12px);
}
.userInfoCard {
display: flex;
align-items: center;
gap: var(--spacing-md, 12px);
padding: var(--spacing-lg, 16px);
background: var(--color-bubble-background, #1a1625);
border-radius: var(--radius-xl, 16px);
color: var(--color-text-primary, #ffffff);
width: 100%;
box-sizing: border-box;
}
.userInfoAvatar {
border-radius: var(--radius-full, 999px);
object-fit: cover;
flex-shrink: 0;
}
.userInfoAvatarFallback {
width: 64px;
height: 64px;
border-radius: var(--radius-full, 999px);
background: var(--color-dark-gray, #2a2a2a);
color: var(--color-text-primary, #ffffff);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: var(--font-size-xl, 20px);
font-weight: 600;
flex-shrink: 0;
}
.userInfoText {
display: flex;
flex-direction: column;
gap: var(--spacing-xs, 4px);
flex: 1 1 auto;
min-width: 0;
}
.userInfoNameRow {
display: flex;
align-items: center;
gap: var(--spacing-sm, 8px);
min-width: 0;
}
.userInfoName {
font-size: var(--font-size-lg, 16px);
font-weight: 600;
color: var(--color-text-primary, #ffffff);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.userInfoEmail {
font-size: var(--font-size-sm, 12px);
color: var(--color-text-secondary, #9e9e9e);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.userInfoCoinRow {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs, 4px);
font-size: var(--font-size-sm, 12px);
color: var(--color-text-secondary, #9e9e9e);
margin-top: 2px;
}
.vipBadge {
display: inline-flex;
align-items: center;
padding: 2px var(--spacing-sm, 8px);
border-radius: var(--radius-full, 999px);
background: var(--color-accent, #f84d96);
color: var(--color-text-primary, #ffffff);
font-size: var(--font-size-xs, 10px);
font-weight: 700;
letter-spacing: 0.5px;
flex-shrink: 0;
text-transform: uppercase;
}
.vipCta {
display: flex;
align-items: center;
justify-content: center;
padding: var(--spacing-md, 12px) var(--spacing-lg, 16px);
border-radius: var(--radius-full, 999px);
background: linear-gradient(
90deg,
var(--color-button-gradient-start, #ff67e0),
var(--color-button-gradient-end, #ff52a2)
);
color: var(--color-text-primary, #ffffff);
font-size: var(--font-size-lg, 16px);
font-weight: 600;
border: 0;
cursor: pointer;
width: 100%;
text-decoration: none;
box-sizing: border-box;
}
.vipCta:hover {
opacity: 0.9;
}
.vipCta:focus-visible {
outline: 2px solid var(--color-accent, #f84d96);
outline-offset: 2px;
}
/* ============================================================
* 未登录态 GuestPanel
* ============================================================ */
.guestPanel {
display: flex;
flex-direction: column;
gap: var(--spacing-sm, 8px);
padding: var(--spacing-xl, 20px);
background: var(--color-bubble-background, #1a1625);
border-radius: var(--radius-xl, 16px);
color: var(--color-text-primary, #ffffff);
width: 100%;
box-sizing: border-box;
}
.guestTitle {
font-size: var(--font-size-xl, 18px);
font-weight: 600;
color: var(--color-text-primary, #ffffff);
margin: 0;
}
.guestSubtitle {
font-size: var(--font-size-sm, 12px);
color: var(--color-text-secondary, #9e9e9e);
margin: 0;
line-height: 1.5;
}
.guestActions {
display: flex;
flex-direction: column;
gap: var(--spacing-sm, 8px);
margin-top: var(--spacing-md, 12px);
}
.guestPrimaryLink {
display: flex;
align-items: center;
justify-content: center;
padding: var(--spacing-md, 12px) var(--spacing-lg, 16px);
border-radius: var(--radius-full, 999px);
background: linear-gradient(
90deg,
var(--color-button-gradient-start, #ff67e0),
var(--color-button-gradient-end, #ff52a2)
);
color: var(--color-text-primary, #ffffff);
font-size: var(--font-size-lg, 16px);
font-weight: 600;
text-decoration: none;
border: 0;
box-sizing: border-box;
}
.guestPrimaryLink:hover {
opacity: 0.9;
}
.guestSecondaryLink {
display: flex;
align-items: center;
justify-content: center;
padding: var(--spacing-md, 12px) var(--spacing-lg, 16px);
border-radius: var(--radius-full, 999px);
background: transparent;
color: var(--color-text-primary, #ffffff);
font-size: var(--font-size-lg, 16px);
font-weight: 600;
text-decoration: none;
border: 1px solid var(--color-dialog-border, rgba(255, 255, 255, 0.1));
box-sizing: border-box;
}
.guestSecondaryLink:hover {
background: var(--color-dark-gray, #2a2a2a);
}
/* ============================================================
* 骨架占位
* ============================================================ */
.skeleton {
display: block;
background: var(--color-dark-gray, #2a2a2a);
border-radius: var(--radius-md, 8px);
}
.skeletonMd {
width: 60%;
height: 18px;
}
.skeletonSm {
width: 80%;
height: 14px;
}
.skeletonXs {
width: 40%;
height: 14px;
.settingsSlot {
padding: var(--spacing-lg, 16px) 0 0;
}