diff --git a/animata/form-controls/scrub-slider.stories.tsx b/animata/form-controls/scrub-slider.stories.tsx new file mode 100644 index 00000000..0bd64850 --- /dev/null +++ b/animata/form-controls/scrub-slider.stories.tsx @@ -0,0 +1,19 @@ +import ScrubSlider from "@/animata/form-controls/scrub-slider"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta = { + title: "Form Controls/Scrub Slider", + component: ScrubSlider, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], + argTypes: {}, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: {}, +}; diff --git a/animata/form-controls/scrub-slider.tsx b/animata/form-controls/scrub-slider.tsx new file mode 100644 index 00000000..14429724 --- /dev/null +++ b/animata/form-controls/scrub-slider.tsx @@ -0,0 +1,99 @@ +"use client"; + +import React, { useState } from "react"; +import { motion } from "framer-motion"; + +interface ScrubSliderProps { + min?: number; + max?: number; + initialValue?: number; + tickStep?: number; +} + +const ScrubSlider: React.FC = ({ + min = 0, + max = 100, + initialValue = 40, + tickStep = 5, +}) => { + const [value, setValue] = useState(initialValue); + const [isDragging, setIsDragging] = useState(false); + + const calculateValue = (e: React.MouseEvent) => { + const rect = e.currentTarget.getBoundingClientRect(); + const x = e.clientX - rect.left; + const newValue = Math.round((x / rect.width) * (max - min) + min); + return Math.max(min, Math.min(max, newValue)); + }; + + const handleMouseMove = (e: React.MouseEvent) => { + if (isDragging) { + const newValue = calculateValue(e); + setValue(newValue); + } + }; + + const handleMouseDown = (e: React.MouseEvent) => { + const newValue = calculateValue(e); + setValue(newValue); + setIsDragging(true); + }; + + const handleMouseUp = () => { + setIsDragging(false); + }; + + const renderTicks = () => { + const ticks = []; + for (let i = min; i <= max; i += tickStep) { + ticks.push( +
, + ); + } + return ticks; + }; + + return ( +
+
{renderTicks()}
+ + + {value}°C + + + +
+ ); +}; + +export default ScrubSlider; diff --git a/config/docs.ts b/config/docs.ts index 034ca70b..d892377f 100644 --- a/config/docs.ts +++ b/config/docs.ts @@ -184,6 +184,10 @@ const sidebarNav: SidebarNavItem[] = [ title: "Floating Action Buttons", items: createLinks("fabs"), }, + { + title: "Form controls", + items: createLinks("form-controls"), + }, ] .filter((category) => Boolean(category.items?.length || category.label)) .sort((a, b) => { diff --git a/content/docs/form-controls/scrub-slider.mdx b/content/docs/form-controls/scrub-slider.mdx new file mode 100644 index 00000000..7fd7be2a --- /dev/null +++ b/content/docs/form-controls/scrub-slider.mdx @@ -0,0 +1,51 @@ +--- +title: Scrub Slider +description: scrub slider component with animated progress and a dynamic indicator. +author: sumedhakoranga +--- + + + +## Installation + + +Install dependencies + +```bash +npm install framer-motion lucide-react +``` + +Update `tailwind.config.js` + +Add the following to your tailwind.config.js file. + +```json +module.exports = { + theme: { + extend: { + } + } +} +``` + +Run the following command + +It will create a new file `scrub-slider.tsx` inside the `components/animata/form-controls` directory. + +```bash +mkdir -p components/animata/form-controls && touch components/animata/form-controls/scrub-slider.tsx +``` + +Paste the code + +Open the newly created file and paste the following code: + +```jsx file=/animata/form-controls/scrub-slider.tsx + +``` + + + +## Credits + +Built by [Sumedha Koranga](https://github.com/sumedhakoranga)