Skip to content

Commit 6e58d1e

Browse files
committed
update roadmap section
1 parent 0dac174 commit 6e58d1e

File tree

2 files changed

+101
-8
lines changed

2 files changed

+101
-8
lines changed

COPYRIGHT

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Copyright:
22

3-
© 2017-2025 Conceal Community
4-
© 2018-2025 Conceal.Network, Conceal Team & Conceal Developers
5-
© 2020-2025 Conceal DAO, Conceal Community & Conceal.Network
3+
© 2017-2026 Conceal Community
4+
© 2018-2026 Conceal.Network, Conceal Team & Conceal Developers
5+
© 2020-2026 Conceal DAO, Conceal Community & Conceal.Network
66

77
License:
88

src/components/sections/RoadmapSection.tsx

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import { useEffect, useRef, useState } from 'react';
12
import { AnimatedElement } from '../ui/AnimatedElement';
23

34
interface TimelineItem {
45
date: string;
56
title: string;
67
description: string;
78
status: 'completed' | 'inprog' | 'activ' | 'done';
9+
url?: string;
810
}
911

1012
const timelineItems: TimelineItem[] = [
@@ -136,6 +138,7 @@ const timelineItems: TimelineItem[] = [
136138
title: 'Conceal Bridge',
137139
description: 'Swap your CCX to wCCX and back the other way with our Bridge tool.',
138140
status: 'completed',
141+
url: 'https://bridge.conceal.network',
139142
},
140143
{
141144
date: 'Q2 2021',
@@ -162,40 +165,60 @@ const timelineItems: TimelineItem[] = [
162165
title: 'Conceal Web Wallet',
163166
description: 'Release of our 100% Client-Side Web Wallet for Conceal.',
164167
status: 'completed',
168+
url: 'https://wallet.conceal.network',
165169
},
166170
{
167171
date: 'Q3 2023',
168172
title: 'Web wallet improvements',
169173
description:
170174
'Improving speed and making optimizations. Now send encrypted Messages from your smartphone',
171175
status: 'completed',
176+
url: 'https://wallet.conceal.network',
172177
},
173178
{
174179
date: 'Q3 2024',
175180
title: 'Web wallet improvements',
176181
description:
177182
'Improving anonymity by randomly picking nodes from a bigger list, now accessing SSL SmartNodes.',
178183
status: 'completed',
184+
url: 'https://wallet.conceal.network',
179185
},
180186
{
181187
date: 'Q3 2024',
182188
title: 'Conceal Marketplace',
183189
description:
184190
'A great place to interact with other Concealers, Buy, Sell in a peer 2 peer way trading with your CCX!',
185191
status: 'completed',
192+
url: 'https://conceal.network/marketplace',
186193
},
187194
{
188195
date: 'Q4 2024',
189196
title: 'Web wallet improvements',
190197
description:
191198
'Now available in 14 languages. Access Deposits (view-only). Use qr code scanning feature to send messages. Get notified of new messages.',
192199
status: 'completed',
200+
url: 'https://wallet.conceal.network',
193201
},
194202
{
195-
date: '',
196-
title: 'Q2 2025, Web wallet deposits',
203+
date: 'Q2 2025',
204+
title: 'Web wallet deposits',
197205
description: 'Bringing deposits to client side web wallet',
198206
status: 'completed',
207+
url: 'https://wallet.conceal.network',
208+
},
209+
{
210+
date: 'Q4 2025',
211+
title: 'Conceal Labs',
212+
description: 'Conceal Authenticator app is launched, your 2FA keys are now stored on the blockchain',
213+
status: 'completed',
214+
url: 'https://f-droid.org/en/packages/com.acktarius.concealauthenticator/',
215+
},
216+
{
217+
date: 'Q1 2026',
218+
title: 'Conceal Labs',
219+
description: 'Conceal-Faucet-API is launched, "one stop shop" for developpers to create faucet or game rewards',
220+
status: 'completed',
221+
url: 'https://github.com/ConcealNetwork/conceal-faucet-api',
199222
},
200223
{
201224
date: '',
@@ -230,8 +253,65 @@ const timelineItems: TimelineItem[] = [
230253
];
231254

232255
export function RoadmapSection() {
256+
const sectionRef = useRef<HTMLElement>(null);
257+
const itemRefs = useRef<Map<number, HTMLDivElement>>(new Map());
258+
const [itemScales, setItemScales] = useState<Map<number, number>>(new Map());
259+
260+
useEffect(() => {
261+
const handleScroll = () => {
262+
if (!sectionRef.current) return;
263+
264+
const sectionRect = sectionRef.current.getBoundingClientRect();
265+
266+
// Only apply effect if roadmap section is in viewport
267+
const isSectionVisible = sectionRect.bottom > 0 && sectionRect.top < window.innerHeight;
268+
269+
if (!isSectionVisible) {
270+
// Reset all scales if section is not visible
271+
const resetScales = new Map<number, number>();
272+
itemRefs.current.forEach((_, index) => {
273+
resetScales.set(index, 1.0);
274+
});
275+
setItemScales(resetScales);
276+
return;
277+
}
278+
279+
const newScales = new Map<number, number>();
280+
const centerY = window.innerHeight / 2;
281+
const maxDistance = 400; // Maximum distance for scaling effect
282+
283+
itemRefs.current.forEach((element, index) => {
284+
if (!element) return;
285+
286+
const rect = element.getBoundingClientRect();
287+
const itemY = rect.top + rect.height / 2;
288+
const distanceFromCenter = Math.abs(centerY - itemY);
289+
290+
// Map distance to scale: 1.22 at center, 1.0 at maxDistance
291+
const normalizedDistance = Math.min(1, distanceFromCenter / maxDistance);
292+
const scale = 1.0 + (0.22 * (1 - normalizedDistance)); // 1.6 at center, 1.0 at maxDistance
293+
294+
newScales.set(index, scale);
295+
});
296+
297+
setItemScales(newScales);
298+
};
299+
300+
// Initial check
301+
handleScroll();
302+
303+
// Listen to scroll events
304+
window.addEventListener('scroll', handleScroll, { passive: true });
305+
window.addEventListener('resize', handleScroll, { passive: true });
306+
307+
return () => {
308+
window.removeEventListener('scroll', handleScroll);
309+
window.removeEventListener('resize', handleScroll);
310+
};
311+
}, []);
312+
233313
return (
234-
<section id="roadmap" className="py-16 px-4 border-b border-[rgba(255,255,255,0.2)] relative">
314+
<section ref={sectionRef} id="roadmap" className="py-16 px-4 border-b border-[rgba(255,255,255,0.2)] relative">
235315
{/* Background image */}
236316
<div
237317
id="herobg"
@@ -282,14 +362,27 @@ export function RoadmapSection() {
282362
const isActiv = item.status === 'activ';
283363
const isDone = item.status === 'done';
284364

365+
const scale = itemScales.get(index) ?? 1.0;
366+
285367
return (
286368
<AnimatedElement
287369
key={`${item.date}-${item.title}`}
288370
types={['fadeIn']}
289371
triggerImmediately={false}
290372
>
291373
<div
292-
className={`single-timeline flex items-center mb-[22px] ${isEven ? 'flex-row-reverse' : ''}`}
374+
ref={(el) => {
375+
if (el) {
376+
itemRefs.current.set(index, el);
377+
} else {
378+
itemRefs.current.delete(index);
379+
}
380+
}}
381+
className={`single-timeline flex items-center mb-[22px] transition-transform duration-300 ease-out ${isEven ? 'flex-row-reverse' : ''}`}
382+
style={{
383+
transform: `scale(${scale})`,
384+
transformOrigin: 'center center',
385+
}}
293386
>
294387
<div className="timeline-blank w-1/2"></div>
295388
<div
@@ -339,7 +432,7 @@ export function RoadmapSection() {
339432
{item.title}
340433
</h6>
341434
)}
342-
{item.description && <span>{item.description}</span>}
435+
{item.description && <span>{item.url ? <a href={item.url} target="_blank" rel="noopener noreferrer" className="text-inherit hover:text-[var(--color1)]" title={`Visit ${item.url}`}>{item.description}</a> : item.description}</span>}
343436
</span>
344437
</div>
345438
</div>

0 commit comments

Comments
 (0)