nattoppet 2.1.1 → 4.0.1

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/ppt.css ADDED
@@ -0,0 +1,304 @@
1
+ html {
2
+ font-family: sans-serif;
3
+ font-size: 20px;
4
+ line-height: 1.5;
5
+ min-height: 100vh;
6
+ color: #233;
7
+ }
8
+ @media (min-width: 1200px) {
9
+ html {
10
+ font-size: 24px;
11
+ }
12
+ }
13
+ body {
14
+ padding: 0;
15
+ margin: 0;
16
+ overflow-x: hidden;
17
+ overflow-y: scroll;
18
+ }
19
+ pre {
20
+ background: white;
21
+ border-top: 1px solid #eee;
22
+ border-bottom: 1px solid #eee;
23
+ padding: 20px;
24
+ font-size: 0.9rem;
25
+ line-height: 1.2;
26
+ text-align: left;
27
+ overflow-x: auto;
28
+ }
29
+ @media (min-width: 1200px) {
30
+ pre {
31
+ padding: 25px;
32
+ }
33
+ }
34
+ code {
35
+ font-family: monospace;
36
+ font-size: 0.9rem;
37
+ }
38
+ h2,
39
+ h3 {
40
+ color: #42b8a6;
41
+ }
42
+ h2 {
43
+ margin-top: 5vh;
44
+ font-size: 2rem;
45
+ }
46
+ h3 {
47
+ margin-top: 6vh;
48
+ font-size: 1.2rem;
49
+ }
50
+ p {
51
+ text-indent: 2rem;
52
+ }
53
+ blockquote p {
54
+ text-indent: 0;
55
+ }
56
+ img {
57
+ max-width: 100%;
58
+ }
59
+ img.full {
60
+ width: 100%;
61
+ }
62
+ img.small {
63
+ width: 40%;
64
+ }
65
+ @media (max-width: 625px) {
66
+ img.small {
67
+ width: 60%;
68
+ }
69
+ }
70
+ img.mid {
71
+ width: 60%;
72
+ }
73
+ img.big {
74
+ width: 80%;
75
+ }
76
+ li {
77
+ font-size: 1.2rem;
78
+ }
79
+ footer {
80
+ font-weight: 300;
81
+ font-size: 0.7rem;
82
+ color: #888;
83
+ }
84
+ .banner > h2 {
85
+ position: absolute;
86
+ left: 10vw;
87
+ top: 45%;
88
+ width: 80vw;
89
+ transform: translateY(-50%);
90
+ text-align: center;
91
+ margin: 0;
92
+ font-family: serif;
93
+ font-size: 3rem;
94
+ font-weight: normal;
95
+ }
96
+ @media (min-width: 1200px) {
97
+ .banner > h2 {
98
+ font-size: 3.2rem;
99
+ }
100
+ }
101
+ a {
102
+ text-decoration: none;
103
+ }
104
+ a:hover {
105
+ text-decoration: underline;
106
+ }
107
+ .scen {
108
+ position: relative;
109
+ margin: 0;
110
+ background-color: #eee;
111
+ transition: background-color 1s ease;
112
+ padding: 10vh 8vw;
113
+ width: 84vw;
114
+ min-height: 60vh;
115
+ }
116
+ .scen.active {
117
+ background-color: white;
118
+ }
119
+ .scen.wide {
120
+ width: 96vw;
121
+ padding: 10vh 2vw;
122
+ }
123
+ .scen::after {
124
+ content: "";
125
+ display: table;
126
+ clear: both;
127
+ }
128
+ @media (min-width: 1200px) {
129
+ .scen {
130
+ width: 76vw;
131
+ padding: 10vh 12vw;
132
+ }
133
+ }
134
+ .col-12 {
135
+ float: left;
136
+ width: 100%;
137
+ }
138
+ .col-11 {
139
+ float: left;
140
+ width: 91.66666667%;
141
+ }
142
+ .col-10 {
143
+ float: left;
144
+ width: 83.33333333%;
145
+ }
146
+ .col-9 {
147
+ float: left;
148
+ width: 75%;
149
+ }
150
+ .col-8 {
151
+ float: left;
152
+ width: 66.66666667%;
153
+ }
154
+ .col-7 {
155
+ float: left;
156
+ width: 58.33333333%;
157
+ }
158
+ .col-6 {
159
+ float: left;
160
+ width: 50%;
161
+ }
162
+ .col-5 {
163
+ float: left;
164
+ width: 41.66666667%;
165
+ }
166
+ .col-4 {
167
+ float: left;
168
+ width: 33.33333333%;
169
+ }
170
+ .col-3 {
171
+ float: left;
172
+ width: 25%;
173
+ }
174
+ .col-2 {
175
+ float: left;
176
+ width: 16.66666667%;
177
+ }
178
+ .col-1 {
179
+ float: left;
180
+ width: 8.33333333%;
181
+ }
182
+ .plum {
183
+ color: #ae81ff;
184
+ }
185
+ .fx-plum {
186
+ transition: color 400ms;
187
+ }
188
+ .fx-plum.fast {
189
+ transition: color 200ms;
190
+ }
191
+ .fx-plum.slow {
192
+ transition: color 600ms;
193
+ }
194
+ .fx-plum.active {
195
+ color: #ae81ff !important;
196
+ }
197
+ .chartreuse {
198
+ color: #a6e22e;
199
+ }
200
+ .fx-chartreuse {
201
+ transition: color 400ms;
202
+ }
203
+ .fx-chartreuse.fast {
204
+ transition: color 200ms;
205
+ }
206
+ .fx-chartreuse.slow {
207
+ transition: color 600ms;
208
+ }
209
+ .fx-chartreuse.active {
210
+ color: #a6e22e !important;
211
+ }
212
+ .cyan {
213
+ color: #66d9ef;
214
+ }
215
+ .fx-cyan {
216
+ transition: color 400ms;
217
+ }
218
+ .fx-cyan.fast {
219
+ transition: color 200ms;
220
+ }
221
+ .fx-cyan.slow {
222
+ transition: color 600ms;
223
+ }
224
+ .fx-cyan.active {
225
+ color: #66d9ef !important;
226
+ }
227
+ .tomato {
228
+ color: #f13c1a;
229
+ }
230
+ .fx-tomato {
231
+ transition: color 400ms;
232
+ }
233
+ .fx-tomato.fast {
234
+ transition: color 200ms;
235
+ }
236
+ .fx-tomato.slow {
237
+ transition: color 600ms;
238
+ }
239
+ .fx-tomato.active {
240
+ color: #f13c1a !important;
241
+ }
242
+ .moccasin {
243
+ color: #ffe4b5;
244
+ }
245
+ .fx-moccasin {
246
+ transition: color 400ms;
247
+ }
248
+ .fx-moccasin.fast {
249
+ transition: color 200ms;
250
+ }
251
+ .fx-moccasin.slow {
252
+ transition: color 600ms;
253
+ }
254
+ .fx-moccasin.active {
255
+ color: #ffe4b5 !important;
256
+ }
257
+ .slide {
258
+ transition: transform 400ms;
259
+ transform: translateX(-100vw);
260
+ }
261
+ .slide.fast {
262
+ transition: transform 200ms;
263
+ }
264
+ .slide.slow {
265
+ transition: transform 600ms;
266
+ }
267
+ .slide.active {
268
+ transform: translateX(0);
269
+ }
270
+ .fade {
271
+ transition: opacity 400ms;
272
+ opacity: 0;
273
+ }
274
+ .fade.fast {
275
+ transition: opacity 200ms;
276
+ }
277
+ .fade.slow {
278
+ transition: opacity 600ms;
279
+ }
280
+ .fade.active {
281
+ opacity: 1;
282
+ }
283
+ .rise {
284
+ transition: opacity 400ms;
285
+ transition: transform 400ms;
286
+ opacity: 0;
287
+ transform: translateY(10vh);
288
+ }
289
+ .rise.fast {
290
+ transition: opacity 200ms;
291
+ }
292
+ .rise.slow {
293
+ transition: opacity 600ms;
294
+ }
295
+ .rise.fast {
296
+ transition: transform 200ms;
297
+ }
298
+ .rise.slow {
299
+ transition: transform 600ms;
300
+ }
301
+ .rise.active {
302
+ opacity: 1;
303
+ transform: translateY(0);
304
+ }
package/ppt.js ADDED
@@ -0,0 +1,83 @@
1
+ // events: click, delay, sim
2
+ // time-for-delay: short, long
3
+ // fx: slide, fade, fx-[color]
4
+ // time-for-fx: fast, slow
5
+ var init;
6
+
7
+ init = function() {
8
+ var clickListener, current, enter, fx, inview, scens, timeline, update;
9
+ scens = [].slice.call(document.querySelectorAll('.scen'));
10
+ current = scens[0];
11
+ timeline = 0;
12
+ clickListener = function() {};
13
+ enter = function(x) {
14
+ x.classList.add('active');
15
+ return fx(++timeline, [].slice.call(x.querySelectorAll('.click, .delay, .sim')));
16
+ };
17
+ inview = function(x) {
18
+ var height, ref, top;
19
+ ({top, height} = x.getBoundingClientRect());
20
+ return (top <= (ref = innerHeight / 2) && ref <= top + height);
21
+ };
22
+ update = function() {
23
+ var e, i, j, len, len1, ref, results, x;
24
+ if (!inview(current)) {
25
+ results = [];
26
+ for (i = 0, len = scens.length; i < len; i++) {
27
+ x = scens[i];
28
+ if (inview(x)) {
29
+ ref = document.querySelectorAll('.active');
30
+ for (j = 0, len1 = ref.length; j < len1; j++) {
31
+ e = ref[j];
32
+ e.classList.remove('active');
33
+ }
34
+ enter(x);
35
+ current = x;
36
+ break;
37
+ } else {
38
+ results.push(void 0);
39
+ }
40
+ }
41
+ return results;
42
+ }
43
+ };
44
+ fx = function(t, [head, ...tail]) {
45
+ var cb;
46
+ if (head == null) {
47
+ return;
48
+ }
49
+ cb = function() {
50
+ if (t !== timeline) {
51
+ return;
52
+ }
53
+ head.classList.add('active');
54
+ return fx(t, tail);
55
+ };
56
+ if (head.classList.contains('click')) {
57
+ return clickListener = cb;
58
+ } else if (head.classList.contains('delay')) {
59
+ if (head.classList.contains('long')) {
60
+ return setTimeout(cb, 800);
61
+ } else if (head.classList.contains('short')) {
62
+ return setTimeout(cb, 200);
63
+ } else {
64
+ return setTimeout(cb, 400);
65
+ }
66
+ } else if (head.classList.contains('sim')) {
67
+ return cb();
68
+ }
69
+ };
70
+ enter(current);
71
+ addEventListener('click', function() {
72
+ return clickListener();
73
+ });
74
+ addEventListener('scroll', update);
75
+ addEventListener('resize', update);
76
+ return setInterval(update, 2000);
77
+ };
78
+
79
+ if (document.readyState === 'loading') {
80
+ document.addEventListener('DOMContentLoaded', init);
81
+ } else {
82
+ init();
83
+ }
@@ -1,3 +1,19 @@
1
+ <!doctype html>
2
+ <meta name=viewport content="width=device-width, initial-scale=1.0">
3
+ <meta name=author content="ylxdzsw@gmail.com">
4
+ <meta charset="utf-8">
5
+ <title>[title] | ylxdzsw's blog</title>
6
+
7
+ <style>
8
+ [mixin] ppt.css
9
+ </style>
10
+
11
+ <script>
12
+ [mixin] ppt.js
13
+ </script>
14
+
15
+ [#slot]
16
+
1
17
  [eval] this.inited ? "</section>" : ''
2
18
 
3
19
  [section]=
@@ -18,4 +34,4 @@ const content = capture_until('\n')
18
34
  const {args:[length]} = std_call()
19
35
  ;`<div style="height: ${length}; min-width: 1px"></div>`
20
36
 
21
- [mixin] @std/common.ymd
37
+ [mixin] common.ymd
package/readme.md CHANGED
@@ -1,33 +1,46 @@
1
1
  nattoppet
2
2
  =========
3
3
 
4
- A tiny markup language and several themes for making documents, slides, or web apps as single-file bundled html or
5
- executable.
4
+ A tiny markup language and themes for making documents, slides, or web apps as single-file bundled html or executables.
6
5
 
7
6
  ### Usage
8
7
 
9
- compile a nattoppet file:
8
+ Compile a nattoppet file:
10
9
 
11
- ```
12
- $ npm exec nattoppet in.ymd > out.html
10
+ ```bash
11
+ bun run nattoppet.ts in.ymd > out.html
13
12
  ```
14
13
 
15
- compile a nattoppet file but don't minimize (for debugging):
14
+ Compile a nattoppet file but don't minimize (for debugging):
16
15
 
17
- ```
18
- $ npm exec nattoppet in.ymd --dev > out.html
16
+ ```bash
17
+ bun run nattoppet.ts in.ymd --dev > out.html
19
18
  ```
20
19
 
21
- watch a nattoppet file and rebuild it whenever it changes; open a browser to view the compiled page
20
+ Open a browser to preview a nattoppet file; rebuild every time the page is refreshed:
22
21
 
23
- ```
24
- $ npm exec nattoppet-dev in.ymd
22
+ ```bash
23
+ bun run nattoppet-dev.ts in.ymd
25
24
  ```
26
25
 
27
- build a double-clickable executable for the page
26
+ Initialize a new project:
28
27
 
28
+ ```bash
29
+ bun run nattoppet-init.ts form
29
30
  ```
30
- $ npm exec nattoppet-native init
31
- $ (edit the metadata as needed)
32
- $ npm exec nattoppet-native build in.ymd
31
+
32
+ Build a double-clickable executable for the page:
33
+
34
+ ```bash
35
+ bun run nattoppet-native.ts init
36
+ # (edit the metadata as needed)
37
+ bun run nattoppet-native.ts build in.ymd
33
38
  ```
39
+
40
+
41
+ ### History
42
+
43
+ - 1.0: This project started as an experiment of co.js to replicate gulp.js, when async/await was not a thing and wind.js was the cool guy that everyone was talking about.
44
+ - 2.0: Later I decided to build ymd.js, a custom LaTeX-style macro-based markup language for blogging, and turned nattoppet a bundler. Promise landed on JavaScript, and async/await became available with babel.
45
+ - 3.0: I became a minimalist and stripped down all dependencies, merged ymd.js and nattoppet, and flattened the directory. I have also migrated to Deno to further remove the nodejs clutters.
46
+ - 4.0: AI came. As an experimental project, nattoppet was put to test AI. Kimi 2.5 successfully ported it from Deno to Bun in half an hour, with all posts on my blog builds without error. It made me feel empty, but I have to embrace it. This project will be fully vibed from now on.
@@ -1,23 +1,27 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict'
4
-
5
- const fs = require('fs')
6
- const path = require('path')
7
-
8
- const coffee = require('coffeescript')
9
- const marked = require('marked')
10
- const katex = require("katex")
11
- const less = require('less')
12
-
13
- module.exports = {
14
- stdlib_dir: __dirname,
1
+ import * as path from "node:path"
2
+ import * as fs from "node:fs"
3
+ import * as zlib from "node:zlib"
4
+
5
+ import { marked } from "marked"
6
+ import coffee from "coffeescript"
7
+ import katex from "katex"
8
+ import less from "less"
9
+
10
+ function compress_sync(data: ArrayBuffer) {
11
+ // Keep using zlib.deflateRawSync for browser compatibility
12
+ // Browser uses DecompressionStream("deflate-raw") which expects raw deflate
13
+ return zlib.deflateRawSync(new Uint8Array(data), {
14
+ flush: zlib.constants.Z_FINISH,
15
+ level: zlib.constants.Z_BEST_COMPRESSION
16
+ })
17
+ }
15
18
 
16
- skip(n) {
19
+ export default {
20
+ skip(n: number) {
17
21
  this.remaining = this.remaining.substring(n)
18
22
  },
19
23
 
20
- capture_until(delimiter) {
24
+ capture_until(delimiter: string) {
21
25
  const p = this.remaining.indexOf(delimiter)
22
26
  if (p < 0) {
23
27
  const result = this.remaining
@@ -30,7 +34,7 @@ module.exports = {
30
34
  },
31
35
 
32
36
  std_call(hascontent = false) {
33
- const opts = [], args = []
37
+ const opts: string[] = [], args: string[] = []
34
38
  const parse_option = () => {
35
39
  const m = this.remaining.match(/^\.([\w\-]+)/)
36
40
  this.skip(m[0].length)
@@ -42,9 +46,9 @@ module.exports = {
42
46
  args.push(m[1] || m[2])
43
47
  }
44
48
  const parse_block = () => {
45
- const m = this.remaining.match(/^>+/)
49
+ const m = this.remaining.match(/^(>+)\n?/)
46
50
  this.skip(m[0].length)
47
- return this.capture_until('<'.repeat(m[0].length))
51
+ return this.capture_until('<'.repeat(m[1].length))
48
52
  }
49
53
 
50
54
  while (true) {
@@ -60,49 +64,57 @@ module.exports = {
60
64
  return { opts, args, block: parse_block() }
61
65
  case ' ':
62
66
  if (hascontent)
63
- return { opts, args, block: this.capture_until('\n') }
67
+ return { opts, args, block: this.capture_until('\n').slice(1) }
64
68
  default:
65
69
  return { opts, args }
66
70
  }
67
71
  }
68
72
  },
69
73
 
70
- rpath(file) {
71
- if (file.startsWith('@std')) {
72
- return path.join(this.stdlib_dir, file.substring(4))
73
- } else if (!path.isAbsolute(file)) {
74
+ rpath(file: string) {
75
+ if (!path.isAbsolute(file))
74
76
  return path.join(this.base_dir, file)
75
- }
76
77
  return file
77
78
  },
78
79
 
79
- read(file, encoding='utf8') {
80
- return fs.readFileSync(this.rpath(file), encoding)
80
+ read(file: string, encoding = "utf-8") {
81
+ const filePath = this.rpath(file)
82
+ switch (encoding) {
83
+ case "utf8":
84
+ case "utf-8":
85
+ return fs.readFileSync(filePath, 'utf-8')
86
+ case "base64":
87
+ return Buffer.from(fs.readFileSync(filePath)).toString('base64')
88
+ case "compressed-base64":
89
+ return Buffer.from(compress_sync(fs.readFileSync(filePath))).toString('base64')
90
+ default:
91
+ throw "unknown encoding: " + encoding
92
+ }
81
93
  },
82
94
 
83
- extname(file) {
95
+ extname(file: string) {
84
96
  return path.extname(file).slice(1)
85
97
  },
86
98
 
87
- basename(file) {
99
+ basename(file: string) {
88
100
  return path.basename(file)
89
101
  },
90
102
 
91
- render_coffee(str, options) {
103
+ render_coffee(str: string, options: any) {
92
104
  return coffee.compile(str, options)
93
105
  },
94
106
 
95
- render_less(str) {
96
- let x; less.render(str, {}, (err, out) => !err && (x = out))
107
+ render_less(str: string) {
108
+ let x: any; less.render(str, {}, (err: any, out: any) => !err && (x = out))
97
109
  if (!x) throw "less failed to compile synchronously"
98
110
  return x.css
99
111
  },
100
112
 
101
- render_markdown(str) {
113
+ render_markdown(str: string) {
102
114
  return marked.parse(str)
103
115
  },
104
116
 
105
- render_katex(str, displayMode=false) {
106
- return katex.renderToString(str, { displayMode })
117
+ render_katex(str: string, displayMode = false) {
118
+ return katex.renderToString(str, { displayMode, output: 'html' })
107
119
  }
108
- }
120
+ } as any