Skip to content

Commit

Permalink
📏 Allow full-length TOC when sidebar is useable (#441)
Browse files Browse the repository at this point in the history
* fix: allow full-width TOC when sidebar is useable

* fix: rename isWide to useIsWide

* chore: add changeset

* refactor: unpack single item
  • Loading branch information
agoose77 authored Sep 6, 2024
1 parent ffed8fb commit 3ae88e1
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 5 deletions.
7 changes: 7 additions & 0 deletions .changeset/cyan-taxis-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@myst-theme/providers': patch
'@myst-theme/site': patch
'@myst-theme/book': patch
---

Grow TOC on narrow screens
10 changes: 8 additions & 2 deletions packages/providers/src/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ import { useMediaQuery } from './hooks.js';

type UiState = {
isNavOpen?: boolean;
isWide?: boolean;
};

type UiContextType = [UiState, (state: UiState) => void];

const UiContext = createContext<UiContextType | undefined>(undefined);
export const UiContext = createContext<UiContextType | undefined>(undefined);

// Create a provider for components to consume and subscribe to changes
export function UiStateProvider({ children }: { children: React.ReactNode }) {
// Close the nav
const wide = useMediaQuery('(min-width: 1280px)');
const [state, setState] = useState<UiState>({ isNavOpen: false });
useEffect(() => {
if (wide) setState({ ...state, isNavOpen: false });
if (wide) setState({ ...state, isNavOpen: false, isWide: wide });
}, [wide]);
return <UiContext.Provider value={[state, setState]}>{children}</UiContext.Provider>;
}
Expand All @@ -28,3 +29,8 @@ export function useNavOpen(): [boolean, (open: boolean) => void] {
};
return [state?.isNavOpen ?? false, setOpen];
}

export function useIsWide(): boolean {
const [state] = useContext(UiContext) ?? [];
return state?.isWide ?? false;
}
8 changes: 7 additions & 1 deletion packages/site/src/components/Navigation/PrimarySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useSiteManifest,
useGridSystemProvider,
useThemeTop,
useIsWide,
} from '@myst-theme/providers';
import type { Heading } from '@myst-theme/common';
import { Toc } from './TableOfContentsItems.js';
Expand Down Expand Up @@ -95,10 +96,15 @@ export function useSidebarHeight<T extends HTMLElement = HTMLElement>(top = 0, i
const container = useRef<T>(null);
const toc = useRef<HTMLDivElement>(null);
const transitionState = useNavigation().state;
const wide = useIsWide();
const setHeight = () => {
if (!container.current || !toc.current) return;
const height = container.current.offsetHeight - window.scrollY;
const div = toc.current.firstChild as HTMLDivElement;
if (div)
div.style.height = wide
? `min(calc(100vh - ${top}px), ${height + inset}px)`
: `calc(100vh - ${top}px)`;
if (div) div.style.height = `min(calc(100vh - ${top}px), ${height + inset}px)`;
const nav = toc.current.querySelector('nav');
if (nav) nav.style.opacity = height > 150 ? '1' : '0';
Expand All @@ -111,7 +117,7 @@ export function useSidebarHeight<T extends HTMLElement = HTMLElement>(top = 0, i
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [container, toc, transitionState]);
}, [container, toc, transitionState, wide]);
return { container, toc };
}

Expand Down
27 changes: 25 additions & 2 deletions themes/book/app/routes/$.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const loader: LoaderFunction = async ({ params, request }) => {
return json({ config, page, project });
};

export function ArticlePageAndNavigation({
function ArticlePageAndNavigationInternal({
children,
hide_toc,
projectSlug,
Expand All @@ -87,7 +87,7 @@ export function ArticlePageAndNavigation({
const top = useThemeTop();
const { container, toc } = useSidebarHeight(top, inset);
return (
<UiStateProvider>
<>
<TopNav hideToc={hide_toc} />
<PrimaryNavigation
sidebarRef={toc}
Expand All @@ -105,6 +105,29 @@ export function ArticlePageAndNavigation({
{children}
</article>
</TabStateProvider>
</>
);
}

export function ArticlePageAndNavigation({
children,
hide_toc,
projectSlug,
inset = 20, // begin text 20px from the top (aligned with menu)
}: {
hide_toc?: boolean;
projectSlug?: string;
children: React.ReactNode;
inset?: number;
}) {
return (
<UiStateProvider>
<ArticlePageAndNavigationInternal
children={children}
hide_toc={hide_toc}
projectSlug={projectSlug}
inset={inset}
/>
</UiStateProvider>
);
}
Expand Down

0 comments on commit 3ae88e1

Please sign in to comment.