diff --git a/src/frontend/client/src/components/Nav/SettingsTabs/Data/SharedLinks.tsx b/src/frontend/client/src/components/Nav/SettingsTabs/Data/SharedLinks.tsx index 2e053f81d..48cb09f6c 100644 --- a/src/frontend/client/src/components/Nav/SettingsTabs/Data/SharedLinks.tsx +++ b/src/frontend/client/src/components/Nav/SettingsTabs/Data/SharedLinks.tsx @@ -14,13 +14,11 @@ import { Label, } from '~/components/ui'; import { useDeleteSharedLinkMutation, useSharedLinksQuery } from '~/hooks/queries/data-provider'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; import { useLocalize, usePrefersMobileLayout } from '~/hooks'; import DataTable from '~/components/ui/DataTable'; import { NotificationSeverity } from '~/common'; -import { useToastContext } from '~/Providers'; +import { useToastContext, useConfirm } from '~/Providers'; import { formatDate } from '~/utils'; -import { Spinner } from '~/components/svg'; const PAGE_SIZE = 25; @@ -37,7 +35,6 @@ export default function SharedLinks() { const { showToast } = useToastContext(); const isSmallScreen = usePrefersMobileLayout(); const [queryParams, setQueryParams] = useState(DEFAULT_PARAMS); - const [isDeleteOpen, setIsDeleteOpen] = useState(false); const [isOpen, setIsOpen] = useState(false); const { data, fetchNextPage, hasNextPage, isFetchingNextPage, refetch, isLoading } = @@ -86,8 +83,6 @@ export default function SharedLinks() { const deleteMutation = useDeleteSharedLinkMutation({ onSuccess: async () => { - setIsDeleteOpen(false); - setDeleteRow(null); await refetch(); }, onError: (error) => { @@ -144,14 +139,22 @@ export default function SharedLinks() { await fetchNextPage(); }, [fetchNextPage, hasNextPage, isFetchingNextPage]); - const [deleteRow, setDeleteRow] = useState(null); - - const confirmDelete = useCallback(() => { - if (deleteRow) { - handleDelete([deleteRow]); - } - setIsDeleteOpen(false); - }, [deleteRow, handleDelete]); + const confirm = useConfirm(); + const handleDeleteClick = useCallback( + async (row: SharedLinkItem) => { + const ok = await confirm({ + variant: 'destructive', + title: localize('com_ui_delete_shared_link'), + description: `${localize('com_ui_delete_confirm')} "${row.title}"`, + confirmText: localize('com_ui_delete'), + }); + if (!ok) { + return; + } + handleDelete([row]); + }, + [confirm, localize, handleDelete], + ); const columns = useMemo( () => [ @@ -247,10 +250,7 @@ export default function SharedLinks() { + ); +} + export function ModalSection() { return (
- 现状有 两套并行体系:A 套 Dialog(毛玻璃遮罩 z-100)与 B 套{' '} - OriginalDialog / OG(纯深色遮罩 z-50)。逐个打开对比背景暗度、模糊、层级。 + 2026-07-09 重新盘点:全站普通弹窗共 5 个并行体系、约 64 个业务文件 + 。二次确认期已把 B 套壳对齐 C 套视觉,但 A 套(原语直接拼 22 处 + 模板 3 + 处)与手拼 AlertDialog(7 处)仍是另外两种壳。逐个打开对比,定统一标准。 } > - {/* Difference table */} -
+ {/* ① Population overview */} +

+ ① 用量盘子(当前精确扫描,排除 ui/ 与画廊) +

+
22(最大人群), + '新页面为主:知识库 8、订阅 2、审批/通知/账号/分享/appChat…(含 MainLayout 全局弹窗)', + ], + [ + 'A 套 · 模板', + 'DialogTemplate', + '3', + 'EditPresetDialog、PresetItems、ContextButton(后者在 SidePanel 死树)', + ], + [ + 'B 套 · 模板', + 'OGDialogTemplate', + '16(原 25,确认迁移后)', + '书签/导出/SetKey/归档/Agent 面板…(其中 SidePanel 死树约 6 处);壳已对齐 C 套', + ], + [ + 'B 套 · 原语直接拼', + 'OGDialog + OGDialogContent 手拼', + '16', + '设置(账号/数据)、Prompts、文件预览、ShareAgent…;壳同上(已对齐 C 套)', + ], + [ + '手拼 AlertDialog', + 'AlertDialogContent + 自拼头尾', + '7', + '频道成员 2、爬取系 4、灵思 TaskModeInput(部分带确认性质,本期一并处理)', + ], + [ + 'C 套 · useConfirm(参照)', + 'ConfirmContext(AlertDialog 底层)', + '26(已收敛 ✅)', + '二次确认已定稿的视觉基准:圆角16 / p-5 / 灰底毛玻璃 —— Modal 壳的天然候选', + ], ]} />
- - {/* A-set raw primitives */} - - - - - - - - Dialog 原语 - 手动拼 Header / Footer 的底层版本。 - - {sampleBody} - - + {/* ② Shell anatomy */} +

+ ② 壳样式解剖(源码当前真实值) +

+
+ +
+ + {/* ③ Side-by-side demos — identical content, different shells */} +

+ ③ 同一内容装进各个壳(逐个打开对比) +

+
+ + {/* A-set raw primitives — the largest population */} + + + + + + + + 弹窗标题 + 标题下的说明文字。 + + {demoBody} + + + + + + + + + + + {/* A-set template — legacy default black confirm button */} + + + + + + null, selectText: '确定' }} + /> + + + + {/* B-set template — shell already aligned with C-set */} + + + + + + null, + selectVariant: 'primary', + selectText: '确定', + }} + /> + + + + {/* B-set raw primitives — same shell, hand-rolled body/footer */} + + + + + + + + 弹窗标题 + 标题下的说明文字。 + + {demoBody} +
- - - - -
-
+ +
+ + + - {/* A-set template */} - - - - - - 确定} - /> - - + {/* Hand-rolled AlertDialog population */} + + + + + + + {/* Business pages hand-roll header/footer like this (ChannelMemberDialog etc.) */} +

弹窗标题

+ {demoBody} +
+ + +
+
+
+
- {/* B-set raw primitives */} - - - - - - - - OG 原语 - OriginalDialog 底层版本。 - -
{sampleBody}
-
-
-
+ {/* C-set reference — the finalized confirm shell */} + + + + + - {/* B-set template — the most used one */} - - - - - - 确定} - /> - - - + {/* ④ Decision checklist */} +

④ 待设计师定夺

+
+
    +
  1. + 遮罩:A 套浅黑毛玻璃(black/40+blur) vs B/C 套灰白毛玻璃(gray-500/90+blur)? + (纯深色 black/80 已在二次确认期淘汰) +
  2. +
  3. + 圆角:8px(A 套 / AlertDialog) vs 16px(B/C 套)?移动端是否保留直角/贴底? +
  4. +
  5. + 内边距:p-5(20px,A/B/C) vs p-6(24px,AlertDialog)?header/body/footer 间距(当前统一 gap-4)? +
  6. +
  7. + 标题:font-semibold(A 套) vs font-medium(B/C 套)? +
  8. +
  9. + 关闭按钮 ×:样式与位置(当前 A/B 内置右上小 ×,AlertDialog 各页自拼)? +
  10. +
  11. + footer 按钮:普通弹窗的取消/确定用 Button 组件(outline+default) 还是 C + 套确认弹窗那对(白底描边 + danger/primary)?按钮间距 gap-2 vs gap-3? +
  12. +
  13. + 层级:z-50 / z-[100] / z-[110] 三档并存,统一到几?(需盘 Drawer/Sheet/Popover 的层级关系) +
  14. +
  15. + 原语收敛:A 套 22 处直拼是最大人群 —— 是把 A 套壳改成标准(业务零改动),还是逐批迁 B 套? +
  16. +
+
); } diff --git a/src/frontend/client/src/pages/standaloneChat/components/GuestConvoItem.tsx b/src/frontend/client/src/pages/standaloneChat/components/GuestConvoItem.tsx index bdedf4f0c..4d6dbd59c 100644 --- a/src/frontend/client/src/pages/standaloneChat/components/GuestConvoItem.tsx +++ b/src/frontend/client/src/pages/standaloneChat/components/GuestConvoItem.tsx @@ -7,8 +7,8 @@ import { useLocalize } from '~/hooks'; import { cn } from '~/utils'; import type { AppConversation } from '~/@types/app'; -import { DropdownPopup, OGDialog, Label } from '~/components'; -import OGDialogTemplate from '~/components/ui/OGDialogTemplate'; +import { DropdownPopup } from '~/components'; +import { useConfirm } from '~/Providers'; import TodayItemIcon from '~/components/ui/icon/TodayItem'; type GuestConvoItemProps = { @@ -29,7 +29,7 @@ export function GuestConvoItem({ conv, isActive, onClick, onRename, onDelete }: const [isPopoverActive, setIsPopoverActive] = useState(false); const [renaming, setRenaming] = useState(false); const [titleInput, setTitleInput] = useState(conv.title); - const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const confirm = useConfirm(); const inputRef = useRef(null); const menuId = useId(); @@ -83,10 +83,18 @@ export function GuestConvoItem({ conv, isActive, onClick, onRename, onDelete }: [conv.title], ); - const confirmDelete = useCallback(() => { + const handleDeleteClick = useCallback(async () => { + const ok = await confirm({ + variant: 'destructive', + title: localize('com_ui_delete_conversation'), + description: `${localize('com_ui_delete_confirm')} "${conv.title}"`, + confirmText: localize('com_ui_delete'), + }); + if (!ok) { + return; + } onDelete(conv.id); - setShowDeleteDialog(false); - }, [conv.id, onDelete]); + }, [confirm, localize, conv.title, conv.id, onDelete]); return (
{ - if (renaming || isPopoverActive || showDeleteDialog) return; + if (renaming || isPopoverActive) return; onClick(); }} > @@ -174,7 +182,7 @@ export function GuestConvoItem({ conv, isActive, onClick, onRename, onDelete }: label: localize('com_ui_delete'), onClick: () => { setIsPopoverActive(false); - setShowDeleteDialog(true); + handleDeleteClick(); }, icon: , hideOnClick: false, @@ -184,31 +192,6 @@ export function GuestConvoItem({ conv, isActive, onClick, onRename, onDelete }: ]} menuId={menuId} /> - - {/* Delete confirmation dialog */} - {showDeleteDialog && ( - - -
- -
-
- } - selection={{ - selectHandler: confirmDelete, - selectClasses: 'bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 text-white', - selectText: localize('com_ui_delete'), - }} - /> - - )} )}