aboutsummaryrefslogtreecommitdiff
path: root/aero.js
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-26 20:11:26 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-26 20:11:26 -0700
commita7ef2c9d7f459145fac5b8a78679aa71b292397c (patch)
tree8ff0708f1ebaa4de59dc9af516a1e62f0778d051 /aero.js
parentc91b67479fb8a6ba1835ba493da013a6c9730ee4 (diff)
browser+resize: implement proper faux browser + resizable windows per design handoff
Browser window (w-browser, Internet icon): - Full aqua browser chrome: toolbar with back/fwd/reload/home SVG nav buttons, URL bar (lock + scheme + host + path + blinking caret), bookmark chips with colored 12x12 favicon squares, scrollable page surface, status bar with animated progress bar - History stack (back/forward state, disable at ends) - Delegated click handler via data-go attributes for in-page navigation - Refresh button spins 700ms via CSS animation - Address bar + title bar update on every navigation - ARTICLES array with 4 entries (self-hosting, jazz, cooking, film) with drop-cap, Georgia body, IBM Plex Mono metadata, blockquotes, inline ilinks - Chrome theme: brushed mercury toolbar, dark navy article surface with iridescent radial hotspots, Audiowide titles with chromeShimmer drop-cap, Michroma UI labels, iridescent progress bar, custom scrollbar Resizable windows: - makeResizable() in aero.js: appends .rs-e (right edge), .rs-s (bottom edge), .rs-se (SE grip) handles; tracks mousedown/move/up; enforces minW/minH - .win.resized flex-column flip: body fills remaining height and scrolls - Aero grip (3-stripe diagonal, blue); Chrome grip (iridescent purple/cyan/pink) - Body cursor forced via body.rs-cursor-* classes during drag CSS in aero.css: chrome overrides for resize handle + full browser window theme CSS in index.html: resize handle rules, full browser/article reading styles Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'aero.js')
-rw-r--r--aero.js43
1 files changed, 42 insertions, 1 deletions
diff --git a/aero.js b/aero.js
index 9429ccf..8a950e9 100644
--- a/aero.js
+++ b/aero.js
@@ -83,6 +83,47 @@ function makeDraggable(el, handle) {
window.addEventListener('mouseup', () => { dragging = false; });
}
+function makeResizable(el, options = {}) {
+ const minW = options.minW || 280;
+ const minH = options.minH || 180;
+ const handles = ['e', 's', 'se'];
+ handles.forEach(mode => {
+ const h = document.createElement('div');
+ h.className = 'rs rs-' + mode + ' no-drag';
+ el.appendChild(h);
+ h.addEventListener('mousedown', (e) => startResize(e, mode));
+ });
+ let mode = null, sx = 0, sy = 0, sw = 0, sh = 0;
+ function startResize(e, m) {
+ e.preventDefault(); e.stopPropagation();
+ mode = m;
+ sx = e.clientX; sy = e.clientY;
+ const r = el.getBoundingClientRect();
+ sw = r.width; sh = r.height;
+ // pin current size as inline so first move doesn't snap
+ el.style.width = sw + 'px';
+ el.style.height = sh + 'px';
+ el.classList.add('resized');
+ el.style.zIndex = (++window.__zTop || (window.__zTop = 100));
+ document.body.classList.add('rs-cursor-' + m);
+ window.addEventListener('mousemove', onMove);
+ window.addEventListener('mouseup', onUp);
+ }
+ function onMove(e) {
+ if (!mode) return;
+ const dx = e.clientX - sx;
+ const dy = e.clientY - sy;
+ if (mode.includes('e')) el.style.width = Math.max(minW, sw + dx) + 'px';
+ if (mode.includes('s')) el.style.height = Math.max(minH, sh + dy) + 'px';
+ }
+ function onUp() {
+ mode = null;
+ document.body.classList.remove('rs-cursor-e', 'rs-cursor-s', 'rs-cursor-se');
+ window.removeEventListener('mousemove', onMove);
+ window.removeEventListener('mouseup', onUp);
+ }
+}
+
function counterHTML(val = 42137, label = "visitors") {
const digits = String(val).padStart(7, '0').split('').map(d => `<div class="d">${d}</div>`).join('');
return `<div class="counter"><div class="digits">${digits}</div><div class="label">${label}</div></div>`;
@@ -228,7 +269,7 @@ async function fetchReelMouthFeed(limit = 6) {
}
window.Aero = {
- spawnBubbles, makeClouds, sparkleCursor, makeDraggable,
+ spawnBubbles, makeClouds, sparkleCursor, makeDraggable, makeResizable,
counterHTML, nowPlayingHTML, animateEq, musicToggleHTML, bindMusicToggle,
// theme api
getTheme, setTheme, mountThemeSwitcher, initTheme, THEMES,