refactor: new mobile layout
This commit is contained in:
@@ -23,6 +23,7 @@ import InviteModal from "../../../common/component/InviteModal";
|
||||
import LoadMore from "../LoadMore";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import GoBackNav from "../GoBackNav";
|
||||
type Props = {
|
||||
cid?: number;
|
||||
dropFiles?: File[];
|
||||
@@ -133,6 +134,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
}
|
||||
header={
|
||||
<header className="h-14 px-5 flex items-center justify-center md:justify-between shadow-[inset_0_-1px_0_rgb(0_0_0_/_10%)]">
|
||||
<GoBackNav />
|
||||
<div className="flex items-center gap-1">
|
||||
<ChannelIcon personal={!is_public} />
|
||||
<span className="text-gray-800 dark:text-white">{name}</span>
|
||||
|
||||
@@ -11,6 +11,7 @@ import LoadMore from "../LoadMore";
|
||||
import { renderMessageFragment } from "../utils";
|
||||
import useMessageFeed from "../../../common/hook/useMessageFeed";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import GoBackNav from "../GoBackNav";
|
||||
type Props = {
|
||||
uid: number;
|
||||
dropFiles?: File[];
|
||||
@@ -64,7 +65,8 @@ const DMChat: FC<Props> = ({ uid = 0, dropFiles }) => {
|
||||
</ul>
|
||||
}
|
||||
header={
|
||||
<header className="box-border h-14 px-5 flex items-center justify-between shadow-[inset_0_-1px_0_rgb(0_0_0_/_10%)]">
|
||||
<header className="box-border h-14 px-5 flex items-center justify-center md:justify-between shadow-[inset_0_-1px_0_rgb(0_0_0_/_10%)]">
|
||||
<GoBackNav />
|
||||
<User interactive={false} uid={currUser.uid} />
|
||||
</header>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import IconArrow from '../../assets/icons/arrow.left.svg';
|
||||
// type Props = {}
|
||||
|
||||
const GoBackNav = () => {
|
||||
const navigate = useNavigate();
|
||||
const handleBack = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
return (
|
||||
<button className='p-2 absolute left-2 md:hidden' onClick={handleBack}>
|
||||
<IconArrow className="dark:stroke-white w-6 h-6" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default GoBackNav;
|
||||
@@ -21,7 +21,7 @@ const GuestBlankPlaceholder = () => {
|
||||
navigateTo("/login");
|
||||
};
|
||||
return (
|
||||
<section className="flex flex-col items-center bg-transparent">
|
||||
<section className="flex flex-col items-center">
|
||||
<h2 className="text-3xl text-gray-600 dark:text-gray-50 font-bold text-center">{t("welcome", { name: serverName })}</h2>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-gray-400 dark:text-gray-200 my-3 text-sm">{t("guest_login_tip")}</span>
|
||||
|
||||
@@ -7,6 +7,7 @@ import Layout from "../Layout";
|
||||
import { renderMessageFragment } from "../utils";
|
||||
import LoadMore from "../LoadMore";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import GoBackNav from "../GoBackNav";
|
||||
|
||||
type Props = {
|
||||
cid?: number;
|
||||
@@ -41,6 +42,7 @@ export default function GuestChannelChat({ cid = 0 }: Props) {
|
||||
context="channel"
|
||||
header={
|
||||
<header className="h-14 px-5 flex items-center justify-center md:justify-between shadow-[inset_0_-1px_0_rgb(0_0_0_/_10%)]">
|
||||
<GoBackNav />
|
||||
<div className="flex items-center gap-1">
|
||||
<ChannelIcon personal={!is_public} />
|
||||
<span className="text-gray-800 dark:text-white">{name}</span>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { FC } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import Session from "./Session";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import LoginTip from "../Layout/LoginTip";
|
||||
export interface ChatSession {
|
||||
key: string;
|
||||
id: number;
|
||||
@@ -40,12 +41,15 @@ const SessionList: FC<Props> = () => {
|
||||
}, [channelIDs, channelMessage, readChannels, readUsers, loginUid, userMessage]);
|
||||
|
||||
return (
|
||||
<ul className="flex flex-col gap-0.5 p-2 overflow-auto h-[calc(100vh_-_56px_-_38px)]">
|
||||
{sessions.map((s) => {
|
||||
const { key, id, mid = 0 } = s;
|
||||
return <Session key={key} id={id} mid={mid} />;
|
||||
})}
|
||||
</ul>
|
||||
<>
|
||||
<ul className="flex flex-col gap-0.5 p-2 overflow-auto h-[calc(100vh_-_56px_-_38px)]">
|
||||
{sessions.map((s) => {
|
||||
const { key, id, mid = 0 } = s;
|
||||
return <Session key={key} id={id} mid={mid} />;
|
||||
})}
|
||||
</ul>
|
||||
<LoginTip placement="session" />
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default SessionList;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
// import { useEffect } from "react";
|
||||
import clsx from "clsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { resetAuthData } from "../../../app/slices/auth.data";
|
||||
import Button from "../../../common/component/styled/Button";
|
||||
import useLogout from "../../../common/hook/useLogout";
|
||||
// type Props = {};
|
||||
type Props = {
|
||||
placement?: "session" | "chat"
|
||||
};
|
||||
|
||||
const LoginTip = () => {
|
||||
const LoginTip = ({ placement = "chat" }: Props) => {
|
||||
const { t } = useTranslation("welcome");
|
||||
const { t: ct } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
@@ -20,8 +23,10 @@ const LoginTip = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between bg-slate-200/80 dark:bg-gray-800 rounded-lg w-full p-4">
|
||||
<span className="text-xs md:text-base text-[#98a2b3] dark:text-gray-100">
|
||||
<div className={clsx("flex items-center justify-between bg-slate-200/80 dark:bg-gray-800 rounded-lg w-full p-4 border border-solid border-gray-200 dark:border-gray-500",
|
||||
placement == "session" && "w-[96%] md:hidden fixed bottom-2 left-1/2 -translate-x-1/2"
|
||||
)}>
|
||||
<span className="text-xs md:text-base text-gray-400 dark:text-gray-100">
|
||||
<i className="mr-2 text-xs md:text-lg ">👋</i>
|
||||
{t("sign_in_tip")}
|
||||
</span>
|
||||
|
||||
@@ -111,7 +111,7 @@ const Layout: FC<Props> = ({
|
||||
<main className="h-full w-full flex items-start justify-between relative" ref={messagesContainer}>
|
||||
<div className="rounded-br-2xl w-full flex flex-col h-[calc(100vh_-_56px_-_18px)]">
|
||||
{children}
|
||||
<div className={`p-4 pt-0 ${selects ? "selecting" : ""}`}>
|
||||
<div className={`px-2 py-0 md:p-4 ${selects ? "selecting" : ""}`}>
|
||||
{readonly ? (
|
||||
<LoginTip />
|
||||
) : reachLimit ? (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { memo, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useMatch, useParams } from "react-router-dom";
|
||||
import clsx from "clsx";
|
||||
|
||||
import BlankPlaceholder from "../../common/component/BlankPlaceholder";
|
||||
@@ -13,9 +13,10 @@ import { useAppSelector } from "../../app/store";
|
||||
import GuestBlankPlaceholder from "./GuestBlankPlaceholder";
|
||||
import GuestChannelChat from "./GuestChannelChat";
|
||||
import GuestSessionList from "./GuestSessionList";
|
||||
import IconList from '../../assets/icons/list.svg';
|
||||
|
||||
function ChatPage() {
|
||||
const isHomePath = useMatch(`/`);
|
||||
const isChatHomePath = useMatch(`/chat`);
|
||||
const [sessionListVisible, setSessionListVisible] = useState(false);
|
||||
const [channelModalVisible, setChannelModalVisible] = useState(false);
|
||||
const [usersModalVisible, setUsersModalVisible] = useState(false);
|
||||
@@ -46,7 +47,7 @@ function ChatPage() {
|
||||
};
|
||||
// console.log("temp uid", tmpUid);
|
||||
const placeholderVisible = channel_id == 0 && user_id == 0;
|
||||
|
||||
const isMainPath = isHomePath || isChatHomePath;
|
||||
return (
|
||||
<>
|
||||
{channelModalVisible && (
|
||||
@@ -55,17 +56,16 @@ function ChatPage() {
|
||||
{usersModalVisible && <UsersModal closeModal={toggleUsersModalVisible} />}
|
||||
<div className={clsx(`flex h-full md:pt-2 md:pb-2.5 md:pr-1`, isGuest ? "guest-container md: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("left-container flex-col md:rounded-l-2xl max-w-[250px] md: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 bg-white dark:!bg-[#1F2A37]", sessionListVisible ? "max-md:translate-x-0" : "max-md:-translate-x-full")}>
|
||||
<div className={clsx("left-container pb-14 md:pb-0 flex-col md:rounded-l-2xl w-full md:max-w-[250px] md:min-w-[268px] h-full shadow-[rgb(0_0_0_/_10%)_-1px_0px_0px_inset] bg-white dark:!bg-gray-800",
|
||||
isMainPath ? "flex" : "hidden md:flex"
|
||||
)}>
|
||||
<Server readonly={isGuest} />
|
||||
{isGuest ? <GuestSessionList /> : <SessionList tempSession={tmpSession} />}
|
||||
{sessionListVisible ? null : <button className="absolute top-2 -right-[52px] z-50 p-2 bg-none md:hidden" onClick={toggleSessionList}>
|
||||
<IconList className="dark:stroke-gray-300" />
|
||||
</button>}
|
||||
{isGuest && <footer className="text-xs text-gray-300 dark:text-gray-700 text-center">
|
||||
{isGuest && <footer className="hidden md:block text-xs text-gray-300 dark:text-gray-700 text-center">
|
||||
Host your own <a href="https://voce.chat" target="_blank" rel="noopener noreferrer" className="text-gray-400 dark:text-gray-600">voce.chat</a>
|
||||
</footer>}
|
||||
</div>
|
||||
<div className={`right-container md:rounded-r-2xl w-full ${placeholderVisible ? "h-full flex-center" : ""} bg-white dark:!bg-[#384250]`}>
|
||||
<div className={clsx(`right-container md:rounded-r-2xl w-full bg-white dark:!bg-gray-700`, placeholderVisible && "h-full flex-center", isMainPath && "hidden md:flex")}>
|
||||
{placeholderVisible && (isGuest ? <GuestBlankPlaceholder /> : <BlankPlaceholder />)}
|
||||
{channel_id !== 0 &&
|
||||
(isGuest ? (
|
||||
|
||||
@@ -118,7 +118,7 @@ function FavsPage() {
|
||||
removeFavorite(id);
|
||||
};
|
||||
return (
|
||||
<div className="h-screen flex bg-white mt-2 mr-6 mb-2.5 overflow-auto dark:bg-[#384250] rounded-2xl">
|
||||
<div className="h-screen flex bg-white mt-2 mr-6 mb-2.5 overflow-auto dark:bg-gray-700 rounded-2xl">
|
||||
<div className=" md:min-w-[268px] p-2 shadow-inner-[-1px_0px_0px_rgba(0,_0,_0,_0.1)]">
|
||||
<ul className="flex flex-col gap-0.5">
|
||||
{Filters.map(({ icon, title, filter: f }) => {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { NavLink, useLocation, useMatch } from 'react-router-dom';
|
||||
import { useAppSelector } from '../../app/store';
|
||||
|
||||
import ChatIcon from "../../assets/icons/chat.svg";
|
||||
import UserIcon from "../../assets/icons/user.svg";
|
||||
|
||||
// type Props = {}
|
||||
|
||||
const MobileNavs = () => {
|
||||
const isHomePath = useMatch(`/`);
|
||||
const { pathname } = useLocation();
|
||||
const isChatHomePath = useMatch(`/chat`);
|
||||
const isDMChat = useMatch(`/chat/dm/:user_id`);
|
||||
const isChannelChat = useMatch(`/chat/channel/:channel_id`);
|
||||
const {
|
||||
ui: {
|
||||
rememberedNavs: { chat: chatPath, user: userPath }
|
||||
}
|
||||
} = useAppSelector((store) => {
|
||||
return {
|
||||
ui: store.ui,
|
||||
loginUid: store.authData.user?.uid,
|
||||
guest: store.authData.guest
|
||||
};
|
||||
});
|
||||
|
||||
const linkClass = `flex`;
|
||||
const isChatPage = isHomePath || pathname.startsWith("/chat");
|
||||
const isChattingPage = !!isDMChat || !!isChannelChat;
|
||||
console.log("rrr", isDMChat, isChannelChat);
|
||||
|
||||
// 有点绕
|
||||
const chatNav = isChatHomePath ? "/chat" : chatPath || "/chat";
|
||||
const userNav = userPath || "/users";
|
||||
return (
|
||||
<ul className={clsx('flex justify-around py-2 fixed bottom-0 left-0 w-full bg-gray-100 dark:bg-gray-800 md:hidden', isChattingPage && "hidden")}>
|
||||
<li>
|
||||
<NavLink
|
||||
className={() => `${linkClass}`}
|
||||
to={chatNav}
|
||||
>
|
||||
{({ isActive }) => {
|
||||
const active = isActive || isChatPage;
|
||||
return <div className='flex flex-col gap-1 items-center'>
|
||||
<ChatIcon className={!active ? "fill-gray-600" : "fill-gray-400"} />
|
||||
<span className={clsx('text-xs', !active ? "text-gray-500" : "text-gray-400")}>Chats</span>
|
||||
</div>;
|
||||
}}
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink className={() => `${linkClass}`} to={userNav}>
|
||||
{({ isActive: active }) => {
|
||||
return <div className='flex flex-col gap-1 items-center'>
|
||||
<UserIcon className={!active ? "fill-gray-600" : "fill-gray-400"} />
|
||||
<span className={clsx('text-xs', !active ? "text-gray-500" : "text-gray-400")}>Contacts</span>
|
||||
</div>;
|
||||
}}
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileNavs;
|
||||
@@ -14,7 +14,7 @@ import UserIcon from "../../assets/icons/user.svg";
|
||||
import FavIcon from "../../assets/icons/bookmark.svg";
|
||||
import FolderIcon from "../../assets/icons/folder.svg";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
import { isMobile } from "../../common/utils";
|
||||
import MobileNavs from "./MobileNavs";
|
||||
|
||||
|
||||
function HomePage() {
|
||||
@@ -49,14 +49,13 @@ function HomePage() {
|
||||
const chatNav = isChatHomePath ? "/chat" : chatPath || "/chat";
|
||||
const userNav = userPath || "/users";
|
||||
const linkClass = `flex items-center gap-2.5 px-3 py-2 font-semibold text-sm text-gray-600 rounded-lg hover:bg-gray-800/10`;
|
||||
const mobile = isMobile();
|
||||
return (
|
||||
<>
|
||||
<Manifest />
|
||||
{!guest && <Notification />}
|
||||
<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-[#e5e7eb] dark:bg-[#121926] transition-all`}>
|
||||
<div className={`hidden md:flex h-full flex-col items-center relative w-16 bg-[#e5e7eb] dark:bg-[#121926] transition-all`}>
|
||||
{loginUid && <User uid={loginUid} />}
|
||||
<nav className="flex flex-col gap-1 px-3 py-6">
|
||||
<NavLink
|
||||
@@ -64,28 +63,28 @@ function HomePage() {
|
||||
to={chatNav}
|
||||
>
|
||||
{({ isActive }) => {
|
||||
return <Tooltip disabled={mobile} tip={t("chat")}>
|
||||
return <Tooltip tip={t("chat")}>
|
||||
<ChatIcon className={(isActive || isChattingPage) ? "fill-white" : ""} />
|
||||
</Tooltip>;
|
||||
}}
|
||||
</NavLink>
|
||||
<NavLink className={({ isActive }) => `${linkClass} ${isActive ? 'bg-primary-400 hover:bg-primary-400' : ""}`} to={userNav}>
|
||||
{({ isActive }) => {
|
||||
return <Tooltip disabled={mobile} tip={t("members")}>
|
||||
return <Tooltip tip={t("members")}>
|
||||
<UserIcon className={isActive ? "fill-white" : ""} />
|
||||
</Tooltip>;
|
||||
}}
|
||||
</NavLink>
|
||||
<NavLink className={({ isActive }) => `${linkClass} ${isActive ? 'bg-primary-400 hover:bg-primary-400' : ""}`} to={"/favs"}>
|
||||
{({ isActive }) => {
|
||||
return <Tooltip disabled={mobile} tip={t("favs")}>
|
||||
return <Tooltip tip={t("favs")}>
|
||||
<FavIcon className={isActive ? "fill-white" : ""} />
|
||||
</Tooltip>;
|
||||
}}
|
||||
</NavLink>
|
||||
<NavLink className={({ isActive }) => `${linkClass} ${isActive ? 'bg-primary-400 hover:bg-primary-400' : ""}`} to={"/files"}>
|
||||
{({ isActive }) => {
|
||||
return <Tooltip disabled={mobile} tip={t("files")}>
|
||||
return <Tooltip tip={t("files")}>
|
||||
<FolderIcon className={isActive ? "fill-white" : ""} />
|
||||
</Tooltip>;
|
||||
}}
|
||||
@@ -98,6 +97,7 @@ function HomePage() {
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
{!guest && <MobileNavs />}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ const InvitePage: FC = () => {
|
||||
if (!valid) return <>invite token expires or invalid</>;
|
||||
|
||||
return (
|
||||
<div className="flex-center h-screen dark:bg-[#384250]">
|
||||
<div className="flex-center h-screen dark:bg-gray-700">
|
||||
<div className="py-8 px-10 shadow-md rounded-xl">
|
||||
<div className="flex-center flex-col pb-6">
|
||||
<img src={`${BASE_URL}/resource/organization/logo`} alt="logo" className="w-14 h-14 mb-7 rounded-full" />
|
||||
|
||||
@@ -124,7 +124,7 @@ export default function LoginPage() {
|
||||
|
||||
|
||||
return (
|
||||
<div className="flex-center h-screen dark:bg-[#384250]">
|
||||
<div className="flex-center h-screen dark:bg-gray-700">
|
||||
<div className="py-8 px-10 shadow-md rounded-xl">
|
||||
<div className="flex-center flex-col pb-6">
|
||||
<img src={`${BASE_URL}/resource/organization/logo`} alt="logo" className="w-14 h-14 mb-3 md:mb-7 rounded-full" />
|
||||
|
||||
@@ -35,10 +35,10 @@ const UpdateFrontendURL = ({ refreshInviteLink }: Props) => {
|
||||
}
|
||||
}, [isSuccess]);
|
||||
return (
|
||||
<div className="absolute left-1/2 -translate-x-1/2 bottom-8 border-2 border-solid border-[#67E3F9] bg-[#F5FEFF] rounded-lg px-2 py-3 flex justify-start gap-4">
|
||||
<div className="absolute left-1/2 -translate-x-1/2 bottom-8 border-2 border-solid border-primary-300 bg-primary-25 rounded-lg px-2 py-3 flex justify-start gap-4">
|
||||
<InfoIcon />
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
<span className="text-sm text-[#0E7090] mb-1">{t("update_domain_tip")}</span>
|
||||
<span className="text-sm text-primary-700 mb-1">{t("update_domain_tip")}</span>
|
||||
<div className="w-[400px] rounded flex gap-2">
|
||||
<StyledInput type={"url"} className="!shadow-none !bg-transparent" placeholder="Frontend URL" value={frontUrl} onChange={handleUpdateUrl} />
|
||||
<StyledButton disabled={!frontUrl || isLoading} onClick={updateFrontUrl} className="small ">
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom";
|
||||
|
||||
export default function RegContainer() {
|
||||
return (
|
||||
<div className="flex-center h-screen dark:bg-[#384250]">
|
||||
<div className="flex-center h-screen dark:bg-gray-700">
|
||||
<div className="py-8 px-10 shadow-md rounded-xl">
|
||||
<Outlet />
|
||||
</div>
|
||||
|
||||
@@ -82,7 +82,7 @@ function ResourceManagement({ fileMessages }) {
|
||||
}, [view, filter]);
|
||||
|
||||
return (
|
||||
<div className="h-screen md:overflow-y-scroll flex flex-col items-start my-2 mr-6 rounded-2xl bg-white dark:bg-[#384250]">
|
||||
<div className="h-screen md:overflow-y-scroll flex flex-col items-start my-2 mr-6 rounded-2xl bg-white dark:bg-gray-700">
|
||||
<Search value={filter.name} updateSearchValue={handleUpdateSearch} />
|
||||
<div className="flex justify-between w-full px-4 py-5">
|
||||
<Filter filter={filter} updateFilter={updateFilter} />
|
||||
|
||||
@@ -76,7 +76,7 @@ const CreateAPIKeyModal = ({ closeModal, uid }: Props) => {
|
||||
</div>
|
||||
: <form ref={formRef} className="w-full flex flex-col gap-2 items-center" action="/">
|
||||
<div className="flex flex-col gap-1 w-full">
|
||||
<label htmlFor={"name"} className="text-sm text-[#6b7280]">Name</label>
|
||||
<label htmlFor={"name"} className="text-sm text-gray-500">Name</label>
|
||||
<Input name={"name"} required placeholder='Please input API Key name'></Input>
|
||||
</div>
|
||||
</form>}
|
||||
|
||||
@@ -79,11 +79,11 @@ const CreateModal = ({ closeModal }: Props) => {
|
||||
>
|
||||
<form ref={formRef} className="w-full flex flex-col gap-2" action="/">
|
||||
<div className="flex flex-col items-start gap-1 w-full">
|
||||
<label htmlFor={"name"} className="text-sm text-[#6b7280]">Name</label>
|
||||
<label htmlFor={"name"} className="text-sm text-gray-500">Name</label>
|
||||
<Input name={"name"} required placeholder='Please input bot name'></Input>
|
||||
</div>
|
||||
<div className="flex flex-col items-start gap-1 w-full">
|
||||
<label htmlFor={"webhook_url"} className="text-sm text-[#6b7280]">Webhook URL (Optional)</label>
|
||||
<label htmlFor={"webhook_url"} className="text-sm text-gray-500">Webhook URL (Optional)</label>
|
||||
<Input name={"webhook_url"} type="url" placeholder='Please input webhook url'></Input>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -58,7 +58,7 @@ const WebhookModal = ({ uid, webhook, closeModal }: Props) => {
|
||||
}
|
||||
>
|
||||
<form ref={formRef} className="w-full flex flex-col gap-2" action="/">
|
||||
<label htmlFor={"webhook"} className="text-sm text-[#6b7280]">Webhook URL</label>
|
||||
<label htmlFor={"webhook"} className="text-sm text-gray-500">Webhook URL</label>
|
||||
<Input name={"webhook"} value={url} onChange={handleUrlChange} type="url"></Input>
|
||||
</form>
|
||||
</StyledModal>
|
||||
|
||||
@@ -8,6 +8,7 @@ import Profile from "../../common/component/Profile";
|
||||
|
||||
import BlankPlaceholder from "../../common/component/BlankPlaceholder";
|
||||
import useFilteredUsers from "../../common/hook/useFilteredUsers";
|
||||
import clsx from "clsx";
|
||||
|
||||
function UsersPage() {
|
||||
const dispatch = useDispatch();
|
||||
@@ -23,12 +24,14 @@ function UsersPage() {
|
||||
}, [pathname]);
|
||||
|
||||
if (!users) return null;
|
||||
|
||||
const isUserDetail = !!user_id;
|
||||
return (
|
||||
<div className="flex h-full pt-2 md:pr-12 pb-2.5">
|
||||
<div className="rounded-l-2xl bg-white dark:bg-[#1F2A37] relative flex flex-col md:min-w-[268px] shadow-[inset_-1px_0px_0px_rgba(0,_0,_0,_0.1)]">
|
||||
<div className={clsx("flex h-full md:pt-2 md:pb-2.5 md:pr-12")}>
|
||||
<div className={clsx("md:rounded-l-2xl bg-white dark:bg-gray-800 relative flex flex-col w-full md:w-auto md:min-w-[268px] shadow-[inset_-1px_0px_0px_rgba(0,_0,_0,_0.1)]",
|
||||
isUserDetail && "hidden"
|
||||
)}>
|
||||
<Search input={input} updateInput={updateInput} />
|
||||
<div className="px-2 py-3 overflow-scroll">
|
||||
<div className="px-2 pt-3 pb-20 md:py-3 overflow-scroll">
|
||||
<nav className="flex flex-col md:gap-1">
|
||||
{users.map(({ uid }) => {
|
||||
return (
|
||||
@@ -40,8 +43,11 @@ function UsersPage() {
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`rounded-r-2xl bg-white w-full flex justify-center items-start ${!user_id ? "h-full items-center" : ""} dark:bg-[#384250]`}>
|
||||
{user_id ? <Profile uid={+user_id} /> : <BlankPlaceholder type="user" />}
|
||||
<div className={clsx(`md:rounded-r-2xl bg-white w-full flex justify-center items-start dark:bg-gray-700`,
|
||||
!user_id && "h-full items-center",
|
||||
!isUserDetail && "hidden md:flex"
|
||||
)}>
|
||||
{isUserDetail ? <Profile uid={+user_id} /> : <BlankPlaceholder type="user" />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user