diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 76a498d2d..01a8278f6 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -66,6 +66,8 @@ "save": "Save", "saveToBrowser": "Save to Browser", "download": "Download", + "pin": "Pin", + "unpin": "Unpin", "undoOperationTooltip": "Click to undo the last operation and restore the original files", "undo": "Undo", "moreOptions": "More Options", diff --git a/frontend/src/components/fileEditor/FileEditor.module.css b/frontend/src/components/fileEditor/FileEditor.module.css index 173738c29..17184bbf4 100644 --- a/frontend/src/components/fileEditor/FileEditor.module.css +++ b/frontend/src/components/fileEditor/FileEditor.module.css @@ -34,9 +34,9 @@ .header { height: 2.25rem; border-radius: 0.0625rem 0.0625rem 0 0; - display: grid; - grid-template-columns: 44px 1fr 44px; + display: flex; align-items: center; + justify-content: space-between; padding: 0 6px; user-select: none; background: var(--bg-toolbar); @@ -86,14 +86,23 @@ } .headerIndex { + position: absolute; + left: 50%; + transform: translateX(-50%); text-align: center; font-weight: 500; font-size: 18px; letter-spacing: 0.04em; } -.kebab { - justify-self: end; +.headerActions { + display: flex; + align-items: center; + gap: 8px; + margin-left: auto; +} + +.headerIconButton { color: #FFFFFF !important; } @@ -216,6 +225,11 @@ color: rgba(0, 0, 0, 0.35); } +.pinned { + color: #FFC107 !important; +} + + /* Unsupported file indicator */ .unsupportedPill { margin-left: 1.75rem; @@ -384,4 +398,4 @@ .addFileSubtext { font-size: 0.875rem; opacity: 0.8; -} \ No newline at end of file +} diff --git a/frontend/src/components/fileEditor/FileEditor.tsx b/frontend/src/components/fileEditor/FileEditor.tsx index 626eaab4f..90ee6eebe 100644 --- a/frontend/src/components/fileEditor/FileEditor.tsx +++ b/frontend/src/components/fileEditor/FileEditor.tsx @@ -288,7 +288,7 @@ const FileEditor = ({ // File operations using context - const handleDeleteFile = useCallback((fileId: FileId) => { + const handleCloseFile = useCallback((fileId: FileId) => { const record = activeStirlingFileStubs.find(r => r.id === fileId); const file = record ? selectors.getFile(record.id) : null; if (record && file) { @@ -467,7 +467,7 @@ const FileEditor = ({ selectedFiles={localSelectedIds} selectionMode={selectionMode} onToggleFile={toggleFile} - onDeleteFile={handleDeleteFile} + onCloseFile={handleCloseFile} onViewFile={handleViewFile} _onSetStatus={showStatus} onReorderFiles={handleReorderFiles} diff --git a/frontend/src/components/fileEditor/FileEditorThumbnail.tsx b/frontend/src/components/fileEditor/FileEditorThumbnail.tsx index f09bfeeb1..8159e30a9 100644 --- a/frontend/src/components/fileEditor/FileEditorThumbnail.tsx +++ b/frontend/src/components/fileEditor/FileEditorThumbnail.tsx @@ -1,10 +1,10 @@ import React, { useState, useCallback, useRef, useMemo, useEffect } from 'react'; -import { Text, ActionIcon, CheckboxIndicator } from '@mantine/core'; +import { Text, ActionIcon, CheckboxIndicator, Tooltip } from '@mantine/core'; import { alert } from '../toast'; import { useTranslation } from 'react-i18next'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import DownloadOutlinedIcon from '@mui/icons-material/DownloadOutlined'; -import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; +import CloseIcon from '@mui/icons-material/Close'; import UnarchiveIcon from '@mui/icons-material/Unarchive'; import PushPinIcon from '@mui/icons-material/PushPin'; import PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined'; @@ -29,7 +29,7 @@ interface FileEditorThumbnailProps { selectedFiles: FileId[]; selectionMode: boolean; onToggleFile: (fileId: FileId) => void; - onDeleteFile: (fileId: FileId) => void; + onCloseFile: (fileId: FileId) => void; onViewFile: (fileId: FileId) => void; _onSetStatus: (status: string) => void; onReorderFiles?: (sourceFileId: FileId, targetFileId: FileId, selectedFileIds: FileId[]) => void; @@ -44,7 +44,7 @@ const FileEditorThumbnail = ({ index, selectedFiles, onToggleFile, - onDeleteFile, + onCloseFile, _onSetStatus, onReorderFiles, onDownloadFile, @@ -258,18 +258,60 @@ const FileEditorThumbnail = ({ {index + 1} - {/* Kebab menu */} - { - e.stopPropagation(); - setShowActions((v) => !v); - }} - > - - + {/* Action buttons group */} +
+ {/* Pin/Unpin icon */} + + { + e.stopPropagation(); + if (actualFile) { + if (isPinned) { + unpinFile(actualFile); + alert({ alertType: 'neutral', title: `Unpinned ${file.name}`, expandable: false, durationMs: 3000 }); + } else { + pinFile(actualFile); + alert({ alertType: 'success', title: `Pinned ${file.name}`, expandable: false, durationMs: 3000 }); + } + } + }} + > + {isPinned ? : } + + + + {/* Download icon */} + + { + e.stopPropagation(); + onDownloadFile(file.id); + alert({ alertType: 'success', title: `Downloading ${file.name}`, expandable: false, durationMs: 2500 }); + }} + > + + + + + {/* Kebab menu */} + { + e.stopPropagation(); + setShowActions((v) => !v); + }} + > + + +
{/* Actions overlay */} @@ -294,7 +336,7 @@ const FileEditorThumbnail = ({ setShowActions(false); }} > - {isPinned ? : } + {isPinned ? : } {isPinned ? t('unpin', 'Unpin') : t('pin', 'Pin')} @@ -321,13 +363,13 @@ const FileEditorThumbnail = ({ )} @@ -394,13 +436,6 @@ const FileEditorThumbnail = ({ )} - {/* Pin indicator (bottom-left) */} - {isPinned && ( - - - - )} - {/* Drag handle (span wrapper so we can attach a ref reliably) */}