mirror of
https://github.com/logseq/logseq.git
synced 2026-05-28 14:39:48 +00:00
feat: structured pages
This commit is contained in:
@@ -1896,22 +1896,6 @@
|
||||
:html (set-priority block priority)}
|
||||
(priority-text priority))))
|
||||
|
||||
(defn block-tags-cp
|
||||
[{:block/keys [pre-block? tags] :as _block}]
|
||||
(when (and (not pre-block?)
|
||||
(seq tags))
|
||||
(->elem
|
||||
:span
|
||||
{:class "block-tags"}
|
||||
(mapv (fn [tag]
|
||||
(when-let [page (db/entity (:db/id tag))]
|
||||
(let [tag (:block/name page)]
|
||||
[:a.tag.mx-1 {:data-ref tag
|
||||
:key (str "tag-" (:db/id tag))
|
||||
:href (rfe/href :page {:name tag})}
|
||||
(str "#" tag)])))
|
||||
tags))))
|
||||
|
||||
(declare block-content)
|
||||
|
||||
(defn build-block-title
|
||||
@@ -1930,7 +1914,6 @@
|
||||
(marker-switch t))
|
||||
marker-cp (marker-cp t)
|
||||
priority (priority-cp t)
|
||||
tags (block-tags-cp t)
|
||||
bg-color (:background-color properties)
|
||||
;; `heading-level` is for backward compatibility, will remove it in later releases
|
||||
heading-level (:block/heading-level t)
|
||||
@@ -2001,8 +1984,6 @@
|
||||
(when (= block-type :whiteboard-shape) [:span.mr-1 (ui/icon "whiteboard-element" {:extension? true})]))
|
||||
[[:span.opacity-50 "Click here to start writing, type '/' to see all the commands."]])
|
||||
|
||||
[tags]
|
||||
|
||||
;; highlight ref block (area)
|
||||
(when area? [(hl-ref)])))))))
|
||||
|
||||
|
||||
@@ -233,10 +233,10 @@
|
||||
[block property value {:keys [inline-text page-cp block-cp
|
||||
editor-id dom-id
|
||||
editor-box editor-args
|
||||
new-item?]}]
|
||||
new-item? editing?]}]
|
||||
(let [multiple-values? (= :many (:cardinality (:block/schema property)))
|
||||
editor-id (or editor-id (str "ls-property-" (:db/id block) "-" (:db/id property)))
|
||||
editing? (state/sub [:editor/editing? editor-id])
|
||||
editing? (or editing? (state/sub [:editor/editing? editor-id]))
|
||||
repo (state/get-current-repo)
|
||||
type (:type (:block/schema property))]
|
||||
(when (or (not new-item?) editing?)
|
||||
@@ -373,7 +373,7 @@
|
||||
[:div.ls-property-add.grid.grid-cols-4.gap-1.flex.flex-row.items-center
|
||||
(property-key-input entity *property-key *property-value *search?)
|
||||
(when (and property (not (:class-schema? opts)))
|
||||
(property-scalar-value entity property @*property-value opts))
|
||||
(property-scalar-value entity property @*property-value (assoc opts :editing? true)))
|
||||
|
||||
[:a.close {:on-mouse-down exit-edit-property}
|
||||
svg/close]]
|
||||
@@ -414,20 +414,19 @@
|
||||
(reset! *property-value nil))}
|
||||
[:div.block {:style {:height 20
|
||||
:width 20}}
|
||||
[:a.add-button-link.block {:style {:margin-left -4}}
|
||||
[:a.add-button-link.block.mt-1 {:style {:margin-left -4}}
|
||||
(ui/icon "circle-plus")]]])))
|
||||
|
||||
(rum/defcs property-key
|
||||
[state block property]
|
||||
(let [repo (state/get-current-repo)]
|
||||
[:div.relative
|
||||
[:a.property-key
|
||||
{:propertyid (:block/uuid property)
|
||||
:blockid (:block/uuid block)
|
||||
:title (str "Configure property: " (:block/original-name property))
|
||||
:on-click (fn []
|
||||
(state/set-sub-modal! #(property-config repo property)))}
|
||||
(:block/original-name property)]]))
|
||||
[:a
|
||||
{:propertyid (:block/uuid property)
|
||||
:blockid (:block/uuid block)
|
||||
:title (str "Configure property: " (:block/original-name property))
|
||||
:on-click (fn []
|
||||
(state/set-sub-modal! #(property-config repo property)))}
|
||||
(:block/original-name property)]))
|
||||
|
||||
(rum/defcs multiple-value-item < (rum/local false ::show-close?)
|
||||
[state entity property items item {:keys [dom-id editor-id
|
||||
@@ -440,7 +439,7 @@
|
||||
editing? (state/sub [:editor/editing? editor-id])]
|
||||
[:div.flex.flex-1.flex-row {:on-mouse-over #(reset! *show-close? true)
|
||||
:on-mouse-out #(reset! *show-close? false)}
|
||||
(property-scalar-value entity property item opts)
|
||||
(property-scalar-value entity property item (assoc opts :editing? editing?))
|
||||
(when (and (or (not new-item?) editing?)
|
||||
@*show-close?
|
||||
(seq items))
|
||||
@@ -514,7 +513,16 @@
|
||||
(rum/defcs properties-area < rum/reactive
|
||||
[state block properties properties-text-values edit-input-id opts]
|
||||
(let [repo (state/get-current-repo)
|
||||
new-property? (= edit-input-id (state/sub :ui/new-property-input-id))]
|
||||
new-property? (= edit-input-id (state/sub :ui/new-property-input-id))
|
||||
class-properties (->> (:block/tags block)
|
||||
(mapcat (fn [tag]
|
||||
(when (= "class" (:block/type tag))
|
||||
(let [e (db/entity (:db/id tag))]
|
||||
(:properties (:block/schema e)) ))))
|
||||
(map (fn [id]
|
||||
[id nil])))
|
||||
properties (->> (concat (seq properties) class-properties)
|
||||
(util/distinct-by first))]
|
||||
(when-not (and (empty? properties)
|
||||
(not new-property?)
|
||||
(not (:page-configure? opts)))
|
||||
@@ -522,22 +530,21 @@
|
||||
(when (:selected? opts)
|
||||
{:class "select-none"})
|
||||
(when (seq properties)
|
||||
[:div.grid.gap-1
|
||||
(for [[prop-uuid-or-built-in-prop v] properties]
|
||||
(let [v (get properties-text-values prop-uuid-or-built-in-prop v)]
|
||||
(if (uuid? prop-uuid-or-built-in-prop)
|
||||
(when-let [property (db/sub-block (:db/id (db/entity [:block/uuid prop-uuid-or-built-in-prop])))]
|
||||
[:div.grid.grid-cols-4.gap-1
|
||||
[:div.property-key.col-span-1
|
||||
(property-key block property)]
|
||||
(if (:class-schema? opts)
|
||||
[:div.property-description.col-span-3.font-light
|
||||
(get-in property [:block/schema :description])]
|
||||
[:div.property-value.col-span-3
|
||||
(property-value block property v opts)])])
|
||||
;; TODO: built in properties should have UUID and corresponding schema
|
||||
;; builtin
|
||||
[:div
|
||||
[:a.mr-2 (str prop-uuid-or-built-in-prop)]
|
||||
[:span v]])))])
|
||||
(for [[prop-uuid-or-built-in-prop v] properties]
|
||||
(let [v (get properties-text-values prop-uuid-or-built-in-prop v)]
|
||||
(if (uuid? prop-uuid-or-built-in-prop)
|
||||
(when-let [property (db/sub-block (:db/id (db/entity [:block/uuid prop-uuid-or-built-in-prop])))]
|
||||
[:div.property-pair
|
||||
[:div.property-key.col-span-1
|
||||
(property-key block property)]
|
||||
(if (:class-schema? opts)
|
||||
[:div.property-description.col-span-3.font-light
|
||||
(get-in property [:block/schema :description])]
|
||||
[:div.property-value.col-span-3
|
||||
(property-value block property v opts)])])
|
||||
;; TODO: built in properties should have UUID and corresponding schema
|
||||
;; builtin
|
||||
[:div
|
||||
[:a.mr-2 (str prop-uuid-or-built-in-prop)]
|
||||
[:span v]]))))
|
||||
(new-property repo block edit-input-id properties new-property? opts)])))
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
}
|
||||
|
||||
.ls-properties-area {
|
||||
@apply grid gap-1;
|
||||
|
||||
.property-pair {
|
||||
@apply grid grid-cols-4 gap-1
|
||||
}
|
||||
|
||||
.add-button-link {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -47,6 +53,25 @@
|
||||
.property-block-container {
|
||||
margin-left: -1.5em;
|
||||
}
|
||||
|
||||
.property-key a {
|
||||
@apply whitespace-nowrap;
|
||||
color: var(--ls-primary-text-color);
|
||||
}
|
||||
|
||||
.property-key a:hover {
|
||||
color: var(--ls-link-text-hover-color);
|
||||
}
|
||||
}
|
||||
|
||||
.block-main-container .ls-properties-area {
|
||||
margin-top: 0.5em;
|
||||
|
||||
gap: 0;
|
||||
|
||||
.property-pair {
|
||||
gap: 0;
|
||||
}
|
||||
}
|
||||
|
||||
input.simple-input {
|
||||
|
||||
@@ -570,7 +570,7 @@
|
||||
(rum/defc user-proxy-settings
|
||||
[{:keys [type protocol host port] :as agent-opts}]
|
||||
(ui/button [:span.flex.items-center
|
||||
[:strong.pr-1
|
||||
[:span.pr-1
|
||||
(case type
|
||||
"system" "System Default"
|
||||
"direct" "Direct"
|
||||
|
||||
@@ -1490,6 +1490,16 @@ independent of format as format specific heading characters are stripped"
|
||||
{:id (str uuid)
|
||||
:nonce (get-in properties [:logseq.tldraw.shape :nonce])}))))
|
||||
|
||||
(defn get-all-classes
|
||||
[repo]
|
||||
(d/q
|
||||
'[:find [?name ...]
|
||||
:where
|
||||
[?page :block/type ?t]
|
||||
[(= ?t "class")]
|
||||
[?page :block/original-name ?name]]
|
||||
(conn/get-db repo)))
|
||||
|
||||
(comment
|
||||
;; For debugging
|
||||
(defn get-all-blocks
|
||||
|
||||
@@ -91,6 +91,40 @@
|
||||
(let [tx (mapv (fn [page] [:db/retractEntity (:db/id page)]) orphaned-pages)]
|
||||
(swap! txs-state (fn [state] (vec (concat state tx)))))))))
|
||||
|
||||
(defn- update-page-when-save-block
|
||||
[txs-state block-entity m]
|
||||
(when-let [e (:block/page block-entity)]
|
||||
(let [m' (cond-> {:db/id (:db/id e)
|
||||
:block/updated-at (util/time-ms)}
|
||||
(not (:block/created-at e))
|
||||
(assoc :block/created-at (util/time-ms)))
|
||||
txs (if (or (:block/pre-block? block-entity)
|
||||
(:block/pre-block? m))
|
||||
(let [properties (:block/properties m)
|
||||
alias (set (:alias properties))
|
||||
tags (set (:tags properties))
|
||||
alias (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) alias)
|
||||
tags (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) tags)
|
||||
deleteable-page-attributes {:block/alias alias
|
||||
:block/tags tags
|
||||
:block/properties properties
|
||||
:block/properties-text-values (:block/properties-text-values m)}
|
||||
;; Retract page attributes to allow for deletion of page attributes
|
||||
page-retractions
|
||||
(mapv #(vector :db/retract (:db/id e) %) (keys deleteable-page-attributes))]
|
||||
(conj page-retractions (merge m' deleteable-page-attributes)))
|
||||
[m'])]
|
||||
(swap! txs-state into txs))))
|
||||
|
||||
(defn- remove-orphaned-refs-when-save
|
||||
[txs-state block-entity m]
|
||||
(when-not (config/db-based-graph? (state/get-current-repo))
|
||||
(let [remove-self-page #(remove (fn [b]
|
||||
(= (:db/id b) (:db/id (:block/page block-entity)))) %)
|
||||
old-refs (remove-self-page (:block/refs block-entity))
|
||||
new-refs (remove-self-page (:block/refs m))]
|
||||
(remove-orphaned-page-refs! (:db/id block-entity) txs-state old-refs new-refs))))
|
||||
|
||||
;; -get-id, -get-parent-id, -get-left-id return block-id
|
||||
;; the :block/parent, :block/left should be datascript lookup ref
|
||||
|
||||
@@ -148,15 +182,10 @@
|
||||
(let [m (-> (:data this)
|
||||
(dissoc :block/children :block/meta :block.temp/top? :block.temp/bottom?
|
||||
:block/title :block/body :block/level)
|
||||
(gp-util/remove-nils))
|
||||
m (block-with-timestamps m)
|
||||
other-tx (:db/other-tx m)
|
||||
gp-util/remove-nils
|
||||
block-with-timestamps)
|
||||
id (:db/id (:data this))
|
||||
block-entity (db/entity id)]
|
||||
(when (seq other-tx)
|
||||
(swap! txs-state (fn [txs]
|
||||
(vec (concat txs other-tx)))))
|
||||
|
||||
(when id
|
||||
;; Retract attributes to prepare for tx which rewrites block attributes
|
||||
(swap! txs-state (fn [txs]
|
||||
@@ -167,38 +196,17 @@
|
||||
db-schema/retract-attributes)))))
|
||||
|
||||
;; Update block's page attributes
|
||||
(when-let [e (:block/page block-entity)]
|
||||
(let [m' (cond-> {:db/id (:db/id e)
|
||||
:block/updated-at (util/time-ms)}
|
||||
(not (:block/created-at e))
|
||||
(assoc :block/created-at (util/time-ms)))
|
||||
txs (if (or (:block/pre-block? block-entity)
|
||||
(:block/pre-block? m))
|
||||
(let [properties (:block/properties m)
|
||||
alias (set (:alias properties))
|
||||
tags (set (:tags properties))
|
||||
alias (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) alias)
|
||||
tags (map (fn [p] {:block/name (util/page-name-sanity-lc p)}) tags)
|
||||
deleteable-page-attributes {:block/alias alias
|
||||
:block/tags tags
|
||||
:block/properties properties
|
||||
:block/properties-text-values (:block/properties-text-values m)}
|
||||
;; Retract page attributes to allow for deletion of page attributes
|
||||
page-retractions
|
||||
(mapv #(vector :db/retract (:db/id e) %) (keys deleteable-page-attributes))]
|
||||
(conj page-retractions (merge m' deleteable-page-attributes)))
|
||||
[m'])]
|
||||
(swap! txs-state into txs)))
|
||||
(update-page-when-save-block txs-state block-entity m)
|
||||
|
||||
;; Remove orphaned refs from block
|
||||
(when-not (config/db-based-graph? (state/get-current-repo))
|
||||
(let [remove-self-page #(remove (fn [b]
|
||||
(= (:db/id b) (:db/id (:block/page block-entity)))) %)
|
||||
old-refs (remove-self-page (:block/refs block-entity))
|
||||
new-refs (remove-self-page (:block/refs m))]
|
||||
(remove-orphaned-page-refs! (:db/id block-entity) txs-state old-refs new-refs))))
|
||||
(remove-orphaned-refs-when-save txs-state block-entity m))
|
||||
|
||||
(swap! txs-state conj (dissoc m :db/other-tx))
|
||||
;; handle others txs
|
||||
(let [other-tx (:db/other-tx m)]
|
||||
(when (seq other-tx)
|
||||
(swap! txs-state (fn [txs]
|
||||
(vec (concat txs other-tx)))))
|
||||
(swap! txs-state conj (dissoc m :db/other-tx)))
|
||||
|
||||
this))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user