Skip to content

Commit

Permalink
Improve Sidenotes (nextjournal#392)
Browse files Browse the repository at this point in the history
Makes Clerk leverage the improved Sidenotes/Footnotes support from nextjournal/markdown#11.

Co-authored-by: Philippa Markovics <philippa@markovics.com>
  • Loading branch information
zampino and philippamarkovics authored Jan 25, 2023
1 parent 60f2399 commit 990749d
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 43 deletions.
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
weavejester/dependency {:mvn/version "0.2.1"}
com.nextjournal/beholder {:mvn/version "1.0.0"}

io.github.nextjournal/markdown {:mvn/version "0.4.135"}
io.github.nextjournal/markdown {:mvn/version "0.4.138"}
io.github.nextjournal/dejavu {:git/sha "4980e0cc18c9b09fb220874ace94ba6b57a749ca"}

com.taoensso/nippy {:mvn/version "3.2.0"}
Expand Down
9 changes: 6 additions & 3 deletions notebooks/markdown.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# $\mathfrak{M}\!⬇$ Markdown Ingestion

This notebook demoes feeding Clerk with markdown files. We currently make no assumption on the kind of source code passed in fenced blocks, we handle code as if it were clojure. Indented code blocks are treated as inert code blocks.
This notebook demoes feeding Clerk with markdown files. We currently make no assumption on the kind of source code passed in fenced blocks[^fenced], we handle code as if it were clojure. Indented code blocks are treated as inert code blocks.

```clj
^:nextjournal.clerk/no-cache
Expand All @@ -22,9 +22,9 @@ Nextjournal Markdown library is able to ingest a markdown string
(def parsed (md/parse markdown-input))
```

At present, Clerk will split top level forms which are grouped together under the same cell, this is to guarantee that Clerk's dependency analysys among forms will still effectively avoid needless recomputations when code changes.
At present, Clerk will split top level forms which are grouped together under the same cell, this is to guarantee that Clerk's dependency analysys among forms will still effectively avoid needless recomputations^[when code changes].

which you can manipulate with your favourite clojure functions
Parsed markdown is a tree of regular Cloure data structures[^data] which you can manipulate with your favourite clojure functions

```clojure
(def sliced (update parsed :content #(take 8 %))) ;; take just a slice
Expand Down Expand Up @@ -52,3 +52,6 @@ and finally render via Clerk's `html` helper.
## Appendix

Don't forget the closing slice 🍕 of markdown!

[^fenced]: E.g. blocks delimited by 3 consecutive backticks.
[^data]: maps and vectors.
33 changes: 19 additions & 14 deletions notebooks/viewers/markdown.clj
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ It's [Markdown](https://daringfireball.net/projects/markdown/), like you know it
;; > — Special Forms

;; ## Sidenotes

;; One of the most distinctive features of Tufte’s style is his extensive use
;; of sidenotes [^sidenote]. This is a sidenote. Sidenotes are like footnotes,
;;
;; One of the most distinctive features of Tufte’s style is his _extensive use
;; of sidenotes_[^sidenote]. Sidenotes are like footnotes,
;; except they don’t force the reader to jump their eye to the bottom of the
;; page, but instead display off to the side in the margin. Perhaps you have
;; noticed their use in this document already. You are very astute.
;;
;; noticed their use in this document already^[If you are _astute_ enough!]. You are very astute.
;;
;; [^sidenote]: This is a sidenote. The purpose of this text is to
;; merely demonstrate the use of sidenotes. All text was originally published
;; on the [Tufte CSS website](https://edwardtufte.github.io/tufte-css/).
Expand All @@ -66,17 +66,22 @@ It's [Markdown](https://daringfireball.net/projects/markdown/), like you know it
;; new content width once a sidenote is present in the document:
;;
;; Things to do:

;; * Hire two private investigators. Get them to follow each other.
;; * Wear t-shirt that says "Life". Hand out lemons on street corner.
;; * Wear t-shirt that says "Life". Hand out lemons^[not oranges] on street corner.
;; * Wear t-shirt that says "Life". Hand out lemons^[not oranges] on street corner.
;; * Change name to Simon. Speak in thirs person.
;; * Major in philosophy. Ask people WHY they would like fries with that.

(clerk/md "---")









;; ### Conclusion^[what usually average folks actually read.]
;; Sidenote references should not be resetted[^crossnote] across code blocks.
;;
;; | Tables | Are | Cool |
;; |----------|:---------|------:|
;; | col 2 is | left[^*] | 1600 |
;; | col 3 is | right | 12 |
;;
;; [^crossnote]: as in: _1-based_ again.
;; [^*]: as in _not right_.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"lezer-clojure": "1.0.0-rc.2",
"markdown-it": "^12.2.0",
"markdown-it-block-image": "^0.0.3",
"markdown-it-sidenote": "gerwitz/markdown-it-sidenote#aa5de8ce3168b7d41cb33c3aed071a5f41ce0083",
"markdown-it-footnote": "^3.0.3",
"markdown-it-texmath": "^0.9.1",
"markdown-it-toc-done-right": "^4.2.0",
"punycode": "2.1.1",
Expand Down
34 changes: 22 additions & 12 deletions resources/stylesheets/viewer.css
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@

.viewer-notebook { @apply py-16; }
#clerk-static-app .viewer-notebook { @apply pt-[0.8rem] pb-16; }
.viewer-markdown *:first-child:not(.viewer-code):not(li):not(h2) { @apply mt-0; }
.viewer-markdown *:first-child:not(.viewer-code):not(li):not(h2):not(.sidenote) { @apply mt-0; }
/*.viewer + .viewer { @apply mt-6; }*/
.viewer + .viewer-result { @apply mt-0; }
.viewer-code + .viewer-result { @apply mt-3; }
Expand All @@ -298,22 +298,32 @@
@apply top-[-0.5em] w-auto h-auto inline border-0 bg-transparent m-0 pointer-events-none;
}
.sidenote {
@apply block w-full float-left clear-both relative font-sans text-xs my-4 bg-slate-100 dark:bg-slate-800 p-4;
font-style: normal;
font-weight: normal;
@apply block font-sans text-xs mt-4 bg-slate-100 dark:bg-slate-800 p-4;
font-style: normal;
font-weight: normal;
}
.sidenote-container {
@apply mb-4;
}
@media (min-width: 860px) {
.sidenote sup { @apply inline; }
.sidenote-column {
@apply w-[165px] absolute right-0 top-0 -mr-[205px];
}
.sidenote {
@apply -mt-[20px] w-[165px] float-right clear-right absolute right-0 p-0 bg-transparent dark:bg-transparent;
@apply bg-transparent dark:bg-transparent p-0;
}
.sidenote:first-child {
@apply mt-1;
}
.sidenotes-layout .viewer-markdown {
@apply pr-[205px];
}
.sidenote-container {
@apply relative mb-0;
}
.sidenotes-layout .viewer-markdown p,
.sidenotes-layout .viewer-markdown ul,
.sidenotes-layout .viewer-markdown ol,
.sidenotes-layout .viewer-markdown h2,
.sidenotes-layout .viewer-markdown h3,
.sidenotes-layout .viewer-markdown h4 {
@apply relative pr-[205px];
.sidenotes-layout h1 {
@apply w-[756px] !important;
}
}
.viewer-code + .viewer:not(.viewer-markdown):not(.viewer-code):not(.viewer-code-folded),
Expand Down
6 changes: 3 additions & 3 deletions src/nextjournal/clerk/parser.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@
(assoc :md-context doc)
(update :blocks conj {:type :markdown
:doc (-> doc
(select-keys [:type :content :sidenotes?])
(select-keys [:type :content :footnotes])
;; take only new nodes, keep context intact
(update :content subvec (inc index)))}))))

Expand All @@ -255,7 +255,7 @@
([{:as opts :keys [doc?]} s]
(let [doc (parse-clojure-string opts {:blocks [] :md-context (markdown-context)} s)]
(select-keys (cond-> doc doc? (merge (:md-context doc)))
[:blocks :title :toc :sidenotes?])))
[:blocks :title :toc :footnotes])))
([{:as _opts :keys [doc?]} initial-state s]
(loop [{:as state :keys [nodes blocks add-comment-on-line?]} (assoc initial-state :nodes (:children (p/parse-string-all s)))]
(if-let [node (first nodes)]
Expand Down Expand Up @@ -315,7 +315,7 @@
(update :blocks #(cond-> % (seq md-slice) (conj {:type :markdown :doc {:type :doc :content md-slice}})))
(select-keys [:blocks :visibility])
(merge (when doc?
(select-keys ctx [:sidenotes? :title :toc]))))))))
(select-keys ctx [:footnotes :title :toc]))))))))

#_(parse-markdown-string {:doc? true} "# Hello\n```\n1\n;; # 1️⃣ Hello\n2\n\n```\nhey\n```\n3\n;; # 2️⃣ Hello\n4\n```\n")

Expand Down
20 changes: 14 additions & 6 deletions src/nextjournal/clerk/viewer.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
[sci.lang]
[applied-science.js-interop :as j]])
[nextjournal.markdown :as md]
[nextjournal.markdown.parser :as md.parser]
[nextjournal.markdown.transform :as md.transform])
#?(:clj (:import (com.pngencoder PngEncoder)
(clojure.lang IDeref IAtom)
Expand Down Expand Up @@ -499,9 +500,14 @@
#_(->display {:result {:nextjournal.clerk/visibility {:code :fold :result :show}}})
#_(->display {:result {:nextjournal.clerk/visibility {:code :fold :result :hide}}})

(defn process-sidenotes [{:as doc :keys [footnotes]} cell-doc]
(if (seq footnotes)
(md.parser/insert-sidenote-containers (assoc cell-doc :footnotes footnotes))
cell-doc))

(defn with-block-viewer [doc {:as cell :keys [type]}]
(case type
:markdown [(with-viewer :markdown (:doc cell))]
:markdown [(with-viewer :markdown (process-sidenotes doc (:doc cell)))]
:code (let [cell (update cell :result apply-viewer-unwrapping-var-from-def)
{:as display-opts :keys [code? result?]} (->display cell)
eval? (-> cell :result :nextjournal/value (get-safe :nextjournal/value) viewer-eval?)]
Expand Down Expand Up @@ -607,8 +613,7 @@

(def markdown-viewers
[{:name :nextjournal.markdown/doc
:transform-fn (into-markup (fn [{:keys [sidenotes?]}]
[(keyword (str "div.viewer-markdown" (when sidenotes? ".contains-sidenotes")))]))}
:transform-fn (into-markup [:div.viewer-markdown])}

;; blocks
{:name :nextjournal.markdown/heading
Expand Down Expand Up @@ -668,10 +673,13 @@
{:name :nextjournal.markdown/toc :transform-fn (into-markup [:div.toc])}

;; sidenotes
{:name :nextjournal.markdown/sidenote-container :transform-fn (into-markup [:div.sidenote-container])}
{:name :nextjournal.markdown/sidenote-column :transform-fn (into-markup [:div.sidenote-column])}
{:name :nextjournal.markdown/sidenote
:transform-fn (into-markup (fn [{:keys [attrs]}] [:span.sidenote [:sup {:style {:margin-right "3px"}} (-> attrs :ref inc)]]))}
:transform-fn (into-markup (fn [{:keys [ref]}]
[:span.sidenote [:sup {:style {:margin-right "3px"}} (str (inc ref))]]))}
{:name :nextjournal.markdown/sidenote-ref
:transform-fn (into-markup [:sup.sidenote-ref])}])
:transform-fn (fn [wrapped-value] (with-viewer :html [:sup.sidenote-ref (-> wrapped-value ->value :ref inc)]))}])

(def char-viewer
{:pred char? :render-fn '(fn [c] [:span.cmt-string.inspected-value "\\" c])})
Expand Down Expand Up @@ -972,10 +980,10 @@
:blocks :bundle?
:css-class
:open-graph
:sidenotes?
:title
:toc
:toc-visibility])
(assoc :sidenotes? (boolean (seq (:footnotes doc))))
#?(:clj (cond-> ns (assoc :scope (datafy-scope ns))))))

(def notebook-viewer
Expand Down
1 change: 1 addition & 0 deletions test/nextjournal/clerk/parser_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
{:type :markdown, :doc {:type :doc :content [{:type :heading}]}}
{:type :code, :text "{2 \"bar\" 1 \"foo\"}"},]
:title "📶 Sorting",
:footnotes []
:toc {:type :toc,
:children [{:type :toc :children [{:type :toc}
{:type :toc}]}]}})
Expand Down
7 changes: 4 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -754,9 +754,10 @@ markdown-it-block-image@^0.0.3:
resolved "https://registry.yarnpkg.com/markdown-it-block-image/-/markdown-it-block-image-0.0.3.tgz#d3fe650ebf2215ea2c7afb577b394e5f7ffc12ca"
integrity sha512-+esbdLegMSWmIRGwVncj5ZwVi5K1qt894uXfnkZIyMFC7ssbv7aR7YEVI16w0PdFWow1HmBNUZ4chl0vScjoIA==

markdown-it-sidenote@gerwitz/markdown-it-sidenote#aa5de8ce3168b7d41cb33c3aed071a5f41ce0083:
version "0.2.0"
resolved "https://codeload.github.com/gerwitz/markdown-it-sidenote/tar.gz/aa5de8ce3168b7d41cb33c3aed071a5f41ce0083"
markdown-it-footnote@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz#e0e4c0d67390a4c5f0c75f73be605c7c190ca4d8"
integrity sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==

markdown-it-texmath@^0.9.1:
version "0.9.7"
Expand Down

0 comments on commit 990749d

Please sign in to comment.