pattern and version pickers using headlessUI
This commit is contained in:
parent
c1b53465cf
commit
b65635c74c
6 changed files with 56 additions and 141 deletions
|
@ -1,47 +1,44 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import DesignIcon from 'shared/components/icons/design.js'
|
import DesignIcon from 'shared/components/icons/design'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import {Picker, PickerLink} from 'shared/components/picker'
|
||||||
|
|
||||||
const PatternPicker = ({ app }) => {
|
const PatternPicker = ({ app }) => {
|
||||||
const { t } = useTranslation(['common'])
|
const { t } = useTranslation(['common'])
|
||||||
|
|
||||||
return (
|
const pickerProps = {
|
||||||
<div className="dropdown w-full md:w-auto">
|
Icon: DesignIcon,
|
||||||
<div tabIndex="0" className={`
|
title: t('designs'),
|
||||||
m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
className: 'overflow-y-scroll navdrop'
|
||||||
md:btn-ghost
|
}
|
||||||
hover:bg-neutral hover:border-neutral-content
|
|
||||||
`}>
|
return (<Picker {...pickerProps}>
|
||||||
<DesignIcon />
|
{Object.keys(app.navigation).map(section => {
|
||||||
<span>{t('designs')}</span>
|
const sectionProps = {
|
||||||
</div>
|
selectedItem: t(app.navigation[section].__title),
|
||||||
<ul tabIndex="0" className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52 overflow-y-scroll navdrop">
|
isStatic: true
|
||||||
{Object.keys(app.navigation).map(section => (
|
}
|
||||||
<React.Fragment key={section}>
|
const sectionTitle = t(app.navigation[section].__title);
|
||||||
<li className={`
|
{return (<React.Fragment key={section}>
|
||||||
capitalize font-bold text-base-content text-center
|
<li className={`
|
||||||
opacity-50 border-b2 my-2 border-base-content
|
capitalize font-bold text-base-content text-center
|
||||||
`}>
|
opacity-50 border-b2 my-2 border-base-content
|
||||||
{t(app.navigation[section].__title)}
|
`} {...sectionProps}>
|
||||||
</li>
|
{sectionTitle}
|
||||||
{Object.keys(app.navigation[section]).filter((p)=>!p.startsWith('__')).map(pattern => {
|
</li>
|
||||||
return (
|
{Object.keys(app.navigation[section]).filter((p)=>!p.startsWith('__')).map(pattern => {
|
||||||
<li key={pattern}>
|
const patternProps = {
|
||||||
<Link href={app.navigation[section][pattern].__slug}>
|
href: app.navigation[section][pattern].__slug,
|
||||||
<button className="btn btn-ghost">
|
key: pattern
|
||||||
<span className="text-base-content">
|
}
|
||||||
{app.navigation[section][pattern].__title}
|
|
||||||
</span>
|
return (<PickerLink {...patternProps} >
|
||||||
</button>
|
<span className="sr-only">{sectionTitle}</span> {app.navigation[section][pattern].__title}
|
||||||
</Link>
|
</PickerLink>)
|
||||||
</li>
|
})}
|
||||||
)})}
|
</React.Fragment>)}
|
||||||
</React.Fragment>
|
})}
|
||||||
))}
|
</Picker>)
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PatternPicker
|
export default PatternPicker
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import VersionsIcon from 'shared/components/icons/versions.js'
|
import VersionsIcon from 'shared/components/icons/versions.js'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import versions from 'site/versions.json'
|
import versions from 'site/versions.json'
|
||||||
import useVersion from 'site/hooks/useVersion.js'
|
import useVersion from 'site/hooks/useVersion.js'
|
||||||
|
import {Picker, PickerLink} from 'shared/components/picker'
|
||||||
|
|
||||||
export const defaultVersion = 'next'
|
export const defaultVersion = 'next'
|
||||||
|
|
||||||
|
@ -23,31 +23,16 @@ const PatternPicker = ({ app }) => {
|
||||||
const { t } = useTranslation(['common'])
|
const { t } = useTranslation(['common'])
|
||||||
const version = useVersion()
|
const version = useVersion()
|
||||||
|
|
||||||
return (
|
const pickerProps = {
|
||||||
<div className="dropdown w-full md:w-auto">
|
title: formatVersionTitle(version),
|
||||||
<div tabIndex="0" className={`
|
Icon: VersionsIcon
|
||||||
m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
}
|
||||||
md:btn-ghost
|
|
||||||
hover:bg-neutral hover:border-neutral-content
|
return (<Picker {...pickerProps}>
|
||||||
`}>
|
{[defaultVersion, ...versions].map(v => (
|
||||||
<VersionsIcon />
|
<PickerLink key={v} href={formatVersionUri(v)}>{formatVersionTitle(v)}</PickerLink>
|
||||||
<span>{formatVersionTitle(version)}</span>
|
))}
|
||||||
</div>
|
</Picker>)
|
||||||
<ul tabIndex="0" className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52 overflow-y-scroll navdrop">
|
|
||||||
{[defaultVersion, ...versions].map(v => (
|
|
||||||
<li key={v}>
|
|
||||||
<Link href={formatVersionUri(v)}>
|
|
||||||
<button className="btn btn-ghost">
|
|
||||||
<span className="text-base-content captialize">
|
|
||||||
{formatVersionTitle(v)}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PatternPicker
|
export default PatternPicker
|
||||||
|
|
|
@ -2,9 +2,7 @@ import themes from 'shared/themes/index.js'
|
||||||
import LocaleIcon from 'shared/components/icons/i18n.js'
|
import LocaleIcon from 'shared/components/icons/i18n.js'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Link from 'next/link'
|
import {Picker, PickerLink} from './picker';
|
||||||
import Picker, {PickerLink} from './picker';
|
|
||||||
import { Menu } from '@headlessui/react'
|
|
||||||
|
|
||||||
const LocalePicker = ({ app, iconOnly=false }) => {
|
const LocalePicker = ({ app, iconOnly=false }) => {
|
||||||
const { t } = useTranslation(['locales'])
|
const { t } = useTranslation(['locales'])
|
||||||
|
@ -13,7 +11,7 @@ const LocalePicker = ({ app, iconOnly=false }) => {
|
||||||
const pickerProps = {
|
const pickerProps = {
|
||||||
iconOnly,
|
iconOnly,
|
||||||
Icon: LocaleIcon,
|
Icon: LocaleIcon,
|
||||||
selectedItem: t(router.locale)
|
title: t(router.locale)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -28,34 +26,6 @@ const LocalePicker = ({ app, iconOnly=false }) => {
|
||||||
))}
|
))}
|
||||||
</Picker>
|
</Picker>
|
||||||
)
|
)
|
||||||
|
|
||||||
// return (
|
|
||||||
// <div className="dropdown dropdown-end w-auto">
|
|
||||||
// <div tabIndex="0" className={ iconOnly
|
|
||||||
// ? 'btn btn-sm'
|
|
||||||
// : `m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
|
||||||
// md:btn-ghost
|
|
||||||
// hover:bg-neutral hover:border-neutral-content
|
|
||||||
// `
|
|
||||||
// }>
|
|
||||||
// <LocaleIcon />
|
|
||||||
// {!iconOnly && <span>{t(router.locale)}</span>}
|
|
||||||
// </div>
|
|
||||||
// <ul tabIndex="0" className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52">
|
|
||||||
// {router.locales.map(locale => (
|
|
||||||
// <li key={locale}>
|
|
||||||
// <Link href={router.asPath} locale={locale}>
|
|
||||||
// <a className="btn btn-ghost text-base-content hover:bg-base-200">
|
|
||||||
// <span className="text-base-content">
|
|
||||||
// {t(locale)}
|
|
||||||
// </span>
|
|
||||||
// </a>
|
|
||||||
// </Link>
|
|
||||||
// </li>
|
|
||||||
// ))}
|
|
||||||
// </ul>
|
|
||||||
// </div>
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LocalePicker
|
export default LocalePicker
|
||||||
|
|
|
@ -2,9 +2,9 @@ import {useRef, forwardRef} from 'react'
|
||||||
import { Menu } from '@headlessui/react'
|
import { Menu } from '@headlessui/react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
const Picker = ({Icon, className, selectedItem, iconOnly=false, children}) => {
|
export const Picker = ({Icon, className, title, iconOnly=false, children, isStatic=false}) => {
|
||||||
|
|
||||||
return (<Menu as="div" className={`dropdown dropdown-end ${className} w-auto`}>
|
return (<Menu as="div" className={`dropdown dropdown-end w-auto`}>
|
||||||
<Menu.Button className={iconOnly
|
<Menu.Button className={iconOnly
|
||||||
? `btn btn-sm`
|
? `btn btn-sm`
|
||||||
: `m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
: `m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
||||||
|
@ -13,16 +13,14 @@ const Picker = ({Icon, className, selectedItem, iconOnly=false, children}) => {
|
||||||
`}
|
`}
|
||||||
aria-label="Choose Theme">
|
aria-label="Choose Theme">
|
||||||
<Icon />
|
<Icon />
|
||||||
{!iconOnly && <span>{selectedItem}</span>}
|
{!iconOnly && <span>{title}</span>}
|
||||||
</Menu.Button>
|
</Menu.Button>
|
||||||
<Menu.Items as="ul" className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52">
|
<Menu.Items as="ul" className={`p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52 ${className}`} static={isStatic}>
|
||||||
{children}
|
{children}
|
||||||
</Menu.Items>
|
</Menu.Items>
|
||||||
</Menu>)
|
</Menu>)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Picker
|
|
||||||
|
|
||||||
const itemClass = (active) => "btn btn-ghost " + (active ? 'bg-base-200' : '')
|
const itemClass = (active) => "btn btn-ghost " + (active ? 'bg-base-200' : '')
|
||||||
|
|
||||||
export const PickerLink = (props) => {
|
export const PickerLink = (props) => {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import themes from 'shared/themes/index.js'
|
import themes from 'shared/themes/index.js'
|
||||||
import ThemeIcon from 'shared/components/icons/theme.js'
|
import ThemeIcon from 'shared/components/icons/theme.js'
|
||||||
import {useRef} from 'react'
|
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
import Picker, {PickerButton} from './picker';
|
import {Picker, PickerButton} from './picker';
|
||||||
import { Menu } from '@headlessui/react'
|
import { Menu } from '@headlessui/react'
|
||||||
|
|
||||||
const ThemePicker = ({ app, className, iconOnly=false }) => {
|
const ThemePicker = ({ app, className, iconOnly=false }) => {
|
||||||
|
@ -17,7 +16,7 @@ const ThemePicker = ({ app, className, iconOnly=false }) => {
|
||||||
className,
|
className,
|
||||||
iconOnly,
|
iconOnly,
|
||||||
Icon: ThemeIcon,
|
Icon: ThemeIcon,
|
||||||
selectedItem: t(`${app.theme}Theme`)
|
title: t(`${app.theme}Theme`)
|
||||||
}
|
}
|
||||||
return (<Picker {...pickerProps}>
|
return (<Picker {...pickerProps}>
|
||||||
{Object.keys(themes).map(theme => (
|
{Object.keys(themes).map(theme => (
|
||||||
|
@ -27,41 +26,6 @@ const ThemePicker = ({ app, className, iconOnly=false }) => {
|
||||||
</PickerButton>
|
</PickerButton>
|
||||||
))}
|
))}
|
||||||
</Picker>)
|
</Picker>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// return (
|
|
||||||
// <div className={`dropdown dropdown-end ${className} w-auto`}>
|
|
||||||
// <div tabIndex="0" className={iconOnly
|
|
||||||
// ? `btn btn-sm`
|
|
||||||
// : `m-0 btn btn-neutral flex flex-row gap-2 btn-outline
|
|
||||||
// md:btn-ghost
|
|
||||||
// hover:bg-neutral hover:border-neutral-content
|
|
||||||
// `}
|
|
||||||
// >
|
|
||||||
// <ThemeIcon />
|
|
||||||
// {!iconOnly && <span>{t(`${app.theme}Theme`)}</span>}
|
|
||||||
// </div>
|
|
||||||
// <ul
|
|
||||||
// tabIndex="0"
|
|
||||||
// className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52"
|
|
||||||
// >
|
|
||||||
// {Object.keys(themes).map(theme => (
|
|
||||||
// <li key={theme}>
|
|
||||||
// <button
|
|
||||||
// onClick={() => app.setTheme(theme)}
|
|
||||||
// className="btn btn-ghost hover:bg-base-200"
|
|
||||||
// >
|
|
||||||
// <span className="text-base-content">
|
|
||||||
// {t(`${theme}Theme`)}
|
|
||||||
// </span>
|
|
||||||
// </button>
|
|
||||||
// </li>
|
|
||||||
// ))}
|
|
||||||
// </ul>
|
|
||||||
// </div>
|
|
||||||
// )
|
|
||||||
// return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ThemePicker
|
export default ThemePicker
|
||||||
|
|
|
@ -57,10 +57,11 @@ const WorkbenchWrapper = ({ app, design, preload=false, from=false, layout=false
|
||||||
// If we don't have the required measurements,
|
// If we don't have the required measurements,
|
||||||
// force view to measurements
|
// force view to measurements
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!gistReady) return
|
||||||
if (gistReady && gist._state?.view !== 'measurements'
|
if (gistReady && gist._state?.view !== 'measurements'
|
||||||
&& !hasRequiredMeasurements
|
&& !hasRequiredMeasurements
|
||||||
) updateGist(['_state', 'view'], 'measurements')
|
) updateGist(['_state', 'view'], 'measurements')
|
||||||
}, [gistReady, gist._state.view, hasRequiredMeasurements])
|
}, [gistReady, gist._state?.view, hasRequiredMeasurements])
|
||||||
|
|
||||||
// If we need to preload the gist, do so
|
// If we need to preload the gist, do so
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue