Create root-level CommandK component inside Modal

This commit is contained in:
Sam Becker 2024-02-19 10:02:51 -06:00
parent 6ea0084e3d
commit e92ec878dc
4 changed files with 72 additions and 6 deletions

View File

@ -13,6 +13,7 @@ import Footer from '@/site/Footer';
import { Suspense } from 'react';
import FooterClient from '@/site/FooterClient';
import NavClient from '@/site/NavClient';
import CommandK from '@/components/CommandK';
import '../site/globals.css';
@ -97,6 +98,7 @@ export default function RootLayout({
<SpeedInsights />
<PhotoEscapeHandler />
<ToasterWithThemes />
<CommandK />
</body>
</html>
);

View File

@ -0,0 +1,54 @@
'use client';
import { Command } from 'cmdk';
import { useEffect, useState } from 'react';
import Modal from './Modal';
import { clsx } from 'clsx/lite';
const LISTENER_KEYDOWN = 'keydown';
export default function CommandK() {
const [open, setOpen] = useState(false);
useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((open) => !open);
}
};
document.addEventListener(LISTENER_KEYDOWN, down);
return () => document.removeEventListener(LISTENER_KEYDOWN, down);
}, []);
const renderItem = (item: string) =>
<Command.Item className={clsx(
'p-1 rounded-md',
'data-[selected=true]:bg-blue-50',
)}>
{item}
</Command.Item>;
return (
<Command.Dialog
open={open}
onOpenChange={setOpen}
label="Global Command Menu"
>
<Modal onClose={() => setOpen(false)} fast>
<Command.Input className="w-full" />
<Command.List>
<Command.Empty>No results found.</Command.Empty>
<Command.Group heading="Letters">
{renderItem('a')}
{renderItem('b')}
<Command.Separator />
{renderItem('c')}
</Command.Group>
{renderItem('Apple')}
</Command.List>
</Modal>
</Command.Dialog>
);
}

View File

@ -11,10 +11,14 @@ import usePrefersReducedMotion from '@/utility/usePrefersReducedMotion';
export default function Modal({
onClosePath,
onClose,
children,
fast,
}: {
onClosePath?: string
onClose?: () => void
children: ReactNode
fast?: boolean
}) {
const router = useRouter();
@ -32,10 +36,16 @@ export default function Modal({
useClickInsideOutside({
htmlElements,
onClickOutside: () => router.push(
onClickOutside: () => {
if (onClose) {
onClose();
} else {
router.push(
onClosePath ?? PATH_ROOT,
{ scroll: false },
),
);
}
},
});
return (
@ -51,7 +61,7 @@ export default function Modal({
transition={{ duration: 0.3, easing: 'easeOut' }}
>
<AnimateItems
duration={0.3}
duration={fast ? 0.1 : 0.3}
items={[<div
key="modalContent"
className={clsx(

View File

@ -1,6 +1,6 @@
import React, { ReactNode, useState } from 'react';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import clsx from 'clsx';
import { clsx } from 'clsx/lite';
import { FiMoreHorizontal } from 'react-icons/fi';
import Link from 'next/link';