diff options
| author | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-26 20:11:26 -0700 |
|---|---|---|
| committer | Tyler Hoang <tyler@tylerhoang.xyz> | 2026-05-26 20:11:26 -0700 |
| commit | a7ef2c9d7f459145fac5b8a78679aa71b292397c (patch) | |
| tree | 8ff0708f1ebaa4de59dc9af516a1e62f0778d051 /aero.js | |
| parent | c91b67479fb8a6ba1835ba493da013a6c9730ee4 (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.js | 43 |
1 files changed, 42 insertions, 1 deletions
@@ -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, |
