refactor: polish the tailwind refactor
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="#616161" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="#667085" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.7036 5.75927L18.2405 10.2962L9.33146 19.2052C9.08325 19.4534 8.77457 19.6325 8.43593 19.7249L3.84998 20.9756C3.34808 21.1124 2.88755 20.6519 3.02443 20.15L4.27515 15.5641C4.3675 15.2254 4.54664 14.9167 4.79484 14.6685L13.7036 5.75927ZM20.0604 3.93956C21.3132 5.19232 21.3132 7.22343 20.0604 8.47618L19.1907 9.34506L14.6538 4.80903L15.5238 3.93956C16.7766 2.68681 18.8077 2.68681 20.0604 3.93956Z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 519 B After Width: | Height: | Size: 519 B |
@@ -1,3 +1,3 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 1.75C14.5563 1.75 18.25 5.44365 18.25 10C18.25 12.8269 17.0262 14.75 15 14.75C13.7958 14.75 12.8751 14.0708 12.3262 12.9264C11.6738 13.7512 10.7016 14.25 9.5 14.25C7.20741 14.25 5.75 12.4342 5.75 10C5.75 7.53639 7.16021 5.75 9.5 5.75C10.3964 5.75 11.1564 6.01222 11.753 6.47429C11.7643 6.07167 12.0946 5.75 12.5 5.75C12.8797 5.75 13.1935 6.03215 13.2432 6.39823L13.25 6.5V10C13.25 12.1017 13.9808 13.25 15 13.25C16.0192 13.25 16.75 12.1017 16.75 10C16.75 6.27208 13.7279 3.25 10 3.25C6.27208 3.25 3.25 6.27208 3.25 10C3.25 13.7279 6.27208 16.75 10 16.75C10.794 16.75 11.5682 16.6132 12.2981 16.3489C12.6876 16.2079 13.1176 16.4093 13.2587 16.7988C13.3997 17.1883 13.1982 17.6183 12.8088 17.7593C11.9157 18.0827 10.9688 18.25 10 18.25C5.44365 18.25 1.75 14.5563 1.75 10C1.75 5.44365 5.44365 1.75 10 1.75ZM9.5 7.25C8.07681 7.25 7.25 8.29737 7.25 10C7.25 11.6694 8.11734 12.75 9.5 12.75C10.8827 12.75 11.75 11.6694 11.75 10C11.75 8.29737 10.9232 7.25 9.5 7.25Z" fill="#475467"/>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="#616161" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 1.75C14.5563 1.75 18.25 5.44365 18.25 10C18.25 12.8269 17.0262 14.75 15 14.75C13.7958 14.75 12.8751 14.0708 12.3262 12.9264C11.6738 13.7512 10.7016 14.25 9.5 14.25C7.20741 14.25 5.75 12.4342 5.75 10C5.75 7.53639 7.16021 5.75 9.5 5.75C10.3964 5.75 11.1564 6.01222 11.753 6.47429C11.7643 6.07167 12.0946 5.75 12.5 5.75C12.8797 5.75 13.1935 6.03215 13.2432 6.39823L13.25 6.5V10C13.25 12.1017 13.9808 13.25 15 13.25C16.0192 13.25 16.75 12.1017 16.75 10C16.75 6.27208 13.7279 3.25 10 3.25C6.27208 3.25 3.25 6.27208 3.25 10C3.25 13.7279 6.27208 16.75 10 16.75C10.794 16.75 11.5682 16.6132 12.2981 16.3489C12.6876 16.2079 13.1176 16.4093 13.2587 16.7988C13.3997 17.1883 13.1982 17.6183 12.8088 17.7593C11.9157 18.0827 10.9688 18.25 10 18.25C5.44365 18.25 1.75 14.5563 1.75 10C1.75 5.44365 5.44365 1.75 10 1.75ZM9.5 7.25C8.07681 7.25 7.25 8.29737 7.25 10C7.25 11.6694 8.11734 12.75 9.5 12.75C10.8827 12.75 11.75 11.6694 11.75 10C11.75 8.29737 10.9232 7.25 9.5 7.25Z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.7042 16.2945C10.0945 16.6853 10.094 17.3184 9.70324 17.7087C9.31245 18.0989 8.67928 18.0985 8.28902 17.7077L3.29241 12.7043C2.90237 12.3137 2.90255 11.681 3.29282 11.2906L8.28943 6.29297C8.67992 5.9024 9.31308 5.90234 9.70365 6.29282C10.0942 6.6833 10.0943 7.31647 9.70379 7.70703L6.411 11H13C17.3349 11 20.8645 14.4478 20.9962 18.7508L21 19C21 19.5523 20.5523 20 20 20C19.4477 20 19 19.5523 19 19C19 15.7616 16.4344 13.1224 13.2249 13.0041L13 13H6.414L9.7042 16.2945Z" fill="#667085"/>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="#667085" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.7042 16.2945C10.0945 16.6853 10.094 17.3184 9.70324 17.7087C9.31245 18.0989 8.67928 18.0985 8.28902 17.7077L3.29241 12.7043C2.90237 12.3137 2.90255 11.681 3.29282 11.2906L8.28943 6.29297C8.67992 5.9024 9.31308 5.90234 9.70365 6.29282C10.0942 6.6833 10.0943 7.31647 9.70379 7.70703L6.411 11H13C17.3349 11 20.8645 14.4478 20.9962 18.7508L21 19C21 19.5523 20.5523 20 20 20C19.4477 20 19 19.5523 19 19C19 15.7616 16.4344 13.1224 13.2249 13.0041L13 13H6.414L9.7042 16.2945Z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 602 B After Width: | Height: | Size: 591 B |
@@ -30,7 +30,6 @@
|
||||
.md-editor {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
/* width: -webkit-fill-available; */
|
||||
margin-top: 16px;
|
||||
grid-column: span 2;
|
||||
}
|
||||
@@ -158,9 +157,6 @@
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.context-menu .item .icon path {
|
||||
fill: #475467;
|
||||
}
|
||||
.context-menu .item.sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
@@ -168,9 +164,6 @@
|
||||
background-color: #22ccee;
|
||||
color: #fff;
|
||||
}
|
||||
.context-menu .item:hover .icon path {
|
||||
fill: #fff;
|
||||
}
|
||||
.context-menu .item.bottom_line {
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
@@ -196,8 +189,11 @@
|
||||
.context-menu .item[data-disabled="true"] {
|
||||
color: #a4a8b3;
|
||||
}
|
||||
.context-menu .item[data-disabled="true"] .icon path {
|
||||
fill: #a4a8b3;
|
||||
html.dark .context-menu {
|
||||
background-color: black;
|
||||
}
|
||||
html.dark .context-menu .item {
|
||||
color: white;
|
||||
}
|
||||
/* text fill transparent */
|
||||
.text-fill-transparent {
|
||||
|
||||
@@ -42,11 +42,11 @@ export default function AddEntriesMenu() {
|
||||
setChannelModalVisible(false);
|
||||
};
|
||||
|
||||
const itemClass = "rounded flex items-center gap-2 text-sm font-semibold cursor-pointer px-2 py-2.5 hover:bg-gray-800/20";
|
||||
const iconClass = "w-5 h-5";
|
||||
const itemClass = "rounded flex items-center gap-2 text-sm font-semibold cursor-pointer px-2 py-2.5 hover:bg-gray-800/20 dark:hover:bg-gray-200/20";
|
||||
const iconClass = "w-5 h-5 dark:fill-gray-300";
|
||||
return (
|
||||
<>
|
||||
<ul className="flex flex-col rounded-xl drop-shadow p-1 select-none text-gray-500 bg-white">
|
||||
<ul className="flex flex-col rounded-xl drop-shadow p-1 select-none text-gray-500 dark:text-gray-300 bg-white dark:bg-black">
|
||||
{/* temp remove public channel */}
|
||||
{currentUser?.is_admin && (
|
||||
<li className={itemClass} onClick={handleOpenChannelModal.bind(null, false)}>
|
||||
|
||||
@@ -31,7 +31,7 @@ const Avatar: FC<Props> = ({
|
||||
}) => {
|
||||
const [avatarSrc, setAvatarSrc] = useState("");
|
||||
useEffect(() => {
|
||||
if (!src) {
|
||||
if (src) {
|
||||
setAvatarSrc(src);
|
||||
}
|
||||
}, [src]);
|
||||
|
||||
@@ -39,7 +39,7 @@ const Channel: FC<Props> = ({ interactive = true, id, compact = false, avatarSiz
|
||||
</div>
|
||||
{!compact && (
|
||||
<div className="flex text-sm text-gray-500 font-semibold">
|
||||
<span className="max-w-[140px] whitespace-nowrap overflow-hidden text-ellipsis">{name}</span> ({is_public ? totalMemberCount : members.length})
|
||||
<span className="max-w-[140px] truncate">{name}</span> ({is_public ? totalMemberCount : members.length})
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -92,7 +92,7 @@ const FileBox: FC<Props> = ({
|
||||
<div className="w-full p-2 flex items-center justify-between gap-2">
|
||||
{icon}
|
||||
<div className="flex flex-col gap-1 w-full overflow-hidden">
|
||||
<span className="font-semibold text-sm text-gray-800 dark:text-gray-200 whitespace-nowrap text-ellipsis">{name}</span>
|
||||
<span className="font-semibold text-sm text-gray-800 dark:text-gray-200 truncate">{name}</span>
|
||||
<em className="text-xs text-gray-500 flex gap-4 not-italic">
|
||||
<span className="size">{formatBytes(size)}</span>
|
||||
<span className="time">{dayjs(created_at).fromNow()}</span>
|
||||
|
||||
@@ -23,7 +23,7 @@ const AudioMessage = ({ url, name, size, download }: Props) => {
|
||||
<div className="flex gap-2 ">
|
||||
<IconAudio className="w-9 h-auto" />
|
||||
<div className="flex flex-col gap-1 text-sm text-gray-700">
|
||||
<span title={name} className='font-bold whitespace-nowrap text-ellipsis w-[240px] overflow-hidden'>{name}</span>
|
||||
<span title={name} className='font-bold w-[240px] truncate'>{name}</span>
|
||||
<span>{_size}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -43,7 +43,7 @@ const VideoMessage = ({ url, name, size, download }: Props) => {
|
||||
<div className="flex gap-2 ">
|
||||
<IconVideo className="w-9 h-auto" />
|
||||
<div className="flex flex-col gap-1 text-sm text-white">
|
||||
<span title={name} className='font-bold whitespace-nowrap text-ellipsis w-[240px] overflow-hidden'>{name}</span>
|
||||
<span title={name} className='font-bold w-[240px] truncate'>{name}</span>
|
||||
<span>{_size}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -156,11 +156,11 @@ const FileMessage: FC<Props> = ({
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<div className={clsx(`file_message bg-slate-50 dark:bg-slate-900 border border-solid border-gray-300 dark:border-gray-500 box-border w-[370px] h-[66px] rounded-md`, sending && "opacity-90")}>
|
||||
<div className="p-2 flex items-center justify-between gap-2">
|
||||
<div className={clsx(`file_message bg-slate-50 dark:bg-slate-900 border border-solid border-gray-300 dark:border-gray-500 box-border w-[370px] rounded-md`, sending && "opacity-90")}>
|
||||
<div className="px-2 py-3 flex items-center justify-between gap-2">
|
||||
{icon}
|
||||
<div className="flex flex-col gap-1 w-full overflow-hidden">
|
||||
<span className="font-semibold text-sm text-gray-800 dark:text-gray-100 whitespace-nowrap text-ellipsis">{name}</span>
|
||||
<span className="font-semibold text-sm text-gray-800 dark:text-gray-100 truncate">{name}</span>
|
||||
<span className="whitespace-nowrap text-xs text-gray-500 dark:text-gray-300 flex gap-4">
|
||||
{sending ? (
|
||||
<Progress value={progress} width={"80%"} />
|
||||
|
||||
@@ -44,7 +44,7 @@ const GoogleLoginInner: FC<Props> = ({ type = "login", loaded, loadError }) => {
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<Button className=" group relative w-full bg-white dark:bg-[#384250] text-gray-600 dark:text-gray-200 !h-[46px] overflow-hidden border border-solid border-[#d0d5dd]" disabled={!loaded || isLoading}>
|
||||
<Button className=" group relative w-full !bg-white dark:!bg-[#384250] !text-gray-600 dark:!text-gray-200 !h-[46px] overflow-hidden border border-solid border-[#d0d5dd]" disabled={!loaded || isLoading}>
|
||||
<div className="absolute left-0 top-0 w-full flex-center gap-3 z-[998] h-10 bg-inherit">
|
||||
<IconGoogle className="w-6 h-6" />
|
||||
{loadError
|
||||
|
||||
@@ -14,7 +14,7 @@ const renderContent = (data: MessagePayload) => {
|
||||
switch (content_type) {
|
||||
case ContentTypes.text:
|
||||
res = (
|
||||
<span className="text-ellipsis overflow-hidden break-words break-all text-gray-800 dark:text-gray-100">
|
||||
<span className="truncate break-words break-all text-gray-800 dark:text-gray-100">
|
||||
<LinkifyText text={content} url={false} mentionTextOnly={true} mentionPopOver={false} />
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function URLPreview({ url = "" }) {
|
||||
const { title, description, ogImage } = data;
|
||||
|
||||
const containerClass = `flex items-center border border-solid border-gray-300 box-border rounded-md w-[380px]`;
|
||||
const dotsClass = `overflow-hidden whitespace-nowrap text-ellipsis`;
|
||||
const dotsClass = `truncate`;
|
||||
return ogImage ? (
|
||||
<a className={`${containerClass} flex-col !items-start p-3`} href={url} target="_blank" rel="noreferrer">
|
||||
<h3 className={`text-base text-primary-500 w-full ${dotsClass}`}>{title}</h3>
|
||||
|
||||
@@ -111,8 +111,8 @@ const Message: FC<IProps> = ({
|
||||
trigger="click"
|
||||
content={<Profile uid={fromUid || 0} type="card" cid={context == "user" ? 0 : contextId} />}
|
||||
>
|
||||
<div className="cursor-pointer" data-uid={fromUid} ref={avatarRef}>
|
||||
<Avatar width={40} height={40} src={currUser?.avatar} name={currUser?.name} />
|
||||
<div className="cursor-pointer w-10 h-10 flex-shrink-0" data-uid={fromUid} ref={avatarRef}>
|
||||
<Avatar className="w-10 h-10 rounded-full object-cover" width={40} height={40} src={currUser?.avatar} name={currUser?.name} />
|
||||
</div>
|
||||
</Tippy>
|
||||
<ContextMenu
|
||||
|
||||
@@ -44,7 +44,7 @@ const Profile: FC<Props> = ({ uid, type = "embed", cid }) => {
|
||||
const isCard = type == 'card';
|
||||
const canRemoveFromServer = !isCard && canRemove;
|
||||
const hasMore = email || canRemoveFromChannel || canRemoveFromServer;
|
||||
const iconClass = `cursor-pointer flex flex-col items-center gap-1 rounded-lg w-32 text-primary-400 bg-gray-100 dark:bg-gray-800 text-sm pt-3.5 pb-3`;
|
||||
const iconClass = `cursor-pointer flex flex-col items-center gap-1 rounded-lg w-32 text-primary-400 bg-gray-50 dark:bg-gray-800 text-sm pt-3.5 pb-3`;
|
||||
const containerClass = clsx(`flex-center flex-col gap-1 z-[99] mt-20 select-none`, isCard ? "p-4 w-[280px] bg-white dark:bg-gray-800 drop-shadow rounded-md" : "w-[432px]");
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
|
||||
@@ -13,10 +13,10 @@ const SaveTip: FC<Props> = ({ saveHandler, resetHandler }) => {
|
||||
const { t } = useTranslation("setting");
|
||||
// const btnClass=clsx("")
|
||||
return (
|
||||
<div className="w-full p-2 absolute bottom-16 left-0 flex items-center justify-between text-gray-500 border border-solid border-gray-200 dark:border-gray-400 dark:bg-gray-600 shadow-md rounded-full">
|
||||
<div className="w-full p-2 absolute bottom-16 left-0 flex items-center justify-between font-semibold text-gray-700 border border-solid border-gray-200 dark:border-gray-400 dark:bg-gray-600 shadow-md rounded-full">
|
||||
<span className="p-2 text-sm dark:text-gray-200">{t('save_tip')}</span>
|
||||
<div className="flex items-center gap-3">
|
||||
<Button className="small ghost !border-none !text-gray-500 !shadow-none dark:!text-gray-100" onClick={resetHandler}>
|
||||
<Button className="small ghost border_less !text-gray-700 !shadow-none dark:!text-gray-100" onClick={resetHandler}>
|
||||
{t('reset')}
|
||||
</Button>
|
||||
<Button className="small !rounded-full" onClick={saveHandler}>
|
||||
|
||||
@@ -60,7 +60,7 @@ export default function UploadFileList({
|
||||
<div className="flex-center w-40 h-40">
|
||||
{type.startsWith("image") ? <img className="w-full h-full object-cover" src={url} alt="image" /> : getFileIcon(type, name)}
|
||||
</div>
|
||||
<h4 className="w-40 mt-4 mb-0.5 font-semibold text-sm text-gray-800 dark:text-gray-100 whitespace-nowrap overflow-hidden text-ellipsis">{name}</h4>
|
||||
<h4 className="w-40 mt-4 mb-0.5 font-semibold text-sm text-gray-800 dark:text-gray-100 truncate">{name}</h4>
|
||||
<span className="text-xs text-gray-500">{formatBytes(size)}</span>
|
||||
<ul className="invisible group-hover:visible bg-inherit border border-solid border-black/10 box-border rounded-md flex items-center absolute -right-5 -top-2.5">
|
||||
<li className="p-1 cursor-pointer edit" onClick={handleOpenEditModal.bind(null, idx)}>
|
||||
|
||||
@@ -45,12 +45,12 @@ const StyledSettingContainer: FC<PropsWithChildren<Props>> = ({
|
||||
);
|
||||
})}
|
||||
{dangers.length ? (
|
||||
<ul className="flex flex-col gap-2 mb-9">
|
||||
<ul className="flex flex-col gap-2 mb-9 text-sm font-semibold text-red-500 dark:text-red-400">
|
||||
{dangers.map((d) => {
|
||||
if (typeof d === "boolean" || !d) return null;
|
||||
const { title, handler } = d;
|
||||
return (
|
||||
<li key={title} onClick={handler} className="text-sm text-red-500 dark:text-red-400 rounded cursor-pointer py-1.5 px-3">
|
||||
<li key={title} onClick={handler} className="rounded cursor-pointer py-1.5 px-3">
|
||||
{title}
|
||||
</li>
|
||||
);
|
||||
|
||||
@@ -44,7 +44,7 @@ const User: FC<Props> = ({
|
||||
if (!curr) return null;
|
||||
const online = curr.online || curr.uid == loginUid;
|
||||
const containerClass = clsx(`relative flex items-center justify-start gap-2 p-2 rounded-lg select-none `, interactive && "hover:bg-gray-500/10", compact && "p-0");
|
||||
const nameClass = clsx(`text-sm text-gray-500 max-w-[190px] overflow-hidden text-ellipsis font-semibold dark:text-white`);
|
||||
const nameClass = clsx(`text-sm text-gray-500 max-w-[190px] truncate font-semibold dark:text-white`);
|
||||
const statusClass = clsx(`absolute -bottom-0.5 -right-1.5 w-3 h-3 box-content rounded-full border-[2px] border-solid border-white dark:border-gray-300`,
|
||||
online ? "bg-[#22c55e]" : "bg-[#a1a1aa]",
|
||||
compact && "w-3.5 h-3.5");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import dayjs from "dayjs";
|
||||
import { FC } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useGetServerVersionQuery } from "../../app/services/server";
|
||||
@@ -5,11 +6,12 @@ type Props = {};
|
||||
const Version: FC<Props> = () => {
|
||||
const { t } = useTranslation("setting", { keyPrefix: "version" });
|
||||
const { data: serverVersion } = useGetServerVersionQuery();
|
||||
const ts = process.env.REACT_APP_BUILD_TIME;
|
||||
return (
|
||||
<div className="flex flex-col gap-3 dark:text-white">
|
||||
<div className="item">{t("client_version")}: {process.env.VERSION}</div>
|
||||
<div className="item">{t("server_version")}: {serverVersion}</div>
|
||||
<div className="item">{t("build_time")}: {process.env.REACT_APP_BUILD_TIME}</div>
|
||||
<div className="item">{t("build_time")}: {ts} {dayjs(ts).fromNow()}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,8 +12,8 @@ const StyledButton = ({ children, className = '', ...rest }: Props) => {
|
||||
const isFull = className.includes('flex');
|
||||
return <button className={clsx(`text-sm text-white bg-primary-400 break-keep shadow rounded-lg box-border px-3.5 py-2.5 hover:bg-primary-500 active:bg-primary-500 disabled:bg-gray-300`,
|
||||
isFull && "w-full",
|
||||
isGhost && "text-primary-400 border border-primary-400 !bg-transparent",
|
||||
isCancel && "!bg-transparent text-gray-800 dark:text-gray-50 border border-gray-200",
|
||||
isGhost && "text-primary-400 border border-solid border-primary-400 !bg-transparent",
|
||||
isCancel && "!bg-transparent text-gray-800 dark:text-gray-50 border border-solid border-gray-200",
|
||||
isSmall && "!py-2",
|
||||
noBorder && "!shadow-none border-none",
|
||||
isMini && "!px-2.5 !py-1 !text-xs",
|
||||
|
||||
@@ -38,25 +38,25 @@ const Input: FC<Props> = ({ type = "text", prefix = "", className = "", ...rest
|
||||
// const noInner=!className.includes("inner");
|
||||
const isPwd = type == "password";
|
||||
const inputClass = clsx(`w-full bg-white dark:bg-gray-800 text-sm text-gray-800 dark:text-gray-200 p-2 outline-none disabled:text-gray-500 disabled:bg-gray-100 dark:disabled:text-gray-500 dark:disabled:bg-gray-800/50 placeholder:text-gray-400`,
|
||||
// noInner && 'rounded border border-gray-200 shadow',
|
||||
// noInner && 'rounded border border-solid border-gray-200 shadow',
|
||||
isLarge && 'py-3',
|
||||
isNone && "border-none bg-transparent shadow-none",
|
||||
isPwd && "pr-[30px]"
|
||||
);
|
||||
return type == "password" ? (
|
||||
<div className={`w-full relative flex overflow-hidden rounded border border-gray-300 dark:border-gray-400 shadow ${className}`}>
|
||||
<div className={`w-full relative flex overflow-hidden rounded border border-solid border-gray-300 dark:border-gray-400 shadow-sm ${className}`}>
|
||||
<input type={inputType} autoComplete={inputType == "password" ? "current-password" : "on"} className={`${inputClass} ${className}`} {...rest} />
|
||||
<div className="absolute top-1/2 right-2.5 -translate-y-1/2 cursor-pointer" onClick={togglePasswordVisible}>
|
||||
{inputType == "password" ? <IconEyeClose className="fill-gray-500" /> : <IconEyeOpen className="fill-gray-500" />}
|
||||
</div>
|
||||
</div>
|
||||
) : prefix ? (
|
||||
<div className={`w-full relative flex overflow-hidden rounded border border-gray-300 dark:border-gray-400 shadow ${className}`}>
|
||||
<span className="px-4 py-2 text-sm text-gray-500 dark:text-gray-300 bg-gray-200 dark:bg-gray-800 border dark:border-gray-600">{prefix}</span>
|
||||
<div className={`w-full relative flex overflow-hidden rounded border border-solid border-gray-300 dark:border-gray-400 shadow-sm ${className}`}>
|
||||
<span className="px-4 py-2 text-sm text-gray-500 dark:text-gray-300 bg-gray-100 dark:bg-gray-800 shadow-[rgb(0_0_0_/_10%)_-1px_0px_0px_inset]">{prefix}</span>
|
||||
<input className={`${inputClass} ${className}`} type={inputType} {...rest} />
|
||||
</div>
|
||||
) : (
|
||||
<input type={inputType} className={`${inputClass} rounded border border-gray-200 dark:border-gray-400 shadow ${className}`} {...rest} />
|
||||
<input type={inputType} className={`${inputClass} rounded border border-solid border-gray-200 dark:border-gray-400 shadow-sm ${className}`} {...rest} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ const Radio: FC<Props> = ({
|
||||
}}
|
||||
id={`${id}-${index}`}
|
||||
/>
|
||||
<div className="drop-shadow px-2 py-3 border border-solid border-gray-300 dark:border-gray-400 rounded-lg w-full h-full bg-white dark:bg-gray-800 peer-checked:bg-primary-400 text-sm text-gray-500 dark:text-gray-300 peer-checked:text-white">
|
||||
<div className="drop-shadow-sm px-2 py-3 border border-solid border-gray-300 dark:border-gray-400 rounded-lg w-full h-full bg-white dark:bg-gray-800 peer-checked:bg-primary-400 text-sm text-gray-500 dark:text-gray-300 peer-checked:text-white">
|
||||
<label className="ml-6" htmlFor={`${id}-${index}`}>{item}</label>
|
||||
</div>
|
||||
<div className="absolute top-1/2 left-3 -translate-y-1/2 w-3.5 h-3.5 rounded-full border border-solid border-gray-300 peer-checked:hidden"></div>
|
||||
|
||||
@@ -2,8 +2,12 @@ import { TextareaHTMLAttributes } from "react";
|
||||
|
||||
type Props = TextareaHTMLAttributes<HTMLTextAreaElement>
|
||||
const StyledTextarea = ({ className, ...rest }: Props) => {
|
||||
return <textarea className={`rounded text-sm p-2 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 resize-none w-full shadow border border-gray-200 dark:border-gray-400
|
||||
disabled:bg-gray-100 dark:disabled:bg-gray-800/50 disabled:text-gray-400 dark:disabled:text-gray-500 disabled:pointer-events-none placeholder:text-gray-400 ${className}`}
|
||||
return <textarea className={`rounded text-sm p-2 bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300 resize-none w-full shadow-sm border border-gray-200 dark:border-gray-400
|
||||
disabled:bg-gray-100 dark:disabled:bg-gray-800/50
|
||||
disabled:text-gray-400 dark:disabled:text-gray-500
|
||||
disabled:pointer-events-none
|
||||
placeholder:text-gray-400
|
||||
${className}`}
|
||||
{...rest}></textarea>;
|
||||
};
|
||||
export default StyledTextarea;
|
||||
|
||||
@@ -64,7 +64,10 @@ export default function useStreaming() {
|
||||
}, timeout ?? 20000);
|
||||
};
|
||||
const startStreaming = useCallback(async () => {
|
||||
if (connectionIsOpen) return;
|
||||
if (connectionIsOpen) {
|
||||
console.log("connection is open, return");
|
||||
return;
|
||||
};
|
||||
window.clearTimeout(aliveInter);
|
||||
if (SSE && (SSE.readyState === EventSource.OPEN || SSE.readyState === EventSource.CONNECTING))
|
||||
return;
|
||||
@@ -116,7 +119,6 @@ export default function useStreaming() {
|
||||
return;
|
||||
}
|
||||
// 重连
|
||||
// connectionIsOpen = false;
|
||||
keepAlive(2000);
|
||||
};
|
||||
SSE.onmessage = (evt) => {
|
||||
|
||||
@@ -64,7 +64,7 @@ const DMChat: FC<Props> = ({ uid = 0, dropFiles }) => {
|
||||
</ul>
|
||||
}
|
||||
header={
|
||||
<header className="box-border h-14 px-5 border-b border-b-black/10 flex items-center justify-between">
|
||||
<header className="box-border h-14 px-5 flex items-center justify-between shadow-[inset_0_-1px_0_rgb(0_0_0_/_10%)]">
|
||||
<User interactive={false} uid={currUser.uid} />
|
||||
</header>
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function GuestChannelChat({ cid = 0 }: Props) {
|
||||
to={cid}
|
||||
context="channel"
|
||||
header={
|
||||
<header className="box-border h-14 px-5 border-solid border-b border-b-black/10 flex items-center justify-center md:justify-between">
|
||||
<header className="h-14 px-5 flex items-center justify-center md:justify-between shadow-[inset_0_-1px_0_rgb(0_0_0_/_10%)]">
|
||||
<div className="flex items-center gap-1">
|
||||
<ChannelIcon personal={!is_public} />
|
||||
<span className="text-gray-800 dark:text-white">{name}</span>
|
||||
|
||||
@@ -45,15 +45,15 @@ const Session: FC<IProps> = ({ id, mid }) => {
|
||||
</div>
|
||||
<div className="w-full flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={clsx(`flex items-center gap-2 font-semibold text-sm text-gray-500 dark:text-white whitespace-nowrap overflow-hidden text-ellipsis`, previewMsg.created_at && "max-w-[190px]")}>
|
||||
<span className={clsx(`flex items-center gap-2 font-semibold text-sm text-gray-500 dark:text-white truncate`, previewMsg.created_at && "max-w-[190px]")}>
|
||||
{name}
|
||||
</span>
|
||||
<span className="text-xs text-gray-600 whitespace-nowrap overflow-hidden max-w-[80px] text-ellipsis">
|
||||
<span className="text-xs text-gray-600 max-w-[80px] truncate">
|
||||
{previewMsg.created_at ? dayjs(previewMsg.created_at).fromNow() : null}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-gray-500 whitespace-nowrap overflow-hidden w-36 text-ellipsis">{renderPreviewMessage(previewMsg)}</span>
|
||||
<span className="text-xs text-gray-500 w-36 truncate">{renderPreviewMessage(previewMsg)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</NavLink>
|
||||
|
||||
@@ -127,17 +127,20 @@ const Session: FC<IProps> = ({
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full flex flex-col justify-between">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={clsx(`flex items-center gap-1 font-semibold text-sm text-gray-500 dark:text-white whitespace-nowrap overflow-hidden text-ellipsis`, previewMsg.created_at && "max-w-[190px]")}>
|
||||
{name} {!is_public && <IconLock className="dark:fill-gray-400" />}
|
||||
<div className="w-full flex flex-col justify-between overflow-hidden">
|
||||
<div className="flex items-center justify-between ">
|
||||
<span className={clsx(`flex items-center gap-1`)}>
|
||||
<i className={clsx("not-italic font-semibold text-sm text-gray-500 dark:text-white max-w-[120px] truncate", !previewMsg.created_at && "max-w-[190px]")}>
|
||||
{name}
|
||||
</i>
|
||||
{!is_public && <IconLock className="dark:fill-gray-400" />}
|
||||
</span>
|
||||
<span className="text-xs text-gray-600 dark:text-gray-400 whitespace-nowrap overflow-hidden max-w-[80px] text-ellipsis">
|
||||
<span className={clsx("text-xs text-gray-600 dark:text-gray-400 max-w-[80px] truncate")}>
|
||||
{previewMsg.created_at ? dayjs(previewMsg.created_at).fromNow() : null}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap overflow-hidden w-36 text-ellipsis">{renderPreviewMessage(previewMsg)}</span>
|
||||
<span className={clsx("text-xs text-gray-500 dark:text-gray-400 truncate", unreads > 0 ? `w-36` : ``)}>{renderPreviewMessage(previewMsg)}</span>
|
||||
{unreads > 0 && (
|
||||
<strong className={clsx(`text-white h-5 min-w-[20px] bg-primary-400 font-bold text-[10px] rounded-[10px] flex-center`, unreads > 99 && 'w-1.5 h-1.5 p-0 min-w-[unset]', muted && "bg-gray-500")}>
|
||||
{unreads > 99 ? null : unreads}
|
||||
|
||||
@@ -37,7 +37,7 @@ const SessionList: FC<Props> = ({ tempSession }) => {
|
||||
if (!mids || mids.length == 0) {
|
||||
return { key: `channel_${id}`, unreads: 0, id, type: "channel" };
|
||||
}
|
||||
const mid = [...mids].sort().pop();
|
||||
const mid = [...mids].pop();
|
||||
return { key: `channel_${id}`, id, mid, type: "channel" };
|
||||
});
|
||||
const uSessions = DMs.map((id) => {
|
||||
@@ -45,7 +45,7 @@ const SessionList: FC<Props> = ({ tempSession }) => {
|
||||
if (!mids || mids.length == 0) {
|
||||
return { key: `user_${id}`, unreads: 0, id, type: "user" };
|
||||
}
|
||||
const mid = [...mids].sort().pop();
|
||||
const mid = [...mids].pop();
|
||||
return { key: `user_${id}`, type: "user", id, mid };
|
||||
});
|
||||
const tmps = [...(cSessions as ChatSession[]), ...(uSessions as ChatSession[])].sort((a, b) => {
|
||||
|
||||
@@ -53,7 +53,7 @@ function ChatPage() {
|
||||
<ChannelModal closeModal={toggleChannelModalVisible} personal={true} />
|
||||
)}
|
||||
{usersModalVisible && <UsersModal closeModal={toggleUsersModalVisible} />}
|
||||
<div className={`flex h-full pt-2 pb-2.5 pr-1 ${isGuest ? "!pr-1 !pt-0" : ""} md:!pr-12 `}>
|
||||
<div className={`flex h-full pt-2 pb-2.5 pr-1 ${isGuest ? "px-1" : "md:pr-12"}`}>
|
||||
{sessionListVisible && <div onClick={toggleSessionList} className="z-30 fixed top-0 left-4 w-screen h-screen bg-black/50 transition-all backdrop-blur-sm"></div>}
|
||||
<div className={clsx("flex-col rounded-l-2xl min-w-[268px] h-full shadow-[rgb(0_0_0_/_10%)_-1px_0px_0px_inset] fixed md:relative top-0 left-0 z-40 transition-all md:overflow-auto bg-white dark:!bg-[#1F2A37]", sessionListVisible ? "max-md:translate-x-0" : "max-md:-translate-x-full")}>
|
||||
<Server readonly={isGuest} />
|
||||
|
||||
@@ -56,7 +56,7 @@ function HomePage() {
|
||||
<>
|
||||
<Manifest />
|
||||
{!guest && <Notification />}
|
||||
<div className={`flex w-screen h-screen bg-[#e5e7eb] dark:bg-[#121926]`}>
|
||||
<div className={`vocechat-container flex w-screen h-screen bg-[#e5e7eb] dark:bg-[#121926]`}>
|
||||
{!guest && (
|
||||
<div className={`h-full flex flex-col items-center relative w-16 bg-transparent transition-all`}>
|
||||
{loginUid && <User uid={loginUid} />}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { ReactNode, Suspense, FC } from "react";
|
||||
import { ReactNode, Suspense, FC } from "react";
|
||||
import Loading from "../common/component/Loading";
|
||||
|
||||
type Props = {
|
||||
@@ -7,7 +7,7 @@ type Props = {
|
||||
|
||||
const Lazy: FC<Props> = ({ children }) => {
|
||||
return (
|
||||
<Suspense fallback={<Loading />}>
|
||||
<Suspense fallback={<Loading fullscreen={true} />}>
|
||||
{children}
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ import UpdateLicenseModal from "./UpdateLicenseModal";
|
||||
|
||||
interface ItemProps extends HTMLAttributes<HTMLSpanElement> { label: string, data?: string | number | string[], foldable?: boolean }
|
||||
const Item = ({ label, data, foldable = false, ...rest }: ItemProps) => {
|
||||
const infoClass = clsx("font-bold w-full cursor-pointer", foldable ? " overflow-hidden text-ellipsis" : "whitespace-pre-wrap break-all");
|
||||
const infoClass = clsx("font-bold w-full cursor-pointer", foldable ? "truncate" : "whitespace-pre-wrap break-all");
|
||||
if (!data) return null;
|
||||
return <div className="whitespace-nowrap flex flex-col items-start justify-start text-lg">
|
||||
<span className="text-sm text-gray-400 dark:text-white">{label}</span>
|
||||
|
||||
@@ -18,7 +18,7 @@ const Search: FC<Props> = ({ input, updateInput }) => {
|
||||
<div className="relative min-h-[56px] px-2 py-3 flex items-center justify-between gap-2 shadow-[rgb(0_0_0_/_10%)_0px_1px_0px] dark:border-b-gray-500">
|
||||
<div className="flex items-center gap-1">
|
||||
<img src={searchIcon} alt="search icon" />
|
||||
<input value={input} placeholder={`${t("action.search")}...`} className="w-full text-sm bg-transparent" onChange={handleInput} />
|
||||
<input value={input} placeholder={`${t("action.search")}...`} className="w-full text-sm bg-transparent dark:text-gray-50" onChange={handleInput} />
|
||||
</div>
|
||||
<Tooltip tip={t("more")} placement="bottom">
|
||||
<Tippy interactive placement="bottom-end" trigger="click" content={<AddEntriesMenu />}>
|
||||
|
||||
Reference in New Issue
Block a user