diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 1d8f048d533..e5cf262bdb3 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -342,6 +342,7 @@ :href href :on-click (fn [e] (util/stop e) + (editor-handler/insert-first-page-block-if-not-exists! redirect-page-name) (if (gobj/get e "shiftKey") (when-let [page-entity (db/entity [:block/name redirect-page-name])] (state/sidebar-add-block! @@ -402,6 +403,7 @@ [:span.text-sm.mr-2 "Alias:" ] redirect-page-name])] (let [page (db/entity [:block/name (string/lower-case redirect-page-name)])] + (editor-handler/insert-first-page-block-if-not-exists! redirect-page-name) (when-let [f (state/get-page-blocks-cp)] (f (state/get-current-repo) page {:sidebar? sidebar? :preview? true})))] :interactive true diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index c454d42f478..5885950d08c 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -87,6 +87,17 @@ page-name)] (db/get-page-format page))) +(rum/defc dummy-block + [page-name] + [:div.ls-block.flex-1.flex-col.rounded-sm {:style {:width "100%"}} + [:div.flex.flex-row + [:div.flex.flex-row.items-center.mr-2.ml-1 {:style {:height 24}} + [:span.bullet-container.cursor + [:span.bullet]]] + [:div.flex.flex-1 {:on-click #(editor-handler/insert-first-page-block-if-not-exists! page-name)} + [:span.opacity-50 + "Click here to edit..."]]]]) + (rum/defc page-blocks-cp < rum/reactive db-mixins/query [repo page-e {:keys [sidebar? preview?] :as config}] @@ -98,34 +109,24 @@ journal? (db/journal-page? page-name) block? (util/uuid-string? page-name) block-id (and block? (uuid page-name)) + page-empty? (and (not block?) (db/page-empty? repo (:db/id page-e))) page-e (if (and page-e (:db/id page-e)) {:db/id (:db/id page-e)} page-e) - - ;; create an empty block if not exists - _ (when (and (not block?) (db/page-empty? repo (:db/id page-e))) - (let [empty-block {:block/uuid (db/new-block-id) - :block/left page-e - :block/format format - :block/content "" - :block/parent page-e - :block/unordered true - :block/page page-e}] - (when (db/page-empty? repo (:db/id page-e)) - (db/transact! [empty-block])))) - raw-page-blocks (get-blocks repo page-name page-original-name block? block-id) - page-blocks raw-page-blocks - document-mode? (state/sub :document/mode?) - hiccup-config (merge - {:id (if block? (str block-id) page-name) - :block? block? - :editor-box editor/box - :page page - :document/mode? document-mode?} - config) - hiccup-config (common-handler/config-with-document-mode hiccup-config) - hiccup (block/->hiccup page-blocks hiccup-config {})] - (page-blocks-inner page-name page-blocks hiccup sidebar?)))) + page-blocks (get-blocks repo page-name page-original-name block? block-id)] + (if (empty? page-blocks) + (dummy-block page-name) + (let [document-mode? (state/sub :document/mode?) + hiccup-config (merge + {:id (if block? (str block-id) page-name) + :block? block? + :editor-box editor/box + :page page + :document/mode? document-mode?} + config) + hiccup-config (common-handler/config-with-document-mode hiccup-config) + hiccup (block/->hiccup page-blocks hiccup-config {})] + (page-blocks-inner page-name page-blocks hiccup sidebar?)))))) (defn contents-page [page] diff --git a/src/main/frontend/components/search.cljs b/src/main/frontend/components/search.cljs index af6dfaf17e8..758ab9ad07c 100644 --- a/src/main/frontend/components/search.cljs +++ b/src/main/frontend/components/search.cljs @@ -155,7 +155,7 @@ result (if config/publishing? (concat pages files blocks) (concat new-page pages files blocks))] - [:div.rounded-md.shadow-lg + [:div.rounded-md.shadow-lg.search-ac {:style (merge {:top 48 :left 32 diff --git a/src/main/frontend/components/search.css b/src/main/frontend/components/search.css index a774c7436b1..c5204ba5f49 100644 --- a/src/main/frontend/components/search.css +++ b/src/main/frontend/components/search.css @@ -4,6 +4,10 @@ } } +.search-ac { + background-color: var(--ls-primary-background-color); +} + #search-wrapper svg { color: var(--ls-search-icon-color, #9fa6b2); opacity: 0.3; diff --git a/src/main/frontend/db/model.cljs b/src/main/frontend/db/model.cljs index c6f3799a6a3..388c961b49f 100644 --- a/src/main/frontend/db/model.cljs +++ b/src/main/frontend/db/model.cljs @@ -477,7 +477,7 @@ (defn page-empty? [repo page-id] - (zero? (get-page-blocks-count repo page-id))) + (empty? (:block/_parent (db-utils/entity repo page-id)))) (defn page-empty-or-dummy? [repo page-id] @@ -559,12 +559,12 @@ ;; FIXME: alert (defn- keep-only-one-file - [blocks parent] + [blocks] (filter (fn [b] (= (:block/file b) (:block/file (first blocks)))) blocks)) (defn sort-by-left [blocks parent] - (let [blocks (keep-only-one-file blocks parent)] + (let [blocks (keep-only-one-file blocks)] (when (not= (count blocks) (count (set (map :block/left blocks)))) (let [duplicates (->> (map (comp :db/id :block/left) blocks) frequencies diff --git a/src/main/frontend/format/block.cljs b/src/main/frontend/format/block.cljs index 966f1fba536..c1905c746b3 100644 --- a/src/main/frontend/format/block.cljs +++ b/src/main/frontend/format/block.cljs @@ -359,6 +359,7 @@ {:block/name (string/lower-case ref)} ref))) (remove vector?) + (remove nil?) (distinct))] (recur (rest blocks) (conj acc (assoc block :block/path-refs path-ref-pages)) @@ -630,7 +631,8 @@ (map :db/id)) {:block/keys [refs]} new-block ref-pages (filter :block/name refs) - path-ref-pages (concat ref-pages parent-refs [(:db/id page)]) + path-ref-pages (->> (concat ref-pages parent-refs [(:db/id page)]) + (remove nil?)) block (merge block new-block diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index bfaeeeb430f..a6c0fcf2c11 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -188,15 +188,15 @@ (defn- text-range-by-lst-fst-line [content [direction pos]] (case direction - :up - (let [last-new-line (or (string/last-index-of content \newline) -1) - end (+ last-new-line pos 1)] - (subs content 0 end)) - :down - (-> (string/split-lines content) - first - (or "") - (subs 0 pos)))) + :up + (let [last-new-line (or (string/last-index-of content \newline) -1) + end (+ last-new-line pos 1)] + (subs content 0 end)) + :down + (-> (string/split-lines content) + first + (or "") + (subs 0 pos)))) ;; id: block dom id, "ls-block-counter-uuid" (defn edit-block! @@ -389,6 +389,7 @@ [config current-block new-block sibling?] (let [ref-top-block? (and (:ref? config) (not (:ref-child? config))) + skip-save-current-block? (:skip-save-current-block? config) [current-node new-node] (mapv outliner-core/block [current-block new-block]) has-children? (db/has-children? (state/get-current-repo) @@ -406,7 +407,8 @@ :else (not has-children?))] (let [*blocks (atom [current-node])] - (outliner-core/save-node current-node) + (when-not skip-save-current-block? + (outliner-core/save-node current-node)) (outliner-core/insert-node new-node current-node sibling? {:blocks-atom *blocks :skip-transact? false}) {:blocks @*blocks @@ -433,7 +435,7 @@ child? (= (first (:block/parent last-block)) (:block/uuid first-block)) blocks-container-id (when-let [id (:id config)] - (and (util/uuid-string? id) (medley/uuid id)))] + (and (util/uuid-string? id) (medley/uuid id)))] (let [new-last-block (let [first-block-id {:db/id (:db/id first-block)}] (assoc last-block :block/left first-block-id @@ -573,9 +575,9 @@ value (or (when new-marker? (property/insert-property (:block/format block) - value - new-marker - ts)) + value + new-marker + ts)) value)] [properties value])) @@ -617,24 +619,56 @@ (defn api-insert-new-block! [content {:keys [page block-uuid sibling? attributes]}] (when (or page block-uuid) - (when-let [block (if block-uuid - (db/pull [:block/uuid block-uuid]) - (let [page (db/entity [:block/name (string/lower-case page)]) - block-uuid (:block/uuid page) - children (:block/_parent page) - blocks (db/sort-by-left children page) - last-block-id (or (:db/id (last blocks)) - (:db/id page))] - (db/pull last-block-id)))] - ;; TODO: DRY - (let [new-block (-> (select-keys block [:block/parent :block/left :block/format - :block/page :block/file :block/journal?]) - (assoc :block/content content) - (wrap-parse-block)) - repo (state/get-current-repo)] - (outliner-insert-block! {} block new-block sibling?) - (db/refresh! repo {:key :block/insert - :data [new-block]}))))) + (let [sibling? (if page false sibling?) + block (if page + (db/entity [:block/name (string/lower-case page)]) + (db/entity [:block/uuid block-uuid]))] + (when block + (let [repo (state/get-current-repo) + last-block (when (not sibling?) + (let [children (:block/_parent block) + blocks (db/sort-by-left children block) + last-block-id (:db/id (last blocks))] + (when last-block-id + (db/pull last-block-id)))) + new-block (-> (select-keys block [:block/page :block/file :block/journal? + :block/journal-day]) + (assoc :block/content content + :block/format (or + (:block/format block) + (db/get-page-format (:db/id block)) + :markdown)) + (wrap-parse-block) + (assoc :block/uuid (db/new-block-id))) + new-block (if (:block/page new-block) + new-block + (assoc new-block :block/page (:db/id block))) + new-block (if-let [db-id (:db/id (:block/file block))] + (assoc new-block :block/file db-id) + new-block)] + (let [[block-m sibling?] (cond + sibling? + [(db/pull (:db/id block)) sibling?] + + last-block + [last-block true] + + page + [(db/pull (:db/id block)) false] + + ;; FIXME: assert + :else + nil)] + (outliner-insert-block! {:skip-save-current-block? true} block-m new-block sibling?) + (db/refresh! repo {:key :block/insert + :data [(assoc block-m :block/page block)]}))))))) + +(defn insert-first-page-block-if-not-exists! + [page-name] + (when (string? page-name) + (when-let [page (db/entity [:block/name (string/lower-case page-name)])] + (when (db/page-empty? (state/get-current-repo) (:db/id page)) + (api-insert-new-block! "" {:page page-name}))))) (defn update-timestamps-content! [{:block/keys [repeated? marker format] :as block} content] @@ -691,8 +725,8 @@ format (or (db/get-page-format (state/get-current-page)) (state/get-preferred-format)) cond-fn (fn [marker] (or (and (= :markdown format) - (util/safe-re-find (re-pattern (str "#*\\s*" marker)) content)) - (util/starts-with? content "TODO"))) + (util/safe-re-find (re-pattern (str "#*\\s*" marker)) content)) + (util/starts-with? content "TODO"))) [new-content marker] (cond (cond-fn "TODO") [(string/replace-first content "TODO" "DOING") "DOING"] @@ -761,37 +795,37 @@ ([repo e delete-children?] (state/set-editor-op! :delete) (let [{:keys [id block-id block-parent-id value format]} (get-state)] - (when block-id - (let [page-id (:db/id (:block/page (db/entity [:block/uuid block-id]))) - page-blocks-count (and page-id (db/get-page-blocks-count repo page-id))] - (when (> page-blocks-count 1) - (let [block (db/entity [:block/uuid block-id]) - has-children? (seq (:block/_parent block)) - block (db/pull (:db/id block)) - left (tree/-get-left (outliner-core/block block)) - left-has-children? (and left - (when-let [block-id (:block/uuid (:data left))] - (let [block (db/entity [:block/uuid block-id])] - (seq (:block/_parent block)))))] - (when-not (and has-children? left-has-children?) - (let [block-parent (gdom/getElement block-parent-id) - sibling-block (get-prev-block-non-collapsed block-parent)] - (delete-block-aux! block delete-children?) - (when (and repo sibling-block) - (when-let [sibling-block-id (dom/attr sibling-block "blockid")] - (when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])] - (let [original-content (util/trim-safe (:block/content block)) - new-value (str original-content " " (string/triml value)) - tail-len (count (string/triml value)) - pos (max - (if original-content - (utf8/length (utf8/encode original-content)) - 0) - 0)] - (edit-block! block pos format id - {:custom-content new-value - :tail-len tail-len - :move-cursor? false})))))))))))) + (when block-id + (let [page-id (:db/id (:block/page (db/entity [:block/uuid block-id]))) + page-blocks-count (and page-id (db/get-page-blocks-count repo page-id))] + (when (> page-blocks-count 1) + (let [block (db/entity [:block/uuid block-id]) + has-children? (seq (:block/_parent block)) + block (db/pull (:db/id block)) + left (tree/-get-left (outliner-core/block block)) + left-has-children? (and left + (when-let [block-id (:block/uuid (:data left))] + (let [block (db/entity [:block/uuid block-id])] + (seq (:block/_parent block)))))] + (when-not (and has-children? left-has-children?) + (let [block-parent (gdom/getElement block-parent-id) + sibling-block (get-prev-block-non-collapsed block-parent)] + (delete-block-aux! block delete-children?) + (when (and repo sibling-block) + (when-let [sibling-block-id (dom/attr sibling-block "blockid")] + (when-let [block (db/pull repo '[*] [:block/uuid (uuid sibling-block-id)])] + (let [original-content (util/trim-safe (:block/content block)) + new-value (str original-content " " (string/triml value)) + tail-len (count (string/triml value)) + pos (max + (if original-content + (utf8/length (utf8/encode original-content)) + 0) + 0)] + (edit-block! block pos format id + {:custom-content new-value + :tail-len tail-len + :move-cursor? false})))))))))))) (state/set-editor-op! nil))) (defn- get-end-block-parent @@ -888,7 +922,7 @@ (if (string/starts-with? (string/lower-case line) key) new-line line)) - lines) + lines) new-lines (if (not= lines new-lines) new-lines (cons (first new-lines) ;; title @@ -977,8 +1011,8 @@ (let [blocks (db-utils/pull-many repo '[*] (mapv (fn [id] [:block/uuid id]) block-ids)) blocks* (flatten (mapv (fn [b] (if (:collapsed (:block/properties b)) - (vec (tree/sort-blocks (db/get-block-children repo (:block/uuid b)) b)) - [b])) blocks)) + (vec (tree/sort-blocks (db/get-block-children repo (:block/uuid b)) b)) + [b])) blocks)) block-ids* (mapv :block/uuid blocks*) unordered? (:block/unordered (first blocks*)) format (:block/format (first blocks*)) @@ -1035,11 +1069,11 @@ (let [blocks (remove (fn [block] (= "true" (dom/attr block "data-transclude"))) blocks)] (when (seq blocks) (let [repo (dom/attr (first blocks) "repo") - ids (distinct (map #(uuid (dom/attr % "blockid")) blocks)) - ids (if (= :up (state/get-selection-direction)) - (reverse ids) - ids)] - (delete-blocks! repo ids)))))) + ids (distinct (map #(uuid (dom/attr % "blockid")) blocks)) + ids (if (= :up (state/get-selection-direction)) + (reverse ids) + ids)] + (delete-blocks! repo ids)))))) (defn- get-nearest-page [] @@ -1343,12 +1377,12 @@ 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 {})) @@ -1381,9 +1415,9 @@ ;; FIXME: should be relative to current block page path (when-let [href (if (util/electron?) href (second (re-find #"\((.+)\)$" full-text)))] (fs/unlink! (config/get-repo-path - repo (-> href - (string/replace #"^../" "/") - (string/replace #"^assets://" ""))) nil))))) + repo (-> href + (string/replace #"^../" "/") + (string/replace #"^assets://" ""))) nil))))) ;; assets/journals_2021_02_03_1612350230540_0.png (defn resolve-relative-path @@ -1464,7 +1498,7 @@ ;; "_" "_" ;; ":" ":" ; TODO: only properties editing and org mode tag ;; "^" "^" -}) + }) (def reversed-autopair-map (zipmap (vals autopair-map) @@ -1677,7 +1711,7 @@ (seq blocks) (do (let [lookup-refs (->> (map (fn [block] (when-let [id (dom/attr block "blockid")] - [:block/uuid (medley/uuid id)])) blocks) + [:block/uuid (medley/uuid id)])) blocks) (remove nil?)) blocks (db/pull-many repo '[*] lookup-refs) blocks (reorder-blocks blocks) @@ -1692,12 +1726,12 @@ (db/refresh! repo opts) (let [blocks (doall (map - (fn [block] - (when-let [id (gobj/get block "id")] - (when-let [block (gdom/getElement id)] - (dom/add-class! block "selected noselect") - block))) - blocks-dom-nodes))] + (fn [block] + (when-let [id (gobj/get block "id")] + (when-let [block (gdom/getElement id)] + (dom/add-class! block "selected noselect") + block))) + blocks-dom-nodes))] (state/set-selection-blocks! blocks))))))))) (defn- get-link @@ -1894,29 +1928,29 @@ collapsed? (:collapsed (:block/properties editing-block))] (conj (match (mapv boolean [(seq fst-block-text) (seq snd-block-text) block-self? has-children? (= parent left) collapsed?]) - ;; when zoom at editing-block - [_ _ true _ _ _] - [editing-block false false] - - ;; insert after editing-block - [true _ false true _ false] - [editing-block false false] - [true _ false true _ true] - [editing-block true false] - [true _ false false _ _] - [editing-block true false] - [false false false true _ false] - [editing-block false false] - [false false false true _ true] - [editing-block true false] - [false false false false _ _] - [editing-block true true] - - ;; insert before editing-block - [false true false _ true _] - [parent-block false false] - [false true false _ false _] - [left-block true false]) + ;; when zoom at editing-block + [_ _ true _ _ _] + [editing-block false false] + + ;; insert after editing-block + [true _ false true _ false] + [editing-block false false] + [true _ false true _ true] + [editing-block true false] + [true _ false false _ _] + [editing-block true false] + [false false false true _ false] + [editing-block false false] + [false false false true _ true] + [editing-block true false] + [false false false false _ _] + [editing-block true true] + + ;; insert before editing-block + [false true false _ true _] + [parent-block false false] + [false true false _ false _] + [left-block true false]) editing-block)))) (defn- paste-block-tree-at-point-edit-aux diff --git a/src/main/frontend/handler/extract.cljs b/src/main/frontend/handler/extract.cljs index 392edf51343..2f38594c426 100644 --- a/src/main/frontend/handler/extract.cljs +++ b/src/main/frontend/handler/extract.cljs @@ -64,7 +64,8 @@ blocks (map (fn [block] (let [block-ref-pages (seq (:block/refs block)) page-lookup-ref [:block/name (string/lower-case page)] - block-path-ref-pages (cons page-lookup-ref (seq (:block/path-refs block)))] + block-path-ref-pages (->> (cons page-lookup-ref (seq (:block/path-refs block))) + (remove nil?))] (when block-ref-pages (swap! ref-pages set/union (set block-ref-pages))) (-> block diff --git a/src/main/frontend/handler/page.cljs b/src/main/frontend/handler/page.cljs index 40222b9d9f4..62f56740853 100644 --- a/src/main/frontend/handler/page.cljs +++ b/src/main/frontend/handler/page.cljs @@ -83,6 +83,7 @@ [tx default-properties] [tx])] (db/transact! txs) + (editor-handler/insert-first-page-block-if-not-exists! page) (when redirect? (route-handler/redirect! {:to :page :path-params {:name page}}))))) @@ -312,8 +313,7 @@ (let [content (str "[[" page-name "]]")] (editor-handler/api-insert-new-block! content - {:page "Contents" - :sibling? true}) + {:page "Contents"}) (notification/show! "Added to contents!" :success) (editor-handler/clear-when-saved!))) diff --git a/src/main/frontend/modules/outliner/core.cljs b/src/main/frontend/modules/outliner/core.cljs index c273631b7c2..556fbde39ba 100644 --- a/src/main/frontend/modules/outliner/core.cljs +++ b/src/main/frontend/modules/outliner/core.cljs @@ -88,8 +88,11 @@ (extend-type Block tree/INode (-get-id [this] - (when-let [block-id (get-in this [:data :block/uuid])] - block-id)) + (or + (when-let [block-id (get-in this [:data :block/uuid])] + block-id) + (when-let [db-id (get-in this [:data :db/id])] + (:block/uuid (db/pull db-id))))) (-get-parent-id [this] (-> (get-in this [:data :block/parent]) diff --git a/src/main/frontend/text.cljs b/src/main/frontend/text.cljs index 0cee1c39c4d..e4603b8bc9b 100644 --- a/src/main/frontend/text.cljs +++ b/src/main/frontend/text.cljs @@ -144,16 +144,17 @@ ([text format] (remove-level-spaces text format false)) ([text format space?] - (cond - (string/blank? text) - "" + (when format + (cond + (string/blank? text) + "" - (and (= "markdown" (name format)) - (string/starts-with? text "---")) - text + (and (= "markdown" (name format)) + (string/starts-with? text "---")) + text - :else - (remove-level-space-aux! text (config/get-block-pattern format) space?)))) + :else + (remove-level-space-aux! text (config/get-block-pattern format) space?))))) (defn build-data-value [col]