summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-08-21 19:22:27 -0500
committerCraig Jennings <c@cjennings.net>2025-08-21 19:22:27 -0500
commitd8ab62d791846870452438882c69ac84d35d58c7 (patch)
tree2e0347412e2864c5a397576fac3d50cad99b96d1
parent685a2b68e36d5f4d2b2d9dfc7b8232317ccae331 (diff)
downloaddotemacs-d8ab62d791846870452438882c69ac84d35d58c7.tar.gz
dotemacs-d8ab62d791846870452438882c69ac84d35d58c7.zip
tufte.css inlined for org to html export
- adding test.org and tufte.css for html exports - removed ox-pandoc from org-export-config - adjusted org-export-config to inline tufte.css instead of the default org css
-rw-r--r--assets/test.org29
-rw-r--r--assets/tufte.css506
-rw-r--r--modules/org-export-config.el80
3 files changed, 595 insertions, 20 deletions
diff --git a/assets/test.org b/assets/test.org
new file mode 100644
index 00000000..7ad5af83
--- /dev/null
+++ b/assets/test.org
@@ -0,0 +1,29 @@
+* My Document Title
+** Level 1
+Text under level 1
+- Bullet item 1 level 1
+*** TODO First Task
+Text under first task
+- Bullet item 1 first task
+*** Level 2
+Test under level 2
+- Bullet item 1 level 2
+**** TODO [#B] Second Task : Bullets and Checkboxes
+Text under second task
+More text under second task
+- Bullet item 1 second task
+- Bullet item 2 second task
+- [ ] unchecked second task
+- [X] checked second task
+**** Level 3: babel
+Text under level 3
+#+begin_src emacs-lisp
+ elisp code
+#+end_src
+
+#+begin_src latex
+ latex code
+#+end_src
+
+***** TODO Third Task
+Text under third task
diff --git a/assets/tufte.css b/assets/tufte.css
new file mode 100644
index 00000000..851f1b80
--- /dev/null
+++ b/assets/tufte.css
@@ -0,0 +1,506 @@
+@charset "UTF-8";
+
+/* Import ET Book styles
+ adapted from https://github.com/edwardtufte/et-book/blob/gh-pages/et-book.css */
+
+@font-face {
+ font-family: "et-book";
+ src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot");
+ src: url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.eot?#iefix") format("embedded-opentype"),
+ url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.woff") format("woff"),
+ url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.ttf") format("truetype"),
+ url("et-book/et-book-roman-line-figures/et-book-roman-line-figures.svg#etbookromanosf") format("svg");
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "et-book";
+ src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot");
+ src: url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.eot?#iefix") format("embedded-opentype"),
+ url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.woff") format("woff"),
+ url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.ttf") format("truetype"),
+ url("et-book/et-book-display-italic-old-style-figures/et-book-display-italic-old-style-figures.svg#etbookromanosf") format("svg");
+ font-weight: normal;
+ font-style: italic;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "et-book";
+ src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot");
+ src: url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.eot?#iefix") format("embedded-opentype"),
+ url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.woff") format("woff"),
+ url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.ttf") format("truetype"),
+ url("et-book/et-book-bold-line-figures/et-book-bold-line-figures.svg#etbookromanosf") format("svg");
+ font-weight: bold;
+ font-style: normal;
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "et-book-roman-old-style";
+ src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot");
+ src: url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.eot?#iefix") format("embedded-opentype"),
+ url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.woff") format("woff"),
+ url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.ttf") format("truetype"),
+ url("et-book/et-book-roman-old-style-figures/et-book-roman-old-style-figures.svg#etbookromanosf") format("svg");
+ font-weight: normal;
+ font-style: normal;
+ font-display: swap;
+}
+
+/* Tufte CSS styles */
+html {
+ font-size: 15px;
+}
+
+body {
+ width: 87.5%;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: 12.5%;
+ font-family: et-book, Palatino, "Palatino Linotype", "Palatino LT STD", "Book Antiqua", Georgia, serif;
+ background-color: #fffff8;
+ color: #111;
+ max-width: 1400px;
+ counter-reset: sidenote-counter;
+}
+
+/* Adds dark mode */
+@media (prefers-color-scheme: dark) {
+ body {
+ background-color: #151515;
+ color: #ddd;
+ }
+}
+
+h1 {
+ font-weight: 400;
+ margin-top: 4rem;
+ margin-bottom: 1.5rem;
+ font-size: 3.2rem;
+ line-height: 1;
+}
+
+h2 {
+ font-style: italic;
+ font-weight: 400;
+ margin-top: 2.1rem;
+ margin-bottom: 1.4rem;
+ font-size: 2.2rem;
+ line-height: 1;
+}
+
+h3 {
+ font-style: italic;
+ font-weight: 400;
+ font-size: 1.7rem;
+ margin-top: 2rem;
+ margin-bottom: 1.4rem;
+ line-height: 1;
+}
+h4 {
+ font-style: italic;
+ font-weight: 400;
+ font-size: 1.7rem;
+ margin-top: 2rem;
+ margin-bottom: 1.4rem;
+ line-height: 1;
+}
+
+h5, h6 {
+ font-style: italic;
+ font-weight: 400;
+ font-size: 1.7rem;
+ margin-top: 2rem;
+ margin-bottom: 1.4rem;
+ line-height: 1;
+}
+hr {
+ display: block;
+ height: 1px;
+ width: 55%;
+ border: 0;
+ border-top: 1px solid #ccc;
+ margin: 1em 0;
+ padding: 0;
+}
+
+p.subtitle {
+ font-style: italic;
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+ font-size: 1.8rem;
+ display: block;
+ line-height: 1;
+}
+
+.numeral {
+ font-family: et-book-roman-old-style;
+}
+
+.danger {
+ color: red;
+}
+
+article {
+ padding: 5rem 0rem;
+}
+
+section {
+ padding-top: 1rem;
+ padding-bottom: 1rem;
+}
+
+p,
+dl,
+ol,
+ul {
+ font-size: 1.4rem;
+ line-height: 2rem;
+}
+
+p {
+ margin-top: 1.4rem;
+ margin-bottom: 1.4rem;
+ padding-right: 0;
+ vertical-align: baseline;
+}
+
+/* Chapter Epigraphs */
+div.epigraph {
+ margin: 5em 0;
+}
+
+div.epigraph > blockquote {
+ margin-top: 3em;
+ margin-bottom: 3em;
+}
+
+div.epigraph > blockquote,
+div.epigraph > blockquote > p {
+ font-style: italic;
+}
+
+div.epigraph > blockquote > footer {
+ font-style: normal;
+}
+
+div.epigraph > blockquote > footer > cite {
+ font-style: italic;
+}
+/* end chapter epigraphs styles */
+
+blockquote {
+ font-size: 1.4rem;
+}
+
+blockquote p {
+ width: 55%;
+ margin-right: 40px;
+}
+
+/* Raised from 1.1rem to 1.4rem */
+blockquote footer {
+ width: 55%;
+ font-size: 1.4rem;
+ text-align: right;
+}
+
+section > p,
+section > footer,
+section > table {
+ width: 55%;
+}
+
+/* 50 + 5 == 55, to be the same width as paragraph */
+section > dl,
+section > ol,
+section > ul {
+ width: 50%;
+ -webkit-padding-start: 5%;
+}
+
+dt:not(:first-child),
+li:not(:first-child) {
+ margin-top: 0.25rem;
+}
+
+figure {
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+ max-width: 55%;
+ -webkit-margin-start: 0;
+ -webkit-margin-end: 0;
+ margin: 0 0 3em 0;
+}
+
+/* Raised from 1.1rem to 1.4rem */
+figcaption {
+ float: right;
+ clear: right;
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 1.4rem;
+ line-height: 1.6;
+ vertical-align: baseline;
+ position: relative;
+ max-width: 40%;
+}
+
+figure.fullwidth figcaption {
+ margin-right: 24%;
+}
+
+a:link,
+a:visited {
+ color: inherit;
+ text-underline-offset: 0.1em;
+ text-decoration-thickness: 0.05em;
+}
+
+/* Sidenotes, margin notes, figures, captions */
+img {
+ max-width: 100%;
+}
+
+/* Raised from 1.1rem to 1.4rem */
+.sidenote,
+.marginnote {
+ float: right;
+ clear: right;
+ margin-right: -60%;
+ width: 50%;
+ margin-top: 0.3rem;
+ margin-bottom: 0;
+ font-size: 1.4rem;
+ line-height: 1.3;
+ vertical-align: baseline;
+ position: relative;
+}
+
+.sidenote-number {
+ counter-increment: sidenote-counter;
+}
+
+/* Raised from 1rem to 1.4rem */
+.sidenote-number:after,
+.sidenote:before {
+ font-family: et-book-roman-old-style;
+ position: relative;
+ vertical-align: baseline;
+ font-size: 1.4rem;
+}
+
+.sidenote-number:after {
+ content: counter(sidenote-counter);
+ top: -0.5rem;
+ left: 0.1rem;
+}
+
+.sidenote:before {
+ content: counter(sidenote-counter) " ";
+ top: -0.5rem;
+}
+
+blockquote .sidenote,
+blockquote .marginnote {
+ margin-right: -82%;
+ min-width: 59%;
+ text-align: left;
+}
+
+div.fullwidth,
+table.fullwidth {
+ width: 100%;
+}
+
+div.table-wrapper {
+ overflow-x: auto;
+ font-family: "Trebuchet MS", "Gill Sans", "Gill Sans MT", sans-serif;
+}
+
+.sans {
+ font-family: "Gill Sans", "Gill Sans MT", Calibri, sans-serif;
+ letter-spacing: .03em;
+}
+
+/* Raised from 1.0/0.9rem to 1.4rem */
+code,
+pre > code {
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 1.4rem;
+ line-height: 1.42;
+ -webkit-text-size-adjust: 100%; /* Prevent adjustments of font size after orientation changes in iOS. */
+}
+
+/* Org-mode TODO keyword styling */
+span.todo {
+ display: inline-block;
+ padding: 0.2em 0.5em;
+ margin-right: 0.3em;
+ font-size: 1.4rem;
+ line-height: 2rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ border-radius: 0.2rem;
+ background-color: rgba(255, 0, 0, 0.1);
+ color: #c00;
+ border: 1px solid #c00;
+}
+
+/* If you ever export a DONE keyword: */
+span.todo.DONE {
+ font-size: 1.4rem;
+ line-height: 2rem;
+ background-color: rgba(0, 128, 0, 0.1);
+ color: #080;
+ border-color: #080;
+}
+
+/* Let heading‐code inherit so it’s never smaller than the heading itself */
+h1 > code,
+h2 > code,
+h3 > code,
+h4 > code {
+ font-size: inherit;
+}
+
+.marginnote > code,
+.sidenote > code {
+ font-size: 1.4rem;
+}
+
+/* Keep the same layout, but code in block still 1.4rem */
+pre > code {
+ width: 52.5%;
+ margin-left: 2.5%;
+ overflow-x: auto;
+ display: block;
+}
+
+pre.fullwidth > code {
+ width: 90%;
+}
+
+.fullwidth {
+ max-width: 90%;
+ clear:both;
+}
+
+span.newthought {
+ font-variant: small-caps;
+ font-size: 1.2em;
+}
+
+input.margin-toggle {
+ display: none;
+}
+
+label.sidenote-number {
+ display: inline-block;
+ max-height: 2rem; /* ≤ paragraph line-height */
+}
+
+label.margin-toggle:not(.sidenote-number) {
+ display: none;
+}
+
+.iframe-wrapper {
+ position: relative;
+ padding-bottom: 56.25%; /* 16:9 */
+ padding-top: 25px;
+ height: 0;
+}
+
+.iframe-wrapper iframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+@media (max-width: 760px) {
+ body {
+ width: 84%;
+ padding-left: 8%;
+ padding-right: 8%;
+ }
+
+ hr,
+ section > p,
+ section > footer,
+ section > table {
+ width: 100%;
+ }
+
+ pre > code {
+ width: 97%;
+ }
+
+ section > dl,
+ section > ol,
+ section > ul {
+ width: 90%;
+ }
+
+ figure {
+ max-width: 90%;
+ }
+
+ figcaption,
+ figure.fullwidth figcaption {
+ margin-right: 0%;
+ max-width: none;
+ }
+
+ blockquote {
+ margin-left: 1.5em;
+ margin-right: 0em;
+ }
+
+ blockquote p,
+ blockquote footer {
+ width: 100%;
+ }
+
+ 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;
+ }
+
+ div.table-wrapper,
+ table {
+ width: 85%;
+ }
+
+ img {
+ width: 100%;
+ }
+}
diff --git a/modules/org-export-config.el b/modules/org-export-config.el
index d451dd6f..6e4db7e8 100644
--- a/modules/org-export-config.el
+++ b/modules/org-export-config.el
@@ -19,9 +19,7 @@
ox-icalendar
ox-latex
ox-md
- ox-odt
- ox-texinfo
- ox-man))
+ ox-odt))
(require feat))
;; now tell Org exactly which backends to use
@@ -29,32 +27,27 @@
'(ascii
beamer
html
- icalendar
latex
md
- odt
- org
- texinfo
- man))
+ odt))
;; Other Settings
- (setq org-export-coding-system 'utf-8) ;; force utf-8 in org
- (setq org-export-headline-levels 6) ;; export headlines 6 levels deep
- (setq org-export-initial-scope 'subtree) ;; export the current subtree by default
- (setq org-export-with-author nil) ;; export without author by default
- (setq org-export-with-section-numbers nil) ;; export without section numbers by default
- (setq org-export-with-tags nil) ;; export without tags by default
- (setq org-export-with-tasks '("TODO")) ;; export with tasks by default
- (setq org-export-with-toc nil)) ;; export without table of contents by default
+ (setq org-export-preserve-breaks t) ;; keep line breaks in all Org export back-ends
+ (setq org-export-coding-system 'utf-8) ;; force utf-8 in org
+ (setq org-export-headline-levels 6) ;; export headlines 6 levels deep
+ (setq org-export-initial-scope 'subtree) ;; export the current subtree by default
+ (setq org-export-with-author nil) ;; export without author by default
+ (setq org-export-with-section-numbers nil) ;; export without section numbers by default
+ (setq org-export-with-tags nil) ;; export without tags by default
+ (setq org-export-with-tasks '("TODO")) ;; export with tasks by default
+ ;; (setq org-export-with-tasks nil) ;; export WITHOUT tasks by default
+ ;; (setq org-export-with-toc nil) ;; export without table of contents by default
+ (setq org-export-with-toc t)) ;; export WITH table of contents by default
;; hugo markdown
(use-package ox-hugo
:after ox)
-;; export via pandoc
-(use-package ox-pandoc
- :after ox)
-
;; github flavored markdown
(use-package ox-gfm
:after ox)
@@ -73,5 +66,52 @@
;; (use-package ox-confluence
;; :after ox)
+;; ------------------------------- Org Tufte CSS -------------------------------
+;; Hacks to inline a superior tufte.css style sheet into your generated html files.
+
+;;
+;; Inline tufte.css into all generated HTML documents
+;; Note: the tufte.css file in my configuration has an extra style for
+;; TODO and DONE task items.
+;;
+
+(defun cj/org-inline-css (path)
+ "Return the contents of the file at PATH as a string.
+If the file doesn’t exist, return an empty string."
+ (if (file-readable-p path)
+ (with-temp-buffer
+ (insert-file-contents path)
+ (buffer-string))
+ (progn
+ (message "[org-inline-css] could not read %s" path)
+ "")))
+
+(with-eval-after-load 'ox-html
+ ;; Disable the postamble (footer) completely:
+ (setq org-html-postamble nil)
+
+ ;; inject tufte.css from the assets folder.
+ (setq org-html-html5-fancy t
+ org-html-head-include-default-style nil
+ org-html-head-extra
+ (let* ((css-file (expand-file-name "assets/tufte.css"
+ user-emacs-directory))
+ (css (cj/org-inline-css css-file)))
+ (format "<style type=\"text/css\">\n%s\n</style>" css))))
+;;
+;; Don't allow Table of Contents to link to TODO items
+;;
+(defun cj/org-html-toc-remove-todo (toc-entry backend _info)
+ "Remove any <span class=\"todo …\">TODO</span> from a single TOC entry."
+ (when (eq backend 'html)
+ (replace-regexp-in-string
+ "<span class=\"todo [^\"]*\">[^<]*</span>[[:space:]]*"
+ "" toc-entry)))
+
+(with-eval-after-load 'ox-html
+ ;; register our filter so each TOC line is run through it
+ (add-hook 'org-export-filter-toc-entry-functions
+ #'cj/org-html-toc-remove-todo))
+
(provide 'org-export-config)
;;; org-export-config.el ends here.