-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFriendsPage.jsx
More file actions
295 lines (273 loc) · 11.3 KB
/
FriendsPage.jsx
File metadata and controls
295 lines (273 loc) · 11.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Broadcast,
BookOpen,
Users,
ArrowSquareOut,
} from '@phosphor-icons/react';
import piml from 'piml';
import Seo from '../components/Seo';
import GenerativeArt from '../components/GenerativeArt';
import BrutalistModal from '../components/BrutalistModal';
import TransmissionTile from '../components/TransmissionTile';
const FriendsPage = () => {
const [data, setData] = useState({});
const [selectedItem, setSelectedItem] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const navigate = useNavigate();
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('/about-me/transmissions.piml');
if (response.ok) {
const text = await response.text();
const parsed = piml.parse(text);
setData(parsed);
}
} catch (error) {
console.error('Failed to load links:', error);
}
};
fetchData();
}, []);
const handleTileClick = (item) => {
setSelectedItem(item);
setIsModalOpen(true);
};
const getCategoryIcon = (key) => {
switch (key) {
case 'friends':
return (
<Users size={32} weight="duotone" className="text-emerald-500" />
);
case 'books':
return (
<BookOpen size={32} weight="duotone" className="text-cyan-500" />
);
default:
return (
<Broadcast size={32} weight="duotone" className="text-rose-500" />
);
}
};
const getCategoryLabel = (key) => {
switch (key) {
case 'friends':
return 'Parallel Realities';
case 'books':
return 'Archive Access';
default:
return key.charAt(0).toUpperCase() + key.slice(1);
}
};
return (
<div className="min-h-screen bg-[#0c0a09] text-white p-8 md:p-24 selection:bg-emerald-500/30 relative overflow-x-hidden">
<Seo
title="Friends of the Show | Fezcodex"
description="A curated list of signals, portals, and archives from the digital garden."
/>
{/* Structural Grid Background */}
<div
className="fixed inset-0 opacity-[0.05] pointer-events-none"
style={{
backgroundImage:
'linear-gradient(#fff 1px, transparent 1px), linear-gradient(90deg, #fff 1px, transparent 1px)',
backgroundSize: '100px 100px',
}}
/>
{/* Decorative Art Background - Increased visibility */}
<div className="fixed inset-0 opacity-[0.08] pointer-events-none">
<GenerativeArt seed="Friends of the Show 2" className="w-full h-full" />
</div>
{/* Scanline Effect */}
<div className="fixed inset-0 pointer-events-none z-50 overflow-hidden opacity-20">
<motion.div
initial={{ y: -100 }}
animate={{ y: '100vh' }}
transition={{ duration: 8, repeat: Infinity, ease: 'linear' }}
className="w-full h-24 bg-gradient-to-b from-transparent via-emerald-500/10 to-transparent"
/>
</div>
<BrutalistModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
maxWidth="max-w-4xl"
title={
<span className="font-playfairDisplay font-bold normal-case text-3xl">
{selectedItem?.title}
</span>
}
>
{' '}
<div className="flex flex-col md:flex-row -m-8 min-h-[400px]">
{/* Left Side: All Generative Art */}
<div className="w-full md:w-5/12 border-b md:border-b-0 md:border-r border-white/10 relative overflow-hidden bg-black">
<div className="absolute inset-0 z-0">
<GenerativeArt
seed={selectedItem?.title || 'void'}
className="w-full h-full"
/>
</div>
{/* Aesthetic Overlays */}
<div className="absolute inset-0 bg-gradient-to-r from-black/20 to-transparent pointer-events-none" />
<div className="absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_0%,rgba(0,0,0,0.4)_100%)] pointer-events-none" />
</div>
{/* Right Side: Detailed Transmission Data */}
<div className="w-full md:w-7/12 p-10 flex flex-col bg-[#050505] relative">
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-8 h-[1px] bg-emerald-500" />
<span className="font-mono text-[10px] uppercase tracking-[0.4em] text-emerald-500/70">
Secure Transmission
</span>
</div>
{selectedItem?.author && (
<p className="font-mono text-xs uppercase tracking-[0.2em] text-gray-500 border-l border-emerald-500/30 pl-4 py-1">
Origin: {selectedItem.author}
</p>
)}
</div>
<div className="flex-grow">
{selectedItem?.description && (
<p className="font-garamond text-xl md:text-2xl text-gray-300 leading-relaxed opacity-90">
"{selectedItem.description}"
</p>
)}
</div>
{selectedItem?.url && (
<div className="mt-12 pt-8 border-t border-white/5">
<a
href={selectedItem.url}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center justify-between w-full p-4 bg-emerald-950/30 border border-emerald-500/30 hover:bg-emerald-500 hover:border-emerald-500 hover:text-black transition-all duration-300"
>
<span className="font-mono text-xs font-bold uppercase tracking-[0.2em] text-emerald-500 group-hover:text-black transition-colors">
Establish Portal Connection
</span>
<ArrowSquareOut
size={20}
weight="bold"
className="text-emerald-500 group-hover:text-black group-hover:translate-x-1 transition-all"
/>
</a>
</div>
)}
{/* Subtle Corner Decoration */}
<div className="absolute bottom-4 right-4 opacity-10 pointer-events-none">
<Broadcast size={40} weight="thin" className="text-emerald-500" />
</div>
</div>
</div>
</BrutalistModal>
<div className="relative z-10">
{/* Navigation */}
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
className="mb-16 flex items-center gap-4"
>
<button
onClick={() => navigate(-1)}
className="group flex items-center gap-3 text-gray-500 hover:text-white transition-all duration-300 font-mono text-xs uppercase tracking-[0.3em] bg-white/5 px-4 py-2 border border-white/10 hover:border-emerald-500/50"
>
<ArrowLeft
weight="bold"
className="group-hover:-translate-x-1 transition-transform"
/>
<span>Return to Archive</span>
</button>
<div className="h-px flex-grow bg-white/10" />
</motion.div>
<div className="max-w-7xl mx-auto">
<header className="mb-32 relative">
<div className="absolute -left-12 top-0 bottom-0 w-1 bg-emerald-500 hidden xl:block" />
<h1 className="text-7xl md:text-9xl font-black font-playfairDisplay italic uppercase tracking-tighter mb-6 leading-none">
<span className="text-emerald-500">Friends</span> of the{' '}
<span className="text-lime-500">Show</span>
</h1>
<p className="text-xl md:text-2xl text-gray-500 font-arvo max-w-2xl leading-relaxed border-l-2 border-white/10 pl-6">
Signals from parallel realities and archived transmissions from
the digital garden.
</p>
</header>
<div className="space-y-48">
{Object.entries(data).map(([key, content], idx) => {
let items = [];
if (Array.isArray(content)) {
items = content;
} else if (
content &&
typeof content === 'object' &&
content.item
) {
items = Array.isArray(content.item)
? content.item
: [content.item];
}
if (items.length === 0) return null;
return (
<motion.section
key={key}
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: idx * 0.1 }}
className="space-y-16"
>
<div className="flex items-center gap-8">
<div className="p-6 bg-white/5 border border-white/10 rounded-sm relative group overflow-hidden">
<div className="absolute inset-0 bg-emerald-500/0 group-hover:bg-emerald-500/5 transition-colors" />
{getCategoryIcon(key)}
</div>
<div className="flex-grow">
<div className="flex items-center gap-4 mb-2">
<h2 className="text-4xl md:text-6xl font-normal font-playfairDisplay uppercase tracking-tighter">
{getCategoryLabel(key)}
</h2>
<div className="h-px flex-grow bg-white/10" />
<span className="font-mono text-[10px] text-emerald-500/50 uppercase tracking-[0.2em]">
Section_{idx + 1}
</span>
</div>
<p className="text-xs font-mono text-gray-500 uppercase tracking-[0.4em]">
Transmissions detected in the {key} sector.
</p>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-16">
{items.map((item, iIdx) => (
<TransmissionTile
key={iIdx}
item={item}
categoryKey={key}
onClick={handleTileClick}
/>
))}
</div>
</motion.section>
);
})}
</div>
</div>
<footer className="mt-64 pt-24 border-t border-white/10 relative">
<div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 px-8 bg-[#050505]">
<Broadcast size={32} className="text-emerald-500 animate-pulse" />
</div>
<p className="font-mono text-[10px] text-gray-600 uppercase tracking-[0.5em] text-center mb-4">
End of Line // Transmission Terminated
</p>
<div className="flex justify-center gap-12 opacity-20">
{[...Array(6)].map((_, i) => (
<div key={i} className="w-1 h-1 bg-white rounded-full" />
))}
</div>
</footer>
</div>
</div>
);
};
export default FriendsPage;