diff options
Diffstat (limited to 'site/posts/cleopatra/theme.org')
-rw-r--r-- | site/posts/cleopatra/theme.org | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/site/posts/cleopatra/theme.org b/site/posts/cleopatra/theme.org new file mode 100644 index 0000000..9b1a129 --- /dev/null +++ b/site/posts/cleopatra/theme.org @@ -0,0 +1,573 @@ +#+TITLE: Layout and Style + +#+SERIES: ../cleopatra.html +#+SERIES_PREV: ./literate-programming.html +#+SERIES_NEXT: ./soupault.html + +#+BEGIN_EXPORT html +<nav id="generate-toc"></nav> +<div id="history">site/cleopatra/theme.org</div> +#+END_EXPORT + +* Setup + + As often when it comes to frontend development, we will use several + tools hosted in the ~npm~ packages repository. ~npm~ is infamous + for downloading lots of files and to store it in the ~node_modules/~ + directory. We configure *~cleopatra~* accordingly. + + #+begin_src makefile :tangle theme.mk +CONFIGURE += package.json package-lock.json node_modules + #+end_src + +* Base CSS + + We know construct piece by piece the “base” CSS layout which we will + inject inside a ~<style>~ tag in each web page. + +** Layout + + Our goal is to have a three columns layout: one aside menu, with + the top-level navigation links (technical articles, news, etc.) and + the table of contents of the current pages if relevant, one main + area for the webpage content, and a margin column with side notes + and margin notes. + + #+caption: Widths of page components (in ~rem~) + #+name: widths + | Content | 35 | + | Gutter | 3 | + | Margin | 13 | + + #+name: main-width + #+begin_src emacs-lisp :exports none :noweb yes :var widths=widths[,1] +(nth 0 widths) + #+end_src + + #+name: gutter-width + #+begin_src emacs-lisp :exports none :noweb yes :var widths=widths[,1] +(nth 1 widths) + #+end_src + + #+name: margin-width + #+begin_src emacs-lisp :exports none :noweb yes :var widths=widths[,1] +(nth 2 widths) + #+end_src + + #+begin_src css :tangle style.css :noweb yes +:root { + --main-width: <<main-width()>>rem; + --gutter-width: <<gutter-width()>>rem; + --margin-width: <<margin-width()>>rem; + --code-width: calc(var(--main-width) + var(--gutter-width) + var(--margin-width)); + --body-width: calc(var(--main-width) + 2 * (var(--gutter-width) + var(--margin-width))); +} + #+end_src + + According to CSS’ own [[https://www.w3.org/TR/css-variables-1/#using-variables][specification]], you cannot use ~var()~ inside + media queries. As a consequnece, for our theme to be responsive, + the full width of the page content (\im 2 \times (that is, + \mathrm{margin\_width} + \mathrm{gutter\_width}) + + \mathrm{content\_width} \mi or call_body-width[:results raw]()rem) + has to be hard-coded[fn::Fortunately, this is a literate + program. This value is actually programmatically computed, so that + we do not have to worry about forgetting to update it]. + + #+name: body-width + #+begin_src bash :exports none :noweb yes +echo $((2 * (<<margin-width()>> + <<gutter-width()>>) + <<main-width()>>)) + #+end_src + + #+begin_src css :tangle style.css :noweb yes +@media (max-width: <<body-width()>>rem) { + :root { + --body-width: var(--main-width); + --code-width: var(--main-width); + } +} + #+end_src + + And now, we are free to actually implement the layout. + + #+begin_src css :tangle style.css :noweb yes +,* { + box-sizing: border-box; +} + +.fullwidth { + width: var(--body-width); +} + +@media (min-width: <<body-width()>>rem) { + .fullwidth { + margin-left: calc(-1 * (var(--margin-width) + var(--gutter-width))); + } +} + +html { + font-size: 1rem; +} + +body { + line-height: 1.4; + max-width: var(--body-width); + margin-left: auto; + margin-right: auto; +} + +aside { + background: var(--bg); + z-index: 9999; + width: var(--body-width); + align-self: flex-start; + position: sticky; + top: 0; +} + +aside nav { + text-align: center; + border-bottom: 1px solid var(--fade); +} + +aside nav ul { + list-style: none; + padding: 1rem 0; + margin: 0; +} + +aside nav li { + display: inline; +} + +aside nav li:not(:first-of-type)::before { + content: " · "; +} + +main { + counter-reset: sidenote-counter; + max-width: var(--main-width); + margin: auto; +} + +main nav { + font-style: italic; + color: var(--fg-plus); + background: var(--current-line); + padding: .5rem 1rem; +} + +main nav .series-next { + text-align: right; +} + +main nav p.series-next::after { + content: " →"; +} + +main nav p.series-prev::before { + content: "← "; +} + +img { + max-width: 100%; +} + +#whoami.marginnote { + color: var(--fg); + margin-bottom: 2em; +} + +img.avatar { + border-radius: 20px; + display: block; + max-width: 90%; + margin: auto; +} + +dd { + margin-left: 0; + margin-bottom: 0.5rem; +} + +.sidenote, +.marginnote { + font-size: smaller; + position: relative; + width: var(--margin-width); +} + +.sidenote { + margin-right: calc(-1 * (var(--margin-width) + var(--gutter-width))); + float: right; + clear: right; +} + +.marginnote { + float: left; + clear: left; + margin-left: calc(-1 * (var(--margin-width) + var(--gutter-width))); +} + +input.margin-toggle { + display: none; +} + +label.sidenote-number { + display: inline; +} + +label.margin-toggle:not(.sidenote-number) { + display: none; +} + +.sidenote-number:after, +.sidenote:before { + position: relative; + vertical-align: baseline; +} + +.sidenote-number { + counter-increment: sidenote-counter; +} + +.sidenote-number::after { + content: "(" counter(sidenote-counter, lower-greek) ")"; + font-size: 60%; + top: -0.4rem; + left: 0.1rem; +} + +.sidenote::before { + content: "(" counter(sidenote-counter, lower-greek) ")"; + font-size: 70%; + top: -0.5rem; + right: 0.1rem; +} + +div.code, +pre { + width: var(--code-width); + overflow-x: auto; + overflow-y: hidden; + padding: 1rem 2rem; +} + +main { + padding-top: 4.2rem; + padding-bottom: 4.2rem; +} + +h1 { + text-align: center; +} + +h2, h3, h4 { + font-style: italic; +} + +h1, h2, h3, h4 { + color: var(--doc); + font-family: serif; + font-weight: normal; +} + +dt { + font-weight: bold; +} + +div.code, +span.inlinecode, +pre, +tt, +.dmath, +.imath { + font-family: monospace; + font-size: 85%; +} + +details { + margin: 1.5rem 0; +} + +table { + border-top: 2px solid var(--fg); + border-bottom: 2px solid var(--fg); + border-collapse: collapse; + width: 100%; + margin: 1.5rem 0; +} + +th { + font-weight: normal; + text-transform: uppercase; +} + +td, +th { + border-top: 1px solid var(--fade); + height: 2em; + padding: 0 1em; +} + +td.date, +td.commit { + text-align: center; + font-size: 0.75em; + font-family: monospace; +} + +/* max-width has to be equal to --body-width */ +@media (max-width: <<body-width()>>rem) { + body { + padding: 2rem; + margin: auto; + display: block; + } + + aside { + width: var(--main-width); + margin: auto; + } + + label.margin-toggle:not(.sidenote-number) { + display: inline; + } + + .sidenote, + .marginnote { + display: none; + } + + .margin-toggle:checked + .sidenote, + .margin-toggle:checked + .marginnote { + display: block; + float: left; + left: 1rem; + clear: both; + width: 95%; + margin: 1rem 2.5%; + vertical-align: baseline; + position: relative; + } + + label { + cursor: pointer; + } + + pre, aside, div.code { + width: 100%; + } +} + #+end_src + +** Colors + + #+begin_src css :tangle style.css +:root { + --bg: white; + --bg-plus: #f7f7f7; + --current-line: #fbfbfb; + --fade: #cfcecb; + --fg: #3c3c3c; + --fg-plus: #575757; + --doc: black; + --warning: #bd745e; + --red: #b3534b; + --green: #6d9319; + --yellow: #d4b100; +} + #+end_src + + #+begin_src css :tangle style.css +body { + font-family: sans-serif; + color: var(--fg); + background: var(--bg); +} + +h2 a.anchor-link, +h3 a.anchor-link, +h4 a.anchor-link { + display: none; + font-style: normal; + text-decoration: none; + font-family: monospace; + font-size: smaller; + color: var(--doc); +} + +[id] { + scroll-margin-top: 4rem; +} + +h2:hover a.anchor-link, +h3:hover a.anchor-link, +h4:hover a.anchor-link { + display: inline; +} + +.sidenote, +.marginnote { + color: var(--fg-plus); +} + +pre, +code, +div.code, +span.inlinecode, +tt { + color: var(--doc); +} + #+end_src + +** Coq + + #+begin_src css :tangle style.css +div.code { + white-space: nowrap; +} + +div.code, +span.inlinecode { + font-family : monospace; +} + +.paragraph { + margin-bottom : .8em; +} + +.code a[href] { + color : inherit; + text-decoration : none; + background : var(--bg-plus); + padding : .1rem .15rem .1rem .15rem; + border-radius : 15%; +} + +.code .icon { + display: none; +} +#+END_SRC + +** Icons + + #+begin_src css :tangle style.css +.icon svg { + display: inline; + width: 1em; + height: .9em; + vertical-align: text-top; +} + +a[href], .margin-toggle { + color: #0000ee; +} + +a[href] .icon svg { + fill: #0000ee; +} + +a[href]:visited { + color: #25008b; +} + +a[href]:visited .icon svg { + fill: #25008b; +} + +.url-mark.fa { + display: inline; + font-size: 90%; + width: 1em; +} + +.url-mark.fa-github::before { + content: "\00a0\f09b"; +} + +.url-mark.fa-external-link::before { + content: "\00a0\f08e"; +} + #+end_src + +** Minify CSS + + #+begin_src shell :shebang #!/bin/bash :tangle scripts/css.sh +minify="$(npm bin)/minify" +normalize="$(npm root)/normalize.css/normalize.css" +style="style.css" + +# minify add a newline character at the end of its input +# we remove it using `head' +echo " +@charset \"UTF-8\"; +$(cat ${normalize}) +$(cat ${style}) +" | ${minify} --css | head -c -1 > style.min.css + #+end_src + + #+begin_src makefile :tangle theme.mk +style.min.css : style.css dependencies-prebuild + @cleopatra echo "Minifying" "CSS" + @scripts/css.sh + +ARTIFACTS += style.min.css + +theme-build : style.min.css + #+end_src + +* HTML Templates + + It would be best if we had a preprocessing step to inject the + minified style, rather than using ~soupault~ to do the work once per + page. + + #+begin_src html :tangle templates/main.html :noweb yes +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <style></style> + <link href="https://soap.coffee/+vendors/katex.0.11.1+swap/katex.css" rel="stylesheet" media="none" onload="if(media!='all')media='all'"> + <title></title> + </head> + <body> + <aside> + <nav> + <ul> + <li> + <a href="/">Technical Posts</a> + </li> + <li> + <a href="/opinions">Opinions</a> + </li> + <li> + <a href="/news">News</a> + </li> + </ul> + </nav> + </aside> + <main> + <span id="whoami" class="marginnote"> + <img class="avatar" src="/img/vampy.jpg" /> + + <p> + Hi, I’m <strong>lthms</strong>. + </p> + + <p> + I don’t like syntax highlighting, but I like + types and functional programming languages. + He/him. + </p> + + <p> + Interested in starting a discussion? Don’t hesitate to <a + href="mailto:~lthms/public-inbox@lists.sr.ht">shoot me an + email</a>. + </p> + </span> + </main> + </body> +</html> + #+end_src |