missions and filter
This commit is contained in:
@@ -5,7 +5,7 @@ interface ButtonProps {
|
||||
disabled?: boolean;
|
||||
text?: string;
|
||||
className?: string;
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
onClick: () => void;
|
||||
children?: React.ReactNode;
|
||||
color?: 'primary' | 'secondary' | 'error' | 'warning' | 'success';
|
||||
}
|
||||
@@ -41,6 +41,9 @@ export const PrimaryButton: React.FC<ButtonProps> = ({
|
||||
disabled && 'pointer-events-none',
|
||||
className,
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{/* Основной контейнер, */}
|
||||
<div
|
||||
@@ -60,10 +63,8 @@ export const PrimaryButton: React.FC<ButtonProps> = ({
|
||||
'[&:focus-visible+*]:outline-liquid-brightmain',
|
||||
)}
|
||||
disabled={disabled}
|
||||
onClick={(
|
||||
e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
||||
) => {
|
||||
onClick(e);
|
||||
onClick={() => {
|
||||
onClick();
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ interface ButtonProps {
|
||||
disabled?: boolean;
|
||||
text?: string;
|
||||
className?: string;
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
onClick: () => void;
|
||||
children?: React.ReactNode;
|
||||
color?: 'primary' | 'secondary' | 'error' | 'warning' | 'success';
|
||||
}
|
||||
@@ -41,6 +41,9 @@ export const ReverseButton: React.FC<ButtonProps> = ({
|
||||
disabled && 'pointer-events-none',
|
||||
className,
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{/* Основной контейнер, */}
|
||||
<div
|
||||
@@ -61,10 +64,8 @@ export const ReverseButton: React.FC<ButtonProps> = ({
|
||||
'[&:focus-visible+*]:outline-liquid-brightmain',
|
||||
)}
|
||||
disabled={disabled}
|
||||
onClick={(
|
||||
e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
||||
) => {
|
||||
onClick(e);
|
||||
onClick={() => {
|
||||
onClick();
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ interface ButtonProps {
|
||||
disabled?: boolean;
|
||||
text?: string;
|
||||
className?: string;
|
||||
onClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
onClick: () => void;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@ export const SecondaryButton: React.FC<ButtonProps> = ({
|
||||
disabled && 'pointer-events-none',
|
||||
className,
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{/* Основной контейнер, */}
|
||||
<div
|
||||
@@ -41,8 +44,8 @@ export const SecondaryButton: React.FC<ButtonProps> = ({
|
||||
'[&:focus-visible+*]:outline-liquid-brightmain',
|
||||
)}
|
||||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
onClick(e);
|
||||
onClick={() => {
|
||||
onClick();
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
124
src/components/drop-down-list/Filter.tsx
Normal file
124
src/components/drop-down-list/Filter.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import { cn } from '../../lib/cn';
|
||||
import { checkMark, chevroneDropDownList } from '../../assets/icons/input';
|
||||
import { useClickOutside } from '../../hooks/useClickOutside';
|
||||
|
||||
export interface FilterItem {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface FilterProps {
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
onChange: (state: string[]) => void; // теперь массив выбранных значений
|
||||
defaultState?: FilterItem[];
|
||||
items: FilterItem[];
|
||||
}
|
||||
|
||||
export const Filter: React.FC<FilterProps> = ({
|
||||
className = '',
|
||||
onChange,
|
||||
defaultState = [],
|
||||
items = [{ text: '', value: '' }],
|
||||
}) => {
|
||||
if (items.length === 0) items.push({ text: '', value: '' });
|
||||
|
||||
const [selectedValues, setSelectedValues] =
|
||||
React.useState<FilterItem[]>(defaultState);
|
||||
const [active, setActive] = React.useState<boolean>(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
onChange(selectedValues.map((v) => v.value));
|
||||
}, [selectedValues]);
|
||||
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
useClickOutside(ref, () => setActive(false));
|
||||
|
||||
const toggleItem = (item: FilterItem) => {
|
||||
const exists = selectedValues.some((v) => v.value === item.value);
|
||||
if (exists) {
|
||||
setSelectedValues(
|
||||
selectedValues.filter((v) => v.value !== item.value),
|
||||
);
|
||||
} else {
|
||||
setSelectedValues([...selectedValues, item]);
|
||||
}
|
||||
};
|
||||
|
||||
const displayText =
|
||||
selectedValues.length > 0
|
||||
? selectedValues.map((v) => v.text).join(', ')
|
||||
: 'Выберите...';
|
||||
|
||||
return (
|
||||
<div className={cn('relative', className)} ref={ref}>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center h-[40px] rounded-[10px] bg-liquid-lighter px-[16px] w-[220px]',
|
||||
'text-[16px] font-bold cursor-pointer select-none',
|
||||
'transition-all active:scale-95 duration-300 overflow-hidden whitespace-nowrap text-ellipsis',
|
||||
)}
|
||||
onClick={() => setActive(!active)}
|
||||
title={displayText}
|
||||
>
|
||||
{displayText}
|
||||
</div>
|
||||
|
||||
<img
|
||||
src={chevroneDropDownList}
|
||||
className={cn(
|
||||
'absolute right-[16px] h-[24px] w-[24px] top-[8.5px] rotate-0 transition-all duration-300 pointer-events-none',
|
||||
active && 'rotate-180',
|
||||
)}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
'absolute rounded-[10px] bg-liquid-lighter w-[220px] left-0 top-[48px] z-50 transition-all duration-300',
|
||||
'grid overflow-hidden',
|
||||
active
|
||||
? 'grid-rows-[1fr] opacity-100'
|
||||
: 'grid-rows-[0fr] opacity-0',
|
||||
)}
|
||||
>
|
||||
<div className="overflow-hidden p-[8px]">
|
||||
<div
|
||||
className={cn(
|
||||
'overflow-y-scroll max-h-[220px] thin-scrollbar pr-[8px]',
|
||||
'grid grid-cols-2 gap-[4px]',
|
||||
)}
|
||||
>
|
||||
{items.map((v, i) => {
|
||||
const isSelected = selectedValues.some(
|
||||
(sel) => sel.value === v.value,
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
className={cn(
|
||||
'cursor-pointer h-[36px] relative transition-all duration-300 flex items-center pl-[8px] pr-[24px] rounded-[6px]',
|
||||
'text-[14px] font-medium select-none',
|
||||
'hover:bg-liquid-background',
|
||||
isSelected &&
|
||||
'bg-liquid-background font-semibold',
|
||||
)}
|
||||
onClick={() => toggleItem(v)}
|
||||
>
|
||||
{v.text}
|
||||
|
||||
{isSelected && (
|
||||
<img
|
||||
src={checkMark}
|
||||
className="absolute right-[6px] w-[16px] h-[16px]"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
127
src/components/drop-down-list/Sorter.tsx
Normal file
127
src/components/drop-down-list/Sorter.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import React from 'react';
|
||||
import { cn } from '../../lib/cn';
|
||||
import { checkMark } from '../../assets/icons/input';
|
||||
import { useClickOutside } from '../../hooks/useClickOutside';
|
||||
import { Sort, SortActive } from '../../assets/icons/filters';
|
||||
|
||||
export interface SorterItem {
|
||||
text: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface SorterProps {
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
onChange: (state: string) => void;
|
||||
defaultState?: SorterItem;
|
||||
items: SorterItem[];
|
||||
}
|
||||
|
||||
export const Sorter: React.FC<SorterProps> = ({
|
||||
// disabled = false,
|
||||
className = '',
|
||||
onChange,
|
||||
defaultState,
|
||||
items = [{ text: '', value: '' }],
|
||||
}) => {
|
||||
if (items.length == 0) items.push({ text: '', value: '' });
|
||||
|
||||
const [value, setValue] = React.useState<SorterItem>(
|
||||
defaultState != undefined ? defaultState : items[0],
|
||||
);
|
||||
const [active, setActive] = React.useState<boolean>(false);
|
||||
|
||||
React.useEffect(() => onChange(value.value), [value]);
|
||||
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
useClickOutside(ref, () => {
|
||||
setActive(false);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={cn('relative', className)} ref={ref}>
|
||||
<div
|
||||
className={cn(
|
||||
'grid items-center h-[40px] rounded-full bg-liquid-lighter grid-cols-[40px]',
|
||||
'text-[18px] font-bold cursor-pointer select-none',
|
||||
'transitin-all active:scale-95 duration-300 overflow-hidden',
|
||||
active && ' grid-cols-[1fr]',
|
||||
)}
|
||||
onClick={() => {
|
||||
setActive(!active);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'text-liquid-brightmain pl-[40px] pr-[16px]',
|
||||
active && '',
|
||||
)}
|
||||
>
|
||||
{' '}
|
||||
{value.text}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="h-[24px] w-[24px] bg-red-500"></div>
|
||||
<img
|
||||
src={Sort}
|
||||
className={cn(
|
||||
' absolute right-[16px] h-[24px] w-[24px] top-[8px] left-[8px] rotate-0 transition-all duration-300 pointer-events-none',
|
||||
)}
|
||||
/>
|
||||
<img
|
||||
src={SortActive}
|
||||
className={cn(
|
||||
' absolute right-[16px] h-[24px] w-[24px] top-[8px] left-[8px] rotate-0 transition-all duration-300 pointer-events-none opacity-0',
|
||||
active && ' opacity-100',
|
||||
)}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
' absolute rounded-[10px] bg-liquid-lighter w-[220px] left-0 top-[48px] z-50 transition-all duration-300',
|
||||
'grid overflow-hidden',
|
||||
active
|
||||
? 'grid-rows-[1fr] opacity-100'
|
||||
: 'grid-rows-[0fr] opacity-0',
|
||||
)}
|
||||
>
|
||||
<div className=" overflow-hidden p-[8px]">
|
||||
<div
|
||||
className={cn(
|
||||
' overflow-y-scroll max-h-[200px] thin-scrollbar pr-[8px] ',
|
||||
)}
|
||||
>
|
||||
{items.map((v, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={cn(
|
||||
'cursor-pointer h-[36px] relative transition-all duration-300',
|
||||
i + 1 != items.length &&
|
||||
'border-b-liquid-light border-b-[1px]',
|
||||
'text-[16px] font-medium cursor-pointer select-none flex items-center pl-[8px]',
|
||||
'hover:bg-liquid-background',
|
||||
'first:rounded-t-[6px] last:rounded-b-[6px]',
|
||||
)}
|
||||
onClick={() => {
|
||||
setValue(v);
|
||||
setActive(false);
|
||||
}}
|
||||
>
|
||||
{v.text}
|
||||
|
||||
{v.text == value.text && (
|
||||
<img
|
||||
src={checkMark}
|
||||
className=" absolute right-[8px]"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user