refactor: style with tailwind

This commit is contained in:
Tristan Yang
2022-12-30 14:39:25 +08:00
parent fbde6f3d92
commit 4a973ee07a
11 changed files with 41 additions and 264 deletions
-43
View File
@@ -1,43 +0,0 @@
import { useState, useEffect, memo, SyntheticEvent, FC, ImgHTMLAttributes } from "react";
import { getInitials, getInitialsAvatar } from "../utils";
interface Props extends ImgHTMLAttributes<HTMLImageElement> {
// className?: string;
// alt?: string;
// src?: string;
name?: string;
type?: "user" | "channel";
}
const Avatar: FC<Props> = ({ src = "", name = "Deleted User", type = "user", ...rest }) => {
const [url, setUrl] = useState("");
const handleError = (err: SyntheticEvent<HTMLImageElement>) => {
console.error("load avatar error", err);
const tmp = getInitialsAvatar({
initials: getInitials(name),
background: type == "channel" ? "#EAECF0" : undefined,
foreground: type == "channel" ? "#475467" : undefined
});
setUrl(tmp);
};
useEffect(() => {
if (!src) {
const tmp = getInitialsAvatar({
initials: getInitials(name),
background: type == "channel" ? "#EAECF0" : undefined,
foreground: type == "channel" ? "#475467" : undefined
});
setUrl(tmp);
} else {
setUrl(src);
}
}, [src, name]);
if (!url) return null;
return <img src={url} onError={handleError} {...rest} />;
};
export default memo(Avatar, (prev, next) => {
return prev.src == next.src;
});
+3 -27
View File
@@ -1,36 +1,12 @@
import styled from "styled-components";
import { FC } from "react"; import { FC } from "react";
const StyledDivider = styled.hr`
display: block;
position: relative;
border: 0;
border-top: 1px solid #e3e5e8;
margin: 25px 0;
overflow: visible;
&:before {
background: #fff;
padding: 2px 4px;
position: absolute;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
content: attr(data-content);
font-style: normal;
font-weight: 600;
font-size: 12px;
line-height: 18px;
color: #78787c;
}
`;
interface Props { interface Props {
content: string; content: string;
} }
const Divider: FC<Props> = ({ content }) => { const Divider: FC<Props> = ({ content }) => {
if (!content) return null; return <div className="relative border-none h-[1px] bg-[#e3e5e8] my-6 overflow-visible">
return <StyledDivider data-content={content}></StyledDivider>; <span className="p-1 absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 text-xs text-gray-500 font-semibold bg-white">{content}</span>
</div>;
}; };
export default Divider; export default Divider;
+4 -21
View File
@@ -1,21 +1,4 @@
import { FC, ReactEventHandler, useState } from "react"; import { FC, ReactEventHandler, useState } from "react";
import styled from "styled-components";
const Styled = styled.div`
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.err {
padding: 18px;
/* font-weight: bold; */
font-size: 16px;
color: #999;
}
audio {
width: 100%;
}
`;
interface Props { interface Props {
url: string; url: string;
@@ -31,13 +14,13 @@ const Audio: FC<Props> = ({ url }) => {
if (!url) return null; if (!url) return null;
return ( return (
<Styled> <div className="flex items-center justify-center h-full">
{err ? ( {err ? (
<div className="err">Unable to play this audio</div> <div className="p-[18px] text-base text-gray-500">Unable to play this audio</div>
) : ( ) : (
<audio controls src={url} onError={handleError} /> <audio className="w-full" controls src={url} onError={handleError} />
)} )}
</Styled> </div>
); );
}; };
+1 -13
View File
@@ -1,16 +1,4 @@
import { useState, useEffect, FC } from "react"; import { useState, useEffect, FC } from "react";
import styled from "styled-components";
const Styled = styled.div`
height: 218px;
padding: 15px 15px 0 15px;
line-height: 1.4;
overflow: scroll;
white-space: pre-wrap;
word-break: break-all;
background-color: #000;
color: #eee;
`;
interface Props { interface Props {
url: string; url: string;
@@ -29,7 +17,7 @@ const Code: FC<Props> = ({ url }) => {
}, [url]); }, [url]);
if (!content) return null; if (!content) return null;
return <Styled>{content}</Styled>; return <div className="h-[218px] p-[15px] pb-0 bg-black text-white overflow-scroll whitespace-pre-wrap break-all leading-snug">{content}</div>;
}; };
export default Code; export default Code;
+3 -16
View File
@@ -1,27 +1,14 @@
import React, { FC } from "react"; import React, { FC } from "react";
import styled from "styled-components";
const Styled = styled.div`
height: 218px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
`;
interface Props { interface Props {
url: string; url: string;
alt?: string; alt?: string;
} }
const Image: FC<Props> = ({ url, alt }) => { const Image: FC<Props> = ({ url, alt }) => {
if (!url) return null;
return ( return (
<Styled> <div className="h-[218px] overflow-hidden">
<img src={url} alt={alt} /> <img className="w-full h-full object-cover" src={url} alt={alt} />
</Styled> </div>
); );
}; };
+3 -23
View File
@@ -1,34 +1,14 @@
import styled from "styled-components";
import { FC } from "react"; import { FC } from "react";
const Styled = styled.div`
padding: 8px;
/* height: 218px; */
overflow: hidden;
embed {
width: 100%;
height: 100%;
}
`;
interface Props { interface Props {
url: string; url: string;
} }
const Pdf: FC<Props> = ({ url }) => { const Pdf: FC<Props> = ({ url }) => {
// const [content, setContent] = useState("");
// const [pageNumber, setPageNumber] = useState(1);
// const [numPages, setNumPages] = useState(null);
// const onDocumentLoadSuccess = ({ numPages }) => {
// setNumPages(numPages);
// };
return ( return (
<Styled> <div className="p-2 overflow-hidden">
<embed src={url} type="application/pdf" /> <embed className="w-full h-full" src={url} type="application/pdf" />
{/* <Document file={url} onLoadSuccess={onDocumentLoadSuccess}> </div>
<Page pageNumber={pageNumber} />
</Document> */}
</Styled>
); );
}; };
+3 -14
View File
@@ -1,24 +1,13 @@
import React, { FC } from "react"; import React, { FC } from "react";
import styled from "styled-components";
const Styled = styled.div`
height: 218px;
video {
width: 100%;
height: 100%;
object-fit: cover;
}
`;
interface Props { interface Props {
url: string; url: string;
} }
const Video: FC<Props> = ({ url }) => { const Video: FC<Props> = ({ url }) => {
return ( return (
<Styled> <div className="h-[218px]">
<video controls src={url} /> <video className="w-full h-full object-cover" controls src={url} />
</Styled> </div>
); );
}; };
+3 -18
View File
@@ -1,19 +1,4 @@
import { FC } from "react"; import { FC } from "react";
import styled from "styled-components";
const Styled = styled.div`
background: #ecfdff;
border-radius: 4px;
height: 8px;
overflow: hidden;
.progress {
transition: all 0.25s ease;
height: 8px;
background: #088ab2;
border-radius: 4px;
}
`;
interface Props { interface Props {
value: number; value: number;
width?: string; width?: string;
@@ -21,9 +6,9 @@ interface Props {
const Progress: FC<Props> = ({ value, width = "100%" }) => { const Progress: FC<Props> = ({ value, width = "100%" }) => {
return ( return (
<Styled style={{ width }}> <div className="bg-[#ecfdff] rounded h-2 overflow-hidden" style={{ width }}>
<div className="progress" style={{ width: `${value}%` }}></div> <div className="h-2 bg-[#088ab2] rounded transition-all" style={{ width: `${value}%` }}></div>
</Styled> </div>
); );
}; };
+4 -27
View File
@@ -1,4 +1,3 @@
import styled from "styled-components";
import InviteByEmail from "./InviteByEmail"; import InviteByEmail from "./InviteByEmail";
import AddMembers from "./AddMembers"; import AddMembers from "./AddMembers";
import CloseIcon from "../../../assets/icons/close.svg"; import CloseIcon from "../../../assets/icons/close.svg";
@@ -7,28 +6,6 @@ import { useAppSelector } from "../../../app/store";
import { FC } from "react"; import { FC } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
const Styled = styled.div`
display: flex;
flex-direction: column;
background: #fff;
box-shadow: 0 25px 50px rgba(31, 41, 55, 0.25);
border-radius: var(--br);
padding: 16px;
min-width: 408px;
> .title {
display: flex;
align-items: center;
justify-content: space-between;
font-style: normal;
font-weight: 600;
font-size: 18px;
line-height: 28px;
color: #374151;
.close {
cursor: pointer;
}
}
`;
interface Props { interface Props {
type?: "server" | "channel"; type?: "server" | "channel";
@@ -48,14 +25,14 @@ const InviteModal: FC<Props> = ({ type = "server", cid, title = "", closeModal }
const finalTitle = type == "server" ? server.name : `#${title || channel?.name}`; const finalTitle = type == "server" ? server.name : `#${title || channel?.name}`;
return ( return (
<Modal> <Modal>
<Styled> <div className="flex flex-col bg-white rounded-lg p-4 min-w-[408px]">
<h2 className="title"> <h2 className="flex items-center justify-between text-lg text-gray-700 ">
{t("invite_title", { name: finalTitle })} {t("invite_title", { name: finalTitle })}
<CloseIcon className="close" onClick={closeModal} /> <CloseIcon className="cursor-pointer" onClick={closeModal} />
</h2> </h2>
{!channel?.is_public && <AddMembers cid={cid} closeModal={closeModal} />} {!channel?.is_public && <AddMembers cid={cid} closeModal={closeModal} />}
<InviteByEmail cid={channel?.is_public ? undefined : cid} /> <InviteByEmail cid={channel?.is_public ? undefined : cid} />
</Styled> </div>
</Modal> </Modal>
); );
}; };
+17 -62
View File
@@ -1,4 +1,3 @@
import styled from "styled-components";
import { NavLink, useLocation } from "react-router-dom"; import { NavLink, useLocation } from "react-router-dom";
import Tippy from "@tippyjs/react"; import Tippy from "@tippyjs/react";
import addIcon from "../../assets/icons/add.svg?url"; import addIcon from "../../assets/icons/add.svg?url";
@@ -7,50 +6,6 @@ import AddEntriesMenu from "./AddEntriesMenu";
import { useAppSelector } from "../../app/store"; import { useAppSelector } from "../../app/store";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
const StyledWrapper = styled.div`
min-height: 56px;
position: relative;
padding: 10px 16px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
.server {
display: flex;
align-items: center;
gap: 8px;
.logo {
width: 32px;
height: 32px;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}
}
.info {
display: flex;
flex-direction: column;
gap: 4px;
.name {
font-weight: 700;
font-size: 14px;
line-height: 100%;
color: #374151;
}
.desc {
font-weight: 400;
font-size: 12px;
line-height: 100%;
color: #78787c;
}
}
}
.add {
cursor: pointer;
}
`;
type Props = { type Props = {
readonly?: boolean; readonly?: boolean;
}; };
@@ -67,42 +22,42 @@ export default function Server({ readonly = false }: Props) {
const { name, description, logo } = server; const { name, description, logo } = server;
if (readonly) if (readonly)
return ( return (
<StyledWrapper> <div className="relative flex items-center justify-between gap-2 px-4 py-2">
<div className="server"> <div className="flex items-center gap-2">
<div className="logo"> <div className="w-8 h-8">
<img alt={`${name} logo`} src={logo} /> <img alt={`${name} logo`} className="w-full h-full object-cover rounded-full" src={logo} />
</div> </div>
<div className="info"> <div className="flex flex-col gap-1">
<h3 className="name" title={description}> <h3 className="text-sm text-gray-600" title={description}>
{name} {name}
</h3> </h3>
<span className="desc">{userCount} {t("members")}</span> <span className="text-xs text-gray-500">{userCount} {t("members")}</span>
</div>
</div> </div>
</div> </div>
</StyledWrapper>
); );
return ( return (
<StyledWrapper> <div className="relative flex items-center justify-between gap-2 px-4 py-2">
<NavLink to={`/setting?f=${pathname}`}> <NavLink to={`/setting?f=${pathname}`}>
<div className="server"> <div className="flex items-center gap-2">
<div className="logo"> <div className="w-8 h-8">
<img alt={`${name} logo`} src={logo} /> <img alt={`${name} logo`} className="w-full h-full object-cover rounded-full" src={logo} />
</div> </div>
<div className="info"> <div className="flex flex-col gap-1">
<h3 className="name" title={description}> <h3 className="text-sm text-gray-600 font-bold" title={description}>
{name} {name}
</h3> </h3>
<span className="desc">{userCount} {t("members")}</span> <span className="text-xs text-gray-500">{userCount} {t("members")}</span>
</div> </div>
</div> </div>
</NavLink> </NavLink>
<Tooltip tip={t("more")} placement="bottom"> <Tooltip tip={t("more")} placement="bottom">
<Tippy interactive placement="bottom-end" trigger="click" content={<AddEntriesMenu />}> <Tippy interactive placement="bottom-end" trigger="click" content={<AddEntriesMenu />}>
<img src={addIcon} alt="add icon" className="add" /> <img src={addIcon} alt="add icon" className="cursor-pointer" />
</Tippy> </Tippy>
</Tooltip> </Tooltip>
</StyledWrapper> </div>
); );
} }