Editor refactored to expose controls; Edit moved into the doc header as the orange primary action; new Revisions dropdown lists page_revisions with a modal preview + Restore. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
69 lines
2.4 KiB
JavaScript
69 lines
2.4 KiB
JavaScript
// Page view: header + markdown editor + backlinks panel.
|
|
import { api } from '../api.js';
|
|
import { el, mount } from '../dom.js';
|
|
import { markdownEditor } from '../components/markdown_editor.js';
|
|
import { backButton } from '../components/backbtn.js';
|
|
import { breadcrumb } from '../components/breadcrumb.js';
|
|
import { exportMenu } from '../components/export_menu.js';
|
|
import { revisionsMenu } from '../components/revisions_menu.js';
|
|
|
|
export async function render(main, ctx) {
|
|
const id = ctx.params.id;
|
|
mount(main, el('p', { class: 'view-sub muted' }, 'Loading …'));
|
|
|
|
let page;
|
|
try { page = await api.get('/api/pages/' + id); }
|
|
catch (e) {
|
|
mount(main,
|
|
el('h1', { class: 'view-h1' }, 'Page not found'),
|
|
el('p', { class: 'view-sub muted' }, e.message)
|
|
);
|
|
return;
|
|
}
|
|
|
|
const editor = markdownEditor({
|
|
initial: page.body_md || '',
|
|
save: (value) => api.patch('/api/pages/' + id, { body_md: value })
|
|
});
|
|
|
|
const backlinksCard = el('div', { class: 'card' },
|
|
el('h3', {}, 'Backlinks'),
|
|
el('div', { id: 'backlinks-list' }, el('span', { class: 'muted' }, 'Loading …'))
|
|
);
|
|
|
|
mount(main,
|
|
el('div', { class: 'doc-head' },
|
|
el('div', { class: 'doc-head-left' }, backButton(), breadcrumb(page)),
|
|
el('div', { class: 'doc-actions' },
|
|
revisionsMenu(id, (md) => editor.setValue(md)),
|
|
editor.controls,
|
|
exportMenu({ filenameBase: page.slug, getContent: async () => ({ title: page.title, md: editor.value() }) })
|
|
)
|
|
),
|
|
el('h1', { class: 'view-h1' }, page.title),
|
|
el('p', { class: 'view-sub muted' }, '/' + page.slug),
|
|
editor.pane,
|
|
backlinksCard
|
|
);
|
|
|
|
try {
|
|
const links = await api.get('/api/pages/' + id + '/backlinks');
|
|
const list = document.getElementById('backlinks-list');
|
|
if (!links.length) mount(list, el('span', { class: 'muted' }, 'No backlinks yet.'));
|
|
else mount(list,
|
|
el('ul', { class: 'plain' }, links.map(l =>
|
|
el('li', {},
|
|
el('span', { class: 'status idle' }, l.from_type),
|
|
' ',
|
|
l.source_title || el('span', { class: 'muted' }, '(untitled)'),
|
|
' ',
|
|
el('span', { class: 'muted', style: { fontSize: '11px' } }, 'rel: ' + l.relation)
|
|
)
|
|
))
|
|
);
|
|
} catch (e) {
|
|
const list = document.getElementById('backlinks-list');
|
|
if (list) mount(list, el('span', { class: 'muted' }, 'Could not load: ' + e.message));
|
|
}
|
|
}
|