Skip to content

Commit

Permalink
feat: add website add button and fuse search
Browse files Browse the repository at this point in the history
  • Loading branch information
moonrailgun committed Apr 7, 2024
1 parent 3f13447 commit 68ace91
Show file tree
Hide file tree
Showing 13 changed files with 586 additions and 86 deletions.
55 changes: 55 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

120 changes: 82 additions & 38 deletions src/client/components/CommonList.tsx
Expand Up @@ -3,6 +3,9 @@ import { ScrollArea } from './ui/scroll-area';
import { cn } from '@/utils/style';
import { Badge } from './ui/badge';
import { useNavigate, useRouterState } from '@tanstack/react-router';
import { LuSearch } from 'react-icons/lu';
import { Input } from './ui/input';
import { useFuseSearch } from '@/hooks/useFuseSearch';

export interface CommonListItem {
id: string;
Expand All @@ -13,55 +16,96 @@ export interface CommonListItem {
}

interface CommonListProps {
hasSearch?: boolean;
items: CommonListItem[];
}
export const CommonList: React.FC<CommonListProps> = React.memo((props) => {
const { location } = useRouterState();
const navigate = useNavigate();

const { searchText, setSearchText, searchResult } = useFuseSearch(
props.items,
{
keys: [
{
name: 'id',
weight: 1,
},
{
name: 'title',
weight: 0.7,
},
{
name: 'tags',
weight: 0.3,
},
],
}
);

const finalList = searchResult ?? props.items;

return (
<ScrollArea className="h-screen">
<div className="flex flex-col gap-2 p-4 pt-0">
{props.items.map((item) => {
const isSelected = item.href === location.pathname;
<>
{props.hasSearch && (
<div className="bg-background/95 p-4 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<form>
<div className="relative">
<LuSearch className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Search"
className="pl-8"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
/>
</div>
</form>
</div>
)}

return (
<button
key={item.id}
className={cn(
'flex flex-col items-start gap-2 rounded-lg border p-3 text-left text-sm transition-all hover:bg-accent',
isSelected && 'bg-muted'
)}
onClick={() =>
navigate({
to: item.href,
})
}
>
<div className="flex w-full flex-col gap-1">
<div className="flex items-center">
<div className="flex items-center gap-2">
<div className="font-semibold">{item.title}</div>
<ScrollArea className="h-screen">
<div className="flex flex-col gap-2 p-4 pt-0">
{finalList.map((item) => {
const isSelected = item.href === location.pathname;

return (
<button
key={item.id}
className={cn(
'flex flex-col items-start gap-2 rounded-lg border p-3 text-left text-sm transition-all hover:bg-accent',
isSelected && 'bg-muted'
)}
onClick={() =>
navigate({
to: item.href,
})
}
>
<div className="flex w-full flex-col gap-1">
<div className="flex items-center">
<div className="flex items-center gap-2">
<div className="font-semibold">{item.title}</div>
</div>
</div>
</div>
</div>
<div className="line-clamp-2 text-xs text-muted-foreground">
{item.content}
</div>
{item.tags.length > 0 ? (
<div className="flex items-center gap-2">
{item.tags.map((tag) => (
<Badge key={tag} variant={getBadgeVariantFromLabel(tag)}>
{tag}
</Badge>
))}
<div className="line-clamp-2 text-xs text-muted-foreground">
{item.content}
</div>
) : null}
</button>
);
})}
</div>
</ScrollArea>
{item.tags.length > 0 ? (
<div className="flex items-center gap-2">
{item.tags.map((tag) => (
<Badge key={tag} variant={getBadgeVariantFromLabel(tag)}>
{tag}
</Badge>
))}
</div>
) : null}
</button>
);
})}
</div>
</ScrollArea>
</>
);
});
CommonList.displayName = 'CommonList';
Expand Down
28 changes: 27 additions & 1 deletion src/client/components/ui/button.tsx
Expand Up @@ -3,6 +3,8 @@ import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';

import { cn } from '@/utils/style';
import { Spinner } from './spinner';
import { IconType } from 'react-icons';

const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-zinc-950 disabled:pointer-events-none disabled:opacity-50 dark:focus-visible:ring-zinc-300',
Expand Down Expand Up @@ -39,16 +41,40 @@ export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
loading?: boolean;
Icon?: IconType;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
(
{
className,
variant,
size,
asChild = false,
loading = false,
Icon,
...props
},
ref
) => {
const Comp = asChild ? Slot : 'button';

const icon = Icon ? <Icon className="mr-1" /> : undefined;
const children = (
<>
{loading ? <Spinner className="mr-1" /> : icon}
{props.children}
</>
);

return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
disabled={loading}
{...props}
children={children}
/>
);
}
Expand Down

0 comments on commit 68ace91

Please sign in to comment.