page.cljs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. (ns frontend.components.db-based.page
  2. "Page components only for DB graphs"
  3. (:require [frontend.components.block :as component-block]
  4. [frontend.components.editor :as editor]
  5. [frontend.components.class :as class-component]
  6. [frontend.components.property :as property-component]
  7. [frontend.config :as config]
  8. [frontend.db :as db]
  9. [logseq.outliner.property :as outliner-property]
  10. [frontend.ui :as ui]
  11. [frontend.state :as state]
  12. [rum.core :as rum]
  13. [logseq.shui.ui :as shui]
  14. [frontend.util :as util]
  15. [clojure.set :as set]
  16. [clojure.string :as string]
  17. [logseq.db.frontend.property :as db-property]))
  18. (rum/defc page-properties
  19. "This component is called by page-inner and within configure/info modal. This should not
  20. be displaying properties from both components at the same time"
  21. < rum/reactive
  22. [page {:keys [mode configure?]}]
  23. (let [edit-input-id-prefix (str "edit-block-" (:block/uuid page))
  24. configure-opts {:selected? false
  25. :page-configure? configure?}
  26. has-viewable-properties? (outliner-property/block-has-viewable-properties? page)
  27. hide-properties? (db-property/property-value-content (:logseq.property/hide-properties? page))]
  28. (when (or configure? (and (not hide-properties?) has-viewable-properties?))
  29. [:div.ls-page-properties
  30. {:class (util/classnames [{:no-properties (not has-viewable-properties?)}])}
  31. (if configure?
  32. (cond
  33. (= mode :class)
  34. (component-block/db-properties-cp {:editor-box editor/box}
  35. page
  36. (str edit-input-id-prefix "-schema")
  37. (assoc configure-opts :class-schema? true))
  38. (= mode :page)
  39. (component-block/db-properties-cp {:editor-box editor/box}
  40. page
  41. (str edit-input-id-prefix "-page")
  42. (assoc configure-opts :class-schema? false :page? true)))
  43. ;; default view for page-inner
  44. (component-block/db-properties-cp {:editor-box editor/box}
  45. page
  46. (str edit-input-id-prefix "-page")
  47. (assoc configure-opts :class-schema? false :page? true)))])))
  48. (rum/defcs page-configure < rum/reactive
  49. [state page *mode]
  50. (let [*mode *mode
  51. mode (rum/react *mode)
  52. type (:block/type page)
  53. class? (= type "class")
  54. property? (= type "property")
  55. page-opts {:configure? true}]
  56. (when (nil? mode)
  57. (reset! *mode (cond
  58. class? :class
  59. property? :property
  60. :else :page)))
  61. [:div.flex.flex-col.gap-1.pb-4
  62. (case mode
  63. :property
  64. (property-component/property-config page {:inline-text component-block/inline-text})
  65. :class
  66. [:div.mt-2.flex.flex-col.gap-2
  67. (class-component/configure page {:show-title? false})
  68. (page-properties page (assoc page-opts :mode mode))]
  69. (page-properties page (assoc page-opts :mode mode)))]))
  70. (rum/defc mode-switch < rum/reactive
  71. [type *mode]
  72. (let [current-mode (rum/react *mode)
  73. class? (= type "class")
  74. property? (= type "property")
  75. modes (->
  76. (cond
  77. property?
  78. ["Property"]
  79. class?
  80. ["Class"]
  81. :else
  82. [])
  83. (conj "Page"))]
  84. [:div.flex.flex-row.items-center.gap-1
  85. (for [mode modes]
  86. (let [mode' (keyword (string/lower-case mode))
  87. selected? (and (= mode' current-mode) (> (count modes) 1))]
  88. (shui/button {:class (when-not selected? "opacity-70")
  89. :variant (if selected? :outline :ghost)
  90. :size :sm
  91. :on-click (fn [e]
  92. (util/stop-propagation e)
  93. (reset! *mode mode'))}
  94. mode)))]))
  95. (rum/defcs page-info < rum/reactive
  96. (rum/local false ::hover?)
  97. (rum/local nil ::mode)
  98. [state page *show-info?]
  99. (let [page (db/sub-block (:db/id page))
  100. *hover? (::hover? state)
  101. *mode (::mode state)
  102. type (:block/type page)
  103. class? (= type "class")
  104. collapsed? (not @*show-info?)
  105. has-properties? (or
  106. (seq (:block/tags page))
  107. (seq (:block/alias page))
  108. (seq (remove (set (keys db-property/built-in-properties))
  109. (keys (:block/properties page)))))
  110. show-info? (or @*show-info? has-properties?)]
  111. (when (if config/publishing?
  112. ;; Since publishing is read-only, hide this component if it has no info to show
  113. ;; as it creates a fair amount of empty vertical space
  114. (some? type)
  115. show-info?)
  116. [:div.page-info
  117. {:class (util/classnames [{:is-collapsed collapsed?}])}
  118. [:div {:class (if (or @*hover? (not collapsed?))
  119. "border rounded"
  120. "border rounded border-transparent")}
  121. (when-not collapsed?
  122. [:div.info-title.cursor.p-1
  123. {:on-mouse-over #(reset! *hover? true)
  124. :on-mouse-leave #(when-not (state/dropdown-opened?)
  125. (reset! *hover? false))
  126. :on-click (if config/publishing?
  127. (fn [_]
  128. (when (contains? #{"class" "property"} type)
  129. (swap! *show-info? not)))
  130. #(do
  131. (swap! *show-info? not)
  132. (swap! *hover? not)))}
  133. [:<>
  134. [:div.flex.flex-row.items-center.gap-1
  135. (mode-switch type *mode)]
  136. [:div.absolute.right-1.top-1
  137. (shui/button
  138. {:variant :ghost :size :sm
  139. :class "px-1 py-1 h-6 w-6"}
  140. (ui/icon "x"))]]])
  141. (if collapsed?
  142. (when (or (seq (:block/properties page))
  143. (and class? (seq (:class/schema.properties page))))
  144. (page-properties page {:mode @*mode}))
  145. [:div.px-3
  146. (page-configure page *mode)])]])))