reactbits-mcp-server
Version:
MCP Server for React Bits - Access 99+ React components with animations, backgrounds, and UI elements
171 lines (156 loc) • 5.57 kB
JSX
import { useState } from "react";
const darkenColor = (hex, percent) => {
let color = hex.startsWith("#") ? hex.slice(1) : hex;
if (color.length === 3) {
color = color
.split("")
.map((c) => c + c)
.join("");
}
const num = parseInt(color, 16);
let r = (num >> 16) & 0xff;
let g = (num >> 8) & 0xff;
let b = num & 0xff;
r = Math.max(0, Math.min(255, Math.floor(r * (1 - percent))));
g = Math.max(0, Math.min(255, Math.floor(g * (1 - percent))));
b = Math.max(0, Math.min(255, Math.floor(b * (1 - percent))));
return (
"#" +
((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()
);
};
const Folder = ({
color = "#5227FF",
size = 1,
items = [],
className = "",
}) => {
const maxItems = 3;
const papers = items.slice(0, maxItems);
while (papers.length < maxItems) {
papers.push(null);
}
const [open, setOpen] = useState(false);
const [paperOffsets, setPaperOffsets] = useState(
Array.from({ length: maxItems }, () => ({ x: 0, y: 0 }))
);
const folderBackColor = darkenColor(color, 0.08);
const paper1 = darkenColor("#ffffff", 0.1);
const paper2 = darkenColor("#ffffff", 0.05);
const paper3 = "#ffffff";
const handleClick = () => {
setOpen((prev) => !prev);
if (open) {
setPaperOffsets(Array.from({ length: maxItems }, () => ({ x: 0, y: 0 })));
}
};
const handlePaperMouseMove = (
e,
index
) => {
if (!open) return;
const rect = e.currentTarget.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const offsetX = (e.clientX - centerX) * 0.15;
const offsetY = (e.clientY - centerY) * 0.15;
setPaperOffsets((prev) => {
const newOffsets = [...prev];
newOffsets[index] = { x: offsetX, y: offsetY };
return newOffsets;
});
};
const handlePaperMouseLeave = (
e,
index
) => {
setPaperOffsets((prev) => {
const newOffsets = [...prev];
newOffsets[index] = { x: 0, y: 0 };
return newOffsets;
});
};
const folderStyle = {
"--folder-color": color,
"--folder-back-color": folderBackColor,
"--paper-1": paper1,
"--paper-2": paper2,
"--paper-3": paper3,
};
const scaleStyle = { transform: `scale(${size})` };
const getOpenTransform = (index) => {
if (index === 0) return "translate(-120%, -70%) rotate(-15deg)";
if (index === 1) return "translate(10%, -70%) rotate(15deg)";
if (index === 2) return "translate(-50%, -100%) rotate(5deg)";
return "";
};
return (
<div style={scaleStyle} className={className}>
<div
className={`group relative transition-all duration-200 ease-in cursor-pointer ${!open ? "hover:-translate-y-2" : ""
}`}
style={{
...folderStyle,
transform: open ? "translateY(-8px)" : undefined,
}}
onClick={handleClick}
>
<div
className="relative w-[100px] h-[80px] rounded-tl-0 rounded-tr-[10px] rounded-br-[10px] rounded-bl-[10px]"
style={{ backgroundColor: folderBackColor }}
>
<span
className="absolute z-0 bottom-[98%] left-0 w-[30px] h-[10px] rounded-tl-[5px] rounded-tr-[5px] rounded-bl-0 rounded-br-0"
style={{ backgroundColor: folderBackColor }}
></span>
{papers.map((item, i) => {
let sizeClasses = "";
if (i === 0) sizeClasses = open ? "w-[70%] h-[80%]" : "w-[70%] h-[80%]";
if (i === 1) sizeClasses = open ? "w-[80%] h-[80%]" : "w-[80%] h-[70%]";
if (i === 2) sizeClasses = open ? "w-[90%] h-[80%]" : "w-[90%] h-[60%]";
const transformStyle = open
? `${getOpenTransform(i)} translate(${paperOffsets[i].x}px, ${paperOffsets[i].y}px)`
: undefined;
return (
<div
key={i}
onMouseMove={(e) => handlePaperMouseMove(e, i)}
onMouseLeave={(e) => handlePaperMouseLeave(e, i)}
className={`absolute z-20 bottom-[10%] left-1/2 transition-all duration-300 ease-in-out ${!open
? "transform -translate-x-1/2 translate-y-[10%] group-hover:translate-y-0"
: "hover:scale-110"
} ${sizeClasses}`}
style={{
...(!open ? {} : { transform: transformStyle }),
backgroundColor: i === 0 ? paper1 : i === 1 ? paper2 : paper3,
borderRadius: "10px",
}}
>
{item}
</div>
);
})}
<div
className={`absolute z-30 w-full h-full origin-bottom transition-all duration-300 ease-in-out ${!open ? "group-hover:[transform:skew(15deg)_scaleY(0.6)]" : ""
}`}
style={{
backgroundColor: color,
borderRadius: "5px 10px 10px 10px",
...(open && { transform: "skew(15deg) scaleY(0.6)" }),
}}
></div>
<div
className={`absolute z-30 w-full h-full origin-bottom transition-all duration-300 ease-in-out ${!open ? "group-hover:[transform:skew(-15deg)_scaleY(0.6)]" : ""
}`}
style={{
backgroundColor: color,
borderRadius: "5px 10px 10px 10px",
...(open && { transform: "skew(-15deg) scaleY(0.6)" }),
}}
></div>
</div>
</div>
</div>
);
};
export default Folder;