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 ( +
+

준비 중…

+
+ Cocktail Shaker +
+
+ ); +} +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; } }