From c91b67479fb8a6ba1835ba493da013a6c9730ee4 Mon Sep 17 00:00:00 2001 From: Tyler Hoang Date: Tue, 26 May 2026 20:02:20 -0700 Subject: browser: add article reader window with themed fetch+inject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - new Articles icon (🌐) on desktop opens w-browser window - browser window has URL bar + bookmark bar (library, music list, software) - fetch()es article HTML, strips Bootstrap stylesheet + navbar, preserves content - blink tags unwrapped (colored spans preserved for retro feel) - full aero + chrome theme CSS for url-bar, bookmarks, article typography - uses DOMParser to cleanly extract body content without iframes Co-Authored-By: Claude Sonnet 4.6 --- index.html | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 3 deletions(-) (limited to 'index.html') diff --git a/index.html b/index.html index 5a9d28e..e2ee661 100755 --- a/index.html +++ b/index.html @@ -113,6 +113,69 @@ .film-rating .star.on { color: oklch(72% 0.16 60); text-shadow: 0 0 4px oklch(80% 0.18 70 / 0.5); } .film-rating .star.half { background: linear-gradient(90deg, oklch(72% 0.16 60) 50%, oklch(80% 0.04 230) 50%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; } .film-note { font-size: 11px; opacity: 0.75; font-style: italic; } + + /* ===== BROWSER / ARTICLE READER ===== */ + .browser-toolbar { + display: flex; align-items: center; gap: 8px; + padding: 6px 12px; + background: rgba(255,255,255,0.22); + border-bottom: 1px solid rgba(200,220,240,0.45); + } + .browser-url-bar { + flex: 1; height: 22px; padding: 0 10px; + border-radius: 11px; + background: rgba(255,255,255,0.62); border: 1px solid rgba(180,200,220,0.45); + font: 400 11px 'IBM Plex Mono', monospace; color: oklch(30% 0.05 230); + display: flex; align-items: center; overflow: hidden; + white-space: nowrap; text-overflow: ellipsis; + } + .browser-bookmarks { + display: flex; gap: 5px; padding: 5px 12px; + background: rgba(255,255,255,0.15); + border-bottom: 1px solid rgba(200,220,240,0.35); + flex-wrap: wrap; + } + .browser-bm { + height: 20px; padding: 0 10px; + border-radius: 10px; border: 1px solid rgba(180,200,220,0.4); + background: rgba(255,255,255,0.55); + font: 600 10px 'Plus Jakarta Sans', sans-serif; color: oklch(30% 0.08 230); + cursor: pointer; letter-spacing: 0.3px; + transition: background 150ms, border-color 150ms; + } + .browser-bm:hover { background: rgba(255,255,255,0.88); } + .browser-bm.active { background: rgba(255,255,255,0.92); border-color: oklch(55% 0.12 220); color: oklch(22% 0.10 230); } + .browser-body { + overflow-y: auto; max-height: 440px; + padding: 16px 20px; border-radius: 0 0 18px 18px; + } + /* article typography inside the browser */ + .browser-body h1 { font-size: 17px; font-weight: 700; margin: 0 0 10px; color: oklch(24% 0.08 230); } + .browser-body h2 { font-size: 14px; font-weight: 700; margin: 16px 0 6px; color: oklch(27% 0.08 230); border-bottom: 1px solid rgba(120,160,200,0.3); padding-bottom: 4px; } + .browser-body h3 { font-size: 13px; font-weight: 600; margin: 12px 0 5px; color: oklch(29% 0.07 230); } + .browser-body h4 { font-size: 12px; font-weight: 600; margin: 10px 0 4px; color: oklch(31% 0.06 230); font-style: italic; } + .browser-body p { margin: 0 0 9px; font-size: 12px; line-height: 1.65; color: oklch(22% 0.04 240); } + .browser-body ul, .browser-body ol { padding-left: 18px; margin: 0 0 9px; } + .browser-body li { font-size: 12px; line-height: 1.7; color: oklch(22% 0.04 240); } + .browser-body img { max-width: 160px; border-radius: 8px; margin: 6px 0; display: block; box-shadow: 0 2px 8px rgba(40,80,140,0.15); } + .browser-body figure { margin: 8px 0; } + .browser-body figcaption { font-size: 10px; opacity: 0.65; margin-top: 3px; } + .browser-body a { color: oklch(42% 0.16 255); text-decoration: none; } + .browser-body a:hover { text-decoration: underline; } + .browser-body pre, .browser-body .body > p { font: 12px 'IBM Plex Mono', monospace; line-height: 1.65; white-space: pre-wrap; color: oklch(22% 0.04 240); } + .browser-body center { text-align: center; } + /* chrome theme overrides for browser */ + body[data-theme="chrome"] .browser-url-bar { background: rgba(195,202,215,0.5); border-color: oklch(50% 0.04 250); color: oklch(14% 0.03 250); } + body[data-theme="chrome"] .browser-bookmarks { background: rgba(195,202,215,0.15); border-bottom-color: oklch(60% 0.03 250); } + body[data-theme="chrome"] .browser-bm { font-family: 'Michroma', sans-serif; font-size: 8px; text-transform: uppercase; letter-spacing: 1px; border-color: oklch(55% 0.04 250); background: linear-gradient(to bottom, oklch(92% 0.01 240), oklch(78% 0.02 240)); color: oklch(18% 0.04 250); } + body[data-theme="chrome"] .browser-bm:hover { background: linear-gradient(to bottom, oklch(97% 0.01 240), oklch(86% 0.02 240)); } + body[data-theme="chrome"] .browser-bm.active { background: linear-gradient(to bottom, oklch(99% 0.01 240), oklch(90% 0.02 240)); border-color: oklch(40% 0.10 280); } + body[data-theme="chrome"] .browser-body h1, + body[data-theme="chrome"] .browser-body h2, + body[data-theme="chrome"] .browser-body h3, + body[data-theme="chrome"] .browser-body h4 { font-family: 'Michroma', sans-serif; text-transform: uppercase; letter-spacing: 0.5px; } + body[data-theme="chrome"] .browser-body p, + body[data-theme="chrome"] .browser-body li { font-family: 'Space Grotesk', sans-serif; } @@ -131,6 +194,7 @@
πŸŽ™
REEL MOUTH
🎞
Films
βœ‰
Contact
+
🌐
Articles
@@ -151,7 +215,7 @@ -

Hi! I'm 23, Vietnamese-American, and this little corner of the internet is where I keep the un-LinkedIn version of myself. Quant finance pays the bills, but tinkering with servers and chasing chord voicings is what I do for fun.

+

Hi! I'm Tyler, 24, Vietnamese-American, and this little corner of the internet is where I keep the un-LinkedIn version of myself. Banking pays the bills, but tinkering with servers, chasing chord voicings, and cooking dishes is what I do for fun.

Poke around β€” drag windows, open icons, click the bubbles. The professional site is elsewhere; this one's all play.

@@ -171,7 +235,7 @@
-
last.fm β€” tylertrains
+
last.fm β€” trollshotlol
recent
@@ -312,6 +376,22 @@
+ + +
❀ tyler
@@ -393,7 +473,7 @@ // music toggle + volume slider (theme-aware) const MUSIC = { aero: { src: '/mus/bazaar-theme.mp3', label: 'β™ͺ a-dog β€” bazaar theme' }, - chrome: { src: '/CoolMan - WhoIsUsingThisComputer_.mp3', label: 'β™ͺ coolman β€” who is using this computer?' }, + chrome: { src: '/mus/CoolMan - WhoIsUsingThisComputer_.mp3', label: 'β™ͺ coolman β€” who is using this computer?' }, }; document.getElementById('mt').innerHTML = Aero.musicToggleHTML(); const mtDiv = document.getElementById('mt'); @@ -517,6 +597,36 @@ }); } + // browser article loader + function browserLoad(src) { + const content = document.getElementById('browser-content'); + const urlBar = document.getElementById('browser-url'); + document.querySelectorAll('.browser-bm').forEach(b => b.classList.toggle('active', b.dataset.src === src)); + urlBar.textContent = 'fun.tylerhoang.xyz/' + src; + content.innerHTML = '
loading…
'; + fetch(src) + .then(r => { if (!r.ok) throw new Error(r.status); return r.text(); }) + .then(html => { + const doc = new DOMParser().parseFromString(html, 'text/html'); + // strip stylesheets, scripts, old styles + doc.querySelectorAll('link[rel="stylesheet"], style, script').forEach(el => el.remove()); + // strip Bootstrap navbar component (the nav bar itself, not the page wrapper) + doc.querySelectorAll('div.navbar').forEach(el => el.remove()); + // strip blink tags, preserving inner HTML (colored spans etc.) + doc.querySelectorAll('blink').forEach(el => { + el.replaceWith(...Array.from(el.childNodes)); + }); + content.innerHTML = doc.body.innerHTML; + content.scrollTop = 0; + }) + .catch(() => { + content.innerHTML = '
couldn\'t load article
'; + }); + } + document.querySelectorAll('.browser-bm').forEach(bm => { + bm.addEventListener('click', () => browserLoad(bm.dataset.src)); + }); + // fetch films Aero.fetchFilms() .then(data => { -- cgit v1.3-2-g0d8e