Browse Source

修改素材库

feature/composer
TianYun 4 weeks ago
parent
commit
8e3d997a7e
  1. 68
      src/components/AssetLibraryManagerModal.tsx

68
src/components/AssetLibraryManagerModal.tsx

@ -39,7 +39,6 @@ import {
import { AssetLibraryUploadModal, type AssetLibraryUploadFolderOption } from "./AssetLibraryUploadModal"; import { AssetLibraryUploadModal, type AssetLibraryUploadFolderOption } from "./AssetLibraryUploadModal";
type AssetLibraryFileKind = "image" | "video" | "audio" | "other"; type AssetLibraryFileKind = "image" | "video" | "audio" | "other";
type AssetLibraryActionMenuView = "actions" | "move";
interface AssetLibraryManagerModalProps { interface AssetLibraryManagerModalProps {
open: boolean; open: boolean;
@ -158,7 +157,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
const [expandedMoveFolderIds, setExpandedMoveFolderIds] = useState<Set<number>>(new Set()); const [expandedMoveFolderIds, setExpandedMoveFolderIds] = useState<Set<number>>(new Set());
const [moveFolderAncestorIds, setMoveFolderAncestorIds] = useState<Record<number, Set<number>>>({}); const [moveFolderAncestorIds, setMoveFolderAncestorIds] = useState<Record<number, Set<number>>>({});
const [actionMenuOpenId, setActionMenuOpenId] = useState<number | null>(null); const [actionMenuOpenId, setActionMenuOpenId] = useState<number | null>(null);
const [actionMenuView, setActionMenuView] = useState<AssetLibraryActionMenuView>("actions"); const [movePanelOpenId, setMovePanelOpenId] = useState<number | null>(null);
const [batchMode, setBatchMode] = useState(false); const [batchMode, setBatchMode] = useState(false);
const [selectedItemIds, setSelectedItemIds] = useState<Set<number>>(new Set()); const [selectedItemIds, setSelectedItemIds] = useState<Set<number>>(new Set());
const [batchDeleting, setBatchDeleting] = useState(false); const [batchDeleting, setBatchDeleting] = useState(false);
@ -213,7 +212,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
setExpandedMoveFolderIds(new Set()); setExpandedMoveFolderIds(new Set());
setMoveFolderAncestorIds({}); setMoveFolderAncestorIds({});
setActionMenuOpenId(null); setActionMenuOpenId(null);
setActionMenuView("actions"); setMovePanelOpenId(null);
setBatchMode(false); setBatchMode(false);
setSelectedItemIds(new Set()); setSelectedItemIds(new Set());
setBatchDeleting(false); setBatchDeleting(false);
@ -331,7 +330,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
await loadItems(); await loadItems();
await onChanged?.(parentId); await onChanged?.(parentId);
setActionMenuOpenId(null); setActionMenuOpenId(null);
setActionMenuView("actions"); setMovePanelOpenId(null);
void message.success(t("assetLibrary.moveSuccess")); void message.success(t("assetLibrary.moveSuccess"));
} catch (err) { } catch (err) {
const messageText = err instanceof Error ? err.message : t("assetLibrary.moveFailed"); const messageText = err instanceof Error ? err.message : t("assetLibrary.moveFailed");
@ -578,7 +577,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
const isSelfOrDescendant = item.nodeType === "folder" && ( const isSelfOrDescendant = item.nodeType === "folder" && (
folder.id === item.id || Boolean(moveFolderAncestorIds[folder.id]?.has(item.id)) folder.id === item.id || Boolean(moveFolderAncestorIds[folder.id]?.has(item.id))
); );
const disabled = isSelfOrDescendant; const disabled = isSelfOrDescendant || isCurrentParent;
return ( return (
<div key={folder.id}> <div key={folder.id}>
@ -604,10 +603,6 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
if (disabled) return; if (disabled) return;
if (isCurrentParent) {
setActionMenuOpenId(null);
return;
}
void handleMoveItem(item, folder.id); void handleMoveItem(item, folder.id);
}} }}
> >
@ -650,8 +645,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
const rootFolders = moveFoldersByParentId[ROOT_PARENT_ID] ?? []; const rootFolders = moveFoldersByParentId[ROOT_PARENT_ID] ?? [];
const rootLoading = loadingMoveFolderIds.has(ROOT_PARENT_ID); const rootLoading = loadingMoveFolderIds.has(ROOT_PARENT_ID);
return ( return (
<div className="max-h-[280px] min-w-[220px] overflow-y-auto p-1 [scrollbar-color:var(--text-muted)_transparent] [scrollbar-width:thin]"> <div className="max-h-[320px] w-[228px] overflow-y-auto p-1 [scrollbar-color:var(--text-muted)_transparent] [scrollbar-width:thin]">
{item.nodeType === "folder" && (
<button <button
type="button" type="button"
disabled={item.parentId === ROOT_PARENT_ID} disabled={item.parentId === ROOT_PARENT_ID}
@ -663,7 +657,6 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
> >
{t("assetLibrary.rootFolder")} {t("assetLibrary.rootFolder")}
</button> </button>
)}
{rootLoading ? ( {rootLoading ? (
<div className="px-3 py-2 text-sm text-[var(--text-muted)]">{t("common.processing")}</div> <div className="px-3 py-2 text-sm text-[var(--text-muted)]">{t("common.processing")}</div>
) : rootFolders.length > 0 ? ( ) : rootFolders.length > 0 ? (
@ -675,40 +668,31 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
); );
}, [handleMoveItem, loadingMoveFolderIds, moveFoldersByParentId, renderMoveTreeRows, t]); }, [handleMoveItem, loadingMoveFolderIds, moveFoldersByParentId, renderMoveTreeRows, t]);
const handleOpenMovePanel = useCallback((item: UserFileItem) => {
setMovePanelOpenId(item.id);
void loadMoveFolderChildren(ROOT_PARENT_ID);
}, [loadMoveFolderChildren]);
const renderItemActions = useCallback((item: UserFileItem) => { const renderItemActions = useCallback((item: UserFileItem) => {
const isFolder = item.nodeType === "folder"; const isFolder = item.nodeType === "folder";
const isMoveView = actionMenuView === "move"; const movePanelOpen = movePanelOpenId === item.id;
return ( return (
<div <div
className="nodrag nopan nowheel min-w-[168px] rounded-lg bg-[var(--surface-2)] p-1 text-sm text-[var(--text-secondary)] shadow-[var(--shadow-panel)]" className="nodrag nopan nowheel relative min-w-[168px] rounded-lg bg-[var(--surface-2)] p-1 text-sm text-[var(--text-secondary)] shadow-[var(--shadow-panel)]"
onClick={(event) => event.stopPropagation()} onClick={(event) => event.stopPropagation()}
> >
{isMoveView ? (
<>
<div className="mb-1 flex h-8 items-center gap-1 px-1">
<button
type="button"
aria-label={t("common.back")}
className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-[var(--text-muted)] transition-colors hover:bg-[var(--surface-hover)] hover:text-[var(--text-primary)]"
onClick={() => setActionMenuView("actions")}
>
<LeftOutlined className="text-[12px]" />
</button>
<span className="min-w-0 flex-1 truncate text-sm font-medium text-[var(--text-primary)]">
{t("assetLibrary.moveTitle")}
</span>
</div>
{renderMovePanel(item)}
</>
) : (
<div className="flex flex-col"> <div className="flex flex-col">
<button <button
type="button" type="button"
className="flex h-8 w-full items-center gap-2 rounded-md px-3 text-left transition-colors hover:bg-[var(--surface-hover)] hover:text-[var(--text-primary)]" className={[
onClick={() => { "flex h-8 w-full items-center gap-2 rounded-md px-3 text-left transition-colors hover:bg-[var(--surface-hover)] hover:text-[var(--text-primary)]",
setActionMenuView("move"); movePanelOpen ? "bg-[var(--surface-hover)] text-[var(--text-primary)]" : "",
void loadMoveFolderChildren(ROOT_PARENT_ID); ].join(" ")}
onMouseEnter={() => handleOpenMovePanel(item)}
onClick={(event) => {
event.stopPropagation();
handleOpenMovePanel(item);
}} }}
> >
<SwapOutlined className="text-[14px]" /> <SwapOutlined className="text-[14px]" />
@ -734,7 +718,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
setActionMenuOpenId(null); setActionMenuOpenId(null);
setActionMenuView("actions"); setMovePanelOpenId(null);
openRenameModal(item); openRenameModal(item);
}} }}
> >
@ -747,7 +731,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
setActionMenuOpenId(null); setActionMenuOpenId(null);
setActionMenuView("actions"); setMovePanelOpenId(null);
handleDeleteItem(item); handleDeleteItem(item);
}} }}
> >
@ -755,10 +739,14 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
<span>{t("assetLibrary.delete")}</span> <span>{t("assetLibrary.delete")}</span>
</button> </button>
</div> </div>
{movePanelOpen && (
<div className="absolute top-0 left-full z-20 ml-2 rounded-lg border border-[var(--border-subtle)] bg-[var(--surface-2)] text-sm text-[var(--text-secondary)] shadow-[var(--shadow-panel)]">
{renderMovePanel(item)}
</div>
)} )}
</div> </div>
); );
}, [actionMenuView, handleDeleteItem, loadMoveFolderChildren, openRenameModal, renderMovePanel, t]); }, [handleDeleteItem, handleOpenMovePanel, movePanelOpenId, openRenameModal, renderMovePanel, t]);
const renderItem = (item: UserFileItem) => { const renderItem = (item: UserFileItem) => {
const isFolder = item.nodeType === "folder"; const isFolder = item.nodeType === "folder";
@ -848,7 +836,7 @@ export function AssetLibraryManagerModal({ open, onClose, onChanged }: AssetLibr
open={actionMenuOpenId === item.id} open={actionMenuOpenId === item.id}
onOpenChange={(nextOpen) => { onOpenChange={(nextOpen) => {
setActionMenuOpenId(nextOpen ? item.id : null); setActionMenuOpenId(nextOpen ? item.id : null);
setActionMenuView("actions"); if (!nextOpen) setMovePanelOpenId(null);
}} }}
trigger={["click"]} trigger={["click"]}
placement="bottomRight" placement="bottomRight"

Loading…
Cancel
Save