feat: add sidebar for libraries panel (#5274)

Co-authored-by: dwelle <luzar.david@gmail.com>
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
This commit is contained in:
Ishtiaq Bhatti 2022-06-21 20:03:23 +05:00 committed by GitHub
parent 4712393b62
commit cdf352d4c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 782 additions and 241 deletions

View file

@ -12,9 +12,9 @@ import {
LibraryItems,
} from "../types";
import { arrayToMap, muteFSAbortError } from "../utils";
import { useDeviceType } from "./App";
import { useDevice } from "./App";
import ConfirmDialog from "./ConfirmDialog";
import { exportToFileIcon, load, publishIcon, trash } from "./icons";
import { close, exportToFileIcon, load, publishIcon, trash } from "./icons";
import { LibraryUnit } from "./LibraryUnit";
import Stack from "./Stack";
import { ToolButton } from "./ToolButton";
@ -25,6 +25,9 @@ import { MIME_TYPES, VERSIONS } from "../constants";
import Spinner from "./Spinner";
import { fileOpen } from "../data/filesystem";
import { SidebarLockButton } from "./SidebarLockButton";
import { trackEvent } from "../analytics";
const LibraryMenuItems = ({
isLoading,
libraryItems,
@ -34,6 +37,7 @@ const LibraryMenuItems = ({
pendingElements,
theme,
setAppState,
appState,
libraryReturnUrl,
library,
files,
@ -52,6 +56,7 @@ const LibraryMenuItems = ({
theme: AppState["theme"];
files: BinaryFiles;
setAppState: React.Component<any, AppState>["setState"];
appState: AppState;
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
library: Library;
id: string;
@ -88,9 +93,7 @@ const LibraryMenuItems = ({
}, [selectedItems, onRemoveFromLibrary, resetLibrary]);
const [showRemoveLibAlert, setShowRemoveLibAlert] = useState(false);
const isMobile = useDeviceType().isMobile;
const device = useDevice();
const renderLibraryActions = () => {
const itemsSelected = !!selectedItems.length;
const items = itemsSelected
@ -101,7 +104,7 @@ const LibraryMenuItems = ({
: t("buttons.resetLibrary");
return (
<div className="library-actions">
{(!itemsSelected || !isMobile) && (
{!itemsSelected && (
<ToolButton
key="import"
type="button"
@ -186,7 +189,7 @@ const LibraryMenuItems = ({
className="library-actions--publish"
onClick={onPublish}
>
{!isMobile && <label>{t("buttons.publishLibrary")}</label>}
{!device.isMobile && <label>{t("buttons.publishLibrary")}</label>}
{selectedItems.length > 0 && (
<span className="library-actions-counter">
{selectedItems.length}
@ -195,11 +198,25 @@ const LibraryMenuItems = ({
</ToolButton>
</Tooltip>
)}
{device.isMobile && (
<div className="library-menu-browse-button--mobile">
<a
href={`${process.env.REACT_APP_LIBRARY_URL}?target=${
window.name || "_blank"
}&referrer=${referrer}&useHash=true&token=${id}&theme=${theme}&version=${
VERSIONS.excalidrawLibrary
}`}
target="_excalidraw_libraries"
>
{t("labels.libraries")}
</a>
</div>
)}
</div>
);
};
const CELLS_PER_ROW = isMobile ? 4 : 6;
const CELLS_PER_ROW = device.isMobile && !device.isSmScreen ? 6 : 4;
const referrer =
libraryReturnUrl || window.location.origin + window.location.pathname;
@ -356,48 +373,169 @@ const LibraryMenuItems = ({
(item) => item.status === "published",
);
return (
<div className="library-menu-items-container">
{showRemoveLibAlert && renderRemoveLibAlert()}
<div className="layer-ui__library-header" key="library-header">
{renderLibraryActions()}
{isLoading ? (
<Spinner />
) : (
<a
href={`${process.env.REACT_APP_LIBRARY_URL}?target=${
window.name || "_blank"
}&referrer=${referrer}&useHash=true&token=${id}&theme=${theme}&version=${
VERSIONS.excalidrawLibrary
}`}
target="_excalidraw_libraries"
>
{t("labels.libraries")}
</a>
)}
</div>
const renderLibraryHeader = () => {
return (
<>
<div className="layer-ui__library-header" key="library-header">
{renderLibraryActions()}
{device.canDeviceFitSidebar && (
<>
<div className="layer-ui__sidebar-lock-button">
<SidebarLockButton
checked={appState.isLibraryMenuDocked}
onChange={() => {
document
.querySelector(".layer-ui__wrapper")
?.classList.add("animate");
const nextState = !appState.isLibraryMenuDocked;
setAppState({
isLibraryMenuDocked: nextState,
});
trackEvent(
"library",
`toggleLibraryDock (${nextState ? "dock" : "undock"})`,
`sidebar (${device.isMobile ? "mobile" : "desktop"})`,
);
}}
/>
</div>
</>
)}
{!device.isMobile && (
<div className="ToolIcon__icon__close">
<button
className="Modal__close"
onClick={() =>
setAppState({
isLibraryOpen: false,
})
}
aria-label={t("buttons.close")}
>
{close}
</button>
</div>
)}
</div>
</>
);
};
const renderLibraryMenuItems = () => {
return (
<Stack.Col
className="library-menu-items-container__items"
align="start"
gap={1}
style={{
flex: publishedItems.length > 0 ? 1 : "0 0 auto",
marginBottom: 0,
}}
>
<>
<div className="separator">{t("labels.personalLib")}</div>
{renderLibrarySection([
// append pending library item
...(pendingElements.length
? [{ id: null, elements: pendingElements }]
: []),
...unpublishedItems,
])}
<div className="separator">
{(pendingElements.length > 0 ||
unpublishedItems.length > 0 ||
publishedItems.length > 0) && (
<div>{t("labels.personalLib")}</div>
)}
{isLoading && (
<div
style={{
marginLeft: "auto",
marginRight: "1rem",
display: "flex",
alignItems: "center",
fontWeight: "normal",
}}
>
<div style={{ transform: "translateY(2px)" }}>
<Spinner />
</div>
</div>
)}
</div>
{!pendingElements.length && !unpublishedItems.length ? (
<div
style={{
height: 65,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
width: "100%",
fontSize: ".9rem",
}}
>
No items yet!
<div
style={{
margin: ".6rem 0",
fontSize: ".8em",
width: "70%",
textAlign: "center",
}}
>
{publishedItems.length > 0
? t("library.hint_emptyPrivateLibrary")
: t("library.hint_emptyLibrary")}
</div>
</div>
) : (
renderLibrarySection([
// append pending library item
...(pendingElements.length
? [{ id: null, elements: pendingElements }]
: []),
...unpublishedItems,
])
)}
</>
<>
<div className="separator">{t("labels.excalidrawLib")} </div>
{renderLibrarySection(publishedItems)}
{(publishedItems.length > 0 ||
(!device.isMobile &&
(pendingElements.length > 0 || unpublishedItems.length > 0))) && (
<div className="separator">{t("labels.excalidrawLib")}</div>
)}
{publishedItems.length > 0 && renderLibrarySection(publishedItems)}
</>
</Stack.Col>
);
};
const renderLibraryFooter = () => {
return (
<a
className="library-menu-browse-button"
href={`${process.env.REACT_APP_LIBRARY_URL}?target=${
window.name || "_blank"
}&referrer=${referrer}&useHash=true&token=${id}&theme=${theme}&version=${
VERSIONS.excalidrawLibrary
}`}
target="_excalidraw_libraries"
>
{t("labels.libraries")}
</a>
);
};
return (
<div
className="library-menu-items-container"
style={
device.isMobile
? {
minHeight: "200px",
maxHeight: "70vh",
}
: undefined
}
>
{showRemoveLibAlert && renderRemoveLibAlert()}
{renderLibraryHeader()}
{renderLibraryMenuItems()}
{!device.isMobile && renderLibraryFooter()}
</div>
);
};