-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
채팅을 위한 컴포넌트 구현 #164
채팅을 위한 컴포넌트 구현 #164
Changes from 12 commits
6992401
4629953
2c5d1f1
81cf83c
7c1bd9b
763fdc8
ba22ee2
e501b29
8d4344a
4f7e3d2
747329e
8bce62c
b3b9988
b79bc7a
2a5adca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import ChatList from './ChatList'; | ||
|
||
const meta: Meta<typeof ChatList> = { | ||
component: ChatList, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof ChatList>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
chats: [ | ||
{ | ||
sender: '상돌', | ||
time: '14:00', | ||
message: '안나야 공은 찰 줄 아냐', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '안나', | ||
time: '14:04', | ||
message: '시비걸꺼면 나가라', | ||
isMyMessage: true, | ||
}, | ||
{ | ||
sender: '안나', | ||
time: '14:04', | ||
message: '지하돌아', | ||
isMyMessage: true, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:06', | ||
message: '여러분~ 싸우지 마세요', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
{ | ||
sender: '테바', | ||
time: '14:07', | ||
message: | ||
'두 분 다 강퇴 당하고 싶지 않으시면 서로 말 예쁘게 해주시고 ~ 각자 괜찮은 시간이나 좀 남겨주세요!', | ||
isMyMessage: false, | ||
}, | ||
], | ||
}, | ||
|
||
decorators: (Story) => { | ||
return ( | ||
<div style={{ height: '200px' }}> | ||
<Story /> | ||
</div> | ||
); | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Theme, css } from '@emotion/react'; | ||
|
||
export const list = ({ theme }: { theme: Theme }) => css` | ||
overflow-y: scroll; | ||
display: flex; | ||
flex-direction: column; | ||
gap: 1rem; | ||
|
||
height: 100%; | ||
padding: 2rem; | ||
|
||
background-color: ${theme.colorPalette.grey[100]}; | ||
|
||
&::-webkit-scrollbar { | ||
display: none; | ||
} | ||
`; |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 어떤 컴포넌트는 Chat이고 어떤 컴포넌트는 Chatting인데 두개를 나누는 기준은 하나의 메세지를 담는 컴포넌트면 Chat, 아니면 대화가 위주가 되면 Chatting이라고 두었습니다. ChatList는 Chat이 여러 개 있어서 ChatList라고 했어요. 근데 이 컴포넌트가 대화가 위주가 된다는 관점도 있어서 Chatting 이라는 방안이 존재합니다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import ChatMessage, { | ||
ChatMessageProps, | ||
} from '@_components/ChatMessage/ChatMessage'; | ||
|
||
import { list } from './ChatList.style'; | ||
import { useTheme } from '@emotion/react'; | ||
|
||
interface ChatListProps { | ||
chats: ChatMessageProps[]; | ||
} | ||
Comment on lines
+6
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ChatListProps의 chats에 ChatMessageProps[]가 들어가는게 좀 특이한데, 아직 서버와 chat 데이터 구조가 정해지지 않아서 임시로 정해둔걸까요? 그 데이터 구조를 type으로 선언해두고 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 아직 서버에서 오는 값이 정해지지 않아서 이렇게 놔뒀어요 값이 정해진다면 업데이트하겠습니다 |
||
|
||
export default function ChatList(props: ChatListProps) { | ||
const { chats } = props; | ||
const theme = useTheme(); | ||
|
||
return ( | ||
<div css={list({ theme })}> | ||
{chats.map((chat) => ( | ||
<ChatMessage key={chat.message + chat.time} {...chat} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 추후 chatid로 변경할 예정 |
||
))} | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import ChatMessage from './ChatMessage'; | ||
|
||
const meta: Meta<typeof ChatMessage> = { | ||
component: ChatMessage, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof ChatMessage>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
sender: '테바', | ||
time: '12:12', | ||
imageUrl: '', | ||
message: '여러분~ 싸우지 마세요', | ||
isMyMessage: false, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { Theme, css } from '@emotion/react'; | ||
|
||
export const ChatMessageStyle = ({ | ||
isMyMessage, | ||
}: { | ||
isMyMessage: boolean; | ||
}) => css` | ||
display: flex; | ||
flex-direction: ${isMyMessage ? 'row-reverse' : 'row'}; | ||
gap: 1rem; | ||
`; | ||
|
||
export const messageContainer = ({ | ||
isMyMessage, | ||
}: { | ||
isMyMessage: boolean; | ||
}) => css` | ||
display: flex; | ||
flex-direction: column; | ||
${isMyMessage && 'align-items: flex-end'} | ||
`; | ||
|
||
export const senderStyle = ({ theme }: { theme: Theme }) => css` | ||
${theme.typography.Medium} | ||
color:${theme.colorPalette.grey[900]}; | ||
`; | ||
|
||
export const messageStyle = ({ | ||
theme, | ||
isMyMessage, | ||
}: { | ||
theme: Theme; | ||
isMyMessage: boolean; | ||
}) => css` | ||
${theme.typography.b4}; | ||
display: inline-block; | ||
|
||
max-width: 25rem; | ||
padding: 10px; | ||
|
||
word-break: break-all; | ||
|
||
background-color: ${isMyMessage | ||
? theme.colorPalette.yellow[200] | ||
: theme.colorPalette.orange[100]}; | ||
border-radius: ${isMyMessage ? '12px' : 0} ${isMyMessage ? 0 : '12px'} 12px | ||
12px; | ||
`; | ||
|
||
export const timeStyle = ({ theme }: { theme: Theme }) => css` | ||
${theme.typography.c3} | ||
color:${theme.colorPalette.grey[400]}; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { | ||
ChatMessageStyle, | ||
messageContainer, | ||
messageStyle, | ||
senderStyle, | ||
timeStyle, | ||
} from './ChatMessage.style'; | ||
|
||
import UserPreview from '@_components/UserPreview/UserPreview'; | ||
import { formatHhmmToKoreanWithPrefix } from '@_utils/formatters'; | ||
import { useTheme } from '@emotion/react'; | ||
|
||
export interface ChatMessageProps { | ||
sender: string; | ||
message: string; | ||
isMyMessage: boolean; | ||
time: string; | ||
imageUrl?: string; | ||
} | ||
|
||
export default function ChatMessage(props: ChatMessageProps) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 메시지를 하나만 구현해서 내가 작성한 글이면 오른쪽 정렬, 아니면 왼쪽정렬하게 구현했어요. 근데 컴포넌트를 내가 작성한 채팅, 상대방이 작성한 컴포넌트로 분리할 수도 있겠다는 생각도 드네요 이건 차차 흘러가는 부분에 따라 함께 고민해보아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 이것도 괜찮다고 생각해요 ui가 다르면 분리하는게 맞을것 같은데 같으니 boolean으로 재사용할 수 있어서 좋은 것 같아요. 저도 고민해보겠습니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 하나로 두는 것이 괜찮을 것 같아요~ |
||
const { sender, message, isMyMessage, time, imageUrl } = props; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 컴포넌트 이름으로 그냥 |
||
const theme = useTheme(); | ||
return ( | ||
<div css={ChatMessageStyle({ isMyMessage })}> | ||
<UserPreview imageUrl={imageUrl} /> | ||
<div css={messageContainer({ isMyMessage })}> | ||
<span css={senderStyle({ theme })}>{sender}</span> | ||
<div css={messageStyle({ theme, isMyMessage })}>{message}</div> | ||
<span css={timeStyle({ theme })}> | ||
{formatHhmmToKoreanWithPrefix(time)} | ||
</span> | ||
</div> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import ChattingFooter from './ChattingFooter'; | ||
|
||
const meta: Meta<typeof ChattingFooter> = { | ||
component: ChattingFooter, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof ChattingFooter>; | ||
|
||
export const Default: Story = { | ||
args: { onSubmit: (string: string) => alert(string) }, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Theme, css } from '@emotion/react'; | ||
|
||
export const footer = ({ theme }: { theme: Theme }) => css` | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-around; | ||
|
||
height: 7rem; | ||
|
||
background-color: ${theme.colorPalette.white[100]}; | ||
box-shadow: 0 -10px 15px rgb(0 0 0 / 20%); | ||
`; | ||
|
||
export const menuButton = ({ theme }: { theme: Theme }) => css` | ||
width: 4.5rem; | ||
height: 4.5rem; | ||
|
||
background-color: ${theme.colorPalette.orange[300]}; | ||
border: 0; | ||
border-radius: 50%; | ||
`; | ||
|
||
export const messageForm = ({ theme }: { theme: Theme }) => css` | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-between; | ||
|
||
width: 80%; | ||
height: 70%; | ||
padding: 1rem 2rem; | ||
|
||
background: ${theme.colorPalette.grey[200]}; | ||
border-radius: 50px; | ||
`; | ||
|
||
export const messageInput = ({ theme }: { theme: Theme }) => css` | ||
${theme.typography.s2} | ||
width: 100%; | ||
background: rgb(0 0 0 / 0%); | ||
border: 0; | ||
outline: none; | ||
`; | ||
|
||
export const sendingButton = css` | ||
background: rgb(0 0 0 / 0%); | ||
border: 0; | ||
`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
부모의 height에 따라 컴포넌트의 사이즈가 변경되는 지 확인하기 위한 부분입니다.