@droppii-org/chat-sdk 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +11 -4
- package/dist/components/AutoScrollAnchor.d.ts +0 -2
- package/dist/components/AutoScrollAnchor.d.ts.map +0 -1
- package/dist/components/AutoScrollAnchor.js +0 -12
- package/dist/components/AutoScrollAnchor.jsx +0 -11
- package/dist/components/ChatBubble.d.ts +0 -2
- package/dist/components/ChatBubble.d.ts.map +0 -1
- package/dist/components/ChatBubble.js +0 -18
- package/dist/components/ChatBubble.jsx +0 -80
- package/dist/components/ChatHeader.d.ts +0 -8
- package/dist/components/ChatHeader.d.ts.map +0 -1
- package/dist/components/ChatHeader.js +0 -32
- package/dist/components/ChatHeader.jsx +0 -72
- package/dist/components/ChatInput.d.ts +0 -3
- package/dist/components/ChatInput.d.ts.map +0 -1
- package/dist/components/ChatInput.js +0 -379
- package/dist/components/ChatInput.jsx +0 -444
- package/dist/components/ChatInputDemo.d.ts +0 -2
- package/dist/components/ChatInputDemo.d.ts.map +0 -1
- package/dist/components/ChatInputDemo.js +0 -38
- package/dist/components/ChatInputDemo.jsx +0 -53
- package/dist/components/ChatInputWithCustomIcon.d.ts +0 -16
- package/dist/components/ChatInputWithCustomIcon.d.ts.map +0 -1
- package/dist/components/ChatInputWithCustomIcon.js +0 -85
- package/dist/components/ChatInputWithCustomIcon.jsx +0 -167
- package/dist/components/ChatLayout.d.ts +0 -6
- package/dist/components/ChatLayout.d.ts.map +0 -1
- package/dist/components/ChatLayout.js +0 -48
- package/dist/components/ChatLayout.jsx +0 -122
- package/dist/components/ConversationItem.d.ts +0 -9
- package/dist/components/ConversationItem.d.ts.map +0 -1
- package/dist/components/ConversationItem.js +0 -27
- package/dist/components/ConversationItem.jsx +0 -51
- package/dist/components/ConversationList.d.ts +0 -8
- package/dist/components/ConversationList.d.ts.map +0 -1
- package/dist/components/ConversationList.js +0 -11
- package/dist/components/ConversationList.jsx +0 -22
- package/dist/components/DateDivider.d.ts +0 -7
- package/dist/components/DateDivider.d.ts.map +0 -1
- package/dist/components/DateDivider.js +0 -27
- package/dist/components/DateDivider.jsx +0 -28
- package/dist/components/EmojiPicker.d.ts +0 -4
- package/dist/components/EmojiPicker.d.ts.map +0 -1
- package/dist/components/EmojiPicker.js +0 -191
- package/dist/components/EmojiPicker.jsx +0 -229
- package/dist/components/ImageLightbox.d.ts +0 -8
- package/dist/components/ImageLightbox.d.ts.map +0 -1
- package/dist/components/ImageLightbox.js +0 -8
- package/dist/components/ImageLightbox.jsx +0 -16
- package/dist/components/ImagePreviewModal.d.ts +0 -12
- package/dist/components/ImagePreviewModal.d.ts.map +0 -1
- package/dist/components/ImagePreviewModal.js +0 -55
- package/dist/components/ImagePreviewModal.jsx +0 -84
- package/dist/components/MessageItem.d.ts +0 -3
- package/dist/components/MessageItem.d.ts.map +0 -1
- package/dist/components/MessageItem.js +0 -38
- package/dist/components/MessageItem.jsx +0 -99
- package/dist/components/MessageItemDemo.d.ts +0 -2
- package/dist/components/MessageItemDemo.d.ts.map +0 -1
- package/dist/components/MessageItemDemo.js +0 -166
- package/dist/components/MessageItemDemo.jsx +0 -179
- package/dist/components/MessageList.d.ts +0 -15
- package/dist/components/MessageList.d.ts.map +0 -1
- package/dist/components/MessageList.js +0 -243
- package/dist/components/MessageList.jsx +0 -306
- package/dist/components/MessageListDemo.d.ts +0 -2
- package/dist/components/MessageListDemo.d.ts.map +0 -1
- package/dist/components/MessageListDemo.js +0 -165
- package/dist/components/MessageListDemo.jsx +0 -183
- package/dist/components/StickerPicker.d.ts +0 -4
- package/dist/components/StickerPicker.d.ts.map +0 -1
- package/dist/components/StickerPicker.js +0 -68
- package/dist/components/StickerPicker.jsx +0 -106
- package/dist/components/SwipeIndicator.d.ts +0 -9
- package/dist/components/SwipeIndicator.d.ts.map +0 -1
- package/dist/components/SwipeIndicator.js +0 -24
- package/dist/components/SwipeIndicator.jsx +0 -28
- package/dist/components/TextFormattingToolbar.d.ts +0 -4
- package/dist/components/TextFormattingToolbar.d.ts.map +0 -1
- package/dist/components/TextFormattingToolbar.js +0 -29
- package/dist/components/TextFormattingToolbar.jsx +0 -52
- package/dist/components/TypingIndicator.d.ts +0 -6
- package/dist/components/TypingIndicator.d.ts.map +0 -1
- package/dist/components/TypingIndicator.js +0 -21
- package/dist/components/TypingIndicator.jsx +0 -27
- package/dist/components/VoiceWaveIcon.d.ts +0 -7
- package/dist/components/VoiceWaveIcon.d.ts.map +0 -1
- package/dist/components/VoiceWaveIcon.js +0 -5
- package/dist/components/VoiceWaveIcon.jsx +0 -11
- package/dist/context/ChatContext.d.ts +0 -72
- package/dist/context/ChatContext.d.ts.map +0 -1
- package/dist/context/ChatContext.js +0 -347
- package/dist/context/ChatContext.jsx +0 -346
- package/dist/hooks/useChat.d.ts +0 -5
- package/dist/hooks/useChat.d.ts.map +0 -1
- package/dist/hooks/useChat.js +0 -73
- package/dist/hooks/useConversationList.d.ts +0 -5
- package/dist/hooks/useConversationList.d.ts.map +0 -1
- package/dist/hooks/useConversationList.js +0 -9
- package/dist/hooks/useMessages.d.ts +0 -5
- package/dist/hooks/useMessages.d.ts.map +0 -1
- package/dist/hooks/useMessages.js +0 -192
- package/dist/hooks/useSocket.d.ts +0 -7
- package/dist/hooks/useSocket.d.ts.map +0 -1
- package/dist/hooks/useSocket.js +0 -120
- package/dist/hooks/useSwipeGesture.d.ts +0 -11
- package/dist/hooks/useSwipeGesture.d.ts.map +0 -1
- package/dist/hooks/useSwipeGesture.js +0 -54
- package/dist/hooks/useTextSelection.d.ts +0 -13
- package/dist/hooks/useTextSelection.d.ts.map +0 -1
- package/dist/hooks/useTextSelection.js +0 -132
- package/dist/hooks/useTyping.d.ts +0 -7
- package/dist/hooks/useTyping.d.ts.map +0 -1
- package/dist/hooks/useTyping.js +0 -64
- package/dist/index.d.ts +0 -28
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -29
- package/dist/types/chat.d.ts +0 -39
- package/dist/types/chat.d.ts.map +0 -1
- package/dist/types/chat.js +0 -1
- package/dist/types/index.d.ts +0 -86
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -1
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { X, Search, Clock, Smile, Heart, Hand, Car, Lightbulb, Coffee, Flag } from "lucide-react";
|
|
6
|
-
const emojiCategories = {
|
|
7
|
-
recent: {
|
|
8
|
-
label: "Thường xuyên sử dụng",
|
|
9
|
-
icon: Clock,
|
|
10
|
-
emojis: ["😊", "😂", "❤️", "👍", "😢", "😮", "😡", "🎉", "👏"],
|
|
11
|
-
},
|
|
12
|
-
smileys: {
|
|
13
|
-
label: "Mặt cười & con người",
|
|
14
|
-
icon: Smile,
|
|
15
|
-
emojis: [
|
|
16
|
-
"😀",
|
|
17
|
-
"😃",
|
|
18
|
-
"😄",
|
|
19
|
-
"😁",
|
|
20
|
-
"😆",
|
|
21
|
-
"😅",
|
|
22
|
-
"😂",
|
|
23
|
-
"🤣",
|
|
24
|
-
"😊",
|
|
25
|
-
"😇",
|
|
26
|
-
"🙂",
|
|
27
|
-
"🙃",
|
|
28
|
-
"😉",
|
|
29
|
-
"😌",
|
|
30
|
-
"😍",
|
|
31
|
-
"🥰",
|
|
32
|
-
"😘",
|
|
33
|
-
"😗",
|
|
34
|
-
"😙",
|
|
35
|
-
"😚",
|
|
36
|
-
"😋",
|
|
37
|
-
"😛",
|
|
38
|
-
"😝",
|
|
39
|
-
"😜",
|
|
40
|
-
"🤪",
|
|
41
|
-
"🤨",
|
|
42
|
-
"🧐",
|
|
43
|
-
"🤓",
|
|
44
|
-
"😎",
|
|
45
|
-
"🤩",
|
|
46
|
-
"🥳",
|
|
47
|
-
"😏",
|
|
48
|
-
"😒",
|
|
49
|
-
"😞",
|
|
50
|
-
"😔",
|
|
51
|
-
"😟",
|
|
52
|
-
"😕",
|
|
53
|
-
"🙁",
|
|
54
|
-
"☹️",
|
|
55
|
-
"😣",
|
|
56
|
-
"😖",
|
|
57
|
-
"😫",
|
|
58
|
-
"😩",
|
|
59
|
-
"🥺",
|
|
60
|
-
"😢",
|
|
61
|
-
"😭",
|
|
62
|
-
"😤",
|
|
63
|
-
"😠",
|
|
64
|
-
"😡",
|
|
65
|
-
"🤬",
|
|
66
|
-
"🤯",
|
|
67
|
-
"😳",
|
|
68
|
-
"🥵",
|
|
69
|
-
"🥶",
|
|
70
|
-
"😱",
|
|
71
|
-
"😨",
|
|
72
|
-
"😰",
|
|
73
|
-
"😥",
|
|
74
|
-
"😓",
|
|
75
|
-
"🤗",
|
|
76
|
-
"🤔",
|
|
77
|
-
"🤭",
|
|
78
|
-
"🤫",
|
|
79
|
-
"🤥",
|
|
80
|
-
"😶",
|
|
81
|
-
"😐",
|
|
82
|
-
"😑",
|
|
83
|
-
"😬",
|
|
84
|
-
"🙄",
|
|
85
|
-
"😯",
|
|
86
|
-
"😦",
|
|
87
|
-
"😧",
|
|
88
|
-
"😮",
|
|
89
|
-
"😲",
|
|
90
|
-
"🥱",
|
|
91
|
-
"😴",
|
|
92
|
-
"🤤",
|
|
93
|
-
"😪",
|
|
94
|
-
"😵",
|
|
95
|
-
"🤐",
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
gestures: {
|
|
99
|
-
label: "Cử chỉ",
|
|
100
|
-
icon: Hand,
|
|
101
|
-
emojis: [
|
|
102
|
-
"👍",
|
|
103
|
-
"👎",
|
|
104
|
-
"👌",
|
|
105
|
-
"✌️",
|
|
106
|
-
"🤞",
|
|
107
|
-
"🤟",
|
|
108
|
-
"🤘",
|
|
109
|
-
"🤙",
|
|
110
|
-
"👈",
|
|
111
|
-
"👉",
|
|
112
|
-
"👆",
|
|
113
|
-
"🖕",
|
|
114
|
-
"👇",
|
|
115
|
-
"☝️",
|
|
116
|
-
"👏",
|
|
117
|
-
"🙌",
|
|
118
|
-
"👐",
|
|
119
|
-
"🤲",
|
|
120
|
-
"🤝",
|
|
121
|
-
"🙏",
|
|
122
|
-
],
|
|
123
|
-
},
|
|
124
|
-
hearts: {
|
|
125
|
-
label: "Trái tim",
|
|
126
|
-
icon: Heart,
|
|
127
|
-
emojis: ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍", "🤎", "💔", "❣️", "💕", "💞", "💓", "💗", "💖", "💘", "💝"],
|
|
128
|
-
},
|
|
129
|
-
objects: {
|
|
130
|
-
label: "Đồ vật",
|
|
131
|
-
icon: Coffee,
|
|
132
|
-
emojis: ["📱", "💻", "⌨️", "🖥️", "🖨️", "📷", "📹", "🎥", "📞", "☎️", "📠", "📺", "📻", "🎵", "🎶", "🎤", "🎧", "📢"],
|
|
133
|
-
},
|
|
134
|
-
travel: {
|
|
135
|
-
label: "Du lịch",
|
|
136
|
-
icon: Car,
|
|
137
|
-
emojis: ["🚗", "🚕", "🚙", "🚌", "🚎", "🏎️", "🚓", "🚑", "🚒", "🚐", "🛻", "🚚", "🚛", "🚜", "🏍️", "🛵", "🚲", "🛴"],
|
|
138
|
-
},
|
|
139
|
-
activities: {
|
|
140
|
-
label: "Hoạt động",
|
|
141
|
-
icon: Lightbulb,
|
|
142
|
-
emojis: [
|
|
143
|
-
"⚽",
|
|
144
|
-
"🏀",
|
|
145
|
-
"🏈",
|
|
146
|
-
"⚾",
|
|
147
|
-
"🥎",
|
|
148
|
-
"🎾",
|
|
149
|
-
"🏐",
|
|
150
|
-
"🏉",
|
|
151
|
-
"🥏",
|
|
152
|
-
"🎱",
|
|
153
|
-
"🪀",
|
|
154
|
-
"🏓",
|
|
155
|
-
"🏸",
|
|
156
|
-
"🏒",
|
|
157
|
-
"🏑",
|
|
158
|
-
"🥍",
|
|
159
|
-
"🏏",
|
|
160
|
-
"🪃",
|
|
161
|
-
],
|
|
162
|
-
},
|
|
163
|
-
flags: {
|
|
164
|
-
label: "Cờ",
|
|
165
|
-
icon: Flag,
|
|
166
|
-
emojis: ["🏳️", "🏴", "🏁", "🚩", "🏳️🌈", "🏳️⚧️", "🇺🇳", "🇻🇳", "🇺🇸", "🇬🇧", "🇫🇷", "🇩🇪", "🇯🇵", "🇰🇷", "🇨🇳", "🇮🇳"],
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
export const EmojiPicker = React.forwardRef(({ onEmojiSelect, onClose, isOpen = false, style }, ref) => {
|
|
170
|
-
const [activeCategory, setActiveCategory] = useState("recent");
|
|
171
|
-
const [searchTerm, setSearchTerm] = useState("");
|
|
172
|
-
if (!isOpen)
|
|
173
|
-
return null;
|
|
174
|
-
const handleEmojiClick = (emoji) => {
|
|
175
|
-
onEmojiSelect === null || onEmojiSelect === void 0 ? void 0 : onEmojiSelect(emoji);
|
|
176
|
-
};
|
|
177
|
-
const filteredEmojis = searchTerm
|
|
178
|
-
? emojiCategories[activeCategory].emojis.filter((emoji) =>
|
|
179
|
-
// Simple search - in a real app you'd have emoji names/keywords
|
|
180
|
-
emoji.includes(searchTerm))
|
|
181
|
-
: emojiCategories[activeCategory].emojis;
|
|
182
|
-
return (_jsx("div", { ref: ref, className: "absolute bottom-full mb-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50 w-full sm:max-w-xs md:w-80", style: style, children: _jsxs("div", { className: "p-2", children: [_jsxs("div", { className: "flex items-center justify-between mb-2 pb-1 border-b border-gray-100", children: [Object.entries(emojiCategories).map(([key, category]) => {
|
|
183
|
-
const Icon = category.icon;
|
|
184
|
-
const isActive = activeCategory === key;
|
|
185
|
-
return (_jsx("button", { onClick: () => setActiveCategory(key), className: `
|
|
186
|
-
p-1.5 rounded-full transition-all duration-200 hover:bg-gray-100
|
|
187
|
-
${isActive ? "text-blue-500 bg-blue-50" : "text-gray-500"}
|
|
188
|
-
`, title: category.label, children: _jsx(Icon, { className: "w-4 h-4" }) }, key));
|
|
189
|
-
}), _jsx("button", { onClick: onClose, className: "p-1.5 text-gray-400 hover:text-gray-600 rounded-full hover:bg-gray-100", children: _jsx(X, { className: "w-4 h-4" }) })] }), _jsxs("div", { className: "relative mb-2", children: [_jsx(Search, { className: "absolute left-2 top-1/2 transform -translate-y-1/2 w-3 h-3 text-gray-400" }), _jsx("input", { type: "text", placeholder: "T\u00ECm ki\u1EBFm", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "w-full pl-7 pr-3 py-1.5 text-xs bg-gray-50 border border-gray-200 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-transparent" })] }), _jsx("div", { className: "mb-2", children: _jsx("h3", { className: "text-xs font-medium text-gray-900", children: emojiCategories[activeCategory].label }) }), _jsx("div", { className: "grid grid-cols-9 gap-0.5 max-h-48 overflow-y-auto", children: filteredEmojis.map((emoji, index) => (_jsx("button", { onClick: () => handleEmojiClick(emoji), className: "p-1.5 text-lg hover:bg-gray-100 rounded transition-all duration-200 hover:scale-110 active:scale-95", title: emoji, children: emoji }, index))) }), filteredEmojis.length === 0 && (_jsxs("div", { className: "text-center py-4 text-gray-500", children: [_jsx("div", { className: "text-lg mb-1", children: "\uD83D\uDD0D" }), _jsx("p", { className: "text-xs", children: "Kh\u00F4ng t\u00ECm th\u1EA5y emoji n\u00E0o" })] }))] }) }));
|
|
190
|
-
});
|
|
191
|
-
EmojiPicker.displayName = "EmojiPicker";
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { X, Search, Clock, Smile, Heart, Hand, Car, Lightbulb, Coffee, Flag } from "lucide-react";
|
|
5
|
-
const emojiCategories = {
|
|
6
|
-
recent: {
|
|
7
|
-
label: "Thường xuyên sử dụng",
|
|
8
|
-
icon: Clock,
|
|
9
|
-
emojis: ["😊", "😂", "❤️", "👍", "😢", "😮", "😡", "🎉", "👏"],
|
|
10
|
-
},
|
|
11
|
-
smileys: {
|
|
12
|
-
label: "Mặt cười & con người",
|
|
13
|
-
icon: Smile,
|
|
14
|
-
emojis: [
|
|
15
|
-
"😀",
|
|
16
|
-
"😃",
|
|
17
|
-
"😄",
|
|
18
|
-
"😁",
|
|
19
|
-
"😆",
|
|
20
|
-
"😅",
|
|
21
|
-
"😂",
|
|
22
|
-
"🤣",
|
|
23
|
-
"😊",
|
|
24
|
-
"😇",
|
|
25
|
-
"🙂",
|
|
26
|
-
"🙃",
|
|
27
|
-
"😉",
|
|
28
|
-
"😌",
|
|
29
|
-
"😍",
|
|
30
|
-
"🥰",
|
|
31
|
-
"😘",
|
|
32
|
-
"😗",
|
|
33
|
-
"😙",
|
|
34
|
-
"😚",
|
|
35
|
-
"😋",
|
|
36
|
-
"😛",
|
|
37
|
-
"😝",
|
|
38
|
-
"😜",
|
|
39
|
-
"🤪",
|
|
40
|
-
"🤨",
|
|
41
|
-
"🧐",
|
|
42
|
-
"🤓",
|
|
43
|
-
"😎",
|
|
44
|
-
"🤩",
|
|
45
|
-
"🥳",
|
|
46
|
-
"😏",
|
|
47
|
-
"😒",
|
|
48
|
-
"😞",
|
|
49
|
-
"😔",
|
|
50
|
-
"😟",
|
|
51
|
-
"😕",
|
|
52
|
-
"🙁",
|
|
53
|
-
"☹️",
|
|
54
|
-
"😣",
|
|
55
|
-
"😖",
|
|
56
|
-
"😫",
|
|
57
|
-
"😩",
|
|
58
|
-
"🥺",
|
|
59
|
-
"😢",
|
|
60
|
-
"😭",
|
|
61
|
-
"😤",
|
|
62
|
-
"😠",
|
|
63
|
-
"😡",
|
|
64
|
-
"🤬",
|
|
65
|
-
"🤯",
|
|
66
|
-
"😳",
|
|
67
|
-
"🥵",
|
|
68
|
-
"🥶",
|
|
69
|
-
"😱",
|
|
70
|
-
"😨",
|
|
71
|
-
"😰",
|
|
72
|
-
"😥",
|
|
73
|
-
"😓",
|
|
74
|
-
"🤗",
|
|
75
|
-
"🤔",
|
|
76
|
-
"🤭",
|
|
77
|
-
"🤫",
|
|
78
|
-
"🤥",
|
|
79
|
-
"😶",
|
|
80
|
-
"😐",
|
|
81
|
-
"😑",
|
|
82
|
-
"😬",
|
|
83
|
-
"🙄",
|
|
84
|
-
"😯",
|
|
85
|
-
"😦",
|
|
86
|
-
"😧",
|
|
87
|
-
"😮",
|
|
88
|
-
"😲",
|
|
89
|
-
"🥱",
|
|
90
|
-
"😴",
|
|
91
|
-
"🤤",
|
|
92
|
-
"😪",
|
|
93
|
-
"😵",
|
|
94
|
-
"🤐",
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
gestures: {
|
|
98
|
-
label: "Cử chỉ",
|
|
99
|
-
icon: Hand,
|
|
100
|
-
emojis: [
|
|
101
|
-
"👍",
|
|
102
|
-
"👎",
|
|
103
|
-
"👌",
|
|
104
|
-
"✌️",
|
|
105
|
-
"🤞",
|
|
106
|
-
"🤟",
|
|
107
|
-
"🤘",
|
|
108
|
-
"🤙",
|
|
109
|
-
"👈",
|
|
110
|
-
"👉",
|
|
111
|
-
"👆",
|
|
112
|
-
"🖕",
|
|
113
|
-
"👇",
|
|
114
|
-
"☝️",
|
|
115
|
-
"👏",
|
|
116
|
-
"🙌",
|
|
117
|
-
"👐",
|
|
118
|
-
"🤲",
|
|
119
|
-
"🤝",
|
|
120
|
-
"🙏",
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
hearts: {
|
|
124
|
-
label: "Trái tim",
|
|
125
|
-
icon: Heart,
|
|
126
|
-
emojis: ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍", "🤎", "💔", "❣️", "💕", "💞", "💓", "💗", "💖", "💘", "💝"],
|
|
127
|
-
},
|
|
128
|
-
objects: {
|
|
129
|
-
label: "Đồ vật",
|
|
130
|
-
icon: Coffee,
|
|
131
|
-
emojis: ["📱", "💻", "⌨️", "🖥️", "🖨️", "📷", "📹", "🎥", "📞", "☎️", "📠", "📺", "📻", "🎵", "🎶", "🎤", "🎧", "📢"],
|
|
132
|
-
},
|
|
133
|
-
travel: {
|
|
134
|
-
label: "Du lịch",
|
|
135
|
-
icon: Car,
|
|
136
|
-
emojis: ["🚗", "🚕", "🚙", "🚌", "🚎", "🏎️", "🚓", "🚑", "🚒", "🚐", "🛻", "🚚", "🚛", "🚜", "🏍️", "🛵", "🚲", "🛴"],
|
|
137
|
-
},
|
|
138
|
-
activities: {
|
|
139
|
-
label: "Hoạt động",
|
|
140
|
-
icon: Lightbulb,
|
|
141
|
-
emojis: [
|
|
142
|
-
"⚽",
|
|
143
|
-
"🏀",
|
|
144
|
-
"🏈",
|
|
145
|
-
"⚾",
|
|
146
|
-
"🥎",
|
|
147
|
-
"🎾",
|
|
148
|
-
"🏐",
|
|
149
|
-
"🏉",
|
|
150
|
-
"🥏",
|
|
151
|
-
"🎱",
|
|
152
|
-
"🪀",
|
|
153
|
-
"🏓",
|
|
154
|
-
"🏸",
|
|
155
|
-
"🏒",
|
|
156
|
-
"🏑",
|
|
157
|
-
"🥍",
|
|
158
|
-
"🏏",
|
|
159
|
-
"🪃",
|
|
160
|
-
],
|
|
161
|
-
},
|
|
162
|
-
flags: {
|
|
163
|
-
label: "Cờ",
|
|
164
|
-
icon: Flag,
|
|
165
|
-
emojis: ["🏳️", "🏴", "🏁", "🚩", "🏳️🌈", "🏳️⚧️", "🇺🇳", "🇻🇳", "🇺🇸", "🇬🇧", "🇫🇷", "🇩🇪", "🇯🇵", "🇰🇷", "🇨🇳", "🇮🇳"],
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
export const EmojiPicker = React.forwardRef(({ onEmojiSelect, onClose, isOpen = false, style }, ref) => {
|
|
169
|
-
const [activeCategory, setActiveCategory] = useState("recent");
|
|
170
|
-
const [searchTerm, setSearchTerm] = useState("");
|
|
171
|
-
if (!isOpen)
|
|
172
|
-
return null;
|
|
173
|
-
const handleEmojiClick = (emoji) => {
|
|
174
|
-
onEmojiSelect === null || onEmojiSelect === void 0 ? void 0 : onEmojiSelect(emoji);
|
|
175
|
-
};
|
|
176
|
-
const filteredEmojis = searchTerm
|
|
177
|
-
? emojiCategories[activeCategory].emojis.filter((emoji) =>
|
|
178
|
-
// Simple search - in a real app you'd have emoji names/keywords
|
|
179
|
-
emoji.includes(searchTerm))
|
|
180
|
-
: emojiCategories[activeCategory].emojis;
|
|
181
|
-
return (<div ref={ref} className="absolute bottom-full mb-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50 w-full sm:max-w-xs md:w-80" style={style} // Apply dynamic style here
|
|
182
|
-
>
|
|
183
|
-
<div className="p-2">
|
|
184
|
-
{/* Category Icons Row - Compact */}
|
|
185
|
-
<div className="flex items-center justify-between mb-2 pb-1 border-b border-gray-100">
|
|
186
|
-
{Object.entries(emojiCategories).map(([key, category]) => {
|
|
187
|
-
const Icon = category.icon;
|
|
188
|
-
const isActive = activeCategory === key;
|
|
189
|
-
return (<button key={key} onClick={() => setActiveCategory(key)} className={`
|
|
190
|
-
p-1.5 rounded-full transition-all duration-200 hover:bg-gray-100
|
|
191
|
-
${isActive ? "text-blue-500 bg-blue-50" : "text-gray-500"}
|
|
192
|
-
`} title={category.label}>
|
|
193
|
-
<Icon className="w-4 h-4"/>
|
|
194
|
-
</button>);
|
|
195
|
-
})}
|
|
196
|
-
|
|
197
|
-
{/* Close button */}
|
|
198
|
-
<button onClick={onClose} className="p-1.5 text-gray-400 hover:text-gray-600 rounded-full hover:bg-gray-100">
|
|
199
|
-
<X className="w-4 h-4"/>
|
|
200
|
-
</button>
|
|
201
|
-
</div>
|
|
202
|
-
|
|
203
|
-
{/* Search Bar - Compact */}
|
|
204
|
-
<div className="relative mb-2">
|
|
205
|
-
<Search className="absolute left-2 top-1/2 transform -translate-y-1/2 w-3 h-3 text-gray-400"/>
|
|
206
|
-
<input type="text" placeholder="Tìm kiếm" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} className="w-full pl-7 pr-3 py-1.5 text-xs bg-gray-50 border border-gray-200 rounded-md focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-transparent"/>
|
|
207
|
-
</div>
|
|
208
|
-
|
|
209
|
-
{/* Category Title - Compact */}
|
|
210
|
-
<div className="mb-2">
|
|
211
|
-
<h3 className="text-xs font-medium text-gray-900">{emojiCategories[activeCategory].label}</h3>
|
|
212
|
-
</div>
|
|
213
|
-
|
|
214
|
-
{/* Emoji Grid - Compact */}
|
|
215
|
-
<div className="grid grid-cols-9 gap-0.5 max-h-48 overflow-y-auto">
|
|
216
|
-
{filteredEmojis.map((emoji, index) => (<button key={index} onClick={() => handleEmojiClick(emoji)} className="p-1.5 text-lg hover:bg-gray-100 rounded transition-all duration-200 hover:scale-110 active:scale-95" title={emoji}>
|
|
217
|
-
{emoji}
|
|
218
|
-
</button>))}
|
|
219
|
-
</div>
|
|
220
|
-
|
|
221
|
-
{/* Empty state */}
|
|
222
|
-
{filteredEmojis.length === 0 && (<div className="text-center py-4 text-gray-500">
|
|
223
|
-
<div className="text-lg mb-1">🔍</div>
|
|
224
|
-
<p className="text-xs">Không tìm thấy emoji nào</p>
|
|
225
|
-
</div>)}
|
|
226
|
-
</div>
|
|
227
|
-
</div>);
|
|
228
|
-
});
|
|
229
|
-
EmojiPicker.displayName = "EmojiPicker";
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface ImageLightboxProps {
|
|
2
|
-
src: string;
|
|
3
|
-
alt: string;
|
|
4
|
-
onClose: () => void;
|
|
5
|
-
}
|
|
6
|
-
export declare function ImageLightbox({ src, alt, onClose }: ImageLightboxProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=ImageLightbox.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ImageLightbox.d.ts","sourceRoot":"","sources":["../../src/components/ImageLightbox.tsx"],"names":[],"mappings":"AAIA,UAAU,kBAAkB;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CA0BtE"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { X } from "lucide-react";
|
|
4
|
-
import Image from "next/image";
|
|
5
|
-
export function ImageLightbox({ src, alt, onClose }) {
|
|
6
|
-
return (_jsxs("div", { className: "fixed inset-0 z-[9999] bg-black bg-opacity-80 flex items-center justify-center p-4", onClick: onClose, children: [_jsx("button", { onClick: onClose, className: "absolute top-4 right-4 text-white p-2 rounded-full bg-gray-800/50 hover:bg-gray-700/70 transition-colors z-50", "aria-label": "Close image", children: _jsx(X, { className: "w-6 h-6" }) }), _jsx("div", { className: "relative max-w-full max-h-full", onClick: (e) => e.stopPropagation(), children: _jsx(Image, { src: src || "/placeholder.svg", alt: alt, width: 1200, height: 800, style: { width: "auto", height: "auto", maxWidth: "90vw", maxHeight: "90vh" }, className: "rounded-lg shadow-xl object-contain", priority // Load immediately
|
|
7
|
-
: true }) })] }));
|
|
8
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { X } from "lucide-react";
|
|
3
|
-
import Image from "next/image";
|
|
4
|
-
export function ImageLightbox({ src, alt, onClose }) {
|
|
5
|
-
return (<div className="fixed inset-0 z-[9999] bg-black bg-opacity-80 flex items-center justify-center p-4" onClick={onClose}>
|
|
6
|
-
<button onClick={onClose} className="absolute top-4 right-4 text-white p-2 rounded-full bg-gray-800/50 hover:bg-gray-700/70 transition-colors z-50" aria-label="Close image">
|
|
7
|
-
<X className="w-6 h-6"/>
|
|
8
|
-
</button>
|
|
9
|
-
<div className="relative max-w-full max-h-full" onClick={(e) => e.stopPropagation()}>
|
|
10
|
-
<Image src={src || "/placeholder.svg"} alt={alt} width={1200} // Max width for lightbox image
|
|
11
|
-
height={800} // Max height for lightbox image
|
|
12
|
-
style={{ width: "auto", height: "auto", maxWidth: "90vw", maxHeight: "90vh" }} className="rounded-lg shadow-xl object-contain" priority // Load immediately
|
|
13
|
-
/>
|
|
14
|
-
</div>
|
|
15
|
-
</div>);
|
|
16
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
interface ImagePreviewModalProps {
|
|
2
|
-
images: {
|
|
3
|
-
id: string;
|
|
4
|
-
url: string;
|
|
5
|
-
name?: string;
|
|
6
|
-
}[];
|
|
7
|
-
initialImageId: string;
|
|
8
|
-
onClose: () => void;
|
|
9
|
-
}
|
|
10
|
-
export declare function ImagePreviewModal({ images, initialImageId, onClose }: ImagePreviewModalProps): import("react/jsx-runtime").JSX.Element | null;
|
|
11
|
-
export {};
|
|
12
|
-
//# sourceMappingURL=ImagePreviewModal.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ImagePreviewModal.d.ts","sourceRoot":"","sources":["../../src/components/ImagePreviewModal.tsx"],"names":[],"mappings":"AAOA,UAAU,sBAAsB;IAC9B,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAA;QACV,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,EAAE,CAAA;IACH,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE,sBAAsB,kDAmH5F"}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect, useCallback } from "react";
|
|
4
|
-
import Image from "next/image";
|
|
5
|
-
import { X, ChevronLeft, ChevronRight } from "lucide-react";
|
|
6
|
-
export function ImagePreviewModal({ images, initialImageId, onClose }) {
|
|
7
|
-
// Find the initial index based on initialImageId
|
|
8
|
-
const initialIndex = images.findIndex((img) => img.id === initialImageId);
|
|
9
|
-
const [currentImageIndex, setCurrentImageIndex] = useState(initialIndex !== -1 ? initialIndex : 0);
|
|
10
|
-
// Ensure currentImageIndex is valid if initialImageId wasn't found or images array is empty
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
if (initialIndex === -1 && images.length > 0) {
|
|
13
|
-
setCurrentImageIndex(0);
|
|
14
|
-
}
|
|
15
|
-
else if (images.length === 0) {
|
|
16
|
-
onClose(); // Close if no images are provided
|
|
17
|
-
}
|
|
18
|
-
}, [initialImageId, images, initialIndex, onClose]);
|
|
19
|
-
const currentImage = images[currentImageIndex];
|
|
20
|
-
const handlePrev = useCallback(() => {
|
|
21
|
-
setCurrentImageIndex((prevIndex) => Math.max(0, prevIndex - 1));
|
|
22
|
-
}, []);
|
|
23
|
-
const handleNext = useCallback(() => {
|
|
24
|
-
setCurrentImageIndex((prevIndex) => Math.min(images.length - 1, prevIndex + 1));
|
|
25
|
-
}, [images.length]);
|
|
26
|
-
const handleKeyDown = useCallback((event) => {
|
|
27
|
-
if (event.key === "Escape") {
|
|
28
|
-
onClose();
|
|
29
|
-
}
|
|
30
|
-
else if (event.key === "ArrowLeft") {
|
|
31
|
-
handlePrev();
|
|
32
|
-
}
|
|
33
|
-
else if (event.key === "ArrowRight") {
|
|
34
|
-
handleNext();
|
|
35
|
-
}
|
|
36
|
-
}, [onClose, handlePrev, handleNext]);
|
|
37
|
-
// Add and remove keyboard event listener
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
40
|
-
return () => {
|
|
41
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
42
|
-
};
|
|
43
|
-
}, [handleKeyDown]);
|
|
44
|
-
if (!currentImage) {
|
|
45
|
-
return null; // Or render a loading/error state
|
|
46
|
-
}
|
|
47
|
-
const isFirstImage = currentImageIndex === 0;
|
|
48
|
-
const isLastImage = currentImageIndex === images.length - 1;
|
|
49
|
-
return (_jsxs("div", { className: "fixed inset-0 z-[9999] bg-black bg-opacity-90 flex items-center justify-center p-4 sm:p-8", onClick: onClose, children: [_jsx("button", { onClick: onClose, className: "absolute top-4 right-4 text-white p-2 rounded-full bg-gray-800/50 hover:bg-gray-700/70 transition-colors z-50", "aria-label": "\u0110\u00F3ng", title: "\u0110\u00F3ng (Esc)", children: _jsx(X, { className: "w-6 h-6" }) }), _jsxs("div", { className: "relative flex items-center justify-center w-full h-full max-w-screen-xl max-h-screen-xl", onClick: (e) => e.stopPropagation(), children: [_jsx("button", { onClick: handlePrev, disabled: isFirstImage, className: `absolute left-2 sm:left-4 p-3 rounded-full bg-gray-800/50 text-white hover:bg-gray-700/70 transition-colors z-40
|
|
50
|
-
${isFirstImage ? "opacity-50 cursor-not-allowed" : ""}`, "aria-label": "\u1EA2nh tr\u01B0\u1EDBc", title: "\u1EA2nh tr\u01B0\u1EDBc (M\u0169i t\u00EAn tr\u00E1i)", children: _jsx(ChevronLeft, { className: "w-6 h-6 sm:w-8 sm:h-8" }) }), _jsx("div", { className: "relative w-full h-full flex items-center justify-center", children: _jsx(Image, { src: currentImage.url || "/placeholder.svg", alt: currentImage.name || "Xem trước hình ảnh", layout: "fill" // Use fill to make it responsive within its parent
|
|
51
|
-
, objectFit: "contain" // Ensure the image fits within the container without cropping
|
|
52
|
-
, className: "rounded-lg shadow-xl", priority // Load immediately for better UX
|
|
53
|
-
: true }) }), _jsx("button", { onClick: handleNext, disabled: isLastImage, className: `absolute right-2 sm:right-4 p-3 rounded-full bg-gray-800/50 text-white hover:bg-gray-700/70 transition-colors z-40
|
|
54
|
-
${isLastImage ? "opacity-50 cursor-not-allowed" : ""}`, "aria-label": "\u1EA2nh ti\u1EBFp theo", title: "\u1EA2nh ti\u1EBFp theo (M\u0169i t\u00EAn ph\u1EA3i)", children: _jsx(ChevronRight, { className: "w-6 h-6 sm:w-8 sm:h-8" }) })] }), _jsxs("div", { className: "absolute bottom-4 text-white text-sm sm:text-base bg-black/50 px-4 py-2 rounded-full", children: [currentImage.name || "Hình ảnh", " (", currentImageIndex + 1, " / ", images.length, ")"] })] }));
|
|
55
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useState, useEffect, useCallback } from "react";
|
|
3
|
-
import Image from "next/image";
|
|
4
|
-
import { X, ChevronLeft, ChevronRight } from "lucide-react";
|
|
5
|
-
export function ImagePreviewModal({ images, initialImageId, onClose }) {
|
|
6
|
-
// Find the initial index based on initialImageId
|
|
7
|
-
const initialIndex = images.findIndex((img) => img.id === initialImageId);
|
|
8
|
-
const [currentImageIndex, setCurrentImageIndex] = useState(initialIndex !== -1 ? initialIndex : 0);
|
|
9
|
-
// Ensure currentImageIndex is valid if initialImageId wasn't found or images array is empty
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
if (initialIndex === -1 && images.length > 0) {
|
|
12
|
-
setCurrentImageIndex(0);
|
|
13
|
-
}
|
|
14
|
-
else if (images.length === 0) {
|
|
15
|
-
onClose(); // Close if no images are provided
|
|
16
|
-
}
|
|
17
|
-
}, [initialImageId, images, initialIndex, onClose]);
|
|
18
|
-
const currentImage = images[currentImageIndex];
|
|
19
|
-
const handlePrev = useCallback(() => {
|
|
20
|
-
setCurrentImageIndex((prevIndex) => Math.max(0, prevIndex - 1));
|
|
21
|
-
}, []);
|
|
22
|
-
const handleNext = useCallback(() => {
|
|
23
|
-
setCurrentImageIndex((prevIndex) => Math.min(images.length - 1, prevIndex + 1));
|
|
24
|
-
}, [images.length]);
|
|
25
|
-
const handleKeyDown = useCallback((event) => {
|
|
26
|
-
if (event.key === "Escape") {
|
|
27
|
-
onClose();
|
|
28
|
-
}
|
|
29
|
-
else if (event.key === "ArrowLeft") {
|
|
30
|
-
handlePrev();
|
|
31
|
-
}
|
|
32
|
-
else if (event.key === "ArrowRight") {
|
|
33
|
-
handleNext();
|
|
34
|
-
}
|
|
35
|
-
}, [onClose, handlePrev, handleNext]);
|
|
36
|
-
// Add and remove keyboard event listener
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
39
|
-
return () => {
|
|
40
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
41
|
-
};
|
|
42
|
-
}, [handleKeyDown]);
|
|
43
|
-
if (!currentImage) {
|
|
44
|
-
return null; // Or render a loading/error state
|
|
45
|
-
}
|
|
46
|
-
const isFirstImage = currentImageIndex === 0;
|
|
47
|
-
const isLastImage = currentImageIndex === images.length - 1;
|
|
48
|
-
return (<div className="fixed inset-0 z-[9999] bg-black bg-opacity-90 flex items-center justify-center p-4 sm:p-8" onClick={onClose} // Close when clicking on the overlay
|
|
49
|
-
>
|
|
50
|
-
{/* Close Button */}
|
|
51
|
-
<button onClick={onClose} className="absolute top-4 right-4 text-white p-2 rounded-full bg-gray-800/50 hover:bg-gray-700/70 transition-colors z-50" aria-label="Đóng" title="Đóng (Esc)">
|
|
52
|
-
<X className="w-6 h-6"/>
|
|
53
|
-
</button>
|
|
54
|
-
|
|
55
|
-
{/* Image Container */}
|
|
56
|
-
<div className="relative flex items-center justify-center w-full h-full max-w-screen-xl max-h-screen-xl" onClick={(e) => e.stopPropagation()} // Prevent closing when clicking on the image itself
|
|
57
|
-
>
|
|
58
|
-
{/* Previous Button */}
|
|
59
|
-
<button onClick={handlePrev} disabled={isFirstImage} className={`absolute left-2 sm:left-4 p-3 rounded-full bg-gray-800/50 text-white hover:bg-gray-700/70 transition-colors z-40
|
|
60
|
-
${isFirstImage ? "opacity-50 cursor-not-allowed" : ""}`} aria-label="Ảnh trước" title="Ảnh trước (Mũi tên trái)">
|
|
61
|
-
<ChevronLeft className="w-6 h-6 sm:w-8 sm:h-8"/>
|
|
62
|
-
</button>
|
|
63
|
-
|
|
64
|
-
{/* Image Display */}
|
|
65
|
-
<div className="relative w-full h-full flex items-center justify-center">
|
|
66
|
-
<Image src={currentImage.url || "/placeholder.svg"} alt={currentImage.name || "Xem trước hình ảnh"} layout="fill" // Use fill to make it responsive within its parent
|
|
67
|
-
objectFit="contain" // Ensure the image fits within the container without cropping
|
|
68
|
-
className="rounded-lg shadow-xl" priority // Load immediately for better UX
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
{/* Next Button */}
|
|
73
|
-
<button onClick={handleNext} disabled={isLastImage} className={`absolute right-2 sm:right-4 p-3 rounded-full bg-gray-800/50 text-white hover:bg-gray-700/70 transition-colors z-40
|
|
74
|
-
${isLastImage ? "opacity-50 cursor-not-allowed" : ""}`} aria-label="Ảnh tiếp theo" title="Ảnh tiếp theo (Mũi tên phải)">
|
|
75
|
-
<ChevronRight className="w-6 h-6 sm:w-8 sm:h-8"/>
|
|
76
|
-
</button>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
{/* Image Name/Counter (Optional) */}
|
|
80
|
-
<div className="absolute bottom-4 text-white text-sm sm:text-base bg-black/50 px-4 py-2 rounded-full">
|
|
81
|
-
{currentImage.name || "Hình ảnh"} ({currentImageIndex + 1} / {images.length})
|
|
82
|
-
</div>
|
|
83
|
-
</div>);
|
|
84
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../src/components/MessageItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,UAAU,CAAA;AAIhE,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,gBAAgB,2CAwLjF"}
|