From f4fb39e0f3860959fbf38bcc492a90fb7864d78b Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sun, 30 Aug 2026 14:16:30 +0800 Subject: [PATCH] feat(frontend): separate profile and chart settings --- frontend/src/app/globals.css | 4 ++ frontend/src/app/page.tsx | 47 +++++++++---------- .../src/components/account-dialog-overlay.tsx | 26 +++------- frontend/src/components/app-sidebar.tsx | 5 ++ frontend/tests/account-dialog-overlay.test.ts | 4 +- 5 files changed, 40 insertions(+), 46 deletions(-) diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 54a6ab96..ec5074ee 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -1596,6 +1596,9 @@ button:disabled { cursor: default; opacity: .45; } .account-modal-overlay { position: fixed; z-index: 40; inset: 0; display: grid; place-items: center; padding: var(--space-4); background: var(--color-scrim); animation: account-overlay-enter 180ms ease-out both; } .account-modal { width: min(100%, 560px); max-height: min(84dvh, 760px); overflow-y: auto; padding: var(--space-8); border: 1px solid var(--color-border); border-radius: var(--radius-xl); background: var(--color-canvas); box-shadow: var(--shadow-elevated); animation: account-dialog-enter 180ms var(--ease-out) both; } .profile-modal { width: min(100%, 680px); scroll-padding-block-start: calc(var(--space-8) + 72px); } +.chart-library-modal { width: min(100%, 760px); scroll-padding-block-start: calc(var(--space-8) + 72px); } +.chart-library-modal .account-modal-header { position: sticky; z-index: 1; top: 0; margin: calc(var(--space-8) * -1) calc(var(--space-8) * -1) var(--space-3); padding: var(--space-8) var(--space-8) var(--space-5); border-bottom: 1px solid var(--color-border); background: var(--color-canvas); } +.settings-dialog-copy { margin: 0 0 var(--space-5); color: var(--color-ink-secondary); font-size: var(--type-body-sm); line-height: 1.6; } .profile-modal .account-modal-header { position: sticky; z-index: 1; top: 0; margin: calc(var(--space-8) * -1) calc(var(--space-8) * -1) var(--space-5); padding: var(--space-8) var(--space-8) var(--space-5); border-bottom: 1px solid var(--color-border); background: var(--color-canvas); } .profile-modal .birth-section { padding-top: var(--space-5); } .avatar-section { padding-top: 0; } @@ -1766,6 +1769,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .select-list { max-height: min(288px, 48dvh) !important; } .account-modal { max-height: calc(100dvh - var(--space-8)); padding: var(--space-6); } .profile-modal .account-modal-header { margin: calc(var(--space-6) * -1) calc(var(--space-6) * -1) var(--space-4); padding: var(--space-6) var(--space-6) var(--space-4); } + .chart-library-modal .account-modal-header { margin: calc(var(--space-6) * -1) calc(var(--space-6) * -1) var(--space-4); padding: var(--space-6) var(--space-6) var(--space-4); } .avatar-editor { grid-template-columns: 72px minmax(0, 1fr); gap: var(--space-4); } .avatar-editor > .user-avatar { width: 72px !important; height: 72px !important; } .avatar-palette-list { grid-template-columns: repeat(2, minmax(64px, 1fr)); } diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index dddb3319..a91b6d5b 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -272,7 +272,7 @@ type Account = { profile: unknown; }; type OnboardingStep = "name" | "birth" | "place" | "rectification"; -type AccountDialog = "profile" | "logout"; +type AccountDialog = "profile" | "chart-library" | "logout"; type DailyStarlanguageCard = { trend: string; action: string; caution: string }; type DailyStarlanguageApiResponse = { status?: "ok" | "unavailable" | "unauthenticated"; @@ -356,11 +356,13 @@ const themes = defaultGuidedJyotishTopics; const accountDialogTitles = { profile: "个人资料", + "chart-library": "星盘资料", logout: "退出登录?", } as const satisfies Record; const accountDialogClasses = { profile: "profile-modal", + "chart-library": "chart-library-modal", logout: "logout-modal", } as const satisfies Record; @@ -1197,7 +1199,6 @@ export default function Home() { const modelSelectionVersions = useRef(new Map()); const activeSessionIdRef = useRef(""); const chartLibraryLoadedAccount = useRef(""); - const openChartLibraryOnDialog = useRef(false); const accountOverlayRef = useRef(null); const accountOverlayEpochRef = useRef(0); const chatActionsRef = useRef({ @@ -3797,14 +3798,9 @@ export default function Home() { dialogClass: activeAccountDialog ? accountDialogClasses[activeAccountDialog] : "", signingOut, close: closeAccountDialog, - takeOpenLibraryRequest() { - if (!openChartLibraryOnDialog.current) return false; - openChartLibraryOnDialog.current = false; - return true; - }, overlayRef: accountDialog, closeButtonRef: closeButton, - renderProfile(library) { + renderProfile() { return ( <> {accountError &&

{accountError}

} @@ -3855,9 +3851,22 @@ export default function Home() { {profileDraft.name.trim() || "未命名"} 角色:本人 - + - {library.open && ( + + + {profileNotice &&

{profileNotice}

} +
+ + + + + ); + }, + renderChartLibrary() { + return ( + <> +

管理本人和其他人的出生资料,之后可直接用于切换默认星盘或发起合盘。

本人 @@ -3929,13 +3938,6 @@ export default function Home() {
- )} - - {profileNotice &&

{profileNotice}

} -
- - - ); }, @@ -3995,15 +3997,10 @@ export default function Home() { onNewChat={() => void startNewChat()} onOpenReports={() => router.push("/reports")} onSelectSession={selectSession} - onSelectChart={() => { - openChartLibraryOnDialog.current = true; - openAccountDialog("profile"); - }} - onAddChart={() => { - openChartLibraryOnDialog.current = true; - openAccountDialog("profile"); - }} + onSelectChart={() => openAccountDialog("chart-library")} + onAddChart={() => openAccountDialog("chart-library")} onOpenProfile={() => openAccountDialog("profile")} + onOpenChartLibrary={() => openAccountDialog("chart-library")} onOpenRedeem={() => router.push(membershipHref("account-menu"))} onOpenLogout={() => openAccountDialog("logout")} /> diff --git a/frontend/src/components/account-dialog-overlay.tsx b/frontend/src/components/account-dialog-overlay.tsx index 1b8638c2..3c360fd4 100644 --- a/frontend/src/components/account-dialog-overlay.tsx +++ b/frontend/src/components/account-dialog-overlay.tsx @@ -1,22 +1,17 @@ "use client"; import { X } from "lucide-react"; -import { memo, useEffect, useState, type MutableRefObject, type ReactNode } from "react"; - -export type AccountOverlayLibraryControls = Readonly<{ - open: boolean; - toggle: () => void; -}>; +import { memo, type MutableRefObject, type ReactNode } from "react"; export type AccountOverlayModel = Readonly<{ title: string; dialogClass: string; signingOut: boolean; close: () => void; - takeOpenLibraryRequest: () => boolean; overlayRef: MutableRefObject; closeButtonRef: MutableRefObject; - renderProfile: (library: AccountOverlayLibraryControls) => ReactNode; + renderProfile: () => ReactNode; + renderChartLibrary: () => ReactNode; renderLogout: () => ReactNode; }>; @@ -27,17 +22,10 @@ export const AccountDialogOverlay = memo(function AccountDialogOverlay({ modelRef, }: Readonly<{ open: boolean; - dialog: "profile" | "logout" | null; + dialog: "profile" | "chart-library" | "logout" | null; openEpoch: number; modelRef: MutableRefObject; }>) { - const [chartLibraryOpen, setChartLibraryOpen] = useState(false); - - useEffect(() => { - if (!open) return; - if (modelRef.current?.takeOpenLibraryRequest()) setChartLibraryOpen(true); - }, [dialog, modelRef, open]); - if (!open || dialog === null) return null; const model = modelRef.current; if (!model) return null; @@ -66,10 +54,8 @@ export const AccountDialogOverlay = memo(function AccountDialogOverlay({
diff --git a/frontend/src/components/app-sidebar.tsx b/frontend/src/components/app-sidebar.tsx index 324f5b48..119a2b67 100644 --- a/frontend/src/components/app-sidebar.tsx +++ b/frontend/src/components/app-sidebar.tsx @@ -71,6 +71,7 @@ export type AppSidebarProps = { onSelectChart: (chartId: string) => void; onAddChart: () => void; onOpenProfile: () => void; + onOpenChartLibrary: () => void; onOpenRedeem: () => void; onOpenLogout: () => void; }; @@ -92,6 +93,7 @@ export function AppSidebar({ onSelectChart, onAddChart, onOpenProfile, + onOpenChartLibrary, onOpenRedeem, onOpenLogout, }: AppSidebarProps) { @@ -303,6 +305,9 @@ export function AppSidebar({ + + diff --git a/frontend/tests/account-dialog-overlay.test.ts b/frontend/tests/account-dialog-overlay.test.ts index 28cf25d3..489863ac 100644 --- a/frontend/tests/account-dialog-overlay.test.ts +++ b/frontend/tests/account-dialog-overlay.test.ts @@ -19,13 +19,15 @@ test("a closed account overlay does not render profile or logout content", () => dialogClass: "profile-modal", signingOut: false, close() {}, - takeOpenLibraryRequest() { return false; }, overlayRef, closeButtonRef, renderProfile() { profileRenders += 1; return null; }, + renderChartLibrary() { + return null; + }, renderLogout() { logoutRenders += 1; return null;