feat(back-button): enhance button styles and add variant support; refactor back navigation in sidebar and coins rules screen

This commit is contained in:
2026-06-29 14:54:03 +08:00
parent 096978e703
commit ef18500de3
9 changed files with 104 additions and 119 deletions
+57 -12
View File
@@ -1,29 +1,74 @@
.backButton {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
color: var(--color-auth-text-primary);
cursor: pointer;
border: 0;
border-radius: 999px;
text-decoration: none;
transition:
background 0.15s ease,
box-shadow 0.18s ease,
transform 0.05s ease;
}
.floating {
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 {
.soft {
width: 42px;
height: 42px;
color: #21191d;
border: 1px solid rgba(25, 19, 22, 0.08);
background: rgba(255, 255, 255, 0.82);
box-shadow: 0 10px 22px rgba(50, 30, 40, 0.08);
}
.ghost {
width: 32px;
height: 32px;
color: #000000;
background: transparent;
}
.floating:hover {
background: rgba(0, 0, 0, 0.04);
}
.backButton:active {
.soft:hover {
background: #ffffff;
box-shadow: 0 14px 26px rgba(50, 30, 40, 0.12);
transform: translateY(-1px);
}
.ghost:hover {
opacity: 0.7;
}
.floating:active {
transform: scale(0.96);
}
.soft:active {
transform: translateY(1px);
}
.ghost:active {
transform: scale(0.96);
}
.backButton:focus-visible {
outline: 2px solid #f657a0;
outline-offset: 3px;
}
+40 -4
View File
@@ -1,28 +1,64 @@
"use client";
import { ChevronLeft } from "lucide-react";
import Link, { type LinkProps } from "next/link";
import styles from "./back-button.module.css";
export interface BackButtonProps {
onClick: () => void;
interface BackButtonBaseProps {
className?: string;
ariaLabel?: string;
iconSize?: number;
variant?: "floating" | "soft" | "ghost";
}
type BackButtonLinkProps = BackButtonBaseProps & {
href: LinkProps["href"];
onClick?: never;
};
type BackButtonActionProps = BackButtonBaseProps & {
href?: never;
onClick: () => void;
};
export type BackButtonProps = BackButtonLinkProps | BackButtonActionProps;
export function BackButton({
href,
onClick,
className,
ariaLabel = "Back",
iconSize = 24,
variant = "floating",
}: BackButtonProps) {
const buttonClassName = [
styles.backButton,
styles[variant],
className,
]
.filter(Boolean)
.join(" ");
const icon = (
<ChevronLeft size={iconSize} strokeWidth={2.5} aria-hidden="true" />
);
if (href) {
return (
<Link href={href} className={buttonClassName} aria-label={ariaLabel}>
{icon}
</Link>
);
}
return (
<button
type="button"
className={[styles.backButton, className].filter(Boolean).join(" ")}
className={buttonClassName}
onClick={onClick}
aria-label={ariaLabel}
>
<ChevronLeft size={20} strokeWidth={2.5} aria-hidden="true" />
{icon}
</button>
);
}
@@ -15,36 +15,6 @@
gap: 18px;
}
.backLink {
display: inline-flex;
width: 42px;
height: 42px;
align-items: center;
justify-content: center;
color: #21191d;
text-decoration: none;
border: 1px solid rgba(25, 19, 22, 0.08);
border-radius: 999px;
background: rgba(255, 255, 255, 0.82);
box-shadow: 0 10px 22px rgba(50, 30, 40, 0.08);
transition: background 0.18s ease, box-shadow 0.18s ease, transform 0.16s ease;
}
.backLink:hover {
background: #ffffff;
box-shadow: 0 14px 26px rgba(50, 30, 40, 0.12);
transform: translateY(-1px);
}
.backLink:active {
transform: translateY(1px);
}
.backLink:focus-visible {
outline: 2px solid #f657a0;
outline-offset: 3px;
}
.hero {
position: relative;
overflow: hidden;
+4 -7
View File
@@ -1,7 +1,6 @@
"use client";
import {
ArrowLeft,
Coins,
Gift,
ImageIcon,
@@ -10,8 +9,8 @@ import {
Phone,
Sparkles,
} from "lucide-react";
import Link from "next/link";
import { BackButton } from "@/app/_components";
import { MobileShell } from "@/app/_components/core";
import { ROUTES } from "@/router/routes";
@@ -69,13 +68,11 @@ export function CoinsRulesScreen() {
<MobileShell background="#fcf3f4">
<main className={styles.screen}>
<header className={styles.header}>
<Link
<BackButton
href={ROUTES.sidebar}
className={styles.backLink}
variant="soft"
aria-label="Back to sidebar"
>
<ArrowLeft size={22} strokeWidth={2.4} aria-hidden="true" />
</Link>
/>
<div className={styles.hero}>
<span className={styles.heroIcon} aria-hidden="true">
@@ -1,28 +0,0 @@
.bar {
padding: var(--spacing-md, 12px) 0;
display: flex;
align-items: center;
}
.link {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
color: #000000;
text-decoration: none;
background: none;
border: 0;
padding: 0;
cursor: pointer;
}
.link:hover {
opacity: 0.7;
}
.icon {
color: currentColor;
flex-shrink: 0;
}
-34
View File
@@ -1,34 +0,0 @@
"use client";
import { ChevronLeft } from "lucide-react";
import Link from "next/link";
import { ROUTES } from "@/router/routes";
import styles from "./back-bar.module.css";
/**
* 顶部返回栏:图标按钮,链接至聊天页。
*
* 视觉规格(与设计稿对齐):
* - 黑色文本(浅色主题下)
* - 居左对齐,顶部留白
*/
export function BackBar() {
return (
<header className={styles.bar}>
<Link
href={ROUTES.chat}
className={styles.link}
aria-label="Back"
>
<ChevronLeft
size={24}
strokeWidth={2.5}
aria-hidden="true"
className={styles.icon}
/>
</Link>
</header>
);
}
-1
View File
@@ -2,7 +2,6 @@
* @file Automatically generated by barrelsby.
*/
export * from "./back-bar";
export * from "./sidebar-wallet-card";
export * from "./user-header";
export * from "./vip-benefits-card";
@@ -49,7 +49,7 @@
}
.topBar {
margin: 4px 0 -2px;
margin: 10px 0 -2px;
}
.hero {
+2 -2
View File
@@ -4,13 +4,13 @@ import { LogOut } from "lucide-react";
import { signOut } from "next-auth/react";
import { useRouter } from "next/navigation";
import { BackButton } from "@/app/_components";
import { MobileShell } from "@/app/_components/core";
import { ROUTES } from "@/router/routes";
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
import { useUserDispatch, useUserState } from "@/stores/user/user-context";
import {
BackBar,
SidebarWalletCard,
UserHeader,
type SidebarUserState,
@@ -56,7 +56,7 @@ export function SidebarScreen() {
<div className={styles.bgOrbTwo} aria-hidden="true" />
<div className={styles.topBar}>
<BackBar />
<BackButton href={ROUTES.chat} variant="soft" />
</div>
<section className={`${styles.userSlot} ${styles.revealOne}`}>