Skip to content
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 client/src/module/student/opensource/CoachFloatingButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { motion } from "framer-motion";
import { Sparkles } from "lucide-react";
import { useCoachStore } from "./stores/coach.store";

/**
* Floating button visible on all open-source section pages.
* Clicking it toggles the coach panel open/closed.
*/
export default function CoachFloatingButton() {
const { toggle, isOpen } = useCoachStore();

if (isOpen) return null;

return (
<motion.button
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: 0.5, type: "spring", stiffness: 300, damping: 20 }}
onClick={toggle}
title="Open Contribution Coach"
className="fixed bottom-6 right-6 z-30 w-12 h-12 rounded-xl bg-lime-400 text-stone-950 shadow-lg shadow-lime-500/25 hover:bg-lime-300 hover:shadow-xl hover:shadow-lime-500/30 transition-all flex items-center justify-center border-0 cursor-pointer group"
>
<Sparkles className="w-5 h-5 group-hover:scale-110 transition-transform" />
</motion.button>
);
Comment on lines +15 to +25
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use the shared Button component for the floating action button.

All new buttons should use the reusable Button component from client/src/components/ui/button.tsx with appropriate variants, modes, and sizes. The Button component supports composition with Framer Motion via the asChild prop (Radix Slot pattern).

♻️ Refactor to use Button component
+import { Button } from "../../../components/ui/button";
+import { Slot } from "`@radix-ui/react-slot`";

 export default function CoachFloatingButton() {
   const { toggle, isOpen } = useCoachStore();

   if (isOpen) return null;

   return (
-    <motion.button
-      initial={{ scale: 0, opacity: 0 }}
-      animate={{ scale: 1, opacity: 1 }}
-      transition={{ delay: 0.5, type: "spring", stiffness: 300, damping: 20 }}
-      onClick={toggle}
-      title="Open Contribution Coach"
-      className="fixed bottom-6 right-6 z-30 w-12 h-12 rounded-xl bg-lime-400 text-stone-950 shadow-lg shadow-lime-500/25 hover:bg-lime-300 hover:shadow-xl hover:shadow-lime-500/30 transition-all flex items-center justify-center border-0 cursor-pointer group"
-    >
-      <Sparkles className="w-5 h-5 group-hover:scale-110 transition-transform" />
-    </motion.button>
+    <Button
+      variant="primary"
+      mode="icon"
+      size="md"
+      onClick={toggle}
+      title="Open Contribution Coach"
+      className="fixed bottom-6 right-6 z-30 group"
+      asChild
+    >
+      <motion.button
+        initial={{ scale: 0, opacity: 0 }}
+        animate={{ scale: 1, opacity: 1 }}
+        transition={{ delay: 0.5, type: "spring", stiffness: 300, damping: 20 }}
+      >
+        <Sparkles className="w-5 h-5 group-hover:scale-110 transition-transform" />
+      </motion.button>
+    </Button>
   );
 }

As per coding guidelines: Use the reusable Button component from client/src/components/ui/button.tsx for all new buttons; supports variants (primary, secondary, mono, ghost, danger), modes (button, icon, link), and sizes (sm, md, lg). Use asChild prop (Radix Slot) when composing Button with other elements.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/src/module/student/opensource/CoachFloatingButton.tsx` around lines 15
- 25, Replace the direct Framer Motion button with the shared Button component:
wrap the existing motion.button usage by using Button (import from
client/src/components/ui/button.tsx) with asChild so Framer Motion can be
composed, keep the same motion props (initial, animate, transition) on the
motion.button element, forward onClick to toggle, preserve title,
className/styling and the Sparkles icon as children, and use the appropriate
variant/mode/size props (e.g., variant="primary" or mode="icon" and size="md")
to match design; update imports to include Button and ensure motion.button
remains the animated element nested via asChild.

}
Loading
Loading