xertica-ui 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.
Files changed (141) hide show
  1. package/App.tsx +182 -0
  2. package/README.md +330 -0
  3. package/assets/xertica-logo.svg +38 -0
  4. package/assets/xertica-x-logo.svg +21 -0
  5. package/bin/cli.ts +193 -0
  6. package/components/AssistenteXertica.tsx +2003 -0
  7. package/components/AudioPlayer.tsx +203 -0
  8. package/components/CodeBlock.tsx +242 -0
  9. package/components/DocumentEditor.tsx +504 -0
  10. package/components/ForgotPasswordPage.tsx +170 -0
  11. package/components/FormattedDocument.tsx +87 -0
  12. package/components/HomeContent.tsx +123 -0
  13. package/components/HomePage.tsx +70 -0
  14. package/components/LanguageSelector.tsx +54 -0
  15. package/components/LoginPage.tsx +199 -0
  16. package/components/MarkdownMessage.tsx +62 -0
  17. package/components/ModernChatInput.tsx +502 -0
  18. package/components/PodcastPlayer.tsx +409 -0
  19. package/components/ResetPasswordPage.tsx +234 -0
  20. package/components/Sidebar.tsx +489 -0
  21. package/components/TemplateContent.tsx +629 -0
  22. package/components/TemplatePage.tsx +70 -0
  23. package/components/ThemeToggle.tsx +65 -0
  24. package/components/VerifyEmailPage.tsx +187 -0
  25. package/components/XerticaLogo.tsx +69 -0
  26. package/components/XerticaOrbe.tsx +1339 -0
  27. package/components/XerticaXLogo.tsx +53 -0
  28. package/components/examples/DrawingMapExample.tsx +530 -0
  29. package/components/examples/FilterableMapExample.tsx +380 -0
  30. package/components/examples/LocationPickerExample.tsx +330 -0
  31. package/components/examples/MapExamples.tsx +280 -0
  32. package/components/examples/MapShowcase.tsx +446 -0
  33. package/components/examples/RouteMapExamples.tsx +329 -0
  34. package/components/examples/SimpleFilterableMap.tsx +192 -0
  35. package/components/examples/index.ts +52 -0
  36. package/components/figma/ImageWithFallback.tsx +27 -0
  37. package/components/index.ts +44 -0
  38. package/components/media/AudioPlayer.tsx +278 -0
  39. package/components/media/FloatingMediaWrapper.tsx +166 -0
  40. package/components/media/VideoPlayer.tsx +285 -0
  41. package/components/ui/accordion.tsx +66 -0
  42. package/components/ui/alert-dialog.tsx +159 -0
  43. package/components/ui/alert.tsx +91 -0
  44. package/components/ui/aspect-ratio.tsx +11 -0
  45. package/components/ui/avatar.tsx +65 -0
  46. package/components/ui/badge.tsx +55 -0
  47. package/components/ui/breadcrumb.tsx +109 -0
  48. package/components/ui/button.tsx +78 -0
  49. package/components/ui/calendar.tsx +235 -0
  50. package/components/ui/card.tsx +92 -0
  51. package/components/ui/carousel.tsx +241 -0
  52. package/components/ui/chart.tsx +353 -0
  53. package/components/ui/checkbox.tsx +32 -0
  54. package/components/ui/collapsible.tsx +33 -0
  55. package/components/ui/command.tsx +177 -0
  56. package/components/ui/context-menu.tsx +252 -0
  57. package/components/ui/dialog.tsx +138 -0
  58. package/components/ui/drawer.tsx +134 -0
  59. package/components/ui/dropdown-menu.tsx +257 -0
  60. package/components/ui/empty.tsx +90 -0
  61. package/components/ui/file-upload.tsx +152 -0
  62. package/components/ui/form.tsx +195 -0
  63. package/components/ui/google-maps-loader.tsx +379 -0
  64. package/components/ui/hover-card.tsx +44 -0
  65. package/components/ui/index.ts +242 -0
  66. package/components/ui/input-otp.tsx +77 -0
  67. package/components/ui/input.tsx +38 -0
  68. package/components/ui/label.tsx +24 -0
  69. package/components/ui/map-config.ts +12 -0
  70. package/components/ui/map-layers.tsx +129 -0
  71. package/components/ui/map.exports.ts +31 -0
  72. package/components/ui/map.tsx +412 -0
  73. package/components/ui/menubar.tsx +276 -0
  74. package/components/ui/navigation-menu.tsx +162 -0
  75. package/components/ui/notification-badge.tsx +61 -0
  76. package/components/ui/page-header.tsx +229 -0
  77. package/components/ui/pagination.tsx +127 -0
  78. package/components/ui/popover.tsx +48 -0
  79. package/components/ui/progress.tsx +31 -0
  80. package/components/ui/radio-group.tsx +56 -0
  81. package/components/ui/rating.tsx +102 -0
  82. package/components/ui/resizable.tsx +405 -0
  83. package/components/ui/route-map.tsx +246 -0
  84. package/components/ui/scroll-area.tsx +58 -0
  85. package/components/ui/search.tsx +70 -0
  86. package/components/ui/select.tsx +176 -0
  87. package/components/ui/separator.tsx +28 -0
  88. package/components/ui/sheet.tsx +138 -0
  89. package/components/ui/sidebar.tsx +726 -0
  90. package/components/ui/simple-map.tsx +92 -0
  91. package/components/ui/skeleton.tsx +13 -0
  92. package/components/ui/slider.tsx +58 -0
  93. package/components/ui/sonner.tsx +77 -0
  94. package/components/ui/stats-card.tsx +84 -0
  95. package/components/ui/stepper.tsx +126 -0
  96. package/components/ui/switch.tsx +34 -0
  97. package/components/ui/table.tsx +116 -0
  98. package/components/ui/tabs.tsx +66 -0
  99. package/components/ui/textarea.tsx +26 -0
  100. package/components/ui/timeline.tsx +140 -0
  101. package/components/ui/toggle-group.tsx +71 -0
  102. package/components/ui/toggle.tsx +46 -0
  103. package/components/ui/tooltip.tsx +61 -0
  104. package/components/ui/tree-view.tsx +123 -0
  105. package/components/ui/use-mobile.ts +24 -0
  106. package/components/ui/utils.ts +6 -0
  107. package/components/ui/xertica-assistant.tsx +1420 -0
  108. package/contexts/ApiKeyContext.tsx +123 -0
  109. package/contexts/AssistenteContext.tsx +118 -0
  110. package/contexts/BrandColorsContext.tsx +551 -0
  111. package/contexts/LanguageContext.tsx +36 -0
  112. package/contexts/ThemeContext.tsx +85 -0
  113. package/dist/cli.js +20922 -0
  114. package/eslint.config.js +41 -0
  115. package/guidelines/Guidelines.md +61 -0
  116. package/hooks/useTheme.ts +4 -0
  117. package/imports/Podcast.tsx +389 -0
  118. package/imports/XerticaAi.tsx +46 -0
  119. package/imports/XerticaX.tsx +20 -0
  120. package/imports/svg-aueiaqngck.ts +11 -0
  121. package/imports/svg-v9krss1ozd.ts +16 -0
  122. package/imports/svg-vhrdofe3qe.ts +5 -0
  123. package/index.css +4448 -0
  124. package/index.html +14 -0
  125. package/main.tsx +10 -0
  126. package/package.json +119 -0
  127. package/postcss.config.js +6 -0
  128. package/routes.tsx +33 -0
  129. package/styles/globals.css +15 -0
  130. package/styles/xertica/app-overrides/chat.css +61 -0
  131. package/styles/xertica/app-overrides/scrollbar.css +33 -0
  132. package/styles/xertica/base.css +70 -0
  133. package/styles/xertica/integrations/google-maps.css +76 -0
  134. package/styles/xertica/integrations/sonner.css +73 -0
  135. package/styles/xertica/theme-map.css +88 -0
  136. package/styles/xertica/tokens.css +190 -0
  137. package/tsconfig.json +31 -0
  138. package/tsconfig.node.json +10 -0
  139. package/utils/gemini.ts +140 -0
  140. package/vite-env.d.ts +12 -0
  141. package/vite.config.ts +36 -0
@@ -0,0 +1,162 @@
1
+ import * as React from "react";
2
+ import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
3
+ import { cva } from "class-variance-authority";
4
+ import { ChevronDownIcon } from "lucide-react";
5
+
6
+ import { cn } from "./utils";
7
+
8
+ function NavigationMenu({
9
+ className,
10
+ children,
11
+ viewport = true,
12
+ ...props
13
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Root> & {
14
+ viewport?: boolean;
15
+ }) {
16
+ return (
17
+ <NavigationMenuPrimitive.Root
18
+ data-slot="navigation-menu"
19
+ className={cn(
20
+ "relative z-10 flex w-full flex-1 items-center justify-center",
21
+ className
22
+ )}
23
+ {...props}
24
+ >
25
+ {children}
26
+ {viewport && <NavigationMenuViewport />}
27
+ </NavigationMenuPrimitive.Root>
28
+ );
29
+ }
30
+
31
+ function NavigationMenuList({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.List>) {
35
+ return (
36
+ <NavigationMenuPrimitive.List
37
+ data-slot="navigation-menu-list"
38
+ className={cn(
39
+ "group flex flex-1 list-none items-center justify-center gap-1",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function NavigationMenuItem({
48
+ className,
49
+ ...props
50
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Item>) {
51
+ return (
52
+ <NavigationMenuPrimitive.Item
53
+ data-slot="navigation-menu-item"
54
+ className={cn("relative", className)}
55
+ {...props}
56
+ />
57
+ );
58
+ }
59
+
60
+ const navigationMenuTriggerStyle = cva(
61
+ "group inline-flex h-10 w-max items-center justify-center rounded-[var(--radius)] bg-background px-4 py-2 text-[var(--text-p)] font-[var(--font-weight-medium)] hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:bg-accent/50 outline-none focus-visible:ring-2 focus-visible:ring-ring"
62
+ );
63
+
64
+ function NavigationMenuTrigger({
65
+ className,
66
+ children,
67
+ ...props
68
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Trigger>) {
69
+ return (
70
+ <NavigationMenuPrimitive.Trigger
71
+ data-slot="navigation-menu-trigger"
72
+ className={cn(navigationMenuTriggerStyle(), "group", className)}
73
+ {...props}
74
+ >
75
+ {children}{" "}
76
+ <ChevronDownIcon
77
+ className="relative top-[1px] ml-1 size-3 group-data-[state=open]:rotate-180"
78
+ aria-hidden="true"
79
+ />
80
+ </NavigationMenuPrimitive.Trigger>
81
+ );
82
+ }
83
+
84
+ function NavigationMenuContent({
85
+ className,
86
+ ...props
87
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Content>) {
88
+ return (
89
+ <NavigationMenuPrimitive.Content
90
+ data-slot="navigation-menu-content"
91
+ className={cn(
92
+ "left-0 top-0 w-full md:w-auto",
93
+ className
94
+ )}
95
+ {...props}
96
+ />
97
+ );
98
+ }
99
+
100
+ function NavigationMenuViewport({
101
+ className,
102
+ ...props
103
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Viewport>) {
104
+ return (
105
+ <div className={cn("absolute left-0 top-full flex justify-center w-full")}>
106
+ <NavigationMenuPrimitive.Viewport
107
+ data-slot="navigation-menu-viewport"
108
+ className={cn(
109
+ "origin-top-center relative mt-1.5 overflow-hidden rounded-[var(--radius)] border border-border bg-popover text-popover-foreground shadow-lg",
110
+ className
111
+ )}
112
+ {...props}
113
+ />
114
+ </div>
115
+ );
116
+ }
117
+
118
+ function NavigationMenuLink({
119
+ className,
120
+ ...props
121
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Link>) {
122
+ return (
123
+ <NavigationMenuPrimitive.Link
124
+ data-slot="navigation-menu-link"
125
+ className={cn(
126
+ "block select-none space-y-1 rounded-[var(--radius)] p-3 leading-none no-underline outline-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
127
+ className
128
+ )}
129
+ {...props}
130
+ />
131
+ );
132
+ }
133
+
134
+ function NavigationMenuIndicator({
135
+ className,
136
+ ...props
137
+ }: React.ComponentProps<typeof NavigationMenuPrimitive.Indicator>) {
138
+ return (
139
+ <NavigationMenuPrimitive.Indicator
140
+ data-slot="navigation-menu-indicator"
141
+ className={cn(
142
+ "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
143
+ className
144
+ )}
145
+ {...props}
146
+ >
147
+ <div className="bg-border relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm shadow-md" />
148
+ </NavigationMenuPrimitive.Indicator>
149
+ );
150
+ }
151
+
152
+ export {
153
+ NavigationMenu,
154
+ NavigationMenuList,
155
+ NavigationMenuItem,
156
+ NavigationMenuContent,
157
+ NavigationMenuTrigger,
158
+ NavigationMenuLink,
159
+ NavigationMenuIndicator,
160
+ NavigationMenuViewport,
161
+ navigationMenuTriggerStyle,
162
+ };
@@ -0,0 +1,61 @@
1
+ import * as React from "react";
2
+ import { cn } from "./utils";
3
+
4
+ interface NotificationBadgeProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ count?: number;
6
+ max?: number;
7
+ showZero?: boolean;
8
+ dot?: boolean;
9
+ variant?: "default" | "primary" | "destructive";
10
+ }
11
+
12
+ const NotificationBadge = React.forwardRef<HTMLDivElement, NotificationBadgeProps>(
13
+ ({
14
+ className,
15
+ count = 0,
16
+ max = 99,
17
+ showZero = false,
18
+ dot = false,
19
+ variant = "destructive",
20
+ children,
21
+ ...props
22
+ }, ref) => {
23
+ const displayCount = count > max ? `${max}+` : count;
24
+ const shouldShow = count > 0 || showZero;
25
+
26
+ const variantStyles = {
27
+ default: "bg-muted text-muted-foreground",
28
+ primary: "bg-primary text-primary-foreground",
29
+ destructive: "bg-destructive text-destructive-foreground",
30
+ };
31
+
32
+ if (!shouldShow && !dot) {
33
+ return <div ref={ref} className={className}>{children}</div>;
34
+ }
35
+
36
+ return (
37
+ <div ref={ref} className={cn("relative inline-block", className)} {...props}>
38
+ {children}
39
+ <span
40
+ className={cn(
41
+ "absolute -right-1 -top-1 flex items-center justify-center rounded-full",
42
+ variantStyles[variant],
43
+ dot
44
+ ? "h-2 w-2"
45
+ : "min-w-[1.25rem] h-5 px-1.5"
46
+ )}
47
+ >
48
+ {!dot && shouldShow && (
49
+ <span className="text-[10px] font-medium leading-none">
50
+ {displayCount}
51
+ </span>
52
+ )}
53
+ </span>
54
+ </div>
55
+ );
56
+ }
57
+ );
58
+ NotificationBadge.displayName = "NotificationBadge";
59
+
60
+ export { NotificationBadge };
61
+ export type { NotificationBadgeProps };
@@ -0,0 +1,229 @@
1
+ import * as React from "react";
2
+ import { ChevronRight, Moon, Sun, Globe } from "lucide-react";
3
+ import { cn } from "./utils";
4
+ import { Button } from "./button";
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger,
10
+ } from "./dropdown-menu";
11
+
12
+ // ============================================================================
13
+ // Types & Interfaces
14
+ // ============================================================================
15
+
16
+ export interface BreadcrumbItem {
17
+ label: string;
18
+ href?: string;
19
+ icon?: React.ReactNode;
20
+ }
21
+
22
+ export interface Language {
23
+ code: string;
24
+ label: string;
25
+ flag?: string;
26
+ }
27
+
28
+ export interface PageHeaderProps {
29
+ /**
30
+ * Array de items do breadcrumb
31
+ */
32
+ breadcrumbs: BreadcrumbItem[];
33
+
34
+ /**
35
+ * Mostra o seletor de idioma
36
+ * @default false
37
+ */
38
+ showLanguageSelector?: boolean;
39
+
40
+ /**
41
+ * Idiomas disponíveis
42
+ */
43
+ languages?: Language[];
44
+
45
+ /**
46
+ * Idioma atual selecionado (código)
47
+ */
48
+ currentLanguage?: string;
49
+
50
+ /**
51
+ * Callback quando o idioma é alterado
52
+ */
53
+ onLanguageChange?: (languageCode: string) => void;
54
+
55
+ /**
56
+ * Mostra o alternador de dark mode
57
+ * @default false
58
+ */
59
+ showThemeToggle?: boolean;
60
+
61
+ /**
62
+ * Tema atual ('light' ou 'dark')
63
+ */
64
+ theme?: "light" | "dark";
65
+
66
+ /**
67
+ * Callback quando o tema é alterado
68
+ */
69
+ onThemeChange?: (theme: "light" | "dark") => void;
70
+
71
+ /**
72
+ * Classes CSS adicionais
73
+ */
74
+ className?: string;
75
+
76
+ /**
77
+ * Conteúdo adicional à direita
78
+ */
79
+ rightContent?: React.ReactNode;
80
+ }
81
+
82
+ // ============================================================================
83
+ // Component
84
+ // ============================================================================
85
+
86
+ export function PageHeader({
87
+ breadcrumbs,
88
+ showLanguageSelector = false,
89
+ languages = [
90
+ { code: "pt-BR", label: "Português (BR)", flag: "🇧🇷" },
91
+ { code: "en-US", label: "English (US)", flag: "🇺🇸" },
92
+ { code: "es-ES", label: "Español", flag: "🇪🇸" },
93
+ ],
94
+ currentLanguage = "pt-BR",
95
+ onLanguageChange,
96
+ showThemeToggle = false,
97
+ theme = "light",
98
+ onThemeChange,
99
+ className,
100
+ rightContent,
101
+ }: PageHeaderProps) {
102
+ const [isDark, setIsDark] = React.useState(theme === "dark");
103
+ const [selectedLanguage, setSelectedLanguage] = React.useState(currentLanguage);
104
+
105
+ // Sincroniza estado interno com props
106
+ React.useEffect(() => {
107
+ setIsDark(theme === "dark");
108
+ }, [theme]);
109
+
110
+ React.useEffect(() => {
111
+ setSelectedLanguage(currentLanguage);
112
+ }, [currentLanguage]);
113
+
114
+ const handleThemeToggle = () => {
115
+ const newTheme = isDark ? "light" : "dark";
116
+ setIsDark(!isDark);
117
+ onThemeChange?.(newTheme);
118
+ };
119
+
120
+ const handleLanguageChange = (languageCode: string) => {
121
+ setSelectedLanguage(languageCode);
122
+ onLanguageChange?.(languageCode);
123
+ };
124
+
125
+ const currentLang = languages.find((lang) => lang.code === selectedLanguage);
126
+
127
+ return (
128
+ <header
129
+ className={cn(
130
+ "sticky top-0 z-40 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60",
131
+ className
132
+ )}
133
+ >
134
+ <div className="container flex h-14 md:h-16 items-center justify-between px-4 md:px-6">
135
+ {/* Breadcrumb */}
136
+ <nav aria-label="Breadcrumb" className="flex items-center gap-1 md:gap-2 overflow-x-auto">
137
+ {breadcrumbs.map((item, index) => {
138
+ const isLast = index === breadcrumbs.length - 1;
139
+
140
+ return (
141
+ <React.Fragment key={index}>
142
+ {index > 0 && (
143
+ <ChevronRight className="w-3 h-3 md:w-4 md:h-4 text-muted-foreground shrink-0" />
144
+ )}
145
+
146
+ {item.href && !isLast ? (
147
+ <a
148
+ href={item.href}
149
+ className="flex items-center gap-1.5 md:gap-2 text-sm md:text-base text-muted-foreground hover:text-foreground transition-colors whitespace-nowrap"
150
+ >
151
+ {item.icon && <span className="shrink-0">{item.icon}</span>}
152
+ <span>{item.label}</span>
153
+ </a>
154
+ ) : (
155
+ <span
156
+ className={cn(
157
+ "flex items-center gap-1.5 md:gap-2 text-sm md:text-base whitespace-nowrap",
158
+ isLast ? "text-foreground font-medium" : "text-muted-foreground"
159
+ )}
160
+ aria-current={isLast ? "page" : undefined}
161
+ >
162
+ {item.icon && <span className="shrink-0">{item.icon}</span>}
163
+ <span>{item.label}</span>
164
+ </span>
165
+ )}
166
+ </React.Fragment>
167
+ );
168
+ })}
169
+ </nav>
170
+
171
+ {/* Right Side Actions */}
172
+ <div className="flex items-center gap-2 md:gap-3 shrink-0">
173
+ {/* Language Selector */}
174
+ {showLanguageSelector && (
175
+ <DropdownMenu>
176
+ <DropdownMenuTrigger asChild>
177
+ <Button
178
+ variant="ghost"
179
+ size="sm"
180
+ className="gap-1.5 md:gap-2 h-8 md:h-9 px-2 md:px-3"
181
+ >
182
+ <Globe className="w-4 h-4" />
183
+ <span className="hidden sm:inline-flex items-center gap-1.5">
184
+ {currentLang?.flag && <span>{currentLang.flag}</span>}
185
+ <span>{currentLang?.label.split(" ")[0]}</span>
186
+ </span>
187
+ </Button>
188
+ </DropdownMenuTrigger>
189
+ <DropdownMenuContent align="end">
190
+ {languages.map((lang) => (
191
+ <DropdownMenuItem
192
+ key={lang.code}
193
+ onClick={() => handleLanguageChange(lang.code)}
194
+ className={cn(
195
+ "gap-2 cursor-pointer",
196
+ lang.code === selectedLanguage && "bg-accent"
197
+ )}
198
+ >
199
+ {lang.flag && <span>{lang.flag}</span>}
200
+ <span>{lang.label}</span>
201
+ </DropdownMenuItem>
202
+ ))}
203
+ </DropdownMenuContent>
204
+ </DropdownMenu>
205
+ )}
206
+
207
+ {/* Theme Toggle */}
208
+ {showThemeToggle && (
209
+ <Button
210
+ variant="ghost"
211
+ size="sm"
212
+ onClick={handleThemeToggle}
213
+ className="h-8 md:h-9 w-8 md:w-9 p-0"
214
+ aria-label={isDark ? "Mudar para modo claro" : "Mudar para modo escuro"}
215
+ >
216
+ {isDark ? (
217
+ <Sun className="w-4 h-4" />
218
+ ) : (
219
+ <Moon className="w-4 h-4" />
220
+ )}
221
+ </Button>
222
+ )}
223
+
224
+ {rightContent}
225
+ </div>
226
+ </div>
227
+ </header>
228
+ );
229
+ }
@@ -0,0 +1,127 @@
1
+ import * as React from "react";
2
+ import {
3
+ ChevronLeftIcon,
4
+ ChevronRightIcon,
5
+ MoreHorizontalIcon,
6
+ } from "lucide-react";
7
+
8
+ import { cn } from "./utils";
9
+ import { Button, buttonVariants } from "./button";
10
+
11
+ function Pagination({ className, ...props }: React.ComponentProps<"nav">) {
12
+ return (
13
+ <nav
14
+ role="navigation"
15
+ aria-label="pagination"
16
+ data-slot="pagination"
17
+ className={cn("mx-auto flex w-full justify-center", className)}
18
+ {...props}
19
+ />
20
+ );
21
+ }
22
+
23
+ function PaginationContent({
24
+ className,
25
+ ...props
26
+ }: React.ComponentProps<"ul">) {
27
+ return (
28
+ <ul
29
+ data-slot="pagination-content"
30
+ className={cn("flex flex-row items-center gap-1", className)}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ function PaginationItem({ ...props }: React.ComponentProps<"li">) {
37
+ return <li data-slot="pagination-item" {...props} />;
38
+ }
39
+
40
+ type PaginationLinkProps = {
41
+ isActive?: boolean;
42
+ } & Pick<React.ComponentProps<typeof Button>, "size"> &
43
+ React.ComponentProps<"a">;
44
+
45
+ function PaginationLink({
46
+ className,
47
+ isActive,
48
+ size = "icon",
49
+ ...props
50
+ }: PaginationLinkProps) {
51
+ return (
52
+ <a
53
+ aria-current={isActive ? "page" : undefined}
54
+ data-slot="pagination-link"
55
+ data-active={isActive}
56
+ className={cn(
57
+ buttonVariants({
58
+ variant: isActive ? "outline" : "ghost",
59
+ size,
60
+ }),
61
+ className,
62
+ )}
63
+ {...props}
64
+ />
65
+ );
66
+ }
67
+
68
+ function PaginationPrevious({
69
+ className,
70
+ ...props
71
+ }: React.ComponentProps<typeof PaginationLink>) {
72
+ return (
73
+ <PaginationLink
74
+ aria-label="Go to previous page"
75
+ size="default"
76
+ className={cn("gap-1 px-2.5 sm:pl-2.5", className)}
77
+ {...props}
78
+ >
79
+ <ChevronLeftIcon />
80
+ <span className="hidden sm:block">Previous</span>
81
+ </PaginationLink>
82
+ );
83
+ }
84
+
85
+ function PaginationNext({
86
+ className,
87
+ ...props
88
+ }: React.ComponentProps<typeof PaginationLink>) {
89
+ return (
90
+ <PaginationLink
91
+ aria-label="Go to next page"
92
+ size="default"
93
+ className={cn("gap-1 px-2.5 sm:pr-2.5", className)}
94
+ {...props}
95
+ >
96
+ <span className="hidden sm:block">Next</span>
97
+ <ChevronRightIcon />
98
+ </PaginationLink>
99
+ );
100
+ }
101
+
102
+ function PaginationEllipsis({
103
+ className,
104
+ ...props
105
+ }: React.ComponentProps<"span">) {
106
+ return (
107
+ <span
108
+ aria-hidden
109
+ data-slot="pagination-ellipsis"
110
+ className={cn("flex size-9 items-center justify-center", className)}
111
+ {...props}
112
+ >
113
+ <MoreHorizontalIcon className="size-4" />
114
+ <span className="sr-only">More pages</span>
115
+ </span>
116
+ );
117
+ }
118
+
119
+ export {
120
+ Pagination,
121
+ PaginationContent,
122
+ PaginationLink,
123
+ PaginationItem,
124
+ PaginationPrevious,
125
+ PaginationNext,
126
+ PaginationEllipsis,
127
+ };
@@ -0,0 +1,48 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
5
+
6
+ import { cn } from "./utils";
7
+
8
+ function Popover({
9
+ ...props
10
+ }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
11
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />;
12
+ }
13
+
14
+ function PopoverTrigger({
15
+ ...props
16
+ }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
17
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
18
+ }
19
+
20
+ function PopoverContent({
21
+ className,
22
+ align = "center",
23
+ sideOffset = 4,
24
+ ...props
25
+ }: React.ComponentProps<typeof PopoverPrimitive.Content>) {
26
+ return (
27
+ <PopoverPrimitive.Portal>
28
+ <PopoverPrimitive.Content
29
+ data-slot="popover-content"
30
+ align={align}
31
+ sideOffset={sideOffset}
32
+ className={cn(
33
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
34
+ className,
35
+ )}
36
+ {...props}
37
+ />
38
+ </PopoverPrimitive.Portal>
39
+ );
40
+ }
41
+
42
+ function PopoverAnchor({
43
+ ...props
44
+ }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
45
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
46
+ }
47
+
48
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
@@ -0,0 +1,31 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as ProgressPrimitive from "@radix-ui/react-progress";
5
+
6
+ import { cn } from "./utils";
7
+
8
+ function Progress({
9
+ className,
10
+ value,
11
+ ...props
12
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
13
+ return (
14
+ <ProgressPrimitive.Root
15
+ data-slot="progress"
16
+ className={cn(
17
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
18
+ className,
19
+ )}
20
+ {...props}
21
+ >
22
+ <ProgressPrimitive.Indicator
23
+ data-slot="progress-indicator"
24
+ className="bg-primary h-full w-full flex-1 transition-all"
25
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
26
+ />
27
+ </ProgressPrimitive.Root>
28
+ );
29
+ }
30
+
31
+ export { Progress };