-
Notifications
You must be signed in to change notification settings - Fork 2
feat(docs): add animated framer-style UI, resizable sidebar, and mobile improvements #1
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ import { getPageBySlug, getAllPages } from '@/lib/pages'; | |||||||||||||
| import ReactMarkdown from 'react-markdown'; | ||||||||||||||
| import { notFound } from 'next/navigation'; | ||||||||||||||
| import { LandingFooter } from "@/features/landing-page/components/footer"; | ||||||||||||||
| import { TextReveal } from '@/components/framer/text-reveal'; | ||||||||||||||
|
|
||||||||||||||
| // This is required for static site generation with dynamic routes | ||||||||||||||
| export async function generateStaticParams() { | ||||||||||||||
|
|
@@ -23,12 +24,12 @@ export default async function Page({ params }: { params: Promise<{ slug: string | |||||||||||||
|
|
||||||||||||||
| return ( | ||||||||||||||
| <> | ||||||||||||||
| <div className="space-y-2 mb-8"> | ||||||||||||||
| <h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl capitalize"> | ||||||||||||||
| {page.title} | ||||||||||||||
| </h1> | ||||||||||||||
| <div className="space-y-2 mb-8 relative"> | ||||||||||||||
| <div className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl capitalize"> | ||||||||||||||
| <TextReveal text={page.title} /> | ||||||||||||||
| </div> | ||||||||||||||
|
Comment on lines
+28
to
+30
|
||||||||||||||
| <div className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl capitalize"> | |
| <TextReveal text={page.title} /> | |
| </div> | |
| <h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl capitalize"> | |
| <TextReveal text={page.title} /> | |
| </h1> |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,16 +1,17 @@ | ||||||||||||||
| import { getAllPages } from '@/lib/pages'; | ||||||||||||||
| import Link from 'next/link'; | ||||||||||||||
| import { LandingFooter } from "@/features/landing-page/components/footer"; | ||||||||||||||
| import { TextReveal } from "@/components/framer/text-reveal"; | ||||||||||||||
| import SpotlightCard from "@/components/framer/spotlight"; | ||||||||||||||
|
|
||||||||||||||
| export default function PagesIndex() { | ||||||||||||||
| const pages = getAllPages(); | ||||||||||||||
|
|
||||||||||||||
| return ( | ||||||||||||||
| <> | ||||||||||||||
| <div className="space-y-4"> | ||||||||||||||
| <h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl"> | ||||||||||||||
| Documentation | ||||||||||||||
| </h1> | ||||||||||||||
| <div className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl"> | ||||||||||||||
| <TextReveal text="Documentation" /> | ||||||||||||||
| </div> | ||||||||||||||
|
Comment on lines
+12
to
+14
|
||||||||||||||
| <div className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl"> | |
| <TextReveal text="Documentation" /> | |
| </div> | |
| <h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl"> | |
| <TextReveal text="Documentation" /> | |
| </h1> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| 'use client'; | ||
|
|
||
| import { useEffect, useState, useRef } from 'react'; | ||
| import { motion } from 'motion/react'; | ||
|
|
||
| const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"; | ||
|
|
||
| interface DecryptedTextProps { | ||
| text: string; | ||
| speed?: number; | ||
| maxIterations?: number; | ||
| className?: string; | ||
| animateOnHover?: boolean; | ||
| revealDirection?: "start" | "end" | "center"; | ||
| } | ||
|
|
||
| export default function DecryptedText({ | ||
| text, | ||
| speed = 50, | ||
| maxIterations = 20, | ||
| className, | ||
| animateOnHover = true, | ||
| revealDirection = "start" | ||
| }: DecryptedTextProps) { | ||
|
Comment on lines
+8
to
+24
|
||
| const [displayText, setDisplayText] = useState(text); | ||
| const [isScrambling, setIsScrambling] = useState(false); | ||
| const intervalRef = useRef<any>(null); | ||
|
|
||
| const scramble = () => { | ||
| if (isScrambling) return; | ||
| setIsScrambling(true); | ||
|
|
||
| let iteration = 0; | ||
|
|
||
| clearInterval(intervalRef.current); | ||
|
|
||
| intervalRef.current = setInterval(() => { | ||
| setDisplayText( | ||
| text | ||
| .split("") | ||
| .map((letter, index) => { | ||
| if (index < iteration) { | ||
| return text[index]; | ||
| } | ||
| return letters[Math.floor(Math.random() * letters.length)]; | ||
| }) | ||
| .join("") | ||
| ); | ||
|
|
||
| if (iteration >= text.length) { | ||
| clearInterval(intervalRef.current); | ||
| setIsScrambling(false); | ||
| } | ||
|
|
||
| iteration += 1 / 3; | ||
| }, speed); | ||
| }; | ||
|
|
||
| useEffect(() => { | ||
| // Optional: Scramble on mount | ||
| // scramble(); | ||
| return () => clearInterval(intervalRef.current); | ||
| }, []); | ||
|
Comment on lines
+25
to
+63
|
||
|
|
||
| return ( | ||
| <motion.span | ||
| className={className} | ||
| onMouseEnter={animateOnHover ? scramble : undefined} | ||
| > | ||
| {displayText} | ||
| </motion.span> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| 'use client'; | ||
|
|
||
| import { useRef, useState } from 'react'; | ||
| import { motion } from 'motion/react'; | ||
|
|
||
| interface MagnetProps { | ||
| children: React.ReactNode; | ||
| magnetStrength?: number; | ||
| active?: boolean; | ||
| } | ||
|
|
||
| export default function Magnet({ children, magnetStrength = 2, active = false }: MagnetProps) { | ||
| const [position, setPosition] = useState({ x: 0, y: 0 }); | ||
|
Comment on lines
+6
to
+13
|
||
| const ref = useRef<HTMLDivElement>(null); | ||
|
|
||
| const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => { | ||
| const { clientX, clientY } = e; | ||
| const { height, width, left, top } = ref.current!.getBoundingClientRect(); | ||
| const middleX = clientX - (left + width / 2); | ||
| const middleY = clientY - (top + height / 2); | ||
| setPosition({ x: middleX, y: middleY }); | ||
| }; | ||
|
|
||
| const reset = () => { | ||
| setPosition({ x: 0, y: 0 }); | ||
| }; | ||
|
|
||
| const { x, y } = position; | ||
| return ( | ||
| <motion.div | ||
| style={{ position: "relative", display: 'inline-block', width: '100%' }} | ||
| ref={ref} | ||
| onMouseMove={handleMouseMove} | ||
| onMouseLeave={reset} | ||
| animate={{ x: x / magnetStrength, y: y / magnetStrength }} | ||
| transition={{ type: "spring", stiffness: 150, damping: 15, mass: 0.1 }} | ||
|
Comment on lines
+30
to
+36
|
||
| > | ||
| {children} | ||
| </motion.div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { cn } from "@/lib/utils"; | ||
|
|
||
| export default function RetroGrid({ | ||
| className, | ||
| angle = 65, | ||
| }: { | ||
| className?: string; | ||
| angle?: number; | ||
| }) { | ||
| return ( | ||
| <div | ||
| className={cn( | ||
| "pointer-events-none absolute h-full w-full overflow-hidden opacity-50 [perspective:200px]", | ||
| className, | ||
| )} | ||
| style={{ "--grid-angle": `${angle}deg` } as React.CSSProperties} | ||
| > | ||
|
Comment on lines
+12
to
+17
|
||
| {/* Grid */} | ||
| <div className="absolute inset-0 [transform:rotateX(var(--grid-angle))]"> | ||
| <div | ||
| className={cn( | ||
| "animate-grid", | ||
| "[background-repeat:repeat] [background-size:60px_60px]", | ||
| "[height:300vh] [inset:0%_0px] [margin-left:-50%] [transform-origin:100%_0_0] [width:600vw]", | ||
|
|
||
| // User styles | ||
| "[background-image:linear-gradient(to_right,rgba(0,0,0,0.3)_1px,transparent_0),linear-gradient(to_bottom,rgba(0,0,0,0.3)_1px,transparent_0)]", | ||
| "dark:[background-image:linear-gradient(to_right,rgba(255,255,255,0.2)_1px,transparent_0),linear-gradient(to_bottom,rgba(255,255,255,0.2)_1px,transparent_0)]", | ||
| )} | ||
| /> | ||
| </div> | ||
|
|
||
| {/* Background Gradient */} | ||
| <div className="absolute inset-0 bg-gradient-to-t from-white to-transparent to-90% dark:from-black" /> | ||
| </div> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LandingFooteris imported but no longer used in this file. This will produce an unused import warning/error under common TS/ESLint configs; remove the import.