orz-mdhtml 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,17 +36,16 @@ as the single source of truth; Save/Export re-serialize the whole document.
36
36
 
37
37
  ## Install / generate
38
38
 
39
- Requires Node 18+. Until this package is published to npm, use it from a clone:
39
+ Requires Node 18+. No install needed run it with `npx`:
40
40
 
41
41
  ```bash
42
- git clone https://github.com/wangyu16/orz-mdhtml.git
43
- cd orz-mdhtml
44
- npm install
45
- npm run bundle # build dist/orzmd.browser.js (the in-browser renderer)
46
- npm run gen -- path/to/doc.md # → path/to/doc.md.html
42
+ npx orz-mdhtml path/to/doc.md # → path/to/doc.md.html
47
43
  open path/to/doc.md.html
48
44
  ```
49
45
 
46
+ Or install the CLI globally (`npm i -g orz-mdhtml`), then `orz-mdhtml doc.md`.
47
+ To hack on it, clone the repo and use `npm run gen -- doc.md`.
48
+
50
49
  ### CLI options
51
50
 
52
51
  ```
@@ -54,11 +53,15 @@ orz-mdhtml <input.md> [options]
54
53
 
55
54
  -o, --out <file> output path (default: <input>.md.html)
56
55
  --theme <name> default theme id (default: light-academic-1)
57
- --inline embed the renderer bundle in the file (default; offline-capable renderer)
58
- --cdn reference the renderer from jsDelivr (needs orz-mdhtml-browser published)
56
+ --cdn reference the renderer from jsDelivr (default; small files)
57
+ --inline embed the renderer bundle (larger file, no renderer fetch)
59
58
  --title <text> document <title> (default: input filename)
60
59
  ```
61
60
 
61
+ By default (`--cdn`), the renderer is fetched from jsDelivr on first open and
62
+ cached, so generated files are small (~tens of KB). Use `--inline` to embed the
63
+ renderer (~750 KB) when you want the file to carry its own renderer.
64
+
62
65
  Themes: `light-academic-1/2`, `light-neat-1/2`, `light-playful-1/2`,
63
66
  `beige-decent-1/2`, `dark-elegant-1/2`. (Readers can switch live in the editor.)
64
67
 
@@ -104,7 +107,7 @@ whole-table/blockquote copy fix.
104
107
  - [x] Document-first UI: read / edit, iframe preview, incremental live updates
105
108
  - [x] Theme picker, reader font size, export, scroll-sync toggle
106
109
  - [x] copy-as-markdown via orz-markdown core
107
- - [ ] Publish `orz-mdhtml` (the CLI) and `orz-mdhtml-browser` (CDN bundle) to npm
110
+ - [x] Publish `orz-mdhtml` (the CLI) and `orz-mdhtml-browser` (CDN bundle) to npm
108
111
  - [ ] Optional fully-offline build (inline themes + editor libs)
109
112
  - [ ] Mermaid/KaTeX live re-render parity in the editor
110
113
 
package/assets/app.js CHANGED
@@ -63,11 +63,18 @@
63
63
  + '<article class="markdown-body" id="orz-doc"></article>'
64
64
  + '<script src="' + f.hljsJs + '"><\/script>'
65
65
  + '<script src="' + f.mermaidJs + '"><\/script>'
66
+ + '<script src="' + f.smilesJs + '"><\/script>'
66
67
  + '<script>try{mermaid.initialize({startOnLoad:false})}catch(e){}<\/script>'
67
68
  + '<script>' + guard(CFG.runtime) + '<\/script>'
68
69
  + '<script>window.__orzEnhance=function(){'
69
70
  + 'try{if(window.hljs){document.querySelectorAll("#orz-doc pre code:not(.hljs)").forEach(function(b){window.hljs.highlightElement(b)})}}catch(e){}'
70
71
  + 'try{if(window.mermaid){window.mermaid.run({querySelector:"#orz-doc .mermaid:not([data-processed])"})}}catch(e){}'
72
+ // SMILES: draw each canvas once (tracked via a JS prop so morphdom keeps
73
+ // the drawn canvas across edits — DOM attributes stay identical).
74
+ + 'try{if(window.SmilesDrawer){document.querySelectorAll("#orz-doc canvas[data-smiles]").forEach(function(c){if(c.__orzSmilesDone)return;var s=c.getAttribute("data-smiles");if(!s)return;c.__orzSmilesDone=true;var dr=new window.SmilesDrawer.Drawer({width:c.width,height:c.height});window.SmilesDrawer.parse(s,function(t){try{dr.draw(t,c,window.__orzSmilesTheme||"light",false)}catch(e){}},function(){})})}}catch(e){}'
75
+ // Tabs init runs in the runtime on load (empty #orz-doc); re-run now that
76
+ // content is injected, and after each incremental update. Idempotent.
77
+ + 'try{if(window.OrzMarkdownRuntime&&window.OrzMarkdownRuntime.initTabs){window.OrzMarkdownRuntime.initTabs(document)}}catch(e){}'
71
78
  + '};<\/script></body></html>';
72
79
  }
73
80
 
@@ -91,7 +98,20 @@
91
98
 
92
99
  function enhance() {
93
100
  var w = frame.contentWindow;
94
- if (w && typeof w.__orzEnhance === 'function') { try { w.__orzEnhance(); } catch (e) {} }
101
+ if (!w) return;
102
+ try { w.__orzSmilesTheme = themeById(currentTheme).scheme === 'dark' ? 'dark' : 'light'; } catch (e) {}
103
+ if (typeof w.__orzEnhance === 'function') { try { w.__orzEnhance(); } catch (e) {} }
104
+ }
105
+
106
+ // Re-draw SMILES canvases (fresh, cleared) so they pick up the current
107
+ // light/dark theme; used after a theme switch.
108
+ function redrawSmiles() {
109
+ var doc = frameDoc(); if (!doc) return;
110
+ Array.prototype.forEach.call(doc.querySelectorAll('#orz-doc canvas[data-smiles]'), function (c) {
111
+ var fresh = c.cloneNode(false); // drops the drawing + the __orzSmilesDone JS prop
112
+ if (c.parentNode) c.parentNode.replaceChild(fresh, c);
113
+ });
114
+ enhance();
95
115
  }
96
116
  // CDN libs inside the iframe load async — retry enhance a few times.
97
117
  function enhanceSoon() { enhance(); setTimeout(enhance, 150); setTimeout(enhance, 600); setTimeout(enhance, 1500); }
@@ -327,6 +347,7 @@
327
347
  root.setAttribute('data-chrome', t.scheme);
328
348
  if (themeSelect) themeSelect.value = id;
329
349
  applyThemeToFrame(t);
350
+ redrawSmiles(); // pick up the new light/dark SMILES palette
330
351
  if (cm) cm.setOption('theme', cmTheme(t.scheme));
331
352
  markDirty();
332
353
  }
@@ -463,19 +484,30 @@
463
484
  }
464
485
 
465
486
  // ---- version check -------------------------------------------------------
487
+ // True only when `a` is a strictly newer semver than `b` (so an older
488
+ // resolved version never shows a bogus "update available").
489
+ function isNewer(a, b) {
490
+ var pa = String(a).split('.'), pb = String(b).split('.');
491
+ for (var i = 0; i < 3; i++) {
492
+ var x = parseInt(pa[i], 10) || 0, y = parseInt(pb[i], 10) || 0;
493
+ if (x > y) return true;
494
+ if (x < y) return false;
495
+ }
496
+ return false;
497
+ }
466
498
  function checkVersion() {
467
499
  if (!CFG.versionManifest || !CFG.rendererVersion) return;
468
500
  try {
469
501
  var cached = JSON.parse(localStorage.getItem('orz-mdhtml:vercheck') || 'null');
470
502
  if (cached && (Date.now() - cached.t) < 86400000) {
471
- if (cached.v && cached.v !== CFG.rendererVersion) showUpdate(cached.v);
503
+ if (cached.v && isNewer(cached.v, CFG.rendererVersion)) showUpdate(cached.v);
472
504
  return;
473
505
  }
474
506
  } catch (e) {}
475
507
  fetch(CFG.versionManifest).then(function (r) { return r.json(); }).then(function (j) {
476
508
  var latest = j && j.version;
477
509
  try { localStorage.setItem('orz-mdhtml:vercheck', JSON.stringify({ t: Date.now(), v: latest })); } catch (e) {}
478
- if (latest && latest !== CFG.rendererVersion) showUpdate(latest);
510
+ if (latest && isNewer(latest, CFG.rendererVersion)) showUpdate(latest);
479
511
  }).catch(function () {});
480
512
  }
481
513
  function showUpdate(latest) {
package/dist/cli.js CHANGED
@@ -140,6 +140,7 @@ function main() {
140
140
  hljsDarkCss: `${CDN.hl}/styles/atom-one-dark.min.css`,
141
141
  hljsJs: `${CDN.hl}/highlight.min.js`,
142
142
  mermaidJs: 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js',
143
+ smilesJs: 'https://cdn.jsdelivr.net/npm/smiles-drawer@1.0.10/dist/smiles-drawer.min.js',
143
144
  },
144
145
  editorLibs: {
145
146
  codemirrorCss: `${CDN.cm}/codemirror.min.css`,