|
|
@ -1,5 +1,5 @@
|
|
|
|
import { chunk } from "lodash";
|
|
|
|
import { chunk } from "lodash";
|
|
|
|
import { useCallback, useState } from "react";
|
|
|
|
import React, { useCallback, useState } from "react";
|
|
|
|
import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json";
|
|
|
|
import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json";
|
|
|
|
import Library from "../data/library";
|
|
|
|
import Library from "../data/library";
|
|
|
|
import { ExcalidrawElement, NonDeleted } from "../element/types";
|
|
|
|
import { ExcalidrawElement, NonDeleted } from "../element/types";
|
|
|
@ -11,7 +11,7 @@ import {
|
|
|
|
LibraryItem,
|
|
|
|
LibraryItem,
|
|
|
|
LibraryItems,
|
|
|
|
LibraryItems,
|
|
|
|
} from "../types";
|
|
|
|
} from "../types";
|
|
|
|
import { muteFSAbortError } from "../utils";
|
|
|
|
import { arrayToMap, muteFSAbortError } from "../utils";
|
|
|
|
import { useDeviceType } from "./App";
|
|
|
|
import { useDeviceType } from "./App";
|
|
|
|
import ConfirmDialog from "./ConfirmDialog";
|
|
|
|
import ConfirmDialog from "./ConfirmDialog";
|
|
|
|
import { exportToFileIcon, load, publishIcon, trash } from "./icons";
|
|
|
|
import { exportToFileIcon, load, publishIcon, trash } from "./icons";
|
|
|
@ -38,7 +38,7 @@ const LibraryMenuItems = ({
|
|
|
|
files,
|
|
|
|
files,
|
|
|
|
id,
|
|
|
|
id,
|
|
|
|
selectedItems,
|
|
|
|
selectedItems,
|
|
|
|
onToggle,
|
|
|
|
onSelectItems,
|
|
|
|
onPublish,
|
|
|
|
onPublish,
|
|
|
|
resetLibrary,
|
|
|
|
resetLibrary,
|
|
|
|
}: {
|
|
|
|
}: {
|
|
|
@ -55,7 +55,7 @@ const LibraryMenuItems = ({
|
|
|
|
library: Library;
|
|
|
|
library: Library;
|
|
|
|
id: string;
|
|
|
|
id: string;
|
|
|
|
selectedItems: LibraryItem["id"][];
|
|
|
|
selectedItems: LibraryItem["id"][];
|
|
|
|
onToggle: (id: LibraryItem["id"], event: React.MouseEvent) => void;
|
|
|
|
onSelectItems: (id: LibraryItem["id"][]) => void;
|
|
|
|
onPublish: () => void;
|
|
|
|
onPublish: () => void;
|
|
|
|
resetLibrary: () => void;
|
|
|
|
resetLibrary: () => void;
|
|
|
|
}) => {
|
|
|
|
}) => {
|
|
|
@ -192,6 +192,55 @@ const LibraryMenuItems = ({
|
|
|
|
(id) => libraryItems.find((item) => item.id === id)?.status === "published",
|
|
|
|
(id) => libraryItems.find((item) => item.id === id)?.status === "published",
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [lastSelectedItem, setLastSelectedItem] = useState<
|
|
|
|
|
|
|
|
LibraryItem["id"] | null
|
|
|
|
|
|
|
|
>(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const onItemSelectToggle = (
|
|
|
|
|
|
|
|
id: LibraryItem["id"],
|
|
|
|
|
|
|
|
event: React.MouseEvent,
|
|
|
|
|
|
|
|
) => {
|
|
|
|
|
|
|
|
const shouldSelect = !selectedItems.includes(id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const orderedItems = [...unpublishedItems, ...publishedItems];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldSelect) {
|
|
|
|
|
|
|
|
if (event.shiftKey && lastSelectedItem) {
|
|
|
|
|
|
|
|
const rangeStart = orderedItems.findIndex(
|
|
|
|
|
|
|
|
(item) => item.id === lastSelectedItem,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
const rangeEnd = orderedItems.findIndex((item) => item.id === id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rangeStart === -1 || rangeEnd === -1) {
|
|
|
|
|
|
|
|
onSelectItems([...selectedItems, id]);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const selectedItemsMap = arrayToMap(selectedItems);
|
|
|
|
|
|
|
|
const nextSelectedIds = orderedItems.reduce(
|
|
|
|
|
|
|
|
(acc: LibraryItem["id"][], item, idx) => {
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
|
|
|
(idx >= rangeStart && idx <= rangeEnd) ||
|
|
|
|
|
|
|
|
selectedItemsMap.has(item.id)
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
acc.push(item.id);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
[],
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onSelectItems(nextSelectedIds);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
onSelectItems([...selectedItems, id]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
setLastSelectedItem(id);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
setLastSelectedItem(null);
|
|
|
|
|
|
|
|
onSelectItems(selectedItems.filter((_id) => _id !== id));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const createLibraryItemCompo = (params: {
|
|
|
|
const createLibraryItemCompo = (params: {
|
|
|
|
item:
|
|
|
|
item:
|
|
|
|
| LibraryItem
|
|
|
|
| LibraryItem
|
|
|
@ -212,9 +261,7 @@ const LibraryMenuItems = ({
|
|
|
|
onClick={params.onClick || (() => {})}
|
|
|
|
onClick={params.onClick || (() => {})}
|
|
|
|
id={params.item?.id || null}
|
|
|
|
id={params.item?.id || null}
|
|
|
|
selected={!!params.item?.id && selectedItems.includes(params.item.id)}
|
|
|
|
selected={!!params.item?.id && selectedItems.includes(params.item.id)}
|
|
|
|
onToggle={(id, event) => {
|
|
|
|
onToggle={onItemSelectToggle}
|
|
|
|
onToggle(id, event);
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</Stack.Col>
|
|
|
|
</Stack.Col>
|
|
|
|
);
|
|
|
|
);
|
|
|
@ -272,16 +319,12 @@ const LibraryMenuItems = ({
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const unpublishedItems = libraryItems.filter(
|
|
|
|
|
|
|
|
(item) => item.status !== "published",
|
|
|
|
|
|
|
|
);
|
|
|
|
const publishedItems = libraryItems.filter(
|
|
|
|
const publishedItems = libraryItems.filter(
|
|
|
|
(item) => item.status === "published",
|
|
|
|
(item) => item.status === "published",
|
|
|
|
);
|
|
|
|
);
|
|
|
|
const unpublishedItems = [
|
|
|
|
|
|
|
|
// append pending library item
|
|
|
|
|
|
|
|
...(pendingElements.length
|
|
|
|
|
|
|
|
? [{ id: null, elements: pendingElements }]
|
|
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
...libraryItems.filter((item) => item.status !== "published"),
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<div className="library-menu-items-container">
|
|
|
|
<div className="library-menu-items-container">
|
|
|
@ -310,7 +353,13 @@ const LibraryMenuItems = ({
|
|
|
|
>
|
|
|
|
>
|
|
|
|
<>
|
|
|
|
<>
|
|
|
|
<div className="separator">{t("labels.personalLib")}</div>
|
|
|
|
<div className="separator">{t("labels.personalLib")}</div>
|
|
|
|
{renderLibrarySection(unpublishedItems)}
|
|
|
|
{renderLibrarySection([
|
|
|
|
|
|
|
|
// append pending library item
|
|
|
|
|
|
|
|
...(pendingElements.length
|
|
|
|
|
|
|
|
? [{ id: null, elements: pendingElements }]
|
|
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
...unpublishedItems,
|
|
|
|
|
|
|
|
])}
|
|
|
|
</>
|
|
|
|
</>
|
|
|
|
|
|
|
|
|
|
|
|
<>
|
|
|
|
<>
|
|
|
|