diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 8ffed2c1fa..863157c721 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -192,19 +192,17 @@ :view-context :class} :properties {:logseq.property/description "When enabled, this tag will show reverse nodes that link to the current node via properties."}} - :logseq.property.class/default-icon-type {:title "Default icon type" - :schema {:type :default - :public? true - :view-context :class} - :closed-values - (mapv (fn [[db-ident value]] - {:db-ident db-ident - :value value - :uuid (common-uuid/gen-uuid :db-ident-block-uuid db-ident)}) - [[:logseq.property.class/default-icon-type.avatar "avatar"] - [:logseq.property.class/default-icon-type.text "text"]]) - :properties - {:logseq.property/description "Set the default icon type for instances of this tag. Icons will be auto-generated from each instance's page title."}} + ;; Unified default icon property - stores icon data with type inferred from :type field + ;; For icon: {:type :tabler-icon :id "checkbox"} + ;; For emoji: {:type :emoji :id "🎯"} + ;; For avatar: {:type :avatar} (value derived from instance title) + ;; For text: {:type :text} (value derived from instance title) + :logseq.property.class/default-icon {:title "Default Icon" + :schema {:type :map + :public? true + :view-context :class} + :properties + {:logseq.property/description "Set the default icon for instances of this tag. Avatar/text are auto-generated from title."}} :logseq.property/hide-empty-value {:title "Hide empty value" :schema {:type :checkbox :public? true diff --git a/deps/db/src/logseq/db/frontend/schema.cljs b/deps/db/src/logseq/db/frontend/schema.cljs index 14586b399d..a5421c67e6 100644 --- a/deps/db/src/logseq/db/frontend/schema.cljs +++ b/deps/db/src/logseq/db/frontend/schema.cljs @@ -30,7 +30,7 @@ (map (juxt :major :minor) [(parse-schema-version x) (parse-schema-version y)]))) -(def version (parse-schema-version "65.22")) +(def version (parse-schema-version "65.26")) (defn major-version "Return a number. diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 6f7da4d6c9..df831f13a6 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -2518,49 +2518,56 @@ ;; Inline block icon - displayed BEFORE positioned properties like Status (when-not (or table? (:page-title? config)) (let [block-icon (:logseq.property/icon block) - tag-icon (some :logseq.property/icon (:block/tags block)) - ;; Check for default-icon-type on tags (for auto-generated icons) + ;; Check for :none override - explicitly hidden icon + icon-hidden? (= :none (:type block-icon)) + ;; Check for default-icon on tags (unified icon inheritance) sorted-tags (sort-by :db/id (:block/tags block)) - default-icon-type (some (fn [tag] - (when-let [dit (:logseq.property.class/default-icon-type tag)] - (or (:block/title dit) - (:logseq.property/value dit)))) - sorted-tags) - has-icon? (or block-icon tag-icon default-icon-type)] + default-icon (some (fn [tag] + (:logseq.property.class/default-icon tag)) + sorted-tags) + ;; Determine if we have an icon to show + has-icon? (and (not icon-hidden?) + (or (and block-icon (not= :none (:type block-icon))) + default-icon))] (when has-icon? - (let [icon (or block-icon - (when (and default-icon-type (:block/title block)) - (case default-icon-type - "avatar" {:type :avatar - :data {:value (icon-component/derive-avatar-initials (:block/title block))}} - "text" {:type :text - :data {:value (icon-component/derive-initials (:block/title block))}} - nil)) - tag-icon)] - [:div.inline-block-icon.flex.items-center.h-6.select-none - (icon-component/icon-picker - icon - {:on-chosen (fn [_e new-icon] - (if new-icon - (let [icon-data (cond - (= :text (:type new-icon)) - {:type :text :data (:data new-icon)} + (let [icon (or (when (and block-icon (not= :none (:type block-icon))) + block-icon) + (when default-icon + (case (:type default-icon) + :avatar (when (:block/title block) + {:type :avatar + :data {:value (icon-component/derive-avatar-initials (:block/title block))}}) + :text (when (:block/title block) + {:type :text + :data {:value (icon-component/derive-initials (:block/title block))}}) + ;; For tabler-icon and emoji, use the stored value directly + default-icon)))] + (when icon + [:div.inline-block-icon.flex.items-center.h-6.select-none + (icon-component/icon-picker + icon + {:on-chosen (fn [_e new-icon] + (if new-icon + (let [icon-data (cond + (= :text (:type new-icon)) + {:type :text :data (:data new-icon)} - (= :avatar (:type new-icon)) - {:type :avatar :data (:data new-icon)} + (= :avatar (:type new-icon)) + {:type :avatar :data (:data new-icon)} - :else - (select-keys new-icon [:id :type :color]))] + :else + (select-keys new-icon [:id :type :color]))] + (db-property-handler/set-block-property! + (:db/id block) + :logseq.property/icon + icon-data)) + ;; Delete = set :none to override inheritance (db-property-handler/set-block-property! (:db/id block) :logseq.property/icon - icon-data)) - ;; Delete icon - (db-property-handler/remove-block-property! - (:db/id block) - :logseq.property/icon))) - :del-btn? (boolean block-icon) - :icon-props {:size 16}})])))) + {:type :none}))) + :del-btn? true ;; Always show delete when icon displayed + :icon-props {:size 16}})]))))) (when-not table? (block-positioned-properties config block :block-left)) @@ -3005,23 +3012,22 @@ children (ldb/get-children block) page-icon (when (:page-title? config) (let [icon' (get block :logseq.property/icon) - ;; Check for default-icon-type on tags (for auto-generated icons) + ;; Check for default-icon on tags (for auto-generated icons) sorted-tags (sort-by :db/id (:block/tags block)) - default-icon-type (some (fn [tag] - (when-let [dit (:logseq.property.class/default-icon-type tag)] - (or (:block/title dit) - (:logseq.property/value dit)))) - sorted-tags)] + default-icon (some (fn [tag] + (:logseq.property.class/default-icon tag)) + sorted-tags)] (when-let [icon (and (ldb/page? block) (or icon' - ;; Generate icon from default-icon-type - (when (and default-icon-type (:block/title block)) - (case default-icon-type - "avatar" {:type :avatar - :data {:value (icon-component/derive-avatar-initials (:block/title block))}} - "text" {:type :text - :data {:value (icon-component/derive-initials (:block/title block))}} - nil)) + ;; Generate icon from default-icon + (when (and default-icon (:block/title block)) + (case (:type default-icon) + :avatar {:type :avatar + :data {:value (icon-component/derive-avatar-initials (:block/title block))}} + :text {:type :text + :data {:value (icon-component/derive-initials (:block/title block))}} + ;; For tabler-icon and emoji, use the stored value + default-icon)) (some :logseq.property/icon (:block/tags block)) (when (ldb/class? block) {:type :tabler-icon @@ -3043,14 +3049,27 @@ :else (select-keys icon [:id :type :color]))] + ;; Set the icon on the page (db-property-handler/set-block-property! (:db/id block) :logseq.property/icon - icon-data)) + icon-data) + ;; For classes, also set default-icon for inheritance + (when (ldb/class? block) + (db-property-handler/set-block-property! + (:db/id block) + :logseq.property.class/default-icon + icon-data))) ;; del - (db-property-handler/remove-block-property! - (:db/id block) - :logseq.property/icon))) + (do + (db-property-handler/remove-block-property! + (:db/id block) + :logseq.property/icon) + ;; For classes, also remove default-icon + (when (ldb/class? block) + (db-property-handler/remove-block-property! + (:db/id block) + :logseq.property.class/default-icon))))) :del-btn? (boolean icon') :icon-props {:style {:width "1lh" :height "1lh" diff --git a/src/main/frontend/components/content.cljs b/src/main/frontend/components/content.cljs index 95d0dca3a5..9dc5e121cb 100644 --- a/src/main/frontend/components/content.cljs +++ b/src/main/frontend/components/content.cljs @@ -5,6 +5,7 @@ [frontend.commands :as commands] [frontend.components.editor :as editor] [frontend.components.export :as export] + [frontend.components.icon :as icon-component] [frontend.components.page-menu :as page-menu] [frontend.context.i18n :refer [t]] [frontend.db :as db] @@ -134,6 +135,41 @@ #(editor-handler/set-heading! block-id true) #(editor-handler/remove-heading! block-id)) + ;; Set icon menu item + (let [current-icon (:logseq.property/icon block)] + (shui/dropdown-menu-item + {:key "Set icon" + :on-click (fn [^js e] + (shui/popup-show! + (.-target e) + (fn [{:keys [id]}] + (icon-component/icon-search + {:on-chosen (fn [_e icon-value] + (let [icon-data (when icon-value + (cond + (= :text (:type icon-value)) + {:type :text :data (:data icon-value)} + + (= :avatar (:type icon-value)) + {:type :avatar :data (:data icon-value)} + + :else + (select-keys icon-value [:type :id :color])))] + (property-handler/set-block-property! + block-id + :logseq.property/icon + icon-data)) + (shui/popup-hide! id)) + :icon-value current-icon + :del-btn? (some? current-icon)})) + {:align :start + :id :ls-icon-picker + :content-props {:class "ls-icon-picker" + :onEscapeKeyDown #(.preventDefault %)}}))} + (if current-icon + (t :content/change-icon) + (t :content/set-icon)))) + (shui/dropdown-menu-separator) (shui/dropdown-menu-item diff --git a/src/main/frontend/components/icon.cljs b/src/main/frontend/components/icon.cljs index 855afc7c87..ee70412f34 100644 --- a/src/main/frontend/components/icon.cljs +++ b/src/main/frontend/components/icon.cljs @@ -124,44 +124,47 @@ (defn get-node-icon [node-entity] - (let [sorted-tags (sort-by :db/id (:block/tags node-entity)) - first-tag-icon (some :logseq.property/icon sorted-tags) - ;; Check for default-icon-type on tags (for auto-generated icons) - default-icon-type (some (fn [tag] - (when-let [dit (:logseq.property.class/default-icon-type tag)] - ;; dit is a reference to the closed value entity - ;; closed values store their value in :block/title or :logseq.property/value - (or (:block/title dit) - (:logseq.property/value dit)))) - sorted-tags)] - (or - ;; 1. Instance's own icon takes precedence - (get node-entity :logseq.property/icon) - ;; 2. Check for default-icon-type from tags (generates icon from page title) - (when (and default-icon-type (:block/title node-entity)) - (let [title (:block/title node-entity)] - (case default-icon-type - "avatar" {:type :avatar - :data {:value (derive-avatar-initials title)}} - "text" {:type :text - :data {:value (derive-initials title)}} - nil))) - ;; 3. Fall back to first tag's explicit icon (existing inheritance) - (when (some? first-tag-icon) - first-tag-icon) - ;; 4. Type-based defaults - (let [asset-type (:logseq.property.asset/type node-entity)] - (cond - (ldb/class? node-entity) - "hash" - (ldb/property? node-entity) - "letter-p" - (ldb/page? node-entity) - "file" - (= asset-type "pdf") - "book" - :else - "point-filled"))))) + (let [block-icon (get node-entity :logseq.property/icon) + sorted-tags (sort-by :db/id (:block/tags node-entity)) + ;; Check for default-icon on tags (unified icon inheritance) + default-icon (some (fn [tag] + (:logseq.property.class/default-icon tag)) + sorted-tags)] + (cond + ;; 1. Explicit "no icon" override - hide icon even if inherited + (= :none (:type block-icon)) + nil + + ;; 2. Instance's own icon takes precedence + block-icon + block-icon + + ;; 3. Resolve from tag's default-icon (unified inheritance) + default-icon + (case (:type default-icon) + :avatar (when (:block/title node-entity) + {:type :avatar + :data {:value (derive-avatar-initials (:block/title node-entity))}}) + :text (when (:block/title node-entity) + {:type :text + :data {:value (derive-initials (:block/title node-entity))}}) + ;; For tabler-icon and emoji, use the stored icon value directly + default-icon) + + ;; 4. Type-based defaults (for classes, properties, pages, etc.) + :else + (let [asset-type (:logseq.property.asset/type node-entity)] + (cond + (ldb/class? node-entity) + "hash" + (ldb/property? node-entity) + "letter-p" + (ldb/page? node-entity) + "file" + (= asset-type "pdf") + "book" + :else + "point-filled"))))) (rum/defc get-node-icon-cp < rum/reactive db-mixins/query [node-entity opts] diff --git a/src/main/frontend/components/property.cljs b/src/main/frontend/components/property.cljs index 69f67f9bd3..5d5b1d2833 100644 --- a/src/main/frontend/components/property.cljs +++ b/src/main/frontend/components/property.cljs @@ -706,8 +706,13 @@ (not (ldb/built-in? block))) (-> (assoc :logseq.property.class/enable-bidirectional? (:logseq.property.class/enable-bidirectional? block)) - (assoc :logseq.property.class/default-icon-type - (:logseq.property.class/default-icon-type block)))) + (assoc :logseq.property.class/default-icon + (:logseq.property.class/default-icon block))) + ;; Show icon properties on built-in classes too + (and (ldb/class? block) + (ldb/built-in? block)) + (assoc :logseq.property.class/default-icon + (:logseq.property.class/default-icon block))) remove-built-in-or-other-position-properties (fn [properties show-in-hidden-properties?] (remove (fn [property] @@ -738,7 +743,7 @@ ;; This section produces own-properties and full-hidden-properties ;; Class properties that should always show even when empty always-show-class-properties #{:logseq.property.class/enable-bidirectional? - :logseq.property.class/default-icon-type} + :logseq.property.class/default-icon} hide-with-property-id (fn [property-id] (let [property (db/entity property-id)] (boolean diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index f2feb142c6..74d3ab08e3 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -684,7 +684,7 @@ (property-type-sub-pane property ops))})) (when (and (= property-type :node) - (not (contains? #{:logseq.property.class/extends} (:db/ident property)))) + (not (contains? #{:logseq.property.class/extends :logseq.property.class/default-icon} (:db/ident property)))) (dropdown-editor-menuitem {:icon :hash :disabled? disabled? :title "Specify node tags" @@ -739,7 +739,7 @@ (when (and (not= :logseq.property/enable-history? (:db/ident property)) (not special-built-in-prop?)) (let [property-type (:logseq.property/type property) - group' (->> [(when (and (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties} (:db/ident property))) + group' (->> [(when (and (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties :logseq.property.class/default-icon} (:db/ident property))) (contains? #{:default :number :date :checkbox :node} property-type) (not (and (= :default property-type) @@ -751,13 +751,13 @@ :disabled? config/publishing? :submenu-content (fn [ops] (ui-position-sub-pane property (assoc ops :ui-position position)))}))) - (when (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties} (:db/ident property))) + (when (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties :logseq.property.class/default-icon} (:db/ident property))) (dropdown-editor-menuitem {:icon :eye-off :title "Hide by default" :toggle-checked? (boolean (:logseq.property/hide? property)) :disabled? config/publishing? :on-toggle-checked-change #(db-property-handler/set-block-property! (:db/id property) :logseq.property/hide? %)})) - (when (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties} (:db/ident property))) + (when (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties :logseq.property.class/default-icon} (:db/ident property))) (dropdown-editor-menuitem {:icon :eye-off :title "Hide empty value" :toggle-checked? (boolean (:logseq.property/hide-empty-value property)) @@ -804,7 +804,7 @@ ;; Any property should be removable from Tag Properties (if class-schema? (contains? (set (map :db/id (:logseq.property.class/properties owner-block))) (:db/id property)) - (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties} (:db/ident property))))) + (not (contains? #{:logseq.property.class/extends :logseq.property.class/properties :logseq.property.class/default-icon} (:db/ident property))))) (dropdown-editor-menuitem {:id :delete-property :icon :x diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index 448b8bf3fd..a2f8b4ce5b 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -141,6 +141,100 @@ :del-btn? (some? icon-value) :on-chosen on-chosen!})]))) +(def ^:private default-icon-type-options + [{:value :tabler-icon :label "Icon"} + {:value :emoji :label "Emoji"} + {:value :avatar :label "Avatar"} + {:value :text :label "Text"}]) + +(rum/defc default-icon-row < rum/reactive + "Renders the unified Default Icon property for classes. + Shows a type dropdown and icon picker side by side." + [block _editing?] + ;; Subscribe to block changes for reactivity + (let [block (or (model/sub-block (:db/id block)) block) + current-value (:logseq.property.class/default-icon block) + ;; Only show a type if we have a value, otherwise show empty state + has-value? (some? current-value) + current-type (when has-value? (:type current-value)) + shows-picker? (contains? #{:tabler-icon :emoji} current-type) + set-default-icon! (fn [icon-data] + (property-handler/set-block-property! + (:db/id block) + :logseq.property.class/default-icon + icon-data)) + on-type-change (fn [new-type] + ;; When changing type, preserve icon data if switching between icon/emoji + ;; For avatar/text, just store the type marker + (cond + (contains? #{:avatar :text} new-type) + (set-default-icon! {:type new-type}) + + ;; Switching to icon/emoji - keep existing icon if compatible + (and (contains? #{:tabler-icon :emoji} new-type) + (contains? #{:tabler-icon :emoji} current-type)) + (set-default-icon! (assoc current-value :type new-type)) + + ;; Switching to icon/emoji from avatar/text - clear and let user pick + :else + (set-default-icon! {:type new-type}))) + on-icon-chosen (fn [_e icon] + (if icon + (let [icon-data (cond + (= :text (:type icon)) + {:type :text :data (:data icon)} + + (= :avatar (:type icon)) + {:type :avatar :data (:data icon)} + + :else + (select-keys icon [:type :id :color]))] + (set-default-icon! icon-data)) + ;; Delete - remove the property + (property-handler/remove-block-property! + (:db/id block) + :logseq.property.class/default-icon))) + type-label (some #(when (= (:value %) current-type) (:label %)) default-icon-type-options)] + [:div.col-span-3.flex.flex-row.items-center.gap-2 + ;; Type dropdown + (shui/dropdown-menu + (shui/dropdown-menu-trigger + {:asChild true} + (shui/button {:variant :ghost :size :sm :class "h-6 px-2 gap-1"} + [:span.text-sm (or type-label "Empty")] + (shui/tabler-icon "chevron-down" {:size 14}))) + (shui/dropdown-menu-content + {:align "start"} + (doall + (for [{:keys [value label]} default-icon-type-options] + (shui/dropdown-menu-item + {:key (name value) + :onSelect (fn [_e] (on-type-change value))} + [:span {:class (when (= value current-type) "font-medium")} label]))))) + ;; Icon picker (only for icon/emoji types) + (when (and has-value? shows-picker?) + [:span.text-muted-foreground.text-sm ">"]) + (cond + ;; No value set yet + (not has-value?) + nil + + ;; Icon/emoji type - show picker + shows-picker? + (icon-component/icon-picker current-value + {:disabled? config/publishing? + :del-btn? (some? (:id current-value)) + :on-chosen on-icon-chosen + :icon-props {:size 18}}) + + ;; Avatar/text type - show preview indicator + :else + [:span.text-muted-foreground.text-xs.italic + (case current-type + :avatar "(auto from title)" + :text "(auto from title)" + "")])])) + (defn select-type? [block property] (let [type (:logseq.property/type property)] @@ -1442,6 +1536,9 @@ (= :logseq.property/icon (:db/ident property)) (icon-row block editing?) + (= :logseq.property.class/default-icon (:db/ident property)) + (default-icon-row block editing?) + (and (= type :number) (not editing?) (not closed-values?)) (single-number-input block property value (:table-view? opts)) diff --git a/src/main/frontend/handler/property.cljs b/src/main/frontend/handler/property.cljs index 0aa894191f..624e5745bd 100644 --- a/src/main/frontend/handler/property.cljs +++ b/src/main/frontend/handler/property.cljs @@ -43,7 +43,7 @@ :logseq.property/page-tags :logseq.property.class/extends :logseq.property.class/bidirectional-property-title :logseq.property.class/enable-bidirectional? - :logseq.property.class/default-icon-type + :logseq.property.class/default-icon :logseq.property/publishing-public? :logseq.property.user/avatar :logseq.property.user/email :logseq.property.user/name}) diff --git a/src/main/frontend/worker/db/migrate.cljs b/src/main/frontend/worker/db/migrate.cljs index cf1e1643ca..9be167acbe 100644 --- a/src/main/frontend/worker/db/migrate.cljs +++ b/src/main/frontend/worker/db/migrate.cljs @@ -197,6 +197,76 @@ updated-icon (assoc icon-value :data updated-data)] [:db/add entity-id :logseq.property/icon updated-icon]))))))))) +(defn- migrate-class-icons-to-default-icon-type-value + "Migrate class icons to use default-icon-type/default-icon-value. + For classes with tabler-icon or emoji icons, set default-icon-type to 'icon' or 'emoji' + and copy the icon to default-icon-value for inheritance to instances. + NOTE: This is an intermediate migration step, later consolidated into default-icon." + [db] + (let [;; Get the closed value entities for default-icon-type + icon-type-entity (db-property/get-closed-value-entity-by-name + db :logseq.property.class/default-icon-type "icon") + emoji-type-entity (db-property/get-closed-value-entity-by-name + db :logseq.property.class/default-icon-type "emoji")] + (->> (d/datoms db :avet :logseq.property/icon) + (mapcat (fn [datom] + (let [icon-value (:v datom) + entity-id (:e datom) + entity (d/entity db entity-id)] + ;; Only process classes that have icons + (when (and (map? icon-value) + (ldb/class? entity) + ;; Don't override if already set + (nil? (:logseq.property.class/default-icon-type entity))) + (let [icon-type (:type icon-value)] + (cond + ;; Tabler icons -> default-icon-type "icon" + (= :tabler-icon icon-type) + (when icon-type-entity + [[:db/add entity-id :logseq.property.class/default-icon-type (:db/id icon-type-entity)] + [:db/add entity-id :logseq.property.class/default-icon-value icon-value]]) + + ;; Emoji icons -> default-icon-type "emoji" + (= :emoji icon-type) + (when emoji-type-entity + [[:db/add entity-id :logseq.property.class/default-icon-type (:db/id emoji-type-entity)] + [:db/add entity-id :logseq.property.class/default-icon-value icon-value]]) + + ;; Other types (avatar, text) - skip, as they're handled differently + :else nil))))))))) + +(defn- migrate-to-unified-default-icon + "Migrate from two-property system (default-icon-type + default-icon-value) + to unified single property (default-icon). + Also migrates classes with :logseq.property/icon to use default-icon." + [db] + (let [tx-data + (->> (d/datoms db :avet :logseq.property/icon) + (mapcat (fn [datom] + (let [icon-value (:v datom) + entity-id (:e datom) + entity (d/entity db entity-id)] + ;; Only process classes that have icons + (when (and (map? icon-value) + (ldb/class? entity) + ;; Don't override if already set + (nil? (:logseq.property.class/default-icon entity))) + ;; Set the unified default-icon property + [[:db/add entity-id :logseq.property.class/default-icon icon-value]])))))] + ;; Also migrate any existing default-icon-type avatar/text settings + (concat tx-data + (->> (d/datoms db :avet :logseq.property.class/default-icon-type) + (keep (fn [datom] + (let [entity-id (:e datom) + entity (d/entity db entity-id) + type-entity (:logseq.property.class/default-icon-type entity) + type-value (or (:block/title type-entity) (:logseq.property/value type-entity))] + ;; For avatar/text types, create the marker icon + (when (and (contains? #{"avatar" "text"} type-value) + (nil? (:logseq.property.class/default-icon entity))) + [:db/add entity-id :logseq.property.class/default-icon + {:type (keyword type-value)}])))))))) + (def schema-version->updates "A vec of tuples defining datascript migrations. Each tuple consists of the schema version integer and a migration map. A migration map can have keys of :properties, :classes @@ -219,7 +289,15 @@ ["65.19" {:properties [:logseq.property/choice-classes :logseq.property/choice-exclusions]}] ["65.20" {:properties [:logseq.property.class/bidirectional-property-title :logseq.property.class/enable-bidirectional?]}] ["65.21" {:properties [:logseq.property.class/default-icon-type]}] - ["65.22" {:fix migrate-icon-colors}]]) + ["65.22" {:fix migrate-icon-colors}] + ["65.23" {:properties [:logseq.property.class/default-icon-value]}] + ["65.24" {:fix migrate-class-icons-to-default-icon-type-value}] + ["65.25" {:properties [:logseq.property.class/default-icon] + :fix migrate-to-unified-default-icon}] + ;; 65.26: Update default-icon property type from :default to :map so it can store map values + ["65.26" {:fix (fn [db] + (when-let [property (d/entity db :logseq.property.class/default-icon)] + [[:db/add (:db/id property) :logseq.property/type :map]]))}]]) (let [[major minor] (last (sort (map (comp (juxt :major :minor) db-schema/parse-schema-version first) schema-version->updates)))] diff --git a/src/resources/dicts/en.edn b/src/resources/dicts/en.edn index 5c65e73765..868a625e90 100644 --- a/src/resources/dicts/en.edn +++ b/src/resources/dicts/en.edn @@ -159,6 +159,8 @@ :content/replace-with-text "Replace with text" :content/replace-with-embed "Replace with embed" :content/open-in-sidebar "Open in sidebar" + :content/set-icon "Set icon" + :content/change-icon "Change icon" :content/click-to-edit "Click to edit" :context-menu/make-a-flashcard "Make a Flashcard" :context-menu/toggle-number-list "Toggle number list"