Fork me on GitHub
#clerk
<
2023-06-01
>
Kira Howe03:06:32

Forgive the probably repeat question.. I haven’t been following Clerk development super closely but I love using it. I was just wondering if there are any plans to implement more publishing-type features in Clerk? E.g. • a single “main” table of contents on the left (which would be a list of namespaces, like the current index) with “sub” TOCs on the right side • navigation links between namespaces • search I’m interested in using Clerk to publish a book but right now there are some features I think add a lot to the usability of educational content online that (as far as I can tell) aren’t present in Clerk (yet?). Anyway.. before I spend much time looking into other solutions I was just curious if there’s anyone privy to the internal development of Clerk who might be interested/willing to share about the future “vision”.. is there any plan to make Clerk like e.g. Quarto, or is the focus more toward e.g. literate programming, interactive demos, etc etc? I noticed (undocumented) support for open graph, the index builder, etc which seem to point toward using it for more “polished” publishing purposes.. anyway. Appreciate any insight anyone has!

jackrusher06:06:09

We’ve recently added a number of these features (links, main index, &c), but I can’t say for sure whether it would meet all of your needs out of the box. However, it’s been an important goal of Clerk to be not only a tool but also a toolbox, so one can customize it to suit other uses with very little code!

Casey10:05:12

@jackrusher I'm familiar with the {:nextjournal.clerk/toc true} option to enable a TOC inside a namespace, but is there a (perhaps undocumented) feature for creating a TOC or between namespaces like Kira suggested?

jackrusher10:05:45

We have some additional stuff for custom TOCs and interlinking, but I’m not sure the status is head. My colleague @U9EQP1K0X was working on that functionality, but he’s currently on holiday for another week or so, and I haven’t time just now to dig into it myself.

Andrea12:05:37

We have some utilities around e.g. cross-doc ToC which might be extracted from a private project sometime, the rough idea of it though should be contained in this example: https://github.com/nextjournal/clerk/blob/main/notebooks/meta_toc.clj

🙌 1
oly08:06:41

I can see there is a :index option for the build option is there something similar for serve so I can have a local index page which has all my notebooks listed with auto refresh ?

mkvlr08:06:20

not yet, at least if your index isn’t called index.clj

mkvlr08:06:48

but coming soon:tm:

👍 2
daveliepmann10:06:21

I'd like to port @mhuebert's https://www.maria.cloud/cells to a Clerk representation. One feature that would be nice to preserve is automatic re-rendering of a value which changes periodically, such as an ever-incrementing counter using interval. Is there prior art on getting Clerk to repeatedly check & display such a value? ::clerk/sync true doesn't seem to be sufficient without somehow also triggering clerk/show but perhaps I'm missing something. In my current experiments the value lives on the JVM side but I'm open to approaches which push it to the cljs side.

👀 6
daveliepmann10:06:21

A quick-and-dirty example of what I'm trying to do:

^{::clerk/sync true}
(do (def x (atom nil))
    (doto (Thread. (fn []
                     (Thread/sleep 1000)
                     (swap! x (fnil inc 0))
                     (recur)))
      (.start))
    x)
I'd like to see this value changing in Clerk without doing anything.

mkvlr11:06:59

clerk sync currently needs to be defined on vars, need to check why your example doesn’t error (think it should). It works if you take things apart like so:

(ns scratch.debug
  (:require [nextjournal.clerk :as clerk]))

^{::clerk/sync true}
(def x (atom nil))

(defonce thread
  (doto (Thread. (fn []
                   (Thread/sleep 1000)
                   (swap! x (fnil inc 0))
                   (recur)))
    (.start)))

mhuebert11:06:23

Would Dave's example work if it returned #'x?

mkvlr11:06:05

I think the var would need to be wrapped in a map under a :nextjournal.clerk/var-from-def key. Can try when I’m back at a 💻

mkvlr12:06:56

this works as well

^{::clerk/sync true}
(defonce a
  (do (doto (Thread. (fn []
                       (Thread/sleep 1000)
                       (swap! a (fnil inc 0))
                       (recur)))
        (.start))
      (atom nil)))

👍 2
jackrusher07:06:08

NB this will leak threads

👍 2
daveliepmann10:06:21

A slightly more mature approach: https://gist.github.com/daveliepmann/0fcb2f4204a395673b723ea721d51a5e Is there a way to accomplish this without manually wrapping with ::clerk/var-from-def?

jackrusher08:06:03

@U05092LD5 The problem is that if someone edits a Clerk document to remove a defonce containing an interval, it will just keep updating the atom in background forever. We need a way for the interval subsystem to know when a var is no longer bound.

mhuebert08:06:24

If we are using cells, and Clerk is watching the cell, and the interval is started from within the cell, then cleanup can happen automatically when clerk unwatches the cell

mhuebert08:06:26

Which shouldn't be that hard since the heavy lifting is done by re-db/reactive

jackrusher08:06:32

@mhuebert these ifs sadly don’t apply to the situation at hand

mhuebert08:06:46

Ah I thought we were still talking about the original Q

jackrusher09:06:32

Clerk uses static analysis to provide dataflow-ish behavior without explicit markers (i.e. def, not defcell), which presents different challenges that need to be addresses as part of the solution here. So, in terms of those ifs: we are not using cells, &c, &c.

jackrusher09:06:08

(that said, there’s definitely utility in creating a cells-like library that can play nice with Clerk!)

mhuebert09:06:22

Ok. I thought Dave wanted to literally port cells to clj/clerk and had just made a minimal example using an atom to try and figure out the change propagation bit

☝️ 2
daveliepmann13:06:14

I'm aware of the orphan thread problem and plan to address that separately (and separate from Clerk's dataflow). Right now I just want to be sure whatever I make will operate harmoniously with Clerk's live updates. My suspicion is that I should be writing a viewer instead of wrapping with {::clerk/var-from-def x} so I was hoping there was an example or some docs so I could understand it. Open to suggestions; maybe we should have a chat

👍 2