From 9ba5a35f96944d1d64f5065bd3f47bfb763770a0 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 18 Jul 2020 02:43:52 +0800 Subject: [PATCH] Org html: add copy button to src/example block --- config.org | 31 +++-- misc/pile-css-theme/README.org | 9 +- misc/pile-css-theme/_code.js | 8 ++ misc/pile-css-theme/_code.scss | 30 ++++- misc/pile-css-theme/{toc.js => _toc.js} | 0 misc/pile-css-theme/main.css | 171 ++++++++++++++++++------ misc/pile-css-theme/main.js | 39 ++++++ 7 files changed, 237 insertions(+), 51 deletions(-) create mode 100644 misc/pile-css-theme/_code.js rename misc/pile-css-theme/{toc.js => _toc.js} (100%) create mode 100644 misc/pile-css-theme/main.js diff --git a/config.org b/config.org index fcf0284..d84cebe 100644 --- a/config.org +++ b/config.org @@ -4638,7 +4638,7 @@ Suffice to say I've snatched it, with a few of my own tweaks applied. (setq org-html-style-default (concat (f-read-text (expand-file-name "misc/org-export-header.html" doom-private-dir)) "\n") @@ -4659,11 +4659,17 @@ somewhat spiffy. (lang (mode-name-to-lang-name (plist-get properties :language))) (name (plist-get properties :name))) - (format "
%s%s
" - (if name " class='named'" "") - (if (not name) (concat "" lang "") - (format "%s%s" name lang)) - (funcall orig-fn src-block contents info)))) + (format + "
%s +
+\ +
+%s +
" + (if name " class='named'" "") + (if (not name) (concat "" lang "") + (format "%s%s" name lang)) + (funcall orig-fn src-block contents info)))) (defun mode-name-to-lang-name (mode) (or (cadr (assoc mode @@ -4747,8 +4753,7 @@ somewhat spiffy. ("vhdl" "VHDL") ("xml" "XML") ("nxml" "XML") - ("conf" "Configuration File") - ))) + ("conf" "Configuration File")))) mode)) #+END_SRC @@ -4757,9 +4762,13 @@ somewhat spiffy. (after! org (defun org-html-block-collapsable (orig-fn block contents info) "Wrap the usual block in a
" - (concat "
" - (funcall orig-fn block contents info) - "
")) + (concat + "
+
\ +\ +
\n" + (funcall orig-fn block contents info) + "
")) (advice-add 'org-html-example-block :around #'org-html-block-collapsable) (advice-add 'org-html-fixed-width :around #'org-html-block-collapsable) diff --git a/misc/pile-css-theme/README.org b/misc/pile-css-theme/README.org index 4c6d2d8..507b0f4 100644 --- a/misc/pile-css-theme/README.org +++ b/misc/pile-css-theme/README.org @@ -3,8 +3,15 @@ Sass files for my org exporting. Taken from [[github:lepisma/pile-theme][lepisma/pile-theme]]. #+NAME: om-sass -#+BEGIN_SRC shell :exports none +#+BEGIN_SRC shell :exports none :results output sassc main.scss main.css #+END_SRC #+RESULTS: om-sass + +#+NAME: make-js +#+BEGIN_SRC shell :exports none :results output +cat _*.js > main.js +#+END_SRC + +#+RESULTS: make-js diff --git a/misc/pile-css-theme/_code.js b/misc/pile-css-theme/_code.js new file mode 100644 index 0000000..c9f13b6 --- /dev/null +++ b/misc/pile-css-theme/_code.js @@ -0,0 +1,8 @@ +function copyPreToClipdord(btn) { + const pre = btn.parentElement.parentElement.getElementsByTagName("PRE")[0]; + const range = document.createRange(); + range.selectNode(pre); + window.getSelection().addRange(range); + var successful = document.execCommand('copy'); + window.getSelection().removeRange(range); +} diff --git a/misc/pile-css-theme/_code.scss b/misc/pile-css-theme/_code.scss index 7ccbf0b..96d0782 100644 --- a/misc/pile-css-theme/_code.scss +++ b/misc/pile-css-theme/_code.scss @@ -68,6 +68,7 @@ li { // folding details.code { + position: relative; summary { position: relative; left: -3px; @@ -100,7 +101,7 @@ details.code { margin-bottom: -26px; } &:not([open]) summary { - margin-bottom: -10px; + margin-bottom: -5px; } } @@ -108,6 +109,9 @@ details.code { p + details.code { margin-top: -20px; // pre margin size } +li p + details.code { + margin-top: -5px; +} // Palette copied from blog // ------------------------ @@ -168,6 +172,30 @@ $code-warning: $orange; } } +// copy button + +details.code > .gutter { + position: absolute; + top: 0; + left: -2.5rem; + width: 2.3rem; + padding-top: 10px; + height: calc(100% - 10px); + z-index: 1; + text-align: right; + transition: opacity 200ms; + opacity: 0; + font-size: 15px; + &:hover { + opacity: 1; + } + button { + color: $text-gray; + background: none; + border: none; + } +} + /* Languages per Org manual */ pre.src-asymptote::before { content: 'Asymptote'; } diff --git a/misc/pile-css-theme/toc.js b/misc/pile-css-theme/_toc.js similarity index 100% rename from misc/pile-css-theme/toc.js rename to misc/pile-css-theme/_toc.js diff --git a/misc/pile-css-theme/main.css b/misc/pile-css-theme/main.css index 413260d..b61c549 100644 --- a/misc/pile-css-theme/main.css +++ b/misc/pile-css-theme/main.css @@ -441,8 +441,8 @@ template { #switch-label { left: auto; left: bottom; - right: 1%; - top: 2.5rem; } } + right: 1vw; + top: 1vh; } } #switch-label::before { content: var(--switch-icon); @@ -1141,45 +1141,46 @@ li code { li p code { font-size: 15px; } -details.code summary { - position: relative; - left: -3px; - padding-left: 10px; - padding-botton: 4px; - margin-left: -10px; - z-index: 1; - outline: none; - font-family: "Open Sans"; - font-weight: normal; - font-style: normal; - font-size: 12px; - line-height: 1.9; - color: var(--text-light); } - details.code summary .name { - font-size: 14px; - color: var(--text-medium); - margin-right: 0.7em; } - details.code summary .lang { - font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; - font-style: italic; } - -details.code summary::marker { - color: var(--back-medium); } - -details.code[open] summary { - margin-bottom: -32px; } - details.code[open] summary .lang { - color: transparent; } - -details.code[open] summary.named { - margin-bottom: -26px; } - -details.code:not([open]) summary { - margin-bottom: -10px; } +details.code { + position: relative; } + details.code summary { + position: relative; + left: -3px; + padding-left: 10px; + padding-botton: 4px; + margin-left: -10px; + z-index: 1; + outline: none; + font-family: "Open Sans"; + font-weight: normal; + font-style: normal; + font-size: 12px; + line-height: 1.9; + color: var(--text-light); } + details.code summary .name { + font-size: 14px; + color: var(--text-medium); + margin-right: 0.7em; } + details.code summary .lang { + font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + font-style: italic; } + details.code summary::marker { + color: var(--back-medium); } + details.code[open] summary { + margin-bottom: -32px; } + details.code[open] summary .lang { + color: transparent; } + details.code[open] summary.named { + margin-bottom: -26px; } + details.code:not([open]) summary { + margin-bottom: -5px; } p + details.code { margin-top: -20px; } +li p + details.code { + margin-top: -5px; } + .example, .src { color: var(--code-foreground); } @@ -1225,6 +1226,25 @@ p + details.code { .src .org-highlight-numbers-number { color: var(--code-const); } +details.code > .gutter { + position: absolute; + top: 0; + left: -2.5rem; + width: 2.3rem; + padding-top: 10px; + height: calc(100% - 10px); + z-index: 1; + text-align: right; + transition: opacity 200ms; + opacity: 0; + font-size: 15px; } + details.code > .gutter:hover { + opacity: 1; } + details.code > .gutter button { + color: var(--text-gray); + background: none; + border: none; } + /* Languages per Org manual */ pre.src-asymptote::before { content: 'Asymptote'; } @@ -1789,7 +1809,82 @@ dl a { #crosslinks a:not(.highlight)[href^="#"], li a[href^="#"], dl a[href^="#"] { - color: var(--text-gray); } + text-shadow: 0.03em 0 var(--back-white), -0.03em 0 var(--back-white), 0 0.03em var(--back-white), 0 -0.03em var(--back-white), 0.06em 0 var(--back-white), -0.06em 0 var(--back-white), 0.09em 0 var(--back-white), -0.09em 0 var(--back-white), 0.12em 0 var(--back-white), -0.12em 0 var(--back-white), 0.15em 0 var(--back-white), -0.15em 0 var(--back-white); + background-image: linear-gradient(var(--text-gray), var(--text-gray)); + background-size: 1px 1px; + background-repeat: repeat-x; + background-position: 0% 95%; + border-radius: 1px; + color: var(--text-gray); + text-decoration: none; } + #breadcrumbs a[href^="#"]::selection, + figcaption a[href^="#"]::selection, + p a[href^="#"]::selection, + .page-tags a[href^="#"]::selection, + table a[href^="#"]::selection, + #crosslinks a:not(.highlight)[href^="#"]::selection, + li a[href^="#"]::selection, + dl a[href^="#"]::selection { + text-shadow: 0.03em 0 var(--back-medium), -0.03em 0 var(--back-medium), 0 0.03em var(--back-medium), 0 -0.03em var(--back-medium), 0.06em 0 var(--back-medium), -0.06em 0 var(--back-medium), 0.09em 0 var(--back-medium), -0.09em 0 var(--back-medium), 0.12em 0 var(--back-medium), -0.12em 0 var(--back-medium), 0.15em 0 var(--back-medium), -0.15em 0 var(--back-medium); + background: var(--back-medium); } + #breadcrumbs a[href^="#"]::-moz-selection, + figcaption a[href^="#"]::-moz-selection, + p a[href^="#"]::-moz-selection, + .page-tags a[href^="#"]::-moz-selection, + table a[href^="#"]::-moz-selection, + #crosslinks a:not(.highlight)[href^="#"]::-moz-selection, + li a[href^="#"]::-moz-selection, + dl a[href^="#"]::-moz-selection { + text-shadow: 0.03em 0 var(--back-medium), -0.03em 0 var(--back-medium), 0 0.03em var(--back-medium), 0 -0.03em var(--back-medium), 0.06em 0 var(--back-medium), -0.06em 0 var(--back-medium), 0.09em 0 var(--back-medium), -0.09em 0 var(--back-medium), 0.12em 0 var(--back-medium), -0.12em 0 var(--back-medium), 0.15em 0 var(--back-medium), -0.15em 0 var(--back-medium); + background: var(--back-medium); } + #breadcrumbs a[href^="#"] *, + #breadcrumbs a[href^="#"] *:after, #breadcrumbs a[href^="#"]:after, + #breadcrumbs a[href^="#"] *:before, #breadcrumbs a[href^="#"]:before, + figcaption a[href^="#"] *, + figcaption a[href^="#"] *:after, + figcaption a[href^="#"]:after, + figcaption a[href^="#"] *:before, + figcaption a[href^="#"]:before, + p a[href^="#"] *, + p a[href^="#"] *:after, + p a[href^="#"]:after, + p a[href^="#"] *:before, + p a[href^="#"]:before, + .page-tags a[href^="#"] *, + .page-tags a[href^="#"] *:after, + .page-tags a[href^="#"]:after, + .page-tags a[href^="#"] *:before, + .page-tags a[href^="#"]:before, + table a[href^="#"] *, + table a[href^="#"] *:after, + table a[href^="#"]:after, + table a[href^="#"] *:before, + table a[href^="#"]:before, + #crosslinks a:not(.highlight)[href^="#"] *, + #crosslinks a:not(.highlight)[href^="#"] *:after, + #crosslinks a:not(.highlight)[href^="#"]:after, + #crosslinks a:not(.highlight)[href^="#"] *:before, + #crosslinks a:not(.highlight)[href^="#"]:before, + li a[href^="#"] *, + li a[href^="#"] *:after, + li a[href^="#"]:after, + li a[href^="#"] *:before, + li a[href^="#"]:before, + dl a[href^="#"] *, + dl a[href^="#"] *:after, + dl a[href^="#"]:after, + dl a[href^="#"] *:before, + dl a[href^="#"]:before { + text-shadow: none; } + #breadcrumbs a[href^="#"]:visited, + figcaption a[href^="#"]:visited, + p a[href^="#"]:visited, + .page-tags a[href^="#"]:visited, + table a[href^="#"]:visited, + #crosslinks a:not(.highlight)[href^="#"]:visited, + li a[href^="#"]:visited, + dl a[href^="#"]:visited { + color: var(--text-gray); } #breadcrumbs a[href^="#"]:hover, figcaption a[href^="#"]:hover, p a[href^="#"]:hover, diff --git a/misc/pile-css-theme/main.js b/misc/pile-css-theme/main.js new file mode 100644 index 0000000..e2b77ab --- /dev/null +++ b/misc/pile-css-theme/main.js @@ -0,0 +1,39 @@ +function copyPreToClipdord(btn) { + const pre = btn.parentElement.parentElement.getElementsByTagName("PRE")[0]; + const range = document.createRange(); + range.selectNode(pre); + window.getSelection().addRange(range); + var successful = document.execCommand('copy'); + window.getSelection().removeRange(range); +} +window.addEventListener('DOMContentLoaded', () => { + const sections = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]'); + const activate = (entry) => { + entry.classList.add('active'); + if (["LI", "UL"].includes(entry.parentElement.tagName)) { + activate(entry.parentElement); + } + }; + const activateLast = () => { + document.querySelectorAll('#text-table-of-contents li.active, #text-table-of-contents ul.active').forEach(a => { + a.classList.remove('active') + }); + let mostRecent = { section: sections[0], bottom: -Infinity }; + const windowHeight = window.innerHeight; + sections.forEach((section) => { + const bounds = section.getBoundingClientRect() + if ( bounds.bottom > mostRecent.bottom && bounds.top < windowHeight ) { + mostRecent = { section, bottom: bounds.bottom }; + } + }) + activate(document.querySelector(`#text-table-of-contents li a[href="#${mostRecent.section.getAttribute('id')}"]`).parentElement); + } + + const observer = new IntersectionObserver(entries => { + activateLast(); + }); + + sections.forEach((section) => { + observer.observe(section); + }); +});