wip(shared): Work on modal menu
This commit is contained in:
parent
aaef2a5b4a
commit
dbab735eeb
16 changed files with 327 additions and 32 deletions
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
|
|
22
sites/org/components/navigation/modal-menu.mjs
Normal file
22
sites/org/components/navigation/modal-menu.mjs
Normal 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>
|
||||
)
|
||||
}
|
44
sites/org/components/navigation/sections-menu.mjs
Normal file
44
sites/org/components/navigation/sections-menu.mjs
Normal 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>
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
|
|
35
sites/org/pages/blog/index.mjs
Normal file
35
sites/org/pages/blog/index.mjs
Normal 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'],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
35
sites/org/pages/community/index.mjs
Normal file
35
sites/org/pages/community/index.mjs
Normal 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'],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
35
sites/org/pages/designs/index.mjs
Normal file
35
sites/org/pages/designs/index.mjs
Normal 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'],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
35
sites/org/pages/showcase/index.mjs
Normal file
35
sites/org/pages/showcase/index.mjs
Normal 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'],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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)} />
|
||||
|
|
|
@ -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
|
||||
|
|
11
sites/shared/components/v3-wip.mjs
Normal file
11
sites/shared/components/v3-wip.mjs
Normal 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>
|
||||
)
|
|
@ -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)}
|
||||
>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue