feat: add NewSelect component for enhanced selection functionality and update Button styles

This commit is contained in:
2025-06-11 18:37:35 +05:00
parent 49f335e83a
commit e11bcb13f3
5 changed files with 143 additions and 4 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ function Button({
variant === "cta" && variant === "cta" &&
"bg-[#7B60F3] text-white hover:bg-[#9184F6] active:bg-[#B3AAF9]", "bg-[#7B60F3] text-white hover:bg-[#9184F6] active:bg-[#B3AAF9]",
variant === "menu" && variant === "menu" &&
"text-[#7D7D7D] hover:bg-[#F0F0F0] active:bg-[#F8F7FE] active:text-[#7B60F3] disabled:text-[#D6D6D6] disabled:bg-[#F6F6F6]", "text-[#7D7D7D] hover:bg-[#F0F0F0] active:bg-[#F8F7FE] active:text-[#7B60F3] disabled:text-[#D6D6D6] disabled:bg-[#F6F6F6] hover:text-[#7B60F3]",
size === "large" && size === "large" &&
"2xl:p-[1.111vw] p-4 button-m 2xl:rounded-[0.833vw] rounded-xl", "2xl:p-[1.111vw] p-4 button-m 2xl:rounded-[0.833vw] rounded-xl",
size === "medium" && size === "medium" &&
+109 -2
View File
@@ -1,5 +1,112 @@
function NewSelect() { import { useEffect, useState } from "react";
return <div className="p-[1.111vw] w-[19.583vw]"></div>; import ChevronDownIcon from "./icons/ChevronDownIcon";
import ChevronUpIcon from "./icons/ChevronUpIcon";
import clsx from "clsx";
import CloseIcon from "./icons/CloseIcon";
function NewSelect<T extends { name: string }>({
data,
isGrid,
placeholder,
}: {
data: T[];
isGrid: boolean;
placeholder: string;
}) {
const [selectedValues, setSelectedValues] = useState<T[]>([]);
const [isSelectVisible, setIsSelectVisible] = useState(false);
const handleSelectClick = (item: T) => {
const isItemSelected = selectedValues.some((val) => val.name === item.name);
if (isItemSelected) {
setSelectedValues(
selectedValues.filter((value) => value.name !== item.name)
);
} else {
setSelectedValues([...selectedValues, item]);
}
};
useEffect(() => {
console.log(selectedValues);
}, [selectedValues]);
return isGrid ? (
<div className="w-[19.583vw] rounded-[0.833vw]">
<div className="grid grid-cols-3 gap[0.139vw]">
{data.map((item) => (
<div key={item.name}>{item.name}</div>
))}
</div>
</div>
) : (
<div className="relative w-[19.583vw] bg-white rounded-[0.833vw] select-none">
<div
className={clsx(
"flex items-center justify-between px-[1.111vw] py-[1.285vw] hover:bg-[#F0F0F0] rounded-[0.833vw] cursor-pointer",
isSelectVisible
? "!bg-[#E1DEFC] !text-[#7B60F3] hover:bg-[#E1DEFC]"
: "text-[#141414]"
)}
onClick={() => setIsSelectVisible(!isSelectVisible)}
>
<div className="button-m font-medium flex gap-[0.278vw] text-ellipsis overflow-hidden">
{selectedValues.length > 0
? selectedValues.map((value, index) => {
return (
<div key={value.name} className="">
{value.name +
(index !== selectedValues.length - 1 ? ", " : "")}
</div>
);
})
: placeholder}
</div>
<span
className={clsx(
"w-[1.389vw] h-[1.389vw] flex items-center justify-center ",
isSelectVisible ? "text-[#7B60F3]" : "text-[#7D7D7D]"
)}
>
{isSelectVisible ? <ChevronUpIcon /> : <ChevronDownIcon />}
</span>
</div>
<div
className={clsx(
"absolute top-[calc(100%+0.278vw)] flex flex-col gap-[0.278vw] rounded-[0.833vw] w-full",
isSelectVisible ? "block" : "hidden"
)}
>
<div
className="flex flex-col gap-[0.278vw] p-[0.833vw] w-full bg-white rounded-[0.833vw]"
style={{
boxShadow: "0px 4px 40px 0px #0000000D, 0px 2px 2px 0px #0000000D",
}}
>
<div
className="text-s font-medium p-[0.833vw] text-[#7D7D7D] flex items-center gap-[0.278vw] cursor-pointer rounded-[0.278vw] hover:bg-[#F6F6F6]"
onClick={() => setSelectedValues([])}
>
<span className="size-[1.111vw] flex items-center justify-center">
<CloseIcon />
</span>
Выбрать всё
</div>
<div className="h-[1px] w-full bg-[#F6F6F6]" />
{data.map((item, index) => (
<div
key={index}
className="w-full p-[0.833vw] text-s rounded-[0.278vw] hover:bg-[#F6F6F6] cursor-pointer"
onClick={() => handleSelectClick(item)}
>
{item.name}
</div>
))}
</div>
</div>
</div>
);
} }
export default NewSelect; export default NewSelect;
+1 -1
View File
@@ -4,7 +4,7 @@ function ChevronDownIcon() {
<path <path
d="M5.833 8.333 10 12.5l4.167-4.167" d="M5.833 8.333 10 12.5l4.167-4.167"
stroke="currentColor" stroke="currentColor"
strokeWidth={1.5} strokeWidth={1.2}
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
/> />
+15
View File
@@ -0,0 +1,15 @@
function ChevronUpIcon() {
return (
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="m5 12.084 5-5 5 5"
stroke="currentColor"
strokeWidth={1.2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export default ChevronUpIcon;
+17
View File
@@ -9,6 +9,7 @@ import SessionCard from "../components/SessionCard";
import Button from "../components/Button"; import Button from "../components/Button";
import ChevronRightIcon from "../components/icons/ChevronRightIcon"; import ChevronRightIcon from "../components/icons/ChevronRightIcon";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import NewSelect from "../components/NewSelect";
function DashboardPage() { function DashboardPage() {
const { data: me } = useQuery({ const { data: me } = useQuery({
@@ -60,6 +61,22 @@ function DashboardPage() {
</div> </div>
</div> </div>
</div> </div>
<NewSelect
data={[
{ name: "test" },
{ name: "test2" },
{ name: "test3" },
{ name: "test4" },
{ name: "test5" },
{ name: "test6" },
{ name: "test7" },
{ name: "test8" },
{ name: "test9" },
{ name: "test10" },
]}
isGrid={false}
placeholder="Выберите сервер"
/>
<div className="w-full"> <div className="w-full">
<div className="flex flex-col gap-[1.667vw]"> <div className="flex flex-col gap-[1.667vw]">
<h1 className="title-l font-[500] ">Последние сеансы</h1> <h1 className="title-l font-[500] ">Последние сеансы</h1>