refactor: update UXs
This commit is contained in:
@@ -6,6 +6,7 @@ import Modal from "../Modal";
|
||||
import ChannelIcon from "../ChannelIcon";
|
||||
import Contact from "../Contact";
|
||||
import StyledWrapper from "./styled";
|
||||
import StyledCheckbox from "../../component/StyledCheckbox";
|
||||
import useFilteredUsers from "../../hook/useFilteredUsers";
|
||||
import { addChannel } from "../../../app/slices/channels";
|
||||
|
||||
@@ -103,10 +104,9 @@ export default function ChannelModal({ personal = false, closeModal }) {
|
||||
className="user"
|
||||
onClick={toggleCheckMember}
|
||||
>
|
||||
<input
|
||||
<StyledCheckbox
|
||||
readOnly
|
||||
checked={checked}
|
||||
type="checkbox"
|
||||
name="cb"
|
||||
id="cb"
|
||||
/>
|
||||
|
||||
@@ -41,7 +41,12 @@ const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
/* margin: 0 4px; */
|
||||
width: -webkit-fill-available;
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
background: rgba(116, 127, 141, 0.1);
|
||||
}
|
||||
> div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -55,10 +55,7 @@ export default function Contact({ interactive = true, status = "", uid = "" }) {
|
||||
if (!contacts) return null;
|
||||
const currUser = contacts.find((c) => c.uid == uid);
|
||||
return (
|
||||
<StyledWrapper
|
||||
className={`${interactive ? "interactive" : ""}`}
|
||||
title={currUser?.email}
|
||||
>
|
||||
<StyledWrapper className={`${interactive ? "interactive" : ""}`}>
|
||||
<div className="avatar">
|
||||
<Avatar url={currUser?.avatar} id={uid} alt="avatar" />
|
||||
<div className={`status ${status}`}></div>
|
||||
|
||||
@@ -6,9 +6,11 @@ import { useSelector, useDispatch } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { clearAuthData } from "../../app/slices/auth.data";
|
||||
import BASE_URL from "../../app/config";
|
||||
import { useLazyLogoutQuery } from "../../app/services/auth";
|
||||
|
||||
import Avatar from "./Avatar";
|
||||
const StyledWrapper = styled.div`
|
||||
background-color: #e5e5e5;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
@@ -57,14 +59,15 @@ export default function CurrentUser({ expand = true }) {
|
||||
}, [isSuccess]);
|
||||
|
||||
if (!user) return null;
|
||||
const { name } = user;
|
||||
const { name, uid } = user;
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="profile" title={name}>
|
||||
<img
|
||||
<Avatar
|
||||
onDoubleClick={handleLogout}
|
||||
title={name}
|
||||
src={`https://avatars.dicebear.com/api/adventurer-neutral/${name}.svg`}
|
||||
url={`${BASE_URL}/resource/avatar?uid=${uid}`}
|
||||
id={uid}
|
||||
alt="user avatar"
|
||||
className="avatar"
|
||||
/>
|
||||
@@ -42,6 +42,7 @@ const StyledMsg = styled.div`
|
||||
}
|
||||
}
|
||||
.down {
|
||||
user-select: text;
|
||||
color: #374151;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
@@ -94,7 +95,7 @@ export default function Message({
|
||||
const { data: contacts } = useGetContactsQuery();
|
||||
useEffect(() => {
|
||||
if (!unread) {
|
||||
avatarRef.current?.scrollIntoView(false);
|
||||
avatarRef.current?.scrollIntoView();
|
||||
}
|
||||
}, [unread]);
|
||||
|
||||
|
||||
@@ -45,7 +45,9 @@ const StyledWrapper = styled.div`
|
||||
right: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 4px;
|
||||
.item {
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
@@ -53,7 +55,10 @@ const StyledWrapper = styled.div`
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
padding: 12px;
|
||||
padding: 10px 8px;
|
||||
&:hover {
|
||||
background: rgba(116, 127, 141, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -31,6 +31,7 @@ const StyledSend = styled.div`
|
||||
width: 100%;
|
||||
position: relative;
|
||||
.content {
|
||||
resize: unset;
|
||||
outline: none;
|
||||
padding: 4px;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// import React from 'react'
|
||||
import styled from "styled-components";
|
||||
const Styled = styled.input`
|
||||
-webkit-appearance: none;
|
||||
/* Remove most all native input styles */
|
||||
appearance: none;
|
||||
/* Not removed via appearance */
|
||||
margin: 0;
|
||||
/* color: #1fe1f9; */
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #d0d5dd;
|
||||
border-radius: 6px;
|
||||
place-content: center;
|
||||
&::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: 4px;
|
||||
clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
|
||||
transform: scale(0);
|
||||
transform-origin: bottom left;
|
||||
transition: 120ms transform ease-in-out;
|
||||
box-shadow: inset 10px 10px #1fe1f9;
|
||||
}
|
||||
&:checked {
|
||||
border-color: #1fe1f9;
|
||||
&:before {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
`;
|
||||
export default function StyledCheckbox(props) {
|
||||
return <Styled {...props} type="checkbox" />;
|
||||
}
|
||||
@@ -66,7 +66,26 @@ export default function ChannelChat({
|
||||
<span className="title">{name}</span>
|
||||
<span className="desc">{description}</span>
|
||||
</div>
|
||||
<ul className="members">members</ul>
|
||||
<ul className="opts">
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.alert.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.pin.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.people.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</StyledHeader>
|
||||
}
|
||||
contacts={
|
||||
|
||||
@@ -22,6 +22,20 @@ export const StyledHeader = styled.header`
|
||||
color: #616161;
|
||||
}
|
||||
}
|
||||
.opts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
.opt {
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const StyledNotification = styled.div`
|
||||
padding: 3px 8px;
|
||||
@@ -57,7 +71,7 @@ export const StyledContacts = styled.div`
|
||||
height: calc(100vh - 56px);
|
||||
overflow-y: scroll;
|
||||
background: #f5f6f7;
|
||||
padding: 16px;
|
||||
padding: 8px;
|
||||
`;
|
||||
export const StyledChannelChat = styled.article`
|
||||
position: relative;
|
||||
|
||||
@@ -22,11 +22,10 @@ const NavItem = ({ data, setFiles }) => {
|
||||
isActive: monitor.canDrop() && monitor.isOver(),
|
||||
}),
|
||||
}));
|
||||
const { id, is_public, name, description, unreads } = data;
|
||||
const { id, is_public, name, unreads } = data;
|
||||
return (
|
||||
<NavLink
|
||||
ref={drop}
|
||||
title={description}
|
||||
key={id}
|
||||
className={`link ${isActive ? "drop_over" : ""}`}
|
||||
to={`/chat/channel/${id}`}
|
||||
|
||||
@@ -36,6 +36,32 @@ export default function DMChat({ uid = "", dropFiles = [] }) {
|
||||
header={
|
||||
<StyledHeader>
|
||||
<Contact interactive={false} uid={currUser.uid} />
|
||||
<ul className="opts">
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.call.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.video.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.people.add.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
<li className="opt">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/icon.mark.read.svg"
|
||||
alt="opt icon"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</StyledHeader>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -27,6 +27,20 @@ export const StyledHeader = styled.header`
|
||||
color: #616161;
|
||||
}
|
||||
}
|
||||
.opts {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
.opt {
|
||||
cursor: pointer;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const StyledDMChat = styled.article`
|
||||
position: relative;
|
||||
|
||||
@@ -20,7 +20,9 @@ const StyledWrapper = styled.article`
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
.members {
|
||||
border-top: 1px solid transparent;
|
||||
box-shadow: inset 0px 10px 2px -10px rgba(0, 0, 0, 0.1);
|
||||
/* margin-top: 1px; */
|
||||
/* border-top: 1px solid transparent; */
|
||||
}
|
||||
}
|
||||
.drag_tip {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useGetContactsQuery } from "../../app/services/contact";
|
||||
import StyledWrapper from "./styled";
|
||||
import Search from "../../common/component/Search";
|
||||
import Avatar from "../../common/component/Avatar";
|
||||
import CurrentUser from "../../common/component/CurrentUser";
|
||||
import ChannelChat from "./ChannelChat";
|
||||
import DMChat from "./DMChat";
|
||||
import ChannelList from "./ChannelList";
|
||||
@@ -41,7 +42,11 @@ export default function ChatPage() {
|
||||
return Object.values(ChannelMsgData[gid] || {}).filter((m) => m.unread)
|
||||
.length;
|
||||
};
|
||||
|
||||
const handleToggleExpand = (evt) => {
|
||||
const { currentTarget } = evt;
|
||||
const listEle = currentTarget.parentElement.parentElement;
|
||||
listEle.classList.toggle("collapse");
|
||||
};
|
||||
if (!contacts) return null;
|
||||
const tmpSessionUser = contacts.find((c) => c.uid == user_id);
|
||||
const transformedChannels = Object.entries(channels).map(([key, obj]) => {
|
||||
@@ -72,8 +77,12 @@ export default function ChatPage() {
|
||||
<Search />
|
||||
<div className="list channels">
|
||||
<h3 className="title">
|
||||
<span className="txt">
|
||||
<AiOutlineCaretDown size={18} color="#78787C" />
|
||||
<span className="txt" onClick={handleToggleExpand}>
|
||||
<AiOutlineCaretDown
|
||||
className="icon"
|
||||
size={18}
|
||||
color="#78787C"
|
||||
/>
|
||||
CHANNELS
|
||||
</span>
|
||||
<MdAdd
|
||||
@@ -91,8 +100,12 @@ export default function ChatPage() {
|
||||
</div>
|
||||
<div className="list dms">
|
||||
<h3 className="title">
|
||||
<span className="txt">
|
||||
<AiOutlineCaretDown size={18} color="#78787C" />
|
||||
<span className="txt" onClick={handleToggleExpand}>
|
||||
<AiOutlineCaretDown
|
||||
className="icon"
|
||||
size={18}
|
||||
color="#78787C"
|
||||
/>
|
||||
DIRECT MESSAGE
|
||||
</span>
|
||||
<MdAdd
|
||||
@@ -125,6 +138,7 @@ export default function ChatPage() {
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
<CurrentUser />
|
||||
</div>
|
||||
<div className="right">
|
||||
{channel_id && (
|
||||
|
||||
@@ -3,6 +3,7 @@ const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
> .left {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 260px;
|
||||
@@ -26,6 +27,10 @@ const StyledWrapper = styled.div`
|
||||
line-height: 20px;
|
||||
color: #78787c;
|
||||
}
|
||||
.icon {
|
||||
transition: transform 0.5s ease;
|
||||
transform-origin: center;
|
||||
}
|
||||
}
|
||||
> .nav {
|
||||
display: flex;
|
||||
@@ -151,6 +156,14 @@ const StyledWrapper = styled.div`
|
||||
outline: 2px solid #52edff;
|
||||
}
|
||||
}
|
||||
&.collapse {
|
||||
.title .icon {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
> .nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
> .right {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { NavLink, useParams } from "react-router-dom";
|
||||
import { useGetContactsQuery } from "../../app/services/contact";
|
||||
import Search from "../../common/component/Search";
|
||||
import Contact from "../../common/component/Contact";
|
||||
import CurrentUser from "../../common/component/CurrentUser";
|
||||
import Profile from "./Profile";
|
||||
|
||||
import StyledWrapper from "./styled";
|
||||
@@ -28,6 +29,7 @@ export default function ContactsPage() {
|
||||
})}
|
||||
</nav>
|
||||
</div>
|
||||
<CurrentUser />
|
||||
</div>
|
||||
{user_id && (
|
||||
<div className="right">
|
||||
|
||||
@@ -3,6 +3,7 @@ const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
> .left {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 260px;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// import React from 'react'
|
||||
import styled from "styled-components";
|
||||
const StyledMenus = styled.ul`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
.menu {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
gap: 10px;
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
.txt {
|
||||
color: #4b5563;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
export default function Menu({ toggle, expand = true }) {
|
||||
return (
|
||||
<StyledMenus>
|
||||
<li className="menu">
|
||||
<img
|
||||
src="https://static.nicegoodthings.com/project/rustchat/menu.setting.png"
|
||||
alt="setting icon"
|
||||
className="icon"
|
||||
/>
|
||||
{expand && <span className="txt">Settings</span>}
|
||||
</li>
|
||||
<li className="menu" onClick={toggle}>
|
||||
<img
|
||||
src={
|
||||
expand
|
||||
? "https://static.nicegoodthings.com/project/rustchat/menu.toggle.collapse.png"
|
||||
: "https://static.nicegoodthings.com/project/rustchat/menu.toggle.expand.png"
|
||||
}
|
||||
alt="expand icon"
|
||||
className="icon"
|
||||
/>
|
||||
{expand && <span className="txt">Expand</span>}
|
||||
</li>
|
||||
</StyledMenus>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { HiChevronDoubleLeft } from "react-icons/hi";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
height: 56px;
|
||||
padding: 0 16px;
|
||||
padding: 0 20px;
|
||||
padding-right: 5px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -20,54 +20,26 @@ const StyledWrapper = styled.div`
|
||||
.logo {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 4px;
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
white-space: nowrap;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #4b5563;
|
||||
}
|
||||
}
|
||||
.arrow {
|
||||
cursor: pointer;
|
||||
transform-origin: center;
|
||||
transition: transform 0.5s ease-in-out;
|
||||
display: flex;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
transform: rotate(180deg);
|
||||
.icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&.expand {
|
||||
transform: rotate(0deg);
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: #1c1c1e;
|
||||
}
|
||||
}
|
||||
`;
|
||||
export default function ServerDropList({ data, toggle, expand = true }) {
|
||||
export default function ServerDropList({ data, expand = true }) {
|
||||
if (!data) return null;
|
||||
return (
|
||||
<StyledWrapper className={expand ? "expand" : ""}>
|
||||
<div className="server">
|
||||
<div className="logo">
|
||||
<img src={data.logo} alt="logo" />
|
||||
</div>
|
||||
<img className="logo" src={data.logo} alt="logo" />
|
||||
{expand && <h2 className="title">{data.name}</h2>}
|
||||
</div>
|
||||
<div onClick={toggle} className={`arrow ${expand ? "expand" : ""}`}>
|
||||
<HiChevronDoubleLeft className="icon" color="#BFBFBF" />
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,17 +34,17 @@ const StyledWrapper = styled.div`
|
||||
color: #4b5563;
|
||||
}
|
||||
.tool {
|
||||
padding: 5px 4px;
|
||||
.logo {
|
||||
border-radius: 5.5px;
|
||||
background: #fff;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.icon {
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
@@ -53,8 +53,8 @@ const StyledWrapper = styled.div`
|
||||
&.add .logo {
|
||||
background: none;
|
||||
.icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ import { toggleMenuExpand } from "../../app/slices/ui";
|
||||
import StyledWrapper from "./styled";
|
||||
import ServerDropList from "./ServerDropList";
|
||||
import Tools from "./Tools";
|
||||
import Menu from "./Menu";
|
||||
import usePreload from "./usePreload";
|
||||
|
||||
import CurrentUser from "./CurrentUser";
|
||||
// import CurrentUser from "./CurrentUser";
|
||||
|
||||
import ChatIcon from "../../assets/icons/chat.svg";
|
||||
import ContactIcon from "../../assets/icons/contact.svg";
|
||||
@@ -50,11 +51,7 @@ export default function HomePage() {
|
||||
/>
|
||||
<StyledWrapper>
|
||||
<div className={`col left ${menuExpand ? "expand" : ""}`}>
|
||||
<ServerDropList
|
||||
data={data?.server}
|
||||
expand={menuExpand}
|
||||
toggle={toggleExpand}
|
||||
/>
|
||||
<ServerDropList data={data?.server} expand={menuExpand} />
|
||||
<nav className="nav">
|
||||
<NavLink className="link" to={"/chat"}>
|
||||
<img src={ChatIcon} alt="chat icon" /> {menuExpand && `Chat`}
|
||||
@@ -64,8 +61,10 @@ export default function HomePage() {
|
||||
{menuExpand && `Contacts`}
|
||||
</NavLink>
|
||||
</nav>
|
||||
<div className="divider"></div>
|
||||
<Tools expand={menuExpand} />
|
||||
<CurrentUser expand={menuExpand} />
|
||||
<Menu toggle={toggleExpand} expand={menuExpand} />
|
||||
{/* <CurrentUser expand={menuExpand} /> */}
|
||||
</div>
|
||||
<div className="col right">
|
||||
<Outlet />
|
||||
|
||||
@@ -14,6 +14,12 @@ const StyledWrapper = styled.div`
|
||||
width: 64px;
|
||||
box-shadow: inset -1px 0px 0px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.5s ease-in;
|
||||
> .divider {
|
||||
width: -webkit-fill-available;
|
||||
height: 1px;
|
||||
background-color: #d4d4d4;
|
||||
margin: 8px 16px;
|
||||
}
|
||||
&.expand {
|
||||
width: 180px;
|
||||
}
|
||||
@@ -31,7 +37,7 @@ const StyledWrapper = styled.div`
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
text-decoration: none;
|
||||
padding: 10px 8px;
|
||||
padding: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
|
||||
Reference in New Issue
Block a user