style(app): normalize tailwind utility syntax
This commit is contained in:
@@ -29,7 +29,7 @@ describe("chat Tailwind components", () => {
|
||||
);
|
||||
|
||||
expect(aiHtml).toContain('aria-label="AI avatar"');
|
||||
expect(aiHtml).toContain("size-[var(--chat-avatar-size,43px)]");
|
||||
expect(aiHtml).toContain("size-(--chat-avatar-size,43px)");
|
||||
expect(aiHtml).toContain("size-full object-cover");
|
||||
expect(aiHtml).toContain("%2Fimages%2Fchat%2Fpic-chat-elio.png");
|
||||
expect(userHtml).toContain('aria-label="User avatar"');
|
||||
@@ -97,7 +97,7 @@ describe("chat Tailwind components", () => {
|
||||
);
|
||||
|
||||
expect(activeHtml).toContain('aria-label="Send message"');
|
||||
expect(activeHtml).toContain("size-[var(--chat-send-button-size,40px)]");
|
||||
expect(activeHtml).toContain("size-(--chat-send-button-size,40px)");
|
||||
expect(activeHtml).toContain(
|
||||
"bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]",
|
||||
);
|
||||
@@ -124,7 +124,7 @@ describe("chat Tailwind components", () => {
|
||||
expect(openableHtml).toContain("rounded-tl-none");
|
||||
expect(openableHtml).toContain("block h-auto w-full object-cover");
|
||||
expect(openableHtml).toContain("data:image/png;base64,/chat-image.png");
|
||||
expect(paywalledHtml).toContain("scale-[1.04] blur-[8px]");
|
||||
expect(paywalledHtml).toContain("scale-104 blur-sm");
|
||||
expect(paywalledHtml).toContain(
|
||||
"bg-[linear-gradient(180deg,rgba(255,255,255,0.04)_0%,rgba(255,255,255,0.14)_100%)]",
|
||||
);
|
||||
@@ -149,7 +149,7 @@ describe("chat Tailwind components", () => {
|
||||
expect(html).toContain("Credits keep the conversation going.");
|
||||
expect(html).toContain('aria-label="Top up"');
|
||||
expect(html).toContain("bg-[linear-gradient(135deg,#f96ade_0%,#f657a0_100%)]");
|
||||
expect(html).toContain("active:scale-[0.98]");
|
||||
expect(html).toContain("active:scale-98");
|
||||
});
|
||||
|
||||
it("renders ChatHeader guest and member branches", () => {
|
||||
@@ -159,12 +159,12 @@ describe("chat Tailwind components", () => {
|
||||
);
|
||||
|
||||
expect(guestHtml).toContain('aria-label="Sign up to unlock more features"');
|
||||
expect(guestHtml).toContain("bg-[var(--color-accent,#f84d96)]");
|
||||
expect(guestHtml).toContain("size-[var(--icon-size-sm,16px)]");
|
||||
expect(guestHtml).toContain("bg-(--color-accent,#f84d96)");
|
||||
expect(guestHtml).toContain("size-(--icon-size-sm,16px)");
|
||||
expect(memberHtml).toContain("Offer");
|
||||
expect(memberHtml).toContain('aria-label="Menu"');
|
||||
expect(memberHtml).toContain("bg-[rgba(13,11,20,0.7)]");
|
||||
expect(memberHtml).toContain("size-[var(--icon-size-xl,32px)]");
|
||||
expect(memberHtml).toContain("size-(--icon-size-xl,32px)");
|
||||
});
|
||||
|
||||
it("renders ChatInputTextField with textarea utilities", () => {
|
||||
@@ -179,10 +179,10 @@ describe("chat Tailwind components", () => {
|
||||
|
||||
expect(html).toContain("<textarea");
|
||||
expect(html).toContain('aria-label="Message"');
|
||||
expect(html).toContain("min-h-[var(--chat-send-button-size,40px)]");
|
||||
expect(html).toContain("min-h-(--chat-send-button-size,40px)");
|
||||
expect(html).toContain("max-h-[min(30vh,120px)]");
|
||||
expect(html).toContain("caret-[var(--color-accent,#f84d96)]");
|
||||
expect(html).toContain("placeholder:text-[var(--color-text-hint,#757575)]");
|
||||
expect(html).toContain("caret-(--color-accent,#f84d96)");
|
||||
expect(html).toContain("placeholder:text-(--color-text-hint,#757575)");
|
||||
expect(html).toContain("Message Elio");
|
||||
expect(html).toContain("Hello");
|
||||
});
|
||||
@@ -202,8 +202,8 @@ describe("chat Tailwind components", () => {
|
||||
expect(html).toContain('aria-expanded="true"');
|
||||
expect(html).toContain('aria-label="Open elsewhere. Better experience"');
|
||||
expect(html).toContain("grid-cols-[auto_minmax(0,1fr)]");
|
||||
expect(html).toContain("backdrop-blur-[12px]");
|
||||
expect(html).toContain("hover:opacity-[0.94]");
|
||||
expect(html).toContain("backdrop-blur-md");
|
||||
expect(html).toContain("hover:opacity-94");
|
||||
expect(html).toContain("Open elsewhere");
|
||||
expect(html).toContain("Better experience");
|
||||
});
|
||||
@@ -217,10 +217,10 @@ describe("chat Tailwind components", () => {
|
||||
expect(html).toContain('aria-modal="true"');
|
||||
expect(html).toContain('aria-labelledby="pwa-dialog-title"');
|
||||
expect(html).toContain("fixed inset-0");
|
||||
expect(html).toContain("max-w-[var(--pwa-install-dialog-max-width,360px)]");
|
||||
expect(html).toContain("size-[var(--icon-size-86,86px)]");
|
||||
expect(html).toContain("min-h-[var(--pwa-button-height,44px)]");
|
||||
expect(html).toContain("text-[var(--color-pwa-button-text,#ffffff)]");
|
||||
expect(html).toContain("max-w-(--pwa-install-dialog-max-width,360px)");
|
||||
expect(html).toContain("size-(--icon-size-86,86px)");
|
||||
expect(html).toContain("min-h-(--pwa-button-height,44px)");
|
||||
expect(html).toContain("text-(--color-pwa-button-text,#ffffff)");
|
||||
expect(html).toContain("%2Fimages%2Ficons%2Ficon-add-to-home.png");
|
||||
expect(html).toContain("Add to Home Screen");
|
||||
expect(html).toContain("Cancel");
|
||||
@@ -251,12 +251,12 @@ describe("chat Tailwind components", () => {
|
||||
);
|
||||
|
||||
expect(html).toContain('aria-labelledby="history-unlock-title"');
|
||||
expect(html).toContain("z-[200]");
|
||||
expect(html).toContain("z-200");
|
||||
expect(html).toContain("Unlock previous messages?");
|
||||
expect(html).toContain("We found 3 locked messages");
|
||||
expect(html).toContain("Could not unlock history.");
|
||||
expect(html).toContain("Unlocking...");
|
||||
expect(html).toContain("text-[var(--color-pwa-button-text,#ffffff)]");
|
||||
expect(html).toContain("text-(--color-pwa-button-text,#ffffff)");
|
||||
expect(html).toContain("disabled");
|
||||
});
|
||||
|
||||
@@ -286,12 +286,12 @@ describe("chat Tailwind components", () => {
|
||||
);
|
||||
|
||||
expect(html).toContain('aria-labelledby="insufficient-credits-title"');
|
||||
expect(html).toContain("z-[220]");
|
||||
expect(html).toContain("z-220");
|
||||
expect(html).toContain("Not enough credits");
|
||||
expect(html).toContain("Balance");
|
||||
expect(html).toContain("Required");
|
||||
expect(html).toContain("Still needed");
|
||||
expect(html).toContain("text-[var(--color-pwa-button-text,#ffffff)]");
|
||||
expect(html).toContain("text-(--color-pwa-button-text,#ffffff)");
|
||||
expect(html).toContain("bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)]");
|
||||
expect(html).toContain("Top up now");
|
||||
});
|
||||
@@ -318,7 +318,7 @@ describe("chat Tailwind components", () => {
|
||||
);
|
||||
|
||||
expect(html).toContain('aria-labelledby="voice-unlock-options-title"');
|
||||
expect(html).toContain("z-[72]");
|
||||
expect(html).toContain("z-72");
|
||||
expect(html).toContain("Unlock voice message");
|
||||
expect(html).toContain("购买语音包");
|
||||
expect(html).toContain("开通 VIP");
|
||||
|
||||
@@ -30,7 +30,7 @@ const DEFAULT_TITLE = "Open in external browser";
|
||||
const DEFAULT_DESCRIPTION = "Find me more easily";
|
||||
const DEFAULT_AUTO_COLLAPSE_DELAY_MS = 3500;
|
||||
const OVERLAY_BASE_CLASS_NAME =
|
||||
"pointer-events-auto absolute right-[var(--spacing-2,8px)] top-[var(--spacing-2,8px)] z-20 box-border min-h-12 max-w-[min(74vw,260px)] cursor-pointer border border-[rgba(255,255,255,0.18)] bg-[linear-gradient(135deg,rgba(255,255,255,0.14),rgba(255,255,255,0.04)),var(--color-blur-background,rgba(13,11,20,0.86))] text-white shadow-[0_12px_28px_rgba(0,0,0,0.24),inset_0_1px_0_rgba(255,255,255,0.16)] backdrop-blur-[12px] backdrop-saturate-[1.2] transition-[border-color,box-shadow,opacity,padding,transform] duration-[180ms] [-webkit-tap-highlight-color:transparent] hover:-translate-y-px hover:border-[rgba(255,255,255,0.28)] hover:opacity-[0.94] hover:shadow-[0_14px_32px_rgba(0,0,0,0.28),inset_0_1px_0_rgba(255,255,255,0.18)] active:translate-y-px active:scale-[0.99] active:opacity-[0.88] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[rgba(255,255,255,0.88)]";
|
||||
"pointer-events-auto absolute right-(--spacing-2,8px) top-(--spacing-2,8px) z-20 box-border min-h-12 max-w-[min(74vw,260px)] cursor-pointer border border-[rgba(255,255,255,0.18)] bg-[linear-gradient(135deg,rgba(255,255,255,0.14),rgba(255,255,255,0.04)),var(--color-blur-background,rgba(13,11,20,0.86))] text-white shadow-[0_12px_28px_rgba(0,0,0,0.24),inset_0_1px_0_rgba(255,255,255,0.16)] backdrop-blur-md backdrop-saturate-120 transition-[border-color,box-shadow,opacity,padding,transform] duration-180 [-webkit-tap-highlight-color:transparent] hover:-translate-y-px hover:border-[rgba(255,255,255,0.28)] hover:opacity-94 hover:shadow-[0_14px_32px_rgba(0,0,0,0.28),inset_0_1px_0_rgba(255,255,255,0.18)] active:translate-y-px active:scale-99 active:opacity-88 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[rgba(255,255,255,0.88)]";
|
||||
const OVERLAY_EXPANDED_CLASS_NAME =
|
||||
"grid w-fit grid-cols-[auto_minmax(0,1fr)] items-center gap-2 rounded-[18px] px-2.5 py-2";
|
||||
const OVERLAY_COLLAPSED_CLASS_NAME =
|
||||
@@ -90,7 +90,7 @@ export function BrowserHintOverlay({
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span
|
||||
className="inline-flex size-[30px] items-center justify-center rounded-full bg-[rgba(255,255,255,0.15)] text-white shadow-[inset_0_1px_0_rgba(255,255,255,0.16)] transition-[background,transform] duration-[180ms]"
|
||||
className="inline-flex size-[30px] items-center justify-center rounded-full bg-[rgba(255,255,255,0.15)] text-white shadow-[inset_0_1px_0_rgba(255,255,255,0.16)] transition-[background,transform] duration-180"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<ExternalLink size={15} strokeWidth={2.4} />
|
||||
@@ -103,7 +103,7 @@ export function BrowserHintOverlay({
|
||||
}
|
||||
aria-hidden={!isExpanded}
|
||||
>
|
||||
<span className="break-words text-[var(--font-size-sm,12px)] font-extrabold leading-[1.25] text-white">
|
||||
<span className="break-words text-(length:--font-size-sm,12px) font-extrabold leading-[1.25] text-white">
|
||||
{title}
|
||||
</span>
|
||||
<span className="break-words text-[11px] font-semibold leading-[1.2] text-[rgba(255,255,255,0.72)]">
|
||||
|
||||
@@ -24,12 +24,12 @@ export function ChatHeader({ isGuest, offerBanner }: ChatHeaderProps) {
|
||||
<header className="flex shrink-0 flex-col items-stretch bg-transparent p-0">
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full cursor-pointer items-center justify-center gap-[var(--spacing-sm,8px)] border-0 bg-[var(--color-accent,#f84d96)] px-[var(--spacing-md,12px)] py-[var(--spacing-sm,8px)] text-center text-[var(--responsive-caption,var(--font-size-sm,12px))] font-medium text-white"
|
||||
className="flex w-full cursor-pointer items-center justify-center gap-(--spacing-sm,8px) border-0 bg-(--color-accent,#f84d96) px-(--spacing-md,12px) py-(--spacing-sm,8px) text-center text-(length:--responsive-caption,var(--font-size-sm,12px)) font-medium text-white"
|
||||
onClick={() => navigator.openAuth(ROUTES.chat)}
|
||||
aria-label="Sign up to unlock more features"
|
||||
>
|
||||
<Lock
|
||||
className="size-[var(--icon-size-sm,16px)]"
|
||||
className="size-(--icon-size-sm,16px)"
|
||||
size={16}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
@@ -43,16 +43,16 @@ export function ChatHeader({ isGuest, offerBanner }: ChatHeaderProps) {
|
||||
<header className="flex shrink-0 flex-col items-stretch bg-transparent p-0">
|
||||
{offerBanner}
|
||||
|
||||
<div className="ml-[var(--spacing-md,12px)] flex items-center justify-between px-[var(--spacing-md,12px)] py-[var(--spacing-sm,8px)]">
|
||||
<div className="ml-(--spacing-md,12px) flex items-center justify-between px-(--spacing-md,12px) py-(--spacing-sm,8px)">
|
||||
{/* 菜单按钮(点击 → push 到 /sidebar,与 Dart MenuButton 一致) */}
|
||||
<button
|
||||
type="button"
|
||||
className="flex cursor-pointer items-center justify-center rounded-[var(--radius-full,999px)] border-0 bg-[rgba(13,11,20,0.7)] p-[var(--spacing-sm,8px)] text-[var(--color-text-primary,#fff)]"
|
||||
className="flex cursor-pointer items-center justify-center rounded-(--radius-full,999px) border-0 bg-[rgba(13,11,20,0.7)] p-(--spacing-sm,8px) text-(--color-text-primary,#fff)"
|
||||
onClick={() => navigator.push(ROUTES.sidebar)}
|
||||
aria-label="Menu"
|
||||
>
|
||||
<Menu
|
||||
className="size-[var(--icon-size-xl,32px)]"
|
||||
className="size-(--icon-size-xl,32px)"
|
||||
size={24}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
@@ -63,7 +63,7 @@ export const ChatInputTextField = forwardRef<
|
||||
<div className="flex min-w-0 flex-auto items-center rounded-full bg-white px-(--spacing-lg,16px)">
|
||||
<textarea
|
||||
ref={innerRef}
|
||||
className="min-h-[var(--chat-send-button-size,40px)] max-h-[min(30vh,120px)] w-full min-w-0 flex-auto resize-none border-0 bg-transparent pb-0 pl-0 pr-0 pt-[clamp(5px,1.111vw,6px)] font-[inherit] text-[16px] leading-[clamp(22px,4.444vw,24px)] text-[var(--color-text-foreground,#000)] caret-[var(--color-accent,#f84d96)] outline-none placeholder:text-[var(--color-text-hint,#757575)]"
|
||||
className="min-h-(--chat-send-button-size,40px) max-h-[min(30vh,120px)] w-full min-w-0 flex-auto resize-none border-0 bg-transparent pb-0 pl-0 pr-0 pt-[clamp(5px,1.111vw,6px)] font-[inherit] text-[16px] leading-[clamp(22px,4.444vw,24px)] text-(--color-text-foreground,#000) caret-(--color-accent,#f84d96) outline-none placeholder:text-(--color-text-hint,#757575)"
|
||||
value={value}
|
||||
onChange={(e: FormEvent<HTMLTextAreaElement>) =>
|
||||
onChange(e.currentTarget.value)
|
||||
|
||||
@@ -49,12 +49,12 @@ export function ChatInsufficientCreditsBanner({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="mx-[var(--chat-inline-padding,16px)] mb-[var(--page-section-gap,16px)] shrink-0 rounded-[var(--responsive-card-radius-sm,24px)] bg-[linear-gradient(135deg,#f96ade_0%,#f657a0_100%)] px-[var(--responsive-card-padding,16px)] py-[var(--page-section-gap-lg,24px)] text-center shadow-[0_4px_16px_rgba(248,77,150,0.25)]"
|
||||
className="mx-(--chat-inline-padding,16px) mb-(--page-section-gap,16px) shrink-0 rounded-(--responsive-card-radius-sm,24px) bg-[linear-gradient(135deg,#f96ade_0%,#f657a0_100%)] px-(--responsive-card-padding,16px) py-(--page-section-gap-lg,24px) text-center shadow-[0_4px_16px_rgba(248,77,150,0.25)]"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
data-testid="chat-insufficient-credits-banner"
|
||||
>
|
||||
<p className="m-0 mb-[var(--spacing-sm,8px)] text-[var(--responsive-card-title,18px)] font-semibold leading-[1.4] text-white opacity-95">
|
||||
<p className="m-0 mb-(--spacing-sm,8px) text-(length:--responsive-card-title,18px) font-semibold leading-[1.4] text-white opacity-95">
|
||||
{titleLines.map((line, index) => (
|
||||
<span key={`${line}-${index}`}>
|
||||
{line}
|
||||
@@ -63,13 +63,13 @@ export function ChatInsufficientCreditsBanner({
|
||||
))}
|
||||
</p>
|
||||
{description ? (
|
||||
<p className="mx-auto mb-[var(--spacing-lg,16px)] mt-0 max-w-[min(100%,360px)] text-[var(--responsive-caption,14px)] font-semibold leading-[1.4] text-[rgba(255,255,255,0.88)]">
|
||||
<p className="mx-auto mb-(--spacing-lg,16px) mt-0 max-w-[min(100%,360px)] text-(length:--responsive-caption,14px) font-semibold leading-[1.4] text-[rgba(255,255,255,0.88)]">
|
||||
{description}
|
||||
</p>
|
||||
) : null}
|
||||
<button
|
||||
type="button"
|
||||
className="min-h-[var(--responsive-control-height,48px)] w-full cursor-pointer rounded-full border-0 bg-[linear-gradient(135deg,#ffb8e0_0%,#f57ec0_100%)] px-[var(--responsive-card-padding-lg,24px)] text-[var(--responsive-card-title,18px)] font-bold text-white shadow-[0_2px_8px_rgba(0,0,0,0.15)] transition-[box-shadow,transform] duration-150 hover:shadow-[0_4px_12px_rgba(0,0,0,0.2)] active:scale-[0.98]"
|
||||
className="min-h-(--responsive-control-height,48px) w-full cursor-pointer rounded-full border-0 bg-[linear-gradient(135deg,#ffb8e0_0%,#f57ec0_100%)] px-(--responsive-card-padding-lg,24px) text-(length:--responsive-card-title,18px) font-bold text-white shadow-[0_2px_8px_rgba(0,0,0,0.15)] transition-[box-shadow,transform] duration-150 hover:shadow-[0_4px_12px_rgba(0,0,0,0.2)] active:scale-98"
|
||||
onClick={handleClick}
|
||||
aria-label={ctaLabel}
|
||||
>
|
||||
|
||||
@@ -30,7 +30,7 @@ export function ChatSendButton({
|
||||
<button
|
||||
type="button"
|
||||
className={[
|
||||
"flex aspect-square size-[var(--chat-send-button-size,40px)] shrink-0 cursor-pointer items-center justify-center rounded-full border-0 bg-[var(--color-button-gradient-end,#fc69df)] text-white transition-[background,transform] duration-200 disabled:cursor-not-allowed disabled:opacity-40 focus-visible:bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]",
|
||||
"flex aspect-square size-(--chat-send-button-size,40px) shrink-0 cursor-pointer items-center justify-center rounded-full border-0 bg-(--color-button-gradient-end,#fc69df) text-white transition-[background,transform] duration-200 disabled:cursor-not-allowed disabled:opacity-40 focus-visible:bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]",
|
||||
isActive
|
||||
? "bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))]"
|
||||
: "bg-[#f8a8ce] text-[rgba(255,255,255,0.88)] shadow-none",
|
||||
@@ -49,7 +49,7 @@ export function ChatSendButton({
|
||||
aria-label="Send message"
|
||||
>
|
||||
<ArrowUp
|
||||
className="size-[var(--icon-size-xl,24px)] text-[length:var(--icon-size-xl,24px)] leading-none"
|
||||
className="size-(--icon-size-xl,24px) text-(length:--icon-size-xl,24px) leading-none"
|
||||
size={24}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
@@ -21,31 +21,31 @@ export function HistoryUnlockDialog({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[200] flex items-center justify-center bg-[rgba(0,0,0,0.5)] pb-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-bottom,0px))] pl-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-left,0px))] pr-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-right,0px))] pt-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-top,0px))]"
|
||||
className="fixed inset-0 z-200 flex items-center justify-center bg-[rgba(0,0,0,0.5)] pb-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-bottom,0px))] pl-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-left,0px))] pr-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-right,0px))] pt-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-top,0px))]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="history-unlock-title"
|
||||
>
|
||||
<div className="w-full max-w-[var(--pwa-install-dialog-max-width,360px)] rounded-[var(--responsive-card-radius,40px)] bg-[var(--color-page-background,#ffffff)] px-[var(--responsive-card-padding,16px)] pb-[var(--responsive-card-padding,16px)] pt-[var(--responsive-card-padding-lg,24px)] text-center shadow-[0_10px_20px_rgba(0,0,0,0.1)]">
|
||||
<div className="w-full max-w-(--pwa-install-dialog-max-width,360px) rounded-(--responsive-card-radius,40px) bg-(--color-page-background,#ffffff) px-(--responsive-card-padding,16px) pb-(--responsive-card-padding,16px) pt-(--responsive-card-padding-lg,24px) text-center shadow-[0_10px_20px_rgba(0,0,0,0.1)]">
|
||||
<h2
|
||||
id="history-unlock-title"
|
||||
className="m-0 mb-2.5 text-[var(--responsive-page-title,var(--font-size-22,22px))] font-bold leading-[1.2] text-[var(--color-text-foreground,#171717)]"
|
||||
className="m-0 mb-2.5 text-(length:--responsive-page-title,var(--font-size-22,22px)) font-bold leading-[1.2] text-(--color-text-foreground,#171717)"
|
||||
>
|
||||
Unlock previous messages?
|
||||
</h2>
|
||||
<p className="mx-[var(--responsive-card-padding-lg,24px)] mb-[var(--spacing-lg,16px)] mt-0 text-left text-[var(--responsive-body,var(--font-size-lg,16px))] leading-[1.5] text-[#393939]">
|
||||
<p className="mx-(--responsive-card-padding-lg,24px) mb-(--spacing-lg,16px) mt-0 text-left text-(length:--responsive-body,var(--font-size-lg,16px)) leading-[1.5] text-[#393939]">
|
||||
We found {lockedCount} locked messages in your chat history. You can
|
||||
unlock them now to continue the conversation with full context.
|
||||
</p>
|
||||
{errorMessage ? (
|
||||
<p className="mx-[var(--responsive-card-padding-lg,24px)] mb-[var(--spacing-lg,16px)] mt-0 text-left text-[var(--responsive-caption,var(--font-size-md,14px))] leading-[1.4] text-[#c0364c]">
|
||||
<p className="mx-(--responsive-card-padding-lg,24px) mb-(--spacing-lg,16px) mt-0 text-left text-(length:--responsive-caption,var(--font-size-md,14px)) leading-[1.4] text-[#c0364c]">
|
||||
{errorMessage}
|
||||
</p>
|
||||
) : null}
|
||||
<div className="flex w-full gap-[var(--spacing-md,12px)]">
|
||||
<div className="flex w-full gap-(--spacing-md,12px)">
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--pwa-button-height,44px)] flex-auto cursor-pointer items-center justify-center rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[var(--color-text-secondary,#9e9e9e)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-semibold text-[var(--color-pwa-button-text,#ffffff)] disabled:cursor-not-allowed disabled:opacity-72"
|
||||
className="flex min-h-(--pwa-button-height,44px) flex-auto cursor-pointer items-center justify-center rounded-(--radius-bottom-sheet,28px) border-0 bg-(--color-text-secondary,#9e9e9e) text-(length:--responsive-body,var(--font-size-lg,16px)) font-semibold text-(--color-pwa-button-text,#ffffff) disabled:cursor-not-allowed disabled:opacity-72"
|
||||
onClick={onClose}
|
||||
disabled={isLoading}
|
||||
>
|
||||
@@ -53,7 +53,7 @@ export function HistoryUnlockDialog({
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--pwa-button-height,44px)] flex-auto cursor-pointer items-center justify-center rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[linear-gradient(var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))] text-[var(--responsive-body,var(--font-size-lg,16px))] font-semibold text-[var(--color-pwa-button-text,#ffffff)] disabled:cursor-not-allowed disabled:opacity-72"
|
||||
className="flex min-h-(--pwa-button-height,44px) flex-auto cursor-pointer items-center justify-center rounded-(--radius-bottom-sheet,28px) border-0 bg-[linear-gradient(var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))] text-(length:--responsive-body,var(--font-size-lg,16px)) font-semibold text-(--color-pwa-button-text,#ffffff) disabled:cursor-not-allowed disabled:opacity-72"
|
||||
onClick={onConfirm}
|
||||
disabled={isLoading}
|
||||
>
|
||||
|
||||
@@ -26,7 +26,7 @@ export function ImageBubble({
|
||||
const canOpen = Boolean(messageId && onOpenImage);
|
||||
const imageClassName = [
|
||||
"block h-auto w-full object-cover",
|
||||
imagePaywalled ? "scale-[1.04] blur-[8px]" : "",
|
||||
imagePaywalled ? "scale-104 blur-sm" : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
@@ -38,7 +38,7 @@ export function ImageBubble({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative max-h-[var(--chat-media-size,220px)] max-w-[var(--chat-media-size,220px)] cursor-pointer overflow-hidden rounded-[var(--radius-lg,12px)] rounded-tl-none bg-[var(--color-bubble-background,#fff)]"
|
||||
className="relative max-h-(--chat-media-size,220px) max-w-(--chat-media-size,220px) cursor-pointer overflow-hidden rounded-(--radius-lg,12px) rounded-tl-none bg-(--color-bubble-background,#fff)"
|
||||
onClick={openImage}
|
||||
role={canOpen ? "button" : undefined}
|
||||
tabIndex={canOpen ? 0 : undefined}
|
||||
@@ -55,7 +55,7 @@ export function ImageBubble({
|
||||
messageId={messageId}
|
||||
remoteUrl={imageUrl}
|
||||
className={imageClassName}
|
||||
errorClassName="flex size-[var(--chat-media-size,220px)] items-center justify-center bg-[var(--color-bubble-background,#fff)] text-[var(--icon-size-xl,24px)] text-[var(--color-text-secondary,#9e9e9e)]"
|
||||
errorClassName="flex size-(--chat-media-size,220px) items-center justify-center bg-(--color-bubble-background,#fff) text-(length:--icon-size-xl,24px) text-(--color-text-secondary,#9e9e9e)"
|
||||
width={240}
|
||||
height={240}
|
||||
>
|
||||
|
||||
@@ -23,56 +23,56 @@ export function InsufficientCreditsDialog({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[220] flex items-center justify-center bg-[rgba(0,0,0,0.52)] pb-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-bottom,0px))] pl-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-left,0px))] pr-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-right,0px))] pt-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-top,0px))]"
|
||||
className="fixed inset-0 z-220 flex items-center justify-center bg-[rgba(0,0,0,0.52)] pb-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-bottom,0px))] pl-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-left,0px))] pr-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-right,0px))] pt-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-top,0px))]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="insufficient-credits-title"
|
||||
>
|
||||
<div className="w-full max-w-[var(--pwa-install-dialog-max-width,360px)] rounded-[var(--responsive-card-radius,36px)] border border-[rgba(246,87,160,0.16)] bg-[var(--color-page-background,#ffffff)] px-[var(--responsive-card-padding,18px)] pb-[var(--responsive-card-padding,18px)] pt-[var(--responsive-card-padding-lg,24px)] text-center shadow-[0_18px_46px_rgba(38,18,31,0.18)]">
|
||||
<div className="w-full max-w-(--pwa-install-dialog-max-width,360px) rounded-(--responsive-card-radius,36px) border border-[rgba(246,87,160,0.16)] bg-(--color-page-background,#ffffff) px-(--responsive-card-padding,18px) pb-(--responsive-card-padding,18px) pt-(--responsive-card-padding-lg,24px) text-center shadow-[0_18px_46px_rgba(38,18,31,0.18)]">
|
||||
<h2
|
||||
id="insufficient-credits-title"
|
||||
className="m-0 mb-2.5 text-[var(--responsive-page-title,var(--font-size-22,22px))] font-bold leading-[1.2] text-[var(--color-text-foreground,#171717)]"
|
||||
className="m-0 mb-2.5 text-(length:--responsive-page-title,var(--font-size-22,22px)) font-bold leading-[1.2] text-(--color-text-foreground,#171717)"
|
||||
>
|
||||
Not enough credits
|
||||
</h2>
|
||||
<p className="mx-[var(--spacing-md,12px)] mb-[var(--page-section-gap,18px)] mt-0 text-[var(--responsive-body,var(--font-size-lg,16px))] leading-[1.5] text-[#393939]">
|
||||
<p className="mx-(--spacing-md,12px) mb-(--page-section-gap,18px) mt-0 text-(length:--responsive-body,var(--font-size-lg,16px)) leading-[1.5] text-[#393939]">
|
||||
Top up your credits to unlock this message and keep the moment going.
|
||||
</p>
|
||||
|
||||
{showCreditDetail ? (
|
||||
<dl className="mb-[var(--page-section-gap,18px)] grid gap-[var(--spacing-sm,8px)] rounded-[var(--responsive-card-radius-sm,22px)] bg-[#fff4f9] p-[var(--spacing-md,12px)]">
|
||||
<div className="flex items-center justify-between gap-[var(--spacing-md,12px)] text-[var(--responsive-caption,var(--font-size-md,14px))] leading-[1.3] text-[#4a3b43]">
|
||||
<dl className="mb-(--page-section-gap,18px) grid gap-(--spacing-sm,8px) rounded-(--responsive-card-radius-sm,22px) bg-[#fff4f9] p-(--spacing-md,12px)">
|
||||
<div className="flex items-center justify-between gap-(--spacing-md,12px) text-(length:--responsive-caption,var(--font-size-md,14px)) leading-[1.3] text-[#4a3b43]">
|
||||
<dt className="m-0 font-medium">Balance</dt>
|
||||
<dd className="m-0 text-[var(--responsive-body,var(--font-size-lg,16px))] font-extrabold text-[#f657a0]">
|
||||
<dd className="m-0 text-(length:--responsive-body,var(--font-size-lg,16px)) font-extrabold text-[#f657a0]">
|
||||
{creditBalance}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-[var(--spacing-md,12px)] text-[var(--responsive-caption,var(--font-size-md,14px))] leading-[1.3] text-[#4a3b43]">
|
||||
<div className="flex items-center justify-between gap-(--spacing-md,12px) text-(length:--responsive-caption,var(--font-size-md,14px)) leading-[1.3] text-[#4a3b43]">
|
||||
<dt className="m-0 font-medium">Required</dt>
|
||||
<dd className="m-0 text-[var(--responsive-body,var(--font-size-lg,16px))] font-extrabold text-[#f657a0]">
|
||||
<dd className="m-0 text-(length:--responsive-body,var(--font-size-lg,16px)) font-extrabold text-[#f657a0]">
|
||||
{requiredCredits}
|
||||
</dd>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-[var(--spacing-md,12px)] text-[var(--responsive-caption,var(--font-size-md,14px))] leading-[1.3] text-[#4a3b43]">
|
||||
<div className="flex items-center justify-between gap-(--spacing-md,12px) text-(length:--responsive-caption,var(--font-size-md,14px)) leading-[1.3] text-[#4a3b43]">
|
||||
<dt className="m-0 font-medium">Still needed</dt>
|
||||
<dd className="m-0 text-[var(--responsive-body,var(--font-size-lg,16px))] font-extrabold text-[#f657a0]">
|
||||
<dd className="m-0 text-(length:--responsive-body,var(--font-size-lg,16px)) font-extrabold text-[#f657a0]">
|
||||
{shortfallCredits}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
) : null}
|
||||
|
||||
<div className="flex w-full gap-[var(--spacing-md,12px)]">
|
||||
<div className="flex w-full gap-(--spacing-md,12px)">
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--pwa-button-height,44px)] flex-auto cursor-pointer items-center justify-center rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[var(--color-text-secondary,#9e9e9e)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-bold text-[var(--color-pwa-button-text,#ffffff)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="flex min-h-(--pwa-button-height,44px) flex-auto cursor-pointer items-center justify-center rounded-(--radius-bottom-sheet,28px) border-0 bg-(--color-text-secondary,#9e9e9e) text-(length:--responsive-body,var(--font-size-lg,16px)) font-bold text-(--color-pwa-button-text,#ffffff) focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
onClick={onClose}
|
||||
>
|
||||
Later
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--pwa-button-height,44px)] flex-auto cursor-pointer items-center justify-center rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-bold text-[var(--color-pwa-button-text,#ffffff)] shadow-[0_6px_14px_rgba(246,87,160,0.28)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="flex min-h-(--pwa-button-height,44px) flex-auto cursor-pointer items-center justify-center rounded-(--radius-bottom-sheet,28px) border-0 bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)] text-(length:--responsive-body,var(--font-size-lg,16px)) font-bold text-(--color-pwa-button-text,#ffffff) shadow-[0_6px_14px_rgba(246,87,160,0.28)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
onClick={onConfirm}
|
||||
>
|
||||
Top up now
|
||||
|
||||
@@ -15,7 +15,7 @@ export function LockedImageMessageCard({
|
||||
}: LockedImageMessageCardProps) {
|
||||
return (
|
||||
<div
|
||||
className="w-[min(72vw,280px)] overflow-hidden rounded-[var(--responsive-card-radius-sm,18px)] rounded-tl-none border border-[rgba(246,87,160,0.2)] bg-white shadow-[0_4px_14px_rgba(246,87,160,0.14)]"
|
||||
className="w-[min(72vw,280px)] overflow-hidden rounded-(--responsive-card-radius-sm,18px) rounded-tl-none border border-[rgba(246,87,160,0.2)] bg-white shadow-[0_4px_14px_rgba(246,87,160,0.14)]"
|
||||
role="group"
|
||||
aria-label="Locked private image"
|
||||
>
|
||||
@@ -25,15 +25,15 @@ export function LockedImageMessageCard({
|
||||
<LockKeyhole size={19} aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="p-[var(--responsive-card-padding,14px)]">
|
||||
<p className="m-0 text-[var(--responsive-body,14px)] leading-[1.4] text-[#3c3b3b]">
|
||||
<div className="p-(--responsive-card-padding,14px)">
|
||||
<p className="m-0 text-(length:--responsive-body,14px) leading-[1.4] text-[#3c3b3b]">
|
||||
{hint && hint.length > 0
|
||||
? hint
|
||||
: "Elio sent you a locked image."}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-[var(--spacing-md,12px)] w-full cursor-pointer rounded-full border-0 bg-[linear-gradient(90deg,#ff67e0,#ff52a2)] px-[var(--spacing-md,12px)] py-[clamp(9px,1.852vw,10px)] text-[var(--responsive-body,14px)] font-bold text-white disabled:cursor-not-allowed disabled:opacity-65 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="mt-(--spacing-md,12px) w-full cursor-pointer rounded-full border-0 bg-[linear-gradient(90deg,#ff67e0,#ff52a2)] px-(--spacing-md,12px) py-[clamp(9px,1.852vw,10px)] text-(length:--responsive-body,14px) font-bold text-white disabled:cursor-not-allowed disabled:opacity-65 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
disabled={isUnlocking || !onUnlock}
|
||||
onClick={onUnlock}
|
||||
>
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface MessageAvatarProps {
|
||||
}
|
||||
|
||||
const AVATAR_CLASS_NAME =
|
||||
"flex size-[var(--chat-avatar-size,43px)] shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-[var(--color-avatar-border,#fbf3f5)] bg-[var(--color-avatar-border,#fbf3f5)] shadow-[var(--shadow-input-box,0_1px_2px_rgba(0,0,0,0.1))]";
|
||||
"flex size-(--chat-avatar-size,43px) shrink-0 items-center justify-center overflow-hidden rounded-full border-2 border-(--color-avatar-border,#fbf3f5) bg-(--color-avatar-border,#fbf3f5) shadow-(--shadow-input-box,0_1px_2px_rgba(0,0,0,0.1))";
|
||||
|
||||
export function MessageAvatar({ isFromAI, userAvatarUrl }: MessageAvatarProps) {
|
||||
if (isFromAI) {
|
||||
|
||||
@@ -15,24 +15,24 @@ export function PrivateMessageCard({
|
||||
}: PrivateMessageCardProps) {
|
||||
return (
|
||||
<div
|
||||
className="max-w-[min(72vw,280px)] rounded-[var(--responsive-card-radius-sm,18px)] rounded-tl-none border border-[rgba(246,87,160,0.2)] bg-[linear-gradient(180deg,rgba(255,244,248,0.95),rgba(255,255,255,0.95)),#ffffff] p-[var(--responsive-card-padding,14px)] text-[#3c3b3b] shadow-[0_4px_12px_rgba(246,87,160,0.12)]"
|
||||
className="max-w-[min(72vw,280px)] rounded-(--responsive-card-radius-sm,18px) rounded-tl-none border border-[rgba(246,87,160,0.2)] bg-[linear-gradient(180deg,rgba(255,244,248,0.95),rgba(255,255,255,0.95)),#ffffff] p-(--responsive-card-padding,14px) text-[#3c3b3b] shadow-[0_4px_12px_rgba(246,87,160,0.12)]"
|
||||
role="group"
|
||||
aria-label="Locked private message"
|
||||
>
|
||||
<div
|
||||
className="mb-[clamp(8px,1.852vw,10px)] flex size-[var(--responsive-icon-button-size,42px)] items-center justify-center rounded-full bg-[linear-gradient(135deg,#ff8fc7_0%,#f657a0_100%)] text-white"
|
||||
className="mb-[clamp(8px,1.852vw,10px)] flex size-(--responsive-icon-button-size,42px) items-center justify-center rounded-full bg-[linear-gradient(135deg,#ff8fc7_0%,#f657a0_100%)] text-white"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<LockKeyhole className="block" size={22} />
|
||||
</div>
|
||||
<p className="m-0 text-[var(--responsive-body,14px)] leading-[1.4] text-[#3c3b3b]">
|
||||
<p className="m-0 text-(length:--responsive-body,14px) leading-[1.4] text-[#3c3b3b]">
|
||||
{hint && hint.length > 0
|
||||
? hint
|
||||
: "Elio has a private message for you."}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-[var(--spacing-md,12px)] w-full cursor-pointer rounded-full border-0 bg-[linear-gradient(90deg,#ff67e0,#ff52a2)] px-[var(--spacing-md,12px)] py-[clamp(9px,1.852vw,10px)] text-[var(--responsive-body,14px)] font-bold text-white disabled:cursor-not-allowed disabled:opacity-65 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="mt-(--spacing-md,12px) w-full cursor-pointer rounded-full border-0 bg-[linear-gradient(90deg,#ff67e0,#ff52a2)] px-(--spacing-md,12px) py-[clamp(9px,1.852vw,10px)] text-(length:--responsive-body,14px) font-bold text-white disabled:cursor-not-allowed disabled:opacity-65 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
disabled={isUnlocking || !onUnlock}
|
||||
onClick={onUnlock}
|
||||
>
|
||||
|
||||
@@ -34,9 +34,9 @@ export function PwaInstallDialog({ onClose, onInstall }: PwaInstallDialogProps)
|
||||
aria-modal="true"
|
||||
aria-labelledby="pwa-dialog-title"
|
||||
>
|
||||
<div className="flex w-full max-w-[var(--pwa-install-dialog-max-width,360px)] flex-col items-center rounded-[var(--responsive-card-radius,40px)] bg-[var(--color-page-background,#ffffff)] px-[var(--responsive-card-padding,16px)] pb-[var(--responsive-card-padding,16px)] pt-[var(--responsive-card-padding-lg,20px)] text-center shadow-[0_10px_20px_rgba(0,0,0,0.1)]">
|
||||
<div className="flex w-full max-w-(--pwa-install-dialog-max-width,360px) flex-col items-center rounded-(--responsive-card-radius,40px) bg-(--color-page-background,#ffffff) px-(--responsive-card-padding,16px) pb-(--responsive-card-padding,16px) pt-(--responsive-card-padding-lg,20px) text-center shadow-[0_10px_20px_rgba(0,0,0,0.1)]">
|
||||
<Image
|
||||
className="mb-[var(--spacing-lg,16px)] size-[var(--icon-size-86,86px)] object-contain"
|
||||
className="mb-(--spacing-lg,16px) size-(--icon-size-86,86px) object-contain"
|
||||
src="/images/icons/icon-add-to-home.png"
|
||||
alt=""
|
||||
width={86}
|
||||
@@ -45,24 +45,24 @@ export function PwaInstallDialog({ onClose, onInstall }: PwaInstallDialogProps)
|
||||
/>
|
||||
<h2
|
||||
id="pwa-dialog-title"
|
||||
className="m-0 mb-[var(--spacing-sm,8px)] text-[var(--responsive-page-title,var(--font-size-22,22px))] font-bold leading-[1.2] text-[var(--color-text-foreground,#171717)]"
|
||||
className="m-0 mb-(--spacing-sm,8px) text-(length:--responsive-page-title,var(--font-size-22,22px)) font-bold leading-[1.2] text-(--color-text-foreground,#171717)"
|
||||
>
|
||||
Add to Home Screen
|
||||
</h2>
|
||||
<p className="mx-[var(--responsive-card-padding-lg,36px)] mb-[var(--page-section-gap-lg,24px)] mt-0 text-[var(--responsive-body,var(--font-size-lg,16px))] leading-[1.5] text-[#393939]">
|
||||
<p className="mx-(--responsive-card-padding-lg,36px) mb-(--page-section-gap-lg,24px) mt-0 text-(length:--responsive-body,var(--font-size-lg,16px)) leading-[1.5] text-[#393939]">
|
||||
Add CozSweet to Home Screen{"\n"}for the best experience
|
||||
</p>
|
||||
<div className="flex w-full gap-[var(--spacing-md,12px)]">
|
||||
<div className="flex w-full gap-(--spacing-md,12px)">
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--pwa-button-height,44px)] flex-auto cursor-pointer items-center justify-center rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[var(--color-text-secondary,#9e9e9e)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-semibold text-[var(--color-pwa-button-text,#ffffff)]"
|
||||
className="flex min-h-(--pwa-button-height,44px) flex-auto cursor-pointer items-center justify-center rounded-(--radius-bottom-sheet,28px) border-0 bg-(--color-text-secondary,#9e9e9e) text-(length:--responsive-body,var(--font-size-lg,16px)) font-semibold text-(--color-pwa-button-text,#ffffff)"
|
||||
onClick={onClose}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--pwa-button-height,44px)] flex-auto cursor-pointer items-center justify-center rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[linear-gradient(var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))] text-[var(--responsive-body,var(--font-size-lg,16px))] font-semibold text-[var(--color-pwa-button-text,#ffffff)]"
|
||||
className="flex min-h-(--pwa-button-height,44px) flex-auto cursor-pointer items-center justify-center rounded-(--radius-bottom-sheet,28px) border-0 bg-[linear-gradient(var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))] text-(length:--responsive-body,var(--font-size-lg,16px)) font-semibold text-(--color-pwa-button-text,#ffffff)"
|
||||
onClick={handleInstall}
|
||||
>
|
||||
OK
|
||||
|
||||
@@ -15,10 +15,10 @@ export interface TextBubbleProps {
|
||||
}
|
||||
|
||||
const BASE_CLASS_NAME =
|
||||
"w-full self-stretch whitespace-pre-wrap break-words rounded-[var(--radius-xxl,24px)] px-[var(--spacing-4,16px)] py-[var(--spacing-3,12px)] text-[length:var(--chat-message-font-size,var(--responsive-body,16px))] leading-[var(--chat-message-line-height,1.5)] shadow-[var(--shadow-input-box,0_1px_2px_rgba(0,0,0,0.1))]";
|
||||
"w-full self-stretch whitespace-pre-wrap break-words rounded-(--radius-xxl,24px) px-(--spacing-4,16px) py-(--spacing-3,12px) text-(length:--chat-message-font-size,var(--responsive-body,16px)) leading-(--chat-message-line-height,1.5) shadow-(--shadow-input-box,0_1px_2px_rgba(0,0,0,0.1))";
|
||||
|
||||
const AI_CLASS_NAME =
|
||||
"rounded-tl-none bg-white text-[var(--color-text-foreground,#000)]";
|
||||
"rounded-tl-none bg-white text-(--color-text-foreground,#000)";
|
||||
|
||||
const USER_CLASS_NAME =
|
||||
"rounded-tr-none bg-[linear-gradient(to_right,var(--color-button-gradient-start,#ff67e0),var(--color-button-gradient-end,#ff52a2))] text-white";
|
||||
|
||||
@@ -17,37 +17,37 @@ export function VoiceUnlockOptionsDialog({
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-[72] flex items-center justify-center bg-[rgba(0,0,0,0.5)] pb-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-bottom,0px))] pl-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-left,0px))] pr-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-right,0px))] pt-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-top,0px))]"
|
||||
className="fixed inset-0 z-72 flex items-center justify-center bg-[rgba(0,0,0,0.5)] pb-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-bottom,0px))] pl-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-left,0px))] pr-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-right,0px))] pt-[calc(var(--dialog-safe-margin,16px)+var(--app-safe-top,0px))]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="voice-unlock-options-title"
|
||||
>
|
||||
<div className="w-full max-w-[var(--dialog-max-width,380px)] rounded-[var(--responsive-card-radius,36px)] bg-[var(--color-page-background,#ffffff)] px-[var(--responsive-card-padding,18px)] pb-[var(--responsive-card-padding,18px)] pt-[var(--responsive-card-padding-lg,24px)] shadow-[0_18px_40px_rgba(0,0,0,0.16)]">
|
||||
<div className="w-full max-w-(--dialog-max-width,380px) rounded-(--responsive-card-radius,36px) bg-(--color-page-background,#ffffff) px-(--responsive-card-padding,18px) pb-(--responsive-card-padding,18px) pt-(--responsive-card-padding-lg,24px) shadow-[0_18px_40px_rgba(0,0,0,0.16)]">
|
||||
<h2
|
||||
id="voice-unlock-options-title"
|
||||
className="m-0 mb-[clamp(7px,1.481vw,8px)] text-center text-[var(--responsive-page-title,var(--font-size-22,22px))] font-bold leading-[1.2] text-[var(--color-text-foreground,#171717)]"
|
||||
className="m-0 mb-[clamp(7px,1.481vw,8px)] text-center text-(length:--responsive-page-title,var(--font-size-22,22px)) font-bold leading-[1.2] text-(--color-text-foreground,#171717)"
|
||||
>
|
||||
Unlock voice message
|
||||
</h2>
|
||||
<p className="mx-[var(--spacing-md,12px)] mb-[var(--page-section-gap-lg,20px)] mt-0 text-center text-[var(--responsive-body,var(--font-size-md,14px))] leading-[1.5] text-[#393939]">
|
||||
<p className="mx-(--spacing-md,12px) mb-(--page-section-gap-lg,20px) mt-0 text-center text-(length:--responsive-body,var(--font-size-md,14px)) leading-[1.5] text-[#393939]">
|
||||
Choose how you would like to unlock this voice message.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-[var(--spacing-md,12px)]">
|
||||
<div className="flex flex-col gap-(--spacing-md,12px)">
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--responsive-control-height,48px)] w-full cursor-pointer flex-col items-center justify-center gap-[var(--responsive-inline-gap-xs,4px)] rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)] px-[var(--responsive-card-padding,16px)] py-[clamp(9px,1.852vw,10px)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-bold text-white shadow-[0_5px_7px_rgba(247,89,168,0.24)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="flex min-h-(--responsive-control-height,48px) w-full cursor-pointer flex-col items-center justify-center gap-(--responsive-inline-gap-xs,4px) rounded-(--radius-bottom-sheet,28px) border-0 bg-[linear-gradient(90deg,#ff67e0_0%,#ff52a2_100%)] px-(--responsive-card-padding,16px) py-[clamp(9px,1.852vw,10px)] text-(length:--responsive-body,var(--font-size-lg,16px)) font-bold text-white shadow-[0_5px_7px_rgba(247,89,168,0.24)] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
onClick={onBuyVoicePackage}
|
||||
>
|
||||
购买语音包
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex min-h-[var(--responsive-control-height,48px)] w-full cursor-pointer flex-col items-center justify-center gap-[var(--responsive-inline-gap-xs,4px)] rounded-[var(--radius-bottom-sheet,28px)] border border-transparent bg-[linear-gradient(#ffffff,#ffffff)_padding-box,linear-gradient(90deg,#ff67e0,#ff52a2)_border-box] px-[var(--responsive-card-padding,16px)] py-[clamp(9px,1.852vw,10px)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-bold text-[#f657a0] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="flex min-h-(--responsive-control-height,48px) w-full cursor-pointer flex-col items-center justify-center gap-(--responsive-inline-gap-xs,4px) rounded-(--radius-bottom-sheet,28px) border border-transparent bg-[linear-gradient(#ffffff,#ffffff)_padding-box,linear-gradient(90deg,#ff67e0,#ff52a2)_border-box] px-(--responsive-card-padding,16px) py-[clamp(9px,1.852vw,10px)] text-(length:--responsive-body,var(--font-size-lg,16px)) font-bold text-[#f657a0] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
onClick={onActivateVip}
|
||||
>
|
||||
<span className="leading-[1.2]">开通 VIP</span>
|
||||
<span className="text-[var(--responsive-caption,13px)] font-medium leading-[1.25] text-[#3c3b3b]">
|
||||
<span className="text-(length:--responsive-caption,13px) font-medium leading-[1.25] text-[#3c3b3b]">
|
||||
免费10条语言消息+无限畅聊
|
||||
</span>
|
||||
</button>
|
||||
@@ -55,7 +55,7 @@ export function VoiceUnlockOptionsDialog({
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="mt-[clamp(12px,2.593vw,14px)] min-h-[var(--responsive-control-height,48px)] w-full cursor-pointer rounded-[var(--radius-bottom-sheet,28px)] border-0 bg-[var(--color-text-secondary,#9e9e9e)] text-[var(--responsive-body,var(--font-size-lg,16px))] font-bold text-white focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
className="mt-[clamp(12px,2.593vw,14px)] min-h-(--responsive-control-height,48px) w-full cursor-pointer rounded-(--radius-bottom-sheet,28px) border-0 bg-(--color-text-secondary,#9e9e9e) text-(length:--responsive-body,var(--font-size-lg,16px)) font-bold text-white focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]"
|
||||
onClick={onClose}
|
||||
>
|
||||
Cancel
|
||||
|
||||
Reference in New Issue
Block a user