The Directory was one grid of every listed feed, 1,472 in production, under Podcasts and Blogs tabs, a wall of about 30 category buttons and a sort menu, with a picked category's subcategories appearing as a second row of buttons that looked like the first. It read as a list to scroll, and the two rows were hard to tell apart. It opens now on the ten most subscribed feeds, ranked, and the categories as tiles, each with three of its shows' covers fanned in its corner on the tint its initials would get, so the shows colour it and no theme's palette changes. A category has a page of its own: its most subscribed, its subcategories with how many each holds, and its grid. See all is every feed, as the grid was. Podcasts or Blogs holds across every page. Popular, the ten most subscribed, had a place of its own in the feed list; it is the Directory's first section instead, and its key, g p, is gone. /api/popular stays for scripts. The search box finds a feed in the Directory by name (#126). It said "Search items…" there and did nothing, since loadEntries returns early for a place that lists feeds. A feed you do not subscribe to opens a page of its own (#128): its cover, category (a link to that category's page), how many here subscribe, a subscribe button and its latest twenty items, each with its title, linking to the post where it has one, its first lines, date and length. Before, a click on it did nothing; only its + did. The items come from GET /api/directory/{id}, which answers only for a feed the Directory lists, so a guessed id reaches nothing private, and carries no file or its address. The feed's own description would belong at the top, but the database does not keep one. Every tile and chart row takes the keyboard, as the feed list's rows do. Feed text made plain keeps a space at a line break or a paragraph's end, which glued "2010)Recorded" together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
108
web/app.css
108
web/app.css
@@ -637,27 +637,86 @@ body.scan-this .fhead [data-a=scan] .i,body.scan-any .fhead [data-a=scanall] .i,
|
||||
/* Quiet buttons: a filled one on every row outshouted the row that is playing. */
|
||||
#listening [data-a=play]{color:var(--accent)}
|
||||
#listening [data-a=remove]{color:var(--faint)}
|
||||
/* Directory's filters: .tabs for what a feed is, as the item filters are, and chips for what it
|
||||
is about. A picked chip is underlined in --accent2, as the download bar and the now-playing EQ
|
||||
are; a .badge's fill already means unread in the sidebar. */
|
||||
.dirbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:4px}
|
||||
.dirbar .tabs{flex:none}
|
||||
/* The Directory, laid out as Apple's is: a large title, then sections. Every page carries what
|
||||
kind of feed (.tabs, as the item filters are) in its title row. */
|
||||
.dhead{margin-bottom:6px}
|
||||
.dback{display:inline-flex;align-items:center;gap:5px;margin:0 0 8px -5px;padding:3px 5px;border-radius:6px;font-size:13px;color:var(--accent)}
|
||||
.dback .i{width:11px;height:11px}
|
||||
.dback:hover{background:var(--raise)}
|
||||
.dtitle{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 18px}
|
||||
.dtitle h2{margin:0;font-size:30px;line-height:1.15;font-weight:700;letter-spacing:-.02em;overflow-wrap:anywhere}
|
||||
.dhead .sub{margin:5px 0 0;color:var(--dim);font-size:13px;font-variant-numeric:tabular-nums}
|
||||
.dsec{margin-top:28px}
|
||||
.dsech{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:10px}
|
||||
.dsech h3{margin:0;font-size:19px;line-height:1.25;font-weight:650;letter-spacing:-.01em}
|
||||
.dall{font-size:13px;color:var(--accent);flex:none}
|
||||
.dall:hover{text-decoration:underline}
|
||||
/* The most subscribed, numbered because they are ranked: down one column, then the next. */
|
||||
.chart{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:repeat(var(--rows,5),auto);grid-auto-flow:column;column-gap:32px}
|
||||
.rank{display:grid;grid-template-columns:22px 52px minmax(0,1fr) auto;align-items:center;gap:12px;padding:8px 0;border-bottom:1px solid var(--line)}
|
||||
.rank .no{font-size:17px;font-weight:650;color:var(--faint);text-align:right;font-variant-numeric:tabular-nums}
|
||||
.rank .art{width:52px;height:52px;font-size:16px}
|
||||
.rank .txt b{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;overflow-wrap:anywhere;font-weight:500;font-size:14px;line-height:1.3}
|
||||
.rank .txt small{display:block;margin-top:2px;color:var(--faint);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||
/* A category: its name on the tint its initials would get, its three most subscribed shows'
|
||||
covers fanned in the corner, so the shows are what colour it. The fan opens a little under the
|
||||
pointer, the only thing on the page that moves. */
|
||||
.cats{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px}
|
||||
.cat{
|
||||
position:relative;overflow:hidden;height:116px;padding:13px 15px;border-radius:12px;text-align:left;
|
||||
display:flex;flex-direction:column;align-items:flex-start;
|
||||
background:color-mix(in srgb,var(--tint) 15%,var(--panel));border:1px solid color-mix(in srgb,var(--tint) 28%,var(--line));
|
||||
}
|
||||
.cat:hover{border-color:var(--accent)}
|
||||
/* The whole width: the fan sits below two lines of name, and a narrower name broke Government
|
||||
in two in the wider faces, Classic's and Glass's. */
|
||||
.cat b{font-size:16px;line-height:1.2;font-weight:650;color:var(--fg);overflow-wrap:break-word}
|
||||
.cat small{margin-top:3px;font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}
|
||||
.cat .fan{position:absolute;right:14px;bottom:-12px;width:112px;height:80px;pointer-events:none}
|
||||
.cat .fan .art{position:absolute;bottom:0;width:62px;height:62px;font-size:16px;border-radius:8px;box-shadow:0 3px 10px rgba(0,0,0,.3);transition:transform .2s ease-out}
|
||||
.cat .fan .art:nth-last-child(1){right:0;transform:rotate(8deg) translateY(-12px)}
|
||||
.cat .fan .art:nth-last-child(2){right:25px;transform:rotate(-3deg) translateY(-4px)}
|
||||
.cat .fan .art:nth-last-child(3){right:50px;transform:rotate(-13deg) translateY(4px)}
|
||||
.cat:hover .fan .art:nth-last-child(1){transform:rotate(12deg) translate(4px,-16px)}
|
||||
.cat:hover .fan .art:nth-last-child(3){transform:rotate(-18deg) translate(-6px,4px)}
|
||||
/* A category's subcategories, each with how many it holds, then the order. A picked one is
|
||||
drawn as a picked tab is. */
|
||||
.dtools{display:flex;align-items:center;gap:10px 14px;margin-bottom:14px}
|
||||
.pills{display:flex;flex-wrap:wrap;gap:6px;flex:1 1 0;min-width:0}
|
||||
.pills button{flex:none;padding:4px 11px;border:1px solid var(--line);border-radius:999px;font-size:13px;color:var(--dim);white-space:nowrap}
|
||||
.pills button small{margin-left:6px;color:var(--faint);font-size:11.5px;font-variant-numeric:tabular-nums}
|
||||
.pills button:hover{border-color:var(--accent);color:var(--fg)}
|
||||
.pills button.on{background:var(--raise);border-color:var(--raise);color:var(--fg);font-weight:500}
|
||||
.dtools .grow{flex:1}
|
||||
#dirsort{flex:none;width:auto;padding:4px 6px;font-size:13px}
|
||||
.chips{display:flex;flex-wrap:wrap;gap:2px 6px;flex:1 1 0;min-width:0}
|
||||
/* A category's subcategories go on a line of their own, under the category picked. */
|
||||
.chips.subs{flex-basis:100%}
|
||||
.chips button{flex:none;padding:4px 6px;font-size:13px;color:var(--dim);white-space:nowrap;border-bottom:2px solid transparent}
|
||||
.chips button:hover{color:var(--fg)}
|
||||
.chips button[aria-pressed="true"]{color:var(--fg);border-bottom-color:var(--accent2)}
|
||||
/* Square cover art, title underneath: podcast art is made to be known at a glance. The subscribe
|
||||
button stays visible, since a button that only shows on hover cannot be reached on a phone. */
|
||||
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:18px 14px;margin-top:14px}
|
||||
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:18px 14px}
|
||||
.tiles>.hint{grid-column:1/-1}
|
||||
.tile{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 2px;align-items:start;cursor:pointer}
|
||||
.tile{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px 2px;align-items:start}
|
||||
.tile .art{grid-column:1/-1;width:100%;height:auto;aspect-ratio:1;font-size:34px}
|
||||
.tile .txt b{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;overflow-wrap:anywhere;font-weight:500;font-size:13px;line-height:1.3}
|
||||
.tile .txt small{display:block;color:var(--faint);font-size:11.5px}
|
||||
.tile:hover .txt b{color:var(--accent)}
|
||||
/* Every one opens: yours its feed, the rest their page here. */
|
||||
.tile,.rank{cursor:pointer}
|
||||
.tile:hover .txt b,.rank:hover .txt b{color:var(--accent)}
|
||||
/* A feed's page before you subscribe, as Apple's show page: the cover large, what it is and who
|
||||
here reads it beside it, then what it has published lately. */
|
||||
.show{display:flex;gap:22px;align-items:flex-end;margin-top:4px}
|
||||
.show>.art{width:180px;height:180px;font-size:48px;border-radius:12px;box-shadow:var(--shadow)}
|
||||
.show .meta{min-width:0;flex:1;display:flex;flex-direction:column;align-items:flex-start;gap:5px}
|
||||
.show h2{margin:0 0 2px;font-size:30px;line-height:1.15;font-weight:700;letter-spacing:-.02em;overflow-wrap:anywhere}
|
||||
.show .sub{margin:0;color:var(--dim);font-size:13px;font-variant-numeric:tabular-nums}
|
||||
.show .acts{margin-top:8px}
|
||||
.dlink{padding:0;font-size:13px;color:var(--accent);text-align:left}
|
||||
.dlink:hover{text-decoration:underline}
|
||||
.latest{max-width:760px}
|
||||
.lep{padding:12px 0;border-bottom:1px solid var(--line)}
|
||||
.lep b{display:block;font-size:15px;font-weight:600;line-height:1.35;overflow-wrap:anywhere}
|
||||
.lep b a{color:var(--fg);text-decoration:none}
|
||||
.lep b a:hover{color:var(--accent)}
|
||||
.lep p{margin:4px 0 0;color:var(--dim);font-size:13px;line-height:1.5;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
|
||||
.lep small{display:flex;align-items:center;gap:7px;margin-top:6px;color:var(--faint);font-size:12px;font-variant-numeric:tabular-nums}
|
||||
/* Outlined, not filled: on --raise the warning and error colours fell short of AA in most light
|
||||
themes, where on the row's own ground they clear it. */
|
||||
.tag{
|
||||
@@ -686,7 +745,7 @@ body.scan-this .fhead [data-a=scan] .i,body.scan-any .fhead [data-a=scanall] .i,
|
||||
/* A selected row is --raise too, and the zero count's pill vanished into it. */
|
||||
.sel .badge.zero{background:var(--bg)}
|
||||
/* Counts, sizes and times that change in place should not jiggle the text around them. */
|
||||
.badge,.feed small,.childrow small,.tile small,.ep,.fhead .sub,.dmeta,#status,#seekrow{font-variant-numeric:tabular-nums}
|
||||
.badge,.feed small,.childrow small,.tile small,.rank small,.ep,.fhead .sub,.dmeta,#status,#seekrow{font-variant-numeric:tabular-nums}
|
||||
|
||||
/* ---------- main ---------- */
|
||||
#main{overflow:hidden;min-height:0;min-width:0;display:flex;flex-direction:column}
|
||||
@@ -1061,9 +1120,22 @@ body:has(#player.on) #status{padding-bottom:3px}
|
||||
#pnow .txt small,#pright #vol{display:none}
|
||||
.wrap.plain{padding:14px}
|
||||
.card{padding:16px}
|
||||
/* The chips get a line of their own and scroll sideways rather than wrap, so they never push
|
||||
the grid down. */
|
||||
.chips{flex:1 1 100%;flex-wrap:nowrap;overflow-x:auto}
|
||||
/* The subcategories get a line of their own and scroll sideways rather than wrap, so they
|
||||
never push the grid down. */
|
||||
.dtitle h2{font-size:25px}
|
||||
.dsec{margin-top:22px}
|
||||
.dsech h3{font-size:17px}
|
||||
.chart{grid-template-columns:minmax(0,1fr);grid-template-rows:none;grid-auto-flow:row}
|
||||
.cats{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
|
||||
.cat{height:100px;padding:11px 12px}
|
||||
.cat b{font-size:15px}
|
||||
.cat .fan{right:6px;bottom:-16px;transform:scale(.7);transform-origin:bottom right}
|
||||
.pills{flex:1 1 100%;flex-wrap:nowrap;overflow-x:auto}
|
||||
.dtools{flex-wrap:wrap}
|
||||
.show{flex-direction:column;align-items:flex-start;gap:14px}
|
||||
.show>.art{width:150px;height:150px;font-size:40px}
|
||||
.show h2{font-size:24px}
|
||||
#dirsort{margin-left:auto}
|
||||
.tiles{grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:14px 10px}
|
||||
|
||||
/* A log line has no room for four columns: keep time and message, wrap as prose. */
|
||||
|
||||
Reference in New Issue
Block a user