Add card button component and enhance routing
This commit introduces the Card Button component to the UI package and improves URL matching by allowing end to be a boolean or function. Navigation menu components now support both cases. Additionally, changes have been made to improve the visual and functional aspects of various components throughout the application. This includes changes in pricing display, route active checking, and the introduction of new files such as HomeAddAccountButton and HomeAccountsList.
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
NavigationMenuItem,
|
||||
NavigationMenuList,
|
||||
} from '../shadcn/navigation-menu';
|
||||
|
||||
import { cn, isRouteActive } from '../utils';
|
||||
import { Trans } from './trans';
|
||||
|
||||
@@ -25,10 +26,14 @@ export function BorderedNavigationMenu(props: React.PropsWithChildren) {
|
||||
export function BorderedNavigationMenuItem(props: {
|
||||
path: string;
|
||||
label: string;
|
||||
end?: boolean | ((path: string) => boolean);
|
||||
active?: boolean;
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
const active = props.active ?? isRouteActive(pathname, props.path);
|
||||
|
||||
const active =
|
||||
props.active ??
|
||||
isRouteActive(props.path, pathname, props.end);
|
||||
|
||||
return (
|
||||
<NavigationMenuItem>
|
||||
@@ -47,4 +52,4 @@ export function BorderedNavigationMenuItem(props: {
|
||||
</Button>
|
||||
</NavigationMenuItem>
|
||||
);
|
||||
}
|
||||
}
|
||||
46
packages/ui/src/makerkit/card-button.tsx
Normal file
46
packages/ui/src/makerkit/card-button.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Slot, Slottable } from '@radix-ui/react-slot';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
|
||||
import { cn } from '../utils';
|
||||
|
||||
export const CardButton = React.forwardRef<
|
||||
HTMLButtonElement,
|
||||
{
|
||||
asChild?: boolean;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
>(({ className, asChild, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button';
|
||||
|
||||
return (
|
||||
<Comp
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'group relative flex h-36 rounded-lg bg-secondary/80 p-4 transition-all hover:bg-secondary/90 hover:shadow-sm active:bg-secondary active:shadow-lg',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<Slottable>{props.children}</Slottable>
|
||||
</Comp>
|
||||
);
|
||||
});
|
||||
|
||||
export function CardButtonHeader(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<>
|
||||
<span className="text-sm font-medium text-muted-foreground transition-colors group-hover:text-secondary-foreground">
|
||||
{props.children}
|
||||
</span>
|
||||
|
||||
<ChevronRight
|
||||
className={
|
||||
'absolute right-2 top-4 h-4 text-muted-foreground transition-colors group-hover:text-secondary-foreground'
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const RouteMatchingEnd = z
|
||||
.union([z.boolean(), z.function().args(z.string()).returns(z.boolean())])
|
||||
.default(false)
|
||||
.optional();
|
||||
|
||||
export const NavigationConfigSchema = z.object({
|
||||
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
|
||||
routes: z.array(
|
||||
@@ -8,7 +13,7 @@ export const NavigationConfigSchema = z.object({
|
||||
label: z.string(),
|
||||
path: z.string(),
|
||||
Icon: z.custom<React.ReactNode>(),
|
||||
end: z.boolean().optional(),
|
||||
end: RouteMatchingEnd,
|
||||
}),
|
||||
z.object({
|
||||
label: z.string(),
|
||||
@@ -19,7 +24,7 @@ export const NavigationConfigSchema = z.object({
|
||||
label: z.string(),
|
||||
path: z.string(),
|
||||
Icon: z.custom<React.ReactNode>(),
|
||||
end: z.boolean().optional(),
|
||||
end: RouteMatchingEnd,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
|
||||
@@ -154,12 +154,12 @@ export function SidebarItem({
|
||||
}: React.PropsWithChildren<{
|
||||
path: string;
|
||||
Icon: React.ReactNode;
|
||||
end?: boolean;
|
||||
end?: boolean | ((path: string) => boolean);
|
||||
}>) {
|
||||
const { collapsed } = useContext(SidebarContext);
|
||||
|
||||
const currentPath = usePathname() ?? '';
|
||||
const active = isRouteActive(path, currentPath, end ? 0 : 3);
|
||||
|
||||
const active = isRouteActive(path, currentPath, end);
|
||||
const variant = active ? 'secondary' : 'ghost';
|
||||
const size = collapsed ? 'icon' : 'sm';
|
||||
|
||||
@@ -254,4 +254,4 @@ export function SidebarNavigation({
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user