Merge branch 'dev' into test
This commit is contained in:
+3
-2
@@ -29,6 +29,7 @@
|
|||||||
"pino": "^10.3.1",
|
"pino": "^10.3.1",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.4",
|
"react-dom": "19.2.4",
|
||||||
|
"react-icons": "^5.6.0",
|
||||||
"stripe": "^22.2.1",
|
"stripe": "^22.2.1",
|
||||||
"unstorage": "^1.17.5",
|
"unstorage": "^1.17.5",
|
||||||
"xstate": "^5",
|
"xstate": "^5",
|
||||||
@@ -36,8 +37,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@serwist/turbopack": "^9.0.0",
|
"@serwist/turbopack": "^9.0.0",
|
||||||
"esbuild": "^0.25.0",
|
|
||||||
"serwist": "^9.0.0",
|
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
@@ -45,9 +44,11 @@
|
|||||||
"@vitest/coverage-v8": "^4.1.8",
|
"@vitest/coverage-v8": "^4.1.8",
|
||||||
"@vitest/ui": "^4.1.8",
|
"@vitest/ui": "^4.1.8",
|
||||||
"barrelsby": "^2.8.1",
|
"barrelsby": "^2.8.1",
|
||||||
|
"esbuild": "^0.25.0",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "16.2.7",
|
"eslint-config-next": "16.2.7",
|
||||||
"jsdom": "^29.1.1",
|
"jsdom": "^29.1.1",
|
||||||
|
"serwist": "^9.0.0",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
"vitest": "^4.1.8"
|
"vitest": "^4.1.8"
|
||||||
|
|||||||
Generated
+12
@@ -47,6 +47,9 @@ importers:
|
|||||||
react-dom:
|
react-dom:
|
||||||
specifier: 19.2.4
|
specifier: 19.2.4
|
||||||
version: 19.2.4(react@19.2.4)
|
version: 19.2.4(react@19.2.4)
|
||||||
|
react-icons:
|
||||||
|
specifier: ^5.6.0
|
||||||
|
version: 5.6.0(react@19.2.4)
|
||||||
stripe:
|
stripe:
|
||||||
specifier: ^22.2.1
|
specifier: ^22.2.1
|
||||||
version: 22.2.1(@types/node@20.19.41)
|
version: 22.2.1(@types/node@20.19.41)
|
||||||
@@ -2698,6 +2701,11 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^19.2.4
|
react: ^19.2.4
|
||||||
|
|
||||||
|
react-icons@5.6.0:
|
||||||
|
resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '*'
|
||||||
|
|
||||||
react-is@16.13.1:
|
react-is@16.13.1:
|
||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
|
|
||||||
@@ -5890,6 +5898,10 @@ snapshots:
|
|||||||
react: 19.2.4
|
react: 19.2.4
|
||||||
scheduler: 0.27.0
|
scheduler: 0.27.0
|
||||||
|
|
||||||
|
react-icons@5.6.0(react@19.2.4):
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.4
|
||||||
|
|
||||||
react-is@16.13.1: {}
|
react-is@16.13.1: {}
|
||||||
|
|
||||||
react@19.2.4: {}
|
react@19.2.4: {}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
|||||||
import { AuthErrorMessage } from "./auth-error-message";
|
import { AuthErrorMessage } from "./auth-error-message";
|
||||||
import { AuthLegalText } from "./auth-legal-text";
|
import { AuthLegalText } from "./auth-legal-text";
|
||||||
import { AuthOtherOptionsDialog } from "./auth-other-options-dialog";
|
import { AuthOtherOptionsDialog } from "./auth-other-options-dialog";
|
||||||
|
import { AuthProviderIcon } from "./auth-provider-icon";
|
||||||
import styles from "./auth-facebook-panel.module.css";
|
import styles from "./auth-facebook-panel.module.css";
|
||||||
|
|
||||||
export interface AuthFacebookPanelProps {
|
export interface AuthFacebookPanelProps {
|
||||||
@@ -70,9 +71,7 @@ export function AuthFacebookPanel({ onSwitchToEmail }: AuthFacebookPanelProps) {
|
|||||||
<span className={styles.spinner} aria-hidden="true" />
|
<span className={styles.spinner} aria-hidden="true" />
|
||||||
) : (
|
) : (
|
||||||
<span className={styles.facebookIcon} aria-hidden="true">
|
<span className={styles.facebookIcon} aria-hidden="true">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="#1877f2">
|
<AuthProviderIcon provider="facebook" />
|
||||||
<path d="M13 22v-8h3l1-4h-4V7.5c0-1.2.4-2 2-2h2V2.2C16.6 2.1 15.5 2 14.3 2 11.5 2 9.5 3.7 9.5 7v3h-3v4h3v8h3.5z" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className={styles.facebookLabel}>
|
<span className={styles.facebookLabel}>
|
||||||
|
|||||||
@@ -14,9 +14,11 @@
|
|||||||
* - Cancel 文本按钮
|
* - Cancel 文本按钮
|
||||||
*/
|
*/
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
import { Mail } from "lucide-react";
|
||||||
|
|
||||||
import { BottomSheet } from "@/app/_components/core/bottom-sheet";
|
import { BottomSheet } from "@/app/_components/core/bottom-sheet";
|
||||||
|
|
||||||
|
import { AuthProviderIcon } from "./auth-provider-icon";
|
||||||
import { AuthSocialButton } from "./auth-social-button";
|
import { AuthSocialButton } from "./auth-social-button";
|
||||||
import styles from "./auth-other-options-dialog.module.css";
|
import styles from "./auth-other-options-dialog.module.css";
|
||||||
|
|
||||||
@@ -53,17 +55,7 @@ export function AuthOtherOptionsDialog({
|
|||||||
|
|
||||||
{mode === "facebook" ? (
|
{mode === "facebook" ? (
|
||||||
<AuthSocialButton
|
<AuthSocialButton
|
||||||
icon={
|
icon={<Mail size={20} aria-hidden="true" />}
|
||||||
<svg
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4-8 5-8-5V6l8 5 8-5v2z" />
|
|
||||||
</svg>
|
|
||||||
}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onClose();
|
onClose();
|
||||||
onEmail();
|
onEmail();
|
||||||
@@ -73,17 +65,7 @@ export function AuthOtherOptionsDialog({
|
|||||||
</AuthSocialButton>
|
</AuthSocialButton>
|
||||||
) : (
|
) : (
|
||||||
<AuthSocialButton
|
<AuthSocialButton
|
||||||
icon={
|
icon={<AuthProviderIcon provider="facebook" />}
|
||||||
<svg
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="var(--color-facebook-blue)"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M13 22v-8h3l1-4h-4V7.5c0-1.2.4-2 2-2h2V2.2C16.6 2.1 15.5 2 14.3 2 11.5 2 9.5 3.7 9.5 7v3h-3v4h3v8h3.5z" />
|
|
||||||
</svg>
|
|
||||||
}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onClose();
|
onClose();
|
||||||
onFacebook();
|
onFacebook();
|
||||||
@@ -97,26 +79,7 @@ export function AuthOtherOptionsDialog({
|
|||||||
<div className={styles.googleSlot}>{googleSlot}</div>
|
<div className={styles.googleSlot}>{googleSlot}</div>
|
||||||
) : (
|
) : (
|
||||||
<AuthSocialButton
|
<AuthSocialButton
|
||||||
icon={
|
icon={<AuthProviderIcon provider="google" />}
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" aria-hidden="true">
|
|
||||||
<path
|
|
||||||
d="M22 12.2c0-.7-.1-1.4-.2-2H12v3.8h5.6c-.2 1.3-1 2.4-2 3.1v2.6h3.2c1.9-1.7 2.9-4.2 2.9-7.5z"
|
|
||||||
fill="#4285F4"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12 22c2.7 0 4.9-.9 6.5-2.4l-3.2-2.5c-.9.6-2 1-3.3 1-2.6 0-4.7-1.7-5.5-4.1H3.2v2.5C4.8 19.7 8.1 22 12 22z"
|
|
||||||
fill="#34A853"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M6.5 14a6 6 0 010-3.9V7.5H3.2a10 10 0 000 9l3.3-2.5z"
|
|
||||||
fill="#FBBC05"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12 5.9c1.5 0 2.8.5 3.8 1.5l2.9-2.9C16.9 2.9 14.7 2 12 2 8.1 2 4.8 4.3 3.2 7.5L6.5 10c.8-2.4 2.9-4.1 5.5-4.1z"
|
|
||||||
fill="#EA4335"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onClose();
|
onClose();
|
||||||
onGoogle();
|
onGoogle();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* 认证面板:顶层 switch(Facebook / Email)+ 悬浮返回按钮
|
* 认证面板:顶层 switch(Facebook / Email)+ 悬浮返回按钮
|
||||||
*/
|
*/
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import { ChevronLeft } from "lucide-react";
|
||||||
|
|
||||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||||
|
|
||||||
@@ -36,19 +37,7 @@ export function AuthPanel() {
|
|||||||
onClick={handleBack}
|
onClick={handleBack}
|
||||||
aria-label="Back"
|
aria-label="Back"
|
||||||
>
|
>
|
||||||
<svg
|
<ChevronLeft size={20} strokeWidth={2.5} aria-hidden="true" />
|
||||||
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>
|
</button>
|
||||||
|
|
||||||
{state.authPanelMode === "facebook" ? (
|
{state.authPanelMode === "facebook" ? (
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FaApple, FaFacebookF } from "react-icons/fa6";
|
||||||
|
import { FcGoogle } from "react-icons/fc";
|
||||||
|
|
||||||
|
export type AuthProviderIconName = "facebook" | "google" | "apple";
|
||||||
|
|
||||||
|
export interface AuthProviderIconProps {
|
||||||
|
provider: AuthProviderIconName;
|
||||||
|
size?: number;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AuthProviderIcon({
|
||||||
|
provider,
|
||||||
|
size = 20,
|
||||||
|
className,
|
||||||
|
}: AuthProviderIconProps) {
|
||||||
|
if (provider === "google") {
|
||||||
|
return <FcGoogle size={size} className={className} aria-hidden="true" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider === "apple") {
|
||||||
|
return <FaApple size={size} className={className} aria-hidden="true" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FaFacebookF
|
||||||
|
size={size}
|
||||||
|
className={className}
|
||||||
|
color="var(--color-facebook-blue)"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
import { type ReactNode } from "react";
|
import { type ReactNode } from "react";
|
||||||
|
|
||||||
|
import { AuthProviderIcon } from "./auth-provider-icon";
|
||||||
import styles from "./auth-social-buttons.module.css";
|
import styles from "./auth-social-buttons.module.css";
|
||||||
|
|
||||||
export interface AuthSocialButtonsProps {
|
export interface AuthSocialButtonsProps {
|
||||||
@@ -37,10 +38,7 @@ export function AuthSocialButtons({
|
|||||||
disabled={loadingProvider !== null && loadingProvider !== "facebook"}
|
disabled={loadingProvider !== null && loadingProvider !== "facebook"}
|
||||||
>
|
>
|
||||||
<span className={styles.icon} aria-hidden="true">
|
<span className={styles.icon} aria-hidden="true">
|
||||||
{/* Facebook "f" logo placeholder */}
|
<AuthProviderIcon provider="facebook" />
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
|
||||||
<path d="M13 22v-8h3l1-4h-4V7.5c0-1.2.4-2 2-2h2V2.2C16.6 2.1 15.5 2 14.3 2 11.5 2 9.5 3.7 9.5 7v3h-3v4h3v8h3.5z" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
</span>
|
||||||
<span>Continue with Facebook</span>
|
<span>Continue with Facebook</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -55,25 +53,7 @@ export function AuthSocialButtons({
|
|||||||
disabled={loadingProvider !== null && loadingProvider !== "google"}
|
disabled={loadingProvider !== null && loadingProvider !== "google"}
|
||||||
>
|
>
|
||||||
<span className={styles.icon} aria-hidden="true">
|
<span className={styles.icon} aria-hidden="true">
|
||||||
{/* Google "G" logo placeholder */}
|
<AuthProviderIcon provider="google" />
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
d="M22 12.2c0-.7-.1-1.4-.2-2H12v3.8h5.6c-.2 1.3-1 2.4-2 3.1v2.6h3.2c1.9-1.7 2.9-4.2 2.9-7.5z"
|
|
||||||
fill="#4285F4"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12 22c2.7 0 4.9-.9 6.5-2.4l-3.2-2.5c-.9.6-2 1-3.3 1-2.6 0-4.7-1.7-5.5-4.1H3.2v2.5C4.8 19.7 8.1 22 12 22z"
|
|
||||||
fill="#34A853"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M6.5 14a6 6 0 010-3.9V7.5H3.2a10 10 0 000 9l3.3-2.5z"
|
|
||||||
fill="#FBBC05"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M12 5.9c1.5 0 2.8.5 3.8 1.5l2.9-2.9C16.9 2.9 14.7 2 12 2 8.1 2 4.8 4.3 3.2 7.5L6.5 10c.8-2.4 2.9-4.1 5.5-4.1z"
|
|
||||||
fill="#EA4335"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</span>
|
</span>
|
||||||
<span>Continue with Google</span>
|
<span>Continue with Google</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -87,9 +67,7 @@ export function AuthSocialButtons({
|
|||||||
disabled={loadingProvider !== null && loadingProvider !== "apple"}
|
disabled={loadingProvider !== null && loadingProvider !== "apple"}
|
||||||
>
|
>
|
||||||
<span className={styles.icon} aria-hidden="true">
|
<span className={styles.icon} aria-hidden="true">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
<AuthProviderIcon provider="apple" />
|
||||||
<path d="M16.4 1.5c0 1.1-.4 2.1-1.1 2.9-.8.8-1.8 1.4-2.8 1.3-.1-1.1.4-2.2 1.1-3 .8-.8 1.9-1.3 2.8-1.2zM20 17.4c-.5 1.2-1.1 2.3-1.9 3.3-1 1.3-2.4 2.9-4.1 2.9-1.5 0-1.9-1-3.9-1-2 0-2.4 1-4 1-1.7 0-3-1.5-4-2.8-2.7-3.6-3-7.8-1.3-10 1.2-1.5 3-2.4 4.8-2.4 1.8 0 2.9 1 4.4 1 1.4 0 2.3-1 4.4-1 1.6 0 3.3.9 4.5 2.4-4 2.1-3.3 7.7.1 8.6z" />
|
|
||||||
</svg>
|
|
||||||
</span>
|
</span>
|
||||||
<span>Continue with Apple</span>
|
<span>Continue with Apple</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export * from "./auth-legal-text";
|
|||||||
export * from "./auth-other-options-dialog";
|
export * from "./auth-other-options-dialog";
|
||||||
export * from "./auth-panel";
|
export * from "./auth-panel";
|
||||||
export * from "./auth-primary-button";
|
export * from "./auth-primary-button";
|
||||||
|
export * from "./auth-provider-icon";
|
||||||
export * from "./auth-social-button";
|
export * from "./auth-social-button";
|
||||||
export * from "./auth-social-buttons";
|
export * from "./auth-social-buttons";
|
||||||
export * from "./auth-text-field";
|
export * from "./auth-text-field";
|
||||||
|
|||||||
Reference in New Issue
Block a user