@reinvented/design 0.3.0 → 1.0.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/package.json +55 -21
- package/src/components/blocks/auth/auth-card/AuthCard.tsx +62 -0
- package/src/components/blocks/auth/auth-card/index.ts +1 -0
- package/src/components/blocks/auth/index.ts +3 -0
- package/src/components/blocks/auth/social-login/SocialLoginGroup.tsx +75 -0
- package/src/components/blocks/auth/social-login/index.ts +1 -0
- package/src/components/blocks/auth/two-factor/TwoFactorForm.tsx +59 -0
- package/src/components/blocks/auth/two-factor/index.ts +1 -0
- package/src/components/blocks/communication/activity-item/ActivityItem.tsx +17 -0
- package/src/components/blocks/communication/activity-item/ActivityItemAvatar.tsx +21 -0
- package/src/components/blocks/communication/activity-item/ActivityItemContent.tsx +16 -0
- package/src/components/blocks/communication/activity-item/index.ts +3 -0
- package/src/components/blocks/communication/chat-bubble/ChatBubble.tsx +21 -0
- package/src/components/blocks/communication/chat-bubble/ChatBubbleAvatar.tsx +19 -0
- package/src/components/blocks/communication/chat-bubble/ChatBubbleMessage.tsx +35 -0
- package/src/components/blocks/communication/chat-bubble/ChatBubbleTimestamp.tsx +15 -0
- package/src/components/blocks/communication/chat-bubble/index.ts +4 -0
- package/src/components/blocks/communication/index.ts +2 -0
- package/src/components/blocks/content/article-header/ArticleHeader.tsx +73 -0
- package/src/components/blocks/content/article-header/index.ts +1 -0
- package/src/components/blocks/content/author-card/AuthorCard.tsx +46 -0
- package/src/components/blocks/content/author-card/index.ts +1 -0
- package/src/components/blocks/content/index.ts +3 -0
- package/src/components/blocks/content/rich-text/RichTextContent.tsx +27 -0
- package/src/components/blocks/content/rich-text/index.ts +1 -0
- package/src/components/blocks/data-management/index.ts +2 -0
- package/src/components/blocks/data-management/kanban/KanbanBoard.tsx +10 -0
- package/src/components/blocks/data-management/kanban/KanbanCard.tsx +102 -0
- package/src/components/blocks/data-management/kanban/KanbanColumn.tsx +41 -0
- package/src/components/blocks/data-management/kanban/index.ts +3 -0
- package/src/components/blocks/data-management/tree-view/TreeItem.tsx +68 -0
- package/src/components/blocks/data-management/tree-view/TreeView.tsx +10 -0
- package/src/components/blocks/data-management/tree-view/index.ts +2 -0
- package/src/components/blocks/data-viz/financial-ticker/FinancialTicker.tsx +35 -0
- package/src/components/blocks/data-viz/financial-ticker/index.ts +1 -0
- package/src/components/blocks/data-viz/index.ts +3 -0
- package/src/components/blocks/data-viz/kpi-card/KpiCard.tsx +61 -0
- package/src/components/blocks/data-viz/kpi-card/index.ts +1 -0
- package/src/components/blocks/data-viz/stat-grid/StatGrid.tsx +28 -0
- package/src/components/blocks/data-viz/stat-grid/index.ts +1 -0
- package/src/components/blocks/ecommerce/index.ts +3 -0
- package/src/components/blocks/ecommerce/pricing-tier/PricingFeatureList.tsx +27 -0
- package/src/components/blocks/ecommerce/pricing-tier/PricingHeader.tsx +25 -0
- package/src/components/blocks/ecommerce/pricing-tier/PricingTier.tsx +31 -0
- package/src/components/blocks/ecommerce/pricing-tier/index.ts +3 -0
- package/src/components/blocks/ecommerce/product-card/ProductCard.tsx +17 -0
- package/src/components/blocks/ecommerce/product-card/ProductCardContent.tsx +15 -0
- package/src/components/blocks/ecommerce/product-card/ProductCardImage.tsx +20 -0
- package/src/components/blocks/ecommerce/product-card/ProductCardPrice.tsx +20 -0
- package/src/components/blocks/ecommerce/product-card/index.ts +4 -0
- package/src/components/blocks/ecommerce/rating-summary/RatingStars.tsx +32 -0
- package/src/components/blocks/ecommerce/rating-summary/index.ts +1 -0
- package/src/components/blocks/feedback/empty-state/EmptyState.tsx +53 -0
- package/src/components/blocks/feedback/empty-state/index.ts +1 -0
- package/src/components/blocks/feedback/error-state/ErrorState.tsx +50 -0
- package/src/components/blocks/feedback/error-state/index.ts +1 -0
- package/src/components/blocks/feedback/index.ts +3 -0
- package/src/components/blocks/feedback/not-found/NotFoundState.tsx +47 -0
- package/src/components/blocks/feedback/not-found/index.ts +1 -0
- package/src/components/blocks/filtering/faceted-sidebar/FacetedGroup.tsx +32 -0
- package/src/components/blocks/filtering/faceted-sidebar/FacetedSidebar.tsx +26 -0
- package/src/components/blocks/filtering/faceted-sidebar/index.ts +2 -0
- package/src/components/blocks/filtering/filter-bar/FilterBar.tsx +85 -0
- package/src/components/blocks/filtering/filter-bar/index.ts +1 -0
- package/src/components/blocks/filtering/index.ts +3 -0
- package/src/components/blocks/filtering/search-result/SearchResultItem.tsx +70 -0
- package/src/components/blocks/filtering/search-result/index.ts +1 -0
- package/src/components/blocks/index.ts +21 -0
- package/src/components/blocks/marketing/cta-block/CtaBlock.tsx +80 -0
- package/src/components/blocks/marketing/cta-block/index.ts +1 -0
- package/src/components/blocks/marketing/feature-grid/FeatureGrid.tsx +47 -0
- package/src/components/blocks/marketing/feature-grid/index.ts +1 -0
- package/src/components/blocks/marketing/hero-section/HeroSection.tsx +89 -0
- package/src/components/blocks/marketing/hero-section/index.ts +1 -0
- package/src/components/blocks/marketing/index.ts +4 -0
- package/src/components/blocks/marketing/testimonial-card/TestimonialCard.tsx +71 -0
- package/src/components/blocks/marketing/testimonial-card/index.ts +1 -0
- package/src/components/blocks/media/call-controls/CallControlButton.tsx +52 -0
- package/src/components/blocks/media/call-controls/CallControls.tsx +10 -0
- package/src/components/blocks/media/call-controls/index.ts +2 -0
- package/src/components/blocks/media/index.ts +2 -0
- package/src/components/blocks/media/media-player/MediaPlayer.tsx +20 -0
- package/src/components/blocks/media/media-player/MediaPlayerControls.tsx +16 -0
- package/src/components/blocks/media/media-player/MediaPlayerScrubber.tsx +29 -0
- package/src/components/blocks/media/media-player/MediaPlayerVideo.tsx +25 -0
- package/src/components/blocks/media/media-player/index.ts +4 -0
- package/src/components/blocks/navigation/app-sidebar/AppSidebar.tsx +32 -0
- package/src/components/blocks/navigation/app-sidebar/NavItem.tsx +43 -0
- package/src/components/blocks/navigation/app-sidebar/index.ts +2 -0
- package/src/components/blocks/navigation/context-switcher/ContextSwitcher.tsx +77 -0
- package/src/components/blocks/navigation/context-switcher/index.ts +1 -0
- package/src/components/blocks/navigation/index.ts +3 -0
- package/src/components/blocks/navigation/top-navbar/TopNavbar.tsx +47 -0
- package/src/components/blocks/navigation/top-navbar/index.ts +1 -0
- package/src/components/blocks/onboarding/index.ts +2 -0
- package/src/components/blocks/onboarding/onboarding-welcome/OnboardingWelcome.tsx +74 -0
- package/src/components/blocks/onboarding/onboarding-welcome/index.ts +1 -0
- package/src/components/blocks/onboarding/step-wizard/StepWizard.tsx +72 -0
- package/src/components/blocks/onboarding/step-wizard/index.ts +1 -0
- package/src/components/blocks/profiles/connection-list/ConnectionItem.tsx +35 -0
- package/src/components/blocks/profiles/connection-list/ConnectionList.tsx +16 -0
- package/src/components/blocks/profiles/connection-list/index.ts +2 -0
- package/src/components/blocks/profiles/index.ts +3 -0
- package/src/components/blocks/profiles/profile-header/ProfileHeader.tsx +88 -0
- package/src/components/blocks/profiles/profile-header/index.ts +1 -0
- package/src/components/blocks/profiles/profile-stats/ProfileStats.tsx +20 -0
- package/src/components/blocks/profiles/profile-stats/index.ts +1 -0
- package/src/components/blocks/scheduling/booking-slot/BookingSlot.tsx +44 -0
- package/src/components/blocks/scheduling/booking-slot/index.ts +1 -0
- package/src/components/blocks/scheduling/event-card/EventCard.tsx +85 -0
- package/src/components/blocks/scheduling/event-card/index.ts +1 -0
- package/src/components/blocks/scheduling/index.ts +3 -0
- package/src/components/blocks/scheduling/timeline-row/TimelineRow.tsx +82 -0
- package/src/components/blocks/scheduling/timeline-row/index.ts +1 -0
- package/src/components/blocks/settings/billing-usage/BillingUsage.tsx +49 -0
- package/src/components/blocks/settings/billing-usage/index.ts +1 -0
- package/src/components/blocks/settings/index.ts +3 -0
- package/src/components/blocks/settings/integration-card/IntegrationCard.tsx +62 -0
- package/src/components/blocks/settings/integration-card/index.ts +1 -0
- package/src/components/blocks/settings/settings-section/SettingsSection.tsx +23 -0
- package/src/components/blocks/settings/settings-section/index.ts +1 -0
- package/src/components/ui/accordion.tsx +56 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/alert.tsx +59 -0
- package/src/components/ui/aspect-ratio.tsx +5 -0
- package/src/components/ui/avatar.tsx +50 -0
- package/src/components/ui/badge.tsx +36 -0
- package/src/components/ui/breadcrumb.tsx +115 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/calendar.tsx +211 -0
- package/src/components/ui/card.tsx +79 -0
- package/src/components/ui/carousel.tsx +262 -0
- package/src/components/ui/chart.tsx +367 -0
- package/src/components/ui/checkbox.tsx +28 -0
- package/src/components/ui/collapsible.tsx +11 -0
- package/src/components/ui/command.tsx +153 -0
- package/src/components/ui/component-placeholder.tsx +38 -0
- package/src/components/ui/context-menu.tsx +198 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/drawer.tsx +116 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/form.tsx +176 -0
- package/src/components/ui/hover-card.tsx +27 -0
- package/src/components/ui/input-otp.tsx +69 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/menubar.tsx +256 -0
- package/src/components/ui/navigation-menu.tsx +128 -0
- package/src/components/ui/pagination.tsx +117 -0
- package/src/components/ui/popover.tsx +29 -0
- package/src/components/ui/progress.tsx +28 -0
- package/src/components/ui/radio-group.tsx +42 -0
- package/src/components/ui/resizable.tsx +45 -0
- package/src/components/ui/scroll-area.tsx +46 -0
- package/src/components/ui/select.tsx +160 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.tsx +140 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/slider.tsx +26 -0
- package/src/components/ui/sonner.tsx +45 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/components/ui/table.tsx +117 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.tsx +22 -0
- package/src/components/ui/toast.tsx +127 -0
- package/src/components/ui/toaster.tsx +33 -0
- package/src/components/ui/toggle-group.tsx +61 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/tooltip.tsx +28 -0
- package/src/hooks/use-toast.ts +194 -0
- package/src/index.ts +53 -56
- package/src/styles/index.css +6 -0
- package/src/styles/tokens.css +30 -18
- package/tailwind.config.js +120 -98
- package/tsconfig.json +2 -2
- package/src/components/ui/accordion/Accordion.vue +0 -13
- package/src/components/ui/accordion/AccordionContent.vue +0 -20
- package/src/components/ui/accordion/AccordionItem.vue +0 -15
- package/src/components/ui/accordion/AccordionTrigger.vue +0 -25
- package/src/components/ui/accordion/index.ts +0 -4
- package/src/components/ui/alert/Alert.vue +0 -38
- package/src/components/ui/alert/AlertDescription.vue +0 -12
- package/src/components/ui/alert/AlertTitle.vue +0 -12
- package/src/components/ui/alert/index.ts +0 -3
- package/src/components/ui/alert-dialog/AlertDialog.vue +0 -13
- package/src/components/ui/alert-dialog/AlertDialogAction.vue +0 -21
- package/src/components/ui/alert-dialog/AlertDialogCancel.vue +0 -21
- package/src/components/ui/alert-dialog/AlertDialogContent.vue +0 -39
- package/src/components/ui/alert-dialog/AlertDialogDescription.vue +0 -15
- package/src/components/ui/alert-dialog/AlertDialogFooter.vue +0 -12
- package/src/components/ui/alert-dialog/AlertDialogHeader.vue +0 -12
- package/src/components/ui/alert-dialog/AlertDialogTitle.vue +0 -15
- package/src/components/ui/alert-dialog/AlertDialogTrigger.vue +0 -11
- package/src/components/ui/alert-dialog/index.ts +0 -9
- package/src/components/ui/avatar/Avatar.vue +0 -14
- package/src/components/ui/avatar/index.ts +0 -1
- package/src/components/ui/badge/Badge.vue +0 -27
- package/src/components/ui/badge/index.ts +0 -1
- package/src/components/ui/breadcrumb/Breadcrumb.vue +0 -6
- package/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +0 -12
- package/src/components/ui/breadcrumb/BreadcrumbItem.vue +0 -6
- package/src/components/ui/breadcrumb/BreadcrumbLink.vue +0 -20
- package/src/components/ui/breadcrumb/BreadcrumbList.vue +0 -6
- package/src/components/ui/breadcrumb/BreadcrumbPage.vue +0 -6
- package/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +0 -11
- package/src/components/ui/breadcrumb/index.ts +0 -7
- package/src/components/ui/button/Button.vue +0 -65
- package/src/components/ui/button/index.ts +0 -1
- package/src/components/ui/card/Card.vue +0 -13
- package/src/components/ui/card/CardContent.vue +0 -7
- package/src/components/ui/card/CardDescription.vue +0 -7
- package/src/components/ui/card/CardFooter.vue +0 -7
- package/src/components/ui/card/CardHeader.vue +0 -9
- package/src/components/ui/card/CardTitle.vue +0 -7
- package/src/components/ui/card/index.ts +0 -6
- package/src/components/ui/checkbox/Checkbox.vue +0 -25
- package/src/components/ui/checkbox/index.ts +0 -1
- package/src/components/ui/collapsible/Collapsible.vue +0 -13
- package/src/components/ui/collapsible/index.ts +0 -2
- package/src/components/ui/command/Command.vue +0 -16
- package/src/components/ui/command/CommandEmpty.vue +0 -5
- package/src/components/ui/command/CommandGroup.vue +0 -22
- package/src/components/ui/command/CommandInput.vue +0 -21
- package/src/components/ui/command/CommandItem.vue +0 -22
- package/src/components/ui/command/CommandList.vue +0 -17
- package/src/components/ui/command/CommandSeparator.vue +0 -5
- package/src/components/ui/command/index.ts +0 -7
- package/src/components/ui/context-menu/ContextMenuContent.vue +0 -24
- package/src/components/ui/context-menu/ContextMenuItem.vue +0 -16
- package/src/components/ui/context-menu/ContextMenuLabel.vue +0 -9
- package/src/components/ui/context-menu/ContextMenuSeparator.vue +0 -9
- package/src/components/ui/context-menu/ContextMenuSubContent.vue +0 -14
- package/src/components/ui/context-menu/index.ts +0 -9
- package/src/components/ui/dialog/Dialog.vue +0 -14
- package/src/components/ui/dialog/DialogClose.vue +0 -12
- package/src/components/ui/dialog/DialogContent.vue +0 -48
- package/src/components/ui/dialog/DialogDescription.vue +0 -23
- package/src/components/ui/dialog/DialogFooter.vue +0 -12
- package/src/components/ui/dialog/DialogHeader.vue +0 -12
- package/src/components/ui/dialog/DialogScrollContent.vue +0 -47
- package/src/components/ui/dialog/DialogTitle.vue +0 -23
- package/src/components/ui/dialog/DialogTrigger.vue +0 -12
- package/src/components/ui/dialog/index.ts +0 -9
- package/src/components/ui/dropdown-menu/DropdownMenu.vue +0 -13
- package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +0 -28
- package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +0 -33
- package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +0 -11
- package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +0 -27
- package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +0 -23
- package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +0 -13
- package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +0 -27
- package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +0 -13
- package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +0 -12
- package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +0 -13
- package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +0 -27
- package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +0 -23
- package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +0 -11
- package/src/components/ui/dropdown-menu/index.ts +0 -14
- package/src/components/ui/form/FormControl.vue +0 -3
- package/src/components/ui/form/FormDescription.vue +0 -6
- package/src/components/ui/form/FormItem.vue +0 -6
- package/src/components/ui/form/FormLabel.vue +0 -10
- package/src/components/ui/form/FormMessage.vue +0 -10
- package/src/components/ui/form/index.ts +0 -9
- package/src/components/ui/hover-card/HoverCard.vue +0 -13
- package/src/components/ui/hover-card/HoverCardContent.vue +0 -26
- package/src/components/ui/hover-card/HoverCardTrigger.vue +0 -11
- package/src/components/ui/hover-card/index.ts +0 -3
- package/src/components/ui/input/Input.vue +0 -23
- package/src/components/ui/input/index.ts +0 -1
- package/src/components/ui/label/Label.vue +0 -18
- package/src/components/ui/label/index.ts +0 -1
- package/src/components/ui/lib/utils.ts +0 -2
- package/src/components/ui/menubar/MenubarContent.vue +0 -15
- package/src/components/ui/menubar/MenubarItem.vue +0 -13
- package/src/components/ui/menubar/MenubarTrigger.vue +0 -13
- package/src/components/ui/menubar/index.ts +0 -5
- package/src/components/ui/navigation-menu/NavigationMenuContent.vue +0 -14
- package/src/components/ui/navigation-menu/NavigationMenuTrigger.vue +0 -15
- package/src/components/ui/navigation-menu/index.ts +0 -4
- package/src/components/ui/pagination/PaginationContent.vue +0 -13
- package/src/components/ui/pagination/PaginationEllipsis.vue +0 -12
- package/src/components/ui/pagination/PaginationNext.vue +0 -14
- package/src/components/ui/pagination/PaginationPrev.vue +0 -14
- package/src/components/ui/pagination/index.ts +0 -6
- package/src/components/ui/popover/Popover.vue +0 -13
- package/src/components/ui/popover/PopoverContent.vue +0 -27
- package/src/components/ui/popover/PopoverTrigger.vue +0 -11
- package/src/components/ui/popover/index.ts +0 -3
- package/src/components/ui/progress/Progress.vue +0 -21
- package/src/components/ui/progress/index.ts +0 -1
- package/src/components/ui/radio-group/RadioGroup.vue +0 -16
- package/src/components/ui/radio-group/RadioGroupItem.vue +0 -24
- package/src/components/ui/radio-group/index.ts +0 -2
- package/src/components/ui/scroll-area/ScrollArea.vue +0 -13
- package/src/components/ui/scroll-area/index.ts +0 -1
- package/src/components/ui/select/Select.vue +0 -13
- package/src/components/ui/select/SelectContent.vue +0 -40
- package/src/components/ui/select/SelectGroup.vue +0 -15
- package/src/components/ui/select/SelectItem.vue +0 -30
- package/src/components/ui/select/SelectLabel.vue +0 -15
- package/src/components/ui/select/SelectSeparator.vue +0 -13
- package/src/components/ui/select/SelectTrigger.vue +0 -23
- package/src/components/ui/select/SelectValue.vue +0 -11
- package/src/components/ui/select/index.ts +0 -8
- package/src/components/ui/separator/Separator.vue +0 -16
- package/src/components/ui/separator/index.ts +0 -1
- package/src/components/ui/sheet/Sheet.vue +0 -13
- package/src/components/ui/sheet/SheetClose.vue +0 -11
- package/src/components/ui/sheet/SheetContent.vue +0 -65
- package/src/components/ui/sheet/SheetDescription.vue +0 -15
- package/src/components/ui/sheet/SheetFooter.vue +0 -12
- package/src/components/ui/sheet/SheetHeader.vue +0 -12
- package/src/components/ui/sheet/SheetTitle.vue +0 -15
- package/src/components/ui/sheet/SheetTrigger.vue +0 -11
- package/src/components/ui/sheet/index.ts +0 -8
- package/src/components/ui/skeleton/Skeleton.vue +0 -9
- package/src/components/ui/skeleton/index.ts +0 -1
- package/src/components/ui/slider/Slider.vue +0 -26
- package/src/components/ui/slider/index.ts +0 -1
- package/src/components/ui/switch/Switch.vue +0 -24
- package/src/components/ui/switch/index.ts +0 -1
- package/src/components/ui/table/Table.vue +0 -13
- package/src/components/ui/table/TableBody.vue +0 -6
- package/src/components/ui/table/TableCaption.vue +0 -6
- package/src/components/ui/table/TableCell.vue +0 -6
- package/src/components/ui/table/TableFooter.vue +0 -6
- package/src/components/ui/table/TableHead.vue +0 -6
- package/src/components/ui/table/TableHeader.vue +0 -6
- package/src/components/ui/table/TableRow.vue +0 -6
- package/src/components/ui/table/index.ts +0 -8
- package/src/components/ui/tabs/Tabs.vue +0 -13
- package/src/components/ui/tabs/TabsContent.vue +0 -21
- package/src/components/ui/tabs/TabsList.vue +0 -21
- package/src/components/ui/tabs/TabsTrigger.vue +0 -21
- package/src/components/ui/tabs/index.ts +0 -4
- package/src/components/ui/textarea/Textarea.vue +0 -29
- package/src/components/ui/textarea/index.ts +0 -1
- package/src/components/ui/toggle/Toggle.vue +0 -40
- package/src/components/ui/toggle/index.ts +0 -1
- package/src/components/ui/toggle-group/ToggleGroup.vue +0 -16
- package/src/components/ui/toggle-group/ToggleGroupItem.vue +0 -21
- package/src/components/ui/toggle-group/index.ts +0 -2
- package/src/components/ui/tooltip/Tooltip.vue +0 -13
- package/src/components/ui/tooltip/TooltipContent.vue +0 -27
- package/src/components/ui/tooltip/TooltipProvider.vue +0 -12
- package/src/components/ui/tooltip/TooltipTrigger.vue +0 -11
- package/src/components/ui/tooltip/index.ts +0 -4
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { AlertTriangle, RefreshCcw } from 'lucide-react'
|
|
5
|
+
|
|
6
|
+
interface ErrorStateProps {
|
|
7
|
+
title?: string
|
|
8
|
+
description?: string
|
|
9
|
+
retryLabel?: string
|
|
10
|
+
className?: string
|
|
11
|
+
onRetry?: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ErrorState({
|
|
15
|
+
title,
|
|
16
|
+
description,
|
|
17
|
+
retryLabel,
|
|
18
|
+
className,
|
|
19
|
+
onRetry,
|
|
20
|
+
}: ErrorStateProps) {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
className={cn(
|
|
24
|
+
'flex flex-col items-center justify-center py-12 px-6 text-center bg-rose-500/5 border border-rose-500/20 rounded-xl',
|
|
25
|
+
className,
|
|
26
|
+
)}
|
|
27
|
+
>
|
|
28
|
+
<div className="h-12 w-12 rounded-full bg-rose-500/10 flex items-center justify-center mb-4 text-rose-500">
|
|
29
|
+
<AlertTriangle className="h-6 w-6" />
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<h3 className="text-lg font-semibold text-foreground mb-1">
|
|
33
|
+
{title || 'Something went wrong'}
|
|
34
|
+
</h3>
|
|
35
|
+
<p className="text-sm text-muted-foreground max-w-md mx-auto mb-6">
|
|
36
|
+
{description ||
|
|
37
|
+
'An unexpected error occurred while trying to load this content. Please try again later.'}
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
<Button
|
|
41
|
+
variant="outline"
|
|
42
|
+
onClick={onRetry}
|
|
43
|
+
className="border-rose-500/20 hover:bg-rose-500/10 hover:text-rose-600 text-rose-600"
|
|
44
|
+
>
|
|
45
|
+
<RefreshCcw className="mr-2 h-4 w-4" />
|
|
46
|
+
{retryLabel || 'Try again'}
|
|
47
|
+
</Button>
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ErrorState'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { Search, Home, ArrowLeft } from 'lucide-react'
|
|
5
|
+
|
|
6
|
+
interface NotFoundStateProps {
|
|
7
|
+
title?: string
|
|
8
|
+
description?: string
|
|
9
|
+
className?: string
|
|
10
|
+
onBack?: () => void
|
|
11
|
+
onHome?: () => void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function NotFoundState({
|
|
15
|
+
title,
|
|
16
|
+
description,
|
|
17
|
+
className,
|
|
18
|
+
onBack,
|
|
19
|
+
onHome,
|
|
20
|
+
}: NotFoundStateProps) {
|
|
21
|
+
return (
|
|
22
|
+
<div className={cn('flex flex-col items-center justify-center py-20 px-6 text-center', className)}>
|
|
23
|
+
<div className="relative mb-6">
|
|
24
|
+
<h1 className="text-7xl sm:text-9xl font-extrabold tracking-tighter text-muted select-none">404</h1>
|
|
25
|
+
<div className="absolute inset-0 flex items-center justify-center">
|
|
26
|
+
<Search className="h-10 w-10 sm:h-12 sm:w-12 text-muted-foreground/50" />
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<h3 className="text-2xl font-bold text-foreground mb-2">{title || 'Page not found'}</h3>
|
|
31
|
+
<p className="text-base text-muted-foreground max-w-md mx-auto mb-8">
|
|
32
|
+
{description || "Sorry, we couldn't find the page you're looking for. It might have been moved or deleted."}
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<div className="flex items-center gap-3">
|
|
36
|
+
<Button variant="outline" onClick={onBack}>
|
|
37
|
+
<ArrowLeft className="mr-2 h-4 w-4" />
|
|
38
|
+
Go back
|
|
39
|
+
</Button>
|
|
40
|
+
<Button onClick={onHome}>
|
|
41
|
+
<Home className="mr-2 h-4 w-4" />
|
|
42
|
+
Back to home
|
|
43
|
+
</Button>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './NotFoundState'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '@/components/ui/collapsible'
|
|
4
|
+
import { ChevronDown } from 'lucide-react'
|
|
5
|
+
|
|
6
|
+
interface FacetedGroupProps {
|
|
7
|
+
title: string
|
|
8
|
+
defaultExpanded?: boolean
|
|
9
|
+
className?: string
|
|
10
|
+
children?: React.ReactNode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function FacetedGroup({ title, defaultExpanded = true, className, children }: FacetedGroupProps) {
|
|
14
|
+
const [isOpen, setIsOpen] = useState(defaultExpanded)
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Collapsible open={isOpen} onOpenChange={setIsOpen} className={cn('w-full', className)}>
|
|
18
|
+
<CollapsibleTrigger className="flex items-center justify-between w-full py-2 hover:bg-muted/50 rounded-md transition-colors group">
|
|
19
|
+
<h4 className="text-sm font-semibold tracking-tight">{title}</h4>
|
|
20
|
+
<ChevronDown
|
|
21
|
+
className={cn(
|
|
22
|
+
'h-4 w-4 text-muted-foreground transition-transform duration-200',
|
|
23
|
+
isOpen ? 'rotate-180' : 'rotate-0'
|
|
24
|
+
)}
|
|
25
|
+
/>
|
|
26
|
+
</CollapsibleTrigger>
|
|
27
|
+
<CollapsibleContent className="pt-3 pb-1 space-y-3">
|
|
28
|
+
{children}
|
|
29
|
+
</CollapsibleContent>
|
|
30
|
+
</Collapsible>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { ScrollArea } from '@/components/ui/scroll-area'
|
|
4
|
+
|
|
5
|
+
interface FacetedSidebarProps {
|
|
6
|
+
title?: string
|
|
7
|
+
className?: string
|
|
8
|
+
children?: React.ReactNode
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function FacetedSidebar({ title, className, children }: FacetedSidebarProps) {
|
|
12
|
+
return (
|
|
13
|
+
<div className={cn('w-full md:w-64 shrink-0 flex flex-col pt-1', className)}>
|
|
14
|
+
{title && (
|
|
15
|
+
<div className="mb-4">
|
|
16
|
+
<h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">{title}</h3>
|
|
17
|
+
</div>
|
|
18
|
+
)}
|
|
19
|
+
<ScrollArea className="h-[calc(100vh-12rem)] pr-4">
|
|
20
|
+
<div className="flex flex-col gap-6 pb-6 w-full">
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
</ScrollArea>
|
|
24
|
+
</div>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Input } from '@/components/ui/input'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { Badge } from '@/components/ui/badge'
|
|
5
|
+
import { Search, Filter, X } from 'lucide-react'
|
|
6
|
+
import { cn } from '@/lib/utils'
|
|
7
|
+
|
|
8
|
+
interface FilterBarProps {
|
|
9
|
+
placeholder?: string
|
|
10
|
+
activeFilters?: { key: string; label: string }[]
|
|
11
|
+
resultsCount?: number
|
|
12
|
+
className?: string
|
|
13
|
+
controls?: React.ReactNode
|
|
14
|
+
onRemoveFilter?: (filter: { key: string; label: string }) => void
|
|
15
|
+
onClearFilters?: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function FilterBar({
|
|
19
|
+
placeholder,
|
|
20
|
+
activeFilters,
|
|
21
|
+
resultsCount,
|
|
22
|
+
className,
|
|
23
|
+
controls,
|
|
24
|
+
onRemoveFilter,
|
|
25
|
+
onClearFilters,
|
|
26
|
+
}: FilterBarProps) {
|
|
27
|
+
return (
|
|
28
|
+
<div className={cn('flex flex-col gap-4 w-full', className)}>
|
|
29
|
+
<div className="flex flex-col sm:flex-row items-center gap-3">
|
|
30
|
+
<div className="relative w-full flex-1">
|
|
31
|
+
<Search className="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
32
|
+
<Input
|
|
33
|
+
placeholder={placeholder || 'Search...'}
|
|
34
|
+
className="w-full pl-9 bg-background border-muted-foreground/20 shadow-sm"
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
<div className="flex items-center gap-2 w-full sm:w-auto">
|
|
38
|
+
{controls !== undefined ? (
|
|
39
|
+
controls
|
|
40
|
+
) : (
|
|
41
|
+
<Button variant="outline" className="w-full sm:w-auto shadow-sm">
|
|
42
|
+
<Filter className="mr-2 h-4 w-4" />
|
|
43
|
+
Filters
|
|
44
|
+
</Button>
|
|
45
|
+
)}
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
{activeFilters && activeFilters.length > 0 && (
|
|
50
|
+
<div className="flex items-center flex-wrap gap-2 text-sm">
|
|
51
|
+
<span className="text-muted-foreground mr-1 text-xs font-medium">Active filters:</span>
|
|
52
|
+
{activeFilters.map((filter) => (
|
|
53
|
+
<Badge
|
|
54
|
+
key={filter.key}
|
|
55
|
+
variant="secondary"
|
|
56
|
+
className="gap-1 pr-1 font-normal bg-primary/10 text-primary hover:bg-primary/20 border-transparent"
|
|
57
|
+
>
|
|
58
|
+
{filter.label}
|
|
59
|
+
<div
|
|
60
|
+
className="h-3.5 w-3.5 rounded-full hover:bg-primary/30 flex items-center justify-center cursor-pointer transition-colors"
|
|
61
|
+
onClick={() => onRemoveFilter?.(filter)}
|
|
62
|
+
>
|
|
63
|
+
<X className="h-2.5 w-2.5" />
|
|
64
|
+
</div>
|
|
65
|
+
</Badge>
|
|
66
|
+
))}
|
|
67
|
+
<Button
|
|
68
|
+
variant="ghost"
|
|
69
|
+
size="sm"
|
|
70
|
+
className="h-6 px-2 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
71
|
+
onClick={() => onClearFilters?.()}
|
|
72
|
+
>
|
|
73
|
+
Clear all
|
|
74
|
+
</Button>
|
|
75
|
+
</div>
|
|
76
|
+
)}
|
|
77
|
+
|
|
78
|
+
{resultsCount !== undefined && (
|
|
79
|
+
<div className="text-xs text-muted-foreground">
|
|
80
|
+
Showing <span className="font-medium text-foreground">{resultsCount}</span> results
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FilterBar'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { Badge } from '@/components/ui/badge'
|
|
4
|
+
|
|
5
|
+
interface SearchResultItemProps {
|
|
6
|
+
title: string
|
|
7
|
+
subtitle?: string
|
|
8
|
+
description?: string
|
|
9
|
+
tag?: string
|
|
10
|
+
url?: string
|
|
11
|
+
image?: string
|
|
12
|
+
className?: string
|
|
13
|
+
meta?: React.ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function SearchResultItem({
|
|
17
|
+
title,
|
|
18
|
+
subtitle,
|
|
19
|
+
description,
|
|
20
|
+
tag,
|
|
21
|
+
url,
|
|
22
|
+
image,
|
|
23
|
+
className,
|
|
24
|
+
meta,
|
|
25
|
+
}: SearchResultItemProps) {
|
|
26
|
+
return (
|
|
27
|
+
<div className={cn('flex py-4 md:py-5 border-b last:border-0 group', className)}>
|
|
28
|
+
{image && (
|
|
29
|
+
<div className="shrink-0 mr-4 md:mr-6 h-20 w-20 sm:h-24 sm:w-24 border rounded-md overflow-hidden bg-muted">
|
|
30
|
+
<img
|
|
31
|
+
src={image}
|
|
32
|
+
className="h-full w-full object-cover group-hover:scale-105 transition-transform duration-300"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
)}
|
|
36
|
+
|
|
37
|
+
<div className="flex flex-col flex-1 min-w-0">
|
|
38
|
+
<div className="flex items-start justify-between gap-4 mb-1">
|
|
39
|
+
<a
|
|
40
|
+
href={url || '#'}
|
|
41
|
+
className="text-lg font-medium text-primary hover:underline underline-offset-4 truncate"
|
|
42
|
+
>
|
|
43
|
+
{title}
|
|
44
|
+
</a>
|
|
45
|
+
{tag && (
|
|
46
|
+
<Badge variant="outline" className="shrink-0 text-[10px] uppercase font-mono">
|
|
47
|
+
{tag}
|
|
48
|
+
</Badge>
|
|
49
|
+
)}
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
{(subtitle || url) && (
|
|
53
|
+
<div className="text-xs font-mono text-muted-foreground mb-2 flex items-center gap-1.5 align-middle truncate">
|
|
54
|
+
<span>{url ? url : subtitle}</span>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
|
|
58
|
+
{description && (
|
|
59
|
+
<p className="text-sm text-foreground/80 line-clamp-2 md:line-clamp-3 leading-relaxed">
|
|
60
|
+
{description}
|
|
61
|
+
</p>
|
|
62
|
+
)}
|
|
63
|
+
|
|
64
|
+
<div className="mt-3 flex items-center gap-4 text-xs text-muted-foreground">
|
|
65
|
+
{meta}
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './SearchResultItem'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// ── @reinvented/design/blocks — Blocks Barrel Export ──────────────
|
|
2
|
+
// This file re-exports all composite Block components from the design system.
|
|
3
|
+
|
|
4
|
+
// As blocks are generated via the `/build-block` workflow, they should be exported here.
|
|
5
|
+
// e.g., export * from './communication'
|
|
6
|
+
|
|
7
|
+
export * from './communication'
|
|
8
|
+
export * from './media'
|
|
9
|
+
export * from './ecommerce'
|
|
10
|
+
export * from './content'
|
|
11
|
+
export * from './data-viz'
|
|
12
|
+
export * from './data-management'
|
|
13
|
+
export * from './auth'
|
|
14
|
+
export * from './profiles'
|
|
15
|
+
export * from './settings'
|
|
16
|
+
export * from './onboarding'
|
|
17
|
+
export * from './feedback'
|
|
18
|
+
export * from './filtering'
|
|
19
|
+
export * from './scheduling'
|
|
20
|
+
export * from './navigation'
|
|
21
|
+
export * from './marketing'
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { ArrowRight } from 'lucide-react'
|
|
5
|
+
|
|
6
|
+
interface CtaBlockProps {
|
|
7
|
+
title: string
|
|
8
|
+
description?: string
|
|
9
|
+
primaryAction?: string
|
|
10
|
+
secondaryAction?: string
|
|
11
|
+
className?: string
|
|
12
|
+
onPrimary?: () => void
|
|
13
|
+
onSecondary?: () => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function CtaBlock({
|
|
17
|
+
title,
|
|
18
|
+
description,
|
|
19
|
+
primaryAction,
|
|
20
|
+
secondaryAction,
|
|
21
|
+
className,
|
|
22
|
+
onPrimary,
|
|
23
|
+
onSecondary,
|
|
24
|
+
}: CtaBlockProps) {
|
|
25
|
+
return (
|
|
26
|
+
<section
|
|
27
|
+
className={cn(
|
|
28
|
+
'w-full py-20 lg:py-24 px-4 md:px-6 relative overflow-hidden rounded-3xl bg-primary text-primary-foreground shadow-xl',
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
>
|
|
32
|
+
{/* Ambient background patterns */}
|
|
33
|
+
<div className="absolute right-0 top-0 -translate-y-12 translate-x-1/3 opacity-10 pointer-events-none">
|
|
34
|
+
<svg width="400" height="400" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
|
|
35
|
+
<path
|
|
36
|
+
fill="currentColor"
|
|
37
|
+
d="M44.7,-76.4C58.8,-69.2,71.8,-59.1,79.6,-45.8C87.4,-32.6,90,-16.3,89.1,-0.5C88.1,15.3,83.5,30.6,74.2,42.5C64.9,54.4,50.9,62.9,36.5,69.5C22.1,76.1,7.3,80.8,-7.4,81.3C-22,81.8,-36.5,78,-50.7,71.4C-64.8,64.9,-78.6,55.5,-86.3,42.1C-93.9,28.6,-95.4,11.3,-91.9,-4.5C-88.5,-20.3,-80.2,-34.5,-69.3,-45C-58.4,-55.5,-44.9,-62.3,-31.6,-69.8C-18.3,-77.3,-5.1,-85.5,5.1,-85C15.3,-84.4,30.6,-83.5,44.7,-76.4Z"
|
|
38
|
+
transform="translate(100 100)"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className="relative z-10 flex flex-col items-center text-center max-w-3xl mx-auto">
|
|
44
|
+
<h2 className="text-3xl md:text-5xl font-bold tracking-tight mb-6">
|
|
45
|
+
{title}
|
|
46
|
+
</h2>
|
|
47
|
+
|
|
48
|
+
{description && (
|
|
49
|
+
<p className="text-lg md:text-xl text-primary-foreground/80 mb-10 leading-relaxed">
|
|
50
|
+
{description}
|
|
51
|
+
</p>
|
|
52
|
+
)}
|
|
53
|
+
|
|
54
|
+
<div className="flex flex-col sm:flex-row gap-4 w-full sm:w-auto">
|
|
55
|
+
{primaryAction && (
|
|
56
|
+
<Button
|
|
57
|
+
size="lg"
|
|
58
|
+
variant="secondary"
|
|
59
|
+
className="h-12 px-8 text-base font-semibold w-full sm:w-auto shadow-sm"
|
|
60
|
+
onClick={onPrimary}
|
|
61
|
+
>
|
|
62
|
+
{primaryAction}
|
|
63
|
+
<ArrowRight className="ml-2 h-4 w-4" />
|
|
64
|
+
</Button>
|
|
65
|
+
)}
|
|
66
|
+
{secondaryAction && (
|
|
67
|
+
<Button
|
|
68
|
+
size="lg"
|
|
69
|
+
variant="outline"
|
|
70
|
+
className="h-12 px-8 text-base font-semibold w-full sm:w-auto border-primary-foreground/30 bg-primary-foreground/5 text-primary-foreground hover:bg-primary-foreground/20 hover:text-primary-foreground backdrop-blur"
|
|
71
|
+
onClick={onSecondary}
|
|
72
|
+
>
|
|
73
|
+
{secondaryAction}
|
|
74
|
+
</Button>
|
|
75
|
+
)}
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</section>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './CtaBlock'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
|
|
4
|
+
interface Feature {
|
|
5
|
+
title: string
|
|
6
|
+
description: string
|
|
7
|
+
icon?: React.ComponentType<{ className?: string }>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface FeatureGridProps {
|
|
11
|
+
features: Feature[]
|
|
12
|
+
columns?: 2 | 3 | 4
|
|
13
|
+
className?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function FeatureGrid({ features, columns, className }: FeatureGridProps) {
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={cn(
|
|
20
|
+
'grid gap-8 sm:gap-12 w-full',
|
|
21
|
+
columns === 2
|
|
22
|
+
? 'grid-cols-1 md:grid-cols-2'
|
|
23
|
+
: columns === 4
|
|
24
|
+
? 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4'
|
|
25
|
+
: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
{features.map((feature) => {
|
|
30
|
+
const Icon = feature.icon
|
|
31
|
+
return (
|
|
32
|
+
<div key={feature.title} className="flex flex-col">
|
|
33
|
+
<div className="h-12 w-12 rounded-lg bg-primary/10 flex items-center justify-center mb-6 text-primary">
|
|
34
|
+
{Icon ? (
|
|
35
|
+
<Icon className="h-6 w-6" />
|
|
36
|
+
) : (
|
|
37
|
+
<div className="h-6 w-6 bg-primary/40 rounded-sm rotate-3 transform transition-transform group-hover:rotate-12" />
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
<h3 className="text-xl font-bold mb-3 tracking-tight">{feature.title}</h3>
|
|
41
|
+
<p className="text-muted-foreground leading-relaxed">{feature.description}</p>
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
})}
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FeatureGrid'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { cn } from '@/lib/utils'
|
|
3
|
+
import { Button } from '@/components/ui/button'
|
|
4
|
+
import { Badge } from '@/components/ui/badge'
|
|
5
|
+
import { ArrowRight } from 'lucide-react'
|
|
6
|
+
|
|
7
|
+
interface HeroSectionProps {
|
|
8
|
+
badge?: string
|
|
9
|
+
title: string
|
|
10
|
+
description?: string
|
|
11
|
+
primaryAction?: string
|
|
12
|
+
secondaryAction?: string
|
|
13
|
+
image?: string
|
|
14
|
+
className?: string
|
|
15
|
+
onPrimary?: () => void
|
|
16
|
+
onSecondary?: () => void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function HeroSection({
|
|
20
|
+
badge,
|
|
21
|
+
title,
|
|
22
|
+
description,
|
|
23
|
+
primaryAction,
|
|
24
|
+
secondaryAction,
|
|
25
|
+
image,
|
|
26
|
+
className,
|
|
27
|
+
onPrimary,
|
|
28
|
+
onSecondary,
|
|
29
|
+
}: HeroSectionProps) {
|
|
30
|
+
return (
|
|
31
|
+
<section className={cn('relative overflow-hidden py-24 lg:py-32', className)}>
|
|
32
|
+
<div className="container mx-auto px-4 md:px-6 relative z-10 flex flex-col items-center text-center">
|
|
33
|
+
{badge && (
|
|
34
|
+
<Badge
|
|
35
|
+
variant="secondary"
|
|
36
|
+
className="mb-6 rounded-full px-4 py-1.5 text-sm font-medium border-primary/20 bg-primary/10 text-primary"
|
|
37
|
+
>
|
|
38
|
+
{badge}
|
|
39
|
+
</Badge>
|
|
40
|
+
)}
|
|
41
|
+
|
|
42
|
+
<h1 className="max-w-4xl text-4xl font-extrabold tracking-tight sm:text-5xl md:text-6xl lg:text-7xl mb-6 leading-[1.1]">
|
|
43
|
+
{title}
|
|
44
|
+
</h1>
|
|
45
|
+
|
|
46
|
+
{description && (
|
|
47
|
+
<p className="max-w-2xl text-lg sm:text-xl text-muted-foreground mb-10 leading-relaxed">
|
|
48
|
+
{description}
|
|
49
|
+
</p>
|
|
50
|
+
)}
|
|
51
|
+
|
|
52
|
+
<div className="flex flex-col sm:flex-row gap-4 w-full sm:w-auto mt-2">
|
|
53
|
+
{primaryAction && (
|
|
54
|
+
<Button
|
|
55
|
+
size="lg"
|
|
56
|
+
className="h-12 px-8 text-base font-semibold w-full sm:w-auto"
|
|
57
|
+
onClick={onPrimary}
|
|
58
|
+
>
|
|
59
|
+
{primaryAction}
|
|
60
|
+
<ArrowRight className="ml-2 h-4 w-4" />
|
|
61
|
+
</Button>
|
|
62
|
+
)}
|
|
63
|
+
{secondaryAction && (
|
|
64
|
+
<Button
|
|
65
|
+
size="lg"
|
|
66
|
+
variant="outline"
|
|
67
|
+
className="h-12 px-8 text-base font-semibold w-full sm:w-auto bg-background/50 backdrop-blur"
|
|
68
|
+
onClick={onSecondary}
|
|
69
|
+
>
|
|
70
|
+
{secondaryAction}
|
|
71
|
+
</Button>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{image && (
|
|
77
|
+
<div className="w-full max-w-6xl mx-auto mt-16 px-4 md:px-6 relative z-10 hidden sm:block">
|
|
78
|
+
<div className="rounded-xl border shadow-2xl overflow-hidden bg-muted">
|
|
79
|
+
<img src={image} className="w-full h-auto object-cover" />
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
|
|
84
|
+
{/* Abstract Background Elements */}
|
|
85
|
+
<div className="absolute inset-0 -z-10 h-full w-full bg-background bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:24px_24px]"></div>
|
|
86
|
+
<div className="absolute left-0 right-0 top-0 -z-10 m-auto h-[310px] w-[310px] rounded-full bg-primary opacity-20 blur-[100px]"></div>
|
|
87
|
+
</section>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './HeroSection'
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Card, CardContent } from '@/components/ui/card'
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
|
4
|
+
import { Star } from 'lucide-react'
|
|
5
|
+
import { cn } from '@/lib/utils'
|
|
6
|
+
|
|
7
|
+
interface TestimonialCardProps {
|
|
8
|
+
quote: string
|
|
9
|
+
name: string
|
|
10
|
+
role?: string
|
|
11
|
+
company?: string
|
|
12
|
+
avatar?: string
|
|
13
|
+
rating?: number
|
|
14
|
+
className?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function TestimonialCard({
|
|
18
|
+
quote,
|
|
19
|
+
name,
|
|
20
|
+
role,
|
|
21
|
+
company,
|
|
22
|
+
avatar,
|
|
23
|
+
rating,
|
|
24
|
+
className,
|
|
25
|
+
}: TestimonialCardProps) {
|
|
26
|
+
return (
|
|
27
|
+
<Card
|
|
28
|
+
className={cn(
|
|
29
|
+
'overflow-hidden h-full border-none shadow-md bg-muted/30 hover:bg-muted/50 transition-colors duration-300',
|
|
30
|
+
className,
|
|
31
|
+
)}
|
|
32
|
+
>
|
|
33
|
+
<CardContent className="p-8 flex flex-col h-full">
|
|
34
|
+
{rating != null && (
|
|
35
|
+
<div className="flex items-center gap-1 mb-6 text-yellow-500">
|
|
36
|
+
{[1, 2, 3, 4, 5].map((i) => (
|
|
37
|
+
<Star
|
|
38
|
+
key={i}
|
|
39
|
+
className="h-4 w-4"
|
|
40
|
+
fill={i <= rating ? 'currentColor' : 'transparent'}
|
|
41
|
+
/>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
|
|
46
|
+
<blockquote className="text-lg md:text-xl text-foreground font-medium mb-8 flex-1 leading-snug">
|
|
47
|
+
“{quote}”
|
|
48
|
+
</blockquote>
|
|
49
|
+
|
|
50
|
+
<div className="flex items-center gap-4 mt-auto">
|
|
51
|
+
<Avatar className="h-12 w-12 border-2 border-background shadow-sm">
|
|
52
|
+
{avatar && <AvatarImage src={avatar} />}
|
|
53
|
+
<AvatarFallback className="bg-primary/5 text-primary font-bold">
|
|
54
|
+
{name.substring(0, 2).toUpperCase()}
|
|
55
|
+
</AvatarFallback>
|
|
56
|
+
</Avatar>
|
|
57
|
+
<div className="flex flex-col">
|
|
58
|
+
<span className="font-bold text-base leading-none">{name}</span>
|
|
59
|
+
{(role || company) && (
|
|
60
|
+
<span className="text-sm text-muted-foreground mt-1.5 leading-none">
|
|
61
|
+
{role}
|
|
62
|
+
{role && company && ', '}
|
|
63
|
+
{company}
|
|
64
|
+
</span>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</CardContent>
|
|
69
|
+
</Card>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TestimonialCard'
|