Skip to content

Commit 8031904

Browse files
feat: add light/dark theme toggle to landing page (#54)
1 parent 183a22e commit 8031904

2 files changed

Lines changed: 93 additions & 9 deletions

File tree

apps/web/src/app.css

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
22

3+
/* light theme — default */
34
:root {
45
/* Primary */
56
--primary: #6366f1;
@@ -8,23 +9,39 @@
89
--accent: #8b5cf6;
910

1011
/* Background */
12+
--bg-primary: #f8fafc;
13+
--bg-secondary: #f1f5f9;
14+
--bg-card: #ffffff;
15+
--bg-elevated: #e2e8f0;
16+
17+
/* Text */
18+
--text-primary: #0f172a;
19+
--text-secondary: #475569;
20+
--text-muted: #94a3b8;
21+
22+
/* Border */
23+
--border: #e2e8f0;
24+
25+
/* Spacing */
26+
--radius: 12px;
27+
--radius-lg: 16px;
28+
--radius-xl: 24px;
29+
30+
--theme-transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
31+
}
32+
33+
/* dark theme */
34+
html.dark {
1135
--bg-primary: #0f0f1a;
1236
--bg-secondary: #1a1a2e;
1337
--bg-card: #16213e;
1438
--bg-elevated: #1e293b;
1539

16-
/* Text */
1740
--text-primary: #f8fafc;
1841
--text-secondary: #94a3b8;
1942
--text-muted: #64748b;
2043

21-
/* Border */
2244
--border: #334155;
23-
24-
/* Spacing */
25-
--radius: 12px;
26-
--radius-lg: 16px;
27-
--radius-xl: 24px;
2845
}
2946

3047
* {
@@ -37,16 +54,17 @@ body {
3754
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
3855
background-color: var(--bg-primary);
3956
color: var(--text-primary);
57+
transition: var(--theme-transition);
4058
-webkit-font-smoothing: antialiased;
4159
min-height: 100vh;
4260
}
4361

4462
a {
45-
color: var(--primary-light);
63+
color: var(--primary);
4664
text-decoration: none;
4765
transition: color 0.2s;
4866
}
4967

5068
a:hover {
51-
color: var(--primary);
69+
color: var(--primary-dark);
5270
}

apps/web/src/routes/+page.svelte

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
<script>
2+
import { onMount } from 'svelte';
3+
4+
let theme = 'light';
5+
6+
onMount(() => {
7+
const saved = localStorage.getItem('devcard-theme');
8+
if (saved) {
9+
theme = saved;
10+
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
11+
theme = 'dark';
12+
}
13+
document.documentElement.classList.toggle('dark', theme === 'dark');
14+
});
15+
16+
function toggleTheme() {
17+
theme = theme === 'light' ? 'dark' : 'light';
18+
document.documentElement.classList.toggle('dark', theme === 'dark');
19+
localStorage.setItem('devcard-theme', theme);
20+
}
21+
</script>
22+
123
<svelte:head>
224
<title>DevCard — One Tap. Every Profile. Every Platform.</title>
325
<meta
@@ -8,6 +30,14 @@
830

931
<main class="landing">
1032
<section class="hero">
33+
<button
34+
id="theme-toggle"
35+
class="theme-toggle"
36+
on:click={toggleTheme}
37+
aria-label="Toggle theme"
38+
>
39+
{theme === 'light' ? '🌙' : '☀️'}
40+
</button>
1141
<div class="logo">⚡</div>
1242
<h1>DevCard</h1>
1343
<p class="tagline">One Tap. Every Profile. Every Platform.</p>
@@ -92,10 +122,46 @@
92122
</main>
93123

94124
<style>
125+
/* ── Theme toggle button ────────────────────────────────────────── */
126+
.theme-toggle {
127+
position: absolute;
128+
top: 1.25rem;
129+
right: 1.25rem;
130+
background: var(--bg-card);
131+
border: 1px solid var(--border);
132+
border-radius: 50%;
133+
width: 2.75rem;
134+
height: 2.75rem;
135+
font-size: 1.3rem;
136+
cursor: pointer;
137+
display: flex;
138+
align-items: center;
139+
justify-content: center;
140+
transition:
141+
background 0.3s ease,
142+
border-color 0.3s ease,
143+
transform 0.2s ease,
144+
box-shadow 0.2s ease;
145+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
146+
line-height: 1;
147+
}
148+
149+
.theme-toggle:hover {
150+
transform: scale(1.12) rotate(15deg);
151+
border-color: var(--primary);
152+
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.3);
153+
}
154+
155+
.theme-toggle:focus-visible {
156+
outline: 2px solid var(--primary);
157+
outline-offset: 3px;
158+
}
159+
95160
.landing {
96161
max-width: 960px;
97162
margin: 0 auto;
98163
padding: 2rem;
164+
position: relative;
99165
}
100166
101167
.hero {

0 commit comments

Comments
 (0)