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 { AppLogo } from "~/modules/app/app-logo"
|
||||||
import { useGuideLinksContext } from "~/modules/navigation/guide-links-context"
|
|
||||||
import { linkClass } from "../ui/components"
|
import { linkClass } from "../ui/components"
|
||||||
import { PopoverMenu } from "../ui/popover-menu"
|
|
||||||
import { AppLink } from "./app-link"
|
import { AppLink } from "./app-link"
|
||||||
import { mainLinks } from "./main-links"
|
import { mainLinks } from "./main-links"
|
||||||
|
import { MainNavigationMenu } from "./main-navigation-menu"
|
||||||
|
|
||||||
export function MainNavigation() {
|
export function MainNavigation() {
|
||||||
const guideLinks = useGuideLinksContext()
|
|
||||||
return (
|
return (
|
||||||
<nav className="flex justify-between items-center h-16">
|
<nav className="flex justify-between items-center h-16">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
@@ -18,25 +16,7 @@ export function MainNavigation() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="md:hidden">
|
<div className="md:hidden">
|
||||||
<PopoverMenu>
|
<MainNavigationMenu />
|
||||||
{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>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</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 name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<Meta />
|
<Meta />
|
||||||
<Links />
|
<Links />
|
||||||
<script defer src="https://unpkg.com/alpinejs@3.7.1/dist/cdn.min.js" />
|
|
||||||
{process.env.NODE_ENV === "production" && (
|
{process.env.NODE_ENV === "production" && (
|
||||||
<script
|
<script
|
||||||
async
|
async
|
||||||
defer
|
|
||||||
data-website-id="49c69ade-5593-4853-9686-c9ca9d519a18"
|
data-website-id="49c69ade-5593-4853-9686-c9ca9d519a18"
|
||||||
src="https://maple-umami.fly.dev/umami.js"
|
src="https://maple-umami.fly.dev/umami.js"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
export default function GuidePage() {
|
export default function GuidePage() {
|
||||||
const guideLinks = useGuideLinksContext()
|
const guideLinks = useGuideLinksContext()
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="isolate">
|
||||||
<header className="bg-slate-700/30 shadow sticky top-0 backdrop-blur-sm transition z-10 flex">
|
<header className="bg-slate-700/30 shadow sticky top-0 backdrop-blur-sm transition z-10 flex">
|
||||||
<div className={maxWidthContainer}>
|
<div className={maxWidthContainer}>
|
||||||
<MainNavigation />
|
<MainNavigation />
|
||||||
@@ -33,6 +33,6 @@ export default function GuidePage() {
|
|||||||
<Outlet />
|
<Outlet />
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
"typecheck": "tsc --noEmit && tsc --project cypress/tsconfig.json --noEmit"
|
"typecheck": "tsc --noEmit && tsc --project cypress/tsconfig.json --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@headlessui/react": "^1.4.2",
|
||||||
"@heroicons/react": "^1.0.5",
|
"@heroicons/react": "^1.0.5",
|
||||||
|
"@reach/rect": "^0.16.0",
|
||||||
"@remix-run/react": "^1.1.1",
|
"@remix-run/react": "^1.1.1",
|
||||||
"@remix-run/serve": "^1.1.1",
|
"@remix-run/serve": "^1.1.1",
|
||||||
"@tailwindcss/typography": "^0.5.0",
|
"@tailwindcss/typography": "^0.5.0",
|
||||||
|
|||||||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -91,7 +91,9 @@ importers:
|
|||||||
|
|
||||||
packages/website:
|
packages/website:
|
||||||
specifiers:
|
specifiers:
|
||||||
|
'@headlessui/react': ^1.4.2
|
||||||
'@heroicons/react': ^1.0.5
|
'@heroicons/react': ^1.0.5
|
||||||
|
'@reach/rect': ^0.16.0
|
||||||
'@remix-run/dev': ^1.1.1
|
'@remix-run/dev': ^1.1.1
|
||||||
'@remix-run/node': ^1.1.1
|
'@remix-run/node': ^1.1.1
|
||||||
'@remix-run/react': ^1.1.1
|
'@remix-run/react': ^1.1.1
|
||||||
@@ -122,7 +124,9 @@ importers:
|
|||||||
typescript: ^4.5.4
|
typescript: ^4.5.4
|
||||||
wait-on: ^6.0.0
|
wait-on: ^6.0.0
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@headlessui/react': 1.4.2_react-dom@17.0.2+react@17.0.2
|
||||||
'@heroicons/react': 1.0.5_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/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
|
'@remix-run/serve': 1.1.1_react-dom@17.0.2+react@17.0.2
|
||||||
'@tailwindcss/typography': 0.5.0_tailwindcss@3.0.13
|
'@tailwindcss/typography': 0.5.0_tailwindcss@3.0.13
|
||||||
@@ -588,6 +592,17 @@ packages:
|
|||||||
'@hapi/hoek': 9.2.1
|
'@hapi/hoek': 9.2.1
|
||||||
dev: true
|
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:
|
/@heroicons/react/1.0.5_react@17.0.2:
|
||||||
resolution: {integrity: sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==}
|
resolution: {integrity: sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -826,6 +841,37 @@ packages:
|
|||||||
'@octokit/openapi-types': 11.2.0
|
'@octokit/openapi-types': 11.2.0
|
||||||
dev: true
|
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:
|
/@remix-run/dev/1.1.1:
|
||||||
resolution: {integrity: sha512-dkzMVgMzaQUppf2za3kD+izsEK1hLsLQSVtDD3wN7pBMEbWXaEkWb2X2lj3c9yRDArPB7y5+09rm4SUnE4mL6A==}
|
resolution: {integrity: sha512-dkzMVgMzaQUppf2za3kD+izsEK1hLsLQSVtDD3wN7pBMEbWXaEkWb2X2lj3c9yRDArPB7y5+09rm4SUnE4mL6A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -8016,6 +8062,10 @@ packages:
|
|||||||
/through/2.3.8:
|
/through/2.3.8:
|
||||||
resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
|
resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
|
||||||
|
|
||||||
|
/tiny-warning/1.0.3:
|
||||||
|
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/tinypool/0.1.1:
|
/tinypool/0.1.1:
|
||||||
resolution: {integrity: sha512-sW2fQZ2BRb/GX5v55NkHiTrbMLx0eX0xNpP+VGhOe2f7Oo04+LeClDyM19zCE/WCy7jJ8kzIJ0Ojrxj3UhN9Sg==}
|
resolution: {integrity: sha512-sW2fQZ2BRb/GX5v55NkHiTrbMLx0eX0xNpP+VGhOe2f7Oo04+LeClDyM19zCE/WCy7jJ8kzIJ0Ojrxj3UhN9Sg==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
|
|||||||
Reference in New Issue
Block a user