feat(ui): Space view — Projects + Open tasks side-by-side; full pages & refs table
Was capped at 6 pages/refs; now lists all pages + refs (≤200) in a table below. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,29 +1,23 @@
|
|||||||
// Space view — header + three columns (projects, recent open tasks, recent pages/refs).
|
// Space view — Projects + Open tasks side by side at the top, then a full
|
||||||
|
// pages & references table below (all pages; refs up to the API max).
|
||||||
import { api } from '../api.js';
|
import { api } from '../api.js';
|
||||||
import { el, mount } from '../dom.js';
|
import { el, mount } from '../dom.js';
|
||||||
|
|
||||||
function projCard(p) {
|
function projItem(p) {
|
||||||
return el('li', {},
|
return el('li', {},
|
||||||
el('a', { href: '#/project/' + p.id }, p.name),
|
el('a', { href: '#/project/' + p.id }, p.name), ' ',
|
||||||
' ',
|
el('span', { class: 'status' + (p.status === 'done' ? ' ok' : p.status === 'paused' ? ' warn' : '') }, p.status));
|
||||||
el('span', { class: 'status' + (p.status === 'done' ? ' ok' : p.status === 'paused' ? ' warn' : '') }, p.status)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function taskCard(t) {
|
function taskItem(t) {
|
||||||
return el('li', {},
|
return el('li', {},
|
||||||
el('span', { class: 'status' + (t.status === 'blocked' ? ' bad' : '') }, t.status),
|
el('span', { class: 'status' + (t.status === 'blocked' ? ' bad' : '') }, t.status), ' ', t.title);
|
||||||
' ', t.title
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pageCard(p) {
|
function tableRow(href, title, type) {
|
||||||
return el('li', {}, el('a', { href: '#/page/' + p.id }, p.title));
|
return el('tr', {},
|
||||||
}
|
el('td', { style: { padding: '5px 8px', borderTop: '1px solid var(--border)' } }, el('a', { href }, title || '(untitled)')),
|
||||||
|
el('td', { class: 'muted', style: { padding: '5px 8px', borderTop: '1px solid var(--border)', width: '90px' } }, type));
|
||||||
function refCard(r) {
|
|
||||||
return el('li', {}, el('a', { href: '#/ref/' + r.id }, r.title || r.source_url || '(untitled)'),
|
|
||||||
' ', el('span', { class: 'status idle' }, r.kind));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function render(main, ctx) {
|
export async function render(main, ctx) {
|
||||||
@@ -47,35 +41,46 @@ export async function render(main, ctx) {
|
|||||||
const [projects, tasks, pages, refs] = await Promise.all([
|
const [projects, tasks, pages, refs] = await Promise.all([
|
||||||
api.get(`/api/spaces/${id}/projects`).catch(() => []),
|
api.get(`/api/spaces/${id}/projects`).catch(() => []),
|
||||||
api.get(`/api/spaces/${id}/tasks?status=todo`).catch(() => []),
|
api.get(`/api/spaces/${id}/tasks?status=todo`).catch(() => []),
|
||||||
api.get(`/api/spaces/${id}/pages`).catch(() => []),
|
api.get(`/api/spaces/${id}/pages`).catch(() => []), // returns ALL pages
|
||||||
api.get(`/api/refs?space_id=${id}&limit=8`).catch(() => [])
|
api.get(`/api/refs?space_id=${id}&limit=200`).catch(() => []) // 200 = API max
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const rows = [
|
||||||
|
...pages.map(p => tableRow('#/page/' + p.id, p.title, 'page')),
|
||||||
|
...refs.map(r => tableRow('#/ref/' + r.id, r.title || r.source_url, r.kind))
|
||||||
|
];
|
||||||
|
|
||||||
mount(main,
|
mount(main,
|
||||||
el('h1', { class: 'view-h1' }, space.name),
|
el('h1', { class: 'view-h1' }, space.name),
|
||||||
el('p', { class: 'view-sub' }, space.description || el('span', { class: 'muted' }, 'No description.')),
|
el('p', { class: 'view-sub' }, space.description || el('span', { class: 'muted' }, 'No description.')),
|
||||||
|
|
||||||
|
// Top: Projects + Open tasks, side by side.
|
||||||
el('div', { class: 'row' },
|
el('div', { class: 'row' },
|
||||||
el('div', { class: 'card' },
|
el('div', { class: 'card' },
|
||||||
el('h3', {}, 'Projects'),
|
el('h3', {}, `Projects${projects.length ? ` (${projects.length})` : ''}`),
|
||||||
projects.length
|
projects.length
|
||||||
? el('ul', { class: 'plain' }, projects.map(projCard))
|
? el('ul', { class: 'plain' }, projects.map(projItem))
|
||||||
: el('p', { class: 'muted' }, 'None yet.')
|
: el('p', { class: 'muted' }, 'None yet.')
|
||||||
),
|
),
|
||||||
el('div', { class: 'card' },
|
el('div', { class: 'card' },
|
||||||
el('h3', {}, 'Open tasks'),
|
el('h3', {}, `Open tasks${tasks.length ? ` (${tasks.length})` : ''}`),
|
||||||
tasks.length
|
tasks.length
|
||||||
? el('ul', { class: 'plain' }, tasks.slice(0, 10).map(taskCard))
|
? el('ul', { class: 'plain' }, tasks.map(taskItem))
|
||||||
: el('p', { class: 'muted' }, 'Clear board.')
|
: el('p', { class: 'muted' }, 'Clear board.')
|
||||||
),
|
|
||||||
el('div', { class: 'card' },
|
|
||||||
el('h3', {}, 'Recent pages & refs'),
|
|
||||||
pages.length || refs.length
|
|
||||||
? el('ul', { class: 'plain' }, [
|
|
||||||
...pages.slice(0, 6).map(pageCard),
|
|
||||||
...refs.slice(0, 6).map(refCard)
|
|
||||||
])
|
|
||||||
: el('p', { class: 'muted' }, 'Nothing here yet.')
|
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Below: the full pages & references table.
|
||||||
|
el('div', { class: 'card' },
|
||||||
|
el('h3', {}, `Pages & references${rows.length ? ` (${pages.length + refs.length})` : ''}`),
|
||||||
|
rows.length
|
||||||
|
? el('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: '13px' } },
|
||||||
|
el('thead', {},
|
||||||
|
el('tr', {},
|
||||||
|
el('th', { class: 'muted', style: { textAlign: 'left', padding: '5px 8px', fontWeight: '500' } }, 'Title'),
|
||||||
|
el('th', { class: 'muted', style: { textAlign: 'left', padding: '5px 8px', width: '90px', fontWeight: '500' } }, 'Type'))),
|
||||||
|
el('tbody', {}, rows))
|
||||||
|
: el('p', { class: 'muted' }, 'Nothing here yet.')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user