Merge branch 'reorderImageFileField' of https://github.com/saravanan-inc/rowy into reorderImageFileField

This commit is contained in:
unknown
2023-02-08 22:21:15 +05:30
5 changed files with 300 additions and 126 deletions

View File

@@ -19,6 +19,17 @@ export const StyledCell = styled("div")(({ theme }) => ({
alignItems: "center",
},
"& > .cell-contents-contain-none": {
padding: "0 var(--cell-padding)",
width: "100%",
height: "100%",
contain: "none",
overflow: "hidden",
display: "flex",
alignItems: "center",
},
backgroundColor: "var(--cell-background-color)",
border: `1px solid ${theme.palette.divider}`,

View File

@@ -192,7 +192,7 @@ export default function withRenderTableCell(
if (editorMode === "inline") {
return (
<div
className="cell-contents"
className="cell-contents-contain-none"
style={options.disablePadding ? { padding: 0 } : undefined}
ref={displayCellRef}
>

View File

@@ -15,6 +15,15 @@ import { DATE_TIME_FORMAT } from "@src/constants/dates";
import { FileValue } from "@src/types/table";
import useFileUpload from "./useFileUpload";
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
import {
DragDropContext,
Droppable,
Draggable,
DropResult,
ResponderProvided,
} from "react-beautiful-dnd";
export default function File_({
column,
value,
@@ -25,11 +34,40 @@ export default function File_({
}: IEditorCellProps) {
const confirm = useSetAtom(confirmDialogAtom, projectScope);
const { loading, progress, handleDelete, localFiles, dropzoneState } =
useFileUpload(_rowy_ref, column.key, { multiple: true });
const {
loading,
progress,
handleDelete,
localFiles,
dropzoneState,
handleUpdate,
} = useFileUpload(_rowy_ref, column.key, { multiple: true });
const { isDragActive, getRootProps, getInputProps } = dropzoneState;
const dropzoneProps = getRootProps();
const onDragEnd = (result: DropResult, provided: ResponderProvided) => {
const { destination, source, draggableId } = result;
if (!destination) {
return;
}
if (
destination.droppableId === source.droppableId &&
destination.index === source.index
) {
return;
}
const newValue = Array.from(value);
newValue.splice(source.index, 1);
newValue.splice(destination.index, 0, value[source.index]);
handleUpdate([...newValue]);
};
return (
<Stack
direction="row"
@@ -37,6 +75,8 @@ export default function File_({
sx={{
width: "100%",
height: "100%",
py: 0,
pl: 1,
...(isDragActive
? {
@@ -54,70 +94,108 @@ export default function File_({
tabIndex={tabIndex}
onClick={undefined}
>
<ChipList rowHeight={rowHeight}>
{Array.isArray(value) &&
value.map((file: FileValue) => (
<Grid
item
key={file.downloadURL}
style={
// Truncate so multiple files still visible
value.length > 1 ? { maxWidth: `calc(100% - 12px)` } : {}
}
>
<Tooltip
title={`File last modified ${format(
file.lastModifiedTS,
DATE_TIME_FORMAT
)}`}
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="image-droppable" direction="horizontal">
{(provided) => (
<ChipList rowHeight={rowHeight}>
<Grid
container
spacing={0.5}
wrap="nowrap"
ref={provided.innerRef}
{...provided.droppableProps}
>
<Chip
label={file.name}
icon={<FileIcon />}
sx={{
"& .MuiChip-label": {
lineHeight: 5 / 3,
},
}}
onClick={(e: any) => e.stopPropagation()}
component="a"
href={file.downloadURL}
target="_blank"
rel="noopener noreferrer"
clickable
onDelete={
disabled
? undefined
: (e) => {
e.preventDefault();
confirm({
handleConfirm: () => handleDelete(file),
title: "Delete file?",
body: "This file cannot be recovered after",
confirm: "Delete",
confirmColor: "error",
});
}
}
tabIndex={tabIndex}
style={{ width: "100%", cursor: "pointer" }}
/>
</Tooltip>
</Grid>
))}
{localFiles &&
localFiles.map((file) => (
<Grid item key={file.name}>
<Chip
icon={<FileIcon />}
label={file.name}
deleteIcon={
<CircularProgressOptical size={20} color="inherit" />
}
/>
</Grid>
))}
</ChipList>
{Array.isArray(value) &&
value.map((file: FileValue, i) => (
<Draggable
key={file.downloadURL}
draggableId={file.downloadURL}
index={i}
>
{(provided) => (
<Grid
item
ref={provided.innerRef}
{...provided.draggableProps}
style={{
display: "flex",
alignItems: "center",
// Truncate so multiple files still visible
maxWidth: `${
value.length > 1 ? "calc(100% - 12px)" : "initial"
}`,
...provided.draggableProps.style,
}}
>
<div
{...provided.dragHandleProps}
style={{
display: "flex",
alignItems: "center",
}}
>
<DragIndicatorIcon />
</div>
<Tooltip
title={`File last modified ${format(
file.lastModifiedTS,
DATE_TIME_FORMAT
)}`}
>
<Chip
label={file.name}
icon={<FileIcon />}
sx={{
"& .MuiChip-label": {
lineHeight: 5 / 3,
},
}}
onClick={(e: any) => e.stopPropagation()}
component="a"
href={file.downloadURL}
target="_blank"
rel="noopener noreferrer"
clickable
onDelete={
disabled
? undefined
: (e) => {
e.preventDefault();
confirm({
handleConfirm: () => handleDelete(file),
title: "Delete file?",
body: "This file cannot be recovered after",
confirm: "Delete",
confirmColor: "error",
});
}
}
tabIndex={tabIndex}
style={{ width: "100%", cursor: "pointer" }}
/>
</Tooltip>
</Grid>
)}
</Draggable>
))}
</Grid>
{localFiles &&
localFiles.map((file) => (
<Grid item key={file.name}>
<Chip
icon={<FileIcon />}
label={file.name}
deleteIcon={
<CircularProgressOptical size={20} color="inherit" />
}
/>
</Grid>
))}
</ChipList>
)}
</Droppable>
</DragDropContext>
{!loading ? (
!disabled && (

View File

@@ -75,6 +75,15 @@ export default function useFileUpload(
[deleteUpload, docRef, fieldName, updateField]
);
// Drag and Drop
const handleUpdate = (files: any) => {
updateField({
path: docRef.path,
fieldName,
value: files,
});
};
return {
localFiles,
progress,
@@ -83,5 +92,6 @@ export default function useFileUpload(
handleUpload,
handleDelete,
dropzoneState,
handleUpdate,
};
}

View File

@@ -18,6 +18,15 @@ import useFileUpload from "@src/components/fields/File/useFileUpload";
import { IMAGE_MIME_TYPES } from "./index";
import { imgSx, thumbnailSx, deleteImgHoverSx } from "./DisplayCell";
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
import {
DragDropContext,
Droppable,
Draggable,
DropResult,
ResponderProvided,
} from "react-beautiful-dnd";
export default function Image_({
column,
value,
@@ -28,11 +37,17 @@ export default function Image_({
}: IEditorCellProps) {
const confirm = useSetAtom(confirmDialogAtom, projectScope);
const { loading, progress, handleDelete, localFiles, dropzoneState } =
useFileUpload(_rowy_ref, column.key, {
multiple: true,
accept: IMAGE_MIME_TYPES,
});
const {
loading,
progress,
handleDelete,
localFiles,
dropzoneState,
handleUpdate,
} = useFileUpload(_rowy_ref, column.key, {
multiple: true,
accept: IMAGE_MIME_TYPES,
});
const localImages = useMemo(
() =>
@@ -45,6 +60,28 @@ export default function Image_({
const { getRootProps, getInputProps, isDragActive } = dropzoneState;
const dropzoneProps = getRootProps();
const onDragEnd = (result: DropResult, provided: ResponderProvided) => {
const { destination, source, draggableId } = result;
if (!destination) {
return;
}
if (
destination.droppableId === source.droppableId &&
destination.index === source.index
) {
return;
}
const newValue = Array.from(value);
newValue.splice(source.index, 1);
newValue.splice(destination.index, 0, value[source.index]);
handleUpdate([...newValue]);
};
let thumbnailSize = "100x100";
if (rowHeight > 50) thumbnailSize = "200x200";
if (rowHeight > 100) thumbnailSize = "400x400";
@@ -84,62 +121,100 @@ export default function Image_({
marginLeft: "0 !important",
}}
>
<Grid container spacing={0.5} wrap="nowrap">
{Array.isArray(value) &&
value.map((file: FileValue, i) => (
<Grid item key={file.downloadURL}>
<ButtonBase
aria-label="Delete…"
sx={imgSx(rowHeight)}
className="img"
onClick={() => {
confirm({
title: "Delete image?",
body: "This image cannot be recovered after",
confirm: "Delete",
confirmColor: "error",
handleConfirm: () => handleDelete(file),
});
}}
disabled={disabled}
tabIndex={tabIndex}
>
<Thumbnail
imageUrl={file.downloadURL}
size={thumbnailSize}
objectFit="contain"
sx={thumbnailSx}
/>
<Grid
container
justifyContent="center"
alignItems="center"
sx={deleteImgHoverSx}
>
<DeleteIcon color="error" />
</Grid>
</ButtonBase>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="image-droppable" direction="horizontal">
{(provided) => (
<Grid
container
spacing={0.5}
wrap="nowrap"
ref={provided.innerRef}
{...provided.droppableProps}
>
{Array.isArray(value) &&
value.map((file: FileValue, i) => (
<Draggable
key={file.downloadURL}
draggableId={file.downloadURL}
index={i}
>
{(provided) => (
<Grid
item
ref={provided.innerRef}
{...provided.draggableProps}
style={{
display: "flex",
alignItems: "center",
...provided.draggableProps.style,
}}
>
<div
{...provided.dragHandleProps}
style={{
display: "flex",
alignItems: "center",
}}
>
<DragIndicatorIcon />
</div>
<ButtonBase
aria-label="Delete…"
sx={imgSx(rowHeight)}
className="img"
onClick={() => {
confirm({
title: "Delete image?",
body: "This image cannot be recovered after",
confirm: "Delete",
confirmColor: "error",
handleConfirm: () => handleDelete(file),
});
}}
disabled={disabled}
tabIndex={tabIndex}
>
<Thumbnail
imageUrl={file.downloadURL}
size={thumbnailSize}
objectFit="contain"
sx={thumbnailSx}
/>
<Grid
container
justifyContent="center"
alignItems="center"
sx={deleteImgHoverSx}
>
<DeleteIcon color="error" />
</Grid>
</ButtonBase>
</Grid>
)}
</Draggable>
))}
{localImages &&
localImages.map((image) => (
<Grid item>
<Box
sx={[
imgSx(rowHeight),
{
boxShadow: (theme) =>
`0 0 0 1px ${theme.palette.divider} inset`,
},
]}
style={{
backgroundImage: `url("${image.localURL}")`,
}}
/>
</Grid>
))}
{provided.placeholder}
</Grid>
))}
{localImages &&
localImages.map((image) => (
<Grid item>
<Box
sx={[
imgSx(rowHeight),
{
boxShadow: (theme) =>
`0 0 0 1px ${theme.palette.divider} inset`,
},
]}
style={{
backgroundImage: `url("${image.localURL}")`,
}}
/>
</Grid>
))}
</Grid>
)}
</Droppable>
</DragDropContext>
</div>
{!loading ? (