feat: all apps in sidebar sorted by activity; inactive apps grouped below divider

This commit is contained in:
posimai 2026-03-22 23:31:58 +09:00
parent f85ad8bd8d
commit 6944c83c0b
2 changed files with 40 additions and 5 deletions

View File

@ -908,7 +908,8 @@ function hasNext(tasks) { return tasks.some(t => t.status === 'next'); }
// ── Sidebar nav ──────────────────────────────────────────────────────────────── // ── Sidebar nav ────────────────────────────────────────────────────────────────
function renderAppNav() { function renderAppNav() {
const q = appSearch.toLowerCase(); const q = appSearch.toLowerCase();
const allApps = [...data.apps, { id: 'global', tasks: data.global || [] }]; const globalEntry = { id: 'global', tasks: data.global || [] };
const allApps = [globalEntry, ...data.apps];
const filtered = q ? allApps.filter(a => a.id.toLowerCase().includes(q)) : allApps; const filtered = q ? allApps.filter(a => a.id.toLowerCase().includes(q)) : allApps;
// Update total open count // Update total open count
@ -922,23 +923,40 @@ function renderAppNav() {
const upd = document.getElementById('sidebarUpdatedLabel'); const upd = document.getElementById('sidebarUpdatedLabel');
if (upd && data.updated) upd.textContent = `更新: ${data.updated}`; if (upd && data.updated) upd.textContent = `更新: ${data.updated}`;
let html = ''; // Sort: global first, then active apps (next > any open > done-only), then inactive apps (alpha)
for (const app of filtered) { const globalList = filtered.filter(a => a.id === 'global');
const active = filtered.filter(a => a.id !== 'global' && openCount(a.tasks) > 0)
.sort((a, b) => (hasNext(b.tasks) ? 1 : 0) - (hasNext(a.tasks) ? 1 : 0));
const inactive = filtered.filter(a => a.id !== 'global' && openCount(a.tasks) === 0)
.sort((a, b) => a.id.localeCompare(b.id));
function navItem(app) {
const open = openCount(app.tasks); const open = openCount(app.tasks);
const hn = hasNext(app.tasks); const hn = hasNext(app.tasks);
const isActive = currentView === 'app' && currentApp === app.id; const isActive = currentView === 'app' && currentApp === app.id;
const countHtml = open > 0 const countHtml = open > 0
? `<span class="nav-count${hn ? ' has-next' : ''}">${open}</span>` ? `<span class="nav-count${hn ? ' has-next' : ''}">${open}</span>`
: ''; : '';
html += `<a class="nav-item${isActive ? ' active' : ''}" data-nav="app" data-app-id="${app.id}" href="#" role="listitem"> return `<a class="nav-item${isActive ? ' active' : ''}" data-nav="app" data-app-id="${app.id}" href="#" role="listitem">
<i data-lucide="${app.id === 'global' ? 'globe' : 'package'}" style="width:14px;height:14px;stroke-width:1.75"></i> <i data-lucide="${app.id === 'global' ? 'globe' : 'package'}" style="width:14px;height:14px;stroke-width:1.75"></i>
<span class="nav-item-label">${shortName(app.id)}</span> <span class="nav-item-label">${shortName(app.id)}</span>
${countHtml} ${countHtml}
<i data-lucide="chevron-right" style="width:11px;height:11px;stroke-width:2.5" class="nav-chevron"></i> <i data-lucide="chevron-right" style="width:11px;height:11px;stroke-width:2.5" class="nav-chevron"></i>
</a>`; </a>`;
} }
let html = '';
if (!filtered.length) { if (!filtered.length) {
html = '<div style="padding:8px 10px;font-size:12px;color:var(--text3);">該当なし</div>'; html = '<div style="padding:8px 10px;font-size:12px;color:var(--text3);">該当なし</div>';
} else {
globalList.forEach(a => { html += navItem(a); });
active.forEach(a => { html += navItem(a); });
if (inactive.length) {
if (active.length || globalList.length) {
html += `<div style="font-size:10px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:0.1em;padding:10px 8px 4px;opacity:0.7;">全アプリ</div>`;
}
inactive.forEach(a => { html += navItem(a); });
}
} }
document.getElementById('appNavList').innerHTML = html; document.getElementById('appNavList').innerHTML = html;

View File

@ -207,7 +207,24 @@
"done_at": null "done_at": null
} }
] ]
} },
{ "id": "posimai-dashboard", "tasks": [] },
{ "id": "posimai-brain", "tasks": [] },
{ "id": "posimai-daily", "tasks": [] },
{ "id": "posimai-reader", "tasks": [] },
{ "id": "posimai-journal", "tasks": [] },
{ "id": "posimai-site", "tasks": [] },
{ "id": "posimai-events", "tasks": [] },
{ "id": "posimai-maps", "tasks": [] },
{ "id": "posimai-ambient", "tasks": [] },
{ "id": "posimai-timer", "tasks": [] },
{ "id": "posimai-pulse", "tasks": [] },
{ "id": "posimai-lens", "tasks": [] },
{ "id": "posimai-diff", "tasks": [] },
{ "id": "posimai-clean", "tasks": [] },
{ "id": "posimai-digest", "tasks": [] },
{ "id": "posimai-think", "tasks": [] },
{ "id": "posimai-tech-events","tasks": [] }
], ],
"global": [ "global": [
{ {