diff --git a/src/index.css b/src/index.css index ccac1a1..155343e 100644 --- a/src/index.css +++ b/src/index.css @@ -102,3 +102,36 @@ tbody tr:nth-child(odd) { backdrop-filter: blur(44px); } + +.design-slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 12px; + height: 12px; + border-radius: 50%; + background: black; + cursor: pointer; + margin-top: -5px; +} + +.design-slider::-moz-range-thumb { + width: 12px; + height: 12px; + border-radius: 50%; + background: black; + border: none; + cursor: pointer; +} + +.design-slider::-webkit-slider-runnable-track { + -webkit-appearance: none; + appearance: none; + background: transparent; + height: 1px; +} + +.design-slider::-moz-range-track { + background: transparent; + height: 1px; + border: none; +} diff --git a/src/pages/settings/components/DesignSettings.tsx b/src/pages/settings/components/DesignSettings.tsx index bc21a2f..533b1dd 100644 --- a/src/pages/settings/components/DesignSettings.tsx +++ b/src/pages/settings/components/DesignSettings.tsx @@ -1,15 +1,27 @@ import ColorPicker from "@/components/ColorPicker"; import Radio from "@/components/Radio"; import { clx } from "@/helpers/utils"; +import DesignSlider from "@/pages/settings/components/DesignSlider"; import { PATTERN_BACKGROUND_OPACITY, usePatterns } from "@/pages/settings/hooks/usePatterns"; -import { useEffect, useState, type FC } from "react"; +import { DocumentUpload, Gallery, Trash } from "iconsax-react"; +import { useCallback, useEffect, useState, type FC } from "react"; +import { useDropzone } from "react-dropzone"; const COLOR_APPLY_DELAY_MS = 500; +type BackgroundType = "pattern" | "custom"; + +const UPLOAD_BOX_CLASS = "w-[200px] h-[362px] rounded-2xl border border-dashed border-description"; const DesignSettings: FC = () => { const [menuColor, setMenuColor] = useState("#000000"); const [appliedColor, setAppliedColor] = useState("#000000"); const [selectedPatternId, setSelectedPatternId] = useState(1); + const [backgroundType, setBackgroundType] = useState("pattern"); + const [customImage, setCustomImage] = useState(null); + const [customImagePreview, setCustomImagePreview] = useState(null); + const [imageOpacity, setImageOpacity] = useState(100); + const [imageBlur, setImageBlur] = useState(0); + const [overlayDarkness, setOverlayDarkness] = useState(0); const patterns = usePatterns(appliedColor); useEffect(() => { @@ -17,6 +29,37 @@ const DesignSettings: FC = () => { return () => clearTimeout(timer); }, [menuColor]); + useEffect(() => { + if (!customImage) { + setCustomImagePreview(null); + return; + } + + const previewUrl = URL.createObjectURL(customImage); + setCustomImagePreview(previewUrl); + + return () => URL.revokeObjectURL(previewUrl); + }, [customImage]); + + const onDrop = useCallback((acceptedFiles: File[]) => { + if (acceptedFiles[0]) { + setCustomImage(acceptedFiles[0]); + } + }, []); + + const { getRootProps, getInputProps } = useDropzone({ + onDrop, + accept: { "image/*": [] }, + multiple: false, + }); + + const handleRemoveImage = () => { + setCustomImage(null); + setImageOpacity(100); + setImageBlur(0); + setOverlayDarkness(0); + }; + return (
تنظیمات طراحی
@@ -27,23 +70,104 @@ const DesignSettings: FC = () => {
- {}} /> + setBackgroundType(value as BackgroundType)} + />
انتخاب پس زمینه
-
- {patterns.map((pattern) => ( - - ))} + {backgroundType === "pattern" && ( +
+ {patterns.map((pattern) => ( + + ))} +
+ )} +
+ +
+
+ setBackgroundType(value as BackgroundType)} + /> +
تصویر پس زمینه دلخواه
+ + {backgroundType === "custom" && ( +
+ {!customImagePreview ? ( +
+ + +
+ تصویر مورد نظر را آپلود کنید +
+
+ +
آپلود
+
+
+ ) : ( +
+
+ پس‌زمینه دلخواه + {overlayDarkness > 0 && ( +
+ )} + +
+ +
+
تنظیمات
+ + + +
+
+ )} +
+ )}
diff --git a/src/pages/settings/components/DesignSlider.tsx b/src/pages/settings/components/DesignSlider.tsx new file mode 100644 index 0000000..db1f533 --- /dev/null +++ b/src/pages/settings/components/DesignSlider.tsx @@ -0,0 +1,41 @@ +import { type FC } from "react"; + +type Props = { + label: string; + value: number; + onChange: (value: number) => void; +}; + +const DesignSlider: FC = ({ label, value, onChange }) => { + return ( +
+
{label}
+
+
+
+
0 ? 2 : 1, + }} + /> + onChange(Number(e.target.value))} + dir="rtl" + className="design-slider absolute inset-0 w-full h-full appearance-none bg-transparent cursor-pointer" + /> +
+ + {value.toLocaleString("fa-IR")}% + +
+
+ ); +}; + +export default DesignSlider;