@borisj74/bv-ds 0.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/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/index.cjs +33885 -0
- package/dist/index.d.cts +2715 -0
- package/dist/index.d.ts +2715 -0
- package/dist/index.js +33717 -0
- package/package.json +67 -0
- package/src/components/ActivityFeed/ActivityFeed.tsx +48 -0
- package/src/components/ActivityFeed/index.ts +2 -0
- package/src/components/ActivityGauge/ActivityGauge.tsx +155 -0
- package/src/components/ActivityGauge/index.ts +7 -0
- package/src/components/AdvancedFilterBar/AdvancedFilterBar.tsx +80 -0
- package/src/components/AdvancedFilterBar/index.ts +2 -0
- package/src/components/Alert/Alert.tsx +210 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/Avatar/Avatar.tsx +111 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/AvatarAddButton/AvatarAddButton.tsx +65 -0
- package/src/components/AvatarAddButton/index.ts +5 -0
- package/src/components/AvatarGroup/AvatarGroup.tsx +79 -0
- package/src/components/AvatarGroup/index.ts +6 -0
- package/src/components/AvatarLabelGroup/AvatarLabelGroup.tsx +62 -0
- package/src/components/AvatarLabelGroup/index.ts +5 -0
- package/src/components/AvatarProfilePhoto/AvatarProfilePhoto.tsx +117 -0
- package/src/components/AvatarProfilePhoto/index.ts +5 -0
- package/src/components/Badge/ColorBadge.tsx +36 -0
- package/src/components/Badge/ModernBadge.tsx +38 -0
- package/src/components/Badge/PillBadge.tsx +36 -0
- package/src/components/Badge/badgeShared.tsx +139 -0
- package/src/components/Badge/index.ts +7 -0
- package/src/components/BadgeCloseX/BadgeCloseX.tsx +64 -0
- package/src/components/BadgeCloseX/index.ts +2 -0
- package/src/components/BadgeGroup/BadgeGroup.tsx +61 -0
- package/src/components/BadgeGroup/index.ts +7 -0
- package/src/components/BreadcrumbButtonBase/BreadcrumbButtonBase.tsx +75 -0
- package/src/components/BreadcrumbButtonBase/index.ts +5 -0
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +62 -0
- package/src/components/Breadcrumbs/index.ts +2 -0
- package/src/components/Button/Button.tsx +71 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/ButtonCloseX/ButtonCloseX.tsx +54 -0
- package/src/components/ButtonCloseX/index.ts +2 -0
- package/src/components/ButtonDestructive/ButtonDestructive.tsx +67 -0
- package/src/components/ButtonDestructive/index.ts +6 -0
- package/src/components/ButtonGroup/ButtonGroup.tsx +28 -0
- package/src/components/ButtonGroup/index.ts +2 -0
- package/src/components/ButtonGroupSegment/ButtonGroupSegment.tsx +54 -0
- package/src/components/ButtonGroupSegment/index.ts +5 -0
- package/src/components/ButtonUtility/ButtonUtility.tsx +67 -0
- package/src/components/ButtonUtility/index.ts +6 -0
- package/src/components/CalendarCell/CalendarCell.tsx +82 -0
- package/src/components/CalendarCell/index.ts +2 -0
- package/src/components/CalendarCellDayWeekView/CalendarCellDayWeekView.tsx +56 -0
- package/src/components/CalendarCellDayWeekView/index.ts +2 -0
- package/src/components/CalendarColumnHeader/CalendarColumnHeader.tsx +45 -0
- package/src/components/CalendarColumnHeader/index.ts +5 -0
- package/src/components/CalendarDateIcon/CalendarDateIcon.tsx +25 -0
- package/src/components/CalendarDateIcon/index.ts +2 -0
- package/src/components/CalendarEvent/CalendarEvent.tsx +76 -0
- package/src/components/CalendarEvent/index.ts +2 -0
- package/src/components/CalendarEventDayWeekView/CalendarEventDayWeekView.tsx +76 -0
- package/src/components/CalendarEventDayWeekView/index.ts +2 -0
- package/src/components/CalendarHeader/CalendarHeader.tsx +47 -0
- package/src/components/CalendarHeader/index.ts +2 -0
- package/src/components/CalendarRowLabel/CalendarRowLabel.tsx +21 -0
- package/src/components/CalendarRowLabel/index.ts +2 -0
- package/src/components/CalendarTimemarker/CalendarTimemarker.tsx +46 -0
- package/src/components/CalendarTimemarker/index.ts +5 -0
- package/src/components/CalendarViewDropdown/CalendarViewDropdown.tsx +101 -0
- package/src/components/CalendarViewDropdown/index.ts +6 -0
- package/src/components/CardHeader/CardHeader.tsx +57 -0
- package/src/components/CardHeader/index.ts +2 -0
- package/src/components/CarouselArrow/CarouselArrow.tsx +47 -0
- package/src/components/CarouselArrow/index.ts +6 -0
- package/src/components/CarouselImage/CarouselImage.tsx +60 -0
- package/src/components/CarouselImage/index.ts +2 -0
- package/src/components/Change/Change.tsx +73 -0
- package/src/components/Change/index.ts +2 -0
- package/src/components/ChartLegend/ChartLegend.tsx +38 -0
- package/src/components/ChartLegend/index.ts +2 -0
- package/src/components/ChartMarker/ChartMarker.tsx +54 -0
- package/src/components/ChartMarker/index.ts +2 -0
- package/src/components/ChartMini/ChartMini.tsx +86 -0
- package/src/components/ChartMini/index.ts +2 -0
- package/src/components/ChartTooltip/ChartTooltip.tsx +44 -0
- package/src/components/ChartTooltip/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.tsx +65 -0
- package/src/components/Checkbox/checkboxBase.tsx +81 -0
- package/src/components/Checkbox/index.ts +3 -0
- package/src/components/CodeSnippet/CodeSnippet.tsx +94 -0
- package/src/components/CodeSnippet/index.ts +2 -0
- package/src/components/CodeSnippetTabs/CodeSnippetTabs.tsx +44 -0
- package/src/components/CodeSnippetTabs/index.ts +2 -0
- package/src/components/CommandBar/CommandBar.tsx +80 -0
- package/src/components/CommandBar/index.ts +2 -0
- package/src/components/CommandBarFooter/CommandBarFooter.tsx +125 -0
- package/src/components/CommandBarFooter/index.ts +5 -0
- package/src/components/CommandBarMenuSection/CommandBarMenuSection.tsx +28 -0
- package/src/components/CommandBarMenuSection/index.ts +2 -0
- package/src/components/CommandBarNavigationIcon/CommandBarNavigationIcon.tsx +47 -0
- package/src/components/CommandBarNavigationIcon/index.ts +2 -0
- package/src/components/CommandDropdownMenuItem/CommandDropdownMenuItem.tsx +51 -0
- package/src/components/CommandDropdownMenuItem/index.ts +2 -0
- package/src/components/CommandInput/CommandInput.tsx +74 -0
- package/src/components/CommandInput/index.ts +2 -0
- package/src/components/CommandShortcut/CommandShortcut.tsx +26 -0
- package/src/components/CommandShortcut/index.ts +2 -0
- package/src/components/ContentDivider/ContentDivider.tsx +80 -0
- package/src/components/ContentDivider/index.ts +6 -0
- package/src/components/ContentFeatureText/ContentFeatureText.tsx +60 -0
- package/src/components/ContentFeatureText/index.ts +5 -0
- package/src/components/ContentHeading/ContentHeading.tsx +43 -0
- package/src/components/ContentHeading/index.ts +5 -0
- package/src/components/ContentParagraph/ContentParagraph.tsx +39 -0
- package/src/components/ContentParagraph/index.ts +5 -0
- package/src/components/ContentQuote/ContentQuote.tsx +114 -0
- package/src/components/ContentQuote/index.ts +6 -0
- package/src/components/ContentRule/ContentRule.tsx +31 -0
- package/src/components/ContentRule/index.ts +2 -0
- package/src/components/ContextMenu/ContextMenu.tsx +67 -0
- package/src/components/ContextMenu/index.ts +7 -0
- package/src/components/ContextMenu/useContextMenu.ts +41 -0
- package/src/components/DatePickerCell/DatePickerCell.tsx +77 -0
- package/src/components/DatePickerCell/index.ts +2 -0
- package/src/components/DatePickerListItem/DatePickerListItem.tsx +39 -0
- package/src/components/DatePickerListItem/index.ts +2 -0
- package/src/components/DatePickerMenu/DatePickerMenu.tsx +131 -0
- package/src/components/DatePickerMenu/index.ts +2 -0
- package/src/components/DropdownAccountListItem/DropdownAccountListItem.tsx +69 -0
- package/src/components/DropdownAccountListItem/index.ts +2 -0
- package/src/components/DropdownMenuFooter/DropdownMenuFooter.tsx +50 -0
- package/src/components/DropdownMenuFooter/index.ts +5 -0
- package/src/components/DropdownMenuHeader/DropdownMenuHeader.tsx +93 -0
- package/src/components/DropdownMenuHeader/index.ts +5 -0
- package/src/components/DropdownMenuItemInsetIcon/DropdownMenuItemInsetIcon.tsx +89 -0
- package/src/components/DropdownMenuItemInsetIcon/index.ts +5 -0
- package/src/components/DropdownMenuListItem/DropdownMenuListItem.tsx +84 -0
- package/src/components/DropdownMenuListItem/index.ts +2 -0
- package/src/components/EmptyState/EmptyState.tsx +65 -0
- package/src/components/EmptyState/index.ts +2 -0
- package/src/components/FeedItemBase/FeedItemBase.tsx +135 -0
- package/src/components/FeedItemBase/index.ts +2 -0
- package/src/components/FileUpload/FileUpload.tsx +112 -0
- package/src/components/FileUpload/index.ts +2 -0
- package/src/components/FileUploadBase/FileUploadBase.tsx +69 -0
- package/src/components/FileUploadBase/index.ts +2 -0
- package/src/components/FileUploadItemBase/FileUploadItemBase.tsx +190 -0
- package/src/components/FileUploadItemBase/index.ts +7 -0
- package/src/components/FilterBar/FilterBar.tsx +62 -0
- package/src/components/FilterBar/index.ts +2 -0
- package/src/components/FilterTabs/FilterTabs.tsx +41 -0
- package/src/components/FilterTabs/index.ts +2 -0
- package/src/components/FiltersDropdownMenu/FiltersDropdownMenu.tsx +104 -0
- package/src/components/FiltersDropdownMenu/index.ts +2 -0
- package/src/components/FiltersSlideoutMenu/FiltersSlideoutMenu.tsx +71 -0
- package/src/components/FiltersSlideoutMenu/index.ts +2 -0
- package/src/components/HeaderNavigation/HeaderNavigation.tsx +178 -0
- package/src/components/HeaderNavigation/index.ts +6 -0
- package/src/components/HelpIcon/HelpIcon.tsx +49 -0
- package/src/components/HelpIcon/index.ts +2 -0
- package/src/components/InputField/InputField.tsx +108 -0
- package/src/components/InputField/index.ts +3 -0
- package/src/components/InputField/inputFieldShared.tsx +68 -0
- package/src/components/LeadingInputField/LeadingInputField.tsx +60 -0
- package/src/components/LeadingInputField/index.ts +2 -0
- package/src/components/LineAndBarChart/LineAndBarChart.tsx +96 -0
- package/src/components/LineAndBarChart/index.ts +2 -0
- package/src/components/LinkMessage/LinkMessage.tsx +52 -0
- package/src/components/LinkMessage/index.ts +2 -0
- package/src/components/LoadingIndicator/LoadingIndicator.tsx +108 -0
- package/src/components/LoadingIndicator/index.ts +6 -0
- package/src/components/MediaMessage/MediaMessage.tsx +109 -0
- package/src/components/MediaMessage/index.ts +2 -0
- package/src/components/MegaInputFieldBase/MegaInputFieldBase.tsx +49 -0
- package/src/components/MegaInputFieldBase/index.ts +5 -0
- package/src/components/Message/Message.tsx +85 -0
- package/src/components/Message/index.ts +3 -0
- package/src/components/Message/messageShared.tsx +73 -0
- package/src/components/MessageAction/MessageAction.tsx +221 -0
- package/src/components/MessageAction/index.ts +2 -0
- package/src/components/MessageActionButton/MessageActionButton.tsx +36 -0
- package/src/components/MessageActionButton/index.ts +2 -0
- package/src/components/MessageActionPanel/MessageActionPanel.tsx +36 -0
- package/src/components/MessageActionPanel/index.ts +2 -0
- package/src/components/MessageReaction/MessageReaction.tsx +37 -0
- package/src/components/MessageReaction/index.ts +2 -0
- package/src/components/MessageStatusIcon/MessageStatusIcon.tsx +54 -0
- package/src/components/MessageStatusIcon/index.ts +2 -0
- package/src/components/MetricItem/MetricItem.tsx +147 -0
- package/src/components/MetricItem/index.ts +2 -0
- package/src/components/ModalActions/ModalActions.tsx +57 -0
- package/src/components/ModalActions/index.ts +2 -0
- package/src/components/ModalHeader/ModalHeader.tsx +99 -0
- package/src/components/ModalHeader/index.ts +2 -0
- package/src/components/MultiSelect/MultiSelect.tsx +118 -0
- package/src/components/MultiSelect/index.ts +2 -0
- package/src/components/NavAccountCard/NavAccountCard.tsx +124 -0
- package/src/components/NavAccountCard/index.ts +2 -0
- package/src/components/NavAccountCardMenuItem/NavAccountCardMenuItem.tsx +101 -0
- package/src/components/NavAccountCardMenuItem/index.ts +5 -0
- package/src/components/NavButton/NavButton.tsx +50 -0
- package/src/components/NavButton/index.ts +2 -0
- package/src/components/NavFeaturedCard/NavFeaturedCard.tsx +82 -0
- package/src/components/NavFeaturedCard/index.ts +2 -0
- package/src/components/NavItemBase/NavItemBase.tsx +79 -0
- package/src/components/NavItemBase/index.ts +2 -0
- package/src/components/NavItemDropdownBase/NavItemDropdownBase.tsx +74 -0
- package/src/components/NavItemDropdownBase/index.ts +2 -0
- package/src/components/NavMenuButton/NavMenuButton.tsx +47 -0
- package/src/components/NavMenuButton/index.ts +2 -0
- package/src/components/Notification/Notification.tsx +102 -0
- package/src/components/Notification/index.ts +2 -0
- package/src/components/NumberInput/NumberInput.tsx +114 -0
- package/src/components/NumberInput/index.ts +2 -0
- package/src/components/PageHeader/PageHeader.tsx +88 -0
- package/src/components/PageHeader/index.ts +2 -0
- package/src/components/Pagination/Pagination.tsx +124 -0
- package/src/components/Pagination/index.ts +2 -0
- package/src/components/PaginationButtonGroupBase/PaginationButtonGroupBase.tsx +69 -0
- package/src/components/PaginationButtonGroupBase/index.ts +5 -0
- package/src/components/PaginationCards/PaginationCards.tsx +72 -0
- package/src/components/PaginationCards/index.ts +2 -0
- package/src/components/PaginationDotGroup/PaginationDotGroup.tsx +66 -0
- package/src/components/PaginationDotGroup/index.ts +2 -0
- package/src/components/PaginationDotIndicator/PaginationDotIndicator.tsx +39 -0
- package/src/components/PaginationDotIndicator/index.ts +6 -0
- package/src/components/PaginationNumberBase/PaginationNumberBase.tsx +42 -0
- package/src/components/PaginationNumberBase/index.ts +5 -0
- package/src/components/PieChart/PieChart.tsx +73 -0
- package/src/components/PieChart/index.ts +2 -0
- package/src/components/ProgressBar/ProgressBar.tsx +75 -0
- package/src/components/ProgressBar/index.ts +2 -0
- package/src/components/ProgressCircle/ProgressCircle.tsx +89 -0
- package/src/components/ProgressCircle/index.ts +6 -0
- package/src/components/RadarChart/RadarChart.tsx +62 -0
- package/src/components/RadarChart/index.ts +2 -0
- package/src/components/Radio/Radio.tsx +55 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/RadioGroup/RadioGroup.tsx +54 -0
- package/src/components/RadioGroup/index.ts +2 -0
- package/src/components/RadioGroupItem/RadioGroupItem.tsx +118 -0
- package/src/components/RadioGroupItem/index.ts +6 -0
- package/src/components/SectionFooter/SectionFooter.tsx +40 -0
- package/src/components/SectionFooter/index.ts +2 -0
- package/src/components/SectionHeader/SectionHeader.tsx +44 -0
- package/src/components/SectionHeader/index.ts +2 -0
- package/src/components/SectionLabel/SectionLabel.tsx +51 -0
- package/src/components/SectionLabel/index.ts +2 -0
- package/src/components/Select/Select.tsx +121 -0
- package/src/components/Select/index.ts +2 -0
- package/src/components/SelectMenuItem/SelectMenuItem.tsx +85 -0
- package/src/components/SelectMenuItem/index.ts +2 -0
- package/src/components/SidebarNavigation/SidebarNavigation.tsx +100 -0
- package/src/components/SidebarNavigation/index.ts +2 -0
- package/src/components/SlideOutMenuHeader/SlideOutMenuHeader.tsx +56 -0
- package/src/components/SlideOutMenuHeader/index.ts +2 -0
- package/src/components/Slider/Slider.tsx +125 -0
- package/src/components/Slider/index.ts +2 -0
- package/src/components/SocialButton/SocialButton.tsx +88 -0
- package/src/components/SocialButton/index.ts +2 -0
- package/src/components/StatusIcon/StatusIcon.tsx +75 -0
- package/src/components/StatusIcon/index.ts +2 -0
- package/src/components/StepBase/StepBase.tsx +90 -0
- package/src/components/StepBase/index.ts +2 -0
- package/src/components/StepIconBase/StepIconBase.tsx +65 -0
- package/src/components/StepIconBase/index.ts +7 -0
- package/src/components/TabButtonBase/TabButtonBase.tsx +88 -0
- package/src/components/TabButtonBase/index.ts +2 -0
- package/src/components/TableCell/TableCell.tsx +44 -0
- package/src/components/TableCell/index.ts +2 -0
- package/src/components/TableHeaderCell/TableHeaderCell.tsx +34 -0
- package/src/components/TableHeaderCell/index.ts +2 -0
- package/src/components/TableHeaderLabel/TableHeaderLabel.tsx +37 -0
- package/src/components/TableHeaderLabel/index.ts +2 -0
- package/src/components/Tabs/Tabs.tsx +80 -0
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Tag/Tag.tsx +91 -0
- package/src/components/Tag/index.ts +2 -0
- package/src/components/TagsInputField/TagsInputField.tsx +90 -0
- package/src/components/TagsInputField/index.ts +2 -0
- package/src/components/TextEditorToolbar/TextEditorToolbar.tsx +33 -0
- package/src/components/TextEditorToolbar/index.ts +2 -0
- package/src/components/TextEditorTooltip/TextEditorTooltip.tsx +28 -0
- package/src/components/TextEditorTooltip/index.ts +2 -0
- package/src/components/TextareaInputField/TextareaInputField.tsx +45 -0
- package/src/components/TextareaInputField/index.ts +2 -0
- package/src/components/Toggle/Toggle.tsx +87 -0
- package/src/components/Toggle/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.tsx +59 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/TrailingInputField/TrailingInputField.tsx +62 -0
- package/src/components/TrailingInputField/index.ts +2 -0
- package/src/components/TreeView/TreeView.tsx +86 -0
- package/src/components/TreeView/index.ts +2 -0
- package/src/components/TreeViewConnector/TreeViewConnector.tsx +36 -0
- package/src/components/TreeViewConnector/index.ts +2 -0
- package/src/components/TreeViewItem/TreeViewItem.tsx +111 -0
- package/src/components/TreeViewItem/index.ts +2 -0
- package/src/components/VerificationCodeInput/VerificationCodeInput.tsx +114 -0
- package/src/components/VerificationCodeInput/index.ts +2 -0
- package/src/illustrations/BoxIllustration.tsx +13 -0
- package/src/illustrations/CloudIllustration.tsx +18 -0
- package/src/illustrations/CreditCardIllustration.tsx +13 -0
- package/src/illustrations/DocumentsIllustration.tsx +13 -0
- package/src/illustrations/index.ts +4 -0
- package/src/index.ts +147 -0
- package/src/internal/chartTheme.ts +30 -0
- package/src/internal/ringBase.tsx +82 -0
- package/src/styles.css +3 -0
- package/tailwind-preset.js +295 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface CalendarCellDayWeekViewProps {
|
|
5
|
+
/** Event block(s) occupying the slot — typically CalendarEventDayWeekView. */
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
/** Renders a hover "+" add button bottom-right. */
|
|
8
|
+
onAdd?: () => void;
|
|
9
|
+
/** Disabled / outside-hours styling. */
|
|
10
|
+
muted?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function PlusIcon() {
|
|
15
|
+
return (
|
|
16
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-4" aria-hidden>
|
|
17
|
+
<path
|
|
18
|
+
d="M10 4.167v11.666M4.167 10h11.666"
|
|
19
|
+
stroke="currentColor"
|
|
20
|
+
strokeWidth="1.667"
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
|
+
/>
|
|
24
|
+
</svg>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** A time-slot cell in day/week view. Holds CalendarEventDayWeekView blocks. */
|
|
29
|
+
export function CalendarCellDayWeekView({
|
|
30
|
+
children,
|
|
31
|
+
onAdd,
|
|
32
|
+
muted = false,
|
|
33
|
+
className,
|
|
34
|
+
}: CalendarCellDayWeekViewProps) {
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
className={clsx(
|
|
38
|
+
"group relative min-h-[64px] border-b border-border-secondary p-xs font-body",
|
|
39
|
+
muted ? "bg-bg-secondary" : "bg-bg-primary",
|
|
40
|
+
className,
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
{onAdd ? (
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
onClick={onAdd}
|
|
48
|
+
aria-label="Add event"
|
|
49
|
+
className="absolute bottom-xs right-xs hidden rounded-md border border-border-primary bg-bg-primary p-xs text-fg-quaternary shadow-xs transition-colors hover:bg-bg-primary-hover group-hover:flex focus-visible:flex focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand"
|
|
50
|
+
>
|
|
51
|
+
<PlusIcon />
|
|
52
|
+
</button>
|
|
53
|
+
) : null}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
|
|
3
|
+
export type CalendarColumnHeaderOrientation = "horizontal" | "vertical";
|
|
4
|
+
|
|
5
|
+
export interface CalendarColumnHeaderProps {
|
|
6
|
+
/** Weekday label (e.g. "Mon"). */
|
|
7
|
+
weekday: string;
|
|
8
|
+
/** Date number. */
|
|
9
|
+
date: string | number;
|
|
10
|
+
/** Active day — renders the date in a brand-solid circle. */
|
|
11
|
+
current?: boolean;
|
|
12
|
+
orientation?: CalendarColumnHeaderOrientation;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function CalendarColumnHeader({
|
|
17
|
+
weekday,
|
|
18
|
+
date,
|
|
19
|
+
current = false,
|
|
20
|
+
orientation = "vertical",
|
|
21
|
+
className,
|
|
22
|
+
}: CalendarColumnHeaderProps) {
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
className={clsx(
|
|
26
|
+
"flex items-center justify-center gap-md py-md font-body",
|
|
27
|
+
orientation === "vertical" && "flex-col gap-xs",
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
<span className="text-xs font-medium text-text-quaternary">{weekday}</span>
|
|
32
|
+
<span
|
|
33
|
+
className={clsx(
|
|
34
|
+
"flex items-center justify-center text-xs font-semibold",
|
|
35
|
+
current
|
|
36
|
+
? "size-6 rounded-full bg-brand-solid text-white"
|
|
37
|
+
: "text-text-secondary",
|
|
38
|
+
)}
|
|
39
|
+
aria-current={current ? "date" : undefined}
|
|
40
|
+
>
|
|
41
|
+
{date}
|
|
42
|
+
</span>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
|
|
3
|
+
export interface CalendarDateIconProps {
|
|
4
|
+
/** Short month label (e.g. "JAN"). Rendered uppercase. */
|
|
5
|
+
month: string;
|
|
6
|
+
/** Day number. */
|
|
7
|
+
day: string | number;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function CalendarDateIcon({ month, day, className }: CalendarDateIconProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
className={clsx(
|
|
15
|
+
"inline-flex w-12 flex-col overflow-hidden rounded-md border border-border-secondary bg-bg-primary text-center font-body",
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
>
|
|
19
|
+
<span className="bg-bg-secondary py-xxs text-xs font-semibold uppercase text-text-quaternary">
|
|
20
|
+
{month}
|
|
21
|
+
</span>
|
|
22
|
+
<span className="py-xs text-lg font-bold text-text-brand-secondary">{day}</span>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
|
|
3
|
+
export type CalendarEventColor =
|
|
4
|
+
| "neutral"
|
|
5
|
+
| "brand"
|
|
6
|
+
| "emerald"
|
|
7
|
+
| "blue"
|
|
8
|
+
| "indigo"
|
|
9
|
+
| "purple"
|
|
10
|
+
| "pink"
|
|
11
|
+
| "orange"
|
|
12
|
+
| "amber";
|
|
13
|
+
|
|
14
|
+
export interface CalendarEventProps {
|
|
15
|
+
/** Event title. */
|
|
16
|
+
title: string;
|
|
17
|
+
/** Optional time label (e.g. "9:00 AM"). */
|
|
18
|
+
time?: string;
|
|
19
|
+
color?: CalendarEventColor;
|
|
20
|
+
/** Filled colour-fill style vs the subtle white style. */
|
|
21
|
+
filled?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Static class maps (utility-<c>-{100,500,700}) — all present in the preset.
|
|
26
|
+
const dotClasses: Record<CalendarEventColor, string> = {
|
|
27
|
+
neutral: "bg-utility-neutral-500",
|
|
28
|
+
brand: "bg-utility-brand-500",
|
|
29
|
+
emerald: "bg-utility-emerald-500",
|
|
30
|
+
blue: "bg-utility-blue-500",
|
|
31
|
+
indigo: "bg-utility-indigo-500",
|
|
32
|
+
purple: "bg-utility-purple-500",
|
|
33
|
+
pink: "bg-utility-pink-500",
|
|
34
|
+
orange: "bg-utility-orange-500",
|
|
35
|
+
amber: "bg-utility-amber-500",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const filledClasses: Record<CalendarEventColor, string> = {
|
|
39
|
+
neutral: "bg-utility-neutral-100 text-utility-neutral-700",
|
|
40
|
+
brand: "bg-utility-brand-100 text-utility-brand-700",
|
|
41
|
+
emerald: "bg-utility-emerald-100 text-utility-emerald-700",
|
|
42
|
+
blue: "bg-utility-blue-100 text-utility-blue-700",
|
|
43
|
+
indigo: "bg-utility-indigo-100 text-utility-indigo-700",
|
|
44
|
+
purple: "bg-utility-purple-100 text-utility-purple-700",
|
|
45
|
+
pink: "bg-utility-pink-100 text-utility-pink-700",
|
|
46
|
+
orange: "bg-utility-orange-100 text-utility-orange-700",
|
|
47
|
+
amber: "bg-utility-amber-100 text-utility-amber-700",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export function CalendarEvent({
|
|
51
|
+
title,
|
|
52
|
+
time,
|
|
53
|
+
color = "neutral",
|
|
54
|
+
filled = false,
|
|
55
|
+
className,
|
|
56
|
+
}: CalendarEventProps) {
|
|
57
|
+
return (
|
|
58
|
+
<div
|
|
59
|
+
className={clsx(
|
|
60
|
+
"flex w-full items-center gap-md rounded-sm px-md py-xs font-body text-xs",
|
|
61
|
+
filled
|
|
62
|
+
? filledClasses[color]
|
|
63
|
+
: "border border-border-secondary bg-bg-primary text-text-secondary",
|
|
64
|
+
className,
|
|
65
|
+
)}
|
|
66
|
+
>
|
|
67
|
+
<span className={clsx("size-2 shrink-0 rounded-full", dotClasses[color])} aria-hidden />
|
|
68
|
+
<span className="truncate font-semibold">{title}</span>
|
|
69
|
+
{time ? (
|
|
70
|
+
<span className={clsx("ml-auto shrink-0 font-normal", !filled && "text-text-tertiary")}>
|
|
71
|
+
{time}
|
|
72
|
+
</span>
|
|
73
|
+
) : null}
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
import type { CalendarEventColor } from "../CalendarEvent";
|
|
3
|
+
|
|
4
|
+
export interface CalendarEventDayWeekViewProps {
|
|
5
|
+
title: string;
|
|
6
|
+
time?: string;
|
|
7
|
+
color?: CalendarEventColor;
|
|
8
|
+
/** Filled colour-fill style vs the subtle tint. */
|
|
9
|
+
filled?: boolean;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Left-accent border colour (utility-<c>-500).
|
|
14
|
+
const accentClasses: Record<CalendarEventColor, string> = {
|
|
15
|
+
neutral: "border-l-utility-neutral-500",
|
|
16
|
+
brand: "border-l-utility-brand-500",
|
|
17
|
+
emerald: "border-l-utility-emerald-500",
|
|
18
|
+
blue: "border-l-utility-blue-500",
|
|
19
|
+
indigo: "border-l-utility-indigo-500",
|
|
20
|
+
purple: "border-l-utility-purple-500",
|
|
21
|
+
pink: "border-l-utility-pink-500",
|
|
22
|
+
orange: "border-l-utility-orange-500",
|
|
23
|
+
amber: "border-l-utility-amber-500",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const dotClasses: Record<CalendarEventColor, string> = {
|
|
27
|
+
neutral: "bg-utility-neutral-500",
|
|
28
|
+
brand: "bg-utility-brand-500",
|
|
29
|
+
emerald: "bg-utility-emerald-500",
|
|
30
|
+
blue: "bg-utility-blue-500",
|
|
31
|
+
indigo: "bg-utility-indigo-500",
|
|
32
|
+
purple: "bg-utility-purple-500",
|
|
33
|
+
pink: "bg-utility-pink-500",
|
|
34
|
+
orange: "bg-utility-orange-500",
|
|
35
|
+
amber: "bg-utility-amber-500",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const fillClasses: Record<CalendarEventColor, string> = {
|
|
39
|
+
neutral: "bg-utility-neutral-100 text-utility-neutral-700",
|
|
40
|
+
brand: "bg-utility-brand-100 text-utility-brand-700",
|
|
41
|
+
emerald: "bg-utility-emerald-100 text-utility-emerald-700",
|
|
42
|
+
blue: "bg-utility-blue-100 text-utility-blue-700",
|
|
43
|
+
indigo: "bg-utility-indigo-100 text-utility-indigo-700",
|
|
44
|
+
purple: "bg-utility-purple-100 text-utility-purple-700",
|
|
45
|
+
pink: "bg-utility-pink-100 text-utility-pink-700",
|
|
46
|
+
orange: "bg-utility-orange-100 text-utility-orange-700",
|
|
47
|
+
amber: "bg-utility-amber-100 text-utility-amber-700",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export function CalendarEventDayWeekView({
|
|
51
|
+
title,
|
|
52
|
+
time,
|
|
53
|
+
color = "brand",
|
|
54
|
+
filled = false,
|
|
55
|
+
className,
|
|
56
|
+
}: CalendarEventDayWeekViewProps) {
|
|
57
|
+
return (
|
|
58
|
+
<div
|
|
59
|
+
className={clsx(
|
|
60
|
+
"relative flex h-full w-full flex-col gap-xxs rounded-sm border-l-2 px-md py-xs font-body text-xs",
|
|
61
|
+
accentClasses[color],
|
|
62
|
+
filled
|
|
63
|
+
? fillClasses[color]
|
|
64
|
+
: "bg-bg-secondary text-text-secondary",
|
|
65
|
+
className,
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
<span className="truncate pr-md font-semibold">{title}</span>
|
|
69
|
+
{time ? <span className="font-normal opacity-80">{time}</span> : null}
|
|
70
|
+
<span
|
|
71
|
+
className={clsx("absolute right-md top-xs size-2 rounded-full", dotClasses[color])}
|
|
72
|
+
aria-hidden
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export interface CalendarHeaderProps {
|
|
5
|
+
/** Period title, e.g. "January 2027". */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Date range subtitle, e.g. "Jan 1, 2027 – Jan 31, 2027". */
|
|
8
|
+
range?: string;
|
|
9
|
+
/** Badge beside the title (e.g. a PillBadge "Week 1"). */
|
|
10
|
+
badge?: ReactNode;
|
|
11
|
+
/** Leading date chip — typically a CalendarDateIcon. */
|
|
12
|
+
dateIcon?: ReactNode;
|
|
13
|
+
/** Trailing controls slot — nav arrows, CalendarViewDropdown, Add event, etc. */
|
|
14
|
+
actions?: ReactNode;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Top bar of the calendar composite. A layout shell — drop controls into `actions`. */
|
|
19
|
+
export function CalendarHeader({
|
|
20
|
+
title,
|
|
21
|
+
range,
|
|
22
|
+
badge,
|
|
23
|
+
dateIcon,
|
|
24
|
+
actions,
|
|
25
|
+
className,
|
|
26
|
+
}: CalendarHeaderProps) {
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
className={clsx(
|
|
30
|
+
"flex flex-wrap items-start justify-between gap-lg font-body",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
>
|
|
34
|
+
<div className="flex items-center gap-lg">
|
|
35
|
+
{dateIcon}
|
|
36
|
+
<div className="flex flex-col gap-xxs">
|
|
37
|
+
<div className="flex items-center gap-md">
|
|
38
|
+
<h2 className="text-lg font-bold text-text-primary">{title}</h2>
|
|
39
|
+
{badge}
|
|
40
|
+
</div>
|
|
41
|
+
{range ? <p className="text-sm text-text-tertiary">{range}</p> : null}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
{actions ? <div className="flex items-center gap-md">{actions}</div> : null}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
|
|
3
|
+
export interface CalendarRowLabelProps {
|
|
4
|
+
/** Time label for the row gutter (e.g. "9 AM"). */
|
|
5
|
+
label: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Left-gutter time label aligned to the top of a day/week-view row. */
|
|
10
|
+
export function CalendarRowLabel({ label, className }: CalendarRowLabelProps) {
|
|
11
|
+
return (
|
|
12
|
+
<div
|
|
13
|
+
className={clsx(
|
|
14
|
+
"pr-md text-right text-xs font-medium text-text-quaternary font-body",
|
|
15
|
+
className,
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
{label}
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import clsx from "clsx";
|
|
2
|
+
|
|
3
|
+
export type CalendarTimemarkerAlign = "left" | "center";
|
|
4
|
+
|
|
5
|
+
export interface CalendarTimemarkerProps {
|
|
6
|
+
/** Time label (e.g. "2:20 PM"). */
|
|
7
|
+
time: string;
|
|
8
|
+
/** Label position: leading, or centered between two line halves. */
|
|
9
|
+
align?: CalendarTimemarkerAlign;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const Dot = () => (
|
|
14
|
+
<span className="size-2 shrink-0 rounded-full bg-fg-brand-primary-alt" aria-hidden />
|
|
15
|
+
);
|
|
16
|
+
const Line = () => (
|
|
17
|
+
<span className="h-px flex-1 bg-fg-brand-primary-alt" aria-hidden />
|
|
18
|
+
);
|
|
19
|
+
const Label = ({ time }: { time: string }) => (
|
|
20
|
+
<span className="shrink-0 text-xs font-medium text-text-brand-tertiary-alt">{time}</span>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export function CalendarTimemarker({
|
|
24
|
+
time,
|
|
25
|
+
align = "left",
|
|
26
|
+
className,
|
|
27
|
+
}: CalendarTimemarkerProps) {
|
|
28
|
+
return (
|
|
29
|
+
<div className={clsx("flex w-full items-center gap-xs font-body", className)}>
|
|
30
|
+
{align === "center" ? (
|
|
31
|
+
<>
|
|
32
|
+
<Dot />
|
|
33
|
+
<Line />
|
|
34
|
+
<Label time={time} />
|
|
35
|
+
<Line />
|
|
36
|
+
</>
|
|
37
|
+
) : (
|
|
38
|
+
<>
|
|
39
|
+
<Label time={time} />
|
|
40
|
+
<Dot />
|
|
41
|
+
<Line />
|
|
42
|
+
</>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type CalendarView = "day" | "week" | "month";
|
|
5
|
+
|
|
6
|
+
export interface CalendarViewOption {
|
|
7
|
+
value: CalendarView;
|
|
8
|
+
label: string;
|
|
9
|
+
shortcut?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CalendarViewDropdownProps {
|
|
13
|
+
value: CalendarView;
|
|
14
|
+
onChange?: (value: CalendarView) => void;
|
|
15
|
+
options?: CalendarViewOption[];
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const DEFAULT_OPTIONS: CalendarViewOption[] = [
|
|
20
|
+
{ value: "day", label: "Day view", shortcut: "⌘D" },
|
|
21
|
+
{ value: "week", label: "Week view", shortcut: "⌘W" },
|
|
22
|
+
{ value: "month", label: "Month view", shortcut: "⌘M" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
function Chevron() {
|
|
26
|
+
return (
|
|
27
|
+
<svg viewBox="0 0 20 20" fill="none" className="size-5 shrink-0" aria-hidden>
|
|
28
|
+
<path
|
|
29
|
+
d="m5 7.5 5 5 5-5"
|
|
30
|
+
stroke="currentColor"
|
|
31
|
+
strokeWidth="1.667"
|
|
32
|
+
strokeLinecap="round"
|
|
33
|
+
strokeLinejoin="round"
|
|
34
|
+
/>
|
|
35
|
+
</svg>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function CalendarViewDropdown({
|
|
40
|
+
value,
|
|
41
|
+
onChange,
|
|
42
|
+
options = DEFAULT_OPTIONS,
|
|
43
|
+
className,
|
|
44
|
+
}: CalendarViewDropdownProps) {
|
|
45
|
+
const [open, setOpen] = useState(false);
|
|
46
|
+
const selected = options.find((o) => o.value === value) ?? options[0];
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={clsx("relative inline-block font-body", className)}>
|
|
50
|
+
<button
|
|
51
|
+
type="button"
|
|
52
|
+
aria-haspopup="listbox"
|
|
53
|
+
aria-expanded={open}
|
|
54
|
+
onClick={() => setOpen((v) => !v)}
|
|
55
|
+
className="inline-flex items-center gap-md rounded-md border border-border-primary bg-bg-primary px-lg py-md text-sm font-semibold text-text-secondary shadow-skeuomorphic transition-colors hover:bg-bg-primary-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-primary"
|
|
56
|
+
>
|
|
57
|
+
{selected.label}
|
|
58
|
+
<span className="text-fg-quaternary">
|
|
59
|
+
<Chevron />
|
|
60
|
+
</span>
|
|
61
|
+
</button>
|
|
62
|
+
{open ? (
|
|
63
|
+
<ul
|
|
64
|
+
role="listbox"
|
|
65
|
+
className="absolute left-0 z-10 mt-xs min-w-[200px] rounded-md border border-border-secondary bg-bg-primary p-xs shadow-lg"
|
|
66
|
+
>
|
|
67
|
+
{options.map((opt) => {
|
|
68
|
+
const isSelected = opt.value === value;
|
|
69
|
+
return (
|
|
70
|
+
<li key={opt.value} role="option" aria-selected={isSelected}>
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
onClick={() => {
|
|
74
|
+
onChange?.(opt.value);
|
|
75
|
+
setOpen(false);
|
|
76
|
+
}}
|
|
77
|
+
className="flex w-full items-center gap-md rounded-sm px-md py-xs text-sm font-medium text-text-secondary transition-colors hover:bg-bg-primary-hover"
|
|
78
|
+
>
|
|
79
|
+
<span
|
|
80
|
+
className={clsx(
|
|
81
|
+
"flex size-4 shrink-0 items-center justify-center rounded-full border",
|
|
82
|
+
isSelected ? "border-border-brand" : "border-border-primary",
|
|
83
|
+
)}
|
|
84
|
+
>
|
|
85
|
+
{isSelected ? (
|
|
86
|
+
<span className="size-2 rounded-full bg-brand-solid" />
|
|
87
|
+
) : null}
|
|
88
|
+
</span>
|
|
89
|
+
<span className="flex-1 text-left">{opt.label}</span>
|
|
90
|
+
{opt.shortcut ? (
|
|
91
|
+
<span className="text-xs text-text-quaternary">{opt.shortcut}</span>
|
|
92
|
+
) : null}
|
|
93
|
+
</button>
|
|
94
|
+
</li>
|
|
95
|
+
);
|
|
96
|
+
})}
|
|
97
|
+
</ul>
|
|
98
|
+
) : null}
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// TODO: source Figma node 1211:169 ("Card header") has no parent page name in
|
|
2
|
+
// metadata (likely a not-yet-discovered "Cards" page). Component is functional,
|
|
3
|
+
// but locate its actual page for completeness / round-trip — see figma-map.md.
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
import clsx from "clsx";
|
|
6
|
+
|
|
7
|
+
export interface CardHeaderProps {
|
|
8
|
+
/** Card section title. */
|
|
9
|
+
title: string;
|
|
10
|
+
/** Supporting description under the title. */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Badge beside the title (e.g. a count "10/20 seats"). */
|
|
13
|
+
badge?: ReactNode;
|
|
14
|
+
/** Leading avatar (Figma `Avatar=True`). */
|
|
15
|
+
avatar?: ReactNode;
|
|
16
|
+
/** Trailing actions slot — buttons, overflow menu, etc. */
|
|
17
|
+
actions?: ReactNode;
|
|
18
|
+
/** Bottom divider rule (default true). */
|
|
19
|
+
divider?: boolean;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function CardHeader({
|
|
24
|
+
title,
|
|
25
|
+
description,
|
|
26
|
+
badge,
|
|
27
|
+
avatar,
|
|
28
|
+
actions,
|
|
29
|
+
divider = true,
|
|
30
|
+
className,
|
|
31
|
+
}: CardHeaderProps) {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
className={clsx(
|
|
35
|
+
"flex items-start justify-between gap-xl pb-lg font-body",
|
|
36
|
+
divider && "border-b border-border-secondary",
|
|
37
|
+
className,
|
|
38
|
+
)}
|
|
39
|
+
>
|
|
40
|
+
<div className="flex min-w-0 items-start gap-lg">
|
|
41
|
+
{avatar}
|
|
42
|
+
<div className="flex min-w-0 flex-col gap-xxs">
|
|
43
|
+
<div className="flex items-center gap-md">
|
|
44
|
+
<h3 className="text-md font-semibold text-text-primary">{title}</h3>
|
|
45
|
+
{badge}
|
|
46
|
+
</div>
|
|
47
|
+
{description ? (
|
|
48
|
+
<p className="text-sm text-text-tertiary">{description}</p>
|
|
49
|
+
) : null}
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
{actions ? (
|
|
53
|
+
<div className="flex shrink-0 items-center gap-lg">{actions}</div>
|
|
54
|
+
) : null}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes } from "react";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
|
|
4
|
+
export type CarouselArrowDirection = "left" | "right";
|
|
5
|
+
export type CarouselArrowSize = "md" | "lg";
|
|
6
|
+
|
|
7
|
+
export interface CarouselArrowProps
|
|
8
|
+
extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
9
|
+
direction?: CarouselArrowDirection;
|
|
10
|
+
size?: CarouselArrowSize;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Round carousel nav button on a translucent blurred background
|
|
15
|
+
* (`alpha-white-90` + `backdrop-blur-sm`). md = 36px / lg = 44px.
|
|
16
|
+
*/
|
|
17
|
+
export function CarouselArrow({
|
|
18
|
+
direction = "left",
|
|
19
|
+
size = "md",
|
|
20
|
+
className,
|
|
21
|
+
type = "button",
|
|
22
|
+
...rest
|
|
23
|
+
}: CarouselArrowProps) {
|
|
24
|
+
const icon = size === "lg" ? "size-6" : "size-5";
|
|
25
|
+
return (
|
|
26
|
+
<button
|
|
27
|
+
type={type}
|
|
28
|
+
aria-label={direction === "left" ? "Previous" : "Next"}
|
|
29
|
+
className={clsx(
|
|
30
|
+
"flex items-center justify-center rounded-full bg-alpha-white-90 p-md text-fg-secondary backdrop-blur-sm",
|
|
31
|
+
size === "lg" ? "size-11" : "size-9",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
{...rest}
|
|
35
|
+
>
|
|
36
|
+
<svg viewBox="0 0 24 24" fill="none" className={icon} aria-hidden>
|
|
37
|
+
<path
|
|
38
|
+
d={direction === "left" ? "M15 18l-6-6 6-6" : "M9 18l6-6-6-6"}
|
|
39
|
+
stroke="currentColor"
|
|
40
|
+
strokeWidth="2"
|
|
41
|
+
strokeLinecap="round"
|
|
42
|
+
strokeLinejoin="round"
|
|
43
|
+
/>
|
|
44
|
+
</svg>
|
|
45
|
+
</button>
|
|
46
|
+
);
|
|
47
|
+
}
|