mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-15 19:10:47 +02:00
Prettier 2: Electric Boogaloo (#6113)
# Description of Changes When I added Prettier formatting in #6052, my aim was to use just the default settings in Prettier. Turns out, Prettier looks _really hard_ for any config files if it's not explicitly given one, which means that if a developer has some sort of Prettier config file lying around on their system, Prettier might find it and use it. Also, Prettier changes its defaults based on stuff in `.editorconfig` without any good way of disabling that behaviour explicitly in its config file. To solve both of these issues, I've introduced a `.prettierrc` file which sets Prettier's defaults explicitly, and then reformatted all our code _again_ in Prettier's actual default settings. This should achieve the aim of #6052 and remove the possibility for it breaking on different dev computers.
This commit is contained in:
@@ -35,9 +35,14 @@ const CompactFileDetails: React.FC<CompactFileDetailsProps> = ({
|
||||
const hasSelection = selectedFiles.length > 0;
|
||||
const hasMultipleFiles = numberOfFiles > 1;
|
||||
const showOwner = Boolean(
|
||||
currentFile && (currentFile.remoteOwnedByCurrentUser === false || currentFile.remoteSharedViaLink),
|
||||
currentFile &&
|
||||
(currentFile.remoteOwnedByCurrentUser === false ||
|
||||
currentFile.remoteSharedViaLink),
|
||||
);
|
||||
const ownerLabel = currentFile ? currentFile.remoteOwnerUsername || t("fileManager.ownerUnknown", "Unknown") : "";
|
||||
const ownerLabel = currentFile
|
||||
? currentFile.remoteOwnerUsername ||
|
||||
t("fileManager.ownerUnknown", "Unknown")
|
||||
: "";
|
||||
|
||||
return (
|
||||
<Stack gap="xs" style={{ height: "100%" }}>
|
||||
@@ -78,7 +83,9 @@ const CompactFileDetails: React.FC<CompactFileDetailsProps> = ({
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<PictureAsPdfIcon style={{ fontSize: 20, color: "var(--mantine-color-gray-6)" }} />
|
||||
<PictureAsPdfIcon
|
||||
style={{ fontSize: 20, color: "var(--mantine-color-gray-6)" }}
|
||||
/>
|
||||
</Center>
|
||||
) : null}
|
||||
</Box>
|
||||
@@ -86,7 +93,9 @@ const CompactFileDetails: React.FC<CompactFileDetailsProps> = ({
|
||||
{/* File info */}
|
||||
<Box style={{ flex: 1, minWidth: 0 }}>
|
||||
<Text size="sm" fw={500} truncate>
|
||||
<PrivateContent>{currentFile ? currentFile.name : "No file selected"}</PrivateContent>
|
||||
<PrivateContent>
|
||||
{currentFile ? currentFile.name : "No file selected"}
|
||||
</PrivateContent>
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed">
|
||||
{currentFile ? getFileSize(currentFile) : ""}
|
||||
@@ -101,7 +110,9 @@ const CompactFileDetails: React.FC<CompactFileDetailsProps> = ({
|
||||
{/* Compact tool chain for mobile */}
|
||||
{currentFile?.toolHistory && currentFile.toolHistory.length > 0 && (
|
||||
<Text size="xs" c="dimmed">
|
||||
{currentFile.toolHistory.map((tool) => t(`home.${tool.toolId}.title`, tool.toolId)).join(" → ")}
|
||||
{currentFile.toolHistory
|
||||
.map((tool) => t(`home.${tool.toolId}.title`, tool.toolId))
|
||||
.join(" → ")}
|
||||
</Text>
|
||||
)}
|
||||
{currentFile && showOwner && (
|
||||
@@ -114,10 +125,20 @@ const CompactFileDetails: React.FC<CompactFileDetailsProps> = ({
|
||||
{/* Navigation arrows for multiple files */}
|
||||
{hasMultipleFiles && (
|
||||
<Box style={{ display: "flex", gap: "0.25rem" }}>
|
||||
<ActionIcon variant="subtle" size="sm" onClick={onPrevious} disabled={isAnimating}>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
onClick={onPrevious}
|
||||
disabled={isAnimating}
|
||||
>
|
||||
<ChevronLeftIcon style={{ fontSize: 16 }} />
|
||||
</ActionIcon>
|
||||
<ActionIcon variant="subtle" size="sm" onClick={onNext} disabled={isAnimating}>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
size="sm"
|
||||
onClick={onNext}
|
||||
disabled={isAnimating}
|
||||
>
|
||||
<ChevronRightIcon style={{ fontSize: 16 }} />
|
||||
</ActionIcon>
|
||||
</Box>
|
||||
@@ -131,7 +152,9 @@ const CompactFileDetails: React.FC<CompactFileDetailsProps> = ({
|
||||
disabled={!hasSelection}
|
||||
fullWidth
|
||||
style={{
|
||||
backgroundColor: hasSelection ? "var(--btn-open-file)" : "var(--mantine-color-gray-4)",
|
||||
backgroundColor: hasSelection
|
||||
? "var(--btn-open-file)"
|
||||
: "var(--mantine-color-gray-4)",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -12,7 +12,12 @@ const DesktopLayout: React.FC = () => {
|
||||
const { activeSource, recentFiles, modalHeight } = useFileManagerContext();
|
||||
|
||||
return (
|
||||
<Grid gutter="xs" h="100%" grow={false} style={{ flexWrap: "nowrap", minWidth: 0 }}>
|
||||
<Grid
|
||||
gutter="xs"
|
||||
h="100%"
|
||||
grow={false}
|
||||
style={{ flexWrap: "nowrap", minWidth: 0 }}
|
||||
>
|
||||
{/* Column 1: File Sources */}
|
||||
<Grid.Col
|
||||
span="content"
|
||||
@@ -74,9 +79,16 @@ const DesktopLayout: React.FC = () => {
|
||||
|
||||
<div style={{ flex: 1, minHeight: 0, overflow: "hidden" }}>
|
||||
<FileListArea
|
||||
scrollAreaHeight={activeSource === "recent" && recentFiles.length > 0 ? `calc(${modalHeight} - 7rem)` : "100%"}
|
||||
scrollAreaHeight={
|
||||
activeSource === "recent" && recentFiles.length > 0
|
||||
? `calc(${modalHeight} - 7rem)`
|
||||
: "100%"
|
||||
}
|
||||
scrollAreaStyle={{
|
||||
height: activeSource === "recent" && recentFiles.length > 0 ? `calc(${modalHeight} - 7rem)` : "100%",
|
||||
height:
|
||||
activeSource === "recent" && recentFiles.length > 0
|
||||
? `calc(${modalHeight} - 7rem)`
|
||||
: "100%",
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
borderRadius: 0,
|
||||
|
||||
@@ -32,7 +32,9 @@ const DragOverlay: React.FC<DragOverlayProps> = ({ isVisible }) => {
|
||||
}}
|
||||
>
|
||||
<Stack align="center" gap="md">
|
||||
<UploadFileIcon style={{ fontSize: "4rem", color: theme.colors.blue[6] }} />
|
||||
<UploadFileIcon
|
||||
style={{ fontSize: "4rem", color: theme.colors.blue[6] }}
|
||||
/>
|
||||
<Text size="xl" fw={500} c="blue.6">
|
||||
{t("fileManager.dropFilesHere", "Drop files here to upload")}
|
||||
</Text>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import { Button, Group, Text, Stack, useMantineColorScheme } from "@mantine/core";
|
||||
import {
|
||||
Button,
|
||||
Group,
|
||||
Text,
|
||||
Stack,
|
||||
useMantineColorScheme,
|
||||
} from "@mantine/core";
|
||||
import HistoryIcon from "@mui/icons-material/History";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useFileManagerContext } from "@app/contexts/FileManagerContext";
|
||||
@@ -49,7 +55,9 @@ const EmptyFilesState: React.FC = () => {
|
||||
>
|
||||
{/* No Recent Files Message */}
|
||||
<Stack align="center" gap="sm">
|
||||
<HistoryIcon style={{ fontSize: "3rem", color: "var(--mantine-color-gray-5)" }} />
|
||||
<HistoryIcon
|
||||
style={{ fontSize: "3rem", color: "var(--mantine-color-gray-5)" }}
|
||||
/>
|
||||
<Text c="dimmed" ta="center" size="lg">
|
||||
{t("fileManager.noRecentFiles", "No recent files")}
|
||||
</Text>
|
||||
@@ -91,7 +99,8 @@ const EmptyFilesState: React.FC = () => {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
transition: "width .5s ease, padding .5s ease, border-radius .5s ease",
|
||||
transition:
|
||||
"width .5s ease, padding .5s ease, border-radius .5s ease",
|
||||
}}
|
||||
onClick={handleUploadClick}
|
||||
onMouseEnter={() => setIsUploadHover(true)}
|
||||
@@ -102,12 +111,19 @@ const EmptyFilesState: React.FC = () => {
|
||||
height="1.25rem"
|
||||
style={{ color: "var(--accent-interactive)" }}
|
||||
/>
|
||||
{isUploadHover && <span style={{ marginLeft: ".5rem" }}>{terminology.uploadFromComputer}</span>}
|
||||
{isUploadHover && (
|
||||
<span style={{ marginLeft: ".5rem" }}>
|
||||
{terminology.uploadFromComputer}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Instruction Text */}
|
||||
<span className="text-[var(--accent-interactive)]" style={{ fontSize: ".8rem", textAlign: "center" }}>
|
||||
<span
|
||||
className="text-[var(--accent-interactive)]"
|
||||
style={{ fontSize: ".8rem", textAlign: "center" }}
|
||||
>
|
||||
{terminology.dropFilesHere}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Group, Text, ActionIcon, Tooltip, SegmentedControl } from "@mantine/core";
|
||||
import {
|
||||
Group,
|
||||
Text,
|
||||
ActionIcon,
|
||||
Tooltip,
|
||||
SegmentedControl,
|
||||
} from "@mantine/core";
|
||||
import SelectAllIcon from "@mui/icons-material/SelectAll";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
||||
@@ -33,33 +39,51 @@ const FileActions: React.FC = () => {
|
||||
onStorageFilterChange,
|
||||
} = useFileManagerContext();
|
||||
const uploadEnabled = config?.storageEnabled === true;
|
||||
const sharingEnabled = uploadEnabled && config?.storageSharingEnabled === true;
|
||||
const shareLinksEnabled = sharingEnabled && config?.storageShareLinksEnabled === true;
|
||||
const sharingEnabled =
|
||||
uploadEnabled && config?.storageSharingEnabled === true;
|
||||
const shareLinksEnabled =
|
||||
sharingEnabled && config?.storageShareLinksEnabled === true;
|
||||
const showStorageFilter = uploadEnabled;
|
||||
const storageFilterOptions = sharingEnabled
|
||||
? [
|
||||
{ value: "all", label: t("fileManager.filterAll", "All") },
|
||||
{ value: "local", label: t("fileManager.filterLocal", "Local") },
|
||||
{ value: "sharedWithMe", label: t("fileManager.filterSharedWithMe", "Shared with me") },
|
||||
{ value: "sharedByMe", label: t("fileManager.filterSharedByMe", "Shared by me") },
|
||||
{
|
||||
value: "sharedWithMe",
|
||||
label: t("fileManager.filterSharedWithMe", "Shared with me"),
|
||||
},
|
||||
{
|
||||
value: "sharedByMe",
|
||||
label: t("fileManager.filterSharedByMe", "Shared by me"),
|
||||
},
|
||||
]
|
||||
: [
|
||||
{ value: "all", label: t("fileManager.filterAll", "All") },
|
||||
{ value: "local", label: t("fileManager.filterLocal", "Local") },
|
||||
];
|
||||
useEffect(() => {
|
||||
if (!sharingEnabled && (storageFilter === "sharedWithMe" || storageFilter === "sharedByMe")) {
|
||||
if (
|
||||
!sharingEnabled &&
|
||||
(storageFilter === "sharedWithMe" || storageFilter === "sharedByMe")
|
||||
) {
|
||||
onStorageFilterChange("all");
|
||||
}
|
||||
}, [sharingEnabled, storageFilter, onStorageFilterChange]);
|
||||
const hasSelection = selectedFileIds.length > 0;
|
||||
const hasOnlyOwnedSelection = selectedFiles.every((file) => file.remoteOwnedByCurrentUser !== false);
|
||||
const hasOnlyOwnedSelection = selectedFiles.every(
|
||||
(file) => file.remoteOwnedByCurrentUser !== false,
|
||||
);
|
||||
const hasDownloadAccess = selectedFiles.every((file) => {
|
||||
const role = (file.remoteOwnedByCurrentUser !== false ? "editor" : (file.remoteAccessRole ?? "viewer")).toLowerCase();
|
||||
const role = (
|
||||
file.remoteOwnedByCurrentUser !== false
|
||||
? "editor"
|
||||
: (file.remoteAccessRole ?? "viewer")
|
||||
).toLowerCase();
|
||||
return role === "editor" || role === "commenter" || role === "viewer";
|
||||
});
|
||||
const canBulkUpload = uploadEnabled && hasSelection && hasOnlyOwnedSelection;
|
||||
const canBulkShare = shareLinksEnabled && hasSelection && hasOnlyOwnedSelection;
|
||||
const canBulkShare =
|
||||
shareLinksEnabled && hasSelection && hasOnlyOwnedSelection;
|
||||
|
||||
const handleSelectAll = () => {
|
||||
onSelectAll();
|
||||
@@ -82,7 +106,8 @@ const FileActions: React.FC = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const allFilesSelected = filteredFiles.length > 0 && selectedFileIds.length === filteredFiles.length;
|
||||
const allFilesSelected =
|
||||
filteredFiles.length > 0 && selectedFileIds.length === filteredFiles.length;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -99,7 +124,11 @@ const FileActions: React.FC = () => {
|
||||
{/* Left: Select All + Filter */}
|
||||
<Group gap="xs">
|
||||
<Tooltip
|
||||
label={allFilesSelected ? t("fileManager.deselectAll", "Deselect All") : t("fileManager.selectAll", "Select All")}
|
||||
label={
|
||||
allFilesSelected
|
||||
? t("fileManager.deselectAll", "Deselect All")
|
||||
: t("fileManager.selectAll", "Select All")
|
||||
}
|
||||
>
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
@@ -116,7 +145,11 @@ const FileActions: React.FC = () => {
|
||||
<SegmentedControl
|
||||
size="xs"
|
||||
value={storageFilter}
|
||||
onChange={(value) => onStorageFilterChange(value as "all" | "local" | "sharedWithMe" | "sharedByMe")}
|
||||
onChange={(value) =>
|
||||
onStorageFilterChange(
|
||||
value as "all" | "local" | "sharedWithMe" | "sharedByMe",
|
||||
)
|
||||
}
|
||||
data={storageFilterOptions}
|
||||
/>
|
||||
)}
|
||||
@@ -132,7 +165,9 @@ const FileActions: React.FC = () => {
|
||||
>
|
||||
{hasSelection && (
|
||||
<Text size="sm" c="dimmed" fw={500}>
|
||||
{t("fileManager.selectedCount", "{{count}} selected", { count: selectedFileIds.length })}
|
||||
{t("fileManager.selectedCount", "{{count}} selected", {
|
||||
count: selectedFileIds.length,
|
||||
})}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,8 @@ const FileDetails: React.FC<FileDetailsProps> = ({ compact = false }) => {
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
|
||||
// Get the currently displayed file
|
||||
const currentFile = selectedFiles.length > 0 ? selectedFiles[currentFileIndex] : null;
|
||||
const currentFile =
|
||||
selectedFiles.length > 0 ? selectedFiles[currentFileIndex] : null;
|
||||
const hasSelection = selectedFiles.length > 0;
|
||||
|
||||
// Use IndexedDB hook for the current file
|
||||
@@ -33,7 +34,9 @@ const FileDetails: React.FC<FileDetailsProps> = ({ compact = false }) => {
|
||||
if (isAnimating) return;
|
||||
setIsAnimating(true);
|
||||
setTimeout(() => {
|
||||
setCurrentFileIndex((prev) => (prev > 0 ? prev - 1 : selectedFiles.length - 1));
|
||||
setCurrentFileIndex((prev) =>
|
||||
prev > 0 ? prev - 1 : selectedFiles.length - 1,
|
||||
);
|
||||
setIsAnimating(false);
|
||||
}, 150);
|
||||
};
|
||||
@@ -42,7 +45,9 @@ const FileDetails: React.FC<FileDetailsProps> = ({ compact = false }) => {
|
||||
if (isAnimating) return;
|
||||
setIsAnimating(true);
|
||||
setTimeout(() => {
|
||||
setCurrentFileIndex((prev) => (prev < selectedFiles.length - 1 ? prev + 1 : 0));
|
||||
setCurrentFileIndex((prev) =>
|
||||
prev < selectedFiles.length - 1 ? prev + 1 : 0,
|
||||
);
|
||||
setIsAnimating(false);
|
||||
}, 150);
|
||||
};
|
||||
@@ -73,7 +78,14 @@ const FileDetails: React.FC<FileDetailsProps> = ({ compact = false }) => {
|
||||
return (
|
||||
<Stack gap="lg" h={`calc(${modalHeight} - 2rem)`} justify="flex-start">
|
||||
{/* Section 1: Thumbnail Preview */}
|
||||
<Box style={{ width: "100%", height: "min(35vh, 280px)", textAlign: "center", flexShrink: 0 }}>
|
||||
<Box
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "min(35vh, 280px)",
|
||||
textAlign: "center",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<FilePreview
|
||||
file={currentFile}
|
||||
thumbnail={getCurrentThumbnail()}
|
||||
@@ -95,7 +107,9 @@ const FileDetails: React.FC<FileDetailsProps> = ({ compact = false }) => {
|
||||
disabled={!hasSelection}
|
||||
fullWidth
|
||||
style={{
|
||||
backgroundColor: hasSelection ? "var(--btn-open-file)" : "var(--mantine-color-gray-4)",
|
||||
backgroundColor: hasSelection
|
||||
? "var(--btn-open-file)"
|
||||
: "var(--mantine-color-gray-4)",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -39,7 +39,8 @@ const FileHistoryGroup: React.FC<FileHistoryGroupProps> = ({
|
||||
<Box ml="md" mt="xs" mb="sm">
|
||||
<Group align="center" mb="sm">
|
||||
<Text size="xs" fw={600} c="dimmed">
|
||||
{t("fileManager.fileHistory", "File History")} ({sortedHistory.length})
|
||||
{t("fileManager.fileHistory", "File History")} (
|
||||
{sortedHistory.length})
|
||||
</Text>
|
||||
</Group>
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { Stack, Card, Box, Text, Badge, Group, Divider, ScrollArea, Button } from "@mantine/core";
|
||||
import {
|
||||
Stack,
|
||||
Card,
|
||||
Box,
|
||||
Text,
|
||||
Badge,
|
||||
Group,
|
||||
Divider,
|
||||
ScrollArea,
|
||||
Button,
|
||||
} from "@mantine/core";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { detectFileExtension, getFileSize } from "@app/utils/fileUtils";
|
||||
import { StirlingFileStub } from "@app/types/fileContext";
|
||||
@@ -14,31 +24,43 @@ interface FileInfoCardProps {
|
||||
modalHeight: string;
|
||||
}
|
||||
|
||||
const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight }) => {
|
||||
const FileInfoCard: React.FC<FileInfoCardProps> = ({
|
||||
currentFile,
|
||||
modalHeight,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { config } = useAppConfig();
|
||||
const { onMakeCopy } = useFileManagerContext();
|
||||
const [showShareManageModal, setShowShareManageModal] = useState(false);
|
||||
const isSharedWithYou = useMemo(() => {
|
||||
if (!currentFile) return false;
|
||||
return currentFile.remoteOwnedByCurrentUser === false || currentFile.remoteSharedViaLink;
|
||||
return (
|
||||
currentFile.remoteOwnedByCurrentUser === false ||
|
||||
currentFile.remoteSharedViaLink
|
||||
);
|
||||
}, [currentFile]);
|
||||
const isOwnedRemote = useMemo(() => {
|
||||
if (!currentFile) return false;
|
||||
return Boolean(currentFile.remoteStorageId) && currentFile.remoteOwnedByCurrentUser !== false;
|
||||
return (
|
||||
Boolean(currentFile.remoteStorageId) &&
|
||||
currentFile.remoteOwnedByCurrentUser !== false
|
||||
);
|
||||
}, [currentFile]);
|
||||
const localUpdatedAt = currentFile?.createdAt ?? currentFile?.lastModified ?? 0;
|
||||
const localUpdatedAt =
|
||||
currentFile?.createdAt ?? currentFile?.lastModified ?? 0;
|
||||
const remoteUpdatedAt = currentFile?.remoteStorageUpdatedAt ?? 0;
|
||||
const isUploaded = Boolean(currentFile?.remoteStorageId);
|
||||
const isUpToDate = isUploaded && remoteUpdatedAt >= localUpdatedAt;
|
||||
const isOutOfSync = isUploaded && !isUpToDate && isOwnedRemote;
|
||||
const isLocalOnly = !currentFile?.remoteStorageId && !currentFile?.remoteSharedViaLink;
|
||||
const isLocalOnly =
|
||||
!currentFile?.remoteStorageId && !currentFile?.remoteSharedViaLink;
|
||||
const isSharedByYou = useMemo(() => {
|
||||
if (!currentFile) return false;
|
||||
return isOwnedRemote && Boolean(currentFile.remoteHasShareLinks);
|
||||
}, [currentFile, isOwnedRemote]);
|
||||
const uploadEnabled = config?.storageEnabled === true;
|
||||
const sharingEnabled = uploadEnabled && config?.storageSharingEnabled === true;
|
||||
const sharingEnabled =
|
||||
uploadEnabled && config?.storageSharingEnabled === true;
|
||||
const ownerLabel = useMemo(() => {
|
||||
if (!currentFile) return "";
|
||||
if (currentFile.remoteOwnerUsername) {
|
||||
@@ -56,7 +78,12 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
withBorder
|
||||
p={0}
|
||||
mah={`calc(${modalHeight} * 0.45)`}
|
||||
style={{ overflow: "hidden", flexShrink: 1, display: "flex", flexDirection: "column" }}
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
flexShrink: 1,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
bg="gray.4"
|
||||
@@ -75,9 +102,16 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
<Stack gap="sm">
|
||||
<Group justify="space-between" py="xs">
|
||||
<Text size="sm" c="dimmed">
|
||||
<PrivateContent>{t("fileManager.fileName", "Name")}</PrivateContent>
|
||||
<PrivateContent>
|
||||
{t("fileManager.fileName", "Name")}
|
||||
</PrivateContent>
|
||||
</Text>
|
||||
<Text size="sm" fw={500} style={{ maxWidth: "60%", textAlign: "right" }} truncate>
|
||||
<Text
|
||||
size="sm"
|
||||
fw={500}
|
||||
style={{ maxWidth: "60%", textAlign: "right" }}
|
||||
truncate
|
||||
>
|
||||
{currentFile ? currentFile.name : ""}
|
||||
</Text>
|
||||
</Group>
|
||||
@@ -112,7 +146,9 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
{t("fileManager.lastModified", "Last modified")}
|
||||
</Text>
|
||||
<Text size="sm" fw={500}>
|
||||
{currentFile ? new Date(currentFile.lastModified).toLocaleDateString() : ""}
|
||||
{currentFile
|
||||
? new Date(currentFile.lastModified).toLocaleDateString()
|
||||
: ""}
|
||||
</Text>
|
||||
</Group>
|
||||
<Divider />
|
||||
@@ -122,7 +158,11 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
{t("fileManager.fileVersion", "Version")}
|
||||
</Text>
|
||||
{currentFile && (
|
||||
<Badge size="sm" variant="light" color={currentFile?.versionNumber ? "blue" : "gray"}>
|
||||
<Badge
|
||||
size="sm"
|
||||
variant="light"
|
||||
color={currentFile?.versionNumber ? "blue" : "gray"}
|
||||
>
|
||||
v{currentFile ? currentFile.versionNumber || 1 : ""}
|
||||
</Badge>
|
||||
)}
|
||||
@@ -154,7 +194,11 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
<Text size="xs" c="dimmed" mb="xs">
|
||||
{t("fileManager.toolChain", "Tools Applied")}
|
||||
</Text>
|
||||
<ToolChain toolChain={currentFile.toolHistory} displayStyle="badges" size="xs" />
|
||||
<ToolChain
|
||||
toolChain={currentFile.toolHistory}
|
||||
displayStyle="badges"
|
||||
size="xs"
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
@@ -162,7 +206,12 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
{currentFile && isSharedWithYou && (
|
||||
<>
|
||||
<Divider />
|
||||
<Button size="sm" variant="light" onClick={() => onMakeCopy(currentFile)} fullWidth>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="light"
|
||||
onClick={() => onMakeCopy(currentFile)}
|
||||
fullWidth
|
||||
>
|
||||
{t("fileManager.makeCopy", "Make a copy")}
|
||||
</Button>
|
||||
</>
|
||||
@@ -177,7 +226,10 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
</Text>
|
||||
{uploadEnabled && isOutOfSync ? (
|
||||
<Badge size="xs" variant="light" color="yellow">
|
||||
{t("fileManager.changesNotUploaded", "Changes not uploaded")}
|
||||
{t(
|
||||
"fileManager.changesNotUploaded",
|
||||
"Changes not uploaded",
|
||||
)}
|
||||
</Badge>
|
||||
) : uploadEnabled ? (
|
||||
<Badge size="xs" variant="light" color="teal">
|
||||
@@ -206,7 +258,12 @@ const FileInfoCard: React.FC<FileInfoCardProps> = ({ currentFile, modalHeight })
|
||||
{t("fileManager.sharedByYou", "Shared by you")}
|
||||
</Badge>
|
||||
</Group>
|
||||
<Button size="sm" variant="light" onClick={() => setShowShareManageModal(true)} fullWidth>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="light"
|
||||
onClick={() => setShowShareManageModal(true)}
|
||||
fullWidth
|
||||
>
|
||||
{t("storageShare.manage", "Manage sharing")}
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@@ -12,7 +12,10 @@ interface FileListAreaProps {
|
||||
scrollAreaStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const FileListArea: React.FC<FileListAreaProps> = ({ scrollAreaHeight, scrollAreaStyle = {} }) => {
|
||||
const FileListArea: React.FC<FileListAreaProps> = ({
|
||||
scrollAreaHeight,
|
||||
scrollAreaStyle = {},
|
||||
}) => {
|
||||
const {
|
||||
activeSource,
|
||||
recentFiles,
|
||||
@@ -94,9 +97,14 @@ const FileListArea: React.FC<FileListAreaProps> = ({ scrollAreaHeight, scrollAre
|
||||
return (
|
||||
<Center style={{ height: "12.5rem" }}>
|
||||
<Stack align="center" gap="sm">
|
||||
<CloudIcon style={{ fontSize: "3rem", color: "var(--mantine-color-gray-5)" }} />
|
||||
<CloudIcon
|
||||
style={{ fontSize: "3rem", color: "var(--mantine-color-gray-5)" }}
|
||||
/>
|
||||
<Text c="dimmed" ta="center">
|
||||
{t("fileManager.googleDriveNotAvailable", "Google Drive integration coming soon")}
|
||||
{t(
|
||||
"fileManager.googleDriveNotAvailable",
|
||||
"Google Drive integration coming soon",
|
||||
)}
|
||||
</Text>
|
||||
</Stack>
|
||||
</Center>
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { Group, Box, Text, ActionIcon, Checkbox, Divider, Menu, Badge } from "@mantine/core";
|
||||
import {
|
||||
Group,
|
||||
Box,
|
||||
Text,
|
||||
ActionIcon,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Menu,
|
||||
Badge,
|
||||
} from "@mantine/core";
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import DownloadIcon from "@mui/icons-material/Download";
|
||||
@@ -60,14 +69,21 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
const [showShareManageModal, setShowShareManageModal] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const { config } = useAppConfig();
|
||||
const { expandedFileIds, onToggleExpansion, onUnzipFile, refreshRecentFiles } = useFileManagerContext();
|
||||
const {
|
||||
expandedFileIds,
|
||||
onToggleExpansion,
|
||||
onUnzipFile,
|
||||
refreshRecentFiles,
|
||||
} = useFileManagerContext();
|
||||
const { removeFiles } = useFileManagement();
|
||||
|
||||
// Check if this is a ZIP file
|
||||
const isZipFile = zipFileService.isZipFileStub(file);
|
||||
|
||||
// Check file extension
|
||||
const extLower = (file.name?.match(/\.([a-z0-9]+)$/i)?.[1] || "").toLowerCase();
|
||||
const extLower = (
|
||||
file.name?.match(/\.([a-z0-9]+)$/i)?.[1] || ""
|
||||
).toLowerCase();
|
||||
const isCBZ = extLower === "cbz";
|
||||
const isCBR = extLower === "cbr";
|
||||
|
||||
@@ -75,33 +91,55 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
const shouldShowHovered = isHovered || isMenuOpen;
|
||||
|
||||
// Get version information for this file
|
||||
const leafFileId = (isLatestVersion ? file.id : file.originalFileId || file.id) as FileId;
|
||||
const leafFileId = (
|
||||
isLatestVersion ? file.id : file.originalFileId || file.id
|
||||
) as FileId;
|
||||
const hasVersionHistory = (file.versionNumber || 1) > 1; // Show history for any processed file (v2+)
|
||||
const currentVersion = file.versionNumber || 1; // Display original files as v1
|
||||
const isExpanded = expandedFileIds.has(leafFileId);
|
||||
const uploadEnabled = config?.storageEnabled === true;
|
||||
const sharingEnabled = uploadEnabled && config?.storageSharingEnabled === true;
|
||||
const shareLinksEnabled = sharingEnabled && config?.storageShareLinksEnabled === true;
|
||||
const sharingEnabled =
|
||||
uploadEnabled && config?.storageSharingEnabled === true;
|
||||
const shareLinksEnabled =
|
||||
sharingEnabled && config?.storageShareLinksEnabled === true;
|
||||
const isOwnedOrLocal = file.remoteOwnedByCurrentUser !== false;
|
||||
const isSharedWithYou = sharingEnabled && (file.remoteOwnedByCurrentUser === false || file.remoteSharedViaLink);
|
||||
const isSharedWithYou =
|
||||
sharingEnabled &&
|
||||
(file.remoteOwnedByCurrentUser === false || file.remoteSharedViaLink);
|
||||
const localUpdatedAt = file.createdAt ?? file.lastModified ?? 0;
|
||||
const remoteUpdatedAt = file.remoteStorageUpdatedAt ?? 0;
|
||||
const isUploaded = Boolean(file.remoteStorageId);
|
||||
const isUpToDate = isUploaded && remoteUpdatedAt >= localUpdatedAt;
|
||||
const isOutOfSync = isUploaded && !isUpToDate && isOwnedOrLocal;
|
||||
const isLocalOnly = !file.remoteStorageId && !file.remoteSharedViaLink;
|
||||
const accessRole = (isOwnedOrLocal ? "editor" : (file.remoteAccessRole ?? "viewer")).toLowerCase();
|
||||
const hasReadAccess = isOwnedOrLocal || accessRole === "editor" || accessRole === "commenter" || accessRole === "viewer";
|
||||
const canUpload = uploadEnabled && isOwnedOrLocal && isLatestVersion && (!isUploaded || !isUpToDate);
|
||||
const accessRole = (
|
||||
isOwnedOrLocal ? "editor" : (file.remoteAccessRole ?? "viewer")
|
||||
).toLowerCase();
|
||||
const hasReadAccess =
|
||||
isOwnedOrLocal ||
|
||||
accessRole === "editor" ||
|
||||
accessRole === "commenter" ||
|
||||
accessRole === "viewer";
|
||||
const canUpload =
|
||||
uploadEnabled &&
|
||||
isOwnedOrLocal &&
|
||||
isLatestVersion &&
|
||||
(!isUploaded || !isUpToDate);
|
||||
const canShare = shareLinksEnabled && isOwnedOrLocal && isLatestVersion;
|
||||
const canManageShare = sharingEnabled && isOwnedOrLocal && Boolean(file.remoteStorageId);
|
||||
const canCopyShareLink = shareLinksEnabled && Boolean(file.remoteHasShareLinks) && Boolean(file.remoteStorageId);
|
||||
const canManageShare =
|
||||
sharingEnabled && isOwnedOrLocal && Boolean(file.remoteStorageId);
|
||||
const canCopyShareLink =
|
||||
shareLinksEnabled &&
|
||||
Boolean(file.remoteHasShareLinks) &&
|
||||
Boolean(file.remoteStorageId);
|
||||
const canDownloadFile = Boolean(onDownload) && hasReadAccess;
|
||||
|
||||
const shareBaseUrl = useMemo(() => {
|
||||
const frontendUrl = (config?.frontendUrl || "").trim();
|
||||
if (frontendUrl) {
|
||||
const normalized = frontendUrl.endsWith("/") ? frontendUrl.slice(0, -1) : frontendUrl;
|
||||
const normalized = frontendUrl.endsWith("/")
|
||||
? frontendUrl.slice(0, -1)
|
||||
: frontendUrl;
|
||||
return `${normalized}/share/`;
|
||||
}
|
||||
return absoluteWithBasePath("/share/");
|
||||
@@ -110,10 +148,11 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
const handleCopyShareLink = useCallback(async () => {
|
||||
if (!file.remoteStorageId) return;
|
||||
try {
|
||||
const response = await apiClient.get<{ shareLinks?: Array<{ token?: string }> }>(
|
||||
`/api/v1/storage/files/${file.remoteStorageId}`,
|
||||
{ suppressErrorToast: true } as any,
|
||||
);
|
||||
const response = await apiClient.get<{
|
||||
shareLinks?: Array<{ token?: string }>;
|
||||
}>(`/api/v1/storage/files/${file.remoteStorageId}`, {
|
||||
suppressErrorToast: true,
|
||||
} as any);
|
||||
const links = response.data?.shareLinks ?? [];
|
||||
const token = links[links.length - 1]?.token;
|
||||
if (!token) {
|
||||
@@ -163,9 +202,13 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
MozUserSelect: "none",
|
||||
msUserSelect: "none",
|
||||
paddingLeft: isHistoryFile ? "2rem" : "0.75rem", // Indent history files
|
||||
borderLeft: isHistoryFile ? "3px solid var(--mantine-color-blue-4)" : "none", // Visual indicator for history
|
||||
borderLeft: isHistoryFile
|
||||
? "3px solid var(--mantine-color-blue-4)"
|
||||
: "none", // Visual indicator for history
|
||||
}}
|
||||
onClick={isHistoryFile || isActive ? undefined : (e) => onSelect(e.shiftKey)}
|
||||
onClick={
|
||||
isHistoryFile || isActive ? undefined : (e) => onSelect(e.shiftKey)
|
||||
}
|
||||
onDoubleClick={onDoubleClick}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
@@ -217,7 +260,10 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
{t("fileManager.sharedWithYou", "Shared with you")}
|
||||
</Badge>
|
||||
) : null}
|
||||
{sharingEnabled && isSharedWithYou && accessRole && accessRole !== "editor" ? (
|
||||
{sharingEnabled &&
|
||||
isSharedWithYou &&
|
||||
accessRole &&
|
||||
accessRole !== "editor" ? (
|
||||
<Badge size="xs" variant="light" color="gray">
|
||||
{accessRole === "commenter"
|
||||
? t("storageShare.roleCommenter", "Commenter")
|
||||
@@ -228,19 +274,31 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
{t("fileManager.localOnly", "Local only")}
|
||||
</Badge>
|
||||
) : uploadEnabled && isOutOfSync ? (
|
||||
<Badge size="xs" variant="light" color="yellow" leftSection={<CloudUploadIcon style={{ fontSize: 12 }} />}>
|
||||
<Badge
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="yellow"
|
||||
leftSection={<CloudUploadIcon style={{ fontSize: 12 }} />}
|
||||
>
|
||||
{t("fileManager.changesNotUploaded", "Changes not uploaded")}
|
||||
</Badge>
|
||||
) : uploadEnabled && isUploaded ? (
|
||||
<Badge size="xs" variant="light" color="teal" leftSection={<CloudDoneIcon style={{ fontSize: 12 }} />}>
|
||||
<Badge
|
||||
size="xs"
|
||||
variant="light"
|
||||
color="teal"
|
||||
leftSection={<CloudDoneIcon style={{ fontSize: 12 }} />}
|
||||
>
|
||||
{t("fileManager.synced", "Synced")}
|
||||
</Badge>
|
||||
) : null}
|
||||
{sharingEnabled && file.remoteOwnedByCurrentUser !== false && file.remoteHasShareLinks && (
|
||||
<Badge size="xs" variant="light" color="blue">
|
||||
{t("fileManager.sharedByYou", "Shared by you")}
|
||||
</Badge>
|
||||
)}
|
||||
{sharingEnabled &&
|
||||
file.remoteOwnedByCurrentUser !== false &&
|
||||
file.remoteHasShareLinks && (
|
||||
<Badge size="xs" variant="light" color="blue">
|
||||
{t("fileManager.sharedByYou", "Shared by you")}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
<Group gap="xs" align="center">
|
||||
<Text size="xs" c="dimmed">
|
||||
@@ -249,7 +307,12 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
|
||||
{/* Tool chain for processed files */}
|
||||
{file.toolHistory && file.toolHistory.length > 0 && (
|
||||
<ToolChain toolChain={file.toolHistory} maxWidth={"150px"} displayStyle="text" size="xs" />
|
||||
<ToolChain
|
||||
toolChain={file.toolHistory}
|
||||
maxWidth={"150px"}
|
||||
displayStyle="text"
|
||||
size="xs"
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
</Box>
|
||||
@@ -368,7 +431,9 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
onToggleExpansion(leafFileId);
|
||||
}}
|
||||
>
|
||||
{isExpanded ? t("fileManager.hideHistory", "Hide History") : t("fileManager.showHistory", "Show History")}
|
||||
{isExpanded
|
||||
? t("fileManager.hideHistory", "Hide History")
|
||||
: t("fileManager.showHistory", "Show History")}
|
||||
</Menu.Item>
|
||||
<Menu.Divider />
|
||||
</>
|
||||
@@ -436,7 +501,11 @@ const FileListItem: React.FC<FileListItemProps> = ({
|
||||
/>
|
||||
)}
|
||||
{canManageShare && (
|
||||
<ShareManagementModal opened={showShareManageModal} onClose={() => setShowShareManageModal(false)} file={file} />
|
||||
<ShareManagementModal
|
||||
opened={showShareManageModal}
|
||||
onClose={() => setShowShareManageModal(false)}
|
||||
file={file}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -32,10 +32,19 @@ const GoogleDriveIcon: React.FC<{ disabled?: boolean }> = ({ disabled }) => (
|
||||
/>
|
||||
);
|
||||
|
||||
const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({ horizontal = false }) => {
|
||||
const { activeSource, onSourceChange, onLocalFileClick, onGoogleDriveSelect, onNewFilesSelect } = useFileManagerContext();
|
||||
const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({
|
||||
horizontal = false,
|
||||
}) => {
|
||||
const {
|
||||
activeSource,
|
||||
onSourceChange,
|
||||
onLocalFileClick,
|
||||
onGoogleDriveSelect,
|
||||
onNewFilesSelect,
|
||||
} = useFileManagerContext();
|
||||
const { t } = useTranslation();
|
||||
const { isEnabled: isGoogleDriveEnabled, openPicker: openGoogleDrivePicker } = useGoogleDrivePicker();
|
||||
const { isEnabled: isGoogleDriveEnabled, openPicker: openGoogleDrivePicker } =
|
||||
useGoogleDrivePicker();
|
||||
const terminology = useFileActionTerminology();
|
||||
const icons = useFileActionIcons();
|
||||
const UploadIcon = icons.upload;
|
||||
@@ -66,21 +75,29 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({ horizontal = fals
|
||||
};
|
||||
|
||||
// Determine visibility of Google Drive button
|
||||
const shouldHideGoogleDrive = !isGoogleDriveEnabled && config?.hideDisabledToolsGoogleDrive;
|
||||
const shouldHideGoogleDrive =
|
||||
!isGoogleDriveEnabled && config?.hideDisabledToolsGoogleDrive;
|
||||
|
||||
// Determine visibility of Mobile QR Scanner button
|
||||
const shouldHideMobileQR = !isMobileUploadEnabled && config?.hideDisabledToolsMobileQRScanner;
|
||||
const shouldHideMobileQR =
|
||||
!isMobileUploadEnabled && config?.hideDisabledToolsMobileQRScanner;
|
||||
|
||||
const buttonProps = {
|
||||
variant: (source: string) => (activeSource === source ? "filled" : "subtle"),
|
||||
getColor: (source: string) => (activeSource === source ? "var(--mantine-color-gray-2)" : undefined),
|
||||
variant: (source: string) =>
|
||||
activeSource === source ? "filled" : "subtle",
|
||||
getColor: (source: string) =>
|
||||
activeSource === source ? "var(--mantine-color-gray-2)" : undefined,
|
||||
getStyles: (source: string) => ({
|
||||
root: {
|
||||
backgroundColor: activeSource === source ? undefined : "transparent",
|
||||
color: activeSource === source ? "var(--mantine-color-gray-9)" : "var(--mantine-color-gray-6)",
|
||||
color:
|
||||
activeSource === source
|
||||
? "var(--mantine-color-gray-9)"
|
||||
: "var(--mantine-color-gray-6)",
|
||||
border: "none",
|
||||
"&:hover": {
|
||||
backgroundColor: activeSource === source ? undefined : "var(--mantine-color-gray-0)",
|
||||
backgroundColor:
|
||||
activeSource === source ? undefined : "var(--mantine-color-gray-0)",
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -97,7 +114,9 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({ horizontal = fals
|
||||
color={buttonProps.getColor("recent")}
|
||||
styles={buttonProps.getStyles("recent")}
|
||||
>
|
||||
{horizontal ? t("fileManager.recent", "Recent") : t("fileManager.recent", "Recent")}
|
||||
{horizontal
|
||||
? t("fileManager.recent", "Recent")
|
||||
: t("fileManager.recent", "Recent")}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
@@ -136,17 +155,24 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({ horizontal = fals
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
"&:hover": {
|
||||
backgroundColor: isGoogleDriveEnabled ? "var(--mantine-color-gray-0)" : "transparent",
|
||||
backgroundColor: isGoogleDriveEnabled
|
||||
? "var(--mantine-color-gray-0)"
|
||||
: "transparent",
|
||||
},
|
||||
},
|
||||
}}
|
||||
title={
|
||||
!isGoogleDriveEnabled
|
||||
? t("fileManager.googleDriveNotAvailable", "Google Drive integration not available")
|
||||
? t(
|
||||
"fileManager.googleDriveNotAvailable",
|
||||
"Google Drive integration not available",
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{horizontal ? t("fileManager.googleDriveShort", "Drive") : t("fileManager.googleDrive", "Google Drive")}
|
||||
{horizontal
|
||||
? t("fileManager.googleDriveShort", "Drive")
|
||||
: t("fileManager.googleDrive", "Google Drive")}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -165,13 +191,24 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({ horizontal = fals
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
"&:hover": {
|
||||
backgroundColor: isMobileUploadEnabled ? "var(--mantine-color-gray-0)" : "transparent",
|
||||
backgroundColor: isMobileUploadEnabled
|
||||
? "var(--mantine-color-gray-0)"
|
||||
: "transparent",
|
||||
},
|
||||
},
|
||||
}}
|
||||
title={!isMobileUploadEnabled ? t("fileManager.mobileUploadNotAvailable", "Mobile upload not available") : undefined}
|
||||
title={
|
||||
!isMobileUploadEnabled
|
||||
? t(
|
||||
"fileManager.mobileUploadNotAvailable",
|
||||
"Mobile upload not available",
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{horizontal ? t("fileManager.mobileShort", "Mobile") : t("fileManager.mobileUpload", "Mobile Upload")}
|
||||
{horizontal
|
||||
? t("fileManager.mobileShort", "Mobile")
|
||||
: t("fileManager.mobileUpload", "Mobile Upload")}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
@@ -195,7 +232,14 @@ const FileSourceButtons: React.FC<FileSourceButtonsProps> = ({ horizontal = fals
|
||||
return (
|
||||
<>
|
||||
<Stack gap="xs" style={{ height: "100%" }}>
|
||||
<Text size="sm" pt="sm" fw={500} c="dimmed" mb="xs" style={{ paddingLeft: "1rem" }}>
|
||||
<Text
|
||||
size="sm"
|
||||
pt="sm"
|
||||
fw={500}
|
||||
c="dimmed"
|
||||
mb="xs"
|
||||
style={{ paddingLeft: "1rem" }}
|
||||
>
|
||||
{t("fileManager.myFiles", "My Files")}
|
||||
</Text>
|
||||
{buttons}
|
||||
|
||||
@@ -27,7 +27,11 @@ const MobileLayout: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Box h="100%" p="sm" style={{ display: "flex", flexDirection: "column", gap: "0.75rem" }}>
|
||||
<Box
|
||||
h="100%"
|
||||
p="sm"
|
||||
style={{ display: "flex", flexDirection: "column", gap: "0.75rem" }}
|
||||
>
|
||||
{/* Section 1: File Sources - Fixed at top */}
|
||||
<Box style={{ flexShrink: 0 }}>
|
||||
<FileSourceButtons horizontal={true} />
|
||||
|
||||
Reference in New Issue
Block a user