Skip to content

Commit 4a50ebb

Browse files
committed
PEER-236: Fix chat component styles
Signed-off-by: SeeuSim <[email protected]>
1 parent 5f1df58 commit 4a50ebb

File tree

8 files changed

+76
-35
lines changed

8 files changed

+76
-35
lines changed

backend/chat/drizzle/0000_violet_micromacro.sql

Lines changed: 0 additions & 19 deletions
This file was deleted.

backend/chat/drizzle/meta/_journal.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"idx": 0,
77
"version": "7",
88
"when": 1729871791234,
9-
"tag": "0000_violet_micromacro",
9+
"tag": "0000_initial_schema",
1010
"breakpoints": true
1111
}
1212
]

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"remark-math": "^6.0.0",
5353
"socket.io-client": "^4.8.0",
5454
"tailwind-merge": "^2.5.2",
55+
"tailwind-scrollbar": "^3.1.0",
5556
"tailwindcss-animate": "^1.0.7",
5657
"ws": "^8.18.0",
5758
"y-codemirror.next": "^0.3.5",

frontend/src/components/blocks/interview/chat/chat-layout.tsx

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import React, { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from '
33

44
import { Alert, AlertDescription } from '@/components/ui/alert';
55
import { Button } from '@/components/ui/button';
6-
import { Input } from '@/components/ui/input';
76
import { ScrollArea } from '@/components/ui/scroll-area';
7+
import { Textarea } from '@/components/ui/textarea';
88

99
import { ChatMessage, ChatMessageType } from './chat-message';
1010

@@ -28,32 +28,44 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
2828
title,
2929
}) => {
3030
const [input, setInput] = useState<string>('');
31-
const inputRef = useRef<HTMLInputElement>(null);
31+
const inputRef = useRef<HTMLTextAreaElement>(null);
3232
const messagesEndRef = useRef<HTMLDivElement>(null);
3333

3434
const scrollToBottom = () => {
3535
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
3636
};
3737

38+
// Focus and scroll to bottom on window open
3839
useEffect(() => {
3940
if (isOpen) {
4041
inputRef.current?.focus();
4142
scrollToBottom();
4243
}
4344
}, [isOpen]);
4445

46+
// Scroll to bottom on reception of messages
4547
useEffect(() => {
4648
scrollToBottom();
4749
}, [messages, isLoading]);
4850

51+
// Resize textarea on input, up to a maximum height
52+
useEffect(() => {
53+
const textAreaEl = inputRef.current;
54+
55+
if (textAreaEl) {
56+
textAreaEl.style.height = 'auto';
57+
textAreaEl.style.height = `${Math.min(textAreaEl.scrollHeight, 100)}px`;
58+
}
59+
}, [input]);
60+
4961
const handleSend = () => {
5062
if (input.trim()) {
5163
onSend(input.trim());
5264
setInput('');
5365
}
5466
};
5567

56-
const handleKeyPress = (e: KeyboardEvent<HTMLInputElement>) => {
68+
const handleKeyPress = (e: KeyboardEvent<HTMLTextAreaElement>) => {
5769
if (e.key === 'Enter' && !e.shiftKey) {
5870
e.preventDefault();
5971
handleSend();
@@ -62,7 +74,10 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
6274

6375
return (
6476
<div className='flex size-full flex-col'>
65-
<div className='bg-secondary/50 border-border flex items-center justify-between border-b px-4 py-3'>
77+
<div
78+
id='chat-header'
79+
className='bg-secondary/50 border-border flex items-center justify-between border-b py-1 pl-3 pr-1'
80+
>
6681
<div className='flex items-center gap-2'>
6782
<h2 className='font-semibold'>{title}</h2>
6883
</div>
@@ -78,7 +93,7 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
7893
</div>
7994
</div>
8095

81-
<ScrollArea className='h-full flex-1 overflow-y-auto p-4'>
96+
<ScrollArea id='chat-messages' className='h-full flex-1 overflow-y-auto p-4'>
8297
{messages.length === 0 && (
8398
<div className='flex h-full flex-col items-center justify-center text-gray-500'>
8499
<MessageSquare className='mb-4 size-12 opacity-50' />
@@ -103,18 +118,24 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
103118
<div ref={messagesEndRef} />
104119
</ScrollArea>
105120

106-
<div className='bg-secondary/50 border-border border-t p-4'>
107-
<div className='flex gap-2'>
108-
<Input
121+
<div className='bg-secondary/50 border-border border-t p-3'>
122+
<div className='flex w-full items-center justify-between gap-3'>
123+
<Textarea
124+
rows={1}
109125
ref={inputRef}
110126
value={input}
111-
onChange={(e: ChangeEvent<HTMLInputElement>) => setInput(e.target.value)}
127+
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => setInput(e.target.value)}
112128
placeholder='Type your message...'
113-
onKeyPress={handleKeyPress}
129+
onKeyDown={handleKeyPress}
114130
disabled={isLoading}
115-
className='bg-primary-foreground flex-1'
131+
className='bg-primary-foreground scrollbar-thin scrollbar-track-black h-10 min-h-10 flex-1 resize-none overflow-y-auto p-2'
116132
/>
117-
<Button variant='outline' onClick={handleSend} disabled={isLoading || !input.trim()}>
133+
<Button
134+
variant='outline'
135+
onClick={handleSend}
136+
disabled={isLoading || !input.trim()}
137+
className='min-h-10 px-3 py-2'
138+
>
118139
{isLoading ? <Loader2 className='size-4 animate-spin' /> : <Send className='size-4' />}
119140
</Button>
120141
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from 'react';
2+
3+
import { cn } from '@/lib/utils';
4+
5+
/* eslint-disable @typescript-eslint/no-empty-object-type */
6+
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
7+
/* eslint-enable @typescript-eslint/no-empty-object-type */
8+
9+
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
10+
({ className, ...props }, ref) => {
11+
return (
12+
<textarea
13+
className={cn(
14+
'flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
15+
className
16+
)}
17+
ref={ref}
18+
{...props}
19+
/>
20+
);
21+
}
22+
);
23+
Textarea.displayName = 'Textarea';
24+
25+
export { Textarea };

frontend/src/routes/interview/[room]/main.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const InterviewRoom = () => {
4949
<WithNavBlocker>
5050
<WithNavBanner crumbs={crumbs}>
5151
<div className='flex flex-1 overflow-hidden'>
52-
<Card className='border-border m-4 w-1/3 overflow-hidden p-4 md:w-2/5'>
52+
<Card className='border-border m-4 flex w-[500px] overflow-hidden p-4 md:w-2/5'>
5353
<QuestionDetails {...{ questionDetails }} />
5454
</Card>
5555
<div className='flex w-full'>
@@ -60,7 +60,7 @@ export const InterviewRoom = () => {
6060
/>
6161
</div>
6262
{(isAIChatOpen || isPartnerChatOpen) && (
63-
<Card className='border-border m-4 w-1/3 overflow-hidden'>
63+
<Card className='border-border m-4 w-[500px] overflow-hidden'>
6464
{isAIChatOpen && (
6565
<AIChat isOpen={isAIChatOpen} onClose={() => setIsAIChatOpen(false)} />
6666
)}

frontend/tailwind.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ const config = {
7171
}
7272
},
7373
},
74-
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography')],
74+
plugins: [require('tailwindcss-animate'), require('@tailwindcss/typography'), require('tailwind-scrollbar'),],
7575
};
7676

7777
export default config;

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)