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
3 changes: 2 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ export default function App() {
return (
<CourseWorkspaceProvider>
<WorkspaceDndProvider>
<div className="m-4 md:m-8 md:max-h-dvh overflow-hidden">
<div className="p-4 md:p-8 md:max-h-dvh overflow-hidden">
<header className="top-0 flex h-20 items-center justify-center bg-carpipink relative z-10">
Comment on lines +15 to 16

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

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

This PR changes the main layout container from margin (m-*) to padding (p-*). That’s a visual/layout change not described in the PR description (“addition of social links”). If it’s required for the social buttons, please document the reason in the PR description; otherwise consider reverting to keep the change scoped.

Copilot uses AI. Check for mistakes.
{/* <SocialTray /> */}

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

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

There is a commented-out <SocialTray /> left in the header. Since this PR adds social links via ButtonTray, this commented code is now misleading—please remove it or wire up the component if it’s intended to ship.

Suggested change
{/* <SocialTray /> */}

Copilot uses AI. Check for mistakes.
<img src="/carpi-black.png" alt="Carpi Logo" className="h-full" />
<ButtonTray />
</header>
Expand Down
17 changes: 10 additions & 7 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,27 @@ interface ButtonProps {
onClick?: () => void;
children: ReactNode;
tooltip: string;
inverted?: boolean; // Optional prop to invert colors
inverted?: boolean;
customStyles?: string;
}

export default function Button({
onClick,
children,
tooltip,
inverted,
customStyles = "",
}: ButtonProps) {
return (
<div className="relative group flex flex-col items-center">
<div className="relative flex flex-col items-center">
<button
onClick={onClick}
className={cn(
"p-3 rounded-full w-fit aspect-square flex items-center justify-center hover:cursor-pointer",
"peer group p-3 rounded-full w-fit aspect-square flex items-center justify-center hover:cursor-pointer",
inverted
? "bg-carpipink/20 text-carpipink hover:text-darkblue hover:bg-carpipink transition-colors"
: "bg-darkblue/20 hover:bg-darkblue hover:text-carpipink transition-colors",
? "bg-carpipink/20 text-carpipink hover:text-darkblue hover:bg-carpipink"
: "bg-[color-mix(in_oklab,var(--color-darkblue)_25%,var(--color-carpipink)_75%)] hover:bg-darkblue hover:text-carpipink",
customStyles,
)}
>
{children}
Expand All @@ -32,13 +35,13 @@ export default function Button({
{/* Tooltip Container */}
<div
className={cn(
"absolute -bottom-7 z-50 hidden group-hover:flex flex-col items-center ",
"absolute -bottom-7 z-50 hidden peer-hover:flex flex-col items-center ",
inverted ? " text-darkblue" : " text-carpipink",
)}
Comment thread
mirmirmirr marked this conversation as resolved.
>
<div
className={cn(
"w-2 h-2 rotate-45",
"w-2 h-2 rotate-45",
inverted ? "bg-carpipink" : "bg-darkblue",
)}
/>
Expand Down
188 changes: 167 additions & 21 deletions src/components/header/ButtonTray.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
BiImport,
BiReset,
BiDotsVerticalRounded,
BiLogoDiscordAlt,
BiLogoGithub,
} from "react-icons/bi";

import Button from "@/components/Button";
Expand Down Expand Up @@ -86,7 +88,20 @@ export default function ButtonTray() {
return true;
};

const buttonList = (
const openExternalLinkAndClose = (url: string) => {
window.open(url, "_blank", "noopener,noreferrer");
setIsOpen(false);
};

const handleDiscordClick = () => {
openExternalLinkAndClose("https://discord.com/invite/xRBvFHgcYT");
};

const handleGithubClick = () => {
openExternalLinkAndClose("https://github.com/Project-CARPI");
};

const mainButtons = (
<>
<Button onClick={handleResetClick} tooltip="Reset Workspace">
<BiReset className="w-5 h-5" />
Expand All @@ -100,6 +115,89 @@ export default function ButtonTray() {
</>
);

const socialButtons = (
<>
<Button
onClick={handleDiscordClick}
tooltip="Join our Discord"
customStyles="hover:bg-[#5865f2] hover:text-[#e0e3ff] hover:p-1.5 p-3 transition-all duration-300"
>
<BiLogoDiscordAlt className="group-hover:w-8 group-hover:h-8 w-5 h-5 transition-all duration-300" />
</Button>

<Button
onClick={handleGithubClick}
tooltip="View on GitHub"
customStyles="hover:bg-[#8534F3] hover:text-[#e0e3ff] hover:p-1.5 p-3 transition-all duration-300"
>
<BiLogoGithub className="group-hover:w-8 group-hover:h-8 w-5 h-5 transition-all duration-300" />
Comment on lines +123 to +133

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

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

These social buttons change padding on hover (hover:p-1.5 vs base p-3), which will change the button’s rendered size and can cause layout shift/jitter in the desktop header as neighboring buttons move. Prefer a size-preserving hover effect (e.g., scale transform on the icon/button, or keep padding constant).

Suggested change
customStyles="hover:bg-[#5865f2] hover:text-[#e0e3ff] hover:p-1.5 p-3 transition-all duration-300"
>
<BiLogoDiscordAlt className="group-hover:w-8 group-hover:h-8 w-5 h-5 transition-all duration-300" />
</Button>
<Button
onClick={handleGithubClick}
tooltip="View on GitHub"
customStyles="hover:bg-[#8534F3] hover:text-[#e0e3ff] hover:p-1.5 p-3 transition-all duration-300"
>
<BiLogoGithub className="group-hover:w-8 group-hover:h-8 w-5 h-5 transition-all duration-300" />
customStyles="hover:bg-[#5865f2] hover:text-[#e0e3ff] p-3 transition-all duration-300"
>
<BiLogoDiscordAlt className="w-5 h-5 transition-transform duration-300 group-hover:scale-125" />
</Button>
<Button
onClick={handleGithubClick}
tooltip="View on GitHub"
customStyles="hover:bg-[#8534F3] hover:text-[#e0e3ff] p-3 transition-all duration-300"
>
<BiLogoGithub className="w-5 h-5 transition-transform duration-300 group-hover:scale-125" />

Copilot uses AI. Check for mistakes.
</Button>
</>
);

const mobileRadialButtons = [
{
id: "export",
component: (
<Button
onClick={handleExportClick}
tooltip="Export Plan"
customStyles="bg-darkblue text-carpipink"
>
<BiExport className="w-5 h-5" />
</Button>
),
},
{
id: "discord",
component: (
<Button
onClick={handleDiscordClick}
tooltip="Join our Discord"
customStyles="bg-[#5865f2] text-[#e0e3ff] p-1.5"
>
<BiLogoDiscordAlt className="w-8 h-8" />
</Button>
),
},
{
id: "import",
component: (
<Button
onClick={handleImportClick}
tooltip="Import Plan"
customStyles="bg-darkblue text-carpipink"
>
<BiImport className="w-5 h-5" />
</Button>
),
},
{
id: "github",
component: (
<Button
onClick={handleGithubClick}
tooltip="View on GitHub"
customStyles="bg-[#8534F3] text-[#e0e3ff] p-1.5"
>
<BiLogoGithub className="w-8 h-8" />
</Button>
),
},
{
id: "reset",
component: (
<Button
onClick={handleResetClick}
tooltip="Reset Workspace"
customStyles="bg-darkblue text-carpipink"
>
<BiReset className="w-5 h-5" />
</Button>
),
},
];

return (
<>
<input
Expand All @@ -110,32 +208,80 @@ export default function ButtonTray() {
className="hidden"
/>

<div className="absolute right-5 top-0 h-full flex items-center z-50">
<div className="hidden md:flex gap-2">{buttonList}</div>
<div className="md:hidden relative flex flex-col items-center justify-center">
<Button onClick={() => setIsOpen(!isOpen)} tooltip="More Options">
<BiDotsVerticalRounded className="w-5 h-5" />
</Button>
<div className="absolute right-4 md:right-0 top-0 h-full flex items-center z-50">
{/* DESKTOP */}
<div className="hidden md:flex gap-2">
{mainButtons}
<div className="w-0.5 bg-darkblue/10 rounded-full my-2 mx-1" />
{socialButtons}
</div>

{/* MOBILE */}
<div className="md:hidden relative flex items-center justify-center">
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0, y: -10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -10, scale: 0.95 }}
transition={{ duration: 0.2 }}
className={cn(
"absolute top-full mt-2 flex flex-col gap-2 p-2 rounded-full shadow-xl z-50",
"bg-carpipink border-darkblue/10 border",
)}
>
{buttonList}
</motion.div>
)}
{isOpen &&
mobileRadialButtons.map((btn, index) => {
// Number of pixels the buttons push outwards
const RADIUS = index % 2 === 0 ? 60 : 105;
const START_ANGLE = 80;
const END_ANGLE = 190;

// Calculate the specific angle for this button
const angleDeg =
START_ANGLE +
index *
((END_ANGLE - START_ANGLE) /
(mobileRadialButtons.length - 1));
const angleRad = angleDeg * (Math.PI / 180);

// Convert angle & radius into X and Y coordinate offsets
const x = RADIUS * Math.cos(angleRad);
const y = RADIUS * Math.sin(angleRad);

return (
<motion.div
key={btn.id}
initial={{ opacity: 0, x: 0, y: 0, scale: 0.5 }}
animate={{ opacity: 1, x, y, scale: 1 }}
exit={{ opacity: 0, x: 0, y: 0, scale: 0.5 }}
transition={{
type: "spring",
stiffness: 260,
damping: 20,
delay: index * 0.04,
}}
className="absolute z-40"
>
{btn.component}
</motion.div>
);
})}
</AnimatePresence>

<motion.div
animate={{
scale: isOpen ? 0.8 : 1,
rotate: isOpen ? 90 : 0,
}}
transition={{ type: "spring", stiffness: 300, damping: 20 }}
className="relative z-50 bg-carpipink rounded-full"
>
<Button
onClick={() => setIsOpen(!isOpen)}
tooltip="More Options"
customStyles={cn(
isOpen
? "bg-darkblue text-carpipink transition-colors duration-300"
: "",
)}
>
<BiDotsVerticalRounded className="w-5 h-5" />
</Button>
</motion.div>
</div>
</div>

{/* RESET DIALOG */}
<Dialog
title="Resetting Workspace"
open={activeDialog === "reset"}
Expand Down
Loading