@@ -23,32 +23,71 @@ ruby = { color = 0xcdd6ff }; } local stylesets = { + list = [[ + @counter-style enclosed { + system: extends decimal; + prefix: "("; + suffix: ") "; + } + ul, ol { + padding: 0 1em; + } + li { + padding: 0.1em 0; + } + ]]; + list_ordered = [[]]; + list_unordered = [[]]; footnote = [[ div.footnote { - font-family: 90%; - display: none; + font-family: 90%; grid-template-columns: 1em 1fr min-content; grid-template-rows: 1fr min-content; position: fixed; padding: 1em; - background: @tone(0.05); - border: black; + background: @tone(0.03); margin:auto; } - div.footnote:target { display:grid; } @media screen { div.footnote { + display: grid; left: 10em; right: 10em; max-width: calc(@width + 2em); max-height: 30vw; bottom: 1em; + border: 1px solid black; + transform: translateY(200%); + transition: 0.4s; + z-index: 100; + } + div.footnote:target { + transform: translateY(0%); + } + #cover { + position: fixed; + top: 0; + left: 0; + height: 100vh; width: 100vw; + background: linear-gradient(to top, + @tone/0.8(-0.07), + @tone/0.4(-0.07)); + opacity: 0%; + transition: 1s; + pointer-events: none; + backdrop-filter: blur(0px); + } + div.footnote:target ~ #cover { + opacity: 100%; + pointer-events: all; + backdrop-filter: blur(5px); } } @media print { div.footnote { + display: grid; position: relative; } div.footnote:first-of-type { border-top: 1px solid black; @@ -58,15 +97,16 @@ div.footnote > a[href="#0"]{ grid-row: 2/3; grid-column: 3/4; display: block; - padding: 0.2em 0.7em; text-align: center; + padding: 0 0.3em; text-decoration: none; background: @tone(0.2); color: @tone(1); border: 1px solid black; margin-top: 0.6em; + font-size: 150%; -webkit-user-select: none; -ms-user-select: none; user-select: none; -webkit-user-drag: none; @@ -93,9 +133,12 @@ div.footnote > div.text { grid-row: 1/2; grid-column: 2/4; padding-left: 1em; - overflow-y: scroll; + overflow-y: auto; + } + div.footnote > div.text > p:first-child { + margin-top: 0; } ]]; header = [[ body { padding: 0 2.5em !important } @@ -208,23 +251,25 @@ ]]; code = [[ code { display: inline-block; - background: @tone(0.9); - color: @bg; + background: @tone(-1); + color: @tone(0.7); font-family: monospace; font-size: 90%; - padding: 3px 5px; + padding: 2px 5px; + user-select: all; } ]]; var = [[ var { font-style: italic; font-family: monospace; color: @tone(0.7); + font-size: 90%; } code var { - color: @tone(0.25); + color: @tone(0.4); } ]]; math = [[ span.equation { @@ -241,16 +286,22 @@ editors_markup = [[]]; block_code_listing = [[ figure.listing { font-family: monospace; - background: @tone(0.05); - color: @fg; + background: @tone(0.05 20); + color: @tone(1 20); padding: 0; margin: 0.3em 0; counter-reset: line-number; position: relative; - border: 1px solid @fg; + border: 1px solid @tone(1 20); } + :not(figure.listing) + figure.listing { + margin-top: 1em; + } + figure.listing + :not(figure.listing) { + margin-top: 1em; + } figure.listing>div { white-space: pre-wrap; tab-size: 3; -moz-tab-size: 3; @@ -262,9 +313,9 @@ width: 1.0em; padding: 0.2em 0.4em; text-align: right; display: inline-block; - background-color: @tone(0.2); + background-color: @tone(0.2 20); border-right: 1px solid @fg; content: counter(line-number); margin-right: 0.3em; } @@ -273,16 +324,16 @@ padding-top: 0; padding-bottom: 0; } figure.listing>div::before { - color: @fg; + color: @tone(1 20); } figure.listing>div:last-child::before { padding-bottom: 0.5em; } figure.listing>figcaption:first-child { border: none; - border-bottom: 1px solid @fg; + border-bottom: 1px solid @tone(1 20); } figure.listing>figcaption::after { display: block; float: right; @@ -295,9 +346,9 @@ font-family: sans-serif; font-size: 120%; padding: 0.2em 0.4em; border: none; - color: @tone(2); + color: @tone(2 20); } figure.listing > hr { border: none; margin: 0; @@ -304,16 +355,44 @@ height: 0.7em; counter-increment: line-number; } ]]; + root = [[ + body { + font-size: 16pt; + page-break-before: always; + } + h1 { + page-break-before: always; + } + h1,h2,h3,h4,h5,h6 { + page-break-after: avoid; + } + ]]; + } + + local stylesNeeded = { + flags = {}; + order = {}; } + local function addStyle(sty) + -- convenience function, also just in case i end up having + -- to change the goddamn implementation again + if not stylesNeeded.flags[sty] then + stylesNeeded.flags[sty] = true + table.insert(stylesNeeded.order, sty) + return true + end + return false + end - local stylesNeeded = {} + addStyle 'root' local render_state_handle = { doc = doc; opts = opts; style_rules = styles; -- use stylesneeded if at all possible + style_add = addStyle; stylesets = stylesets; stylesets_active = stylesNeeded; obj_htmlid = getSafeID; -- remaining fields added later @@ -403,8 +482,12 @@ return s end local cssRulesFor = {} + function getCSSImageForResource(r) + return '' -- TODO + end + local function getSpanRenderers(procs) local tag, elt, catenate = procs.tag, procs.elt, procs.catenate local span_renderers = {} local plainrdr = getBaseRenderers(tagproc.toTXT, span_renderers) @@ -412,13 +495,13 @@ function span_renderers.format(sp,...) local tags = { strong = 'strong', emph = 'em', strike = 'del', insert = 'ins', literal = 'code', variable = 'var'} if sp.style == 'literal' and not opts['fossil-uv'] then - stylesNeeded.code = true + addStyle 'code' elseif sp.style == 'strike' or sp.style == 'insert' then - stylesNeeded.editors_markup = true + addStyle 'editors_markup' elseif sp.style == 'variable' then - stylesNeeded.var = true + addStyle 'var' end return tag(tags[sp.style],nil,htmlSpan(sp.spans,...)) end @@ -426,9 +509,9 @@ local r = b.origin:ref(t.ref) local name = t.ref if name:find'%.' then name = name:match '^[^.]*%.(.+)$' end if type(r) == 'string' then - stylesNeeded.abbr = true + addStyle 'abbr' return tag('abbr',{title=r},next(t.spans) and htmlSpan(t.spans,b,s) or name) end if r.kind == 'resource' then local rid = getSafeID(r, 'res-') @@ -435,15 +518,16 @@ if r.class == 'image' then if not cssRulesFor[r] then local css = prepcss(string.format([[ section p > .%s { + background: %s; } - ]], rid)) + ]], rid, getCSSImageForResource(r))) stylesets[r] = css cssRulesFor[r] = css - stylesNeeded[r] = true + addStyle(r) end - return tag('div',{class=rid},catenate{'blaah'}) + return tag('div',{class=rid},catenate{''}) elseif r.class == 'video' then local vid = {} return tag('video',nil,vid) elseif r.class == 'font' then @@ -507,9 +591,9 @@ mctx.invocation = m return htmlSpan(ct.parse_span(r, mctx),b,s) end function span_renderers.math(m,b,s) - stylesNeeded.math = true + addStyle 'math' local spans = {} local function fmt(sp, target) for i,v in ipairs(sp) do if type(v) == 'string' then @@ -542,9 +626,9 @@ return htmlSpan(d.spans, b, s) end end function span_renderers.footnote(f,b,s) - stylesNeeded.footnote = true + addStyle 'footnote' local source, sid, ssec = b.origin:ref(f.ref) local cnc = getSafeID(ssec) .. ' ' .. sid local fn if footnotes[cnc] then @@ -570,9 +654,9 @@ anchor = function(b,s) return tag('a',{id = getSafeID(b)},null()) end; paragraph = function(b,s) - stylesNeeded.paragraph = true; + addStyle 'paragraph' return tag('p', nil, sr.htmlSpan(b.spans, b, s), b) end; directive = function(b,s) -- deal with renderer directives @@ -585,9 +669,9 @@ end; label = function(b,s) if ct.sec.is(b.captions) then if not (opts['fossil-uv'] or opts.snippet) then - stylesNeeded.header = true + addStyle 'header' end local h = math.min(6,math.max(1,b.captions.depth)) return tag(f('h%u',h), nil, sr.htmlSpan(b.spans, b, s), b) else @@ -609,9 +693,9 @@ end return tag('table',nil,catenate(tb)) end; listing = function(b,s) - stylesNeeded.block_code_listing = true + addStyle 'block_code_listing' local nodes = ss.map(function(l) if #l > 0 then return tag('div',nil,sr.htmlSpan(l, b, s)) else @@ -625,9 +709,9 @@ return tag('figure', {class='listing', lang=b.lang, id=b.id and getSafeID(b)}, catenate(nodes)) end; aside = function(b,s) local bn = {} - stylesNeeded.aside = true + addStyle 'aside' if #b.lines == 1 then bn[1] = sr.htmlSpan(b.lines[1], b, s) else for _,v in pairs(b.lines) do @@ -691,9 +775,9 @@ end end if rd then if opts['heading-anchors'] and block == sec.heading_node then - stylesNeeded.headingAnchors = true + addStyle 'headingAnchors' table.insert(rd.nodes, ' ') table.insert(rd.nodes, { tag = 'a'; attrs = {href = '#' .. irs.attrs.id, class='anchor'}; @@ -738,12 +822,15 @@ renderBlocks(ftir,body) local note = tag('div',{class='footnote',id=fn.id}, { tag('div',{class='number'}, tostring(fn.num)), tag('div',{class='text'}, body.nodes), - tag('a',{href='#0'},'close') + tag('a',{href='#0'},'⤫') }) table.insert(ir, note) end + if next(footnotes) then + table.insert(ir, tagproc.toIR.tag('div',{id='cover'},'')) + end -- restructure passes runhook('ir_restructure_pre', ir) @@ -752,12 +839,13 @@ for _, sec in pairs(ir) do if sec.tag == 'section' then local i = 1 while i <= #sec.nodes do local v = sec.nodes[i] if v.tag == 'li' then + addStyle 'list' local ltag if v.src.ordered - then ltag = 'ol' - else ltag = 'ul' + then ltag = 'ol' addStyle 'list_ordered' + else ltag = 'ul' addStyle 'list_unordered' end local last = i>1 and sec.nodes[i-1] if last and last.embed == 'list' and not ( last.ref[#last.ref].src.depth == v.src.depth and @@ -903,13 +991,13 @@ if opts.accent then table.insert(styles, string.format(':root {--accent:%s}', opts.accent)) end if opts.accent or (not opts['dark-on-light']) and (not opts['fossil-uv']) then - stylesNeeded.accent = true + addStyle 'accent' end - for k in pairs(stylesNeeded) do + for _,k in pairs(stylesNeeded.order) do if not stylesets[k] then ct.exns.unimpl('styleset %s not implemented (!)', k):throw() end table.insert(styles, prepcss(stylesets[k])) end