@hua-labs/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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +363 -0
  3. package/dist/components/Accordion.d.ts +39 -0
  4. package/dist/components/Accordion.d.ts.map +1 -0
  5. package/dist/components/Accordion.js +84 -0
  6. package/dist/components/Alert.d.ts +17 -0
  7. package/dist/components/Alert.d.ts.map +1 -0
  8. package/dist/components/Alert.js +61 -0
  9. package/dist/components/Avatar.d.ts +13 -0
  10. package/dist/components/Avatar.d.ts.map +1 -0
  11. package/dist/components/Avatar.js +18 -0
  12. package/dist/components/Badge.d.ts +7 -0
  13. package/dist/components/Badge.d.ts.map +1 -0
  14. package/dist/components/Badge.js +15 -0
  15. package/dist/components/BottomSheet.d.ts +29 -0
  16. package/dist/components/BottomSheet.d.ts.map +1 -0
  17. package/dist/components/BottomSheet.js +96 -0
  18. package/dist/components/Breadcrumb.d.ts +27 -0
  19. package/dist/components/Breadcrumb.d.ts.map +1 -0
  20. package/dist/components/Breadcrumb.js +47 -0
  21. package/dist/components/Button.d.ts +9 -0
  22. package/dist/components/Button.d.ts.map +1 -0
  23. package/dist/components/Button.js +23 -0
  24. package/dist/components/Card.d.ts +21 -0
  25. package/dist/components/Card.d.ts.map +1 -0
  26. package/dist/components/Card.js +18 -0
  27. package/dist/components/ChatMessage.d.ts +35 -0
  28. package/dist/components/ChatMessage.d.ts.map +1 -0
  29. package/dist/components/ChatMessage.js +59 -0
  30. package/dist/components/Checkbox.d.ts +12 -0
  31. package/dist/components/Checkbox.d.ts.map +1 -0
  32. package/dist/components/Checkbox.js +30 -0
  33. package/dist/components/Command.d.ts +36 -0
  34. package/dist/components/Command.d.ts.map +1 -0
  35. package/dist/components/Command.js +119 -0
  36. package/dist/components/ConfirmModal.d.ts +26 -0
  37. package/dist/components/ConfirmModal.d.ts.map +1 -0
  38. package/dist/components/ConfirmModal.js +53 -0
  39. package/dist/components/Container.d.ts +10 -0
  40. package/dist/components/Container.d.ts.map +1 -0
  41. package/dist/components/Container.js +23 -0
  42. package/dist/components/ContextMenu.d.ts +26 -0
  43. package/dist/components/ContextMenu.d.ts.map +1 -0
  44. package/dist/components/ContextMenu.js +110 -0
  45. package/dist/components/Divider.d.ts +11 -0
  46. package/dist/components/Divider.d.ts.map +1 -0
  47. package/dist/components/Divider.js +39 -0
  48. package/dist/components/Drawer.d.ts +32 -0
  49. package/dist/components/Drawer.d.ts.map +1 -0
  50. package/dist/components/Drawer.js +79 -0
  51. package/dist/components/Dropdown.d.ts +28 -0
  52. package/dist/components/Dropdown.d.ts.map +1 -0
  53. package/dist/components/Dropdown.js +174 -0
  54. package/dist/components/EmotionAnalysis.d.ts +25 -0
  55. package/dist/components/EmotionAnalysis.d.ts.map +1 -0
  56. package/dist/components/EmotionAnalysis.js +40 -0
  57. package/dist/components/EmotionButton.d.ts +9 -0
  58. package/dist/components/EmotionButton.d.ts.map +1 -0
  59. package/dist/components/EmotionButton.js +16 -0
  60. package/dist/components/EmotionMeter.d.ts +10 -0
  61. package/dist/components/EmotionMeter.d.ts.map +1 -0
  62. package/dist/components/EmotionMeter.js +21 -0
  63. package/dist/components/EmotionSelector.d.ts +20 -0
  64. package/dist/components/EmotionSelector.d.ts.map +1 -0
  65. package/dist/components/EmotionSelector.js +46 -0
  66. package/dist/components/Grid.d.ts +11 -0
  67. package/dist/components/Grid.d.ts.map +1 -0
  68. package/dist/components/Grid.js +44 -0
  69. package/dist/components/Icon.d.ts +26 -0
  70. package/dist/components/Icon.d.ts.map +1 -0
  71. package/dist/components/Icon.js +48 -0
  72. package/dist/components/Input.d.ts +12 -0
  73. package/dist/components/Input.d.ts.map +1 -0
  74. package/dist/components/Input.js +25 -0
  75. package/dist/components/LanguageToggle.d.ts +17 -0
  76. package/dist/components/LanguageToggle.d.ts.map +1 -0
  77. package/dist/components/LanguageToggle.js +61 -0
  78. package/dist/components/LoadingSpinner.d.ts +10 -0
  79. package/dist/components/LoadingSpinner.d.ts.map +1 -0
  80. package/dist/components/LoadingSpinner.js +37 -0
  81. package/dist/components/Menu.d.ts +29 -0
  82. package/dist/components/Menu.d.ts.map +1 -0
  83. package/dist/components/Menu.js +122 -0
  84. package/dist/components/Modal.d.ts +15 -0
  85. package/dist/components/Modal.d.ts.map +1 -0
  86. package/dist/components/Modal.js +62 -0
  87. package/dist/components/PageTransition.d.ts +18 -0
  88. package/dist/components/PageTransition.d.ts.map +1 -0
  89. package/dist/components/PageTransition.js +39 -0
  90. package/dist/components/Pagination.d.ts +21 -0
  91. package/dist/components/Pagination.d.ts.map +1 -0
  92. package/dist/components/Pagination.js +87 -0
  93. package/dist/components/Popover.d.ts +16 -0
  94. package/dist/components/Popover.d.ts.map +1 -0
  95. package/dist/components/Popover.js +159 -0
  96. package/dist/components/Progress.d.ts +23 -0
  97. package/dist/components/Progress.d.ts.map +1 -0
  98. package/dist/components/Progress.js +51 -0
  99. package/dist/components/Radio.d.ts +12 -0
  100. package/dist/components/Radio.d.ts.map +1 -0
  101. package/dist/components/Radio.js +29 -0
  102. package/dist/components/ScrollArea.d.ts +16 -0
  103. package/dist/components/ScrollArea.d.ts.map +1 -0
  104. package/dist/components/ScrollArea.js +42 -0
  105. package/dist/components/ScrollIndicator.d.ts +17 -0
  106. package/dist/components/ScrollIndicator.d.ts.map +1 -0
  107. package/dist/components/ScrollIndicator.js +60 -0
  108. package/dist/components/ScrollProgress.d.ts +12 -0
  109. package/dist/components/ScrollProgress.d.ts.map +1 -0
  110. package/dist/components/ScrollProgress.js +39 -0
  111. package/dist/components/ScrollToTop.d.ts +15 -0
  112. package/dist/components/ScrollToTop.d.ts.map +1 -0
  113. package/dist/components/ScrollToTop.js +46 -0
  114. package/dist/components/Select.d.ts +17 -0
  115. package/dist/components/Select.d.ts.map +1 -0
  116. package/dist/components/Select.js +29 -0
  117. package/dist/components/Skeleton.d.ts +19 -0
  118. package/dist/components/Skeleton.d.ts.map +1 -0
  119. package/dist/components/Skeleton.js +71 -0
  120. package/dist/components/Stack.d.ts +11 -0
  121. package/dist/components/Stack.d.ts.map +1 -0
  122. package/dist/components/Stack.js +34 -0
  123. package/dist/components/Switch.d.ts +12 -0
  124. package/dist/components/Switch.d.ts.map +1 -0
  125. package/dist/components/Switch.js +29 -0
  126. package/dist/components/Tabs.d.ts +36 -0
  127. package/dist/components/Tabs.d.ts.map +1 -0
  128. package/dist/components/Tabs.js +117 -0
  129. package/dist/components/Textarea.d.ts +11 -0
  130. package/dist/components/Textarea.d.ts.map +1 -0
  131. package/dist/components/Textarea.js +31 -0
  132. package/dist/components/ThemeProvider.d.ts +19 -0
  133. package/dist/components/ThemeProvider.d.ts.map +1 -0
  134. package/dist/components/ThemeProvider.js +76 -0
  135. package/dist/components/ThemeToggle.d.ts +14 -0
  136. package/dist/components/ThemeToggle.d.ts.map +1 -0
  137. package/dist/components/ThemeToggle.js +49 -0
  138. package/dist/components/Toast.d.ts +32 -0
  139. package/dist/components/Toast.d.ts.map +1 -0
  140. package/dist/components/Toast.js +138 -0
  141. package/dist/components/Tooltip.d.ts +14 -0
  142. package/dist/components/Tooltip.d.ts.map +1 -0
  143. package/dist/components/Tooltip.js +102 -0
  144. package/dist/index.d.ts +50 -0
  145. package/dist/index.d.ts.map +1 -0
  146. package/dist/index.js +49 -0
  147. package/dist/lib/icons.d.ts +43 -0
  148. package/dist/lib/icons.d.ts.map +1 -0
  149. package/dist/lib/icons.js +321 -0
  150. package/dist/lib/utils.d.ts +3 -0
  151. package/dist/lib/utils.d.ts.map +1 -0
  152. package/dist/lib/utils.js +5 -0
  153. package/package.json +67 -0
@@ -0,0 +1,174 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const Dropdown = React.forwardRef(({ className, trigger, children, open: controlledOpen, onOpenChange, placement = "bottom", align = "start", offset = 8, disabled = false, showArrow = true, ...props }, ref) => {
6
+ const [internalOpen, setInternalOpen] = React.useState(false);
7
+ const [coords, setCoords] = React.useState({ x: 0, y: 0 });
8
+ const triggerRef = React.useRef(null);
9
+ const dropdownRef = React.useRef(null);
10
+ const isControlled = controlledOpen !== undefined;
11
+ const isOpen = isControlled ? controlledOpen : internalOpen;
12
+ const handleOpenChange = (newOpen) => {
13
+ if (disabled)
14
+ return;
15
+ if (!isControlled) {
16
+ setInternalOpen(newOpen);
17
+ }
18
+ onOpenChange?.(newOpen);
19
+ };
20
+ const handleTriggerClick = () => {
21
+ handleOpenChange(!isOpen);
22
+ };
23
+ const updatePosition = React.useCallback(() => {
24
+ if (!triggerRef.current || !dropdownRef.current)
25
+ return;
26
+ const triggerRect = triggerRef.current.getBoundingClientRect();
27
+ const dropdownRect = dropdownRef.current.getBoundingClientRect();
28
+ const viewportWidth = window.innerWidth;
29
+ const viewportHeight = window.innerHeight;
30
+ let x = 0;
31
+ let y = 0;
32
+ // 기본 위치 계산
33
+ switch (placement) {
34
+ case "top":
35
+ x = triggerRect.left;
36
+ y = triggerRect.top - offset;
37
+ break;
38
+ case "bottom":
39
+ x = triggerRect.left;
40
+ y = triggerRect.bottom + offset;
41
+ break;
42
+ case "left":
43
+ x = triggerRect.left - offset;
44
+ y = triggerRect.top;
45
+ break;
46
+ case "right":
47
+ x = triggerRect.right + offset;
48
+ y = triggerRect.top;
49
+ break;
50
+ }
51
+ // 정렬 조정
52
+ switch (align) {
53
+ case "center":
54
+ if (placement === "top" || placement === "bottom") {
55
+ x = triggerRect.left + triggerRect.width / 2 - dropdownRect.width / 2;
56
+ }
57
+ else {
58
+ y = triggerRect.top + triggerRect.height / 2 - dropdownRect.height / 2;
59
+ }
60
+ break;
61
+ case "end":
62
+ if (placement === "top" || placement === "bottom") {
63
+ x = triggerRect.right - dropdownRect.width;
64
+ }
65
+ else {
66
+ y = triggerRect.bottom - dropdownRect.height;
67
+ }
68
+ break;
69
+ case "start":
70
+ default:
71
+ // 기본값은 이미 start 정렬
72
+ break;
73
+ }
74
+ // 뷰포트 경계 확인 및 조정
75
+ if (x < 8)
76
+ x = 8; // 8px 여백
77
+ if (x + dropdownRect.width > viewportWidth - 8) {
78
+ x = viewportWidth - dropdownRect.width - 8; // 8px 여백
79
+ }
80
+ if (y < 8)
81
+ y = 8; // 8px 여백
82
+ if (y + dropdownRect.height > viewportHeight - 8) {
83
+ y = viewportHeight - dropdownRect.height - 8; // 8px 여백
84
+ }
85
+ setCoords({ x, y });
86
+ }, [placement, align, offset]);
87
+ React.useEffect(() => {
88
+ if (isOpen) {
89
+ updatePosition();
90
+ window.addEventListener('resize', updatePosition);
91
+ window.addEventListener('scroll', updatePosition);
92
+ return () => {
93
+ window.removeEventListener('resize', updatePosition);
94
+ window.removeEventListener('scroll', updatePosition);
95
+ };
96
+ }
97
+ }, [isOpen, updatePosition]);
98
+ React.useEffect(() => {
99
+ const handleClickOutside = (event) => {
100
+ if (triggerRef.current &&
101
+ dropdownRef.current &&
102
+ !triggerRef.current.contains(event.target) &&
103
+ !dropdownRef.current.contains(event.target)) {
104
+ handleOpenChange(false);
105
+ }
106
+ };
107
+ if (isOpen) {
108
+ document.addEventListener('mousedown', handleClickOutside);
109
+ return () => {
110
+ document.removeEventListener('mousedown', handleClickOutside);
111
+ };
112
+ }
113
+ }, [isOpen]);
114
+ const getPlacementClasses = () => {
115
+ switch (placement) {
116
+ case "top":
117
+ return "bottom-full left-0 mb-2"; // 8px 간격
118
+ case "bottom":
119
+ return "top-full left-0 mt-2"; // 8px 간격
120
+ case "left":
121
+ return "right-full top-0 mr-2"; // 8px 간격
122
+ case "right":
123
+ return "left-full top-0 ml-2"; // 8px 간격
124
+ default:
125
+ return "top-full left-0 mt-2";
126
+ }
127
+ };
128
+ const getArrowClasses = () => {
129
+ switch (placement) {
130
+ case "top":
131
+ return "top-full left-4 -translate-x-1/2 border-t-gray-100 dark:border-t-gray-800";
132
+ case "bottom":
133
+ return "bottom-full left-4 -translate-x-1/2 border-b-gray-100 dark:border-b-gray-800";
134
+ case "left":
135
+ return "left-full top-4 -translate-y-1/2 border-l-gray-100 dark:border-l-gray-800";
136
+ case "right":
137
+ return "right-full top-4 -translate-y-1/2 border-r-gray-100 dark:border-r-gray-800";
138
+ default:
139
+ return "bottom-full left-4 -translate-x-1/2 border-b-gray-100 dark:border-b-gray-800";
140
+ }
141
+ };
142
+ return (_jsxs("div", { ref: ref, className: cn("relative", className), ...props, children: [_jsx("div", { ref: triggerRef, onClick: handleTriggerClick, className: "inline-block cursor-pointer", children: trigger }), isOpen && (_jsxs("div", { ref: dropdownRef, className: cn("absolute z-50 bg-white dark:bg-gray-800 rounded-lg shadow-xl backdrop-blur-sm", // 보더 대신 섀도우 사용
143
+ "min-w-[200px] py-2", // 16px 패딩
144
+ getPlacementClasses()), style: {
145
+ transform: `translate(${coords.x}px, ${coords.y}px)`,
146
+ boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
147
+ }, children: [showArrow && (_jsx("div", { className: cn("absolute w-0 h-0 border-4 border-transparent", getArrowClasses()) })), _jsx("div", { className: "relative z-10", children: children })] }))] }));
148
+ });
149
+ Dropdown.displayName = "Dropdown";
150
+ const DropdownItem = React.forwardRef(({ className, icon, variant = "default", children, disabled, ...props }, ref) => {
151
+ const getVariantClasses = () => {
152
+ switch (variant) {
153
+ case "destructive":
154
+ return "text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20";
155
+ case "disabled":
156
+ return "text-gray-400 dark:text-gray-500 cursor-not-allowed";
157
+ default:
158
+ return "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700";
159
+ }
160
+ };
161
+ return (_jsxs("button", { ref: ref, className: cn("w-full flex items-center gap-3 px-4 py-3 text-sm font-medium transition-colors focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700", // 16px, 12px 패딩
162
+ getVariantClasses(), className), disabled: disabled || variant === "disabled", ...props, children: [icon && (_jsx("div", { className: "flex-shrink-0 w-4 h-4", children: icon })), _jsx("span", { className: "flex-1 text-left", children: children })] }));
163
+ });
164
+ DropdownItem.displayName = "DropdownItem";
165
+ const DropdownSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("h-px bg-gray-200 dark:bg-gray-700 my-2", className), ...props })));
166
+ DropdownSeparator.displayName = "DropdownSeparator";
167
+ const DropdownLabel = React.forwardRef(({ className, children, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("px-4 py-2 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wide", className), ...props, children: children })));
168
+ DropdownLabel.displayName = "DropdownLabel";
169
+ // 편의 컴포넌트들
170
+ const DropdownMenu = React.forwardRef(({ className, children, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("py-1", className), ...props, children: children })));
171
+ DropdownMenu.displayName = "DropdownMenu";
172
+ const DropdownGroup = React.forwardRef(({ className, children, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("space-y-1", className), ...props, children: children })));
173
+ DropdownGroup.displayName = "DropdownGroup";
174
+ export { Dropdown, DropdownItem, DropdownSeparator, DropdownLabel, DropdownMenu, DropdownGroup };
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+ interface EmotionAnalysisProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ primaryEmotion?: {
4
+ name: string;
5
+ intensity: number;
6
+ color?: string;
7
+ };
8
+ emotionDistribution?: Array<{
9
+ emotion: string;
10
+ percentage: number;
11
+ color: string;
12
+ }>;
13
+ keywords?: string[];
14
+ intensity?: number;
15
+ positivity?: number;
16
+ energy?: number;
17
+ showMeter?: boolean;
18
+ showDistribution?: boolean;
19
+ showKeywords?: boolean;
20
+ showMetrics?: boolean;
21
+ layout?: "compact" | "detailed" | "card";
22
+ }
23
+ declare const EmotionAnalysis: React.ForwardRefExoticComponent<EmotionAnalysisProps & React.RefAttributes<HTMLDivElement>>;
24
+ export { EmotionAnalysis };
25
+ //# sourceMappingURL=EmotionAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmotionAnalysis.d.ts","sourceRoot":"","sources":["../../src/components/EmotionAnalysis.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,UAAU,oBAAqB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,MAAM,CAAA;QACZ,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD,mBAAmB,CAAC,EAAE,KAAK,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;IACF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAA;CACzC;AAED,QAAA,MAAM,eAAe,6FAgSpB,CAAA;AAID,OAAO,EAAE,eAAe,EAAE,CAAA"}
@@ -0,0 +1,40 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./Card";
6
+ import { Badge } from "./Badge";
7
+ import { EmotionMeter } from "./EmotionMeter";
8
+ const EmotionAnalysis = React.forwardRef(({ className, primaryEmotion, emotionDistribution = [], keywords = [], intensity = 50, positivity = 70, energy = 60, showMeter = true, showDistribution = true, showKeywords = true, showMetrics = true, layout = "detailed", ...props }, ref) => {
9
+ const getIntensityLabel = (value) => {
10
+ if (value < 30)
11
+ return "약함";
12
+ if (value < 70)
13
+ return "보통";
14
+ return "강함";
15
+ };
16
+ const getPositivityLabel = (value) => {
17
+ if (value < 30)
18
+ return "부정적";
19
+ if (value < 70)
20
+ return "중립적";
21
+ return "긍정적";
22
+ };
23
+ const getEnergyLabel = (value) => {
24
+ if (value < 30)
25
+ return "낮음";
26
+ if (value < 70)
27
+ return "보통";
28
+ return "높음";
29
+ };
30
+ if (layout === "compact") {
31
+ return (_jsxs("div", { ref: ref, className: cn("space-y-3", className), ...props, children: [primaryEmotion && (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium", children: "\uC8FC\uC694 \uAC10\uC815:" }), _jsxs("div", { className: "flex items-center space-x-2", children: [_jsxs("span", { className: "text-sm text-muted-foreground", children: [primaryEmotion.name, " (", primaryEmotion.intensity, "%)"] }), showMeter && (_jsx(EmotionMeter, { value: primaryEmotion.intensity, size: "sm", color: "blue" }))] })] })), showMetrics && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium", children: "\uAC10\uC815 \uAC15\uB3C4:" }), _jsx("span", { className: "text-sm text-muted-foreground", children: getIntensityLabel(intensity) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium", children: "\uAE0D\uC815\uC131:" }), _jsx("span", { className: "text-sm text-muted-foreground", children: getPositivityLabel(positivity) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium", children: "\uC5D0\uB108\uC9C0:" }), _jsx("span", { className: "text-sm text-muted-foreground", children: getEnergyLabel(energy) })] })] })), showKeywords && keywords.length > 0 && (_jsxs("div", { children: [_jsx("span", { className: "text-sm font-medium", children: "\uD0A4\uC6CC\uB4DC:" }), _jsx("div", { className: "flex flex-wrap gap-1 mt-1", children: keywords.map((keyword) => (_jsx(Badge, { variant: "secondary", className: "text-xs", children: keyword }, keyword))) })] }))] }));
32
+ }
33
+ if (layout === "card") {
34
+ return (_jsxs(Card, { ref: ref, className: cn("", className), ...props, children: [_jsxs(CardHeader, { children: [_jsxs(CardTitle, { className: "flex items-center", children: [_jsx("span", { className: "text-2xl mr-2", children: "\u2728" }), "AI \uBD84\uC11D"] }), _jsx(CardDescription, { children: "\uAC10\uC815 \uBD84\uC11D \uACB0\uACFC" })] }), _jsxs(CardContent, { className: "space-y-4", children: [primaryEmotion && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "\uC8FC\uC694 \uAC10\uC815:" }), _jsxs("span", { className: "ml-2 text-muted-foreground", children: [primaryEmotion.name, " (", primaryEmotion.intensity, "%)"] })] }), showMeter && (_jsx("div", { className: "flex justify-center", children: _jsx(EmotionMeter, { value: primaryEmotion.intensity, size: "md", color: "blue" }) }))] })), showMetrics && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "\uAC10\uC815 \uAC15\uB3C4:" }), _jsx("span", { className: "ml-2 text-muted-foreground", children: getIntensityLabel(intensity) })] }), _jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "\uAE0D\uC815\uC131:" }), _jsx("span", { className: "ml-2 text-muted-foreground", children: getPositivityLabel(positivity) })] }), _jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "\uC5D0\uB108\uC9C0:" }), _jsx("span", { className: "ml-2 text-muted-foreground", children: getEnergyLabel(energy) })] })] })), showKeywords && keywords.length > 0 && (_jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "\uD0A4\uC6CC\uB4DC:" }), _jsx("div", { className: "flex flex-wrap gap-1 mt-1", children: keywords.map((keyword) => (_jsx(Badge, { variant: "secondary", className: "text-xs", children: keyword }, keyword))) })] }))] })] }));
35
+ }
36
+ // detailed layout (default)
37
+ return (_jsxs("div", { ref: ref, className: cn("space-y-6", className), ...props, children: [primaryEmotion && (_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: "\uC8FC\uC694 \uAC10\uC815" }), _jsxs("div", { className: "flex items-center space-x-4", children: [_jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-2xl font-bold text-primary", children: primaryEmotion.name }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [primaryEmotion.intensity, "% \uAC15\uB3C4"] })] }), showMeter && (_jsx(EmotionMeter, { value: primaryEmotion.intensity, size: "lg", color: "blue" }))] })] })), showDistribution && emotionDistribution.length > 0 && (_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: "\uAC10\uC815 \uBD84\uD3EC" }), _jsx("div", { className: "space-y-3", children: emotionDistribution.map((item, index) => (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium", children: item.emotion }), _jsxs("span", { className: "text-sm text-muted-foreground", children: [item.percentage, "%"] })] }), _jsx("div", { className: "w-full bg-muted rounded-full h-2", children: _jsx("div", { className: `${item.color} h-2 rounded-full transition-all duration-300`, style: { width: `${item.percentage}%` } }) })] }, index))) })] })), showMetrics && (_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: "\uBD84\uC11D \uC9C0\uD45C" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium", children: "\uAC10\uC815 \uAC15\uB3C4" }), _jsx("div", { className: "text-2xl font-bold text-primary", children: getIntensityLabel(intensity) }), _jsx("div", { className: "w-full bg-muted rounded-full h-2", children: _jsx("div", { className: "bg-primary h-2 rounded-full transition-all duration-300", style: { width: `${intensity}%` } }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium", children: "\uAE0D\uC815\uC131" }), _jsx("div", { className: "text-2xl font-bold text-green-600", children: getPositivityLabel(positivity) }), _jsx("div", { className: "w-full bg-muted rounded-full h-2", children: _jsx("div", { className: "bg-green-500 h-2 rounded-full transition-all duration-300", style: { width: `${positivity}%` } }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-sm font-medium", children: "\uC5D0\uB108\uC9C0" }), _jsx("div", { className: "text-2xl font-bold text-orange-600", children: getEnergyLabel(energy) }), _jsx("div", { className: "w-full bg-muted rounded-full h-2", children: _jsx("div", { className: "bg-orange-500 h-2 rounded-full transition-all duration-300", style: { width: `${energy}%` } }) })] })] })] })), showKeywords && keywords.length > 0 && (_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: "\uAC10\uC815 \uD0A4\uC6CC\uB4DC" }), _jsx("div", { className: "flex flex-wrap gap-2", children: keywords.map((keyword) => (_jsx(Badge, { variant: "outline", className: "text-sm", children: keyword }, keyword))) })] }))] }));
38
+ });
39
+ EmotionAnalysis.displayName = "EmotionAnalysis";
40
+ export { EmotionAnalysis };
@@ -0,0 +1,9 @@
1
+ import * as React from "react";
2
+ export interface EmotionButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
3
+ emotion: string;
4
+ isSelected?: boolean;
5
+ size?: "sm" | "md" | "lg";
6
+ }
7
+ declare const EmotionButton: React.ForwardRefExoticComponent<EmotionButtonProps & React.RefAttributes<HTMLButtonElement>>;
8
+ export { EmotionButton };
9
+ //# sourceMappingURL=EmotionButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmotionButton.d.ts","sourceRoot":"","sources":["../../src/components/EmotionButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,kBAAmB,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACvF,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAC1B;AAED,QAAA,MAAM,aAAa,8FAyBlB,CAAA;AAGD,OAAO,EAAE,aAAa,EAAE,CAAA"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const EmotionButton = React.forwardRef(({ className, emotion, isSelected = false, size = "md", ...props }, ref) => {
6
+ const sizeClasses = {
7
+ sm: "w-8 h-8 text-sm",
8
+ md: "w-12 h-12 text-lg",
9
+ lg: "w-16 h-16 text-xl"
10
+ };
11
+ return (_jsx("button", { ref: ref, className: cn("rounded-full border-2 transition-all duration-200 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500", sizeClasses[size], isSelected
12
+ ? "border-blue-500 bg-blue-50 dark:bg-blue-900/20"
13
+ : "border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800", className), ...props, children: emotion }));
14
+ });
15
+ EmotionButton.displayName = "EmotionButton";
16
+ export { EmotionButton };
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ export interface EmotionMeterProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ value: number;
4
+ max?: number;
5
+ size?: "sm" | "md" | "lg";
6
+ color?: "blue" | "green" | "yellow" | "red";
7
+ }
8
+ declare const EmotionMeter: React.ForwardRefExoticComponent<EmotionMeterProps & React.RefAttributes<HTMLDivElement>>;
9
+ export { EmotionMeter };
10
+ //# sourceMappingURL=EmotionMeter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmotionMeter.d.ts","sourceRoot":"","sources":["../../src/components/EmotionMeter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC7E,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;CAC5C;AAED,QAAA,MAAM,YAAY,0FAqCjB,CAAA;AAGD,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const EmotionMeter = React.forwardRef(({ className, value, max = 100, size = "md", color = "blue", ...props }, ref) => {
6
+ const sizeClasses = {
7
+ sm: "h-2",
8
+ md: "h-3",
9
+ lg: "h-4"
10
+ };
11
+ const colorClasses = {
12
+ blue: "bg-blue-500",
13
+ green: "bg-green-500",
14
+ yellow: "bg-yellow-500",
15
+ red: "bg-red-500"
16
+ };
17
+ const percentage = Math.min(Math.max((value / max) * 100, 0), 100);
18
+ return (_jsx("div", { ref: ref, className: cn("w-full bg-gray-200 rounded-full dark:bg-gray-700", sizeClasses[size], className), ...props, children: _jsx("div", { className: cn("h-full rounded-full transition-all duration-300", colorClasses[color]), style: { width: `${percentage}%` } }) }));
19
+ });
20
+ EmotionMeter.displayName = "EmotionMeter";
21
+ export { EmotionMeter };
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ interface EmotionSelectorProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ selectedEmotion?: string;
4
+ onEmotionSelect?: (emotion: string) => void;
5
+ layout?: "grid" | "list" | "compact";
6
+ showIntensity?: boolean;
7
+ intensity?: number;
8
+ onIntensityChange?: (intensity: number) => void;
9
+ emotions?: Array<{
10
+ key: string;
11
+ label: string;
12
+ icon?: string;
13
+ color?: string;
14
+ }>;
15
+ size?: "sm" | "md" | "lg";
16
+ variant?: "button" | "card" | "chip";
17
+ }
18
+ declare const EmotionSelector: React.ForwardRefExoticComponent<EmotionSelectorProps & React.RefAttributes<HTMLDivElement>>;
19
+ export { EmotionSelector };
20
+ //# sourceMappingURL=EmotionSelector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmotionSelector.d.ts","sourceRoot":"","sources":["../../src/components/EmotionSelector.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,UAAU,oBAAqB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACpC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAC,CAAA;IACF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAA;CACrC;AAaD,QAAA,MAAM,eAAe,6FAgJpB,CAAA;AAID,OAAO,EAAE,eAAe,EAAE,CAAA"}
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { EmotionButton } from "./EmotionButton";
6
+ import { EmotionMeter } from "./EmotionMeter";
7
+ const defaultEmotions = [
8
+ { key: "joy", label: "기쁨", icon: "smile", color: "yellow" },
9
+ { key: "sadness", label: "슬픔", icon: "frown", color: "blue" },
10
+ { key: "anger", label: "화남", icon: "angry", color: "red" },
11
+ { key: "calm", label: "평온", icon: "heart", color: "green" },
12
+ { key: "excitement", label: "설렘", icon: "star", color: "pink" },
13
+ { key: "worry", label: "걱정", icon: "meh", color: "gray" },
14
+ { key: "gratitude", label: "감사", icon: "heart", color: "purple" },
15
+ { key: "loneliness", label: "외로움", icon: "user", color: "indigo" }
16
+ ];
17
+ const EmotionSelector = React.forwardRef(({ className, selectedEmotion, onEmotionSelect, layout = "grid", showIntensity = false, intensity = 50, onIntensityChange, emotions = defaultEmotions, size = "md", variant = "button", ...props }, ref) => {
18
+ const handleEmotionClick = (emotionKey) => {
19
+ onEmotionSelect?.(emotionKey);
20
+ };
21
+ const renderEmotionItem = (emotion) => {
22
+ const isSelected = selectedEmotion === emotion.key;
23
+ if (variant === "button") {
24
+ return (_jsx(EmotionButton, { emotion: emotion.key, isSelected: isSelected, size: size, onClick: () => handleEmotionClick(emotion.key), className: cn("transition-all duration-200", isSelected && "ring-2 ring-offset-2 ring-primary"), children: emotion.label }, emotion.key));
25
+ }
26
+ if (variant === "card") {
27
+ return (_jsx("div", { className: cn("p-4 rounded-lg border-2 cursor-pointer transition-all duration-200 hover:shadow-md", isSelected
28
+ ? "border-primary bg-primary/5"
29
+ : "border-border hover:border-primary/50"), onClick: () => handleEmotionClick(emotion.key), children: _jsxs("div", { className: "flex items-center space-x-3", children: [_jsx("div", { className: cn("w-8 h-8 rounded-full flex items-center justify-center", isSelected ? "bg-primary text-primary-foreground" : "bg-muted"), children: emotion.icon && (_jsxs("span", { className: "text-lg", children: [emotion.icon === "smile" && "😊", emotion.icon === "frown" && "😢", emotion.icon === "angry" && "😠", emotion.icon === "heart" && "❤️", emotion.icon === "star" && "⭐", emotion.icon === "meh" && "😐", emotion.icon === "user" && "👤"] })) }), _jsx("span", { className: "font-medium", children: emotion.label })] }) }, emotion.key));
30
+ }
31
+ if (variant === "chip") {
32
+ return (_jsx("div", { className: cn("px-3 py-1 rounded-full cursor-pointer transition-all duration-200 text-sm font-medium", isSelected
33
+ ? "bg-primary text-primary-foreground"
34
+ : "bg-muted hover:bg-muted/80"), onClick: () => handleEmotionClick(emotion.key), children: emotion.label }, emotion.key));
35
+ }
36
+ return null;
37
+ };
38
+ const layoutClasses = {
39
+ grid: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2 md:gap-3",
40
+ list: "space-y-2",
41
+ compact: "flex flex-wrap gap-1"
42
+ };
43
+ return (_jsxs("div", { ref: ref, className: cn("space-y-4", className), ...props, children: [_jsx("div", { className: layoutClasses[layout], children: emotions.map(renderEmotionItem) }), showIntensity && selectedEmotion && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-medium", children: "\uAC10\uC815 \uAC15\uB3C4" }), _jsxs("span", { className: "text-sm text-muted-foreground", children: [intensity, "%"] })] }), _jsx("input", { type: "range", min: "0", max: "100", value: intensity, onChange: (e) => onIntensityChange?.(Number(e.target.value)), className: "w-full h-2 bg-muted rounded-lg appearance-none cursor-pointer slider" }), _jsxs("div", { className: "flex justify-between text-xs text-muted-foreground", children: [_jsx("span", { children: "\uC57D\uD568" }), _jsx("span", { children: "\uBCF4\uD1B5" }), _jsx("span", { children: "\uAC15\uD568" })] })] })), selectedEmotion && showIntensity && (_jsx("div", { className: "flex justify-center", children: _jsx(EmotionMeter, { value: intensity, size: "md", color: "blue" }) }))] }));
44
+ });
45
+ EmotionSelector.displayName = "EmotionSelector";
46
+ export { EmotionSelector };
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+ export interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ cols?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
4
+ gap?: "none" | "sm" | "md" | "lg" | "xl";
5
+ gapX?: "none" | "sm" | "md" | "lg" | "xl";
6
+ gapY?: "none" | "sm" | "md" | "lg" | "xl";
7
+ responsive?: boolean;
8
+ }
9
+ declare const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<HTMLDivElement>>;
10
+ export { Grid };
11
+ //# sourceMappingURL=Grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Grid.d.ts","sourceRoot":"","sources":["../../src/components/Grid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACrE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IACvD,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACxC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzC,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,QAAA,MAAM,IAAI,kFA+DT,CAAA;AAGD,OAAO,EAAE,IAAI,EAAE,CAAA"}
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const Grid = React.forwardRef(({ className, cols = 1, gap = "md", gapX, gapY, responsive = true, ...props }, ref) => {
6
+ const colsClasses = {
7
+ 1: "grid-cols-1",
8
+ 2: "grid-cols-1 sm:grid-cols-2",
9
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
10
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",
11
+ 5: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-5",
12
+ 6: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-6",
13
+ 7: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-7",
14
+ 8: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-8",
15
+ 9: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-9",
16
+ 10: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-10",
17
+ 11: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-11",
18
+ 12: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-12"
19
+ };
20
+ const gapClasses = {
21
+ none: "gap-0",
22
+ sm: "gap-4", // 16px
23
+ md: "gap-6", // 24px
24
+ lg: "gap-8", // 32px
25
+ xl: "gap-12" // 48px
26
+ };
27
+ const gapXClasses = {
28
+ none: "gap-x-0",
29
+ sm: "gap-x-4", // 16px
30
+ md: "gap-x-6", // 24px
31
+ lg: "gap-x-8", // 32px
32
+ xl: "gap-x-12" // 48px
33
+ };
34
+ const gapYClasses = {
35
+ none: "gap-y-0",
36
+ sm: "gap-y-4", // 16px
37
+ md: "gap-y-6", // 24px
38
+ lg: "gap-y-8", // 32px
39
+ xl: "gap-y-12" // 48px
40
+ };
41
+ return (_jsx("div", { ref: ref, className: cn("grid", responsive ? colsClasses[cols] : `grid-cols-${cols}`, gapX ? gapXClasses[gapX] : gapClasses[gap], gapY && gapYClasses[gapY], className), ...props }));
42
+ });
43
+ Grid.displayName = "Grid";
44
+ export { Grid };
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { LucideProps } from 'lucide-react';
3
+ import { IconName, emotionIcons, statusIcons } from '../lib/icons';
4
+ export interface IconProps extends Omit<LucideProps, 'size'> {
5
+ name: IconName;
6
+ size?: number | string;
7
+ className?: string;
8
+ emotion?: keyof typeof emotionIcons;
9
+ status?: keyof typeof statusIcons;
10
+ animated?: boolean;
11
+ pulse?: boolean;
12
+ spin?: boolean;
13
+ bounce?: boolean;
14
+ variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'muted';
15
+ }
16
+ export declare const Icon: React.ForwardRefExoticComponent<Omit<IconProps, "ref"> & React.RefAttributes<SVGSVGElement>>;
17
+ export declare const EmotionIcon: React.ForwardRefExoticComponent<Omit<Omit<IconProps, "name"> & {
18
+ emotion: keyof typeof emotionIcons;
19
+ }, "ref"> & React.RefAttributes<SVGSVGElement>>;
20
+ export declare const StatusIcon: React.ForwardRefExoticComponent<Omit<Omit<IconProps, "name"> & {
21
+ status: keyof typeof statusIcons;
22
+ }, "ref"> & React.RefAttributes<SVGSVGElement>>;
23
+ export declare const LoadingIcon: React.ForwardRefExoticComponent<Omit<Omit<IconProps, "name" | "status">, "ref"> & React.RefAttributes<SVGSVGElement>>;
24
+ export declare const SuccessIcon: React.ForwardRefExoticComponent<Omit<Omit<IconProps, "name" | "status">, "ref"> & React.RefAttributes<SVGSVGElement>>;
25
+ export declare const ErrorIcon: React.ForwardRefExoticComponent<Omit<Omit<IconProps, "name" | "status">, "ref"> & React.RefAttributes<SVGSVGElement>>;
26
+ //# sourceMappingURL=Icon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../src/components/Icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,EAAS,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAEzE,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;IAC1D,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB,OAAO,CAAC,EAAE,MAAM,OAAO,YAAY,CAAA;IACnC,MAAM,CAAC,EAAE,MAAM,OAAO,WAAW,CAAA;IAEjC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;CAC1F;AAED,eAAO,MAAM,IAAI,8FAyDf,CAAA;AAKF,eAAO,MAAM,WAAW;aAAwE,MAAM,OAAO,YAAY;+CAIxH,CAAA;AAID,eAAO,MAAM,UAAU;YAAuE,MAAM,OAAO,WAAW;+CAIrH,CAAA;AAKD,eAAO,MAAM,WAAW,uHAIvB,CAAA;AAKD,eAAO,MAAM,WAAW,uHAIvB,CAAA;AAKD,eAAO,MAAM,SAAS,uHAIrB,CAAA"}
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { cn } from '../lib/utils';
4
+ import { icons, emotionIcons, statusIcons } from '../lib/icons';
5
+ export const Icon = React.forwardRef(({ name, size = 24, className, emotion, status, animated = false, pulse = false, spin = false, bounce = false, variant = 'default', ...props }, ref) => {
6
+ // 감정이나 상태가 지정되면 해당 아이콘으로 오버라이드
7
+ const iconName = emotion ? emotionIcons[emotion] :
8
+ status ? statusIcons[status] :
9
+ name;
10
+ const IconComponent = icons[iconName];
11
+ if (!IconComponent) {
12
+ console.warn(`Icon "${iconName}" not found`);
13
+ return null;
14
+ }
15
+ // 애니메이션 클래스 생성
16
+ const animationClasses = cn({
17
+ 'animate-pulse': pulse,
18
+ 'animate-spin': spin,
19
+ 'animate-bounce': bounce,
20
+ 'transition-all duration-200 ease-in-out': animated,
21
+ });
22
+ // 색상 변형 클래스
23
+ const variantClasses = cn({
24
+ 'text-gray-900 dark:text-white': variant === 'default',
25
+ 'text-blue-600 dark:text-blue-400': variant === 'primary',
26
+ 'text-gray-600 dark:text-gray-400': variant === 'secondary',
27
+ 'text-green-600 dark:text-green-400': variant === 'success',
28
+ 'text-yellow-600 dark:text-yellow-400': variant === 'warning',
29
+ 'text-red-600 dark:text-red-400': variant === 'error',
30
+ 'text-gray-500 dark:text-gray-500': variant === 'muted',
31
+ });
32
+ return (_jsx(IconComponent, { ref: ref, size: size, className: cn('inline-block', animationClasses, variantClasses, className), ...props }));
33
+ });
34
+ Icon.displayName = 'Icon';
35
+ // 편의를 위한 특화된 아이콘 컴포넌트들
36
+ export const EmotionIcon = React.forwardRef(({ emotion, ...props }, ref) => (_jsx(Icon, { ref: ref, name: "smile", emotion: emotion, ...props })));
37
+ EmotionIcon.displayName = 'EmotionIcon';
38
+ export const StatusIcon = React.forwardRef(({ status, ...props }, ref) => (_jsx(Icon, { ref: ref, name: "info", status: status, ...props })));
39
+ StatusIcon.displayName = 'StatusIcon';
40
+ // 로딩 상태 전용 아이콘
41
+ export const LoadingIcon = React.forwardRef((props, ref) => (_jsx(Icon, { ref: ref, name: "loader", status: "loading", spin: true, ...props })));
42
+ LoadingIcon.displayName = 'LoadingIcon';
43
+ // 성공 상태 전용 아이콘
44
+ export const SuccessIcon = React.forwardRef((props, ref) => (_jsx(Icon, { ref: ref, name: "check", status: "success", variant: "success", ...props })));
45
+ SuccessIcon.displayName = 'SuccessIcon';
46
+ // 에러 상태 전용 아이콘
47
+ export const ErrorIcon = React.forwardRef((props, ref) => (_jsx(Icon, { ref: ref, name: "alert", status: "error", variant: "error", ...props })));
48
+ ErrorIcon.displayName = 'ErrorIcon';
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
3
+ variant?: "default" | "outline" | "filled" | "ghost";
4
+ size?: "sm" | "md" | "lg";
5
+ error?: boolean;
6
+ success?: boolean;
7
+ leftIcon?: React.ReactNode;
8
+ rightIcon?: React.ReactNode;
9
+ }
10
+ declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
11
+ export { Input };
12
+ //# sourceMappingURL=Input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC3F,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;IACpD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC5B;AAED,QAAA,MAAM,KAAK,qFA4DV,CAAA;AAGD,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const Input = React.forwardRef(({ className, type, variant = "default", size = "md", error = false, success = false, leftIcon, rightIcon, ...props }, ref) => {
6
+ const variantClasses = {
7
+ default: "border-gray-300 bg-white text-gray-900 placeholder-gray-500 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-400 dark:focus:ring-blue-400",
8
+ outline: "border-2 border-gray-200 bg-transparent text-gray-900 placeholder-gray-500 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-400 dark:focus:ring-blue-400",
9
+ filled: "border-transparent bg-gray-50 text-gray-900 placeholder-gray-500 focus:bg-white focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:bg-gray-800 dark:focus:border-blue-400 dark:focus:ring-blue-400",
10
+ ghost: "border-transparent bg-transparent text-gray-900 placeholder-gray-500 focus:bg-gray-50 focus:border-gray-300 focus:ring-gray-500 dark:text-white dark:placeholder-gray-400 dark:focus:bg-gray-800 dark:focus:border-gray-600 dark:focus:ring-gray-400"
11
+ };
12
+ const sizeClasses = {
13
+ sm: "h-8 px-3 text-sm",
14
+ md: "h-10 px-4 text-base",
15
+ lg: "h-12 px-4 text-lg"
16
+ };
17
+ const stateClasses = error
18
+ ? "border-red-500 focus:border-red-500 focus:ring-red-500 dark:border-red-400 dark:focus:border-red-400 dark:focus:ring-red-400"
19
+ : success
20
+ ? "border-green-500 focus:border-green-500 focus:ring-green-500 dark:border-green-400 dark:focus:border-green-400 dark:focus:ring-green-400"
21
+ : "";
22
+ return (_jsxs("div", { className: "relative", children: [leftIcon && (_jsx("div", { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: leftIcon })), _jsx("input", { type: type, className: cn("flex w-full rounded-md border transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", variantClasses[variant], sizeClasses[size], stateClasses, leftIcon ? "pl-10" : "", rightIcon ? "pr-10" : "", className), ref: ref, ...props }), rightIcon && (_jsx("div", { className: "absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 dark:text-gray-500", children: rightIcon }))] }));
23
+ });
24
+ Input.displayName = "Input";
25
+ export { Input };
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ export interface LanguageToggleProps {
3
+ className?: string;
4
+ size?: "sm" | "md" | "lg";
5
+ variant?: "button" | "icon" | "dropdown";
6
+ showLabel?: boolean;
7
+ languages?: Array<{
8
+ code: string;
9
+ name: string;
10
+ flag?: string;
11
+ }>;
12
+ currentLanguage?: string;
13
+ onLanguageChange?: (language: string) => void;
14
+ }
15
+ declare const LanguageToggle: React.ForwardRefExoticComponent<LanguageToggleProps & React.RefAttributes<HTMLDivElement>>;
16
+ export { LanguageToggle };
17
+ //# sourceMappingURL=LanguageToggle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LanguageToggle.d.ts","sourceRoot":"","sources":["../../src/components/LanguageToggle.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAA;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;IACF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAC9C;AAED,QAAA,MAAM,cAAc,4FAmKnB,CAAA;AAGD,OAAO,EAAE,cAAc,EAAE,CAAA"}