Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed src/api/.gitkeep
Empty file.
Empty file removed src/assets/.gitkeep
Empty file.
Empty file removed src/components/.gitkeep
Empty file.
90 changes: 90 additions & 0 deletions src/components/chat/ChatInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useState } from 'react';

const AddIcon: React.FC = () => (
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0.5C3.5888 0.5 0 4.0888 0 8.50001C0 12.9112 3.5888 16.5 8 16.5C12.4112 16.5 16 12.9112 16 8.50001C16 4.0888 12.4112 0.5 8 0.5ZM12 9.30001H8.8V12.5H7.2V9.30001H4V7.70001H7.2V4.5H8.8V7.70001H12V9.30001Z" fill="#B9BBBE"/>
</svg>
);

const EmojiIcon: React.FC = () => (
<svg width="58" height="21" viewBox="0 0 58 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.14258 19C13.837 19 17.6426 15.1944 17.6426 10.5C17.6426 5.80558 13.837 2 9.14258 2C4.44816 2 0.642578 5.80558 0.642578 10.5C0.642578 15.1944 4.44816 19 9.14258 19Z" fill="#B9BBBE"/>
</svg>
);

const DividerIcon: React.FC = () => (
<svg width="1" height="21" viewBox="0 0 1 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 0V21" stroke="#4F545C"/>
</svg>
);

type ReplyIconProps = {
onReply: () => void;
};

const ReplyIcon: React.FC<ReplyIconProps> = ({ onReply }) => (
<button onClick={onReply} className="hover:opacity-80 transition-opacity">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 2L5 7L10 12" stroke="#B9BBBE" strokeWidth="2"/>
</svg>
</button>
);

type ChatInputProps = {
onSendMessage: (message: string) => void;
};

const ChatInput: React.FC<ChatInputProps> = ({ onSendMessage }) => {
const [message, setMessage] = useState('');
const [replyTo, setReplyTo] = useState<string | null>(null);

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setMessage(event.target.value);
};

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.key === 'Enter' && message.trim() !== '') {
onSendMessage(message);
setMessage('');
setReplyTo(null);
}
};

const handleReply = () => {
setReplyTo("Replying to last message...");
};

return (
<div className="w-full max-w-[931px] h-[39px] px-[13px] py-[9px] bg-[#40444b] rounded-[7px] flex items-center gap-3">
<button>
<AddIcon />
</button>

<div className="flex-grow flex flex-col">
{replyTo && (
<div className="text-[#B9BBBE] text-xs italic mb-1">
{replyTo}
</div>
)}
<input
type="text"
value={message}
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder="Type a message..."
className="w-full bg-transparent text-[#dcddde] text-xs font-medium placeholder-[#72767D] outline-none"
/>
</div>

<button>
<EmojiIcon />
</button>

<DividerIcon />

<ReplyIcon onReply={handleReply} />
</div>
);
};

export default ChatInput;
66 changes: 66 additions & 0 deletions src/components/chat/Message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';

type AvatarProps = {
imageUrl: string;
altText: string;
};

const Avatar: React.FC<AvatarProps> = ({ imageUrl, altText }) => {
return (
<div className="w-[35px] h-[35px] relative">
<div className="w-[35px] h-[35.51px] left-0 top-0 absolute rounded-full bg-gray-500" />
<img
className="w-[31px] h-[30.94px] left-[2px] top-[2.03px] absolute rounded-full"
src={imageUrl}
alt={altText}
/>
</div>
);
};

type MessageHeaderProps = {
username: string;
timestamp: string;
};

const MessageHeader: React.FC<MessageHeaderProps> = ({ username, timestamp }) => {
return (
<div className="justify-start items-end gap-1.5 inline-flex">
<div className="text-white text-xs font-semibold font-['Whitney Semibold']">{username}</div>
<div className="text-[#72767d] text-[9px] font-medium font-['Whitney']">{timestamp}</div>
</div>
);
};

type MessageContentProps = {
content: string;
};

const MessageContent: React.FC<MessageContentProps> = ({ content }) => {
return (
<div className="justify-start items-start inline-flex">
<div className="text-[#dcddde] text-xs font-medium font-['Whitney']">{content}</div>
</div>
);
};

type MessageProps = {
avatarUrl: string;
username: string;
timestamp: string;
content: string;
};

const Message: React.FC<MessageProps> = ({ avatarUrl, username, timestamp, content }) => {
return (
<div className="h-[35px] justify-start items-start gap-[9px] inline-flex">
<Avatar imageUrl={avatarUrl} altText="User avatar" />
<div className="flex-col justify-start items-start gap-[5px] inline-flex">
<MessageHeader username={username} timestamp={timestamp} />
<MessageContent content={content} />
</div>
</div>
);
};

export default Message;
58 changes: 58 additions & 0 deletions src/components/chat/Reply.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';

const MentionIcon: React.FC = () => {
return (
<svg width="26" height="9" viewBox="0 0 26 9" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 9V6C1 3.23858 3.23858 1 6 1H25.5" stroke="#72767D" />
</svg>
);
};

type MentionAvatarProps = {
avatarUrl: string;
};

const MentionAvatar: React.FC<MentionAvatarProps> = ({ avatarUrl }) => {
return (
<div className="w-3.5 h-3.5 relative opacity-90">
<div className="w-3.5 h-[14.20px] left-0 top-0 absolute rounded-full bg-gray-500" />
<img className="w-[12.40px] h-[12.38px] left-[0.80px] top-[0.81px] absolute rounded-full" src={avatarUrl} alt="Mention avatar" />
</div>
);
};

type MentionTextProps = {
username: string;
message: string;
};

const MentionText: React.FC<MentionTextProps> = ({ username, message }) => {
return (
<div className="justify-start items-end gap-[3px] flex">
<div className="opacity-80 text-white text-[10px] font-bold font-['Whitney']">@{username}</div>
<div className="opacity-50 text-[#dcddde] text-[9px] font-medium font-['Whitney']">{message}</div>
</div>
);
};

type MentionMessageProps = {
avatarUrl: string;
username: string;
message: string;
};

const MentionMessage: React.FC<MentionMessageProps> = ({ avatarUrl, username, message }) => {
return (
<div className="h-3.5 pl-[18px] pr-px justify-start items-end gap-0.5 inline-flex">
<div data-svg-wrapper>
<MentionIcon />
</div>
<div className="justify-start items-center gap-0.5 flex">
<MentionAvatar avatarUrl={avatarUrl} />
<MentionText username={username} message={message} />
</div>
</div>
);
};

export default MentionMessage;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/pages/Login/components/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { signIn } from "@api/authService.ts";
import { FieldInfos, FieldValue } from "src/types/LoginTypes";
import { isEmptyString } from "@utils/stringValidations.ts";
import useForm from "@hooks/useForm";
import LoginTextInput from "@components/LoginTextInput";
import LoginTextInput from "@components/user/LoginTextInput.tsx";

const fieldInfos: FieldInfos = {
email: {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/SignupPage/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import DropDown from "@components/DropDown";
import DropDown from "@components/shared/DropDown.tsx";
import { useState } from "react";

type DatePickerProps = {
Expand Down
8 changes: 4 additions & 4 deletions src/pages/SignupPage/SignupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import {
isName,
} from "@utils/stringValidations.ts";
import useForm from "@hooks/useForm.ts";
import Button from "@components/Button.tsx";
import Checkbox from "@components/Checkbox.tsx";
import Button from "@components/shared/Button.tsx";
import Checkbox from "@components/shared/Checkbox.tsx";
import DatePicker from "./DatePicker.tsx";
import LoginLabel from "@components/LoginLabel.tsx";
import LoginTextInput from "@components/LoginTextInput.tsx";
import LoginLabel from "@components/user/LoginLabel.tsx";
import LoginTextInput from "@components/user/LoginTextInput.tsx";

import type { FieldInfos, FieldValue } from "src/types/LoginTypes";

Expand Down
63 changes: 50 additions & 13 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,49 @@ export default {
'./src/App.tsx',
],
theme: {
fontSize: {
lg: '16px',
base: '14px',
sm: '12px',
},
extend: {
fontFamily: {
sans: ["gg sans", "sans-serif"],
display: ["ABC Ginto Nord Trial", "sans-serif"],
regular: ['gg sans Regular', 'sans-serif'],
bold: ['gg sans Bold', 'sans-serif'],
medium: ['gg sans Medium', 'sans-serif'],
semibold: ['gg sans Semibold', 'sans-serif'],
kr: ['NotoSansKR-VariableFont_wght', 'sans-serif'],
},
fontSize: {
"heading-sm": "0.875rem", // 14px
"heading-md": "1rem", // 16px
"heading-lg": "1.25rem", // 20px
"heading-xl": "1.5rem", // 24px
"heading-xxl": "2rem", // 32px
"text-xxs": "0.625rem", // 10px
"text-xs": "0.75rem", // 12px
"text-sm": "0.875rem", // 14px
"text-md": "1rem", // 16px
"text-lg": "1.25rem", // 20px
"display-sm": "1.5rem", // 24px
"display-md": "2.125rem", // 34px
"display-lg": "2.75rem", // 44px
lg: '16px',
base: '14px',
sm: '12px',
},
fontWeight: {
normal: "400",
medium: "500",
semibold: "600",
bold: "700",
extrabold: "800",
black: "900",
},
lineHeight: {
none: "1",
tight: "1.1",
snug: "1.2",
normal: "1.5",
relaxed: "1.75",
},
colors: {
'wrapper': '#313338',
'sidebar': '#2E3036',
Expand All @@ -21,13 +58,13 @@ export default {
'des': '#DCDDDE',
'primary': '#5865F2',
'panel': '#292b2f',
},
fontFamily: {
regular: ['gg sans Regular', 'sans-serif'],
bold: ['gg sans Bold', 'sans-serif'],
medium: ['gg sans Medium', 'sans-serif'],
semibold: ['gg sans Semibold', 'sans-serif'],
kr: ['NotoSansKR-VariableFont_wght', 'sans-serif'],
'blurple': '#5865F2', // CMYK 80, 60, 0, 0
'green': '#57F287', // CMYK 50, 0, 55, 0
'yellow': '#FEE75C', // CMYK 0, 5, 80, 0
'fuchsia': '#EB459E', // CMYK 0, 90, 0, 0
'red': '#ED4245', // CMYK 0, 90, 65, 0
'white': '#FFFFFF', // CMYK 0, 0, 0, 0
'black': '#000000', // CMYK 35, 0, 0, 100
},
width: {
'wrapper': '72px',
Expand All @@ -37,4 +74,4 @@ export default {
},
},
plugins: [],
}
};