Skip to content

Commit bafe226

Browse files
Merge pull request #4 from NesoHQ/deep/cactus
feat: rewrite theme toggle with switch-style design and circular wave…
2 parents edbd1a7 + 281048f commit bafe226

File tree

7 files changed

+624
-157
lines changed

7 files changed

+624
-157
lines changed

app/globals.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,23 @@
134134
}
135135
}
136136

137+
/* View Transitions optimization */
138+
::view-transition-old(root),
139+
::view-transition-new(root) {
140+
animation: none;
141+
mix-blend-mode: normal;
142+
display: block;
143+
}
144+
145+
/* Ensure the old view doesn't disappear too early */
146+
::view-transition-old(root) {
147+
z-index: 1;
148+
}
149+
150+
::view-transition-new(root) {
151+
z-index: 999;
152+
}
153+
137154
@layer utilities {
138155
@keyframes fade-in {
139156
from {

app/oss-projects/page.tsx

Lines changed: 372 additions & 86 deletions
Large diffs are not rendered by default.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"use client";
2+
3+
import { useState, useEffect } from "react";
4+
import { Navbar } from "@/components/navbar";
5+
import { Footer } from "@/components/footer";
6+
import { Construction, ArrowLeft } from "lucide-react";
7+
import Link from "next/link";
8+
9+
export default function ComingSoonPage() {
10+
return (
11+
<main className="min-h-screen flex flex-col bg-background">
12+
<Navbar />
13+
14+
<section className="relative flex-1 flex items-center justify-center overflow-hidden py-32">
15+
{/* Technical Grid Background */}
16+
<div className="absolute inset-0 -z-10 bg-[linear-gradient(to_right,#80808008_1px,transparent_1px),linear-gradient(to_bottom,#80808008_1px,transparent_1px)] bg-size-[32px_32px]" />
17+
18+
{/* Neptunian Glows */}
19+
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] bg-primary/5 rounded-full blur-[140px]" />
20+
21+
<div className="container px-6 mx-auto relative z-10">
22+
<div className="max-w-3xl mx-auto text-center space-y-10">
23+
{/* Status Badge */}
24+
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-primary/20 bg-primary/5 text-[10px] font-mono uppercase tracking-[0.3em] text-primary mx-auto animate-pulse">
25+
<Construction className="h-4 w-4" />
26+
Upgrade in Progress
27+
</div>
28+
29+
{/* Main Title */}
30+
<div className="relative">
31+
<h1 className="text-6xl md:text-8xl font-bold tracking-tighter text-foreground mb-4">
32+
Coming <span className="text-primary italic">Soon</span>
33+
</h1>
34+
<p className="text-xl text-muted-foreground max-w-lg mx-auto leading-relaxed">
35+
We are actively forging the next generation of open-source
36+
protocols. Data compilation is currently underway.
37+
</p>
38+
</div>
39+
40+
{/* Diagnostic/Loading Visual */}
41+
<DynamicLoader />
42+
43+
{/* Action */}
44+
<div className="pt-8">
45+
<Link
46+
href="/"
47+
className="inline-flex items-center gap-2 text-muted-foreground hover:text-primary transition-colors font-mono uppercase tracking-widest text-xs group py-2"
48+
>
49+
<ArrowLeft className="h-4 w-4 transition-transform duration-300 ease-in-out group-hover:-translate-x-2" />
50+
Return to Base
51+
</Link>
52+
</div>
53+
</div>
54+
</div>
55+
</section>
56+
57+
<Footer />
58+
</main>
59+
);
60+
}
61+
62+
function DynamicLoader() {
63+
const [progress, setProgress] = useState(0);
64+
const [dots, setDots] = useState("");
65+
66+
useEffect(() => {
67+
// Animate progress bar (simulated download that gets stuck)
68+
const timer = setInterval(() => {
69+
setProgress((prev) => {
70+
// Stick around 82% to simulate a heavy process
71+
if (prev >= 50) return 50;
72+
// Random increment between 1 and 5
73+
const diff = Math.random() * 5;
74+
return Math.min(prev + diff, 82);
75+
});
76+
}, 200);
77+
78+
// Animate dots
79+
const dotsTimer = setInterval(() => {
80+
setDots((prev) => (prev.length >= 3 ? "" : prev + "."));
81+
}, 500);
82+
83+
return () => {
84+
clearInterval(timer);
85+
clearInterval(dotsTimer);
86+
};
87+
}, []);
88+
89+
return (
90+
<div className="max-w-md mx-auto bg-card/40 border border-white/5 backdrop-blur-md rounded-2xl p-6 relative overflow-hidden group">
91+
{/* Scanline Effect */}
92+
<div className="absolute inset-0 bg-linear-to-b from-transparent via-primary/5 to-transparent h-[200%] w-full -translate-y-full group-hover:animate-[scan_3s_linear_infinite]" />
93+
94+
<div className="space-y-4">
95+
<div className="flex justify-between text-xs font-mono uppercase tracking-widest text-muted-foreground">
96+
<span>System Status</span>
97+
<span className="text-primary w-24 text-left">Compiling{dots}</span>
98+
</div>
99+
{/* Progress Bar */}
100+
<div className="h-2 w-full bg-secondary/30 rounded-full overflow-hidden">
101+
<div
102+
className="h-full bg-primary rounded-full transition-all duration-200 ease-out"
103+
style={{ width: `${progress}%` }}
104+
/>
105+
</div>
106+
<div className="flex justify-between text-[10px] font-mono text-muted-foreground/60">
107+
<span>Module: OSS_Registry</span>
108+
<span>{Math.round(progress)}% Complete</span>
109+
</div>
110+
</div>
111+
</div>
112+
);
113+
}

components/footer.tsx

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -170,37 +170,20 @@ export function Footer() {
170170
<div className="flex flex-col md:flex-row justify-between items-start md:items-end gap-6">
171171
<div className="space-y-4">
172172
<div className="flex flex-wrap gap-6 text-xs text-muted-foreground">
173-
<Link href="#" className="hover:text-primary transition-colors">
174-
Privacy
175-
</Link>
176-
<Link href="#" className="hover:text-primary transition-colors">
177-
Site Terms
178-
</Link>
179-
<Link href="#" className="hover:text-primary transition-colors">
180-
Cookie Preferences
181-
</Link>
182173
<span>
183174
© 2026, NesoHQ, Inc. or its affiliates. All rights reserved.
184175
</span>
185176
</div>
186177
</div>
187178

188179
<div className="flex items-center gap-4 text-muted-foreground">
189-
<Link href="#" className="hover:text-primary transition-colors">
190-
<Twitter className="h-5 w-5" />
191-
</Link>
192-
<Link href="#" className="hover:text-primary transition-colors">
193-
<Linkedin className="h-5 w-5" />
194-
</Link>
195-
<Link href="#" className="hover:text-primary transition-colors">
180+
<Link
181+
href="https://github.com/NesoHQ"
182+
target="blank"
183+
className="hover:text-primary transition-colors"
184+
>
196185
<Github className="h-5 w-5" />
197186
</Link>
198-
<Link href="#" className="hover:text-primary transition-colors">
199-
<Youtube className="h-5 w-5" />
200-
</Link>
201-
<Link href="#" className="hover:text-primary transition-colors">
202-
<MessageCircle className="h-5 w-5" />
203-
</Link>
204187
</div>
205188
</div>
206189
</div>

components/mode-toggle.tsx

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,127 @@
33
import * as React from "react";
44
import { Moon, Sun } from "lucide-react";
55
import { useTheme } from "next-themes";
6-
7-
import { Button } from "@/components/ui/button";
6+
import { cn } from "@/lib/utils";
87

98
export function ModeToggle() {
109
const { theme, setTheme } = useTheme();
10+
const [mounted, setMounted] = React.useState(false);
11+
12+
// Avoid hydration mismatch
13+
React.useEffect(() => {
14+
setMounted(true);
15+
}, []);
16+
17+
const toggleTheme = (event: React.MouseEvent) => {
18+
const isDark = theme === "dark";
19+
20+
// Check if the browser supports the View Transitions API
21+
if (!document.startViewTransition) {
22+
setTheme(isDark ? "light" : "dark");
23+
return;
24+
}
25+
26+
// Circular "Eye" transition effect
27+
const x = event.clientX;
28+
const y = event.clientY;
29+
const endRadius = Math.hypot(
30+
Math.max(x, innerWidth - x),
31+
Math.max(y, innerHeight - y),
32+
);
33+
34+
const transition = document.startViewTransition(async () => {
35+
setTheme(isDark ? "light" : "dark");
36+
// Give a tiny moment for React to flush the state to the DOM
37+
await new Promise((resolve) => setTimeout(resolve, 0));
38+
});
39+
40+
transition.ready.then(() => {
41+
document.documentElement.animate(
42+
{
43+
clipPath: [
44+
`circle(0px at ${x}px ${y}px)`,
45+
`circle(${endRadius}px at ${x}px ${y}px)`,
46+
],
47+
},
48+
{
49+
duration: 500,
50+
easing: "ease-in-out",
51+
pseudoElement: "::view-transition-new(root)",
52+
},
53+
);
54+
});
55+
};
56+
57+
if (!mounted) {
58+
return (
59+
<div className="h-8 w-14 rounded-full bg-muted/50 border border-border animate-pulse" />
60+
);
61+
}
62+
63+
const isDark = theme === "dark";
1164

1265
return (
13-
<Button
14-
variant="ghost"
15-
size="icon"
16-
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
66+
<button
67+
onClick={toggleTheme}
68+
className={cn(
69+
"group relative flex items-center h-8 w-14 rounded-full p-1 transition-all duration-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background hover:scale-105 active:scale-95 cursor-pointer",
70+
isDark
71+
? "bg-slate-900 shadow-[inset_0_2px_4px_rgba(0,0,0,0.6)]"
72+
: "bg-linear-to-r from-blue-400 to-sky-300 shadow-[inset_0_2px_4px_rgba(0,0,0,0.2)]",
73+
)}
74+
aria-label="Toggle theme"
1775
>
18-
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
19-
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
20-
<span className="sr-only">Toggle theme</span>
21-
</Button>
76+
{/* Background Icons - subtle indicators */}
77+
<div className="absolute inset-0 flex justify-between px-2 items-center pointer-events-none">
78+
<Sun
79+
size={10}
80+
className={cn(
81+
"transition-all duration-500",
82+
isDark ? "text-slate-700 opacity-50" : "text-white opacity-0",
83+
)}
84+
/>
85+
<Moon
86+
size={10}
87+
className={cn(
88+
"transition-all duration-500",
89+
!isDark ? "text-blue-600 opacity-50" : "text-white opacity-0",
90+
)}
91+
/>
92+
</div>
93+
94+
{/* Sliding Thumb */}
95+
<div
96+
className={cn(
97+
"relative flex items-center justify-center h-6 w-6 rounded-full transition-all duration-500 ease-[cubic-bezier(0.34,1.56,0.64,1)]",
98+
isDark
99+
? "translate-x-6 bg-slate-800 shadow-[0_0_15px_rgba(120,119,198,0.4)] border border-slate-700"
100+
: "translate-x-0 bg-white shadow-lg",
101+
)}
102+
>
103+
<div className="relative h-4 w-4">
104+
<Sun
105+
className={cn(
106+
"absolute inset-0 h-4 w-4 text-orange-500 transition-all duration-500",
107+
isDark
108+
? "rotate-180 scale-0 opacity-0"
109+
: "rotate-0 scale-100 opacity-100",
110+
)}
111+
/>
112+
<Moon
113+
className={cn(
114+
"absolute inset-0 h-4 w-4 text-blue-400 transition-all duration-500",
115+
isDark
116+
? "rotate-0 scale-100 opacity-100"
117+
: "-rotate-180 scale-0 opacity-0",
118+
)}
119+
/>
120+
</div>
121+
</div>
122+
123+
{/* Sparkles or extra glow for dark mode */}
124+
{isDark && (
125+
<span className="absolute right-2 top-1 w-1 h-1 bg-white rounded-full animate-pulse opacity-50" />
126+
)}
127+
</button>
22128
);
23129
}

components/navbar.tsx

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,6 @@ export function Navbar() {
7272
{/* CTA - Solid & Minimal */}
7373
<div className="hidden md:flex items-center gap-4">
7474
<ModeToggle />
75-
<Link
76-
href="/login"
77-
className="text-sm font-medium text-foreground hover:text-primary transition-colors"
78-
>
79-
Log In
80-
</Link>
81-
<Button className="rounded-full px-6 bg-foreground text-background hover:bg-primary hover:text-foreground transition-all duration-300 font-medium">
82-
<Link href="/join">Initialize</Link>
83-
</Button>
8475
</div>
8576

8677
{/* Mobile Menu Button */}
@@ -117,21 +108,6 @@ export function Navbar() {
117108
</Link>
118109
);
119110
})}
120-
<div className="mt-8 flex flex-col gap-4">
121-
<Button
122-
size="lg"
123-
className="w-full bg-foreground text-background rounded-xl"
124-
>
125-
Initialize Sequence
126-
</Button>
127-
<Button
128-
size="lg"
129-
variant="outline"
130-
className="w-full border-border rounded-xl"
131-
>
132-
Log In
133-
</Button>
134-
</div>
135111
</div>
136112
</div>
137113
)}

0 commit comments

Comments
 (0)