From 33ec49d5bf6f9813e5f2245fa93233bfd0f5648f Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Fri, 7 Oct 2022 23:15:02 -0400 Subject: [PATCH] feat(guide): add outline for pages (#8722) Co-authored-by: iCrawl --- packages/guide/src/components/Outline.tsx | 72 +++++++++++++++++++ .../guide/src/components/SidebarItems.tsx | 34 ++++++--- .../guide/src/components/SidebarLayout.astro | 20 +++++- .../guide/src/layouts/SidebarLayout.astro | 6 +- packages/ui/unocss.config.ts | 7 +- 5 files changed, 124 insertions(+), 15 deletions(-) create mode 100644 packages/guide/src/components/Outline.tsx diff --git a/packages/guide/src/components/Outline.tsx b/packages/guide/src/components/Outline.tsx new file mode 100644 index 000000000..af8779d70 --- /dev/null +++ b/packages/guide/src/components/Outline.tsx @@ -0,0 +1,72 @@ +import type { MarkdownHeading } from 'astro'; +import { useEffect, useMemo, useState } from 'react'; +import { Scrollbars } from 'react-custom-scrollbars-2'; +import { VscListSelection } from 'react-icons/vsc'; +import { useLocation } from 'react-use'; + +const LINK_HEIGHT = 30; +const INDICATOR_SIZE = 10; +const INDICATOR_OFFSET = (LINK_HEIGHT - INDICATOR_SIZE) / 2; + +export function Outline({ headings }: { headings: MarkdownHeading[] }) { + const state = useLocation(); + const [active, setActive] = useState(0); + + const headingItems = useMemo( + () => + headings.map((heading, idx) => ( + + {heading.text} + + )), + [headings, active], + ); + + useEffect(() => { + const idx = headings.findIndex((heading) => heading.slug === state.hash?.slice(1)); + if (idx >= 0) { + setActive(idx); + } + }, [state, headings]); + + return ( +
} + renderTrackVertical={(props) => ( +
+ )} + universal + > +
+
+ + Contents +
+
+
+
+ {headingItems} +
+
+
+ + ); +} diff --git a/packages/guide/src/components/SidebarItems.tsx b/packages/guide/src/components/SidebarItems.tsx index d14987077..d328403b6 100644 --- a/packages/guide/src/components/SidebarItems.tsx +++ b/packages/guide/src/components/SidebarItems.tsx @@ -1,29 +1,43 @@ import { Section } from '@discordjs/ui'; import type { MDXInstance } from 'astro'; +import { useEffect, useMemo, useState } from 'react'; +import { useLocation } from 'react-use'; export type MDXPage = MDXInstance<{ category: string; title: string }>; export function SidebarItems({ pages }: { pages: MDXPage[] }) { - const categories = pages.reduce>((acc, page) => { - if (acc[page.frontmatter.category]) { - acc[page.frontmatter.category]?.push(page); - } else { - acc[page.frontmatter.category] = [page]; - } + const state = useLocation(); + const [active, setActive] = useState(''); - return acc; - }, {}); + const categories = useMemo( + () => + pages.reduce>((acc, page) => { + if (acc[page.frontmatter.category]) { + acc[page.frontmatter.category]?.push(page); + } else { + acc[page.frontmatter.category] = [page]; + } + + return acc; + }, {}), + [pages], + ); + + useEffect(() => { + setActive(state.pathname); + }, [state]); return Object.keys(categories).map((category, idx) => (
{categories[category]?.map((member, index) => ( diff --git a/packages/guide/src/components/SidebarLayout.astro b/packages/guide/src/components/SidebarLayout.astro index fa31cd3a6..20580343c 100644 --- a/packages/guide/src/components/SidebarLayout.astro +++ b/packages/guide/src/components/SidebarLayout.astro @@ -1,8 +1,13 @@ --- +import type { MarkdownLayoutProps } from 'astro'; import { Navbar } from './Navbar.jsx'; +import { Outline } from './Outline.jsx'; import { SidebarItems } from './SidebarItems.jsx'; const pages = await Astro.glob<{ category: string; title: string }>('../pages/**/*.mdx'); + +type Props = MarkdownLayoutProps<{}>; +const { headings } = Astro.props; --- @@ -10,15 +15,23 @@ const pages = await Astro.glob<{ category: string; title: string }>('../pages/**
-
+
+
Test
diff --git a/packages/guide/src/layouts/SidebarLayout.astro b/packages/guide/src/layouts/SidebarLayout.astro index e9193cc90..ba9024df0 100644 --- a/packages/guide/src/layouts/SidebarLayout.astro +++ b/packages/guide/src/layouts/SidebarLayout.astro @@ -1,8 +1,12 @@ --- import '@code-hike/mdx/styles.css'; import '../styles/ch.css'; +import type { MarkdownLayoutProps } from 'astro'; import SidebarLayout from '../components/SidebarLayout.astro'; import { DESCRIPTION } from '../util/constants.js'; + +type Props = MarkdownLayoutProps<{}>; +const props = Astro.props; --- @@ -51,7 +55,7 @@ import { DESCRIPTION } from '../util/constants.js'; .addEventListener('change', (ev) => setTheme(ev.matches, persistedColorPreference)); })(); - + diff --git a/packages/ui/unocss.config.ts b/packages/ui/unocss.config.ts index 273c5d26e..c4d14b912 100644 --- a/packages/ui/unocss.config.ts +++ b/packages/ui/unocss.config.ts @@ -49,11 +49,16 @@ export default defineConfig({ 'a > img': { display: 'inline-block', }, + h1: { + 'scroll-margin-top': '6.5rem', + }, h2: { 'margin-top': '1.25em', + 'scroll-margin-top': '6.5rem', }, h3: { - 'margin-top': '0.75em', + 'margin-top': '1.25em', + 'scroll-margin-top': '6.5rem', }, // eslint-disable-next-line id-length p: {