mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
Merge branch 'master' into feat/outliner-core
This commit is contained in:
@@ -30,7 +30,8 @@
|
||||
:autoHideMenuBar (not mac?)
|
||||
:titleBarStyle (if mac? "hidden" nil)
|
||||
:webPreferences
|
||||
{:nodeIntegration false
|
||||
{:plugins true ; pdf
|
||||
:nodeIntegration false
|
||||
:nodeIntegrationInWorker false
|
||||
:contextIsolation true
|
||||
:spellcheck true
|
||||
@@ -43,7 +44,7 @@
|
||||
win))
|
||||
|
||||
(defn setup-updater! [^js win]
|
||||
;; manual updater
|
||||
;; manual/auto updater
|
||||
(init-updater {:repo "logseq/logseq"
|
||||
:logger logger
|
||||
:win win}))
|
||||
@@ -58,37 +59,40 @@
|
||||
(callback #js {:path path}))))
|
||||
#(.unregisterProtocol protocol "assets"))
|
||||
|
||||
(defn- handle-export-publish-assets [_event html]
|
||||
(defn- handle-export-publish-assets [_event html custom-css-path]
|
||||
(let [app-path (. app getAppPath)
|
||||
paths (js->clj (. dialog showOpenDialogSync (clj->js {:properties ["openDirectory" "createDirectory" "promptToCreate", "multiSelections"]})))]
|
||||
(when (seq paths)
|
||||
(let [root-dir (first paths)
|
||||
static-dir (path/join root-dir "static")
|
||||
path (path/join root-dir "index.html")]
|
||||
index-html-path (path/join root-dir "index.html")]
|
||||
(p/let [_ (. fs ensureDir static-dir)
|
||||
_ (p/all (concat
|
||||
[(. fs writeFile path html)
|
||||
[(. fs writeFile index-html-path html)
|
||||
|
||||
(. fs copy (path/join app-path "404.html") (path/join root-dir "404.html"))]
|
||||
|
||||
(map
|
||||
(fn [part]
|
||||
(. fs copy (path/join app-path part) (path/join static-dir part)))
|
||||
["css" "fonts" "icons" "img" "js"])))
|
||||
(fn [part]
|
||||
(. fs copy (path/join app-path part) (path/join static-dir part)))
|
||||
["css" "fonts" "icons" "img" "js"])))
|
||||
custom-css (. fs readFile custom-css-path)
|
||||
_ (. fs appendFile (path/join static-dir "css" "style.css") custom-css)
|
||||
js-files ["main.js" "code-editor.js" "excalidraw.js"]
|
||||
_ (p/all (map (fn [file]
|
||||
(. fs removeSync (path/join static-dir "js" file)))
|
||||
js-files))
|
||||
js-files))
|
||||
_ (p/all (map (fn [file]
|
||||
(. fs moveSync
|
||||
(path/join static-dir "js" "publishing" file)
|
||||
(path/join static-dir "js" file)))
|
||||
js-files))
|
||||
js-files))
|
||||
_ (. fs removeSync (path/join static-dir "js" "publishing"))
|
||||
;; remove source map files
|
||||
;; TODO: ugly, replace with ls-files and filter with ".map"
|
||||
_ (p/all (map (fn [file]
|
||||
(. fs removeSync (path/join static-dir "js" (str file ".map"))))
|
||||
["main.js" "code-editor.js" "excalidraw.js" "age-encryption.js"]))]
|
||||
["main.js" "code-editor.js" "excalidraw.js" "age-encryption.js"]))]
|
||||
(. dialog showMessageBox (clj->js {:message (str "Export publish assets to " root-dir " successfully")})))))))
|
||||
|
||||
(defn setup-app-manager!
|
||||
@@ -137,51 +141,59 @@
|
||||
|
||||
(defonce *win (atom nil))
|
||||
|
||||
|
||||
(defn- destroy-window!
|
||||
[^js win]
|
||||
(.destroy win))
|
||||
|
||||
(defn main
|
||||
[]
|
||||
(.on app "window-all-closed" (fn [] (.quit app)))
|
||||
(.on app "ready"
|
||||
(fn []
|
||||
(let [^js win (create-main-window)
|
||||
_ (reset! *win win)
|
||||
*quitting? (atom false)]
|
||||
(.. logger (info (str "Logseq App(" (.getVersion app) ") Starting... ")))
|
||||
(if-not (.requestSingleInstanceLock app)
|
||||
(.quit app)
|
||||
(do
|
||||
(.on app "second-instance"
|
||||
(fn [_event _commandLine _workingDirectory]
|
||||
(when-let [win @*win]
|
||||
(when (.isMinimized ^object win)
|
||||
(.restore win))
|
||||
(.focus win))))
|
||||
(.on app "window-all-closed" (fn [] (.quit app)))
|
||||
(.on app "ready"
|
||||
(fn []
|
||||
(let [^js win (create-main-window)
|
||||
_ (reset! *win win)
|
||||
*quitting? (atom false)]
|
||||
(.. logger (info (str "Logseq App(" (.getVersion app) ") Starting... ")))
|
||||
|
||||
(vreset! *setup-fn
|
||||
(fn []
|
||||
(let [t0 (setup-updater! win)
|
||||
t1 (setup-interceptor!)
|
||||
t2 (setup-app-manager! win)
|
||||
tt (handler/set-ipc-handler! win)]
|
||||
(vreset! *setup-fn
|
||||
(fn []
|
||||
(let [t0 (setup-updater! win)
|
||||
t1 (setup-interceptor!)
|
||||
t2 (setup-app-manager! win)
|
||||
tt (handler/set-ipc-handler! win)]
|
||||
|
||||
(vreset! *teardown-fn
|
||||
#(doseq [f [t0 t1 t2 tt]]
|
||||
(and f (f)))))))
|
||||
(vreset! *teardown-fn
|
||||
#(doseq [f [t0 t1 t2 tt]]
|
||||
(and f (f)))))))
|
||||
|
||||
;; setup effects
|
||||
(@*setup-fn)
|
||||
;; setup effects
|
||||
(@*setup-fn)
|
||||
|
||||
;; main window events
|
||||
(.on win "close" (fn [e]
|
||||
(.preventDefault e)
|
||||
(let [web-contents (. win -webContents)]
|
||||
(.send web-contents "persistent-dbs"))
|
||||
(async/go
|
||||
;; FIXME: What if persistence failed?
|
||||
(let [_ (async/<! state/persistent-dbs-chan)]
|
||||
(if (or @*quitting? (not mac?))
|
||||
(when-let [win @*win]
|
||||
(destroy-window! win)
|
||||
(reset! *win nil))
|
||||
(do (.preventDefault ^js/Event e)
|
||||
(.hide win)))))))
|
||||
(.on app "before-quit" (fn [_e] (reset! *quitting? true)))
|
||||
(.on app "activate" #(if @*win (.show win)))))))
|
||||
;; main window events
|
||||
(.on win "close" (fn [e]
|
||||
(.preventDefault e)
|
||||
(let [web-contents (. win -webContents)]
|
||||
(.send web-contents "persistent-dbs"))
|
||||
(async/go
|
||||
;; FIXME: What if persistence failed?
|
||||
(let [_ (async/<! state/persistent-dbs-chan)]
|
||||
(if (or @*quitting? (not mac?))
|
||||
(when-let [win @*win]
|
||||
(destroy-window! win)
|
||||
(reset! *win nil))
|
||||
(do (.preventDefault ^js/Event e)
|
||||
(.hide win)))))))
|
||||
(.on app "before-quit" (fn [_e] (reset! *quitting? true)))
|
||||
(.on app "activate" #(if @*win (.show win)))))))))
|
||||
|
||||
(defn start []
|
||||
(js/console.log "Main - start")
|
||||
|
||||
@@ -55,17 +55,37 @@
|
||||
(string/replace path "\\" "/")
|
||||
path)))
|
||||
|
||||
;; TODO: ignore according to mime types
|
||||
(defn ignored-path?
|
||||
[dir path]
|
||||
(or
|
||||
(some #(string/starts-with? path (str dir "/" %))
|
||||
["." "assets" "node_modules"])
|
||||
(some #(string/ends-with? path (str dir "/" %))
|
||||
[".swap" ".crswap" ".tmp"])))
|
||||
|
||||
(defonce allowed-formats
|
||||
#{:org :markdown :md :edn :json :css :excalidraw})
|
||||
|
||||
(defn get-ext
|
||||
[p]
|
||||
(-> (.extname path p)
|
||||
(subs 1)
|
||||
keyword))
|
||||
|
||||
(defn- get-files
|
||||
[path]
|
||||
(let [result (->> (map
|
||||
(fn [path]
|
||||
(let [stat (fs/statSync path)]
|
||||
(when-not (.isDirectory stat)
|
||||
{:path (fix-win-path! path)
|
||||
:content (read-file path)
|
||||
:stat stat})))
|
||||
(readdir path))
|
||||
(remove nil?))]
|
||||
(let [result (->>
|
||||
(readdir path)
|
||||
(remove (partial ignored-path? path))
|
||||
(filter #(contains? allowed-formats (get-ext %)))
|
||||
(map (fn [path]
|
||||
(let [stat (fs/statSync path)]
|
||||
(when-not (.isDirectory stat)
|
||||
{:path (fix-win-path! path)
|
||||
:content (read-file path)
|
||||
:stat stat}))))
|
||||
(remove nil?))]
|
||||
(vec (cons {:path (fix-win-path! path)} result))))
|
||||
|
||||
;; TODO: Is it going to be slow if it's a huge directory
|
||||
@@ -100,13 +120,8 @@
|
||||
(when (fs/existsSync dir)
|
||||
(let [watcher (.watch watcher dir
|
||||
(clj->js
|
||||
{:ignored (fn [path]
|
||||
(or
|
||||
(some #(string/starts-with? path (str dir "/" %))
|
||||
["." "assets" "node_modules"])
|
||||
(some #(string/ends-with? path (str dir "/" %))
|
||||
[".swap" ".crswap" ".tmp"])))
|
||||
:ignoreInitial false
|
||||
{:ignored (partial ignored-path? dir)
|
||||
:ignoreInitial true
|
||||
:persistent true
|
||||
:awaitWriteFinish true}))]
|
||||
(.on watcher "add"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
[clojure.string :as string]
|
||||
[promesa.core :as p]
|
||||
[cljs-bean.core :as bean]
|
||||
["semver" :as semver]
|
||||
["os" :as os]
|
||||
["fs" :as fs]
|
||||
["path" :as path]
|
||||
@@ -30,7 +31,7 @@
|
||||
[repo]
|
||||
(let [;endpoint "https://update.electronjs.org/xyhp915/cljs-todo/darwin-x64/0.0.4"
|
||||
endpoint (str "https://update.electronjs.org/" repo "/" js/process.platform "-" js/process.arch "/" electron-version)]
|
||||
(debug "[updater]" endpoint)
|
||||
(debug "checking" endpoint)
|
||||
(p/catch
|
||||
(p/let [res (fetch endpoint)
|
||||
status (.-status res)
|
||||
@@ -103,8 +104,26 @@
|
||||
(fn []
|
||||
(emit "completed" nil))))))))
|
||||
|
||||
(defn init-auto-updater
|
||||
[repo]
|
||||
(when (.valid semver electron-version)
|
||||
(p/let [info (get-latest-artifact-info repo)]
|
||||
(when-let [remote-version (and info (re-find #"\d+.\d+.\d+" (:url info)))]
|
||||
(if (and (. semver valid remote-version)
|
||||
(. semver lt electron-version remote-version))
|
||||
|
||||
;; start auto updater
|
||||
(do
|
||||
(debug "Found remote version" remote-version)
|
||||
(when mac?
|
||||
(when-let [f (js/require "update-electron-app")]
|
||||
(f #js{}))))
|
||||
|
||||
(debug "Skip remote version [ahead of pre-release]" remote-version))))))
|
||||
|
||||
(defn init-updater
|
||||
[{:keys [repo logger ^js win] :as opts}]
|
||||
(and prod? (init-auto-updater repo))
|
||||
(let [check-channel "check-for-updates"
|
||||
install-channel "install-updates"
|
||||
check-listener (fn [e & args]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[frontend.format :as format]
|
||||
[frontend.handler.common :as common-handler]
|
||||
[frontend.handler.draw :as draw]
|
||||
[frontend.handler.notification :as notification]
|
||||
[promesa.core :as p]))
|
||||
|
||||
;; TODO: move to frontend.handler.editor.commands
|
||||
@@ -100,9 +101,9 @@
|
||||
["B" (->priority "B")]
|
||||
["C" (->priority "C")]
|
||||
["Deadline" [[:editor/clear-current-slash]
|
||||
[:editor/show-date-picker]]]
|
||||
[:editor/show-date-picker :deadline]]]
|
||||
["Scheduled" [[:editor/clear-current-slash]
|
||||
[:editor/show-date-picker]]]
|
||||
[:editor/show-date-picker :scheduled]]]
|
||||
["Query" [[:editor/input "{{query }}" {:backward-pos 2}]]]
|
||||
["Draw" (fn []
|
||||
(let [file (draw/file-name)
|
||||
@@ -246,12 +247,22 @@
|
||||
edit-content (gobj/get input "value")
|
||||
current-pos (:pos (util/get-caret-pos input))
|
||||
prefix (subs edit-content 0 current-pos)
|
||||
space? (when last-pattern
|
||||
(let [s (when-let [last-index (string/last-index-of prefix last-pattern)]
|
||||
(util/safe-subs prefix 0 last-index))]
|
||||
(not (and (string/ends-with? s "(")
|
||||
(or (string/starts-with? last-pattern "((")
|
||||
(string/starts-with? last-pattern "[["))))))
|
||||
prefix (if (string/blank? last-pattern)
|
||||
(util/concat-without-spaces prefix value)
|
||||
(util/replace-last last-pattern prefix value))
|
||||
(if space?
|
||||
(util/concat-without-spaces prefix value)
|
||||
(str prefix value))
|
||||
(util/replace-last last-pattern prefix value space?))
|
||||
postfix (subs edit-content current-pos)
|
||||
postfix (if postfix-fn (postfix-fn postfix) postfix)
|
||||
new-value (util/concat-without-spaces prefix postfix)
|
||||
new-value (if space?
|
||||
(util/concat-without-spaces prefix postfix)
|
||||
(str prefix postfix))
|
||||
new-pos (- (+ (count prefix)
|
||||
(or forward-pos 0))
|
||||
(or backward-pos 0))]
|
||||
@@ -462,8 +473,15 @@
|
||||
(defmethod handle-step :editor/show-input [[_ option]]
|
||||
(state/set-editor-show-input! option))
|
||||
|
||||
(defmethod handle-step :editor/show-date-picker [[_]]
|
||||
(state/set-editor-show-date-picker! true))
|
||||
(defmethod handle-step :editor/show-date-picker [[_ type]]
|
||||
(if (and
|
||||
(contains? #{:scheduled :deadline} type)
|
||||
(when-let [value (gobj/get (state/get-input) "value")]
|
||||
(string/blank? value)))
|
||||
(do
|
||||
(notification/show! [:div "Please add some content first."] :warning)
|
||||
(restore-state false))
|
||||
(state/set-editor-show-date-picker! true)))
|
||||
|
||||
(defmethod handle-step :editor/click-hidden-file-input [[_ input-id]]
|
||||
(when-let [input-file (gdom/getElement "upload-file")]
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
(ui/resize-provider
|
||||
(ui/resize-consumer
|
||||
(cond->
|
||||
{:className "resize"
|
||||
{:className "resize image-resize"
|
||||
:onSizeChanged (fn [value]
|
||||
(when (and (not @*resizing-image?)
|
||||
(some? @size)
|
||||
@@ -330,21 +330,18 @@
|
||||
|
||||
(rum/defc page-cp
|
||||
[{:keys [html-export? label children contents-page?] :as config} page]
|
||||
(when-let [page-name (:block/name page)]
|
||||
(let [source-page (model/get-alias-source-page (state/get-current-repo)
|
||||
(string/lower-case page-name))
|
||||
original-page-name (get page :block/original-name page-name)
|
||||
original-page-name (if (date/valid-journal-title? original-page-name)
|
||||
(string/capitalize original-page-name)
|
||||
original-page-name)
|
||||
(when-let [page-name (:block/name page)]
|
||||
(let [page-entity page
|
||||
page (string/lower-case page-name)
|
||||
redirect-page-name (cond
|
||||
(:block/alias? config)
|
||||
page
|
||||
|
||||
(db/page-empty? (state/get-current-repo) page-name)
|
||||
(or (when source-page (:block/name source-page))
|
||||
page)
|
||||
(db/page-empty? (state/get-current-repo) page)
|
||||
(let [source-page (model/get-alias-source-page (state/get-current-repo)
|
||||
(string/lower-case page-name))]
|
||||
(or (when source-page (:block/name source-page))
|
||||
page))
|
||||
|
||||
:else
|
||||
page)
|
||||
@@ -372,7 +369,7 @@
|
||||
(if (seq children)
|
||||
(for [child children]
|
||||
(if (= (first child) "Label")
|
||||
[:span (last child)]
|
||||
(last child)
|
||||
(let [{:keys [content children]} (last child)
|
||||
page-name (subs content 2 (- (count content) 2))]
|
||||
(page-reference html-export? page-name (assoc config :children children) nil))))
|
||||
@@ -380,13 +377,26 @@
|
||||
(string? label)
|
||||
(not (string/blank? label))) ; alias
|
||||
label
|
||||
original-page-name))])))
|
||||
(get page-entity :page/original-name page-name)))])))
|
||||
|
||||
(rum/defc asset-reference
|
||||
[title path]
|
||||
(let [repo-path (config/get-repo-dir (state/get-current-repo))
|
||||
full-path (.. util/node-path (join repo-path (config/get-local-asset-absolute-path path)))]
|
||||
[:a.asset-ref {:target "_blank" :href full-path} (or title path)]))
|
||||
[:div
|
||||
[:a.asset-ref {:target "_blank" :href full-path} (or title path)]
|
||||
|
||||
(case (util/get-file-ext full-path)
|
||||
"pdf"
|
||||
[:iframe {:src full-path
|
||||
:fullscreen true
|
||||
:height 800}]
|
||||
;; https://en.wikipedia.org/wiki/HTML5_video
|
||||
("mp4" "ogg" "webm")
|
||||
[:video {:src full-path
|
||||
:controls true}]
|
||||
|
||||
nil)]))
|
||||
|
||||
(defonce excalidraw-loaded? (atom false))
|
||||
(rum/defc excalidraw < rum/reactive
|
||||
@@ -416,9 +426,10 @@
|
||||
(not html-export?)
|
||||
(not contents-page?))
|
||||
[:span.text-gray-500.bracket "[["])
|
||||
(page-cp (assoc config
|
||||
:label (mldoc/plain->text label)
|
||||
:contents-page? contents-page?) {:block/name s})
|
||||
(let [s (string/trim s)]
|
||||
(page-cp (assoc config
|
||||
:label (mldoc/plain->text label)
|
||||
:contents-page? contents-page?) {:block/name s}))
|
||||
(when (and (or show-brackets? nested-link?)
|
||||
(not html-export?)
|
||||
(not contents-page?))
|
||||
@@ -446,7 +457,7 @@
|
||||
|
||||
(rum/defc page-embed < rum/reactive db-mixins/query
|
||||
[config page-name]
|
||||
(let [page-name (string/lower-case page-name)
|
||||
(let [page-name (string/trim (string/lower-case page-name))
|
||||
current-page (state/get-current-page)]
|
||||
[:div.color-level.embed.embed-page.bg-base-2
|
||||
{:class (if (:sidebar? config) "in-sidebar")}
|
||||
@@ -484,32 +495,40 @@
|
||||
|
||||
(declare block-content)
|
||||
(rum/defc block-reference < rum/reactive
|
||||
[config id]
|
||||
[config id label]
|
||||
(when-not (string/blank? id)
|
||||
(let [block (and (util/uuid-string? id)
|
||||
(db/pull-block (uuid id)))]
|
||||
(if block
|
||||
[:span
|
||||
[:div.block-ref-wrap
|
||||
{:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(if (gobj/get e "shiftKey")
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id block)
|
||||
:block-ref
|
||||
{:block block})
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name id}})))}
|
||||
[:div.block-ref-wrap
|
||||
{:on-mouse-down
|
||||
(fn [e]
|
||||
(util/stop e)
|
||||
(if (gobj/get e "shiftKey")
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id block)
|
||||
:block-ref
|
||||
{:block block})
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name id}})))}
|
||||
|
||||
(let [title (:block/title block)]
|
||||
(if (empty? title)
|
||||
;; display the content
|
||||
[:div.block-ref
|
||||
(block-content config block nil (:block/uuid block) (:slide? config))]
|
||||
(->elem
|
||||
:span.block-ref
|
||||
(map-inline config title))))]]
|
||||
(let [title (let [title (:block/title block)]
|
||||
(if (empty? title)
|
||||
;; display the content
|
||||
[:div.block-ref
|
||||
(block-content config block nil (:block/uuid block) (:slide? config))]
|
||||
(->elem
|
||||
:span.block-ref
|
||||
(map-inline config title))))]
|
||||
(if label
|
||||
(->elem
|
||||
:span.block-ref {:title (some->
|
||||
(:block/content block)
|
||||
(text/remove-level-spaces (:block/format block))
|
||||
(text/remove-properties!))} ; TODO: replace with a popup
|
||||
(map-inline config label))
|
||||
title))]
|
||||
[:span.warning.mr-1 {:title "Block ref invalid"}
|
||||
(util/format "((%s))" id)]))))
|
||||
|
||||
@@ -626,7 +645,7 @@
|
||||
|
||||
["Block_reference" id]
|
||||
;; FIXME: alert when self block reference
|
||||
(block-reference config id)
|
||||
(block-reference config id nil)
|
||||
|
||||
["Nested_link" link]
|
||||
(nested-link config html-export? link)
|
||||
@@ -640,6 +659,14 @@
|
||||
(string/blank? s)
|
||||
[:span.warning {:title "Invalid link"} full_text]
|
||||
|
||||
(text/block-ref? s)
|
||||
(let [block-id (text/block-ref-un-brackets! s)]
|
||||
(block-reference config block-id label))
|
||||
|
||||
(text/page-ref? s)
|
||||
(let [page (text/page-ref-un-brackets! s)]
|
||||
(page-reference (:html-export? config) page config label))
|
||||
|
||||
;; image
|
||||
(text/image-link? img-formats s)
|
||||
(image-link config url s label metadata full_text)
|
||||
@@ -676,7 +703,7 @@
|
||||
(= protocol "id")
|
||||
(string? (:link (second url)))
|
||||
(util/uuid-string? (:link (second url)))) ; org mode id
|
||||
(block-reference config (:link (second url)))
|
||||
(block-reference config (:link (second url)) nil)
|
||||
|
||||
(= protocol "file")
|
||||
(if (text/image-link? img-formats href)
|
||||
@@ -943,11 +970,11 @@
|
||||
macro-content (when macro-content
|
||||
(template/resolve-dynamic-template! macro-content))]
|
||||
(render-macro config name arguments macro-content format))
|
||||
(when-let [macro-txt (macro->text name arguments)]
|
||||
(let [macro-txt (when macro-txt
|
||||
(template/resolve-dynamic-template! macro-txt))
|
||||
format (get-in config [:block :block/format] :markdown)]
|
||||
(render-macro config name arguments macro-txt format))))))
|
||||
(let [macro-content (or
|
||||
(get (state/get-macros) name)
|
||||
(get (state/get-macros) (keyword name)))
|
||||
format (get-in config [:block :block/format] :markdown)]
|
||||
(render-macro config name arguments macro-content format)))))
|
||||
|
||||
:else
|
||||
""))
|
||||
@@ -958,23 +985,49 @@
|
||||
[block]
|
||||
block)
|
||||
|
||||
(defonce *control-show? (atom {}))
|
||||
(defn- dnd-same-block?
|
||||
[uuid]
|
||||
(= (:block/uuid @*dragging-block) uuid))
|
||||
|
||||
(defn- get-data-transfer-attr
|
||||
[event attr]
|
||||
(.getData (gobj/get event "dataTransfer") attr))
|
||||
|
||||
(defn- bullet-drag-start
|
||||
[event block uuid block-id]
|
||||
(editor-handler/highlight-block! uuid)
|
||||
(.setData (gobj/get event "dataTransfer")
|
||||
"block-uuid"
|
||||
uuid)
|
||||
(.setData (gobj/get event "dataTransfer")
|
||||
"block-dom-id"
|
||||
block-id)
|
||||
(state/clear-selection!)
|
||||
(reset! *dragging? true)
|
||||
(reset! *dragging-block block))
|
||||
|
||||
(defn- bullet-on-click
|
||||
[e block config uuid]
|
||||
(if (gobj/get e "shiftKey")
|
||||
(do
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id block)
|
||||
:block
|
||||
block)
|
||||
(util/stop e))
|
||||
(when (:embed? config)
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name (str uuid)}}))))
|
||||
|
||||
(rum/defcs block-control < rum/reactive
|
||||
{:will-mount (fn [state]
|
||||
(let [block (nth (:rum/args state) 1)
|
||||
collapsed? (:block/collapsed? block)]
|
||||
(state/set-collapsed-state! (:block/uuid block)
|
||||
collapsed?))
|
||||
state)}
|
||||
[state config block uuid block-id level start-level body children dummy?]
|
||||
[state config block uuid block-id level start-level body children dummy? *control-show? *collapsed?]
|
||||
(let [has-child? (and
|
||||
(not (:pre-block? block))
|
||||
(or (seq children)
|
||||
(seq body)))
|
||||
collapsed? (state/sub [:ui/collapsed-blocks uuid])
|
||||
collapsed? (and has-child? collapsed?)
|
||||
control-show (util/react (rum/cursor *control-show? block-id))
|
||||
collapsed? (rum/react *collapsed?)
|
||||
control-show? (util/react *control-show?)
|
||||
dark? (= "dark" (state/sub :ui/theme))
|
||||
heading? (= (get (:block/properties block) "heading") "true")]
|
||||
[:div.mr-2.flex.flex-row.items-center
|
||||
@@ -999,45 +1052,23 @@
|
||||
(if collapsed?
|
||||
(expand/expand! block)
|
||||
(expand/collapse! block))
|
||||
|
||||
(state/set-collapsed-state! uuid (not collapsed?)))}
|
||||
(reset! *collapsed? (not collapsed?)))}
|
||||
(cond
|
||||
(and control-show collapsed?)
|
||||
(and control-show? collapsed?)
|
||||
(svg/caret-right)
|
||||
|
||||
(and control-show has-child?)
|
||||
(and control-show? has-child?)
|
||||
(svg/caret-down)
|
||||
|
||||
:else
|
||||
[:span ""])]
|
||||
[:a (if (not dummy?)
|
||||
{:href (rfe/href :page {:name uuid})
|
||||
:on-click (fn [e]
|
||||
(if (gobj/get e "shiftKey")
|
||||
(do
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id block)
|
||||
:block
|
||||
block)
|
||||
(util/stop e))
|
||||
(when (:embed? config)
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name (str uuid)}}))))})
|
||||
:on-click (fn [e] (bullet-on-click e block config uuid))})
|
||||
[:span.bullet-container.cursor
|
||||
{:id (str "dot-" uuid)
|
||||
:draggable true
|
||||
:on-drag-start (fn [event]
|
||||
(editor-handler/highlight-block! uuid)
|
||||
(.setData (gobj/get event "dataTransfer")
|
||||
"block-uuid"
|
||||
uuid)
|
||||
(.setData (gobj/get event "dataTransfer")
|
||||
"block-dom-id"
|
||||
block-id)
|
||||
(state/clear-selection!)
|
||||
(reset! *dragging? true)
|
||||
(reset! *dragging-block block))
|
||||
:on-drag-start (fn [event] (bullet-drag-start event block uuid block-id))
|
||||
:blockid (str uuid)
|
||||
:class (str (when collapsed? "bullet-closed")
|
||||
" "
|
||||
@@ -1223,10 +1254,6 @@
|
||||
[[:span.opacity-50 "Click here to start writing"]])
|
||||
[tags])))))))
|
||||
|
||||
(defn dnd-same-block?
|
||||
[uuid]
|
||||
(= (:block/uuid @*dragging-block) uuid))
|
||||
|
||||
(defn show-dnd-separator
|
||||
[element-id]
|
||||
(when-let [element (gdom/getElement element-id)]
|
||||
@@ -1241,10 +1268,6 @@
|
||||
(d/remove-class! element "dnd-separator-cur")
|
||||
(d/add-class! element "dnd-separator"))))
|
||||
|
||||
(defn- get-data-transfer-attr
|
||||
[event attr]
|
||||
(.getData (gobj/get event "dataTransfer") attr))
|
||||
|
||||
(defn- pre-block-cp
|
||||
[config content format]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
@@ -1330,52 +1353,77 @@
|
||||
[:div.my-4
|
||||
(datetime-comp/date-picker nil nil ts)]))]))
|
||||
|
||||
(defn- block-content-on-mouse-down
|
||||
[e block block-id properties content format edit-input-id]
|
||||
(.stopPropagation e)
|
||||
(let [target (gobj/get e "target")
|
||||
button (gobj/get e "buttons")]
|
||||
(when (contains? #{1 0} button)
|
||||
(when-not (or (util/link? target)
|
||||
(util/input? target)
|
||||
(util/details-or-summary? target)
|
||||
(and (util/sup? target)
|
||||
(d/has-class? target "fn"))
|
||||
(d/has-class? target "image-resize"))
|
||||
(editor-handler/clear-selection! nil)
|
||||
(editor-handler/unhighlight-block!)
|
||||
(let [properties-hidden? (text/properties-hidden? properties)
|
||||
content (text/remove-level-spaces content format)
|
||||
content (if properties-hidden? (text/remove-properties! content) content)
|
||||
block (db/pull [:block/uuid (:block/uuid block)])
|
||||
f #(let [cursor-range (util/caret-range (gdom/getElement block-id))]
|
||||
(state/set-editing!
|
||||
edit-input-id
|
||||
content
|
||||
block
|
||||
cursor-range))]
|
||||
;; wait a while for the value of the caret range
|
||||
(if (util/ios?)
|
||||
(f)
|
||||
(js/setTimeout f 5)))
|
||||
|
||||
(when-not (state/get-selection-start-block)
|
||||
(when block-id (state/set-selection-start-block! block-id)))))))
|
||||
|
||||
(defn- block-content-on-drag-over
|
||||
[event uuid]
|
||||
(util/stop event)
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(show-dnd-separator (str uuid "-nested"))))
|
||||
|
||||
(defn- block-content-on-drag-leave
|
||||
[uuid]
|
||||
(hide-dnd-separator (str uuid))
|
||||
(hide-dnd-separator (str uuid "-nested"))
|
||||
(hide-dnd-separator (str uuid "-top")))
|
||||
|
||||
(defn- block-content-on-drop
|
||||
[event block uuid]
|
||||
(util/stop event)
|
||||
(when (and (not (dnd-same-block? uuid))
|
||||
(not (:block/dummy? block)))
|
||||
(let [from-dom-id (get-data-transfer-attr event "block-dom-id")]
|
||||
(dnd/move-block @*dragging-block
|
||||
block
|
||||
false
|
||||
true)))
|
||||
(reset! *dragging? false)
|
||||
(reset! *dragging-block nil)
|
||||
(editor-handler/unhighlight-block!))
|
||||
|
||||
(rum/defc block-content < rum/reactive
|
||||
[config {:block/keys [uuid title level body meta content marker dummy? page format repo children pre-block? properties collapsed? idx container block-refs-count scheduled deadline repeated?] :as block} edit-input-id block-id slide?]
|
||||
(let [dragging? (rum/react *dragging?)
|
||||
mouse-down-key (if (util/ios?)
|
||||
:on-click
|
||||
:on-mouse-down ; TODO: it seems that Safari doesn't work well with on-mouse-down
|
||||
)
|
||||
attrs {:blockid (str uuid)
|
||||
;; FIXME: Click to copy a selection instead of click first and then copy
|
||||
;; It seems that `util/caret-range` can't get the correct range
|
||||
:on-click (fn [e]
|
||||
(when-not (selection-range-in-block?)
|
||||
(let [target (gobj/get e "target")]
|
||||
(when-not (or (util/link? target)
|
||||
(util/input? target)
|
||||
(util/details-or-summary? target)
|
||||
(and (util/sup? target)
|
||||
(d/has-class? target "fn")))
|
||||
(editor-handler/clear-selection! nil)
|
||||
(editor-handler/unhighlight-block!)
|
||||
(let [cursor-range (util/caret-range (gdom/getElement block-id))
|
||||
properties-hidden? (text/properties-hidden? properties)
|
||||
content (text/remove-level-spaces content format)
|
||||
content (if properties-hidden? (text/remove-properties! content) content)
|
||||
block (db/pull [:block/uuid (:block/uuid block)])]
|
||||
(state/set-editing!
|
||||
edit-input-id
|
||||
content
|
||||
block
|
||||
cursor-range))
|
||||
(util/stop e)))))
|
||||
:on-drag-over (fn [event]
|
||||
(util/stop event)
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(show-dnd-separator (str uuid "-nested"))))
|
||||
:on-drag-leave (fn [event]
|
||||
(hide-dnd-separator (str uuid))
|
||||
(hide-dnd-separator (str uuid "-nested"))
|
||||
(hide-dnd-separator (str uuid "-top")))
|
||||
:on-drop (fn [event]
|
||||
(util/stop event)
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(let [from-dom-id (get-data-transfer-attr event "block-dom-id")]
|
||||
(dnd/move-block @*dragging-block
|
||||
block
|
||||
false
|
||||
true)))
|
||||
(reset! *dragging? false)
|
||||
(reset! *dragging-block nil)
|
||||
(editor-handler/unhighlight-block!))}]
|
||||
mouse-down-key (fn [e]
|
||||
(block-content-on-mouse-down e block block-id properties content format edit-input-id))
|
||||
:on-drag-over (fn [event] (block-content-on-drag-over event uuid))
|
||||
:on-drag-leave (fn [_event] (block-content-on-drag-leave uuid))
|
||||
:on-drop (fn [event] (block-content-on-drop event block uuid))}]
|
||||
[:div.flex.relative
|
||||
[:div.flex-1.flex-col.relative.block-content
|
||||
(cond-> {:id (str "block-content-" uuid)}
|
||||
@@ -1469,12 +1517,11 @@
|
||||
(rum/defc dnd-separator-wrapper < rum/reactive
|
||||
[block slide? top?]
|
||||
(let [dragging? (rum/react *dragging?)]
|
||||
(cond
|
||||
(and dragging? (not slide?) (not (:block/dummy? block)))
|
||||
(dnd-separator block 20 0 top? false)
|
||||
|
||||
:else
|
||||
nil)))
|
||||
(when (and dragging?
|
||||
(not slide?)
|
||||
(not (:block/dummy? block))
|
||||
(not (:block/pre-block? block)))
|
||||
(dnd-separator block 20 0 top? false))))
|
||||
|
||||
(defn non-dragging?
|
||||
[e]
|
||||
@@ -1517,8 +1564,104 @@
|
||||
(when (or (seq @parents-atom) show-page?)
|
||||
component))))))
|
||||
|
||||
(rum/defc block-container < rum/static
|
||||
{:did-mount (fn [state]
|
||||
(defn- block-drag-over
|
||||
[event uuid top? block-id *move-to-top?]
|
||||
(util/stop event)
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(if top?
|
||||
(let [element-top (gobj/get (utils/getOffsetRect (gdom/getElement block-id)) "top")
|
||||
cursor-top (gobj/get event "clientY")]
|
||||
(if (<= (js/Math.abs (- cursor-top element-top)) 16)
|
||||
;; top
|
||||
(do
|
||||
(hide-dnd-separator (str uuid))
|
||||
(show-dnd-separator (str uuid "-top"))
|
||||
(reset! *move-to-top? true))
|
||||
(do
|
||||
(hide-dnd-separator (str uuid "-top"))
|
||||
(show-dnd-separator (str uuid)))))
|
||||
(show-dnd-separator (str uuid)))))
|
||||
|
||||
(defn- block-drag-leave
|
||||
[event uuid *move-to-top?]
|
||||
(hide-dnd-separator (str uuid))
|
||||
(hide-dnd-separator (str uuid "-nested"))
|
||||
(hide-dnd-separator (str uuid "-top"))
|
||||
(reset! *move-to-top? false))
|
||||
|
||||
(defn- block-drop
|
||||
[event uuid block *move-to-top?]
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(let [from-dom-id (get-data-transfer-attr event "block-dom-id")]
|
||||
(dnd/move-block @*dragging-block
|
||||
block
|
||||
@*move-to-top?
|
||||
false)))
|
||||
(reset! *dragging? false)
|
||||
(reset! *dragging-block nil)
|
||||
(editor-handler/unhighlight-block!))
|
||||
|
||||
(defn- block-mouse-over
|
||||
[e has-child? *control-show? block-id doc-mode?]
|
||||
(util/stop e)
|
||||
(when has-child?
|
||||
(reset! *control-show? true))
|
||||
(when-let [parent (gdom/getElement block-id)]
|
||||
(let [node (.querySelector parent ".bullet-container")]
|
||||
(when doc-mode?
|
||||
(d/remove-class! node "hide-inner-bullet"))))
|
||||
(when (and
|
||||
(state/in-selection-mode?)
|
||||
(non-dragging? e))
|
||||
(util/stop e)
|
||||
(editor-handler/highlight-selection-area! block-id)))
|
||||
|
||||
(defn- block-mouse-leave
|
||||
[e has-child? *control-show? block-id doc-mode?]
|
||||
(util/stop e)
|
||||
(when has-child?
|
||||
(reset! *control-show? false))
|
||||
(when doc-mode?
|
||||
(when-let [parent (gdom/getElement block-id)]
|
||||
(when-let [node (.querySelector parent ".bullet-container")]
|
||||
(d/add-class! node "hide-inner-bullet"))))
|
||||
(when (and (non-dragging? e)
|
||||
(not @*resizing-image?))
|
||||
(state/into-selection-mode!)))
|
||||
|
||||
(defn- on-drag-and-mouse-attrs
|
||||
[block uuid top? block-id *move-to-top? has-child? *control-show? doc-mode?]
|
||||
{:on-drag-over (fn [event]
|
||||
(block-drag-over event uuid top? block-id *move-to-top?))
|
||||
:on-drag-leave (fn [event]
|
||||
(block-drag-leave event uuid *move-to-top?))
|
||||
:on-drop (fn [event]
|
||||
(block-drop event uuid block *move-to-top?))
|
||||
:on-mouse-over (fn [e]
|
||||
(block-mouse-over e has-child? *control-show? block-id doc-mode?))
|
||||
:on-mouse-leave (fn [e]
|
||||
(block-mouse-leave e has-child? *control-show? block-id doc-mode?))})
|
||||
|
||||
(defn- get-data-refs-and-self
|
||||
[block refs-with-children]
|
||||
(let [refs (model/get-page-names-by-ids
|
||||
(->> (map :db/id refs-with-children)
|
||||
(remove nil?)))
|
||||
data-refs (text/build-data-value refs)
|
||||
refs (model/get-page-names-by-ids
|
||||
(->> (map :db/id (:block/ref-pages block))
|
||||
(remove nil?)))
|
||||
data-refs-self (text/build-data-value refs)]
|
||||
[data-refs data-refs-self]))
|
||||
|
||||
(rum/defcs block-container < rum/static
|
||||
{:init (fn [state]
|
||||
(let [block (last (:rum/args state))
|
||||
collapsed? (:block/collapsed? block)]
|
||||
(assoc state
|
||||
::control-show? (atom false)
|
||||
::collapsed? (atom collapsed?))))
|
||||
:did-mount (fn [state]
|
||||
(let [block (nth (:rum/args state) 1)
|
||||
collapsed? (:block/collapsed? block)]
|
||||
(when collapsed?
|
||||
@@ -1527,15 +1670,16 @@
|
||||
:should-update (fn [old-state new-state]
|
||||
(not= (:block/content (second (:rum/args old-state)))
|
||||
(:block/content (second (:rum/args new-state)))))}
|
||||
[config {:block/keys [uuid title level body meta content dummy? page format repo children collapsed? pre-block? idx properties refs-with-children] :as block}]
|
||||
(let [ref? (boolean (:ref? config))
|
||||
[state config {:block/keys [uuid title level body meta content dummy? page format repo children collapsed? pre-block? top? properties refs-with-children] :as block}]
|
||||
(let [*control-show? (get state ::control-show?)
|
||||
*collapsed? (get state ::collapsed?)
|
||||
ref? (boolean (:ref? config))
|
||||
breadcrumb-show? (:breadcrumb-show? config)
|
||||
sidebar? (boolean (:sidebar? config))
|
||||
slide? (boolean (:slide? config))
|
||||
doc-mode? (:document/mode? config)
|
||||
embed? (:embed? config)
|
||||
unique-dom-id (build-id (dissoc config :block/uuid))
|
||||
edit-input-id (str "edit-block-" unique-dom-id uuid)
|
||||
block-id (str "ls-block-" unique-dom-id uuid)
|
||||
has-child? (boolean
|
||||
(and
|
||||
@@ -1543,80 +1687,8 @@
|
||||
(or (seq children)
|
||||
(seq body))))
|
||||
start-level (or (:start-level config) 1)
|
||||
attrs {:on-drag-over (fn [event]
|
||||
(util/stop event)
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(if (zero? idx)
|
||||
(let [element-top (gobj/get (utils/getOffsetRect (gdom/getElement block-id)) "top")
|
||||
cursor-top (gobj/get event "clientY")]
|
||||
(if (<= (js/Math.abs (- cursor-top element-top)) 16)
|
||||
;; top
|
||||
(do
|
||||
(hide-dnd-separator (str uuid))
|
||||
(show-dnd-separator (str uuid "-top"))
|
||||
(reset! *move-to-top? true))
|
||||
(do
|
||||
(hide-dnd-separator (str uuid "-top"))
|
||||
(show-dnd-separator (str uuid)))))
|
||||
(show-dnd-separator (str uuid)))))
|
||||
:on-drag-leave (fn [event]
|
||||
(hide-dnd-separator (str uuid))
|
||||
(hide-dnd-separator (str uuid "-nested"))
|
||||
(hide-dnd-separator (str uuid "-top"))
|
||||
(reset! *move-to-top? false))
|
||||
:on-drop (fn [event]
|
||||
(when-not (dnd-same-block? uuid)
|
||||
(let [from-dom-id (get-data-transfer-attr event "block-dom-id")]
|
||||
(dnd/move-block @*dragging-block
|
||||
block
|
||||
@*move-to-top?
|
||||
false)))
|
||||
(reset! *dragging? false)
|
||||
(reset! *dragging-block nil)
|
||||
(editor-handler/unhighlight-block!))
|
||||
:on-mouse-move (fn [e]
|
||||
(when (and (non-dragging? e)
|
||||
(not @*resizing-image?))
|
||||
(state/into-selection-mode!)))
|
||||
:on-mouse-down (fn [e]
|
||||
(when (and
|
||||
(not (state/get-selection-start-block))
|
||||
(= (gobj/get e "buttons") 1))
|
||||
(when block-id (state/set-selection-start-block! block-id))))
|
||||
:on-mouse-over (fn [e]
|
||||
(util/stop e)
|
||||
(when has-child?
|
||||
(swap! *control-show? assoc block-id true))
|
||||
(when-let [parent (gdom/getElement block-id)]
|
||||
(let [node (.querySelector parent ".bullet-container")
|
||||
closed? (d/has-class? node "bullet-closed")]
|
||||
(if closed?
|
||||
(state/collapse-block! uuid)
|
||||
(state/expand-block! uuid))
|
||||
(when doc-mode?
|
||||
(d/remove-class! node "hide-inner-bullet"))))
|
||||
(when (and
|
||||
(state/in-selection-mode?)
|
||||
(non-dragging? e))
|
||||
(util/stop e)
|
||||
(editor-handler/highlight-selection-area! block-id)))
|
||||
:on-mouse-out (fn [e]
|
||||
(util/stop e)
|
||||
(when has-child?
|
||||
(swap! *control-show?
|
||||
assoc block-id false))
|
||||
(when doc-mode?
|
||||
(when-let [parent (gdom/getElement block-id)]
|
||||
(when-let [node (.querySelector parent ".bullet-container")]
|
||||
(d/add-class! node "hide-inner-bullet")))))}
|
||||
data-refs (let [refs (model/get-page-names-by-ids
|
||||
(->> (map :db/id refs-with-children)
|
||||
(remove nil?)))]
|
||||
(text/build-data-value refs))
|
||||
data-refs-self (let [refs (model/get-page-names-by-ids
|
||||
(->> (map :db/id (:block/refs block))
|
||||
(remove nil?)))]
|
||||
(text/build-data-value refs))]
|
||||
attrs (on-drag-and-mouse-attrs block uuid top? block-id *move-to-top? has-child? *control-show? doc-mode?)
|
||||
[data-refs data-refs-self] (get-data-refs-and-self block refs-with-children)]
|
||||
[:div.ls-block.flex.flex-col.rounded-sm
|
||||
(cond->
|
||||
{:id block-id
|
||||
@@ -1638,13 +1710,14 @@
|
||||
(when-let [comp (block-parents config repo uuid format false)]
|
||||
[:div.my-2.opacity-50.ml-4 comp]))
|
||||
|
||||
(dnd-separator-wrapper block slide? (zero? idx))
|
||||
(dnd-separator-wrapper block slide? top?)
|
||||
|
||||
[:div.flex-1.flex-row
|
||||
(when (not slide?)
|
||||
(block-control config block uuid block-id level start-level body children dummy?))
|
||||
(block-control config block uuid block-id level start-level body children dummy? *control-show? *collapsed?))
|
||||
|
||||
(block-content-or-editor config block edit-input-id block-id slide?)]
|
||||
(let [edit-input-id (str "edit-block-" unique-dom-id uuid)]
|
||||
(block-content-or-editor config block edit-input-id block-id slide?))]
|
||||
|
||||
(when (seq children)
|
||||
[:div.block-children {:style {:margin-left (if doc-mode? 12 21)
|
||||
@@ -1805,12 +1878,13 @@
|
||||
query-atom (if (:dsl-query? config)
|
||||
(let [result (query-dsl/query (state/get-current-repo) (:query query))]
|
||||
(if (string? result) ; full-text search
|
||||
(atom
|
||||
(if (string/blank? result)
|
||||
[]
|
||||
(let [blocks (search/block-search result 50)]
|
||||
(when (seq blocks)
|
||||
(db/pull-many (state/get-current-repo) '[*] (map (fn [b] [:block/uuid (uuid (:block/uuid b))]) blocks))))))
|
||||
(atom nil)
|
||||
;; (atom
|
||||
;; (if (string/blank? result)
|
||||
;; []
|
||||
;; (let [blocks (search/block-search result 50)]
|
||||
;; (when (seq blocks)
|
||||
;; (db/pull-many (state/get-current-repo) '[*] (map (fn [b] [:block/uuid (uuid (:block/uuid b))]) blocks))))))
|
||||
result))
|
||||
(db/custom-query query))]
|
||||
(assoc state :query-atom query-atom)))
|
||||
@@ -1829,87 +1903,91 @@
|
||||
(db/remove-custom-query! (state/get-current-repo) query))
|
||||
state)}
|
||||
[state config {:keys [title query inputs view collapsed? children?] :as q}]
|
||||
(let [dsl-query? (:dsl-query? config)
|
||||
query-atom (:query-atom state)]
|
||||
(let [current-block-uuid (or (:block/uuid (:block config))
|
||||
(:block/uuid config))
|
||||
;; exclude the current one, otherwise it'll loop forever
|
||||
remove-blocks (if current-block-uuid [current-block-uuid] nil)
|
||||
query-result (and query-atom (rum/react query-atom))
|
||||
(ui/catch-error
|
||||
[:div.warning
|
||||
[:p "Query failed: "]
|
||||
[:pre (str q)]]
|
||||
(let [dsl-query? (:dsl-query? config)
|
||||
query-atom (:query-atom state)]
|
||||
(let [current-block-uuid (or (:block/uuid (:block config))
|
||||
(:block/uuid config))
|
||||
;; exclude the current one, otherwise it'll loop forever
|
||||
remove-blocks (if current-block-uuid [current-block-uuid] nil)
|
||||
query-result (and query-atom (rum/react query-atom))
|
||||
|
||||
result (if (and query-result dsl-query?)
|
||||
query-result
|
||||
(db/custom-query-result-transform query-result remove-blocks q))
|
||||
result (if query-result
|
||||
(db/custom-query-result-transform query-result remove-blocks q))
|
||||
view-f (and view (sci/eval-string (pr-str view)))
|
||||
only-blocks? (:block/uuid (first result))
|
||||
blocks-grouped-by-page? (and (seq result)
|
||||
(coll? (first result))
|
||||
(:block/name (ffirst result))
|
||||
(:block/uuid (first (second (first result))))
|
||||
true)
|
||||
built-in? (built-in-custom-query? title)]
|
||||
[:div.custom-query.mt-2 (get config :attr {})
|
||||
(when-not (and built-in? (empty? result))
|
||||
(ui/foldable
|
||||
[:div.opacity-70
|
||||
title]
|
||||
(cond
|
||||
(and (seq result) view-f)
|
||||
(let [result (try
|
||||
(sci/call-fn view-f result)
|
||||
(catch js/Error error
|
||||
(log/error :custom-view-failed {:error error
|
||||
:result result})
|
||||
[:div "Custom view failed: "
|
||||
(str error)]))]
|
||||
(util/hiccup-keywordize result))
|
||||
result (if (and query-result dsl-query?)
|
||||
query-result
|
||||
(db/custom-query-result-transform query-result remove-blocks q))
|
||||
result (if query-result
|
||||
(db/custom-query-result-transform query-result remove-blocks q))
|
||||
view-f (and view (sci/eval-string (pr-str view)))
|
||||
only-blocks? (:block/uuid (first result))
|
||||
blocks-grouped-by-page? (and (seq result)
|
||||
(coll? (first result))
|
||||
(:block/name (ffirst result))
|
||||
(:block/uuid (first (second (first result))))
|
||||
true)
|
||||
built-in? (built-in-custom-query? title)]
|
||||
[:div.custom-query.mt-2 (get config :attr {})
|
||||
(when-not (and built-in? (empty? result))
|
||||
(ui/foldable
|
||||
[:div.opacity-70
|
||||
title]
|
||||
(cond
|
||||
(and (seq result) view-f)
|
||||
(let [result (try
|
||||
(sci/call-fn view-f result)
|
||||
(catch js/Error error
|
||||
(log/error :custom-view-failed {:error error
|
||||
:result result})
|
||||
[:div "Custom view failed: "
|
||||
(str error)]))]
|
||||
(util/hiccup-keywordize result))
|
||||
|
||||
(and (seq result)
|
||||
(or only-blocks? blocks-grouped-by-page?))
|
||||
(->hiccup result (cond-> (assoc config
|
||||
:custom-query? true
|
||||
;; :breadcrumb-show? true
|
||||
:group-by-page? blocks-grouped-by-page?
|
||||
;; :ref? true
|
||||
)
|
||||
children?
|
||||
(assoc :ref? true))
|
||||
{:style {:margin-top "0.25rem"
|
||||
:margin-left "0.25rem"}})
|
||||
(and (seq result)
|
||||
(or only-blocks? blocks-grouped-by-page?))
|
||||
(->hiccup result (cond-> (assoc config
|
||||
:custom-query? true
|
||||
;; :breadcrumb-show? true
|
||||
:group-by-page? blocks-grouped-by-page?
|
||||
;; :ref? true
|
||||
)
|
||||
children?
|
||||
(assoc :ref? true))
|
||||
{:style {:margin-top "0.25rem"
|
||||
:margin-left "0.25rem"}})
|
||||
|
||||
;; page list
|
||||
(and (seq result)
|
||||
(:block/name (first result)))
|
||||
[:ul#query-pages.mt-1
|
||||
(for [{:block/keys [name original-name] :as page-entity} result]
|
||||
[:li.mt-1
|
||||
[:a {:href (rfe/href :page {:name name})
|
||||
:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(if (gobj/get e "shiftKey")
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id page-entity)
|
||||
:page
|
||||
{:page page-entity})
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name name}})))}
|
||||
(or original-name name)]])]
|
||||
;; page list
|
||||
(and (seq result)
|
||||
(:block/name (first result)))
|
||||
[:ul#query-pages.mt-1
|
||||
(for [{:page/keys [name original-name] :as page-entity} result]
|
||||
[:li.mt-1
|
||||
[:a {:href (rfe/href :page {:name name})
|
||||
:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(if (gobj/get e "shiftKey")
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id page-entity)
|
||||
:page
|
||||
{:page page-entity})
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name name}})))}
|
||||
(or original-name name)]])]
|
||||
|
||||
(seq result) ;TODO: table
|
||||
(let [result (->>
|
||||
(for [record result]
|
||||
(if (map? record)
|
||||
(str (util/pp-str record) "\n")
|
||||
record))
|
||||
(remove nil?))]
|
||||
[:pre result])
|
||||
(seq result) ;TODO: table
|
||||
(let [result (->>
|
||||
(for [record result]
|
||||
(if (map? record)
|
||||
(str (util/pp-str record) "\n")
|
||||
record))
|
||||
(remove nil?))]
|
||||
[:pre result])
|
||||
|
||||
:else
|
||||
[:div.text-sm.mt-2.ml-2.font-medium.opacity-50 "Empty"])
|
||||
collapsed?))])))
|
||||
:else
|
||||
[:div.text-sm.mt-2.ml-2.font-medium.opacity-50 "Empty"])
|
||||
collapsed?))]))))
|
||||
|
||||
(defn admonition
|
||||
[config type options result]
|
||||
@@ -2154,9 +2232,11 @@
|
||||
blocks)
|
||||
first-id (:block/uuid (first blocks))]
|
||||
(for [[idx item] (medley/indexed blocks)]
|
||||
(let [item (-> (if (:block/dummy? item)
|
||||
item
|
||||
(dissoc item :block/meta)))
|
||||
(let [item (->
|
||||
(if (:block/dummy? item)
|
||||
item
|
||||
(dissoc item :block/meta))
|
||||
(assoc :block/top? (zero? idx)))
|
||||
config (assoc config :block/uuid (:block/uuid item))]
|
||||
(rum/with-key
|
||||
(block-container config item)
|
||||
@@ -2186,24 +2266,3 @@
|
||||
(when alias? [:span.text-sm.font-medium.opacity-50 " Alias"])]
|
||||
(blocks-container blocks config))])))]
|
||||
(blocks-container blocks config))])
|
||||
|
||||
(comment
|
||||
;; timestamps
|
||||
;; [2020-02-10 Mon 13:22]
|
||||
;; repetition
|
||||
(def r1 "<2005-10-01 Sat +1m>")
|
||||
;; TODO: mldoc add supports
|
||||
(def r2 "<2005-10-01 Sat +1m -3d>")
|
||||
|
||||
(def l
|
||||
"1. First item
|
||||
hello world
|
||||
2. Second item
|
||||
nice
|
||||
3. Third item")
|
||||
|
||||
(def t
|
||||
"| Name | Phone | Age |
|
||||
|-------+-------+-----|
|
||||
| Peter | 1234 | 17 |
|
||||
| Anna | 4321 | 25 |"))
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
}
|
||||
|
||||
.resize {
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.draw [aria-labelledby="shapes-title"] {
|
||||
|
||||
@@ -39,8 +39,7 @@
|
||||
"Your commit message:"]]]
|
||||
|
||||
[:input#commit-message.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
|
||||
{:style {:color "#000"}
|
||||
:auto-focus true
|
||||
{:auto-focus true
|
||||
:default-value ""}]
|
||||
|
||||
[:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
(let [{:keys [block typ show?]} block-data
|
||||
block-id (or (:block/uuid (state/get-edit-block))
|
||||
(:block/uuid block))
|
||||
typ (or typ @commands/*current-command)]
|
||||
typ (or @commands/*current-command typ)]
|
||||
(editor-handler/set-block-timestamp! block-id
|
||||
typ
|
||||
text)
|
||||
@@ -141,8 +141,8 @@
|
||||
(string/lower-case current-command)))
|
||||
date (get @*timestamp :date)]
|
||||
(when (state/sub :editor/show-date-picker?)
|
||||
[:div#date-time-picker.flex.flex-row {:on-click (fn [e]
|
||||
(util/stop e))}
|
||||
[:div#date-time-picker.flex.flex-row {:on-click (fn [e] (util/stop e))
|
||||
:on-mouse-down (fn [e] (util/stop e))}
|
||||
(ui/datepicker
|
||||
date
|
||||
{:deadline-or-schedule? deadline-or-schedule?
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
{:href (rfe/href :home)
|
||||
:on-click (fn []
|
||||
(util/scroll-to-top)
|
||||
(state/set-journals-length! 1))}
|
||||
(state/set-journals-length! 2))}
|
||||
(if-let [logo (and config/publishing?
|
||||
(get-in (state/get-config) [:project :logo]))]
|
||||
[:img.cp__header-logo-img {:src logo}]
|
||||
|
||||
@@ -110,14 +110,15 @@
|
||||
|
||||
(when intro? (onboarding/intro))]))
|
||||
|
||||
(rum/defc journals
|
||||
(rum/defc journals < rum/reactive
|
||||
[latest-journals]
|
||||
[:div#journals
|
||||
(ui/infinite-list
|
||||
(for [[journal-name format] latest-journals]
|
||||
[:div.journal-item.content {:key journal-name}
|
||||
(journal-cp [journal-name format])])
|
||||
{:on-load (fn []
|
||||
{:has-more (page-handler/has-more-journals?)
|
||||
:on-load (fn []
|
||||
(page-handler/load-more-journals!))})])
|
||||
|
||||
(rum/defc all-journals < rum/reactive db-mixins/query
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#journals {
|
||||
margin-bottom: 70vh;
|
||||
|
||||
textarea {
|
||||
word-break: break-word;
|
||||
overflow: hidden;
|
||||
@@ -10,12 +8,13 @@
|
||||
.journal-item {
|
||||
border-top: 1px solid;
|
||||
border-top-color: var(--ls-border-color, #738694);
|
||||
padding: 48px 0;
|
||||
margin: 24px 0 128px 0;
|
||||
margin: 24px 0;
|
||||
padding: 24px 0;
|
||||
min-height: 250px;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
border-top: none;
|
||||
padding: 0;
|
||||
min-height: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,6 @@
|
||||
|
||||
[:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
|
||||
{:auto-focus true
|
||||
:style {:color "#000"}
|
||||
:on-change (fn [e]
|
||||
(reset! input (util/evalue e)))}]
|
||||
|
||||
@@ -277,6 +276,7 @@
|
||||
{:keys [title] :as properties} (:block/properties page)
|
||||
page-name (:block/name page)
|
||||
page-original-name (:block/original-name page)
|
||||
title (or title page-original-name page-name)
|
||||
file (:block/file page)
|
||||
file-path (and (:db/id file) (:file/path (db/entity repo (:db/id file))))
|
||||
today? (and
|
||||
@@ -434,16 +434,18 @@
|
||||
|
||||
(defonce graph-ref (atom nil))
|
||||
(defonce show-journal? (atom false))
|
||||
(defonce dot-mode? (atom false))
|
||||
|
||||
(rum/defcs global-graph < rum/reactive
|
||||
(mixins/event-mixin
|
||||
(fn [state]
|
||||
(mixins/listen state js/window "resize"
|
||||
(fn [e]
|
||||
(reset! layout [js/window.outerWidth js/window.outerHeight])))))
|
||||
[state]
|
||||
(let [theme (state/sub :ui/theme)
|
||||
sidebar-open? (state/sub :ui/sidebar-open?)
|
||||
[width height] (rum/react layout)
|
||||
dark? (= theme "dark")
|
||||
graph (graph-handler/build-global-graph theme (rum/react show-journal?))
|
||||
dot-mode-value? (rum/react dot-mode?)]
|
||||
graph (graph-handler/build-global-graph theme (rum/react show-journal?))]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div.relative#global-graph
|
||||
(if (seq (:nodes graph))
|
||||
@@ -451,7 +453,6 @@
|
||||
(graph/build-graph-opts
|
||||
graph
|
||||
dark?
|
||||
dot-mode-value?
|
||||
{:width (if (and (> width 1280) sidebar-open?)
|
||||
(- width 24 600)
|
||||
(- width 24))
|
||||
@@ -466,15 +467,7 @@
|
||||
{:on-click (fn [_e]
|
||||
(swap! show-journal? not))}
|
||||
(str (t :page/show-journals)
|
||||
(if @show-journal? " (ON)"))]
|
||||
[:a.text-sm.font-medium.mt-4
|
||||
{:title (if @dot-mode?
|
||||
(t :page/show-name)
|
||||
(t :page/hide-name))
|
||||
:on-click (fn [_e]
|
||||
(swap! dot-mode? not))}
|
||||
(str (t :dot-mode)
|
||||
(if @dot-mode? " (ON)"))]]]])))
|
||||
(if @show-journal? " (ON)"))]]]])))
|
||||
|
||||
(rum/defc all-pages < rum/reactive
|
||||
;; {:did-mount (fn [state]
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
|
||||
[:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
|
||||
{:auto-focus true
|
||||
:style {:color "#000"}
|
||||
:on-change (fn [e]
|
||||
(reset! project (util/evalue e)))}]
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
(db/get-block-referenced-blocks block-id)
|
||||
:else
|
||||
(db/get-page-referenced-blocks page-name))
|
||||
scheduled-or-deadlines (if journal?
|
||||
scheduled-or-deadlines (if (and journal?
|
||||
(not (true? (state/scheduled-deadlines-disabled?))))
|
||||
(db/get-date-scheduled-or-deadlines (string/capitalize page-name))
|
||||
nil)
|
||||
references (db/get-page-linked-refs-refed-pages repo page-name)
|
||||
@@ -105,11 +106,11 @@
|
||||
[:a.opacity-50.hover:opacity-100
|
||||
{:title "Filter"
|
||||
:on-click #(state/set-modal! (filter-dialog references page-name))}
|
||||
(svg/filter-icon (cond
|
||||
(empty? filter-state) nil
|
||||
(every? true? (vals filter-state)) "text-green-400"
|
||||
(every? false? (vals filter-state)) "text-red-400"
|
||||
:else "text-yellow-400"))]]
|
||||
(svg/filter-icon (cond
|
||||
(empty? filter-state) nil
|
||||
(every? true? (vals filter-state)) "text-green-400"
|
||||
(every? false? (vals filter-state)) "text-red-400"
|
||||
:else "text-yellow-400"))]]
|
||||
|
||||
[:div.references-blocks
|
||||
(let [ref-hiccup (block/->hiccup filtered-ref-blocks
|
||||
|
||||
@@ -39,9 +39,13 @@
|
||||
:sidebar? true
|
||||
:repo repo}))
|
||||
|
||||
(rum/defc page-graph < db-mixins/query
|
||||
[page]
|
||||
(let [theme (:ui/theme @state/state)
|
||||
(rum/defc page-graph < db-mixins/query rum/reactive
|
||||
[]
|
||||
(let [page (or
|
||||
(and (= :page (state/sub [:route-match :data :name]))
|
||||
(state/sub [:route-match :path-params :name]))
|
||||
(date/today))
|
||||
theme (:ui/theme @state/state)
|
||||
dark? (= theme "dark")
|
||||
graph (if (util/uuid-string? page)
|
||||
(graph-handler/build-block-graph (uuid page) theme)
|
||||
@@ -50,7 +54,7 @@
|
||||
[:div.sidebar-item.flex-col.flex-1
|
||||
(graph-2d/graph
|
||||
(graph/build-graph-opts
|
||||
graph dark? false
|
||||
graph dark?
|
||||
{:width 600
|
||||
:height 600}))])))
|
||||
|
||||
@@ -100,8 +104,8 @@
|
||||
[(t :right-side-bar/help) (onboarding/help)]
|
||||
|
||||
:page-graph
|
||||
[(str (t :right-side-bar/graph-ref) (db-model/get-page-original-name block-data))
|
||||
(page-graph block-data)]
|
||||
[(str (t :right-side-bar/page-graph))
|
||||
(page-graph)]
|
||||
|
||||
:block-ref
|
||||
(when-let [block (db/entity repo [:block/uuid (:block/uuid (:block block-data))])]
|
||||
@@ -183,7 +187,7 @@
|
||||
(if collapse?
|
||||
(svg/caret-right)
|
||||
(svg/caret-down))]
|
||||
[:div.ml-1
|
||||
[:div.ml-1.font-medium
|
||||
title]]
|
||||
(close #(state/sidebar-remove-block! idx))]
|
||||
[:div {:class (if collapse? "hidden" "initial")}
|
||||
|
||||
@@ -276,8 +276,10 @@
|
||||
;; hide context menu
|
||||
(state/hide-custom-context-menu!)
|
||||
|
||||
(if-not (state/get-selection-start-block)
|
||||
(editor-handler/clear-selection! e)
|
||||
(editor-handler/clear-selection! e)))
|
||||
(mixins/listen state js/window "mouseup"
|
||||
(fn [e]
|
||||
(when (state/get-selection-start-block)
|
||||
(state/set-selection-start-block! nil))))
|
||||
|
||||
;; TODO: move to keyboards
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
:excalidraw})))
|
||||
|
||||
(def markup-formats
|
||||
#{:org :md :markdown :asciidoc :rst})
|
||||
#{:org :md :markdown :asciidoc :adoc :rst})
|
||||
|
||||
(defn img-formats
|
||||
[]
|
||||
@@ -283,7 +283,7 @@
|
||||
(def metadata-file "metadata.edn")
|
||||
|
||||
(def config-default-content
|
||||
"{;; Currently, we support either \"Markdown\" or \"Org\".\n ;; This can overwrite your global preference so that\n ;; maybe your personal preferred format is Org but you'd\n ;; need to use Markdown for some projects.\n ;; :preferred-format \"\"\n \n ;; Preferred workflow style. \n ;; Value is either \":now\" for NOW/LATER style,\n ;; or \":todo\" for TODO/DOING style.\n :preferred-workflow :now\n\n ;; Git settings\n :git-pull-secs 60\n :git-push-secs 10\n :git-auto-push true\n\n ;; The app will ignore those directories or files.\n ;; E.g. \"/archived\" \"/test.md\"\n :hidden []\n\n ;; When creating the new journal page, the app will use your template content here.\n ;; Example for Markdown users: \"## [[Work]]\\n###\\n## [[Family]]\\n###\\n\n ;; Example for Org mode users: \"** [[Work]]\\n***\\n** [[Family]]\\n***\\n\n :default-templates\n {:journals \"\"}\n\n ;; The app will show those queries in today's journal page,\n ;; the \"NOW\" query asks the tasks which need to be finished \"now\",\n ;; the \"NEXT\" query asks the future tasks.\n :default-queries\n {:journals\n [{:title \"🔨 NOW\"\n :query [:find (pull ?h [*])\n :in $ ?start ?today\n :where\n [?h :block/marker ?marker]\n [?h :block/page ?p]\n [?p :block/journal? true]\n [?p :block/journal-day ?d]\n [(>= ?d ?start)]\n [(<= ?d ?today)]\n [(contains? #{\"NOW\" \"DOING\"} ?marker)]]\n :inputs [:14d :today]\n :result-transform (fn [result]\n (sort-by (fn [h]\n (get h :block/priority \"Z\")) result))\n :collapsed? false}\n {:title \"📅 NEXT\"\n :query [:find (pull ?h [*])\n :in $ ?start ?next\n :where\n [?h :block/marker ?marker]\n [?h :block/refs ?p]\n [?p :block/journal? true]\n [?p :block/journal-day ?d]\n [(> ?d ?start)]\n [(< ?d ?next)]\n [(contains? #{\"NOW\" \"LATER\" \"TODO\"} ?marker)]]\n :inputs [:today :7d-after]\n :collapsed? false}]}\n\n ;; Add your own commands to speedup.\n ;; E.g. [[\"js\" \"Javascript\"]]\n :commands\n []\n\n ;; Macros replace texts and will make you more productive.\n ;; For example:\n ;; Add this to the macros below:\n ;; {\"poem\" \"Rose is $1, violet's $2. Life's ordered: Org assists you.\"}\n ;; input \"{{{poem(red,blue)}}}\"\n ;; becomes\n ;; Rose is red, violet's blue. Life's ordered: Org assists you.\n :macros {}}\n")
|
||||
"{;; Currently, we support either \"Markdown\" or \"Org\".\n ;; This can overwrite your global preference so that\n ;; maybe your personal preferred format is Org but you'd\n ;; need to use Markdown for some projects.\n ;; :preferred-format \"\"\n \n ;; Preferred workflow style. \n ;; Value is either \":now\" for NOW/LATER style,\n ;; or \":todo\" for TODO/DOING style.\n :preferred-workflow :now\n\n ;; Git settings\n :git-pull-secs 60\n :git-push-secs 10\n :git-auto-push true\n\n ;; The app will ignore those directories or files.\n ;; E.g. \"/archived\" \"/test.md\"\n :hidden []\n\n ;; When creating the new journal page, the app will use your template content here.\n ;; Example for Markdown users: \"## [[Work]]\\n###\\n## [[Family]]\\n###\\n\n ;; Example for Org mode users: \"** [[Work]]\\n***\\n** [[Family]]\\n***\\n\n :default-templates\n {:journals \"\"}\n\n ;; The app will show those queries in today's journal page,\n ;; the \"NOW\" query asks the tasks which need to be finished \"now\",\n ;; the \"NEXT\" query asks the future tasks.\n :default-queries\n {:journals\n [{:title \"🔨 NOW\"\n :query [:find (pull ?h [*])\n :in $ ?start ?today\n :where\n [?h :block/marker ?marker]\n [?h :block/page ?p]\n [?p :block/journal? true]\n [?p :block/journal-day ?d]\n [(>= ?d ?start)]\n [(<= ?d ?today)]\n [(contains? #{\"NOW\" \"DOING\"} ?marker)]]\n :inputs [:14d :today]\n :result-transform (fn [result]\n (sort-by (fn [h]\n (get h :block/priority \"Z\")) result))\n :collapsed? false}\n {:title \"📅 NEXT\"\n :query [:find (pull ?h [*])\n :in $ ?start ?next\n :where\n [?h :block/marker ?marker]\n [?h :block/ref-pages ?p]\n [?p :block/journal? true]\n [?p :block/journal-day ?d]\n [(> ?d ?start)]\n [(< ?d ?next)]\n [(contains? #{\"NOW\" \"LATER\" \"TODO\"} ?marker)]]\n :inputs [:today :7d-after]\n :collapsed? false}]}\n\n ;; Add your own commands to speedup.\n ;; E.g. [[\"js\" \"Javascript\"]]\n :commands\n []\n\n ;; Macros replace texts and will make you more productive.\n ;; For example:\n ;; Add this to the macros below:\n ;; {\"poem\" \"Rose is $1, violet's $2. Life's ordered: Org assists you.\"}\n ;; input \"{{{poem red,blue}}}\"\n ;; becomes\n ;; Rose is red, violet's blue. Life's ordered: Org assists you.\n :macros {}}\n")
|
||||
|
||||
(def markers
|
||||
#{"now" "later" "todo" "doing" "done" "wait" "waiting"
|
||||
|
||||
@@ -1024,20 +1024,31 @@
|
||||
(defn get-date-scheduled-or-deadlines
|
||||
[journal-title]
|
||||
(when-let [date (date/journal-title->int journal-title)]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [conn (conn/get-conn repo)]
|
||||
(->> (react/q repo [:custom :scheduled-deadline journal-title] {}
|
||||
'[:find (pull ?block [*])
|
||||
:in $ ?day
|
||||
:where
|
||||
(or
|
||||
[?block :block/scheduled ?day]
|
||||
[?block :block/deadline ?day])]
|
||||
date)
|
||||
react
|
||||
db-utils/seq-flatten
|
||||
sort-blocks
|
||||
db-utils/group-by-page)))))
|
||||
(let [future-days (state/get-scheduled-future-days)]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [conn (conn/get-conn repo)]
|
||||
(->> (react/q repo [:custom :scheduled-deadline journal-title] {}
|
||||
'[:find (pull ?block [*])
|
||||
:in $ ?day ?future
|
||||
:where
|
||||
(or
|
||||
[?block :block/scheduled ?d]
|
||||
[?block :block/deadline ?d])
|
||||
[(get-else $ ?block :block/repeated? false) ?repeated]
|
||||
[(get-else $ ?block :block/marker "NIL") ?marker]
|
||||
[(not= ?marker "DONE")]
|
||||
[(not= ?marker "CANCELED")]
|
||||
[(not= ?marker "CANCELLED")]
|
||||
[(<= ?d ?future)]
|
||||
(or-join [?repeated ?d ?day]
|
||||
[(true? ?repeated)]
|
||||
[(>= ?d ?day)])]
|
||||
date
|
||||
(+ date future-days))
|
||||
react
|
||||
db-utils/seq-flatten
|
||||
sort-blocks
|
||||
db-utils/group-by-page))))))
|
||||
|
||||
(defn get-files-that-referenced-page
|
||||
[page-id]
|
||||
|
||||
@@ -387,7 +387,7 @@
|
||||
(let [query-string (template/resolve-dynamic-template! query-string)]
|
||||
(when-not (string/blank? query-string)
|
||||
(let [{:keys [query sort-by blocks?] :as result} (parse repo query-string)]
|
||||
(if (string? result)
|
||||
(if (and (string? result) (not (string/includes? result " ")))
|
||||
(if (= "\"" (first result) (last result))
|
||||
(subs result 1 (dec (count result)))
|
||||
result)
|
||||
|
||||
@@ -180,7 +180,7 @@ title: How to take dummy notes?
|
||||
:right-side-bar/page "Page graph"
|
||||
:right-side-bar/recent "Recent"
|
||||
:right-side-bar/contents "Contents"
|
||||
:right-side-bar/graph-ref "Graph of "
|
||||
:right-side-bar/page-graph "Page graph"
|
||||
:right-side-bar/block-ref "Block reference"
|
||||
:git/set-access-token "Set Github personal access token"
|
||||
:git/token-is-encrypted "The token will be encrypted and stored in the browser local storage"
|
||||
@@ -243,6 +243,8 @@ title: How to take dummy notes?
|
||||
:block/name "Page name"
|
||||
:page/last-modified "Last modified at"
|
||||
:page/new-title "What's your new page title?"
|
||||
:page/earlier "Earlier"
|
||||
:page/no-more-journals "No more journals"
|
||||
:publishing/pages "Pages"
|
||||
:publishing/page-name "Page name"
|
||||
:publishing/current-project "Current Project"
|
||||
@@ -300,7 +302,6 @@ title: How to take dummy notes?
|
||||
:settings-page/developer-mode-desc "Developer mode helps contributors and extension developers test their integration with Logseq more efficient."
|
||||
:settings-page/current-version "Current version"
|
||||
:logseq "Logseq"
|
||||
:dot-mode "Dot mode"
|
||||
:on "ON"
|
||||
:more-options "More options"
|
||||
:to "to"
|
||||
@@ -419,7 +420,6 @@ title: How to take dummy notes?
|
||||
:right-side-bar/page "Seiten-Graph"
|
||||
:right-side-bar/recent "Neueste"
|
||||
:right-side-bar/contents "Inhalt"
|
||||
:right-side-bar/graph-ref "Graph von "
|
||||
:right-side-bar/block-ref "Blockreferenz"
|
||||
:git/set-access-token "Persönliches Github-Zugangs-Token festlegen"
|
||||
:git/token-is-encrypted "Das Token wird verschlüsselt und im lokalen Speicher des Browsers gespeichert"
|
||||
@@ -538,7 +538,6 @@ title: How to take dummy notes?
|
||||
:settings-page/developer-mode-desc "Der Entwicklermodus hilft Mitwirkenden und Erweiterungsentwicklern, ihre Integration mit Logseq effizienter zu testen."
|
||||
:settings-page/current-version "Aktuelle Version"
|
||||
:logseq "Logseq"
|
||||
:dot-mode "Punktmodus"
|
||||
:on "AN"
|
||||
:more-options "Weitere Optionen"
|
||||
:to "zu"
|
||||
@@ -648,7 +647,6 @@ title: How to take dummy notes?
|
||||
:right-side-bar/page "Graphe de la page"
|
||||
:right-side-bar/recent "Récents"
|
||||
:right-side-bar/contents "Contenus"
|
||||
:right-side-bar/graph-ref "Graphe de "
|
||||
:right-side-bar/block-ref "Référence des blocs"
|
||||
:git/set-access-token "Définir un jeton d'accès personnel GitHub"
|
||||
:git/token-is-encrypted "Le jeton sera chiffré et gardé dans le stockage local du navigateur (local storage)"
|
||||
@@ -755,7 +753,6 @@ title: How to take dummy notes?
|
||||
:settings-page/disable-developer-mode "Désactiver le mode développeur"
|
||||
:settings-page/developer-mode-desc "Le mode développeur aide les contributeurs et les développeurs d'extension à tester leur intégration avec Logseq."
|
||||
:logseq "Logseq"
|
||||
:dot-mode "Dot mode"
|
||||
:on "ON"
|
||||
:more-options "Plus d'options"
|
||||
:to "à"
|
||||
@@ -910,7 +907,7 @@ title: How to take dummy notes?
|
||||
:right-side-bar/page "页面图谱"
|
||||
:right-side-bar/recent "最近"
|
||||
:right-side-bar/contents "目录"
|
||||
:right-side-bar/graph-ref "图谱:"
|
||||
:right-side-bar/page-graph "页面图谱:"
|
||||
:right-side-bar/block-ref "块引用"
|
||||
:git/set-access-token "设定 Github 个人访问令牌"
|
||||
:git/token-is-encrypted "令牌将被加密并存储在浏览器本地存储"
|
||||
@@ -973,6 +970,8 @@ title: How to take dummy notes?
|
||||
:block/name "页面名称"
|
||||
:page/last-modified "最后更改于"
|
||||
:page/new-title "请输入新页面的名字:"
|
||||
:page/earlier "之前"
|
||||
:page/no-more-journals "没有更多了"
|
||||
:publishing/pages "页面"
|
||||
:publishing/page-name "页面名"
|
||||
:publishing/current-project "当前项目"
|
||||
@@ -1027,7 +1026,6 @@ title: How to take dummy notes?
|
||||
:settings-page/developer-mode-desc "开发者模式帮助贡献者和扩展开发者更有效地测试他们与 Logseq 的集成。"
|
||||
:settings-page/current-version "当前版本"
|
||||
:logseq "Logseq"
|
||||
:dot-mode "点模式"
|
||||
:on "已打开"
|
||||
:more-options "更多选项"
|
||||
:to "至"
|
||||
@@ -1046,7 +1044,7 @@ title: How to take dummy notes?
|
||||
:graph "图谱"
|
||||
:graph-view "全局图谱"
|
||||
:publishing "发布"
|
||||
:export "导出公开页面"
|
||||
:export "导出"
|
||||
:all-graphs "所有库"
|
||||
:all-pages "所有页面"
|
||||
:all-files "所有文件"
|
||||
@@ -1187,7 +1185,6 @@ title: How to take dummy notes?
|
||||
:right-side-bar/page "頁面圖譜"
|
||||
:right-side-bar/recent "最近"
|
||||
:right-side-bar/contents "目錄"
|
||||
:right-side-bar/graph-ref "圖譜:"
|
||||
:right-side-bar/block-ref "塊引用"
|
||||
:git/set-access-token "設定 Github 個人訪問令牌"
|
||||
:git/token-is-encrypted "令牌將被加密並存儲在瀏覽器本地存儲"
|
||||
@@ -1245,6 +1242,8 @@ title: How to take dummy notes?
|
||||
:block/name "頁面名稱:"
|
||||
:page/last-modified "最後更改於"
|
||||
:page/new-title "請輸入新頁面的名字:"
|
||||
:page/load-more-journals "載入更多"
|
||||
:page/no-more-journals "沒有更多了"
|
||||
:publishing/pages "頁面"
|
||||
:publishing/page-name "頁面名稱"
|
||||
:publishing/current-project "當前項目"
|
||||
@@ -1292,7 +1291,6 @@ title: How to take dummy notes?
|
||||
:settings-page/disable-developer-mode "禁用開發者模式"
|
||||
:settings-page/developer-mode-desc "開發者模式幫助貢獻者和擴展開發者更有效地測試他們與 Logseq 的集成。"
|
||||
:logseq "Logseq"
|
||||
:dot-mode "點模式"
|
||||
:on "已打開"
|
||||
:more-options "更多選項"
|
||||
:to "至"
|
||||
@@ -1440,7 +1438,6 @@ title: How to take dummy notes?
|
||||
:right-side-bar/page "Grafiek bladsy"
|
||||
:right-side-bar/recent "Onlangs"
|
||||
:right-side-bar/contents "Inhoud"
|
||||
:right-side-bar/graph-ref "Grafiek van "
|
||||
:right-side-bar/block-ref "Blok verwysing"
|
||||
:git/set-access-token "Set Github personal access token"
|
||||
:git/token-is-encrypted "The token will be encrypted and stored in the browser local storage"
|
||||
@@ -1543,7 +1540,6 @@ title: How to take dummy notes?
|
||||
:settings-page/disable-developer-mode "Skakel ontwikkelaars modus af"
|
||||
:settings-page/developer-mode-desc "Ontwikkelaarmodus help bydraers en ontwikkelaars van uitbreidings om hul integrasie met Logseq doeltreffender te toets."
|
||||
:logseq "Logseq"
|
||||
:dot-mode "Punt modus"
|
||||
:on "AAN"
|
||||
:more-options "More options"
|
||||
:to "na"
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
["codemirror" :as cm]
|
||||
["codemirror/addon/edit/matchbrackets"]
|
||||
["codemirror/addon/edit/closebrackets"]
|
||||
["codemirror/addon/selection/active-line"]
|
||||
["codemirror/mode/clojure/clojure"]
|
||||
["codemirror/mode/powershell/powershell"]
|
||||
["codemirror/mode/javascript/javascript"]
|
||||
@@ -22,6 +23,7 @@
|
||||
["codemirror/mode/commonlisp/commonlisp"]
|
||||
["codemirror/mode/coffeescript/coffeescript"]
|
||||
["codemirror/mode/css/css"]
|
||||
["codemirror/mode/sass/sass"]
|
||||
["codemirror/mode/dart/dart"]
|
||||
["codemirror/mode/dockerfile/dockerfile"]
|
||||
["codemirror/mode/elm/elm"]
|
||||
@@ -50,43 +52,43 @@
|
||||
[editor textarea config state]
|
||||
(.save editor)
|
||||
(let [value (gobj/get textarea "value")
|
||||
default-value (gobj/get textarea "defaultValue")]
|
||||
(cond
|
||||
(:block/uuid config)
|
||||
(let [block (db/pull [:block/uuid (:block/uuid config)])
|
||||
format (:block/format block)
|
||||
;; Get newest state
|
||||
pos-meta (:pos-meta state)
|
||||
content (:block/content block)
|
||||
{:keys [start_pos end_pos]} @pos-meta
|
||||
prev-content (utf8/substring (utf8/encode content)
|
||||
0 start_pos)
|
||||
value (str (if (not= "\n" (last prev-content))
|
||||
"\n")
|
||||
(string/trimr value)
|
||||
"\n")
|
||||
content' (utf8/insert! content
|
||||
start_pos
|
||||
end_pos
|
||||
value)]
|
||||
(reset! pos-meta {:start_pos start_pos
|
||||
:end_pos (+ start_pos
|
||||
(utf8/length (utf8/encode value)))})
|
||||
(editor-handler/save-block-if-changed! block content'))
|
||||
default-value (gobj/get textarea "defaultValue")
|
||||
pos-meta (:pos-meta state)]
|
||||
(when (not= value default-value)
|
||||
(cond
|
||||
(:block/uuid config)
|
||||
(let [block (db/pull [:block/uuid (:block/uuid config)])
|
||||
format (:block/format block)
|
||||
content (:block/content block)
|
||||
{:keys [start_pos end_pos]} @pos-meta
|
||||
prev-content (utf8/substring (utf8/encode content)
|
||||
0 start_pos)
|
||||
value (str (if (not= "\n" (last prev-content))
|
||||
"\n")
|
||||
(string/trimr value)
|
||||
"\n")
|
||||
content' (utf8/insert! content start_pos end_pos value)]
|
||||
(state/set-editor-op! :code-editor)
|
||||
(editor-handler/save-block-if-changed! block content')
|
||||
(let [new-pos-meta {:start_pos start_pos
|
||||
:end_pos (+ start_pos
|
||||
(utf8/length (utf8/encode value)))}
|
||||
old-pos-meta @pos-meta]
|
||||
(reset! pos-meta new-pos-meta)))
|
||||
|
||||
(:file-path config)
|
||||
(let [path (:file-path config)
|
||||
content (db/get-file-no-sub path)
|
||||
value (some-> (gdom/getElement path)
|
||||
(gobj/get "value"))]
|
||||
(when (and
|
||||
(not (string/blank? value))
|
||||
(not= (string/trim value) (string/trim content)))
|
||||
(file-handler/alter-file (state/get-current-repo) path (string/trim value)
|
||||
{:re-render-root? true})))
|
||||
(:file-path config)
|
||||
(let [path (:file-path config)
|
||||
content (db/get-file-no-sub path)
|
||||
value (some-> (gdom/getElement path)
|
||||
(gobj/get "value"))]
|
||||
(when (and
|
||||
(not (string/blank? value))
|
||||
(not= (string/trim value) (string/trim content)))
|
||||
(file-handler/alter-file (state/get-current-repo) path (string/trim value)
|
||||
{:re-render-root? true})))
|
||||
|
||||
:else
|
||||
nil)))
|
||||
:else
|
||||
nil))))
|
||||
|
||||
(defn- text->cm-mode
|
||||
[text]
|
||||
@@ -105,14 +107,17 @@
|
||||
"typescript" "text/typescript"
|
||||
"ts" "text/typescript"
|
||||
"tsx" "text/typescript-jsx"
|
||||
"scss" "text/x-scss"
|
||||
"less" "text/x-less"
|
||||
mode))))
|
||||
|
||||
(defn render!
|
||||
[state]
|
||||
(let [editor-atom (:editor-atom state)]
|
||||
(let [editor-atom (:editor-atom state)
|
||||
esc-pressed? (atom nil)]
|
||||
(if @editor-atom
|
||||
@editor-atom
|
||||
(let [[config id attr code pos_meta] (:rum/args state)
|
||||
(let [[config id attr code] (:rum/args state)
|
||||
original-mode (get attr :data-lang)
|
||||
mode (or original-mode "javascript")
|
||||
clojure? (contains? #{"clojure" "clj" "text/x-clojure" "cljs" "cljc"} mode)
|
||||
@@ -128,6 +133,7 @@
|
||||
:matchBrackets lisp?
|
||||
:autoCloseBrackets true
|
||||
:lineNumbers true
|
||||
:styleActiveLine true
|
||||
:extraKeys #js {"Esc" (fn [cm]
|
||||
(let [save! #(save-file-or-block-when-blur-or-esc! cm textarea config state)]
|
||||
(if-let [block-id (:block/uuid config)]
|
||||
@@ -138,11 +144,16 @@
|
||||
(if changed?
|
||||
(save!)
|
||||
(editor-handler/edit-block! block :max (:block/format block) block-id)))
|
||||
(save!))))}})))]
|
||||
(save!)))
|
||||
;; TODO: return "handled" or false doesn't always prevent event bubbles
|
||||
(reset! esc-pressed? true)
|
||||
(js/setTimeout #(reset! esc-pressed? false) 10))}})))]
|
||||
(when editor
|
||||
(let [element (.getWrapperElement editor)]
|
||||
(.on editor "blur" (fn []
|
||||
(save-file-or-block-when-blur-or-esc! editor textarea config state)))
|
||||
(.on editor "blur" (fn [_cm e]
|
||||
(util/stop e)
|
||||
(when-not @esc-pressed?
|
||||
(save-file-or-block-when-blur-or-esc! editor textarea config state))))
|
||||
(.addEventListener element "click"
|
||||
(fn [e]
|
||||
(util/stop e)))
|
||||
@@ -167,8 +178,9 @@
|
||||
:did-remount (fn [old_state state]
|
||||
(load-and-render! state)
|
||||
state)}
|
||||
[state config id attr code pos_meta]
|
||||
[state config id attr code pos-meta]
|
||||
[:div.extensions__code
|
||||
{:on-mouse-down (fn [e] (util/stop e))}
|
||||
[:div.extensions__code-lang
|
||||
(let [mode (string/lower-case (get attr :data-lang "javascript"))]
|
||||
(if (= mode "text/x-clojure")
|
||||
|
||||
@@ -14,5 +14,10 @@
|
||||
padding: 6px 0 0 0;
|
||||
font-family: Fira Code, Monaco, Menlo, Consolas, 'COURIER NEW', monospace;
|
||||
max-width: 86vw;
|
||||
&:not(.CodeMirror-focused) {
|
||||
.CodeMirror-activeline-background {
|
||||
background: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
*elements (get state ::elements)
|
||||
file (:file option)]
|
||||
(when data
|
||||
[:div.overflow-hidden
|
||||
[:div.overflow-hidden {:on-mouse-down (fn [e] (util/stop e))}
|
||||
[:div.my-1 {:style {:font-size 10}}
|
||||
[:a.mr-2 {:on-click ui-handler/toggle-wide-mode!}
|
||||
(util/format "Wide Mode (%s)" (if wide-mode? "ON" "OFF"))]
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
(when (and (not (util/starts-with? page "http:"))
|
||||
(not (util/starts-with? page "https:"))
|
||||
(not (util/starts-with? page "file:"))
|
||||
(not (contains? (config/supported-formats) ext)))
|
||||
(or (= ext :excalidraw) (not (contains? (config/supported-formats) ext))))
|
||||
page)))
|
||||
|
||||
(and
|
||||
@@ -65,12 +65,30 @@
|
||||
(string? argument)
|
||||
(text/page-ref? argument))
|
||||
(text/page-ref-un-brackets! argument))))
|
||||
|
||||
(and (vector? block)
|
||||
(= "Tag" (first block)))
|
||||
(let [text (second block)]
|
||||
(when (and
|
||||
(string? text)
|
||||
(text/page-ref? text))
|
||||
(text/page-ref-un-brackets! text)))
|
||||
|
||||
:else
|
||||
nil)]
|
||||
(when (and
|
||||
(string? page)
|
||||
(not (string/blank? page)))
|
||||
(string/trim page))))
|
||||
(cond
|
||||
(and
|
||||
(string? page)
|
||||
(text/block-ref? page))
|
||||
(text/block-ref-un-brackets! page)
|
||||
|
||||
(and
|
||||
(string? page)
|
||||
(not (string/blank? page)))
|
||||
(string/trim page)
|
||||
|
||||
:else
|
||||
nil)))
|
||||
|
||||
(defn get-block-reference
|
||||
[block]
|
||||
@@ -153,16 +171,20 @@
|
||||
(let [properties (into {} properties)
|
||||
page-refs (->>
|
||||
(map (fn [v]
|
||||
(when v
|
||||
(->> (re-seq text/page-ref-re v)
|
||||
(map second)
|
||||
(map string/lower-case))))
|
||||
(when (string? v)
|
||||
(let [page-refs (->> (re-seq text/page-ref-re v)
|
||||
(map second))
|
||||
tags (->> (string/split v #",")
|
||||
(filter (fn [s] (= \# (first s))))
|
||||
(map (fn [s] (subs s 1))))]
|
||||
(concat page-refs tags))))
|
||||
(vals properties))
|
||||
(apply concat)
|
||||
(distinct))
|
||||
(remove string/blank?))
|
||||
properties (->> properties
|
||||
(medley/map-kv (fn [k v]
|
||||
(let [v (string/trim v)]
|
||||
(let [v (string/trim v)
|
||||
k (string/replace k " " "_")]
|
||||
(cond
|
||||
(and (= "\"" (first v) (last v))) ; wrapped in ""
|
||||
[(string/lower-case k) (string/trim (subs v 1 (dec (count v))))]
|
||||
@@ -309,7 +331,9 @@
|
||||
(defn safe-blocks
|
||||
[blocks]
|
||||
(map (fn [block]
|
||||
(block-keywordize (util/remove-nils block)))
|
||||
(if (map? block)
|
||||
(block-keywordize (util/remove-nils block))
|
||||
block))
|
||||
blocks))
|
||||
|
||||
(defn with-path-refs
|
||||
@@ -369,6 +393,7 @@
|
||||
[blocks content with-id?]
|
||||
(let [encoded-content (utf8/encode content)
|
||||
last-pos (utf8/length encoded-content)
|
||||
pre-block-body (atom nil)
|
||||
blocks
|
||||
(loop [headings []
|
||||
block-body []
|
||||
@@ -440,8 +465,11 @@
|
||||
:else
|
||||
(let [block-body' (conj block-body block)]
|
||||
(recur headings block-body' (rest blocks) timestamps properties last-pos last-level children))))
|
||||
(-> (reverse headings)
|
||||
safe-blocks)))]
|
||||
(do
|
||||
(when (seq block-body)
|
||||
(reset! pre-block-body block-body))
|
||||
(-> (reverse headings)
|
||||
safe-blocks))))]
|
||||
(let [first-block (first blocks)
|
||||
first-block-start-pos (get-in first-block [:block/meta :start-pos])
|
||||
blocks (if (and
|
||||
@@ -458,7 +486,8 @@
|
||||
:meta {:start-pos 0
|
||||
:end-pos (or first-block-start-pos
|
||||
(utf8/length encoded-content))}
|
||||
:body (take-while (fn [block] (not (heading-block? block))) blocks)
|
||||
:body @pre-block-body
|
||||
;; (take-while (fn [block] (not (heading-block? block))) blocks)
|
||||
:pre-block? true}
|
||||
(block-keywordize)))
|
||||
(select-keys first-block [:block/file :block/format :block/page]))
|
||||
|
||||
@@ -29,8 +29,9 @@
|
||||
;; 4. old content will overwrites the new content in step 2
|
||||
(not (and db-content
|
||||
(string/starts-with? db-content content))))
|
||||
(file-handler/alter-file repo path content {:re-render-root? true
|
||||
:from-disk? true})))
|
||||
(let [_ (file-handler/alter-file repo path content {:re-render-root? true
|
||||
:from-disk? true})]
|
||||
(db/set-file-last-modified-at! repo path mtime))))
|
||||
|
||||
(and (= "change" type)
|
||||
(nil? (db/get-file path)))
|
||||
|
||||
@@ -54,26 +54,10 @@
|
||||
(.toString 16)
|
||||
(.padStart 6 "0"))))
|
||||
|
||||
(defn- dot-mode
|
||||
[node ctx global-scale dark?]
|
||||
(let [label (gobj/get node "id")
|
||||
val (gobj/get node "val")
|
||||
font-size (/ 15 global-scale)
|
||||
arc-radius (/ 3 global-scale)
|
||||
x (gobj/get node "x")
|
||||
y (gobj/get node "y")
|
||||
color (gobj/get node "color")]
|
||||
(set! (.-fillStyle ctx) color)
|
||||
(.beginPath ctx)
|
||||
(.arc ctx x y (if (zero? val)
|
||||
arc-radius
|
||||
(* arc-radius (js/Math.sqrt (js/Math.sqrt val)))) 0 (* 2 js/Math.PI) false)
|
||||
(set! (.-fillStyle ctx) (if dark? "#aaa" "#222"))
|
||||
(.fill ctx)))
|
||||
|
||||
(defn- dot-text-mode
|
||||
[node ctx global-scale dark?]
|
||||
(let [label (gobj/get node "id")
|
||||
(let [hide-text? (< global-scale 0.45)
|
||||
label (gobj/get node "id")
|
||||
val (gobj/get node "val")
|
||||
val (if (zero? val) 1 val)
|
||||
font-size (min
|
||||
@@ -89,9 +73,10 @@
|
||||
(set! (.-filltextAlign ctx) "center")
|
||||
(set! (.-textBaseLine ctx) "middle")
|
||||
(set! (.-fillStyle ctx) color)
|
||||
(.fillText ctx label
|
||||
(- x (/ text-width 2))
|
||||
(- y (/ 9 global-scale)))
|
||||
(when-not hide-text?
|
||||
(.fillText ctx label
|
||||
(- x (/ text-width 2))
|
||||
(- y (/ 9 global-scale))))
|
||||
|
||||
(.beginPath ctx)
|
||||
(.arc ctx x y (if (zero? val)
|
||||
@@ -124,7 +109,7 @@
|
||||
:nodes nodes}))
|
||||
|
||||
(defn- build-graph-opts
|
||||
[graph dark? dot-mode? option]
|
||||
[graph dark? option]
|
||||
(let [nodes-count (count (:nodes graph))
|
||||
graph-data (build-graph-data graph)]
|
||||
(merge
|
||||
@@ -149,7 +134,7 @@
|
||||
(let [k (:k (bean/->clj z))]
|
||||
(reset! graph-mode
|
||||
(cond
|
||||
(or dot-mode? (< k 0.4))
|
||||
(< k 0.4)
|
||||
:dot
|
||||
|
||||
:else
|
||||
@@ -172,8 +157,5 @@
|
||||
;; (.zoomToFit @ref 400)))
|
||||
:nodeCanvasObject
|
||||
(fn [node ^CanvasRenderingContext2D ctx global-scale]
|
||||
(case @graph-mode
|
||||
:dot-text
|
||||
(dot-text-mode node ctx global-scale dark?)
|
||||
(dot-mode node ctx global-scale dark?)))}
|
||||
(dot-text-mode node ctx global-scale dark?))}
|
||||
option)))
|
||||
|
||||
@@ -152,11 +152,13 @@
|
||||
property-names (keys properties)]
|
||||
(and (every? #(contains? #{:title :filters} %) property-names)
|
||||
(let [ast (mldoc/->edn (:block/content block) (mldoc/default-config (:block/format block)))]
|
||||
(or
|
||||
(empty? (rest ast))
|
||||
(every? (fn [[[typ break-lines]] _]
|
||||
(and (= typ "Paragraph")
|
||||
(every? #(= % ["Break_Line"]) break-lines))) (rest ast))))))))
|
||||
(and
|
||||
(= "Properties" (ffirst (first ast)))
|
||||
(or
|
||||
(empty? (rest ast))
|
||||
(every? (fn [[[typ break-lines]] _]
|
||||
(and (= typ "Paragraph")
|
||||
(every? #(= % ["Break_Line"]) break-lines))) (rest ast)))))))))
|
||||
|
||||
(defn with-dummy-block
|
||||
([blocks format]
|
||||
|
||||
@@ -79,15 +79,18 @@
|
||||
(let [{:keys [selection-start selection-end format value block edit-id input]} m
|
||||
empty-selection? (= selection-start selection-end)
|
||||
pattern (pattern-fn format)
|
||||
new-value (str
|
||||
(subs value 0 selection-start)
|
||||
pattern
|
||||
(subs value selection-start selection-end)
|
||||
pattern
|
||||
(subs value selection-end))]
|
||||
pattern-count (count pattern)
|
||||
prefix (subs value 0 selection-start)
|
||||
wrapped-value (str pattern
|
||||
(subs value selection-start selection-end)
|
||||
pattern)
|
||||
postfix (subs value selection-end)
|
||||
new-value (str prefix wrapped-value postfix)]
|
||||
(state/set-edit-content! edit-id new-value)
|
||||
(when empty-selection?
|
||||
(util/cursor-move-back input (count pattern))))))
|
||||
(if empty-selection?
|
||||
(util/cursor-move-back input (count pattern))
|
||||
(let [new-pos (count (str prefix wrapped-value))]
|
||||
(util/move-cursor-to input new-pos))))))
|
||||
|
||||
(defn bold-format! []
|
||||
(format-text! config/get-bold))
|
||||
@@ -309,6 +312,7 @@
|
||||
after-blocks)]
|
||||
[after-blocks @block-and-children-content @last-child-end-pos]))
|
||||
|
||||
;; FIXME: children' :block/path-ref-pages
|
||||
(defn compute-retract-refs
|
||||
"Computes old references to be retracted."
|
||||
[eid {:block/keys [ref-pages ref-blocks]} old-ref-pages old-ref-blocks]
|
||||
@@ -379,6 +383,7 @@
|
||||
content (if (and (seq properties) (text/properties-hidden? properties))
|
||||
(text/remove-properties! content)
|
||||
content)
|
||||
content (text/remove-level-spaces content format true)
|
||||
content-length (count content)
|
||||
text-range (cond
|
||||
(and (> tail-len 0) (>= (count content) tail-len))
|
||||
@@ -720,7 +725,6 @@
|
||||
(when (seq files)
|
||||
(file-handler/alter-files repo files opts)))))
|
||||
(state/set-editor-op! nil))]
|
||||
|
||||
;; Replace with batch transactions
|
||||
(state/add-tx! transact-fn)
|
||||
|
||||
@@ -1443,7 +1447,10 @@
|
||||
(when (and (if check-idle? (state/input-idle? repo) true)
|
||||
(not (state/get-editor-show-page-search?))
|
||||
(not (state/get-editor-show-page-search-hashtag?))
|
||||
(not (state/get-editor-show-block-search?)))
|
||||
(not (state/get-editor-show-block-search?))
|
||||
(not (state/get-editor-show-date-picker?))
|
||||
(not (state/get-editor-show-template-search?))
|
||||
(not (state/get-editor-show-input)))
|
||||
(state/set-editor-op! :auto-save)
|
||||
(try
|
||||
(let [input-id (state/get-edit-input-id)
|
||||
@@ -1525,7 +1532,9 @@
|
||||
[format url file-name image?]
|
||||
(case (keyword format)
|
||||
:markdown (util/format (str (when image? "!") "[%s](%s)") file-name url)
|
||||
:org (util/format "[[%s]]" url)
|
||||
:org (if image?
|
||||
(util/format "[[%s]]" url)
|
||||
(util/format "[[%s][%s]]" url file-name))
|
||||
nil))
|
||||
|
||||
(defn- get-asset-link
|
||||
@@ -1551,22 +1560,28 @@
|
||||
prefix) "/" "_"))
|
||||
prefix (and prefix (subs prefix 0 (string/last-index-of prefix ".")))]
|
||||
(save-assets! repo repo-dir assets-dir files
|
||||
(fn [index]
|
||||
(str prefix "_" (.now js/Date) "_" index)))))))
|
||||
(fn [index file-base]
|
||||
(str (string/replace file-base " " "_") "_" (.now js/Date) "_" index)))))))
|
||||
([repo dir path files gen-filename]
|
||||
(p/all
|
||||
(for [[index ^js file] (map-indexed vector files)]
|
||||
(let [ext (.-name file)
|
||||
ext (if ext (subs ext (string/last-index-of ext ".")) "")
|
||||
filename (str (gen-filename index file) ext)
|
||||
filename (str path "/" filename)]
|
||||
(do
|
||||
;; WARN file name maybe fully qualified path when paste file
|
||||
(let [file-name (util/node-path.basename (.-name file))
|
||||
[file-base ext] (if file-name
|
||||
(let [last-dot-index (string/last-index-of file-name ".")]
|
||||
[(subs file-name 0 last-dot-index)
|
||||
(subs file-name last-dot-index)])
|
||||
["" ""])
|
||||
filename (str (gen-filename index file-base) ext)
|
||||
filename (str path "/" filename)]
|
||||
;(js/console.debug "Write asset #" dir filename file)
|
||||
(if (util/electron?)
|
||||
(let [from (.-path file)]
|
||||
(p/then (js/window.apis.copyFileToAssets dir filename from)
|
||||
#(p/resolved [filename (if (string? %) (js/File. #js[] %) file) (.join util/node-path dir filename)])))
|
||||
(p/then (fs/write-file! repo dir filename (.stream file) nil)
|
||||
#(p/resolved [filename file]))))))))
|
||||
(if (util/electron?)
|
||||
(let [from (.-path file)]
|
||||
(p/then (js/window.apis.copyFileToAssets dir filename from)
|
||||
#(p/resolved [filename (if (string? %) (js/File. #js[] %) file) (.join util/node-path dir filename)])))
|
||||
(p/then (fs/write-file! repo dir filename (.stream file) nil)
|
||||
#(p/resolved [filename file])))))))))
|
||||
|
||||
(defonce *assets-url-cache (atom {}))
|
||||
|
||||
@@ -1970,16 +1985,12 @@
|
||||
(defn expand!
|
||||
[]
|
||||
(when-let [current-block (state/get-edit-block)]
|
||||
(expand/expand! current-block)
|
||||
(state/set-collapsed-state! (:block/uuid current-block)
|
||||
false)))
|
||||
(expand/expand! current-block)))
|
||||
|
||||
(defn collapse!
|
||||
[]
|
||||
(when-let [current-block (state/get-edit-block)]
|
||||
(expand/collapse! current-block)
|
||||
(state/set-collapsed-state! (:block/uuid current-block)
|
||||
true)))
|
||||
(expand/collapse! current-block)))
|
||||
|
||||
(defn cycle-collapse!
|
||||
[e]
|
||||
@@ -2416,8 +2427,9 @@
|
||||
|
||||
(defn- on-arrow-move-to-boundray
|
||||
[state input e direction]
|
||||
(when (or (and (= :left direction) (util/input-start? input))
|
||||
(and (= :right direction) (util/input-end? input)))
|
||||
(when (and (not (util/input-selected? input))
|
||||
(or (and (= :left direction) (util/input-start? input))
|
||||
(and (= :right direction) (util/input-end? input))))
|
||||
(move-to-block-when-cross-boundrary state e direction)))
|
||||
|
||||
(defn keydown-arrow-handler
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[frontend.db :as db]
|
||||
[frontend.format.protocol :as fp]
|
||||
[frontend.format :as f]
|
||||
[frontend.config :as config]
|
||||
[datascript.core :as d]
|
||||
[frontend.util :as util]
|
||||
[cljs-bean.core :as bean]
|
||||
@@ -78,7 +79,6 @@
|
||||
db-str (db/db->string db)
|
||||
state (select-keys @state/state
|
||||
[:ui/theme :ui/cycle-collapse
|
||||
:ui/collapsed-blocks
|
||||
:ui/sidebar-collapsed-blocks
|
||||
:ui/show-recent?
|
||||
:config])
|
||||
@@ -88,7 +88,7 @@
|
||||
html-str (str "data:text/html;charset=UTF-8,"
|
||||
(js/encodeURIComponent raw-html-str))]
|
||||
(if (util/electron?)
|
||||
(js/window.apis.exportPublishAssets raw-html-str)
|
||||
(js/window.apis.exportPublishAssets raw-html-str (config/get-custom-css-path))
|
||||
(when-let [anchor (gdom/getElement "download-as-html")]
|
||||
(.setAttribute anchor "href" html-str)
|
||||
(.setAttribute anchor "download" "index.html")
|
||||
@@ -106,8 +106,6 @@
|
||||
(.setAttribute anchor "download" (.-name zipfile))
|
||||
(.click anchor))))))
|
||||
|
||||
|
||||
|
||||
(defn- get-file-contents-with-suffix
|
||||
[repo]
|
||||
(let [conn (db/get-conn repo)]
|
||||
@@ -124,56 +122,60 @@
|
||||
[?e2 :block/original-name ?n2]] conn path)
|
||||
:format (f/get-format path)})))))
|
||||
|
||||
(defn- get-embed-and-refs-blocks-pages-aux
|
||||
[repo page-or-block is-block? exclude-blocks exclude-pages]
|
||||
(let [[ref-blocks ref-pages]
|
||||
(->> (if is-block?
|
||||
[page-or-block]
|
||||
(db/get-page-blocks
|
||||
repo page-or-block {:use-cache? false
|
||||
:pull-keys '[:block/refs]}))
|
||||
(filterv :block/refs)
|
||||
(mapv (fn [b] [(:block/ref-blocks b), (:block/ref-pages b)]))
|
||||
(apply mapv vector)
|
||||
(mapv #(vec (distinct (flatten (remove nil? %))))))
|
||||
ref-block-ids
|
||||
(->> ref-blocks
|
||||
(#(remove (fn [b] (contains? exclude-blocks (:db/id b))) %))
|
||||
(mapv #(:db/id %)))
|
||||
ref-page-ids
|
||||
(->> ref-pages
|
||||
(#(remove (fn [b] (contains? exclude-pages (:db/id b))) %))
|
||||
(mapv #(:db/id %)))
|
||||
ref-blocks
|
||||
(->> ref-block-ids
|
||||
(db/pull-many repo '[*])
|
||||
(flatten))
|
||||
ref-pages
|
||||
(->> ref-page-ids
|
||||
(db/pull-many repo '[*])
|
||||
(flatten))
|
||||
[next-ref-blocks1 next-ref-pages1]
|
||||
(->> ref-blocks
|
||||
(mapv #(get-embed-and-refs-blocks-pages-aux repo % true
|
||||
(set (concat ref-block-ids exclude-blocks)) exclude-pages))
|
||||
(apply mapv vector))
|
||||
[next-ref-blocks2 next-ref-pages2]
|
||||
(->> ref-pages
|
||||
(mapv #(get-embed-and-refs-blocks-pages-aux repo (:block/name %) false
|
||||
exclude-blocks (set (concat ref-page-ids exclude-pages))))
|
||||
(apply mapv vector))]
|
||||
[(->> (concat ref-block-ids next-ref-blocks1 next-ref-blocks2)
|
||||
(flatten)
|
||||
(distinct))
|
||||
(->> (concat ref-page-ids next-ref-pages1 next-ref-pages2)
|
||||
(flatten)
|
||||
(distinct))]))
|
||||
(defn- get-embed-and-refs-blocks-pages-aux []
|
||||
(let [mem (atom {})]
|
||||
(letfn [(f [repo page-or-block is-block? exclude-blocks exclude-pages]
|
||||
(let [v (get @mem [repo page-or-block])]
|
||||
(if v v
|
||||
(let [[ref-blocks ref-pages]
|
||||
(->> (if is-block?
|
||||
[page-or-block]
|
||||
(db/get-page-blocks
|
||||
repo page-or-block {:use-cache? false
|
||||
:pull-keys '[:block/refs]}))
|
||||
(filterv :block/refs)
|
||||
(apply mapv vector)
|
||||
(mapv #(vec (distinct (flatten (remove nil? %))))))
|
||||
ref-block-ids
|
||||
(->> ref-blocks
|
||||
(#(remove (fn [b] (contains? exclude-blocks (:db/id b))) %))
|
||||
(mapv #(:db/id %)))
|
||||
ref-page-ids
|
||||
(->> ref-pages
|
||||
(#(remove (fn [b] (contains? exclude-pages (:db/id b))) %))
|
||||
(mapv #(:db/id %)))
|
||||
ref-blocks
|
||||
(->> ref-block-ids
|
||||
(db/pull-many repo '[*])
|
||||
(flatten))
|
||||
ref-pages
|
||||
(->> ref-page-ids
|
||||
(db/pull-many repo '[*])
|
||||
(flatten))
|
||||
[next-ref-blocks1 next-ref-pages1]
|
||||
(->> ref-blocks
|
||||
(mapv #(f repo % true (set (concat ref-block-ids exclude-blocks)) exclude-pages))
|
||||
(apply mapv vector))
|
||||
[next-ref-blocks2 next-ref-pages2]
|
||||
(->> ref-pages
|
||||
(mapv #(f repo (:block/name %) false exclude-blocks (set (concat ref-page-ids exclude-pages))))
|
||||
(apply mapv vector))
|
||||
result
|
||||
[(->> (concat ref-block-ids next-ref-blocks1 next-ref-blocks2)
|
||||
(flatten)
|
||||
(distinct))
|
||||
(->> (concat ref-page-ids next-ref-pages1 next-ref-pages2)
|
||||
(flatten)
|
||||
(distinct))]]
|
||||
(when (and (empty? exclude-blocks) (empty? exclude-pages))
|
||||
(swap! mem assoc [repo page-or-block] result))
|
||||
result))))]
|
||||
f)))
|
||||
|
||||
|
||||
(defn- get-embed-and-refs-blocks-pages
|
||||
[repo page]
|
||||
(defn- get-page&block-refs-by-query
|
||||
[repo page get-page&block-refs-by-query-aux]
|
||||
(let [[block-ids page-ids]
|
||||
(get-embed-and-refs-blocks-pages-aux repo page false #{} #{})
|
||||
(get-page&block-refs-by-query-aux repo page false #{} #{})
|
||||
blocks
|
||||
(db/pull-many repo '[*] block-ids)
|
||||
pages-name-and-content
|
||||
@@ -185,9 +187,9 @@
|
||||
[?e :block/name ?n]
|
||||
[?e :block/original-name ?n2]] (db/get-conn repo))
|
||||
(mapv (fn [[name origin-name file-path]]
|
||||
(if (= name origin-name)
|
||||
[[name file-path]]
|
||||
[[name file-path] [origin-name file-path]])))
|
||||
(if (= name origin-name)
|
||||
[[name file-path]]
|
||||
[[name file-path] [origin-name file-path]])))
|
||||
(apply concat)
|
||||
(mapv (fn [[page-name file-path]] [page-name (:file/path file-path)]))
|
||||
(d/q '[:find ?n ?c
|
||||
@@ -205,16 +207,169 @@
|
||||
{:embed_blocks embed-blocks
|
||||
:embed_pages pages-name-and-content}))
|
||||
|
||||
(defn- page&block-refs
|
||||
[repo]
|
||||
(let [block-refs
|
||||
(->>
|
||||
(d/q '[:find ?pn ?pon ?bt ?bc ?bid ?e ?rb
|
||||
:where
|
||||
[?e :block/refs ?rb]
|
||||
[?e :block/page ?p]
|
||||
[?p :block/name ?pn]
|
||||
[?p :block/original-name ?pon]
|
||||
[?rb :block/title ?bt]
|
||||
[?rb :block/content ?bc]
|
||||
[?rb :block/uuid ?bid]] (db/get-conn repo)))
|
||||
page-block-refs
|
||||
(->> block-refs
|
||||
(mapv (fn [[pn pon bt bc bid _ rb]]
|
||||
(if (= pn pon)
|
||||
[[pn bt bc bid rb]]
|
||||
[[pn bt bc bid rb] [pon bt bc bid rb]])))
|
||||
(apply concat)
|
||||
(reduce (fn [r [k & v]] (assoc r k (cons v (get r k)))) {})
|
||||
(mapv (fn [[k v]] [k (distinct v)]))
|
||||
(into {}))
|
||||
block-block-refs
|
||||
(->> block-refs
|
||||
(mapv (fn [[_ _ bt bc bid e rb]] [e bt bc bid rb]))
|
||||
(reduce (fn [r [k & v]] (assoc r k (cons v (get r k)))) {})
|
||||
(mapv (fn [[k v]] [k (distinct v)]))
|
||||
(into {}))
|
||||
page-refs
|
||||
(->> (d/q '[:find ?pn ?pon ?rpn ?rpon ?fp ?e
|
||||
:where
|
||||
[?e :block/refs ?rp]
|
||||
[?e :block/page ?p]
|
||||
[?p :block/name ?pn]
|
||||
[?p :block/original-name ?pon]
|
||||
[?rp :block/name ?rpn]
|
||||
[?rp :block/original-name ?rpon]
|
||||
[?rp :block/file ?pf]
|
||||
[?pf :file/path ?fp]] (db/get-conn repo))
|
||||
(d/q '[:find ?pn ?pon ?rpn ?rpon ?fc ?be
|
||||
:in $ [[?pn ?pon ?rpn ?rpon ?fp ?be] ...]
|
||||
:where
|
||||
[?e :file/path ?fp]
|
||||
[?e :file/content ?fc]] @(db/get-files-conn repo)))
|
||||
page-page-refs
|
||||
(->>
|
||||
page-refs
|
||||
(mapv (fn [[pn pon rpn rpon fc _]]
|
||||
(case [(= pn pon) (= rpn rpon)]
|
||||
[true true] [[pn rpn fc]]
|
||||
[true false] [[pn rpn fc] [pn rpon fc]]
|
||||
[false true] [[pn rpn fc] [pon rpn fc]]
|
||||
[false false] [[pn rpn fc] [pn rpon fc] [pon rpn fc] [pon rpon fc]])))
|
||||
(apply concat)
|
||||
(reduce (fn [r [k & v]] (assoc r k (cons v (get r k)))) {})
|
||||
(mapv (fn [[k v]] [k (distinct v)]))
|
||||
(into {}))
|
||||
block-page-refs
|
||||
(->>
|
||||
page-refs
|
||||
(mapv (fn [[pn pon rpn rpon fc e]]
|
||||
(if (= rpn rpon) [[e rpn fc]] [[e rpn fc] [e rpon fc]])))
|
||||
(apply concat)
|
||||
(reduce (fn [r [k & v]] (assoc r k (cons v (get r k)))) {})
|
||||
(mapv (fn [[k v]] [k (distinct v)]))
|
||||
(into {}))]
|
||||
[page-block-refs page-page-refs block-block-refs block-page-refs]))
|
||||
|
||||
(defn- get-page&block-refs-aux
|
||||
[repo page-or-block-id is-block-id? page&block-refs exclude-blocks exclude-pages]
|
||||
(let [[page-block-refs page-page-refs block-block-refs block-page-refs] page&block-refs]
|
||||
(if is-block-id?
|
||||
(when (not (contains? exclude-blocks page-or-block-id))
|
||||
(let [block-refs (get block-block-refs page-or-block-id)
|
||||
block-ref-ids (->>
|
||||
(mapv (fn [[_ _ _ rb]] rb) block-refs)
|
||||
(remove #(contains? exclude-blocks %)))
|
||||
page-refs (get block-page-refs page-or-block-id)
|
||||
page-ref-names (->>
|
||||
(mapv (fn [[rpn _]] rpn) page-refs)
|
||||
(remove #(contains? exclude-pages %)))
|
||||
[other-block-refs1 other-page-refs1]
|
||||
(->>
|
||||
(mapv
|
||||
#(get-page&block-refs-aux repo % true
|
||||
page&block-refs
|
||||
(conj exclude-blocks %)
|
||||
exclude-pages)
|
||||
block-ref-ids)
|
||||
(apply mapv vector))
|
||||
[other-block-refs2 other-page-refs2]
|
||||
(->>
|
||||
(mapv
|
||||
#(get-page&block-refs-aux repo % false
|
||||
page&block-refs
|
||||
exclude-blocks
|
||||
(conj exclude-pages %))
|
||||
page-ref-names)
|
||||
(apply mapv vector))
|
||||
block-refs* (apply concat (concat other-block-refs1 other-block-refs2 [block-refs]))
|
||||
page-refs* (apply concat (concat other-page-refs1 other-page-refs2 [page-refs]))]
|
||||
[block-refs* page-refs*]))
|
||||
(when (not (contains? exclude-pages page-or-block-id))
|
||||
(let [block-refs (get page-block-refs page-or-block-id)
|
||||
block-ref-ids (->>
|
||||
(mapv (fn [[_ _ _ rb]] rb) block-refs)
|
||||
(remove #(contains? exclude-blocks %)))
|
||||
page-refs (get page-page-refs page-or-block-id)
|
||||
page-ref-names (->>
|
||||
(mapv (fn [[rpn _]] rpn) page-refs)
|
||||
(remove #(contains? exclude-pages %)))
|
||||
[other-block-refs1 other-page-refs1]
|
||||
(->>
|
||||
(mapv
|
||||
#(get-page&block-refs-aux repo % true
|
||||
page&block-refs
|
||||
(conj exclude-blocks %)
|
||||
exclude-pages)
|
||||
block-ref-ids)
|
||||
(apply mapv vector))
|
||||
[other-block-refs2 other-page-refs2]
|
||||
(->>
|
||||
(mapv
|
||||
#(get-page&block-refs-aux repo % false
|
||||
page&block-refs
|
||||
exclude-blocks
|
||||
(conj exclude-pages %))
|
||||
page-ref-names)
|
||||
(apply mapv vector))
|
||||
block-refs* (apply concat (concat other-block-refs1 other-block-refs2 [block-refs]))
|
||||
page-refs* (apply concat (concat other-page-refs1 other-page-refs2 [page-refs]))]
|
||||
[block-refs* page-refs*])))))
|
||||
|
||||
(defn- get-page&block-refs
|
||||
[repo page page&block-refs]
|
||||
(let [[block-refs page-refs]
|
||||
(get-page&block-refs-aux repo page false page&block-refs #{} #{})]
|
||||
{:embed_blocks
|
||||
(mapv (fn [[title _content uuid id]]
|
||||
[(str uuid)
|
||||
[(apply str
|
||||
(mapv #(:block/content %)
|
||||
(db/get-block-and-children repo uuid)))
|
||||
title]])
|
||||
block-refs)
|
||||
:embed_pages (vec page-refs)}))
|
||||
|
||||
(defn- export-files-as-markdown
|
||||
[repo files heading-to-list?]
|
||||
(->> files
|
||||
(mapv (fn [{:keys [path content names format]}]
|
||||
(when (first names)
|
||||
[path (fp/exportMarkdown f/mldoc-record content
|
||||
(f/get-default-config format heading-to-list?)
|
||||
(js/JSON.stringify
|
||||
(clj->js (get-embed-and-refs-blocks-pages repo (first names)))))])))
|
||||
(remove nil?)))
|
||||
(let [get-page&block-refs-by-query-aux (get-embed-and-refs-blocks-pages-aux)
|
||||
f (if (< (count files) 30) ;query db for per page if (< (count files) 30), or pre-compute whole graph's page&block-refs
|
||||
#(get-page&block-refs-by-query repo % get-page&block-refs-by-query-aux)
|
||||
(let [page&block-refs (page&block-refs repo)]
|
||||
#(get-page&block-refs repo % page&block-refs)))]
|
||||
(->> files
|
||||
(mapv (fn [{:keys [path content names format]}]
|
||||
(when (first names)
|
||||
[path (fp/exportMarkdown f/mldoc-record content
|
||||
(f/get-default-config format heading-to-list?)
|
||||
(js/JSON.stringify
|
||||
(clj->js (f (first names)))))])))
|
||||
(remove nil?))))
|
||||
|
||||
(defn export-repo-as-markdown!
|
||||
[repo]
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
[frontend.util :as util]
|
||||
[frontend.date :as date]
|
||||
[frontend.state :as state]
|
||||
[clojure.set :as set]))
|
||||
[clojure.set :as set]
|
||||
[medley.core :as medley]))
|
||||
|
||||
(defn- build-edges
|
||||
[edges]
|
||||
@@ -27,17 +28,21 @@
|
||||
(->>
|
||||
(mapv (fn [p]
|
||||
(when p
|
||||
(let [current-page? (= p current-page)
|
||||
color (case [dark? current-page?] ; FIXME: Put it into CSS
|
||||
[false false] "#222222"
|
||||
[false true] "#045591"
|
||||
[true false] "#8abbbb"
|
||||
[true true] "#ffffff")
|
||||
(let [p (str p)
|
||||
current-page? (= p current-page)
|
||||
block? (and p (util/uuid-string? p))
|
||||
color (if block?
|
||||
"#1a6376"
|
||||
(case [dark? current-page?] ; FIXME: Put it into CSS
|
||||
[false false] "#222222"
|
||||
[false true] "#045591"
|
||||
[true false] "#8abbbb"
|
||||
[true true] "#ffffff"))
|
||||
color (if (contains? tags (string/lower-case (str p)))
|
||||
(if dark? "orange" "green")
|
||||
color)]
|
||||
{:id p
|
||||
:name p
|
||||
:name name
|
||||
:val (get-connections p edges)
|
||||
:autoColorBy "group"
|
||||
:group (js/Math.ceil (* (js/Math.random) 12))
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
(defn- get-file-name
|
||||
[journal? title]
|
||||
(when-let [s (if journal?
|
||||
(date/journal-title->default title)
|
||||
(util/page-name-sanity (string/lower-case title)))]
|
||||
(date/journal-title->default title)
|
||||
(util/page-name-sanity (string/lower-case title)))]
|
||||
;; Win10 file path has a length limit of 260 chars
|
||||
(util/safe-subs s 0 200)))
|
||||
|
||||
@@ -102,9 +102,12 @@
|
||||
file (db/entity (:db/id (:block/file page)))
|
||||
file-path (:file/path file)
|
||||
file-content (db/get-file file-path)
|
||||
after-content (if (empty? properties-content)
|
||||
after-content (if (string/blank? properties-content)
|
||||
file-content
|
||||
(subs file-content (inc (count properties-content))))
|
||||
properties-content (if properties-content
|
||||
(string/trim properties-content)
|
||||
(config/properties-wrapper page-format))
|
||||
new-properties-content (db/add-properties! page-format properties-content properties)
|
||||
full-content (str new-properties-content "\n\n" (string/trim after-content))]
|
||||
(file-handler/alter-file (state/get-current-repo)
|
||||
@@ -339,50 +342,55 @@
|
||||
|
||||
(defn rename!
|
||||
[old-name new-name]
|
||||
(when (and old-name new-name
|
||||
(not= (string/lower-case old-name) (string/lower-case new-name)))
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(if (db/entity [:block/name (string/lower-case new-name)])
|
||||
(notification/show! "Page already exists!" :error)
|
||||
(when-let [page (db/entity [:block/name (string/lower-case old-name)])]
|
||||
(let [old-original-name (:block/original-name page)
|
||||
file (:block/file page)
|
||||
journal? (:block/journal? page)]
|
||||
(d/transact! (db/get-conn repo false)
|
||||
[{:db/id (:db/id page)
|
||||
:block/name (string/lower-case new-name)
|
||||
:block/original-name new-name}])
|
||||
(let [new-name (string/trim new-name)]
|
||||
(when-not (string/blank? new-name)
|
||||
(when (and old-name new-name)
|
||||
(let [case-changed? (and (= (string/lower-case old-name)
|
||||
(string/lower-case new-name))
|
||||
(not= (string/trim old-name)
|
||||
(string/trim new-name)))
|
||||
name-changed? (not= (string/lower-case (string/trim old-name))
|
||||
(string/lower-case (string/trim new-name)))]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [page (db/entity [:block/name (string/lower-case old-name)])]
|
||||
(let [old-original-name (:block/original-name page)
|
||||
file (:block/file page)
|
||||
journal? (:block/journal? page)]
|
||||
(d/transact! (db/get-conn repo false)
|
||||
[{:db/id (:db/id page)
|
||||
:block/name (string/lower-case new-name)
|
||||
:block/original-name new-name}])
|
||||
|
||||
(when (and file (not journal?))
|
||||
(rename-file! file new-name
|
||||
(fn []
|
||||
(page-add-properties! (string/lower-case new-name) {:title new-name}))))
|
||||
(when (and file (not journal?) name-changed?)
|
||||
(rename-file! file new-name
|
||||
(fn []
|
||||
(page-add-properties! (string/lower-case new-name) {:title new-name}))))
|
||||
|
||||
;; update all files which have references to this page
|
||||
(let [files (db/get-files-that-referenced-page (:db/id page))]
|
||||
(doseq [file-path files]
|
||||
(let [file-content (db/get-file file-path)
|
||||
;; FIXME: not safe
|
||||
new-content (string/replace file-content
|
||||
(util/format "[[%s]]" old-original-name)
|
||||
(util/format "[[%s]]" new-name))]
|
||||
(file-handler/alter-file repo
|
||||
file-path
|
||||
new-content
|
||||
{:reset? true
|
||||
:re-render-root? false})))))
|
||||
;; update all files which have references to this page
|
||||
(let [files (db/get-files-that-referenced-page (:db/id page))]
|
||||
(doseq [file-path files]
|
||||
(let [file-content (db/get-file file-path)
|
||||
;; FIXME: not safe
|
||||
new-content (string/replace file-content
|
||||
(util/format "[[%s]]" old-original-name)
|
||||
(util/format "[[%s]]" new-name))]
|
||||
(file-handler/alter-file repo
|
||||
file-path
|
||||
new-content
|
||||
{:reset? true
|
||||
:re-render-root? false})))))
|
||||
|
||||
;; TODO: update browser history, remove the current one
|
||||
;; TODO: update browser history, remove the current one
|
||||
|
||||
;; Redirect to the new page
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name (string/lower-case new-name)}})
|
||||
;; Redirect to the new page
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name (string/lower-case new-name)}})
|
||||
|
||||
(notification/show! "Page renamed successfully!" :success)
|
||||
(notification/show! "Page renamed successfully!" :success)
|
||||
|
||||
(repo-handler/push-if-auto-enabled! repo)
|
||||
(repo-handler/push-if-auto-enabled! repo)
|
||||
|
||||
(ui-handler/re-render-root!))))))
|
||||
(ui-handler/re-render-root!))))))))
|
||||
|
||||
(defn rename-when-alter-title-property!
|
||||
[page path format original-content content]
|
||||
@@ -422,11 +430,15 @@
|
||||
:new-level 2
|
||||
:current-page "Contents"})))
|
||||
|
||||
(defn load-more-journals!
|
||||
(defn has-more-journals?
|
||||
[]
|
||||
(let [current-length (:journals-length @state/state)]
|
||||
(when (< current-length (db/get-journals-length))
|
||||
(state/update-state! :journals-length inc))))
|
||||
(< current-length (db/get-journals-length))))
|
||||
|
||||
(defn load-more-journals!
|
||||
[]
|
||||
(when (has-more-journals?)
|
||||
(state/update-state! :journals-length inc)))
|
||||
|
||||
(defn update-public-attribute!
|
||||
[page-name value]
|
||||
@@ -514,8 +526,8 @@
|
||||
(defn ls-dir-files!
|
||||
[]
|
||||
(web-nfs/ls-dir-files-with-handler!
|
||||
(fn []
|
||||
(init-commands!))))
|
||||
(fn []
|
||||
(init-commands!))))
|
||||
|
||||
|
||||
;; TODO: add use :file/last-modified-at
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
|
||||
(defn go-to-journals!
|
||||
[]
|
||||
(state/set-journals-length! 1)
|
||||
(state/set-journals-length! 2)
|
||||
(let [route (if (state/custom-home-page?)
|
||||
:all-journals
|
||||
:home)]
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
:draw? false
|
||||
:db/restoring? nil
|
||||
|
||||
:journals-length 1
|
||||
:journals-length 2
|
||||
|
||||
:search/q ""
|
||||
:search/result nil
|
||||
@@ -57,7 +57,6 @@
|
||||
:ui/wide-mode? false
|
||||
;; :show-all, :hide-block-body, :hide-block-children
|
||||
:ui/cycle-collapse :show-all
|
||||
:ui/collapsed-blocks {}
|
||||
:ui/sidebar-collapsed-blocks {}
|
||||
:ui/root-component nil
|
||||
:ui/file-component nil
|
||||
@@ -188,6 +187,11 @@
|
||||
(true? (:feature/enable-grammarly?
|
||||
(get (sub-config) (get-current-repo)))))
|
||||
|
||||
(defn scheduled-deadlines-disabled?
|
||||
[]
|
||||
(true? (:feature/disable-scheduled-and-deadline-query?
|
||||
(get (sub-config) (get-current-repo)))))
|
||||
|
||||
(defn enable-timetracking?
|
||||
[]
|
||||
(not (false? (:feature/enable-timetracking?
|
||||
@@ -392,6 +396,11 @@
|
||||
[]
|
||||
(ffirst (:editor/editing? @state)))
|
||||
|
||||
(defn get-input
|
||||
[]
|
||||
(when-let [id (get-edit-input-id)]
|
||||
(gdom/getElement id)))
|
||||
|
||||
(defn get-last-edit-input-id
|
||||
[]
|
||||
(:editor/last-edit-block-id @state))
|
||||
@@ -427,39 +436,10 @@
|
||||
[range]
|
||||
(set-state! :cursor-range range))
|
||||
|
||||
; FIXME: unused function
|
||||
(defn get-cloning?
|
||||
[]
|
||||
(:repo/cloning? @state))
|
||||
|
||||
(defn set-cloning!
|
||||
[value]
|
||||
(set-state! :repo/cloning? value))
|
||||
|
||||
(defn get-block-collapsed-state
|
||||
[block-id]
|
||||
(get-in @state [:ui/collapsed-blocks block-id]))
|
||||
|
||||
(defn set-collapsed-state!
|
||||
[block-id value]
|
||||
(set-state! [:ui/collapsed-blocks block-id] value))
|
||||
|
||||
(defn collapse-block!
|
||||
[block-id]
|
||||
(set-collapsed-state! block-id true))
|
||||
|
||||
(defn expand-block!
|
||||
[block-id]
|
||||
(set-collapsed-state! block-id false))
|
||||
|
||||
(defn collapsed?
|
||||
[block-id]
|
||||
(get-in @state [:ui/collapsed-blocks block-id]))
|
||||
|
||||
(defn clear-collapsed-blocks!
|
||||
[]
|
||||
(set-state! :ui/collapsed-blocks {}))
|
||||
|
||||
(defn set-q!
|
||||
[value]
|
||||
(set-state! :search/q value))
|
||||
@@ -1026,6 +1006,11 @@
|
||||
[]
|
||||
(:commands (get-config)))
|
||||
|
||||
(defn get-scheduled-future-days
|
||||
[]
|
||||
(let [days (:scheduled/future-days (get-config))]
|
||||
(or (when (int? days) days) 0)))
|
||||
|
||||
(defn set-graph-syncing?
|
||||
[value]
|
||||
(set-state! :graph/syncing? value))
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
(string/starts-with? s "[[")
|
||||
(string/ends-with? s "]]")))
|
||||
|
||||
(defn block-ref?
|
||||
[s]
|
||||
(and
|
||||
(string? s)
|
||||
(string/starts-with? s "((")
|
||||
(string/ends-with? s "))")))
|
||||
|
||||
(defonce page-ref-re #"\[\[(.*?)\]\]")
|
||||
|
||||
(defonce page-ref-re-2 #"(\[\[.*?\]\])")
|
||||
@@ -24,6 +31,13 @@
|
||||
(subs s 2 (- (count s) 2))
|
||||
s)))
|
||||
|
||||
(defn block-ref-un-brackets!
|
||||
[s]
|
||||
(when (string? s)
|
||||
(if (block-ref? s)
|
||||
(subs s 2 (- (count s) 2))
|
||||
s)))
|
||||
|
||||
;; E.g "Foo Bar"
|
||||
(defn sep-by-comma
|
||||
[s]
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
[:div {:style {:margin-right "8px"}} title]
|
||||
;; [:div {:style {:position "absolute" :right "8px"}}
|
||||
;; icon]
|
||||
]]
|
||||
]]
|
||||
(rum/with-key
|
||||
(menu-link new-options child)
|
||||
title)))
|
||||
@@ -280,7 +280,6 @@
|
||||
(.removeEventListener viewport "resize" handler)
|
||||
(.removeEventListener viewport "scroll" handler)))))
|
||||
|
||||
;; FIXME: compute the right scroll position when scrolling back to the top
|
||||
(defn on-scroll
|
||||
[on-load on-top-reached]
|
||||
(let [node js/document.documentElement
|
||||
@@ -306,9 +305,15 @@
|
||||
(rum/defcs infinite-list <
|
||||
(mixins/event-mixin attach-listeners)
|
||||
"Render an infinite list."
|
||||
[state body {:keys [on-load on-top-reached]
|
||||
:as opts}]
|
||||
body)
|
||||
[state body {:keys [on-load has-more]}]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
(rum/fragment
|
||||
body
|
||||
[:a.fade-link.text-link.font-bold.text-4xl
|
||||
{:on-click on-load
|
||||
:disabled (not has-more)
|
||||
:class (when (not has-more) "cursor-not-allowed ")}
|
||||
(t (if has-more :page/earlier :page/no-more-journals))])))
|
||||
|
||||
(rum/defcs auto-complete <
|
||||
(rum/local 0 ::current-idx)
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
|
||||
input[type=checkbox] {
|
||||
input[type='checkbox'] {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@
|
||||
focus:outline-none transition ease-in-out duration-150 mt-1;
|
||||
|
||||
&:disabled {
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&.is-link {
|
||||
@@ -134,7 +134,7 @@
|
||||
width: 0;
|
||||
height: 0;
|
||||
vertical-align: middle;
|
||||
content: "";
|
||||
content: '';
|
||||
border-top-style: solid;
|
||||
border-top-width: 4px;
|
||||
border-right: 4px solid transparent;
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#?(:cljs
|
||||
(defn ios?
|
||||
[]
|
||||
(not (nil? (re-find #"iPad|iPhone|iPod" js/navigator.userAgent)))))
|
||||
(utils/ios)))
|
||||
|
||||
#?(:cljs
|
||||
(defn safari?
|
||||
@@ -610,11 +610,15 @@
|
||||
(when-let [first-index (string/index-of s pattern)]
|
||||
(str new-value (subs s (+ first-index (count pattern))))))
|
||||
|
||||
(defn replace-last [pattern s new-value]
|
||||
(when-let [last-index (string/last-index-of s pattern)]
|
||||
(concat-without-spaces
|
||||
(subs s 0 last-index)
|
||||
new-value)))
|
||||
(defn replace-last
|
||||
([pattern s new-value]
|
||||
(replace-last pattern s new-value true))
|
||||
([pattern s new-value space?]
|
||||
(when-let [last-index (string/last-index-of s pattern)]
|
||||
(let [prefix (subs s 0 last-index)]
|
||||
(if space?
|
||||
(concat-without-spaces prefix new-value)
|
||||
(str prefix new-value))))))
|
||||
|
||||
;; copy from https://stackoverflow.com/questions/18735665/how-can-i-get-the-positions-of-regex-matches-in-clojurescript
|
||||
#?(:cljs
|
||||
@@ -763,6 +767,12 @@
|
||||
(= (count (.-value input))
|
||||
(.-selectionStart input)))))
|
||||
|
||||
#?(:cljs
|
||||
(defn input-selected?
|
||||
[input]
|
||||
(not= (.-selectionStart input)
|
||||
(.-selectionEnd input))))
|
||||
|
||||
#?(:cljs
|
||||
(defn get-selected-text
|
||||
[]
|
||||
@@ -1052,7 +1062,7 @@
|
||||
(when (some? style)
|
||||
(let [parent-node (d/sel1 :head)
|
||||
id "logseq-custom-theme-id"
|
||||
old-link-element (d/sel1 id)
|
||||
old-link-element (d/sel1 (str "#" id))
|
||||
style (if (string/starts-with? style "http")
|
||||
style
|
||||
(str "data:text/css;charset=utf-8," (js/encodeURIComponent style)))]
|
||||
|
||||
@@ -204,3 +204,16 @@ export const win32 = path => {
|
||||
// UNC paths are always absolute
|
||||
return Boolean(result[2] || isUnc);
|
||||
};
|
||||
|
||||
export const ios = function () {
|
||||
return [
|
||||
'iPad Simulator',
|
||||
'iPhone Simulator',
|
||||
'iPod Simulator',
|
||||
'iPad',
|
||||
'iPhone',
|
||||
'iPod'
|
||||
].includes(navigator.platform)
|
||||
// iPad on iOS 13 detection
|
||||
|| (navigator.userAgent.includes("Mac") && "ontouchend" in document)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
(ns frontend.version)
|
||||
|
||||
(defonce version "0.0.13-1")
|
||||
(defonce version "0.0.17")
|
||||
|
||||
Reference in New Issue
Block a user