mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
enhance: page properties ux
This commit is contained in:
@@ -27,50 +27,9 @@
|
||||
[title]
|
||||
(let [;; Don't edit the journal title
|
||||
page (string/lower-case title)
|
||||
repo (state/sub :git/current-repo)
|
||||
today? (= (string/lower-case title)
|
||||
(string/lower-case (date/journal-name)))
|
||||
page-entity (db/pull [:block/name (util/page-name-sanity-lc title)])
|
||||
data-page-tags (when (seq (:block/tags page-entity))
|
||||
(let [page-names (model/get-page-names-by-ids (map :db/id (:block/tags page)))]
|
||||
(text-util/build-data-value page-names)))]
|
||||
[:div.flex-1.journal.page (cond-> {}
|
||||
data-page-tags
|
||||
(assoc :data-page-tags data-page-tags))
|
||||
|
||||
(ui/foldable
|
||||
[:a.initial-color.title.journal-title
|
||||
{:href (rfe/href :page {:name page})
|
||||
:on-mouse-down (fn [e]
|
||||
(when (util/right-click? e)
|
||||
(state/set-state! :page-title/context {:page page})))
|
||||
:on-click (fn [e]
|
||||
(when (gobj/get e "shiftKey")
|
||||
(when-let [page page-entity]
|
||||
(state/sidebar-add-block!
|
||||
(state/get-current-repo)
|
||||
(:db/id page)
|
||||
:page))
|
||||
(.preventDefault e)))}
|
||||
[:h1.title
|
||||
(gp-util/capitalize-all title)]]
|
||||
|
||||
(if today?
|
||||
(blocks-cp repo page)
|
||||
(ui/lazy-visible
|
||||
(fn [] (blocks-cp repo page))
|
||||
{:debug-id (str "journal-blocks " page)}))
|
||||
|
||||
{})
|
||||
|
||||
(page/today-queries repo today? false)
|
||||
|
||||
(when today?
|
||||
(scheduled/scheduled-and-deadlines page))
|
||||
|
||||
(rum/with-key
|
||||
(reference/references title)
|
||||
(str title "-refs"))]))
|
||||
repo (state/sub :git/current-repo)]
|
||||
(page/page {:repo repo
|
||||
:page-name page})))
|
||||
|
||||
(rum/defc journals < rum/reactive
|
||||
[latest-journals]
|
||||
|
||||
@@ -287,11 +287,13 @@
|
||||
(rum/defcs page-title < rum/reactive
|
||||
(rum/local false ::edit?)
|
||||
(rum/local "" ::input-value)
|
||||
(rum/local false ::hover?)
|
||||
{:init (fn [state]
|
||||
(assoc state ::title-value (atom (nth (:rum/args state) 2))))}
|
||||
[state page-name icon title _format fmt-journal?]
|
||||
[state page-name icon title {:keys [fmt-journal? *configure-show? built-in-property?]}]
|
||||
(when title
|
||||
(let [page (when page-name (db/entity [:block/name page-name]))
|
||||
*hover? (::hover? state)
|
||||
*title-value (get state ::title-value)
|
||||
*edit? (get state ::edit?)
|
||||
*input-value (get state ::input-value)
|
||||
@@ -304,50 +306,70 @@
|
||||
(if fmt-journal?
|
||||
(date/journal-title->custom-format title)
|
||||
title))
|
||||
old-name (or title page-name)]
|
||||
[:h1.page-title.flex.cursor-pointer.gap-1.w-full
|
||||
{:class (when-not whiteboard-page? "title")
|
||||
:on-mouse-down (fn [e]
|
||||
(when (util/right-click? e)
|
||||
(state/set-state! :page-title/context {:page page-name})))
|
||||
:on-click (fn [e]
|
||||
(when-not (= (.-nodeName (.-target e)) "INPUT")
|
||||
(.preventDefault e)
|
||||
(if (gobj/get e "shiftKey")
|
||||
(when-let [page (db/pull repo '[*] [:block/name page-name])]
|
||||
(state/sidebar-add-block!
|
||||
repo
|
||||
(:db/id page)
|
||||
:page))
|
||||
(when (and (not hls-page?)
|
||||
(not fmt-journal?)
|
||||
(not config/publishing?)
|
||||
(not (and (= "property" (:block/type page))
|
||||
(contains? gp-property/db-built-in-properties-keys-str page-name))))
|
||||
(reset! *input-value (if untitled? "" old-name))
|
||||
(reset! *edit? true)))))}
|
||||
(when (not= icon "") [:span.page-icon icon])
|
||||
[:div.page-title-sizer-wrapper.relative
|
||||
(when @*edit?
|
||||
(page-title-editor {:*title-value *title-value
|
||||
:*edit? *edit?
|
||||
:*input-value *input-value
|
||||
:title title
|
||||
:page-name page-name
|
||||
:old-name old-name
|
||||
:untitled? untitled?
|
||||
:whiteboard-page? whiteboard-page?}))
|
||||
[:span.title.block
|
||||
{:data-value @*input-value
|
||||
:data-ref page-name
|
||||
:style {:opacity (when @*edit? 0)}}
|
||||
(let [nested? (and (string/includes? title page-ref/left-brackets)
|
||||
(string/includes? title page-ref/right-brackets))]
|
||||
(cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)]
|
||||
untitled? [:span.opacity-50 (t :untitled)]
|
||||
nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config
|
||||
(:block/format page))))
|
||||
:else title))]]])))
|
||||
old-name (or title page-name)
|
||||
db-based? (config/db-based-graph? repo)]
|
||||
[:div.ls-page-title.flex-1.flex-row.w-full.relative
|
||||
{:on-mouse-over #(reset! *hover? true)
|
||||
:on-mouse-out #(reset! *hover? false)}
|
||||
[:h1.page-title.flex.cursor-pointer.gap-1.w-full
|
||||
{:class (when-not whiteboard-page? "title")
|
||||
:on-mouse-down (fn [e]
|
||||
(when (util/right-click? e)
|
||||
(state/set-state! :page-title/context {:page page-name})))
|
||||
:on-click (fn [e]
|
||||
(when-not (= (.-nodeName (.-target e)) "INPUT")
|
||||
(.preventDefault e)
|
||||
(if (gobj/get e "shiftKey")
|
||||
(when-let [page (db/pull repo '[*] [:block/name page-name])]
|
||||
(state/sidebar-add-block!
|
||||
repo
|
||||
(:db/id page)
|
||||
:page))
|
||||
(when (and (not hls-page?)
|
||||
(not fmt-journal?)
|
||||
(not config/publishing?)
|
||||
(not (and (= "property" (:block/type page))
|
||||
(contains? gp-property/db-built-in-properties-keys-str page-name))))
|
||||
(reset! *input-value (if untitled? "" old-name))
|
||||
(reset! *edit? true)))))}
|
||||
(when (not= icon "") [:span.page-icon icon])
|
||||
[:div.page-title-sizer-wrapper.relative
|
||||
(when @*edit?
|
||||
(page-title-editor {:*title-value *title-value
|
||||
:*edit? *edit?
|
||||
:*input-value *input-value
|
||||
:title title
|
||||
:page-name page-name
|
||||
:old-name old-name
|
||||
:untitled? untitled?
|
||||
:whiteboard-page? whiteboard-page?}))
|
||||
[:span.title.block
|
||||
{:on-click (fn []
|
||||
(when (state/home?)
|
||||
(route-handler/redirect-to-page! page-name)))
|
||||
:data-value @*input-value
|
||||
:data-ref page-name
|
||||
:style {:opacity (when @*edit? 0)}}
|
||||
(let [nested? (and (string/includes? title page-ref/left-brackets)
|
||||
(string/includes? title page-ref/right-brackets))]
|
||||
(cond @*edit? [:span {:style {:white-space "pre"}} (rum/react *input-value)]
|
||||
untitled? [:span.opacity-50 (t :untitled)]
|
||||
nested? (component-block/map-inline {} (gp-mldoc/inline->edn title (gp-mldoc/default-config
|
||||
(:block/format page))))
|
||||
:else title))]]]
|
||||
(when (and @*hover?
|
||||
db-based?
|
||||
(not built-in-property?)
|
||||
(not @*edit?)
|
||||
(not (seq (:block/properties page)))
|
||||
(not (seq (:block/alias page)))
|
||||
(not (seq (:block/tags page))))
|
||||
[:div.absolute.bottom-2.left-0
|
||||
[:div.flex.flex-row.items-center.flex-wrap.ml-2
|
||||
[:a.fade-link.flex.flex-row.items-center
|
||||
{:on-click #(reset! *configure-show? true)}
|
||||
(ui/icon "plus" {:size 14})
|
||||
[:div.ml-1.text-sm "Add property"]]]])])))
|
||||
|
||||
(defn- page-mouse-over
|
||||
[e *control-show? *all-collapsed?]
|
||||
@@ -378,11 +400,56 @@
|
||||
"control-show cursor-pointer" "control-hide")}
|
||||
(ui/rotating-arrow @*all-collapsed?)]])
|
||||
|
||||
(rum/defcs configure < rum/reactive
|
||||
[state page opts]
|
||||
(let [page-id (:db/id page)
|
||||
page (when page-id (db/sub-block page-id))
|
||||
type (:block/type page)
|
||||
properties-opts (merge {:selected? false
|
||||
:page-configure? true}
|
||||
opts)]
|
||||
(when page
|
||||
[:div.property-configure
|
||||
[:div.grid.gap-4.p-1
|
||||
(case type
|
||||
"class"
|
||||
[:div
|
||||
[:div.structured-schema
|
||||
;; properties
|
||||
[:h2.text-lg.font-medium.mb-2 "Schema:"]
|
||||
[:div.grid.gap-1
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page) "-schema")]
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
page
|
||||
edit-input-id
|
||||
(assoc properties-opts :class-schema? true)))]]
|
||||
|
||||
(when (seq (:block/properties page))
|
||||
[:div.my-4
|
||||
[:div.grid.gap-1
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page))]
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
page
|
||||
edit-input-id
|
||||
properties-opts))]])]
|
||||
|
||||
[:div
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page))]
|
||||
[:div
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
page
|
||||
edit-input-id
|
||||
properties-opts)])])]])))
|
||||
|
||||
;; A page is just a logical block
|
||||
(rum/defcs ^:large-vars/cleanup-todo page < rum/reactive
|
||||
(rum/local false ::all-collapsed?)
|
||||
(rum/local false ::control-show?)
|
||||
(rum/local nil ::current-page)
|
||||
(rum/local false ::configure-show?)
|
||||
[state {:keys [repo page-name] :as option}]
|
||||
(when-let [path-page-name (or page-name
|
||||
(get-block-uuid-by-block-route-name state)
|
||||
@@ -391,14 +458,14 @@
|
||||
(state/get-current-page))]
|
||||
(let [current-repo (state/sub :git/current-repo)
|
||||
repo (or repo current-repo)
|
||||
*configure-show? (::configure-show? state)
|
||||
page-name (util/page-name-sanity-lc path-page-name)
|
||||
block-id (parse-uuid page-name)
|
||||
block? (boolean block-id)
|
||||
format (let [page (if block-id
|
||||
(:block/name (:block/page (db/entity [:block/uuid block-id])))
|
||||
page-name)]
|
||||
(db/get-page-format page))
|
||||
journal? (db/journal-page? page-name)
|
||||
db-based? (config/db-based-graph? repo)
|
||||
built-in-property? (and (= "property" (:block/type page))
|
||||
(contains? gp-property/db-built-in-properties-keys-str page-name))
|
||||
fmt-journal? (boolean (date/journal-title->int page-name))
|
||||
sidebar? (:sidebar? option)
|
||||
whiteboard? (:whiteboard? option) ;; in a whiteboard portal shape?
|
||||
@@ -447,13 +514,18 @@
|
||||
(page-mouse-leave e *control-show?))}
|
||||
(page-blocks-collapse-control title *control-show? *all-collapsed?)])
|
||||
(when-not whiteboard?
|
||||
[:div.ls-page-title.flex-1.flex-row.w-full
|
||||
(page-title page-name icon title format fmt-journal?)])
|
||||
(page-title page-name icon title {:fmt-journal? fmt-journal?
|
||||
:*configure-show? *configure-show?
|
||||
:built-in-property? built-in-property?}))
|
||||
(when (not config/publishing?)
|
||||
(when config/lsp-enabled?
|
||||
[:div.flex.flex-row
|
||||
(plugins/hook-ui-slot :page-head-actions-slotted nil)
|
||||
(plugins/hook-ui-items :pagebar)]))])
|
||||
|
||||
(when (and @*configure-show? db-based? (not built-in-property?))
|
||||
(configure page {:*configure-show? *configure-show?}))
|
||||
|
||||
[:div
|
||||
(when (and block? (not sidebar?) (not whiteboard?))
|
||||
(let [config {:id "block-parent"
|
||||
@@ -468,7 +540,7 @@
|
||||
(or (seq (:block/properties page))
|
||||
(seq (:block/alias page))
|
||||
(seq (:block/tags page))))
|
||||
[:div.page-properties.p-2.mb-4
|
||||
[:div.p-2.mb-4
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page) "-schema")]
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
@@ -1155,60 +1227,3 @@
|
||||
:total total-items
|
||||
:per-page per-page-num
|
||||
:on-change #(to-page %))]])]))
|
||||
|
||||
(rum/defcs configure < rum/reactive
|
||||
[state page]
|
||||
(let [page-id (:db/id page)
|
||||
page (when page-id (db/sub-block page-id))
|
||||
type (:block/type page)
|
||||
class? (= "class" type)
|
||||
journal? (:block/journal? page)]
|
||||
(when page
|
||||
[:div.page-configure
|
||||
[:h1.title "Configure page"]
|
||||
|
||||
[:div.grid.gap-4.p-1
|
||||
(case type
|
||||
"class"
|
||||
[:div
|
||||
[:div.structured-schema
|
||||
;; properties
|
||||
[:h2.text-lg.font-medium.mb-2 "Schema properties:"]
|
||||
[:div.grid.gap-1
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page) "-schema")]
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
page
|
||||
edit-input-id
|
||||
{:selected? false
|
||||
:page-configure? true
|
||||
:class-schema? true}))]]
|
||||
|
||||
(when (seq (:block/properties page))
|
||||
[:div.my-4
|
||||
[:h2.text-lg.font-medium.mb-2 "Page properties:"]
|
||||
[:div.grid.gap-1
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page))]
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
page
|
||||
edit-input-id
|
||||
{:selected? false
|
||||
:page-configure? true}))]])]
|
||||
|
||||
[:div
|
||||
[:h2.text-lg.font-medium.mb-2 "Properties:"]
|
||||
(let [edit-input-id (str "edit-block-" (:block/uuid page))]
|
||||
[:div
|
||||
(component-block/db-properties-cp
|
||||
{:editor-box editor/box}
|
||||
page
|
||||
edit-input-id
|
||||
{:selected? false
|
||||
:page-configure? true})])])]
|
||||
|
||||
(when config/dev?
|
||||
[:div {:style {:max-width 900}}
|
||||
[:hr]
|
||||
[:p "Debug data:"]
|
||||
[:pre (util/pp-str page)]])])))
|
||||
|
||||
@@ -84,14 +84,7 @@
|
||||
(contains? gp-property/db-built-in-properties-keys-str page-name))]
|
||||
(when (and page (not block?))
|
||||
(->>
|
||||
[(when (and (not config/publishing?)
|
||||
(config/db-based-graph? repo)
|
||||
(not built-in-property?))
|
||||
{:title (t :page/configure)
|
||||
:options {:on-click
|
||||
(fn []
|
||||
(state/pub-event! [:page/configure page]))}})
|
||||
(when-not config/publishing?
|
||||
[(when-not config/publishing?
|
||||
{:title (if favorited?
|
||||
(t :page/unfavorite)
|
||||
(t :page/add-to-favorites))
|
||||
|
||||
@@ -9,14 +9,12 @@
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.model :as model]
|
||||
[frontend.config :as config]
|
||||
[rum.core :as rum]
|
||||
[frontend.state :as state]
|
||||
[frontend.mixins :as mixins]
|
||||
[clojure.string :as string]
|
||||
[goog.dom :as gdom]
|
||||
[frontend.search :as search]
|
||||
[frontend.components.svg :as svg]
|
||||
[frontend.modules.shortcut.core :as shortcut]
|
||||
[frontend.components.select :as select]
|
||||
[logseq.graph-parser.property :as gp-property]
|
||||
@@ -60,7 +58,7 @@
|
||||
(reset! (::property-name state) (:block/original-name property))
|
||||
(reset! (::property-schema state) (:block/schema property))
|
||||
state))}
|
||||
[state repo property]
|
||||
[state repo property {:keys [toggle-fn]}]
|
||||
(let [*property-name (::property-name state)
|
||||
*property-schema (::property-schema state)
|
||||
built-in-property? (contains? gp-property/db-built-in-properties-keys-str (:block/original-name property))
|
||||
@@ -122,18 +120,14 @@
|
||||
(when-not built-in-property?
|
||||
(ui/button
|
||||
"Save"
|
||||
:on-click (fn []
|
||||
:on-click (fn [e]
|
||||
(util/stop e)
|
||||
(property-handler/update-property!
|
||||
repo (:block/uuid property)
|
||||
{:property-name @*property-name
|
||||
:property-schema @*property-schema})
|
||||
(state/close-modal!))))]
|
||||
|
||||
(when config/dev?
|
||||
[:div {:style {:max-width 900}}
|
||||
[:hr]
|
||||
[:p "Debug data:"]
|
||||
[:pre (util/pp-str property)]])]]))
|
||||
(state/close-modal!)
|
||||
(when toggle-fn (toggle-fn)))))]]]))
|
||||
|
||||
(defn- exit-edit-property
|
||||
[]
|
||||
@@ -282,7 +276,7 @@
|
||||
[block property value {:keys [inline-text page-cp block-cp
|
||||
editor-id dom-id row?
|
||||
editor-box editor-args
|
||||
editing? editing-atom
|
||||
editing? editing-atom *configure-show?
|
||||
blocks-container-id]}]
|
||||
(let [property (model/sub-block (:db/id property))
|
||||
multiple-values? (= :many (:cardinality (:block/schema property)))
|
||||
@@ -290,7 +284,9 @@
|
||||
editing? (or editing? (state/sub [:editor/editing? editor-id]))
|
||||
repo (state/get-current-repo)
|
||||
type (:type (:block/schema property))
|
||||
select-opts {:on-chosen (fn [] (when editing-atom (reset! editing-atom false)))}]
|
||||
select-opts {:on-chosen (fn []
|
||||
(when *configure-show? (reset! *configure-show? false))
|
||||
(when editing-atom (reset! editing-atom false)))}]
|
||||
(case type
|
||||
:date
|
||||
(date-picker block property value)
|
||||
@@ -396,7 +392,7 @@
|
||||
(db-property/upsert-property! repo property-name {:type :default} {})
|
||||
;; configure new property
|
||||
(when-let [property (get-property-from-db property-name)]
|
||||
(state/set-sub-modal! #(property-config repo property)))))
|
||||
(state/set-sub-modal! #(property-config repo property {})))))
|
||||
(do (notification/show! "This is an invalid property name. A property name cannot start with page reference characters '#' or '[['." :error)
|
||||
(exit-edit-property))))))
|
||||
|
||||
@@ -422,9 +418,7 @@
|
||||
[:div.col-span-1 @*property-key]
|
||||
[:div.col-span-3.flex.flex-row
|
||||
(when (and property (not class-schema?))
|
||||
(property-scalar-value entity property @*property-value (assoc opts :editing? true)))
|
||||
[:a.close {:on-mouse-down exit-edit-property}
|
||||
svg/close]]])
|
||||
(property-scalar-value entity property @*property-value (assoc opts :editing? true)))]])
|
||||
|
||||
[:div.ls-property-add.h-6
|
||||
(select/select {:items (map (fn [x] {:value x}) properties)
|
||||
@@ -489,9 +483,9 @@
|
||||
;; default property icon
|
||||
(ui/icon "circle-dotted" {:size 16}))
|
||||
[:div.ml-1 (:block/original-name property)]]])
|
||||
(fn [{:keys [_toggle-fn]}]
|
||||
(fn [{:keys [toggle-fn]}]
|
||||
[:div.p-8
|
||||
(property-config repo property)])
|
||||
(property-config repo property {:toggle-fn toggle-fn})])
|
||||
{:modal-class (util/hiccup->class
|
||||
"origin-top-right.absolute.left-0.rounded-md.shadow-lg")})))
|
||||
|
||||
@@ -608,7 +602,6 @@
|
||||
alias (set (map :block/uuid (:block/alias block)))
|
||||
alias-properties (when (seq alias)
|
||||
[[(:block/uuid (db/entity [:block/name "alias"])) alias]])
|
||||
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))
|
||||
@@ -618,14 +611,19 @@
|
||||
[id nil])))
|
||||
built-in-properties (set/difference
|
||||
(set (map name gp-property/db-built-in-properties-keys))
|
||||
#{"alias"})
|
||||
#{"alias" "tags"})
|
||||
properties (->> (concat (seq alias-properties)
|
||||
(seq properties)
|
||||
class-properties)
|
||||
(util/distinct-by first)
|
||||
(remove (fn [[k _v]]
|
||||
(when (uuid? k)
|
||||
(contains? built-in-properties (:block/name (db/entity [:block/uuid k])))))))]
|
||||
(contains? built-in-properties (:block/name (db/entity [:block/uuid k])))))))
|
||||
new-property? (or
|
||||
(and (:*configure-show? opts)
|
||||
@(:*configure-show? opts)
|
||||
(empty? properties))
|
||||
(= edit-input-id (state/sub :ui/new-property-input-id)))]
|
||||
(when-not (and (empty? properties)
|
||||
(not new-property?)
|
||||
(not (:page-configure? opts)))
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
.property-configure {
|
||||
min-width: 600px;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.property-value-content {
|
||||
@apply px-1 rounded-sm;
|
||||
cursor: text;
|
||||
|
||||
@@ -982,9 +982,6 @@
|
||||
(when-let [blocks (and block (db-model/get-block-immediate-children (state/get-current-repo) (:block/uuid block)))]
|
||||
(editor-handler/toggle-blocks-as-own-order-list! blocks)))
|
||||
|
||||
(defmethod handle :page/configure [[_ page]]
|
||||
(state/set-modal! #(page/configure page)))
|
||||
|
||||
(defn run!
|
||||
[]
|
||||
(let [chan (state/get-events-chan)]
|
||||
|
||||
@@ -169,7 +169,6 @@
|
||||
:page/open-backup-directory "Open page backups directory"
|
||||
:page/make-private "Make it private"
|
||||
:page/delete "Delete page"
|
||||
:page/configure "Configure page"
|
||||
:page/add-to-favorites "Add to Favorites"
|
||||
:page/unfavorite "Unfavorite page"
|
||||
:page/show-journals "Show journals"
|
||||
|
||||
Reference in New Issue
Block a user