Skip to content

Commit 60b46d8

Browse files
committed
docs: 优化附件管理器
1 parent 42dd103 commit 60b46d8

File tree

1 file changed

+65
-52
lines changed

1 file changed

+65
-52
lines changed

app/src/sub/AttachmentsWindow.tsx

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { Button } from "@/components/ui/button";
22
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu";
33
import { Dialog } from "@/components/ui/dialog";
44
import { Popover } from "@/components/ui/popover";
5-
import { Separator } from "@/components/ui/separator";
65
import { SubWindow } from "@/core/service/SubWindow";
76
import { activeProjectAtom } from "@/state";
87
import { Vector } from "@graphif/data-structures";
@@ -44,7 +43,7 @@ export default function AttachmentsWindow() {
4443
}, [attachments]);
4544

4645
return (
47-
<div className="flex flex-col gap-4 p-4">
46+
<div className="bg-background flex flex-col gap-2 p-2">
4847
<div className="flex gap-3">
4948
<Button
5049
onClick={async () => {
@@ -71,17 +70,21 @@ export default function AttachmentsWindow() {
7170
title="清理附件"
7271
description="删除所有未被实体引用的附件,且此操作不可撤销,是否继续?"
7372
onConfirm={async () => {
73+
let deletedCount = 0;
7474
const referencedAttachmentIds = project.stageManager
7575
.getEntities()
7676
.map((it) => ("attachmentId" in it ? (it.attachmentId as string) : ""))
7777
.filter(Boolean);
7878
for (const id of project.attachments.keys()) {
7979
if (!referencedAttachmentIds.includes(id)) {
8080
project.attachments.delete(id);
81+
deletedCount++;
8182
}
8283
}
83-
refresh();
84-
toast.success("ok");
84+
toast.success(`已清理 ${deletedCount} 个未被引用的附件`);
85+
setTimeout(() => {
86+
refresh();
87+
}, 500); // TODO: 在windows上未生效
8588
}}
8689
destructive
8790
>
@@ -91,56 +94,66 @@ export default function AttachmentsWindow() {
9194
</Button>
9295
</Popover.Confirm>
9396
</div>
94-
{attachments.entries().map(([id, blob]) => (
95-
<ContextMenu key={id}>
96-
<ContextMenuTrigger>
97-
<div className="flex flex-col gap-2">
98-
<Separator />
99-
<div className="flex flex-col gap-0.5">
100-
<span className="text-xs opacity-50">{id}</span>
101-
<div className="flex flex-wrap gap-x-2">
102-
<span>{blob.type}</span>
103-
<span>{formatBytes(blob.size)}</span>
97+
<div>
98+
<span className="text-xs opacity-50">提示:对着附件右键可进行操作</span>
99+
</div>
100+
101+
{/* 一个又一个的附件展示 */}
102+
<div className="flex flex-wrap gap-1">
103+
{attachments.entries().map(([id, blob]) => (
104+
<ContextMenu key={id}>
105+
{/* 非右键的直接展示部分 */}
106+
<ContextMenuTrigger>
107+
<div className="bg-card hover:bg-primary text-primary hover:text-primary-foreground flex flex-col gap-2 rounded-sm p-1 transition-colors hover:ring">
108+
{/* <Separator /> */}
109+
{blob.type.startsWith("image") && (
110+
<img src={urls.get(id)} alt={id} className="max-h-12 max-w-full object-contain" />
111+
)}
112+
<div className="flex flex-col gap-0.5">
113+
<span className="text-[6px] opacity-50">{id}</span>
114+
<div className="flex flex-wrap gap-x-2 text-xs">
115+
<span>{blob.type}</span>
116+
<span>{formatBytes(blob.size)}</span>
117+
</div>
104118
</div>
105119
</div>
106-
{blob.type.startsWith("image") && (
107-
<img src={urls.get(id)} alt={id} className="max-h-64 max-w-full object-contain" />
108-
)}
109-
</div>
110-
</ContextMenuTrigger>
111-
<ContextMenuContent>
112-
<ContextMenuItem
113-
onClick={async () => {
114-
const path = await save({
115-
filters: [
116-
{
117-
name: blob.type,
118-
extensions: [...(mime.getAllExtensions(blob.type) ?? [])],
119-
},
120-
],
121-
});
122-
if (!path) return;
123-
await writeFile(path, new Uint8Array(await blob.arrayBuffer()));
124-
}}
125-
>
126-
<FileOutput />
127-
导出
128-
</ContextMenuItem>
129-
<ContextMenuItem
130-
variant="destructive"
131-
onClick={async () => {
132-
if (await Dialog.confirm("删除附件", "所有引用了此附件的实体将无法正常渲染", { destructive: true })) {
133-
project.attachments.delete(id);
134-
refresh();
135-
}
136-
}}
137-
>
138-
<Trash />
139-
删除
140-
</ContextMenuItem>
141-
</ContextMenuContent>
142-
</ContextMenu>
143-
))}
120+
</ContextMenuTrigger>
121+
122+
{/* 右键内容 */}
123+
<ContextMenuContent>
124+
<ContextMenuItem
125+
onClick={async () => {
126+
const path = await save({
127+
filters: [
128+
{
129+
name: blob.type,
130+
extensions: [...(mime.getAllExtensions(blob.type) ?? [])],
131+
},
132+
],
133+
});
134+
if (!path) return;
135+
await writeFile(path, new Uint8Array(await blob.arrayBuffer()));
136+
}}
137+
>
138+
<FileOutput />
139+
导出
140+
</ContextMenuItem>
141+
<ContextMenuItem
142+
variant="destructive"
143+
onClick={async () => {
144+
if (await Dialog.confirm("删除附件", "所有引用了此附件的实体将无法正常渲染", { destructive: true })) {
145+
project.attachments.delete(id);
146+
refresh();
147+
}
148+
}}
149+
>
150+
<Trash />
151+
删除
152+
</ContextMenuItem>
153+
</ContextMenuContent>
154+
</ContextMenu>
155+
))}
156+
</div>
144157
</div>
145158
);
146159
}

0 commit comments

Comments
 (0)