new main nav menu, remove alpine
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { Menu, Transition } from "@headlessui/react"
|
||||
import { MenuAlt4Icon } from "@heroicons/react/outline"
|
||||
import clsx from "clsx"
|
||||
import { useGuideLinksContext } from "~/modules/navigation/guide-links-context"
|
||||
import { Popper } from "~/modules/ui/popper"
|
||||
import { AppLink } from "./app-link"
|
||||
import { mainLinks } from "./main-links"
|
||||
|
||||
export function MainNavigationMenu() {
|
||||
const guideLinks = useGuideLinksContext()
|
||||
return (
|
||||
<Menu>
|
||||
<Popper
|
||||
renderReference={(reference) => (
|
||||
<Menu.Button {...reference}>
|
||||
<MenuAlt4Icon className="w-6" />
|
||||
<span className="sr-only">Menu</span>
|
||||
</Menu.Button>
|
||||
)}
|
||||
renderPopover={() => (
|
||||
<Transition
|
||||
enter="transition"
|
||||
enterFrom="translate-y-4 opacity-0"
|
||||
enterTo="translate-y-0 opacity-100"
|
||||
leave="transition"
|
||||
leaveFrom="translate-y-0 opacity-100"
|
||||
leaveTo="translate-y-4 opacity-0"
|
||||
>
|
||||
<Menu.Items className="w-48 max-h-[calc(100vh-5rem)] bg-slate-800 shadow rounded-lg overflow-hidden overflow-y-auto focus:outline-none">
|
||||
{mainLinks.map((link) => (
|
||||
<Menu.Item key={link.to}>
|
||||
{({ active }) => (
|
||||
<AppLink {...link} className={menuItemClass({ active })} />
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
<Menu.Item disabled>
|
||||
<hr className="border-0 h-[2px] bg-black/50" />
|
||||
</Menu.Item>
|
||||
{guideLinks.map(({ link }) => (
|
||||
<Menu.Item key={link.to}>
|
||||
{({ active }) => (
|
||||
<AppLink {...link} className={menuItemClass({ active })} />
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
)}
|
||||
/>
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
const menuItemClass = ({ active = false }) =>
|
||||
clsx(
|
||||
clsx`px-3 py-2 transition text-left font-medium block opacity-50`,
|
||||
active && clsx`opacity-100 bg-black/75 text-emerald-400`,
|
||||
)
|
||||
@@ -1,12 +1,10 @@
|
||||
import { AppLogo } from "~/modules/app/app-logo"
|
||||
import { useGuideLinksContext } from "~/modules/navigation/guide-links-context"
|
||||
import { linkClass } from "../ui/components"
|
||||
import { PopoverMenu } from "../ui/popover-menu"
|
||||
import { AppLink } from "./app-link"
|
||||
import { mainLinks } from "./main-links"
|
||||
import { MainNavigationMenu } from "./main-navigation-menu"
|
||||
|
||||
export function MainNavigation() {
|
||||
const guideLinks = useGuideLinksContext()
|
||||
return (
|
||||
<nav className="flex justify-between items-center h-16">
|
||||
<a href="/">
|
||||
@@ -18,25 +16,7 @@ export function MainNavigation() {
|
||||
))}
|
||||
</div>
|
||||
<div className="md:hidden">
|
||||
<PopoverMenu>
|
||||
{mainLinks.map((link) => (
|
||||
<AppLink
|
||||
{...link}
|
||||
role="menuitem"
|
||||
key={link.to}
|
||||
className={PopoverMenu.itemClass}
|
||||
/>
|
||||
))}
|
||||
<hr className="border-0 h-[2px] bg-black/50" />
|
||||
{guideLinks.map(({ link }) => (
|
||||
<AppLink
|
||||
{...link}
|
||||
role="menuitem"
|
||||
key={link.to}
|
||||
className={PopoverMenu.itemClass}
|
||||
/>
|
||||
))}
|
||||
</PopoverMenu>
|
||||
<MainNavigationMenu />
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { MenuAlt4Icon } from "@heroicons/react/outline"
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { linkClass } from "./components"
|
||||
|
||||
export function PopoverMenu({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="relative" x-data="{ open: false }">
|
||||
<button title="Menu" className={linkClass} x-on:click="open = !open">
|
||||
<MenuAlt4Icon className="w-6" />
|
||||
</button>
|
||||
<div
|
||||
role="menu"
|
||||
className={`
|
||||
w-48 max-h-[calc(100vh-4rem)]
|
||||
absolute right-0 top-[calc(100%+8px)]
|
||||
bg-slate-800 shadow rounded-lg
|
||||
overflow-hidden overflow-y-auto
|
||||
transition-all
|
||||
`}
|
||||
x-bind:class="open ? 'visible opacity-100' : 'invisible opacity-0 translate-y-3'"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
PopoverMenu.itemClass = clsx`
|
||||
px-3 py-2 transition text-left font-medium block
|
||||
opacity-50 hover:opacity-100 hover:bg-black/30
|
||||
`
|
||||
41
packages/website/app/modules/ui/popper.tsx
Normal file
41
packages/website/app/modules/ui/popper.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { useRect } from "@reach/rect"
|
||||
import * as React from "react"
|
||||
import { Portal } from "~/modules/dom/portal"
|
||||
|
||||
export function Popper({
|
||||
renderReference,
|
||||
renderPopover,
|
||||
}: {
|
||||
renderReference: (referenceProps: {
|
||||
ref: (element: HTMLElement | null | undefined) => void
|
||||
}) => React.ReactNode
|
||||
renderPopover: () => React.ReactNode
|
||||
}) {
|
||||
const [reference, referenceRef] = React.useState<HTMLElement | null>()
|
||||
const referenceRect = useRect(useValueAsRefObject(reference))
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderReference({ ref: referenceRef })}
|
||||
<Portal>
|
||||
{referenceRect && (
|
||||
<div
|
||||
className="fixed -translate-x-full"
|
||||
style={{
|
||||
left: referenceRect.right,
|
||||
top: referenceRect.bottom + 16,
|
||||
}}
|
||||
>
|
||||
{renderPopover()}
|
||||
</div>
|
||||
)}
|
||||
</Portal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function useValueAsRefObject<Value>(value: Value): { readonly current: Value } {
|
||||
const ref = React.useRef<Value>(value)
|
||||
ref.current = value
|
||||
return ref
|
||||
}
|
||||
@@ -73,11 +73,9 @@ export default function App() {
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<Meta />
|
||||
<Links />
|
||||
<script defer src="https://unpkg.com/alpinejs@3.7.1/dist/cdn.min.js" />
|
||||
{process.env.NODE_ENV === "production" && (
|
||||
<script
|
||||
async
|
||||
defer
|
||||
data-website-id="49c69ade-5593-4853-9686-c9ca9d519a18"
|
||||
src="https://maple-umami.fly.dev/umami.js"
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
export default function GuidePage() {
|
||||
const guideLinks = useGuideLinksContext()
|
||||
return (
|
||||
<>
|
||||
<div className="isolate">
|
||||
<header className="bg-slate-700/30 shadow sticky top-0 backdrop-blur-sm transition z-10 flex">
|
||||
<div className={maxWidthContainer}>
|
||||
<MainNavigation />
|
||||
@@ -33,6 +33,6 @@ export default function GuidePage() {
|
||||
<Outlet />
|
||||
</section>
|
||||
</main>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
"typecheck": "tsc --noEmit && tsc --project cypress/tsconfig.json --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.4.2",
|
||||
"@heroicons/react": "^1.0.5",
|
||||
"@reach/rect": "^0.16.0",
|
||||
"@remix-run/react": "^1.1.1",
|
||||
"@remix-run/serve": "^1.1.1",
|
||||
"@tailwindcss/typography": "^0.5.0",
|
||||
|
||||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -91,7 +91,9 @@ importers:
|
||||
|
||||
packages/website:
|
||||
specifiers:
|
||||
'@headlessui/react': ^1.4.2
|
||||
'@heroicons/react': ^1.0.5
|
||||
'@reach/rect': ^0.16.0
|
||||
'@remix-run/dev': ^1.1.1
|
||||
'@remix-run/node': ^1.1.1
|
||||
'@remix-run/react': ^1.1.1
|
||||
@@ -122,7 +124,9 @@ importers:
|
||||
typescript: ^4.5.4
|
||||
wait-on: ^6.0.0
|
||||
dependencies:
|
||||
'@headlessui/react': 1.4.2_react-dom@17.0.2+react@17.0.2
|
||||
'@heroicons/react': 1.0.5_react@17.0.2
|
||||
'@reach/rect': 0.16.0_react-dom@17.0.2+react@17.0.2
|
||||
'@remix-run/react': 1.1.1_react-dom@17.0.2+react@17.0.2
|
||||
'@remix-run/serve': 1.1.1_react-dom@17.0.2+react@17.0.2
|
||||
'@tailwindcss/typography': 0.5.0_tailwindcss@3.0.13
|
||||
@@ -588,6 +592,17 @@ packages:
|
||||
'@hapi/hoek': 9.2.1
|
||||
dev: true
|
||||
|
||||
/@headlessui/react/1.4.2_react-dom@17.0.2+react@17.0.2:
|
||||
resolution: {integrity: sha512-N8tv7kLhg9qGKBkVdtg572BvKvWhmiudmeEpOCyNwzOsZHCXBtl8AazGikIfUS+vBoub20Fse3BjawXDVPPdug==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
react: ^16 || ^17 || ^18
|
||||
react-dom: ^16 || ^17 || ^18
|
||||
dependencies:
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
dev: false
|
||||
|
||||
/@heroicons/react/1.0.5_react@17.0.2:
|
||||
resolution: {integrity: sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==}
|
||||
peerDependencies:
|
||||
@@ -826,6 +841,37 @@ packages:
|
||||
'@octokit/openapi-types': 11.2.0
|
||||
dev: true
|
||||
|
||||
/@reach/observe-rect/1.2.0:
|
||||
resolution: {integrity: sha512-Ba7HmkFgfQxZqqaeIWWkNK0rEhpxVQHIoVyW1YDSkGsGIXzcaW4deC8B0pZrNSSyLTdIk7y+5olKt5+g0GmFIQ==}
|
||||
dev: false
|
||||
|
||||
/@reach/rect/0.16.0_react-dom@17.0.2+react@17.0.2:
|
||||
resolution: {integrity: sha512-/qO9jQDzpOCdrSxVPR6l674mRHNTqfEjkaxZHluwJ/2qGUtYsA0GSZiF/+wX/yOWeBif1ycxJDa6HusAMJZC5Q==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || 17.x
|
||||
react-dom: ^16.8.0 || 17.x
|
||||
dependencies:
|
||||
'@reach/observe-rect': 1.2.0
|
||||
'@reach/utils': 0.16.0_react-dom@17.0.2+react@17.0.2
|
||||
prop-types: 15.8.1
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
tiny-warning: 1.0.3
|
||||
tslib: 2.3.1
|
||||
dev: false
|
||||
|
||||
/@reach/utils/0.16.0_react-dom@17.0.2+react@17.0.2:
|
||||
resolution: {integrity: sha512-PCggBet3qaQmwFNcmQ/GqHSefadAFyNCUekq9RrWoaU9hh/S4iaFgf2MBMdM47eQj5i/Bk0Mm07cP/XPFlkN+Q==}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || 17.x
|
||||
react-dom: ^16.8.0 || 17.x
|
||||
dependencies:
|
||||
react: 17.0.2
|
||||
react-dom: 17.0.2_react@17.0.2
|
||||
tiny-warning: 1.0.3
|
||||
tslib: 2.3.1
|
||||
dev: false
|
||||
|
||||
/@remix-run/dev/1.1.1:
|
||||
resolution: {integrity: sha512-dkzMVgMzaQUppf2za3kD+izsEK1hLsLQSVtDD3wN7pBMEbWXaEkWb2X2lj3c9yRDArPB7y5+09rm4SUnE4mL6A==}
|
||||
hasBin: true
|
||||
@@ -8016,6 +8062,10 @@ packages:
|
||||
/through/2.3.8:
|
||||
resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
|
||||
|
||||
/tiny-warning/1.0.3:
|
||||
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||
dev: false
|
||||
|
||||
/tinypool/0.1.1:
|
||||
resolution: {integrity: sha512-sW2fQZ2BRb/GX5v55NkHiTrbMLx0eX0xNpP+VGhOe2f7Oo04+LeClDyM19zCE/WCy7jJ8kzIJ0Ojrxj3UhN9Sg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
Reference in New Issue
Block a user