From fa960ec204ea859e7cb8aa48717211ca4e6eaff8 Mon Sep 17 00:00:00 2001 From: Tyler Koenig Date: Sat, 16 May 2026 22:46:01 -0400 Subject: [PATCH] feat(ui): inline expansion for cards view at mobile Same accordion pattern as stream: card-row gets entity-exp markup, selectEntity/expandInline/dismissPeek/Escape all handle .card-row. Fullscreen expand works for both views. --- web/app.js | 33 ++++++++++++++++++++------------- web/style.css | 28 ++++++++++++++++++---------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/web/app.js b/web/app.js index 249a830..5d2904e 100644 --- a/web/app.js +++ b/web/app.js @@ -636,14 +636,21 @@ const affHtml = affs.map(a => `${AFF_LABELS[a]}`).join(''); return `
- ${escHtml(title)} - - ${preview} -
- ${affHtml} - ${tags} - ${e.pinned ? '' : ''} - ${e.use_count > 0 ? `${e.use_count}×` : ''} +
+ ${escHtml(title)} + + ${preview} +
+ ${affHtml} + ${tags} + ${e.pinned ? '' : ''} + ${e.use_count > 0 ? `${e.use_count}×` : ''} +
+
+
+
+ ${renderInlineDetail(e)} +
`; } @@ -1138,9 +1145,9 @@ } else { state.selectedIndex = idx; } - $$('.entity-item.selected').forEach(el => el.classList.remove('selected')); + $$('.entity-item.selected, .card-row.selected').forEach(el => el.classList.remove('selected')); if (state.selectedIndex >= 0) { - const target = $(`.entity-item[data-index="${state.selectedIndex}"]`); + const target = $(`.entity-item[data-index="${state.selectedIndex}"], .card-row[data-index="${state.selectedIndex}"]`); if (target) target.classList.add('selected'); } return; @@ -1459,7 +1466,7 @@ }, expandInline() { - const sel = $(`.entity-item.selected`); + const sel = $(`.entity-item.selected, .card-row.selected`); if (!sel) return; sel.classList.toggle('exp-full'); const btn = sel.querySelector('.exp-toolbar .peek-mobile-btn'); @@ -1468,7 +1475,7 @@ dismissPeek() { if (isMobileBreakpoint()) { - const sel = $(`.entity-item.selected`); + const sel = $(`.entity-item.selected, .card-row.selected`); if (sel) sel.classList.remove('selected', 'exp-full'); state.selectedIndex = -1; return; @@ -1531,7 +1538,7 @@ if (ev.key === 'Escape') { if (isMobileBreakpoint()) { if (state.selectedIndex >= 0) { - const sel = $(`.entity-item.selected`); + const sel = $(`.entity-item.selected, .card-row.selected`); if (sel) sel.classList.remove('selected', 'exp-full'); state.selectedIndex = -1; return; diff --git a/web/style.css b/web/style.css index 647de4a..07fb835 100644 --- a/web/style.css +++ b/web/style.css @@ -600,20 +600,23 @@ main.focus-peek .resize-handle { visibility: hidden; } /* ── CARD ROWS ──────────────────────────────────────── */ .card-row { - display: flex; - align-items: center; - gap: 7px; - padding: 9px 12px 9px 14px; margin: 2px 10px; background: var(--surf); border: 1px solid var(--border); border-radius: var(--r2); cursor: pointer; - min-height: 40px; position: relative; transition: border-color var(--t-fast), background var(--t-fast); } +.card-head { + display: flex; + align-items: center; + gap: 7px; + padding: 9px 12px 9px 14px; + min-height: 40px; +} + .card-row:hover { border-color: var(--muted); } .card-row.selected { border-color: var(--accent); background: var(--a-bg); } .card-row.pinned { border-left: 2px solid var(--accent); } @@ -1531,10 +1534,13 @@ kbd { background: var(--raised); border: 1px solid var(--border); border-radius: grid-template-rows: 0fr; transition: grid-template-rows .2s ease; } - .entity-item.selected .entity-exp { grid-template-rows: 1fr; } - .entity-item.selected .exp-toolbar { display: flex; } + .entity-item.selected .entity-exp, + .card-row.selected .entity-exp { grid-template-rows: 1fr; } + .entity-item.selected .exp-toolbar, + .card-row.selected .exp-toolbar { display: flex; } .entity-item.exp-full, - .entity-item.is-card.exp-full { + .entity-item.is-card.exp-full, + .card-row.exp-full { position: fixed; inset: 0; z-index: 60; @@ -1544,7 +1550,9 @@ kbd { background: var(--raised); border: 1px solid var(--border); border-radius: margin: 0; border-radius: 0; } - .entity-item.exp-full .entity-exp { grid-template-rows: 1fr; } - .entity-item.exp-full .exp-inner { padding-top: 1rem; padding-bottom: 2rem; } + .entity-item.exp-full .entity-exp, + .card-row.exp-full .entity-exp { grid-template-rows: 1fr; } + .entity-item.exp-full .exp-inner, + .card-row.exp-full .exp-inner { padding-top: 1rem; padding-bottom: 2rem; } main.focus-peek #entity-panel { display: block; overflow: auto; min-width: 0; } }