Initial commit for new panel

This commit is contained in:
AmirReza Jamali
2025-09-09 11:20:26 +03:30
commit 1d4ccb3575
343 changed files with 20031 additions and 0 deletions
@@ -0,0 +1,35 @@
import { useState } from "react";
const CheckboxFive = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelFive"
className="flex cursor-pointer select-none items-center text-body-sm font-medium text-dark dark:text-white"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelFive"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`box mr-2 flex h-5 w-5 items-center justify-center rounded-full border border-primary ${
isChecked && "!border-4"
}`}
>
<span className="h-2.5 w-2.5 rounded-full bg-white dark:bg-transparent"></span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxFive;
@@ -0,0 +1,43 @@
import { useState } from "react";
const CheckboxFour = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelFour"
className="flex cursor-pointer select-none items-center text-body-sm font-medium text-dark dark:text-white"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelFour"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`mr-2 flex h-5 w-5 items-center justify-center rounded-full border ${
isChecked
? "border-primary bg-gray-2 dark:bg-dark-2"
: "border-dark-5 dark:border-dark-6"
}`}
>
<span
className={`h-2.5 w-2.5 rounded-full bg-transparent ${
isChecked && "!bg-primary"
}`}
>
{" "}
</span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxFour;
@@ -0,0 +1,39 @@
import { useState } from "react";
const CheckboxOne = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelOne"
className="flex cursor-pointer select-none items-center text-body-sm font-medium"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelOne"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`mr-2 flex h-5 w-5 items-center justify-center rounded border ${
isChecked
? "border-primary bg-gray-2 dark:bg-transparent"
: "border-dark-5 dark:border-dark-6"
}`}
>
<span
className={`h-2.5 w-2.5 rounded-sm ${isChecked && "bg-primary"}`}
></span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxOne;
@@ -0,0 +1,64 @@
import { useState } from "react";
const CheckboxThree = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelThree"
className="flex cursor-pointer select-none items-center text-body-sm font-medium"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelThree"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`box mr-2 flex h-5 w-5 items-center justify-center rounded border ${
isChecked
? "border-primary bg-gray-2 dark:bg-transparent"
: "border-dark-5 dark:border-dark-6"
}`}
>
<span
className={`text-primary opacity-0 ${
isChecked && "!opacity-100"
}`}
>
<svg
className="fill-current"
width="11"
height="11"
viewBox="0 0 11 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_803_2686)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.23529 2.29669C0.942402 2.00379 0.942402 1.52892 1.23529 1.23603C1.52819 0.943134 2.00306 0.943134 2.29596 1.23603L5.37433 4.3144L8.45261 1.23612C8.7455 0.943225 9.22038 0.943225 9.51327 1.23612C9.80616 1.52901 9.80616 2.00389 9.51327 2.29678L6.43499 5.37506L9.51327 8.45334C9.80616 8.74624 9.80616 9.22111 9.51327 9.514C9.22038 9.8069 8.7455 9.8069 8.45261 9.514L5.37433 6.43572L2.29596 9.51409C2.00306 9.80699 1.52819 9.80699 1.23529 9.51409C0.942402 9.2212 0.942402 8.74633 1.23529 8.45343L4.31367 5.37506L1.23529 2.29669Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_803_2686">
<rect width="10.75" height="10.75" fill="white" />
</clipPath>
</defs>
</svg>
</span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxThree;
@@ -0,0 +1,52 @@
import { useState } from "react";
const CheckboxTwo = () => {
const [isChecked, setIsChecked] = useState<boolean>(false);
return (
<div>
<label
htmlFor="checkboxLabelTwo"
className="flex cursor-pointer select-none items-center text-body-sm font-medium"
>
<div className="relative">
<input
type="checkbox"
id="checkboxLabelTwo"
className="sr-only"
onChange={() => {
setIsChecked(!isChecked);
}}
/>
<div
className={`mr-2 flex h-5 w-5 items-center justify-center rounded border ${
isChecked
? "border-primary bg-gray-2 dark:bg-transparent"
: "border border-dark-5 dark:border-dark-6"
}`}
>
<span className={`opacity-0 ${isChecked && "!opacity-100"}`}>
<svg
width="11"
height="8"
viewBox="0 0 11 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.0915 0.951972L10.0867 0.946075L10.0813 0.940568C9.90076 0.753564 9.61034 0.753146 9.42927 0.939309L4.16201 6.22962L1.58507 3.63469C1.40401 3.44841 1.11351 3.44879 0.932892 3.63584C0.755703 3.81933 0.755703 4.10875 0.932892 4.29224L0.932878 4.29225L0.934851 4.29424L3.58046 6.95832C3.73676 7.11955 3.94983 7.2 4.1473 7.2C4.36196 7.2 4.55963 7.11773 4.71406 6.9584L10.0468 1.60234C10.2436 1.4199 10.2421 1.1339 10.0915 0.951972ZM4.2327 6.30081L4.2317 6.2998C4.23206 6.30015 4.23237 6.30049 4.23269 6.30082L4.2327 6.30081Z"
fill="#5750F1"
stroke="#5750F1"
strokeWidth="0.4"
/>
</svg>
</span>
</div>
</div>
Checkbox Text
</label>
</div>
);
};
export default CheckboxTwo;
@@ -0,0 +1,38 @@
"use client";
import { Calendar } from "@/components/Layouts/sidebar/icons";
import flatpickr from "flatpickr";
import { useEffect } from "react";
const DatePickerOne = () => {
useEffect(() => {
// Init flatpickr
flatpickr(".form-datepicker", {
mode: "single",
static: true,
monthSelectorType: "static",
dateFormat: "M j, Y",
});
}, []);
return (
<div>
<label className="mb-3 block text-body-sm font-medium text-dark dark:text-white">
Date picker
</label>
<div className="relative">
<input
className="form-datepicker w-full rounded-[7px] border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary"
placeholder="mm/dd/yyyy"
data-class="flatpickr-right"
/>
<div className="pointer-events-none absolute inset-0 left-auto right-5 flex items-center">
<Calendar className="size-5 text-[#9CA3AF]" />
</div>
</div>
</div>
);
};
export default DatePickerOne;
@@ -0,0 +1,38 @@
"use client";
import { ChevronUpIcon } from "@/assets/icons";
import flatpickr from "flatpickr";
import { useEffect } from "react";
const DatePickerTwo = () => {
useEffect(() => {
// Init flatpickr
flatpickr(".form-datepicker", {
mode: "single",
static: true,
monthSelectorType: "static",
dateFormat: "M j, Y",
});
}, []);
return (
<div>
<label className="mb-3 block text-body-sm font-medium text-dark dark:text-white">
Select date
</label>
<div className="relative">
<input
className="form-datepicker w-full rounded-[7px] border-[1.5px] border-stroke bg-transparent px-5 py-3 font-normal outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary"
placeholder="mm/dd/yyyy"
data-class="flatpickr-right"
/>
<div className="pointer-events-none absolute inset-0 left-auto right-5 flex items-center text-dark-4 dark:text-dark-6">
<ChevronUpIcon className="rotate-180" />
</div>
</div>
</div>
);
};
export default DatePickerTwo;
@@ -0,0 +1,122 @@
import { cn } from "@/lib/utils";
import { type HTMLInputTypeAttribute, useId } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegister,
type UseFormRegisterReturn,
} from "react-hook-form";
type InputGroupProps<T extends FieldValues> = {
name: Path<T>;
label: string;
type: HTMLInputTypeAttribute;
placeholder: string;
className?: string;
fileStyleVariant?: "style1" | "style2";
required?: boolean;
disabled?: boolean;
active?: boolean;
handleChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
value?: string;
icon?: React.ReactNode;
iconPosition?: "left" | "right";
height?: "sm" | "default";
defaultValue?: string;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
} & Partial<UseFormRegisterReturn>;
const InputGroup = <T extends FieldValues>({
className,
label,
type,
placeholder,
required,
disabled,
active,
handleChange,
icon,
name,
register,
errors,
onChange,
onBlur,
ref,
...props
}: InputGroupProps<T>): React.ReactElement => {
const id = useId();
const error = errors && errors[name];
return (
<div className={className}>
<label
htmlFor={id}
className="text-body-sm font-medium text-dark dark:text-white"
>
{label}
{required && <span className="text-red ml-1 select-none">*</span>}
</label>
<div
className={cn(
"relative mt-3 [&_svg]:absolute [&_svg]:top-1/2 [&_svg]:-translate-y-1/2",
props.iconPosition === "left"
? "[&_svg]:left-4.5"
: "[&_svg]:right-4.5",
)}
>
<input
id={id}
type={type}
placeholder={placeholder}
name={name}
ref={ref}
onChange={(e) => {
onChange?.(e);
handleChange?.(e);
}}
onBlur={onBlur}
{...(!onChange &&
props.value !== undefined && { value: props.value })}
{...(!onChange &&
props.defaultValue !== undefined && {
defaultValue: props.defaultValue,
})}
className={cn(
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent outline-none transition focus:border-primary disabled:cursor-default disabled:bg-gray-2 data-[active=true]:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary dark:disabled:bg-dark dark:data-[active=true]:border-primary",
// Add error styles conditionally
error && "border-red focus:border-red dark:border-red",
type === "file"
? getFileStyles(props.fileStyleVariant!)
: "px-5.5 py-3 text-dark placeholder:text-dark-6 dark:text-white",
props.iconPosition === "left" && "pl-12.5",
props.height === "sm" && "py-2.5",
)}
disabled={disabled}
data-active={active}
/>
{icon}
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
};
export default InputGroup;
function getFileStyles(variant: "style1" | "style2") {
switch (variant) {
case "style1":
return `file:mr-5 file:border-collapse file:cursor-pointer file:border-0 file:border-r file:border-solid file:border-stroke file:bg-[#E2E8F0] file:px-6.5 file:py-[13px] file:text-body-sm file:font-medium file:text-dark-5 file:hover:bg-primary file:hover:bg-opacity-10 dark:file:border-dark-3 dark:file:bg-white/30 dark:file:text-white`;
default:
return `file:mr-4 file:rounded file:border-[0.5px] file:border-stroke file:bg-stroke file:px-2.5 file:py-1 file:text-body-xs file:font-medium file:text-dark-5 file:focus:border-primary dark:file:border-dark-3 dark:file:bg-white/30 dark:file:text-white px-3 py-[9px]`;
}
}
@@ -0,0 +1,89 @@
import { cn } from "@/lib/utils";
import { useId } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegister,
type UseFormRegisterReturn,
} from "react-hook-form";
type PropsType<T extends FieldValues> = {
name: Path<T>;
label: string;
placeholder: string;
required?: boolean;
disabled?: boolean;
active?: boolean;
className?: string;
icon?: React.ReactNode;
defaultValue?: string;
handleChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
} & Partial<UseFormRegisterReturn>;
export function TextAreaGroup<T extends FieldValues>({
name,
label,
placeholder,
required,
disabled,
active,
className,
icon,
defaultValue,
handleChange,
register,
errors,
onChange,
onBlur,
ref,
...props
}: PropsType<T>) {
const id = useId();
const error = errors && errors[name];
return (
<div className={cn(className)}>
<label
htmlFor={id}
className="mb-3 block text-body-sm font-medium text-dark dark:text-white"
>
{label}
{required && <span className="text-red ml-1 select-none">*</span>}
</label>
<div className="relative mt-3 [&_svg]:pointer-events-none [&_svg]:absolute [&_svg]:left-5.5 [&_svg]:top-5.5">
<textarea
id={id}
name={name}
ref={ref}
rows={6}
placeholder={placeholder}
defaultValue={defaultValue}
onChange={(e) => {
onChange?.(e);
handleChange?.(e);
}}
onBlur={onBlur}
className={cn(
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5.5 py-3 text-dark outline-none transition focus:border-primary disabled:cursor-default disabled:bg-gray-2 data-[active=true]:border-primary dark:border-dark-3 dark:bg-dark-2 dark:text-white dark:focus:border-primary dark:disabled:bg-dark dark:data-[active=true]:border-primary",
error && "border-red focus:border-red dark:border-red",
icon && "py-5 pl-13 pr-5",
)}
required={required}
disabled={disabled}
data-active={active}
/>
{icon}
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
}
+241
View File
@@ -0,0 +1,241 @@
"use client";
import React, { useEffect, useRef, useState, useId } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegisterReturn,
} from "react-hook-form";
interface Option {
value: string;
text: string;
selected: boolean;
}
type MultiSelectProps<T extends FieldValues> = {
label: string;
items: { value: string; text: string }[];
errors?: FieldErrors<T>;
required?: boolean;
placeholder?: string;
className?: string;
} & UseFormRegisterReturn<Path<T>>;
function MultiSelect<T extends FieldValues>({
name,
label,
items,
errors,
required,
placeholder = "Select an option",
className,
onChange,
onBlur,
ref,
}: MultiSelectProps<T>) {
const id = useId();
const error = errors && errors[name];
const [options, setOptions] = useState<Option[]>([]);
const [selected, setSelected] = useState<number[]>([]);
const [show, setShow] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
const trigger = useRef<HTMLDivElement | null>(null);
useEffect(() => {
setOptions(
items.map((item) => ({
...item,
selected: false,
})),
);
}, [items]);
const open = () => {
setShow(true);
};
const isOpen = () => {
return show === true;
};
const combinedRef = (el: HTMLDivElement) => {
trigger.current = el;
if (typeof ref === "function") {
ref(el);
}
};
const handleSelect = (index: number) => {
const newOptions = [...options];
let newSelected = [...selected];
if (!newOptions[index].selected) {
newOptions[index].selected = true;
newSelected.push(index);
} else {
newOptions[index].selected = false;
newSelected = newSelected.filter((i) => i !== index);
}
setOptions(newOptions);
setSelected(newSelected);
const selectedValues = newSelected.map((i) => options[i].value);
onChange?.({ target: { name, value: selectedValues } });
};
const remove = (index: number, event: React.MouseEvent) => {
event.stopPropagation();
const newOptions = [...options];
const newSelected = selected.filter((i) => i !== index);
newOptions[index].selected = false;
setOptions(newOptions);
setSelected(newSelected);
const selectedValues = newSelected.map((i) => options[i].value);
onChange?.({ target: { name, value: selectedValues } });
};
useEffect(() => {
const clickHandler = ({ target }: MouseEvent) => {
if (!dropdownRef.current) return;
if (
!show ||
dropdownRef.current.contains(target as Node) ||
trigger.current?.contains(target as Node)
)
return;
setShow(false);
};
document.addEventListener("click", clickHandler);
return () => document.removeEventListener("click", clickHandler);
}, [show]);
return (
<div className={`relative z-50 ${className}`}>
<label
htmlFor={id}
className="mb-3 block text-body-sm font-medium text-dark dark:text-white"
>
{label}
</label>
<div className="relative">
<div
ref={combinedRef}
onClick={open}
onBlur={onBlur}
tabIndex={0}
className={`flex min-h-[46px] w-full cursor-pointer items-center rounded-[7px] border-[1.5px] bg-transparent py-2 pl-3 pr-3 outline-none transition focus:border-primary active:border-primary dark:bg-dark-2 ${
error
? "border-red focus:border-red dark:border-red"
: "border-stroke dark:border-dark-3"
}`}
>
<div className="flex flex-auto flex-wrap gap-2">
{selected.map((index) => (
<div
key={index}
className="flex items-center justify-center rounded-[5px] border-[.5px] border-stroke bg-gray-2 px-2.5 py-1 text-body-sm font-medium dark:border-dark-3 dark:bg-dark"
>
<div className="max-w-full flex-initial">
{options[index]?.text}
</div>
<div className="flex flex-auto flex-row-reverse">
<div
onClick={(e) => remove(index, e)}
className="hover:text-red cursor-pointer pl-2"
>
<svg
className="fill-current"
role="button"
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.35355 3.35355C9.54882 3.15829 9.54882 2.84171 9.35355 2.64645C9.15829 2.45118 8.84171 2.45118 8.64645 2.64645L6 5.29289L3.35355 2.64645C3.15829 2.45118 2.84171 2.45118 2.64645 2.64645C2.45118 2.84171 2.45118 3.15829 2.64645 3.35355L5.29289 6L2.64645 8.64645C2.45118 8.84171 2.45118 9.15829 2.64645 9.35355C2.84171 9.54882 3.15829 9.54882 3.35355 9.35355L6 6.70711L8.64645 9.35355C8.84171 9.54882 9.15829 9.54882 9.35355 9.35355C9.54882 9.15829 9.54882 8.84171 9.35355 8.64645L6.70711 6L9.35355 3.35355Z"
fill="currentColor"
/>
</svg>
</div>
</div>
</div>
))}
{selected.length === 0 && (
<div className="flex-1">
<span className="h-full w-full bg-transparent p-1 px-2 text-dark-5 outline-none dark:text-dark-6">
{placeholder}
</span>
</div>
)}
</div>
<div className="flex items-center py-1 pl-1 pr-1">
<button
type="button"
className="cursor-pointer text-dark-4 outline-none focus:outline-none dark:text-dark-6"
>
<svg
className={`fill-current transition-transform duration-200 ${
isOpen() ? "rotate-180" : ""
}`}
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.69149 7.09327C3.91613 6.83119 4.31069 6.80084 4.57277 7.02548L9.99936 11.6768L15.4259 7.02548C15.688 6.80084 16.0826 6.83119 16.3072 7.09327C16.5319 7.35535 16.5015 7.74991 16.2394 7.97455L10.4061 12.9745C10.172 13.1752 9.82667 13.1752 9.59261 12.9745L3.75928 7.97455C3.4972 7.74991 3.46685 7.35535 3.69149 7.09327Z"
fill="currentColor"
/>
</svg>
</button>
</div>
</div>
<div
className={`max-h-select absolute left-0 top-full z-40 w-full overflow-y-auto rounded bg-white shadow-1 dark:bg-dark-2 dark:shadow-card ${
isOpen() ? "" : "hidden"
}`}
ref={dropdownRef}
>
<div className="flex w-full flex-col">
{options.map((option, index) => (
<div key={index}>
<div
className="w-full cursor-pointer rounded-t border-b border-stroke hover:bg-primary/5 dark:border-dark-3"
onClick={() => handleSelect(index)}
>
<div
className={`relative flex w-full items-center border-l-2 p-2 pl-2 ${
option.selected ? "border-primary" : "border-transparent"
}`}
>
<div className="flex w-full items-center">
<div className="mx-2 leading-6">{option.text}</div>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
}
export default MultiSelect;
@@ -0,0 +1,33 @@
import { useState } from "react";
const SwitcherFour = () => {
const [enabled, setEnabled] = useState<boolean>(false);
return (
<div>
<label
htmlFor="toggle4"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
type="checkbox"
id="toggle4"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="block h-8 w-14 rounded-full bg-[#212B36] dark:bg-primary"></div>
<div
className={`absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white transition ${
enabled && "!right-1 !translate-x-full"
}`}
></div>
</div>
</label>
</div>
);
};
export default SwitcherFour;
@@ -0,0 +1,33 @@
import { useState } from "react";
const SwitcherOne = () => {
const [enabled, setEnabled] = useState<boolean>(false);
return (
<div>
<label
htmlFor="toggle1"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
type="checkbox"
id="toggle1"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="block h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]"></div>
<div
className={`absolute left-1 top-1 h-6 w-6 rounded-full bg-white shadow-switch-1 transition ${
enabled && "!right-1 !translate-x-full !bg-primary dark:!bg-white"
}`}
></div>
</div>
</label>
</div>
);
};
export default SwitcherOne;
@@ -0,0 +1,75 @@
import { useState } from "react";
const SwitcherThree = () => {
const [enabled, setEnabled] = useState(false);
return (
<div>
<label
htmlFor="toggle3"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
type="checkbox"
id="toggle3"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="block h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]"></div>
<div
className={`dot absolute left-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-white shadow-switch-1 transition ${
enabled && "!right-1 !translate-x-full !bg-primary dark:!bg-white"
}`}
>
<span className={`hidden ${enabled && "!block"}`}>
<svg
className="fill-white dark:fill-dark"
width="11"
height="8"
viewBox="0 0 11 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.2355 0.812752L10.2452 0.824547C10.4585 1.08224 10.4617 1.48728 10.1855 1.74621L4.85633 7.09869C4.66442 7.29617 4.41535 7.4001 4.14693 7.4001C3.89823 7.4001 3.63296 7.29979 3.43735 7.09851L0.788615 4.43129C0.536589 4.1703 0.536617 3.758 0.788643 3.49701C1.04747 3.22897 1.4675 3.22816 1.72731 3.49457L4.16182 5.94608L9.28643 0.799032C9.54626 0.532887 9.96609 0.533789 10.2248 0.801737L10.2355 0.812752Z"
fill=""
/>
</svg>
</span>
<span className={`${enabled && "hidden"}`}>
<svg
className="fill-current"
width="11"
height="11"
viewBox="0 0 11 11"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_803_2686)">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M1.23529 2.29669C0.942402 2.00379 0.942402 1.52892 1.23529 1.23603C1.52819 0.943134 2.00306 0.943134 2.29596 1.23603L5.37433 4.3144L8.45261 1.23612C8.7455 0.943225 9.22038 0.943225 9.51327 1.23612C9.80616 1.52901 9.80616 2.00389 9.51327 2.29678L6.43499 5.37506L9.51327 8.45334C9.80616 8.74624 9.80616 9.22111 9.51327 9.514C9.22038 9.8069 8.7455 9.8069 8.45261 9.514L5.37433 6.43572L2.29596 9.51409C2.00306 9.80699 1.52819 9.80699 1.23529 9.51409C0.942402 9.2212 0.942402 8.74633 1.23529 8.45343L4.31367 5.37506L1.23529 2.29669Z"
fill=""
/>
</g>
<defs>
<clipPath id="clip0_803_2686">
<rect width="10.75" height="10.75" fill="white" />
</clipPath>
</defs>
</svg>
</span>
</div>
</div>
</label>
</div>
);
};
export default SwitcherThree;
@@ -0,0 +1,33 @@
import { useState } from "react";
const SwitcherTwo = () => {
const [enabled, setEnabled] = useState(false);
return (
<div>
<label
htmlFor="toggle2"
className="flex cursor-pointer select-none items-center"
>
<div className="relative">
<input
id="toggle2"
type="checkbox"
className="sr-only"
onChange={() => {
setEnabled(!enabled);
}}
/>
<div className="h-5 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]"></div>
<div
className={`dot shadow-switch-2 absolute -top-1 left-0 h-7 w-7 rounded-full bg-white transition ${
enabled && "!right-0 !translate-x-full !bg-primary dark:!bg-white"
}`}
></div>
</div>
</label>
</div>
);
};
export default SwitcherTwo;
+69
View File
@@ -0,0 +1,69 @@
import { CheckIcon, XIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { useId } from "react";
type PropsType = {
withIcon?: "check" | "x";
withBg?: boolean;
label: string;
name?: string;
minimal?: boolean;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
radius?: "default" | "md";
};
export function Checkbox({
withIcon,
label,
name,
withBg,
minimal,
onChange,
radius,
}: PropsType) {
const id = useId();
return (
<div>
<label
htmlFor={id}
className={cn(
"flex cursor-pointer select-none items-center",
!minimal && "text-body-sm font-medium",
)}
>
<div className="relative">
<input
type="checkbox"
onChange={onChange}
name={name}
id={id}
className="peer sr-only"
/>
<div
className={cn(
"mr-2 flex size-5 items-center justify-center rounded border border-dark-5 peer-checked:border-primary dark:border-dark-6 peer-checked:[&>*]:block",
withBg
? "peer-checked:bg-primary [&>*]:text-white"
: "peer-checked:bg-gray-2 dark:peer-checked:bg-transparent",
minimal && "mr-3 border-stroke dark:border-dark-3",
radius === "md" && "rounded-md",
)}
>
{!withIcon && (
<span className="hidden size-2.5 rounded-sm bg-primary" />
)}
{withIcon === "check" && (
<CheckIcon className="hidden text-primary" />
)}
{withIcon === "x" && <XIcon className="hidden text-primary" />}
</div>
</div>
<span>{label}</span>
</label>
</div>
);
}
+58
View File
@@ -0,0 +1,58 @@
import { cn } from "@/lib/utils";
import { useId } from "react";
type PropsType = {
variant?: "dot" | "circle";
label: string;
name?: string;
value?: string;
minimal?: boolean;
};
export function RadioInput({
label,
variant = "dot",
name,
value,
minimal,
}: PropsType) {
const id = useId();
return (
<div>
<label
htmlFor={id}
className="flex cursor-pointer select-none items-center text-body-sm font-medium text-dark dark:text-white"
>
<div className="relative">
<input
type="radio"
name={name}
id={id}
className="peer sr-only"
value={value}
/>
<div
className={cn(
"mr-2 flex size-5 items-center justify-center rounded-full border peer-checked:[&>*]:block",
{
"border-primary peer-checked:border-6": variant === "circle",
"border-dark-5 peer-checked:border-primary peer-checked:bg-gray-2 dark:border-dark-6 dark:peer-checked:bg-dark-2":
variant === "dot",
},
minimal && "border-stroke dark:border-dark-3",
)}
>
<span
className={cn(
"hidden size-2.5 rounded-full bg-primary",
variant === "circle" && "bg-transparent",
)}
/>
</div>
</div>
<span>{label}</span>
</label>
</div>
);
}
+105
View File
@@ -0,0 +1,105 @@
"use client";
import { ChevronUpIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { useId, useState } from "react";
import {
type FieldErrors,
type FieldValues,
type Path,
type UseFormRegister,
type UseFormRegisterReturn,
} from "react-hook-form";
type PropsType<T extends FieldValues> = {
name: Path<T>;
label: string;
items: { value: string; label: string }[];
prefixIcon?: React.ReactNode;
className?: string;
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
required?: boolean;
} & (
| { placeholder?: string; defaultValue: string }
| { placeholder: string; defaultValue?: string }
) &
Partial<UseFormRegisterReturn>;
export function Select<T extends FieldValues>({
items,
label,
defaultValue,
placeholder,
prefixIcon,
className,
name,
register,
errors,
required,
onChange,
onBlur,
ref,
...props
}: PropsType<T>) {
const id = useId();
const [isOptionSelected, setIsOptionSelected] = useState(!!defaultValue);
const error = errors && errors[name];
return (
<div className={cn("space-y-3", className)}>
<label
htmlFor={id}
className="block text-body-sm font-medium text-dark dark:text-white"
>
{label}
{required && <span className="text-red ml-1 select-none">*</span>}
</label>
<div className="relative">
{prefixIcon && (
<div className="absolute left-4 top-1/2 -translate-y-1/2">
{prefixIcon}
</div>
)}
<select
id={id}
name={name}
ref={ref}
defaultValue={defaultValue || ""}
onChange={(e) => {
setIsOptionSelected(!!e.target.value);
onChange?.(e);
}}
onBlur={onBlur}
className={cn(
"w-full appearance-none rounded-lg border border-stroke bg-transparent px-5.5 py-3 outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary [&>option]:text-dark-5 dark:[&>option]:text-dark-6",
isOptionSelected && "text-dark dark:text-white",
error && "border-red focus:border-red dark:border-red",
prefixIcon && "pl-11.5",
)}
>
{placeholder && (
<option value="" disabled hidden>
{placeholder}
</option>
)}
{items.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</select>
<ChevronUpIcon className="pointer-events-none absolute right-4 top-1/2 -translate-y-1/2 rotate-180" />
</div>
{error && (
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
)}
</div>
);
}
+54
View File
@@ -0,0 +1,54 @@
import { CheckIcon, XIcon } from "@/assets/icons";
import { cn } from "@/lib/utils";
import { useId } from "react";
type PropsType = {
withIcon?: boolean;
background?: "dark" | "light";
backgroundSize?: "sm" | "default";
name?: string;
};
export function Switch({
background,
withIcon,
backgroundSize,
name,
}: PropsType) {
const id = useId();
return (
<label
htmlFor={id}
className="flex max-w-fit cursor-pointer select-none items-center"
>
<div className="relative">
<input type="checkbox" name={name} id={id} className="peer sr-only" />
<div
className={cn("h-8 w-14 rounded-full bg-gray-3 dark:bg-[#5A616B]", {
"h-5": backgroundSize === "sm",
"bg-[#212B36] dark:bg-primary": background === "dark",
})}
/>
<div
className={cn(
"absolute left-1 top-1 flex size-6 items-center justify-center rounded-full bg-white shadow-switch-1 transition peer-checked:right-1 peer-checked:translate-x-full peer-checked:[&_.check-icon]:block peer-checked:[&_.x-icon]:hidden",
{
"-top-1 left-0 size-7 shadow-switch-2": backgroundSize === "sm",
"peer-checked:bg-primary peer-checked:dark:bg-white":
background !== "dark",
},
)}
>
{withIcon && (
<>
<CheckIcon className="check-icon hidden fill-white dark:fill-dark" />
<XIcon className="x-icon" />
</>
)}
</div>
</div>
</label>
);
}