From 6ec79d48cb8fe47a012c2d8d6663c249dde94384 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 7 Aug 2023 15:03:03 +0800 Subject: [PATCH] feat: property icon emoji picker --- .../src/logseq/graph_parser/property.cljs | 2 +- package.json | 3 + src/main/frontend/components/property.cljs | 65 +++++++++++++++---- .../frontend/handler/db_based/property.cljs | 8 ++- src/main/frontend/handler/editor.cljs | 11 ++-- src/main/frontend/handler/property.cljs | 2 +- src/main/frontend/ui.cljs | 21 ++++-- yarn.lock | 15 +++++ 8 files changed, 99 insertions(+), 28 deletions(-) diff --git a/deps/graph-parser/src/logseq/graph_parser/property.cljs b/deps/graph-parser/src/logseq/graph_parser/property.cljs index 7e0371d07a..abbd0c1546 100644 --- a/deps/graph-parser/src/logseq/graph_parser/property.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/property.cljs @@ -190,7 +190,7 @@ :logseq.order-list-type {:schema {:type :checkbox}} :logseq.tldraw.page {:schema {:type :map}} :logseq.tldraw.shape {:schema {:type :map}} - :icon {:schema {:type :default}} + :icon {:schema {:type :map}} :public {:schema {:type :checkbox}} :filters {:schema {:type :map}} :exclude-from-graph-view {:schema {:type :checkbox}}}) diff --git a/package.json b/package.json index b554931876..bb138f0fec 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,8 @@ "@capacitor/splash-screen": "^4.0.0", "@capacitor/status-bar": "^4.0.0", "@capawesome/capacitor-background-task": "^2.0.0", + "@emoji-mart/data": "^1.1.2", + "@emoji-mart/react": "^1.1.1", "@excalidraw/excalidraw": "0.12.0", "@hugotomazi/capacitor-navigation-bar": "^2.0.0", "@logseq/capacitor-file-sync": "0.0.32", @@ -109,6 +111,7 @@ "dompurify": "2.4.0", "electron": "24.6.3", "electron-dl": "3.3.0", + "emoji-mart": "^5.5.2", "fs": "0.0.1-security", "fs-extra": "9.1.0", "fuse.js": "6.4.6", diff --git a/src/main/frontend/components/property.cljs b/src/main/frontend/components/property.cljs index 33cf6d158f..b27d232fce 100644 --- a/src/main/frontend/components/property.cljs +++ b/src/main/frontend/components/property.cljs @@ -23,10 +23,35 @@ [medley.core :as medley] [cljs-time.coerce :as tc] [clojure.set :as set] - [frontend.db-mixins :as db-mixins])) + [frontend.db-mixins :as db-mixins] + [frontend.handler.property.util :as pu])) + +(rum/defc icon + [block {:keys [_type id]}] ; only :emoji supported yet + (let [value (or id "Pick an Icon") + repo (state/get-current-repo) + icon-property-id (:block/uuid (db/entity [:block/name "icon"]))] + (ui/dropdown + (fn [{:keys [toggle-fn]}] + (if id + [:a {:on-click toggle-fn} + [:em-emoji {:id id}]] + (ui/button value + :small? true + :intent "border-link" + :on-click toggle-fn))) + (fn [{:keys [toggle-fn]}] + (ui/emoji-picker + {:auto-focus true + :on-emoji-select (fn [icon] + (when-let [id (.-id icon)] + (property-handler/update-property! repo (:block/uuid block) {:properties {icon-property-id {:type :emoji + :id id}}})) + (toggle-fn))}))))) + (rum/defcs property-config < - rum/static + rum/reactive (rum/local nil ::property-name) (rum/local nil ::property-schema) {:will-mount (fn [state] @@ -34,10 +59,11 @@ (reset! (::property-name state) (:block/original-name property)) (reset! (::property-schema state) (:block/schema property)) state))} - [state repo property ] + [state repo property] (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))] + built-in-property? (contains? gp-property/db-built-in-properties-keys-str (:block/original-name property)) + property (db/sub-block (:db/id property))] [:div.property-configure [:h1.title (if built-in-property? @@ -52,6 +78,11 @@ :disabled built-in-property? :value @*property-name}]] + [:div.grid.grid-cols-4.gap-1.items-center.leading-8 + [:label "Icon:"] + (let [icon-value (pu/get-property property :icon)] + (icon property icon-value))] + [:div.grid.grid-cols-4.gap-1.leading-8 [:label "Schema type:"] (let [schema-types (->> (keys property-handler/builtin-schema-types) @@ -89,13 +120,13 @@ [:div (when-not built-in-property? (ui/button - "Save" - :on-click (fn [] - (property-handler/update-property! - repo (:block/uuid property) - {:property-name @*property-name - :property-schema @*property-schema}) - (state/close-modal!))))] + "Save" + :on-click (fn [] + (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}} @@ -442,7 +473,8 @@ (rum/defcs property-key [state block property {:keys [class-schema?]}] - (let [repo (state/get-current-repo)] + (let [repo (state/get-current-repo) + icon (pu/get-property property :icon)] [:a {:data-propertyid (:block/uuid property) :data-blockid (:block/uuid block) @@ -450,7 +482,14 @@ :title (str "Configure property: " (:block/original-name property)) :on-click (fn [] (state/set-sub-modal! #(property-config repo property)))} - (:block/original-name property)])) + [:div.flex.flex-row.items-center + (or + (when-let [id (:id icon)] + (when (= :emoji (:type icon)) + [:em-emoji {:id id}])) + ;; default property icon + (ui/icon "circle-dotted" {:size 16})) + [:div.ml-1 (:block/original-name property)]]])) (rum/defcs multiple-value-item < (rum/local false ::show-close?) [state entity property item {:keys [editor-id row?] diff --git a/src/main/frontend/handler/db_based/property.cljs b/src/main/frontend/handler/db_based/property.cljs index 291ac011d1..5853b8b445 100644 --- a/src/main/frontend/handler/db_based/property.cljs +++ b/src/main/frontend/handler/db_based/property.cljs @@ -217,7 +217,8 @@ {:outliner-op :save-block})))) (defn update-property! - [repo property-uuid {:keys [property-name property-schema]}] + [repo property-uuid {:keys [property-name property-schema + properties]}] {:pre [(uuid? property-uuid)]} (when-let [property (db/entity [:block/uuid property-uuid])] (when (and (= :many (:cardinality property-schema)) @@ -229,9 +230,12 @@ {:block/original-name property-name :block/name (gp-util/page-name-sanity-lc property-name)}) property-schema (assoc :block/schema property-schema) + properties (assoc :block/properties + (merge (:block/properties property) + properties)) true outliner-core/block-with-updated-at)] (db/transact! repo [tx-data] - {:outliner-op :save-block})))) + {:outliner-op :save-block})))) (defn delete-property-value! "Delete value if a property has multiple values" diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index b0b665cc46..79863f8c79 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -3335,11 +3335,12 @@ [block] (let [entity (db/entity (:db/id block)) content (:block/content entity)] - (when (and (string/includes? content "#+BEGIN_QUERY") - (string/includes? content "#+END_QUERY")) - (let [ast (mldoc/->edn (string/trim content) (gp-mldoc/default-config (or (:block/format entity) :markdown))) - q (mldoc/extract-first-query-from-ast ast)] - (some? (:query (gp-util/safe-read-string q))))))) + (when content + (when (and (string/includes? content "#+BEGIN_QUERY") + (string/includes? content "#+END_QUERY")) + (let [ast (mldoc/->edn (string/trim content) (gp-mldoc/default-config (or (:block/format entity) :markdown))) + q (mldoc/extract-first-query-from-ast ast)] + (some? (:query (gp-util/safe-read-string q)))))))) (defn collapsable? ([block-id] diff --git a/src/main/frontend/handler/property.cljs b/src/main/frontend/handler/property.cljs index 0ed55423d5..1ccde12784 100644 --- a/src/main/frontend/handler/property.cljs +++ b/src/main/frontend/handler/property.cljs @@ -27,7 +27,7 @@ [repo property-uuid opts] {:pre [(uuid? property-uuid)]} #_:clj-kondo/ignore - (if (config/db-based-graph? repo) + (when (config/db-based-graph? repo) (db-property/update-property! repo property-uuid opts))) (defn delete-property-value! diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index e014dcb17d..24cd12e71a 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -6,6 +6,9 @@ ["react-textarea-autosize" :as TextareaAutosize] ["react-tippy" :as react-tippy] ["react-transition-group" :refer [CSSTransition TransitionGroup]] + ["@emoji-mart/data" :as emoji-data] + ["@emoji-mart/react" :as Picker] + ["emoji-mart" :as emoji-mart] [camel-snake-kebab.core :as csk] [cljs-bean.core :as bean] [clojure.string :as string] @@ -46,6 +49,8 @@ (def Tippy (r/adapt-class (gobj/get react-tippy "Tooltip"))) (def ReactTweetEmbed (r/adapt-class react-tweet-embed)) (def useInView (gobj/get react-intersection-observer "useInView")) +(defonce _emoji-init-data ((gobj/get emoji-mart "init") #js {:data emoji-data})) +(def EmojiPicker (r/adapt-class (gobj/get Picker "default"))) (defn reset-ios-whole-page-offset! [] @@ -1013,16 +1018,16 @@ (rum/defc icon ([name] (icon name nil)) - ([name {:keys [extension? font? class] :as opts}] + ([name {:keys [extension? font? class size] :as opts}] (when-not (string/blank? name) (let [^js jsTablerIcons (gobj/get js/window "tablerIcons")] (if (or extension? font? (not jsTablerIcons)) [:span.ui__icon (merge {:class (util/format - (str "%s-" name - (when (:class opts) - (str " " (string/trim (:class opts))))) - (if extension? "tie tie" "ti ti"))} + (str "%s-" name + (when (:class opts) + (str " " (string/trim (:class opts))))) + (if extension? "tie tie" "ti ti"))} (dissoc opts :class :extension? :font?))] ;; tabler svg react @@ -1030,7 +1035,7 @@ (let [f (get-adapt-icon-class klass)] [:span.ui__icon.ti {:class (str "ls-icon-" name " " class)} - (f (merge {:size 18} (r/map-keys->camel-case (dissoc opts :class))))]))))))) + (f (merge {:size (or size 18)} (r/map-keys->camel-case (dissoc opts :class))))]))))))) (rum/defc button [text & {:keys [background href class intent on-click small? large? title icon icon-props disabled?] @@ -1210,3 +1215,7 @@ :on-click rm-heading-fn :intent "link" :small? true)]])) + +(rum/defc emoji-picker + [opts] + (EmojiPicker. (assoc opts :data emoji-data))) diff --git a/yarn.lock b/yarn.lock index 5d0f8edcb4..bb7fb5465f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -350,6 +350,16 @@ optionalDependencies: global-agent "^3.0.0" +"@emoji-mart/data@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.1.2.tgz#777c976f8f143df47cbb23a7077c9ca9fe5fc513" + integrity sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg== + +"@emoji-mart/react@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@emoji-mart/react/-/react-1.1.1.tgz#ddad52f93a25baf31c5383c3e7e4c6e05554312a" + integrity sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g== + "@excalidraw/excalidraw@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.12.0.tgz#0c281624f29aa7834a015035b21dfd928be861d4" @@ -2611,6 +2621,11 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emoji-mart@^5.5.2: + version "5.5.2" + resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af" + integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"