Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: New Component - Animated Scroll Progress #177

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions __registry__/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: [],
},
"scroll-progress": {
name: "scroll-progress",
type: "registry:ui",
registryDependencies: undefined,
files: ["registry/default/magicui/scroll-progress.tsx"],
component: React.lazy(
() => import("@/registry/default/magicui/scroll-progress.tsx"),
),
source: "",
category: "undefined",
subcategory: "undefined",
chunks: [],
},
"neon-gradient-card": {
name: "neon-gradient-card",
type: "registry:ui",
Expand Down Expand Up @@ -763,6 +776,19 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: [],
},
"scroll-progress-demo": {
name: "scroll-progress-demo",
type: "registry:example",
registryDependencies: ["scroll-progress"],
files: ["registry/default/example/scroll-progress-demo.tsx"],
component: React.lazy(
() => import("@/registry/default/example/scroll-progress-demo.tsx"),
),
source: "",
category: "undefined",
subcategory: "undefined",
chunks: [],
},
"neon-gradient-card-demo": {
name: "neon-gradient-card-demo",
type: "registry:example",
Expand Down
6 changes: 6 additions & 0 deletions config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ export const docsConfig: DocsConfig = {
items: [],
label: "",
},
{
title: "Scroll Progress",
href: `/docs/components/scroll-progress`,
items: [],
label: "New",
},
],
},
{
Expand Down
50 changes: 50 additions & 0 deletions content/docs/components/scroll-progress.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: Scroll Progress
date: 2024-12-19
description: Animated Scroll Progress for your pages
author: dipesh_the_dev
published: true
---

<ComponentPreview name="scroll-progress-demo" />

## Installation

<Tabs defaultValue="cli">
<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">

```bash
npx shadcn@latest add "https://magicui.design/r/scroll-progress"
```

</TabsContent>

<TabsContent value="manual">

<Steps>

<Step>Copy and paste the following code into your project.</Step>

<ComponentSource name="scroll-progress" />

</Steps>

</TabsContent>

</Tabs>

## Props

| Prop | Type | Description | Default |
| --------- | ------ | --------------------------------------------- | ------- |
| className | string | The class name to be applied to the component | - |

The `ScrollProgress` component also accepts all properties of the `HTMLDivElement` type.

## Credits

- Credit to [dipesh_the_dev](https://twitter.com/dipesh_the_dev)
13 changes: 13 additions & 0 deletions public/r/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@
}
]
},
{
"name": "scroll-progress",
"type": "registry:ui",
"dependencies": [
"framer-motion"
],
"files": [
{
"path": "magicui/scroll-progress.tsx",
"type": "registry:ui"
}
]
},
{
"name": "neon-gradient-card",
"type": "registry:ui",
Expand Down
2 changes: 1 addition & 1 deletion public/r/styles/default/bento-grid.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"files": [
{
"path": "magicui/bento-grid.tsx",
"content": "import { ReactNode } from \"react\";\nimport { ArrowRightIcon } from \"@radix-ui/react-icons\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\nconst BentoGrid = ({\n children,\n className,\n}: {\n children: ReactNode;\n className?: string;\n}) => {\n return (\n <div\n className={cn(\n \"grid w-full auto-rows-[22rem] grid-cols-3 gap-4\",\n className,\n )}\n >\n {children}\n </div>\n );\n};\n\nconst BentoCard = ({\n name,\n className,\n background,\n Icon,\n description,\n href,\n cta,\n}: {\n name: string;\n className: string;\n background: ReactNode;\n Icon: any;\n description: string;\n href: string;\n cta: string;\n}) => (\n <div\n key={name}\n className={cn(\n \"group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl\",\n // light styles\n \"bg-white [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]\",\n // dark styles\n \"transform-gpu dark:bg-black dark:[border:1px_solid_rgba(255,255,255,.1)] dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset]\",\n className,\n )}\n >\n <div>{background}</div>\n <div className=\"pointer-events-none z-10 flex transform-gpu flex-col gap-1 p-6 transition-all duration-300 group-hover:-translate-y-10\">\n <Icon className=\"h-12 w-12 origin-left transform-gpu text-neutral-700 transition-all duration-300 ease-in-out group-hover:scale-75\" />\n <h3 className=\"text-xl font-semibold text-neutral-700 dark:text-neutral-300\">\n {name}\n </h3>\n <p className=\"max-w-lg text-neutral-400\">{description}</p>\n </div>\n\n <div\n className={cn(\n \"pointer-events-none absolute bottom-0 flex w-full translate-y-10 transform-gpu flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100\",\n )}\n >\n <Button variant=\"ghost\" asChild size=\"sm\" className=\"pointer-events-auto\">\n <a href={href}>\n {cta}\n <ArrowRightIcon className=\"ml-2 h-4 w-4\" />\n </a>\n </Button>\n </div>\n <div className=\"pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] group-hover:dark:bg-neutral-800/10\" />\n </div>\n);\n\nexport { BentoCard, BentoGrid };\n",
"content": "import { ReactNode } from \"react\";\nimport { ArrowRightIcon } from \"@radix-ui/react-icons\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\ntype BentoGridProps = {\n children: ReactNode;\n className?: string;\n};\n\ntype BentoCardProps = {\n name: string;\n className: string;\n background: ReactNode;\n Icon: any;\n description: string;\n href: string;\n cta: string;\n};\n\nconst BentoGrid = ({ children, className }: BentoGridProps) => {\n return (\n <div\n className={cn(\n \"grid w-full auto-rows-[22rem] grid-cols-3 gap-4\",\n className,\n )}\n >\n {children}\n </div>\n );\n};\n\nconst BentoCard = ({\n name,\n className,\n background,\n Icon,\n description,\n href,\n cta,\n}: BentoCardProps) => (\n <div\n key={name}\n className={cn(\n \"group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl\",\n // light styles\n \"bg-white [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]\",\n // dark styles\n \"transform-gpu dark:bg-black dark:[border:1px_solid_rgba(255,255,255,.1)] dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset]\",\n className,\n )}\n >\n <div>{background}</div>\n <div className=\"pointer-events-none z-10 flex transform-gpu flex-col gap-1 p-6 transition-all duration-300 group-hover:-translate-y-10\">\n <Icon className=\"h-12 w-12 origin-left transform-gpu text-neutral-700 transition-all duration-300 ease-in-out group-hover:scale-75\" />\n <h3 className=\"text-xl font-semibold text-neutral-700 dark:text-neutral-300\">\n {name}\n </h3>\n <p className=\"max-w-lg text-neutral-400\">{description}</p>\n </div>\n\n <div\n className={cn(\n \"pointer-events-none absolute bottom-0 flex w-full translate-y-10 transform-gpu flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100\",\n )}\n >\n <Button variant=\"ghost\" asChild size=\"sm\" className=\"pointer-events-auto\">\n <a href={href}>\n {cta}\n <ArrowRightIcon className=\"ml-2 h-4 w-4\" />\n </a>\n </Button>\n </div>\n <div className=\"pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] group-hover:dark:bg-neutral-800/10\" />\n </div>\n);\n\nexport { BentoCard, BentoGrid };\n",
"type": "registry:ui",
"target": ""
}
Expand Down
15 changes: 15 additions & 0 deletions public/r/styles/default/scroll-progress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "scroll-progress",
"type": "registry:ui",
"dependencies": [
"framer-motion"
],
"files": [
{
"path": "magicui/scroll-progress.tsx",
"content": "import { cn } from \"@/lib/utils\";\nimport { motion, useScroll, useSpring } from \"framer-motion\";\n\ninterface ScrollProgressProps {\n className?: string;\n}\n\nexport default function ScrollProgress({ className }: ScrollProgressProps) {\n const { scrollYProgress } = useScroll();\n\n const scaleX = useSpring(scrollYProgress, {\n stiffness: 200,\n damping: 50,\n restDelta: 0.001,\n });\n\n return (\n <motion.div\n className={cn(\n \"fixed inset-x-0 top-0 z-[1000] h-1 origin-left bg-gradient-to-r from-[#A97CF8] via-[#F38CB8] to-[#FDCC92]\",\n className,\n )}\n style={{\n scaleX,\n }}\n />\n );\n}\n",
"type": "registry:ui",
"target": ""
}
]
}
20 changes: 20 additions & 0 deletions registry/default/example/scroll-progress-demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import ScrollProgress from "@/registry/default/magicui/scroll-progress";

const ScrollProgressDemo = () => {
return (
<div className="z-10 rounded-lg border border-gray-200 bg-white p-4">
<ScrollProgress className="top-[65px]" />
<h2 className="pb-4 font-bold">
Note: The scroll progress is shown below the navbar of the page.
</h2>
<p className="pb-4">
Magic UI is a collection of re-usable components that you can copy and
paste into your web apps. It primarily features components, blocks, and
templates geared towards creating landing pages and user-facing
marketing materials.
</p>
</div>
);
};

export default ScrollProgressDemo;
28 changes: 28 additions & 0 deletions registry/default/magicui/scroll-progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { cn } from "@/lib/utils";
import { motion, useScroll, useSpring } from "framer-motion";

interface ScrollProgressProps {
className?: string;
}

export default function ScrollProgress({ className }: ScrollProgressProps) {
const { scrollYProgress } = useScroll();

const scaleX = useSpring(scrollYProgress, {
stiffness: 200,
damping: 50,
restDelta: 0.001,
});

return (
<motion.div
className={cn(
"fixed inset-x-0 top-0 z-[1000] h-1 origin-left bg-gradient-to-r from-[#A97CF8] via-[#F38CB8] to-[#FDCC92]",
className,
)}
style={{
scaleX,
}}
/>
);
}
6 changes: 6 additions & 0 deletions registry/registry-examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export const examples: Registry = [
registryDependencies: ["magic-card"],
files: ["example/magic-card-demo.tsx"],
},
{
name: "scroll-progress-demo",
type: "registry:example",
registryDependencies: ["scroll-progress"],
files: ["example/scroll-progress-demo.tsx"],
},
{
name: "neon-gradient-card-demo",
type: "registry:example",
Expand Down
6 changes: 6 additions & 0 deletions registry/registry-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ export const ui: Registry = [
dependencies: ["framer-motion"],
files: ["magicui/magic-card.tsx"],
},
{
name: "scroll-progress",
type: "registry:ui",
dependencies: ["framer-motion"],
files: ["magicui/scroll-progress.tsx"],
},
{
name: "neon-gradient-card",
type: "registry:ui",
Expand Down
Loading