Files
Jyotisha/frontend/src/components/account-dialog-overlay.tsx
T
Jesse_ChenandCursor 3198fb6b2b
Independent Staging Quality Gate / validate (push) Successful in 10m14s
Independent Staging Quality Gate / publish (push) Successful in 11m5s
perf(frontend): split chat streaming, load Inter, isolate admin CSS
Settled messages no longer rebuild on every token, Inter is actually
requested, and admin routes drop the 33 KB chat stylesheet. Root
force-dynamic is gone so public shells can prerender without changing
the no-store Cache-Control contract.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-29 03:39:43 +08:00

78 lines
2.2 KiB
TypeScript

"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;
}>;
export type AccountOverlayModel = Readonly<{
title: string;
dialogClass: string;
signingOut: boolean;
close: () => void;
takeOpenLibraryRequest: () => boolean;
overlayRef: MutableRefObject<HTMLElement | null>;
closeButtonRef: MutableRefObject<HTMLButtonElement | null>;
renderProfile: (library: AccountOverlayLibraryControls) => ReactNode;
renderLogout: () => ReactNode;
}>;
export const AccountDialogOverlay = memo(function AccountDialogOverlay({
open,
dialog,
openEpoch,
modelRef,
}: Readonly<{
open: boolean;
dialog: "profile" | "logout" | null;
openEpoch: number;
modelRef: MutableRefObject<AccountOverlayModel | null>;
}>) {
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;
void openEpoch;
return (
<div className="account-modal-overlay" onMouseDown={model.close}>
<section
className={`account-modal ${model.dialogClass}`}
ref={model.overlayRef}
role="dialog"
aria-modal="true"
aria-labelledby="account-dialog-title"
onMouseDown={(event) => event.stopPropagation()}
>
<header className="account-modal-header">
<h2 id="account-dialog-title">{model.title}</h2>
<button
className="dialog-close"
ref={model.closeButtonRef}
aria-label="关闭"
type="button"
onClick={model.close}
disabled={model.signingOut}
>
<X aria-hidden="true" />
</button>
</header>
{dialog === "profile" && model.renderProfile({
open: chartLibraryOpen,
toggle: () => setChartLibraryOpen((current) => !current),
})}
{dialog === "logout" && model.renderLogout()}
</section>
</div>
);
});