style(responsive): finish responsive token migration

This commit is contained in:
2026-07-03 11:19:27 +08:00
parent 489554cd78
commit e5bfb4e373
27 changed files with 132 additions and 98 deletions
@@ -55,8 +55,8 @@
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
width: var(--responsive-icon-size-md, 24px);
height: var(--responsive-icon-size-md, 24px);
color: var(--color-chevron-icon, #000000);
flex-shrink: 0;
}
+5 -4
View File
@@ -7,7 +7,7 @@ import styles from "./user-message-avatar.module.css";
export interface UserMessageAvatarProps {
avatarUrl?: string | null;
className?: string;
size?: number;
size?: number | string;
}
export function UserMessageAvatar({
@@ -17,6 +17,7 @@ export function UserMessageAvatar({
}: UserMessageAvatarProps) {
const avatarClassName = [styles.avatar, className].filter(Boolean).join(" ");
const avatarStyle = { width: size, height: size };
const imageSize = typeof size === "number" ? size : 64;
if (avatarUrl && avatarUrl.length > 0) {
return (
@@ -25,7 +26,7 @@ export function UserMessageAvatar({
style={avatarStyle}
aria-label="User avatar"
>
<Image src={avatarUrl} alt="" width={size} height={size} />
<Image src={avatarUrl} alt="" width={imageSize} height={imageSize} />
</div>
);
}
@@ -39,8 +40,8 @@ export function UserMessageAvatar({
<Image
src="/images/chat/pic-chat-guest.png"
alt="Guest"
width={size}
height={size}
width={imageSize}
height={imageSize}
/>
</div>
);
@@ -77,8 +77,8 @@
.spinner {
display: inline-block;
width: 18px;
height: 18px;
width: var(--responsive-spinner-size, 18px);
height: var(--responsive-spinner-size, 18px);
border-width: 2px;
border-style: solid;
border-color: var(--color-facebook-blue) transparent transparent transparent;
@@ -46,8 +46,8 @@
.spinner {
display: inline-block;
width: 18px;
height: 18px;
width: var(--responsive-spinner-size, 18px);
height: var(--responsive-spinner-size, 18px);
border-width: 2px;
border-style: solid;
border-color: #ffffff transparent transparent transparent;
@@ -13,7 +13,7 @@
}
.emoji {
font-size: 24px;
font-size: var(--responsive-icon-size-md, 24px);
line-height: 1;
}
@@ -26,5 +26,5 @@
color: #fff;
white-space: pre-line;
backdrop-filter: blur(10px);
max-width: 200px;
max-width: min(52vw, 200px);
}
+2 -2
View File
@@ -99,8 +99,8 @@
.typingDot {
display: inline-block;
width: 6px;
height: 6px;
width: var(--responsive-dot-size, 6px);
height: var(--responsive-dot-size, 6px);
border-radius: 50%;
background: currentColor;
margin: 0 2px;
@@ -18,7 +18,7 @@
width: 100%;
min-height: var(--chat-send-button-size, 40px);
max-height: min(30vh, 120px); /* 约 5 行 × 24px line-height */
padding: 6px 0 0 0; /* 上 6px让文字视觉下移,避开正中位置 */
padding: clamp(5px, 1.111vw, 6px) 0 0 0; /* 让文字视觉下移,避开正中位置 */
border: 0;
outline: none;
background: transparent;
@@ -86,7 +86,7 @@
display: flex;
min-width: 0;
flex-wrap: wrap;
gap: 5px;
gap: var(--responsive-inline-gap-xs, 5px);
align-items: baseline;
color: #241019;
font-size: var(--responsive-caption, 13px);
@@ -10,20 +10,20 @@
.bubble {
display: flex;
align-items: center;
gap: 4px;
gap: var(--responsive-inline-gap-xs, 4px);
padding: var(--spacing-3, 12px) var(--spacing-4, 16px);
background: #fff;
border-radius: var(--radius-xxl, 24px);
border-top-left-radius: 0;
min-width: 60px;
min-height: 40px;
min-width: var(--bubble-min-width, 60px);
min-height: clamp(38px, 7.407vw, 40px);
box-shadow: var(--shadow-input-box, 0 1px 2px rgba(0, 0, 0, 0.1));
}
.dot {
display: inline-block;
width: 8px;
height: 8px;
width: var(--responsive-dot-size, 8px);
height: var(--responsive-dot-size, 8px);
border-radius: 50%;
background: var(--color-text-foreground, #000);
animation: bounce 1.4s infinite ease-in-out both;
@@ -77,13 +77,13 @@
.wave {
display: flex;
align-items: center;
gap: 4px;
gap: var(--responsive-inline-gap-xs, 4px);
height: clamp(32px, 6.296vw, 34px);
}
.wave span {
display: block;
width: 4px;
width: clamp(3px, 0.741vw, 4px);
border-radius: 999px;
background: currentColor;
opacity: 0.72;
@@ -26,7 +26,7 @@
}
.title {
margin: 0 0 8px;
margin: 0 0 clamp(7px, 1.481vw, 8px);
color: var(--color-text-foreground, #171717);
font-size: var(--responsive-page-title, var(--font-size-22, 22px));
font-weight: 700;
@@ -64,7 +64,7 @@
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
gap: var(--responsive-inline-gap-xs, 4px);
padding:
clamp(9px, 1.852vw, 10px)
var(--responsive-card-padding, 16px);
@@ -56,6 +56,11 @@
0 12px 24px rgba(216, 132, 22, 0.2);
}
.heroIcon svg {
width: var(--responsive-icon-size-md, 24px);
height: var(--responsive-icon-size-md, 24px);
}
.eyebrow {
margin: var(--page-section-gap, 16px) 0 0;
color: #f657a0;
@@ -67,7 +72,7 @@
}
.title {
margin: 8px 0 0;
margin: clamp(6px, 1.481vw, 8px) 0 0;
color: #171114;
font-size: var(--responsive-page-title, 30px);
font-weight: 900;
@@ -118,7 +123,7 @@
}
.freeText {
margin: 5px 0 0;
margin: clamp(4px, 0.926vw, 5px) 0 0;
color: #7a6040;
font-size: var(--responsive-caption, 13px);
font-weight: 650;
@@ -162,6 +167,12 @@
color: #f657a0;
}
.freeIcon svg,
.ruleIcon svg {
width: var(--responsive-icon-size-sm, 18px);
height: var(--responsive-icon-size-sm, 18px);
}
.ruleContent {
min-width: 0;
}
@@ -176,8 +187,8 @@
.freeBadge {
display: inline-flex;
margin: 7px 0 0;
padding: 4px 9px;
margin: clamp(6px, 1.296vw, 7px) 0 0;
padding: var(--responsive-pill-padding-sm, 4px 9px);
border-radius: 999px;
background: #edf4ff;
color: #2e6eea;
+3 -3
View File
@@ -75,7 +75,7 @@ export function CoinsRulesScreen() {
<div className={styles.hero}>
<span className={styles.heroIcon} aria-hidden="true">
<FaCoins size={24} />
<FaCoins />
</span>
<p className={styles.eyebrow}>Coins Guide</p>
<h1 className={styles.title}>Coin Usage Rules</h1>
@@ -87,7 +87,7 @@ export function CoinsRulesScreen() {
<section className={styles.freeCard} aria-label="Free quota">
<div className={styles.freeIcon} aria-hidden="true">
<Gift size={20} strokeWidth={2.3} />
<Gift strokeWidth={2.3} />
</div>
<div>
<h2 className={styles.freeTitle}>Free Allowance</h2>
@@ -108,7 +108,7 @@ export function CoinsRulesScreen() {
style={{ animationDelay: `${index * 45}ms` }}
>
<span className={styles.ruleIcon} aria-hidden="true">
<Icon size={18} strokeWidth={2.35} />
<Icon strokeWidth={2.35} />
</span>
<div className={styles.ruleContent}>
<h2 className={styles.ruleTitle}>{rule.title}</h2>
@@ -78,7 +78,7 @@
}
.title {
margin: 8px 0 0;
margin: clamp(6px, 1.481vw, 8px) 0 0;
color: #171114;
font-size: var(--responsive-display-title, 34px);
font-weight: 920;
@@ -33,7 +33,7 @@
.text {
display: flex;
flex-direction: column;
gap: 4px;
gap: var(--sidebar-card-gap-y, 4px);
flex: 1 1 auto;
min-width: 0;
}
@@ -62,7 +62,7 @@
align-items: center;
gap: var(--spacing-xs, 4px);
align-self: flex-start;
padding: 3px var(--spacing-sm, 8px);
padding: var(--responsive-pill-padding-sm, 3px 8px);
border-radius: var(--radius-full, 999px);
background: var(--color-pill-bg, rgba(248, 77, 150, 0.10));
color: var(--color-accent, #f84d96);
@@ -72,8 +72,8 @@
}
.diamondIcon {
width: 14px;
height: 13px;
width: clamp(12px, 2.593vw, 14px);
height: clamp(11px, 2.407vw, 13px);
display: block;
flex-shrink: 0;
}
@@ -83,7 +83,7 @@
display: inline-flex;
align-items: center;
justify-content: center;
padding: 6px var(--spacing-lg, 16px);
padding: clamp(5px, 1.111vw, 6px) var(--spacing-lg, 16px);
border-radius: var(--radius-full, 999px);
background: linear-gradient(
90deg,
@@ -118,15 +118,15 @@
.skeletonMd {
width: 60%;
height: 18px;
height: clamp(16px, 3.333vw, 18px);
}
.skeletonSm {
width: 80%;
height: 14px;
height: clamp(12px, 2.593vw, 14px);
}
.skeletonXs {
width: 40%;
height: 14px;
height: clamp(12px, 2.593vw, 14px);
}
+1 -1
View File
@@ -54,7 +54,7 @@ export function UserHeader({
<UserMessageAvatar
avatarUrl={avatarUrl}
className={styles.avatar}
size={56}
size="var(--sidebar-avatar-size, 56px)"
/>
<div className={styles.text}>
@@ -1,7 +1,7 @@
.wrapper {
position: relative;
width: 100%;
height: 4px;
height: var(--responsive-inline-gap-xs, 4px);
border-radius: var(--radius-full);
background: rgba(255, 255, 255, 0.1);
overflow: hidden;
@@ -31,12 +31,12 @@
}
.header {
margin-bottom: 18px;
margin-bottom: var(--page-section-gap, 18px);
text-align: left;
}
.title {
margin: 0 0 8px;
margin: 0 0 clamp(7px, 1.481vw, 8px);
color: var(--color-text-foreground, #171717);
font-size: var(--responsive-page-title, 22px);
font-weight: 700;
@@ -53,7 +53,7 @@
.form {
display: flex;
flex-direction: column;
gap: 18px;
gap: var(--page-section-gap, 18px);
}
.error {
@@ -2,8 +2,8 @@
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px;
margin-left: -8px;
padding: var(--spacing-sm, 8px);
margin-left: calc(-1 * var(--spacing-sm, 8px));
color: #000;
text-decoration: none;
border-radius: var(--radius-md);
@@ -8,7 +8,7 @@
.header {
background-color: #fce4ec;
border-radius: 5px;
border-radius: clamp(5px, 1.111vw, 6px);
padding: var(--responsive-card-padding, var(--spacing-md));
text-align: center;
}
@@ -29,9 +29,9 @@
.notch {
position: absolute;
left: 50%;
bottom: -12px;
width: 24px;
height: 24px;
bottom: calc(var(--subscription-section-notch-size, 24px) / -2);
width: var(--subscription-section-notch-size, 24px);
height: var(--subscription-section-notch-size, 24px);
background: #fff3c8;
transform: translateX(-50%) rotate(45deg);
}
@@ -51,11 +51,19 @@
.row {
display: grid;
grid-template-columns: 48px minmax(0, 1fr) auto auto;
grid-template-columns:
var(--subscription-coin-column-width, 48px)
minmax(0, 1fr)
auto
auto;
align-items: center;
width: 100%;
min-height: var(--responsive-control-height, 48px);
padding: 8px 12px 8px 6px;
padding:
clamp(7px, 1.481vw, 8px)
clamp(10px, 2.222vw, 12px)
clamp(7px, 1.481vw, 8px)
clamp(5px, 1.111vw, 6px);
border: 1px solid transparent;
border-radius: var(--responsive-card-radius-sm, 18px);
background: #ffffff;
@@ -83,8 +91,8 @@
.coinIcon {
display: inline-flex;
width: 32px;
height: 32px;
width: var(--subscription-coin-icon-size, 32px);
height: var(--subscription-coin-icon-size, 32px);
align-items: center;
justify-content: center;
justify-self: center;
@@ -99,6 +107,8 @@
.coinIcon svg {
display: block;
width: var(--subscription-coin-svg-size, 18px);
height: var(--subscription-coin-svg-size, 18px);
}
.coins {
@@ -110,7 +120,7 @@
.offerBadge {
justify-self: end;
padding: 5px 9px;
padding: var(--subscription-offer-badge-padding, 5px 9px);
border-radius: 999px;
background: linear-gradient(135deg, #ff5fae 0%, #ff8a34 100%);
color: #ffffff;
@@ -123,7 +133,7 @@
.priceGroup {
display: inline-flex;
min-width: 54px;
min-width: clamp(48px, 10vw, 54px);
flex-direction: column;
align-items: flex-end;
justify-content: center;
@@ -149,26 +159,25 @@
@media (max-width: 360px) {
.title {
font-size: 20px;
font-size: var(--responsive-section-title, 20px);
}
.panel {
padding-right: 14px;
padding-left: 10px;
padding-right: clamp(10px, 2.593vw, 14px);
padding-left: clamp(10px, 2.222vw, 12px);
}
.row {
grid-template-columns: 46px minmax(0, 1fr) auto auto;
}
.coins,
.price {
font-size: 14px;
grid-template-columns:
clamp(42px, 8.519vw, 46px)
minmax(0, 1fr)
auto
auto;
}
.offerBadge {
padding-right: 6px;
padding-left: 6px;
font-size: 10px;
padding-right: clamp(6px, 1.296vw, 7px);
padding-left: clamp(6px, 1.296vw, 7px);
font-size: var(--responsive-micro, 10px);
}
}
@@ -46,7 +46,7 @@ export function SubscriptionCoinsOfferSection({
onClick={() => onSelectPlan(plan.id)}
>
<span className={styles.coinIcon} aria-hidden="true">
<FaCoins size={18} />
<FaCoins />
</span>
<span className={styles.coins}>{plan.coins} Coins</span>
{plan.isFirstRechargeOffer ? (
@@ -43,7 +43,7 @@
}
.title {
margin: 0 0 8px;
margin: 0 0 clamp(7px, 1.481vw, 8px);
color: var(--color-text-foreground, #171717);
font-size: var(--responsive-page-title, 22px);
font-weight: 700;
@@ -75,7 +75,7 @@
.perDayBar {
align-self: stretch;
margin: auto calc(-1 * var(--spacing-xs)) 0;
padding: 6px 0;
padding: clamp(5px, 1.111vw, 6px) 0;
border-radius: 0;
color: #ffffff;
font-size: var(--responsive-caption, var(--font-size-md));
@@ -61,7 +61,7 @@
}
.firstRechargeSubtitle {
margin: 4px 0 0;
margin: var(--responsive-inline-gap-xs, 4px) 0 0;
color: #75656d;
font-size: var(--responsive-micro, 12px);
font-weight: 700;
@@ -21,7 +21,7 @@
.title {
display: flex;
align-items: baseline;
gap: 10px;
gap: clamp(8px, 1.852vw, 10px);
margin: 0;
line-height: 1.25;
}
@@ -39,7 +39,7 @@
}
.subtitle {
margin: 8px 0 0;
margin: clamp(6px, 1.481vw, 8px) 0 0;
color: rgba(255, 255, 255, 0.9);
font-size: var(--responsive-body, 15px);
font-weight: 700;
@@ -49,9 +49,9 @@
.notch {
position: absolute;
left: 50%;
bottom: -12px;
width: 24px;
height: 24px;
bottom: calc(var(--subscription-section-notch-size, 24px) / -2);
width: var(--subscription-section-notch-size, 24px);
height: var(--subscription-section-notch-size, 24px);
background: #ff61ad;
transform: translateX(-50%) rotate(45deg);
}
@@ -61,7 +61,7 @@
z-index: 1;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: clamp(7px, 1.667vw, 9px);
gap: var(--subscription-plan-grid-gap, 9px);
padding:
var(--responsive-card-padding, 18px)
clamp(8px, 1.852vw, 10px)
@@ -72,11 +72,14 @@
position: relative;
display: flex;
min-width: 0;
min-height: clamp(116px, 23.704vw, 128px);
min-height: var(--subscription-plan-card-min-height, 128px);
flex-direction: column;
align-items: center;
justify-content: center;
padding: clamp(10px, 2.222vw, 12px) 6px clamp(9px, 2.037vw, 11px);
padding:
clamp(10px, 2.222vw, 12px)
clamp(5px, 1.111vw, 6px)
clamp(9px, 2.037vw, 11px);
border: 1px solid rgba(246, 87, 160, 0.08);
border-radius: var(--responsive-card-radius-sm, 20px);
background: #ffffff;
@@ -110,10 +113,10 @@
.offerBadge {
position: absolute;
top: 8px;
top: clamp(6px, 1.481vw, 8px);
left: 50%;
max-width: calc(100% - 12px);
padding: 4px 8px;
padding: var(--subscription-offer-badge-padding, 4px 8px);
border-radius: 999px;
background: linear-gradient(135deg, #ff5fae 0%, #ff8a34 100%);
color: #ffffff;
@@ -127,7 +130,7 @@
.planTitle {
margin-top: 20px;
font-size: clamp(16px, 3.519vw, 19px);
font-size: var(--subscription-plan-title-size, 19px);
font-weight: 800;
line-height: 1.15;
white-space: nowrap;
@@ -137,12 +140,12 @@
display: inline-flex;
align-items: flex-end;
justify-content: center;
margin-top: 4px;
margin-top: clamp(3px, 0.741vw, 4px);
line-height: 1;
}
.price {
font-size: var(--font-responsive-number-lg, 30px);
font-size: var(--subscription-price-size-lg, 30px);
font-weight: 500;
letter-spacing: -0.8px;
}
@@ -166,16 +169,7 @@
@media (max-width: 360px) {
.planGrid {
gap: 7px;
padding-right: 8px;
padding-left: 8px;
}
.planTitle {
font-size: 17px;
}
.price {
font-size: 27px;
padding-right: clamp(8px, 1.852vw, 10px);
padding-left: clamp(8px, 1.852vw, 10px);
}
}
+19
View File
@@ -39,6 +39,13 @@
--responsive-card-padding-lg: clamp(18px, 4.074vw, 22px);
--responsive-control-height: clamp(44px, 8.889vw, 48px);
--responsive-icon-button-size: clamp(38px, 8.148vw, 44px);
--responsive-icon-size-sm: clamp(14px, 2.963vw, 16px);
--responsive-icon-size-md: clamp(18px, 4.444vw, 24px);
--responsive-spinner-size: clamp(16px, 3.333vw, 18px);
--responsive-dot-size: clamp(6px, 1.481vw, 8px);
--responsive-inline-gap-xs: clamp(4px, 0.926vw, 5px);
--responsive-pill-padding-sm: clamp(3px, 0.741vw, 4px)
clamp(7px, 1.667vw, 9px);
/* Chat 专用响应式尺寸 */
--chat-inline-padding: clamp(14px, 3.704vw, 20px);
@@ -61,4 +68,16 @@
--font-responsive-lg: clamp(16px, 3.333vw, 18px);
--font-responsive-xl: clamp(18px, 3.704vw, 20px);
--font-responsive-number-lg: clamp(24px, 5.556vw, 30px);
/* Subscription 专用响应式尺寸 */
--subscription-section-notch-size: clamp(18px, 4.444vw, 24px);
--subscription-plan-grid-gap: clamp(7px, 1.667vw, 9px);
--subscription-plan-card-min-height: clamp(108px, 23.704vw, 128px);
--subscription-plan-title-size: clamp(16px, 3.519vw, 19px);
--subscription-price-size-lg: clamp(24px, 5.556vw, 30px);
--subscription-offer-badge-padding: clamp(4px, 0.741vw, 5px)
clamp(7px, 1.481vw, 8px);
--subscription-coin-icon-size: clamp(28px, 5.926vw, 32px);
--subscription-coin-svg-size: clamp(16px, 3.333vw, 18px);
--subscription-coin-column-width: clamp(42px, 8.889vw, 48px);
}