Popular is a top 10; a Directory lists every listed feed A to Z

- GET /api/popular returns the ten most subscribed feeds. The new GET
  /api/directory returns every feed that may be listed, sorted by name,
  from the same list: everyone counted, you included, never a URL, never
  a private feed or a feed inside an OPML. POST /api/popular/{id} still
  subscribes to anything on it.
- A Directory button sits beside Popular; both open the same list
  screen. The sidebar toolbar wraps rather than squeezing four buttons.
- Tests: the directory is A to Z, Popular is its top ten, Paid Show is
  in neither, and subscribing works from the directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016HdTEWQNrzyFULijigkmMn
This commit is contained in:
2026-09-11 14:13:16 +00:00
parent c0f4b0bcb2
commit f3825cfc57
7 changed files with 62 additions and 22 deletions

View File

@@ -75,7 +75,7 @@ a{color:var(--accent)}
color:var(--dim);flex:none;
}
.iconbtn:hover{background:var(--raise);color:var(--fg)}
.sidetools{display:flex;gap:6px;padding:0 12px 10px}
.sidetools{display:flex;flex-wrap:wrap;gap:6px;padding:0 12px 10px}
.sidetools button,.sidefoot button{
flex:1;background:var(--panel2);border:1px solid var(--line);border-radius:8px;
padding:6px 8px;font-size:12.5px;color:var(--dim);
@@ -373,7 +373,8 @@ input[type=range]::-moz-range-thumb{width:12px;height:12px;border:0;border-radiu
</div>
<div class="sidetools">
<button id="addFeed">+ Feed</button>
<button id="popularFeeds" title="What everyone on this server subscribes to">Popular</button>
<button id="popularFeeds" title="The ten most subscribed feeds on this server">Popular</button>
<button id="directoryFeeds" title="Every feed anyone on this server subscribes to">Directory</button>
<button id="scanAll">Scan all</button>
</div>
<div class="searchwrap"><input type="search" id="feedFilter" placeholder="Filter feeds…"></div>
@@ -1148,7 +1149,7 @@ $('#addFeed').onclick=()=>{
<div class="cardacts"><button class="btn" onclick="closeModal()">Cancel</button>
<button class="btn primary" id="nsave">Add feed</button></div>`);
$('#nurl').focus();
showPopular();
listFeeds('/api/popular');
$('#nsave').onclick=async()=>{
const url=$('#nurl').value.trim(); if(!url) return;
$('#nsave').textContent='Adding…'; $('#nsave').disabled=true;
@@ -1164,10 +1165,10 @@ $('#addFeed').onclick=()=>{
// What everyone here reads, you included, as a place to start. The rows carry an id, never a
// URL, so a key in someone's feed address never reaches this page.
async function showPopular(){
async function listFeeds(url){
const box=$('#popular');
let rows=[];
try{ rows=await api('/api/popular')||[]; }catch{}
try{ rows=await api(url)||[]; }catch{}
box.innerHTML=rows.length?'':'<p class="hint">Nothing yet. Feeds people here subscribe to show up here.</p>';
for(const p of rows){
const el=document.createElement('div');
@@ -1189,14 +1190,19 @@ async function showPopular(){
}
}
$('#popularFeeds').onclick=()=>{
openModal(`<h3>Popular on this server</h3>
<p class="hint" style="margin:-6px 0 12px">What everyone here subscribes to, you included, most
subscribers first. Feeds inside an OPML subscription, and private feeds, are never listed.</p>
// Popular and the directory are the same list: the top ten by subscribers, or all of it A to Z.
function listedModal(title,blurb,url){
openModal(`<h3>${title}</h3>
<p class="hint" style="margin:-6px 0 12px">${blurb} Everyone counts, you included. Feeds inside
an OPML subscription, and private feeds, are never listed.</p>
<div class="childlist" id="popular"><p class="hint">Loading…</p></div>
<div class="cardacts"><button class="btn" onclick="closeModal()">Close</button></div>`);
showPopular();
};
listFeeds(url);
}
$('#popularFeeds').onclick=()=>listedModal('Popular on this server',
'The ten feeds with the most subscribers here.','/api/popular');
$('#directoryFeeds').onclick=()=>listedModal('Directory',
'Every feed anyone on this server subscribes to, A to Z.','/api/directory');
let expanded = new Set(JSON.parse(localStorage.getItem('ipx.expanded')||'[]'));
function toggleGroup(id){