diff --git a/src/games/ai/assets/favicon.ico b/src/games/ai/assets/favicon.ico new file mode 100644 index 0000000..c355512 Binary files /dev/null and b/src/games/ai/assets/favicon.ico differ diff --git a/src/games/ai/assets/style.css b/src/games/ai/assets/style.css index cba440e..9abe603 100644 --- a/src/games/ai/assets/style.css +++ b/src/games/ai/assets/style.css @@ -36,6 +36,7 @@ textarea { width: 100%; scrollbar-width: thin; scrollbar-color: var(--color) transparent; + padding: 4px; } body { @@ -97,16 +98,21 @@ body { &.role-user { background-color: var(--shadeColor); - :not(.last-user) .content .text { + &:not(.last-user) .content .text { opacity: 0.5; + font-size: 12px; } } + &.role-assistant { + border-top: 1px solid var(--backgroundColorDark); + } + >.content { white-space: pre-wrap; line-height: 1.5; display: flex; - flex-direction: row; + flex-direction: column; width: 100%; gap: 8px; @@ -116,7 +122,7 @@ body { min-height: 100px; height: unset; resize: vertical; - line-height: 1.25; + line-height: 1.5; padding: 5px; border-radius: 3px; } @@ -124,6 +130,7 @@ body { >.text { flex-grow: 1; width: 100%; + animation-duration: 300ms; >.bold { font-weight: bold; @@ -141,7 +148,9 @@ body { >.buttons { display: flex; - flex-direction: column; + flex-direction: row; + align-items: center; + justify-content: flex-end; gap: 8px; >.icon { @@ -158,6 +167,19 @@ body { font-family: var(--emojiColorFont); } } + + >.swipes { + display: flex; + width: 100%; + flex-direction: row; + justify-content: space-between; + gap: 8px; + + >div { + cursor: pointer; + font-size: 20px; + } + } } } } @@ -172,4 +194,27 @@ body { border: var(--border); } } +} + +@keyframes swipe-from-left { + 0% { + position: relative; + left: -100%; + } + + 100% { + position: relative; + left: 0; + } +} +@keyframes swipe-from-right { + 0% { + position: relative; + right: -100%; + } + + 100% { + position: relative; + right: 0; + } } \ No newline at end of file diff --git a/src/games/ai/components/chat.tsx b/src/games/ai/components/chat.tsx index 2ebc2f2..c9a787e 100644 --- a/src/games/ai/components/chat.tsx +++ b/src/games/ai/components/chat.tsx @@ -8,8 +8,9 @@ export const Chat = () => { const lastMessage = messages.at(-1); const lastMessageSwipe = lastMessage?.swipes[lastMessage.currentSwipe]; - const lastMessageContent = lastMessageSwipe?.displayContent ?? lastMessageSwipe.content; + const lastMessageContent = lastMessageSwipe?.displayContent ?? lastMessageSwipe?.content; const lastUserId = messages.findLastIndex(m => m.role === 'user'); + const lastAssistantId = messages.findLastIndex(m => m.role === 'assistant'); useEffect(() => { if (chatRef.current) { @@ -23,7 +24,11 @@ export const Chat = () => { return (
{messages.map((m, i) => ( - + ))}
); diff --git a/src/games/ai/components/message.tsx b/src/games/ai/components/message.tsx index de09c2f..e1bac24 100644 --- a/src/games/ai/components/message.tsx +++ b/src/games/ai/components/message.tsx @@ -6,17 +6,19 @@ interface IProps { message: IMessage; index: number; isLastUser: boolean; + isLastAssistant: boolean; } -export const Message = ({ message, index, isLastUser }: IProps) => { - const { editMessage, deleteMessage } = useContext(GlobalContext); +export const Message = ({ message, index, isLastUser, isLastAssistant }: IProps) => { + const { editMessage, deleteMessage, setCurrentSwipe } = useContext(GlobalContext); const [editing, setEditing] = useState(false); const [savedMessage, setSavedMessage] = useState(''); const textareaRef = useRef(null); + const textRef = useRef(null); const swipe = useMemo(() => message.swipes[message.currentSwipe], [message.swipes, message.currentSwipe]); - const content = useMemo(() => swipe.displayContent ?? swipe.content, [swipe]); - const htmlContent = useMemo(() => formatMessage(content), [content]); + const content = useMemo(() => swipe?.displayContent ?? swipe?.content, [swipe]); + const htmlContent = useMemo(() => formatMessage(content ?? ''), [content]); const handleToggleEdit = useCallback(() => { setEditing(!editing); @@ -44,6 +46,22 @@ export const Message = ({ message, index, isLastUser }: IProps) => { } }, [editMessage, index]); + const handleSwipeLeft = useCallback(() => { + setCurrentSwipe(index, message.currentSwipe - 1); + if (textRef.current) { + textRef.current.style.animationName = ''; + textRef.current.style.animationName = 'swipe-from-left'; + } + }, [setCurrentSwipe, index, message]); + + const handleSwipeRight = useCallback(() => { + setCurrentSwipe(index, message.currentSwipe + 1); + if (textRef.current) { + textRef.current.style.animationName = ''; + textRef.current.style.animationName = 'swipe-from-right'; + } + }, [setCurrentSwipe, index, message]); + useEffect(() => { if (textareaRef.current) { const area = textareaRef.current; @@ -57,20 +75,29 @@ export const Message = ({ message, index, isLastUser }: IProps) => {
{editing ?