B2B-36: add personal dashboard (#20)
* B2B-36: add dashboard cards * B2B-36: add dashboard cards * card variants, some improvements, gen db types * add menus to home page * update db types * remove unnecessary card variant --------- Co-authored-by: Helena <helena@Helenas-MacBook-Pro.local>
This commit is contained in:
@@ -29,7 +29,7 @@ const RouteChild = z.object({
|
||||
});
|
||||
|
||||
const RouteGroup = z.object({
|
||||
label: z.string(),
|
||||
label: z.string().optional(),
|
||||
collapsible: z.boolean().optional(),
|
||||
collapsed: z.boolean().optional(),
|
||||
children: z.array(RouteChild),
|
||||
@@ -37,12 +37,8 @@ const RouteGroup = z.object({
|
||||
});
|
||||
|
||||
export const NavigationConfigSchema = z.object({
|
||||
style: z.enum(['custom', 'sidebar', 'header']).default('sidebar'),
|
||||
sidebarCollapsed: z
|
||||
.enum(['false', 'true'])
|
||||
.default('true')
|
||||
.optional()
|
||||
.transform((value) => value === `true`),
|
||||
style: z.enum(['custom', 'sidebar', 'header']).default('custom'),
|
||||
sidebarCollapsed: z.boolean().optional(),
|
||||
sidebarCollapsedStyle: z.enum(['offcanvas', 'icon', 'none']).default('icon'),
|
||||
routes: z.array(z.union([RouteGroup, Divider])),
|
||||
});
|
||||
|
||||
@@ -14,10 +14,6 @@ type PageProps = React.PropsWithChildren<{
|
||||
sticky?: boolean;
|
||||
}>;
|
||||
|
||||
const ENABLE_SIDEBAR_TRIGGER = process.env.NEXT_PUBLIC_ENABLE_SIDEBAR_TRIGGER
|
||||
? process.env.NEXT_PUBLIC_ENABLE_SIDEBAR_TRIGGER === 'true'
|
||||
: true;
|
||||
|
||||
export function Page(props: PageProps) {
|
||||
switch (props.style) {
|
||||
case 'header':
|
||||
@@ -79,7 +75,7 @@ function PageWithHeader(props: PageProps) {
|
||||
const { Navigation, Children, MobileNavigation } = getSlotsFromPage(props);
|
||||
|
||||
return (
|
||||
<div className={cn('flex h-screen flex-1 flex-col', props.className)}>
|
||||
<div className={cn('flex h-screen flex-1 flex-col z-1000', props.className)}>
|
||||
<div
|
||||
className={
|
||||
props.contentContainerClassName ?? 'flex flex-1 flex-col space-y-4'
|
||||
@@ -87,9 +83,9 @@ function PageWithHeader(props: PageProps) {
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'bg-muted/40 dark:border-border dark:shadow-primary/10 flex h-14 items-center justify-between px-4 lg:justify-start lg:shadow-xs',
|
||||
'bg-muted/40 dark:border-border dark:shadow-primary/10 flex h-14 items-center justify-between px-4 lg:justify-start lg:shadow-xs border-b',
|
||||
{
|
||||
'sticky top-0 z-10 backdrop-blur-md': props.sticky ?? true,
|
||||
'sticky top-0 z-1000 backdrop-blur-md': props.sticky ?? true,
|
||||
},
|
||||
)}
|
||||
>
|
||||
@@ -113,7 +109,10 @@ export function PageBody(
|
||||
className?: string;
|
||||
}>,
|
||||
) {
|
||||
const className = cn('flex w-full flex-1 flex-col lg:px-4', props.className);
|
||||
const className = cn(
|
||||
'flex w-full flex-1 flex-col space-y-6 lg:px-4',
|
||||
props.className,
|
||||
);
|
||||
|
||||
return <div className={className}>{props.children}</div>;
|
||||
}
|
||||
@@ -125,7 +124,7 @@ export function PageNavigation(props: React.PropsWithChildren) {
|
||||
export function PageDescription(props: React.PropsWithChildren) {
|
||||
return (
|
||||
<div className={'flex h-6 items-center'}>
|
||||
<div className={'text-muted-foreground text-xs leading-none font-normal'}>
|
||||
<div className={'text-muted-foreground text-sm leading-none font-normal'}>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,7 +152,7 @@ export function PageHeader({
|
||||
title,
|
||||
description,
|
||||
className,
|
||||
displaySidebarTrigger = ENABLE_SIDEBAR_TRIGGER,
|
||||
displaySidebarTrigger = false,
|
||||
}: React.PropsWithChildren<{
|
||||
className?: string;
|
||||
title?: string | React.ReactNode;
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { VariantProps } from 'class-variance-authority';
|
||||
import { cn } from '../lib/utils';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'focus-visible:ring-ring inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap transition-colors focus-visible:ring-1 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',
|
||||
'focus-visible:ring-ring gap-1 inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap transition-colors focus-visible:ring-1 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { cn } from '../lib/utils';
|
||||
import { VariantProps, cva } from 'class-variance-authority';
|
||||
import { cn } from '.';
|
||||
|
||||
const Card: React.FC<React.HTMLAttributes<HTMLDivElement>> = ({
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
<div
|
||||
className={cn('bg-card text-card-foreground rounded-xl border', className)}
|
||||
{...props}
|
||||
/>
|
||||
const cardVariants = cva('text-card-foreground rounded-xl border', {
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-card',
|
||||
'gradient-warning':
|
||||
'from-warning/30 via-warning/10 to-background bg-gradient-to-t',
|
||||
'gradient-destructive':
|
||||
'from-destructive/30 via-destructive/10 to-background bg-gradient-to-t',
|
||||
'gradient-success':
|
||||
'from-success/30 via-success/10 to-background bg-gradient-to-t',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
},
|
||||
});
|
||||
|
||||
export interface CardProps
|
||||
extends React.HTMLAttributes<HTMLDivElement>,
|
||||
VariantProps<typeof cardVariants> {}
|
||||
|
||||
const Card: React.FC<CardProps> = ({ className, variant, ...props }) => (
|
||||
<div className={cn(cardVariants({ variant, className }))} {...props} />
|
||||
);
|
||||
Card.displayName = 'Card';
|
||||
|
||||
|
||||
3
packages/ui/src/shadcn/constants.ts
Normal file
3
packages/ui/src/shadcn/constants.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const SIDEBAR_WIDTH = '16rem';
|
||||
export const SIDEBAR_WIDTH_MOBILE = '18rem';
|
||||
export const SIDEBAR_WIDTH_ICON = '4rem';
|
||||
@@ -21,6 +21,11 @@ import {
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from './collapsible';
|
||||
import {
|
||||
SIDEBAR_WIDTH,
|
||||
SIDEBAR_WIDTH_ICON,
|
||||
SIDEBAR_WIDTH_MOBILE,
|
||||
} from './constants';
|
||||
import { Input } from './input';
|
||||
import { Separator } from './separator';
|
||||
import { Sheet, SheetContent } from './sheet';
|
||||
@@ -34,9 +39,6 @@ import {
|
||||
|
||||
const SIDEBAR_COOKIE_NAME = 'sidebar:state';
|
||||
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
||||
const SIDEBAR_WIDTH = '16rem';
|
||||
const SIDEBAR_WIDTH_MOBILE = '18rem';
|
||||
const SIDEBAR_WIDTH_ICON = '4rem';
|
||||
const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
|
||||
const SIDEBAR_MINIMIZED_WIDTH = SIDEBAR_WIDTH_ICON;
|
||||
|
||||
@@ -276,7 +278,7 @@ const Sidebar: React.FC<
|
||||
<div
|
||||
data-sidebar="sidebar"
|
||||
className={cn(
|
||||
'bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm',
|
||||
'bg-sidebar group-data-[variant=floating]:border-sidebar-border ml-3 flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm',
|
||||
{
|
||||
'bg-transparent': variant === 'ghost',
|
||||
},
|
||||
@@ -908,7 +910,7 @@ export function SidebarNavigation({
|
||||
tooltip={child.label}
|
||||
>
|
||||
<Link
|
||||
className={cn('flex items-center', {
|
||||
className={cn('flex items-center font-medium', {
|
||||
'mx-auto w-full gap-0! [&>svg]:flex-1': !open,
|
||||
})}
|
||||
href={path}
|
||||
@@ -916,7 +918,7 @@ export function SidebarNavigation({
|
||||
{child.Icon}
|
||||
<span
|
||||
className={cn(
|
||||
'w-auto transition-opacity duration-300',
|
||||
'text-md w-auto font-medium transition-opacity duration-300',
|
||||
{
|
||||
'w-0 opacity-0': !open,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user