@alquimia-ai/ui 1.2.1 → 1.2.4

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 (101) hide show
  1. package/dist/components/hooks/index.js +41 -32
  2. package/dist/components/hooks/index.js.map +1 -1
  3. package/dist/components/hooks/index.mjs +42 -33
  4. package/dist/components/hooks/index.mjs.map +1 -1
  5. package/dist/components/molecules/index.js +41 -32
  6. package/dist/components/molecules/index.js.map +1 -1
  7. package/dist/components/molecules/index.mjs +42 -33
  8. package/dist/components/molecules/index.mjs.map +1 -1
  9. package/dist/components/organisms/index.js +41 -32
  10. package/dist/components/organisms/index.js.map +1 -1
  11. package/dist/components/organisms/index.mjs +42 -33
  12. package/dist/components/organisms/index.mjs.map +1 -1
  13. package/dist/index.js +41 -32
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.mjs +42 -33
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/package.json +136 -0
  18. package/package.json +50 -53
  19. package/src/components/atoms/index.ts +0 -32
  20. package/src/components/atoms/ui/alert.tsx +0 -59
  21. package/src/components/atoms/ui/aspect-ratio.tsx +0 -7
  22. package/src/components/atoms/ui/avatar.tsx +0 -50
  23. package/src/components/atoms/ui/badge.tsx +0 -36
  24. package/src/components/atoms/ui/breadcrumb.tsx +0 -120
  25. package/src/components/atoms/ui/button.tsx +0 -56
  26. package/src/components/atoms/ui/card.tsx +0 -87
  27. package/src/components/atoms/ui/checkbox.tsx +0 -31
  28. package/src/components/atoms/ui/command.tsx +0 -155
  29. package/src/components/atoms/ui/dialog.tsx +0 -125
  30. package/src/components/atoms/ui/drawer.tsx +0 -119
  31. package/src/components/atoms/ui/input.tsx +0 -26
  32. package/src/components/atoms/ui/label.tsx +0 -26
  33. package/src/components/atoms/ui/loader.tsx +0 -52
  34. package/src/components/atoms/ui/popover.tsx +0 -31
  35. package/src/components/atoms/ui/rich-text.tsx +0 -19
  36. package/src/components/atoms/ui/scroll-area.tsx +0 -48
  37. package/src/components/atoms/ui/select.tsx +0 -160
  38. package/src/components/atoms/ui/skeleton.tsx +0 -15
  39. package/src/components/atoms/ui/slider.tsx +0 -29
  40. package/src/components/atoms/ui/switch.tsx +0 -30
  41. package/src/components/atoms/ui/table.tsx +0 -118
  42. package/src/components/atoms/ui/tabs.tsx +0 -56
  43. package/src/components/atoms/ui/text-area/index.tsx +0 -24
  44. package/src/components/atoms/ui/textarea.tsx +0 -25
  45. package/src/components/atoms/ui/think-indicator.tsx +0 -103
  46. package/src/components/atoms/ui/toast.tsx +0 -129
  47. package/src/components/atoms/ui/toaster.tsx +0 -38
  48. package/src/components/atoms/ui/toggle.tsx +0 -45
  49. package/src/components/atoms/ui/typography/index.tsx +0 -30
  50. package/src/components/hooks/index.ts +0 -4
  51. package/src/components/hooks/use-document.tsx +0 -44
  52. package/src/components/hooks/use-resize-observer.ts +0 -28
  53. package/src/components/hooks/use-text-streaming.ts +0 -63
  54. package/src/components/hooks/use-toast.ts +0 -194
  55. package/src/components/index.ts +0 -1
  56. package/src/components/molecules/alert-dialog.tsx +0 -141
  57. package/src/components/molecules/assistant-button.tsx +0 -148
  58. package/src/components/molecules/call-out.tsx +0 -163
  59. package/src/components/molecules/carousel.tsx +0 -262
  60. package/src/components/molecules/documents/document-selector.tsx +0 -79
  61. package/src/components/molecules/documents/document-viewer.tsx +0 -85
  62. package/src/components/molecules/documents/index.ts +0 -2
  63. package/src/components/molecules/index.ts +0 -11
  64. package/src/components/molecules/navigation-menu.tsx +0 -128
  65. package/src/components/molecules/page-container.tsx +0 -17
  66. package/src/components/molecules/rating-comment.tsx +0 -93
  67. package/src/components/molecules/rating-stars.tsx +0 -136
  68. package/src/components/molecules/rating-thumbs.tsx +0 -90
  69. package/src/components/molecules/sidebar.tsx +0 -107
  70. package/src/components/molecules/sonner.tsx +0 -30
  71. package/src/components/molecules/viewers/index.ts +0 -2
  72. package/src/components/molecules/viewers/pdf-viewer.tsx +0 -138
  73. package/src/components/molecules/viewers/plain-text-viewer.tsx +0 -40
  74. package/src/components/organisms/assistant.tsx +0 -271
  75. package/src/components/organisms/index.ts +0 -6
  76. package/src/components/organisms/rating-dialog.tsx +0 -104
  77. package/src/components/organisms/speechToText.tsx +0 -92
  78. package/src/components/organisms/whisper.tsx +0 -106
  79. package/src/components/templates/cards/index.ts +0 -2
  80. package/src/components/templates/cards/with-image-heading-description-avatar.tsx +0 -94
  81. package/src/components/templates/cards/with-image-heading-description.tsx +0 -63
  82. package/src/components/templates/hero/index.tsx +0 -39
  83. package/src/components/templates/index.ts +0 -4
  84. package/src/components/templates/messages-window.tsx +0 -15
  85. package/src/components/templates/query-box.tsx +0 -13
  86. package/src/components/ui/input.tsx +0 -25
  87. package/src/components/ui/select.tsx +0 -163
  88. package/src/index.ts +0 -7
  89. package/src/lib/index.ts +0 -1
  90. package/src/lib/utils.ts +0 -34
  91. package/src/styles/call-out.css +0 -153
  92. package/src/styles/drawer.css +0 -28
  93. package/src/styles/globals.css +0 -69
  94. package/src/styles/prose.css +0 -51
  95. package/src/styles/ratings.css +0 -27
  96. package/src/styles/themes/base-alquimia.css +0 -95
  97. package/src/styles/themes/base-nordic.css +0 -83
  98. package/src/styles/themes/base-primary.css +0 -85
  99. package/src/styles/themes/base.css +0 -8
  100. package/src/types/index.ts +0 -1
  101. package/src/types/type.ts +0 -76
@@ -1,79 +0,0 @@
1
- import React, { useState } from 'react';
2
- import {
3
- Select,
4
- SelectTrigger,
5
- SelectContent,
6
- SelectItem,
7
- SelectLabel,
8
- SelectGroup,
9
- SelectValue,
10
- } from "../../atoms";
11
- import { AlquimiaDocument, ActionResponse } from '../../../types/type';
12
- import { ExternalLink } from "lucide-react";
13
- import { DocumentViewer } from './document-viewer';
14
-
15
- type DocumentSelectorProps = {
16
- documents: AlquimiaDocument[];
17
- getDocument: (id: string) => Promise<ActionResponse<Blob>>
18
- logInfoMessage: (info: string, data: any) => void
19
- }
20
- export const DocumentSelector = ({ documents, getDocument, logInfoMessage }: DocumentSelectorProps) =>{
21
- const [selectedDocName, setSelectedDocName] = useState<string | undefined>(undefined);
22
- const [selectedDoc, setSelectedDoc] = useState<string | null>(null);
23
- const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
24
-
25
-
26
- const handleDocumentClick = (doc: any, event: React.MouseEvent) => {
27
- event.stopPropagation();
28
- setSelectedDoc(doc);
29
- logInfoMessage("Selected document", {
30
- documentId: doc.id,
31
- documentName: doc.name,
32
- });
33
- setIsModalOpen(true);
34
- };
35
-
36
- const handleDrawerClose = () => {
37
- setIsModalOpen(false)
38
- }
39
-
40
- return (
41
- <div className="w-full md:w-4/6 alq--document-selector">
42
- <Select value={selectedDocName} onValueChange={setSelectedDocName}>
43
- <SelectTrigger aria-label="Documentos">
44
- <SelectValue placeholder="Documentos" />
45
- </SelectTrigger>
46
- <SelectContent>
47
- <SelectGroup>
48
- <SelectLabel>Documents</SelectLabel>
49
- {documents.map((doc) => (
50
- <div key={doc.id} className="w-full flex relative">
51
- <SelectItem className="w-full" key={doc.id} value={doc.id}>
52
- <div className="flex justify-between w-full">
53
- <p className="h-4 truncate mr-5">{doc.name}</p>
54
- </div>
55
- </SelectItem>
56
- <div
57
- onClick={(event) => handleDocumentClick(doc, event)}
58
- className="bflex items-center text-gray-400 hover:text-gray-500 absolute right-0 mt-2"
59
- aria-label={`Open ${doc.name}`}
60
- >
61
- <ExternalLink className="h-4 w-4 mx-2" />
62
- </div>
63
- </div>
64
- ))}
65
- </SelectGroup>
66
- </SelectContent>
67
- </Select>
68
- {selectedDoc && (
69
- <DocumentViewer
70
- doc={selectedDoc}
71
- docName={selectedDocName || ''}
72
- isOpen={isModalOpen}
73
- onClose={handleDrawerClose}
74
- getDocument={getDocument}
75
- />
76
- )}
77
- </div>
78
- );
79
- }
@@ -1,85 +0,0 @@
1
- 'use client'
2
-
3
- import React, { useEffect } from 'react'
4
- import {
5
- Dialog,
6
- DialogContent,
7
- DialogHeader,
8
- DialogTitle,
9
- Loader
10
- } from "../../atoms";
11
- import { useDocumentReader } from '../../hooks/use-document';
12
- import dynamic from 'next/dynamic';
13
- import { ActionResponse } from '../../../types/type';
14
- const PdfViewer = dynamic(() => import("../viewers/pdf-viewer"), { ssr: false });
15
- const PlainTextViewer = dynamic(() => import("../viewers/plain-text-viewer"), { ssr: false });
16
-
17
- type DocumentViewerProps = {
18
- docId?: string;
19
- doc: any;
20
- docName: string;
21
- isOpen: boolean;
22
- onClose: () => void;
23
- getDocument: (id: string) => Promise<ActionResponse<Blob>>;
24
- };
25
-
26
- export const DocumentViewer = ({
27
- docId,
28
- doc,
29
- isOpen,
30
- onClose,
31
- getDocument,
32
- }: DocumentViewerProps) => {
33
- const { document, loading, fetchDocument, resetDocument, error } =
34
- useDocumentReader(doc.id, getDocument);
35
-
36
- useEffect(() => {
37
- resetDocument();
38
-
39
- if (isOpen) {
40
- fetchDocument();
41
- }
42
- }, [isOpen]);
43
-
44
- const documentRender = document && !error ? (
45
- <DocumentFactory document={document} docId={doc.id} />
46
- ) : (
47
- <div className="flex flex-col items-center justify-center h-full w-full text-center p-4">
48
- <div className="text-primary font-medium">{error}</div>
49
- </div>
50
- );
51
-
52
- return (
53
- <Dialog open={isOpen} onOpenChange={onClose}>
54
- <DialogContent
55
- aria-describedby={document ? "document-description" : undefined}
56
- className="h-[90%] max-w-[90%] gap-0 flex flex-col focus:outline-none"
57
- >
58
- <DialogHeader className="border-b border-border pb-2">
59
- <DialogTitle>{doc.name}</DialogTitle>
60
- </DialogHeader>
61
- {!document && loading ? (
62
- <Loader size="xl" colorVariant="destructive" />
63
- ) : (
64
- documentRender
65
- )}
66
- </DialogContent>
67
- </Dialog>
68
- );
69
- };
70
-
71
- type DocViewerFactoryProps = {
72
- document: Blob | null;
73
- docId: string;
74
- };
75
-
76
- const DocumentFactory: React.FC<DocViewerFactoryProps> = ({ document, docId }) => {
77
- switch (document && document.type) {
78
- case 'application/pdf':
79
- return <PdfViewer doc={document} docId={docId} />;
80
- case 'text/plain':
81
- return <PlainTextViewer doc={document} docId={docId} />;
82
- default:
83
- return <div>Unsupported file type</div>;
84
- }
85
- };
@@ -1,2 +0,0 @@
1
- export * from "./document-selector";
2
- export * from "./document-viewer";
@@ -1,11 +0,0 @@
1
- export { PageContainer } from "./page-container";
2
- export * from "./alert-dialog";
3
- export * from "./assistant-button";
4
- export * from "./carousel";
5
- export * from "./navigation-menu";
6
- export * from "./sidebar";
7
- export * from "./sonner";
8
- export * from "./rating-stars";
9
- export * from "./rating-thumbs";
10
- export * from "./rating-comment";
11
- export * from "./call-out";
@@ -1,128 +0,0 @@
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 { ChevronDown } from "lucide-react";
5
-
6
- import { cn } from "../../lib/utils";
7
-
8
- const NavigationMenu = React.forwardRef<
9
- React.ElementRef<typeof NavigationMenuPrimitive.Root>,
10
- React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
11
- >(({ className, children, ...props }, ref) => (
12
- <NavigationMenuPrimitive.Root
13
- ref={ref}
14
- className={cn(
15
- "relative z-10 flex max-w-max flex-1 items-center justify-center",
16
- className
17
- )}
18
- {...props}
19
- >
20
- {children}
21
- <NavigationMenuViewport />
22
- </NavigationMenuPrimitive.Root>
23
- ));
24
- NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
25
-
26
- const NavigationMenuList = React.forwardRef<
27
- React.ElementRef<typeof NavigationMenuPrimitive.List>,
28
- React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
29
- >(({ className, ...props }, ref) => (
30
- <NavigationMenuPrimitive.List
31
- ref={ref}
32
- className={cn(
33
- "group flex flex-1 list-none items-center justify-center space-x-1",
34
- className
35
- )}
36
- {...props}
37
- />
38
- ));
39
- NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
40
-
41
- const NavigationMenuItem = NavigationMenuPrimitive.Item;
42
-
43
- const navigationMenuTriggerStyle = cva(
44
- "group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
45
- );
46
-
47
- const NavigationMenuTrigger = React.forwardRef<
48
- React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
49
- React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
50
- >(({ className, children, ...props }, ref) => (
51
- <NavigationMenuPrimitive.Trigger
52
- ref={ref}
53
- className={cn(navigationMenuTriggerStyle(), "group", className)}
54
- {...props}
55
- >
56
- {children}{" "}
57
- <ChevronDown
58
- className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
59
- aria-hidden="true"
60
- />
61
- </NavigationMenuPrimitive.Trigger>
62
- ));
63
- NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
64
-
65
- const NavigationMenuContent = React.forwardRef<
66
- React.ElementRef<typeof NavigationMenuPrimitive.Content>,
67
- React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
68
- >(({ className, ...props }, ref) => (
69
- <NavigationMenuPrimitive.Content
70
- ref={ref}
71
- className={cn(
72
- "left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
73
- className
74
- )}
75
- {...props}
76
- />
77
- ));
78
- NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
79
-
80
- const NavigationMenuLink = NavigationMenuPrimitive.Link;
81
-
82
- const NavigationMenuViewport = React.forwardRef<
83
- React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
84
- React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
85
- >(({ className, ...props }, ref) => (
86
- <div className={cn("absolute left-0 top-full flex justify-center")}>
87
- <NavigationMenuPrimitive.Viewport
88
- className={cn(
89
- "origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
90
- className
91
- )}
92
- ref={ref}
93
- {...props}
94
- />
95
- </div>
96
- ));
97
- NavigationMenuViewport.displayName =
98
- NavigationMenuPrimitive.Viewport.displayName;
99
-
100
- const NavigationMenuIndicator = React.forwardRef<
101
- React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
102
- React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
103
- >(({ className, ...props }, ref) => (
104
- <NavigationMenuPrimitive.Indicator
105
- ref={ref}
106
- className={cn(
107
- "top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
108
- className
109
- )}
110
- {...props}
111
- >
112
- <div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
113
- </NavigationMenuPrimitive.Indicator>
114
- ));
115
- NavigationMenuIndicator.displayName =
116
- NavigationMenuPrimitive.Indicator.displayName;
117
-
118
- export {
119
- navigationMenuTriggerStyle,
120
- NavigationMenu,
121
- NavigationMenuList,
122
- NavigationMenuItem,
123
- NavigationMenuContent,
124
- NavigationMenuTrigger,
125
- NavigationMenuLink,
126
- NavigationMenuIndicator,
127
- NavigationMenuViewport,
128
- };
@@ -1,17 +0,0 @@
1
- import { forwardRef } from "react";
2
- import { cn } from "../../lib/utils";
3
-
4
- interface PageContainerProps extends React.HTMLAttributes<HTMLDivElement> {}
5
- const PageContainer = forwardRef<HTMLDivElement, PageContainerProps>(
6
- ({ className, ...props }, ref) => {
7
- return (
8
- <div
9
- ref={ref}
10
- className={cn(className, "alq--page-container")}
11
- {...props}
12
- />
13
- );
14
- }
15
- );
16
- PageContainer.displayName = "PageContainer";
17
- export { PageContainer };
@@ -1,93 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { Book } from "lucide-react"
5
- import { cn } from "../../lib/utils"
6
- import { Button } from "../atoms"
7
- import {
8
- Dialog,
9
- DialogTrigger,
10
- DialogContent,
11
- DialogOverlay,
12
- DialogTitle,
13
- } from "../atoms/ui/dialog";
14
-
15
- interface RatingCommentProps {
16
- currentRating: string
17
- onRate: (comment: string) => void
18
- className?: string
19
- isLoading?: boolean
20
- }
21
-
22
- export const RatingComment = React.forwardRef<HTMLButtonElement, RatingCommentProps>(
23
- ({ currentRating, onRate, className, isLoading }, ref) => {
24
- const [open, setOpen] = React.useState(false)
25
- const [comment, setComment] = React.useState("")
26
- const [animate, setAnimate] = React.useState(false);
27
-
28
- const handleRate = () => {
29
- onRate(comment)
30
- setOpen(false)
31
- }
32
-
33
- React.useEffect(() => {
34
- if (currentRating) {
35
- setAnimate(true);
36
- const timer = setTimeout(() => setAnimate(false), 150);
37
- return () => clearTimeout(timer);
38
- }
39
- }, [currentRating]);
40
-
41
- React.useEffect(() => {
42
- setComment("")
43
- }, [open])
44
-
45
- return (
46
- <Dialog open={open} onOpenChange={setOpen}>
47
- <DialogTrigger asChild>
48
- <Button
49
- ref={ref}
50
- variant="link"
51
- size={"lg"}
52
- className={cn(
53
- "inline-flex p-2 items-center justify-center rounded-md text-sm font-medium transition-colors [&_svg]:size-5 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring bg-transparent hover:none disabled:pointer-events-none disabled:opacity-50",
54
- className
55
- )}
56
- disabled={isLoading}
57
- >
58
- <Book
59
- className={cn(
60
- "w-5 h-5 transition-all duration-500",
61
- animate && "animate-ping",
62
- isLoading && "animate-pulse",
63
- `${comment ? "alq-rating-comment" : "stroke-gray-400"}`
64
- )}
65
- />
66
- </Button>
67
- </DialogTrigger>
68
- <DialogOverlay className="fixed inset-0 bg-black bg-opacity-50" />
69
- <DialogContent aria-describedby={undefined}>
70
- <DialogTitle className="text-lg font-medium">
71
- Deja un comentario
72
- </DialogTitle>
73
- <textarea
74
- className="mt-4 w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
75
- rows={4}
76
- value={comment}
77
- onChange={(e) => setComment(e.target.value)}
78
- />
79
- <div className="mt-4 flex justify-end">
80
- <Button
81
- onClick={handleRate}
82
- disabled={!comment}
83
- >
84
- Enviar
85
- </Button>
86
- </div>
87
- </DialogContent>
88
- </Dialog>
89
- );
90
- }
91
- )
92
-
93
- RatingComment.displayName = "RatingComment"
@@ -1,136 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import * as TooltipPrimitive from "@radix-ui/react-tooltip"
5
- import { Star } from "lucide-react"
6
- import { cn } from "../../lib/utils";
7
- import { Button } from "../atoms";
8
-
9
- const TooltipProvider = TooltipPrimitive.Provider
10
- const Tooltip = TooltipPrimitive.Root
11
- const TooltipTrigger = TooltipPrimitive.Trigger
12
-
13
- const TooltipContent = React.forwardRef<
14
- React.ElementRef<typeof TooltipPrimitive.Content>,
15
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
16
- >(({ className, sideOffset = 4, ...props }, ref) => (
17
- <TooltipPrimitive.Content
18
- ref={ref}
19
- sideOffset={sideOffset}
20
- className={cn(
21
- "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground shadow-lg animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
22
- className
23
- )}
24
- {...props}
25
- />
26
- ))
27
- TooltipContent.displayName = TooltipPrimitive.Content.displayName
28
-
29
- interface StarColors {
30
- fill: string
31
- stroke: string
32
- }
33
-
34
- interface RatingStarsProps {
35
- currentRating: number
36
- isLoading: boolean
37
- onRate: (rating: number) => void
38
- className?: string
39
- }
40
-
41
- const StarRating = React.forwardRef<
42
- HTMLDivElement,
43
- { rating: number; onRate: (r: number) => void }
44
- >(({ rating, onRate }, ref) => (
45
- <div ref={ref} className="flex">
46
- {[1, 2, 3, 4, 5].map((star) => (
47
- <Button
48
- key={star}
49
- onClick={() => onRate(star)}
50
- variant="link"
51
- className="p-1 transition-colors [&_svg]:size-5 h-5"
52
- aria-label={`Rate ${star} star${star !== 1 ? "s" : ""}`}
53
- >
54
- <Star
55
- className={cn(
56
- "w-5 h-5",
57
- star <= rating ? "alq-rating-star-active fill-current stroke-current" : "alq-rating-star-inactive",
58
- )}
59
- />
60
- </Button>
61
- ))}
62
- </div>
63
- ));
64
- StarRating.displayName = "StarRating"
65
-
66
- export const RatingStars = React.forwardRef<
67
- HTMLButtonElement,
68
- RatingStarsProps
69
- >(({
70
- currentRating = 0,
71
- onRate,
72
- className,
73
- isLoading
74
- }, ref) => {
75
- const [open, setOpen] = React.useState(false)
76
- const [animate, setAnimate] = React.useState(false)
77
-
78
- const handleRate = (rating: number) => {
79
- onRate(rating)
80
- setOpen(false)
81
- }
82
-
83
- React.useEffect(() => {
84
- if (currentRating > 0) {
85
- setAnimate(true)
86
- const timer = setTimeout(() => setAnimate(false), 150)
87
- return () => clearTimeout(timer)
88
- }
89
- }, [currentRating])
90
-
91
- const hasRated = currentRating > 0
92
-
93
- return (
94
- <TooltipProvider>
95
- <Tooltip open={open} onOpenChange={setOpen}>
96
- <TooltipTrigger asChild>
97
- <Button
98
- ref={ref}
99
- variant="link"
100
- className={cn(
101
- "inline-flex items-center justify-center rounded-md text-sm font-medium [&_svg]:size-5 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
102
- className
103
- )}
104
- disabled={isLoading}
105
- onClick={() => setOpen(!open)}
106
- >
107
- <Star
108
- className={cn(
109
- "w-5 h-5 transition-all duration-500",
110
- animate && "animate-ping",
111
- isLoading && "animate-pulse",
112
- hasRated ? "alq-rating-star-active fill-current stroke-current" : "alq-rating-star-inactive",
113
- )}
114
- />
115
- </Button>
116
- </TooltipTrigger>
117
- <TooltipContent side="top" align="center" className="p-0">
118
- <div className="p-2 bg-background">
119
- <StarRating
120
- rating={currentRating}
121
- onRate={handleRate}
122
- />
123
- </div>
124
- </TooltipContent>
125
- </Tooltip>
126
- </TooltipProvider>
127
- )
128
- })
129
- RatingStars.displayName = "RatingStars"
130
-
131
- export {
132
- Tooltip,
133
- TooltipTrigger,
134
- TooltipContent,
135
- TooltipProvider,
136
- }
@@ -1,90 +0,0 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { ThumbsUp, ThumbsDown } from "lucide-react"
5
- import { Button } from "../atoms";
6
- import { cn } from "../../lib/utils";
7
-
8
- interface RatingThumbsProps {
9
- currentRating: string
10
- isLoading: boolean
11
- onRate: (rating: "thumbsUp" | "thumbsDown" | "") => void
12
- direction?: "row" | "column"
13
- className?: string
14
- }
15
-
16
- export const RatingThumbs = React.forwardRef<HTMLDivElement, RatingThumbsProps>(
17
- (
18
- {
19
- currentRating,
20
- onRate,
21
- direction = "row",
22
- className,
23
- isLoading
24
- },
25
- ref
26
- ) => {
27
- const [animate, setAnimate] = React.useState(false);
28
-
29
- React.useEffect(() => {
30
- if (currentRating) {
31
- setAnimate(true);
32
- const timer = setTimeout(() => setAnimate(false), 150);
33
- return () => clearTimeout(timer);
34
- }
35
- }, [currentRating]);
36
-
37
- return (
38
- <div
39
- ref={ref}
40
- className={cn(
41
- "inline-flex",
42
- direction === "column" ? "flex-col" : "flex-row",
43
- "space-x-1 gap-4",
44
- className
45
- )}
46
- >
47
- <Button
48
- variant="link"
49
- onClick={() => onRate(currentRating === "thumbsUp" ? "" : "thumbsUp")}
50
- className={cn(
51
- "p-1 transition-colors disabled:opacity-50 [&_svg]:size-5",
52
- `hover:alq-rating-thumbsup/10`
53
- )}
54
- aria-label="Thumbs up"
55
- disabled={isLoading}
56
- >
57
- <ThumbsUp
58
- className={cn(
59
- "w-5 h-5 transition-all duration-500",
60
- animate && currentRating === "thumbsUp" && "animate-ping",
61
- isLoading && "animate-pulse",
62
- currentRating === "thumbsUp" ? "alq-rating-thumbsup fill-current stroke-current" : "alq-rating-thumbs-inactive fill-transparent"
63
- )}
64
- />
65
- </Button>
66
- <Button
67
- variant="link"
68
- onClick={() => onRate(currentRating === "thumbsDown" ? "" : "thumbsDown")}
69
- className={cn(
70
- "p-1 transition-colors disabled:opacity-50 mt-0.5 [&_svg]:size-5",
71
- `hover:bg-alq-rating-thumbsdown/10`
72
- )}
73
- aria-label="Thumbs down"
74
- disabled={isLoading}
75
- >
76
- <ThumbsDown
77
- className={cn(
78
- "w-5 h-5 transition-all duration-500",
79
- animate && currentRating === "thumbsDown" && "animate-ping",
80
- isLoading && "animate-pulse",
81
- currentRating === "thumbsDown" ? "alq-rating-thumbsdown fill-current stroke-current" : "alq-rating-thumbs-inactive fill-transparent"
82
- )}
83
- />
84
- </Button>
85
- </div>
86
- );
87
- }
88
- );
89
-
90
- RatingThumbs.displayName = "RatingThumbs"