refactor: style with tailwind
This commit is contained in:
@@ -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;
|
||||
});
|
||||
@@ -1,36 +1,12 @@
|
||||
import styled from "styled-components";
|
||||
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 {
|
||||
content: string;
|
||||
}
|
||||
|
||||
const Divider: FC<Props> = ({ content }) => {
|
||||
if (!content) return null;
|
||||
return <StyledDivider data-content={content}></StyledDivider>;
|
||||
return <div className="relative border-none h-[1px] bg-[#e3e5e8] my-6 overflow-visible">
|
||||
<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;
|
||||
|
||||
@@ -1,21 +1,4 @@
|
||||
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 {
|
||||
url: string;
|
||||
@@ -31,13 +14,13 @@ const Audio: FC<Props> = ({ url }) => {
|
||||
|
||||
if (!url) return null;
|
||||
return (
|
||||
<Styled>
|
||||
<div className="flex items-center justify-center h-full">
|
||||
{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,16 +1,4 @@
|
||||
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 {
|
||||
url: string;
|
||||
@@ -29,7 +17,7 @@ const Code: FC<Props> = ({ url }) => {
|
||||
}, [url]);
|
||||
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;
|
||||
|
||||
@@ -1,27 +1,14 @@
|
||||
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 {
|
||||
url: string;
|
||||
alt?: string;
|
||||
}
|
||||
|
||||
const Image: FC<Props> = ({ url, alt }) => {
|
||||
if (!url) return null;
|
||||
return (
|
||||
<Styled>
|
||||
<img src={url} alt={alt} />
|
||||
</Styled>
|
||||
<div className="h-[218px] overflow-hidden">
|
||||
<img className="w-full h-full object-cover" src={url} alt={alt} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,34 +1,14 @@
|
||||
import styled from "styled-components";
|
||||
import { FC } from "react";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 8px;
|
||||
/* height: 218px; */
|
||||
overflow: hidden;
|
||||
embed {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
url: string;
|
||||
}
|
||||
|
||||
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 (
|
||||
<Styled>
|
||||
<embed src={url} type="application/pdf" />
|
||||
{/* <Document file={url} onLoadSuccess={onDocumentLoadSuccess}>
|
||||
<Page pageNumber={pageNumber} />
|
||||
</Document> */}
|
||||
</Styled>
|
||||
<div className="p-2 overflow-hidden">
|
||||
<embed className="w-full h-full" src={url} type="application/pdf" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
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 {
|
||||
url: string;
|
||||
}
|
||||
|
||||
const Video: FC<Props> = ({ url }) => {
|
||||
return (
|
||||
<Styled>
|
||||
<video controls src={url} />
|
||||
</Styled>
|
||||
<div className="h-[218px]">
|
||||
<video className="w-full h-full object-cover" controls src={url} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,19 +1,4 @@
|
||||
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 {
|
||||
value: number;
|
||||
width?: string;
|
||||
@@ -21,9 +6,9 @@ interface Props {
|
||||
|
||||
const Progress: FC<Props> = ({ value, width = "100%" }) => {
|
||||
return (
|
||||
<Styled style={{ width }}>
|
||||
<div className="progress" style={{ width: `${value}%` }}></div>
|
||||
</Styled>
|
||||
<div className="bg-[#ecfdff] rounded h-2 overflow-hidden" style={{ width }}>
|
||||
<div className="h-2 bg-[#088ab2] rounded transition-all" style={{ width: `${value}%` }}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import styled from "styled-components";
|
||||
import InviteByEmail from "./InviteByEmail";
|
||||
import AddMembers from "./AddMembers";
|
||||
import CloseIcon from "../../../assets/icons/close.svg";
|
||||
@@ -7,28 +6,6 @@ import { useAppSelector } from "../../../app/store";
|
||||
import { FC } from "react";
|
||||
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 {
|
||||
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}`;
|
||||
return (
|
||||
<Modal>
|
||||
<Styled>
|
||||
<h2 className="title">
|
||||
<div className="flex flex-col bg-white rounded-lg p-4 min-w-[408px]">
|
||||
<h2 className="flex items-center justify-between text-lg text-gray-700 ">
|
||||
{t("invite_title", { name: finalTitle })}
|
||||
<CloseIcon className="close" onClick={closeModal} />
|
||||
<CloseIcon className="cursor-pointer" onClick={closeModal} />
|
||||
</h2>
|
||||
{!channel?.is_public && <AddMembers cid={cid} closeModal={closeModal} />}
|
||||
<InviteByEmail cid={channel?.is_public ? undefined : cid} />
|
||||
</Styled>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import styled from "styled-components";
|
||||
import { NavLink, useLocation } from "react-router-dom";
|
||||
import Tippy from "@tippyjs/react";
|
||||
import addIcon from "../../assets/icons/add.svg?url";
|
||||
@@ -7,50 +6,6 @@ import AddEntriesMenu from "./AddEntriesMenu";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
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 = {
|
||||
readonly?: boolean;
|
||||
};
|
||||
@@ -67,42 +22,42 @@ export default function Server({ readonly = false }: Props) {
|
||||
const { name, description, logo } = server;
|
||||
if (readonly)
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="server">
|
||||
<div className="logo">
|
||||
<img alt={`${name} logo`} src={logo} />
|
||||
<div className="relative flex items-center justify-between gap-2 px-4 py-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8">
|
||||
<img alt={`${name} logo`} className="w-full h-full object-cover rounded-full" src={logo} />
|
||||
</div>
|
||||
<div className="info">
|
||||
<h3 className="name" title={description}>
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="text-sm text-gray-600" title={description}>
|
||||
{name}
|
||||
</h3>
|
||||
<span className="desc">{userCount} {t("members")}</span>
|
||||
<span className="text-xs text-gray-500">{userCount} {t("members")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<div className="relative flex items-center justify-between gap-2 px-4 py-2">
|
||||
<NavLink to={`/setting?f=${pathname}`}>
|
||||
<div className="server">
|
||||
<div className="logo">
|
||||
<img alt={`${name} logo`} src={logo} />
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8">
|
||||
<img alt={`${name} logo`} className="w-full h-full object-cover rounded-full" src={logo} />
|
||||
</div>
|
||||
<div className="info">
|
||||
<h3 className="name" title={description}>
|
||||
<div className="flex flex-col gap-1">
|
||||
<h3 className="text-sm text-gray-600 font-bold" title={description}>
|
||||
{name}
|
||||
</h3>
|
||||
<span className="desc">{userCount} {t("members")}</span>
|
||||
<span className="text-xs text-gray-500">{userCount} {t("members")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</NavLink>
|
||||
|
||||
<Tooltip tip={t("more")} placement="bottom">
|
||||
<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>
|
||||
</Tooltip>
|
||||
</StyledWrapper>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user