Skip to content

Move render code to cljs file and load using require-cljs #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{:aliases
{:dev {:extra-paths ["dev"]}
:nextjournal/clerk
{:extra-deps {io.github.nextjournal/clerk {:git/sha "b7207926bacb10e6af17075efd71df3363b74d21"}}
{:extra-deps {io.github.nextjournal/clerk {:git/sha "2f6ef0d041126f54478ce1cba3a961916fb3c99a"}}
:extra-paths ["notebooks"]
:exec-fn nextjournal.clerk/build-static-app!
:exec-args {:paths ["notebooks/simple_slideshow.clj"]}}}}
73 changes: 7 additions & 66 deletions src/nextjournal/clerk_slideshow.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@
;; ---
(ns nextjournal.clerk-slideshow
(:require [nextjournal.clerk.viewer :as v]
[nextjournal.clerk-slideshow.render :as-alias render]
[nextjournal.clerk :as clerk]))

;; With a custom viewer and some helper functions, we can turn a Clerk notebooks into a presentation.
;;
;; `slide-viewer` wraps a collection of blocks into markup suitable for rendering a slide.

(def slide-viewer
{:render-fn '(fn [blocks opts]
[:div.flex.flex-col.justify-center
{:style {:min-block-size "100vh"}}
(into [:div.text-xl.p-20 {:class ["prose max-w-none prose-h1:mb-0 prose-h2:mb-8 prose-h3:mb-8 prose-h4:mb-8"
"prose-h1:text-6xl prose-h2:text-5xl prose-h3:text-3xl prose-h4:text-2xl"]}]
(nextjournal.clerk.render/inspect-children opts)
blocks)])})
{:render-fn `render/render-slide
:require-cljs true})

;; We need a simpler code viewer than the default one, one that adapts to the full width of the slideshow.
(def code-viewer
{:render-fn '(fn [code] [:div.code-viewer [nextjournal.clerk.render.code/render-code code {:language "clojure"}]])
{:render-fn `render/render-code
:require-cljs true
:transform-fn (comp v/mark-presented (v/update-val :text-without-meta))})

;; ---
Expand All @@ -40,64 +37,8 @@
(def viewer
(assoc v/notebook-viewer
:transform-fn (v/update-val doc->slides)
:render-fn '(fn [slides]
(reagent.core/with-let [!state (reagent.core/atom {:current-slide 0
:grid? false
:viewport-width js/innerWidth
:viewport-height js/innerHeight})
ref-fn (fn [el]
(when el
(swap! !state assoc :stage-el el)
(js/addEventListener "resize"
#(swap! !state assoc
:viewport-width js/innerWidth
:viewport-height js/innerHeight))
(js/document.addEventListener "keydown"
(fn [e]
(case (.-key e)
"Escape" (swap! !state update :grid? not)
"ArrowRight" (when-not (:grid? !state)
(swap! !state update :current-slide #(min (dec (count slides)) (inc %))))
"ArrowLeft" (when-not (:grid? !state)
(swap! !state update :current-slide #(max 0 (dec %))))
nil)))))
default-transition {:type :spring :duration 0.4 :bounce 0.1}]
(let [{:keys [grid? current-slide viewport-width viewport-height]} @!state]
[:div.overflow-hidden.relative.bg-slate-50.dark:bg-slate-800
{:ref ref-fn :id "stage" :style {:width viewport-width :height viewport-height}}
(into [:> (.. framer-motion -motion -div)
{:style {:width (if grid? viewport-width (* (count slides) viewport-width))}
:initial false
:animate {:x (if grid? 0 (* -1 current-slide viewport-width))}
:transition default-transition}]
(map-indexed
(fn [i slide]
(let [width 250
height 150
gap 40
slides-per-row (int (/ viewport-width (+ gap width)))
col (mod i slides-per-row)
row (int (/ i slides-per-row))]
[:> (.. framer-motion -motion -div)
{:initial false
:class ["absolute left-0 top-0 overflow-x-hidden bg-white"
(when grid?
"rounded-lg shadow-lg overflow-y-hidden cursor-pointer ring-1 ring-slate-200 hover:ring hover:ring-blue-500/50 active:ring-blue-500")]
:animate {:width (if grid? width viewport-width)
:height (if grid? height viewport-height)
:x (if grid? (+ gap (* (+ gap width) col)) (* i viewport-width))
:y (if grid? (+ gap (* (+ gap height) row)) 0)}
:transition default-transition
:on-click #(when grid? (swap! !state assoc :current-slide i :grid? false))}
[:> (.. framer-motion -motion -div)
{:style {:width viewport-width
:height viewport-height
:transformOrigin "left top"}
:initial false
:animate {:scale (if grid? (/ width viewport-width) 1)}
:transition default-transition}
[nextjournal.clerk.render/inspect-presented slide]]]))
slides))])))))
:render-fn `render/render-slideshow
:require-cljs true))

(comment
(clerk/add-viewers! [viewer])
Expand Down
77 changes: 77 additions & 0 deletions src/nextjournal/clerk_slideshow/render.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
(ns nextjournal.clerk-slideshow.render
(:require ["framer-motion" :as framer-motion :refer [motion]]
[nextjournal.clerk.render :as render]
[nextjournal.clerk.render.code :as render.code]
[reagent.core :as reagent]))

(defn render-slide [blocks opts]
[:div.flex.flex-col.justify-center
{:style {:min-block-size "100vh"}}
(into [:div.text-xl.p-20 {:class ["prose max-w-none prose-h1:mb-0 prose-h2:mb-8 prose-h3:mb-8 prose-h4:mb-8"
"prose-h1:text-6xl prose-h2:text-5xl prose-h3:text-3xl prose-h4:text-2xl"]}]
(render/inspect-children opts)
blocks)])

;; We need a simpler code viewer than the default one, one that adapts to the full width of the slideshow.
(defn render-code [code]
[:div.code-viewer [render.code/render-code code {:language "clojure"}]])

(defn render-slideshow [slides]
(reagent/with-let [!state (reagent/atom {:current-slide 0
:grid? false
:viewport-width js/innerWidth
:viewport-height js/innerHeight})
ref-fn (fn [el]
(when el
(swap! !state assoc :stage-el el)
(js/addEventListener "resize"
#(swap! !state assoc
:viewport-width js/innerWidth
:viewport-height js/innerHeight))
(js/document.addEventListener "keydown"
(fn [e]
(case (.-key e)
"Escape" (swap! !state update :grid? not)
"ArrowRight" (when-not (:grid? !state)
(swap! !state update :current-slide #(min (dec (count slides)) (inc %))))
"ArrowLeft" (when-not (:grid? !state)
(swap! !state update :current-slide #(max 0 (dec %))))
nil)))))
default-transition {:type :spring :duration 0.4 :bounce 0.1}]
(let [{:keys [grid? current-slide viewport-width viewport-height]} @!state]
[:div.overflow-hidden.relative.bg-slate-50.dark:bg-slate-800
{:ref ref-fn :id "stage" :style {:width viewport-width :height viewport-height}}
(into [:> (.-div motion)
{:style {:width (if grid? viewport-width (* (count slides) viewport-width))}
:initial false
:animate {:x (if grid? 0 (* -1 current-slide viewport-width))}
:transition default-transition}]
(map-indexed
(fn [i slide]
(let [width 250
height 150
gap 40
slides-per-row (int (/ viewport-width (+ gap width)))
col (mod i slides-per-row)
row (int (/ i slides-per-row))]
[:> (.-div motion)
{:initial false
:class ["absolute left-0 top-0 overflow-x-hidden bg-white"
(when grid?
"rounded-lg shadow-lg overflow-y-hidden cursor-pointer ring-1 ring-slate-200 hover:ring hover:ring-blue-500/50 active:ring-blue-500")]
:animate {:width (if grid? width viewport-width)
:height (if grid? height viewport-height)
:x (if grid? (+ gap (* (+ gap width) col)) (* i viewport-width))
:y (if grid? (+ gap (* (+ gap height) row)) 0)}
:transition default-transition
:on-click #(when grid? (swap! !state assoc :current-slide i :grid? false))}
[:> (.-div motion)
{:style {:width viewport-width
:height viewport-height
:transformOrigin "left top"}
:initial false
:animate {:scale (if grid? (/ width viewport-width) 1)}
:transition default-transition}
[render/inspect-presented slide]]]))
slides))])))