Initial commit

This commit is contained in:
unknown
2026-05-18 22:26:10 +02:00
commit db92ad2f88
34 changed files with 2158 additions and 0 deletions

View File

@@ -0,0 +1,258 @@
import { useEffect, useRef, useState } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import {
MessageSquare,
ExternalLink,
Copy,
Check,
Key,
type LucideIcon,
} from "lucide-react";
import { useReducedMotion } from "../hooks/useReducedMotion";
gsap.registerPlugin(ScrollTrigger);
interface ContactItem {
label: string;
value: string;
href?: string;
isLink?: boolean;
unavailable?: boolean;
icon?: LucideIcon;
}
interface ContactGroup {
category: string;
items: ContactItem[];
}
const contacts: ContactGroup[] = [
{
category: "Messaging",
items: [
{
label: "Simplex",
value: "Open chat",
href: "https://simplex.chat/contact#/?v=2-7&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2F3_XOiEnk2Ebup7DqgOwGM5kXlIZX-uJo%23%2F%3Fv%3D1-4%26dh%3DMCowBQYDK2VuAyEAPJz5X-WHhJk_y1MLRxy7NTfspD-vKF0pmmi_GAJpExY%253D%26q%3Dc%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion",
isLink: true,
},
{
label: "Discord",
value:
"@sysrand [1408202642588438589] / @forgecadrape [1452113626365169958]",
},
{ label: "Telegram", value: "@forgecadrape (main) / @xorededx" },
{ label: "XMPP", value: "sw@anoxinon.me (main) / me0w@xmpp.jp" },
{
label: "Session",
value:
"056834db96cedde6012da9d5402c683c0eb260ed866da145a8f86e7f329bf77222",
},
{
label: "Tox",
value:
"5622A2D2218AF235E39E356792270413BBE7CAEEAA531A20EEF11BF2FD10576E5050F0A55970",
},
{ label: "Potato Chat", value: "@depoliticized" },
{
label: "Element",
value: "Open profile",
href: "https://matrix.to/#/@depoliticized:tchncs.de",
isLink: true,
},
{ label: "Briar", value: "temporary unavailable", unavailable: true },
],
},
{
category: "Email",
items: [
{
label: "Primary",
value: "contact@stealer.wtf (temporary unavailable)",
unavailable: true,
},
],
},
{
category: "Git",
items: [
{
label: "serpent256",
value: "View profile",
href: "https://git.fingeri.ng/serpent256",
isLink: true,
},
{
label: "raped.cc",
value: "View profile (main)",
href: "https://git.fingeri.ng/raped.cc",
isLink: true,
},
{
label: "whiskers",
value: "View org",
href: "https://git.fingeri.ng/whiskers",
isLink: true,
},
],
},
{
category: "PGP",
items: [
{
label: "Public Key",
value: "Download /pub-pgp.txt",
href: "./pub-pgp.txt",
isLink: true,
icon: Key,
},
],
},
];
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
// Fallback
}
};
return (
<button
onClick={handleCopy}
className="p-1.5 rounded-md text-grey-400 hover:text-pink-brand hover:bg-pink-brand/10 transition-all"
aria-label="Copy to clipboard"
>
{copied ? (
<Check className="w-3.5 h-3.5" />
) : (
<Copy className="w-3.5 h-3.5" />
)}
</button>
);
}
export default function ContactSection() {
const sectionRef = useRef<HTMLElement>(null);
const reducedMotion = useReducedMotion();
useEffect(() => {
if (reducedMotion || !sectionRef.current) return;
const ctx = gsap.context(() => {
gsap.fromTo(
".contact-reveal",
{ y: 40, opacity: 0 },
{
y: 0,
opacity: 1,
duration: 0.8,
stagger: 0.1,
ease: "expo.out",
scrollTrigger: {
trigger: sectionRef.current,
start: "top 70%",
toggleActions: "play none none none",
},
},
);
}, sectionRef);
return () => ctx.revert();
}, [reducedMotion]);
return (
<section
id="contact"
ref={sectionRef}
className="relative py-32 md:py-40 px-6 overflow-hidden"
>
{!reducedMotion && (
<div className="absolute bottom-0 left-1/2 w-[800px] h-[400px] -translate-x-1/2 translate-y-1/2 rounded-full bg-pink-brand/3 blur-[120px] pointer-events-none" />
)}
<div className="max-w-6xl mx-auto relative z-10">
{/* Section label */}
<div className="contact-reveal flex items-center gap-4 mb-16">
<span className="text-pink-brand font-mono text-xs tracking-[0.3em] uppercase">
006
</span>
<div className="flex-1 h-px bg-pink-brand/20" />
<span className="text-grey-500 font-display text-xs tracking-[0.2em] uppercase">
Contact
</span>
</div>
{/* Header */}
<div className="contact-reveal mb-16">
<h2 className="font-display text-4xl md:text-6xl lg:text-7xl font-light text-grey-900 mb-4">
Get in <span className="text-gradient">touch</span>
</h2>
<p className="text-grey-500 text-lg font-body max-w-xl">
Reach out through any of these channels. I prefer encrypted
messaging when possible.
</p>
</div>
{/* Contact grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{contacts.map((group) => (
<div key={group.category} className="contact-reveal">
<div className="flex items-center gap-2 mb-4">
<MessageSquare className="w-4 h-4 text-pink-brand" />
<h3 className="font-display text-sm font-medium text-grey-900 uppercase tracking-widest">
{group.category}
</h3>
</div>
<div className="space-y-3">
{group.items.map((item) => (
<div
key={item.label + item.value}
className="group flex items-center justify-between p-4 rounded-xl bg-skin-100/40 border border-pink-brand/5 hover:border-pink-brand/15 hover:bg-skin-100/70 transition-all duration-300"
>
<div className="flex-1 min-w-0">
<span className="text-xs font-mono text-grey-400 block mb-0.5">
{item.label}
</span>
{item.isLink && item.href ? (
<a
href={item.href}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 text-sm text-grey-700 hover:text-pink-brand transition-colors font-body"
>
{item.icon && <item.icon className="w-3.5 h-3.5" />}
{item.value}
<ExternalLink className="w-3 h-3" />
</a>
) : item.unavailable ? (
<span className="text-sm italic text-red-400 font-body">
{item.value}
</span>
) : (
<span className="text-sm text-grey-700 font-body break-all">
{item.value}
</span>
)}
</div>
{!item.isLink && !item.unavailable && (
<CopyButton text={item.value} />
)}
</div>
))}
</div>
</div>
))}
</div>
</div>
</section>
);
}