Skip to content
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

Window API & Taps Window #457

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e245283
Expose window in SCI env and remove from render
philippamarkovics Apr 17, 2023
f7029eb
Fix shrinking header
philippamarkovics Apr 17, 2023
ec933d5
Add tap window poc
philippamarkovics Apr 17, 2023
78d417b
Draft for a global stateful clerk/window API
zampino Apr 17, 2023
5dcb35d
Draft of window-based global taps
zampino Apr 17, 2023
9997dfa
Pass options to clerk/window
zampino Apr 17, 2023
02f4161
Fix compile
zampino Apr 17, 2023
e0399f9
Fix taps
zampino Apr 17, 2023
d395617
Lint
zampino Apr 17, 2023
7be982b
Consistency
zampino Apr 17, 2023
a2c1438
Toward fixing pagination
zampino Apr 18, 2023
a2427a6
Fix changing same window values
zampino Apr 18, 2023
f0217a2
Fix pagination inside windows
zampino Apr 18, 2023
7882b71
Fix pagination across windows
zampino Apr 18, 2023
1c17fcf
Window titles and close button
philippamarkovics Apr 18, 2023
1bdea94
Reset default result padding in window
philippamarkovics Apr 18, 2023
75e5743
Also respect already existing css-classes
philippamarkovics Apr 18, 2023
655549f
Re-use tap viewers and state for taps window, add window ns
philippamarkovics Apr 18, 2023
ff404b1
Restore top-level API / rename
zampino Apr 18, 2023
5620687
Fix showing new taps
zampino Apr 18, 2023
c7a57e9
Show usage
zampino Apr 18, 2023
3f698f4
Remove destroyed windows from state
zampino Apr 18, 2023
61c5504
Fix cyclic deps
zampino Apr 18, 2023
fbe6509
Reimplement switch view for taps window
zampino Apr 18, 2023
c490f3e
Allow to clear taps
zampino Apr 18, 2023
943237c
Persist taps window view choice
zampino Apr 18, 2023
7e46979
Fix
zampino Apr 18, 2023
bc7a3e2
More work on tap window design
philippamarkovics Apr 18, 2023
34fc068
Cleaner switcher
philippamarkovics Apr 18, 2023
25cf8b6
Naming: close-window, close-all-windows, ::clerk/taps; use clerk-eval…
philippamarkovics Apr 18, 2023
462cbd7
Key windows with id so they don’t take over themselves
philippamarkovics Apr 18, 2023
456fae4
Fix switching
philippamarkovics Apr 18, 2023
985ff1b
Keep windows open when reloading page or showing different notebooks
philippamarkovics Apr 18, 2023
45aa8b5
Add intro to windows
philippamarkovics Apr 19, 2023
ca9a489
Merge branch 'main' into taps-window-2
mk Jun 21, 2023
0bf559b
sci repl window WIP
philippamarkovics Jun 20, 2023
cc90f90
Fix lint warnings
mk Jun 21, 2023
f9fd783
Resolve circular dep and avoid requring-resolve
mk Jun 21, 2023
1c793df
Start refactoring from window to generic session
mk Jun 21, 2023
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
49 changes: 49 additions & 0 deletions notebooks/tap_window.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
;; # 🪟 Windows
(ns tap-window
{:nextjournal.clerk/visibility {:code :hide :result :hide}
:nextjournal.clerk/no-cache true}
(:require [nextjournal.clerk :as clerk]
[nextjournal.clerk.tap :as tap]))

{::clerk/visibility {:code :show}}

;; Clerk windows are draggable, resizable and dockable containers that are floating on top of other content. Windows make it easy to show arbitary content, independent of a notebook, while still getting all the benefits of Clerk viewers. This can be nice for debugging. For example you could use it to inspect a data structure in one window and show the same data structure as a graph in a second window.

;; Windows have identity. In order to spawn one, you have to call something like:

(clerk/window! :my-window {:foo (vec (repeat 2 {:baz (range 30) :fooze (range 40)})) :bar (range 20)})

;; This creates a window with a `:my-window` id. The id makes the window addressable and, as such, allows to update its contents from the REPL. For example, you can call …

(clerk/window! :my-window {:title "A debug window"} (zipmap (range 1000) (map #(* % %) (range 1000))))

;; … to replace the contens of `:my-window`. The window itself will not be reinstantiated. The example also shows that `window!` takes an optional second `opts` argument that can be used to give it a custom title.

;; Windows have a dedicated close button but you can also use the id to close it from the REPL, e.g.

(clerk/close-window! :my-window)

;; Finally, there's also special `::clerk/taps` window that doesn't require you to set any content. Instead, it will show you a stream of taps (independant of the notebooks you are working in). So, whenever you `tap>` something, the Taps window will show it when it's open:

(comment
(clerk/window! ::clerk/taps))

;; Mind that windows live outside notebooks and once you spawn one, it shows until you close it again, even if you reload the page or show a different notebook!

(comment
(clerk/window! :test {:title "My Super-Duper Window"} (range 100))
(clerk/window! :test (clerk/html [:div.w-8.h-8.bg-green-500]))
(clerk/close-window! :test)
(clerk/close-all-windows!)
(clerk/window! ::clerk/taps)
(tap> (clerk/html [:div.w-8.h-8.bg-green-500]))
(tap> (clerk/vl {:description "A simple bar chart with embedded data."
:data {:values [{:a "A" :b 28} {:a "B" :b 55} {:a "C" :b 43}
{:a "D" :b 91} {:a "E" :b 81} {:a "F" :b 53}
{:a "G" :b 19} {:a "H" :b 87} {:a "I" :b 52}]}
:mark "bar"
:encoding {:x {:field "a" :type "nominal" :axis {:labelAngle 0}}
:y {:field "b" :type "quantitative"}}}))
(tap> 1)
(tap/reset-taps!)
(clerk/window! ::clerk/sci-repl))
36 changes: 36 additions & 0 deletions scratch_window.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
;; # 🪲Debug
(ns scratch-window
{:nextjournal.clerk/visibility {:code :hide :result :hide}
:nextjournal.clerk/no-cache true}
(:require [nextjournal.clerk :as clerk]
[nextjournal.clerk.viewer :as v]))

(def window-viewer
{:render-fn '(fn [{:keys [vals]} opts]
[nextjournal.clerk.render.window/show
(into [:div]
(map (fn [v]
[:div.mb-4.pb-4.border-b
[nextjournal.clerk.render/inspect-presented v]]))
(:nextjournal/value vals))])
:transform-fn v/mark-preserve-keys})

(defonce !taps (atom '()))

(defonce taps-setup (add-tap (fn [x]
(swap! !taps conj x)
(clerk/recompute!))))

^{::clerk/visibility {:result :show}}
(clerk/with-viewer window-viewer
{:vals @!taps})

(comment
(tap> (clerk/html [:div.w-8.h-8.bg-green-500]))
(tap> (clerk/plotly {:data [{:x [1 2 3 4]}]})))

(clerk/window! ::clerk/taps)
(clerk/destroy-window ::clerk/taps)
(clerk/list-windows)

(clerk/window! :test (range 100))
7 changes: 6 additions & 1 deletion src/nextjournal/clerk.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
[nextjournal.clerk.eval :as eval]
[nextjournal.clerk.parser :as parser]
[nextjournal.clerk.viewer :as v]
[nextjournal.clerk.webserver :as webserver]))
[nextjournal.clerk.webserver :as webserver]
[nextjournal.clerk.window :as window]))

(defonce ^:private !show-filter-fn (atom nil))
(defonce ^:private !last-file (atom nil))
Expand Down Expand Up @@ -78,6 +79,10 @@
#_(show! "https://raw.githubusercontent.com/nextjournal/clerk-demo/main/notebooks/rule_30.clj")
#_(show! (java.io.StringReader. ";; # In Memory Notebook 👋\n(+ 41 1)"))

(defn window! [& args] (apply window/open! args))
(defn close-window! [id] (window/close! id))
(defn close-all-windows! [] (window/close-all!))

(defn recompute!
"Recomputes the currently visible doc, without parsing it."
[]
Expand Down
24 changes: 20 additions & 4 deletions src/nextjournal/clerk/render.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
[nextjournal.clerk.render.hooks :as hooks]
[nextjournal.clerk.render.localstorage :as localstorage]
[nextjournal.clerk.render.navbar :as navbar]
[nextjournal.clerk.render.window :as window]
#_[nextjournal.clerk.render.window :as window]
[nextjournal.clerk.viewer :as viewer]
[reagent.core :as r]
[reagent.ratom :as ratom]
Expand Down Expand Up @@ -138,6 +138,7 @@
(assoc :fragment (subs (.-hash url) 1))))))))

(defn history-push-state [{:as opts :keys [path fragment replace?]}]
(js/console.log :history-push-state opts)
(when (not= path (some-> js/history .-state .-path))
(j/call js/history (if replace? :replaceState :pushState) (clj->js opts) "" (str (.. js/document -location -origin)
"/" path (when fragment (str "#" fragment))))))
Expand Down Expand Up @@ -549,6 +550,7 @@
[:span.cmt-meta tag] (when space? nbsp) value]))

(defonce !doc (ratom/atom nil))
(defonce !windows (ratom/atom {}))
(defonce !viewers viewer/!viewers)

(defn set-viewers! [scope viewers]
Expand Down Expand Up @@ -588,8 +590,7 @@
(swap! !state update :desc viewer/merge-presentations more fetch-opts))))}
[inspect-presented (:desc @!state)]]))

(defn show-window [& content]
[window/show content])
(declare clerk-eval)

(defn root []
[:<>
Expand All @@ -601,7 +602,17 @@
[exec-status status])]
(when-let [error (get-in @!doc [:nextjournal/value :error])]
[:div.fixed.top-0.left-0.w-full.h-full
[inspect-presented error]])])
[inspect-presented error]])
#_(when-not (:nextjournal/window-id @!doc)
(into [:<>]
(map (fn [[id state]]
^{:key id}
[window/show
[render-result state {}]
(-> state
(assoc :id id :on-close #(clerk-eval `(nextjournal.clerk.window/close! ~id)))
(dissoc :nextjournal/presented))]))
@!windows))])

(declare mount)

Expand Down Expand Up @@ -697,9 +708,14 @@
(if error (reject error) (resolve reply)))
(js/console.warn :process-eval-reply!/not-found :eval-id eval-id :keys (keys @!pending-clerk-eval-replies))))

(defn set-window-state! [{:keys [id state]}] (swap! !windows assoc id state))
(defn close-window! [{:keys [id]}] (swap! !windows dissoc id))

(defn ^:export dispatch [{:as msg :keys [type]}]
(let [dispatch-fn (get {:patch-state! patch-state!
:set-state! set-state!
:set-window-state! set-window-state!
:close-window! close-window!
:eval-reply process-eval-reply!}
type
(fn [_]
Expand Down
Loading