feat: all apps in sidebar sorted by activity; inactive apps grouped below divider
This commit is contained in:
parent
f85ad8bd8d
commit
6944c83c0b
26
index.html
26
index.html
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
19
roadmap.json
19
roadmap.json
|
|
@ -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": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue