Files
headlessui/packages/@headlessui-react/pages/transitions/full-page-examples/layout-with-sidebar.tsx
T
Robin Malfait ef00732685 cleanup and consistency (#213)
- Made the use of `const` and `let` consistent
- import required functions and types from 'react' instead of using the
  `React.` namespace.
- Added `Expand` type, which can expand complex types to their "final"
  result.
- Ensured that we use `as const` for DEFAULT_XXX_TAG where we used a
  string. So that we have the type of `div` instead of `string` for
  example.
- Used `interface` over `type` where possible. I'm personally more of a
  `type` fan. But the TypeScript recommends `interfaces` where possible
  because they are faster, yield better error messages and so on.
2021-01-30 14:46:54 +01:00

171 lines
6.7 KiB
TypeScript

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>
</>
)
}