Differences From
Artifact [1e64ee70c7]:
20 20 lisp = { color = 0x77ff88 };
21 21 fortran = { color = 0xff779a };
22 22 python = { color = 0xffd277 };
23 23 ruby = { color = 0xcdd6ff };
24 24 }
25 25
26 26 local stylesets = {
27 + list = [[
28 + @counter-style enclosed {
29 + system: extends decimal;
30 + prefix: "(";
31 + suffix: ") ";
32 + }
33 + ul, ol {
34 + padding: 0 1em;
35 + }
36 + li {
37 + padding: 0.1em 0;
38 + }
39 + ]];
40 + list_ordered = [[]];
41 + list_unordered = [[]];
27 42 footnote = [[
28 43 div.footnote {
29 - font-family: 90%;
30 - display: none;
44 + font-family: 90%;
31 45 grid-template-columns: 1em 1fr min-content;
32 46 grid-template-rows: 1fr min-content;
33 47 position: fixed;
34 48 padding: 1em;
35 - background: @tone(0.05);
36 - border: black;
49 + background: @tone(0.03);
37 50 margin:auto;
38 51 }
39 - div.footnote:target { display:grid; }
40 52 @media screen {
41 53 div.footnote {
54 + display: grid;
42 55 left: 10em;
43 56 right: 10em;
44 57 max-width: calc(@width + 2em);
45 58 max-height: 30vw;
46 59 bottom: 1em;
60 + border: 1px solid black;
61 + transform: translateY(200%);
62 + transition: 0.4s;
63 + z-index: 100;
64 + }
65 + div.footnote:target {
66 + transform: translateY(0%);
67 + }
68 + #cover {
69 + position: fixed;
70 + top: 0;
71 + left: 0;
72 + height: 100vh; width: 100vw;
73 + background: linear-gradient(to top,
74 + @tone/0.8(-0.07),
75 + @tone/0.4(-0.07));
76 + opacity: 0%;
77 + transition: 1s;
78 + pointer-events: none;
79 + backdrop-filter: blur(0px);
80 + }
81 + div.footnote:target ~ #cover {
82 + opacity: 100%;
83 + pointer-events: all;
84 + backdrop-filter: blur(5px);
47 85 }
48 86 }
49 87 @media print {
50 88 div.footnote {
89 + display: grid;
51 90 position: relative;
52 91 }
53 92 div.footnote:first-of-type {
54 93 border-top: 1px solid black;
55 94 }
56 95 }
57 96
58 97 div.footnote > a[href="#0"]{
59 98 grid-row: 2/3;
60 99 grid-column: 3/4;
61 100 display: block;
62 - padding: 0.2em 0.7em;
63 101 text-align: center;
102 + padding: 0 0.3em;
64 103 text-decoration: none;
65 104 background: @tone(0.2);
66 105 color: @tone(1);
67 106 border: 1px solid black;
68 107 margin-top: 0.6em;
108 + font-size: 150%;
69 109 -webkit-user-select: none;
70 110 -ms-user-select: none;
71 111 user-select: none;
72 112 -webkit-user-drag: none;
73 113 user-drag: none;
74 114 }
75 115 div.footnote > a[href="#0"]:hover {
................................................................................
90 130 grid-row: 1/2;
91 131 grid-column: 1/2;
92 132 }
93 133 div.footnote > div.text {
94 134 grid-row: 1/2;
95 135 grid-column: 2/4;
96 136 padding-left: 1em;
97 - overflow-y: scroll;
137 + overflow-y: auto;
138 + }
139 + div.footnote > div.text > p:first-child {
140 + margin-top: 0;
98 141 }
99 142 ]];
100 143 header = [[
101 144 body { padding: 0 2.5em !important }
102 145 h1,h2,h3,h4,h5,h6 { border-bottom: 1px solid @tone(0.7); }
103 146 h1 { font-size: 200%; border-bottom-style: double !important; border-bottom-width: 3px !important; margin: 0em -1em; }
104 147 h2 { font-size: 130%; margin: 0em -0.7em; }
................................................................................
205 248 section > aside p:first-child {
206 249 margin: 0;
207 250 }
208 251 ]];
209 252 code = [[
210 253 code {
211 254 display: inline-block;
212 - background: @tone(0.9);
213 - color: @bg;
255 + background: @tone(-1);
256 + color: @tone(0.7);
214 257 font-family: monospace;
215 258 font-size: 90%;
216 - padding: 3px 5px;
259 + padding: 2px 5px;
260 + user-select: all;
217 261 }
218 262 ]];
219 263 var = [[
220 264 var {
221 265 font-style: italic;
222 266 font-family: monospace;
223 267 color: @tone(0.7);
268 + font-size: 90%;
224 269 }
225 270 code var {
226 - color: @tone(0.25);
271 + color: @tone(0.4);
227 272 }
228 273 ]];
229 274 math = [[
230 275 span.equation {
231 276 display: inline-block;
232 277 background: @tone(0.08);
233 278 color: @tone(2);
................................................................................
238 283 abbr = [[
239 284 abbr[title] { cursor: help; }
240 285 ]];
241 286 editors_markup = [[]];
242 287 block_code_listing = [[
243 288 figure.listing {
244 289 font-family: monospace;
245 - background: @tone(0.05);
246 - color: @fg;
290 + background: @tone(0.05 20);
291 + color: @tone(1 20);
247 292 padding: 0;
248 293 margin: 0.3em 0;
249 294 counter-reset: line-number;
250 295 position: relative;
251 - border: 1px solid @fg;
296 + border: 1px solid @tone(1 20);
252 297 }
298 + :not(figure.listing) + figure.listing {
299 + margin-top: 1em;
300 + }
301 + figure.listing + :not(figure.listing) {
302 + margin-top: 1em;
303 + }
253 304 figure.listing>div {
254 305 white-space: pre-wrap;
255 306 tab-size: 3;
256 307 -moz-tab-size: 3;
257 308 counter-increment: line-number;
258 309 text-indent: -2.3em;
259 310 margin-left: 2.3em;
260 311 }
261 312 figure.listing>:is(div,hr)::before {
262 313 width: 1.0em;
263 314 padding: 0.2em 0.4em;
264 315 text-align: right;
265 316 display: inline-block;
266 - background-color: @tone(0.2);
317 + background-color: @tone(0.2 20);
267 318 border-right: 1px solid @fg;
268 319 content: counter(line-number);
269 320 margin-right: 0.3em;
270 321 }
271 322 figure.listing>hr::before {
272 323 color: transparent;
273 324 padding-top: 0;
274 325 padding-bottom: 0;
275 326 }
276 327 figure.listing>div::before {
277 - color: @fg;
328 + color: @tone(1 20);
278 329 }
279 330 figure.listing>div:last-child::before {
280 331 padding-bottom: 0.5em;
281 332 }
282 333 figure.listing>figcaption:first-child {
283 334 border: none;
284 - border-bottom: 1px solid @fg;
335 + border-bottom: 1px solid @tone(1 20);
285 336 }
286 337 figure.listing>figcaption::after {
287 338 display: block;
288 339 float: right;
289 340 font-weight: normal;
290 341 font-style: italic;
291 342 font-size: 70%;
................................................................................
292 343 padding-top: 0.3em;
293 344 }
294 345 figure.listing>figcaption {
295 346 font-family: sans-serif;
296 347 font-size: 120%;
297 348 padding: 0.2em 0.4em;
298 349 border: none;
299 - color: @tone(2);
350 + color: @tone(2 20);
300 351 }
301 352 figure.listing > hr {
302 353 border: none;
303 354 margin: 0;
304 355 height: 0.7em;
305 356 counter-increment: line-number;
306 357 }
307 358 ]];
359 + root = [[
360 + body {
361 + font-size: 16pt;
362 + page-break-before: always;
363 + }
364 + h1 {
365 + page-break-before: always;
366 + }
367 + h1,h2,h3,h4,h5,h6 {
368 + page-break-after: avoid;
369 + }
370 + ]];
371 + }
372 +
373 + local stylesNeeded = {
374 + flags = {};
375 + order = {};
308 376 }
377 + local function addStyle(sty)
378 + -- convenience function, also just in case i end up having
379 + -- to change the goddamn implementation again
380 + if not stylesNeeded.flags[sty] then
381 + stylesNeeded.flags[sty] = true
382 + table.insert(stylesNeeded.order, sty)
383 + return true
384 + end
385 + return false
386 + end
309 387
310 - local stylesNeeded = {}
388 + addStyle 'root'
311 389
312 390 local render_state_handle = {
313 391 doc = doc;
314 392 opts = opts;
315 393 style_rules = styles; -- use stylesneeded if at all possible
394 + style_add = addStyle;
316 395 stylesets = stylesets;
317 396 stylesets_active = stylesNeeded;
318 397 obj_htmlid = getSafeID;
319 398 -- remaining fields added later
320 399 }
321 400
322 401 local renderJob = doc:job('render_html', nil, render_state_handle)
................................................................................
400 479 local spanparse = function(...)
401 480 local s = ct.parse_span(...)
402 481 doc.docjob:hook('meddle_span', s)
403 482 return s
404 483 end
405 484
406 485 local cssRulesFor = {}
486 + function getCSSImageForResource(r)
487 + return '' -- TODO
488 + end
489 +
407 490 local function getSpanRenderers(procs)
408 491 local tag, elt, catenate = procs.tag, procs.elt, procs.catenate
409 492 local span_renderers = {}
410 493 local plainrdr = getBaseRenderers(tagproc.toTXT, span_renderers)
411 494 local htmlSpan = getBaseRenderers(procs, span_renderers).htmlSpan
412 495
413 496 function span_renderers.format(sp,...)
414 497 local tags = { strong = 'strong', emph = 'em', strike = 'del', insert = 'ins', literal = 'code', variable = 'var'}
415 498 if sp.style == 'literal' and not opts['fossil-uv'] then
416 - stylesNeeded.code = true
499 + addStyle 'code'
417 500 elseif sp.style == 'strike' or sp.style == 'insert' then
418 - stylesNeeded.editors_markup = true
501 + addStyle 'editors_markup'
419 502 elseif sp.style == 'variable' then
420 - stylesNeeded.var = true
503 + addStyle 'var'
421 504 end
422 505 return tag(tags[sp.style],nil,htmlSpan(sp.spans,...))
423 506 end
424 507
425 508 function span_renderers.deref(t,b,s)
426 509 local r = b.origin:ref(t.ref)
427 510 local name = t.ref
428 511 if name:find'%.' then name = name:match '^[^.]*%.(.+)$' end
429 512 if type(r) == 'string' then
430 - stylesNeeded.abbr = true
513 + addStyle 'abbr'
431 514 return tag('abbr',{title=r},next(t.spans) and htmlSpan(t.spans,b,s) or name)
432 515 end
433 516 if r.kind == 'resource' then
434 517 local rid = getSafeID(r, 'res-')
435 518 if r.class == 'image' then
436 519 if not cssRulesFor[r] then
437 520 local css = prepcss(string.format([[
438 521 section p > .%s {
522 + background: %s;
439 523 }
440 - ]], rid))
524 + ]], rid, getCSSImageForResource(r)))
441 525 stylesets[r] = css
442 526 cssRulesFor[r] = css
443 - stylesNeeded[r] = true
527 + addStyle(r)
444 528 end
445 - return tag('div',{class=rid},catenate{'blaah'})
529 + return tag('div',{class=rid},catenate{''})
446 530 elseif r.class == 'video' then
447 531 local vid = {}
448 532 return tag('video',nil,vid)
449 533 elseif r.class == 'font' then
450 534 b.origin:fail('fonts cannot be instantiated, use %font directive instead')
451 535 end
452 536 else
................................................................................
504 588 b.origin:fail('%s is an object, not a reference', t.ref)
505 589 end
506 590 local mctx = b.origin:clone()
507 591 mctx.invocation = m
508 592 return htmlSpan(ct.parse_span(r, mctx),b,s)
509 593 end
510 594 function span_renderers.math(m,b,s)
511 - stylesNeeded.math = true
595 + addStyle 'math'
512 596 local spans = {}
513 597 local function fmt(sp, target)
514 598 for i,v in ipairs(sp) do
515 599 if type(v) == 'string' then
516 600 local x = ct.tool.mathfmt(b.origin, v)
517 601 for _,v in ipairs(x) do
518 602 table.insert(target, v)
................................................................................
539 623 elseif d.crit then
540 624 b.origin:fail('critical extension %s unavailable', d.ext)
541 625 elseif d.failthru then
542 626 return htmlSpan(d.spans, b, s)
543 627 end
544 628 end
545 629 function span_renderers.footnote(f,b,s)
546 - stylesNeeded.footnote = true
630 + addStyle 'footnote'
547 631 local source, sid, ssec = b.origin:ref(f.ref)
548 632 local cnc = getSafeID(ssec) .. ' ' .. sid
549 633 local fn
550 634 if footnotes[cnc] then
551 635 fn = footnotes[cnc]
552 636 else
553 637 footnotecount = footnotecount + 1
................................................................................
567 651 local null = function() return catenate{} end
568 652
569 653 local block_renderers = {
570 654 anchor = function(b,s)
571 655 return tag('a',{id = getSafeID(b)},null())
572 656 end;
573 657 paragraph = function(b,s)
574 - stylesNeeded.paragraph = true;
658 + addStyle 'paragraph'
575 659 return tag('p', nil, sr.htmlSpan(b.spans, b, s), b)
576 660 end;
577 661 directive = function(b,s)
578 662 -- deal with renderer directives
579 663 local _, cmd, args = b.words(2)
580 664 if cmd == 'page-title' then
581 665 if not opts.title then doctitle = args end
................................................................................
582 666 elseif b.critical then
583 667 b.origin:fail('critical HTML renderer directive “%s” not supported', cmd)
584 668 end
585 669 end;
586 670 label = function(b,s)
587 671 if ct.sec.is(b.captions) then
588 672 if not (opts['fossil-uv'] or opts.snippet) then
589 - stylesNeeded.header = true
673 + addStyle 'header'
590 674 end
591 675 local h = math.min(6,math.max(1,b.captions.depth))
592 676 return tag(f('h%u',h), nil, sr.htmlSpan(b.spans, b, s), b)
593 677 else
594 678 -- handle other uses of labels here
595 679 end
596 680 end;
................................................................................
606 690 {align=c.align}, sr.htmlSpan(c.spans, b)))
607 691 end
608 692 table.insert(tb, tag('tr',nil,catenate(row)))
609 693 end
610 694 return tag('table',nil,catenate(tb))
611 695 end;
612 696 listing = function(b,s)
613 - stylesNeeded.block_code_listing = true
697 + addStyle 'block_code_listing'
614 698 local nodes = ss.map(function(l)
615 699 if #l > 0 then
616 700 return tag('div',nil,sr.htmlSpan(l, b, s))
617 701 else
618 702 return elt('hr')
619 703 end
620 704 end, b.lines)
................................................................................
622 706 table.insert(nodes,1, tag('figcaption',nil,sr.htmlSpan(b.title)))
623 707 end
624 708 if b.lang then langsused[b.lang] = true end
625 709 return tag('figure', {class='listing', lang=b.lang, id=b.id and getSafeID(b)}, catenate(nodes))
626 710 end;
627 711 aside = function(b,s)
628 712 local bn = {}
629 - stylesNeeded.aside = true
713 + addStyle 'aside'
630 714 if #b.lines == 1 then
631 715 bn[1] = sr.htmlSpan(b.lines[1], b, s)
632 716 else
633 717 for _,v in pairs(b.lines) do
634 718 table.insert(bn, tag('p', {}, sr.htmlSpan(v, b, s)))
635 719 end
636 720 end
................................................................................
688 772 tagproc = tagproc.toIR;
689 773 astproc = astproc.toIR;
690 774 }, block, sec)
691 775 end
692 776 end
693 777 if rd then
694 778 if opts['heading-anchors'] and block == sec.heading_node then
695 - stylesNeeded.headingAnchors = true
779 + addStyle 'headingAnchors'
696 780 table.insert(rd.nodes, ' ')
697 781 table.insert(rd.nodes, {
698 782 tag = 'a';
699 783 attrs = {href = '#' .. irs.attrs.id, class='anchor'};
700 784 nodes = {type(opts['heading-anchors'])=='string' and opts['heading-anchors'] or '§'};
701 785 })
702 786 end
................................................................................
735 819 for l in fn.source:gmatch('([^\n]*)') do
736 820 ct.parse_line(l, fn.origin, ftir)
737 821 end
738 822 renderBlocks(ftir,body)
739 823 local note = tag('div',{class='footnote',id=fn.id}, {
740 824 tag('div',{class='number'}, tostring(fn.num)),
741 825 tag('div',{class='text'}, body.nodes),
742 - tag('a',{href='#0'},'close')
826 + tag('a',{href='#0'},'⤫')
743 827 })
744 828 table.insert(ir, note)
745 829 end
830 + if next(footnotes) then
831 + table.insert(ir, tagproc.toIR.tag('div',{id='cover'},''))
832 + end
746 833
747 834 -- restructure passes
748 835 runhook('ir_restructure_pre', ir)
749 836
750 837 ---- list insertion pass
751 838 local lists = {}
752 839 for _, sec in pairs(ir) do
753 840 if sec.tag == 'section' then
754 841 local i = 1 while i <= #sec.nodes do local v = sec.nodes[i]
755 842 if v.tag == 'li' then
843 + addStyle 'list'
756 844 local ltag
757 845 if v.src.ordered
758 - then ltag = 'ol'
759 - else ltag = 'ul'
846 + then ltag = 'ol' addStyle 'list_ordered'
847 + else ltag = 'ul' addStyle 'list_unordered'
760 848 end
761 849 local last = i>1 and sec.nodes[i-1]
762 850 if last and last.embed == 'list' and not (
763 851 last.ref[#last.ref].src.depth == v.src.depth and
764 852 last.ref[#last.ref].src.ordered ~= v.src.ordered
765 853 ) then
766 854 -- add to existing list
................................................................................
900 988 if opts.width then
901 989 table.insert(styles, string.format([[body {padding:0 1em;margin:auto;max-width:%s}]], opts.width))
902 990 end
903 991 if opts.accent then
904 992 table.insert(styles, string.format(':root {--accent:%s}', opts.accent))
905 993 end
906 994 if opts.accent or (not opts['dark-on-light']) and (not opts['fossil-uv']) then
907 - stylesNeeded.accent = true
995 + addStyle 'accent'
908 996 end
909 997
910 998
911 - for k in pairs(stylesNeeded) do
999 + for _,k in pairs(stylesNeeded.order) do
912 1000 if not stylesets[k] then ct.exns.unimpl('styleset %s not implemented (!)', k):throw() end
913 1001 table.insert(styles, prepcss(stylesets[k]))
914 1002 end
915 1003
916 1004 local head = {}
917 1005 local styletag = ''
918 1006 if opts['link-css'] then