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.TFrame({ padding: 6 });
bar.pack.configure({ fill: 'x' });
const backBtn = bar.TButton({ text: '← Back' });
const fwdBtn = bar.TButton({ text: 'Forward →' });
const homeBtn = bar.TButton({ text: 'Home' });
const title = bar.TLabel({ 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.TFrame();
body.pack.configure({ fill: 'both', expand: true });
const text = body.Text({ wrap: 'word', borderwidth: 0, highlightthickness: 0 });
const sb = body.TScrollbar({ orient: 'vertical' });
__native_tcl(text._id, 'configure', '-yscrollcommand', sb._id + ' set');
__native_tcl(sb._id, 'configure', '-command', text._id + ' yview');
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', '.']) {
try {
__native_tcl_eval('close [open {' + b + '/index.md} r]');
return b;
} catch (e) {}
}
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