mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
refactor(editor): drop the file library's location row
The row carrying "All files" was the last of the library's own chrome, and with the controls in the workbench bar it was a line on its own holding a breadcrumb and a tab name. The folder tree in the file sidebar covers what it did: it names where you are, reaches any folder including the root, and accepts a drop the way the breadcrumb ancestors did. The tab strip already says which tab is open. Takes the Breadcrumbs component and its styles with it, and the strings only it read.
This commit is contained in:
@@ -4287,7 +4287,6 @@ allFiles = "All files"
|
||||
back = "Back"
|
||||
backToFolder = "Back to {{folder}}"
|
||||
backToMyFiles = "Back to File library"
|
||||
breadcrumbs = "Folder path"
|
||||
bulkActions = "Actions"
|
||||
cancel = "Cancel"
|
||||
classification = "Classification"
|
||||
@@ -4514,9 +4513,6 @@ server = "Server error during folder sync."
|
||||
|
||||
[filesPage.tabName]
|
||||
local = "Local"
|
||||
recent = "Recent"
|
||||
shared = "Shared with me"
|
||||
sharedByMe = "Shared by me"
|
||||
|
||||
[filesPage.tabs]
|
||||
all = "All"
|
||||
|
||||
@@ -29,7 +29,6 @@ import DriveFileMoveIcon from "@mui/icons-material/DriveFileMove";
|
||||
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
|
||||
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
||||
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
||||
import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
|
||||
import { FilesToolbarBulkMenu } from "@app/components/filesPage/FilesToolbarBulkMenu";
|
||||
import { FilesToolbarCount } from "@app/components/filesPage/FilesToolbarCount";
|
||||
import { FilesToolbarFilterMenu } from "@app/components/filesPage/FilesToolbarFilterMenu";
|
||||
@@ -76,10 +75,7 @@ import { duplicateStoredFile } from "@app/utils/duplicateFile";
|
||||
import { downloadFileFromStorage } from "@app/utils/downloadUtils";
|
||||
import { fileStorage } from "@app/services/fileStorage";
|
||||
import { materializeServerStubs } from "@app/services/fileSyncService";
|
||||
import {
|
||||
FILES_PAGE_DRAG_TYPE,
|
||||
parseFilesPageDragPayload,
|
||||
} from "@app/components/filesPage/dragDrop";
|
||||
import {} from "@app/components/filesPage/dragDrop";
|
||||
import { clearFilesPageReturnRoute } from "@app/components/filesPage/filesPageReturnRoute";
|
||||
import { EDITOR_BASENAME } from "@app/routes/editorBasename";
|
||||
import "@app/components/filesPage/FilesPage.css";
|
||||
@@ -986,25 +982,6 @@ export default function FileManagerView() {
|
||||
|
||||
return (
|
||||
<div className="files-page" ref={dropZoneRef}>
|
||||
{/* Folder context, not a bar: the controls that used to sit beside this are
|
||||
registered into the workbench bar the other views use. */}
|
||||
<div className="files-page-location">
|
||||
{(currentTab === "all" || currentTab === "cloud") && <Breadcrumbs />}
|
||||
{(currentTab === "local" ||
|
||||
currentTab === "recent" ||
|
||||
currentTab === "shared" ||
|
||||
currentTab === "sharedByMe") && (
|
||||
<span className="files-page-location-name">
|
||||
{currentTab === "local"
|
||||
? t("filesPage.tabName.local", "Local")
|
||||
: currentTab === "recent"
|
||||
? t("filesPage.tabName.recent", "Recent")
|
||||
: currentTab === "shared"
|
||||
? t("filesPage.tabName.shared", "Shared with me")
|
||||
: t("filesPage.tabName.sharedByMe", "Shared by me")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
@@ -1799,92 +1776,3 @@ export default function FileManagerView() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Breadcrumbs() {
|
||||
const { t } = useTranslation();
|
||||
const folders = useFolders();
|
||||
const filesPage = useFilesPage();
|
||||
const trail = folders.breadcrumbs;
|
||||
return (
|
||||
<nav
|
||||
className="files-page-breadcrumbs"
|
||||
aria-label={t("filesPage.breadcrumbs", "Folder path")}
|
||||
>
|
||||
{trail.map((entry, idx) => {
|
||||
const isLast = idx === trail.length - 1;
|
||||
return (
|
||||
<React.Fragment key={entry.id ?? "root"}>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
className={`files-page-breadcrumb${isLast ? " is-current" : ""}`}
|
||||
onClick={() => folders.setCurrentFolderId(entry.id)}
|
||||
onDragOver={(e) => {
|
||||
if (e.dataTransfer.types.includes(FILES_PAGE_DRAG_TYPE)) {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
}}
|
||||
onDrop={(e) => {
|
||||
e.preventDefault();
|
||||
const payload = parseFilesPageDragPayload(e.dataTransfer);
|
||||
if (!payload) return;
|
||||
if (payload.kind === "files") {
|
||||
// Route through moveFilesTo (→ IndexedDBContext.moveFilesToFolder)
|
||||
// so the revision bumps and the grid refreshes. Surface
|
||||
// rejection via the banner - console-only was invisible
|
||||
// to non-dev users.
|
||||
void filesPage
|
||||
.moveFilesTo(payload.fileIds, entry.id)
|
||||
.catch((err) => {
|
||||
console.error("[breadcrumb] drop failed", err);
|
||||
folders.setError(
|
||||
err instanceof Error
|
||||
? t("filesPage.error.moveFilesFailedDetail", {
|
||||
message: err.message,
|
||||
defaultValue: `Could not move files: ${err.message}`,
|
||||
})
|
||||
: t(
|
||||
"filesPage.error.moveFilesFailed",
|
||||
"Could not move files.",
|
||||
),
|
||||
);
|
||||
});
|
||||
} else if (payload.kind === "folder") {
|
||||
// Route through moveFolderTo so the client-side cycle guard fires
|
||||
// before the server call - otherwise dragging an ancestor onto a
|
||||
// child crumb shows the generic banner instead of the localized
|
||||
// "Can't move a folder into one of its own subfolders." message.
|
||||
void filesPage
|
||||
.moveFolderTo(payload.folderId, entry.id)
|
||||
.catch((err) => {
|
||||
console.error("[breadcrumb] folder drop failed", err);
|
||||
folders.setError(
|
||||
err instanceof Error
|
||||
? t("filesPage.error.moveFolderFailedDetail", {
|
||||
message: err.message,
|
||||
defaultValue: `Could not move folder: ${err.message}`,
|
||||
})
|
||||
: t(
|
||||
"filesPage.error.moveFolderFailed",
|
||||
"Could not move folder.",
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{entry.name}
|
||||
</Button>
|
||||
{!isLast && (
|
||||
<KeyboardArrowRightIcon
|
||||
className="files-page-breadcrumb-sep"
|
||||
fontSize="small"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,68 +8,6 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Where you are in the library. Not a bar - the controls that used to share this
|
||||
row are registered into the workbench bar, and the search lives there too. */
|
||||
.files-page-location {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 2rem;
|
||||
padding: 0.25rem 0.75rem 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.files-page-location-name {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
padding: 0.25rem 0.5rem;
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
||||
.files-page-breadcrumbs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.95rem;
|
||||
min-width: 0;
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.files-page-breadcrumbs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.files-page-breadcrumb {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
color: var(--c-text-muted);
|
||||
cursor: pointer;
|
||||
font-size: inherit;
|
||||
font-weight: 500;
|
||||
transition:
|
||||
background-color 0.12s ease,
|
||||
color 0.12s ease;
|
||||
white-space: nowrap;
|
||||
max-width: 18rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.files-page-breadcrumb:hover,
|
||||
.files-page-breadcrumb.is-current {
|
||||
background: var(--c-hover);
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
||||
.files-page-breadcrumb-sep {
|
||||
color: var(--c-text-subtle);
|
||||
font-size: 1rem !important;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
opacity: 0.55;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.files-page-body {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
@@ -1344,23 +1282,6 @@
|
||||
navigation, so the in-header Home/Apps/Close trio is duplicated
|
||||
and the first to go. Same for "Upload" - the user can use the
|
||||
centre drop overlay. */
|
||||
/* ── Mobile + tablet chrome (≤1024px = useIsMobile) ──────────────────
|
||||
The desktop header is a 3-column grid whose middle track can grow to
|
||||
40rem. Below ~1024px that track eats the row: the breadcrumb column
|
||||
collapsed to ~36px (wrapping "All files" to two lines) and the action
|
||||
column overflowed, pushing Upload off the right edge. One flex row
|
||||
instead - breadcrumb and actions keep their intrinsic width and the
|
||||
search takes whatever is left. Ends at the app's mobile breakpoint so
|
||||
it matches the layout HomePage is already rendering. */
|
||||
@media (max-width: 1024px) {
|
||||
.files-page-breadcrumbs {
|
||||
flex: 0 1 auto;
|
||||
font-size: 0.85rem;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
/* Grid: single column on very narrow phones; two columns from ~440px */
|
||||
|
||||
Reference in New Issue
Block a user