Skip to content

Commit 83d9c33

Browse files
committed
feat: transmissions
1 parent 083086f commit 83d9c33

File tree

6 files changed

+467
-16
lines changed

6 files changed

+467
-16
lines changed

public/about-me/transmissions.piml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
(friends)
2+
> (person)
3+
(title) Celil Yiğit
4+
(url) https://celilygt.com
5+
(description)
6+
He is a backend engineer specializing in high-performance computing and
7+
machine learning with a passion for technical writing and interactive projects.
8+
9+
> (person)
10+
(title) Mervan Savğa
11+
(url) https://mervansavga.com/
12+
(description)
13+
He is a results-driven Software Engineer with a strong foundation
14+
in computer science, also a photographer and visual artist.
15+
16+
(books)
17+
> (book)
18+
(title) Clean Code: A Handbook of Agile Software Craftsmanship
19+
(author) Robert C. Martin
20+
(description)
21+
A fundamental guide that teaches developers how to write better, more readable code by applying principles, patterns, and
22+
practices of craftsmanship to transform "bad" code into maintainable, professional software.
23+
24+
> (book)
25+
(title) Clean Architecture: A Craftsman's Guide to Software Structure and Design
26+
(author) Robert C. Martin
27+
(description)
28+
An essential exploration of software design principles that focuses on creating systems with clear boundaries, ensuring that core
29+
business logic remains independent of frameworks, databases, and UI for maximum flexibility and testability.

src/components/AnimatedRoutes.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const BlogPostPage = lazy(() => import('../pages/BlogPostPage'));
1010
const ProjectsPage = lazy(() => import('../pages/ProjectsPage'));
1111
const ProjectPage = lazy(() => import('../pages/ProjectPage'));
1212
const AboutPage = lazy(() => import('../pages/AboutPage'));
13+
const FriendsPage = lazy(() => import('../pages/FriendsPage'));
1314
const LogsPage = lazy(() => import('../pages/LogsPage'));
1415
const LogDetailPage = lazy(() => import('../pages/LogDetailPage'));
1516
const NotFoundPage = lazy(() => import('../pages/NotFoundPage'));
@@ -332,6 +333,22 @@ const AnimatedRoutes = ({
332333
</motion.div>
333334
}
334335
/>
336+
<Route
337+
path="/about/friends"
338+
element={
339+
<motion.div
340+
initial="initial"
341+
animate="in"
342+
exit="out"
343+
variants={pageVariants}
344+
transition={pageTransition}
345+
>
346+
<Suspense fallback={<Loading />}>
347+
<FriendsPage />
348+
</Suspense>
349+
</motion.div>
350+
}
351+
/>
335352
<Route
336353
path="/settings" // New route for SettingsPage
337354
element={

src/components/BrutalistModal.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import React from 'react';
2+
import { motion, AnimatePresence } from 'framer-motion';
3+
import { XIcon, ArrowSquareOutIcon } from '@phosphor-icons/react';
4+
import GenerativeArt from './GenerativeArt';
5+
6+
const BrutalistModal = ({
7+
isOpen,
8+
onClose,
9+
item,
10+
}) => {
11+
if (!item) return null;
12+
13+
const title = item.label || item.title;
14+
const description = item.description;
15+
const url = item.url;
16+
17+
return (
18+
<AnimatePresence>
19+
{isOpen && (
20+
<div className="fixed inset-0 z-[100] flex items-center justify-center p-4 md:p-12">
21+
{/* Backdrop */}
22+
<motion.div
23+
initial={{ opacity: 0 }}
24+
animate={{ opacity: 1 }}
25+
exit={{ opacity: 0 }}
26+
onClick={onClose}
27+
className="absolute inset-0 bg-black/90 backdrop-blur-xl"
28+
/>
29+
30+
{/* Modal Container */}
31+
<motion.div
32+
initial={{ opacity: 0, scale: 0.95, y: 40 }}
33+
animate={{ opacity: 1, scale: 1, y: 0 }}
34+
exit={{ opacity: 0, scale: 0.95, y: 40 }}
35+
className="relative w-full max-w-4xl bg-[#050505] border border-white/20 rounded-sm shadow-2xl overflow-hidden flex flex-col md:flex-row h-full md:h-auto max-h-[90vh]"
36+
onClick={(e) => e.stopPropagation()}
37+
>
38+
{/* Left/Top side: Large Art */}
39+
<div className="relative w-full md:w-1/2 h-64 md:h-auto border-b md:border-b-0 md:border-r border-white/20">
40+
<GenerativeArt seed={"2"+title+"[]"} className="w-full h-full" />
41+
<div className="absolute inset-0 bg-gradient-to-t md:bg-gradient-to-r from-[#050505] to-transparent opacity-60" />
42+
</div>
43+
44+
{/* Right side: Content */}
45+
<div className="flex-1 flex flex-col p-8 md:p-12 relative">
46+
{/* Decorative background logo */}
47+
<div className="absolute top-0 right-0 p-12 opacity-[0.02] pointer-events-none select-none">
48+
<h1 className="text-9xl font-black font-playfairDisplay leading-none">FC</h1>
49+
</div>
50+
51+
<div className="flex justify-between items-start mb-12">
52+
<div className="space-y-1">
53+
<div className="h-1 w-12 bg-emerald-500 mb-4" />
54+
<h2 className="text-4xl md:text-5xl font-normal font-playfairDisplay tracking-tighter text-white uppercase leading-none">
55+
{title}
56+
</h2>
57+
</div>
58+
<button
59+
onClick={onClose}
60+
className="p-2 text-gray-500 hover:text-white transition-colors"
61+
>
62+
<XIcon weight="bold" size={32} />
63+
</button>
64+
</div>
65+
66+
<div className="flex-grow space-y-8">
67+
<p className="text-xl md:text-2xl text-gray-300 font-arvo leading-relaxed">
68+
{description}
69+
</p>
70+
{item.author && (
71+
<div className="pt-4 flex items-center gap-3">
72+
<div className="w-8 h-px bg-white/20" />
73+
<span className="text-xs font-mono uppercase tracking-[0.4em] text-gray-500">
74+
Authored by // {item.author}
75+
</span>
76+
</div>
77+
)}
78+
</div>
79+
80+
{url && url !== '#' && (
81+
<div className="mt-12">
82+
<a
83+
href={url}
84+
target="_blank"
85+
rel="noopener noreferrer"
86+
className="group inline-flex items-center gap-4 bg-white text-black px-8 py-5 font-mono font-black text-xs uppercase tracking-[0.4em] hover:bg-emerald-400 transition-all w-full md:w-auto"
87+
>
88+
<span>Visit</span>
89+
<ArrowSquareOutIcon weight="bold" size={20} />
90+
</a>
91+
</div>
92+
)}
93+
94+
{/* Grid corner markers */}
95+
<div className="absolute bottom-0 right-0 w-4 h-4 border-b border-r border-white/20 m-4" />
96+
<div className="absolute bottom-0 right-6 w-1 h-1 bg-emerald-500 m-4 rounded-full animate-pulse" />
97+
</div>
98+
</motion.div>
99+
</div>
100+
)}
101+
</AnimatePresence>
102+
);
103+
};
104+
105+
export default BrutalistModal;

src/components/TransmissionTile.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import React from 'react';
2+
import { motion } from 'framer-motion';
3+
import { ArrowSquareOut } from '@phosphor-icons/react';
4+
import GenerativeArt from './GenerativeArt';
5+
6+
const TransmissionTile = ({ item, categoryKey, onClick }) => {
7+
const getCategoryTheme = (key) => {
8+
switch (key) {
9+
case 'friends': return { color: '#10b981', bg: 'rgba(16, 185, 129, 0.1)', badge: 'Signal' };
10+
case 'books': return { color: '#06b6d4', bg: 'rgba(6, 182, 212, 0.1)', badge: 'Archive' };
11+
default: return { color: '#f59e0b', bg: 'rgba(245, 158, 11, 0.1)', badge: 'Node' };
12+
}
13+
};
14+
15+
const theme = getCategoryTheme(categoryKey);
16+
const title = item.title;
17+
const subTitle = item.description || (item.author ? `By ${item.author}` : '');
18+
19+
const handleClick = (e) => {
20+
e.preventDefault();
21+
onClick(item);
22+
};
23+
24+
return (
25+
<motion.div
26+
whileHover={{ y: -10 }}
27+
className="group relative flex flex-col overflow-hidden rounded-sm bg-[#0c0a09] border border-white/10 h-full transition-all duration-500 hover:border-emerald-500/50 hover:shadow-[0_0_30px_rgba(16,185,129,0.1)]"
28+
>
29+
{/* Subtle Brown Overlay */}
30+
<div className="absolute inset-0 bg-[#443627] opacity-[0.03] pointer-events-none group-hover:opacity-[0.05] transition-opacity" />
31+
32+
{/* Corner Accents */}
33+
<div className="absolute top-0 right-0 w-4 h-4 border-t border-r border-white/20 group-hover:border-emerald-500 transition-colors z-20" />
34+
<div className="absolute bottom-0 left-0 w-4 h-4 border-b border-l border-white/20 group-hover:border-emerald-500 transition-colors z-20" />
35+
36+
<button
37+
onClick={handleClick}
38+
className="flex flex-col h-full text-left relative z-10"
39+
>
40+
{/* Visual Header */}
41+
<div className="relative h-48 w-full overflow-hidden border-b border-white/5">
42+
<GenerativeArt
43+
seed={"2"+title+"[]"}
44+
className="w-full h-full opacity-40 transition-transform duration-1000 ease-out group-hover:scale-125 group-hover:opacity-60 sepia-[0.2]"
45+
/>
46+
<div className="absolute inset-0 bg-gradient-to-t from-[#0c0a09] via-[#0c0a09]/20 to-transparent" />
47+
48+
{/* CSS Scanline Overlay on hover */}
49+
<div className="absolute inset-0 opacity-0 group-hover:opacity-10 pointer-events-none transition-opacity bg-[linear-gradient(rgba(18,16,16,0)_50%,rgba(0,0,0,0.25)_50%),linear-gradient(90deg,rgba(255,0,0,0.06),rgba(0,255,0,0.02),rgba(0,0,255,0.06))] bg-[length:100%_2px,3px_100%]" />
50+
51+
<div className="absolute bottom-4 left-6 flex items-center gap-3">
52+
<span
53+
className="px-3 py-1 text-[10px] font-mono font-bold uppercase tracking-widest border rounded-sm transition-all duration-300 text-gray-300"
54+
style={{
55+
borderColor: theme.color,
56+
backgroundColor: theme.bg,
57+
}}
58+
>
59+
{theme.badge}
60+
</span>
61+
</div>
62+
</div>
63+
64+
{/* Content */}
65+
<div className="flex flex-col flex-grow p-8 relative bg-inherit">
66+
<div className="absolute top-0 right-0 p-4 font-mono text-[10px] text-white/5 uppercase select-none tracking-widest">
67+
{categoryKey}
68+
</div>
69+
70+
<h3 className="text-3xl font-normal font-playfairDisplay text-white mb-4 group-hover:text-emerald-400 transition-colors line-clamp-2 leading-tight tracking-tighter">
71+
{title}
72+
</h3>
73+
74+
<p className="text-base text-gray-400 font-arvo line-clamp-3 mb-8 leading-relaxed opacity-60 group-hover:opacity-100 transition-opacity">
75+
{subTitle}
76+
</p>
77+
78+
<div className="mt-auto pt-6 flex items-center justify-between border-t border-white/5 group-hover:border-emerald-500/20 transition-colors">
79+
<div className="flex items-center gap-2">
80+
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
81+
<span className="text-[10px] font-mono font-bold uppercase tracking-[0.3em] text-gray-500 group-hover:text-white transition-colors">
82+
Access Intel
83+
</span>
84+
</div>
85+
<ArrowSquareOut
86+
weight="bold"
87+
size={18}
88+
className="text-emerald-500 transform -translate-x-2 opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100"
89+
/>
90+
</div>
91+
</div>
92+
</button>
93+
</motion.div>
94+
);
95+
};
96+
97+
export default TransmissionTile;

src/pages/AboutPage.js

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import React, { useEffect } from 'react';
22
import { motion, AnimatePresence } from 'framer-motion';
33
import { Link, useParams, Navigate } from 'react-router-dom';
44
import {
5-
ArrowLeft,
6-
TreeStructure,
7-
Graph,
8-
Terminal,
9-
Article,
10-
Bug,
5+
ArrowLeftIcon,
6+
TreeStructureIcon,
7+
GraphIcon,
8+
TerminalIcon,
9+
ArticleIcon,
10+
BugIcon,
11+
HandHeartIcon,
1112
} from '@phosphor-icons/react';
1213
import CommandPalette from '../components/CommandPalette';
1314
import { useCommandPalette } from '../context/CommandPaletteContext';
@@ -21,11 +22,11 @@ import useSeo from '../hooks/useSeo';
2122

2223
const ViewSwitcher = ({ currentView }) => {
2324
const views = [
24-
{ id: 'brutalist', icon: Bug, label: 'Brutalist' },
25-
{ id: 'dossier', icon: Article, label: 'Dossier' },
26-
{ id: 'hud', icon: Terminal, label: 'Terminal' },
27-
{ id: 'blueprint', icon: TreeStructure, label: 'Blueprint' },
28-
{ id: 'map', icon: Graph, label: 'Mind Map' },
25+
{ id: 'brutalist', icon: BugIcon, label: 'Brutalist' },
26+
{ id: 'dossier', icon: ArticleIcon, label: 'Dossier' },
27+
{ id: 'hud', icon: TerminalIcon, label: 'TerminalIcon' },
28+
{ id: 'blueprint', icon: TreeStructureIcon, label: 'Blueprint' },
29+
{ id: 'map', icon: GraphIcon, label: 'Mind Map' },
2930
];
3031

3132
return (
@@ -103,22 +104,33 @@ const AboutPage = () => {
103104

104105
return (
105106
<div className="min-h-screen bg-black relative">
106-
{/* Global Back Button */}
107+
{/* Global Navigation */}
107108
<motion.div
108-
initial={{ opacity: 0, y: -20 }}
109-
animate={{ opacity: 1, y: 0 }}
110-
className="fixed top-6 left-6 z-50"
109+
initial={{ opacity: 0, x: -20 }}
110+
animate={{ opacity: 1, x: 0 }}
111+
className="fixed top-6 left-6 z-50 flex flex-col items-start gap-3"
111112
>
112113
<Link
113114
to="/"
114115
className={`group flex items-center gap-2 px-4 py-2 transition-all duration-300 ${getButtonStyle(view)}`}
115116
>
116-
<ArrowLeft
117+
<ArrowLeftIcon
117118
weight="bold"
118119
className="group-hover:-translate-x-1 transition-transform"
119120
/>
120121
<span className="hidden sm:inline">Back to Reality</span>
121122
</Link>
123+
124+
<Link
125+
to="/about/friends"
126+
className={`group flex items-center gap-2 px-4 py-2 transition-all duration-300 ${getButtonStyle(view)}`}
127+
>
128+
<HandHeartIcon
129+
weight="bold"
130+
className="group-hover:scale-110 transition-transform"
131+
/>
132+
<span className="hidden sm:inline">Friends of the Show</span>
133+
</Link>
122134
</motion.div>
123135

124136
{/* View Container */}

0 commit comments

Comments
 (0)