feat(freesewing.dev): ToC and layout changes
This commit is contained in:
parent
fbbad22dcc
commit
6c41b1d941
17 changed files with 478 additions and 94 deletions
|
@ -1,6 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
const Docs = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Docs = ({ className="h-6 w-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Guides = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Guides = ({ className="h-6 w-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 3L3 10.53v.98l6.84 2.65L12.48 21h.98L21 3z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
const Help = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Help = ({ className="w-6 h-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Sourced from heroicons.com - Thanks guys! */
|
||||
const Rss = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Rss = ({ className='h-6 w-6' }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 5c7.18 0 13 5.82 13 13M6 11a7 7 0 017 7m-6 0a1 1 0 11-2 0 1 1 0 012 0z" />
|
||||
</svg>
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Tutorial = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
const Tutorial = ({ className="w-6 h-6" }) => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path d="M12 14l9-5-9-5-9 5 9 5z" />
|
||||
<path d="M12 14l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 14l9-5-9-5-9 5 9 5zm0 0l6.16-3.422a12.083 12.083 0 01.665 6.479A11.952 11.952 0 0012 20.055a11.952 11.952 0 00-6.824-2.998 12.078 12.078 0 01.665-6.479L12 14zm-4 6v-7.5l4-2.222" />
|
||||
|
|
|
@ -74,8 +74,9 @@ const asideClasses = `
|
|||
overflow-y-scroll
|
||||
z-20
|
||||
bg-base-100 text-base-content
|
||||
sm:bg-neutral sm:bg-opacity-95 sm:text-neutral-content
|
||||
transition-all `
|
||||
transition-all
|
||||
xl:w-1/4
|
||||
`
|
||||
|
||||
|
||||
const DefaultLayout = ({
|
||||
|
@ -110,53 +111,58 @@ const DefaultLayout = ({
|
|||
bg-base-100
|
||||
`}>
|
||||
<Header app={app} setSearch={setSearch} />
|
||||
<main className={`
|
||||
grow flex flex-row
|
||||
gap-2
|
||||
${!workbench ? 'lg:gap-8 xl:gap-16' : ''}
|
||||
`}>
|
||||
<aside className={`
|
||||
${asideClasses}
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
sm:flex-row-reverse
|
||||
${workbench && collapsePrimaryNav
|
||||
? 'sm:px-0 sm:w-16'
|
||||
: 'sm:px-1 md:px-4 lg:px-8 sm:w-[38.2%]'
|
||||
}
|
||||
`}>
|
||||
{workbench && (
|
||||
<div className={`hidden sm:flex`}>
|
||||
<button
|
||||
className="text-secondary-focus h-full px-2 pl-4 hover:animate-pulse"
|
||||
onClick={() => setCollapsePrimaryNav(!collapsePrimaryNav)}
|
||||
>
|
||||
{collapsePrimaryNav
|
||||
? <><Right /><Right /><Right /></>
|
||||
: <><Left /><Left /><Left /></>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<PrimaryNavigation app={app} active={slug}/>
|
||||
</aside>
|
||||
<section className={`
|
||||
p-4 pt-24 sm:pt-28 w-full
|
||||
sm:px-1 md:px-4 lg:px-8
|
||||
${workbench && collapsePrimaryNav
|
||||
? ''
|
||||
: 'max-w-61.8%'
|
||||
}
|
||||
`}>
|
||||
<div className={workbench ? '' : "max-w-5xl"}>
|
||||
{title && (
|
||||
<>
|
||||
<Breadcrumbs app={app} slug={slug} title={title} />
|
||||
<PageTitle app={app} slug={slug} title={title} />
|
||||
</>
|
||||
<main className="grow bg-base-100">
|
||||
<div className="m-auto flex flex-row justify-center">
|
||||
|
||||
<aside className={`
|
||||
${asideClasses}
|
||||
${app.primaryMenu ? '' : 'translate-x-[-100%]'} transition-transform
|
||||
sm:flex-row-reverse
|
||||
${workbench && collapsePrimaryNav
|
||||
? 'sm:px-0 sm:w-16'
|
||||
: 'sm:px-1 md:px-4 lg:px-8'
|
||||
}
|
||||
w-96
|
||||
`}>
|
||||
{workbench && (
|
||||
<div className={`hidden sm:flex`}>
|
||||
<button
|
||||
className="text-secondary-focus h-full px-2 pl-4 hover:animate-pulse"
|
||||
onClick={() => setCollapsePrimaryNav(!collapsePrimaryNav)}
|
||||
>
|
||||
{collapsePrimaryNav
|
||||
? <><Right /><Right /><Right /></>
|
||||
: <><Left /><Left /><Left /></>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
<PrimaryNavigation app={app} active={slug}/>
|
||||
</aside>
|
||||
|
||||
<div className="p-0 m-0 bg-base-100">
|
||||
<section className={`
|
||||
p-4 pt-24 sm:pt-28
|
||||
sm:px-1 md:px-4 lg:px-8
|
||||
${workbench && collapsePrimaryNav
|
||||
? ''
|
||||
: 'max-w-7xl'
|
||||
}
|
||||
`}>
|
||||
<div>
|
||||
{title && (
|
||||
<>
|
||||
<Breadcrumbs app={app} slug={slug} title={title} />
|
||||
<PageTitle app={app} slug={slug} title={title} />
|
||||
</>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
{workbench && AltMenu && (
|
||||
<aside className={`
|
||||
${asideClasses}
|
||||
|
|
|
@ -19,11 +19,11 @@ const force = [
|
|||
|
||||
// List of icons matched to top-level slug
|
||||
const icons = {
|
||||
blog: <RssIcon />,
|
||||
tutorials: <TutorialIcon />,
|
||||
guides: <GuideIcon />,
|
||||
howtos: <HelpIcon />,
|
||||
reference: <DocsIcon />
|
||||
blog: (className='') => <RssIcon className={className}/>,
|
||||
tutorials: (className='') => <TutorialIcon className={className}/>,
|
||||
guides: (className='') => <GuideIcon className={className}/>,
|
||||
howtos: (className='') => <HelpIcon className={className}/>,
|
||||
reference: (className='') => <DocsIcon className={className}/>
|
||||
}
|
||||
|
||||
/* helper method to order nav entries */
|
||||
|
@ -33,7 +33,7 @@ const order = obj => orderBy(obj, ['__order', '__title'], ['asc', 'asc'])
|
|||
// Exported for re-use
|
||||
export const Chevron = ({w=8, m=2}) => <svg className={`
|
||||
fill-current opacity-75 w-${w} h-${w} mr-${m}
|
||||
details-toggle hover:text-secondary sm:hover:text-secondary-focus
|
||||
details-toggle hover:text-secondary sm:hover:text-secondary
|
||||
`}
|
||||
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
<path d="M12.95 10.707l.707-.707L8 4.343 6.586 5.757 10.828 10l-4.242 4.243L8 15.657l4.95-4.95z"/>
|
||||
|
@ -47,9 +47,9 @@ const currentChildren = current => Object.values(order(current))
|
|||
// Exported for re-use
|
||||
export const linkClasses = `text-lg lg:text-xl
|
||||
py-1
|
||||
text-base-content sm:text-neutral-content
|
||||
text-base-content sm:text-base-content
|
||||
hover:text-secondary
|
||||
sm:hover:text-secondary-focus
|
||||
sm:hover:text-secondary
|
||||
`
|
||||
|
||||
// Figure out whether a page is on the path to the active page
|
||||
|
@ -76,7 +76,7 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
flex flex-row
|
||||
px-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
hover:cursor-row-resize
|
||||
items-center
|
||||
`}>
|
||||
|
@ -86,16 +86,16 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
${linkClasses}
|
||||
hover:cursor-pointer
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
sm:hover:border-secondary
|
||||
${child.__slug === active
|
||||
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
||||
: 'text-base-content sm:text-neutral-content'
|
||||
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}
|
||||
`}>
|
||||
<span className={`
|
||||
text-3xl mr-2 inline-block p-0 leading-3
|
||||
${child.__slug === active
|
||||
? 'text-secondary sm:text-secondary-focus translate-y-1'
|
||||
? 'text-secondary sm:text-secondary translate-y-1'
|
||||
: 'translate-y-3'
|
||||
}
|
||||
`}>
|
||||
|
@ -120,15 +120,15 @@ const SubLevel = ({ nodes={}, active }) => (
|
|||
${linkClasses}
|
||||
hover:cursor-pointer
|
||||
hover:border-secondary
|
||||
sm:hover:border-secondary-focus
|
||||
sm:hover:border-secondary
|
||||
${child.__slug === active
|
||||
? 'text-secondary border-secondary sm:text-secondary-focus sm:border-secondary-focus'
|
||||
: 'text-base-content sm:text-neutral-content'
|
||||
? 'text-secondary border-secondary sm:text-secondary sm:border-secondary'
|
||||
: 'text-base-content sm:text-base-content'
|
||||
}`}>
|
||||
<span className={`
|
||||
text-3xl mr-2 inline-block p-0 leading-3
|
||||
${child.__slug === active
|
||||
? 'text-secondary sm:text-secondary-focus translate-y-1'
|
||||
? 'text-secondary sm:text-secondary translate-y-1'
|
||||
: 'translate-y-3'
|
||||
}
|
||||
`}>
|
||||
|
@ -154,15 +154,15 @@ const TopLevel = ({ icon, title, nav, current, slug, hasChildren=false, active }
|
|||
hover:cursor-row-resize
|
||||
p-2
|
||||
text-base-content
|
||||
sm:text-neutral-content
|
||||
sm:text-base-content
|
||||
items-center
|
||||
`}>
|
||||
<span className="text-secondary-focus">{icon}</span>
|
||||
<span className="text-secondary">{icon}</span>
|
||||
<Link href={`/${slug}`}>
|
||||
<a className={`
|
||||
grow ${linkClasses} hover:cursor-pointer
|
||||
${slug === active
|
||||
? 'text-secondary sm:text-secondary-focus'
|
||||
? 'text-secondary sm:text-secondary'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
|
@ -175,12 +175,15 @@ const TopLevel = ({ icon, title, nav, current, slug, hasChildren=false, active }
|
|||
</details>
|
||||
)
|
||||
|
||||
const Navigation = ({ app, active }) => {
|
||||
const Navigation = ({ app, active, className='' }) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) output.push(<TopLevel
|
||||
key={page.__slug}
|
||||
icon={icons[page.__slug] || <span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>}
|
||||
icon={icons[page.__slug]
|
||||
? icons[page.__slug]('w-6 h-6')
|
||||
: <span className="text-3xl mr-2 translate-y-3 inline-block p-0 leading-3">°</span>
|
||||
}
|
||||
title={page.__title}
|
||||
slug={page.__slug}
|
||||
hasChildren={keepClosed.indexOf(page.__slug) === -1}
|
||||
|
@ -189,13 +192,39 @@ const Navigation = ({ app, active }) => {
|
|||
active={active}
|
||||
/>)
|
||||
|
||||
return <div className='pb-20'>{output}</div>
|
||||
return <div className={`pb-20 ${className}`}>{output}</div>
|
||||
}
|
||||
|
||||
const Icons = ({ app, active, className='' }) => {
|
||||
if (!app.navigation) return null
|
||||
const output = []
|
||||
for (const page of order(app.navigation)) {
|
||||
output.push(
|
||||
<li key={page.__slug} className="py-4">
|
||||
<Link href={`/${page.__slug}`}>
|
||||
<a
|
||||
className={`grow ${linkClasses} hover:cursor-pointer flex flex-col items-center`}
|
||||
title={page.__title}
|
||||
>
|
||||
{icons[page.__slug]
|
||||
? icons[page.__slug]('w-14 h-14')
|
||||
: <HelpIcon />
|
||||
}
|
||||
<span className='font-bold'>{page.__title}</span>
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return <ul className={`flex flex-col items-center ${className}`}>{output}</ul>
|
||||
}
|
||||
|
||||
const PrimaryMenu = ({ app, active }) => (
|
||||
<nav className="sm:max-w-lg grow mb-12">
|
||||
<ThemePicker app={app} className="w-full sm:hidden"/>
|
||||
<Navigation app={app} active={active} />
|
||||
<nav className="mb-12">
|
||||
<ThemePicker app={app} className="w-full md:hidden"/>
|
||||
<Icons app={app} className="hidden md:block lg:hidden"/>
|
||||
<Navigation app={app} active={active} className="md:hidden lg:block"/>
|
||||
</nav>
|
||||
)
|
||||
|
||||
|
|
41
packages/freesewing.shared/components/wrappers/toc.js
Normal file
41
packages/freesewing.shared/components/wrappers/toc.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This is used to wrap a Table of Contents (toc) as returned
|
||||
* from the mdxLoader method (see shared/mdx/loader.js)
|
||||
* It is NOT for wrapping plain markdown/mdx
|
||||
*/
|
||||
import { useState, useEffect, Fragment } from 'react'
|
||||
|
||||
// See: https://mdxjs.com/guides/mdx-on-demand/
|
||||
import { run } from '@mdx-js/mdx'
|
||||
import * as runtime from 'react/jsx-runtime.js'
|
||||
|
||||
// Components that are available in all MDX
|
||||
import customComponents from 'shared/components/mdx'
|
||||
|
||||
const TocWrapper = ({toc, app}) => {
|
||||
|
||||
const [mdxModule, setMdxModule] = useState()
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
setMdxModule(await run(toc, runtime))
|
||||
})()
|
||||
}, [toc])
|
||||
|
||||
// React component for MDX content
|
||||
const MdxContent = mdxModule ? mdxModule.default : Fragment
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
mdx mdx-toc text-base-content text-lg lg:text-xl
|
||||
sticky top-8 max-h-screen overflow-y-auto
|
||||
md:border-l-4 md:pl-4 md:mb-8 md:border-base-200
|
||||
`}
|
||||
>
|
||||
{mdxModule && <MdxContent components={customComponents(app)}/>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TocWrapper
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue