Skip to content

Commit

Permalink
Add syntax highlighting for Markdown code blocks (#255)
Browse files Browse the repository at this point in the history
* Add code syntax highlighting using highlight.js

* Highlight blocks without languages as plain text

* Add themes for syntax highlighting

* Fix CSS; support highlighting for more languages

* Syntax highlight each post only once
  • Loading branch information
flybot-nam-nguyenhoai authored Aug 4, 2023
1 parent 6fc9694 commit 56a701b
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 15 deletions.
7 changes: 7 additions & 0 deletions client/web/src/flybot/client/web/core/db/event.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@
:fx [[:fx.app/set-theme-local-store next-theme]
[:fx.app/toggle-css-class [cur-theme next-theme]]]})))

;; Code syntax highlighting

(rf/reg-event-fx
:evt.app/highlight-code
(fn [_ [_ html-id]]
{:fx [[:fx.app/highlight-code html-id]]}))

;; ---------- Navbar ----------

(rf/reg-event-db
Expand Down
12 changes: 11 additions & 1 deletion client/web/src/flybot/client/web/core/db/fx.cljs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
(ns flybot.client.web.core.db.fx
(:require [clojure.edn :as edn]
(:require [cljsjs.highlight]
[clojure.edn :as edn]
[clojure.string :as str]
[flybot.client.common.db.fx]
[flybot.client.common.utils :refer [cljs->js]]
[flybot.client.web.core.db.class-utils :as cu]
[flybot.client.web.core.db.fx.highlight]
[flybot.client.web.core.db.localstorage :as l-storage]
[re-frame.core :as rf]
[reagent.core :as reagent]
Expand Down Expand Up @@ -64,6 +66,14 @@
(fn [next-theme]
(l-storage/set-item :theme next-theme)))

;; code syntax highlighting

(rf/reg-fx
:fx.app/highlight-code
(fn [id]
(.configure js/hljs #js {:cssSelector (str "#" id " pre code")})
(.highlightAll js/hljs)))

;; ----- Notification ------

;; Pop-ups (toasts)
Expand Down
12 changes: 12 additions & 0 deletions client/web/src/flybot/client/web/core/db/fx/highlight.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(ns flybot.client.web.core.db.fx.highlight
(:require [cljsjs.highlight.langs.asciidoc]
[cljsjs.highlight.langs.bash]
[cljsjs.highlight.langs.clojure]
[cljsjs.highlight.langs.clojure-repl]
[cljsjs.highlight.langs.cpp]
[cljsjs.highlight.langs.dockerfile]
[cljsjs.highlight.langs.java]
[cljsjs.highlight.langs.javascript]
[cljsjs.highlight.langs.lisp]
[cljsjs.highlight.langs.markdown]
[cljsjs.highlight.langs.python]))
42 changes: 37 additions & 5 deletions client/web/src/flybot/client/web/core/dom/hiccup.cljs
Original file line number Diff line number Diff line change
@@ -1,26 +1,58 @@
(ns flybot.client.web.core.dom.hiccup
(:require [clojure.walk :refer [postwalk]]
(:require [clojure.string :as str]
[clojure.walk :refer [postwalk]]
[markdown-to-hiccup.core :as mth]
[re-frame.core :as rf]))

(defn- hiccup-with-properties
"Add an empty property map to Hiccup vectors without one."
[[tag & rest :as hiccup]]
(if (map? (first rest))
hiccup
(into [tag {}] rest)))

;; ---------- Post hiccup conversion logic ----------

(defn md-dark-image
"Extract the dark mode src from the markdown
and add it to the hiccup props."
"Extracts the dark mode src from the markdown
and add it to the hiccup props."
[[tag {:keys [srcdark] :as props} value]]
(if (and srcdark (= :dark @(rf/subscribe [:subs/pattern '{:app/theme ?x}])))
[tag (assoc props :src (:srcdark props)) value]
[tag props value]))

(defn md-code-block
"Decorates code blocks:
- Mark code blocks without any specified languages as plain text.
- Make code blocks responsive to dark and light themes."
[h]
(let [theme @(rf/subscribe [:subs/pattern '{:app/theme ?x}])
[_ props content] (hiccup-with-properties h)]
(if (= :code (get content 0))
(let [[_ code-props code-content] (hiccup-with-properties content)]
[:pre (if (= :dark theme)
(merge-with #(str/join " " %&) {:class "dark"} props)
props)
[:code (merge {:class "text"} code-props)
code-content]])
h)))

(defn post-hiccup
"Given the hiccup, apply some customisation."
"Given the Hiccup content, applies customizations to images and code blocks:
- Add dark versions to images.
- Mark code blocks without any specified languages as plain text."
[hiccup]
(->> hiccup
(postwalk
(fn [h]
(if (and (vector? h) (= :img (first h)))
(cond
(and (vector? h) (= :img (first h)))
(md-dark-image h)
(and (vector? h) (= :pre (first h)))
(md-code-block h)
:else
h)))))

;; ---------- Markdown to Hiccup ----------
Expand Down
20 changes: 12 additions & 8 deletions client/web/src/flybot/client/web/core/dom/page/post.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,18 @@
(user-info editor-name last-edit-date nil :editor)])])))

(defn post-view
[{:post/keys [css-class image-beside hiccup-content] :as post}]
[{:post/keys [id css-class image-beside hiccup-content] :as post}]
(let [{:image/keys [src src-dark alt]} image-beside
src (if (= :dark @(rf/subscribe [:subs/pattern '{:app/theme ?x}]))
src-dark src)
full-content [[:div {:style {:height 0}}
[:a {:id (web.utils/post->url-identifier post)}]]
fragment-anchor [:div {:style {:height 0}}
[:a {:id (web.utils/post->url-identifier post)}]]
code-highlighting (fn [] (rf/dispatch [:evt.app/highlight-code
(str "post-" id)]))
full-content [fragment-anchor
[post-authors post]
hiccup-content]]
hiccup-content
[code-highlighting]]]
(if (seq src)
;; returns 2 hiccup divs to be displayed in 2 columns
[:div.post-body
Expand All @@ -254,7 +258,7 @@
(when-not (utils/temporary-id? id)
[:div.post
{:key id
:id id}
:id (str "post-" id)}
[post-view post]]))

(defn post-read
Expand All @@ -264,7 +268,7 @@
:as post}]
[:div.post
{:key id
:id id}
:id (str "post-" id)}
[:div.post-header
[:form
[edit-button id]
Expand All @@ -279,7 +283,7 @@
[{:post/keys [id]}]
[:div.post
{:key id
:id id}
:id (str "post-" id)}
[:div.post-header
(when-not @(rf/subscribe [:subs/pattern '{:form/fields {:post/to-delete? ?x}}])
[:form
Expand Down Expand Up @@ -339,7 +343,7 @@
(let [post-title (client.utils/post->title post)]
[:div.post.short
{:key id
:id id}
:id (str "post-" id)}
[post-link post
[:div.post-body
{:class css-class}
Expand Down
1 change: 1 addition & 0 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
:client {:extra-deps {com.bhauman/figwheel-main {:mvn/version "0.2.18"}
org.clojure/clojurescript {:mvn/version "1.11.60"}
reagent/reagent {:mvn/version "1.2.0"}
cljsjs/highlight {:mvn/version "11.7.0-0"}
cljsjs/react {:mvn/version "18.2.0-1"}
cljsjs/react-dom {:mvn/version "18.2.0-1"}
cljsjs/react-toastify {:mvn/version "9.1.0-0"}
Expand Down
Loading

0 comments on commit 56a701b

Please sign in to comment.