feat: Optional full-width toggle for document display (#2869)
* Migration, model, presenter * Working implementation * fix: Account for table of contents * Checkbox -> Toggle * Checkbox -> Toggle
This commit is contained in:
@@ -7,6 +7,7 @@ import useWindowScrollPosition from "~/hooks/useWindowScrollPosition";
|
||||
const HEADING_OFFSET = 20;
|
||||
|
||||
type Props = {
|
||||
isFullWidth: boolean;
|
||||
headings: {
|
||||
title: string;
|
||||
level: number;
|
||||
@@ -14,7 +15,7 @@ type Props = {
|
||||
}[];
|
||||
};
|
||||
|
||||
export default function Contents({ headings }: Props) {
|
||||
export default function Contents({ headings, isFullWidth }: Props) {
|
||||
const [activeSlug, setActiveSlug] = React.useState<string>();
|
||||
const position = useWindowScrollPosition({
|
||||
throttle: 100,
|
||||
@@ -49,8 +50,8 @@ export default function Contents({ headings }: Props) {
|
||||
const headingAdjustment = minHeading - 1;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Wrapper>
|
||||
<Wrapper isFullWidth={isFullWidth}>
|
||||
<Sticky>
|
||||
<Heading>Contents</Heading>
|
||||
{headings.length ? (
|
||||
<List>
|
||||
@@ -67,30 +68,38 @@ export default function Contents({ headings }: Props) {
|
||||
) : (
|
||||
<Empty>Headings you add to the document will appear here</Empty>
|
||||
)}
|
||||
</Wrapper>
|
||||
</div>
|
||||
</Sticky>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const Wrapper = styled.div`
|
||||
const Wrapper = styled.div<{ isFullWidth: boolean }>`
|
||||
width: 256px;
|
||||
display: none;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
display: block;
|
||||
`};
|
||||
|
||||
${(props) =>
|
||||
!props.isFullWidth &&
|
||||
breakpoint("desktopLarge")`
|
||||
transform: translateX(-256px);
|
||||
width: 0;
|
||||
`}
|
||||
`;
|
||||
|
||||
const Sticky = styled.div`
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
max-height: calc(100vh - 80px);
|
||||
|
||||
box-shadow: 1px 0 0 ${(props) => props.theme.divider};
|
||||
margin-top: 40px;
|
||||
margin-right: 3.2em;
|
||||
margin-right: 32px;
|
||||
width: 224px;
|
||||
min-height: 40px;
|
||||
overflow-y: auto;
|
||||
|
||||
${breakpoint("desktopLarge")`
|
||||
margin-left: -16em;
|
||||
`};
|
||||
|
||||
${breakpoint("tablet")`
|
||||
display: block;
|
||||
`};
|
||||
`;
|
||||
|
||||
const Heading = styled.h3`
|
||||
|
||||
@@ -493,6 +493,7 @@ class DocumentScene extends React.Component<Props> {
|
||||
archived={document.isArchived}
|
||||
showContents={showContents}
|
||||
isEditing={!readOnly}
|
||||
isFullWidth={document.fullWidth}
|
||||
column
|
||||
auto
|
||||
>
|
||||
@@ -544,7 +545,12 @@ class DocumentScene extends React.Component<Props> {
|
||||
)}
|
||||
<React.Suspense fallback={<PlaceholderDocument />}>
|
||||
<Flex auto={!readOnly}>
|
||||
{showContents && <Contents headings={headings} />}
|
||||
{showContents && (
|
||||
<Contents
|
||||
headings={headings}
|
||||
isFullWidth={document.fullWidth}
|
||||
/>
|
||||
)}
|
||||
<Editor
|
||||
id={document.id}
|
||||
key={disableEmbeds ? "disabled" : "enabled"}
|
||||
@@ -628,6 +634,7 @@ const ReferencesWrapper = styled.div<{ isOnlyTitle?: boolean }>`
|
||||
|
||||
type MaxWidthProps = {
|
||||
isEditing?: boolean;
|
||||
isFullWidth?: boolean;
|
||||
archived?: boolean;
|
||||
showContents?: boolean;
|
||||
};
|
||||
@@ -636,22 +643,23 @@ const MaxWidth = styled(Flex)<MaxWidthProps>`
|
||||
${(props) =>
|
||||
props.archived && `* { color: ${props.theme.textSecondary} !important; } `};
|
||||
|
||||
// Adds space to the gutter to make room for heading annotations on mobile
|
||||
// Adds space to the gutter to make room for heading annotations
|
||||
padding: 0 32px;
|
||||
transition: padding 100ms;
|
||||
|
||||
max-width: 100vw;
|
||||
width: 100%;
|
||||
|
||||
${breakpoint("tablet")`
|
||||
padding: 0 24px;
|
||||
margin: 4px auto 12px;
|
||||
max-width: calc(48px + ${(props: MaxWidthProps) =>
|
||||
props.showContents ? "64em" : "46em"});
|
||||
max-width: ${(props: MaxWidthProps) =>
|
||||
props.isFullWidth
|
||||
? "100vw"
|
||||
: `calc(64px + 46em + ${props.showContents ? "256px" : "0px"});`}
|
||||
`};
|
||||
|
||||
${breakpoint("desktopLarge")`
|
||||
max-width: calc(48px + 52em);
|
||||
max-width: ${(props: MaxWidthProps) =>
|
||||
props.isFullWidth ? "100vw" : `calc(64px + 52em);`}
|
||||
`};
|
||||
`;
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ function DocumentHeader({
|
||||
/>
|
||||
)}
|
||||
showToggleEmbeds={canToggleEmbeds}
|
||||
showPrint
|
||||
showDisplayOptions
|
||||
/>
|
||||
</Action>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user