Example: Markdown help viewer
A browsable documentation viewer built with MarkView: a
Back / Forward / Home toolbar over a scrolled Text
widget, driven by a Navigator. It's a trimmed-down version of the very app
scriptweaver --help runs.
Bundle the three MarkView modules (parser.js, render.js, nav.js) and your
.md pages next to this main.js, then run the folder or a .zip of it.
A toolbar
Three themed buttons and a title label, packed across the top:
import { Navigator } from './nav.js';
const bar = app.Frame({ padding: 6 });
bar.pack.configure({ fill: 'x' });
const backBtn = bar.Button({ text: '← Back' });
const fwdBtn = bar.Button({ text: 'Forward →' });
const homeBtn = bar.Button({ text: 'Home' });
const title = bar.Label({ text: '' });
for (const w of [backBtn, fwdBtn, homeBtn]) w.pack.configure({ side: 'left' });
title.pack.configure({ side: 'left', padx: 14 });
The page area
A Text widget and a vertical scrollbar, wired together:
const body = app.Frame();
body.pack.configure({ fill: 'both', expand: true });
const text = body.Text({ wrap: 'word', borderwidth: 0, highlightthickness: 0 });
const sb = body.Scrollbar({ orient: 'vertical' });
sb.attach(text); // wire both directions; axis from the scrollbar's orient
sb.pack.configure({ side: 'right', fill: 'y' });
text.pack.configure({ side: 'left', fill: 'both', expand: true });
Wiring the Navigator
The Navigator renders pages into the Text. Its onNavigate callback keeps
the title and the toolbar buttons in sync; the buttons drive history:
const nav = new Navigator(text, {
base: findBase(),
onNavigate(info) {
title.text = info.title;
app.wm.title('Help — ' + info.title);
backBtn.state(info.canBack ? '!disabled' : 'disabled');
fwdBtn.state(info.canForward ? '!disabled' : 'disabled');
},
});
backBtn.onClick = () => nav.back();
fwdBtn.onClick = () => nav.forward();
homeBtn.onClick = () => nav.go('index.md');
nav.go('index.md'); // open the home page
Finding the docs, disk or zip
Run loose during development and bundled in production from the same file by
probing for wherever index.md opens — on disk (docs/) or in a mounted zip
(//zipfs:/app/docs):
function findBase() {
for (const b of ['//zipfs:/app/docs', 'docs', '.']) {
if (sw.fs.exists(b + '/index.md')) return b;
}
return 'docs';
}
Mouse-wheel scrolling, relative links, #anchor jumps, external links (opened
in the system browser), and light/dark theming all come from MarkView — there's
nothing else to wire.
Run it
scriptweaver markview/main.js # loose, from the source tree
scriptweaver help.zip # bundled (main.js + modules + docs/)
Full source: markview/main.js.
See also
- MarkView: in-app Markdown — the component and its API
- Text — the widget it renders into
- Packaging apps — bundling the viewer and pages