Remove playground (#1053)

* remove local testing playgrounds

* bump outdated packages
This commit is contained in:
Robin Malfait
2022-01-19 16:51:09 +01:00
committed by GitHub
parent 186a4cfcef
commit cae976a18b
64 changed files with 512 additions and 9106 deletions
+1 -4
View File
@@ -32,13 +32,10 @@
"trailingComma": "es5"
},
"devDependencies": {
"@tailwindcss/ui": "^0.6.2",
"@testing-library/jest-dom": "^5.11.9",
"@types/node": "^14.14.22",
"husky": "^4.3.8",
"lint-staged": "^10.5.3",
"prismjs": "^1.23.0",
"tailwindcss": "^1.9.6",
"lint-staged": "^12.2.1",
"tsdx": "^0.14.1",
"tslib": "^2.1.0",
"typescript": "^3.9.7"
-2
View File
@@ -1,2 +0,0 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
@@ -1,5 +0,0 @@
module.exports = {
devIndicators: {
autoPrerender: false,
},
}
+1 -6
View File
@@ -23,8 +23,6 @@
"access": "public"
},
"scripts": {
"playground": "next dev",
"playground:build": "next build",
"prepublishOnly": "npm run build",
"test": "../../scripts/test.sh",
"build": "../../scripts/build.sh",
@@ -35,12 +33,9 @@
"react-dom": "^16 || ^17 || ^18"
},
"devDependencies": {
"@testing-library/react": "^11.2.3",
"@types/react": "^16.14.2",
"@types/react-dom": "^16.9.10",
"@popperjs/core": "^2.6.0",
"@testing-library/react": "^11.2.3",
"framer-motion": "^2.9.5",
"next": "10.0.5",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"snapshot-diff": "^0.8.1"
-201
View File
@@ -1,201 +0,0 @@
import React, { useState, useEffect } from 'react'
import Link from 'next/link'
import Head from 'next/head'
import 'tailwindcss/tailwind.css'
import { useDisposables } from '../src/hooks/use-disposables'
import { PropsOf } from '../src/types'
function NextLink(props: PropsOf<'a'>) {
let { href, children, ...rest } = props
return (
<Link href={href}>
<a {...rest}>{children}</a>
</Link>
)
}
enum KeyDisplayMac {
ArrowUp = '↑',
ArrowDown = '↓',
ArrowLeft = '←',
ArrowRight = '→',
Home = '↖',
End = '↘',
Alt = '⌥',
CapsLock = '⇪',
Meta = '⌘',
Shift = '⇧',
Control = '⌃',
Backspace = '⌫',
Delete = '⌦',
Enter = '↵',
Escape = '⎋',
Tab = '↹',
PageUp = '⇞',
PageDown = '⇟',
' ' = '␣',
}
enum KeyDisplayWindows {
ArrowUp = '↑',
ArrowDown = '↓',
ArrowLeft = '←',
ArrowRight = '→',
Meta = 'Win',
Control = 'Ctrl',
Backspace = '⌫',
Delete = 'Del',
Escape = 'Esc',
PageUp = 'PgUp',
PageDown = 'PgDn',
' ' = '␣',
}
function tap<T>(value: T, cb: (value: T) => void) {
cb(value)
return value
}
function useKeyDisplay() {
let [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) return {}
let isMac = navigator.userAgent.indexOf('Mac OS X') !== -1
return isMac ? KeyDisplayMac : KeyDisplayWindows
}
function KeyCaster() {
let [keys, setKeys] = useState<string[]>([])
let d = useDisposables()
let KeyDisplay = useKeyDisplay()
useEffect(() => {
function handler(event: KeyboardEvent) {
setKeys(current => [
event.shiftKey && event.key !== 'Shift'
? KeyDisplay[`Shift${event.key}`] ?? event.key
: KeyDisplay[event.key] ?? event.key,
...current,
])
d.setTimeout(() => setKeys(current => tap(current.slice(), clone => clone.pop())), 2000)
}
window.addEventListener('keydown', handler, true)
return () => window.removeEventListener('keydown', handler, true)
}, [d, KeyDisplay])
if (keys.length <= 0) return null
return (
<div className="fixed z-50 px-4 py-2 overflow-hidden text-2xl tracking-wide text-blue-100 bg-blue-800 rounded-md shadow cursor-default pointer-events-none select-none right-4 bottom-4">
{keys
.slice()
.reverse()
.join(' ')}
</div>
)
}
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="https://headlessui.dev/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="https://headlessui.dev/favicon-16x16.png"
/>
</Head>
<div className="flex flex-col h-screen overflow-hidden font-sans antialiased text-gray-900 bg-gray-700">
<header className="relative z-10 flex items-center justify-between flex-shrink-0 px-4 py-4 bg-gray-700 border-b border-gray-200 sm:px-6 lg:px-8">
<NextLink href="/">
<Logo className="h-6" />
</NextLink>
</header>
<KeyCaster />
<main className="flex-1 overflow-auto bg-gray-50">
<Component {...pageProps} />
</main>
</div>
</>
)
}
function Logo({ className }) {
return (
<svg className={className} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 243 42">
<path
fill="#fff"
d="M65.74 13.663c-2.62 0-4.702.958-5.974 2.95V6.499h-4.163V33.32h4.163V23.051c0-3.908 2.159-5.518 4.896-5.518 2.62 0 4.317 1.533 4.317 4.445V33.32h4.162V21.557c0-4.982-3.083-7.894-7.4-7.894zM79.936 25.503h15.341c.077-.536.154-1.15.154-1.724 0-5.518-3.931-10.116-9.674-10.116-6.052 0-10.176 4.407-10.176 10.078 0 5.748 4.124 10.078 10.484 10.078 3.778 0 6.668-1.572 8.441-4.177l-3.43-1.993c-.925 1.341-2.66 2.376-4.972 2.376-3.084 0-5.512-1.533-6.168-4.521zm-.038-3.372c.578-2.873 2.698-4.713 5.82-4.713 2.506 0 4.934 1.418 5.512 4.713H79.898zM113.282 14.161v2.72c-1.465-1.992-3.739-3.218-6.746-3.218-5.242 0-9.597 4.368-9.597 10.078 0 5.67 4.355 10.078 9.597 10.078 3.007 0 5.281-1.227 6.746-3.258v2.76h4.162V14.16h-4.162zm-6.09 15.71c-3.469 0-6.091-2.567-6.091-6.13 0-3.564 2.622-6.131 6.091-6.131 3.469 0 6.09 2.567 6.09 6.13 0 3.564-2.621 6.132-6.09 6.132zM136.597 6.498v10.384c-1.465-1.993-3.739-3.219-6.746-3.219-5.242 0-9.597 4.368-9.597 10.078 0 5.67 4.355 10.078 9.597 10.078 3.007 0 5.281-1.227 6.746-3.258v2.76h4.163V6.497h-4.163zm-6.09 23.374c-3.469 0-6.09-2.568-6.09-6.131 0-3.564 2.621-6.131 6.09-6.131s6.09 2.567 6.09 6.13c0 3.564-2.621 6.132-6.09 6.132zM144.648 33.32h4.163V5.348h-4.163V33.32zM155.957 25.503h15.341c.077-.536.154-1.15.154-1.724 0-5.518-3.931-10.116-9.675-10.116-6.051 0-10.176 4.407-10.176 10.078 0 5.748 4.125 10.078 10.485 10.078 3.777 0 6.668-1.572 8.441-4.177l-3.43-1.993c-.926 1.341-2.66 2.376-4.973 2.376-3.083 0-5.512-1.533-6.167-4.521zm-.038-3.372c.578-2.873 2.698-4.713 5.82-4.713 2.505 0 4.934 1.418 5.512 4.713h-11.332zM177.137 19.45c0-1.38 1.311-2.032 2.814-2.032 1.581 0 2.93.69 3.623 2.184l3.508-1.954c-1.349-2.529-3.97-3.985-7.131-3.985-3.931 0-7.053 2.26-7.053 5.863 0 6.859 10.368 4.943 10.368 8.353 0 1.533-1.426 2.146-3.276 2.146-2.12 0-3.662-1.035-4.279-2.759l-3.584 2.07c1.233 2.758 4.008 4.483 7.863 4.483 4.163 0 7.516-2.07 7.516-5.902 0-7.088-10.369-4.98-10.369-8.468zM192.774 19.45c0-1.38 1.31-2.032 2.813-2.032 1.581 0 2.93.69 3.624 2.184l3.507-1.954c-1.349-2.529-3.97-3.985-7.131-3.985-3.931 0-7.053 2.26-7.053 5.863 0 6.859 10.368 4.943 10.368 8.353 0 1.533-1.426 2.146-3.276 2.146-2.12 0-3.662-1.035-4.278-2.759l-3.585 2.07c1.233 2.758 4.009 4.483 7.863 4.483 4.163 0 7.516-2.07 7.516-5.902 0-7.088-10.368-4.98-10.368-8.468zM224.523 28.9c2.889 0 5.027-1.715 5.027-4.53v-8.782h-2.588v8.577c0 1.268-.676 2.219-2.439 2.219s-2.438-.951-2.438-2.22v-8.576h-2.569v8.782c0 2.815 2.138 4.53 5.007 4.53zM232.257 15.588V28.64h2.588V15.588h-2.588z"
/>
<path
fill="#fff"
fillRule="evenodd"
d="M233.817 9.328H220.42c-2.96 0-5.359 2.385-5.359 5.327v13.318c0 2.942 2.399 5.327 5.359 5.327h13.397c2.959 0 5.358-2.385 5.358-5.327V14.655c0-2.942-2.399-5.327-5.358-5.327zM220.42 6.664c-4.439 0-8.038 3.578-8.038 7.99v13.319c0 4.413 3.599 7.99 8.038 7.99h13.397c4.439 0 8.038-3.577 8.038-7.99V14.655c0-4.413-3.599-7.99-8.038-7.99H220.42z"
clipRule="evenodd"
/>
<path
fill="#fff"
fillRule="evenodd"
d="M220.42 9.328h13.397c2.959 0 5.358 2.385 5.358 5.327v13.318c0 2.942-2.399 5.327-5.358 5.327H220.42c-2.96 0-5.359-2.385-5.359-5.327V14.655c0-2.942 2.399-5.327 5.359-5.327zm-8.038 5.327c0-4.413 3.599-7.99 8.038-7.99h13.397c4.439 0 8.038 3.577 8.038 7.99v13.318c0 4.413-3.599 7.99-8.038 7.99H220.42c-4.439 0-8.038-3.577-8.038-7.99V14.655z"
clipRule="evenodd"
/>
<path
fill="url(#prefix__paint0_linear)"
d="M8.577 26.097l25.779-8.556c-.514-3.201-.88-5.342-1.307-6.974-.457-1.756-.821-2.226-.965-2.39a5.026 5.026 0 00-1.81-1.306c-.2-.086-.762-.284-2.583-.175-1.924.116-4.453.507-8.455 1.137-4.003.63-6.529 1.035-8.395 1.516-1.766.456-2.239.817-2.403.96a4.999 4.999 0 00-1.315 1.8c-.085.198-.285.757-.175 2.568.116 1.913.51 4.426 1.143 8.405.178 1.114.337 2.113.486 3.015z"
/>
<path
fill="url(#prefix__paint1_linear)"
fillRule="evenodd"
d="M1.47 24.124C.244 16.427-.37 12.58.96 9.49A11.665 11.665 0 014.027 5.29c2.545-2.21 6.416-2.82 14.16-4.039C25.93.031 29.8-.578 32.907.743a11.729 11.729 0 014.225 3.05c2.223 2.53 2.836 6.38 4.063 14.076 1.226 7.698 1.84 11.546.511 14.636a11.666 11.666 0 01-3.069 4.199c-2.545 2.21-6.416 2.82-14.159 4.039-7.743 1.219-11.614 1.828-14.722.508a11.728 11.728 0 01-4.224-3.05C3.31 35.67 2.697 31.82 1.47 24.123zm13.657 13.668c2.074-.125 4.743-.54 8.697-1.163 3.953-.622 6.62-1.047 8.632-1.566 1.949-.502 2.846-.992 3.426-1.496a7.5 7.5 0 001.973-2.7c.302-.703.494-1.703.372-3.7-.125-2.063-.543-4.716-1.17-8.646-.625-3.93-1.053-6.582-1.574-8.582-.506-1.937-.999-2.83-1.505-3.405a7.54 7.54 0 00-2.716-1.961c-.707-.301-1.713-.492-3.723-.371-2.074.125-4.743.54-8.697 1.163-3.953.622-6.62 1.047-8.632 1.565-1.949.503-2.846.993-3.426 1.497a7.5 7.5 0 00-1.972 2.699c-.303.704-.495 1.704-.373 3.701.125 2.062.543 4.716 1.17 8.646.625 3.93 1.053 6.582 1.574 8.581.506 1.938 1 2.83 1.505 3.406a7.54 7.54 0 002.716 1.961c.707.3 1.713.492 3.723.37z"
clipRule="evenodd"
/>
<defs>
<linearGradient
id="prefix__paint0_linear"
x1="16.759"
x2="23.386"
y1="0"
y2="41.662"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#66E3FF" />
<stop offset="1" stopColor="#7064F9" />
</linearGradient>
<linearGradient
id="prefix__paint1_linear"
x1="16.759"
x2="23.386"
y1="0"
y2="41.662"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#66E3FF" />
<stop offset="1" stopColor="#7064F9" />
</linearGradient>
</defs>
</svg>
)
}
export default MyApp
@@ -1,64 +0,0 @@
import React from 'react'
import ErrorPage from 'next/error'
import Head from 'next/head'
import Link from 'next/link'
import { ExamplesType, resolveAllExamples } from '../playground-utils/resolve-all-examples'
import { PropsOf } from '../src/types'
function NextLink(props: PropsOf<'a'>) {
let { href, children, ...rest } = props
return (
<Link href={href}>
<a {...rest}>{children}</a>
</Link>
)
}
export async function getStaticProps() {
return {
props: {
examples: await resolveAllExamples('pages'),
},
}
}
export default function Page(props: { examples: false | ExamplesType[] }) {
if (props.examples === false) {
return <ErrorPage statusCode={404} />
}
return (
<>
<Head>
<title>Examples</title>
</Head>
<div className="container my-24">
<div className="prose">
<h2>Examples</h2>
<Examples examples={props.examples} />
</div>
</div>
</>
)
}
export function Examples(props: { examples: ExamplesType[] }) {
return (
<ul>
{props.examples.map(example => (
<li key={example.path}>
{example.children ? (
<h3 className="text-xl capitalize">{example.name}</h3>
) : (
<NextLink href={example.path} className="capitalize">
{example.name}
</NextLink>
)}
{example.children && <Examples examples={example.children} />}
</li>
))}
</ul>
)
}
@@ -1,241 +0,0 @@
import React, { useState, Fragment } from 'react'
import { Dialog, Menu, Portal, Transition } from '@headlessui/react'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
function resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
}
function Nested({ onClose, level = 0 }) {
let [showChild, setShowChild] = useState(false)
return (
<>
<Dialog open={true} onClose={onClose} className="fixed z-10 inset-0">
<Dialog.Overlay className="fixed inset-0 bg-gray-500 opacity-25" />
<div
className="z-10 fixed left-12 top-24 bg-white w-96 p-4"
style={{
transform: `translate(calc(50px * ${level}), calc(50px * ${level}))`,
}}
>
<p>Level: {level}</p>
<div className="space-x-4">
<button className="bg-gray-200 px-2 py-1 rounded" onClick={() => setShowChild(true)}>
Open (1)
</button>
<button className="bg-gray-200 px-2 py-1 rounded" onClick={() => setShowChild(true)}>
Open (2)
</button>
<button className="bg-gray-200 px-2 py-1 rounded" onClick={() => setShowChild(true)}>
Open (3)
</button>
</div>
</div>
{showChild && <Nested onClose={() => setShowChild(false)} level={level + 1} />}
</Dialog>
</>
)
}
export default function Home() {
let [isOpen, setIsOpen] = useState(false)
let [nested, setNested] = useState(false)
let [trigger, container] = usePopper({
placement: 'bottom-end',
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 10] } }],
})
return (
<>
<button
type="button"
onClick={() => setIsOpen(v => !v)}
className="m-12 px-4 py-2 text-base font-medium leading-6 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue sm:text-sm sm:leading-5"
>
Toggle!
</button>
<button onClick={() => setNested(true)}>Show nested</button>
{nested && <Nested onClose={() => setNested(false)} />}
<Transition show={isOpen} as={Fragment} afterLeave={() => console.log('done')}>
<Dialog onClose={setIsOpen}>
<div className="fixed z-10 inset-0 overflow-y-auto">
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-75"
leave="ease-in duration-200"
leaveFrom="opacity-75"
leaveTo="opacity-0"
entered="opacity-75"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 transition-opacity" />
</Transition.Child>
<Transition.Child
enter="ease-out transform duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in transform duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
{/* This element is to trick the browser into centering the modal contents. */}
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
{/* Heroicon name: exclamation */}
<svg
className="h-6 w-6 text-red-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg leading-6 font-medium text-gray-900"
>
Deactivate account
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-gray-500">
Are you sure you want to deactivate your account? All of your data will
be permanently removed. This action cannot be undone.
</p>
<div className="relative inline-block text-left mt-10">
<Menu>
<span className="rounded-md shadow-sm">
<Menu.Button
ref={trigger}
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Choose a reason</span>
<svg
className="w-5 h-5 ml-2 -mr-1"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<Transition
enter="transition duration-300 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Portal>
<Menu.Items
ref={container}
className="z-20 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div className="py-1">
<Menu.Item
as="a"
href="#account-settings"
className={resolveClass}
>
Account settings
</Menu.Item>
<Menu.Item as="a" href="#support" className={resolveClass}>
Support
</Menu.Item>
<Menu.Item
as="a"
disabled
href="#new-feature"
className={resolveClass}
>
New feature (soon)
</Menu.Item>
<Menu.Item as="a" href="#license" className={resolveClass}>
License
</Menu.Item>
</div>
<div className="py-1">
<Menu.Item as="a" href="#sign-out" className={resolveClass}>
Sign out
</Menu.Item>
</div>
</Menu.Items>
</Portal>
</Transition>
</Menu>
</div>
</div>
</div>
</div>
</div>
<div className="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
onClick={() => setIsOpen(false)}
className="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:shadow-outline-red sm:ml-3 sm:w-auto sm:text-sm"
>
Deactivate
</button>
<button
type="button"
onClick={() => setIsOpen(false)}
className="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:shadow-outline-indigo sm:mt-0 sm:w-auto sm:text-sm"
>
Cancel
</button>
</div>
</div>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
</>
)
}
@@ -1,25 +0,0 @@
import React from 'react'
import { Disclosure, Transition } from '@headlessui/react'
export default function Home() {
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="w-full max-w-xs mx-auto">
<Disclosure>
<Disclosure.Button>Trigger</Disclosure.Button>
<Transition
enter="transition duration-1000 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-1000 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Disclosure.Panel className="p-4 bg-white mt-4">Content</Disclosure.Panel>
</Transition>
</Disclosure>
</div>
</div>
)
}
@@ -1,115 +0,0 @@
import React, { useState, useEffect } from 'react'
import { Listbox } from '@headlessui/react'
import { classNames } from '../../src/utils/class-names'
let people = [
'Wade Cooper',
'Arlene Mccoy',
'Devon Webb',
'Tom Cook',
'Tanya Fox',
'Hellen Schmidt',
'Caroline Schultz',
'Mason Heaney',
'Claudie Smitham',
'Emil Schaefer',
]
export default function Home() {
let [active, setActivePerson] = useState(people[2])
// Choose a random person on mount
useEffect(() => {
setActivePerson(people[Math.floor(Math.random() * people.length)])
}, [])
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="w-full max-w-xs mx-auto">
<div className="space-y-1">
<Listbox
value={active}
onChange={value => {
console.log('value:', value)
setActivePerson(value)
}}
>
<Listbox.Label className="block text-sm font-medium leading-5 text-gray-700">
Assigned to
</Listbox.Label>
<div className="relative">
<span className="inline-block w-full rounded-md shadow-sm">
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md cursor-default focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5">
<span className="block truncate">{active}</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
className="w-5 h-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</Listbox.Button>
</span>
<div className="absolute w-full mt-1 bg-white rounded-md shadow-lg">
<Listbox.Options className="py-1 overflow-auto text-base leading-6 rounded-md shadow-xs max-h-60 focus:outline-none sm:text-sm sm:leading-5">
{people.map(name => (
<Listbox.Option
key={name}
value={name}
className={({ active }) => {
return classNames(
'relative py-2 pl-3 cursor-default select-none pr-9 focus:outline-none',
active ? 'text-white bg-indigo-600' : 'text-gray-900'
)
}}
>
{({ active, selected }) => (
<>
<span
className={classNames(
'block truncate',
selected ? 'font-semibold' : 'font-normal'
)}
>
{name}
</span>
{selected && (
<span
className={classNames(
'absolute inset-y-0 right-0 flex items-center pr-4',
active ? 'text-white' : 'text-indigo-600'
)}
>
<svg className="w-5 h-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
)}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</div>
</div>
</Listbox>
</div>
</div>
</div>
)
}
@@ -1,137 +0,0 @@
import React, { useState, useEffect } from 'react'
import { Listbox } from '@headlessui/react'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
let people = [
'Wade Cooper',
'Arlene Mccoy',
'Devon Webb',
'Tom Cook',
'Tanya Fox',
'Hellen Schmidt',
'Caroline Schultz',
'Mason Heaney',
'Claudie Smitham',
'Emil Schaefer',
]
export default function Home() {
return (
<div className="flex justify-center w-screen h-full p-12 space-x-4 bg-gray-50">
<PeopleList />
<div>
<label htmlFor="email" className="block text-sm font-medium leading-5 text-gray-700">
Email
</label>
<div className="relative mt-1 rounded-md shadow-sm">
<input
className="block w-full form-input sm:text-sm sm:leading-5"
placeholder="you@example.com"
/>
</div>
</div>
<PeopleList />
</div>
)
}
function PeopleList() {
let [active, setActivePerson] = useState(people[2])
// Choose a random person on mount
useEffect(() => {
setActivePerson(people[Math.floor(Math.random() * people.length)])
}, [])
return (
<div className="w-64">
<div className="space-y-1">
<Listbox
value={active}
onChange={value => {
console.log('value:', value)
setActivePerson(value)
}}
>
<Listbox.Label className="block text-sm font-medium leading-5 text-gray-700">
Assigned to
</Listbox.Label>
<div className="relative">
<span className="inline-block w-full rounded-md shadow-sm">
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md cursor-default focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5">
<span className="block truncate">{active}</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
className="w-5 h-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</Listbox.Button>
</span>
<div className="absolute w-full mt-1 bg-white rounded-md shadow-lg">
<Listbox.Options className="py-1 overflow-auto text-base leading-6 rounded-md shadow-xs max-h-60 focus:outline-none sm:text-sm sm:leading-5">
{people.map(name => (
<Listbox.Option
key={name}
value={name}
className={({ active }) => {
return classNames(
'relative py-2 pl-3 cursor-default select-none pr-9 focus:outline-none',
active ? 'text-white bg-indigo-600' : 'text-gray-900'
)
}}
>
{({ active, selected }) => (
<>
<span
className={classNames(
'block truncate',
selected ? 'font-semibold' : 'font-normal'
)}
>
{name}
</span>
{selected && (
<span
className={classNames(
'absolute inset-y-0 right-0 flex items-center pr-4',
active ? 'text-white' : 'text-indigo-600'
)}
>
<svg className="w-5 h-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
)}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</div>
</div>
</Listbox>
</div>
</div>
)
}
@@ -1,112 +0,0 @@
import React from 'react'
import Link from 'next/link'
import { AnimatePresence, motion } from 'framer-motion'
import { Menu } from '../../src/components/menu/menu'
import { classNames } from '../../src/utils/class-names'
import { PropsOf } from '../../src/types'
export default function Home() {
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="relative inline-block text-left">
<Menu>
{({ open }) => (
<>
<span className="rounded-md shadow-sm">
<Menu.Button className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
<span>Options</span>
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<AnimatePresence>
{open && (
<Menu.Items
static
as={motion.div}
initial={{ opacity: 0, y: 0 }}
animate={{ opacity: 1, y: '0.5rem' }}
exit={{ opacity: 0, y: 0 }}
className="absolute right-0 w-56 bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none opacity-0"
>
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div className="py-1">
<Item href="#account-settings">Account settings</Item>
<Item as={NextLink} href="#support">
Support
</Item>
<Item href="#new-feature" disabled>
New feature (soon)
</Item>
<Item href="#license">License</Item>
</div>
<div className="py-1">
<Item as={SignOutButton} />
</div>
</Menu.Items>
)}
</AnimatePresence>
</>
)}
</Menu>
</div>
</div>
)
}
function NextLink(props: PropsOf<'a'>) {
let { href, children, ...rest } = props
return (
<Link href={href}>
<a {...rest}>{children}</a>
</Link>
)
}
function SignOutButton(props) {
return (
<form
method="POST"
action="#"
onSubmit={e => {
e.preventDefault()
alert('SIGNED OUT')
}}
className="w-full"
>
<button type="submit" {...props}>
Sign out
</button>
</form>
)
}
function Item(props: PropsOf<typeof Menu.Item>) {
return (
<Menu.Item
as="a"
className={({ active, disabled }) =>
classNames(
'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700',
active && 'bg-gray-100 text-gray-900',
disabled && 'cursor-not-allowed opacity-50'
)
}
{...props}
/>
)
}
@@ -1,98 +0,0 @@
import React, { ReactNode, useState, useEffect } from 'react'
import { createPortal } from 'react-dom'
import { Menu } from '@headlessui/react'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Home() {
let [trigger, container] = usePopper({
placement: 'bottom-end',
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 10] } }],
})
function resolveClass({ active, disabled }) {
return classNames(
'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700',
active && 'bg-gray-100 text-gray-900',
disabled && 'cursor-not-allowed opacity-50'
)
}
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="inline-block mt-64 text-left">
<Menu>
<span className="inline-flex rounded-md shadow-sm">
<Menu.Button
ref={trigger}
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<Portal>
<Menu.Items
className="w-56 bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
ref={container}
>
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div className="py-1">
<Menu.Item as="a" href="#account-settings" className={resolveClass}>
Account settings
</Menu.Item>
<Menu.Item>
{data => (
<a href="#support" className={resolveClass(data)}>
Support
</a>
)}
</Menu.Item>
<Menu.Item as="a" disabled href="#new-feature" className={resolveClass}>
New feature (soon)
</Menu.Item>
<Menu.Item as="a" href="#license" className={resolveClass}>
License
</Menu.Item>
</div>
<div className="py-1">
<Menu.Item as="a" href="#sign-out" className={resolveClass}>
Sign out
</Menu.Item>
</div>
</Menu.Items>
</Portal>
</Menu>
</div>
</div>
)
}
function Portal(props: { children: ReactNode }) {
let { children } = props
let [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return null
return createPortal(children, document.body)
}
@@ -1,92 +0,0 @@
import React from 'react'
import { Menu, Transition } from '@headlessui/react'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Home() {
let [trigger, container] = usePopper({
placement: 'bottom-end',
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 10] } }],
})
function resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
}
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="inline-block mt-64 text-left">
<Menu>
<span className="rounded-md shadow-sm">
<Menu.Button
ref={trigger}
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<div ref={container} className="w-56">
<Transition
enter="transition duration-100 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Menu.Items className="bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none">
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div className="py-1">
<Menu.Item as="a" href="#account-settings" className={resolveClass}>
Account settings
</Menu.Item>
<Menu.Item>
{data => (
<a href="#support" className={resolveClass(data)}>
Support
</a>
)}
</Menu.Item>
<Menu.Item as="a" disabled href="#new-feature" className={resolveClass}>
New feature (soon)
</Menu.Item>
<Menu.Item as="a" href="#license" className={resolveClass}>
License
</Menu.Item>
</div>
<div className="py-1">
<Menu.Item as="a" href="#sign-out" className={resolveClass}>
Sign out
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</div>
</Menu>
</div>
</div>
)
}
@@ -1,76 +0,0 @@
import React from 'react'
import { Menu, Transition } from '@headlessui/react'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Home() {
function resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
}
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="relative inline-block text-left">
<Menu>
<span className="rounded-md shadow-sm">
<Menu.Button className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
<span>Options</span>
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<Transition
enter="transition duration-1000 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-1000 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Menu.Items className="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none">
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div className="py-1">
<Menu.Item as="a" href="#account-settings" className={resolveClass}>
Account settings
</Menu.Item>
<Menu.Item as="a" href="#support" className={resolveClass}>
Support
</Menu.Item>
<Menu.Item as="a" disabled href="#new-feature" className={resolveClass}>
New feature (soon)
</Menu.Item>
<Menu.Item as="a" href="#license" className={resolveClass}>
License
</Menu.Item>
</div>
<div className="py-1">
<Menu.Item as="a" href="#sign-out" className={resolveClass}>
Sign out
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
</div>
)
}
@@ -1,76 +0,0 @@
import React from 'react'
import { Menu } from '@headlessui/react'
import { PropsOf } from '../../src/types'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Home() {
return (
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="relative inline-block text-left">
<Menu>
<span className="rounded-md shadow-sm">
<Menu.Button className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
<span>Options</span>
<svg
className="w-5 h-5 ml-2 -mr-1 transition-transform duration-150"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<Menu.Items className="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none">
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div className="py-1">
<CustomMenuItem href="#account-settings">Account settings</CustomMenuItem>
<CustomMenuItem href="#support">Support</CustomMenuItem>
<CustomMenuItem disabled href="#new-feature">
New feature (soon)
</CustomMenuItem>
<CustomMenuItem href="#license">License</CustomMenuItem>
</div>
<div className="py-1">
<CustomMenuItem href="#sign-out">Sign out</CustomMenuItem>
</div>
</Menu.Items>
</Menu>
</div>
</div>
)
}
function CustomMenuItem(props: PropsOf<typeof Menu.Item>) {
return (
<Menu.Item {...props}>
{({ active, disabled }) => (
<a
href={props.href}
className={classNames(
'flex justify-between w-full text-left px-4 py-2 text-sm leading-5',
active ? 'bg-indigo-500 text-white' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)}
>
<span className={classNames(active && 'font-bold')}>{props.children}</span>
<kbd className={classNames('font-sans', active && 'text-indigo-50')}>K</kbd>
</a>
)}
</Menu.Item>
)
}
@@ -1,86 +0,0 @@
import React from 'react'
import { Menu } from '@headlessui/react'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default function Home() {
return (
<div className="flex justify-center w-screen h-full p-12 space-x-4 bg-gray-50">
<Dropdown />
<div>
<div className="relative rounded-md shadow-sm">
<input
className="block w-full form-input sm:text-sm sm:leading-5"
placeholder="you@example.com"
/>
</div>
</div>
<Dropdown />
</div>
)
}
function Dropdown() {
function resolveClass({ active, disabled }) {
return classNames(
'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700',
active && 'bg-gray-100 text-gray-900',
disabled && 'cursor-not-allowed opacity-50'
)
}
return (
<div className="relative inline-block text-left">
<Menu>
<span className="inline-flex rounded-md shadow-sm">
<Menu.Button className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
<span>Options</span>
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</Menu.Button>
</span>
<Menu.Items className="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none">
<div className="px-4 py-3">
<p className="text-sm leading-5">Signed in as</p>
<p className="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div className="py-1">
<Menu.Item as="a" href="#account-settings" className={resolveClass}>
Account settings
</Menu.Item>
<Menu.Item>
{data => (
<a href="#support" className={resolveClass(data)}>
Support
</a>
)}
</Menu.Item>
<Menu.Item as="a" disabled href="#new-feature" className={resolveClass}>
New feature (soon)
</Menu.Item>
<Menu.Item as="a" href="#license" className={resolveClass}>
License
</Menu.Item>
</div>
<div className="py-1">
<Menu.Item as="a" href="#sign-out" className={resolveClass}>
Sign out
</Menu.Item>
</div>
</Menu.Items>
</Menu>
</div>
)
}
@@ -1,115 +0,0 @@
import React, { forwardRef, Fragment } from 'react'
import { Popover, Portal, Transition } from '@headlessui/react'
import { usePopper } from '../../playground-utils/hooks/use-popper'
import { PropsOf as Props } from '../../src/types'
let Button = forwardRef((props: Props<'button'>, ref) => {
return (
<Popover.Button
ref={ref}
className="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900"
{...props}
/>
)
})
function Link(props: Props<'a'>) {
return (
<a
href="/"
className="px-3 py-2 border-2 border-transparent hover:bg-gray-200 focus:bg-gray-200 focus:outline-none focus:border-blue-900"
{...props}
>
{props.children}
</a>
)
}
export default function Home() {
let options = {
placement: 'bottom-start',
strategy: 'fixed',
modifiers: [],
}
let [reference1, popper1] = usePopper(options)
let [reference2, popper2] = usePopper(options)
let links = ['First', 'Second', 'Third', 'Fourth']
return (
<div className="flex justify-center items-center space-x-12 p-12">
<button>Previous</button>
<Popover.Group as="nav" aria-label="Mythical University" className="flex space-x-3">
<Popover as="div" className="relative">
<Transition
as={Fragment}
enter="transition ease-out duration-300 transform"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition ease-in duration-300 transform"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Overlay className="bg-opacity-75 bg-gray-500 fixed inset-0 z-20"></Popover.Overlay>
</Transition>
<Popover.Button className="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900 relative z-30">
Normal
</Popover.Button>
<Popover.Panel className="absolute flex flex-col w-64 bg-gray-100 border-2 border-blue-900 z-30">
{links.map((link, i) => (
<Link key={link} hidden={i === 2}>
Normal - {link}
</Link>
))}
</Popover.Panel>
</Popover>
<Popover as="div" className="relative">
<Button>Focus</Button>
<Popover.Panel
focus
className="absolute flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
{links.map((link, i) => (
<Link key={link}>Focus - {link}</Link>
))}
</Popover.Panel>
</Popover>
<Popover as="div" className="relative">
<Button ref={reference1}>Portal</Button>
<Portal>
<Popover.Panel
ref={popper1}
className="flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
{links.map(link => (
<Link key={link}>Portal - {link}</Link>
))}
</Popover.Panel>
</Portal>
</Popover>
<Popover as="div" className="relative">
<Button ref={reference2}>Focus in Portal</Button>
<Portal>
<Popover.Panel
ref={popper2}
focus
className="flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
{links.map(link => (
<Link key={link}>Focus in Portal - {link}</Link>
))}
</Popover.Panel>
</Portal>
</Popover>
</Popover.Group>
<button>Next</button>
</div>
)
}
@@ -1,101 +0,0 @@
import React, { useState } from 'react'
import { RadioGroup } from '@headlessui/react'
import { classNames } from '../../src/utils/class-names'
export default function Home() {
let access = [
{
id: 'access-1',
name: 'Public access',
description: 'This project would be available to anyone who has the link',
},
{
id: 'access-2',
name: 'Private to Project Members',
description: 'Only members of this project would be able to access',
},
{
id: 'access-3',
name: 'Private to you',
description: 'You are the only one able to access this project',
},
]
let [active, setActive] = useState()
return (
<div className="p-12 max-w-xl">
<a href="/">Link before</a>
<RadioGroup value={active} onChange={setActive}>
<fieldset className="space-y-4">
<legend>
<h2 className="text-xl">Privacy setting</h2>
</legend>
<div className="bg-white rounded-md -space-y-px">
{access.map(({ id, name, description }, i) => {
return (
<RadioGroup.Option
key={id}
value={id}
className={({ active }) =>
classNames(
// Rounded corners
i === 0 && 'rounded-tl-md rounded-tr-md',
access.length - 1 === i && 'rounded-bl-md rounded-br-md',
// Shared
'relative border p-4 flex focus:outline-none',
active ? 'bg-indigo-50 border-indigo-200 z-10' : 'border-gray-200'
)
}
>
{({ active, checked }) => (
<div className="flex justify-between items-center w-full">
<div className="ml-3 flex flex-col cursor-pointer">
<span
className={classNames(
'block text-sm leading-5 font-medium',
active ? 'text-indigo-900' : 'text-gray-900'
)}
>
{name}
</span>
<span
className={classNames(
'block text-sm leading-5',
active ? 'text-indigo-700' : 'text-gray-500'
)}
>
{description}
</span>
</div>
<div>
{checked && (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
className="h-5 w-5 text-indigo-500"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
)}
</div>
</div>
)}
</RadioGroup.Option>
)
})}
</div>
</fieldset>
</RadioGroup>
<a href="/">Link after</a>
</div>
)
}
@@ -1,39 +0,0 @@
import React, { useState } from 'react'
import { Switch } from '@headlessui/react'
import { classNames } from '../../src/utils/class-names'
export default function Home() {
let [state, setState] = useState(false)
return (
<div className="flex items-start justify-center w-screen h-full p-12 bg-gray-50">
<Switch.Group as="div" className="flex items-center space-x-4">
<Switch.Label>Enable notifications</Switch.Label>
<Switch
as="button"
checked={state}
onChange={setState}
className={({ checked }) =>
classNames(
'relative inline-flex flex-shrink-0 h-6 border-2 border-transparent rounded-full cursor-pointer w-11 focus:outline-none focus:shadow-outline transition-colors ease-in-out duration-200',
checked ? 'bg-indigo-600' : 'bg-gray-200'
)
}
>
{({ checked }) => (
<>
<span
className={classNames(
'inline-block w-5 h-5 bg-white rounded-full transform transition ease-in-out duration-200',
checked ? 'translate-x-5' : 'translate-x-0'
)}
/>
</>
)}
</Switch>
</Switch.Group>
</div>
)
}
@@ -1,86 +0,0 @@
import React, { useState } from 'react'
import { Tab, Switch } from '@headlessui/react'
import { classNames } from '../../src/utils/class-names'
export default function Home() {
let tabs = [
{ name: 'My Account', content: 'Tab content for my account' },
{ name: 'Company', content: 'Tab content for company', disabled: true },
{ name: 'Team Members', content: 'Tab content for team members' },
{ name: 'Billing', content: 'Tab content for billing' },
]
let [manual, setManual] = useState(false)
return (
<div className="flex flex-col items-start w-screen h-full p-12 bg-gray-50 space-y-12">
<Switch.Group as="div" className="flex items-center space-x-4">
<Switch.Label>Manual keyboard activation</Switch.Label>
<Switch
as="button"
checked={manual}
onChange={setManual}
className={({ checked }) =>
classNames(
'relative inline-flex flex-shrink-0 h-6 border-2 border-transparent rounded-full cursor-pointer w-11 focus:outline-none focus:shadow-outline transition-colors ease-in-out duration-200',
checked ? 'bg-indigo-600' : 'bg-gray-200'
)
}
>
{({ checked }) => (
<span
className={classNames(
'inline-block w-5 h-5 bg-white rounded-full transform transition ease-in-out duration-200',
checked ? 'translate-x-5' : 'translate-x-0'
)}
/>
)}
</Switch>
</Switch.Group>
<Tab.Group className="flex flex-col max-w-3xl w-full" as="div" manual={manual}>
<Tab.List className="relative z-0 rounded-lg shadow flex divide-x divide-gray-200">
{tabs.map((tab, tabIdx) => (
<Tab
key={tab.name}
disabled={tab.disabled}
className={({ selected }) =>
classNames(
selected ? 'text-gray-900' : 'text-gray-500 hover:text-gray-700',
tabIdx === 0 ? 'rounded-l-lg' : '',
tabIdx === tabs.length - 1 ? 'rounded-r-lg' : '',
tab.disabled && 'opacity-50',
'group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-sm font-medium text-center hover:bg-gray-50 focus:z-10'
)
}
>
{({ selected }) => (
<>
<span>{tab.name}</span>
{tab.disabled && <small className="inline-block px-4 text-xs">(disabled)</small>}
<span
aria-hidden="true"
className={classNames(
selected ? 'bg-indigo-500' : 'bg-transparent',
'absolute inset-x-0 bottom-0 h-0.5'
)}
/>
</>
)}
</Tab>
))}
</Tab.List>
<Tab.Panels className="mt-4">
{tabs.map(tab => (
<Tab.Panel className="bg-white rounded-lg p-4 shadow" key={tab.name}>
{tab.content}
</Tab.Panel>
))}
</Tab.Panels>
</Tab.Group>
</div>
)
}
@@ -1,98 +0,0 @@
import React, { useState } from 'react'
import Head from 'next/head'
import { Transition } from '@headlessui/react'
export default function Home() {
return (
<>
<Head>
<title>Transition Component - Playground</title>
</Head>
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<Dropdown />
</div>
</>
)
}
function Dropdown() {
let [isOpen, setIsOpen] = useState(false)
return (
<div className="relative inline-block text-left">
<div>
<span className="rounded-md shadow-sm">
<button
type="button"
className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
id="options-menu"
aria-haspopup="true"
aria-expanded={isOpen}
onClick={() => setIsOpen(v => !v)}
>
Options
<svg className="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
</span>
</div>
<Transition
show={isOpen}
enter="transition ease-out duration-75"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-150"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
className="absolute right-0 w-56 mt-2 origin-top-right rounded-md shadow-lg"
>
<div className="bg-white rounded-md shadow-xs">
<div
className="py-1"
role="menu"
aria-orientation="vertical"
aria-labelledby="options-menu"
>
<a
href="/"
className="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
role="menuitem"
>
Account settings
</a>
<a
href="/"
className="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
role="menuitem"
>
Support
</a>
<a
href="/"
className="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
role="menuitem"
>
License
</a>
<form method="POST" action="#">
<button
type="submit"
className="block w-full px-4 py-2 text-sm leading-5 text-left text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
role="menuitem"
>
Sign out
</button>
</form>
</div>
</div>
</Transition>
</div>
)
}
@@ -1,168 +0,0 @@
import React, { useRef, useState } from 'react'
import { Transition } from '@headlessui/react'
export default function Home() {
let [isOpen, setIsOpen] = useState(false)
function toggle() {
setIsOpen(v => !v)
}
let [email, setEmail] = useState('')
let [events, setEvents] = useState([])
let inputRef = useRef(null)
function addEvent(name) {
setEvents(existing => [...existing, `${new Date().toJSON()} - ${name}`])
}
return (
<div>
<div className="flex p-12 space-x-4">
<div className="inline-block p-12">
<span className="flex w-full mt-3 rounded-md shadow-sm sm:mt-0 sm:w-auto">
<button
onClick={toggle}
type="button"
className="inline-flex justify-center w-full px-4 py-2 text-base font-medium leading-6 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue sm:text-sm sm:leading-5"
>
Show modal
</button>
</span>
</div>
<ul className="p-4 text-gray-900 bg-gray-200">
<h3 className="font-bold">Events:</h3>
{events.map((event, i) => (
<li key={i} className="font-mono text-sm">
{event}
</li>
))}
</ul>
</div>
<Transition
show={isOpen}
className="fixed inset-0 z-10 overflow-y-auto"
beforeEnter={() => {
addEvent('Before enter')
}}
afterEnter={() => {
inputRef.current.focus()
addEvent('After enter')
}}
beforeLeave={() => {
addEvent('Before leave (before confirm)')
window.confirm('Are you sure?')
addEvent('Before leave (after confirm)')
}}
afterLeave={() => {
addEvent('After leave (before alert)')
window.alert('Consider it done!')
addEvent('After leave (after alert)')
setEmail('')
}}
>
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 transition-opacity">
<div className="absolute inset-0 bg-gray-500 opacity-75"></div>
</div>
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span className="hidden sm:inline-block sm:align-middle sm:h-screen"></span>&#8203;
<Transition.Child
className="inline-block overflow-hidden text-left align-bottom transition-all transform bg-white rounded-lg shadow-xl sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog"
aria-modal="true"
aria-labelledby="modal-headline"
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className="px-4 pt-5 pb-4 bg-white sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto bg-red-100 rounded-full sm:mx-0 sm:h-10 sm:w-10">
{/* Heroicon name: exclamation */}
<svg
className="w-6 h-6 text-red-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-headline">
Deactivate account
</h3>
<div className="mt-2">
<p className="text-sm leading-5 text-gray-500">
Are you sure you want to deactivate your account? All of your data will be
permanently removed. This action cannot be undone.
</p>
</div>
<div className="mt-2">
<div>
<label
htmlFor="email"
className="block text-sm font-medium leading-5 text-gray-700"
>
Email address
</label>
<div className="relative mt-1 rounded-md shadow-sm">
<input
ref={inputRef}
value={email}
onChange={event => setEmail(event.target.value)}
id="email"
className="block w-full px-3 form-input sm:text-sm sm:leading-5"
placeholder="name@example.com"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="px-4 py-3 bg-gray-50 sm:px-6 sm:flex sm:flex-row-reverse">
<span className="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
<button
type="button"
className="inline-flex justify-center w-full px-4 py-2 text-base font-medium leading-6 text-white transition duration-150 ease-in-out bg-red-600 border border-transparent rounded-md shadow-sm hover:bg-red-500 focus:outline-none focus:border-red-700 focus:shadow-outline-red sm:text-sm sm:leading-5"
>
Deactivate
</button>
</span>
<span className="flex w-full mt-3 rounded-md shadow-sm sm:mt-0 sm:w-auto">
<button
onClick={toggle}
type="button"
className="inline-flex justify-center w-full px-4 py-2 text-base font-medium leading-6 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue sm:text-sm sm:leading-5"
>
Cancel
</button>
</span>
</div>
</Transition.Child>
</div>
</Transition>
</div>
)
}
@@ -1,60 +0,0 @@
import React, { useState, ReactNode } from 'react'
import { Transition } from '@headlessui/react'
export default function Home() {
let [isOpen, setIsOpen] = useState(true)
return (
<>
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="space-y-2 w-96">
<span className="inline-flex rounded-md shadow-sm">
<button
type="button"
onClick={() => setIsOpen(v => !v)}
className="inline-flex items-center px-3 py-2 text-sm font-medium leading-4 text-gray-700 transition bg-white border border-gray-300 rounded-md duration-150-out hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50"
>
{isOpen ? 'Hide' : 'Show'}
</button>
</span>
<Transition show={isOpen} unmount={false}>
<Box>
<Box>
<Box>
<Box />
</Box>
<Box>
<Box>
<Box>
<Box />
</Box>
</Box>
</Box>
</Box>
</Box>
</Transition>
</div>
</div>
</>
)
}
function Box({ children }: { children?: ReactNode }) {
return (
<Transition.Child
unmount={false}
enter="transition translate duration-300"
enterFrom="transform -translate-x-full"
enterTo="transform translate-x-0"
leave="transition translate duration-300"
leaveFrom="transform translate-x-0"
leaveTo="transform translate-x-full"
>
<div className="p-4 space-y-2 text-sm font-semibold tracking-wide text-gray-700 uppercase bg-white rounded-md shadow">
<span>This is a box</span>
{children}
</div>
</Transition.Child>
)
}
@@ -1,60 +0,0 @@
import React, { useState, ReactNode } from 'react'
import { Transition } from '@headlessui/react'
export default function Home() {
let [isOpen, setIsOpen] = useState(true)
return (
<>
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="space-y-2 w-96">
<span className="inline-flex rounded-md shadow-sm">
<button
type="button"
onClick={() => setIsOpen(v => !v)}
className="inline-flex items-center px-3 py-2 text-sm font-medium leading-4 text-gray-700 transition bg-white border border-gray-300 rounded-md duration-150-out hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50"
>
{isOpen ? 'Hide' : 'Show'}
</button>
</span>
<Transition show={isOpen} unmount={true}>
<Box>
<Box>
<Box>
<Box />
</Box>
<Box>
<Box>
<Box>
<Box />
</Box>
</Box>
</Box>
</Box>
</Box>
</Transition>
</div>
</div>
</>
)
}
function Box({ children }: { children?: ReactNode }) {
return (
<Transition.Child
unmount={true}
enter="transition translate duration-300"
enterFrom="transform -translate-x-full"
enterTo="transform translate-x-0"
leave="transition translate duration-300"
leaveFrom="transform translate-x-0"
leaveTo="transform translate-x-full"
>
<div className="p-4 space-y-2 text-sm font-semibold tracking-wide text-gray-700 uppercase bg-white rounded-md shadow">
<span>This is a box</span>
{children}
</div>
</Transition.Child>
)
}
@@ -1,38 +0,0 @@
import React, { useState } from 'react'
import { Transition } from '@headlessui/react'
export default function Home() {
let [isOpen, setIsOpen] = useState(true)
return (
<>
<div className="flex justify-center w-screen h-full p-12 bg-gray-50">
<div className="space-y-2 w-96">
<span className="inline-flex rounded-md shadow-sm">
<button
type="button"
onClick={() => setIsOpen(v => !v)}
className="inline-flex items-center px-3 py-2 text-sm font-medium leading-4 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:text-gray-800 active:bg-gray-50"
>
{isOpen ? 'Hide' : 'Show'}
</button>
</span>
<Transition
show={isOpen}
unmount={false}
enter="transition ease-out duration-300"
enterFrom="transform opacity-0"
enterTo="transform opacity-100"
leave="transition ease-in duration-300"
leaveFrom="transform opacity-100"
leaveTo="transform opacity-0"
className="p-4 bg-white rounded-md shadow"
>
Contents to show and hide
</Transition>
</div>
</div>
</>
)
}
@@ -1,181 +0,0 @@
import React, { useEffect, useRef, useState } from 'react'
import Head from 'next/head'
import { Transition } from '@headlessui/react'
import { classNames } from '../../../src/utils/class-names'
import { match } from '../../../src/utils/match'
export default function Shell() {
return (
<>
<Head>
<title>Transition Component - Full Page Transition</title>
</Head>
<div className="h-full p-12 bg-gray-50">
<div className="flex flex-col flex-1 h-full overflow-hidden rounded-lg shadow-lg">
<FullPageTransition />
</div>
</div>
</>
)
}
function usePrevious<T>(value: T) {
let ref = useRef(value)
useEffect(() => {
ref.current = value
}, [value])
return ref.current
}
enum Direction {
Forwards = ' -> ',
Backwards = ' <- ',
}
let pages = ['Dashboard', 'Team', 'Projects', 'Calendar', 'Reports']
let colors = [
'bg-gradient-to-r from-teal-400 to-blue-400',
'bg-gradient-to-r from-blue-400 to-orange-400',
'bg-gradient-to-r from-orange-400 to-purple-400',
'bg-gradient-to-r from-purple-400 to-green-400',
'bg-gradient-to-r from-green-400 to-teal-400',
]
function FullPageTransition() {
let [activePage, setActivePage] = useState(0)
let previousPage = usePrevious(activePage)
let direction = activePage > previousPage ? Direction.Forwards : Direction.Backwards
let transitions = match(direction, {
[Direction.Forwards]: {
enter: 'transition transform ease-in-out duration-500',
enterFrom: 'translate-x-full',
enterTo: 'translate-x-0',
leave: 'transition transform ease-in-out duration-500',
leaveFrom: 'translate-x-0',
leaveTo: '-translate-x-full',
},
[Direction.Backwards]: {
enter: 'transition transform ease-in-out duration-500',
enterFrom: '-translate-x-full',
enterTo: 'translate-x-0',
leave: 'transition transform ease-in-out duration-500',
leaveFrom: 'translate-x-0',
leaveTo: 'translate-x-full',
},
})
return (
<div>
<div className="pb-32 bg-gray-800">
<nav className="bg-gray-800">
<div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div className="border-b border-gray-700">
<div className="flex items-center justify-between h-16 px-4 sm:px-0">
<div className="flex items-center">
<div className="flex-shrink-0">
<img
className="w-8 h-8"
src="https://tailwindui.com/img/logos/workflow-mark-on-dark.svg"
alt="Workflow logo"
/>
</div>
<div className="hidden md:block">
<div className="flex items-baseline ml-10 space-x-4">
{pages.map((page, i) => (
<button
key={page}
onClick={() => setActivePage(i)}
className={classNames(
'px-3 py-2 text-sm font-medium rounded-md focus:outline-none focus:text-white focus:bg-gray-700',
i === activePage
? 'text-white bg-gray-900'
: 'text-gray-300 hover:text-white hover:bg-gray-700'
)}
>
{page}
</button>
))}
</div>
</div>
</div>
<div className="hidden md:block">
<div className="flex items-center ml-4 md:ml-6">
<button
className="p-1 text-gray-400 border-2 border-transparent rounded-full hover:text-white focus:outline-none focus:text-white focus:bg-gray-700"
aria-label="Notifications"
>
<svg
className="w-6 h-6"
stroke="currentColor"
fill="none"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
/>
</svg>
</button>
{/* Profile dropdown */}
<div className="relative ml-3">
<div>
<button
className="flex items-center max-w-xs text-sm text-white rounded-full focus:outline-none focus:shadow-solid"
id="user-menu"
aria-label="User menu"
aria-haspopup="true"
>
<img
className="w-8 h-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt=""
/>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</nav>
<header className="py-10">
<div className="px-4 mx-auto max-w-7xl sm:px-6 lg:px-8">
<h1 className="relative inline-block text-3xl font-bold leading-9 text-white">
{pages[activePage]}
</h1>
</div>
</header>
</div>
<main className="-mt-32">
<div className="px-4 pb-12 mx-auto max-w-7xl sm:px-6 lg:px-8">
<div className="px-5 py-6 bg-white rounded-lg shadow sm:px-6">
<div className="relative overflow-hidden rounded-lg h-96">
{pages.map((page, i) => (
<Transition
appear={false}
key={page}
show={activePage === i}
className={classNames(
'absolute inset-0 p-8 text-3xl rounded-lg text-white font-bold',
colors[i]
)}
{...transitions}
>
{page} page content
</Transition>
))}
</div>
</div>
</div>
</main>
</div>
)
}
@@ -1,170 +0,0 @@
import React, { useEffect, useState } from 'react'
import Head from 'next/head'
import { Transition } from '@headlessui/react'
export default function App() {
let [mobileOpen, setMobileOpen] = useState(false)
useEffect(() => {
function handleEscape(event) {
if (!mobileOpen) return
if (event.key === 'Escape') {
setMobileOpen(false)
}
}
document.addEventListener('keyup', handleEscape)
return () => document.removeEventListener('keyup', handleEscape)
}, [mobileOpen])
return (
<>
<Head>
<title>Transition Component - Layout with sidebar</title>
</Head>
<div className="flex h-screen overflow-hidden bg-cool-gray-100">
{/* Off-canvas menu for mobile */}
<Transition show={mobileOpen} unmount={false} className="fixed inset-0 z-40 flex">
{/* Off-canvas menu overlay, show/hide based on off-canvas menu state. */}
<Transition.Child
unmount={false}
enter="transition-opacity ease-linear duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity ease-linear duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
{() => (
<div className="fixed inset-0">
<div
onClick={() => setMobileOpen(false)}
className="absolute inset-0 opacity-75 bg-cool-gray-600"
/>
</div>
)}
</Transition.Child>
{/* Off-canvas menu, show/hide based on off-canvas menu state. */}
<Transition.Child
unmount={false}
enter="transition ease-in-out duration-300 transform"
enterFrom="-translate-x-full"
enterTo="translate-x-0"
leave="transition ease-in-out duration-300 transform"
leaveFrom="translate-x-0"
leaveTo="-translate-x-full"
className="relative flex flex-col flex-1 w-full max-w-xs pt-5 pb-4 bg-teal-600"
>
<div className="absolute top-0 right-0 p-1 -mr-14">
<Transition.Child
unmount={false}
className="flex items-center justify-center w-12 h-12 rounded-full focus:outline-none focus:bg-cool-gray-600"
aria-label="Close sidebar"
as="button"
onClick={() => setMobileOpen(false)}
>
<svg
className="w-6 h-6 text-white"
stroke="currentColor"
fill="none"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</Transition.Child>
</div>
<div className="flex items-center flex-shrink-0 px-4">
<img
className="w-auto h-8"
src="https://tailwindui.com/img/logos/easywire-logo-on-brand.svg"
alt="Easywire logo"
/>
</div>
</Transition.Child>
<div className="flex-shrink-0 w-14">
{/* Dummy element to force sidebar to shrink to fit close icon */}
</div>
</Transition>
{/* Static sidebar for desktop */}
<div className="hidden lg:flex lg:flex-shrink-0">
<div className="flex flex-col w-64">
{/* Sidebar component, swap this element with another sidebar if you like */}
<div className="flex flex-col flex-grow pt-5 pb-4 overflow-y-auto bg-teal-600">
<div className="flex items-center flex-shrink-0 px-4">
<img
className="w-auto h-8"
src="https://tailwindui.com/img/logos/easywire-logo-on-brand.svg"
alt="Easywire logo"
/>
</div>
</div>
</div>
</div>
<div className="flex-1 overflow-auto focus:outline-none" tabIndex={0}>
<div className="relative z-10 flex flex-shrink-0 h-16 bg-white border-b border-gray-200 lg:border-none">
<button
className="px-4 border-r border-cool-gray-200 text-cool-gray-400 focus:outline-none focus:bg-cool-gray-100 focus:text-cool-gray-600 lg:hidden"
aria-label="Open sidebar"
onClick={() => setMobileOpen(true)}
>
<svg
className="w-6 h-6 transition duration-150 ease-in-out"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</button>
{/* Search bar */}
<div className="flex justify-between flex-1 px-4 sm:px-6 lg:max-w-6xl lg:mx-auto lg:px-8">
<div className="flex flex-1">
<form className="flex w-full md:ml-0" action="#" method="GET">
<label htmlFor="search_field" className="sr-only">
Search
</label>
<div className="relative w-full text-cool-gray-400 focus-within:text-cool-gray-600">
<div className="absolute inset-y-0 left-0 flex items-center pointer-events-none">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
/>
</svg>
</div>
<input
id="search_field"
className="block w-full h-full py-2 pl-8 pr-3 rounded-md text-cool-gray-900 placeholder-cool-gray-500 focus:outline-none focus:placeholder-cool-gray-400 sm:text-sm"
placeholder="Search"
type="search"
/>
</div>
</form>
</div>
</div>
</div>
<main className="relative z-0 flex-1 p-8 overflow-y-auto">
{/* Replace with your content */}
<div className="border-4 border-gray-200 border-dashed rounded-lg h-96"></div>
{/* /End replace */}
</main>
</div>
</div>
</>
)
}
@@ -1,37 +0,0 @@
import { RefCallback, useRef, useCallback, useMemo } from 'react'
import { createPopper, Options } from '@popperjs/core'
/**
* Example implementation to use Popper: https://popper.js.org/
*/
export function usePopper(
options?: Partial<Options>
): [RefCallback<Element | null>, RefCallback<HTMLElement | null>] {
let reference = useRef<Element>(null)
let popper = useRef<HTMLElement>(null)
let cleanupCallback = useRef(() => {})
let instantiatePopper = useCallback(() => {
if (!reference.current) return
if (!popper.current) return
if (cleanupCallback.current) cleanupCallback.current()
cleanupCallback.current = createPopper(reference.current, popper.current, options).destroy
}, [reference, popper, cleanupCallback, options])
return useMemo(
() => [
referenceDomNode => {
reference.current = referenceDomNode
instantiatePopper()
},
popperDomNode => {
popper.current = popperDomNode
instantiatePopper()
},
],
[reference, popper, instantiatePopper]
)
}
@@ -1,46 +0,0 @@
import fs from 'fs'
import path from 'path'
export type ExamplesType = {
name: string
path: string
children?: ExamplesType[]
}
export async function resolveAllExamples(...paths: string[]) {
let base = path.resolve(process.cwd(), ...paths)
if (!fs.existsSync(base)) {
return false
}
let files = await fs.promises.readdir(base, { withFileTypes: true })
let items: ExamplesType[] = []
for (let file of files) {
// Skip reserved filenames from Next. E.g.: _app.tsx, _error.tsx
if (file.name.startsWith('_')) {
continue
}
let bucket: ExamplesType = {
name: file.name.replace(/-/g, ' ').replace(/\.tsx?/g, ''),
path: [...paths, file.name]
.join('/')
.replace(/^pages/, '')
.replace(/\.tsx?/g, '')
.replace(/\/+/g, '/'),
}
if (file.isDirectory()) {
let children = await resolveAllExamples(...paths, file.name)
if (children) {
bucket.children = children
}
}
items.push(bucket)
}
return items
}
@@ -1 +0,0 @@
module.exports = require('../../postcss.config.js')
@@ -1 +0,0 @@
module.exports = require('../../tailwind.config.js')
-3
View File
@@ -1,3 +0,0 @@
{
"routes": [{ "handle": "filesystem" }, { "src": "/(.*)", "status": 404, "dest": "/404.html" }]
}
@@ -1,4 +0,0 @@
node_modules
.DS_Store
dist
*.local
@@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Headless UI - Playground</title>
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
</head>
<body class="w-full h-full font-sans antialiased text-gray-900">
<div class="w-full h-full" id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

@@ -1,2 +0,0 @@
*
!.gitignore
@@ -1,96 +0,0 @@
<template>
<div
class="flex flex-col h-screen overflow-hidden font-sans antialiased text-gray-900 bg-gray-700"
>
<header
class="relative z-10 flex items-center justify-between flex-shrink-0 px-4 py-4 bg-gray-700 border-b border-gray-200 sm:px-6 lg:px-8"
>
<router-link to="/">
<svg class="h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 243 42">
<path
fill="#fff"
d="M65.74 13.663c-2.62 0-4.702.958-5.974 2.95V6.499h-4.163V33.32h4.163V23.051c0-3.908 2.159-5.518 4.896-5.518 2.62 0 4.317 1.533 4.317 4.445V33.32h4.162V21.557c0-4.982-3.083-7.894-7.4-7.894zM79.936 25.503h15.341c.077-.536.154-1.15.154-1.724 0-5.518-3.931-10.116-9.674-10.116-6.052 0-10.176 4.407-10.176 10.078 0 5.748 4.124 10.078 10.484 10.078 3.778 0 6.668-1.572 8.441-4.177l-3.43-1.993c-.925 1.341-2.66 2.376-4.972 2.376-3.084 0-5.512-1.533-6.168-4.521zm-.038-3.372c.578-2.873 2.698-4.713 5.82-4.713 2.506 0 4.934 1.418 5.512 4.713H79.898zM113.282 14.161v2.72c-1.465-1.992-3.739-3.218-6.746-3.218-5.242 0-9.597 4.368-9.597 10.078 0 5.67 4.355 10.078 9.597 10.078 3.007 0 5.281-1.227 6.746-3.258v2.76h4.162V14.16h-4.162zm-6.09 15.71c-3.469 0-6.091-2.567-6.091-6.13 0-3.564 2.622-6.131 6.091-6.131 3.469 0 6.09 2.567 6.09 6.13 0 3.564-2.621 6.132-6.09 6.132zM136.597 6.498v10.384c-1.465-1.993-3.739-3.219-6.746-3.219-5.242 0-9.597 4.368-9.597 10.078 0 5.67 4.355 10.078 9.597 10.078 3.007 0 5.281-1.227 6.746-3.258v2.76h4.163V6.497h-4.163zm-6.09 23.374c-3.469 0-6.09-2.568-6.09-6.131 0-3.564 2.621-6.131 6.09-6.131s6.09 2.567 6.09 6.13c0 3.564-2.621 6.132-6.09 6.132zM144.648 33.32h4.163V5.348h-4.163V33.32zM155.957 25.503h15.341c.077-.536.154-1.15.154-1.724 0-5.518-3.931-10.116-9.675-10.116-6.051 0-10.176 4.407-10.176 10.078 0 5.748 4.125 10.078 10.485 10.078 3.777 0 6.668-1.572 8.441-4.177l-3.43-1.993c-.926 1.341-2.66 2.376-4.973 2.376-3.083 0-5.512-1.533-6.167-4.521zm-.038-3.372c.578-2.873 2.698-4.713 5.82-4.713 2.505 0 4.934 1.418 5.512 4.713h-11.332zM177.137 19.45c0-1.38 1.311-2.032 2.814-2.032 1.581 0 2.93.69 3.623 2.184l3.508-1.954c-1.349-2.529-3.97-3.985-7.131-3.985-3.931 0-7.053 2.26-7.053 5.863 0 6.859 10.368 4.943 10.368 8.353 0 1.533-1.426 2.146-3.276 2.146-2.12 0-3.662-1.035-4.279-2.759l-3.584 2.07c1.233 2.758 4.008 4.483 7.863 4.483 4.163 0 7.516-2.07 7.516-5.902 0-7.088-10.369-4.98-10.369-8.468zM192.774 19.45c0-1.38 1.31-2.032 2.813-2.032 1.581 0 2.93.69 3.624 2.184l3.507-1.954c-1.349-2.529-3.97-3.985-7.131-3.985-3.931 0-7.053 2.26-7.053 5.863 0 6.859 10.368 4.943 10.368 8.353 0 1.533-1.426 2.146-3.276 2.146-2.12 0-3.662-1.035-4.278-2.759l-3.585 2.07c1.233 2.758 4.009 4.483 7.863 4.483 4.163 0 7.516-2.07 7.516-5.902 0-7.088-10.368-4.98-10.368-8.468zM224.523 28.9c2.889 0 5.027-1.715 5.027-4.53v-8.782h-2.588v8.577c0 1.268-.676 2.219-2.439 2.219s-2.438-.951-2.438-2.22v-8.576h-2.569v8.782c0 2.815 2.138 4.53 5.007 4.53zM232.257 15.588V28.64h2.588V15.588h-2.588z"
/>
<path
fill="#fff"
fill-rule="evenodd"
d="M233.817 9.328H220.42c-2.96 0-5.359 2.385-5.359 5.327v13.318c0 2.942 2.399 5.327 5.359 5.327h13.397c2.959 0 5.358-2.385 5.358-5.327V14.655c0-2.942-2.399-5.327-5.358-5.327zM220.42 6.664c-4.439 0-8.038 3.578-8.038 7.99v13.319c0 4.413 3.599 7.99 8.038 7.99h13.397c4.439 0 8.038-3.577 8.038-7.99V14.655c0-4.413-3.599-7.99-8.038-7.99H220.42z"
clip-rule="evenodd"
/>
<path
fill="#fff"
fill-rule="evenodd"
d="M220.42 9.328h13.397c2.959 0 5.358 2.385 5.358 5.327v13.318c0 2.942-2.399 5.327-5.358 5.327H220.42c-2.96 0-5.359-2.385-5.359-5.327V14.655c0-2.942 2.399-5.327 5.359-5.327zm-8.038 5.327c0-4.413 3.599-7.99 8.038-7.99h13.397c4.439 0 8.038 3.577 8.038 7.99v13.318c0 4.413-3.599 7.99-8.038 7.99H220.42c-4.439 0-8.038-3.577-8.038-7.99V14.655z"
clip-rule="evenodd"
/>
<path
fill="url(#prefix__paint0_linear)"
d="M8.577 26.097l25.779-8.556c-.514-3.201-.88-5.342-1.307-6.974-.457-1.756-.821-2.226-.965-2.39a5.026 5.026 0 00-1.81-1.306c-.2-.086-.762-.284-2.583-.175-1.924.116-4.453.507-8.455 1.137-4.003.63-6.529 1.035-8.395 1.516-1.766.456-2.239.817-2.403.96a4.999 4.999 0 00-1.315 1.8c-.085.198-.285.757-.175 2.568.116 1.913.51 4.426 1.143 8.405.178 1.114.337 2.113.486 3.015z"
/>
<path
fill="url(#prefix__paint1_linear)"
fill-rule="evenodd"
d="M1.47 24.124C.244 16.427-.37 12.58.96 9.49A11.665 11.665 0 014.027 5.29c2.545-2.21 6.416-2.82 14.16-4.039C25.93.031 29.8-.578 32.907.743a11.729 11.729 0 014.225 3.05c2.223 2.53 2.836 6.38 4.063 14.076 1.226 7.698 1.84 11.546.511 14.636a11.666 11.666 0 01-3.069 4.199c-2.545 2.21-6.416 2.82-14.159 4.039-7.743 1.219-11.614 1.828-14.722.508a11.728 11.728 0 01-4.224-3.05C3.31 35.67 2.697 31.82 1.47 24.123zm13.657 13.668c2.074-.125 4.743-.54 8.697-1.163 3.953-.622 6.62-1.047 8.632-1.566 1.949-.502 2.846-.992 3.426-1.496a7.5 7.5 0 001.973-2.7c.302-.703.494-1.703.372-3.7-.125-2.063-.543-4.716-1.17-8.646-.625-3.93-1.053-6.582-1.574-8.582-.506-1.937-.999-2.83-1.505-3.405a7.54 7.54 0 00-2.716-1.961c-.707-.301-1.713-.492-3.723-.371-2.074.125-4.743.54-8.697 1.163-3.953.622-6.62 1.047-8.632 1.565-1.949.503-2.846.993-3.426 1.497a7.5 7.5 0 00-1.972 2.699c-.303.704-.495 1.704-.373 3.701.125 2.062.543 4.716 1.17 8.646.625 3.93 1.053 6.582 1.574 8.581.506 1.938 1 2.83 1.505 3.406a7.54 7.54 0 002.716 1.961c.707.3 1.713.492 3.723.37z"
clip-rule="evenodd"
/>
<defs>
<linearGradient
id="prefix__paint0_linear"
x1="16.759"
x2="23.386"
y1="0"
y2="41.662"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#66E3FF" />
<stop offset="1" stop-color="#7064F9" />
</linearGradient>
<linearGradient
id="prefix__paint1_linear"
x1="16.759"
x2="23.386"
y1="0"
y2="41.662"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#66E3FF" />
<stop offset="1" stop-color="#7064F9" />
</linearGradient>
</defs>
</svg>
</router-link>
</header>
<main class="flex-1 overflow-auto bg-gray-50">
<router-view />
<KeyCaster />
<!-- TODO: Position this in the correct spot -->
<div
v-if="sourceCode"
class="container fixed bottom-0 left-0 right-0 hidden my-12 overflow-scroll rounded-md max-h-96"
v-html="sourceCode"
/>
</main>
</div>
</template>
<script>
import { computed, watchEffect } from 'vue'
import { useRoute } from 'vue-router'
import KeyCaster from './KeyCaster.vue'
import './.generated/preload.js'
import source from './.generated/source.json'
export default {
name: 'App',
components: {
KeyCaster,
},
setup() {
let route = useRoute()
let sourceCode = computed(() => source[route.path])
return { sourceCode }
},
}
</script>
@@ -1,74 +0,0 @@
<template>
<div
class="fixed z-50 px-4 py-2 overflow-hidden text-2xl tracking-wide text-blue-100 bg-blue-800 rounded-md shadow cursor-default pointer-events-none select-none right-4 bottom-4"
v-if="keys.length > 0"
>
{{
keys
.slice()
.reverse()
.join(' ')
}}
</div>
</template>
<script>
import { defineComponent, ref } from 'vue'
let isMac = navigator.userAgent.indexOf('Mac OS X') !== -1
let KeyDisplay = isMac
? {
ArrowUp: '↑',
ArrowDown: '↓',
ArrowLeft: '←',
ArrowRight: '→',
Home: '↖',
End: '↘',
Alt: '⌥',
CapsLock: '⇪',
Meta: '⌘',
Shift: '⇧',
Control: '⌃',
Backspace: '⌫',
Delete: '⌦',
Enter: '↵',
Escape: '⎋',
Tab: '⇥',
ShiftTab: '⇤',
PageUp: '⇞',
PageDown: '⇟',
' ': '␣',
}
: {
ArrowUp: '↑',
ArrowDown: '↓',
ArrowLeft: '←',
ArrowRight: '→',
Meta: 'Win',
Control: 'Ctrl',
Backspace: '⌫',
Delete: 'Del',
Escape: 'Esc',
PageUp: 'PgUp',
PageDown: 'PgDn',
' ': '␣',
}
export default defineComponent({
setup() {
let keys = ref([])
window.addEventListener('keydown', event => {
keys.value.unshift(
event.shiftKey && event.key !== 'Shift'
? KeyDisplay[`Shift${event.key}`] ?? event.key
: KeyDisplay[event.key] ?? event.key
)
setTimeout(() => keys.value.pop(), 2000)
})
return { keys }
},
})
</script>
@@ -1,44 +0,0 @@
<template>
<div class="container my-24">
<div class="prose">
<h2>Examples</h2>
<Examples :examples="examples" />
</div>
</div>
</template>
<script>
import { defineComponent, h } from 'vue'
import { RouterLink } from 'vue-router'
import routes from '../routes.json'
let Examples = defineComponent({
props: ['examples'],
setup(props) {
return () => {
return h(
'ul',
props.examples.map(example =>
h(
'li',
{ key: example.path },
example.children
? h('h3', { class: 'text-xl' }, example.name)
: [h(RouterLink, { to: example.path }, () => example.name)],
example.children && h(Examples, { examples: example.children })
)
)
)
}
},
})
export default {
components: { Examples },
setup() {
return {
examples: routes,
}
},
}
</script>
@@ -1,238 +0,0 @@
<template>
<button
type="button"
@click="toggleIsOpen()"
class="m-12 px-4 py-2 text-base font-medium leading-6 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue sm:text-sm sm:leading-5"
>
Toggle!
</button>
<TransitionRoot :show="isOpen" as="template">
<Dialog @close="setIsOpen">
<div class="fixed z-10 inset-0 overflow-y-auto">
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<TransitionChild
as="template"
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-75"
leave="ease-in duration-200"
leaveFrom="opacity-75"
leaveTo="opacity-0"
entered="opacity-75"
>
<DialogOverlay className="fixed inset-0 bg-gray-500 transition-opacity" />
</TransitionChild>
<TransitionChild
enter="ease-out transform duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in transform duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<!-- This element is to trick the browser into centering the modal contents. -->
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
&#8203;
</span>
<div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"
>
<!-- Heroicon name: exclamation -->
<svg
class="h-6 w-6 text-red-600"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
stroke-width="2"
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
/>
</svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<DialogTitle as="h3" class="text-lg leading-6 font-medium text-gray-900">
Deactivate account
</DialogTitle>
<div class="mt-2">
<p class="text-sm text-gray-500">
Are you sure you want to deactivate your account? All of your data will be
permanently removed. This action cannot be undone.
</p>
<div class="relative inline-block text-left mt-10">
<Menu>
<span class="rounded-md shadow-sm">
<MenuButton
ref="trigger"
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Choose a reason</span>
<svg
class="w-5 h-5 ml-2 -mr-1"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<TransitionRoot
enter="transition duration-300 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-75 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<Portal>
<MenuItems
ref="container"
class="z-20 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">
tom@example.com
</p>
</div>
<div class="py-1">
<MenuItem as="a" href="#account-settings" :className="resolveClass">
Account settings
</MenuItem>
<MenuItem as="a" href="#support" :className="resolveClass">
Support
</MenuItem>
<MenuItem
as="a"
disabled
href="#new-feature"
:className="resolveClass"
>
New feature (soon)
</MenuItem>
<MenuItem as="a" href="#license" :className="resolveClass">
License
</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" href="#sign-out" :className="resolveClass">
Sign out
</MenuItem>
</div>
</MenuItems>
</Portal>
</TransitionRoot>
</Menu>
</div>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
type="button"
@click="setIsOpen(false)"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:shadow-outline-red sm:ml-3 sm:w-auto sm:text-sm"
>
Deactivate
</button>
<button
type="button"
@click="setIsOpen(false)"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:shadow-outline-indigo sm:mt-0 sm:w-auto sm:text-sm"
>
Cancel
</button>
</div>
</div>
</TransitionChild>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>
<script>
import { ref, defineComponent } from 'vue'
import {
Dialog,
DialogTitle,
DialogOverlay,
Menu,
MenuButton,
MenuItems,
MenuItem,
Portal,
TransitionRoot,
TransitionChild,
} from '@headlessui/vue'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
function resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
}
export default {
components: {
Dialog,
DialogTitle,
DialogOverlay,
Menu,
MenuButton,
MenuItems,
MenuItem,
Portal,
TransitionRoot,
TransitionChild,
},
setup() {
let isOpen = ref(false)
let [trigger, container] = usePopper({
placement: 'bottom-end',
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 10] } }],
})
return {
isOpen,
trigger,
container,
setIsOpen(value) {
isOpen.value = value
},
toggleIsOpen() {
isOpen.value = !isOpen.value
},
resolveClass,
}
},
}
</script>
@@ -1,33 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="w-full max-w-xs mx-auto">
<Disclosure>
<DisclosureButton>Trigger</DisclosureButton>
<TransitionRoot
enter="transition duration-1000 ease-out"
enterFrom="transform scale-95 opacity-0"
enterTo="transform scale-100 opacity-100"
leave="transition duration-1000 ease-out"
leaveFrom="transform scale-100 opacity-100"
leaveTo="transform scale-95 opacity-0"
>
<DisclosurePanel class="p-4 bg-white mt-4">Content</DisclosurePanel>
</TransitionRoot>
</Disclosure>
</div>
</div>
</template>
<script>
import { Disclosure, DisclosureButton, DisclosurePanel, TransitionRoot } from '@headlessui/vue'
export default {
components: {
Disclosure,
DisclosureButton,
DisclosurePanel,
TransitionRoot,
},
}
</script>
@@ -1,27 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="w-full max-w-xs mx-auto">
<button>Previous</button>
<FocusTrap>
<button>Trigger</button>
</FocusTrap>
<button>After</button>
</div>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import { FocusTrap } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { FocusTrap },
setup(props, context) {
return {}
},
}
</script>
@@ -1,126 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="w-full max-w-xs mx-auto">
<div class="space-y-1">
<Listbox v-model="active">
<ListboxLabel class="block text-sm font-medium leading-5 text-gray-700"
>Assigned to</ListboxLabel
>
<div class="relative">
<span class="inline-block w-full rounded-md shadow-sm">
<ListboxButton
class="relative w-full py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md cursor-default focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5"
>
<span class="block truncate">{{ active.name }}</span>
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
class="w-5 h-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</ListboxButton>
</span>
<div class="absolute w-full mt-1 bg-white rounded-md shadow-lg">
<ListboxOptions
class="py-1 overflow-auto text-base leading-6 rounded-md shadow-xs max-h-60 focus:outline-none sm:text-sm sm:leading-5"
>
<ListboxOption
v-for="person in people"
:key="person.id"
:value="person"
:className="resolveListboxOptionClassName"
:disabled="person.disabled"
v-slot="{ active, selected }"
>
<span
:class="
classNames('block truncate', selected ? 'font-semibold' : 'font-normal')
"
>
{{ person.name }}
</span>
<span
v-if="selected"
:class="
classNames(
'absolute inset-y-0 right-0 flex items-center pr-4',
active ? 'text-white' : 'text-indigo-600'
)
"
>
<svg class="w-5 h-5" viewbox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
</ListboxOption>
</ListboxOptions>
</div>
</div>
</Listbox>
</div>
</div>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import {
Listbox,
ListboxLabel,
ListboxButton,
ListboxOptions,
ListboxOption,
} from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption },
setup(props, context) {
let people = [
{ id: 1, name: 'Wade Cooper' },
{ id: 2, name: 'Arlene Mccoy' },
{ id: 3, name: 'Devon Webb' },
{ id: 4, name: 'Tom Cook' },
{ id: 5, name: 'Tanya Fox', disabled: true },
{ id: 6, name: 'Hellen Schmidt' },
{ id: 7, name: 'Caroline Schultz' },
{ id: 8, name: 'Mason Heaney' },
{ id: 9, name: 'Claudie Smitham' },
{ id: 10, name: 'Emil Schaefer' },
]
let active = ref(people[Math.floor(Math.random() * people.length)])
return {
people,
active,
classNames,
resolveListboxOptionClassName({ active, disabled }) {
return classNames(
'relative py-2 pl-3 cursor-default select-none pr-9 focus:outline-none',
active ? 'text-white bg-indigo-600' : 'text-gray-900',
disabled && 'bg-gray-50 text-gray-300'
)
},
}
},
}
</script>
@@ -1,210 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 space-x-4 bg-gray-50">
<div class="w-64">
<div class="space-y-1">
<Listbox v-model="active">
<ListboxLabel class="block text-sm font-medium leading-5 text-gray-700"
>Assigned to</ListboxLabel
>
<div class="relative">
<span class="inline-block w-full rounded-md shadow-sm">
<ListboxButton
class="relative w-full py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md cursor-default focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5"
>
<span class="block truncate">{{ active.name }}</span>
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
class="w-5 h-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</ListboxButton>
</span>
<div class="absolute w-full mt-1 bg-white rounded-md shadow-lg">
<ListboxOptions
class="py-1 overflow-auto text-base leading-6 rounded-md shadow-xs max-h-60 focus:outline-none sm:text-sm sm:leading-5"
>
<ListboxOption
v-for="person in people"
:key="person.id"
:value="person"
:className="resolveListboxOptionClassName"
v-slot="{ active, selected }"
>
<span
:class="
classNames('block truncate', selected ? 'font-semibold' : 'font-normal')
"
>
{{ person.name }}
</span>
<span
v-if="selected"
:class="
classNames(
'absolute inset-y-0 right-0 flex items-center pr-4',
active ? 'text-white' : 'text-indigo-600'
)
"
>
<svg class="w-5 h-5" viewbox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
</ListboxOption>
</ListboxOptions>
</div>
</div>
</Listbox>
</div>
</div>
<div>
<label for="email" class="block text-sm font-medium leading-5 text-gray-700">
Email
</label>
<div class="relative mt-1 rounded-md shadow-sm">
<input
class="block w-full form-input sm:text-sm sm:leading-5"
placeholder="you@example.com"
/>
</div>
</div>
<div class="w-64">
<div class="space-y-1">
<Listbox v-model="active">
<ListboxLabel class="block text-sm font-medium leading-5 text-gray-700"
>Assigned to</ListboxLabel
>
<div class="relative">
<span class="inline-block w-full rounded-md shadow-sm">
<ListboxButton
class="relative w-full py-2 pl-3 pr-10 text-left transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md cursor-default focus:outline-none focus:shadow-outline-blue focus:border-blue-300 sm:text-sm sm:leading-5"
>
<span class="block truncate">{{ active.name }}</span>
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg
class="w-5 h-5 text-gray-400"
viewBox="0 0 20 20"
fill="none"
stroke="currentColor"
>
<path
d="M7 7l3-3 3 3m0 6l-3 3-3-3"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</span>
</ListboxButton>
</span>
<div class="absolute w-full mt-1 bg-white rounded-md shadow-lg">
<ListboxOptions
class="py-1 overflow-auto text-base leading-6 rounded-md shadow-xs max-h-60 focus:outline-none sm:text-sm sm:leading-5"
>
<ListboxOption
v-for="person in people"
:key="person.id"
:value="person"
:className="resolveListboxOptionClassName"
v-slot="{ active, selected }"
>
<span
:class="
classNames('block truncate', selected ? 'font-semibold' : 'font-normal')
"
>
{{ person.name }}
</span>
<span
v-if="selected"
:class="
classNames(
'absolute inset-y-0 right-0 flex items-center pr-4',
active ? 'text-white' : 'text-indigo-600'
)
"
>
<svg class="w-5 h-5" viewbox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
</span>
</ListboxOption>
</ListboxOptions>
</div>
</div>
</Listbox>
</div>
</div>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import {
Listbox,
ListboxLabel,
ListboxButton,
ListboxOptions,
ListboxOption,
} from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption },
setup(props, context) {
let people = [
{ id: 1, name: 'Wade Cooper' },
{ id: 2, name: 'Arlene Mccoy' },
{ id: 3, name: 'Devon Webb' },
{ id: 4, name: 'Tom Cook' },
{ id: 5, name: 'Tanya Fox' },
{ id: 6, name: 'Hellen Schmidt' },
{ id: 7, name: 'Caroline Schultz' },
{ id: 8, name: 'Mason Heaney' },
{ id: 9, name: 'Claudie Smitham' },
{ id: 10, name: 'Emil Schaefer' },
]
let active = ref(people[Math.floor(Math.random() * people.length)])
return {
people,
active,
classNames,
resolveListboxOptionClassName({ active }) {
return classNames(
'relative py-2 pl-3 cursor-default select-none pr-9 focus:outline-none',
active ? 'text-white bg-indigo-600' : 'text-gray-900'
)
},
}
},
}
</script>
@@ -1,86 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="inline-block mt-64 text-left">
<Menu>
<span class="inline-flex rounded-md shadow-sm">
<MenuButton
ref="trigger"
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<teleport to="body">
<MenuItems
ref="container"
class="absolute right-0 w-56 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div class="py-1">
<MenuItem as="a" href="#account-settings" :className="resolveClass">
Account settings
</MenuItem>
<MenuItem v-slot="data">
<a href="#support" :class="resolveClass(data)">Support</a>
</MenuItem>
<MenuItem as="a" disabled href="#new-feature" :className="resolveClass">
New feature (soon)
</MenuItem>
<MenuItem as="a" href="#license" :className="resolveClass">License</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" href="#sign-out" :className="resolveClass">Sign out</MenuItem>
</div>
</MenuItems>
</teleport>
</Menu>
</div>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { Menu, MenuButton, MenuItems, MenuItem },
setup(props, context) {
let [trigger, container] = usePopper({
placement: 'bottom-end',
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 10] } }],
})
function resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
}
return {
trigger,
container,
resolveClass,
}
},
}
</script>
@@ -1,94 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="relative inline-block mt-64 text-left">
<Menu>
<span class="inline-flex rounded-md shadow-sm">
<MenuButton
ref="trigger"
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<div ref="container" class="w-56">
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems
class="w-full bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div class="py-1">
<MenuItem as="a" :className="resolveClass" href="#account-settings">
Account settings
</MenuItem>
<MenuItem v-slot="data">
<a href="#support" :class="resolveClass(data)">Support</a>
</MenuItem>
<MenuItem as="a" :className="resolveClass" disabled href="#new-feature">
New feature (soon)
</MenuItem>
<MenuItem as="a" :className="resolveClass" href="#license">License</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" :className="resolveClass" href="#sign-out">Sign out</MenuItem>
</div>
</MenuItems>
</transition>
</div>
</Menu>
</div>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { Menu, MenuButton, MenuItems, MenuItem },
setup(props, context) {
let [trigger, container] = usePopper({
placement: 'bottom-end',
strategy: 'fixed',
modifiers: [{ name: 'offset', options: { offset: [0, 10] } }],
})
function resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
}
return {
trigger,
container,
resolveClass,
}
},
}
</script>
@@ -1,83 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="relative inline-block text-left">
<Menu>
<span class="rounded-md shadow-sm">
<MenuButton
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems
class="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div class="py-1">
<MenuItem as="a" href="#account-settings" :className="resolveClass">
Account settings
</MenuItem>
<MenuItem as="a" href="#support" :className="resolveClass">Support</MenuItem>
<MenuItem as="a" disabled href="#new-feature" :className="resolveClass">
New feature (soon)
</MenuItem>
<MenuItem as="a" href="#license" :className="resolveClass">License</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" href="#sign-out" :className="resolveClass">Sign out</MenuItem>
</div>
</MenuItems>
</transition>
</Menu>
</div>
</div>
</template>
<script>
import { defineComponent, h } from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: {
Menu,
MenuButton,
MenuItems,
MenuItem,
},
setup() {
return {
resolveClass({ active, disabled }) {
return classNames(
'flex justify-between w-full px-4 py-2 text-sm leading-5 text-left',
active ? 'bg-gray-100 text-gray-900' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
)
},
}
},
}
</script>
@@ -1,84 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="relative inline-block text-left">
<Menu>
<span class="rounded-md shadow-sm">
<MenuButton
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<MenuItems
class="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div class="py-1">
<CustomMenuItem href="#account-settings">Account settings</CustomMenuItem>
<CustomMenuItem href="#support">Support</CustomMenuItem>
<CustomMenuItem disabled href="#new-feature">New feature (soon)</CustomMenuItem>
<CustomMenuItem href="#license">License</CustomMenuItem>
</div>
<div class="py-1">
<CustomMenuItem href="#sign-out">Sign out</CustomMenuItem>
</div>
</MenuItems>
</Menu>
</div>
</div>
</template>
<script>
import { defineComponent, h } from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
let CustomMenuItem = defineComponent({
components: { Menu, MenuButton, MenuItems, MenuItem },
setup(props, { slots }) {
return () => {
return h(MenuItem, ({ active, disabled }) => {
return h(
'a',
{
class: classNames(
'flex justify-between w-full text-left px-4 py-2 text-sm leading-5',
active ? 'bg-indigo-500 text-white' : 'text-gray-700',
disabled && 'cursor-not-allowed opacity-50'
),
},
[
h('span', { class: classNames(active && 'font-bold') }, slots.default()),
h('kbd', { class: classNames('font-sans', active && 'text-indigo-50') }, '⌘K'),
]
)
})
}
},
})
export default {
components: {
Menu,
MenuButton,
MenuItems,
MenuItem,
CustomMenuItem,
},
}
</script>
@@ -1,125 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 space-x-4 bg-gray-50">
<div class="relative inline-block text-left">
<Menu>
<span class="rounded-md shadow-sm">
<MenuButton
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<MenuItems
class="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div class="py-1">
<MenuItem as="a" :className="resolveClass" href="#account-settings"
>Account settings</MenuItem
>
<MenuItem as="a" :className="resolveClass" href="#support">Support</MenuItem>
<MenuItem as="a" :className="resolveClass" disabled href="#new-feature"
>New feature (soon)</MenuItem
>
<MenuItem as="a" :className="resolveClass" href="#license">License</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" :className="resolveClass" href="#sign-out">Sign out</MenuItem>
</div>
</MenuItems>
</Menu>
</div>
<div>
<div class="relative rounded-md shadow-sm">
<input
class="block w-full form-input sm:text-sm sm:leading-5"
placeholder="you@example.com"
/>
</div>
</div>
<div class="relative inline-block text-left">
<Menu>
<span class="rounded-md shadow-sm">
<MenuButton
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
>
<span>Options</span>
<svg class="w-5 h-5 ml-2 -mr-1" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</MenuButton>
</span>
<MenuItems
class="absolute right-0 w-56 mt-2 origin-top-right bg-white border border-gray-200 divide-y divide-gray-100 rounded-md shadow-lg outline-none"
>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<div class="py-1">
<MenuItem as="a" :className="resolveClass" href="#account-settings"
>Account settings</MenuItem
>
<MenuItem as="a" :className="resolveClass" href="#support">Support</MenuItem>
<MenuItem as="a" :className="resolveClass" disabled href="#new-feature"
>New feature (soon)</MenuItem
>
<MenuItem as="a" :className="resolveClass" href="#license">License</MenuItem>
</div>
<div class="py-1">
<MenuItem as="a" :className="resolveClass" href="#sign-out">Sign out</MenuItem>
</div>
</MenuItems>
</Menu>
</div>
</div>
</template>
<script>
import { defineComponent, h } from 'vue'
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: {
Menu,
MenuButton,
MenuItems,
MenuItem,
},
setup() {
return {
resolveClass({ active, disabled }) {
return classNames(
'block w-full text-left px-4 py-2 text-sm leading-5 text-gray-700',
active && 'bg-gray-100 text-gray-900',
disabled && 'cursor-not-allowed opacity-50'
)
},
}
},
}
</script>
@@ -1,146 +0,0 @@
<template>
<div class="flex justify-center items-center space-x-12 p-12">
<button>Previous</button>
<PopoverGroup as="nav" ar-label="Mythical University" class="flex space-x-3">
<Popover as="div" class="relative">
<transition
enter-active-class="transition ease-out duration-300 transform"
enter-from-class="opacity-0"
enter-to-class="opacity-100"
leave-active-class="transition ease-in duration-300 transform"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<PopoverOverlay
class="bg-opacity-75 bg-gray-500 fixed inset-0 z-20"
></PopoverOverlay>
</transition>
<PopoverButton
class="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900 relative z-30"
>Normal</PopoverButton
>
<PopoverPanel class="absolute flex flex-col w-64 bg-gray-100 border-2 border-blue-900 z-30">
<a
v-for="(link, i) of links"
:hidden="i === 2"
href="/"
class="px-3 py-2 border-2 border-transparent hover:bg-gray-200 focus:bg-gray-200 focus:outline-none focus:border-blue-900"
>
Normal - {{ link }}
</a>
</PopoverPanel>
</Popover>
<Popover as="div" class="relative">
<PopoverButton
class="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900"
>Focus</PopoverButton
>
<PopoverPanel
focus
class="absolute flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
<a
v-for="(link, i) of links"
href="/"
class="px-3 py-2 border-2 border-transparent hover:bg-gray-200 focus:bg-gray-200 focus:outline-none focus:border-blue-900"
>
Focus - {{ link }}
</a>
</PopoverPanel>
</Popover>
<Popover as="div" class="relative">
<PopoverButton
ref="trigger1"
class="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900"
>Portal</PopoverButton
>
<Portal>
<PopoverPanel
ref="container1"
class="flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
<a
v-for="(link, i) of links"
href="/"
class="px-3 py-2 border-2 border-transparent hover:bg-gray-200 focus:bg-gray-200 focus:outline-none focus:border-blue-900"
>
Portal - {{ link }}
</a>
</PopoverPanel>
</Portal>
</Popover>
<Popover as="div" class="relative">
<PopoverButton
ref="trigger2"
class="px-3 py-2 bg-gray-300 border-2 border-transparent focus:outline-none focus:border-blue-900"
>Focus in portal</PopoverButton
>
<Portal>
<PopoverPanel
ref="container2"
focus
class="flex flex-col w-64 bg-gray-100 border-2 border-blue-900"
>
<a
v-for="(link, i) of links"
href="/"
class="px-3 py-2 border-2 border-transparent hover:bg-gray-200 focus:bg-gray-200 focus:outline-none focus:border-blue-900"
>
Focus in Portal - {{ link }}
</a>
</PopoverPanel>
</Portal>
</Popover>
</PopoverGroup>
<button>Next</button>
</div>
</template>
<script>
import { defineComponent } from 'vue'
import {
Popover,
PopoverOverlay,
PopoverPanel,
PopoverGroup,
PopoverButton,
Portal,
} from '@headlessui/vue'
import { usePopper } from '../../playground-utils/hooks/use-popper'
function html(templates) {
return templates.join('')
}
export default {
components: {
Popover,
PopoverPanel,
PopoverOverlay,
PopoverGroup,
PopoverButton,
Portal,
},
setup() {
let links = ['First', 'Second', 'Third', 'Fourth']
let [trigger1, container1] = usePopper({
placement: 'bottom-start',
strategy: 'fixed',
})
let [trigger2, container2] = usePopper({
placement: 'bottom-start',
strategy: 'fixed',
})
return { links, trigger1, container1, trigger2, container2 }
},
}
</script>
@@ -1,37 +0,0 @@
<template>
<div class="flex justify-center w-screen h-full p-12 bg-gray-50">
<div class="w-full max-w-xs mx-auto">
<main>
<aside ref="container" id="group-1">
A
</aside>
<PortalGroup :target="container">
<section id="group-2">
<span>B</span>
</section>
<Portal>Next to A</Portal>
</PortalGroup>
<Portal>I am in the portal root</Portal>
</main>
</div>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import { Portal, PortalGroup } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { Portal, PortalGroup },
setup(props, context) {
let container = ref(null)
return { container }
},
}
</script>
@@ -1,104 +0,0 @@
<template>
<div class="p-12 max-w-xl">
<a href="/">Link before</a>
<RadioGroup v-model="active">
<fieldset class="space-y-4">
<legend>
<h2 class="text-xl">Privacy setting</h2>
</legend>
<div class="bg-white rounded-md -space-y-px">
<RadioGroupOption
v-for="({ id, name, description }, i) in access"
:key="id"
:value="id"
v-slot="{ active, checked }"
:className="
({ active }) =>
classNames(
// Rounded corners
i === 0 && 'rounded-tl-md rounded-tr-md',
access.length - 1 === i && 'rounded-bl-md rounded-br-md',
// Shared
'relative border p-4 flex focus:outline-none',
active ? 'bg-indigo-50 border-indigo-200 z-10' : 'border-gray-200'
)
"
>
<div class="flex justify-between items-center w-full">
<div class="ml-3 flex flex-col cursor-pointer">
<span
:class="[
'block text-sm leading-5 font-medium',
active ? 'text-indigo-900' : 'text-gray-900',
]"
>
{{ name }}
</span>
<span
:class="['block text-sm leading-5', active ? 'text-indigo-700' : 'text-gray-500']"
>
{{ description }}
</span>
</div>
<div>
<svg
v-if="checked"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
class="h-5 w-5 text-indigo-500"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
</div>
</RadioGroupOption>
</div>
</fieldset>
</RadioGroup>
<a href="/">Link after</a>
</div>
</template>
<script>
import { ref } from 'vue'
import { RadioGroup, RadioGroupOption } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean)
}
export default {
components: { RadioGroup, RadioGroupOption },
setup() {
let active = ref()
let access = ref([
{
id: 'access-1',
name: 'Public access',
description: 'This project would be available to anyone who has the link',
},
{
id: 'access-2',
name: 'Private to Project Members',
description: 'Only members of this project would be able to access',
},
{
id: 'access-3',
name: 'Private to you',
description: 'You are the only one able to access this project',
},
])
return { active, access, classNames }
},
}
</script>
@@ -1,40 +0,0 @@
<template>
<div class="flex items-start justify-center w-screen h-full p-12 bg-gray-50">
<SwitchGroup as="div" class="flex items-center space-x-4">
<SwitchLabel>Enable notifications</SwitchLabel>
<Switch as="button" v-model="state" :className="resolveSwitchClass" v-slot="{ checked }">
<span
class="inline-block w-5 h-5 transition duration-200 ease-in-out transform bg-white rounded-full"
:class="{ 'translate-x-5': checked, 'translate-x-0': !checked }"
/>
</Switch>
</SwitchGroup>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import { SwitchGroup, Switch, SwitchLabel } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
export default {
components: { SwitchGroup, Switch, SwitchLabel },
setup(props, context) {
let state = ref(false)
return {
state,
resolveSwitchClass({ checked }) {
return classNames(
'relative inline-flex flex-shrink-0 h-6 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer w-11 focus:outline-none focus:shadow-outline',
checked ? 'bg-indigo-600' : 'bg-gray-200'
)
},
}
},
}
</script>
@@ -1,81 +0,0 @@
<template>
<div class="flex flex-col items-start w-screen h-full p-12 bg-gray-50 space-y-12">
<SwitchGroup as="div" class="flex items-center space-x-4">
<SwitchLabel>Manual keyboard activation</SwitchLabel>
<Switch as="button" v-model="manual" :className="resolveSwitchClass" v-slot="{ checked }">
<span
class="inline-block w-5 h-5 transition duration-200 ease-in-out transform bg-white rounded-full"
:class="{ 'translate-x-5': checked, 'translate-x-0': !checked }"
/>
</Switch>
</SwitchGroup>
<TabGroup class="flex flex-col max-w-3xl w-full" as="div" :manual="manual">
<TabList class="relative z-0 rounded-lg shadow flex divide-x divide-gray-200">
<Tab
v-for="(tab, tabIdx) in tabs"
:key="tab.name"
:disabled="tab.disabled"
class="group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-sm font-medium text-center hover:bg-gray-50 focus:z-10"
:class="{
'text-gray-900': selected,
'text-gray-500 hover:text-gray-700': !selected,
'rounded-l-lg': tabIdx === 0,
'rounded-r-lg': tabIdx === tabs.length - 1,
'opacity-50': tab.disabled,
}"
v-slot="{ selected }"
>
<span>{{tab.name}}</span>
<small v-if="tab.disabled" class="inline-block px-4 text-xs">(disabled)</small>
<span
aria-hidden="true"
class="absolute inset-x-0 bottom-0 h-0.5"
:class="{'bg-indigo-500': selected, 'bg-transparent':!selected}"
/>
</Tab>
</TabList>
<TabPanels class="mt-4">
<TabPanel v-for="tab in tabs" class="bg-white rounded-lg p-4 shadow" key="tab.name">
{{tab.content}}
</TabPanel>
</TabPanels>
</TabGroup>
</div>
</template>
<script>
import { defineComponent, h, ref, onMounted, watchEffect, watch } from 'vue'
import { SwitchGroup, Switch, SwitchLabel, TabGroup, TabList, Tab, TabPanels, TabPanel } from '@headlessui/vue'
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
}
let tabs = [
{ name: 'My Account', content: 'Tab content for my account' },
{ name: 'Company', content: 'Tab content for company', disabled: true },
{ name: 'Team Members', content: 'Tab content for team members' },
{ name: 'Billing', content: 'Tab content for billing' },
]
export default {
components: { SwitchGroup, Switch, SwitchLabel, TabGroup, TabList, Tab, TabPanels, TabPanel },
setup(props, context) {
let manual = ref(false)
return {
tabs: ref(tabs),
manual,
resolveSwitchClass({ checked }) {
return classNames(
'relative inline-flex flex-shrink-0 h-6 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer w-11 focus:outline-none focus:shadow-outline',
checked ? 'bg-indigo-600' : 'bg-gray-200'
)
},
}
},
}
</script>
@@ -1,9 +0,0 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import 'tailwindcss/tailwind.css'
createApp(App)
.use(router)
.mount('#app')
@@ -1,26 +0,0 @@
import { ref, onMounted, watchEffect } from 'vue'
import { createPopper } from '@popperjs/core'
export function usePopper(options) {
let reference = ref(null)
let popper = ref(null)
onMounted(() => {
watchEffect(onInvalidate => {
if (!popper.value) return
if (!reference.value) return
let popperEl = popper.value.el || popper.value
let referenceEl = reference.value.el || reference.value
if (!(referenceEl instanceof HTMLElement)) return
if (!(popperEl instanceof HTMLElement)) return
let { destroy } = createPopper(referenceEl, popperEl, options)
onInvalidate(destroy)
})
})
return [reference, popper]
}
@@ -1,23 +0,0 @@
import { createWebHistory, createRouter, RouterView } from 'vue-router'
import lookup from './.generated/preload.js'
import routes from './routes.json'
function buildRoutes(routes) {
return routes.map(route => {
let definition = {
path: route.path,
component: route.component ? lookup[route.component] : RouterView,
}
if (route.children) {
definition.children = buildRoutes(route.children)
}
return definition
})
}
export default createRouter({
history: createWebHistory(),
routes: buildRoutes(routes),
})
@@ -1,141 +0,0 @@
[
{
"path": "/",
"component": "./components/Home.vue"
},
{
"name": "Menu",
"path": "/menu",
"children": [
{
"name": "Menu (basic)",
"path": "/menu/menu",
"component": "./components/menu/menu.vue"
},
{
"name": "Menu with Popper",
"path": "/menu/menu-with-popper",
"component": "./components/menu/menu-with-popper.vue"
},
{
"name": "Menu with Transition",
"path": "/menu/menu-with-transition",
"component": "./components/menu/menu-with-transition.vue"
},
{
"name": "Menu with Popper + Transition",
"path": "/menu/menu-with-transition-and-popper",
"component": "./components/menu/menu-with-transition-and-popper.vue"
},
{
"name": "Menu multiple elements",
"path": "/menu/multiple-elements",
"component": "./components/menu/multiple-elements.vue"
}
]
},
{
"name": "Listbox",
"path": "/listbox",
"children": [
{
"name": "Listbox (basic)",
"path": "/listbox/listbox",
"component": "./components/listbox/listbox.vue"
},
{
"name": "Listbox multiple elements",
"path": "/listbox/multiple-elements",
"component": "./components/listbox/multiple-elements.vue"
}
]
},
{
"name": "Switch",
"path": "/switch",
"children": [
{
"name": "Switch (basic)",
"path": "/switch/switch",
"component": "./components/switch/switch.vue"
}
]
},
{
"name": "Tabs",
"path": "/tabs",
"children": [
{
"name": "Tabs (basic)",
"path": "/tabs/tabs",
"component": "./components/tabs/tabs.vue"
}
]
},
{
"name": "Focus Trap",
"path": "/focus-trap",
"children": [
{
"name": "FocusTrap (basic)",
"path": "/focus-trap/focus-trap",
"component": "./components/focus-trap/focus-trap.vue"
}
]
},
{
"name": "Portal",
"path": "/portal",
"children": [
{
"name": "Portal (group)",
"path": "/portal/portal",
"component": "./components/portal/portal.vue"
}
]
},
{
"name": "Popover",
"path": "/popover",
"children": [
{
"name": "Popover",
"path": "/popover/popover",
"component": "./components/popover/popover.vue"
}
]
},
{
"name": "Disclosure",
"path": "/disclosure",
"children": [
{
"name": "Disclosure",
"path": "/disclosure/disclosure",
"component": "./components/disclosure/disclosure.vue"
}
]
},
{
"name": "Dialog",
"path": "/dialog",
"children": [
{
"name": "Dialog",
"path": "/dialog/dialog",
"component": "./components/dialog/dialog.vue"
}
]
},
{
"name": "RadioGroup",
"path": "/radio-group",
"children": [
{
"name": "RadioGroup",
"path": "/radio-group/radio-group",
"component": "./components/radio-group/radio-group.vue"
}
]
}
]
+1 -8
View File
@@ -23,8 +23,6 @@
"access": "public"
},
"scripts": {
"playground": "vite --config ./vite.config.js serve examples",
"playground:build": "NODE_ENV=production vite build examples",
"prepublishOnly": "npm run build",
"build": "../../scripts/build.sh",
"watch": "../../scripts/watch.sh",
@@ -35,13 +33,8 @@
"vue": "^3.0.0"
},
"devDependencies": {
"@popperjs/core": "^2.5.3",
"@testing-library/vue": "^5.1.0",
"@types/debounce": "^1.2.0",
"@vue/compiler-sfc": "3.0.1",
"@vue/test-utils": "^2.0.0-beta.7",
"vite": "^1.0.0-rc.4",
"vue": "^3.0.0",
"vue-router": "^4.0.0-beta.13"
"vue": "3.0.7"
}
}
@@ -1 +0,0 @@
module.exports = require('../../tailwind.config.js')
-122
View File
@@ -1,122 +0,0 @@
let fs = require('fs')
let path = require('path')
let prettier = require('prettier')
let Prism = require('prismjs')
require('prismjs/plugins/custom-class/prism-custom-class')
let routes = require('./examples/src/routes')
function flatten(routes, resolver) {
return routes
.map(route => (route.children ? flatten(route.children, resolver) : resolver(route)))
.flat(Infinity)
}
// This is a hack, but the idea is that we want to import all the examples from the routes.json
// file. However just doing dynamic imports() doesn't work well at build time. Therefore we will
// generate a fake file that contains them all.
let i = 0
let map = {}
let contents = flatten(routes, route => route.component)
.map(path => {
let name = `Component$${++i}`
map[path] = name
return `import ${name} from ".${path}";`
})
.join('\n')
fs.writeFileSync(
path.resolve(__dirname, './examples/src/.generated/preload.js'),
`${contents}\n\nexport default {\n${Object.entries(map)
.map(([path, name]) => ` "${path}": ${name}`)
.join(',\n')}\n}`,
'utf8'
)
// ---
function pipe(...fns) {
return fns.reduceRight((f, g) => (...args) => f(g(...args)), fns.pop())
}
Prism.plugins.customClass.map({
tag: 'text-code-red',
'attr-name': 'text-code-yellow',
'attr-value': 'text-code-green',
deleted: 'text-code-red',
inserted: 'text-code-green',
punctuation: 'text-code-white',
keyword: 'text-code-purple',
string: 'text-code-green',
function: 'text-code-blue',
boolean: 'text-code-red',
comment: 'text-gray-400 italic',
})
let sourcePipeline = pipe(
path => fs.readFileSync(path, 'utf8'),
contents =>
prettier.format(contents, {
parser: 'vue',
printWidth: 100,
semi: false,
singleQuote: true,
trailingComma: 'es5',
}),
contents => Prism.highlight(contents, Prism.languages.markup),
contents =>
[
'<pre class="language-vue rounded-md bg-gray-800 py-3 px-4 overflow-x-auto">',
'<code class="language-vue text-gray-200">',
contents,
'</code>',
'</pre>',
].join('')
)
let skipRoutes = ['/']
let source = Object.assign(
{},
...flatten(routes, route => ({
urlPath: route.path,
sourcePath: route.component,
}))
.filter(({ urlPath }) => !skipRoutes.includes(urlPath))
.map(({ urlPath, sourcePath }) => ({
[urlPath]: sourcePipeline(path.resolve(__dirname, 'examples', 'src', sourcePath), 'utf8'),
}))
)
fs.writeFileSync(
path.resolve(__dirname, './examples/src/.generated/source.json'),
JSON.stringify(source, null, 2),
'utf8'
)
// ---
let HeadlessUIPlugin = ({
root, // project root directory, absolute path
app, // Koa app instance
server, // raw http server instance
watcher, // chokidar file watcher instance
resolver, // chokidar file watcher instance
}) => {
let routePaths = flatten(routes, route => route.path)
app.use(async (ctx, next) => {
if (routePaths.includes(ctx.path)) {
ctx.path = './index.html'
}
await next()
})
}
module.exports = {
alias: {
[process.env.NODE_ENV === 'production' ? '@headlessui/vue' : '/@headlessui/vue/']: path.resolve(
__dirname,
'./src/index.ts'
),
},
configureServer: [HeadlessUIPlugin],
}
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
-27
View File
@@ -1,27 +0,0 @@
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
purge: [],
theme: {
container: {
center: true,
},
extend: {
fontFamily: {
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
},
colors: {
code: {
green: '#b5f4a5',
yellow: '#ffe484',
purple: '#d9a9ff',
red: '#ff8383',
blue: '#93ddfd',
white: '#fff',
},
},
},
},
variants: {},
plugins: [require('@tailwindcss/ui')],
}
+509 -4451
View File
File diff suppressed because it is too large Load Diff