mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
feat(web): add batch delete for selected design files (#771)
Adds batch deletion for selected design files.
This commit is contained in:
parent
bc9a49ff48
commit
168cb8ab4d
21 changed files with 120 additions and 0 deletions
|
|
@ -16,6 +16,7 @@ interface Props {
|
|||
onOpenFile: (name: string) => void;
|
||||
onOpenLiveArtifact: (tabId: LiveArtifactWorkspaceEntry['tabId']) => void;
|
||||
onDeleteFile: (name: string) => void;
|
||||
onDeleteFiles: (names: string[]) => Promise<void> | void;
|
||||
onUpload: () => void;
|
||||
onUploadFiles: (files: File[]) => void;
|
||||
onPaste: () => void;
|
||||
|
|
@ -50,6 +51,7 @@ export function DesignFilesPanel({
|
|||
onOpenFile,
|
||||
onOpenLiveArtifact,
|
||||
onDeleteFile,
|
||||
onDeleteFiles,
|
||||
onUpload,
|
||||
onUploadFiles,
|
||||
onPaste,
|
||||
|
|
@ -67,6 +69,7 @@ export function DesignFilesPanel({
|
|||
const [sectionLimits, setSectionLimits] = useState<Partial<Record<Section, number>>>({});
|
||||
const [isSectionExpansionPending, startSectionExpansion] = useTransition();
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [deleting, setDeleting] = useState(false);
|
||||
|
||||
const grouped = useMemo(() => {
|
||||
const groups: Record<Section, ProjectFile[]> = {
|
||||
|
|
@ -160,6 +163,22 @@ export function DesignFilesPanel({
|
|||
});
|
||||
}
|
||||
|
||||
async function handleBatchDelete() {
|
||||
if (deleting) return;
|
||||
const fileList = [...selected];
|
||||
if (fileList.length === 0) return;
|
||||
setDeleting(true);
|
||||
try {
|
||||
await onDeleteFiles(fileList);
|
||||
// Don't clear `selected` here: confirm-cancel and all-fail paths
|
||||
// should leave the user's selection intact for retry. The
|
||||
// `useEffect` above prunes successfully-deleted names automatically
|
||||
// once `files` refreshes.
|
||||
} finally {
|
||||
setDeleting(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleBatchDownload() {
|
||||
const fileList = [...selected];
|
||||
if (fileList.length === 0) return;
|
||||
|
|
@ -239,6 +258,16 @@ export function DesignFilesPanel({
|
|||
<Icon name="download" size={13} />
|
||||
<span>{t('designFiles.downloadSelected', { n: selected.size })}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="danger"
|
||||
data-testid="design-files-batch-delete"
|
||||
disabled={deleting}
|
||||
onClick={() => void handleBatchDelete()}
|
||||
title={t('designFiles.deleteSelected', { n: selected.size })}
|
||||
>
|
||||
<span>{t('designFiles.deleteSelected', { n: selected.size })}</span>
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="df-actions">
|
||||
|
|
|
|||
|
|
@ -301,6 +301,40 @@ export function FileWorkspace({
|
|||
}
|
||||
}
|
||||
|
||||
async function handleDeleteMany(names: string[]) {
|
||||
if (names.length === 0) return;
|
||||
if (!confirm(t('workspace.deleteSelectedFilesConfirm', { n: names.length }))) return;
|
||||
const deleted: string[] = [];
|
||||
const failed: string[] = [];
|
||||
for (const name of names) {
|
||||
const ok = await deleteProjectFile(projectId, name);
|
||||
if (ok) deleted.push(name);
|
||||
else failed.push(name);
|
||||
}
|
||||
if (deleted.length > 0) {
|
||||
await onRefreshFiles();
|
||||
const deletedSet = new Set(deleted);
|
||||
const nextTabs = persistedTabs.filter((n) => !deletedSet.has(n));
|
||||
if (activeTab && deletedSet.has(activeTab)) {
|
||||
const nextActive = nextTabs[nextTabs.length - 1] ?? null;
|
||||
onTabsStateChange({ tabs: nextTabs, active: nextActive });
|
||||
setActiveTab(nextActive ?? DESIGN_FILES_TAB);
|
||||
} else {
|
||||
const nextActive =
|
||||
tabsState.active && deletedSet.has(tabsState.active) ? null : tabsState.active;
|
||||
onTabsStateChange({ tabs: nextTabs, active: nextActive });
|
||||
}
|
||||
setSketches((curr) => {
|
||||
const next = { ...curr };
|
||||
for (const name of deleted) delete next[name];
|
||||
return next;
|
||||
});
|
||||
}
|
||||
if (failed.length > 0) {
|
||||
alert(t('workspace.deleteSelectedFilesPartial', { n: failed.length }));
|
||||
}
|
||||
}
|
||||
|
||||
function startNewSketch() {
|
||||
const stamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
||||
const name = `sketch-${stamp}.sketch.json`;
|
||||
|
|
@ -483,6 +517,7 @@ export function FileWorkspace({
|
|||
onOpenFile={openFile}
|
||||
onOpenLiveArtifact={(tabId) => openFile(tabId)}
|
||||
onDeleteFile={(name) => void handleDelete(name)}
|
||||
onDeleteFiles={handleDeleteMany}
|
||||
onUpload={() => fileInputRef.current?.click()}
|
||||
onUploadFiles={(picked) => void uploadFiles(picked)}
|
||||
onPaste={() => setShowPasteDialog(true)}
|
||||
|
|
|
|||
|
|
@ -511,6 +511,8 @@ export const ar: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'إغلاق علامة التبويب',
|
||||
'workspace.deleteFileConfirm': 'حذف "{name}" من مجلد المشروع؟',
|
||||
'workspace.deleteSelectedFilesConfirm': 'حذف {n} ملف(ات) محددة من مجلد المشروع؟',
|
||||
'workspace.deleteSelectedFilesPartial': 'فشل حذف {n} ملف(ات).',
|
||||
'workspace.openFromDesignFiles': 'فتح ملف من',
|
||||
'workspace.designFilesLink': 'ملفات التصميم',
|
||||
'workspace.loadingSketch': 'جاري تحميل الرسم...',
|
||||
|
|
@ -530,6 +532,7 @@ export const ar: Dict = {
|
|||
'designFiles.openInTab': 'فتح في علامة تبويب',
|
||||
'designFiles.download': 'تحميل',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'حذف {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ أسقط الملفات هنا',
|
||||
|
|
|
|||
|
|
@ -465,6 +465,8 @@ export const de: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Tab schließen',
|
||||
'workspace.deleteFileConfirm': '„{name}“ aus dem Projektordner löschen?',
|
||||
'workspace.deleteSelectedFilesConfirm': '{n} ausgewählte Datei(en) aus dem Projektordner löschen?',
|
||||
'workspace.deleteSelectedFilesPartial': '{n} Datei(en) konnten nicht gelöscht werden.',
|
||||
'workspace.openFromDesignFiles': 'Datei öffnen aus',
|
||||
'workspace.designFilesLink': 'Design-Dateien',
|
||||
'workspace.loadingSketch': 'Sketch wird geladen…',
|
||||
|
|
@ -484,6 +486,7 @@ export const de: Dict = {
|
|||
'designFiles.openInTab': 'In Tab öffnen',
|
||||
'designFiles.download': 'Herunterladen',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': '{n} löschen',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Dateien hier ablegen',
|
||||
|
|
|
|||
|
|
@ -522,6 +522,8 @@ export const en: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Close tab',
|
||||
'workspace.deleteFileConfirm': 'Delete "{name}" from the project folder?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Delete {n} selected file(s) from the project folder?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Failed to delete {n} file(s).',
|
||||
'workspace.openFromDesignFiles': 'Open a file from',
|
||||
'workspace.designFilesLink': 'Design Files',
|
||||
'workspace.loadingSketch': 'Loading sketch…',
|
||||
|
|
@ -541,6 +543,7 @@ export const en: Dict = {
|
|||
'designFiles.openInTab': 'Open in tab',
|
||||
'designFiles.download': 'Download',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Delete {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Drop files here',
|
||||
|
|
|
|||
|
|
@ -466,6 +466,8 @@ export const esES: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Cerrar pestaña',
|
||||
'workspace.deleteFileConfirm': '¿Eliminar «{name}» de la carpeta del proyecto?',
|
||||
'workspace.deleteSelectedFilesConfirm': '¿Eliminar {n} archivo(s) seleccionado(s) de la carpeta del proyecto?',
|
||||
'workspace.deleteSelectedFilesPartial': 'No se pudieron eliminar {n} archivo(s).',
|
||||
'workspace.openFromDesignFiles': 'Abre un archivo desde',
|
||||
'workspace.designFilesLink': 'Archivos de diseño',
|
||||
'workspace.loadingSketch': 'Cargando boceto…',
|
||||
|
|
@ -485,6 +487,7 @@ export const esES: Dict = {
|
|||
'designFiles.openInTab': 'Abrir en pestaña',
|
||||
'designFiles.download': 'Descargar',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Eliminar {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Suelta archivos aquí',
|
||||
|
|
|
|||
|
|
@ -522,6 +522,8 @@ export const fa: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'بستن تب',
|
||||
'workspace.deleteFileConfirm': 'آیا «{name}» از پوشه پروژه حذف شود؟',
|
||||
'workspace.deleteSelectedFilesConfirm': 'آیا {n} فایل انتخابشده از پوشه پروژه حذف شوند؟',
|
||||
'workspace.deleteSelectedFilesPartial': 'حذف {n} فایل ناموفق بود.',
|
||||
'workspace.openFromDesignFiles': 'باز کردن یک فایل از',
|
||||
'workspace.designFilesLink': 'فایلهای طراحی',
|
||||
'workspace.loadingSketch': 'در حال بارگذاری طرح…',
|
||||
|
|
@ -541,6 +543,7 @@ export const fa: Dict = {
|
|||
'designFiles.openInTab': 'باز کردن در تب',
|
||||
'designFiles.download': 'دانلود',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'حذف {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ فایلها را اینجا رها کنید',
|
||||
|
|
|
|||
|
|
@ -511,6 +511,8 @@ export const fr: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Fermer l\'onglet',
|
||||
'workspace.deleteFileConfirm': 'Supprimer « {name} » du dossier du projet ?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Supprimer les {n} fichier(s) sélectionné(s) du dossier du projet ?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Échec de la suppression de {n} fichier(s).',
|
||||
'workspace.openFromDesignFiles': 'Ouvrir un fichier depuis',
|
||||
'workspace.designFilesLink': 'Fichiers de design',
|
||||
'workspace.loadingSketch': 'Chargement du croquis…',
|
||||
|
|
@ -530,6 +532,7 @@ export const fr: Dict = {
|
|||
'designFiles.openInTab': 'Ouvrir dans un onglet',
|
||||
'designFiles.download': 'Télécharger',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Supprimer {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Déposez les fichiers ici',
|
||||
|
|
|
|||
|
|
@ -511,6 +511,8 @@ export const hu: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Lap bezárása',
|
||||
'workspace.deleteFileConfirm': 'Törlöd a(z) „{name}" fájlt a projektmappából?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Törlöd a(z) {n} kijelölt fájlt a projektmappából?',
|
||||
'workspace.deleteSelectedFilesPartial': '{n} fájl törlése sikertelen.',
|
||||
'workspace.openFromDesignFiles': 'Nyiss meg egy fájlt innen:',
|
||||
'workspace.designFilesLink': 'Designfájlok',
|
||||
'workspace.loadingSketch': 'Vázlat betöltése…',
|
||||
|
|
@ -530,6 +532,7 @@ export const hu: Dict = {
|
|||
'designFiles.openInTab': 'Megnyitás lapon',
|
||||
'designFiles.download': 'Letöltés',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': '{n} törlése',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Húzd ide a fájlokat',
|
||||
|
|
|
|||
|
|
@ -511,6 +511,8 @@ export const id: Dict = {
|
|||
'workspace.showChat': 'Tampilkan chat',
|
||||
'workspace.closeTab': 'Tutup tab',
|
||||
'workspace.deleteFileConfirm': 'Hapus "{name}" dari folder proyek?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Hapus {n} file terpilih dari folder proyek?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Gagal menghapus {n} file.',
|
||||
'workspace.openFromDesignFiles': 'Buka file dari',
|
||||
'workspace.designFilesLink': 'File desain',
|
||||
'workspace.loadingSketch': 'Memuat sketsa...',
|
||||
|
|
@ -530,6 +532,7 @@ export const id: Dict = {
|
|||
'designFiles.openInTab': 'Buka di tab',
|
||||
'designFiles.download': 'Unduh',
|
||||
'designFiles.downloadSelected': 'Unduh {n} sebagai ZIP',
|
||||
'designFiles.deleteSelected': 'Hapus {n}',
|
||||
'designFiles.clearSelection': 'Bersihkan',
|
||||
'designFiles.selectAll': 'Pilih semua',
|
||||
'designFiles.dropTitle': 'Lepaskan file di sini',
|
||||
|
|
|
|||
|
|
@ -464,6 +464,8 @@ export const ja: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'タブを閉じる',
|
||||
'workspace.deleteFileConfirm': 'プロジェクトフォルダーから "{name}" を削除しますか?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'プロジェクトフォルダーから選択した {n} 個のファイルを削除しますか?',
|
||||
'workspace.deleteSelectedFilesPartial': '{n} 個のファイルの削除に失敗しました。',
|
||||
'workspace.openFromDesignFiles': 'ファイルを開く: ',
|
||||
'workspace.designFilesLink': 'デザインファイル',
|
||||
'workspace.loadingSketch': 'スケッチを読み込み中…',
|
||||
|
|
@ -483,6 +485,7 @@ export const ja: Dict = {
|
|||
'designFiles.openInTab': 'タブで開く',
|
||||
'designFiles.download': 'ダウンロード',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': '{n} 件を削除',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ ファイルをここにドロップ',
|
||||
|
|
|
|||
|
|
@ -511,6 +511,8 @@ export const ko: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': '탭 닫기',
|
||||
'workspace.deleteFileConfirm': '프로젝트 폴더에서 "{name}" 파일을 삭제하시겠습니까?',
|
||||
'workspace.deleteSelectedFilesConfirm': '프로젝트 폴더에서 선택한 {n}개 파일을 삭제하시겠습니까?',
|
||||
'workspace.deleteSelectedFilesPartial': '{n}개 파일을 삭제하지 못했습니다.',
|
||||
'workspace.openFromDesignFiles': '디자인 파일 열기',
|
||||
'workspace.designFilesLink': '디자인 파일',
|
||||
'workspace.loadingSketch': '스케치 불러오는 중…',
|
||||
|
|
@ -530,6 +532,7 @@ export const ko: Dict = {
|
|||
'designFiles.openInTab': '탭에서 열기',
|
||||
'designFiles.download': '다운로드',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': '{n}개 삭제',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ 여기에 파일을 놓으세요',
|
||||
|
|
|
|||
|
|
@ -511,6 +511,8 @@ export const pl: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Zamknij kartę',
|
||||
'workspace.deleteFileConfirm': 'Usunąć „{name}” z folderu projektu?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Usunąć {n} wybranych plików z folderu projektu?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Nie udało się usunąć {n} plików.',
|
||||
'workspace.openFromDesignFiles': 'Otwórz plik z',
|
||||
'workspace.designFilesLink': 'Pliki projektu',
|
||||
'workspace.loadingSketch': 'Ładowanie szkicu…',
|
||||
|
|
@ -530,6 +532,7 @@ export const pl: Dict = {
|
|||
'designFiles.openInTab': 'Otwórz w karcie',
|
||||
'designFiles.download': 'Pobierz',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Usuń {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Upuść pliki tutaj',
|
||||
|
|
|
|||
|
|
@ -521,6 +521,8 @@ export const ptBR: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Fechar aba',
|
||||
'workspace.deleteFileConfirm': 'Excluir "{name}" da pasta do projeto?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Excluir {n} arquivo(s) selecionado(s) da pasta do projeto?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Falha ao excluir {n} arquivo(s).',
|
||||
'workspace.openFromDesignFiles': 'Abra um arquivo em',
|
||||
'workspace.designFilesLink': 'Arquivos de design',
|
||||
'workspace.loadingSketch': 'Carregando esboço…',
|
||||
|
|
@ -540,6 +542,7 @@ export const ptBR: Dict = {
|
|||
'designFiles.openInTab': 'Abrir em aba',
|
||||
'designFiles.download': 'Baixar',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Excluir {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Solte arquivos aqui',
|
||||
|
|
|
|||
|
|
@ -521,6 +521,8 @@ export const ru: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Закрыть вкладку',
|
||||
'workspace.deleteFileConfirm': 'Удалить «{name}» из папки проекта?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Удалить {n} выбранных файла(ов) из папки проекта?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Не удалось удалить {n} файл(ов).',
|
||||
'workspace.openFromDesignFiles': 'Открыть файл из',
|
||||
'workspace.designFilesLink': 'Файлы дизайна',
|
||||
'workspace.loadingSketch': 'Загрузка эскиза…',
|
||||
|
|
@ -540,6 +542,7 @@ export const ru: Dict = {
|
|||
'designFiles.openInTab': 'Открыть во вкладке',
|
||||
'designFiles.download': 'Скачать',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Удалить {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Перетащите файлы сюда',
|
||||
|
|
|
|||
|
|
@ -502,6 +502,8 @@ export const tr: Dict = {
|
|||
'workspace.designFiles': 'Tasarım Dosyaları',
|
||||
'workspace.closeTab': 'Sekmeyi kapat',
|
||||
'workspace.deleteFileConfirm': '"{name}"ı proje klasöründen sil?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Seçili {n} dosya proje klasöründen silinsin mi?',
|
||||
'workspace.deleteSelectedFilesPartial': '{n} dosya silinemedi.',
|
||||
'workspace.openFromDesignFiles': 'bir dosya aç',
|
||||
'workspace.designFilesLink': 'Tasarım Dosyaları',
|
||||
'workspace.loadingSketch': 'Taslak yükleniyor…',
|
||||
|
|
@ -521,6 +523,7 @@ export const tr: Dict = {
|
|||
'designFiles.openInTab': 'Sekmede aç',
|
||||
'designFiles.download': 'İndir',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': '{n} sil',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Dosyaları buraya sürükleyin',
|
||||
|
|
|
|||
|
|
@ -522,6 +522,8 @@ export const uk: Dict = {
|
|||
'workspace.showChat': 'Show chat',
|
||||
'workspace.closeTab': 'Закрити вкладку',
|
||||
'workspace.deleteFileConfirm': 'Видалити "{name}" з папки проекту?',
|
||||
'workspace.deleteSelectedFilesConfirm': 'Видалити {n} вибраних файлів з папки проекту?',
|
||||
'workspace.deleteSelectedFilesPartial': 'Не вдалося видалити {n} файл(ів).',
|
||||
'workspace.openFromDesignFiles': 'Відкрити файл з',
|
||||
'workspace.designFilesLink': 'Файли дизайну',
|
||||
'workspace.loadingSketch': 'Завантаження ескізу…',
|
||||
|
|
@ -541,6 +543,7 @@ export const uk: Dict = {
|
|||
'designFiles.openInTab': 'Відкрити на вкладці',
|
||||
'designFiles.download': 'Завантажити',
|
||||
'designFiles.downloadSelected': 'Download {n} as ZIP',
|
||||
'designFiles.deleteSelected': 'Видалити {n}',
|
||||
'designFiles.clearSelection': 'Clear',
|
||||
'designFiles.selectAll': 'Select all',
|
||||
'designFiles.dropTitle': '⤓ Перенесіть файли сюди',
|
||||
|
|
|
|||
|
|
@ -513,6 +513,8 @@ export const zhCN: Dict = {
|
|||
'workspace.showChat': '显示聊天',
|
||||
'workspace.closeTab': '关闭标签页',
|
||||
'workspace.deleteFileConfirm': '从项目文件夹中删除「{name}」?',
|
||||
'workspace.deleteSelectedFilesConfirm': '从项目文件夹中删除选中的 {n} 个文件?',
|
||||
'workspace.deleteSelectedFilesPartial': '有 {n} 个文件删除失败。',
|
||||
'workspace.openFromDesignFiles': '请从',
|
||||
'workspace.designFilesLink': '设计文件',
|
||||
'workspace.loadingSketch': '正在加载草图…',
|
||||
|
|
@ -531,6 +533,7 @@ export const zhCN: Dict = {
|
|||
'designFiles.openInTab': '在标签页中打开',
|
||||
'designFiles.download': '下载',
|
||||
'designFiles.downloadSelected': '下载选中的 {n} 个文件为 ZIP',
|
||||
'designFiles.deleteSelected': '删除 {n} 个',
|
||||
'designFiles.clearSelection': '取消选择',
|
||||
'designFiles.selectAll': '全选',
|
||||
'designFiles.dropTitle': '⤓ 把文件拖到这里',
|
||||
|
|
|
|||
|
|
@ -513,6 +513,8 @@ export const zhTW: Dict = {
|
|||
'workspace.showChat': '顯示聊天',
|
||||
'workspace.closeTab': '關閉分頁',
|
||||
'workspace.deleteFileConfirm': '從專案資料夾中刪除「{name}」?',
|
||||
'workspace.deleteSelectedFilesConfirm': '從專案資料夾中刪除選中的 {n} 個檔案?',
|
||||
'workspace.deleteSelectedFilesPartial': '有 {n} 個檔案刪除失敗。',
|
||||
'workspace.openFromDesignFiles': '請從',
|
||||
'workspace.designFilesLink': '設計檔案',
|
||||
'workspace.loadingSketch': '正在載入草圖…',
|
||||
|
|
@ -531,6 +533,7 @@ export const zhTW: Dict = {
|
|||
'designFiles.openInTab': '在分頁中開啟',
|
||||
'designFiles.download': '下載',
|
||||
'designFiles.downloadSelected': '下載選中的 {n} 個檔案為 ZIP',
|
||||
'designFiles.deleteSelected': '刪除 {n} 個',
|
||||
'designFiles.clearSelection': '取消選擇',
|
||||
'designFiles.selectAll': '全選',
|
||||
'designFiles.dropTitle': '⤓ 把檔案拖到這裡',
|
||||
|
|
|
|||
|
|
@ -582,6 +582,8 @@ export interface Dict {
|
|||
'workspace.showChat': string;
|
||||
'workspace.closeTab': string;
|
||||
'workspace.deleteFileConfirm': string;
|
||||
'workspace.deleteSelectedFilesConfirm': string;
|
||||
'workspace.deleteSelectedFilesPartial': string;
|
||||
'workspace.openFromDesignFiles': string;
|
||||
'workspace.designFilesLink': string;
|
||||
'workspace.loadingSketch': string;
|
||||
|
|
@ -600,6 +602,7 @@ export interface Dict {
|
|||
'designFiles.openInTab': string;
|
||||
'designFiles.download': string;
|
||||
'designFiles.downloadSelected': string;
|
||||
'designFiles.deleteSelected': string;
|
||||
'designFiles.clearSelection': string;
|
||||
'designFiles.selectAll': string;
|
||||
'designFiles.dropTitle': string;
|
||||
|
|
|
|||
|
|
@ -4734,6 +4734,8 @@ button.connector-action.is-loading {
|
|||
gap: 6px;
|
||||
}
|
||||
.df-head .df-actions button:hover:not(:disabled) { background: var(--bg-subtle); color: var(--text); }
|
||||
.df-head .df-actions button.danger { color: var(--red); }
|
||||
.df-head .df-actions button.danger:hover:not(:disabled) { background: var(--red-bg); color: var(--red); }
|
||||
|
||||
.df-body {
|
||||
flex: 1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue