@olympusoss/canvas 2.20.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -35
- package/package.json +45 -177
- package/src/cn.ts +3 -0
- package/src/index.ts +12 -603
- package/src/theme.ts +62 -0
- package/src/tokens.ts +11 -0
- package/styles/base.css +17 -0
- package/styles/canvas.css +77 -52
- package/styles/components/alert.css +66 -0
- package/styles/components/app-shell.css +46 -0
- package/styles/components/avatar.css +22 -0
- package/styles/components/badge.css +83 -0
- package/styles/components/breadcrumb.css +35 -0
- package/styles/components/button-group.css +23 -0
- package/styles/components/button.css +107 -0
- package/styles/components/calendar.css +73 -0
- package/styles/components/card.css +58 -0
- package/styles/components/checkbox.css +55 -0
- package/styles/components/code-block.css +18 -0
- package/styles/components/combobox.css +75 -0
- package/styles/components/command.css +94 -0
- package/styles/components/data-table.css +142 -0
- package/styles/components/dialog.css +72 -0
- package/styles/components/dropdown.css +54 -0
- package/styles/components/empty-state.css +17 -0
- package/styles/components/field.css +27 -0
- package/styles/components/filter-panel.css +58 -0
- package/styles/components/form.css +27 -0
- package/styles/components/icon.css +8 -0
- package/styles/components/input-group.css +45 -0
- package/styles/components/input.css +56 -0
- package/styles/components/kbd.css +15 -0
- package/styles/components/page-header.css +52 -0
- package/styles/components/pagination.css +48 -0
- package/styles/components/popover.css +14 -0
- package/styles/components/radio.css +28 -0
- package/styles/components/row-menu.css +69 -0
- package/styles/components/section-card.css +49 -0
- package/styles/components/select.css +57 -0
- package/styles/components/separator.css +32 -0
- package/styles/components/sheet.css +70 -0
- package/styles/components/sidebar.css +146 -0
- package/styles/components/skeleton.css +32 -0
- package/styles/components/spinner.css +26 -0
- package/styles/components/stat-card.css +71 -0
- package/styles/components/stepper.css +63 -0
- package/styles/components/switch.css +45 -0
- package/styles/components/tabs.css +40 -0
- package/styles/components/textarea.css +31 -0
- package/styles/components/toast.css +95 -0
- package/styles/components/tooltip.css +53 -0
- package/styles/components/topbar.css +24 -0
- package/styles/components/typography.css +105 -0
- package/styles/patterns/backdrops.css +35 -0
- package/styles/patterns/density.css +66 -0
- package/styles/patterns/focus.css +22 -0
- package/styles/patterns/glass.css +85 -0
- package/styles/patterns/high-contrast.css +70 -0
- package/styles/patterns/reduced-motion.css +12 -0
- package/styles/patterns/scrollbar.css +10 -0
- package/styles/reset.css +89 -0
- package/styles/tokens/colors.css +106 -0
- package/styles/tokens/motion.css +33 -0
- package/styles/tokens/radius.css +10 -0
- package/styles/tokens/shadows.css +35 -0
- package/styles/tokens/spacing.css +19 -0
- package/styles/tokens/typography.css +6 -0
- package/styles/tokens/z-index.css +12 -0
- package/styles/utilities/display.css +66 -0
- package/styles/utilities/flexbox.css +240 -0
- package/styles/utilities/gap.css +288 -0
- package/styles/utilities/grid.css +138 -0
- package/styles/utilities/position.css +78 -0
- package/styles/utilities/sizing.css +138 -0
- package/tsconfig.json +20 -21
- package/src/components/atoms/README.md +0 -11
- package/src/components/atoms/aspect-ratio.tsx +0 -32
- package/src/components/atoms/avatar.tsx +0 -98
- package/src/components/atoms/badge.tsx +0 -44
- package/src/components/atoms/brand-mark.tsx +0 -74
- package/src/components/atoms/button.tsx +0 -105
- package/src/components/atoms/checkbox.tsx +0 -63
- package/src/components/atoms/flex-box.tsx +0 -105
- package/src/components/atoms/icon.tsx +0 -34
- package/src/components/atoms/input.tsx +0 -92
- package/src/components/atoms/label.tsx +0 -41
- package/src/components/atoms/logo.tsx +0 -89
- package/src/components/atoms/progress.tsx +0 -55
- package/src/components/atoms/radio-group.tsx +0 -122
- package/src/components/atoms/scroll-area.tsx +0 -106
- package/src/components/atoms/section.tsx +0 -48
- package/src/components/atoms/separator.tsx +0 -45
- package/src/components/atoms/skeleton.tsx +0 -17
- package/src/components/atoms/slider.tsx +0 -93
- package/src/components/atoms/spinner.tsx +0 -47
- package/src/components/atoms/switch.tsx +0 -60
- package/src/components/atoms/textarea.tsx +0 -78
- package/src/components/atoms/toggle.tsx +0 -80
- package/src/components/charts/activity-heatmap.tsx +0 -186
- package/src/components/charts/axes.tsx +0 -21
- package/src/components/charts/chart-container.tsx +0 -254
- package/src/components/charts/chart-legend.tsx +0 -67
- package/src/components/charts/chart-tooltip.tsx +0 -161
- package/src/components/charts/chart-types.tsx +0 -49
- package/src/components/charts/containers.tsx +0 -11
- package/src/components/charts/data.tsx +0 -16
- package/src/components/charts/details.tsx +0 -25
- package/src/components/charts/dot-pulse.tsx +0 -61
- package/src/components/charts/gauge.tsx +0 -106
- package/src/components/charts/grids.tsx +0 -8
- package/src/components/charts/index.ts +0 -62
- package/src/components/charts/labeled-bar-list.tsx +0 -85
- package/src/components/charts/metric-breakdown.tsx +0 -316
- package/src/components/charts/references.tsx +0 -8
- package/src/components/charts/service-health-list.tsx +0 -85
- package/src/components/charts/sparkline-area.tsx +0 -80
- package/src/components/charts/sparkline.tsx +0 -52
- package/src/components/charts/stacked-bar.tsx +0 -104
- package/src/components/charts/text.tsx +0 -10
- package/src/components/charts/world-heat-map-inner.tsx +0 -317
- package/src/components/charts/world-heat-map.tsx +0 -184
- package/src/components/molecules/README.md +0 -12
- package/src/components/molecules/action-bar.tsx +0 -73
- package/src/components/molecules/activity-item.tsx +0 -74
- package/src/components/molecules/alert.tsx +0 -86
- package/src/components/molecules/animated-background.tsx +0 -92
- package/src/components/molecules/auth-shell.tsx +0 -95
- package/src/components/molecules/brand-lockup.tsx +0 -48
- package/src/components/molecules/breadcrumb.tsx +0 -157
- package/src/components/molecules/button-group.tsx +0 -104
- package/src/components/molecules/calendar.tsx +0 -217
- package/src/components/molecules/card.tsx +0 -102
- package/src/components/molecules/client-brand.tsx +0 -95
- package/src/components/molecules/code-block.tsx +0 -86
- package/src/components/molecules/countdown-button.tsx +0 -92
- package/src/components/molecules/empty-state.tsx +0 -56
- package/src/components/molecules/error-state.tsx +0 -42
- package/src/components/molecules/field-display.tsx +0 -35
- package/src/components/molecules/input-otp.tsx +0 -74
- package/src/components/molecules/launcher-card.tsx +0 -152
- package/src/components/molecules/loading-state.tsx +0 -36
- package/src/components/molecules/notification-item.tsx +0 -67
- package/src/components/molecules/notification-list.tsx +0 -45
- package/src/components/molecules/number-badge.tsx +0 -53
- package/src/components/molecules/or-separator.tsx +0 -38
- package/src/components/molecules/page-header.tsx +0 -88
- package/src/components/molecules/page-tabs.tsx +0 -94
- package/src/components/molecules/pagination.tsx +0 -150
- package/src/components/molecules/password-input.tsx +0 -83
- package/src/components/molecules/password-strength-meter.tsx +0 -104
- package/src/components/molecules/phone-input.tsx +0 -200
- package/src/components/molecules/search-bar.tsx +0 -64
- package/src/components/molecules/secret-field.tsx +0 -158
- package/src/components/molecules/section-card.tsx +0 -91
- package/src/components/molecules/social-buttons.tsx +0 -165
- package/src/components/molecules/stat-card.tsx +0 -100
- package/src/components/molecules/status-badge.tsx +0 -42
- package/src/components/molecules/stepper.tsx +0 -96
- package/src/components/molecules/table.tsx +0 -157
- package/src/components/molecules/terminal.tsx +0 -74
- package/src/components/molecules/toggle-group.tsx +0 -145
- package/src/components/molecules/tooltip.tsx +0 -155
- package/src/components/molecules/user-avatar-chip.tsx +0 -71
- package/src/components/organisms/README.md +0 -14
- package/src/components/organisms/accordion.tsx +0 -154
- package/src/components/organisms/alert-dialog.tsx +0 -277
- package/src/components/organisms/carousel.tsx +0 -244
- package/src/components/organisms/collapsible.tsx +0 -69
- package/src/components/organisms/command.tsx +0 -144
- package/src/components/organisms/context-menu.tsx +0 -339
- package/src/components/organisms/dashboard-grid.tsx +0 -369
- package/src/components/organisms/data-table.tsx +0 -330
- package/src/components/organisms/dialog.tsx +0 -312
- package/src/components/organisms/drawer.tsx +0 -123
- package/src/components/organisms/dropdown-menu.tsx +0 -440
- package/src/components/organisms/editors/code-editor.tsx +0 -144
- package/src/components/organisms/editors/index.ts +0 -4
- package/src/components/organisms/editors/markdown-editor.tsx +0 -153
- package/src/components/organisms/editors/markdown-renderer.ts +0 -27
- package/src/components/organisms/editors/prose-canvas-classes.ts +0 -45
- package/src/components/organisms/editors/rich-text-editor.tsx +0 -126
- package/src/components/organisms/editors/toolbar/md-toolbar.tsx +0 -129
- package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +0 -211
- package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +0 -45
- package/src/components/organisms/editors/use-codemirror-theme.ts +0 -61
- package/src/components/organisms/error-boundary.tsx +0 -61
- package/src/components/organisms/form.tsx +0 -174
- package/src/components/organisms/hover-card.tsx +0 -115
- package/src/components/organisms/menubar.tsx +0 -498
- package/src/components/organisms/navbar.tsx +0 -104
- package/src/components/organisms/navigation-menu.tsx +0 -235
- package/src/components/organisms/popover.tsx +0 -149
- package/src/components/organisms/resizable.tsx +0 -58
- package/src/components/organisms/schema-form.tsx +0 -232
- package/src/components/organisms/select.tsx +0 -309
- package/src/components/organisms/sheet.tsx +0 -265
- package/src/components/organisms/sidebar.tsx +0 -1040
- package/src/components/organisms/sonner.tsx +0 -96
- package/src/components/organisms/tabs.tsx +0 -133
- package/src/components/organisms/theme-provider.tsx +0 -101
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/lib/portal-container.tsx +0 -35
- package/src/lib/utils.ts +0 -6
- package/src/native.ts +0 -23
- package/src/tokens/colors.ts +0 -91
- package/src/tokens/index.ts +0 -3
- package/src/tokens/spacing.ts +0 -55
- package/src/tokens/typography.ts +0 -27
- package/styles/dashboard-grid.css +0 -47
- package/styles/fonts/Roboto-VariableFont_wdth_wght.ttf +0 -0
- package/styles/glass.css +0 -171
- package/styles/leaflet.css +0 -13
- package/styles/tokens.css +0 -317
- package/tailwind.config.ts +0 -70
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
-
import { ChevronRight, MoreHorizontal } from "lucide-react";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
|
|
7
|
-
export interface BreadcrumbProps extends React.ComponentPropsWithoutRef<"nav"> {
|
|
8
|
-
/**
|
|
9
|
-
* Custom separator element used between items. Defaults to a chevron
|
|
10
|
-
* via `<BreadcrumbSeparator>`.
|
|
11
|
-
*/
|
|
12
|
-
separator?: React.ReactNode;
|
|
13
|
-
/** A `<BreadcrumbList>` containing items. */
|
|
14
|
-
children?: React.ReactNode;
|
|
15
|
-
/** Tailwind / CSS classes merged onto the `<nav>` via `cn()`. */
|
|
16
|
-
className?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const Breadcrumb = React.forwardRef<HTMLElement, BreadcrumbProps>(({ ...props }, ref) => (
|
|
20
|
-
<nav ref={ref} aria-label="breadcrumb" {...props} />
|
|
21
|
-
));
|
|
22
|
-
Breadcrumb.displayName = "Breadcrumb";
|
|
23
|
-
|
|
24
|
-
export interface BreadcrumbListProps extends React.ComponentPropsWithoutRef<"ol"> {
|
|
25
|
-
/** A flat list of `<BreadcrumbItem>`s, separated by `<BreadcrumbSeparator>`. */
|
|
26
|
-
children?: React.ReactNode;
|
|
27
|
-
/** Tailwind / CSS classes merged onto the `<ol>` via `cn()`. */
|
|
28
|
-
className?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const BreadcrumbList = React.forwardRef<HTMLOListElement, BreadcrumbListProps>(
|
|
32
|
-
({ className, ...props }, ref) => (
|
|
33
|
-
<ol
|
|
34
|
-
ref={ref}
|
|
35
|
-
className={cn(
|
|
36
|
-
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
|
|
37
|
-
className,
|
|
38
|
-
)}
|
|
39
|
-
{...props}
|
|
40
|
-
/>
|
|
41
|
-
),
|
|
42
|
-
);
|
|
43
|
-
BreadcrumbList.displayName = "BreadcrumbList";
|
|
44
|
-
|
|
45
|
-
export interface BreadcrumbItemProps extends React.ComponentPropsWithoutRef<"li"> {
|
|
46
|
-
/** Typically a `<BreadcrumbLink>` or `<BreadcrumbPage>`. */
|
|
47
|
-
children?: React.ReactNode;
|
|
48
|
-
/** Tailwind / CSS classes merged onto the `<li>` via `cn()`. */
|
|
49
|
-
className?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const BreadcrumbItem = React.forwardRef<HTMLLIElement, BreadcrumbItemProps>(
|
|
53
|
-
({ className, ...props }, ref) => (
|
|
54
|
-
<li ref={ref} className={cn("inline-flex items-center gap-1.5", className)} {...props} />
|
|
55
|
-
),
|
|
56
|
-
);
|
|
57
|
-
BreadcrumbItem.displayName = "BreadcrumbItem";
|
|
58
|
-
|
|
59
|
-
export interface BreadcrumbLinkProps extends React.ComponentPropsWithoutRef<"a"> {
|
|
60
|
-
/**
|
|
61
|
-
* Render as a Radix Slot — useful for wrapping a router `<Link>` so
|
|
62
|
-
* it inherits breadcrumb styling.
|
|
63
|
-
* @default false
|
|
64
|
-
*/
|
|
65
|
-
asChild?: boolean;
|
|
66
|
-
/** Anchor target. Used when not in `asChild` mode. */
|
|
67
|
-
href?: string;
|
|
68
|
-
/** Link label. */
|
|
69
|
-
children?: React.ReactNode;
|
|
70
|
-
/** Tailwind / CSS classes merged onto the link via `cn()`. */
|
|
71
|
-
className?: string;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
|
|
75
|
-
({ asChild, className, ...props }, ref) => {
|
|
76
|
-
const Comp = asChild ? Slot : "a";
|
|
77
|
-
|
|
78
|
-
return (
|
|
79
|
-
<Comp ref={ref} className={cn("transition-colors hover:text-brand", className)} {...props} />
|
|
80
|
-
);
|
|
81
|
-
},
|
|
82
|
-
);
|
|
83
|
-
BreadcrumbLink.displayName = "BreadcrumbLink";
|
|
84
|
-
|
|
85
|
-
export interface BreadcrumbPageProps extends React.ComponentPropsWithoutRef<"span"> {
|
|
86
|
-
/**
|
|
87
|
-
* Label of the current page. This is the last breadcrumb item and is
|
|
88
|
-
* non-clickable; sets `aria-current="page"` for assistive tech.
|
|
89
|
-
*/
|
|
90
|
-
children?: React.ReactNode;
|
|
91
|
-
/** Tailwind / CSS classes merged onto the page span via `cn()`. */
|
|
92
|
-
className?: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const BreadcrumbPage = React.forwardRef<HTMLSpanElement, BreadcrumbPageProps>(
|
|
96
|
-
({ className, ...props }, ref) => (
|
|
97
|
-
<span
|
|
98
|
-
ref={ref}
|
|
99
|
-
role="link"
|
|
100
|
-
aria-disabled="true"
|
|
101
|
-
aria-current="page"
|
|
102
|
-
className={cn("font-normal text-foreground", className)}
|
|
103
|
-
{...props}
|
|
104
|
-
/>
|
|
105
|
-
),
|
|
106
|
-
);
|
|
107
|
-
BreadcrumbPage.displayName = "BreadcrumbPage";
|
|
108
|
-
|
|
109
|
-
export interface BreadcrumbSeparatorProps extends React.ComponentProps<"li"> {
|
|
110
|
-
/**
|
|
111
|
-
* Override the default chevron with a custom node (e.g. a slash, an
|
|
112
|
-
* arrow icon).
|
|
113
|
-
*/
|
|
114
|
-
children?: React.ReactNode;
|
|
115
|
-
/** Tailwind / CSS classes merged onto the separator via `cn()`. */
|
|
116
|
-
className?: string;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const BreadcrumbSeparator = ({ children, className, ...props }: BreadcrumbSeparatorProps) => (
|
|
120
|
-
<li
|
|
121
|
-
role="presentation"
|
|
122
|
-
aria-hidden="true"
|
|
123
|
-
className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
|
|
124
|
-
{...props}
|
|
125
|
-
>
|
|
126
|
-
{children ?? <ChevronRight />}
|
|
127
|
-
</li>
|
|
128
|
-
);
|
|
129
|
-
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
|
|
130
|
-
|
|
131
|
-
export interface BreadcrumbEllipsisProps extends React.ComponentProps<"span"> {
|
|
132
|
-
/** Tailwind / CSS classes merged onto the ellipsis via `cn()`. */
|
|
133
|
-
className?: string;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const BreadcrumbEllipsis = ({ className, ...props }: BreadcrumbEllipsisProps) => (
|
|
137
|
-
<span
|
|
138
|
-
role="presentation"
|
|
139
|
-
aria-hidden="true"
|
|
140
|
-
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
|
141
|
-
{...props}
|
|
142
|
-
>
|
|
143
|
-
<MoreHorizontal className="h-4 w-4" />
|
|
144
|
-
<span className="sr-only">More</span>
|
|
145
|
-
</span>
|
|
146
|
-
);
|
|
147
|
-
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
|
|
148
|
-
|
|
149
|
-
export {
|
|
150
|
-
Breadcrumb,
|
|
151
|
-
BreadcrumbEllipsis,
|
|
152
|
-
BreadcrumbItem,
|
|
153
|
-
BreadcrumbLink,
|
|
154
|
-
BreadcrumbList,
|
|
155
|
-
BreadcrumbPage,
|
|
156
|
-
BreadcrumbSeparator,
|
|
157
|
-
};
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
-
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
-
import type * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
import { Separator } from "../atoms/separator";
|
|
7
|
-
|
|
8
|
-
const buttonGroupVariants = cva(
|
|
9
|
-
"flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
|
10
|
-
{
|
|
11
|
-
variants: {
|
|
12
|
-
orientation: {
|
|
13
|
-
horizontal:
|
|
14
|
-
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
|
|
15
|
-
vertical:
|
|
16
|
-
"flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
defaultVariants: {
|
|
20
|
-
orientation: "horizontal",
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
export interface ButtonGroupProps
|
|
26
|
-
extends React.ComponentProps<"div">,
|
|
27
|
-
VariantProps<typeof buttonGroupVariants> {
|
|
28
|
-
/**
|
|
29
|
-
* `horizontal` (default) lays buttons left-to-right with shared borders;
|
|
30
|
-
* `vertical` stacks them with shared horizontal borders.
|
|
31
|
-
* @default "horizontal"
|
|
32
|
-
*/
|
|
33
|
-
orientation?: "horizontal" | "vertical";
|
|
34
|
-
/** A row/column of `<Button>`s, `<ButtonGroupText>`s, or separators. */
|
|
35
|
-
children?: React.ReactNode;
|
|
36
|
-
className?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function ButtonGroup({ className, orientation, ...props }: ButtonGroupProps) {
|
|
40
|
-
return (
|
|
41
|
-
<div
|
|
42
|
-
role="group"
|
|
43
|
-
data-slot="button-group"
|
|
44
|
-
data-orientation={orientation}
|
|
45
|
-
className={cn(buttonGroupVariants({ orientation }), className)}
|
|
46
|
-
{...props}
|
|
47
|
-
/>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface ButtonGroupTextProps extends React.ComponentProps<"div"> {
|
|
52
|
-
/**
|
|
53
|
-
* Render as a Radix Slot — useful for wrapping a label or icon as the
|
|
54
|
-
* group's text element.
|
|
55
|
-
* @default false
|
|
56
|
-
*/
|
|
57
|
-
asChild?: boolean;
|
|
58
|
-
/** Text or icon content. */
|
|
59
|
-
children?: React.ReactNode;
|
|
60
|
-
className?: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function ButtonGroupText({ className, asChild = false, ...props }: ButtonGroupTextProps) {
|
|
64
|
-
const Comp = asChild ? Slot : "div";
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<Comp
|
|
68
|
-
className={cn(
|
|
69
|
-
"bg-muted shadow-xs flex items-center gap-2 rounded-md border border-border px-4 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
|
|
70
|
-
className,
|
|
71
|
-
)}
|
|
72
|
-
{...props}
|
|
73
|
-
/>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface ButtonGroupSeparatorProps extends React.ComponentProps<typeof Separator> {
|
|
78
|
-
/**
|
|
79
|
-
* Layout direction.
|
|
80
|
-
* @default "vertical"
|
|
81
|
-
*/
|
|
82
|
-
orientation?: "horizontal" | "vertical";
|
|
83
|
-
className?: string;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function ButtonGroupSeparator({
|
|
87
|
-
className,
|
|
88
|
-
orientation = "vertical",
|
|
89
|
-
...props
|
|
90
|
-
}: ButtonGroupSeparatorProps) {
|
|
91
|
-
return (
|
|
92
|
-
<Separator
|
|
93
|
-
data-slot="button-group-separator"
|
|
94
|
-
orientation={orientation}
|
|
95
|
-
className={cn(
|
|
96
|
-
"bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto",
|
|
97
|
-
className,
|
|
98
|
-
)}
|
|
99
|
-
{...props}
|
|
100
|
-
/>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import { type DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
|
|
6
|
-
|
|
7
|
-
import { cn } from "../../lib/utils";
|
|
8
|
-
import { Button, buttonVariants } from "../atoms/button";
|
|
9
|
-
|
|
10
|
-
export type CalendarProps = React.ComponentProps<typeof DayPicker> & {
|
|
11
|
-
/**
|
|
12
|
-
* Variant applied to the prev/next month nav buttons. Maps to the
|
|
13
|
-
* `Button` atom's variants.
|
|
14
|
-
* @default "ghost"
|
|
15
|
-
*/
|
|
16
|
-
buttonVariant?: React.ComponentProps<typeof Button>["variant"];
|
|
17
|
-
/**
|
|
18
|
-
* Show days from the previous/next month as faded entries to fill the
|
|
19
|
-
* grid.
|
|
20
|
-
* @default true
|
|
21
|
-
*/
|
|
22
|
-
showOutsideDays?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* How the month/year heading renders. `label` is plain text, the
|
|
25
|
-
* dropdown variants render selectable controls.
|
|
26
|
-
* @default "label"
|
|
27
|
-
*/
|
|
28
|
-
captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years";
|
|
29
|
-
className?: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
function Calendar({
|
|
33
|
-
className,
|
|
34
|
-
classNames,
|
|
35
|
-
showOutsideDays = true,
|
|
36
|
-
captionLayout = "label",
|
|
37
|
-
buttonVariant = "ghost",
|
|
38
|
-
formatters,
|
|
39
|
-
components,
|
|
40
|
-
...props
|
|
41
|
-
}: CalendarProps) {
|
|
42
|
-
const defaultClassNames = getDefaultClassNames();
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<DayPicker
|
|
46
|
-
showOutsideDays={showOutsideDays}
|
|
47
|
-
data-slot="calendar"
|
|
48
|
-
className={cn(
|
|
49
|
-
"bg-background group/calendar p-4 [--cell-size:2rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
|
50
|
-
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
51
|
-
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
|
52
|
-
className,
|
|
53
|
-
)}
|
|
54
|
-
captionLayout={captionLayout}
|
|
55
|
-
formatters={{
|
|
56
|
-
formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
|
|
57
|
-
...formatters,
|
|
58
|
-
}}
|
|
59
|
-
classNames={{
|
|
60
|
-
root: cn("w-fit", defaultClassNames.root),
|
|
61
|
-
months: cn("relative flex flex-col gap-4 md:flex-row", defaultClassNames.months),
|
|
62
|
-
month: cn("flex w-full flex-col gap-3", defaultClassNames.month),
|
|
63
|
-
nav: cn(
|
|
64
|
-
"absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
|
|
65
|
-
defaultClassNames.nav,
|
|
66
|
-
),
|
|
67
|
-
button_previous: cn(
|
|
68
|
-
buttonVariants({ variant: buttonVariant }),
|
|
69
|
-
"h-[var(--cell-size)] w-[var(--cell-size)] select-none p-0 aria-disabled:opacity-50",
|
|
70
|
-
defaultClassNames.button_previous,
|
|
71
|
-
),
|
|
72
|
-
button_next: cn(
|
|
73
|
-
buttonVariants({ variant: buttonVariant }),
|
|
74
|
-
"h-[var(--cell-size)] w-[var(--cell-size)] select-none p-0 aria-disabled:opacity-50",
|
|
75
|
-
defaultClassNames.button_next,
|
|
76
|
-
),
|
|
77
|
-
month_caption: cn(
|
|
78
|
-
"flex h-[var(--cell-size)] w-full items-center justify-center px-[var(--cell-size)]",
|
|
79
|
-
defaultClassNames.month_caption,
|
|
80
|
-
),
|
|
81
|
-
dropdowns: cn(
|
|
82
|
-
"flex h-[var(--cell-size)] w-full items-center justify-center gap-1.5 text-sm font-medium",
|
|
83
|
-
defaultClassNames.dropdowns,
|
|
84
|
-
),
|
|
85
|
-
dropdown_root: cn(
|
|
86
|
-
"has-focus:border-ring border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] relative rounded-md border",
|
|
87
|
-
defaultClassNames.dropdown_root,
|
|
88
|
-
),
|
|
89
|
-
dropdown: cn("bg-popover absolute inset-0 opacity-0", defaultClassNames.dropdown),
|
|
90
|
-
caption_label: cn(
|
|
91
|
-
"select-none font-semibold tracking-tight text-foreground",
|
|
92
|
-
captionLayout === "label"
|
|
93
|
-
? "text-sm"
|
|
94
|
-
: "[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5",
|
|
95
|
-
defaultClassNames.caption_label,
|
|
96
|
-
),
|
|
97
|
-
table: "w-full border-collapse",
|
|
98
|
-
weekdays: cn("flex border-b border-border pb-1.5", defaultClassNames.weekdays),
|
|
99
|
-
weekday: cn(
|
|
100
|
-
"text-muted-foreground flex-1 select-none rounded-md text-[0.7rem] font-medium uppercase tracking-wider",
|
|
101
|
-
defaultClassNames.weekday,
|
|
102
|
-
),
|
|
103
|
-
week: cn("mt-1.5 flex w-full", defaultClassNames.week),
|
|
104
|
-
week_number_header: cn(
|
|
105
|
-
"w-[var(--cell-size)] select-none",
|
|
106
|
-
defaultClassNames.week_number_header,
|
|
107
|
-
),
|
|
108
|
-
week_number: cn(
|
|
109
|
-
"text-muted-foreground select-none text-[0.8rem]",
|
|
110
|
-
defaultClassNames.week_number,
|
|
111
|
-
),
|
|
112
|
-
day: cn(
|
|
113
|
-
"group/day relative aspect-square h-full w-full select-none p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md",
|
|
114
|
-
defaultClassNames.day,
|
|
115
|
-
),
|
|
116
|
-
range_start: cn("bg-brand/10 rounded-l-md", defaultClassNames.range_start),
|
|
117
|
-
range_middle: cn("bg-brand/10 rounded-none", defaultClassNames.range_middle),
|
|
118
|
-
range_end: cn("bg-brand/10 rounded-r-md", defaultClassNames.range_end),
|
|
119
|
-
today: cn(
|
|
120
|
-
"text-brand font-semibold data-[selected=true]:rounded-none",
|
|
121
|
-
defaultClassNames.today,
|
|
122
|
-
),
|
|
123
|
-
outside: cn(
|
|
124
|
-
"text-muted-foreground/50 aria-selected:text-muted-foreground",
|
|
125
|
-
defaultClassNames.outside,
|
|
126
|
-
),
|
|
127
|
-
disabled: cn("text-muted-foreground opacity-40", defaultClassNames.disabled),
|
|
128
|
-
hidden: cn("invisible", defaultClassNames.hidden),
|
|
129
|
-
...classNames,
|
|
130
|
-
}}
|
|
131
|
-
components={{
|
|
132
|
-
Root: ({ className, rootRef, ...props }) => {
|
|
133
|
-
return <div data-slot="calendar" ref={rootRef} className={cn(className)} {...props} />;
|
|
134
|
-
},
|
|
135
|
-
Chevron: ({ className, orientation, ...props }) => {
|
|
136
|
-
if (orientation === "left") {
|
|
137
|
-
return <ChevronLeftIcon className={cn("size-4", className)} {...props} />;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (orientation === "right") {
|
|
141
|
-
return <ChevronRightIcon className={cn("size-4", className)} {...props} />;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return <ChevronDownIcon className={cn("size-4", className)} {...props} />;
|
|
145
|
-
},
|
|
146
|
-
DayButton: CalendarDayButton,
|
|
147
|
-
WeekNumber: ({ children, ...props }) => {
|
|
148
|
-
return (
|
|
149
|
-
<td {...props}>
|
|
150
|
-
<div className="flex size-[var(--cell-size)] items-center justify-center text-center">
|
|
151
|
-
{children}
|
|
152
|
-
</div>
|
|
153
|
-
</td>
|
|
154
|
-
);
|
|
155
|
-
},
|
|
156
|
-
...components,
|
|
157
|
-
}}
|
|
158
|
-
{...props}
|
|
159
|
-
/>
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function CalendarDayButton({
|
|
164
|
-
className,
|
|
165
|
-
day,
|
|
166
|
-
modifiers,
|
|
167
|
-
...props
|
|
168
|
-
}: React.ComponentProps<typeof DayButton>) {
|
|
169
|
-
const defaultClassNames = getDefaultClassNames();
|
|
170
|
-
|
|
171
|
-
const ref = React.useRef<HTMLButtonElement>(null);
|
|
172
|
-
React.useEffect(() => {
|
|
173
|
-
if (modifiers.focused) ref.current?.focus();
|
|
174
|
-
}, [modifiers.focused]);
|
|
175
|
-
|
|
176
|
-
return (
|
|
177
|
-
<Button
|
|
178
|
-
ref={ref}
|
|
179
|
-
variant="ghost"
|
|
180
|
-
size="icon"
|
|
181
|
-
data-day={day.date.toLocaleDateString()}
|
|
182
|
-
data-selected-single={
|
|
183
|
-
modifiers.selected &&
|
|
184
|
-
!modifiers.range_start &&
|
|
185
|
-
!modifiers.range_end &&
|
|
186
|
-
!modifiers.range_middle
|
|
187
|
-
}
|
|
188
|
-
data-range-start={modifiers.range_start}
|
|
189
|
-
data-range-end={modifiers.range_end}
|
|
190
|
-
data-range-middle={modifiers.range_middle}
|
|
191
|
-
className={cn(
|
|
192
|
-
// base size + typography (small inner inset so adjacent dates breathe)
|
|
193
|
-
"m-0.5 flex aspect-square h-auto w-[calc(100%-0.25rem)] min-w-[calc(var(--cell-size)-0.25rem)] items-center justify-center rounded-md text-sm font-normal leading-none transition-colors",
|
|
194
|
-
// hover (when not selected)
|
|
195
|
-
"hover:bg-accent hover:text-accent-foreground",
|
|
196
|
-
// today: keep brand text colour from row classNames; add subtle ring
|
|
197
|
-
"group-[[data-today=true]]/day:ring-1 group-[[data-today=true]]/day:ring-brand/40",
|
|
198
|
-
// single selection: brand fill, white text, full rounding
|
|
199
|
-
"data-[selected-single=true]:bg-brand data-[selected-single=true]:text-brand-foreground data-[selected-single=true]:hover:bg-brand/90 data-[selected-single=true]:hover:text-brand-foreground",
|
|
200
|
-
// range endpoints: brand fill, only outer corners rounded
|
|
201
|
-
"data-[range-start=true]:bg-brand data-[range-start=true]:text-brand-foreground data-[range-start=true]:hover:bg-brand/90 data-[range-start=true]:hover:text-brand-foreground data-[range-start=true]:rounded-r-none",
|
|
202
|
-
"data-[range-end=true]:bg-brand data-[range-end=true]:text-brand-foreground data-[range-end=true]:hover:bg-brand/90 data-[range-end=true]:hover:text-brand-foreground data-[range-end=true]:rounded-l-none",
|
|
203
|
-
// range middle: foreground stays default, no rounding
|
|
204
|
-
"data-[range-middle=true]:bg-transparent data-[range-middle=true]:text-foreground data-[range-middle=true]:rounded-none",
|
|
205
|
-
// focus ring (for keyboard nav)
|
|
206
|
-
"group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-brand/40 group-data-[focused=true]/day:border-brand",
|
|
207
|
-
// modifier label (e.g. holidays) sub-line
|
|
208
|
-
"[&>span]:text-xs [&>span]:opacity-70",
|
|
209
|
-
defaultClassNames.day,
|
|
210
|
-
className,
|
|
211
|
-
)}
|
|
212
|
-
{...props}
|
|
213
|
-
/>
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export { Calendar, CalendarDayButton };
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../../lib/utils";
|
|
4
|
-
|
|
5
|
-
export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
6
|
-
/** `<CardHeader>`, `<CardContent>`, `<CardFooter>` (or any custom layout). */
|
|
7
|
-
children?: React.ReactNode;
|
|
8
|
-
/**
|
|
9
|
-
* Tailwind / CSS classes merged onto the card via `cn()`. Default
|
|
10
|
-
* styling: `rounded-xl` (12px), `border`, `bg-card`, `shadow`.
|
|
11
|
-
*/
|
|
12
|
-
className?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const Card = React.forwardRef<HTMLDivElement, CardProps>(({ className, ...props }, ref) => (
|
|
16
|
-
<div
|
|
17
|
-
ref={ref}
|
|
18
|
-
data-slot="card"
|
|
19
|
-
className={cn("rounded-xl border border-border bg-card text-card-foreground shadow", className)}
|
|
20
|
-
{...props}
|
|
21
|
-
/>
|
|
22
|
-
));
|
|
23
|
-
Card.displayName = "Card";
|
|
24
|
-
|
|
25
|
-
export interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
26
|
-
/** Typically `<CardTitle>` + `<CardDescription>`. */
|
|
27
|
-
children?: React.ReactNode;
|
|
28
|
-
/** Tailwind / CSS classes merged onto the header via `cn()`. Default: `p-6 space-y-1.5`. */
|
|
29
|
-
className?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const CardHeader = React.forwardRef<HTMLDivElement, CardHeaderProps>(
|
|
33
|
-
({ className, ...props }, ref) => (
|
|
34
|
-
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
|
|
35
|
-
),
|
|
36
|
-
);
|
|
37
|
-
CardHeader.displayName = "CardHeader";
|
|
38
|
-
|
|
39
|
-
export interface CardTitleProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
40
|
-
/** The card heading. */
|
|
41
|
-
children?: React.ReactNode;
|
|
42
|
-
/** Tailwind / CSS classes merged onto the title via `cn()`. */
|
|
43
|
-
className?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const CardTitle = React.forwardRef<HTMLDivElement, CardTitleProps>(
|
|
47
|
-
({ className, ...props }, ref) => (
|
|
48
|
-
<div
|
|
49
|
-
ref={ref}
|
|
50
|
-
className={cn("font-semibold leading-none tracking-tight", className)}
|
|
51
|
-
{...props}
|
|
52
|
-
/>
|
|
53
|
-
),
|
|
54
|
-
);
|
|
55
|
-
CardTitle.displayName = "CardTitle";
|
|
56
|
-
|
|
57
|
-
export interface CardDescriptionProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
58
|
-
/** Subtitle / supporting copy below the title. */
|
|
59
|
-
children?: React.ReactNode;
|
|
60
|
-
/** Tailwind / CSS classes merged onto the description via `cn()`. */
|
|
61
|
-
className?: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const CardDescription = React.forwardRef<HTMLDivElement, CardDescriptionProps>(
|
|
65
|
-
({ className, ...props }, ref) => (
|
|
66
|
-
<div ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
|
|
67
|
-
),
|
|
68
|
-
);
|
|
69
|
-
CardDescription.displayName = "CardDescription";
|
|
70
|
-
|
|
71
|
-
export interface CardContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
72
|
-
/** Card body. */
|
|
73
|
-
children?: React.ReactNode;
|
|
74
|
-
/** Tailwind / CSS classes merged onto the content via `cn()`. Default: `p-6 pt-0`. */
|
|
75
|
-
className?: string;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const CardContent = React.forwardRef<HTMLDivElement, CardContentProps>(
|
|
79
|
-
({ className, ...props }, ref) => (
|
|
80
|
-
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
81
|
-
),
|
|
82
|
-
);
|
|
83
|
-
CardContent.displayName = "CardContent";
|
|
84
|
-
|
|
85
|
-
export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
86
|
-
/** Card actions / metadata row. */
|
|
87
|
-
children?: React.ReactNode;
|
|
88
|
-
/**
|
|
89
|
-
* Tailwind / CSS classes merged onto the footer via `cn()`. Default:
|
|
90
|
-
* `flex items-center p-6 pt-0`.
|
|
91
|
-
*/
|
|
92
|
-
className?: string;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const CardFooter = React.forwardRef<HTMLDivElement, CardFooterProps>(
|
|
96
|
-
({ className, ...props }, ref) => (
|
|
97
|
-
<div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
|
|
98
|
-
),
|
|
99
|
-
);
|
|
100
|
-
CardFooter.displayName = "CardFooter";
|
|
101
|
-
|
|
102
|
-
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle };
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../../lib/utils";
|
|
6
|
-
|
|
7
|
-
export interface ClientBrandProps {
|
|
8
|
-
/** OAuth2 client display name (e.g. "Questrade", "Athena"). */
|
|
9
|
-
clientName: string;
|
|
10
|
-
/**
|
|
11
|
-
* Optional logo URI. Renders as an `<img>` next to the wordmark when
|
|
12
|
-
* present. When absent, a tinted monogram tile is rendered using the
|
|
13
|
-
* first letter of `clientName`.
|
|
14
|
-
*/
|
|
15
|
-
clientLogoUri?: string;
|
|
16
|
-
/**
|
|
17
|
-
* Pixel size of the logo/monogram tile.
|
|
18
|
-
* @default 36
|
|
19
|
-
*/
|
|
20
|
-
size?: number;
|
|
21
|
-
/**
|
|
22
|
-
* Show the wordmark next to the logo.
|
|
23
|
-
* @default true
|
|
24
|
-
*/
|
|
25
|
-
showWordmark?: boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Background colour applied to the monogram fallback tile. Honours
|
|
28
|
-
* Tailwind classes or a raw CSS colour.
|
|
29
|
-
* @default "bg-foreground text-background"
|
|
30
|
-
*/
|
|
31
|
-
monogramClassName?: string;
|
|
32
|
-
/** Tailwind / CSS classes merged onto the root via `cn()`. */
|
|
33
|
-
className?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* OAuth2 client lockup. Renders the requesting application's logo + name
|
|
38
|
-
* so users see "you're signing in to [App]", not the identity-provider
|
|
39
|
-
* platform underneath.
|
|
40
|
-
*
|
|
41
|
-
* Provide `clientLogoUri` to render the client's logo image. Falls back to
|
|
42
|
-
* a monogram tile when no URI is supplied or the image fails to load.
|
|
43
|
-
*
|
|
44
|
-
* Designed for the brand slot of `AuthShell` / sign-in pages. Stays a thin
|
|
45
|
-
* presentation primitive: no client-registry lookups, no fetches. Pass the
|
|
46
|
-
* shaped data in from your auth backend.
|
|
47
|
-
*/
|
|
48
|
-
const ClientBrand = React.forwardRef<HTMLDivElement, ClientBrandProps>(
|
|
49
|
-
(
|
|
50
|
-
{ clientName, clientLogoUri, size = 36, showWordmark = true, monogramClassName, className },
|
|
51
|
-
ref,
|
|
52
|
-
) => {
|
|
53
|
-
const [imgFailed, setImgFailed] = React.useState(false);
|
|
54
|
-
const showImage = !!clientLogoUri && !imgFailed;
|
|
55
|
-
const initial = (clientName?.trim()?.[0] || "?").toUpperCase();
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div
|
|
59
|
-
ref={ref}
|
|
60
|
-
role="img"
|
|
61
|
-
aria-label={`Signing in to ${clientName}`}
|
|
62
|
-
className={cn("flex items-center gap-2.5", className)}
|
|
63
|
-
>
|
|
64
|
-
{showImage ? (
|
|
65
|
-
<img
|
|
66
|
-
src={clientLogoUri}
|
|
67
|
-
alt=""
|
|
68
|
-
width={size}
|
|
69
|
-
height={size}
|
|
70
|
-
className="shrink-0 rounded-lg object-contain"
|
|
71
|
-
style={{ width: size, height: size }}
|
|
72
|
-
onError={() => setImgFailed(true)}
|
|
73
|
-
/>
|
|
74
|
-
) : (
|
|
75
|
-
<div
|
|
76
|
-
className={cn(
|
|
77
|
-
"flex shrink-0 items-center justify-center rounded-lg font-semibold",
|
|
78
|
-
monogramClassName || "bg-foreground text-background",
|
|
79
|
-
)}
|
|
80
|
-
style={{ width: size, height: size, fontSize: Math.round(size * 0.5) }}
|
|
81
|
-
aria-hidden
|
|
82
|
-
>
|
|
83
|
-
{initial}
|
|
84
|
-
</div>
|
|
85
|
-
)}
|
|
86
|
-
{showWordmark && (
|
|
87
|
-
<span className="text-lg font-semibold tracking-tight text-foreground">{clientName}</span>
|
|
88
|
-
)}
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
},
|
|
92
|
-
);
|
|
93
|
-
ClientBrand.displayName = "ClientBrand";
|
|
94
|
-
|
|
95
|
-
export { ClientBrand };
|