feat (section): Add and Fixed animated pricing cards components#447
feat (section): Add and Fixed animated pricing cards components#447KeenIsHere wants to merge 16 commits intocodse:mainfrom
Conversation
📝 WalkthroughWalkthroughAdds two new UI components (DropdownMenu, AnimatedPricingCards) with Storybook stories and documentation; implements keyboard, click-outside, and motion behaviors for the dropdown and viewport-staggered entry/hover scaling for pricing cards; updates Storybook config, development script to use Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 6/8 reviews remaining, refill in 14 minutes and 38 seconds.Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (7)
animata/section/animated-pricing-cards.tsx (1)
78-80: Consider a more robust React key.
plan.nameis used as the list key. If consumers pass two plans with the samename, React will warn and reconciliation can misbehave. Combining withindex(or requiring a uniqueidfield) is safer.♻️ Suggested tweak
- {safePlans.map((plan, index) => ( - <motion.article - key={plan.name} + {safePlans.map((plan, index) => ( + <motion.article + key={`${plan.name}-${index}`}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@animata/section/animated-pricing-cards.tsx` around lines 78 - 80, The list key for each item is currently using plan.name inside safePlans.map and passed to the motion.article key prop; replace this fragile key with a more robust unique identifier (e.g., use a dedicated id property on plan or combine plan.name with the loop index like `${plan.name}-${index}`) so duplicate names don't break React reconciliation, and update any relevant prop or type expectations to require/accept a unique id if you choose that approach.animata/section/animated-pricing-cards.stories.tsx (1)
18-74: Optional: hoist the render wrapper to remove duplication.
PrimaryandCustomPlansuse an identical render wrapper. Consider extracting it (or moving the wrapper intometa.render) so each story only needs to overrideargs.♻️ Suggested cleanup
const meta = { title: "Section/Animated Pricing Cards", component: AnimatedPricingCards, parameters: { layout: "fullscreen", }, tags: ["autodocs"], + render: (args) => ( + <div className="full-content w-full bg-background"> + <AnimatedPricingCards {...args} /> + </div> + ), } satisfies Meta<typeof AnimatedPricingCards>; @@ -export const Primary: Story = { - args: {}, - render: (args: AnimatedPricingCardsProps) => ( - <div className="full-content w-full bg-background"> - <AnimatedPricingCards {...args} /> - </div> - ), -}; +export const Primary: Story = { + args: {}, +}; @@ - render: (args: AnimatedPricingCardsProps) => ( - <div className="full-content w-full bg-background"> - <AnimatedPricingCards {...args} /> - </div> - ), };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@animata/section/animated-pricing-cards.stories.tsx` around lines 18 - 74, Primary and CustomPlans both duplicate the same render wrapper around AnimatedPricingCards; hoist that wrapper into a shared place by moving the JSX into meta.render (or extracting a helper render function) so stories only supply args. Update the storybook export so meta.render returns <div className="full-content w-full bg-background"><AnimatedPricingCards {...args} /></div>, then remove the render implementations from Primary and CustomPlans and leave just their args.content/docs/navigation/dropdown-menu.mdx (1)
23-25: Accessibility section is too sparse for what the component advertises.The PR description and component implementation tout full keyboard support (ArrowUp/Down cycle, Enter to activate, Escape to close + restore focus to trigger), reduced-motion compliance, and ARIA attributes. The docs reduce all of that to one sentence. Consider documenting the actual keymap and ARIA roles so consumers can verify expected behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@content/docs/navigation/dropdown-menu.mdx` around lines 23 - 25, Expand the Accessibility section for the DropdownMenu component to list the supported keyboard interactions, ARIA roles/states, focus behavior, and reduced-motion handling; specifically document the ArrowUp/ArrowDown cycling behavior, Enter/Space activation, Escape to close and restore focus to the trigger, Home/End if supported, any typeahead behavior, the roles used (e.g., role="menu"/"menuitem" or aria-haspopup/aria-expanded on the trigger), and mention that animations respect prefers-reduced-motion — update the DropdownMenu docs to include these explicit keymap and ARIA details so consumers can verify expected behavior.animata/navigation/dropdown-menu.tsx (3)
113-125: Arrow icon path is a full-length up arrow, not a chevron.The SVG path draws a full down/up arrow (with shaft) rather than the conventional
chevron-downused for dropdown indicators. Functionally fine, but visually unusual for a menu trigger. Consider replacing with a simple chevron path (e.g.M19 9l-7 7-7-7) orlucide-react'sChevronDown(already a dependency in the stories).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@animata/navigation/dropdown-menu.tsx` around lines 113 - 125, The SVG used in dropdown-menu.tsx renders a full-length arrow shaft ("d=\"M19 14l-7 7m0 0l-7-7m7 7V3\"") instead of a chevron; replace the path with a chevron path (for example "M19 9l-7 7-7-7") or swap the inline SVG for the project's existing ChevronDown icon from lucide-react (import and render ChevronDown in place of the current <svg> in the DropdownMenu trigger) so the visual matches a standard dropdown chevron.
35-39:prefersReducedMotionshould be state, not a ref.The ref is mutated in
useEffectbut read during render at Line 87 — mutating a ref does not trigger re-render, so the value is only "correct" because the menu starts closed and the effect runs before the first open. It also won't react to runtime changes of the user's motion preference. PreferuseStateplus achangelistener on theMediaQueryList:♻️ Proposed refactor
- const prefersReducedMotion = useRef(false); - - useEffect(() => { - prefersReducedMotion.current = window.matchMedia("(prefers-reduced-motion: reduce)").matches; - }, []); + const [prefersReducedMotion, setPrefersReducedMotion] = useState(false); + + useEffect(() => { + const mql = window.matchMedia("(prefers-reduced-motion: reduce)"); + setPrefersReducedMotion(mql.matches); + const onChange = (e: MediaQueryListEvent) => setPrefersReducedMotion(e.matches); + mql.addEventListener("change", onChange); + return () => mql.removeEventListener("change", onChange); + }, []); @@ - const animationProps = prefersReducedMotion.current + const animationProps = prefersReducedMotion ? {} : { initial: { opacity: 0, translateY: -8 }, animate: { opacity: 1, translateY: 0 }, exit: { opacity: 0, translateY: -8 }, };Also applies to: 87-93
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@animata/navigation/dropdown-menu.tsx` around lines 35 - 39, Replace the prefersReducedMotion ref with React state: use useState<boolean> for prefersReducedMotion (instead of useRef) and initialize it from window.matchMedia("(prefers-reduced-motion: reduce)").matches inside a useEffect; attach a MediaQueryList change listener that updates the state when the preference changes, and remove that listener in the effect cleanup. Update any code that reads prefersReducedMotion (the render logic that currently reads prefersReducedMotion.current) to read the state variable directly so changes trigger re-renders.
47-67: Consider scope and focus management for the Enter key handler.The handler listens globally on
windowand triggersitems[selectedIndex]?.onClick?.()regardless of which menu item has DOM focus. If a user manually tabs to a different menu item than the one highlighted via arrow keys, pressing Enter will fire the wrong item's onClick handler. Consider either: (1) preventing menu items from receiving tab focus withtabIndex={-1}, (2) syncingselectedIndexwith actual DOM focus state, or (3) removing the manual Enter handler and letting the focused button handle it natively.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@animata/navigation/dropdown-menu.tsx` around lines 47 - 67, The Enter branch in handleKeyDown triggers items[selectedIndex]?.onClick regardless of actual DOM focus and should be removed so the focused menu item handles activation natively; delete the `else if (e.key === "Enter") { ... }` block from handleKeyDown, ensure each menu item element is a native focusable control (button/a) that invokes its onClick, and if you want to keep keyboard-only selection, alternatively set menu item elements to tabIndex={-1} and keep selection-only navigation via selectedIndex—choose one approach and update the code around handleKeyDown, selectedIndex, items, and setIsOpen accordingly.animata/navigation/dropdown-menu.stories.tsx (1)
28-62: LGTM — duplication is minor and acceptable for stories.Both stories duplicate the same
itemsarray; for two stories that's fine, but if more variants are added consider hoisting to a module-levelsampleItemsconstant. Otherwise the meta typing,argTypes, and render wrappers all look correct.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@animata/navigation/dropdown-menu.stories.tsx` around lines 28 - 62, Hoist the duplicated items arrays used by the Primary and RightAlign stories into a shared module-level constant (e.g., sampleItems) and have both story args reference that constant instead of inline arrays; update the args for Primary and RightAlign to use sampleItems and keep the existing render wrappers and props passed to DropdownMenu unchanged so behavior and typings (Story, argTypes) remain intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@animata/navigation/dropdown-menu.tsx`:
- Around line 47-67: The arrow-key handler currently updates selectedIndex
visually but doesn't move DOM focus; fix by creating an array of refs for the
menu item buttons (e.g., menuItemRefs) and, in an effect that runs when
selectedIndex or isOpen changes, call
menuItemRefs[selectedIndex]?.current?.focus() when the menu is open so the
corresponding <button role="menuitem"> receives focus; update the Enter handling
in handleKeyDown to rely on the focused button (or call
menuItemRefs[selectedIndex]?.current?.click()) instead of directly invoking
items[selectedIndex]?.onClick, and ensure you create/cleanup refs and keep
triggerRef focus behavior on Escape (triggerRef.current?.focus()); apply the
same ref/focus pattern to the other menu instance referenced similarly in this
file.
In `@animata/section/animated-pricing-cards.tsx`:
- Around line 120-130: The checkmark SVG in animated-pricing-cards.tsx is
decorative and should be hidden from assistive tech; update the SVG element (the
<svg> wrapping the checkmark path with className "h-5 w-5 shrink-0
text-primary") to include aria-hidden="true" and focusable="false" so screen
readers ignore it (do not add role="img").
- Around line 136-149: The Framer Motion props on motion.button
(whileHover/whileTap) still run for users with prefers-reduced-motion because
the Tailwind motion-reduce: variant only affects CSS; fix by importing
useReducedMotion from "framer-motion" (or "motion/react" per project) inside the
component that renders the motion.button, call useReducedMotion() (e.g., const
reduceMotion = useReducedMotion()), and conditionally pass the whileHover and
whileTap props only when reduceMotion is false—i.e., build an props object (or
inline conditional) to omit whileHover/whileTap for reduced motion users while
keeping the existing className and plan.ctaText handling in the
AnimatedPricingCards component/motion.button render.
- Around line 79-93: The Tailwind transform utilities (lg:scale-105,
motion-safe:hover:-translate-y-2) are being overridden by Framer Motion's inline
transform on motion.article; remove those transform classes from className and
instead express them via Motion props: add a conditional animate or whileInView
scale when plan.highlighted (e.g., animate={{ scale: plan.highlighted ? 1.05 : 1
}} or include scale in whileInView) and replace the hover translate with a
whileHover prop that applies y: -8 (or equivalent); gate the whileHover by using
useReducedMotion() from "motion/react" so you only set whileHover when reduced
motion is false. Ensure className retains non-transform utilities and refer to
motion.article, whileInView, animate/whileHover, useReducedMotion, and
plan.highlighted when making the changes.
In `@content/docs/navigation/dropdown-menu.mdx`:
- Around line 17-21: The docs table incorrectly states the items prop default is
[] but the component dropdown-menu.tsx defines a 4-entry defaultItems array
(Profile, Settings, Help, Sign Out) used when items is omitted; update the docs
in content/docs/navigation/dropdown-menu.mdx to show the actual default (e.g.,
defaultItems — or list the four default entries) for the items prop and mention
that dropdown-menu.tsx uses defaultItems as the fallback to keep docs in sync
with the DropdownMenu component.
- Around line 7-13: Update the Usage section to include the shadcn registry
install command using the required registry URL format for this component; add a
line with the npx shadcn@latest add
https://animata.design/r/navigation/dropdown-menu.json command before the import
example so users can install the DropdownMenu from the registry, then keep the
existing import of DropdownMenu and usage example unchanged.
In `@content/docs/section/animated-pricing-cards.mdx`:
- Around line 107-113: Update the "Browser Support" section so it only lists
actual browser features (e.g., CSS Grid and Flexbox, CSS Custom Properties,
ES2020+ JavaScript) and remove "Framer Motion" from that list; instead add a
note elsewhere (or a new "Runtime dependencies" or "Requirements" line) stating
the component depends on the Motion library bundled with the app and imports
from "motion/react" (not the browser), so browsers themselves need only the
listed language and CSS features.
- Line 56: Update the wording that currently says "Middle card features a 'Most
Popular' badge and scale effect" to clarify that the badge/scale is applied to
any plan with highlighted: true rather than by position; reference the prop/flag
highlighted: true and the plan object so copy explains "The card with
highlighted: true shows the 'Most Popular' badge and scale effect" instead of
implying it's always the middle card.
---
Nitpick comments:
In `@animata/navigation/dropdown-menu.stories.tsx`:
- Around line 28-62: Hoist the duplicated items arrays used by the Primary and
RightAlign stories into a shared module-level constant (e.g., sampleItems) and
have both story args reference that constant instead of inline arrays; update
the args for Primary and RightAlign to use sampleItems and keep the existing
render wrappers and props passed to DropdownMenu unchanged so behavior and
typings (Story, argTypes) remain intact.
In `@animata/navigation/dropdown-menu.tsx`:
- Around line 113-125: The SVG used in dropdown-menu.tsx renders a full-length
arrow shaft ("d=\"M19 14l-7 7m0 0l-7-7m7 7V3\"") instead of a chevron; replace
the path with a chevron path (for example "M19 9l-7 7-7-7") or swap the inline
SVG for the project's existing ChevronDown icon from lucide-react (import and
render ChevronDown in place of the current <svg> in the DropdownMenu trigger) so
the visual matches a standard dropdown chevron.
- Around line 35-39: Replace the prefersReducedMotion ref with React state: use
useState<boolean> for prefersReducedMotion (instead of useRef) and initialize it
from window.matchMedia("(prefers-reduced-motion: reduce)").matches inside a
useEffect; attach a MediaQueryList change listener that updates the state when
the preference changes, and remove that listener in the effect cleanup. Update
any code that reads prefersReducedMotion (the render logic that currently reads
prefersReducedMotion.current) to read the state variable directly so changes
trigger re-renders.
- Around line 47-67: The Enter branch in handleKeyDown triggers
items[selectedIndex]?.onClick regardless of actual DOM focus and should be
removed so the focused menu item handles activation natively; delete the `else
if (e.key === "Enter") { ... }` block from handleKeyDown, ensure each menu item
element is a native focusable control (button/a) that invokes its onClick, and
if you want to keep keyboard-only selection, alternatively set menu item
elements to tabIndex={-1} and keep selection-only navigation via
selectedIndex—choose one approach and update the code around handleKeyDown,
selectedIndex, items, and setIsOpen accordingly.
In `@animata/section/animated-pricing-cards.stories.tsx`:
- Around line 18-74: Primary and CustomPlans both duplicate the same render
wrapper around AnimatedPricingCards; hoist that wrapper into a shared place by
moving the JSX into meta.render (or extracting a helper render function) so
stories only supply args. Update the storybook export so meta.render returns
<div className="full-content w-full bg-background"><AnimatedPricingCards
{...args} /></div>, then remove the render implementations from Primary and
CustomPlans and leave just their args.
In `@animata/section/animated-pricing-cards.tsx`:
- Around line 78-80: The list key for each item is currently using plan.name
inside safePlans.map and passed to the motion.article key prop; replace this
fragile key with a more robust unique identifier (e.g., use a dedicated id
property on plan or combine plan.name with the loop index like
`${plan.name}-${index}`) so duplicate names don't break React reconciliation,
and update any relevant prop or type expectations to require/accept a unique id
if you choose that approach.
In `@content/docs/navigation/dropdown-menu.mdx`:
- Around line 23-25: Expand the Accessibility section for the DropdownMenu
component to list the supported keyboard interactions, ARIA roles/states, focus
behavior, and reduced-motion handling; specifically document the
ArrowUp/ArrowDown cycling behavior, Enter/Space activation, Escape to close and
restore focus to the trigger, Home/End if supported, any typeahead behavior, the
roles used (e.g., role="menu"/"menuitem" or aria-haspopup/aria-expanded on the
trigger), and mention that animations respect prefers-reduced-motion — update
the DropdownMenu docs to include these explicit keymap and ARIA details so
consumers can verify expected behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 66f242ba-068c-46eb-9fef-e06a3cb985b8
📒 Files selected for processing (6)
animata/navigation/dropdown-menu.stories.tsxanimata/navigation/dropdown-menu.tsxanimata/section/animated-pricing-cards.stories.tsxanimata/section/animated-pricing-cards.tsxcontent/docs/navigation/dropdown-menu.mdxcontent/docs/section/animated-pricing-cards.mdx
| const handleKeyDown = (e: KeyboardEvent) => { | ||
| if (e.key === "ArrowDown") { | ||
| e.preventDefault(); | ||
| setSelectedIndex((prev) => (prev + 1) % items.length); | ||
| } else if (e.key === "ArrowUp") { | ||
| e.preventDefault(); | ||
| setSelectedIndex((prev) => (prev - 1 + items.length) % items.length); | ||
| } else if (e.key === "Enter") { | ||
| e.preventDefault(); | ||
| items[selectedIndex]?.onClick?.(); | ||
| setIsOpen(false); | ||
| } else if (e.key === "Escape") { | ||
| e.preventDefault(); | ||
| setIsOpen(false); | ||
| triggerRef.current?.focus(); | ||
| } | ||
| }; | ||
|
|
||
| window.addEventListener("keydown", handleKeyDown); | ||
| return () => window.removeEventListener("keydown", handleKeyDown); | ||
| }, [isOpen, selectedIndex, items]); |
There was a problem hiding this comment.
Arrow keys update visual selection but do not move DOM focus — a11y gap.
Arrow keys mutate selectedIndex (visual highlight only) while DOM focus remains on the trigger button. Screen readers won't announce the active menuitem, and Tab order isn't synchronized with the highlighted row. Since the docs (dropdown-menu.mdx) advertise full keyboard navigation, consider focusing the matching <button role="menuitem"> when selectedIndex changes (e.g., via an array of refs and .focus() in an effect), and let Enter rely on the focused button.
Also applies to: 141-162
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@animata/navigation/dropdown-menu.tsx` around lines 47 - 67, The arrow-key
handler currently updates selectedIndex visually but doesn't move DOM focus; fix
by creating an array of refs for the menu item buttons (e.g., menuItemRefs) and,
in an effect that runs when selectedIndex or isOpen changes, call
menuItemRefs[selectedIndex]?.current?.focus() when the menu is open so the
corresponding <button role="menuitem"> receives focus; update the Enter handling
in handleKeyDown to rely on the focused button (or call
menuItemRefs[selectedIndex]?.current?.click()) instead of directly invoking
items[selectedIndex]?.onClick, and ensure you create/cleanup refs and keep
triggerRef focus behavior on Escape (triggerRef.current?.focus()); apply the
same ref/focus pattern to the other menu instance referenced similarly in this
file.
| <motion.article | ||
| key={plan.name} | ||
| initial={{ opacity: 0, y: 20 }} | ||
| whileInView={{ opacity: 1, y: 0 }} | ||
| transition={{ delay: index * 0.1, duration: 0.4 }} | ||
| viewport={{ once: true, margin: "-100px" }} | ||
| className={cn( | ||
| "group relative flex flex-col rounded-2xl border transition-all duration-300", | ||
| "motion-safe:hover:-translate-y-2", | ||
| "bg-background p-6 sm:p-8 lg:p-10", | ||
| plan.highlighted | ||
| ? "border-primary shadow-lg lg:scale-105" | ||
| : "border-border shadow-sm motion-safe:hover:shadow-md", | ||
| )} | ||
| > |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does Framer Motion / motion v12 set transform via inline style and override Tailwind transform utility classes like hover:-translate-y-2andlg:scale-105?
💡 Result:
Yes, Framer Motion (now Motion) v12 sets transform properties via inline styles, which override Tailwind CSS transform utility classes such as hover:-translate-y-2 and lg:scale-105. Motion animates by applying inline styles or native browser animations, both of which override Tailwind CSS classes. This is by design, as the libraries complement each other: Tailwind for static/responsive styling, Motion for animations. Tailwind transform utilities (e.g., translate, scale) generate CSS transform properties with higher specificity from classes, but inline styles applied by Motion during/after animation have higher CSS specificity and take precedence. Once Motion animates a transform property (e.g., via animate={{ scale: 1.05 }} or whileHover), it persists the final inline style value, preventing Tailwind's CSS-declared transforms (including pseudo-class like hover or media-query like lg:) from applying. Evidence from official Motion docs confirms inline styles override classes. Community reports (Stack Overflow, GitHub issues) consistently show Tailwind hover transforms failing on Motion elements, requiring !important variants (e.g., hover:!scale-110) as workarounds, confirming the override behavior. No v12-specific changes alter this core mechanism; upgrade guides mention transform optimizations but retain inline style application.
Citations:
- 1: https://motion.dev/docs/react-tailwind
- 2: [BUG] Styles set using CSS rules are overridden by inline styles after transition exited motiondivision/motion#1666
- 3: https://stackoverflow.com/questions/72792550/tailwind-hoverscale-not-working-with-framer-motion
- 4: https://motion.dev/docs/react-upgrade-guide
- 5: https://motion.dev/docs/react
Tailwind transforms will be overridden by Motion's inline transform style.
Motion applies transform via inline style attribute, which has higher CSS specificity than Tailwind utility classes. Once motion.article animates, the inline transform persists, preventing:
lg:scale-105from taking effect on the highlighted cardmotion-safe:hover:-translate-y-2from applying on hover
Move these into Motion's animation props instead:
♻️ Suggested fix
<motion.article
key={plan.name}
initial={{ opacity: 0, y: 20 }}
- whileInView={{ opacity: 1, y: 0 }}
+ whileInView={{ opacity: 1, y: 0, scale: plan.highlighted ? 1.05 : 1 }}
+ whileHover={{ y: -8 }}
transition={{ delay: index * 0.1, duration: 0.4 }}
viewport={{ once: true, margin: "-100px" }}
className={cn(
"group relative flex flex-col rounded-2xl border transition-all duration-300",
- "motion-safe:hover:-translate-y-2",
"bg-background p-6 sm:p-8 lg:p-10",
plan.highlighted
- ? "border-primary shadow-lg lg:scale-105"
+ ? "border-primary shadow-lg"
: "border-border shadow-sm motion-safe:hover:shadow-md",
)}
>Gate whileHover with useReducedMotion() from motion/react to respect prefers-reduced-motion.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <motion.article | |
| key={plan.name} | |
| initial={{ opacity: 0, y: 20 }} | |
| whileInView={{ opacity: 1, y: 0 }} | |
| transition={{ delay: index * 0.1, duration: 0.4 }} | |
| viewport={{ once: true, margin: "-100px" }} | |
| className={cn( | |
| "group relative flex flex-col rounded-2xl border transition-all duration-300", | |
| "motion-safe:hover:-translate-y-2", | |
| "bg-background p-6 sm:p-8 lg:p-10", | |
| plan.highlighted | |
| ? "border-primary shadow-lg lg:scale-105" | |
| : "border-border shadow-sm motion-safe:hover:shadow-md", | |
| )} | |
| > | |
| <motion.article | |
| key={plan.name} | |
| initial={{ opacity: 0, y: 20 }} | |
| whileInView={{ opacity: 1, y: 0, scale: plan.highlighted ? 1.05 : 1 }} | |
| whileHover={{ y: -8 }} | |
| transition={{ delay: index * 0.1, duration: 0.4 }} | |
| viewport={{ once: true, margin: "-100px" }} | |
| className={cn( | |
| "group relative flex flex-col rounded-2xl border transition-all duration-300", | |
| "bg-background p-6 sm:p-8 lg:p-10", | |
| plan.highlighted | |
| ? "border-primary shadow-lg" | |
| : "border-border shadow-sm motion-safe:hover:shadow-md", | |
| )} | |
| > |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@animata/section/animated-pricing-cards.tsx` around lines 79 - 93, The
Tailwind transform utilities (lg:scale-105, motion-safe:hover:-translate-y-2)
are being overridden by Framer Motion's inline transform on motion.article;
remove those transform classes from className and instead express them via
Motion props: add a conditional animate or whileInView scale when
plan.highlighted (e.g., animate={{ scale: plan.highlighted ? 1.05 : 1 }} or
include scale in whileInView) and replace the hover translate with a whileHover
prop that applies y: -8 (or equivalent); gate the whileHover by using
useReducedMotion() from "motion/react" so you only set whileHover when reduced
motion is false. Ensure className retains non-transform utilities and refer to
motion.article, whileInView, animate/whileHover, useReducedMotion, and
plan.highlighted when making the changes.
| <motion.button | ||
| whileHover={{ scale: 1.02 }} | ||
| whileTap={{ scale: 0.98 }} | ||
| className={cn( | ||
| "h-11 w-full rounded-lg font-semibold transition-colors duration-200", | ||
| "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", | ||
| "motion-reduce:hover:scale-100", | ||
| plan.highlighted | ||
| ? "bg-primary text-primary-foreground hover:bg-primary/90" | ||
| : "border border-border text-foreground hover:bg-muted", | ||
| )} | ||
| > | ||
| {plan.ctaText || "Get Started"} | ||
| </motion.button> |
There was a problem hiding this comment.
motion-reduce:hover:scale-100 doesn't disable Motion's whileHover/whileTap.
Tailwind's motion-reduce: variant only neutralizes CSS-based transforms; it has no effect on Framer Motion's whileHover/whileTap, which animate via inline transform. So this button still scales for users with prefers-reduced-motion, contradicting the docs' "motion handling".
Use useReducedMotion() from motion/react and conditionally drop the props:
♻️ Suggested fix
-import { motion } from "motion/react";
+import { motion, useReducedMotion } from "motion/react";
@@
export default function AnimatedPricingCards({ plans = defaultPlans }: AnimatedPricingCardsProps) {
const safePlans = Array.isArray(plans) ? plans : defaultPlans;
+ const prefersReducedMotion = useReducedMotion();
@@
<motion.button
- whileHover={{ scale: 1.02 }}
- whileTap={{ scale: 0.98 }}
+ whileHover={prefersReducedMotion ? undefined : { scale: 1.02 }}
+ whileTap={prefersReducedMotion ? undefined : { scale: 0.98 }}
className={cn(
"h-11 w-full rounded-lg font-semibold transition-colors duration-200",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
- "motion-reduce:hover:scale-100",
plan.highlighted🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@animata/section/animated-pricing-cards.tsx` around lines 136 - 149, The
Framer Motion props on motion.button (whileHover/whileTap) still run for users
with prefers-reduced-motion because the Tailwind motion-reduce: variant only
affects CSS; fix by importing useReducedMotion from "framer-motion" (or
"motion/react" per project) inside the component that renders the motion.button,
call useReducedMotion() (e.g., const reduceMotion = useReducedMotion()), and
conditionally pass the whileHover and whileTap props only when reduceMotion is
false—i.e., build an props object (or inline conditional) to omit
whileHover/whileTap for reduced motion users while keeping the existing
className and plan.ctaText handling in the AnimatedPricingCards
component/motion.button render.
| ## Usage | ||
|
|
||
| Copy the component into your project and import it. | ||
|
|
||
| ```typescript | ||
| import DropdownMenu from "@/animata/navigation/dropdown-menu"; | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Missing shadcn registry installation snippet.
The Usage section only suggests copying the component. Per repo convention, docs should reference the shadcn registry URL so users can install via the registry. As per coding guidelines: "Use shadcn registry URL format https://animata.design/r/{category}/{name}.json in docs/changelog — never bare npx shadcn add component-name".
📝 Suggested addition
## Usage
-Copy the component into your project and import it.
+Install via the registry:
+
+```bash
+npx shadcn@latest add https://animata.design/r/navigation/dropdown-menu.json
+```
+
+Then import and use:
```typescript
import DropdownMenu from "@/animata/navigation/dropdown-menu";
```As per coding guidelines: **/*.mdx: Use shadcn registry URL format https://animata.design/r/{category}/{name}.json in docs/changelog — never bare npx shadcn add component-name.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## Usage | |
| Copy the component into your project and import it. | |
| ```typescript | |
| import DropdownMenu from "@/animata/navigation/dropdown-menu"; | |
| ``` | |
| ## Usage | |
| Install via the registry: | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/navigation/dropdown-menu.mdx` around lines 7 - 13, Update the
Usage section to include the shadcn registry install command using the required
registry URL format for this component; add a line with the npx shadcn@latest
add https://animata.design/r/navigation/dropdown-menu.json command before the
import example so users can install the DropdownMenu from the registry, then
keep the existing import of DropdownMenu and usage example unchanged.
| | Prop | Type | Default | Description | | ||
| |---|---|---|---| | ||
| | items | MenuItem[] | [] | Array of menu items | | ||
| | triggerLabel | string | "Options" | Button label | | ||
| | align | "left" \| "right" | "left" | Dropdown alignment | |
There was a problem hiding this comment.
items default does not match the implementation.
Docs list the default as [], but dropdown-menu.tsx (Line 19-24, 27) defaults items to a 4-entry defaultItems array (Profile, Settings, Help, Sign Out). Update the table to reflect the actual default so consumers aren't surprised by populated content when they omit the prop.
📝 Proposed fix
-| items | MenuItem[] | [] | Array of menu items |
+| items | MenuItem[] | `defaultItems` (Profile, Settings, Help, Sign Out) | Array of menu items |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | Prop | Type | Default | Description | | |
| |---|---|---|---| | |
| | items | MenuItem[] | [] | Array of menu items | | |
| | triggerLabel | string | "Options" | Button label | | |
| | align | "left" \| "right" | "left" | Dropdown alignment | | |
| | Prop | Type | Default | Description | | |
| |---|---|---|---| | |
| | items | MenuItem[] | `defaultItems` (Profile, Settings, Help, Sign Out) | Array of menu items | | |
| | triggerLabel | string | "Options" | Button label | | |
| | align | "left" \| "right" | "left" | Dropdown alignment | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/navigation/dropdown-menu.mdx` around lines 17 - 21, The docs
table incorrectly states the items prop default is [] but the component
dropdown-menu.tsx defines a 4-entry defaultItems array (Profile, Settings, Help,
Sign Out) used when items is omitted; update the docs in
content/docs/navigation/dropdown-menu.mdx to show the actual default (e.g.,
defaultItems — or list the four default entries) for the items prop and mention
that dropdown-menu.tsx uses defaultItems as the fallback to keep docs in sync
with the DropdownMenu component.
| ## Browser Support | ||
|
|
||
| Works in all modern browsers that support: | ||
| - CSS Grid and Flexbox | ||
| - CSS Custom Properties | ||
| - Framer Motion | ||
| - ES2020+ JavaScript |
There was a problem hiding this comment.
Framer Motion is a runtime dependency, not a browser feature.
The Browser Support list mixes browser capabilities (Grid, Flexbox, CSS variables, ES2020+) with Framer Motion, which is a JS library bundled with the app — not something the browser needs to "support". Also, the component imports from motion/react (the renamed Motion package), so referring to it as Framer Motion is doubly inaccurate.
📝 Suggested edit
Works in all modern browsers that support:
- CSS Grid and Flexbox
- CSS Custom Properties
-- Framer Motion
- ES2020+ JavaScript📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## Browser Support | |
| Works in all modern browsers that support: | |
| - CSS Grid and Flexbox | |
| - CSS Custom Properties | |
| - Framer Motion | |
| - ES2020+ JavaScript | |
| ## Browser Support | |
| Works in all modern browsers that support: | |
| - CSS Grid and Flexbox | |
| - CSS Custom Properties | |
| - ES2020+ JavaScript |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/section/animated-pricing-cards.mdx` around lines 107 - 113,
Update the "Browser Support" section so it only lists actual browser features
(e.g., CSS Grid and Flexbox, CSS Custom Properties, ES2020+ JavaScript) and
remove "Framer Motion" from that list; instead add a note elsewhere (or a new
"Runtime dependencies" or "Requirements" line) stating the component depends on
the Motion library bundled with the app and imports from "motion/react" (not the
browser), so browsers themselves need only the listed language and CSS features.
|
🚀 Preview deployed to: https://e7646919.animata.pages.dev |
|
@KeenIsHere, here are a few things to fix/consider:
|
| --- | ||
| title: Animated Pricing Cards | ||
| description: A responsive pricing section with smooth hover animations, "Most Popular" badge, and premium SaaS design. | ||
| author: AnimataContributor |
|
|
🚀 Preview deployed to: https://9d8772e0.animata.pages.dev |
Move transforms to Motion props to avoid Tailwind overrides and respect prefers-reduced-motion.
…aders Add aria-hidden and focusable=false to checkmark SVG for accessibility.
…on guide - Clarify highlighted card is driven by highlighted prop, not position - Remove Framer Motion from browser support (runtime dependency, not browser feature) - Add installation instructions using yarn animata:new - Update animation details to reflect Motion-based approach
- Replace Unix shell syntax (&, wait) with cross-platform concurrently - Install concurrently package for parallel process management - Update .storybook/main.ts with webpack configuration - Add .env.storybook for font optimization settings - Include comprehensive troubleshooting guide This fixes yarn dev failures on Windows and provides workarounds for Google Fonts network connectivity issues.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.storybook/main.ts:
- Around line 13-29: The webpackFinal hook is a no-op: mapping config.plugins
and returning each plugin unchanged (including the ProgressPlugin) doesn't
suppress Google Fonts errors; either remove the entire webpackFinal block or
implement real suppression by mutating config.plugins (e.g., filter out or
replace the plugin that triggers Google Fonts loads) instead of the current
identity map. Locate webpackFinal and the config.plugins map and replace the map
with logic that filters out the specific plugin by constructor.name (or returns
a stubbed plugin) that causes Google Fonts errors (or simply delete the hook if
no suppression is needed) so the hook actually changes config.plugins rather
than leaving it unchanged.
In `@content/docs/section/animated-pricing-cards.mdx`:
- Around line 14-22: Update the Installation section to include the direct
registry URL install form alongside the existing yarn animata:new flow: add a
short sentence and an example install command using the shadcn registry URL
format (https://animata.design/r/{category}/{name}.json) so consumers can
install a generated component directly (e.g., show the registry URL with
placeholders for {category} and {name} and a corresponding yarn or curl command)
and ensure the docs avoid suggesting bare npx/shadcn add usage.
- Around line 101-106: The docs incorrectly state that motion handling uses the
useReducedMotion() hook; update content in animated-pricing-cards.mdx to reflect
the component implementation in animata/section/animated-pricing-cards.tsx by
replacing the reference to useReducedMotion() with that animations are
controlled via the motion-safe and motion-reduce CSS classes (e.g., mention
"motion-safe/motion-reduce classes" and that they are applied to the
cards/viewport animations) so the docs match the actual behavior.
In `@package.json`:
- Line 7: The dev script in package.json starts Storybook on port 6006 while
your .env.development exposes NEXT_PUBLIC_STORYBOOK_URL pointing to :6007,
causing preview links to 6007 to fail; update the "dev" script (the "dev" npm
script string in package.json that currently invokes "storybook dev -p 6006
--no-open --debug-webpack") to use the same port as NEXT_PUBLIC_STORYBOOK_URL
(e.g., change 6006 to 6007) or refactor the script to read the port from the env
var so Storybook and NEXT_PUBLIC_STORYBOOK_URL stay aligned.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 490847db-3005-4eff-b2d2-550388b00ae7
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (5)
.env.development.storybook/main.tsanimata/section/animated-pricing-cards.tsxcontent/docs/section/animated-pricing-cards.mdxpackage.json
✅ Files skipped from review due to trivial changes (1)
- .env.development
🚧 Files skipped from review as they are similar to previous changes (1)
- animata/section/animated-pricing-cards.tsx
| webpackFinal: async (config) => { | ||
| // Suppress Google Fonts loading errors during dev | ||
| if (config.plugins) { | ||
| config.plugins = config.plugins.map((plugin) => { | ||
| if ( | ||
| plugin && | ||
| typeof plugin === "object" && | ||
| "constructor" in plugin && | ||
| plugin.constructor.name === "ProgressPlugin" | ||
| ) { | ||
| return plugin; | ||
| } | ||
| return plugin; | ||
| }); | ||
| } | ||
| return config; | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
sed -n '13,29p' .storybook/main.ts
rg -n 'return plugin;|constructor.name === "ProgressPlugin"' .storybook/main.tsRepository: codse/animata
Length of output: 617
webpackFinal is a no-op that does not suppress Google Fonts errors.
Both branches of the conditional on lines 21–25 return plugin unchanged. The map over config.plugins produces no mutations, so this hook adds misleading configuration without actually addressing the stated problem.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.storybook/main.ts around lines 13 - 29, The webpackFinal hook is a no-op:
mapping config.plugins and returning each plugin unchanged (including the
ProgressPlugin) doesn't suppress Google Fonts errors; either remove the entire
webpackFinal block or implement real suppression by mutating config.plugins
(e.g., filter out or replace the plugin that triggers Google Fonts loads)
instead of the current identity map. Locate webpackFinal and the config.plugins
map and replace the map with logic that filters out the specific plugin by
constructor.name (or returns a stubbed plugin) that causes Google Fonts errors
(or simply delete the hook if no suppression is needed) so the hook actually
changes config.plugins rather than leaving it unchanged.
| ## Installation | ||
|
|
||
| To create and install this component, use the following command: | ||
|
|
||
| ```bash | ||
| yarn animata:new | ||
| ``` | ||
|
|
||
| Then select the section category and follow the prompts to generate the component files. |
There was a problem hiding this comment.
Add the direct registry URL install path here.
The install section only documents yarn animata:new. For MDX docs, this component should also expose the registry URL form so consumers can install it directly.
📝 Suggested doc update
## Installation
-To create and install this component, use the following command:
+Install directly from the registry with:
+
+`https://animata.design/r/section/animated-pricing-cards.json`
+
+If you prefer the guided generator flow, use:
```bash
yarn animata:new</details>
As per coding guidelines: `**/*.mdx`: Use shadcn registry URL format `https://animata.design/r/{category}/{name}.json` in docs/changelog — never bare `npx shadcn add component-name`.
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against the current code and only fix it if needed.
In @content/docs/section/animated-pricing-cards.mdx around lines 14 - 22, Update
the Installation section to include the direct registry URL install form
alongside the existing yarn animata:new flow: add a short sentence and an
example install command using the shadcn registry URL format
(https://animata.design/r/{category}/{name}.json) so consumers can install a
generated component directly (e.g., show the registry URL with placeholders for
{category} and {name} and a corresponding yarn or curl command) and ensure the
docs avoid suggesting bare npx/shadcn add usage.
</details>
<!-- fingerprinting:phantom:medusa:ocelot:daf43c5a-171c-4553-a9a1-2f40e6cb0d3e -->
<!-- d98c2f50 -->
<!-- This is an auto-generated comment by CodeRabbit -->
| - **Stagger delay**: 100ms between cards on initial load | ||
| - **Hover effect**: 8px upward lift (y: -8) with smooth transition | ||
| - **Button hover**: Scale to 1.02 on hover for visual feedback | ||
| - **Button tap**: Scale to 0.98 on tap for mobile feedback | ||
| - **Viewport animation**: Triggers when cards enter viewport | ||
| - **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
sed -n '1,170p' animata/section/animated-pricing-cards.tsx
rg -n 'useReducedMotion|motion-safe|motion-reduce' animata/section/animated-pricing-cards.tsxRepository: codse/animata
Length of output: 5915
Update docs to match component implementation: use motion-safe/motion-reduce instead of useReducedMotion() hook.
Lines 101-106 incorrectly state that motion handling uses useReducedMotion(), but animata/section/animated-pricing-cards.tsx uses only motion-safe and motion-reduce CSS classes (lines 87, 91, 144).
📝 Suggested doc update
-- **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook
+- **Motion handling**: Hover and interaction animations respect `prefers-reduced-motion` via `motion-safe` and `motion-reduce` classes📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - **Stagger delay**: 100ms between cards on initial load | |
| - **Hover effect**: 8px upward lift (y: -8) with smooth transition | |
| - **Button hover**: Scale to 1.02 on hover for visual feedback | |
| - **Button tap**: Scale to 0.98 on tap for mobile feedback | |
| - **Viewport animation**: Triggers when cards enter viewport | |
| - **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook | |
| - **Stagger delay**: 100ms between cards on initial load | |
| - **Hover effect**: 8px upward lift (y: -8) with smooth transition | |
| - **Button hover**: Scale to 1.02 on hover for visual feedback | |
| - **Button tap**: Scale to 0.98 on tap for mobile feedback | |
| - **Viewport animation**: Triggers when cards enter viewport | |
| - **Motion handling**: Hover and interaction animations respect `prefers-reduced-motion` via `motion-safe` and `motion-reduce` classes |
🧰 Tools
🪛 LanguageTool
[grammar] ~101-~101: Ensure spelling is correct
Context: ...Animation Details - Stagger delay: 100ms between cards on initial load - **Hover...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~102-~102: Ensure spelling is correct
Context: ...rds on initial load - Hover effect: 8px upward lift (y: -8) with smooth transit...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/section/animated-pricing-cards.mdx` around lines 101 - 106, The
docs incorrectly state that motion handling uses the useReducedMotion() hook;
update content in animated-pricing-cards.mdx to reflect the component
implementation in animata/section/animated-pricing-cards.tsx by replacing the
reference to useReducedMotion() with that animations are controlled via the
motion-safe and motion-reduce CSS classes (e.g., mention
"motion-safe/motion-reduce classes" and that they are applied to the
cards/viewport animations) so the docs match the actual behavior.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
content/docs/section/animated-pricing-cards.mdx (2)
16-22:⚠️ Potential issue | 🟡 MinorAdd the direct registry install URL to the Installation section.
Right now this only documents the generator flow. Please also include the direct registry URL format for this component.
Suggested doc patch
## Installation -To create and install this component, use the following command: +Install directly from the registry: + +`https://animata.design/r/section/animated-pricing-cards.json` + +Or use the guided generator flow: ```bash yarn animata:newThen select the section category and follow the prompts to generate the component files.
</details> As per coding guidelines: `**/*.mdx`: Use shadcn registry URL format `https://animata.design/r/{category}/{name}.json` in docs/changelog — never bare `npx shadcn add component-name`. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@content/docs/section/animated-pricing-cards.mdxaround lines 16 - 22, The
Installation section currently only documents the generator commandyarn animata:new; update that section to also show the direct registry install URL
using the shadcn registry format
https://animata.design/r/{category}/{name}.jsonand include the concrete URL
for this component (category "section", name "animated-pricing-cards") so
readers can install directly without the generator; modify content in
animated-pricing-cards.mdx to include one sentence after the generator
instructions that provides the registry URL and an example using the component's
category/name format.</details> --- `106-106`: _⚠️ Potential issue_ | _🟡 Minor_ **Motion handling docs are inaccurate for the current implementation.** This line says reduced motion is handled via `useReducedMotion()` hook, but the component currently uses `motion-safe` / `motion-reduce` classes. <details> <summary>Suggested doc patch</summary> ```diff -- **Motion handling**: All animations respect `prefers-reduced-motion` via `useReducedMotion()` hook +- **Motion handling**: Animations respect `prefers-reduced-motion` via `motion-safe` and `motion-reduce` utility classes#!/bin/bash set -e echo "Doc line check:" sed -n '99,110p' content/docs/section/animated-pricing-cards.mdx echo echo "Implementation check:" rg -n 'useReducedMotion|motion-safe|motion-reduce' animata/section/animated-pricing-cards.tsxExpected: docs currently mention
useReducedMotion, while implementation matchesmotion-safe/motion-reduce.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@content/docs/section/animated-pricing-cards.mdx` at line 106, Update the documentation sentence that currently claims reduced-motion is handled via useReducedMotion() to reflect the actual implementation: mention that the component uses Tailwind's motion-safe / motion-reduce utility classes (motion-safe and motion-reduce) to respect prefers-reduced-motion. Replace the reference to useReducedMotion() in the animated-pricing-cards docs and, if helpful, add a brief note that these Tailwind classes wrap the animation CSS rather than a React hook.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@content/docs/section/animated-pricing-cards.mdx`:
- Around line 16-22: The Installation section currently only documents the
generator command `yarn animata:new`; update that section to also show the
direct registry install URL using the shadcn registry format
`https://animata.design/r/{category}/{name}.json` and include the concrete URL
for this component (category "section", name "animated-pricing-cards") so
readers can install directly without the generator; modify content in
animated-pricing-cards.mdx to include one sentence after the generator
instructions that provides the registry URL and an example using the component's
category/name format.
- Line 106: Update the documentation sentence that currently claims
reduced-motion is handled via useReducedMotion() to reflect the actual
implementation: mention that the component uses Tailwind's motion-safe /
motion-reduce utility classes (motion-safe and motion-reduce) to respect
prefers-reduced-motion. Replace the reference to useReducedMotion() in the
animated-pricing-cards docs and, if helpful, add a brief note that these
Tailwind classes wrap the animation CSS rather than a React hook.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4a63fa4c-6c86-404d-a771-3e12ae2e3e10
📒 Files selected for processing (1)
content/docs/section/animated-pricing-cards.mdx
Summary
Introduced a premium Animated Pricing Cards section designed for modern SaaS and AI landing pages. The component focuses on clean layout, subtle motion, and strong visual hierarchy, making it suitable for real-world product integrations as well as demo showcases.
Changes
QA
Notes
This component is designed to be production-ready, reusable, and easy to customize, aligning with Animata’s goal of providing high-quality, copy-paste-friendly UI building blocks.
Summary by CodeRabbit
New Features
Documentation