feat(auth): redesign auth UI to match Dart original
- Full-bleed bg_login.png background outside 500px MobileShell - Facebook landing: logo + Facebook pill button + "Other Sign In Options" link - Replace centered Dialog with true bottom sheet (drag handle, top radius 28px) - Email panel: internal login/register toggle, no separate route - Pink gradient primary button (#f96ADE → #f657A0) - Pill input fields (46px, white, radius 24, pink 10% shadow) - Pink circular checkbox + bold Privacy/Terms rich text (visual only, non-blocking) - Floating 40x40 white back button (top:20/left:20) - Wire AuthPanelModeChanged dispatch for panel switching - New design tokens (--color-auth-*, --auth-*, --radius-bottom-sheet) - New generic BottomSheet component - Copy ic-logo-login.png (+@2x, +@3x) from Dart assets 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,30 +1,74 @@
|
||||
"use client";
|
||||
/**
|
||||
* 认证面板:顶层 switch(Facebook / Email)
|
||||
* 认证面板:顶层 switch(Facebook / Email)+ 悬浮返回按钮
|
||||
*
|
||||
* 原始 Dart: lib/ui/auth/widgets/auth_panel.dart
|
||||
*
|
||||
* 行为对齐:
|
||||
* - 状态机:`authPanelMode`("facebook" | "email")由 XState 管理
|
||||
* - 切换派发 `AuthPanelModeChanged`
|
||||
* - 悬浮返回按钮(40×40 白圆,top:20, left:20):
|
||||
* - facebook 模式:`router.back()`
|
||||
* - email 模式:派发 `AuthPanelModeChanged(facebook)`
|
||||
* - Email 面板的弹层 Facebook 按钮同样派发 `AuthPanelModeChanged(facebook)`
|
||||
*/
|
||||
import { useAuthState } from "@/stores/auth/auth-context";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
|
||||
import { AuthFacebookPanel } from "./auth-facebook-panel";
|
||||
import { AuthEmailPanel } from "./auth-email-panel";
|
||||
import { AuthFacebookPanel } from "./auth-facebook-panel";
|
||||
import styles from "./auth-panel.module.css";
|
||||
|
||||
export function AuthPanel() {
|
||||
const state = useAuthState();
|
||||
const dispatch = useAuthDispatch();
|
||||
const router = useRouter();
|
||||
|
||||
const switchToEmail = () =>
|
||||
dispatch({ type: "AuthPanelModeChanged", mode: "email" });
|
||||
const switchToFacebook = () =>
|
||||
dispatch({ type: "AuthPanelModeChanged", mode: "facebook" });
|
||||
|
||||
const handleBack = () => {
|
||||
if (state.authPanelMode === "email") {
|
||||
switchToFacebook();
|
||||
} else {
|
||||
router.back();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.panel}>
|
||||
<div className={styles.panelShell}>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.backButton}
|
||||
onClick={handleBack}
|
||||
aria-label="Back"
|
||||
>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M15 18l-6-6 6-6" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{state.authPanelMode === "facebook" ? (
|
||||
<AuthFacebookPanel
|
||||
onSwitchToEmail={() => {
|
||||
// 切换模式由外部 dispatch 触发;这里不直接处理
|
||||
// 因为 auth-panel 受 `authPanelMode` 控制,调用方需要 dispatch `AuthPanelModeChanged`
|
||||
// 但我们目前 AuthFacebookPanel 内部 click "Continue with Email" 直接调用 onSwitchToEmail
|
||||
// 实际上本组件直接渲染对应 panel
|
||||
<AuthFacebookPanel onSwitchToEmail={switchToEmail} />
|
||||
) : (
|
||||
<AuthEmailPanel
|
||||
onSwitchToFacebook={() => {
|
||||
switchToFacebook();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<AuthEmailPanel onBack={() => undefined} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user