Line up the feed sidebar
Every row reserves the chevron slot, so artwork and titles share one column instead of stepping left when a feed has no children. Children keep a single icon size and read as nested from the indent alone. Labels stack on one line-height, and the unread count has a min-width so a three-digit feed doesn't shove its own title. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
14
PROGRESS.md
14
PROGRESS.md
@@ -56,6 +56,20 @@ and until now nothing set them.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-09-10 — Sidebar alignment
|
||||||
|
|
||||||
|
The feed list had four different left edges: a row with no children skipped the chevron entirely, so
|
||||||
|
its artwork sat a chevron-width left of a folder's; children then used a different indent *and* a
|
||||||
|
smaller icon. Nothing lined up with anything.
|
||||||
|
|
||||||
|
Every row now reserves the chevron slot whether or not it opens (an empty one is
|
||||||
|
`pointer-events:none`, so the click falls through to the row), all artwork is one size, and nesting
|
||||||
|
reads from the indent alone. Both label lines are `display:block` on a shared line-height instead of
|
||||||
|
an inline baseline, and the unread count has a `min-width` so three-digit feeds don't shove the
|
||||||
|
title. Rows came out shorter, so more feeds fit without scrolling.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-09-10 — An item's picture
|
## 2026-09-10 — An item's picture
|
||||||
|
|
||||||
An item's artwork now resolves in order of how deliberate the source is: `itunes:image`, then Media
|
An item's artwork now resolves in order of how deliberate the source is: `itunes:image`, then Media
|
||||||
|
|||||||
@@ -174,7 +174,8 @@ test('an OPML subscription is a collapsible folder', async ({ page }) => {
|
|||||||
body: JSON.stringify({ feed: 'test-subscriptions', force: true }),
|
body: JSON.stringify({ feed: 'test-subscriptions', force: true }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const chev = page.locator('.feed .chev');
|
// Every row reserves the chevron slot for alignment; only a folder's is clickable.
|
||||||
|
const chev = page.locator('.feed.group .chev');
|
||||||
await expect(chev).toBeVisible({ timeout: 20_000 });
|
await expect(chev).toBeVisible({ timeout: 20_000 });
|
||||||
|
|
||||||
// Closed by default: the child is not listed until the folder is opened.
|
// Closed by default: the child is not listed until the folder is opened.
|
||||||
|
|||||||
@@ -92,13 +92,13 @@ input:focus,select:focus{outline:0;border-color:var(--accent)}
|
|||||||
}
|
}
|
||||||
.feed:hover{background:var(--panel2)}
|
.feed:hover{background:var(--panel2)}
|
||||||
.feed.sel{background:var(--raise)}
|
.feed.sel{background:var(--raise)}
|
||||||
.feed.child{margin-left:14px}
|
.feed.child{margin-left:16px}
|
||||||
.feed.child .art{width:28px;height:28px;font-size:11px}
|
|
||||||
.chev{
|
.chev{
|
||||||
flex:none;width:18px;height:18px;display:grid;place-items:center;border-radius:4px;
|
flex:none;width:18px;height:18px;display:grid;place-items:center;border-radius:4px;
|
||||||
color:var(--faint);font-size:11px;transition:transform .12s;
|
color:var(--faint);font-size:11px;transition:transform .12s;
|
||||||
}
|
}
|
||||||
.chev:hover{background:var(--raise);color:var(--fg)}
|
.chev:empty{pointer-events:none}
|
||||||
|
.chev:not(:empty):hover{background:var(--raise);color:var(--fg)}
|
||||||
.chev.open{transform:rotate(90deg)}
|
.chev.open{transform:rotate(90deg)}
|
||||||
.childlist{display:grid;gap:4px;margin-top:10px}
|
.childlist{display:grid;gap:4px;margin-top:10px}
|
||||||
.childrow{
|
.childrow{
|
||||||
@@ -117,13 +117,13 @@ input:focus,select:focus{outline:0;border-color:var(--accent)}
|
|||||||
border-radius:7px;object-fit:cover;background:var(--raise);flex:none;
|
border-radius:7px;object-fit:cover;background:var(--raise);flex:none;
|
||||||
display:grid;place-items:center;color:var(--faint);font-weight:700;overflow:hidden;
|
display:grid;place-items:center;color:var(--faint);font-weight:700;overflow:hidden;
|
||||||
}
|
}
|
||||||
.feed .art{width:38px;height:38px;font-size:14px}
|
.feed .art{width:34px;height:34px;font-size:13px}
|
||||||
.feed .txt{min-width:0;flex:1}
|
.feed .txt{min-width:0;flex:1}
|
||||||
.feed .txt b{display:block;font-weight:600;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
.feed .txt b{display:block;font-weight:600;font-size:13.5px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||||
.feed .txt small{color:var(--faint);font-size:11.5px}
|
.feed .txt small{display:block;color:var(--faint);font-size:11.5px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||||
.badge{
|
.badge{
|
||||||
background:var(--accent);color:var(--ink);border-radius:20px;padding:1px 7px;
|
background:var(--accent);color:var(--ink);border-radius:20px;padding:1px 7px;
|
||||||
font-size:11px;font-weight:700;flex:none;
|
font-size:11px;font-weight:700;flex:none;min-width:26px;text-align:center;
|
||||||
}
|
}
|
||||||
.badge.zero{background:var(--raise);color:var(--faint)}
|
.badge.zero{background:var(--raise);color:var(--faint)}
|
||||||
|
|
||||||
@@ -461,7 +461,7 @@ function renderFeeds(){
|
|||||||
el.className='feed'+(S.feed===f.id?' sel':'')+(depth?' child':'')+(kids?' group':'');
|
el.className='feed'+(S.feed===f.id?' sel':'')+(depth?' child':'')+(kids?' group':'');
|
||||||
const open = kids && (expanded.has(f.id) || q);
|
const open = kids && (expanded.has(f.id) || q);
|
||||||
el.innerHTML =
|
el.innerHTML =
|
||||||
(kids?`<span class="chev${open?' open':''}" title="Show or hide the feeds inside">▶</span>`:'')+
|
`<span class="chev${open?' open':''}"${kids?' title="Show or hide the feeds inside"':''}>${kids?'▶':''}</span>`+
|
||||||
artHTML(f.image,f.title||f.id)+
|
artHTML(f.image,f.title||f.id)+
|
||||||
`<div class="txt"><b>${esc(f.title||f.id)}</b><small>`+
|
`<div class="txt"><b>${esc(f.title||f.id)}</b><small>`+
|
||||||
(kids?`${kids} feed${kids===1?'':'s'}${f.unread?` · ${f.unread} unread`:''}`
|
(kids?`${kids} feed${kids===1?'':'s'}${f.unread?` · ${f.unread} unread`:''}`
|
||||||
@@ -470,8 +470,7 @@ function renderFeeds(){
|
|||||||
(f.orphaned?'<span class="tag" title="No longer listed in the OPML, kept because it has downloads">gone</span>':'')+
|
(f.orphaned?'<span class="tag" title="No longer listed in the OPML, kept because it has downloads">gone</span>':'')+
|
||||||
`<span class="badge${f.unread?'':' zero'}">${f.unread}</span>`;
|
`<span class="badge${f.unread?'':' zero'}">${f.unread}</span>`;
|
||||||
el.onclick=()=>{ selectFeed(f.id); $('#sidebar').classList.remove('open'); };
|
el.onclick=()=>{ selectFeed(f.id); $('#sidebar').classList.remove('open'); };
|
||||||
const chev=$('.chev',el);
|
if(kids) $('.chev',el).onclick=ev=>{ ev.stopPropagation(); toggleGroup(f.id); };
|
||||||
if(chev) chev.onclick=ev=>{ ev.stopPropagation(); toggleGroup(f.id); };
|
|
||||||
list.appendChild(el);
|
list.appendChild(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user