From 09f964451d7d92e9891430ec4595c1276d486aab Mon Sep 17 00:00:00 2001
From: zwlucas <lucas.fariamo08@gmail.com>
Date: Fri, 5 Jun 2026 17:52:54 -0300
Subject: feat: upload

Signed-off-by: zwlucas <lucas.fariamo08@gmail.com>
---
 src/components/UI/Slider.tsx | 74 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
 create mode 100644 src/components/UI/Slider.tsx

(limited to 'src/components/UI/Slider.tsx')

diff --git a/src/components/UI/Slider.tsx b/src/components/UI/Slider.tsx
new file mode 100644
index 0000000..22a65ee
--- /dev/null
+++ b/src/components/UI/Slider.tsx
@@ -0,0 +1,74 @@
+import { useRef, useCallback, useEffect, useState } from 'react'
+
+interface SliderProps {
+  value: number
+  min: number
+  max: number
+  step?: number
+  onChange: (value: number) => void
+}
+
+export default function Slider({ value, min, max, step = 1, onChange }: SliderProps) {
+  const trackRef = useRef<HTMLDivElement>(null)
+  const [dragging, setDragging] = useState(false)
+
+  const pct = ((value - min) / (max - min)) * 100
+
+  const updateFromClient = useCallback((clientX: number) => {
+    const rect = trackRef.current?.getBoundingClientRect()
+    if (!rect) return
+    const raw = (clientX - rect.left) / rect.width
+    const clamped = Math.max(0, Math.min(1, raw))
+    const stepped = Math.round((min + clamped * (max - min)) / step) * step
+    onChange(Math.max(min, Math.min(max, stepped)))
+  }, [min, max, step, onChange])
+
+  const handleMouseDown = useCallback((e: React.MouseEvent) => {
+    e.preventDefault()
+    setDragging(true)
+    updateFromClient(e.clientX)
+  }, [updateFromClient])
+
+  useEffect(() => {
+    if (!dragging) return
+    const handleMove = (e: MouseEvent) => { e.preventDefault(); updateFromClient(e.clientX) }
+    const handleUp = () => setDragging(false)
+    window.addEventListener('mousemove', handleMove)
+    window.addEventListener('mouseup', handleUp)
+    return () => { window.removeEventListener('mousemove', handleMove); window.removeEventListener('mouseup', handleUp) }
+  }, [dragging, updateFromClient])
+
+  return (
+    <div
+      ref={trackRef}
+      className="relative h-4 w-full cursor-pointer flex items-center"
+      onMouseDown={handleMouseDown}
+      role="slider"
+      aria-valuemin={min}
+      aria-valuemax={max}
+      aria-valuenow={value}
+      tabIndex={0}
+      onKeyDown={(e) => {
+        if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { e.preventDefault(); onChange(Math.min(max, value + step)) }
+        if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { e.preventDefault(); onChange(Math.max(min, value - step)) }
+      }}
+    >
+      <div className="absolute h-[3px] w-full rounded-full" style={{ backgroundColor: 'var(--color-panel-border)' }}>
+        <div
+          className="absolute h-full rounded-full transition-[width] duration-75"
+          style={{ width: `${pct}%`, backgroundColor: 'var(--color-accent)' }}
+        />
+      </div>
+      <div
+        className="absolute w-3.5 h-3.5 rounded-full shadow-sm border-2 transition-transform duration-75"
+        style={{
+          left: `${pct}%`,
+          marginLeft: '-7px',
+          backgroundColor: dragging ? 'var(--color-accent)' : 'var(--color-panel-bg)',
+          borderColor: 'var(--color-accent)',
+          transform: dragging ? 'scale(1.15)' : 'scale(1)',
+        }}
+      />
+    </div>
+  )
+}
-- 
cgit v1.2.3

