diff options
| author | Craig Jennings <c@cjennings.net> | 2026-02-14 03:21:13 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-02-14 03:21:13 -0600 |
| commit | 176ea668cdd83beddd54a24334a8a9db3cc87dfb (patch) | |
| tree | e0ee5727213fc9bf46bbf1c99dc574877410ac30 /modules | |
| parent | ebd8b2ce83941386b196e663d8f8ba83d7ce44c1 (diff) | |
feat(reveal): add org-reveal presentation workflow with ERT tests
Replaced pandoc-based reveal.js export with native ox-reveal integration.
New org-reveal-config.el module provides offline, self-contained HTML export
with keybindings under C-; p. Includes setup script for reveal.js 5.1.0
and 34 ERT tests covering header template and title-to-filename helpers.
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/org-export-config.el | 52 | ||||
| -rw-r--r-- | modules/org-reveal-config.el | 162 |
2 files changed, 167 insertions, 47 deletions
diff --git a/modules/org-export-config.el b/modules/org-export-config.el index 33e170f5..4451eddd 100644 --- a/modules/org-export-config.el +++ b/modules/org-export-config.el @@ -13,14 +13,14 @@ ;; - Texinfo: GNU documentation and Info files ;; ;; Extended via Pandoc: -;; - Additional formats: DOCX, EPUB, reveal.js presentations -;; - Self-contained HTML exports with embedded resources +;; - Additional formats: DOCX, self-contained HTML5 ;; - Custom PDF export with Zathura integration ;; ;; Key features: ;; - UTF-8 encoding enforced across all backends ;; - Subtree export as default scope -;; - reveal.js presentations with CDN or local embedding options +;; +;; Note: reveal.js presentations are handled by org-reveal-config.el (C-; p) ;; ;;; Code: @@ -79,47 +79,7 @@ (setq org-pandoc-options '((standalone . t) (mathjax . t))) - ;; Configure reveal.js specific options - (setq org-pandoc-options-for-revealjs - '((standalone . t) - (variable . "revealjs-url=https://cdn.jsdelivr.net/npm/reveal.js") - (variable . "theme=black") ; or white, league, beige, sky, night, serif, simple, solarized - (variable . "transition=slide") ; none, fade, slide, convex, concave, zoom - (variable . "slideNumber=true") - (variable . "hash=true") - (self-contained . t))) ; This embeds CSS/JS when possible - - ;; Custom function for self-contained reveal.js export - (defun my/org-pandoc-export-to-revealjs-standalone () - "Export to reveal.js with embedded dependencies." - (interactive) - (let* ((org-pandoc-options-for-revealjs - (append org-pandoc-options-for-revealjs - '((self-contained . t) - (embed-resources . t)))) ; pandoc 3.0+ option - (html-file (org-pandoc-export-to-revealjs))) - (when html-file - (browse-url-of-file html-file) - (message "Opened reveal.js presentation: %s" html-file)))) - - ;; Alternative: Download and embed local reveal.js - (defun my/org-pandoc-export-to-revealjs-local () - "Export to reveal.js using local copy of reveal.js." - (interactive) - (let* ((reveal-dir (expand-file-name "reveal.js" user-emacs-directory)) - (org-pandoc-options-for-revealjs - `((standalone . t) - (variable . ,(format "revealjs-url=%s" reveal-dir)) - (variable . "theme=black") - (variable . "transition=slide") - (variable . "slideNumber=true")))) - (unless (file-exists-p reveal-dir) - (cj/log-silently "Downloading reveal.js...") - (shell-command - (format "git clone https://github.com/hakimel/reveal.js.git %s" reveal-dir))) - (org-pandoc-export-to-revealjs))) - - ;; Configure specific format options (your existing config) + ;; Configure specific format options (setq org-pandoc-options-for-latex-pdf '((pdf-engine . "pdflatex"))) (setq org-pandoc-options-for-html5 '((html-q-tags . t) (self-contained . t))) @@ -134,12 +94,10 @@ (start-process "zathura-pdf" nil "zathura" pdf-file) (message "Opened %s in Zathura" pdf-file)))) - ;; Updated menu entries with reveal.js options + ;; Pandoc export menu entries (setq org-pandoc-menu-entry '((?4 "to html5 and open" org-pandoc-export-to-html5-and-open) (?$ "as html5" org-pandoc-export-as-html5) - (?r "to reveal.js (CDN) and open" org-pandoc-export-to-revealjs-and-open) - (?R "to reveal.js (self-contained)" my/org-pandoc-export-to-revealjs-standalone) (?< "to markdown" org-pandoc-export-to-markdown) (?d "to docx and open" org-pandoc-export-to-docx-and-open) (?z "to pdf and open (Zathura)" my/org-pandoc-export-to-pdf-and-open)))) diff --git a/modules/org-reveal-config.el b/modules/org-reveal-config.el new file mode 100644 index 00000000..3ab80315 --- /dev/null +++ b/modules/org-reveal-config.el @@ -0,0 +1,162 @@ +;;; org-reveal-config.el --- Reveal.js Presentation Configuration -*- lexical-binding: t; coding: utf-8; -*- +;; author: Craig Jennings <c@cjennings.net> + +;;; Commentary: +;; Integrates ox-reveal for creating reveal.js presentations from Org files. +;; +;; Fully offline workflow using a local reveal.js clone (managed by +;; scripts/setup-reveal.sh) and self-contained HTML export. +;; +;; Keybindings (C-; p prefix): +;; - C-; p e : Export to self-contained HTML and open in browser +;; - C-; p p : Start live preview (re-exports on save) +;; - C-; p s : Stop live preview +;; - C-; p h : Insert #+REVEAL_ header block at top of current buffer +;; - C-; p n : Create new presentation file (prompts for title and location) + +;;; Code: + +;; Forward declarations for byte-compiler (ox-reveal loaded via use-package) +(defvar org-reveal-root) +(defvar org-reveal-single-file) +(defvar org-reveal-plugins) +(defvar org-reveal-highlight-css) +(defvar org-reveal-init-options) +(declare-function org-reveal-export-to-html "ox-reveal") + +;; --------------------------------- Constants --------------------------------- + +(defconst cj/reveal-root + (expand-file-name "reveal.js" user-emacs-directory) + "Local reveal.js installation directory.") + +(defconst cj/reveal-default-theme "black" + "Default reveal.js theme for new presentations.") + +(defconst cj/reveal-default-transition "slide" + "Default reveal.js slide transition for new presentations.") + +;; --------------------------------- ox-reveal --------------------------------- + +(use-package ox-reveal + :after ox + :config + (setq org-reveal-root (concat "file://" cj/reveal-root)) + (setq org-reveal-single-file t) + (setq org-reveal-plugins '(highlight notes search zoom)) + (setq org-reveal-highlight-css "%r/plugin/highlight/monokai.css") + (setq org-reveal-init-options "slideNumber:true, hash:true")) + +;; ----------------------------- Private Helpers ------------------------------- + +(defun cj/--reveal-header-template (title) + "Return the reveal.js header block string for TITLE." + (unless (stringp title) + (user-error "Title must be a string")) + (format "#+TITLE: %s +#+AUTHOR: %s +#+DATE: %s +#+REVEAL_ROOT: %s +#+REVEAL_THEME: %s +#+REVEAL_TRANS: %s +#+REVEAL_INIT_OPTIONS: slideNumber:true, hash:true +#+REVEAL_PLUGINS: (highlight notes search zoom) +#+REVEAL_HIGHLIGHT_CSS: %%r/plugin/highlight/monokai.css +#+OPTIONS: toc:nil num:nil + +" title (user-full-name) (format-time-string "%Y-%m-%d") + (concat "file://" cj/reveal-root) + cj/reveal-default-theme + cj/reveal-default-transition)) + +(defun cj/--reveal-title-to-filename (title) + "Convert TITLE to a slug-based .org filename. +Downcases TITLE, replaces whitespace runs with hyphens, appends .org." + (concat (replace-regexp-in-string "[[:space:]]+" "-" (downcase title)) + ".org")) + +(defun cj/--reveal-preview-export-on-save () + "Export current org buffer to reveal.js HTML silently. +Intended for use as a buffer-local `after-save-hook'." + (when (derived-mode-p 'org-mode) + (let ((inhibit-message t)) + (org-reveal-export-to-html)))) + +;; ----------------------------- Public Functions ------------------------------ + +(defun cj/reveal-export () + "Export current Org buffer to self-contained reveal.js HTML and open in browser." + (interactive) + (unless (derived-mode-p 'org-mode) + (user-error "Not in an Org buffer")) + (let ((html-file (org-reveal-export-to-html))) + (when html-file + (browse-url-of-file html-file) + (message "Opened presentation: %s" html-file)))) + +(defun cj/reveal-preview-start () + "Start live preview: re-export to HTML on every save. +Opens the presentation in a browser on first call. Subsequent saves +re-export silently; refresh the browser to see changes." + (interactive) + (unless (derived-mode-p 'org-mode) + (user-error "Not in an Org buffer")) + (add-hook 'after-save-hook #'cj/--reveal-preview-export-on-save nil t) + (let ((html-file (org-reveal-export-to-html))) + (when html-file + (browse-url-of-file html-file))) + (message "Live preview started — save to re-export, refresh browser to update")) + +(defun cj/reveal-preview-stop () + "Stop live preview by removing the after-save-hook." + (interactive) + (remove-hook 'after-save-hook #'cj/--reveal-preview-export-on-save t) + (message "Live preview stopped")) + +(defun cj/reveal-insert-header () + "Insert a #+REVEAL_ header block at the top of the current Org buffer." + (interactive) + (unless (derived-mode-p 'org-mode) + (user-error "Not in an Org buffer")) + (let ((title (read-from-minibuffer "Presentation title: "))) + (save-excursion + (goto-char (point-min)) + (insert (cj/--reveal-header-template title))) + (message "Inserted reveal.js headers"))) + +(defun cj/reveal-new () + "Create a new reveal.js presentation file. +Prompts for a title and save location, then opens the file with +reveal.js headers pre-filled." + (interactive) + (let* ((title (read-from-minibuffer "Presentation title: ")) + (default-dir (expand-file-name "~/")) + (file (read-file-name "Save presentation to: " default-dir nil nil + (cj/--reveal-title-to-filename title)))) + (when (file-exists-p file) + (user-error "File already exists: %s" file)) + (find-file file) + (insert (cj/--reveal-header-template title)) + (insert "* Slide 1\n\n") + (save-buffer) + (message "New presentation: %s" file))) + +;; -------------------------------- Keybindings -------------------------------- + +(global-set-key (kbd "C-; p e") #'cj/reveal-export) +(global-set-key (kbd "C-; p p") #'cj/reveal-preview-start) +(global-set-key (kbd "C-; p s") #'cj/reveal-preview-stop) +(global-set-key (kbd "C-; p h") #'cj/reveal-insert-header) +(global-set-key (kbd "C-; p n") #'cj/reveal-new) + +(with-eval-after-load 'which-key + (which-key-add-key-based-replacements + "C-; p" "presentations" + "C-; p e" "export & open" + "C-; p p" "start live preview" + "C-; p s" "stop live preview" + "C-; p h" "insert headers" + "C-; p n" "new presentation")) + +(provide 'org-reveal-config) +;;; org-reveal-config.el ends here |
