2025-08-20 14:14:33 +02:00
|
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
|
|
import { Player } from "@lordicon/react";
|
|
|
|
|
|
import { motion } from "framer-motion";
|
|
|
|
|
|
import { ArrowLeft } from "lucide-react";
|
|
|
|
|
|
import { useRouter } from "next/navigation";
|
2025-08-20 16:41:27 +02:00
|
|
|
|
import {
|
|
|
|
|
|
ForwardedRef,
|
|
|
|
|
|
forwardRef,
|
|
|
|
|
|
useEffect,
|
|
|
|
|
|
useRef,
|
|
|
|
|
|
useState,
|
|
|
|
|
|
} from "react";
|
2025-08-20 14:14:33 +02:00
|
|
|
|
|
|
|
|
|
|
// URLs d’icônes Lordicon
|
|
|
|
|
|
const icons = {
|
|
|
|
|
|
simplicity: "https://cdn.lordicon.com/tsrgicte.json", // simplicité
|
|
|
|
|
|
shield: "https://cdn.lordicon.com/sjoccsdj.json", // sécurité
|
|
|
|
|
|
community: "https://cdn.lordicon.com/ubpgwkmy.json", // communauté / open source
|
|
|
|
|
|
github: "https://cdn.lordicon.com/jjxzcivr.json", // GitHub
|
|
|
|
|
|
discord: "https://cdn.lordicon.com/zvnxzuwv.json", // Discord
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Wrapper pour Lordicon
|
|
|
|
|
|
const LordIcon = forwardRef(function LordIcon(
|
2025-08-20 16:41:27 +02:00
|
|
|
|
{
|
|
|
|
|
|
url,
|
|
|
|
|
|
size = 30,
|
|
|
|
|
|
colorize = "#3b82f6",
|
|
|
|
|
|
}: { url: string; size?: number; colorize?: string },
|
|
|
|
|
|
ref: ForwardedRef<Player>
|
2025-08-20 14:14:33 +02:00
|
|
|
|
) {
|
2025-08-20 16:41:27 +02:00
|
|
|
|
const [iconData, setIconData] = useState<Record<string, unknown> | null>(null);
|
2025-08-20 14:14:33 +02:00
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2025-08-20 16:41:27 +02:00
|
|
|
|
fetch(url)
|
|
|
|
|
|
.then((res) => res.json())
|
|
|
|
|
|
.then(setIconData)
|
|
|
|
|
|
.catch(() => setIconData(null));
|
2025-08-20 14:14:33 +02:00
|
|
|
|
}, [url]);
|
|
|
|
|
|
|
|
|
|
|
|
if (!iconData) return null;
|
|
|
|
|
|
return <Player ref={ref} icon={iconData} size={size} colorize={colorize} />;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Carte Feature
|
|
|
|
|
|
function FeatureCard({
|
|
|
|
|
|
title,
|
|
|
|
|
|
desc,
|
|
|
|
|
|
icon,
|
|
|
|
|
|
}: {
|
|
|
|
|
|
title: string;
|
|
|
|
|
|
desc: string;
|
|
|
|
|
|
icon: string;
|
|
|
|
|
|
}) {
|
2025-08-20 16:41:27 +02:00
|
|
|
|
const iconRef = useRef<Player>(null);
|
2025-08-20 14:14:33 +02:00
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
whileHover={{ scale: 1.03 }}
|
|
|
|
|
|
className="rounded-2xl bg-[#11131c] border border-white/10 p-6 shadow-lg hover:border-blue-500/40 transition-colors"
|
|
|
|
|
|
onMouseEnter={() => iconRef.current?.playFromBeginning()}
|
|
|
|
|
|
onMouseLeave={() => iconRef.current?.goToFirstFrame()}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="flex items-center gap-3 mb-3">
|
|
|
|
|
|
<div className="p-2 rounded-xl bg-blue-500/20 text-blue-400">
|
|
|
|
|
|
<LordIcon ref={iconRef} url={icon} size={32} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h3 className="text-lg font-semibold">{title}</h3>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p className="text-neutral-400 text-sm leading-relaxed">{desc}</p>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Bouton Contact
|
|
|
|
|
|
function ContactButton({
|
|
|
|
|
|
href,
|
|
|
|
|
|
icon,
|
|
|
|
|
|
text,
|
|
|
|
|
|
gradient,
|
|
|
|
|
|
shadow,
|
|
|
|
|
|
color = "#fff",
|
|
|
|
|
|
}: {
|
|
|
|
|
|
href: string;
|
|
|
|
|
|
icon: string;
|
|
|
|
|
|
text: string;
|
|
|
|
|
|
gradient: string;
|
|
|
|
|
|
shadow: string;
|
|
|
|
|
|
color?: string;
|
|
|
|
|
|
}) {
|
2025-08-20 16:41:27 +02:00
|
|
|
|
const iconRef = useRef<Player>(null);
|
2025-08-20 14:14:33 +02:00
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<motion.a
|
|
|
|
|
|
whileHover={{ scale: 1.05 }}
|
|
|
|
|
|
whileTap={{ scale: 0.97 }}
|
|
|
|
|
|
href={href}
|
|
|
|
|
|
target="_blank"
|
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
|
className={`cursor-pointer inline-flex items-center gap-2 px-6 py-3 rounded-xl text-base font-medium text-white ${gradient} ${shadow} transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-blue-400/60`}
|
|
|
|
|
|
onMouseEnter={() => iconRef.current?.playFromBeginning()}
|
|
|
|
|
|
onMouseLeave={() => iconRef.current?.goToFirstFrame()}
|
|
|
|
|
|
>
|
|
|
|
|
|
<LordIcon ref={iconRef} url={icon} size={32} colorize={color} />
|
|
|
|
|
|
<span>{text}</span>
|
|
|
|
|
|
</motion.a>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default function AboutPage() {
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
|
|
const features = [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: "Simplicity",
|
|
|
|
|
|
desc: "Create a paste in seconds, distraction-free.",
|
|
|
|
|
|
icon: icons.simplicity,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: "Security",
|
|
|
|
|
|
desc: "Protect your posts with a password or limited number of views.",
|
|
|
|
|
|
icon: icons.shield,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: "Open Source",
|
|
|
|
|
|
desc: "Contribute to the project and improve the platform.",
|
|
|
|
|
|
icon: icons.community,
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="p-8 relative min-h-screen bg-[#0e0f13] text-white">
|
|
|
|
|
|
{/* Navbar */}
|
|
|
|
|
|
<div className="flex justify-between items-center mb-12 max-w-6xl mx-auto">
|
|
|
|
|
|
<motion.button
|
|
|
|
|
|
whileHover={{ scale: 1.05 }}
|
|
|
|
|
|
whileTap={{ scale: 0.97 }}
|
|
|
|
|
|
onClick={() => router.back()}
|
|
|
|
|
|
className="cursor-pointer inline-flex items-center gap-2 px-5 py-2 rounded-xl text-sm font-medium
|
|
|
|
|
|
text-white bg-gradient-to-r from-blue-600 to-blue-500 shadow-lg shadow-blue-500/30
|
|
|
|
|
|
hover:shadow-blue-500/50 transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-blue-400/60"
|
|
|
|
|
|
>
|
|
|
|
|
|
<ArrowLeft size={18} className="text-blue-200" />
|
|
|
|
|
|
Back
|
|
|
|
|
|
</motion.button>
|
|
|
|
|
|
|
|
|
|
|
|
<h1 className="text-lg font-bold text-neutral-300">AltBin</h1>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Features */}
|
|
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-6 max-w-6xl mx-auto">
|
|
|
|
|
|
{features.map((f, i) => (
|
|
|
|
|
|
<FeatureCard key={i} title={f.title} desc={f.desc} icon={f.icon} />
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Contact */}
|
|
|
|
|
|
<div className="mt-20 max-w-2xl mx-auto text-center">
|
|
|
|
|
|
<h2 className="text-xl md:text-2xl font-bold mb-4">Contact</h2>
|
|
|
|
|
|
<p className="text-neutral-400 mb-8">
|
|
|
|
|
|
Any <span className="text-blue-400">questions</span> or{" "}
|
|
|
|
|
|
<span className="text-blue-400">suggestions</span>?
|
|
|
|
|
|
Join the community or check out the source code
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex justify-center gap-4 flex-wrap">
|
|
|
|
|
|
<ContactButton
|
|
|
|
|
|
href="https://discord.gg/ton-serveur"
|
|
|
|
|
|
icon={icons.discord}
|
|
|
|
|
|
text="Join Discord"
|
|
|
|
|
|
gradient="bg-gradient-to-r from-indigo-600 to-indigo-500"
|
|
|
|
|
|
shadow="shadow-lg shadow-indigo-500/30 hover:shadow-indigo-500/50"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<ContactButton
|
|
|
|
|
|
href="https://github.com/UltraLionfr/altbin.dev"
|
|
|
|
|
|
icon={icons.github}
|
|
|
|
|
|
text="GitHub"
|
|
|
|
|
|
gradient="bg-gradient-to-r from-gray-800 to-gray-700"
|
|
|
|
|
|
shadow="shadow-lg shadow-black/30 hover:shadow-blue-500/40"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|