Merge branch 'master' into feat/pdf

pull/2471/head
charlie 2021-08-04 09:46:54 +08:00
commit 9cf94a66a4
14 changed files with 204 additions and 156 deletions

View File

@ -1,6 +1,6 @@
{
"name": "Logseq",
"version": "0.3.0",
"version": "0.3.1",
"main": "electron.js",
"author": "Logseq",
"description": "A privacy-first, open-source platform for knowledge management and collaboration.",

View File

@ -381,25 +381,11 @@
(let [s (get page-entity :block/original-name page-name)]
(if tag? (str "#" s) s))))]))
(defn- use-delayed-open [open? page-name]
"A react hook to debounce open? value.
If open? changed from false to open, there will be a `timeout` delay.
Otherwise, the value will be changed to false immediately"
(let [[deval set-deval!] (rum/use-state nil)]
(rum/use-effect!
(fn []
(if open? (let [timer (js/setTimeout #(set-deval! open?) 1000)]
#(js/clearTimeout timer))
(set-deval! open?))) ;; immediately change
[open? page-name])
deval))
(rum/defc page-preview-trigger
[{:keys [children sidebar? tippy-position tippy-distance fixed-position? open? manual?] :as config} page-name]
(let [redirect-page-name (or (model/get-redirect-page-name page-name (:block/alias? config))
page-name)
page-original-name (model/get-page-original-name redirect-page-name)
debounced-open? (use-delayed-open open? page-name)
html-template (fn []
(when redirect-page-name
[:div.tippy-wrapper.overflow-y-auto.p-4
@ -427,7 +413,6 @@
(if (or (not manual?) open?)
(ui/tippy {:html html-template
:interactive true
:open? debounced-open?
:delay [1000, 100]
:fixed-position? fixed-position?
:position (or tippy-position "top")
@ -1249,7 +1234,7 @@
(when (and (coll? children)
(seq children)
(not collapsed?))
(let [doc-mode? (:document/mode? config)]
(let [doc-mode? (state/sub :document/mode?)]
[:div.block-children {:style {:margin-left (if doc-mode? 12 21)
:display (if collapsed? "none" "")}}
(for [child children]
@ -1265,8 +1250,9 @@
(:block/uuid child)))))]))))
(rum/defcs block-control < rum/reactive
[state config block uuid block-id body children collapsed? *ref-collapsed? *control-show? edit-input-id]
(let [has-children-blocks? (and (coll? children) (seq children))
[state config block uuid block-id body children collapsed? *ref-collapsed? *control-show? edit-input-id edit? doc-mode?]
(let [doc-mode? (state/sub :document/mode?)
has-children-blocks? (and (coll? children) (seq children))
has-child? (and
(not (:pre-block? block))
(or has-children-blocks? (seq body)))
@ -1282,8 +1268,7 @@
empty-content? (string/blank?
(property/remove-built-in-properties
(:block/format block)
(:block/content block)))
edit? (state/sub [:editor/editing? edit-input-id])]
(:block/content block)))]
[:div.mr-2.flex.flex-row.items-center
{:style {:height 24
:margin-top 0
@ -1304,25 +1289,37 @@
(editor-handler/collapse-block! uuid)))))}
[:span {:class (if control-show? "control-show" "control-hide")}
(ui/rotating-arrow collapsed?)]]
(if (and empty-content? (not edit?)
(not (:block/top? block))
(not (:block/bottom? block)))
[:span.bullet-container]
(let [bullet [:a {: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]
(bullet-drag-start event block uuid block-id))
:blockid (str uuid)
:class (str (when collapsed? "bullet-closed")
" "
(when (and (:document/mode? config)
(not collapsed?))
"hide-inner-bullet"))}
[:span.bullet {:blockid (str uuid)}]]]]
(cond
(and (:ui/show-empty-bullets? (state/get-config)) (not doc-mode?))
bullet
[:a {: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]
(bullet-drag-start event block uuid block-id))
:blockid (str uuid)
:class (str (when collapsed? "bullet-closed")
" "
(when (and (:document/mode? config)
(not collapsed?))
"hide-inner-bullet"))}
[:span.bullet {:blockid (str uuid)}]]])]))
(or
(and empty-content? (not edit?)
(not (:block/top? block))
(not (:block/bottom? block))
(not (util/react *control-show?)))
(and doc-mode?
(not collapsed?)
(not (util/react *control-show?))))
;; hidden
[:span.bullet-container]
:else
bullet))]))
(rum/defc dnd-separator
[block move-to block-content?]
@ -1731,9 +1728,8 @@
(str uuid "-" idx)))))])]]]))
(rum/defc block-content-or-editor < rum/reactive
[config {:block/keys [uuid title body meta content page format repo children marker properties pre-block? idx] :as block} edit-input-id block-id slide? heading-level]
[config {:block/keys [uuid title body meta content page format repo children marker properties pre-block? idx] :as block} edit-input-id block-id slide? heading-level edit?]
(let [editor-box (get config :editor-box)
edit? (state/sub [:editor/editing? edit-input-id])
editor-id (str "editor-" edit-input-id)
slide? (:slide? config)]
(if (and edit? editor-box)
@ -1888,8 +1884,7 @@
(defn- block-mouse-over
[e has-child? *control-show? block-id doc-mode?]
(util/stop e)
(when has-child?
(reset! *control-show? true))
(reset! *control-show? true)
(when-let [parent (gdom/getElement block-id)]
(let [node (.querySelector parent ".bullet-container")]
(when doc-mode?
@ -1903,8 +1898,7 @@
(defn- block-mouse-leave
[e has-child? *control-show? block-id doc-mode?]
(util/stop e)
(when has-child?
(reset! *control-show? false))
(reset! *control-show? false)
(when doc-mode?
(when-let [parent (gdom/getElement block-id)]
(when-let [node (.querySelector parent ".bullet-container")]
@ -1941,7 +1935,7 @@
;; :ref? true
;; :ref-child? true))]))))
(rum/defcs block-container < rum/static
(rum/defcs block-container < rum/reactive
{:init (fn [state]
(let [[config block] (:rum/args state)
ref-collpased? (boolean
@ -1955,12 +1949,14 @@
::control-show? (atom false)
::ref-collapsed? (atom ref-collpased?))))
:should-update (fn [old-state new-state]
(not= (:block/content (second (:rum/args old-state)))
(:block/content (second (:rum/args new-state)))))}
(let [compare-keys [:block/uuid :block/properties
:block/parent :block/left
:block/children :block/content]]
(not= (select-keys (second (:rum/args old-state)) compare-keys)
(select-keys (second (:rum/args new-state)) compare-keys))))}
[state config {:block/keys [uuid title body meta content page format repo children pre-block? top? properties refs path-refs heading-level level type idx] :as block}]
(let [blocks-container-id (:blocks-container-id config)
config (update config :block merge block)
;; Each block might have multiple queries, but we store only the first query's result
config (if (nil? (:query-result config))
(assoc config :query-result (atom nil))
@ -1986,7 +1982,8 @@
attrs (on-drag-and-mouse-attrs block uuid top? block-id *move-to has-child? *control-show? doc-mode?)
data-refs (build-refs-data-value block (remove (set refs) path-refs))
data-refs-self (build-refs-data-value block refs)
edit-input-id (str "edit-block-" blocks-container-id "-" uuid)]
edit-input-id (str "edit-block-" blocks-container-id "-" uuid)
edit? (state/sub [:editor/editing? edit-input-id])]
[:div.ls-block.flex.flex-col.rounded-sm
(cond->
{:id block-id
@ -2024,9 +2021,9 @@
:on-mouse-leave (fn [e]
(block-mouse-leave e has-child? *control-show? block-id doc-mode?))}
(when (not slide?)
(block-control config block uuid block-id body children collapsed? *ref-collapsed? *control-show? edit-input-id))
(block-control config block uuid block-id body children collapsed? *ref-collapsed? *control-show? edit-input-id edit? doc-mode?))
(block-content-or-editor config block edit-input-id block-id slide? heading-level)]
(block-content-or-editor config block edit-input-id block-id slide? heading-level edit?)]
(block-children config children collapsed? *ref-collapsed?)
@ -2558,9 +2555,8 @@
(assoc :block/top? (zero? idx)
:block/bottom? (= (count blocks) (inc idx))))
config (assoc config :block/uuid (:block/uuid item))]
(rum/with-key
(block-container config item)
(:block/uuid item)))))
(rum/with-key (block-container config item)
(str (:block/uuid item))))))
(defonce ignore-scroll? (atom false))
(rum/defcs lazy-blocks <

View File

@ -174,7 +174,6 @@
(when input
(let [current-pos (cursor/pos input)
edit-content (state/sub [:editor/content id])
edit-block (state/sub :editor/block)
q (or
(when (>= (count edit-content) current-pos)
(subs edit-content pos current-pos))
@ -184,7 +183,7 @@
(state/set-editor-show-template-search! false))]
(ui/auto-complete
matched-templates
{:on-chosen (editor-handler/template-on-chosen-handler input id q format edit-block edit-content)
{:on-chosen (editor-handler/template-on-chosen-handler id)
:on-enter non-exist-handler
:empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a template"]
:item-render (fn [[template _block-db-id]]

View File

@ -141,9 +141,14 @@
(rum/defc search-auto-complete
[{:keys [pages files blocks has-more?] :as result} search-q all?]
(rum/with-context [[t] i18n/*tongue-context*]
(let [pages (when-not all? (map (fn [page] {:type :page
:data page
:alias (model/get-redirect-page-name page)}) pages))
(let [pages (when-not all? (map (fn [page]
(let [alias (model/get-redirect-page-name page)]
(cond->
{:type :page
:data page}
(not= (string/lower-case page)
(string/lower-case alias))
(assoc :alias alias)))) pages))
files (when-not all? (map (fn [file] {:type :file :data file}) files))
blocks (map (fn [block] {:type :block :data block}) blocks)
search-mode (state/sub :search/mode)

View File

@ -1183,6 +1183,20 @@
[(get m :template) e]))
(into {}))))
(defn get-template-by-name
[name]
(when (string? name)
(->> (d/q
'[:find (pull ?b [*])
:in $ ?name
:where
[?b :block/properties ?p]
[(get ?p :template) ?t]
[(= ?t ?name)]]
(conn/get-conn)
name)
ffirst)))
(defonce blocks-count-cache (atom nil))
(defn blocks-count

View File

@ -390,9 +390,10 @@
(defn- compute-fst-snd-block-text
[value pos]
(let [fst-block-text (subs value 0 pos)
snd-block-text (string/triml (subs value pos))]
[fst-block-text snd-block-text]))
(when (string? value)
(let [fst-block-text (subs value 0 pos)
snd-block-text (string/triml (subs value pos))]
[fst-block-text snd-block-text])))
(defn outliner-insert-block!
[config current-block new-block sibling?]
@ -445,7 +446,8 @@
(:block/uuid first-block))
blocks-container-id (when-let [id (:id config)]
(and (util/uuid-string? id) (medley/uuid id)))]
(let [new-last-block (let [first-block-id {:db/id (:db/id first-block)}]
(let [new-last-block (let [first-block-uuid (:block/uuid (db/entity (:db/id first-block)))
first-block-id {:db/id (:db/id first-block)}]
(assoc last-block
:block/left first-block-id
:block/parent (if child?
@ -2017,42 +2019,43 @@
m)))))
(defn paste-block-vec-tree-at-target
([tree exclude-properties]
(paste-block-vec-tree-at-target tree exclude-properties nil nil nil))
([tree exclude-properties content-update-fn]
(paste-block-vec-tree-at-target tree exclude-properties content-update-fn nil nil))
([tree exclude-properties content-update-fn get-pos-fn page-block]
(let [repo (state/get-current-repo)
page (or page-block
(:block/page (db/entity (:db/id (state/get-edit-block)))))
file (:block/file page)]
(when-let [[target-block sibling? delete-editing-block? editing-block]
((or get-pos-fn get-block-tree-insert-pos-at-point))]
(let [target-block (outliner-core/block target-block)
editing-block (outliner-core/block editing-block)
format (or (:block/format target-block) (state/get-preferred-format))
new-block-uuids (atom #{})
metadata-replaced-blocks
(zip/root
(loop [loc (zip/vector-zip tree)]
(if (zip/end? loc)
loc
(if (vector? (zip/node loc))
(recur (zip/next loc))
(let [uuid (random-uuid)]
(swap! new-block-uuids (fn [acc uuid] (conj acc uuid)) uuid)
(recur (zip/next (zip/edit
loc
(paste-block-tree-at-point-edit-aux
uuid file page exclude-properties format content-update-fn)))))))))
_ (outliner-core/save-node editing-block)
_ (outliner-core/insert-nodes metadata-replaced-blocks target-block sibling?)
_ (when delete-editing-block?
(when-let [id (:db/id (outliner-core/get-data editing-block))]
(outliner-core/delete-node (outliner-core/block (db/pull id)) true)))
new-blocks (db/pull-many repo '[*] (map (fn [id] [:block/uuid id]) @new-block-uuids))]
(db/refresh! repo {:key :block/insert :data new-blocks})
(last metadata-replaced-blocks))))))
[tree exclude-properties {:keys [content-update-fn
get-pos-fn
page-block]
:as opts}]
(let [repo (state/get-current-repo)
page (or page-block
(:block/page (db/entity (:db/id (state/get-edit-block)))))
file (:block/file page)
[target-block sibling? delete-editing-block? editing-block]
((or get-pos-fn get-block-tree-insert-pos-at-point))]
(when target-block
(let [target-block (outliner-core/block target-block)
format (or (:block/format target-block) (state/get-preferred-format))
new-block-uuids (atom #{})
metadata-replaced-blocks
(zip/root
(loop [loc (zip/vector-zip tree)]
(if (zip/end? loc)
loc
(if (vector? (zip/node loc))
(recur (zip/next loc))
(let [uuid (random-uuid)]
(swap! new-block-uuids (fn [acc uuid] (conj acc uuid)) uuid)
(recur (zip/next (zip/edit
loc
(paste-block-tree-at-point-edit-aux
uuid file page exclude-properties format content-update-fn)))))))))
_ (when editing-block
(let [editing-block (outliner-core/block editing-block)]
(outliner-core/save-node editing-block)))
_ (outliner-core/insert-nodes metadata-replaced-blocks target-block sibling?)
_ (when (and delete-editing-block? editing-block)
(when-let [id (:db/id editing-block)]
(outliner-core/delete-node (outliner-core/block (db/pull id)) true)))
new-blocks (db/pull-many repo '[*] (map (fn [id] [:block/uuid id]) @new-block-uuids))]
(db/refresh! repo {:key :block/insert :data new-blocks})
(last metadata-replaced-blocks)))))
(defn- tree->vec-tree
"tree:
@ -2105,45 +2108,59 @@
page-block (if (:block/name target-block) target-block
(db/entity (:db/id (:block/page (db/pull target-block-id)))))
;; sibling? = false, when target-block is a page-block
sibling? (if (= target-block-id (:db/id page-block))
sibling? (if (= target-block-id (:db/id page-block))
false
sibling?)]
(paste-block-vec-tree-at-target
block-tree [] nil
#(get-block-tree-insert-pos-after-target target-block-id sibling?)
page-block)))
block-tree []
{:get-pos-fn #(get-block-tree-insert-pos-after-target target-block-id sibling?)
:page-block page-block})))
(defn insert-template!
([element-id db-id]
(insert-template! element-id db-id {}))
([element-id db-id opts]
(when-let [db-id (if (integer? db-id)
db-id
(:db/id (db-model/get-template-by-name (name db-id))))]
(let [repo (state/get-current-repo)
block (db/entity db-id)
format (:block/format block)
block-uuid (:block/uuid block)
template-including-parent? (not (false? (:template-including-parent (:block/properties block))))
blocks (if template-including-parent? (db/get-block-and-children repo block-uuid) (db/get-block-children repo block-uuid))
level-blocks (vals (blocks-with-level blocks))
grouped-blocks (group-by #(= db-id (:db/id %)) level-blocks)
root-block (or (first (get grouped-blocks true)) (assoc (db/pull db-id) :level 1))
blocks-exclude-root (get grouped-blocks false)
sorted-blocks (tree/sort-blocks blocks-exclude-root root-block)
result-blocks (if template-including-parent? sorted-blocks (drop 1 sorted-blocks))
tree (blocks-vec->tree result-blocks)]
(when element-id
(insert-command! element-id "" format {}))
(let [opts (merge
{:content-update-fn (fn [content]
(->> content
(property/remove-property format "template")
(property/remove-property format "template-including-parent")
template/resolve-dynamic-template!))}
opts)
last-block (paste-block-vec-tree-at-target tree [:id :template :template-including-parent] opts)]
(clear-when-saved!)
(db/refresh! repo {:key :block/insert :data [(db/pull db-id)]})
;; FIXME:
;; (js/setTimeout
;; #(edit-block! {:block/uuid (:block/uuid last-block)} :max nil (:block/uuid last-block))
;; 100)
)))
(when-let [input (gdom/getElement element-id)]
(.focus input))))
(defn template-on-chosen-handler
[_input id _q format _edit-block _edit-content]
[element-id]
(fn [[_template db-id] _click?]
(let [repo (state/get-current-repo)
block (db/entity db-id)
block-uuid (:block/uuid block)
template-including-parent? (not (false? (:template-including-parent (:block/properties block))))
blocks (if template-including-parent? (db/get-block-and-children repo block-uuid) (db/get-block-children repo block-uuid))
level-blocks (vals (blocks-with-level blocks))
grouped-blocks (group-by #(= db-id (:db/id %)) level-blocks)
root-block (or (first (get grouped-blocks true)) (assoc (db/pull db-id) :level 1))
blocks-exclude-root (get grouped-blocks false)
sorted-blocks (tree/sort-blocks blocks-exclude-root root-block)
result-blocks (if template-including-parent? sorted-blocks (drop 1 sorted-blocks))
tree (blocks-vec->tree result-blocks)]
(insert-command! id "" format {})
(let [last-block (paste-block-vec-tree-at-target tree [:template :template-including-parent]
(fn [content]
(->> content
(property/remove-property format "template")
(property/remove-property format "template-including-parent")
template/resolve-dynamic-template!)))]
(clear-when-saved!)
(db/refresh! repo {:key :block/insert :data [(db/pull db-id)]})
;; FIXME:
;; (js/setTimeout
;; #(edit-block! {:block/uuid (:block/uuid last-block)} :max nil (:block/uuid last-block))
;; 100)
))
(when-let [input (gdom/getElement id)]
(.focus input))))
(insert-template! element-id db-id)))
(defn parent-is-page?
[{{:block/keys [parent page]} :data :as node}]
@ -2674,7 +2691,7 @@
tree* (->> tree
(mapv #(assoc % :level (- (:block/level %) prefix-level)))
(blocks-vec->tree))]
(paste-block-vec-tree-at-target tree* [])))
(paste-block-vec-tree-at-target tree* [] nil)))
(defn- paste-segmented-text
[format text]
@ -2706,7 +2723,7 @@
(string/replace (string/trim (:copy/content copied-blocks)) "\r" "")))
(do
;; copy from logseq internally
(paste-block-vec-tree-at-target copied-block-tree [])
(paste-block-vec-tree-at-target copied-block-tree [] nil)
(util/stop e))
(do

View File

@ -85,8 +85,8 @@
[page-block false]))
tree (editor/blocks->tree-by-level parsed-blocks)]
(editor/paste-block-vec-tree-at-target
tree [] nil
#(editor/get-block-tree-insert-pos-after-target
(:db/id target-block) sibling?)
page-block)
tree []
{:get-pos-fn #(editor/get-block-tree-insert-pos-after-target
(:db/id target-block) sibling?)
:page-block page-block})
(finished-ok-handler [page-name])))))

View File

@ -79,9 +79,9 @@
:block/path-refs block-path-ref-pages))))
blocks)
page-entity (let [page-file? (= page (string/lower-case file))
aliases (and (:alias properties)
(seq (remove #(= page %)
(:alias properties))))
alias (:alias properties)
alias (if (string? alias) [alias] alias)
aliases (and alias (seq (remove #(= page %) alias)))
page-list (when-let [list-content (:list properties)]
(extract-page-list list-content))]
(cond->
@ -113,8 +113,9 @@
aliases))
(:tags properties)
(assoc :block/tags (let [tags (->> (:tags properties)
(remove string/blank?))]
(assoc :block/tags (let [tags (:tags properties)
tags (if (string? tags) [tags] tags)
tags (remove string/blank? tags)]
(swap! ref-tags set/union (set tags))
(map (fn [tag] {:block/name (string/lower-case tag)
:block/original-name tag})

View File

@ -585,7 +585,17 @@
(let [path (config/get-config-path)]
(db/get-file path))))
(let [title (date/today)
today-page (string/lower-case title)]
today-page (string/lower-case title)
template (state/get-default-journal-template)]
(when (db/page-empty? repo today-page)
(create! title {:redirect? false
:create-first-block? true}))))))
:create-first-block? (not template)})
(when template
(let [page (db/pull [:block/name today-page])]
(editor-handler/insert-template!
nil
template
{:get-pos-fn (fn []
[page false false false])
:page-block page})
(ui-handler/re-render-root!))))))))

View File

@ -20,7 +20,10 @@
(let [r (safe-pull db-before '[*] db-id)]
(when (= keys-of-deleted-entity (count r))
;; TODO: What can cause this happen?
(log/error :outliner-pipeline/cannot-find-entity {:entity r}))
(js/console.error {:db-id db-id
:entity r})
(log/error :outliner-pipeline/cannot-find-entity {:db-id db-id
:entity r}))
r)
r)))

View File

@ -223,6 +223,12 @@
[]
(:custom-css-url (get-config)))
(defn get-default-journal-template
[]
(when-let [template (get-in (get-config) [:default-templates :journals])]
(when-not (string/blank? template)
(string/trim template))))
(defn all-pages-public?
[]
(let [value (:publishing/all-pages-public? (get-config))

View File

@ -1,3 +1,3 @@
(ns frontend.version)
(defonce version "0.3.0")
(defonce version "0.3.1")

View File

@ -13,9 +13,8 @@
;; E.g. "/archived" "/test.md"
:hidden []
;; When creating the new journal page, the app will use your template content here.
;; Example for Markdown users: "[[Work]]\n -\n- [[Family]]\n -\n"
;; Example for Org mode users: "** [[Work]]\n***\n** [[Family]]\n***\n"
;; When creating the new journal page, the app will use your template if there is one.
;; You only need to input your template name here.
:default-templates
{:journals ""}
@ -96,6 +95,9 @@
;; Whether to show command doc on hover
:ui/show-command-doc? true
;; Whether to show empty bullets for non-document mode (the default mode)
:ui/show-empty-bullets? false
;; The app will show those queries in today's journal page,
;; the "NOW" query asks the tasks which need to be finished "now",
;; the "NEXT" query asks the future tasks.

View File

@ -7598,11 +7598,6 @@ react-grid-layout@^0.16.6:
react-draggable "3.x"
react-resizable "1.x"
react-icon-base@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-icon-base/-/react-icon-base-2.1.0.tgz#a196e33fdf1e7aaa1fda3aefbb68bdad9e82a79d"
integrity sha1-oZbjP98eeqof2jrvu2i9rZ6Cp50=
react-icons@^2.2.7:
version "2.2.7"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-2.2.7.tgz#d7860826b258557510dac10680abea5ca23cf650"