Merge branch 'master' into feat/outliner-core

This commit is contained in:
Tienson Qin
2021-04-05 09:53:18 +08:00
48 changed files with 1151 additions and 880 deletions

View File

@@ -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")

View File

@@ -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"

View File

@@ -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]

View File

@@ -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")]

View 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 |"))

View File

@@ -73,7 +73,7 @@
}
.resize {
display: flex;
display: inline-flex;
}
.draw [aria-labelledby="shapes-title"] {

View File

@@ -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

View File

@@ -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?

View File

@@ -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}]

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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]

View File

@@ -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)))}]

View File

@@ -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

View File

@@ -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")}

View File

@@ -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

View File

@@ -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"

View File

@@ -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]

View File

@@ -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)

View File

@@ -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"

View File

@@ -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")

View File

@@ -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;
}
}
}
}

View File

@@ -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"))]

View File

@@ -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]))

View File

@@ -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)))

View File

@@ -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)))

View File

@@ -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]

View File

@@ -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

View File

@@ -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]

View File

@@ -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))

View File

@@ -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

View File

@@ -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)]

View File

@@ -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))

View File

@@ -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]

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)))]

View File

@@ -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)
}

View File

@@ -1,3 +1,3 @@
(ns frontend.version)
(defonce version "0.0.13-1")
(defonce version "0.0.17")