mirror of
https://github.com/dataelement/bisheng.git
synced 2026-09-21 12:43:36 +08:00
refactor(client): migrate SharedLinks + guest-convo delete to the unified ConfirmDialog (UI unification infra)
Replace OGDialog/OGDialogTemplate delete confirmations in SharedLinks and the standalone guest-convo item with useConfirm; touch up the ConfirmDialog + Modal gallery sections. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0836db4b6f
commit
1166f52aa1
@@ -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<SharedLinksListParams>(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<SharedLinkItem | null>(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() {
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="h-8 w-8 p-0 hover:bg-surface-hover"
|
||||
onClick={() => {
|
||||
setDeleteRow(row.original);
|
||||
setIsDeleteOpen(true);
|
||||
}}
|
||||
onClick={() => handleDeleteClick(row.original)}
|
||||
title={localize('com_ui_delete')}
|
||||
>
|
||||
<TrashIcon className="size-4" />
|
||||
@@ -261,7 +261,7 @@ export default function SharedLinks() {
|
||||
),
|
||||
},
|
||||
],
|
||||
[isSmallScreen, localize],
|
||||
[isSmallScreen, localize, handleDeleteClick],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -294,31 +294,6 @@ export default function SharedLinks() {
|
||||
/>
|
||||
</OGDialogContent>
|
||||
</OGDialog>
|
||||
<OGDialog open={isDeleteOpen} onOpenChange={setIsDeleteOpen}>
|
||||
<OGDialogTemplate
|
||||
showCloseButton={false}
|
||||
title={localize('com_ui_delete_shared_link')}
|
||||
className="max-w-[450px]"
|
||||
main={
|
||||
<>
|
||||
<div className="flex w-full flex-col items-center gap-2">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label htmlFor="dialog-confirm-delete" className="text-left text-sm font-medium">
|
||||
{localize('com_ui_delete_confirm')} <strong>{deleteRow?.title}</strong>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
selection={{
|
||||
selectHandler: confirmDelete,
|
||||
selectClasses: `bg-red-700 dark:bg-red-600 hover:bg-red-800 dark:hover:bg-red-800 text-white ${
|
||||
deleteMutation.isLoading ? 'cursor-not-allowed opacity-80' : ''
|
||||
}`,
|
||||
selectText: deleteMutation.isLoading ? <Spinner /> : localize('com_ui_delete'),
|
||||
}}
|
||||
/>
|
||||
</OGDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -109,8 +109,9 @@ export function ConfirmDialogSection() {
|
||||
subtitle={
|
||||
<>
|
||||
删除/危险操作时的「确认 / 取消」小弹窗。两套体系:旧页面走{' '}
|
||||
<code>OGDialogTemplate selection</code>(剩 14 文件),新页面走 <code>useConfirm()</code>
|
||||
(24 文件,含已迁入的 8 处)。<b>收敛第一步已完成</b>:B 套壳与按钮已对齐 C 套,历史 9 种 selectClasses
|
||||
<code>OGDialogTemplate selection</code>(剩 13 文件:7 处死 UI 确认 + 6 处表单弹窗),新页面走{' '}
|
||||
<code>useConfirm()</code>(26 文件,含已迁入的 10 处)。
|
||||
<b>用户可见的真确认已全部迁完</b>;死 UI(被注释的 SidePanel 树 + 无人引用的 Chat/Header 树)待死代码清理,表单弹窗归 Modal 期。<b>收敛第一步已完成</b>:B 套壳与按钮已对齐 C 套,历史 9 种 selectClasses
|
||||
被自动折叠为 danger / primary 两档 —— 下方旧写法卡片现在应呈现统一外观,逐个打开即是验收。
|
||||
(另有 9 个文件手拼 <code>AlertDialog</code> —— 属于普通弹窗,归 Modal 改造范围,本期不动。)
|
||||
</>
|
||||
@@ -126,7 +127,7 @@ export function ConfirmDialogSection() {
|
||||
<>
|
||||
<code>OGDialogTemplate</code> + <code>selection</code>
|
||||
</>,
|
||||
'14(原 21,迁移中)',
|
||||
'13(原 21;剩余全是死 UI 或表单)',
|
||||
'旧页面(会话/书签/Agent/设置/Prompt…LibreChat 血统)',
|
||||
'差 · 确认按钮 9 种写法',
|
||||
],
|
||||
@@ -135,7 +136,7 @@ export function ConfirmDialogSection() {
|
||||
<>
|
||||
<code>useConfirm()</code>(ConfirmContext + AlertDialog)
|
||||
</>,
|
||||
'24(收敛目标,含已迁入 8 处)',
|
||||
'26(收敛完成,含已迁入 10 处)',
|
||||
'新页面(知识空间 / 订阅频道 / 权限)',
|
||||
'好 · 样式集中在一个文件,destructive/default 两档',
|
||||
],
|
||||
@@ -151,20 +152,20 @@ export function ConfirmDialogSection() {
|
||||
[
|
||||
'1',
|
||||
<code key="c">bg-red-700 dark:bg-red-600 hover:bg-red-800 …</code>,
|
||||
'删除(书签/工具/分享链接…)· 删会话 2 处已迁 C',
|
||||
'6(原 8)',
|
||||
'可达的 4 处已迁 C;剩 4 处全是死 UI(书签/分享弹窗/两个工具移除)',
|
||||
'4(原 8)· 全死 UI',
|
||||
],
|
||||
[
|
||||
'2',
|
||||
<code key="c">bg-red-600 hover:bg-red-700 dark:hover:bg-red-800</code>,
|
||||
'删除(Agent / Assistant)· Prompt 组已迁 C',
|
||||
'2(原 3)',
|
||||
'删除 Agent / Assistant —— 死 UI(SidePanel 被注释)',
|
||||
'2(原 3)· 全死 UI',
|
||||
],
|
||||
[
|
||||
'3',
|
||||
<code key="c">bg-red-600 hover:bg-red-700 dark:hover:bg-red-600</code>,
|
||||
'清空预设',
|
||||
'1',
|
||||
'清空预设 —— 死 UI(Chat/Header 无人引用)',
|
||||
'1 · 死 UI',
|
||||
],
|
||||
[
|
||||
'4',
|
||||
@@ -292,7 +293,7 @@ export function ConfirmDialogSection() {
|
||||
/>
|
||||
<ConfirmDemo
|
||||
label="Loading 态(isLoading: true)"
|
||||
note="模板内置 Spinner · 自塞 Spinner 的只剩 SharedLinks 1 处(原 4 处,3 处已迁 C)"
|
||||
note="模板内置 Spinner · 各页自塞 Spinner 的写法已随迁移清零(原 4 处)"
|
||||
title="删除会话"
|
||||
body="确认按钮处于加载中。"
|
||||
selectText="删除"
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
/**
|
||||
* Modal / Dialog gallery — DEV-ONLY. See docs-ui-refactor/组件-Modal弹窗.md.
|
||||
*
|
||||
* Renders BiSheng's two parallel dialog families side by side so the difference
|
||||
* (overlay darkness / blur / z-index) is visible by opening them.
|
||||
* Fresh survey (2026-07-09): FIVE coexisting modal populations. The same demo
|
||||
* content (title + description + input + cancel/confirm footer) is mounted into
|
||||
* each shell so the shell differences (overlay / radius / padding / title /
|
||||
* buttons) are the only variable when opening them side by side.
|
||||
*/
|
||||
import { Button } from '~/components/ui/Button';
|
||||
import { Input } from '~/components/ui/Input';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
@@ -23,16 +26,46 @@ import {
|
||||
OGDialogTitle,
|
||||
OGDialogDescription,
|
||||
} from '~/components/ui/OriginalDialog';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
} from '~/components/ui/AlertDialog';
|
||||
import DialogTemplate from '~/components/ui/DialogTemplate';
|
||||
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
|
||||
import { useConfirm } from '~/Providers';
|
||||
import { Section, Demo, DemoGrid, CompareTable } from '../components/kit';
|
||||
|
||||
const sampleBody = (
|
||||
<p className="text-sm text-text-primary">
|
||||
这里是弹窗正文示例。放一段说明文字、表单或列表,用来观察内边距、行距与滚动表现。
|
||||
</p>
|
||||
/** Identical body for every shell so only the shell itself differs. */
|
||||
const demoBody = (
|
||||
<div className="flex flex-col gap-3">
|
||||
<p className="text-sm text-text-primary">
|
||||
这里是弹窗正文示例。观察内边距、行距与正文和标题/按钮的间距。
|
||||
</p>
|
||||
<Input placeholder="示例输入框" />
|
||||
</div>
|
||||
);
|
||||
|
||||
/** Small reference demo of the finalized confirm dialog, for shell comparison. */
|
||||
function ConfirmReferenceDemo() {
|
||||
const confirm = useConfirm();
|
||||
return (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
confirm({
|
||||
variant: 'destructive',
|
||||
title: '确认删除',
|
||||
description: '弹窗壳视觉参照:圆角16 / p-5 / 灰底毛玻璃遮罩。',
|
||||
confirmText: '确认删除',
|
||||
})
|
||||
}
|
||||
>
|
||||
打开
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export function ModalSection() {
|
||||
return (
|
||||
<Section
|
||||
@@ -40,94 +73,263 @@ export function ModalSection() {
|
||||
title="Modal 弹窗"
|
||||
subtitle={
|
||||
<>
|
||||
现状有 <b>两套并行体系</b>:A 套 <code>Dialog</code>(毛玻璃遮罩 z-100)与 B 套{' '}
|
||||
<code>OriginalDialog / OG</code>(纯深色遮罩 z-50)。逐个打开对比背景暗度、模糊、层级。
|
||||
2026-07-09 重新盘点:全站普通弹窗共 <b>5 个并行体系、约 64 个业务文件</b>
|
||||
。二次确认期已把 B 套壳对齐 C 套视觉,但 A 套(原语直接拼 22 处 + 模板 3
|
||||
处)与手拼 AlertDialog(7 处)仍是另外两种壳。逐个打开对比,定统一标准。
|
||||
</>
|
||||
}
|
||||
>
|
||||
{/* Difference table */}
|
||||
<div className="mb-6">
|
||||
{/* ① Population overview */}
|
||||
<h3 className="mb-3 mt-2 text-base font-semibold text-text-primary">
|
||||
① 用量盘子(当前精确扫描,排除 ui/ 与画廊)
|
||||
</h3>
|
||||
<div className="mb-8">
|
||||
<CompareTable
|
||||
head={['维度', 'A 套 Dialog', 'B 套 OriginalDialog / OG']}
|
||||
head={['体系', '实现', '业务文件数', '用在哪 / 备注']}
|
||||
rows={[
|
||||
['遮罩颜色', 'bg-black/40(浅)', 'bg-black/80(深)'],
|
||||
['毛玻璃模糊', '有 backdrop-blur-md', '无'],
|
||||
['层级 z-index', 'z-[100]', 'z-50'],
|
||||
['便捷模板', 'DialogTemplate(~4 处)', 'OGDialogTemplate(~25 处 · 用得最多)'],
|
||||
[
|
||||
'A 套 · 原语直接拼',
|
||||
'Dialog + DialogContent 手拼',
|
||||
<b key="a1">22(最大人群)</b>,
|
||||
'新页面为主:知识库 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 壳的天然候选',
|
||||
],
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DemoGrid cols={4}>
|
||||
{/* A-set raw primitives */}
|
||||
<Demo label="A 套 · Dialog 原语" note="ui/Dialog.tsx · 毛玻璃遮罩">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Dialog 原语</DialogTitle>
|
||||
<DialogDescription>手动拼 Header / Footer 的底层版本。</DialogDescription>
|
||||
</DialogHeader>
|
||||
{sampleBody}
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
{/* ② Shell anatomy */}
|
||||
<h3 className="mb-3 text-base font-semibold text-text-primary">
|
||||
② 壳样式解剖(源码当前真实值)
|
||||
</h3>
|
||||
<div className="mb-8">
|
||||
<CompareTable
|
||||
head={['维度', 'A 套 Dialog', 'B 套 OriginalDialog(已对齐 C 套)', 'AlertDialog(手拼底座)']}
|
||||
rows={[
|
||||
[
|
||||
'遮罩',
|
||||
'bg-black/40 + blur(浅黑毛玻璃)',
|
||||
'bg-gray-500/90 + blur(灰白毛玻璃)',
|
||||
'bg-gray-500/90 + blur(同 B)',
|
||||
],
|
||||
['层级 z-index', 'z-[100]', 'z-50', 'z-[110]'],
|
||||
['圆角', 'sm:rounded-lg(8px,移动端直角)', 'rounded-2xl(16px)', 'sm:rounded-lg(8px,移动端直角)'],
|
||||
['内边距', 'p-5(20px)', 'p-5(20px)', 'p-6(24px)'],
|
||||
[
|
||||
'边框 / 阴影',
|
||||
'border + shadow-lg',
|
||||
'border #ebebeb + 淡投影',
|
||||
'无边框、无阴影',
|
||||
],
|
||||
[
|
||||
'标题',
|
||||
'text-base font-semibold',
|
||||
'text-base font-medium',
|
||||
'组件是 text-lg semibold,但各页多自拼标题行',
|
||||
],
|
||||
[
|
||||
'关闭按钮 ×',
|
||||
'内置右上(可关)',
|
||||
'内置右上(可关)',
|
||||
'无内置,各页自拼',
|
||||
],
|
||||
[
|
||||
'深色模式底色',
|
||||
'dark:bg-[#303134](写死)',
|
||||
'bg-background(跟主题)',
|
||||
'dark:bg-gray-900',
|
||||
],
|
||||
[
|
||||
'移动端行为',
|
||||
'居中缩放出现',
|
||||
'居中缩放出现',
|
||||
'从底部滑入、贴底',
|
||||
],
|
||||
[
|
||||
'footer 按钮',
|
||||
'各页自拼(多为 Button outline + default)',
|
||||
'模板:取消白底描边 + 确认 danger/primary 档;直接拼的各页自理',
|
||||
'各页自拼(红 #F53F3F 等)',
|
||||
],
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* ③ Side-by-side demos — identical content, different shells */}
|
||||
<h3 className="mb-3 text-base font-semibold text-text-primary">
|
||||
③ 同一内容装进各个壳(逐个打开对比)
|
||||
</h3>
|
||||
<div className="mb-8">
|
||||
<DemoGrid cols={3}>
|
||||
{/* A-set raw primitives — the largest population */}
|
||||
<Demo label="A 套 · 原语直接拼(22 处)" note="ui/Dialog.tsx · 浅黑毛玻璃 · 圆角8 · p-5">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>弹窗标题</DialogTitle>
|
||||
<DialogDescription>标题下的说明文字。</DialogDescription>
|
||||
</DialogHeader>
|
||||
{demoBody}
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button variant="outline">取消</Button>
|
||||
</DialogClose>
|
||||
<Button>确定</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Demo>
|
||||
|
||||
{/* A-set template — legacy default black confirm button */}
|
||||
<Demo label="A 套 · DialogTemplate(3 处)" note="旧模板 · 默认黑底确认钮 · 正文额外 px-6">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</DialogTrigger>
|
||||
<DialogTemplate
|
||||
title="弹窗标题"
|
||||
description="标题下的说明文字。"
|
||||
main={demoBody}
|
||||
selection={{ selectHandler: () => null, selectText: '确定' }}
|
||||
/>
|
||||
</Dialog>
|
||||
</Demo>
|
||||
|
||||
{/* B-set template — shell already aligned with C-set */}
|
||||
<Demo label="B 套 · OGDialogTemplate(16 处)" note="壳已对齐 C 套 · 圆角16 · 取消/确认已统一">
|
||||
<OGDialog>
|
||||
<OGDialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</OGDialogTrigger>
|
||||
<OGDialogTemplate
|
||||
title="弹窗标题"
|
||||
description="标题下的说明文字。"
|
||||
className="max-w-md"
|
||||
main={demoBody}
|
||||
selection={{
|
||||
selectHandler: () => null,
|
||||
selectVariant: 'primary',
|
||||
selectText: '确定',
|
||||
}}
|
||||
/>
|
||||
</OGDialog>
|
||||
</Demo>
|
||||
|
||||
{/* B-set raw primitives — same shell, hand-rolled body/footer */}
|
||||
<Demo label="B 套 · OG 原语直接拼(16 处)" note="壳同左 · 头尾各页自拼(设置/Prompts 老页面)">
|
||||
<OGDialog>
|
||||
<OGDialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</OGDialogTrigger>
|
||||
<OGDialogContent className="max-w-md">
|
||||
<OGDialogHeader>
|
||||
<OGDialogTitle>弹窗标题</OGDialogTitle>
|
||||
<OGDialogDescription>标题下的说明文字。</OGDialogDescription>
|
||||
</OGDialogHeader>
|
||||
{demoBody}
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="outline">取消</Button>
|
||||
</DialogClose>
|
||||
<Button>确定</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Demo>
|
||||
<Button>确定</Button>
|
||||
</div>
|
||||
</OGDialogContent>
|
||||
</OGDialog>
|
||||
</Demo>
|
||||
|
||||
{/* A-set template */}
|
||||
<Demo label="A 套 · DialogTemplate" note="ui/DialogTemplate.tsx">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</DialogTrigger>
|
||||
<DialogTemplate
|
||||
title="DialogTemplate"
|
||||
description="传 title / main / buttons 的便捷版。"
|
||||
main={sampleBody}
|
||||
buttons={<Button>确定</Button>}
|
||||
/>
|
||||
</Dialog>
|
||||
</Demo>
|
||||
{/* Hand-rolled AlertDialog population */}
|
||||
<Demo
|
||||
label="手拼 AlertDialog(7 处)"
|
||||
note="p-6 · 圆角8 · 无边框阴影 · z-110 · 移动端贴底滑入"
|
||||
>
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent className="max-w-md">
|
||||
{/* Business pages hand-roll header/footer like this (ChannelMemberDialog etc.) */}
|
||||
<h3 className="text-base font-medium text-text-primary">弹窗标题</h3>
|
||||
{demoBody}
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button variant="outline">取消</Button>
|
||||
<Button>确定</Button>
|
||||
</div>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</Demo>
|
||||
|
||||
{/* B-set raw primitives */}
|
||||
<Demo label="B 套 · OG 原语" note="ui/OriginalDialog.tsx · 纯深色遮罩">
|
||||
<OGDialog>
|
||||
<OGDialogTrigger asChild>
|
||||
<Button variant="outline">打开</Button>
|
||||
</OGDialogTrigger>
|
||||
<OGDialogContent className="w-11/12 max-w-lg bg-background text-foreground">
|
||||
<OGDialogHeader>
|
||||
<OGDialogTitle>OG 原语</OGDialogTitle>
|
||||
<OGDialogDescription>OriginalDialog 底层版本。</OGDialogDescription>
|
||||
</OGDialogHeader>
|
||||
<div className="py-2">{sampleBody}</div>
|
||||
</OGDialogContent>
|
||||
</OGDialog>
|
||||
</Demo>
|
||||
{/* C-set reference — the finalized confirm shell */}
|
||||
<Demo
|
||||
label="C 套 · useConfirm 参照(已定稿)"
|
||||
note="二次确认基准壳:圆角16 / p-5 / 灰底毛玻璃 —— Modal 壳候选"
|
||||
>
|
||||
<ConfirmReferenceDemo />
|
||||
</Demo>
|
||||
</DemoGrid>
|
||||
</div>
|
||||
|
||||
{/* B-set template — the most used one */}
|
||||
<Demo label="B 套 · OGDialogTemplate" note="用得最多 · 基准候选">
|
||||
<OGDialog>
|
||||
<OGDialogTrigger asChild>
|
||||
<Button>打开</Button>
|
||||
</OGDialogTrigger>
|
||||
<OGDialogTemplate
|
||||
title="OGDialogTemplate"
|
||||
description="全站用得最多的便捷模板,收敛基准候选。"
|
||||
className="max-w-lg"
|
||||
main={sampleBody}
|
||||
buttons={<Button>确定</Button>}
|
||||
/>
|
||||
</OGDialog>
|
||||
</Demo>
|
||||
</DemoGrid>
|
||||
{/* ④ Decision checklist */}
|
||||
<h3 className="mb-3 text-base font-semibold text-text-primary">④ 待设计师定夺</h3>
|
||||
<div className="rounded-xl border border-border-light bg-muted/20 p-5 text-sm leading-7 text-text-primary">
|
||||
<ol className="list-decimal space-y-1 pl-5">
|
||||
<li>
|
||||
<b>遮罩</b>:A 套浅黑毛玻璃(black/40+blur) vs B/C 套灰白毛玻璃(gray-500/90+blur)?
|
||||
(纯深色 black/80 已在二次确认期淘汰)
|
||||
</li>
|
||||
<li>
|
||||
<b>圆角</b>:8px(A 套 / AlertDialog) vs 16px(B/C 套)?移动端是否保留直角/贴底?
|
||||
</li>
|
||||
<li>
|
||||
<b>内边距</b>:p-5(20px,A/B/C) vs p-6(24px,AlertDialog)?header/body/footer 间距(当前统一 gap-4)?
|
||||
</li>
|
||||
<li>
|
||||
<b>标题</b>:font-semibold(A 套) vs font-medium(B/C 套)?
|
||||
</li>
|
||||
<li>
|
||||
<b>关闭按钮 ×</b>:样式与位置(当前 A/B 内置右上小 ×,AlertDialog 各页自拼)?
|
||||
</li>
|
||||
<li>
|
||||
<b>footer 按钮</b>:普通弹窗的取消/确定用 Button 组件(outline+default) 还是 C
|
||||
套确认弹窗那对(白底描边 + danger/primary)?按钮间距 gap-2 vs gap-3?
|
||||
</li>
|
||||
<li>
|
||||
<b>层级</b>:z-50 / z-[100] / z-[110] 三档并存,统一到几?(需盘 Drawer/Sheet/Popover 的层级关系)
|
||||
</li>
|
||||
<li>
|
||||
<b>原语收敛</b>:A 套 22 处直拼是最大人群 —— 是把 A 套壳改成标准(业务零改动),还是逐批迁 B 套?
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<HTMLInputElement>(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 (
|
||||
<div
|
||||
@@ -96,7 +104,7 @@ export function GuestConvoItem({ conv, isActive, onClick, onRename, onDelete }:
|
||||
renaming ? 'bg-[#EEE]' : '',
|
||||
)}
|
||||
onClick={(e) => {
|
||||
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: <Trash className="icon-sm mr-2 text-text-primary" />,
|
||||
hideOnClick: false,
|
||||
@@ -184,31 +192,6 @@ export function GuestConvoItem({ conv, isActive, onClick, onRename, onDelete }:
|
||||
]}
|
||||
menuId={menuId}
|
||||
/>
|
||||
|
||||
{/* Delete confirmation dialog */}
|
||||
{showDeleteDialog && (
|
||||
<OGDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog} triggerRef={deleteButtonRef}>
|
||||
<OGDialogTemplate
|
||||
showCloseButton={false}
|
||||
title={localize('com_ui_delete_conversation')}
|
||||
className="max-w-[450px]"
|
||||
main={
|
||||
<div className="flex w-full flex-col items-center gap-2">
|
||||
<div className="grid w-full items-center gap-2">
|
||||
<Label className="text-left text-sm font-medium">
|
||||
{localize('com_ui_delete_confirm')} <strong>{conv.title}</strong>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
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'),
|
||||
}}
|
||||
/>
|
||||
</OGDialog>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user