feat: library sidebar design tweaks (#6582)
This commit is contained in:
parent
e619e06055
commit
fff9d1522a
@ -1,11 +1,6 @@
|
|||||||
@import "open-color/open-color";
|
@import "open-color/open-color";
|
||||||
|
|
||||||
.excalidraw {
|
.excalidraw {
|
||||||
.library-menu-items-container {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-ui__library {
|
.layer-ui__library {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -70,6 +65,16 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 0.625rem;
|
gap: 0.625rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&--at-bottom::before {
|
||||||
|
content: "";
|
||||||
|
width: calc(100% - 1.5rem);
|
||||||
|
height: 1px;
|
||||||
|
position: absolute;
|
||||||
|
top: -1px;
|
||||||
|
background: var(--sidebar-border-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.library-menu-browse-button {
|
.library-menu-browse-button {
|
||||||
@ -126,4 +131,20 @@
|
|||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer-ui__library .library-menu-dropdown-container {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&--in-heading {
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,12 +121,11 @@ export const LibraryMenuContent = ({
|
|||||||
/>
|
/>
|
||||||
{showBtn && (
|
{showBtn && (
|
||||||
<LibraryMenuControlButtons
|
<LibraryMenuControlButtons
|
||||||
|
className="library-menu-control-buttons--at-bottom"
|
||||||
style={{ padding: "16px 12px 0 12px" }}
|
style={{ padding: "16px 12px 0 12px" }}
|
||||||
id={id}
|
id={id}
|
||||||
libraryReturnUrl={libraryReturnUrl}
|
libraryReturnUrl={libraryReturnUrl}
|
||||||
theme={appState.theme}
|
theme={appState.theme}
|
||||||
selectedItems={selectedItems}
|
|
||||||
onSelectItems={onSelectItems}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</LibraryMenuWrapper>
|
</LibraryMenuWrapper>
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
import { LibraryItem, ExcalidrawProps, UIAppState } from "../types";
|
import { ExcalidrawProps, UIAppState } from "../types";
|
||||||
import LibraryMenuBrowseButton from "./LibraryMenuBrowseButton";
|
import LibraryMenuBrowseButton from "./LibraryMenuBrowseButton";
|
||||||
import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent";
|
import clsx from "clsx";
|
||||||
|
|
||||||
export const LibraryMenuControlButtons = ({
|
export const LibraryMenuControlButtons = ({
|
||||||
selectedItems,
|
|
||||||
onSelectItems,
|
|
||||||
libraryReturnUrl,
|
libraryReturnUrl,
|
||||||
theme,
|
theme,
|
||||||
id,
|
id,
|
||||||
style,
|
style,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
}: {
|
}: {
|
||||||
selectedItems: LibraryItem["id"][];
|
|
||||||
onSelectItems: (id: LibraryItem["id"][]) => void;
|
|
||||||
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
|
||||||
theme: UIAppState["theme"];
|
theme: UIAppState["theme"];
|
||||||
id: string;
|
id: string;
|
||||||
style: React.CSSProperties;
|
style: React.CSSProperties;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="library-menu-control-buttons" style={style}>
|
<div
|
||||||
|
className={clsx("library-menu-control-buttons", className)}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
<LibraryMenuBrowseButton
|
<LibraryMenuBrowseButton
|
||||||
id={id}
|
id={id}
|
||||||
libraryReturnUrl={libraryReturnUrl}
|
libraryReturnUrl={libraryReturnUrl}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
/>
|
/>
|
||||||
<LibraryDropdownMenu
|
{children}
|
||||||
selectedItems={selectedItems}
|
|
||||||
onSelectItems={onSelectItems}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ import { Dialog } from "./Dialog";
|
|||||||
import DropdownMenu from "./dropdownMenu/DropdownMenu";
|
import DropdownMenu from "./dropdownMenu/DropdownMenu";
|
||||||
import { isLibraryMenuOpenAtom } from "./LibraryMenu";
|
import { isLibraryMenuOpenAtom } from "./LibraryMenu";
|
||||||
import { useUIAppState } from "../context/ui-appState";
|
import { useUIAppState } from "../context/ui-appState";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
const getSelectedItems = (
|
const getSelectedItems = (
|
||||||
libraryItems: LibraryItems,
|
libraryItems: LibraryItems,
|
||||||
@ -37,6 +38,7 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||||||
resetLibrary: () => void;
|
resetLibrary: () => void;
|
||||||
onSelectItems: (items: LibraryItem["id"][]) => void;
|
onSelectItems: (items: LibraryItem["id"][]) => void;
|
||||||
appState: UIAppState;
|
appState: UIAppState;
|
||||||
|
className?: string;
|
||||||
}> = ({
|
}> = ({
|
||||||
setAppState,
|
setAppState,
|
||||||
selectedItems,
|
selectedItems,
|
||||||
@ -45,6 +47,7 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||||||
resetLibrary,
|
resetLibrary,
|
||||||
onSelectItems,
|
onSelectItems,
|
||||||
appState,
|
appState,
|
||||||
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope);
|
const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope);
|
||||||
const [isLibraryMenuOpen, setIsLibraryMenuOpen] = useAtom(
|
const [isLibraryMenuOpen, setIsLibraryMenuOpen] = useAtom(
|
||||||
@ -236,7 +239,7 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: "relative" }}>
|
<div className={clsx("library-menu-dropdown-container", className)}>
|
||||||
{renderLibraryMenu()}
|
{renderLibraryMenu()}
|
||||||
{selectedItems.length > 0 && (
|
{selectedItems.length > 0 && (
|
||||||
<div className="library-actions-counter">{selectedItems.length}</div>
|
<div className="library-actions-counter">{selectedItems.length}</div>
|
||||||
@ -270,9 +273,11 @@ export const LibraryDropdownMenuButton: React.FC<{
|
|||||||
export const LibraryDropdownMenu = ({
|
export const LibraryDropdownMenu = ({
|
||||||
selectedItems,
|
selectedItems,
|
||||||
onSelectItems,
|
onSelectItems,
|
||||||
|
className,
|
||||||
}: {
|
}: {
|
||||||
selectedItems: LibraryItem["id"][];
|
selectedItems: LibraryItem["id"][];
|
||||||
onSelectItems: (id: LibraryItem["id"][]) => void;
|
onSelectItems: (id: LibraryItem["id"][]) => void;
|
||||||
|
className?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { library } = useApp();
|
const { library } = useApp();
|
||||||
const appState = useUIAppState();
|
const appState = useUIAppState();
|
||||||
@ -308,6 +313,7 @@ export const LibraryDropdownMenu = ({
|
|||||||
removeFromLibrary(libraryItemsData.libraryItems)
|
removeFromLibrary(libraryItemsData.libraryItems)
|
||||||
}
|
}
|
||||||
resetLibrary={resetLibrary}
|
resetLibrary={resetLibrary}
|
||||||
|
className={className}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.library-menu-items-container {
|
.library-menu-items-container {
|
||||||
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
@ -35,10 +36,14 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-bottom: 1px solid var(--sidebar-border-color);
|
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
padding-right: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
&__row {
|
&__row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
@ -59,6 +64,9 @@
|
|||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 4rem; // due to dropdown button
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
&--excal {
|
&--excal {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
@ -75,4 +83,11 @@
|
|||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.library-menu-items-private-library-container {
|
||||||
|
// so that when you toggle between pending item and no items, there's
|
||||||
|
// no layout shift (this is hardcoded and works only with ENG locale)
|
||||||
|
min-height: 3.75rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import { MIME_TYPES } from "../constants";
|
|||||||
import Spinner from "./Spinner";
|
import Spinner from "./Spinner";
|
||||||
import { duplicateElements } from "../element/newElement";
|
import { duplicateElements } from "../element/newElement";
|
||||||
import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons";
|
import { LibraryMenuControlButtons } from "./LibraryMenuControlButtons";
|
||||||
|
import { LibraryDropdownMenu } from "./LibraryMenuHeaderContent";
|
||||||
|
|
||||||
import "./LibraryMenuItems.scss";
|
import "./LibraryMenuItems.scss";
|
||||||
|
|
||||||
@ -207,6 +208,11 @@ const LibraryMenuItems = ({
|
|||||||
|
|
||||||
const showBtn = !libraryItems.length && !pendingElements.length;
|
const showBtn = !libraryItems.length && !pendingElements.length;
|
||||||
|
|
||||||
|
const isLibraryEmpty =
|
||||||
|
!pendingElements.length &&
|
||||||
|
!unpublishedItems.length &&
|
||||||
|
!publishedItems.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="library-menu-items-container"
|
className="library-menu-items-container"
|
||||||
@ -218,6 +224,13 @@ const LibraryMenuItems = ({
|
|||||||
: { borderBottom: 0 }
|
: { borderBottom: 0 }
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{!isLibraryEmpty && (
|
||||||
|
<LibraryDropdownMenu
|
||||||
|
selectedItems={selectedItems}
|
||||||
|
onSelectItems={onSelectItems}
|
||||||
|
className="library-menu-dropdown-container--in-heading"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Stack.Col
|
<Stack.Col
|
||||||
className="library-menu-items-container__items"
|
className="library-menu-items-container__items"
|
||||||
align="start"
|
align="start"
|
||||||
@ -228,47 +241,45 @@ const LibraryMenuItems = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<div>
|
{!isLibraryEmpty && (
|
||||||
{(pendingElements.length > 0 ||
|
<div className="library-menu-items-container__header">
|
||||||
unpublishedItems.length > 0 ||
|
{t("labels.personalLib")}
|
||||||
publishedItems.length > 0) && (
|
</div>
|
||||||
<div className="library-menu-items-container__header">
|
)}
|
||||||
{t("labels.personalLib")}
|
{isLoading && (
|
||||||
</div>
|
<div
|
||||||
)}
|
style={{
|
||||||
{isLoading && (
|
position: "absolute",
|
||||||
<div
|
top: "var(--container-padding-y)",
|
||||||
style={{
|
right: "var(--container-padding-x)",
|
||||||
position: "absolute",
|
transform: "translateY(50%)",
|
||||||
top: "var(--container-padding-y)",
|
}}
|
||||||
right: "var(--container-padding-x)",
|
>
|
||||||
transform: "translateY(50%)",
|
<Spinner />
|
||||||
}}
|
</div>
|
||||||
>
|
)}
|
||||||
<Spinner />
|
<div className="library-menu-items-private-library-container">
|
||||||
|
{!pendingElements.length && !unpublishedItems.length ? (
|
||||||
|
<div className="library-menu-items__no-items">
|
||||||
|
<div className="library-menu-items__no-items__label">
|
||||||
|
{t("library.noItems")}
|
||||||
|
</div>
|
||||||
|
<div className="library-menu-items__no-items__hint">
|
||||||
|
{publishedItems.length > 0
|
||||||
|
? t("library.hint_emptyPrivateLibrary")
|
||||||
|
: t("library.hint_emptyLibrary")}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
renderLibrarySection([
|
||||||
|
// append pending library item
|
||||||
|
...(pendingElements.length
|
||||||
|
? [{ id: null, elements: pendingElements }]
|
||||||
|
: []),
|
||||||
|
...unpublishedItems,
|
||||||
|
])
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!pendingElements.length && !unpublishedItems.length ? (
|
|
||||||
<div className="library-menu-items__no-items">
|
|
||||||
<div className="library-menu-items__no-items__label">
|
|
||||||
{t("library.noItems")}
|
|
||||||
</div>
|
|
||||||
<div className="library-menu-items__no-items__hint">
|
|
||||||
{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,
|
|
||||||
])
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
|
|
||||||
<>
|
<>
|
||||||
@ -304,9 +315,12 @@ const LibraryMenuItems = ({
|
|||||||
id={id}
|
id={id}
|
||||||
libraryReturnUrl={libraryReturnUrl}
|
libraryReturnUrl={libraryReturnUrl}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
selectedItems={selectedItems}
|
>
|
||||||
onSelectItems={onSelectItems}
|
<LibraryDropdownMenu
|
||||||
/>
|
selectedItems={selectedItems}
|
||||||
|
onSelectItems={onSelectItems}
|
||||||
|
/>
|
||||||
|
</LibraryMenuControlButtons>
|
||||||
)}
|
)}
|
||||||
</Stack.Col>
|
</Stack.Col>
|
||||||
</div>
|
</div>
|
||||||
|
@ -46,8 +46,17 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-top: 1rem;
|
padding: 1rem 0.75rem;
|
||||||
padding-bottom: 1rem;
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
width: calc(100% - 1.5rem);
|
||||||
|
height: 1px;
|
||||||
|
background: var(--sidebar-border-color);
|
||||||
|
position: absolute;
|
||||||
|
bottom: -1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__header__buttons {
|
.sidebar__header__buttons {
|
||||||
@ -89,7 +98,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
padding: 1rem 0.75rem;
|
padding: 1rem 0;
|
||||||
|
|
||||||
[role="tabpanel"] {
|
[role="tabpanel"] {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -161,9 +170,5 @@
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar__header {
|
|
||||||
border-bottom: 1px solid var(--sidebar-border-color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user