feat: lots of updates

This commit is contained in:
zerosoul
2022-01-27 22:06:44 +08:00
commit e18c7323a6
72 changed files with 12432 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
// import React from 'react';
import styled from "styled-components";
import { AiOutlineCaretDown, AiOutlineSound } from "react-icons/ai";
import { MdOutlineKeyboardVoice } from "react-icons/md";
import { useSelector } from "react-redux";
const StyledWrapper = styled.div`
position: absolute;
bottom: 0;
left: 0;
padding: 16px 12px;
width: -webkit-fill-available;
display: flex;
align-items: center;
justify-content: space-between;
.profile {
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
gap: 5px;
.avatar {
width: 24px;
height: 24px;
border-radius: 50%;
}
.toggle {
}
}
.settings {
gap: 20px;
display: flex;
align-items: center;
justify-content: space-between;
.icon {
cursor: pointer;
}
}
`;
export default function CurrentUser({ collaspe = false }) {
const { user } = useSelector((store) => store.authData);
if (!user) return null;
const { name } = user;
return (
<StyledWrapper>
<div className="profile" title={name}>
<img
title={name}
src={`https://avatars.dicebear.com/api/adventurer-neutral/${name}.svg`}
alt="user avatar"
className="avatar"
/>
<AiOutlineCaretDown className="toggle" width={20} color="#C4C4C4" />
</div>
{!collaspe && (
<div className="settings">
<AiOutlineSound className="icon" size={15} color="#1C1C1E" />
<MdOutlineKeyboardVoice className="icon" size={15} color="#1C1C1E" />
</div>
)}
</StyledWrapper>
);
}
+71
View File
@@ -0,0 +1,71 @@
// import React from 'react';
import styled from "styled-components";
import { HiChevronDoubleLeft } from "react-icons/hi";
const StyledWrapper = styled.div`
height: 56px;
padding: 0 16px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.1);
&.collaspe {
padding-right: 5px;
}
.server {
display: flex;
align-items: center;
gap: 8px;
.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;
.icon {
width: 100%;
height: 100%;
}
&.collaspe {
transform: rotate(180deg);
}
}
`;
export default function ServerDropList({ data, toggle, collaspe = false }) {
if (!data) return null;
return (
<StyledWrapper className={collaspe ? "collaspe" : ""}>
<div className="server">
<div className="logo">
<img src={data.logo} alt="logo" />
</div>
{!collaspe && <h2 className="title">{data.name}</h2>}
</div>
<div onClick={toggle} className={`arrow ${collaspe ? "collaspe" : ""}`}>
<HiChevronDoubleLeft className="icon" color="#BFBFBF" />
</div>
</StyledWrapper>
);
}
+93
View File
@@ -0,0 +1,93 @@
// import React from 'react';
import { RiAddFill } from "react-icons/ri";
import styled from "styled-components";
import { IoLogoGithub } from "react-icons/io5";
const StyledWrapper = styled.div`
padding: 0 6px;
display: flex;
align-items: center;
flex-direction: column;
align-items: flex-start;
gap: 20px;
> hr {
border: none;
width: 40%;
height: 1px;
background: rgba(255, 255, 255, 0.2);
}
.tools {
padding: 0 10px;
display: flex;
flex-direction: column;
gap: 10px;
.tool,
.add {
cursor: pointer;
gap: 9px;
display: flex;
align-items: center;
font-weight: 600;
font-size: 14px;
line-height: 20px;
color: #4b5563;
}
.tool {
.logo {
border-radius: 5.5px;
background: #fff;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 21px;
height: 21px;
}
}
.title {
white-space: nowrap;
}
&.add .logo {
background: none;
.icon {
width: 40px;
height: 40px;
}
}
}
}
`;
export default function Tools({ collaspe = false }) {
return (
<StyledWrapper>
<hr />
<ul className="tools">
<li className="tool">
<div className="logo">
<img
className="icon"
src="https://static.nicegoodthings.com/project/ext/webrowse.logo.png"
alt="logo"
/>
</div>
{!collaspe && <h2 className="title">Webrowse</h2>}
</li>
<li className="tool">
<div className="logo">
<IoLogoGithub size={40} className="icon" />
</div>
{!collaspe && <h2 className="title">Github</h2>}
</li>
<li className="tool add">
<div className="logo">
<RiAddFill className="icon" size={40} color="#4B5563" />
</div>
{!collaspe && <h2 className="title">Add new app</h2>}
</li>
</ul>
</StyledWrapper>
);
}
+50
View File
@@ -0,0 +1,50 @@
// import React from 'react';
import { useState } from "react";
import StyledWrapper from "./styled";
import { Outlet, NavLink } from "react-router-dom";
import ServerDropList from "./ServerDropList";
import Tools from "./Tools";
import usePreload from "./usePreload";
import CurrentUser from "./CurrentUser";
import ChatIcon from "../../assets/icons/chat.svg";
import ContactIcon from "../../assets/icons/contact.svg";
import NotificationHub from "../../common/component/NotificationHub";
export default function HomePage() {
const { data, error, success } = usePreload();
const [collaspe, setCollaspe] = useState(false);
const toggleCollaspe = () => {
setCollaspe((prev) => !prev);
};
console.log({ data, error, success });
return (
<>
<NotificationHub />
<StyledWrapper>
<div className={`col left ${collaspe ? "collaspe" : ""}`}>
<ServerDropList
data={data?.server}
collaspe={collaspe}
toggle={toggleCollaspe}
/>
<nav className="nav">
<NavLink className="link" to={"/chat"}>
<img src={ChatIcon} alt="chat icon" /> {!collaspe && `Chat`}
</NavLink>
<NavLink className="link" to={"/contacts"}>
<img src={ContactIcon} alt="contact icon" />{" "}
{!collaspe && `Contacts`}
</NavLink>
</nav>
<Tools collaspe={collaspe} />
<CurrentUser collaspe={collaspe} />
</div>
<div className="col right">
<Outlet />
</div>
</StyledWrapper>
</>
);
}
+49
View File
@@ -0,0 +1,49 @@
import styled from "styled-components";
const StyledWrapper = styled.div`
display: flex;
width: 100vw;
height: 100vh;
background-color: #f5f6f7;
> .col {
height: 100%;
display: flex;
flex-direction: column;
&.left {
position: relative;
/* background: #0891B2; */
width: 180px;
box-shadow: inset -1px 0px 0px rgba(0, 0, 0, 0.1);
transition: all 0.5s ease-in;
&.collaspe {
width: 64px;
}
}
&.right {
width: 100%;
}
> .nav {
display: flex;
flex-direction: column;
gap: 4px;
padding: 24px 8px 10px 8px;
.link {
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
padding: 10px 8px;
font-weight: 600;
font-size: 14px;
line-height: 20px;
color: #4b5563;
border-radius: 8px;
&:hover,
&.active {
background-color: rgba(0, 0, 0, 0.08);
}
}
}
}
`;
export default StyledWrapper;
+39
View File
@@ -0,0 +1,39 @@
// import React from 'react';
import { useGetContactsQuery } from "../../app/services/contact";
import { useGetChannelsQuery } from "../../app/services/channel";
import { useGetServerQuery } from "../../app/services/server";
// pollingInterval: 0,
const querySetting = {
refetchOnMountOrArgChange: true,
};
export default function usePreload() {
const {
isLoading: contactsLoading,
isSuccess: contactsSuccess,
isError: contactsError,
data: contacts,
} = useGetContactsQuery(undefined, querySetting);
const {
isLoading: serverLoading,
isSuccess: serverSuccess,
isError: serverError,
data: server,
} = useGetServerQuery(undefined, querySetting);
const {
isLoading: groupsLoading,
isSuccess: groupsSuccess,
isError: groupsError,
data: groups,
} = useGetChannelsQuery(undefined, querySetting);
return {
loading: contactsLoading && groupsLoading && serverLoading,
error: contactsError && groupsError && serverError,
success: contactsSuccess && groupsSuccess && serverSuccess,
data: {
contacts,
server,
groups,
},
};
}