1
0
Fork 0

pattern and version pickers using headlessUI

This commit is contained in:
Enoch Riese 2022-07-01 18:41:07 -05:00
parent c1b53465cf
commit b65635c74c
6 changed files with 56 additions and 141 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) => {

View file

@ -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

View file

@ -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(() => {