From a37ce3dfed549afe151a0c046920fa0398284d3c Mon Sep 17 00:00:00 2001 From: Eshan Singh <32596297+R0X4R@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:41:39 +0530 Subject: [PATCH 1/3] feat(widget): add run widget --- .../button/animated-follow-button.stories.tsx | 72 +++++++++ animata/button/animated-follow-button.tsx | 87 ++++++++++ animata/container/animated-dock.stories.tsx | 11 +- animata/container/animated-dock.tsx | 9 +- animata/widget/run.stories.tsx | 19 +++ animata/widget/run.tsx | 153 ++++++++++++++++++ .../docs/button/animated-follow-button.mdx | 38 +++++ content/docs/widget/run.mdx | 53 ++++++ 8 files changed, 430 insertions(+), 12 deletions(-) create mode 100644 animata/button/animated-follow-button.stories.tsx create mode 100644 animata/button/animated-follow-button.tsx create mode 100644 animata/widget/run.stories.tsx create mode 100644 animata/widget/run.tsx create mode 100644 content/docs/button/animated-follow-button.mdx create mode 100644 content/docs/widget/run.mdx diff --git a/animata/button/animated-follow-button.stories.tsx b/animata/button/animated-follow-button.stories.tsx new file mode 100644 index 00000000..6c163f74 --- /dev/null +++ b/animata/button/animated-follow-button.stories.tsx @@ -0,0 +1,72 @@ +import AnimatedFollowButton from "@/animata/button/animated-follow-button"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Button/Animated Follow Button", + component: AnimatedFollowButton, + parameters: { layout: "centered" }, + argTypes: { + initialText: { control: "text" }, + changeText: { control: "text" }, + className: { control: "text" }, + changeTextClassName: { control: "text" }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + initialText: "Follow", + changeText: "Following!", + className: "h-16 bg-green-100 text-green-700 flex rounded-full items-center justify-center", + changeTextClassName: "h-16 bg-green-700 text-green-100 rounded-full text-white flex items-center justify-center", + }, + render: (args) => ( +
+ +
+ ), +}; + +export const DifferentAnimations: Story = { + args: {}, + render: () => { + const buttons = [ + { + initialText: "Default", + changeText: "Up To Down", + animationType: "up-to-down" as const, + color: "blue", + }, + { + initialText: "Click Me", + changeText: "Down To Up", + animationType: "down-to-up" as const, + color: "zinc", + }, + { + initialText: "Click Me", + changeText: "Zoom In", + animationType: "zoom-in" as const, + color: "red", + }, + ]; + + return ( +
+ {buttons.map(({ initialText, changeText, animationType, color }, idx) => ( + {initialText}} + changeText={{changeText}} + animationType={animationType} + /> + ))} +
+ ); + }, +}; diff --git a/animata/button/animated-follow-button.tsx b/animata/button/animated-follow-button.tsx new file mode 100644 index 00000000..8ee8c638 --- /dev/null +++ b/animata/button/animated-follow-button.tsx @@ -0,0 +1,87 @@ +"use client"; + +import React, { useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; + +interface AnimatedFollowButtonProps { + initialText: React.ReactElement | string; // Text or element displayed initially + changeText: React.ReactElement | string; // Text or element displayed after the button is clicked + className?: string; // ClassName prop for custom button styling + changeTextClassName?: string; // ClassName prop for custom styling of changeText + animationType?: "up-to-down" | "down-to-up" | "left-to-right" | "right-to-left" | "zoom-in" | "zoom-out"; // Prop to define animation type +} + +const AnimatedFollowButton: React.FC = ({ + initialText, + changeText, + className, + changeTextClassName, + animationType = "up-to-down", // Set default animation to "up-to-down" +}) => { + const [isClicked, setIsClicked] = useState(false); // Track button click state + + // Determine animation settings based on animationType prop + const getAnimation = () => { + switch (animationType) { + case "down-to-up": + return { initial: { y: 20 }, animate: { y: 0 }, exit: { y: 20 } }; // Down to up animation + case "left-to-right": + return { initial: { x: -20 }, animate: { x: 0 }, exit: { x: -20 } }; // Left to right animation + case "right-to-left": + return { initial: { x: 20 }, animate: { x: 0 }, exit: { x: 20 } }; // Right to left animation + case "zoom-in": + return { initial: { scale: 0.8 }, animate: { scale: 1 }, exit: { scale: 0.8 } }; // Zoom in animation + case "zoom-out": + return { initial: { scale: 1.2 }, animate: { scale: 1 }, exit: { scale: 1.2 } }; // Zoom out animation + case "up-to-down": + default: + return { initial: { y: -20 }, animate: { y: 0 }, exit: { y: -20 } }; // Default: Up to down animation + } + }; + + const animation = getAnimation(); // Get animation settings based on the selected type + + return ( + + {isClicked ? ( + // Button after being clicked + setIsClicked(false)} // On click, toggle button state + initial={{ opacity: 0 }} // Initial animation for opacity + animate={{ opacity: 1 }} // Animate to full opacity + exit={{ opacity: 0 }} // Exit animation for opacity + > + {/* Change text with defined animation */} + + {changeText} {/* Display the changeText */} + + + ) : ( + // Button before being clicked + setIsClicked(true)} // On click, toggle button state + initial={{ opacity: 0 }} // Initial animation for opacity + animate={{ opacity: 1 }} // Animate to full opacity + exit={{ opacity: 0 }} // Exit animation for opacity + > + {/* Initial text with defined animation */} + + {initialText} {/* Display the initialText */} + + + )} + + ); +}; + +export default AnimatedFollowButton; diff --git a/animata/container/animated-dock.stories.tsx b/animata/container/animated-dock.stories.tsx index 705d1df4..7c780dd2 100644 --- a/animata/container/animated-dock.stories.tsx +++ b/animata/container/animated-dock.stories.tsx @@ -1,7 +1,7 @@ -import { Meta, StoryObj } from "@storybook/react"; -import { Home, Search, Bell, User } from "lucide-react"; -import AnimatedDock from "@/animata/container/animated-dock"; +import { Bell, Home, Search, User } from "lucide-react"; +import AnimatedDock from "@/animata/container/animated-dock"; +import { Meta, StoryObj } from "@storybook/react"; const meta = { title: "Container/Animated Dock", @@ -19,7 +19,6 @@ const meta = { export default meta; type Story = StoryObj; - // Example contents for AnimatedDock const dockItems = [ { title: "Home", icon: , href: "/" }, @@ -28,7 +27,6 @@ const dockItems = [ { title: "Profile", icon: , href: "/profile" }, ]; - // Primary story for AnimatedDock (default layout) export const Primary: Story = { args: { @@ -43,7 +41,6 @@ export const Primary: Story = { ), }; - // Story focused on the Small layout (for mobile view) export const Small: Story = { args: { @@ -57,7 +54,6 @@ export const Small: Story = { ), }; - // Story focused on the Large layout (for desktop view) export const Large: Story = { args: { @@ -71,7 +67,6 @@ export const Large: Story = { ), }; - // Story showing both layouts at the same time (for comparison) export const Multiple: Story = { args: { diff --git a/animata/container/animated-dock.tsx b/animata/container/animated-dock.tsx index 190815cc..a2579be6 100644 --- a/animata/container/animated-dock.tsx +++ b/animata/container/animated-dock.tsx @@ -1,16 +1,17 @@ -import { cn } from "@/lib/utils"; // Import utility for conditional class names +import React, { useRef, useState } from "react"; // Importing React hooks +import Link from "next/link"; // Next.js Link component for navigation import { AnimatePresence, // Enables animation presence detection - MotionValue, // Type for motion values motion, // Main component for animations + MotionValue, // Type for motion values useMotionValue, // Hook to create a motion value useSpring, // Hook to create smooth spring animations useTransform, // Hook to transform motion values } from "framer-motion"; -import Link from "next/link"; // Next.js Link component for navigation -import React, { useRef, useState } from "react"; // Importing React hooks import { Menu, X } from "lucide-react"; // Importing icons from lucide-react +import { cn } from "@/lib/utils"; // Import utility for conditional class names + // Interface for props accepted by the AnimatedDock component interface AnimatedDockProps { items: { title: string; icon: React.ReactNode; href: string }[]; // Array of menu items diff --git a/animata/widget/run.stories.tsx b/animata/widget/run.stories.tsx new file mode 100644 index 00000000..f54d1412 --- /dev/null +++ b/animata/widget/run.stories.tsx @@ -0,0 +1,19 @@ +import Run from "@/animata/widget/run"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta = { + title: "Widget/Run", + component: Run, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], + argTypes: {}, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: {}, +}; diff --git a/animata/widget/run.tsx b/animata/widget/run.tsx new file mode 100644 index 00000000..cd98067b --- /dev/null +++ b/animata/widget/run.tsx @@ -0,0 +1,153 @@ +"use client"; +import { useEffect, useRef, useState } from "react"; +import { + AnimatePresence, + motion, + MotionValue, + useMotionValue, + useMotionValueEvent, + useSpring, + useTransform, +} from "framer-motion"; +import { MoveUpRight } from "lucide-react"; +import PropTypes from "prop-types"; + +const AnimatedScroll: React.FC<{ setDistance: React.Dispatch> }> = ({ + setDistance, +}) => { + const sliderRef = useRef(null); + + const x = useMotionValue(0); + + useMotionValueEvent(x, "change", (latest) => { + let val = Math.ceil(Math.floor(latest) / 10); + val = -val + 10; + setDistance(val); + }); + + return ( +
+
+ + {Array.from({ length: 88 }, (_, index) => ( +
|
+ ))} +
+
+
|
+
+ ); +}; + +AnimatedScroll.propTypes = { + setDistance: PropTypes.func.isRequired, +}; + +const fontSize = 30; +const padding = 15; +const height = fontSize + padding; + +function Counter({ value }: { value: number }) { + return ( +
+ + . + +
+ ); +} + +function Digit({ place, value }: { place: number; value: number }) { + const valueRoundedToPlace = Math.floor(value / place); + const animatedValue = useSpring(valueRoundedToPlace, { + stiffness: 45, + damping: 7, + }); + + useEffect(() => { + animatedValue.set(valueRoundedToPlace); + }, [animatedValue, valueRoundedToPlace]); + + return ( +
+ {[...Array(10).keys()].map((i) => ( + + ))} +
+ ); +} + +function Number({ mv, number }: { mv: MotionValue; number: number }) { + const y = useTransform(mv, (latest) => { + const placeValue = latest % 10; + const offset = (10 + number - placeValue) % 10; + + let memo = -offset * height; + + if (offset > 5) { + memo += 10 * height; + } + + return memo; + }); + + const opacity = useTransform(y, [-height, 0, height], [0.2, 1, 0.2]); + const scale = useTransform(y, [-height, 0, height], [0.2, 1, 0.2]); + const filter = useTransform(y, [-height, 0, height], ["blur(5px)", "blur(0px)", "blur(5px)"]); + + return ( + + {number} + + ); +} + +export function RunCard({ unit, buttonText }: { unit?: string; buttonText?: string }) { + const [distance, setDistance] = useState(10); + + return ( +
+
+
+ + + +
+ +
+
{unit}
+
+ +
+ {" "} + {/*https://emojipedia.org/man-running*/} +
+ ); +} + +export default function Run() { + return ; +} diff --git a/content/docs/button/animated-follow-button.mdx b/content/docs/button/animated-follow-button.mdx new file mode 100644 index 00000000..063df174 --- /dev/null +++ b/content/docs/button/animated-follow-button.mdx @@ -0,0 +1,38 @@ +--- +title: Animated Follow Button +description: The Animated Follow Button is an interactive UI component with customizable entrance animations and dynamic text changes on click, offering flexible styling options. Perfect for engaging user interactions like follow or subscribe actions. +author: R0X4R +--- + + + +## Installation + + +Install dependencies + +```bash +npm install framer-motion +``` + +Run the following command + +It will create a new file `animated-follow-button.tsx` inside the `components/animata/button` directory. + +```bash +mkdir -p components/animata/button && touch components/animata/button/animated-follow-button.tsx +``` + +Paste the code + +Open the newly created file and paste the following code: + +```jsx file=/animata/button/animated-follow-button.tsx + +``` + + + +## Credits + + Built by [Eshan Singh](https://github.com/R0X4R) with [Framer Motion](https://www.framer.com/motion/). diff --git a/content/docs/widget/run.mdx b/content/docs/widget/run.mdx new file mode 100644 index 00000000..d7848352 --- /dev/null +++ b/content/docs/widget/run.mdx @@ -0,0 +1,53 @@ +--- +title: Run +description: A widget to set a target for the distance to run +author: YourTwitterUsername +--- + + + +## 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 `run.tsx` inside the `components/animata/widget` directory. + +```bash +mkdir -p components/animata/widget && touch components/animata/widget/run.tsx +``` + +Paste the code{" "} + +Open the newly created file and paste the following code: + +```jsx file=/animata/widget/run.tsx + +``` + + + +## Credits + +Built by [Your name](https://github.com/YourGithubUsername) + +...Add appropriate credits here. From a6bb8c980de4e39facf32d5d440c07441586aea0 Mon Sep 17 00:00:00 2001 From: Eshan Singh <32596297+R0X4R@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:41:39 +0530 Subject: [PATCH 2/3] feat(widget): add run widget --- .../button/animated-follow-button.stories.tsx | 72 ++++++++ animata/button/animated-follow-button.tsx | 87 +++++++++ animata/container/animated-dock.stories.tsx | 11 +- animata/container/animated-dock.tsx | 9 +- animata/widget/run.stories.tsx | 22 +++ animata/widget/run.tsx | 169 ++++++++++++++++++ .../docs/button/animated-follow-button.mdx | 38 ++++ content/docs/widget/run.mdx | 51 ++++++ 8 files changed, 447 insertions(+), 12 deletions(-) create mode 100644 animata/button/animated-follow-button.stories.tsx create mode 100644 animata/button/animated-follow-button.tsx create mode 100644 animata/widget/run.stories.tsx create mode 100644 animata/widget/run.tsx create mode 100644 content/docs/button/animated-follow-button.mdx create mode 100644 content/docs/widget/run.mdx diff --git a/animata/button/animated-follow-button.stories.tsx b/animata/button/animated-follow-button.stories.tsx new file mode 100644 index 00000000..6c163f74 --- /dev/null +++ b/animata/button/animated-follow-button.stories.tsx @@ -0,0 +1,72 @@ +import AnimatedFollowButton from "@/animata/button/animated-follow-button"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta: Meta = { + title: "Button/Animated Follow Button", + component: AnimatedFollowButton, + parameters: { layout: "centered" }, + argTypes: { + initialText: { control: "text" }, + changeText: { control: "text" }, + className: { control: "text" }, + changeTextClassName: { control: "text" }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + initialText: "Follow", + changeText: "Following!", + className: "h-16 bg-green-100 text-green-700 flex rounded-full items-center justify-center", + changeTextClassName: "h-16 bg-green-700 text-green-100 rounded-full text-white flex items-center justify-center", + }, + render: (args) => ( +
+ +
+ ), +}; + +export const DifferentAnimations: Story = { + args: {}, + render: () => { + const buttons = [ + { + initialText: "Default", + changeText: "Up To Down", + animationType: "up-to-down" as const, + color: "blue", + }, + { + initialText: "Click Me", + changeText: "Down To Up", + animationType: "down-to-up" as const, + color: "zinc", + }, + { + initialText: "Click Me", + changeText: "Zoom In", + animationType: "zoom-in" as const, + color: "red", + }, + ]; + + return ( +
+ {buttons.map(({ initialText, changeText, animationType, color }, idx) => ( + {initialText}} + changeText={{changeText}} + animationType={animationType} + /> + ))} +
+ ); + }, +}; diff --git a/animata/button/animated-follow-button.tsx b/animata/button/animated-follow-button.tsx new file mode 100644 index 00000000..8ee8c638 --- /dev/null +++ b/animata/button/animated-follow-button.tsx @@ -0,0 +1,87 @@ +"use client"; + +import React, { useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; + +interface AnimatedFollowButtonProps { + initialText: React.ReactElement | string; // Text or element displayed initially + changeText: React.ReactElement | string; // Text or element displayed after the button is clicked + className?: string; // ClassName prop for custom button styling + changeTextClassName?: string; // ClassName prop for custom styling of changeText + animationType?: "up-to-down" | "down-to-up" | "left-to-right" | "right-to-left" | "zoom-in" | "zoom-out"; // Prop to define animation type +} + +const AnimatedFollowButton: React.FC = ({ + initialText, + changeText, + className, + changeTextClassName, + animationType = "up-to-down", // Set default animation to "up-to-down" +}) => { + const [isClicked, setIsClicked] = useState(false); // Track button click state + + // Determine animation settings based on animationType prop + const getAnimation = () => { + switch (animationType) { + case "down-to-up": + return { initial: { y: 20 }, animate: { y: 0 }, exit: { y: 20 } }; // Down to up animation + case "left-to-right": + return { initial: { x: -20 }, animate: { x: 0 }, exit: { x: -20 } }; // Left to right animation + case "right-to-left": + return { initial: { x: 20 }, animate: { x: 0 }, exit: { x: 20 } }; // Right to left animation + case "zoom-in": + return { initial: { scale: 0.8 }, animate: { scale: 1 }, exit: { scale: 0.8 } }; // Zoom in animation + case "zoom-out": + return { initial: { scale: 1.2 }, animate: { scale: 1 }, exit: { scale: 1.2 } }; // Zoom out animation + case "up-to-down": + default: + return { initial: { y: -20 }, animate: { y: 0 }, exit: { y: -20 } }; // Default: Up to down animation + } + }; + + const animation = getAnimation(); // Get animation settings based on the selected type + + return ( + + {isClicked ? ( + // Button after being clicked + setIsClicked(false)} // On click, toggle button state + initial={{ opacity: 0 }} // Initial animation for opacity + animate={{ opacity: 1 }} // Animate to full opacity + exit={{ opacity: 0 }} // Exit animation for opacity + > + {/* Change text with defined animation */} + + {changeText} {/* Display the changeText */} + + + ) : ( + // Button before being clicked + setIsClicked(true)} // On click, toggle button state + initial={{ opacity: 0 }} // Initial animation for opacity + animate={{ opacity: 1 }} // Animate to full opacity + exit={{ opacity: 0 }} // Exit animation for opacity + > + {/* Initial text with defined animation */} + + {initialText} {/* Display the initialText */} + + + )} + + ); +}; + +export default AnimatedFollowButton; diff --git a/animata/container/animated-dock.stories.tsx b/animata/container/animated-dock.stories.tsx index 705d1df4..7c780dd2 100644 --- a/animata/container/animated-dock.stories.tsx +++ b/animata/container/animated-dock.stories.tsx @@ -1,7 +1,7 @@ -import { Meta, StoryObj } from "@storybook/react"; -import { Home, Search, Bell, User } from "lucide-react"; -import AnimatedDock from "@/animata/container/animated-dock"; +import { Bell, Home, Search, User } from "lucide-react"; +import AnimatedDock from "@/animata/container/animated-dock"; +import { Meta, StoryObj } from "@storybook/react"; const meta = { title: "Container/Animated Dock", @@ -19,7 +19,6 @@ const meta = { export default meta; type Story = StoryObj; - // Example contents for AnimatedDock const dockItems = [ { title: "Home", icon: , href: "/" }, @@ -28,7 +27,6 @@ const dockItems = [ { title: "Profile", icon: , href: "/profile" }, ]; - // Primary story for AnimatedDock (default layout) export const Primary: Story = { args: { @@ -43,7 +41,6 @@ export const Primary: Story = { ), }; - // Story focused on the Small layout (for mobile view) export const Small: Story = { args: { @@ -57,7 +54,6 @@ export const Small: Story = { ), }; - // Story focused on the Large layout (for desktop view) export const Large: Story = { args: { @@ -71,7 +67,6 @@ export const Large: Story = { ), }; - // Story showing both layouts at the same time (for comparison) export const Multiple: Story = { args: { diff --git a/animata/container/animated-dock.tsx b/animata/container/animated-dock.tsx index 190815cc..a2579be6 100644 --- a/animata/container/animated-dock.tsx +++ b/animata/container/animated-dock.tsx @@ -1,16 +1,17 @@ -import { cn } from "@/lib/utils"; // Import utility for conditional class names +import React, { useRef, useState } from "react"; // Importing React hooks +import Link from "next/link"; // Next.js Link component for navigation import { AnimatePresence, // Enables animation presence detection - MotionValue, // Type for motion values motion, // Main component for animations + MotionValue, // Type for motion values useMotionValue, // Hook to create a motion value useSpring, // Hook to create smooth spring animations useTransform, // Hook to transform motion values } from "framer-motion"; -import Link from "next/link"; // Next.js Link component for navigation -import React, { useRef, useState } from "react"; // Importing React hooks import { Menu, X } from "lucide-react"; // Importing icons from lucide-react +import { cn } from "@/lib/utils"; // Import utility for conditional class names + // Interface for props accepted by the AnimatedDock component interface AnimatedDockProps { items: { title: string; icon: React.ReactNode; href: string }[]; // Array of menu items diff --git a/animata/widget/run.stories.tsx b/animata/widget/run.stories.tsx new file mode 100644 index 00000000..918ccc21 --- /dev/null +++ b/animata/widget/run.stories.tsx @@ -0,0 +1,22 @@ +import Run from "@/animata/widget/run"; +import { Meta, StoryObj } from "@storybook/react"; + +const meta = { + title: "Widget/Run", + component: Run, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], + argTypes: {}, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + unit: "miles", + buttonText: "🏃 Begin Run", + }, +}; diff --git a/animata/widget/run.tsx b/animata/widget/run.tsx new file mode 100644 index 00000000..bb6e5a2f --- /dev/null +++ b/animata/widget/run.tsx @@ -0,0 +1,169 @@ +"use client"; +import { useEffect, useRef, useState } from "react"; +import { + AnimatePresence, + motion, + MotionValue, + useMotionValue, + useMotionValueEvent, + useSpring, + useTransform, +} from "framer-motion"; +import { MoveUpRight } from "lucide-react"; +import PropTypes from "prop-types"; + +const AnimatedScroll: React.FC<{ setDistance: React.Dispatch> }> = ({ + setDistance, +}) => { + const sliderRef = useRef(null); + + const x = useMotionValue(0); + + useMotionValueEvent(x, "change", (latest) => { + let val = Math.ceil(Math.floor(latest) / 10); + val = -val + 10; + setDistance(val); + }); + + return ( +
+
+ + {Array.from({ length: 88 }, (_, index) => ( +
|
+ ))} +
+
+
|
+
+ ); +}; + +const fontSize = 30; +const padding = 15; +const height = fontSize + padding; + +const Counter: React.FC<{ value: number }> = ({ value }) => { + return ( +
+ + . + +
+ ); +}; + +const Digit: React.FC<{ place: number; value: number }> = ({ place, value }) => { + const valueRoundedToPlace = Math.floor(value / place); + const animatedValue = useSpring(valueRoundedToPlace, { + stiffness: 45, + damping: 7, + }); + + useEffect(() => { + animatedValue.set(valueRoundedToPlace); + }, [animatedValue, valueRoundedToPlace]); + + return ( +
+ {[...Array(10).keys()].map((i) => ( + + ))} +
+ ); +}; + +const Number: React.FC<{ mv: MotionValue; number: number }> = ({ mv, number }) => { + const y = useTransform(mv, (latest) => { + const placeValue = latest % 10; + const offset = (10 + number - placeValue) % 10; + + let memo = -offset * height; + + if (offset > 5) { + memo += 10 * height; + } + + return memo; + }); + + const opacity = useTransform(y, [-height, 0, height], [0.2, 1, 0.2]); + const scale = useTransform(y, [-height, 0, height], [0.2, 1, 0.2]); + const filter = useTransform(y, [-height, 0, height], ["blur(5px)", "blur(0px)", "blur(5px)"]); + + return ( + + {number} + + ); +}; + +AnimatedScroll.propTypes = { + setDistance: PropTypes.func.isRequired, +}; + +Counter.propTypes = { + value: PropTypes.number.isRequired, +}; + +Digit.propTypes = { + place: PropTypes.number.isRequired, + value: PropTypes.number.isRequired, +}; + +Number.propTypes = { + mv: PropTypes.instanceOf(MotionValue).isRequired, + number: PropTypes.number.isRequired, +}; + +export default function Run({ + unit = "miles", + buttonText = "🏃 Begin Run", +}: { + unit?: string; + buttonText?: string; +}) { + const [distance, setDistance] = useState(10); + + return ( +
+
+
+ + + +
+ +
+
{unit}
+
+ +
+ {" "} + {/*https://emojipedia.org/man-running*/} +
+ ); +} diff --git a/content/docs/button/animated-follow-button.mdx b/content/docs/button/animated-follow-button.mdx new file mode 100644 index 00000000..063df174 --- /dev/null +++ b/content/docs/button/animated-follow-button.mdx @@ -0,0 +1,38 @@ +--- +title: Animated Follow Button +description: The Animated Follow Button is an interactive UI component with customizable entrance animations and dynamic text changes on click, offering flexible styling options. Perfect for engaging user interactions like follow or subscribe actions. +author: R0X4R +--- + + + +## Installation + + +Install dependencies + +```bash +npm install framer-motion +``` + +Run the following command + +It will create a new file `animated-follow-button.tsx` inside the `components/animata/button` directory. + +```bash +mkdir -p components/animata/button && touch components/animata/button/animated-follow-button.tsx +``` + +Paste the code + +Open the newly created file and paste the following code: + +```jsx file=/animata/button/animated-follow-button.tsx + +``` + + + +## Credits + + Built by [Eshan Singh](https://github.com/R0X4R) with [Framer Motion](https://www.framer.com/motion/). diff --git a/content/docs/widget/run.mdx b/content/docs/widget/run.mdx new file mode 100644 index 00000000..9b3bf5ce --- /dev/null +++ b/content/docs/widget/run.mdx @@ -0,0 +1,51 @@ +--- +title: Run +description: A widget to set a target for the distance to run +author: YourTwitterUsername +--- + + + +## 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 `run.tsx` inside the `components/animata/widget` directory. + +```bash +mkdir -p components/animata/widget && touch components/animata/widget/run.tsx +``` + +Paste the code{" "} + +Open the newly created file and paste the following code: + +```jsx file=/animata/widget/run.tsx + +``` + + + +## Credits + +Built by [Abir Roy](https://github.com/roy-abir05) From ee96e0cd11d972f8a5fb4ae4abb5f27d595564ff Mon Sep 17 00:00:00 2001 From: Abir Roy <144606544+roy-abir05@users.noreply.github.com> Date: Thu, 31 Oct 2024 23:08:42 +0530 Subject: [PATCH 3/3] Added run widget --- content/docs/widget/run.mdx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/content/docs/widget/run.mdx b/content/docs/widget/run.mdx index 8021caee..9b3bf5ce 100644 --- a/content/docs/widget/run.mdx +++ b/content/docs/widget/run.mdx @@ -48,11 +48,4 @@ Open the newly created file and paste the following code: ## Credits -<<<<<<< HEAD Built by [Abir Roy](https://github.com/roy-abir05) -======= -Built by [Your name](https://github.com/YourGithubUsername) - -...Add appropriate credits here. - -> > > > > > > a37ce3dfed549afe151a0c046920fa0398284d3c