Skip to content

Commit

Permalink
UI: [expermental] Use drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
fuma-nama committed Jan 7, 2024
1 parent e372d7a commit 9bc2a26
Show file tree
Hide file tree
Showing 16 changed files with 347 additions and 119 deletions.
4 changes: 1 addition & 3 deletions apps/docs/app/provider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
'use client';

import { RootProvider } from 'next-docs-ui/provider';
import dynamic from 'next/dynamic';
import type { ReactNode } from 'react';

const SearchDialog = dynamic(() => import('@/components/search'));
import SearchDialog from '@/components/search';

export function Provider({ children }: { children: ReactNode }): JSX.Element {
return (
Expand Down
3 changes: 2 additions & 1 deletion apps/docs/app/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
@tailwind utilities;

.dark {
--background: 210 100% 1%;
--background: 0 0% 1%;
--popover: 0 0% 4%;
--card: 0 0% 4%;
--muted: 0 0% 8%;
--border: 0 0% 14%;
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/components/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default function CustomSearchDialog(props: SharedProps): JSX.Element {
filters: `tag:${tag}`,
}}
footer={
<div className="flex flex-row items-center gap-1 p-3">
<div className="flex flex-row items-center gap-1">
{modes.map((mode) => (
<button
key={mode.param}
Expand Down
5 changes: 2 additions & 3 deletions apps/docs/tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const { default: createDocsUI } = require('next-docs-ui/tailwind-plugin');

/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: 'class',
Expand All @@ -10,6 +8,7 @@ module.exports = {
'./mdx-components.tsx',
'./node_modules/next-docs-ui/dist/**/*.js',
],
presets: [require('next-docs-ui/tailwind-plugin').default()],
theme: {
extend: {
fontFamily: {
Expand Down Expand Up @@ -57,5 +56,5 @@ module.exports = {
},
},
},
plugins: [require('tailwindcss-animate'), ...createDocsUI()],
plugins: [require('tailwindcss-animate')],
};
22 changes: 18 additions & 4 deletions packages/headless/src/search-algolia/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import useSWR, { type SWRResponse } from 'swr';
import type { SortedResult } from '@/search/shared';
import type { BaseIndex } from './server';

export interface Options extends SearchOptions {
allowEmpty?: boolean;
}

export function groupResults(hits: Hit<BaseIndex>[]): SortedResult[] {
const grouped: SortedResult[] = [];
const scannedUrls = new Set<string>();
Expand Down Expand Up @@ -37,6 +41,16 @@ export async function searchDocs(
query: string,
options?: SearchOptions,
): Promise<SortedResult[]> {
if (query.length === 0) {
const result = await index.search<BaseIndex>(query, {
distinct: 1,
hitsPerPage: 8,
...options,
});

return groupResults(result.hits).filter((hit) => hit.type === 'page');
}

const result = await index.search<BaseIndex>(query, {
distinct: 5,
hitsPerPage: 10,
Expand All @@ -58,16 +72,16 @@ interface UseAlgoliaSearch {

export function useAlgoliaSearch(
index: SearchIndex,
options?: SearchOptions,
options: Options = {},
): UseAlgoliaSearch {
const [search, setSearch] = useState('');

const query = useSWR(
['/api/search', search, options],
async ([, searchV, optionsV]) => {
if (searchV.length === 0) return 'empty';
async () => {
if (!options.allowEmpty && search.length === 0) return 'empty';

return searchDocs(index, searchV, optionsV);
return searchDocs(index, search, options);
},
{
keepPreviousData: true,
Expand Down
3 changes: 2 additions & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@
"next-themes": "^0.2.1",
"react-medium-image-zoom": "^5.1.8",
"tailwind-merge": "^2.0.0",
"tailwindcss": "^3.4.1"
"tailwindcss": "^3.4.1",
"vaul": "^0.8.0"
},
"devDependencies": {
"@algolia/client-search": "^4.20.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const Accordion = forwardRef<
className={cn('group/accordion scroll-m-20', className)}
{...props}
>
<AccordionPrimitive.Header className="not-prose flex items-center text-muted-foreground">
<AccordionPrimitive.Header className="not-prose flex items-center text-medium text-muted-foreground">
<AccordionPrimitive.Trigger className="flex w-full items-center gap-1 py-4 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">
<ChevronRightIcon className="h-5 w-5 transition-transform duration-200 group-data-[state=open]/accordion:rotate-90" />
<span className="text-medium font-medium text-foreground">
Expand Down
8 changes: 5 additions & 3 deletions packages/ui/src/components/dialog/search-algolia.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
'use client';

import type { SearchOptions } from '@algolia/client-search';
import type { SearchIndex } from 'algoliasearch/lite';
import { useAlgoliaSearch } from 'next-docs-zeta/search-algolia/client';
import {
type Options,
useAlgoliaSearch,
} from 'next-docs-zeta/search-algolia/client';
import { createContext, useContext, type ReactNode } from 'react';
import { SearchDialog, type SharedProps } from './search';

export type AlgoliaSearchDialogProps = SharedProps & {
searchOptions?: SearchOptions;
searchOptions?: Options;
footer?: ReactNode;
children?: ReactNode;
};
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/dialog/search-default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export default function DefaultSearchDialog({
search={search}
onSearchChange={setSearch}
data={query.data}
showOnEmpty={links.length > 0}
{...props}
>
<CommandGroup value="items">
Expand Down
73 changes: 31 additions & 42 deletions packages/ui/src/components/dialog/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,16 @@ export type SearchDialogProps = SharedProps & {
* displayed in item list
*/
children?: ReactNode;

showOnEmpty?: boolean;
};

export function SearchDialog({
search,
onSearchChange,
data,
showOnEmpty = false,
...props
}: SearchDialogProps): JSX.Element {
const router = useRouter();
const { text } = useI18n();
const showList = data !== 'empty' || showOnEmpty;

const onOpen = (url: string): void => {
router.push(url);
Expand All @@ -52,44 +48,37 @@ export function SearchDialog({

return (
<CommandDialog {...props}>
<Command shouldFilter={false} loop>
<CommandInput
value={search}
onValueChange={onSearchChange}
placeholder={text.search ?? 'Search'}
/>
{showList ? (
<CommandList>
<CommandEmpty>
{text.searchNoResult ?? 'No results found'}
</CommandEmpty>
<CommandGroup value="result">
{Array.isArray(data) &&
data.map((item) => (
<CommandItem
key={item.id}
value={item.id}
onSelect={() => {
onOpen(item.url);
}}
nested={item.type !== 'page'}
>
{
{
text: <TextIcon />,
heading: <HashIcon />,
page: <FileTextIcon />,
}[item.type]
}
<p className="w-0 flex-1 truncate">{item.content}</p>
</CommandItem>
))}
</CommandGroup>
{props.children}
</CommandList>
) : null}
{props.footer}
</Command>
<CommandInput
value={search}
onValueChange={onSearchChange}
placeholder={text.search ?? 'Search'}
/>
<CommandList>
<CommandEmpty>{text.searchNoResult ?? 'No results found'}</CommandEmpty>
<CommandGroup value="result">
{Array.isArray(data) &&
data.map((item) => (
<CommandItem
key={item.id}
value={item.id}
onSelect={() => {
onOpen(item.url);
}}
nested={item.type !== 'page'}
>
{
{
text: <TextIcon />,
heading: <HashIcon />,
page: <FileTextIcon />,
}[item.type]
}
<p className="w-0 flex-1 truncate">{item.content}</p>
</CommandItem>
))}
</CommandGroup>
{props.children}
</CommandList>
</CommandDialog>
);
}
24 changes: 15 additions & 9 deletions packages/ui/src/components/ui/command.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { DialogProps } from '@radix-ui/react-dialog';
import { type DialogProps } from '@radix-ui/react-dialog';
import { Command as CommandPrimitive } from 'cmdk';
import { Search } from 'lucide-react';
import * as React from 'react';
import { cn } from '@/utils/cn';
import { Dialog, DialogContent } from './dialog';
import { Drawer, DrawerContent, DrawerFooter } from './drawer';

const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
Expand All @@ -20,18 +20,24 @@ const Command = React.forwardRef<
));
Command.displayName = CommandPrimitive.displayName;

type CommandDialogProps = DialogProps;
interface CommandDialogProps extends DialogProps {
footer?: React.ReactNode;
}

function CommandDialog({
footer,
children,
...props
}: CommandDialogProps): JSX.Element {
return (
<Dialog {...props}>
<DialogContent className="bg-popover p-0 text-popover-foreground">
{children}
</DialogContent>
</Dialog>
<Drawer {...props}>
<DrawerContent className="p-0">
<Command shouldFilter={false} loop>
{children}
{footer ? <DrawerFooter>{footer}</DrawerFooter> : null}
</Command>
</DrawerContent>
</Drawer>
);
}

Expand All @@ -44,7 +50,7 @@ const CommandInput = React.forwardRef<
<CommandPrimitive.Input
ref={ref}
className={cn(
'flex w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
'flex w-full rounded-md bg-transparent py-3 text-base outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
Expand Down
44 changes: 3 additions & 41 deletions packages/ui/src/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
'relative grid w-[95vw] max-w-2xl gap-4 rounded-lg border bg-background p-6 shadow-lg data-[state=closed]:animate-dialog-out data-[state=open]:animate-dialog-in',
'relative grid w-[95vw] max-w-2xl gap-4 rounded-lg border bg-popover p-6 text-popover-foreground shadow-lg data-[state=closed]:animate-dialog-out data-[state=open]:animate-dialog-in',
className,
)}
{...props}
Expand Down Expand Up @@ -54,49 +54,11 @@ function DialogFooter({
}: React.HTMLAttributes<HTMLDivElement>): JSX.Element {
return (
<div
className={cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
className,
)}
className={cn('mt-auto flex flex-col gap-2 p-4', className)}
{...props}
/>
);
}
DialogFooter.displayName = 'DialogFooter';

const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
'text-lg font-semibold leading-none tracking-tight',
className,
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;

const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;

export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
};
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter };
Loading

0 comments on commit 9bc2a26

Please sign in to comment.