This commit is contained in:
2025-06-10 16:58:54 +05:00
parent f204767e0a
commit e3eea86e28
8 changed files with 166 additions and 87 deletions
+2 -2
View File
@@ -25,13 +25,13 @@ function Layout() {
const { setModal, setPosition } = useModalStore(); const { setModal, setPosition } = useModalStore();
return ( return (
<div className="flex gap-[1.667vw] overflow-hidden"> <div className="flex gap-[1.667vw] overflow-hidden px-[2.222vw] pt-[1.667vw] pb-[2.778vw]">
<div className="flex-1"></div> <div className="flex-1"></div>
<div className="w-[42.5vw] flex flex-col gap-[1.667vw]"> <div className="w-[42.5vw] flex flex-col gap-[1.667vw]">
<Navbar /> <Navbar />
<Outlet /> <Outlet />
</div> </div>
<div className="flex-1 flex flex-col items-center gap-y-[0.833vw] py-[1.667vw]"> <div className="flex-1 flex flex-col items-center gap-y-[0.833vw]">
<AnimatePresence> <AnimatePresence>
{currentStartedSessions?.map((session, index, { length }) => ( {currentStartedSessions?.map((session, index, { length }) => (
<CurrentSessionCard <CurrentSessionCard
+91 -73
View File
@@ -1,82 +1,100 @@
import { NavLink } from "react-router"; import { Link, useLocation } from "react-router";
import clsx from "clsx";
import HomeIcon from "./icons/HomeIcon"; import HomeIcon from "./icons/HomeIcon";
import DesktopIcon from "./icons/DesktopIcon"; import DesktopIcon from "./icons/DesktopIcon";
import NewButton from "./NewButton";
import clsx from "clsx";
import PeopleIcon from "./icons/PeopleIcon";
import ClientIcon from "./icons/ClientIcon";
import AppsIcon from "./icons/AppsIcon";
function Navbar() { function Navbar() {
const { pathname } = useLocation();
return ( return (
<div className="flex 2xl:gap-[0.278vw] items-center"> <div className="flex 2xl:gap-[0.278vw] items-center">
<NavLink <Link to="/">
to="/" <NewButton
className={({ isActive }) => variant="menu"
clsx( size="large"
"2xl:p-[1.493vw] 2xl:py-[1.111vw] px-[21.5px] py-4 transition-colors flex 2xl:gap-[0.556vw] gap-2 items-center text-[#7D7D7D] hover:text-[#7B60F3]", className={clsx(
isActive && "text-[#7B60F3]" "pointer-events-none",
) pathname === "/" && "!bg-[#F8F7FE] !text-[#7B60F3]"
} )}
> >
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4"> <span className="2xl:size-[1.111vw] size-4">
<HomeIcon /> <HomeIcon />
</span> </span>
<span className="2xl:text-[0.972vw] text-sm font-medium">Главная</span> <span className="2xl:text-[0.972vw] text-sm font-medium">
</NavLink> Главная
<NavLink </span>
to="sessions" </NewButton>
className={({ isActive }) => </Link>
clsx( <Link to="/sessions">
"2xl:p-[1.493vw] 2xl:py-[1.111vw] px-[21.5px] py-4 transition-colors flex 2xl:gap-[0.556vw] gap-2 items-center text-[#7D7D7D] hover:text-[#7B60F3]", <NewButton
isActive && "text-[#7B60F3]" variant="menu"
) size="large"
} className={clsx(
> "pointer-events-none",
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4"> pathname === "/sessions" && "!bg-[#F8F7FE] !text-[#7B60F3]"
<DesktopIcon /> )}
</span> >
<span className="2xl:text-[0.972vw] text-sm font-medium">Сеансы</span> <span className="2xl:size-[1.111vw] size-4">
</NavLink> <DesktopIcon />
<NavLink </span>
to="/" <span className="2xl:text-[0.972vw] text-sm font-medium">Сеансы</span>
className={({ isActive }) => </NewButton>
clsx( </Link>
"2xl:p-[1.493vw] 2xl:py-[1.111vw] px-[21.5px] py-4 transition-colors flex 2xl:gap-[0.556vw] gap-2 items-center text-[#7D7D7D] hover:text-[#7B60F3]", <Link to="/">
isActive && "text-[#7B60F3]" <NewButton
) variant="menu"
} size="large"
> className={clsx(
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4"> "pointer-events-none",
<HomeIcon /> pathname === "/clients" && "!bg-[#F8F7FE] !text-[#7B60F3]"
</span> )}
<span className="2xl:text-[0.972vw] text-sm font-medium">Главная</span> >
</NavLink> <span className="2xl:size-[1.111vw] size-4">
<NavLink <PeopleIcon />
to="/" </span>
className={({ isActive }) => <span className="2xl:text-[0.972vw] text-sm font-medium">
clsx( Менеджеры
"2xl:p-[1.493vw] 2xl:py-[1.111vw] px-[21.5px] py-4 transition-colors flex 2xl:gap-[0.556vw] gap-2 items-center text-[#7D7D7D] hover:text-[#7B60F3]", </span>
isActive && "text-[#7B60F3]" </NewButton>
) </Link>
} <Link to="/">
> <NewButton
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4"> variant="menu"
<HomeIcon /> size="large"
</span> className={clsx(
<span className="2xl:text-[0.972vw] text-sm font-medium">Главная</span> "pointer-events-none",
</NavLink> pathname === "/settings" && "!bg-[#F8F7FE] !text-[#7B60F3]"
<NavLink )}
to="/" >
className={({ isActive }) => <span className="2xl:size-[1.111vw] size-4">
clsx( <ClientIcon />
"2xl:p-[1.493vw] 2xl:py-[1.111vw] px-[21.5px] py-4 transition-colors flex 2xl:gap-[0.556vw] gap-2 items-center text-[#7D7D7D] hover:text-[#7B60F3]", </span>
isActive && "text-[#7B60F3]" <span className="2xl:text-[0.972vw] text-sm font-medium">
) Клиенты
} </span>
> </NewButton>
<span className="2xl:w-[1.111vw] 2xl:h-[1.111vw] w-4 h-4"> </Link>
<HomeIcon /> <Link to="/">
</span> <NewButton
<span className="2xl:text-[0.972vw] text-sm font-medium">Главная</span> variant="menu"
</NavLink> size="large"
{/* */} className={clsx(
"pointer-events-none",
pathname === "/projects" && "!bg-[#F8F7FE] !text-[#7B60F3]"
)}
>
<span className="2xl:size-[1.111vw] size-4">
<AppsIcon />
</span>
<span className="2xl:text-[0.972vw] text-sm font-medium">
Проекты
</span>
</NewButton>
</Link>
</div> </div>
); );
} }
+9 -4
View File
@@ -27,7 +27,7 @@ function NewButton({
onClick?.(e); onClick?.(e);
}} }}
className={clsx( className={clsx(
"transition-all 2xl:rounded-[0.556vw] rounded-lg flex 2xl:gap-[0.556vw] gap-2 items-center justify-center font-medium disabled:bg-[#F6F6F6] disabled:text-[#D6D6D6]", "transition-all flex 2xl:gap-[0.556vw] gap-2 items-center justify-center font-medium disabled:bg-[#F6F6F6] disabled:text-[#D6D6D6]",
variant === "critical" && variant === "critical" &&
"text-[#FF4517] bg-[#FEF3F2] hover:bg-[#FEE4E2]", "text-[#FF4517] bg-[#FEF3F2] hover:bg-[#FEE4E2]",
variant === "secondary" && variant === "secondary" &&
@@ -36,9 +36,14 @@ function NewButton({
"bg-[#F8F7FE] text-[#7B60F3] hover:bg-[#E1DEFC] active:bg-[#F8F7FE]", "bg-[#F8F7FE] text-[#7B60F3] hover:bg-[#E1DEFC] active:bg-[#F8F7FE]",
variant === "cta" && variant === "cta" &&
"bg-[#7B60F3] text-white hover:bg-[#9184F6] active:bg-[#B3AAF9]", "bg-[#7B60F3] text-white hover:bg-[#9184F6] active:bg-[#B3AAF9]",
size === "large" && "2xl:p-[1.111vw] p-4 button-m", variant === "menu" &&
size === "medium" && "2xl:p-[0.833vw] p-3 button-s", "text-[#7D7D7D] hover:bg-[#F0F0F0] active:bg-[#F8F7FE] active:text-[#7B60F3] disabled:text-[#D6D6D6] disabled:bg-[#F6F6F6]",
size === "small" && "2xl:p-[0.556vw] p-2 text-[10px]", size === "large" &&
"2xl:p-[1.111vw] p-4 button-m 2xl:rounded-[0.833vw] rounded-xl",
size === "medium" &&
"2xl:p-[0.833vw] p-3 button-s 2xl:rounded-[0.833vw] rounded-xl",
size === "small" &&
"2xl:p-[0.556vw] p-2 text-[10px] 2xl:rounded-[0.556vw] rounded-lg",
className className
)} )}
> >
+1 -1
View File
@@ -6,7 +6,7 @@ function SessionCard({ session }: { session: Session }) {
const { setModal, setPosition } = useModalStore(); const { setModal, setPosition } = useModalStore();
return ( return (
<div <div
className="w-full h-[4.444vw] border-b-1 first:border-t-1 border-[#F6F6F6] flex py-[0.278vw] items-center gap-[0.556vw] cursor-pointer group" className="w-full h-[4.444vw] not-last:border-b-1 border-[#F6F6F6] flex py-[0.278vw] items-center gap-[0.556vw] cursor-pointer group"
onClick={() => { onClick={() => {
setModal(<SessionModal session={session} />); setModal(<SessionModal session={session} />);
setPosition("right"); setPosition("right");
+28
View File
@@ -0,0 +1,28 @@
function AppsIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="a" fill="#fff">
<rect width={8.58} height={8.58} rx={1} />
</mask>
<rect
width={8.58}
height={8.58}
rx={1}
transform="matrix(.87416 .48564 -.87416 .48564 10 3.5)"
stroke="currentColor"
strokeWidth={2.4}
mask="url(#a)"
/>
<path
d="M10.875 14.894c-.483.268-1.266.268-1.749 0l-5.828-3.238c-.449-.25-.473-.65-.055-.914.23-.146.633-.154.88-.017l5.368 2.983a1 1 0 0 0 .868.003l5.48-2.964a.96.96 0 0 1 .828.003c.46.256.46.67 0 .926l-5 2.778z"
fill="currentColor"
/>
<path
d="M10.874 18.014c-.483.268-1.265.268-1.748 0l-5.91-3.283c-.416-.231-.48-.594-.154-.866l.026-.022c.215-.179.668-.206.945-.056l5.537 2.981c.24.13.62.13.86 0l5.537-2.981c.277-.15.73-.123.945.056l.026.022c.327.272.262.635-.155.866l-5.116 2.843z"
fill="currentColor"
/>
</svg>
);
}
export default AppsIcon;
+22
View File
@@ -0,0 +1,22 @@
function ClientIcon() {
return (
<svg viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.45 12.28v1.32h9.6v-12h-9.6v1.68M2.25 9.6h1.333m-1.333-2h1.333m-1.333-2h1.333"
stroke="currentColor"
strokeWidth={1.2}
strokeLinecap="square"
strokeLinejoin="round"
/>
<path
d="M8.25 7a1.333 1.333 0 1 0 0-2.667A1.333 1.333 0 0 0 8.25 7Zm2.666 4.667a2.667 2.667 0 1 0-5.333 0"
stroke="currentColor"
strokeWidth={1.2}
strokeLinecap="square"
strokeLinejoin="round"
/>
</svg>
);
}
export default ClientIcon;
+12 -6
View File
@@ -41,9 +41,11 @@ function EditTable({ table }: { table: Server }) {
isError={tableName.length > 16} isError={tableName.length > 16}
errorMessage="Не больше 16 символов" errorMessage="Не больше 16 символов"
/> />
<p className="caption-s text-[#BDBDBD] font-medium w-full tracking-[-0.02em]"> {tableName.length <= 16 && (
Придумайте название до 16 символов, например «Тузик» <p className="caption-s text-[#BDBDBD] font-medium w-full tracking-[-0.02em]">
</p> Придумайте название до 16 символов, например «Тузик»
</p>
)}
</div> </div>
<div className="space-y-[0.556vw]"> <div className="space-y-[0.556vw]">
<NewInput <NewInput
@@ -53,13 +55,16 @@ function EditTable({ table }: { table: Server }) {
isError={tableDescription.length > 20} isError={tableDescription.length > 20}
errorMessage="Не больше 20 символов" errorMessage="Не больше 20 символов"
/> />
<p className="caption-s text-[#BDBDBD] font-medium w-full tracking-[-0.02em]"> {tableDescription.length <= 20 && (
Придумайте описание до 20 символов, например «Расположен в офисе» <p className="caption-s text-[#BDBDBD] font-medium w-full tracking-[-0.02em]">
</p> Придумайте описание до 20 символов, например «Расположен в офисе»
</p>
)}
</div> </div>
<div className="flex flex-col gap-[0.556vw]"> <div className="flex flex-col gap-[0.556vw]">
<NewButton <NewButton
variant="cta" variant="cta"
size="large"
disabled={ disabled={
tableName.length < 1 || tableName.length < 1 ||
tableName.length > 16 || tableName.length > 16 ||
@@ -72,6 +77,7 @@ function EditTable({ table }: { table: Server }) {
</NewButton> </NewButton>
<NewButton <NewButton
variant="primary" variant="primary"
size="large"
className="flex justify-center" className="flex justify-center"
onClick={() => setModal(null)} onClick={() => setModal(null)}
> >
+1 -1
View File
@@ -14,7 +14,7 @@ import SessionComments from "../SessionComments";
function SessionModal({ session }: { session: Session }) { function SessionModal({ session }: { session: Session }) {
return ( return (
<div className="bg-[#FFFFFF] w-[49.722vw] rounded-[2.222vw]"> <div className="bg-[#FFFFFF] w-[49.722vw] rounded-[2.222vw]">
<div className="w-full flex justify-center items-center h-[4.861vw]"> <div className="w-full flex justify-center items-center h-[4.861vw] border-b-1 border-[#D6D6D6]">
<div className="title-s flex font-medium"> <div className="title-s flex font-medium">
<p>{format(session.createdAt, "dd MMMM yyyy", { locale: ru })}</p> <p>{format(session.createdAt, "dd MMMM yyyy", { locale: ru })}</p>
<p>,&nbsp;{format(session.createdAt, "HH:mm")}</p> <p>,&nbsp;{format(session.createdAt, "HH:mm")}</p>