fix: add toc to mobile views and account for branding on shared view layouts (#2997)
* fix: add toc to mobile views and center the branding * add padding to bottom of sidebar * put the mobile branding inline * finesse the padding * make spelling of sign-in email less crazy looking * move mobile sidebar button into header * adds scene to search and 404 pages * fix title alignment * make filter buttons tight * clean up unused imports * lint Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import env from "~/env";
|
||||
import OutlineLogo from "./OutlineLogo";
|
||||
|
||||
@@ -17,10 +18,8 @@ function Branding({ href = env.URL }: Props) {
|
||||
}
|
||||
|
||||
const Link = styled.a`
|
||||
z-index: ${(props) => props.theme.depths.sidebar + 1};
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
justify-content: center;
|
||||
padding-bottom: 16px;
|
||||
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
@@ -29,7 +28,6 @@ const Link = styled.a`
|
||||
color: ${(props) => props.theme.text};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
|
||||
svg {
|
||||
fill: ${(props) => props.theme.text};
|
||||
@@ -38,6 +36,14 @@ const Link = styled.a`
|
||||
&:hover {
|
||||
background: ${(props) => props.theme.sidebarBackground};
|
||||
}
|
||||
|
||||
${breakpoint("tablet")`
|
||||
z-index: ${(props: any) => props.theme.depths.sidebar + 1};
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 16px;
|
||||
`};
|
||||
`;
|
||||
|
||||
export default Branding;
|
||||
|
||||
@@ -94,13 +94,15 @@ const StyledButton = styled(Button)`
|
||||
box-shadow: none;
|
||||
text-transform: none;
|
||||
border-color: transparent;
|
||||
height: auto;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
${Inner} {
|
||||
line-height: 28px;
|
||||
line-height: 24px;
|
||||
min-height: auto;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
import { throttle } from "lodash";
|
||||
import { observer } from "mobx-react";
|
||||
import { MenuIcon } from "outline-icons";
|
||||
import { transparentize } from "polished";
|
||||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import Button from "~/components/Button";
|
||||
import Fade from "~/components/Fade";
|
||||
import Flex from "~/components/Flex";
|
||||
import useMobile from "~/hooks/useMobile";
|
||||
import useStores from "~/hooks/useStores";
|
||||
|
||||
type Props = {
|
||||
breadcrumb?: React.ReactNode;
|
||||
title: React.ReactNode;
|
||||
actions?: React.ReactNode;
|
||||
hasSidebar?: boolean;
|
||||
};
|
||||
|
||||
function Header({ breadcrumb, title, actions }: Props) {
|
||||
function Header({ breadcrumb, title, actions, hasSidebar }: Props) {
|
||||
const { ui } = useStores();
|
||||
const isMobile = useMobile();
|
||||
|
||||
const hasMobileSidebar = hasSidebar && isMobile;
|
||||
|
||||
const passThrough = !actions && !breadcrumb && !title;
|
||||
|
||||
const [isScrolled, setScrolled] = React.useState(false);
|
||||
const handleScroll = React.useCallback(
|
||||
throttle(() => setScrolled(window.scrollY > 75), 50),
|
||||
@@ -33,8 +45,21 @@ function Header({ breadcrumb, title, actions }: Props) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Wrapper align="center" shrink={false}>
|
||||
{breadcrumb ? <Breadcrumbs>{breadcrumb}</Breadcrumbs> : null}
|
||||
<Wrapper align="center" shrink={false} $passThrough={passThrough}>
|
||||
{breadcrumb || hasMobileSidebar ? (
|
||||
<Breadcrumbs>
|
||||
{hasMobileSidebar && (
|
||||
<MobileMenuButton
|
||||
onClick={ui.toggleMobileSidebar}
|
||||
icon={<MenuIcon />}
|
||||
iconColor="currentColor"
|
||||
neutral
|
||||
/>
|
||||
)}
|
||||
{breadcrumb}
|
||||
</Breadcrumbs>
|
||||
) : null}
|
||||
|
||||
{isScrolled ? (
|
||||
<Title onClick={handleClickTitle}>
|
||||
<Fade>{title}</Fade>
|
||||
@@ -42,11 +67,9 @@ function Header({ breadcrumb, title, actions }: Props) {
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
{actions && (
|
||||
<Actions align="center" justify="flex-end">
|
||||
{actions}
|
||||
</Actions>
|
||||
)}
|
||||
<Actions align="center" justify="flex-end">
|
||||
{actions}
|
||||
</Actions>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
@@ -56,12 +79,7 @@ const Breadcrumbs = styled("div")`
|
||||
flex-basis: 0;
|
||||
align-items: center;
|
||||
padding-right: 8px;
|
||||
|
||||
/* Don't show breadcrumbs on mobile */
|
||||
display: none;
|
||||
${breakpoint("tablet")`
|
||||
display: flex;
|
||||
`};
|
||||
`;
|
||||
|
||||
const Actions = styled(Flex)`
|
||||
@@ -75,11 +93,23 @@ const Actions = styled(Flex)`
|
||||
`};
|
||||
`;
|
||||
|
||||
const Wrapper = styled(Flex)`
|
||||
position: sticky;
|
||||
const Wrapper = styled(Flex)<{ $passThrough?: boolean }>`
|
||||
top: 0;
|
||||
z-index: ${(props) => props.theme.depths.header};
|
||||
position: sticky;
|
||||
background: ${(props) => props.theme.background};
|
||||
|
||||
${(props) =>
|
||||
props.$passThrough
|
||||
? `
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
`
|
||||
: `
|
||||
background: ${transparentize(0.2, props.theme.background)};
|
||||
backdrop-filter: blur(20px);
|
||||
`};
|
||||
|
||||
padding: 12px;
|
||||
transition: all 100ms ease-out;
|
||||
transform: translate3d(0, 0, 0);
|
||||
@@ -111,7 +141,7 @@ const Title = styled("div")`
|
||||
cursor: pointer;
|
||||
min-width: 0;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
${breakpoint("tablet")`
|
||||
padding-left: 0;
|
||||
display: block;
|
||||
`};
|
||||
@@ -126,4 +156,13 @@ const Title = styled("div")`
|
||||
}
|
||||
`;
|
||||
|
||||
const MobileMenuButton = styled(Button)`
|
||||
margin-right: 8px;
|
||||
pointer-events: auto;
|
||||
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export default observer(Header);
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { MenuIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { Helmet } from "react-helmet";
|
||||
import styled from "styled-components";
|
||||
import breakpoint from "styled-components-breakpoint";
|
||||
import Button from "~/components/Button";
|
||||
import Flex from "~/components/Flex";
|
||||
import { LoadingIndicatorBar } from "~/components/LoadingIndicator";
|
||||
import SkipNavContent from "~/components/SkipNavContent";
|
||||
@@ -41,15 +39,6 @@ function Layout({ title, children, sidebar, rightRail }: Props) {
|
||||
|
||||
{ui.progressBarVisible && <LoadingIndicatorBar />}
|
||||
|
||||
{sidebar && (
|
||||
<MobileMenuButton
|
||||
onClick={ui.toggleMobileSidebar}
|
||||
icon={<MenuIcon />}
|
||||
iconColor="currentColor"
|
||||
neutral
|
||||
/>
|
||||
)}
|
||||
|
||||
<Container auto>
|
||||
{sidebar}
|
||||
|
||||
@@ -85,21 +74,6 @@ const Container = styled(Flex)`
|
||||
min-height: 100%;
|
||||
`;
|
||||
|
||||
const MobileMenuButton = styled(Button)`
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
z-index: ${(props) => props.theme.depths.sidebar - 1};
|
||||
|
||||
${breakpoint("tablet")`
|
||||
display: none;
|
||||
`};
|
||||
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const Content = styled(Flex)<{
|
||||
$isResizing?: boolean;
|
||||
$sidebarCollapsed?: boolean;
|
||||
|
||||
@@ -6,7 +6,7 @@ import PageTitle from "~/components/PageTitle";
|
||||
|
||||
type Props = {
|
||||
icon?: React.ReactNode;
|
||||
title: React.ReactNode;
|
||||
title?: React.ReactNode;
|
||||
textTitle?: string;
|
||||
children: React.ReactNode;
|
||||
breadcrumb?: React.ReactNode;
|
||||
@@ -27,6 +27,7 @@ function Scene({
|
||||
<FillWidth>
|
||||
<PageTitle title={textTitle || title} />
|
||||
<Header
|
||||
hasSidebar
|
||||
title={
|
||||
icon ? (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import Scrollable from "~/components/Scrollable";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import { NavigationNode } from "~/types";
|
||||
@@ -17,7 +18,7 @@ function SharedSidebar({ rootNode, shareId }: Props) {
|
||||
|
||||
return (
|
||||
<Sidebar>
|
||||
<Scrollable flex>
|
||||
<ScrollContainer flex>
|
||||
<Section>
|
||||
<DocumentLink
|
||||
index={0}
|
||||
@@ -27,9 +28,13 @@ function SharedSidebar({ rootNode, shareId }: Props) {
|
||||
activeDocument={documents.active}
|
||||
/>
|
||||
</Section>
|
||||
</Scrollable>
|
||||
</ScrollContainer>
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
|
||||
const ScrollContainer = styled(Scrollable)`
|
||||
padding-bottom: 16px;
|
||||
`;
|
||||
|
||||
export default observer(SharedSidebar);
|
||||
|
||||
Reference in New Issue
Block a user