From c5258f80684d1e28bd1bc20c345335a29c304302 Mon Sep 17 00:00:00 2001
From: Maria Rushkova <66270386+mrushkova@users.noreply.github.com>
Date: Tue, 28 Sep 2021 13:36:56 +0200
Subject: [PATCH] Add channels and improve styles (#15)
---
.../react-chat/src/components/Channels.tsx | 225 +++++++++++++++++-
packages/react-chat/src/components/Chat.tsx | 26 +-
.../src/components/Chat/ChatBody.tsx | 36 ++-
.../src/components/Chat/ChatInput.tsx | 53 +++--
.../src/components/Chat/ChatMessages.tsx | 95 ++++----
.../react-chat/src/components/Members.tsx | 14 +-
.../react-chat/src/components/ReactChat.tsx | 2 +-
.../react-chat/src/helpers/channelsMock.ts | 32 +++
packages/react-chat/src/styles/themes.ts | 12 +
9 files changed, 405 insertions(+), 90 deletions(-)
create mode 100644 packages/react-chat/src/helpers/channelsMock.ts
diff --git a/packages/react-chat/src/components/Channels.tsx b/packages/react-chat/src/components/Channels.tsx
index 817f4cc..77813c6 100644
--- a/packages/react-chat/src/components/Channels.tsx
+++ b/packages/react-chat/src/components/Channels.tsx
@@ -1,18 +1,235 @@
import React from "react";
import styled from "styled-components";
+import { ChannelData, channels } from "../helpers/channelsMock";
import { Theme } from "../styles/themes";
interface ChannelsProps {
theme: Theme;
+ icon: string;
+ name: string;
+ members: number;
+ setActiveChannel: (val: ChannelData) => void;
+ activeChannelId: number;
}
-export function Channels({ theme }: ChannelsProps) {
- return Channels;
+export function Channels({
+ theme,
+ icon,
+ name,
+ members,
+ setActiveChannel,
+ activeChannelId,
+}: ChannelsProps) {
+ return (
+
+
+
+
+ {name}
+ {members} members
+
+
+
+ {channels.map((channel) => (
+ {
+ setActiveChannel(channel);
+ }}
+ />
+ ))}
+
+
+ );
}
-const ChannelsWrapper = styled.div`
- width: 33%;
+interface ChannelProps {
+ theme: Theme;
+ channel: ChannelData;
+ isActive: boolean;
+ activeView?: boolean;
+ onClick?: () => void;
+}
+
+export function Channel({
+ theme,
+ channel,
+ isActive,
+ activeView,
+ onClick,
+}: ChannelProps) {
+ return (
+
+
+
+ {!channel.icon && channel.name.slice(0, 1).toUpperCase()}
+
+
+
+ # {channel.name}
+
+ {activeView && (
+
+ {" "}
+ {channel.members} members
+
+ )}
+
+
+ {channel.notifications && !activeView && (
+
+ {channel.notifications}
+
+ )}
+
+ );
+}
+interface ThemeProps {
+ theme: Theme;
+}
+
+const ChannelsWrapper = styled.div`
+ width: 21%;
height: 100%;
background-color: ${({ theme }) => theme.sectionBackgroundColor};
+ padding: 10px 0.6%;
+ display: flex;
+ flex-direction: column;
+`;
+
+const Community = styled.div`
+ display: flex;
+ margin-bottom: 16px;
+`;
+
+const CommunityLogo = styled.img`
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ margin-left: 10px;
+`;
+
+const CommunityInfo = styled.div`
+ display: flex;
+ flex-direction: column;
+ margin-left: 8px;
+`;
+
+const CommunityName = styled.h1`
+ font-weight: 500;
+ font-size: 15px;
+ line-height: 22px;
+ color: ${({ theme }) => theme.textPrimaryColor};
+`;
+
+const MembersAmount = styled.p`
+ font-size: 12px;
+ line-height: 16px;
+ letter-spacing: 0.1px;
+ color: ${({ theme }) => theme.textSecondaryColor};
+`;
+
+const ChannelList = styled.div`
+ display: flex;
+ flex-direction: column;
+`;
+
+const ChannelWrapper = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px;
+ cursor: pointer;
+
+ &.active {
+ background-color: ${({ theme }) => theme.activeChannelBackground};
+ border-radius: 8px;
+ }
+`;
+
+const ChannelInfo = styled.div`
+ display: flex;
+ align-items: center;
+`;
+
+const ChannelTextInfo = styled.div`
+ display: flex;
+ flex-direction: column;
+`;
+
+const ChannelLogo = styled.div`
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 10px;
+ border-radius: 50%;
+ font-weight: bold;
+ font-size: 15px;
+ line-height: 20px;
+ background-color: ${({ theme }) => theme.iconColor};
+ background-size: cover;
+ background-repeat: no-repeat;
+ color: ${({ theme }) => theme.iconTextColor};
+
+ &.active {
+ width: 36px;
+ height: 36px;
+ font-size: 20px;
+ line-height: 20px;
+ }
+`;
+
+const ChannelName = styled.p`
+ color: ${({ theme }) => theme.textPrimaryColor};
+ font-weight: 500;
+ font-size: 15px;
+ line-height: 22px;
+ opacity: 0.7;
+
+ &.active,
+ &.notified {
+ opacity: 1;
+ }
+
+ &.muted {
+ opacity: 0.4;
+ }
+
+ &.notified {
+ font-weight: 600;
+ }
+`;
+
+const NotificationBagde = styled.div`
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ font-size: 12px;
+ line-height: 16px;
+ background-color: ${({ theme }) => theme.notificationColor};
+ color: ${({ theme }) => theme.bodyBackgroundColor};
+ display: flex;
+ align-items: center;
+ justify-content: center;
`;
diff --git a/packages/react-chat/src/components/Chat.tsx b/packages/react-chat/src/components/Chat.tsx
index a58d01c..3249760 100644
--- a/packages/react-chat/src/components/Chat.tsx
+++ b/packages/react-chat/src/components/Chat.tsx
@@ -1,6 +1,7 @@
-import React from "react";
+import React, { useState } from "react";
import styled from "styled-components";
+import { ChannelData, channels } from "../helpers/channelsMock";
import { Theme } from "../styles/themes";
import { Channels } from "./Channels";
@@ -9,16 +10,27 @@ import { Members } from "./Members";
interface ChatProps {
theme: Theme;
- channels?: boolean;
- members?: boolean;
+ channelsON?: boolean;
+ membersON?: boolean;
}
-export function Chat({ theme, channels, members }: ChatProps) {
+export function Chat({ theme, channelsON, membersON }: ChatProps) {
+ const [activeChannel, setActiveChannel] = useState(channels[0]);
+
return (
- {channels && }
-
- {members && }
+ {channelsON && (
+
+ )}
+
+ {membersON && }
);
}
diff --git a/packages/react-chat/src/components/Chat/ChatBody.tsx b/packages/react-chat/src/components/Chat/ChatBody.tsx
index 5942c25..7efb985 100644
--- a/packages/react-chat/src/components/Chat/ChatBody.tsx
+++ b/packages/react-chat/src/components/Chat/ChatBody.tsx
@@ -1,12 +1,20 @@
import React, { useCallback, useState } from "react";
import styled from "styled-components";
+import { ChannelData } from "../../helpers/channelsMock";
+import { Theme } from "../../styles/themes";
+import { Channel } from "../Channels";
import { ChatMessage } from "../models/ChatMessage";
import { ChatInput } from "./ChatInput";
import { ChatMessages } from "./ChatMessages";
-export function ChatBody() {
+interface ChatBodyProps {
+ theme: Theme;
+ channel: ChannelData;
+}
+
+export function ChatBody({ theme, channel }: ChatBodyProps) {
const [messages, setMessages] = useState([]);
const addMessage = useCallback(
@@ -20,16 +28,32 @@ export function ChatBody() {
);
return (
-
-
-
+
+
+
+
+
+
);
}
+interface ThemeProps {
+ theme: Theme;
+}
-const ChatBodyWrapper = styled.div`
+const ChatBodyWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
flex: 1;
height: 100%;
- max-width: 50%;
background: ${({ theme }) => theme.bodyBackgroundColor};
`;
+
+const ChannelWrapper = styled.div`
+ padding-left: 8px;
+`;
diff --git a/packages/react-chat/src/components/Chat/ChatInput.tsx b/packages/react-chat/src/components/Chat/ChatInput.tsx
index cbce356..2355e0a 100644
--- a/packages/react-chat/src/components/Chat/ChatInput.tsx
+++ b/packages/react-chat/src/components/Chat/ChatInput.tsx
@@ -1,41 +1,56 @@
import React, { useState } from "react";
import styled from "styled-components";
+import { Theme } from "../../styles/themes";
+
type ChatInputProps = {
+ theme: Theme;
addMessage: (message: string) => void;
};
-export function ChatInput({ addMessage }: ChatInputProps) {
+export function ChatInput({ theme, addMessage }: ChatInputProps) {
const [content, setContent] = useState("");
return (
- setContent(e.target.value)}
- onKeyPress={(e) => {
- if (e.key == "Enter") {
- addMessage(content);
- setContent("");
- }
- }}
- />
+
+ setContent(e.target.value)}
+ onKeyPress={(e) => {
+ if (e.key == "Enter") {
+ addMessage(content);
+ setContent("");
+ }
+ }}
+ />
+
);
}
-const Input = styled.input`
+interface ThemeProps {
+ theme: Theme;
+}
+
+const InputWrapper = styled.div`
+ display: flex;
+ padding: 6px 8px 6px 10px;
+`;
+const Input = styled.input`
width: 100%;
- margin-left: 8px;
- margin-right: 8px;
- margin-bottom: 4px;
+ margin-left: 10px;
height: 40px;
- background: #eef2f5;
+ background: ${({ theme }) => theme.inputColor};
border-radius: 36px 16px 4px 36px;
- border: 0px;
+ border: 1px solid ${({ theme }) => theme.inputColor};
padding-left: 12px;
outline: none;
+ font-size: 15px;
+ line-height: 22px;
&:focus {
- border: 1px solid grey;
+ outline: none;
+ caret-color: ${({ theme }) => theme.notificationColor};
}
`;
diff --git a/packages/react-chat/src/components/Chat/ChatMessages.tsx b/packages/react-chat/src/components/Chat/ChatMessages.tsx
index e9d383e..c03601a 100644
--- a/packages/react-chat/src/components/Chat/ChatMessages.tsx
+++ b/packages/react-chat/src/components/Chat/ChatMessages.tsx
@@ -1,13 +1,15 @@
import React, { useEffect, useRef } from "react";
import styled from "styled-components";
+import { Theme } from "../../styles/themes";
import { ChatMessage } from "../models/ChatMessage";
type ChatMessagesProps = {
messages: ChatMessage[];
+ theme: Theme;
};
-export function ChatMessages({ messages }: ChatMessagesProps) {
+export function ChatMessages({ messages, theme }: ChatMessagesProps) {
const ref = useRef(null);
useEffect(() => {
if (ref && ref.current) {
@@ -19,15 +21,15 @@ export function ChatMessages({ messages }: ChatMessagesProps) {
{messages.map((message) => (
-
-
-
+
- {message.sender}
- {message.date.toLocaleTimeString()}
+ {message.sender}
+
+ {message.date.toLocaleTimeString()}
+
- {message.content}
+ {message.content}
))}
@@ -35,64 +37,59 @@ export function ChatMessages({ messages }: ChatMessagesProps) {
);
}
-const MessageText = styled.div`
- overflow-wrap: anywhere;
+interface ThemeProps {
+ theme: Theme;
+}
+
+const MessagesWrapper = styled.div`
+ height: calc(100% - 44px);
+ overflow: auto;
+ padding: 8px 16px 0;
+`;
+
+const MessageWrapper = styled.div`
width: 100%;
-`;
-
-const MessageHeaderWrapper = styled.div`
display: flex;
-`;
-
-const TimeWrapper = styled.div`
- font-family: Inter;
- font-style: normal;
- font-weight: normal;
- font-size: 10px;
- line-height: 14px;
- letter-spacing: 0.2px;
- text-transform: uppercase;
- color: #939ba1;
-
- text-align: center;
- margin-top: auto;
- margin-bottom: auto;
- margin-left: 4px;
-`;
-
-const UserNameWrapper = styled.div`
- font-family: Inter;
- font-style: normal;
- font-weight: 500;
- font-size: 15px;
- line-height: 22px;
+ align-items: center;
+ padding: 8px 0;
+ margin-bottom: 8px;
`;
const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
+ margin-left: 8px;
+`;
+
+const MessageHeaderWrapper = styled.div`
+ display: flex;
+ align-items: center;
`;
const Icon = styled.div`
width: 40px;
height: 40px;
border-radius: 50%;
- background-color: blue;
+ background-color: #bcbdff;
`;
-const IconWrapper = styled.div`
- margin-left: 16px;
- margin-right: 8px;
+const UserNameWrapper = styled.div`
+ font-size: 15px;
+ line-height: 22px;
+ color: ${({ theme }) => theme.memberNameColor};
`;
-const MessageWrapper = styled.div`
+const TimeWrapper = styled.div`
+ font-size: 10px;
+ line-height: 14px;
+ letter-spacing: 0.2px;
+ text-transform: uppercase;
+ color: ${({ theme }) => theme.textSecondaryColor};
+ margin-left: 4px;
+`;
+
+const MessageText = styled.div`
+ overflow-wrap: anywhere;
width: 100%;
- display: flex;
- margin-top: 8px;
- margin-bottom: 8px;
-`;
-
-const MessagesWrapper = styled.div`
- height: calc(100% - 44px);
- overflow: auto;
+ color: ${({ theme }) => theme.textPrimaryColor};
`;
diff --git a/packages/react-chat/src/components/Members.tsx b/packages/react-chat/src/components/Members.tsx
index 9c6e9aa..758a7ed 100644
--- a/packages/react-chat/src/components/Members.tsx
+++ b/packages/react-chat/src/components/Members.tsx
@@ -1,12 +1,18 @@
import React from "react";
import styled from "styled-components";
-export function Members() {
- return ;
+import { Theme } from "../styles/themes";
+
+interface MembersProps {
+ theme: Theme;
}
-const MembersWrapper = styled.div`
- width: 33%;
+export function Members({ theme }: MembersProps) {
+ return Members;
+}
+
+const MembersWrapper = styled.div`
+ width: 18%;
height: 100%;
background-color: ${({ theme }) => theme.sectionBackgroundColor};
`;
diff --git a/packages/react-chat/src/components/ReactChat.tsx b/packages/react-chat/src/components/ReactChat.tsx
index d9d25d3..1d68426 100644
--- a/packages/react-chat/src/components/ReactChat.tsx
+++ b/packages/react-chat/src/components/ReactChat.tsx
@@ -9,7 +9,7 @@ export function ReactChat() {
return (
-
+
);
}
diff --git a/packages/react-chat/src/helpers/channelsMock.ts b/packages/react-chat/src/helpers/channelsMock.ts
new file mode 100644
index 0000000..c0f5070
--- /dev/null
+++ b/packages/react-chat/src/helpers/channelsMock.ts
@@ -0,0 +1,32 @@
+export type ChannelData = {
+ id: number;
+ name: string;
+ icon?: string;
+ members: number;
+ notifications?: number;
+};
+
+export const channels = [
+ {
+ id: 1,
+ name: "welcome",
+ icon: "https://www.cryptokitties.co/icons/logo.svg",
+ members: 7,
+ },
+ {
+ id: 2,
+ name: "general",
+ members: 15,
+ },
+ {
+ id: 3,
+ name: "beginners",
+ members: 3,
+ notifications: 1,
+ },
+ {
+ id: 4,
+ name: "random",
+ members: 6,
+ },
+];
diff --git a/packages/react-chat/src/styles/themes.ts b/packages/react-chat/src/styles/themes.ts
index ad3b550..ee83d79 100644
--- a/packages/react-chat/src/styles/themes.ts
+++ b/packages/react-chat/src/styles/themes.ts
@@ -5,7 +5,11 @@ export type Theme = {
sectionBackgroundColor: string;
memberNameColor: string;
guestNameColor: string;
+ iconColor: string;
+ iconTextColor: string;
+ activeChannelBackground: string;
notificationColor: string;
+ inputColor: string;
};
export const lightTheme: Theme = {
@@ -15,7 +19,11 @@ export const lightTheme: Theme = {
sectionBackgroundColor: "#F6F8FA",
memberNameColor: "#4360DF",
guestNameColor: "#887AF9",
+ iconColor: "#D37EF4",
+ iconTextColor: "rgba(255, 255, 255, 0.7)",
+ activeChannelBackground: "#E9EDF1",
notificationColor: "#4360DF",
+ inputColor: "#EEF2F5",
};
export const darkTheme: Theme = {
@@ -25,7 +33,11 @@ export const darkTheme: Theme = {
sectionBackgroundColor: "#252525",
memberNameColor: "#88B0FF",
guestNameColor: "#887AF9",
+ iconColor: "#D37EF4",
+ iconTextColor: "rgba(0, 0, 0, 0.7)",
+ activeChannelBackground: "#2C2C2C",
notificationColor: "#887AF9",
+ inputColor: "#373737",
};
export default { lightTheme, darkTheme };