V2 File Editor Shortcuts (#4619)

# Description of Changes
Add shortcut icons for Pin and Download, and rename Delete to Close for
consistency with the rest of the tool.
This commit is contained in:
James Brunton 2025-10-07 11:48:42 +01:00 committed by GitHub
parent 2a29bda34f
commit d714a1617f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 86 additions and 35 deletions

View File

@ -66,6 +66,8 @@
"save": "Save", "save": "Save",
"saveToBrowser": "Save to Browser", "saveToBrowser": "Save to Browser",
"download": "Download", "download": "Download",
"pin": "Pin",
"unpin": "Unpin",
"undoOperationTooltip": "Click to undo the last operation and restore the original files", "undoOperationTooltip": "Click to undo the last operation and restore the original files",
"undo": "Undo", "undo": "Undo",
"moreOptions": "More Options", "moreOptions": "More Options",

View File

@ -34,9 +34,9 @@
.header { .header {
height: 2.25rem; height: 2.25rem;
border-radius: 0.0625rem 0.0625rem 0 0; border-radius: 0.0625rem 0.0625rem 0 0;
display: grid; display: flex;
grid-template-columns: 44px 1fr 44px;
align-items: center; align-items: center;
justify-content: space-between;
padding: 0 6px; padding: 0 6px;
user-select: none; user-select: none;
background: var(--bg-toolbar); background: var(--bg-toolbar);
@ -86,14 +86,23 @@
} }
.headerIndex { .headerIndex {
position: absolute;
left: 50%;
transform: translateX(-50%);
text-align: center; text-align: center;
font-weight: 500; font-weight: 500;
font-size: 18px; font-size: 18px;
letter-spacing: 0.04em; letter-spacing: 0.04em;
} }
.kebab { .headerActions {
justify-self: end; display: flex;
align-items: center;
gap: 8px;
margin-left: auto;
}
.headerIconButton {
color: #FFFFFF !important; color: #FFFFFF !important;
} }
@ -216,6 +225,11 @@
color: rgba(0, 0, 0, 0.35); color: rgba(0, 0, 0, 0.35);
} }
.pinned {
color: #FFC107 !important;
}
/* Unsupported file indicator */ /* Unsupported file indicator */
.unsupportedPill { .unsupportedPill {
margin-left: 1.75rem; margin-left: 1.75rem;
@ -384,4 +398,4 @@
.addFileSubtext { .addFileSubtext {
font-size: 0.875rem; font-size: 0.875rem;
opacity: 0.8; opacity: 0.8;
} }

View File

@ -288,7 +288,7 @@ const FileEditor = ({
// File operations using context // File operations using context
const handleDeleteFile = useCallback((fileId: FileId) => { const handleCloseFile = useCallback((fileId: FileId) => {
const record = activeStirlingFileStubs.find(r => r.id === fileId); const record = activeStirlingFileStubs.find(r => r.id === fileId);
const file = record ? selectors.getFile(record.id) : null; const file = record ? selectors.getFile(record.id) : null;
if (record && file) { if (record && file) {
@ -467,7 +467,7 @@ const FileEditor = ({
selectedFiles={localSelectedIds} selectedFiles={localSelectedIds}
selectionMode={selectionMode} selectionMode={selectionMode}
onToggleFile={toggleFile} onToggleFile={toggleFile}
onDeleteFile={handleDeleteFile} onCloseFile={handleCloseFile}
onViewFile={handleViewFile} onViewFile={handleViewFile}
_onSetStatus={showStatus} _onSetStatus={showStatus}
onReorderFiles={handleReorderFiles} onReorderFiles={handleReorderFiles}

View File

@ -1,10 +1,10 @@
import React, { useState, useCallback, useRef, useMemo, useEffect } from 'react'; 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 { alert } from '../toast';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import MoreVertIcon from '@mui/icons-material/MoreVert'; import MoreVertIcon from '@mui/icons-material/MoreVert';
import DownloadOutlinedIcon from '@mui/icons-material/DownloadOutlined'; 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 UnarchiveIcon from '@mui/icons-material/Unarchive';
import PushPinIcon from '@mui/icons-material/PushPin'; import PushPinIcon from '@mui/icons-material/PushPin';
import PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined'; import PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined';
@ -29,7 +29,7 @@ interface FileEditorThumbnailProps {
selectedFiles: FileId[]; selectedFiles: FileId[];
selectionMode: boolean; selectionMode: boolean;
onToggleFile: (fileId: FileId) => void; onToggleFile: (fileId: FileId) => void;
onDeleteFile: (fileId: FileId) => void; onCloseFile: (fileId: FileId) => void;
onViewFile: (fileId: FileId) => void; onViewFile: (fileId: FileId) => void;
_onSetStatus: (status: string) => void; _onSetStatus: (status: string) => void;
onReorderFiles?: (sourceFileId: FileId, targetFileId: FileId, selectedFileIds: FileId[]) => void; onReorderFiles?: (sourceFileId: FileId, targetFileId: FileId, selectedFileIds: FileId[]) => void;
@ -44,7 +44,7 @@ const FileEditorThumbnail = ({
index, index,
selectedFiles, selectedFiles,
onToggleFile, onToggleFile,
onDeleteFile, onCloseFile,
_onSetStatus, _onSetStatus,
onReorderFiles, onReorderFiles,
onDownloadFile, onDownloadFile,
@ -258,18 +258,60 @@ const FileEditorThumbnail = ({
{index + 1} {index + 1}
</div> </div>
{/* Kebab menu */} {/* Action buttons group */}
<ActionIcon <div className={styles.headerActions}>
aria-label={t('moreOptions', 'More options')} {/* Pin/Unpin icon */}
variant="subtle" <Tooltip label={isPinned ? t('unpin', 'Unpin') : t('pin', 'Pin')}>
className={styles.kebab} <ActionIcon
onClick={(e) => { aria-label={isPinned ? t('unpin', 'Unpin') : t('pin', 'Pin')}
e.stopPropagation(); variant="subtle"
setShowActions((v) => !v); className={isPinned ? styles.pinned : styles.headerIconButton}
}} onClick={(e) => {
> e.stopPropagation();
<MoreVertIcon fontSize="small" /> if (actualFile) {
</ActionIcon> 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 ? <PushPinIcon fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />}
</ActionIcon>
</Tooltip>
{/* Download icon */}
<Tooltip label={t('download', 'Download')}>
<ActionIcon
aria-label={t('download', 'Download')}
variant="subtle"
className={styles.headerIconButton}
onClick={(e) => {
e.stopPropagation();
onDownloadFile(file.id);
alert({ alertType: 'success', title: `Downloading ${file.name}`, expandable: false, durationMs: 2500 });
}}
>
<DownloadOutlinedIcon fontSize="small" />
</ActionIcon>
</Tooltip>
{/* Kebab menu */}
<ActionIcon
aria-label={t('moreOptions', 'More options')}
variant="subtle"
className={styles.headerIconButton}
onClick={(e) => {
e.stopPropagation();
setShowActions((v) => !v);
}}
>
<MoreVertIcon fontSize="small" />
</ActionIcon>
</div>
</div> </div>
{/* Actions overlay */} {/* Actions overlay */}
@ -294,7 +336,7 @@ const FileEditorThumbnail = ({
setShowActions(false); setShowActions(false);
}} }}
> >
{isPinned ? <PushPinIcon fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />} {isPinned ? <PushPinIcon className={styles.pinned} fontSize="small" /> : <PushPinOutlinedIcon fontSize="small" />}
<span>{isPinned ? t('unpin', 'Unpin') : t('pin', 'Pin')}</span> <span>{isPinned ? t('unpin', 'Unpin') : t('pin', 'Pin')}</span>
</button> </button>
@ -321,13 +363,13 @@ const FileEditorThumbnail = ({
<button <button
className={`${styles.actionRow} ${styles.actionDanger}`} className={`${styles.actionRow} ${styles.actionDanger}`}
onClick={() => { onClick={() => {
onDeleteFile(file.id); onCloseFile(file.id);
alert({ alertType: 'neutral', title: `Deleted ${file.name}`, expandable: false, durationMs: 3500 }); alert({ alertType: 'neutral', title: `Closed ${file.name}`, expandable: false, durationMs: 3500 });
setShowActions(false); setShowActions(false);
}} }}
> >
<DeleteOutlineIcon fontSize="small" /> <CloseIcon fontSize="small" />
<span>{t('delete', 'Delete')}</span> <span>{t('close', 'Close')}</span>
</button> </button>
</div> </div>
)} )}
@ -394,13 +436,6 @@ const FileEditorThumbnail = ({
)} )}
</div> </div>
{/* Pin indicator (bottom-left) */}
{isPinned && (
<span className={styles.pinIndicator} aria-hidden>
<PushPinIcon fontSize="small" />
</span>
)}
{/* Drag handle (span wrapper so we can attach a ref reliably) */} {/* Drag handle (span wrapper so we can attach a ref reliably) */}
<span ref={handleRef} className={styles.dragHandle} aria-hidden> <span ref={handleRef} className={styles.dragHandle} aria-hidden>
<DragIndicatorIcon fontSize="small" /> <DragIndicatorIcon fontSize="small" />