refactor(app): tighten chat and sync boundaries

This commit is contained in:
2026-07-01 14:03:25 +08:00
parent f6e7adbe96
commit 760e4fe343
19 changed files with 215 additions and 677 deletions
@@ -1,50 +0,0 @@
.panel {
min-height: 170px;
padding: 24px 16px 20px;
border-top: 1px solid rgba(246, 87, 160, 0.14);
background: #fff1f4;
}
.voiceCard {
width: 142px;
min-height: 153px;
padding: 12px 12px 14px;
border: 1px solid rgba(30, 30, 30, 0.08);
border-radius: 18px;
background: #ffffff;
box-shadow: 0 1px 2px rgba(30, 30, 30, 0.03);
color: #1e1e1e;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
.voiceCard:focus-visible {
outline: 2px solid var(--color-accent, #f84d96);
outline-offset: 3px;
}
.voiceIcon {
display: block;
width: 78px;
height: 78px;
object-fit: contain;
}
.voiceTitle,
.voiceMinutes {
font-family: var(--font-athelas), Athelas, serif;
font-size: 14px;
line-height: 1.08;
text-align: center;
}
.voiceTitle {
margin-top: 8px;
}
.voiceMinutes {
color: var(--color-accent, #f84d96);
}
@@ -1,37 +0,0 @@
"use client";
import Image from "next/image";
import styles from "./chat-input-action-panel.module.css";
export interface ChatInputActionPanelProps {
voiceMinutesRemaining: number;
onVoiceMessageClick?: () => void;
}
export function ChatInputActionPanel({
voiceMinutesRemaining,
onVoiceMessageClick,
}: ChatInputActionPanelProps) {
return (
<div className={styles.panel}>
<button
type="button"
className={styles.voiceCard}
onClick={onVoiceMessageClick}
aria-label={`Voice message, ${voiceMinutesRemaining} minutes remaining`}
>
<Image
src="/images/chat/ic_voicemessage_act.png"
alt=""
width={78}
height={78}
className={styles.voiceIcon}
aria-hidden="true"
/>
<span className={styles.voiceTitle}>voice message</span>
<span className={styles.voiceMinutes}>({voiceMinutesRemaining}min)</span>
</button>
</div>
);
}
@@ -1,4 +1,4 @@
/* ChatQuotaExhaustedBanner 游客配额耗尽横幅
/* ChatInsufficientCreditsBanner 积分不足横幅
* 视觉规格与设计稿对齐
* - 品红渐变背景 splash gradient 一致
* - 居中文案 + 渐变 pill 按钮
@@ -1,6 +1,6 @@
"use client";
/**
* ChatQuotaExhaustedBanner
* ChatInsufficientCreditsBanner
*
*
* - cannotSendReason="insufficient_credits"
@@ -8,38 +8,36 @@
* 稿
* - splash
* - /
* - pill /subscription
* - pill /subscription?type=topup
*
*
* - `src/app/sidebar/components/vip-benefits-card.tsx` "Activate VIP Membership"
* - VIP
* - top up
*
*
* - state machinechat UI
* - total<=0 "耗尽"
*/
import { useRouter } from "next/navigation";
import { ROUTES } from "@/router/routes";
import { ROUTE_BUILDERS } from "@/router/routes";
import styles from "./chat-quota-exhausted-banner.module.css";
import styles from "./chat-insufficient-credits-banner.module.css";
export interface ChatQuotaExhaustedBannerProps {
export interface ChatInsufficientCreditsBannerProps {
title?: string;
ctaLabel?: string;
/**
* router.push(ROUTES.subscription)
* router.push(topup subscription)
* - mock
* - nested overlay
*/
onUnlock?: () => void;
}
export function ChatQuotaExhaustedBanner({
export function ChatInsufficientCreditsBanner({
title = "Insufficient credits\nTop up to continue chatting",
ctaLabel = "Top up credits to continue",
onUnlock,
}: ChatQuotaExhaustedBannerProps) {
}: ChatInsufficientCreditsBannerProps) {
const router = useRouter();
const titleLines = title.split("\n");
@@ -48,7 +46,7 @@ export function ChatQuotaExhaustedBanner({
onUnlock();
return;
}
router.push(`${ROUTES.subscription}?type=vip`);
router.push(ROUTE_BUILDERS.subscription("topup"));
};
return (
@@ -56,7 +54,7 @@ export function ChatQuotaExhaustedBanner({
className={styles.banner}
role="status"
aria-live="polite"
data-testid="chat-quota-exhausted-banner"
data-testid="chat-insufficient-credits-banner"
>
<p className={styles.text}>
{titleLines.map((line, index) => (
+1 -2
View File
@@ -6,10 +6,9 @@ export * from "./ai-disclosure-banner";
export * from "./browser-hint-overlay";
export * from "./chat-area";
export * from "./chat-header";
export * from "./chat-input-action-panel";
export * from "./chat-insufficient-credits-banner";
export * from "./chat-input-bar";
export * from "./chat-input-text-field";
export * from "./chat-quota-exhausted-banner";
export * from "./chat-send-button";
export * from "./date-header";
export * from "./external-browser-dialog";