From a88a2cac2d09742492e04ac1ef596282dcad7df9 Mon Sep 17 00:00:00 2001 From: 0div Date: Fri, 27 Sep 2024 11:59:04 +0200 Subject: [PATCH] create TOC page instead of nested navigation --- apps/web/prebuild.js | 33 +++++-- apps/web/src/components/Footer.tsx | 87 ++++++++++--------- apps/web/src/components/Search.tsx | 135 +++++++++++++++++------------ 3 files changed, 150 insertions(+), 105 deletions(-) diff --git a/apps/web/prebuild.js b/apps/web/prebuild.js index 18dc759cc..945849036 100644 --- a/apps/web/prebuild.js +++ b/apps/web/prebuild.js @@ -1,7 +1,7 @@ const fs = require('fs') const path = require('path') -function walkDir(dir, basePath = '') { +function walkDir(dirName, dir, basePath = '', depth = 1) { const entries = fs.readdirSync(dir, { withFileTypes: true }) return entries @@ -9,12 +9,31 @@ function walkDir(dir, basePath = '') { const relativePath = path.join(basePath, entry.name) if (entry.isDirectory()) { - let route = { title: entry.name } - const links = walkDir(path.join(dir, entry.name), relativePath) + let route = { + title: depth === 1 ? entry.name.toLocaleUpperCase() : entry.name, + } + const entryName = entry.name + const childPath = path.join(dir, entry.name) + const links = walkDir(entryName, childPath, relativePath, depth + 1) if (links.length > 0) { - route.links = links - } else { - route.href = '/' + relativePath + if (depth === 1) { + route.href = '.' + relativePath + route.links = links + } else if (depth === 2) { + route.href = '/docs/api-reference/' + relativePath + const mdxFilePath = path.join(childPath, 'page.mdx') + console.log(`Generating ${mdxFilePath}`) + const mdxContent = `# ${dirName} ${entryName}\n\n${links + .map( + (link) => + `- [${ + link.title.charAt(0).toUpperCase() + + link.title.slice(1).toLowerCase() + }](./${entryName}/${link.title})` + ) + .join('\n')}` + fs.writeFileSync(mdxFilePath, mdxContent) + } } return route } @@ -29,7 +48,7 @@ function generateApiRefRoutes() { return [] } - return walkDir(apiRefPath) + return walkDir('api-reference', apiRefPath) } const apiRefRoutes = generateApiRefRoutes() diff --git a/apps/web/src/components/Footer.tsx b/apps/web/src/components/Footer.tsx index 4d34e2cec..ffcc2d179 100644 --- a/apps/web/src/components/Footer.tsx +++ b/apps/web/src/components/Footer.tsx @@ -5,15 +5,15 @@ import { usePathname } from 'next/navigation' import { Button } from '@/components/Button' import { routes } from '@/components/Navigation/routes' -import { DiscordIcon } from '@/components/icons/DiscordIcon' -import { GitHubIcon } from '@/components/icons/GitHubIcon' import { TwitterIcon } from '@/components/icons/TwitterIcon' +import { GitHubIcon } from '@/components/icons/GitHubIcon' +import { DiscordIcon } from '@/components/icons/DiscordIcon' function PageLink({ - label, - page, - previous = false, -}: { + label, + page, + previous = false, + }: { label: string page: { href: string; title: string } previous?: boolean @@ -43,27 +43,10 @@ function PageLink({ function PageNavigation() { let initialPathname = usePathname() // Running on the server, there's bug with usePathname() and basePath https://github.com/vercel/next.js/issues/52700 - if (typeof window === 'undefined' && initialPathname === '/') - initialPathname = '/docs' + if (typeof window === 'undefined' && initialPathname === '/') initialPathname = '/docs' - const allPages = routes.flatMap((group) => { - if ('links' in group) { - return group.links.flatMap((link) => { - if ('links' in link) { - return { - title: link.title, - href: link.href, - icon: link.icon, - } - } - return link - }) - } - return [group] - }) - const currentPageIndex = allPages.findIndex( - (page) => page.href === initialPathname - ) + const allPages = routes.flatMap(group => group.links) + const currentPageIndex = allPages.findIndex(page => page.href === initialPathname) if (currentPageIndex === -1) return null @@ -76,12 +59,19 @@ function PageNavigation() {
{previousPage && (
- +
)} {nextPage && (
- +
)}
@@ -89,18 +79,21 @@ function PageNavigation() { } function SocialLink({ - href, - icon: Icon, - children, -}: { + href, + icon: Icon, + children, + }: { href: string icon: React.ComponentType<{ className?: string }> children: React.ReactNode }) { return ( - + {children} - + ) } @@ -110,21 +103,29 @@ function SmallPrint() {

- © FoundryLabs, Inc. {new Date().getFullYear()}. All rights - reserved. + © FoundryLabs, Inc. {new Date().getFullYear()}. All rights reserved.

548 Market Street #83122, San Francisco, CA 94104

- + Follow us on Twitter - + Follow us on GitHub - + Join our Discord server
@@ -135,8 +136,8 @@ function SmallPrint() { export function Footer() { return (
- - + +
) } @@ -145,8 +146,8 @@ export function FooterMain() { return (
- +
) -} +} \ No newline at end of file diff --git a/apps/web/src/components/Search.tsx b/apps/web/src/components/Search.tsx index 355b0c2ee..b9bba507c 100644 --- a/apps/web/src/components/Search.tsx +++ b/apps/web/src/components/Search.tsx @@ -1,5 +1,8 @@ 'use client' +import { forwardRef, Fragment, Suspense, useCallback, useEffect, useId, useRef, useState } from 'react' +import Highlighter from 'react-highlight-words' +import { usePathname, useRouter, useSearchParams } from 'next/navigation' import { type AutocompleteApi, type AutocompleteCollection, @@ -7,22 +10,10 @@ import { createAutocomplete, } from '@algolia/autocomplete-core' import clsx from 'clsx' -import { usePathname, useRouter, useSearchParams } from 'next/navigation' -import { - forwardRef, - Fragment, - Suspense, - useCallback, - useEffect, - useId, - useRef, - useState, -} from 'react' -import Highlighter from 'react-highlight-words' -import { DialogAnimated } from '@/components/DialogAnimated' import { routes } from '@/components/Navigation/routes' import { type Result } from '@/mdx/search.mjs' +import { DialogAnimated } from '@/components/DialogAnimated' type EmptyObject = Record @@ -91,7 +82,7 @@ function useAutocomplete({ close }: { close: () => void }) { ] }) }, - }) + }), ) return { autocomplete, autocompleteState } @@ -99,7 +90,12 @@ function useAutocomplete({ close }: { close: () => void }) { function SearchIcon(props: React.ComponentPropsWithoutRef<'svg'>) { return ( -
  • 0 && 'border-t border-zinc-100 dark:border-zinc-800' + resultIndex > 0 && 'border-t border-zinc-100 dark:border-zinc-800', )} aria-labelledby={`${id}-hierarchy ${id}-title`} {...autocomplete.getItemProps({ @@ -201,7 +215,10 @@ function SearchResult({ aria-hidden="true" className="text-sm font-medium text-zinc-900 group-aria-selected:text-brand-500 dark:text-white" > - +
  • {hierarchy.length > 0 && (
    {hierarchy.map((item, itemIndex, items) => ( - + @@ -241,7 +261,7 @@ function SearchResults({ if (collection.items.length === 0) { return (
    - +

    Nothing found for{' '} @@ -281,15 +301,15 @@ const SearchInput = forwardRef< return (

    - + { + onKeyDown={event => { if ( event.key === 'Escape' && !autocompleteState.isOpen && @@ -309,7 +329,8 @@ const SearchInput = forwardRef< /> {autocompleteState.status === 'stalled' && (
    - +
    )}
    @@ -317,10 +338,10 @@ const SearchInput = forwardRef< }) function SearchDialog({ - open, - setOpen, - className, -}: { + open, + setOpen, + className, + }: { open: boolean setOpen: (open: boolean) => void className?: string @@ -420,12 +441,12 @@ function useSearchProps() { setOpen: useCallback( (open: boolean) => { const { width = 0, height = 0 } = - buttonRef.current?.getBoundingClientRect() ?? {} + buttonRef.current?.getBoundingClientRect() ?? {} if (!open || (width !== 0 && height !== 0)) { setOpen(open) } }, - [setOpen] + [setOpen], ), }, } @@ -436,9 +457,7 @@ export function Search() { const { buttonProps, dialogProps } = useSearchProps() useEffect(() => { - setModifierKey( - /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘' : 'Ctrl ' - ) + setModifierKey(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘' : 'Ctrl ') }, []) return ( @@ -448,7 +467,7 @@ export function Search() { className="hidden h-8 w-full items-center gap-2 whitespace-nowrap rounded-full bg-white pl-2 pr-3 text-sm text-zinc-500 ring-1 ring-zinc-900/10 transition hover:ring-zinc-900/20 ui-not-focus-visible:outline-none dark:bg-white/5 dark:text-zinc-400 dark:ring-inset dark:ring-white/10 dark:hover:ring-white/20 lg:flex" {...buttonProps} > - + Search in docs... {modifierKey} @@ -456,7 +475,10 @@ export function Search() { - +
    ) @@ -473,10 +495,13 @@ export function MobileSearch() { aria-label="Search in docs..." {...buttonProps} > - + - +
    )