feat: ajout sitemap, api et components

This commit is contained in:
2025-11-25 05:43:26 +01:00
parent da613c822a
commit 5a7cf45d98
29 changed files with 3339 additions and 34 deletions
+58
View File
@@ -0,0 +1,58 @@
"use client";
import { ReactNode } from "react";
interface GlowButtonProps {
href: string;
children: ReactNode;
variant?: "primary" | "secondary";
}
export default function GlowButton({
href,
children,
variant = "primary",
}: GlowButtonProps) {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
const targetId = href.replace("#", "");
const element = document.getElementById(targetId);
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "start",
});
}
};
if (variant === "primary") {
return (
<a
href={href}
onClick={handleClick}
className="relative inline-block px-8 py-3 bg-black text-white font-semibold rounded-lg border-2 border-purple-500 hover:border-purple-400 transition-all duration-300 hover:shadow-[0_0_20px_10px_rgba(168,85,247,0.6)] active:scale-95 active:shadow-[0_0_10px_5px_rgba(168,85,247,0.4)] group cursor-pointer"
>
<span className="flex items-center justify-center space-x-2 relative z-10">
<span>{children}</span>
</span>
<span className="absolute inset-0 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity duration-300 bg-linear-to-r from-purple-500/20 to-indigo-500/20"></span>
</a>
);
}
// Variante secondaire (bleu)
return (
<a
href={href}
onClick={handleClick}
className="relative inline-block px-8 py-3 bg-black text-white font-semibold rounded-lg border-2 border-blue-500 hover:border-blue-400 transition-all duration-300 hover:shadow-[0_0_20px_10px_rgba(59,130,246,0.6)] active:scale-95 active:shadow-[0_0_10px_5px_rgba(59,130,246,0.4)] group cursor-pointer"
>
<span className="flex items-center justify-center space-x-2 relative z-10">
<span>{children}</span>
</span>
<span className="absolute inset-0 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity duration-300 bg-linear-to-r from-blue-500/20 to-cyan-500/20"></span>
</a>
);
}
+35
View File
@@ -0,0 +1,35 @@
"use client";
import { motion, useScroll, useTransform } from "framer-motion";
interface GridBackgroundProps {
variant?: "dark" | "light";
}
export default function GridBackground({
variant = "light",
}: GridBackgroundProps) {
const { scrollY } = useScroll();
const opacity = useTransform(scrollY, [0, 400, 800], [1, 0.4, 0.2]);
const y = useTransform(scrollY, [0, 1000], [0, 100]);
return (
<motion.div
className="fixed inset-0 pointer-events-none z-0"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1 }}
style={{
opacity,
y,
backgroundImage:
variant === "dark"
? "linear-gradient(to right, #1e293b 1px, transparent 1px), linear-gradient(to bottom, #1e293b 1px, transparent 1px)"
: "linear-gradient(to right, #e2e8f0 1px, transparent 1px), linear-gradient(to bottom, #e2e8f0 1px, transparent 1px)",
backgroundSize: "100px 100px",
}}
/>
);
}
+41
View File
@@ -0,0 +1,41 @@
"use client";
import { ReactNode } from "react";
interface SmoothLinkProps {
href: string;
children: ReactNode;
className?: string;
onClick?: () => void;
}
export default function SmoothLink({
href,
children,
className,
onClick,
}: SmoothLinkProps) {
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
e.preventDefault();
const targetId = href.replace("#", "");
const element = document.getElementById(targetId);
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "start",
});
}
if (onClick) {
onClick();
}
};
return (
<a href={href} onClick={handleClick} className={className}>
{children}
</a>
);
}