Sidebar improvements from comments branch (#4419)

This commit is contained in:
Tom Moor
2022-11-13 18:26:53 -08:00
committed by GitHub
parent b60c66316a
commit 24a1eac804
7 changed files with 95 additions and 77 deletions

View File

@@ -9,7 +9,7 @@ import PaginatedEventList from "~/components/PaginatedEventList";
import useKeyDown from "~/hooks/useKeyDown";
import useStores from "~/hooks/useStores";
import { documentUrl } from "~/utils/routeHelpers";
import Sidebar from "./RightSidebar";
import Sidebar from "./SidebarLayout";
const EMPTY_ARRAY: Event[] = [];

View File

@@ -17,7 +17,7 @@ import useKeyDown from "~/hooks/useKeyDown";
import useStores from "~/hooks/useStores";
import useTextSelection from "~/hooks/useTextSelection";
import { documentUrl } from "~/utils/routeHelpers";
import Sidebar from "./RightSidebar";
import Sidebar from "./SidebarLayout";
function Insights() {
const { views, documents } = useStores();

View File

@@ -1,174 +0,0 @@
import { m } from "framer-motion";
import { observer } from "mobx-react";
import { BackIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import styled, { useTheme } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import Button from "~/components/Button";
import Flex from "~/components/Flex";
import Scrollable from "~/components/Scrollable";
import ResizeBorder from "~/components/Sidebar/components/ResizeBorder";
import Tooltip from "~/components/Tooltip";
import usePersistedState from "~/hooks/usePersistedState";
type Props = React.HTMLAttributes<HTMLDivElement> & {
title: React.ReactNode;
children: React.ReactNode;
onClose: React.MouseEventHandler;
border?: boolean;
};
function RightSidebar({ title, onClose, children, border, className }: Props) {
const theme = useTheme();
const { t } = useTranslation();
const [width, setWidth] = usePersistedState(
"rightSidebarWidth",
theme.sidebarWidth
);
const [isResizing, setResizing] = React.useState(false);
const maxWidth = theme.sidebarMaxWidth;
const minWidth = theme.sidebarMinWidth + 16; // padding
const handleDrag = React.useCallback(
(event: MouseEvent) => {
// suppresses text selection
event.preventDefault();
const width = Math.max(
Math.min(window.innerWidth - event.pageX, maxWidth),
minWidth
);
setWidth(width);
},
[minWidth, maxWidth, setWidth]
);
const handleReset = React.useCallback(() => {
setWidth(theme.sidebarWidth);
}, [setWidth, theme.sidebarWidth]);
const handleStopDrag = React.useCallback(() => {
setResizing(false);
if (document.activeElement) {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'blur' does not exist on type 'Element'.
document.activeElement.blur();
}
}, []);
const handleMouseDown = React.useCallback(() => {
setResizing(true);
}, []);
React.useEffect(() => {
if (isResizing) {
document.addEventListener("mousemove", handleDrag);
document.addEventListener("mouseup", handleStopDrag);
}
return () => {
document.removeEventListener("mousemove", handleDrag);
document.removeEventListener("mouseup", handleStopDrag);
};
}, [isResizing, handleDrag, handleStopDrag]);
const style = React.useMemo(
() => ({
width: `${width}px`,
}),
[width]
);
return (
<Sidebar
initial={{
width: 0,
}}
animate={{
transition: isResizing
? { duration: 0 }
: {
type: "spring",
bounce: 0.2,
duration: 0.6,
},
width,
}}
exit={{
width: 0,
}}
$border={border}
className={className}
>
<Position style={style} column>
<Header>
<Title>{title}</Title>
<Tooltip tooltip={t("Close")} shortcut="Esc" delay={500}>
<Button
icon={<ForwardIcon />}
onClick={onClose}
borderOnHover
neutral
/>
</Tooltip>
</Header>
<Scrollable topShadow>{children}</Scrollable>
<ResizeBorder
onMouseDown={handleMouseDown}
onDoubleClick={handleReset}
dir="right"
/>
</Position>
</Sidebar>
);
}
const ForwardIcon = styled(BackIcon)`
transform: rotate(180deg);
flex-shrink: 0;
`;
const Position = styled(Flex)`
position: fixed;
top: 0;
bottom: 0;
`;
const Sidebar = styled(m.div)<{ $border?: boolean }>`
display: none;
position: relative;
flex-shrink: 0;
background: ${(props) => props.theme.background};
width: ${(props) => props.theme.sidebarWidth}px;
border-left: 1px solid ${(props) => props.theme.divider};
transition: border-left 100ms ease-in-out;
z-index: 1;
${breakpoint("tablet")`
display: flex;
`};
`;
const Title = styled(Flex)`
font-size: 16px;
font-weight: 600;
text-align: center;
align-items: center;
justify-content: flex-start;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
overflow: hidden;
width: 0;
flex-grow: 1;
`;
const Header = styled(Flex)`
align-items: center;
position: relative;
padding: 16px 12px 16px 16px;
color: ${(props) => props.theme.text};
flex-shrink: 0;
`;
export default observer(RightSidebar);

View File

@@ -0,0 +1,66 @@
import { observer } from "mobx-react";
import { BackIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import Button from "~/components/Button";
import Flex from "~/components/Flex";
import Scrollable from "~/components/Scrollable";
import Tooltip from "~/components/Tooltip";
type Props = React.HTMLAttributes<HTMLDivElement> & {
title: React.ReactNode;
children: React.ReactNode;
onClose: React.MouseEventHandler;
border?: boolean;
};
function SidebarLayout({ title, onClose, children }: Props) {
const { t } = useTranslation();
return (
<>
<Header>
<Title>{title}</Title>
<Tooltip tooltip={t("Close")} shortcut="Esc" delay={500}>
<Button
icon={<ForwardIcon />}
onClick={onClose}
borderOnHover
neutral
/>
</Tooltip>
</Header>
<Scrollable topShadow>{children}</Scrollable>
</>
);
}
const ForwardIcon = styled(BackIcon)`
transform: rotate(180deg);
flex-shrink: 0;
`;
const Title = styled(Flex)`
font-size: 16px;
font-weight: 600;
text-align: center;
align-items: center;
justify-content: flex-start;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
overflow: hidden;
width: 0;
flex-grow: 1;
`;
const Header = styled(Flex)`
align-items: center;
position: relative;
padding: 16px 12px 16px 16px;
color: ${(props) => props.theme.text};
flex-shrink: 0;
`;
export default observer(SidebarLayout);