1
0
Fork 0

wip(shared): Work on modal menu

This commit is contained in:
joostdecock 2023-04-09 15:57:25 +02:00
parent aaef2a5b4a
commit dbab735eeb
16 changed files with 327 additions and 32 deletions

View file

@ -19,7 +19,6 @@
"dev": "next dev -p 8000",
"develop": "next dev -p 8000",
"lint": "next lint",
"i18n": "SITE=dev node ../shared/prebuild/i18n-only.mjs",
"prebuild": "SITE=dev node --experimental-json-modules ../shared/prebuild/index.mjs",
"serve": "pm2 start npm --name 'dev' -- run start",
"start": "yarn prebuild && yarn dev"

View file

@ -26,11 +26,10 @@ import { useTranslation } from 'next-i18next'
import { ModalThemePicker } from 'shared/components/modal/theme-picker.mjs'
import { ModalLocalePicker } from 'shared/components/modal/locale-picker.mjs'
import { Search, ns as searchNs } from 'site/components/search.mjs'
import { ModalMenu } from 'site/components/navigation/modal-menu.mjs'
export const ns = [...new Set(['header', ...themeNs, ...localeNs])]
const MainMenu = () => <p>Main menu here</p>
const NavButton = ({ href, label, color, children, onClick = false, extraClasses = '' }) => {
const className =
'border-0 px-1 lg:px-4 text-base py-3 lg:py-4 text-center flex flex-col items-center 2xl:w-36 ' +
@ -54,37 +53,64 @@ const NavSpacer = () => (
<div className="hidden lg:block text-base lg:text-4xl font-thin opacity-30 px-0.5 lg:px-2">|</div>
)
export const colors = {
menu: 'red',
designs: 'orange',
showcase: 'yellow',
docs: 'lime',
blog: 'green',
community: 'cyan',
theme: 'blue',
language: 'indigo',
search: 'violet',
account: 'purple',
}
const NavIcons = ({ app, setSearch }) => {
const { t } = useTranslation(['header'])
const iconSize = 'h-6 w-6 lg:h-12 lg:w-12'
return (
<>
<NavButton onClick={() => app.setModal(<MainMenu />)} label={t('header:menu')} color="red">
<NavButton
onClick={() => app.setModal(<ModalMenu app={app} />)}
label={t('header:menu')}
color={colors.menu}
>
<MenuIcon className={iconSize} />
</NavButton>
<NavSpacer />
<NavButton href="/designs" label={t('header:designs')} color="orange">
<NavButton href="/designs" label={t('header:designs')} color={colors.designs}>
<DesignIcon className={iconSize} />
</NavButton>
<NavButton
href="/showcase"
label={t('header:showcase')}
color="yellow"
color={colors.showcase}
extraClasses="hidden lg:flex"
>
<ShowcaseIcon className={iconSize} />
</NavButton>
<NavButton href="/docs" label={t('header:docs')} color="lime" extraClasses="hidden lg:flex">
<NavButton
href="/docs"
label={t('header:docs')}
color={colors.docs}
extraClasses="hidden lg:flex"
>
<DocsIcon className={iconSize} />
</NavButton>
<NavButton href="/blog" label={t('header:blog')} color="green" extraClasses="hidden lg:flex">
<NavButton
href="/blog"
label={t('header:blog')}
color={colors.blog}
extraClasses="hidden lg:flex"
>
<RssIcon className={iconSize} />
</NavButton>
<NavButton
href="/community"
label={t('header:community')}
color="cyan"
color={colors.community}
extraClasses="hidden lg:flex"
>
<CommunityIcon className={iconSize} />
@ -93,22 +119,22 @@ const NavIcons = ({ app, setSearch }) => {
<NavButton
onClick={() => app.setModal(<ModalThemePicker app={app} />)}
label={t('header:theme')}
color="blue"
color={colors.theme}
>
<ThemeIcon className={iconSize} />
</NavButton>
<NavButton
onClick={() => app.setModal(<ModalLocalePicker app={app} />)}
label={t('header:language')}
color="indigo"
color={colors.language}
>
<I18nIcon className={iconSize} />
</NavButton>
<NavButton onClick={() => setSearch(true)} label={t('header:search')} color="violet">
<NavButton onClick={() => setSearch(true)} label={t('header:search')} color={colors.search}>
<SearchIcon className={iconSize} />
</NavButton>
<NavSpacer />
<NavButton href="/account" label={t('header:account')} color="purple">
<NavButton href="/account" label={t('header:account')} color={colors.account}>
<UserIcon className={iconSize} />
</NavButton>
</>

View file

@ -0,0 +1,22 @@
import { SectionsMenu } from 'site/components/navigation/sections-menu.mjs'
import { useTranslation } from 'next-i18next'
import { ActiveSection, ns as primaryNs } from 'shared/components/navigation/primary.mjs'
export const ns = primaryNs
export const ModalMenu = ({ app }) => {
const { t } = useTranslation(ns)
return (
<div className="px-4 lg:px-0 flex flex-col-reverse lg:flex-row flex-wrap gap-8 py-16 justify-between w-full max-w-6xl m-auto">
<div className="w1/3">
<h3>{t('mainSections')}</h3>
<SectionsMenu app={app} />
</div>
<div className="w1/3">
<h3>{t('currentSection')}</h3>
<ActiveSection app={app} />
</div>
</div>
)
}

View file

@ -0,0 +1,44 @@
import Link from 'next/link'
import { icons, isActive, ns as sectionsNs } from 'shared/components/navigation/primary.mjs'
import { useTranslation } from 'next-i18next'
import orderBy from 'lodash.orderby'
import { colors } from 'site/components/header/index.mjs'
export const ns = sectionsNs
export const SectionsMenu = ({ app }) => {
const { t } = useTranslation(ns)
if (!app.state.sections) return null
// Ensure each page as an `o` key so we can put them in order
const sortableSections = app.state.sections.map((s) => ({ ...s, o: s.o ? s.o : s.t }))
const output = []
for (const page of orderBy(sortableSections, ['o', 't'])) {
const act = isActive(page.s, app.state.slug)
const item = (
<Link
key={page.s}
className={`bg-${
colors[page.s]
}-400 p-0 rounded shadow hover:shadow-lg w-full bg-opacity-70 hover:bg-opacity-100 text-neutral-900
`}
href={`/${page.s}`}
title={page.t}
>
<div className="flex flex-col rounded">
<div className={`flex flex-row items-center justify-between pt-2 px-4`}>
<h4 className="text-neutral-900">{page.t}</h4>
{icons[page.s] ? icons[page.s]('w-10 h-10') : <HelpIcon />}
</div>
<div className={`font-medium text-base leading-5 text-left rounded-b py-4 px-4 `}>
{t(page.s + 'About')}
</div>
</div>
</Link>
)
output.push(item)
}
return <div className="flex flex-col gap-2">{output}</div>
}

View file

@ -21,17 +21,46 @@ const sitePages = (locale, t = false) => {
// Handle t not being present
if (!t) t = (string) => string
const pages = {
// Top-level pages that are the sections menu
designs: {
t: t('sections:designs'),
s: 'designs',
o: 10,
},
showcase: {
t: t('sections:showcase'),
s: 'showcase',
o: 20,
},
docs: {
t: t('sections:docs'),
s: 'docs',
o: 30,
},
blog: {
t: t('sections:blog'),
s: 'blog',
o: 40,
},
community: {
t: t('sections:community'),
s: 'community',
o: 50,
},
account: {
t: t('sections:account'),
s: 'account',
o: 60,
},
// Top-level pages that are not in the sections menu
profile: {
t: t('yourProfile'),
s: 'profile',
h: 1,
},
// Not translated, this is a developer page
typography: {
t: 'Typography', // Not translated, this is a developer page
t: 'Typography',
s: 'typography',
h: 1,
},

View file

@ -0,0 +1,35 @@
// Hooks
import { useApp } from 'shared/hooks/use-app.mjs'
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(['designs', ...pageNs])]
const DesignsPage = (props) => {
const app = useApp(props)
return (
<PageWrapper app={app}>
<div className="max-w-2xl">
<V3Wip />
</div>
</PageWrapper>
)
}
export default DesignsPage
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, namespaces)),
page: {
path: ['blog'],
},
},
}
}

View file

@ -0,0 +1,35 @@
// Hooks
import { useApp } from 'shared/hooks/use-app.mjs'
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(['community', ...pageNs])]
const CommunityPage = (props) => {
const app = useApp(props)
return (
<PageWrapper app={app}>
<div className="max-w-2xl">
<V3Wip />
</div>
</PageWrapper>
)
}
export default CommunityPage
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, namespaces)),
page: {
path: ['community'],
},
},
}
}

View file

@ -0,0 +1,35 @@
// Hooks
import { useApp } from 'shared/hooks/use-app.mjs'
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(['designs', ...pageNs])]
const DesignsPage = (props) => {
const app = useApp(props)
return (
<PageWrapper app={app}>
<div className="max-w-2xl">
<V3Wip />
</div>
</PageWrapper>
)
}
export default DesignsPage
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, namespaces)),
page: {
path: ['designs'],
},
},
}
}

View file

@ -8,6 +8,7 @@ import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
import { ReadMore } from 'shared/components/mdx/read-more.mjs'
import { jargon } from 'site/jargon.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(['docs', ...pageNs])]
@ -15,14 +16,11 @@ const namespaces = [...new Set(['docs', ...pageNs])]
const DocsPage = (props) => {
const app = useApp(props)
// We don't need all MDX components here, just ReadMore
const components = {
//ReadMore: (props) => <ReadMore {...props} app={app} slug="docs" recurse />,
}
return (
<PageWrapper app={app}>
<div className="w-full"></div>
<div className="max-w-2xl">
<V3Wip />
</div>
</PageWrapper>
)
}

View file

@ -0,0 +1,35 @@
// Hooks
import { useApp } from 'shared/hooks/use-app.mjs'
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { V3Wip } from 'shared/components/v3-wip.mjs'
// Translation namespaces used on this page
const namespaces = [...new Set(['designs', ...pageNs])]
const DesignsPage = (props) => {
const app = useApp(props)
return (
<PageWrapper app={app}>
<div className="max-w-2xl">
<V3Wip />
</div>
</PageWrapper>
)
}
export default DesignsPage
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, namespaces)),
page: {
path: ['showcase'],
},
},
}
}

View file

@ -24,7 +24,9 @@ export const AsideNavigation = ({ app, mobileOnly = false, before = [], after =
<div className="w-screen lg:w-auto">
{before}
<MainSections app={app} />
<ActiveSection app={app} />
<div className=" border border-l-0 border-r-0 border-b-0 border-dashed border-base-300 mt-4 pt-4">
<ActiveSection app={app} />
</div>
{after}
</div>
</aside>

View file

@ -1,12 +1,14 @@
import Link from 'next/link'
import orderBy from 'lodash.orderby'
import {
TutorialIcon,
CommunityIcon,
DesignIcon,
DocsIcon,
GuideIcon,
HelpIcon,
DocsIcon,
RssIcon,
ShowcaseIcon,
TutorialIcon,
UserIcon,
} from 'shared/components/icons.mjs'
import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
@ -14,18 +16,19 @@ import { Breadcrumbs } from 'shared/components/breadcrumbs.mjs'
export const ns = ['sections']
// List of icons matched to top-level slug
const icons = {
export const icons = {
// FreeSewing.dev
guides: (className = '') => <GuideIcon className={className} />,
howtos: (className = '') => <HelpIcon className={className} />,
reference: (className = '') => <DocsIcon className={className} />,
tutorials: (className = '') => <TutorialIcon className={className} />,
// FreeSewing.org
blog: (className = '') => <RssIcon className={className} stroke={3} />,
showcase: (className = '') => <ShowcaseIcon className={className} />,
docs: (className = '') => <DocsIcon className={className} />,
account: (className = '') => <UserIcon className={className} />,
Account: (className = '') => <UserIcon className={className} />,
blog: (className = '') => <RssIcon className={className} stroke={3} />,
designs: (className = '') => <DesignIcon className={className} stroke={3} />,
docs: (className = '') => <DocsIcon className={className} />,
showcase: (className = '') => <ShowcaseIcon className={className} />,
community: (className = '') => <CommunityIcon className={className} />,
}
/* helper method to order nav entries */
@ -60,8 +63,7 @@ export const linkClasses = `
`
// Figure out whether a page is on the path to the active page
const isActive = (slug, active) => {
console.log({ slug, active })
export const isActive = (slug, active) => {
if (!slug) return false
if (slug === active) return true
let result = true
@ -251,7 +253,7 @@ export const MainSections = ({ app }) => {
}
export const ActiveSection = ({ app }) => (
<div className="mt-4 pt-4 border border-l-0 border-r-0 border-b-0 border-dashed border-base-300">
<div>
{app.state.crumbs ? (
<div className="pl-4">
<Breadcrumbs crumbs={app.state.crumbs.slice(0, 1)} />

View file

@ -1,4 +1,14 @@
blog: Blog
blogAbout: News and updates from the FreeSewing community
showcase: Showcase
showcaseAbout: Examples and inspiration from the FreeSewing community using our designs
docs: Documentation
docsAbout: In-depth documenation for all our designs, our website, and much more
account: Account
accountAbout: Manage your account settings and preferences, and your presonal data
designs: Designs
designsAbout: Our library of designs that you can turn into made-to-measure patterns with a few clicks
community: Community
communityAbout: More information about the peope behind FreeSewing and where to fine like-minded makers
mainSections: Main sections
currentSection: Current section

View file

@ -0,0 +1,11 @@
import { Popout } from 'shared/components/popout.mjs'
export const V3Wip = () => (
<Popout fixme>
<h5>This is not yet implemented</h5>
<p>
This is a work-in-progress to build a new FreeSewing.org website for version 3 of FreeSewing.
</p>
<p>This warning indicates that something that should be here is not yet implemented.</p>
</Popout>
)

View file

@ -85,7 +85,7 @@ export const PageWrapper = ({
<div
className={`fixed top-0 left-0 m-0 p-0 shadow drop-shadow-lg w-full h-screen
bg-base-100 bg-opacity-95 z-50 hover:cursor-pointer
flex flex-row items-center justify-center
flex flex-row justify-center overflow-auto
`}
onClick={() => app.updateState('modal', false)}
>

View file

@ -31,4 +31,16 @@
<div className="hover:bg-violet-400"></div>
<div className="hover:bg-purple-400"></div>
<!-- Colors for the header -->
<div className="bg-red-400"></div>
<div className="bg-orange-400"></div>
<div className="bg-yellow-400"></div>
<div className="bg-lime-400"></div>
<div className="bg-green-400"></div>
<div className="bg-cyan-400"></div>
<div className="bg-blue-400"></div>
<div className="bg-indigo-400"></div>
<div className="bg-violet-400"></div>
<div className="bg-purple-400"></div>