feat(docs): add animated framer-style UI, resizable sidebar, and mobile improvements#1
feat(docs): add animated framer-style UI, resizable sidebar, and mobile improvements#1youngcoder45 wants to merge 2 commits intomainfrom
Conversation
…esizable and color is non gradient solid no shadow
There was a problem hiding this comment.
Pull request overview
Adds a set of animated “framer-style” UI components and integrates them into the docs pages, alongside a new resizable desktop sidebar and a mobile sheet-based navigation.
Changes:
- Introduces new animated UI primitives (text reveal, decrypted text, spotlight cards, retro grid, magnet hover).
- Reworks
/pageslayout with desktop resizable panels and a mobile drawer menu. - Updates docs index + docs content pages to use the new animated header/cards and adds supporting global CSS animations.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| components/ui/sheet.tsx | Adds a Radix-based sheet component for the mobile drawer UI. |
| components/ui/resizable.tsx | Adds wrappers around react-resizable-panels for resizable desktop layout. |
| components/sidebar-nav.tsx | Updates sidebar nav styling/animation using Magnet + Motion. |
| components/framer/text-reveal.tsx | Adds animated word-by-word reveal component for headers. |
| components/framer/spotlight.tsx | Adds spotlight-hover card container used for docs cards. |
| components/framer/retro-grid.tsx | Adds animated background grid used in docs layout. |
| components/framer/magnet.tsx | Adds magnetic hover wrapper used by sidebar nav items. |
| components/framer/decrypted-text.tsx | Adds decrypted/scramble text effect for sidebar headings. |
| app/pages/page.tsx | Updates docs index header/cards to use new animated components. |
| app/pages/layout.tsx | Integrates background, mobile sheet nav, and resizable desktop sidebar. |
| app/pages/[slug]/page.tsx | Updates docs content page header/container styling with animation. |
| app/globals.css | Adds keyframes/classes used by the retro grid / shine effects. |
Comments suppressed due to low confidence (2)
components/sidebar-nav.tsx:13
SidebarNavPropsextendsReact.HTMLAttributes, but the file does not import React (orimport type React from "react"). This will fail TypeScript compilation (Cannot find namespace 'React'). Add the missing React type import or rewrite the types to avoid theReact.namespace.
interface SidebarNavProps extends React.HTMLAttributes<HTMLElement> {
items: {
href: string;
title: string;
}[];
app/pages/layout.tsx:17
- This layout types
childrenasReact.ReactNodebut does not import React (orimport type React from "react"), which will fail TypeScript compilation (Cannot find namespace 'React'). Also,Linkis imported but unused. Add the missing React type import and remove the unusedLinkimport.
import { getAllPages } from '@/lib/pages';
import Link from 'next/link';
import { LandingFooter } from "@/features/landing-page/components/footer";
import { SidebarNav } from "@/components/sidebar-nav";
import { ScrollArea } from "@/components/ui/scroll-area";
import RetroGrid from "@/components/framer/retro-grid";
import DecryptedText from '@/components/framer/decrypted-text';
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
import { Menu } from "lucide-react";
export default function PagesLayout({
children,
}: {
children: React.ReactNode;
}) {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 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 }); |
There was a problem hiding this comment.
This component uses React.ReactNode/React.MouseEvent types but never imports React (or import type React from "react"), which will fail TypeScript compilation. Also, the active prop is declared but unused; either implement its behavior or remove it to avoid a misleading API.
| <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 }} |
There was a problem hiding this comment.
The wrapper is hard-coded to width: '100%', which forces full-width layout wherever Magnet is used (e.g., SidebarNav in horizontal mode) and can cause overflow/spacing issues. Prefer letting the caller control sizing via className/style, or only apply w-full where it’s actually needed.
| 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) { |
There was a problem hiding this comment.
maxIterations and revealDirection are exposed in the props and defaulted in the function signature, but they are never used. This makes the component API misleading and will typically trigger unused-variable lint/TS warnings. Either implement these options (e.g., cap iterations and support reveal direction) or remove them from the public props.
| 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); | ||
| }, []); |
There was a problem hiding this comment.
intervalRef is typed as any, and displayText is initialized from text but never updated if the text prop changes. This can lead to stale UI and makes it easy to miss interval cleanup issues. Prefer typing the ref as ReturnType<typeof setInterval> | null and add an effect to reset displayText (and clear any running interval) when text changes.
| const handleMouseMove = (e: MouseEvent<HTMLDivElement>) => { | ||
| if (!divRef.current || isFocused) return; | ||
|
|
||
| const div = divRef.current; | ||
| const rect = div.getBoundingClientRect(); | ||
|
|
||
| setPosition({ x: e.clientX - rect.left, y: e.clientY - rect.top }); | ||
| }; |
There was a problem hiding this comment.
handleMouseMove calls setPosition on every mouse move, which forces a React re-render per pointer event and can cause noticeable jank on lower-end devices. Consider using motion values / CSS variables (and updating them via requestAnimationFrame) so pointer tracking doesn’t re-render the whole card each time.
| 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} | ||
| > |
There was a problem hiding this comment.
This file casts to React.CSSProperties but does not import React (or import type React from "react"), which will fail TypeScript compilation (Cannot find namespace 'React'). Add the missing type import or avoid the React. namespace by using CSSProperties imported from react.
| <div className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl"> | ||
| <TextReveal text="Documentation" /> | ||
| </div> |
There was a problem hiding this comment.
This page replaces the <h1> with a <div>, which removes the semantic top-level heading for the page (hurts accessibility and SEO). Keep an actual <h1> and render/animate TextReveal inside it so the heading semantics remain intact.
| <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> |
| @@ -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"; | |||
There was a problem hiding this comment.
LandingFooter is imported but no longer used in this file. This will produce an unused import warning/error under common TS/ESLint configs; remove the import.
| import { LandingFooter } from "@/features/landing-page/components/footer"; |
| <div className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl capitalize"> | ||
| <TextReveal text={page.title} /> | ||
| </div> |
There was a problem hiding this comment.
This page replaces the <h1> with a <div>, which removes the semantic main heading for the page (accessibility/SEO regression). Prefer keeping the <h1> element and placing the TextReveal animation inside it so the document outline remains correct.
| <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> |
| @@ -0,0 +1,74 @@ | |||
| 'use client'; | |||
| import React, { useRef, useState,MouseEvent } from 'react'; | |||
| import { motion } from 'motion/react'; | |||
There was a problem hiding this comment.
Unused import motion.
| import { motion } from 'motion/react'; |
SO I HAVE JUST TRIED MY BEST TO ADD REACTBITS TO THE SITE. https://reactbits.dev/
Added components
Resizable and mobile UI
Layout and integration
Documentation pages
Sidebar polish