Skip to content

Commit a9d3525

Browse files
committed
Add github pinned projects as cards
1 parent bae7c7e commit a9d3525

2 files changed

Lines changed: 626 additions & 4 deletions

File tree

index.html

Lines changed: 281 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,288 @@
11
<!DOCTYPE html>
22
<html lang="en">
33
<head>
4-
<meta charset="UTF-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>Hello World!</title>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Daniel Dreke</title>
7+
<meta name="description" content="Open source projects by Daniel Dreke — developer tools, web apps, and utilities.">
8+
<link rel="preconnect" href="https://fonts.googleapis.com">
9+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10+
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,400;0,14..32,500;0,14..32,600;0,14..32,700;1,14..32,400&display=swap" rel="stylesheet">
11+
<link rel="stylesheet" href="styles.css">
712
</head>
813
<body>
9-
Hello World!
14+
15+
<canvas id="bg"></canvas>
16+
17+
<button class="theme-toggle" id="themeToggle" aria-label="Toggle light/dark">
18+
<!-- icon set by JS -->
19+
</button>
20+
<button class="theme-toggle" id="starToggle" style="right:68px" aria-label="Toggle star mode">
21+
<!-- icon set by JS -->
22+
</button>
23+
24+
<main class="container">
25+
26+
<!-- Hero -->
27+
<header class="hero">
28+
<!-- <div class="hero-avatar">DD</div> -->
29+
<h1><span>Daniel</span> Dreke</h1>
30+
<!-- <p>Building open source tools and web apps — free, offline-friendly, and focused on utility.</p> -->
31+
<!-- <p>Building open source tools and web apps — <br>focus on usabilty, safety and privacy</p> -->
32+
<p>Building open source tools and web apps</p>
33+
<div class="hero-links">
34+
<a href="https://github.com/danieldreke" class="btn btn-primary" target="_blank" rel="noopener">
35+
<svg class="icon-gh" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
36+
GitHub Profile
37+
</a>
38+
</div>
39+
</header>
40+
41+
<!-- Projects -->
42+
<section class="projects">
43+
44+
<div class="grid">
45+
46+
<!-- 1: website-blocker-linux -->
47+
<article class="card">
48+
<div class="card-header">
49+
<div class="card-icon" style="background:rgba(53,114,165,.15);">🛡️</div>
50+
<div class="card-meta">
51+
<span class="lang-badge">
52+
<span class="lang-dot" style="background:var(--py)"></span>
53+
Python
54+
</span>
55+
</div>
56+
</div>
57+
<h3>Website Blocker · Linux</h3>
58+
<p>Block distracting websites at the system level to protect your time and focus. A no-frills CLI tool for Linux.</p>
59+
<div class="card-actions">
60+
<a href="https://github.com/danieldreke/website-blocker-linux" class="btn btn-ghost btn-sm" target="_blank" rel="noopener">
61+
<svg class="icon-gh" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
62+
GitHub
63+
</a>
64+
</div>
65+
</article>
66+
67+
<!-- 2: qr-code-generator -->
68+
<article class="card">
69+
<div class="card-header">
70+
<div class="card-icon" style="background:rgba(240,192,32,.12);"></div>
71+
<div class="card-meta">
72+
<span class="lang-badge">
73+
<span class="lang-dot" style="background:var(--js)"></span>
74+
JavaScript
75+
</span>
76+
</div>
77+
</div>
78+
<h3>QR Code Generator</h3>
79+
<p>Generate QR codes entirely in the browser — no server, no tracking, fully offline-capable.</p>
80+
<div class="card-actions">
81+
<a href="https://danieldreke.github.io/qr-code-generator/" class="btn btn-primary btn-sm" target="_blank" rel="noopener">Open ↗</a>
82+
<a href="https://github.com/danieldreke/qr-code-generator" class="btn btn-ghost btn-sm" target="_blank" rel="noopener">
83+
<svg class="icon-gh" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
84+
GitHub
85+
</a>
86+
</div>
87+
</article>
88+
89+
<!-- 3: matrixcode -->
90+
<article class="card">
91+
<div class="card-header">
92+
<div class="card-icon" style="background:rgba(0,212,100,.12);">🟩</div>
93+
<div class="card-meta">
94+
<span class="lang-badge">
95+
<span class="lang-dot" style="background:var(--html)"></span>
96+
HTML
97+
</span>
98+
</div>
99+
</div>
100+
<h3>Matrix Code</h3>
101+
<p>An interactive Matrix digital rain effect rendered in the browser — pure HTML, CSS, and canvas.</p>
102+
<div class="card-actions">
103+
<a href="https://danieldreke.github.io/matrixcode/" class="btn btn-primary btn-sm" target="_blank" rel="noopener">Open ↗</a>
104+
<a href="https://github.com/danieldreke/matrixcode" class="btn btn-ghost btn-sm" target="_blank" rel="noopener">
105+
<svg class="icon-gh" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
106+
GitHub
107+
</a>
108+
</div>
109+
</article>
110+
111+
<!-- 4: fuel-cost-calculator-webapp -->
112+
<article class="card">
113+
<div class="card-header">
114+
<div class="card-icon" style="background:rgba(240,192,32,.12);"></div>
115+
<div class="card-meta">
116+
<span class="lang-badge">
117+
<span class="lang-dot" style="background:var(--js)"></span>
118+
JavaScript
119+
</span>
120+
</div>
121+
</div>
122+
<h3>Fuel Cost Calculator</h3>
123+
<p>Calculate trip fuel costs quickly. An installable PWA — works offline and on mobile like a native app.</p>
124+
<div class="card-actions">
125+
<a href="https://danieldreke.github.io/fuel-cost-calculator-webapp/" class="btn btn-primary btn-sm" target="_blank" rel="noopener">Open ↗</a>
126+
<a href="https://github.com/danieldreke/fuel-cost-calculator-webapp" class="btn btn-ghost btn-sm" target="_blank" rel="noopener">
127+
<svg class="icon-gh" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
128+
GitHub
129+
</a>
130+
</div>
131+
</article>
132+
133+
<!-- 5: wim-hof-breathing-session -->
134+
<article class="card">
135+
<div class="card-header">
136+
<div class="card-icon" style="background:rgba(100,180,255,.12);">🌬️</div>
137+
<div class="card-meta">
138+
<span class="lang-badge">
139+
<span class="lang-dot" style="background:var(--js)"></span>
140+
JavaScript
141+
</span>
142+
<span class="lang-badge" style="background:var(--accent-badge); color:var(--accent);">★ 1</span>
143+
</div>
144+
</div>
145+
<h3>Wim Hof Breathing</h3>
146+
<p>A guided Wim Hof breathing session as a web app — visual cues, timed rounds, and retention holds.</p>
147+
<div class="card-actions">
148+
<a href="https://danieldreke.github.io/wim-hof-breathing-session/" class="btn btn-primary btn-sm" target="_blank" rel="noopener">Open ↗</a>
149+
<a href="https://github.com/danieldreke/wim-hof-breathing-session" class="btn btn-ghost btn-sm" target="_blank" rel="noopener">
150+
<svg class="icon-gh" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
151+
GitHub
152+
</a>
153+
</div>
154+
</article>
155+
156+
<!-- 6: software-solutions -->
157+
<article class="card">
158+
<div class="card-header">
159+
<div class="card-icon" style="background:var(--accent-icon);">💡</div>
160+
<div class="card-meta">
161+
<span class="lang-badge" style="background:var(--accent-badge); color:var(--accent);">★ 1</span>
162+
</div>
163+
</div>
164+
<h3>Software Solutions</h3>
165+
<p>A curated collection of software solutions, utilities, and development resources published as a web resource.</p>
166+
<div class="card-actions">
167+
<a href="https://danieldreke.github.io/software-solutions/" class="btn btn-primary btn-sm" target="_blank" rel="noopener">Open ↗</a>
168+
<a href="https://github.com/danieldreke/software-solutions" class="btn btn-ghost btn-sm" target="_blank" rel="noopener">
169+
<svg class="icon-gh" viewBox="0 0 24 24"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844a9.59 9.59 0 012.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
170+
GitHub
171+
</a>
172+
</div>
173+
</article>
174+
175+
</div>
176+
</section>
177+
178+
</main>
179+
180+
<script>
181+
const MOON = `<svg viewBox="0 0 24 24"><path d="M21 12.79A9 9 0 1111.21 3a7 7 0 009.79 9.79z"/></svg>`;
182+
const SUN = `<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>`;
183+
const toggleBtn = document.getElementById('themeToggle');
184+
185+
const applyTheme = (light) => {
186+
document.body.classList.toggle('light', light);
187+
toggleBtn.innerHTML = light ? MOON : SUN;
188+
localStorage.setItem('theme', light ? 'light' : 'dark');
189+
};
190+
191+
applyTheme(localStorage.getItem('theme') === 'light');
192+
toggleBtn.addEventListener('click', () => {
193+
applyTheme(!document.body.classList.contains('light'));
194+
});
195+
196+
// Relative luminance of hsl(h, 100%, 60%) — used to detect bright accent colors
197+
function accentLuminance(h) {
198+
const s = 1, l = 0.6;
199+
const a = s * Math.min(l, 1 - l);
200+
const f = n => { const k = (n + h/30) % 12; return l - a * Math.max(-1, Math.min(k-3, 9-k, 1)); };
201+
const lin = c => c <= 0.04045 ? c/12.92 : Math.pow((c+0.055)/1.055, 2.4);
202+
return 0.2126*lin(f(0)) + 0.7152*lin(f(8)) + 0.0722*lin(f(4));
203+
}
204+
205+
let hue = 210, lastX = null, lastY = null;
206+
207+
document.addEventListener('mousemove', (e) => {
208+
if (lastX === null) { lastX = e.clientX; lastY = e.clientY; return; }
209+
const dx = e.clientX - lastX, dy = e.clientY - lastY;
210+
const dist = Math.sqrt(dx*dx + dy*dy);
211+
hue += dist * 0.1;
212+
hue = hue > 360 ? 0 : hue;
213+
document.documentElement.style.setProperty('--hue', Math.round(hue));
214+
// shadow on button text when accent is bright enough to clash with white
215+
document.body.classList.toggle('bright-accent', accentLuminance(hue) > 0.18);
216+
lastX = e.clientX; lastY = e.clientY;
217+
});
218+
219+
// ── Star field ──
220+
const canvas = document.getElementById('bg');
221+
const ctx = canvas.getContext('2d');
222+
let W, H, mx = innerWidth/2, my = innerHeight/2;
223+
224+
function resize() { W = canvas.width = innerWidth; H = canvas.height = innerHeight; }
225+
window.addEventListener('resize', resize);
226+
resize();
227+
window.addEventListener('mousemove', e => { mx = e.clientX; my = e.clientY; });
228+
229+
const layers = [
230+
Array.from({length: 320}, () => ({
231+
x: Math.random(), y: Math.random(),
232+
r: 0.8 + Math.random() * 0.6,
233+
base: 0.12 + Math.random() * 0.22,
234+
swing: 0.06 + Math.random() * 0.10,
235+
spd: 0.04 + Math.random() * 0.12,
236+
phase: Math.random() * Math.PI * 2,
237+
})),
238+
Array.from({length: 100}, (_, i) => ({
239+
x: Math.random(), y: Math.random(),
240+
r: i < 6 ? 1.4 + Math.random() * 0.8 : 0.8 + Math.random() * 0.5,
241+
base: i < 6 ? 0.55 + Math.random() * 0.30 : 0.22 + Math.random() * 0.22,
242+
swing: i < 6 ? 0.20 : 0.10,
243+
spd: 0.03 + Math.random() * 0.08,
244+
phase: Math.random() * Math.PI * 2,
245+
})),
246+
];
247+
const PULL = [0.016, 0.032];
248+
const DRIFT = [10, 20 ];
249+
250+
const starToggleBtn = document.getElementById('starToggle');
251+
const MOUSE_ICON = `<svg viewBox="0 0 24 24"><rect x="7" y="2" width="10" height="16" rx="5"/><line x1="12" y1="6" x2="12" y2="10"/></svg>`;
252+
const DRIFT_ICON = `<svg viewBox="0 0 24 24"><line x1="5" y1="8" x2="19" y2="8"/><line x1="5" y1="12" x2="19" y2="12"/><line x1="5" y1="16" x2="19" y2="16"/><polyline points="15,4 19,8 15,12"/></svg>`;
253+
254+
let driftMode = localStorage.getItem('starMode') === 'drift';
255+
let driftOffset = 0;
256+
257+
const applyStarMode = (drift) => {
258+
driftMode = drift;
259+
starToggleBtn.innerHTML = drift ? MOUSE_ICON : DRIFT_ICON;
260+
localStorage.setItem('starMode', drift ? 'drift' : 'mouse');
261+
};
262+
applyStarMode(driftMode);
263+
starToggleBtn.addEventListener('click', () => applyStarMode(!driftMode));
264+
265+
function draw(t) {
266+
if (driftMode) driftOffset += 0.015;
267+
ctx.clearRect(0, 0, W, H);
268+
const isLightMode = document.body.classList.contains('light');
269+
layers.forEach((stars, li) => {
270+
const pull = PULL[li];
271+
const ox = driftMode ? -(driftOffset * DRIFT[li]) : (mx - W/2) * pull;
272+
const oy = driftMode ? 0 : (my - H/2) * pull;
273+
for (const s of stars) {
274+
const alpha = s.base + s.swing * Math.abs(Math.sin(t * s.spd * 0.0001 + s.phase));
275+
const x = driftMode ? ((s.x * W + ox) % W + W) % W : s.x * W + ox;
276+
ctx.beginPath();
277+
ctx.arc(x, s.y * H + oy, s.r, 0, Math.PI * 2);
278+
ctx.fillStyle = isLightMode ? `rgba(0,0,0,${alpha})` : `rgba(230,240,255,${alpha})`;
279+
ctx.fill();
280+
}
281+
});
282+
requestAnimationFrame(draw);
283+
}
284+
requestAnimationFrame(draw);
285+
</script>
286+
10287
</body>
11288
</html>

0 commit comments

Comments
 (0)