feat: rework entire project structure

This commit is contained in:
2026-03-23 00:04:04 +01:00
parent 6282951b88
commit 8185757933
26 changed files with 1414 additions and 86 deletions

View File

@@ -0,0 +1,38 @@
import { ReactNode } from "react";
type ButtonProps = {
children: ReactNode;
onClick?: () => void;
label: string;
variant?: "icon" | "text";
className?: string;
};
export default function Button({ children, onClick, label, variant = "icon", className = "" }: ButtonProps) {
const BASECLASS = "cursor-pointer flex items-center justify-center backdrop-blur-sm \
bg-black/17 shadow-md text-white transition-all duration-200 ease-out \
hover:bg-white/15 active:scale-95 shadow-lg shadow-black/50 \
pointer-events-auto hover:shadow-black/0";
// dictionary to choose if it's a icon or text button
const variants: Record<typeof variant, string> = {
icon: "rounded-full w-12 h-12 md:w-14 md:h-14 hover:scale-110",
text: "rounded-3xl px-4 h-12 md:h-14 md:px-6 max-w-max hover:scale-105",
};
return (
<div className="relative group">
<button onClick={onClick} aria-label={label} className={`${BASECLASS} ${variants[variant]}`}>
{children}
</button>
{label && (
<span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1
rounded-md text-xs text-white bg-black/80 opacity-0
group-hover:opacity-100 transition-opacity whitespace-nowrap">
{label}
</span>
)}
</div>
);
}

View File

@@ -0,0 +1,22 @@
import Button from '@app/components/ui/Button';
import i18n from "@app/lib/i18n";
export default function Lang() {
const toggleLanguage = () => {
const newLang = i18n.language === "fr" ? "en" : "fr";
i18n.changeLanguage(newLang);
};
const nextLangLabel = i18n.language === "fr" ? "EN" : "FR";
return (
<Button
onClick={toggleLanguage}
label={`Lang: ${nextLangLabel}`}
variant="icon"
>
{nextLangLabel}
</Button>
)
}

View File

@@ -0,0 +1,43 @@
import React, { ReactNode, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
interface SectionProps {
open: boolean;
onClose: () => void;
children: ReactNode;
}
export default function Window ({ open, onClose, children }: SectionProps) {
useEffect(() => {
if (open) document.body.style.overflow = "hidden";
else document.body.style.overflow = "";
}, [open]);
return (
<AnimatePresence>
{open && (
<motion.div
className="fixed inset-0 z-10 bg-black/30 backdrop-blur-sm"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{
duration: 0.3
}}
>
<div className="h-full overflow-y-auto text-white">
<motion.div
initial={{ opacity: 0, y: 40 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 40 }}
transition={{ duration: 0.3 }}
className="flex flex-col md:flex-row items-center justify-center gap-10 px-6 md:px-24 py-20 md:py-32"
>
{children}
</motion.div>
</div>
</motion.div>
)}
</AnimatePresence>
);
};