feat(app): improve payment and paywall UX

This commit is contained in:
2026-06-24 10:02:22 +08:00
parent 6c25a24440
commit bfbf7ee91a
23 changed files with 344 additions and 129 deletions
@@ -0,0 +1,29 @@
.backButton {
position: absolute;
top: var(--spacing-xl);
left: var(--spacing-xl);
z-index: 2;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--back-button-size);
height: var(--back-button-size);
padding: 0 2px 0 0;
color: var(--color-auth-text-primary);
cursor: pointer;
background: var(--color-auth-surface);
border: none;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition:
background 0.15s ease,
transform 0.05s ease;
}
.backButton:hover {
background: rgba(0, 0, 0, 0.04);
}
.backButton:active {
transform: scale(0.96);
}
+28
View File
@@ -0,0 +1,28 @@
"use client";
import { ChevronLeft } from "lucide-react";
import styles from "./back-button.module.css";
export interface BackButtonProps {
onClick: () => void;
className?: string;
ariaLabel?: string;
}
export function BackButton({
onClick,
className,
ariaLabel = "Back",
}: BackButtonProps) {
return (
<button
type="button"
className={[styles.backButton, className].filter(Boolean).join(" ")}
onClick={onClick}
aria-label={ariaLabel}
>
<ChevronLeft size={20} strokeWidth={2.5} aria-hidden="true" />
</button>
);
}
@@ -1,22 +0,0 @@
.button {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: none;
border-radius: var(--radius-full);
background: transparent;
color: var(--color-text-primary);
cursor: pointer;
transition: background 0.15s ease;
}
.button:hover {
background: rgba(255, 255, 255, 0.08);
}
.button:focus-visible {
outline: var(--border-medium) solid var(--color-accent);
outline-offset: 2px;
}
@@ -1,59 +0,0 @@
"use client";
/**
* 通用返回按钮
*
* 原始 Dart: lib/ui/auth/widgets/back_button.dart(被 auth/chat/sidebar 共用)。
*/
import { useRouter } from "next/navigation";
import { type MouseEvent } from "react";
import styles from "./auth-back-button.module.css";
export interface AuthBackButtonProps {
/** 自定义跳转目标(默认 history.back)。 */
href?: string;
/** 自定义点击处理(覆盖默认跳转)。 */
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
className?: string;
ariaLabel?: string;
}
export function AuthBackButton({
href,
onClick,
className,
ariaLabel = "Back",
}: AuthBackButtonProps) {
const router = useRouter();
return (
<button
type="button"
aria-label={ariaLabel}
className={[styles.button, className].filter(Boolean).join(" ")}
onClick={(e) => {
if (onClick) {
onClick(e);
return;
}
if (href) router.push(href);
else router.back();
}}
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
>
<path
d="M15 18l-6-6 6-6"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
);
}
-1
View File
@@ -2,7 +2,6 @@
* @file Automatically generated by barrelsby.
*/
export * from "./auth-back-button";
export * from "./bottom-sheet";
export * from "./checkbox";
export * from "./dialog";
+5
View File
@@ -0,0 +1,5 @@
/**
* @file Shared app component barrel.
*/
export * from "./back-button";