diff --git a/public/views/space.js b/public/views/space.js index 757333a..3df4d09 100644 --- a/public/views/space.js +++ b/public/views/space.js @@ -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 { el, mount } from '../dom.js'; -function projCard(p) { +function projItem(p) { return el('li', {}, - el('a', { href: '#/project/' + p.id }, p.name), - ' ', - el('span', { class: 'status' + (p.status === 'done' ? ' ok' : p.status === 'paused' ? ' warn' : '') }, p.status) - ); + el('a', { href: '#/project/' + p.id }, p.name), ' ', + el('span', { class: 'status' + (p.status === 'done' ? ' ok' : p.status === 'paused' ? ' warn' : '') }, p.status)); } -function taskCard(t) { +function taskItem(t) { return el('li', {}, - el('span', { class: 'status' + (t.status === 'blocked' ? ' bad' : '') }, t.status), - ' ', t.title - ); + el('span', { class: 'status' + (t.status === 'blocked' ? ' bad' : '') }, t.status), ' ', t.title); } -function pageCard(p) { - return el('li', {}, el('a', { href: '#/page/' + p.id }, p.title)); -} - -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)); +function tableRow(href, title, type) { + 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)); } export async function render(main, ctx) { @@ -47,35 +41,46 @@ export async function render(main, ctx) { const [projects, tasks, pages, refs] = await Promise.all([ api.get(`/api/spaces/${id}/projects`).catch(() => []), api.get(`/api/spaces/${id}/tasks?status=todo`).catch(() => []), - api.get(`/api/spaces/${id}/pages`).catch(() => []), - api.get(`/api/refs?space_id=${id}&limit=8`).catch(() => []) + api.get(`/api/spaces/${id}/pages`).catch(() => []), // returns ALL pages + 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, el('h1', { class: 'view-h1' }, space.name), 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: 'card' }, - el('h3', {}, 'Projects'), + el('h3', {}, `Projects${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('div', { class: 'card' }, - el('h3', {}, 'Open tasks'), + el('h3', {}, `Open tasks${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('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.') ) ); }