first commit
Made-with: Cursor
This commit is contained in:
169
frontend/components/public/CommunityLinksSection.tsx
Normal file
169
frontend/components/public/CommunityLinksSection.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
import { type SVGProps } from "react";
|
||||
|
||||
interface PlatformDef {
|
||||
name: string;
|
||||
description: string;
|
||||
settingKey: string;
|
||||
Icon: (props: SVGProps<SVGSVGElement>) => JSX.Element;
|
||||
}
|
||||
|
||||
function IconTelegram(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" {...props}>
|
||||
<path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function IconNostr(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" {...props}>
|
||||
<path d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function IconX(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" {...props}>
|
||||
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function IconYouTube(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" {...props}>
|
||||
<path d="M22.54 6.42a2.78 2.78 0 00-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 00-1.94 2A29 29 0 001 11.75a29 29 0 00.46 5.33 2.78 2.78 0 001.94 2c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 001.94-2 29 29 0 00.46-5.33 29 29 0 00-.46-5.33z" />
|
||||
<path d="M9.75 15.02l5.75-3.27-5.75-3.27v6.54z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function IconDiscord(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" {...props}>
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function IconLinkedIn(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" {...props}>
|
||||
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zM7.119 20.452H3.554V9h3.565v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function IconArrowOut(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" {...props}>
|
||||
<path d="M7 17l9.2-9.2M17 17V7H7" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
const PLATFORMS: PlatformDef[] = [
|
||||
{
|
||||
name: "Telegram",
|
||||
description: "Join the main Belgian chat group for daily discussion and local coordination.",
|
||||
settingKey: "telegram_link",
|
||||
Icon: IconTelegram,
|
||||
},
|
||||
{
|
||||
name: "Nostr",
|
||||
description: "Follow the BBE on the censorship-resistant social protocol for true signal.",
|
||||
settingKey: "nostr_link",
|
||||
Icon: IconNostr,
|
||||
},
|
||||
{
|
||||
name: "X",
|
||||
description: "Stay updated with our latest local announcements and event drops.",
|
||||
settingKey: "x_link",
|
||||
Icon: IconX,
|
||||
},
|
||||
{
|
||||
name: "YouTube",
|
||||
description: "Watch past talks, educational content, and high-quality BBE meetup recordings.",
|
||||
settingKey: "youtube_link",
|
||||
Icon: IconYouTube,
|
||||
},
|
||||
{
|
||||
name: "Discord",
|
||||
description: "Deep dive into technical discussions, node running, and project collaboration.",
|
||||
settingKey: "discord_link",
|
||||
Icon: IconDiscord,
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
description: "Connect with the Belgian Bitcoin professional network and industry leaders.",
|
||||
settingKey: "linkedin_link",
|
||||
Icon: IconLinkedIn,
|
||||
},
|
||||
];
|
||||
|
||||
interface CommunityLinksSectionProps {
|
||||
settings?: Record<string, string>;
|
||||
}
|
||||
|
||||
export function CommunityLinksSection({ settings = {} }: CommunityLinksSectionProps) {
|
||||
return (
|
||||
<section
|
||||
id="community"
|
||||
className="relative py-16 sm:py-20 px-4 sm:px-8"
|
||||
>
|
||||
<div className="max-w-[1100px] mx-auto w-full">
|
||||
<header className="text-center mb-8 sm:mb-10">
|
||||
<h2 className="text-[1.75rem] sm:text-4xl font-extrabold tracking-tight text-white mb-2">
|
||||
Join the <span className="text-[#F7931A]">community</span>
|
||||
</h2>
|
||||
<p className="text-zinc-400 text-sm sm:text-[0.95rem] max-w-[550px] mx-auto leading-relaxed">
|
||||
Connect with local Belgian Bitcoiners, builders, and educators.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-4">
|
||||
{PLATFORMS.map((platform) => {
|
||||
const href = settings[platform.settingKey] || "#";
|
||||
const isExternal = href.startsWith("http");
|
||||
const Icon = platform.Icon;
|
||||
|
||||
return (
|
||||
<a
|
||||
key={platform.name}
|
||||
href={href}
|
||||
target={isExternal ? "_blank" : undefined}
|
||||
rel={isExternal ? "noopener noreferrer" : undefined}
|
||||
className="group relative flex flex-col rounded-xl border border-zinc-800 bg-zinc-900 p-5 no-underline overflow-hidden transition-all duration-300 hover:-translate-y-[3px] hover:border-[rgba(247,147,26,0.4)] hover:shadow-[0_10px_25px_-10px_rgba(0,0,0,0.5)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#F7931A]"
|
||||
>
|
||||
<span
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100 bg-[radial-gradient(circle_at_top_right,rgba(247,147,26,0.08),transparent_60%)]"
|
||||
/>
|
||||
|
||||
<div className="relative z-[1] flex items-center justify-between mb-3">
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-zinc-800 bg-black text-[#F7931A] transition-all duration-300 group-hover:scale-105 group-hover:-rotate-[5deg] group-hover:border-[#F7931A] group-hover:bg-[#F7931A] group-hover:text-black">
|
||||
<Icon className="h-[18px] w-[18px] shrink-0" aria-hidden />
|
||||
</span>
|
||||
<h3 className="text-[1.05rem] font-bold text-white truncate transition-colors duration-300 group-hover:text-[#F7931A]">
|
||||
{platform.name}
|
||||
</h3>
|
||||
</div>
|
||||
<IconArrowOut
|
||||
className="h-[18px] w-[18px] shrink-0 text-zinc-600 transition-all duration-300 group-hover:text-[#F7931A] group-hover:translate-x-[3px] group-hover:-translate-y-[3px]"
|
||||
aria-hidden
|
||||
/>
|
||||
</div>
|
||||
<p className="relative z-[1] text-[0.85rem] leading-relaxed text-zinc-400">
|
||||
{platform.description}
|
||||
</p>
|
||||
</a>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user