diff --git a/src/domains/recommend/components/ChatCocktailCard.tsx b/src/domains/recommend/components/BotCocktailCard.tsx
similarity index 93%
rename from src/domains/recommend/components/ChatCocktailCard.tsx
rename to src/domains/recommend/components/BotCocktailCard.tsx
index 1d3e554..9ddf0d0 100644
--- a/src/domains/recommend/components/ChatCocktailCard.tsx
+++ b/src/domains/recommend/components/BotCocktailCard.tsx
@@ -3,7 +3,7 @@ import Dummy from '@/shared/assets/images/dummy/exampleCocktail.png';
import Link from 'next/link';
import Keep from '@/domains/shared/components/keep/Keep';
-function ChatCocktailCard() {
+function BotCocktailCard() {
return (
@@ -20,4 +20,4 @@ function ChatCocktailCard() {
);
}
-export default ChatCocktailCard;
+export default BotCocktailCard;
diff --git a/src/domains/recommend/components/SsuryChat.tsx b/src/domains/recommend/components/BotMessage.tsx
similarity index 86%
rename from src/domains/recommend/components/SsuryChat.tsx
rename to src/domains/recommend/components/BotMessage.tsx
index d0c4b7a..80652ec 100644
--- a/src/domains/recommend/components/SsuryChat.tsx
+++ b/src/domains/recommend/components/BotMessage.tsx
@@ -3,8 +3,8 @@
import Ssury from '@/shared/assets/ssury/ssury_shaker.webp';
import Image from 'next/image';
import { useState } from 'react';
-import ChatRadio from './ChatRadio';
-import ChatCocktailCard from './ChatCocktailCard';
+import BotCocktailCard from './BotCocktailCard';
+import BotOptions from './BotOptions';
interface Message {
id: string;
@@ -12,7 +12,7 @@ interface Message {
type?: 'radio' | 'text' | 'recommend';
}
-function SsuryChat() {
+function BotMessage() {
const [selected, setSelected] = useState('option1');
// radio 옵션
@@ -61,13 +61,13 @@ function SsuryChat() {
{msg.type === 'recommend' ? (
) : (
@@ -76,7 +76,7 @@ function SsuryChat() {
{/* radio */}
{msg.type === 'radio' && (
-
+
)}
)}
@@ -86,4 +86,4 @@ function SsuryChat() {
);
}
-export default SsuryChat;
+export default BotMessage;
diff --git a/src/domains/recommend/components/ChatRadio.tsx b/src/domains/recommend/components/BotOptions.tsx
similarity index 91%
rename from src/domains/recommend/components/ChatRadio.tsx
rename to src/domains/recommend/components/BotOptions.tsx
index c42de30..68fafee 100644
--- a/src/domains/recommend/components/ChatRadio.tsx
+++ b/src/domains/recommend/components/BotOptions.tsx
@@ -9,7 +9,7 @@ interface RadioGroupProps {
onChange: (value: string) => void;
}
-function ChatRadio({ options, value, onChange }: RadioGroupProps) {
+function BotOptions({ options, value, onChange }: RadioGroupProps) {
return (
{options.map((opt) => (
@@ -39,4 +39,4 @@ function ChatRadio({ options, value, onChange }: RadioGroupProps) {
);
}
-export default ChatRadio;
+export default BotOptions;
diff --git a/src/domains/recommend/components/ChatSection.tsx b/src/domains/recommend/components/ChatSection.tsx
index cbf7512..8dfc12b 100644
--- a/src/domains/recommend/components/ChatSection.tsx
+++ b/src/domains/recommend/components/ChatSection.tsx
@@ -1,9 +1,10 @@
'use client';
import { useState } from 'react';
-import ChatForm from './ChatForm';
-import MyChat from './MyChat';
-import SsuryChat from './SsuryChat';
+import BotMessage from './BotMessage';
+import UserMessage from './UserMessage';
+import MessageInput from './MessageInput';
+import TypingIndicator from './TypingIndicator';
function ChatSection() {
const [messages, setMessages] = useState([]);
@@ -16,12 +17,13 @@ function ChatSection() {
대화 목록 및 입력 창
-
+
+
{messages.map((msg, i) => (
-
+
))}
-
+
);
}
diff --git a/src/domains/recommend/components/ChatForm.tsx b/src/domains/recommend/components/MessageInput.tsx
similarity index 96%
rename from src/domains/recommend/components/ChatForm.tsx
rename to src/domains/recommend/components/MessageInput.tsx
index 57e8e44..c758c56 100644
--- a/src/domains/recommend/components/ChatForm.tsx
+++ b/src/domains/recommend/components/MessageInput.tsx
@@ -9,7 +9,7 @@ interface Props {
onSubmit: (message: string) => void;
}
-function ChatForm({ onSubmit }: Props) {
+function MessageInput({ onSubmit }: Props) {
const [value, setValue] = useState('');
const textareaRef = useRef(null);
@@ -51,4 +51,4 @@ function ChatForm({ onSubmit }: Props) {
);
}
-export default ChatForm;
+export default MessageInput;
diff --git a/src/domains/recommend/components/TypingIndicator.tsx b/src/domains/recommend/components/TypingIndicator.tsx
new file mode 100644
index 0000000..4d77749
--- /dev/null
+++ b/src/domains/recommend/components/TypingIndicator.tsx
@@ -0,0 +1,14 @@
+import Image from 'next/image';
+import shaker from '@/shared/assets/images/shaker.png';
+
+function TypingIndicator() {
+ return (
+
+ );
+}
+export default TypingIndicator;
diff --git a/src/domains/recommend/components/MyChat.tsx b/src/domains/recommend/components/UserMessage.tsx
similarity index 92%
rename from src/domains/recommend/components/MyChat.tsx
rename to src/domains/recommend/components/UserMessage.tsx
index c984d87..f63a1ed 100644
--- a/src/domains/recommend/components/MyChat.tsx
+++ b/src/domains/recommend/components/UserMessage.tsx
@@ -12,7 +12,7 @@ interface Props {
// { id: '2', sender: 'user', text: '배고파요' },
// ];
-function MyChat({ message }: Props) {
+function UserMessage({ message }: Props) {
return (
@@ -28,4 +28,4 @@ function MyChat({ message }: Props) {
);
}
-export default MyChat;
+export default UserMessage;
diff --git a/src/shared/assets/images/shaker.png b/src/shared/assets/images/shaker.png
new file mode 100644
index 0000000..dcb6cf7
Binary files /dev/null and b/src/shared/assets/images/shaker.png differ
diff --git a/src/shared/assets/ssury/ssury_happy.webp b/src/shared/assets/ssury/ssury_happy.webp
new file mode 100644
index 0000000..03044b5
Binary files /dev/null and b/src/shared/assets/ssury/ssury_happy.webp differ
diff --git a/src/shared/styles/_utilities.css b/src/shared/styles/_utilities.css
index d0cbd92..60db4b2 100644
--- a/src/shared/styles/_utilities.css
+++ b/src/shared/styles/_utilities.css
@@ -55,24 +55,44 @@
display: none;
}
- @media (min-width: 768px) {
- .custom-scrollbar {
- scrollbar-width: thin; /* Firefox 전용 */
- scrollbar-color: #7a7581; /* Firefox 전용: thumb track */
+ @keyframes shake {
+ 0%,
+ 100% {
+ transform: translateY(0) rotate(0deg) scale(1);
}
- .custom-scrollbar::-webkit-scrollbar {
- width: 4px;
- border-radius: 8px;
+ 10% {
+ transform: rotate(-25deg) scaleX(1.05) scaleY(0.95);
+ }
+ 20% {
+ transform: rotate(25deg) scaleX(0.95) scaleY(1.05);
+ }
+ 30% {
+ transform: rotate(-20deg) scaleX(1.05) scaleY(0.95);
+ }
+ 40% {
+ transform: rotate(20deg) scaleX(0.95) scaleY(1.05);
}
- .custom-scrollbar::-webkit-scrollbar-thumb {
- background-color: #ab98c2;
- border-radius: 8px;
+ 50% {
+ transform: translateY(-10px) rotate(360deg) scale(1);
}
- .custom-scrollbar::-webkit-scrollbar-track {
- background-color: aliceblue;
+ 60% {
+ transform: translateY(-25px) rotate(20deg) scaleX(1.05) scaleY(0.95);
+ }
+ 70% {
+ transform: translateY(-10px) rotate(-25deg) scaleX(0.95) scaleY(1.05);
}
+ 80% {
+ transform: translateY(-5px) rotate(20deg) scaleX(1.02) scaleY(0.98);
+ }
+ 90% {
+ transform: translateY(-2px) rotate(-15deg) scale(1);
+ }
+ }
+
+ .animate-shake {
+ animation: shake 3s ease-in-out infinite;
}
}