From 4ad4057878e0d3bd9475ef17e161039487f5d1a0 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 3 Sep 2024 11:59:33 +0200 Subject: [PATCH] :recycle: Refactor page options data structure --- common/src/app/common/files/builder.cljc | 42 ++--- common/src/app/common/files/changes.cljc | 144 ++++++++++++++++-- .../src/app/common/files/changes_builder.cljc | 128 +++++++++++----- common/src/app/common/files/defaults.cljc | 2 +- common/src/app/common/files/migrations.cljc | 27 +++- common/src/app/common/files/page_diff.cljc | 4 +- common/src/app/common/logic/libraries.cljc | 86 +++++------ common/src/app/common/logic/shapes.cljc | 48 +++--- common/src/app/common/types/grid.cljc | 25 ++- common/src/app/common/types/page.cljc | 66 ++++---- common/test/common_tests/pages_test.cljc | 65 -------- frontend/src/app/main/data/comments.cljs | 10 +- frontend/src/app/main/data/workspace.cljs | 4 +- .../src/app/main/data/workspace/comments.cljs | 52 ++++--- .../src/app/main/data/workspace/grid.cljs | 29 +--- .../src/app/main/data/workspace/guides.cljs | 35 +++-- .../app/main/data/workspace/interactions.cljs | 59 +++---- .../main/data/workspace/state_helpers.cljs | 13 +- .../app/main/data/workspace/thumbnails.cljs | 9 +- frontend/src/app/main/refs.cljs | 6 +- frontend/src/app/main/render.cljs | 4 +- frontend/src/app/main/ui/shapes/export.cljs | 14 +- frontend/src/app/main/ui/viewer/comments.cljs | 2 +- .../src/app/main/ui/viewer/interactions.cljs | 13 +- .../app/main/ui/workspace/context_menu.cljs | 19 ++- .../sidebar/options/menus/frame_grid.cljs | 17 ++- .../sidebar/options/menus/interactions.cljs | 25 +-- .../ui/workspace/sidebar/options/page.cljs | 16 +- .../src/app/main/ui/workspace/viewport.cljs | 29 ++-- .../main/ui/workspace/viewport/comments.cljs | 3 +- .../main/ui/workspace/viewport/guides.cljs | 113 +++++++------- .../ui/workspace/viewport/pixel_overlay.cljs | 6 +- .../main/ui/workspace/viewport/widgets.cljs | 1 + frontend/src/app/plugins/page.cljs | 14 +- frontend/src/app/plugins/utils.cljs | 2 +- frontend/src/app/util/snap_data.cljs | 4 +- frontend/src/app/worker/import.cljs | 28 ++-- frontend/src/app/worker/import/parser.cljs | 8 +- frontend/src/app/worker/thumbnails.cljs | 3 +- .../logic/frame_guides_test.cljs | 1 - .../frontend_tests/util_snap_data_test.cljs | 8 +- 41 files changed, 659 insertions(+), 525 deletions(-) diff --git a/common/src/app/common/files/builder.cljc b/common/src/app/common/files/builder.cljc index 988164c20..01a39f5eb 100644 --- a/common/src/app/common/files/builder.cljc +++ b/common/src/app/common/files/builder.cljc @@ -741,46 +741,36 @@ (defn add-guide [file guide] - (let [guide (cond-> guide (nil? (:id guide)) (assoc :id (uuid/next))) - page-id (:current-page-id file) - old-guides (or (dm/get-in file [:data :pages-index page-id :options :guides]) {}) - new-guides (assoc old-guides (:id guide) guide)] + page-id (:current-page-id file)] (-> file (commit-change - {:type :set-option + {:type :set-guide :page-id page-id - :option :guides - :value new-guides}) + :id (:id guide) + :params guide}) (assoc :last-id (:id guide))))) (defn delete-guide [file id] - (let [page-id (:current-page-id file) - old-guides (or (dm/get-in file [:data :pages-index page-id :options :guides]) {}) - new-guides (dissoc old-guides id)] - (-> file - (commit-change - {:type :set-option - :page-id page-id - :option :guides - :value new-guides})))) + (let [page-id (:current-page-id file)] + (commit-change file + {:type :set-guide + :page-id page-id + :id id + :params nil}))) (defn update-guide [file guide] - - (let [page-id (:current-page-id file) - old-guides (or (dm/get-in file [:data :pages-index page-id :options :guides]) {}) - new-guides (assoc old-guides (:id guide) guide)] - (-> file - (commit-change - {:type :set-option - :page-id page-id - :option :guides - :value new-guides})))) + (let [page-id (:current-page-id file)] + (commit-change file + {:type :set-guide + :page-id page-id + :id (:id guide) + :params guide}))) (defn strip-image-extension [filename] (let [image-extensions-re #"(\.png)|(\.jpg)|(\.jpeg)|(\.webp)|(\.gif)|(\.svg)$"] diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index 9df975937..f861cf3f1 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -10,21 +10,25 @@ [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.files.helpers :as cfh] + [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.schema :as sm] [app.common.schema.desc-native :as smd] + [app.common.schema.generators :as sg] [app.common.types.color :as ctc] [app.common.types.colors-list :as ctcl] [app.common.types.component :as ctk] [app.common.types.components-list :as ctkl] [app.common.types.container :as ctn] [app.common.types.file :as ctf] + [app.common.types.grid :as ctg] [app.common.types.page :as ctp] [app.common.types.pages-list :as ctpl] [app.common.types.shape :as cts] [app.common.types.shape-tree :as ctst] [app.common.types.typographies-list :as ctyl] [app.common.types.typography :as ctt] + [app.common.uuid :as uuid] [clojure.set :as set])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -60,6 +64,44 @@ [:type [:= :set-remote-synced]] [:remote-synced {:optional true} [:maybe :boolean]]]]]) +(defn- set-default-grid-change-generator + [] + (->> (sg/elements #{:square :column :row}) + (sg/mcat (fn [type] + (sg/fmap (fn [params] + {:page-id (uuid/next) + :type :mod-grid + :grid-type type + :params params}) + + (case type + :square (sg/generator ctg/schema:square-params) + :column (sg/generator ctg/schema:column-params) + :row (sg/generator ctg/schema:column-params))))))) + +(def schema:set-default-grid-change + [:multi {:decode/json #(update % :grid-type keyword) + :gen/gen (set-default-grid-change-generator) + :dispatch :grid-type + ::smd/simplified true} + [:square + [:map + [:page-id ::sm/uuid] + [:grid-type [:and :keyword [:= :square]]] + [:params [:maybe ctg/schema:square-params]]]] + + [:column + [:map + [:page-id ::sm/uuid] + [:grid-type [:and :keyword [:= :column]]] + [:params [:maybe ctg/schema:column-params]]]] + + [:row + [:map + [:page-id ::sm/uuid] + [:grid-type [:and :keyword [:= :row]]] + [:params [:maybe ctg/schema:column-params]]]]]) + (def schema:change [:schema [:multi {:dispatch :type @@ -67,13 +109,18 @@ :decode/json #(update % :type keyword) ::smd/simplified true} [:set-option - [:map {:title "SetOptionChange"} - [:type [:= :set-option]] + + ;; DEPRECATED: remove before 2.3 release + ;; + ;; Is still there for not cause error when event is received + [:map {:title "SetOptionChange"}]] + + [:set-comment-thread-position + [:map + [:comment-thread-id ::sm/uuid] [:page-id ::sm/uuid] - [:option [:union - [:keyword] - [:vector {:gen/max 10} :keyword]]] - [:value :any]]] + [:frame-id [:maybe ::sm/uuid]] + [:position [:maybe ::gpt/point]]]] [:add-obj [:map {:title "AddObjChange"} @@ -103,6 +150,22 @@ [:component-id {:optional true} ::sm/uuid] [:ignore-touched {:optional true} :boolean]]] + [:set-guide + [:map {:title "SetGuideChange"} + [:page-id ::sm/uuid] + [:id ::sm/uuid] + [:params [:maybe ::ctp/guide]]]] + + [:set-flow + [:map {:title "SetFlowChange"} + [:page-id ::sm/uuid] + [:id ::sm/uuid] + [:params [:maybe ::ctp/flow]]]] + + ;; Change used for all crud operation on persisted grid options on + ;; the page. + [:set-default-grid schema:set-default-grid-change] + [:fix-obj [:map {:title "FixObjChange"} [:type [:= :fix-obj]] @@ -143,7 +206,10 @@ [:map {:title "ModPageChange"} [:type [:= :mod-page]] [:id ::sm/uuid] - [:name :string]]] + ;; All props are optional, background can be nil because is the + ;; way to remove already set background + [:background {:optional true} [:maybe ::ctc/rgb-color]] + [:name {:optional true} :string]]] [:mod-plugin-data [:map {:title "ModPagePluginData"} @@ -356,14 +422,49 @@ #?(:clj (validate-shapes! data result items)) result)))) +;; DEPRECATED: remove before 2.3 release (defmethod process-change :set-option - [data {:keys [page-id option value]}] + [data _] + data) + +;; --- Comment Threads + +(defmethod process-change :set-comment-thread-position + [data {:keys [page-id comment-thread-id position frame-id]}] (d/update-in-when data [:pages-index page-id] - (fn [data] - (let [path (if (seqable? option) option [option])] - (if value - (assoc-in data (into [:options] path) value) - (assoc data :options (d/dissoc-in (:options data) path))))))) + (fn [page] + (if (and position frame-id) + (update page :comment-thread-positions assoc + comment-thread-id {:frame-id frame-id + :position position}) + (update page :comment-thread-positions dissoc + comment-thread-id))))) + +;; --- Guides + +(defmethod process-change :set-guide + [data {:keys [page-id id params]}] + (if (nil? params) + (d/update-in-when data [:pages-index page-id] update :guides dissoc id) + (d/update-in-when data [:pages-index page-id] update :guides assoc id params))) + +;; --- Flows + +(defmethod process-change :set-flow + [data {:keys [page-id id params]}] + (if (nil? params) + (d/update-in-when data [:pages-index page-id] update :flows dissoc id) + (d/update-in-when data [:pages-index page-id] update :flows assoc id params))) + +;; --- Grids + +(defmethod process-change :set-default-grid + [data {:keys [page-id grid-type params]}] + (if (nil? params) + (d/update-in-when data [:pages-index page-id] update :default-grids dissoc grid-type) + (d/update-in-when data [:pages-index page-id] update :default-grids assoc grid-type params))) + +;; --- Shape / Obj (defmethod process-change :add-obj [data {:keys [id obj page-id component-id frame-id parent-id index ignore-touched]}] @@ -603,8 +704,20 @@ (ctpl/add-page data page))) (defmethod process-change :mod-page - [data {:keys [id name]}] - (d/update-in-when data [:pages-index id] assoc :name name)) + [data {:keys [id] :as params}] + (d/update-in-when data [:pages-index id] + (fn [page] + (let [name (get params :name) + bg (get params :background :not-found)] + (cond-> page + (string? name) + (assoc :name name) + + (string? bg) + (assoc :background bg) + + (nil? bg) + (dissoc :background)))))) (defmethod process-change :mod-plugin-data [data {:keys [object-type object-id page-id namespace key value]}] @@ -660,6 +773,7 @@ [data _] data) + ;; -- Media (defmethod process-change :add-media diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 9c613a91d..4aa995ee8 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -135,12 +135,6 @@ (or (contains? (meta changes) ::page-id) (contains? (meta changes) ::component-id)))) -(defn- assert-page! - [changes] - (dm/assert! - "Call (with-page) before using this function" - (contains? (meta changes) ::page))) - (defn- assert-objects! [changes] (dm/assert! @@ -195,11 +189,30 @@ (apply-changes-local))) (defn mod-page - [changes page new-name] - (-> changes - (update :redo-changes conj {:type :mod-page :id (:id page) :name new-name}) - (update :undo-changes conj {:type :mod-page :id (:id page) :name (:name page)}) - (apply-changes-local))) + ([changes options] + (let [page (::page (meta changes))] + (mod-page changes page options))) + + ([changes page {:keys [name background]}] + (let [change {:type :mod-page :id (:id page)} + redo (cond-> change + (some? name) + (assoc :name name) + + (some? background) + (assoc :background background)) + + undo (cond-> change + (some? name) + (assoc :name (:name page)) + + (some? background) + (assoc :background (:background page)))] + + (-> changes + (update :redo-changes conj redo) + (update :undo-changes conj undo) + (apply-changes-local))))) (defn mod-plugin-data ([changes namespace key value] @@ -246,42 +259,77 @@ (update :undo-changes conj {:type :mov-page :id page-id :index prev-index}) (apply-changes-local))) -(defn set-page-option - [changes option-key option-val] - (assert-page! changes) + +(defn set-guide + [changes id guide] (let [page-id (::page-id (meta changes)) - page (::page (meta changes)) - old-val (get-in page [:options option-key])] + page (::page (meta changes)) + old-val (dm/get-in page [:guides id])] (-> changes - (update :redo-changes conj {:type :set-option + (update :redo-changes conj {:type :set-guide :page-id page-id - :option option-key - :value option-val}) - (update :undo-changes conj {:type :set-option + :id id + :params guide}) + (update :undo-changes conj {:type :set-guide :page-id page-id - :option option-key - :value old-val}) - (apply-changes-local)))) - -(defn update-page-option - [changes option-key update-fn & args] - (assert-page! changes) + :id id + :params old-val})))) +(defn set-flow + [changes id flow] (let [page-id (::page-id (meta changes)) - page (::page (meta changes)) - old-val (get-in page [:options option-key]) - new-val (apply update-fn old-val args)] + page (::page (meta changes)) + old-val (dm/get-in page [:flows id]) - (-> changes - (update :redo-changes conj {:type :set-option - :page-id page-id - :option option-key - :value new-val}) - (update :undo-changes conj {:type :set-option - :page-id page-id - :option option-key - :value old-val}) - (apply-changes-local)))) + changes (-> changes + (update :redo-changes conj {:type :set-flow + :page-id page-id + :id id + :params flow}) + (update :undo-changes conj {:type :set-flow + :page-id page-id + :id id + :params old-val}))] + ;; FIXME: not sure if we need this + (apply-changes-local changes))) + +(defn set-comment-thread-position + [changes {:keys [id frame-id position] :as thread}] + (let [page-id (::page-id (meta changes)) + page (::page (meta changes)) + + old-val (dm/get-in page [:comment-thread-positions id]) + + changes (-> changes + (update :redo-changes conj {:type :set-comment-thread-position + :comment-thread-id id + :page-id page-id + :frame-id frame-id + :position position}) + (update :undo-changes conj {:type :set-comment-thread-position + :page-id page-id + :comment-thread-id id + :frame-id (:frame-id old-val) + :position (:position old-val)}))] + ;; FIXME: not sure if we need this + (apply-changes-local changes))) + +(defn set-default-grid + [changes type params] + (let [page-id (::page-id (meta changes)) + page (::page (meta changes)) + old-val (dm/get-in page [:grids type]) + + changes (update changes :redo-changes conj {:type :set-default-grid + :page-id page-id + :grid-type type + :params params}) + changes (update changes :undo-changes conj {:type :set-default-grid + :page-id page-id + :grid-type type + :params old-val})] + ;; FIXME: not sure if we need this + (apply-changes-local changes))) ;; Shape tree changes diff --git a/common/src/app/common/files/defaults.cljc b/common/src/app/common/files/defaults.cljc index 6ef70b5ea..4c2dd1d96 100644 --- a/common/src/app/common/files/defaults.cljc +++ b/common/src/app/common/files/defaults.cljc @@ -6,4 +6,4 @@ (ns app.common.files.defaults) -(def version 51) +(def version 52) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 111d05072..2570c31fc 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -1017,6 +1017,30 @@ (into {} (filter #(-> % val valid-color?) colors)))] (update data :colors update-colors))) +(defn migrate-up-52 + "This migration moves page options to the page level" + [data] + (let [update-page + (fn [{:keys [options] :as page}] + (cond-> page + (and (some? (:saved-grids options)) + (not (contains? page :default-grids))) + (assoc :default-grids (:saved-grids options)) + + (and (some? (:flows options)) + (not (contains? page :flows))) + (assoc :flows (:flows options)) + + (and (some? (:guides options)) + (not (contains? page :guides))) + (assoc :guides (:guides options)) + + (and (some? (:comment-threads-position options)) + (not (contains? page :comment-thread-positions))) + (assoc :comment-thread-positions (:comment-threads-position options))))] + + (update data :pages-index d/update-vals update-page))) + (def migrations "A vector of all applicable migrations" [{:id 2 :migrate-up migrate-up-2} @@ -1059,4 +1083,5 @@ {:id 48 :migrate-up migrate-up-48} {:id 49 :migrate-up migrate-up-49} {:id 50 :migrate-up migrate-up-50} - {:id 51 :migrate-up migrate-up-51}]) + {:id 51 :migrate-up migrate-up-51} + {:id 52 :migrate-up migrate-up-52}]) diff --git a/common/src/app/common/files/page_diff.cljc b/common/src/app/common/files/page_diff.cljc index e347309ec..821238b95 100644 --- a/common/src/app/common/files/page_diff.cljc +++ b/common/src/app/common/files/page_diff.cljc @@ -15,10 +15,10 @@ [old-page page check-attrs] (let [old-objects (get old-page :objects) - old-guides (or (get-in old-page [:options :guides]) []) + old-guides (or (get old-page :guides) []) new-objects (get page :objects) - new-guides (or (get-in page [:options :guides]) []) + new-guides (or (get page :guides) []) changed-object? (fn [id] diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index 85382be2c..25cf38cca 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -1947,54 +1947,54 @@ (defn generate-duplicate-flows [changes shapes page ids-map] - (let [flows (-> page :options :flows) - unames (volatile! (into #{} (map :name flows))) - frames-with-flow (->> shapes - (filter #(= (:type %) :frame)) - (filter #(some? (ctp/get-frame-flow flows (:id %)))))] - (if-not (empty? frames-with-flow) - (let [update-flows (fn [flows] - (reduce - (fn [flows frame] - (let [name (cfh/generate-unique-name @unames "Flow 1") - _ (vswap! unames conj name) - new-flow {:id (uuid/next) - :name name - :starting-frame (get ids-map (:id frame))}] - (ctp/add-flow flows new-flow))) - flows - frames-with-flow))] - (pcb/update-page-option changes :flows update-flows)) - changes))) + (let [flows (get page :flows) + unames (volatile! (cfh/get-used-names (vals flows))) + has-flow? (partial ctp/get-frame-flow flows)] + + (reduce (fn [changes frame-id] + (let [name (cfh/generate-unique-name @unames "Flow 1") + frame-id (get ids-map frame-id) + flow-id (uuid/next) + new-flow {:id flow-id + :name name + :starting-frame frame-id}] + + (vswap! unames conj name) + (pcb/set-flow changes flow-id new-flow))) + + changes + (->> shapes + (filter cfh/frame-shape?) + (map :id) + (filter has-flow?))))) (defn generate-duplicate-guides [changes shapes page ids-map delta] - (let [guides (get-in page [:options :guides]) - frames (->> shapes (filter cfh/frame-shape?)) + (let [guides (get page :guides) + frames (filter cfh/frame-shape? shapes)] - new-guides - (reduce - (fn [g frame] - (let [new-id (ids-map (:id frame)) - new-frame (-> frame (gsh/move delta)) + ;; FIXME: this can be implemented efficiently just indexing guides + ;; by frame-id instead of iterate over all guides all the time - new-guides - (->> guides - (vals) - (filter #(= (:frame-id %) (:id frame))) - (map #(-> % - (assoc :id (uuid/next)) - (assoc :frame-id new-id) - (assoc :position (if (= (:axis %) :x) - (+ (:position %) (- (:x new-frame) (:x frame))) - (+ (:position %) (- (:y new-frame) (:y frame))))))))] - (cond-> g - (not-empty new-guides) - (conj (into {} (map (juxt :id identity) new-guides)))))) - guides - frames)] - (-> (pcb/with-page changes page) - (pcb/set-page-option :guides new-guides)))) + (reduce (fn [changes frame] + (let [new-id (get ids-map (:id frame)) + new-frame (gsh/move frame delta)] + + (reduce-kv (fn [changes _ guide] + (if (= (:id frame) (:frame-id guide)) + (let [guide-id (uuid/next) + position (if (= (:axis guide) :x) + (+ (:position guide) (- (:x new-frame) (:x frame))) + (+ (:position guide) (- (:y new-frame) (:y frame)))) + guide {:id guide-id + :frame-id new-id + :position position}] + (pcb/set-guide changes guide-id guide)) + changes)) + changes + guides))) + (pcb/with-page changes page) + frames))) (defn generate-duplicate-component-change [changes objects page component-root parent-id frame-id delta libraries library-data] diff --git a/common/src/app/common/logic/shapes.cljc b/common/src/app/common/logic/shapes.cljc index f5d38f0c2..6f9897f08 100644 --- a/common/src/app/common/logic/shapes.cljc +++ b/common/src/app/common/logic/shapes.cljc @@ -7,13 +7,11 @@ (ns app.common.logic.shapes (:require [app.common.data :as d] - [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] [app.common.geom.shapes :as gsh] [app.common.types.component :as ctk] [app.common.types.container :as ctn] - [app.common.types.page :as ctp] [app.common.types.shape.interactions :as ctsi] [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid])) @@ -85,7 +83,9 @@ (pcb/with-page page) (pcb/with-objects objects) (pcb/with-library-data file)) + lookup (d/getf objects) + groups-to-unmask (reduce (fn [group-ids id] ;; When the shape to delete is the mask of a masked group, @@ -110,23 +110,14 @@ interactions))) (vals objects)) - ids-set (set ids-to-delete) - guides-to-remove - (->> (dm/get-in page [:options :guides]) - (vals) - (filter #(contains? ids-set (:frame-id %))) - (map :id)) + changes + (reduce (fn [changes {:keys [id] :as flow}] + (if (contains? ids-to-delete (:starting-frame flow)) + (pcb/set-flow changes id nil) + changes)) + changes + (:flows page)) - guides - (->> guides-to-remove - (reduce dissoc (dm/get-in page [:options :guides]))) - - starting-flows - (filter (fn [flow] - ;; If any of the deleted is a frame that starts a flow, - ;; this must be deleted, too. - (contains? ids-to-delete (:starting-frame flow))) - (-> page :options :flows)) all-parents (reduce (fn [res id] @@ -172,8 +163,18 @@ (into ids-to-delete all-children)) []) - changes (-> changes - (pcb/set-page-option :guides guides)) + ids-set (set ids-to-delete) + + guides-to-delete + (->> (:guides page) + (vals) + (filter #(contains? ids-set (:frame-id %))) + (map :id)) + + changes (reduce (fn [changes guide-id] + (pcb/set-flow changes guide-id nil)) + changes + guides-to-delete) changes (reduce (fn [changes component-id] ;; It's important to delete the component before the main instance, because we @@ -181,6 +182,7 @@ (pcb/delete-component changes component-id (:id page))) changes components-to-delete) + changes (-> changes (generate-update-shape-flags ids-to-hide objects {:hidden true}) (pcb/remove-objects all-children {:ignore-touched true}) @@ -197,11 +199,7 @@ (into [] (remove #(and (ctsi/has-destination %) (contains? ids-to-delete (:destination %)))) - interactions))))) - (cond-> (seq starting-flows) - (pcb/update-page-option :flows (fn [flows] - (->> (map :id starting-flows) - (reduce ctp/remove-flow flows))))))] + interactions))))))] [all-parents changes])) diff --git a/common/src/app/common/types/grid.cljc b/common/src/app/common/types/grid.cljc index 41e7d1c15..45a73383f 100644 --- a/common/src/app/common/types/grid.cljc +++ b/common/src/app/common/types/grid.cljc @@ -6,6 +6,7 @@ (ns app.common.types.grid (:require + [app.common.colors :as clr] [app.common.schema :as sm] [app.common.types.color :as ctc])) @@ -54,7 +55,7 @@ [:display :boolean] [:params schema:square-params]]]]) -(def schema:saved-grids +(def schema:default-grids [:map {:title "PageGrid"} [:square {:optional true} ::square-params] [:row {:optional true} ::column-params] @@ -63,4 +64,24 @@ (sm/register! ::square-params schema:square-params) (sm/register! ::column-params schema:column-params) (sm/register! ::grid schema:grid) -(sm/register! ::saved-grids schema:saved-grids) +(sm/register! ::default-grids schema:default-grids) + +(def ^:private default-square-params + {:size 16 + :color {:color clr/info + :opacity 0.4}}) + +(def ^:private default-layout-params + {:size 12 + :type :stretch + :item-length nil + :gutter 8 + :margin 0 + :color {:color clr/default-layout + :opacity 0.1}}) + +(def default-grid-params + {:square default-square-params + :column default-layout-params + :row default-layout-params}) + diff --git a/common/src/app/common/types/page.cljc b/common/src/app/common/types/page.cljc index b49755115..3af84b406 100644 --- a/common/src/app/common/types/page.cljc +++ b/common/src/app/common/types/page.cljc @@ -7,6 +7,7 @@ (ns app.common.types.page (:require [app.common.data :as d] + [app.common.geom.point :as-alias gpt] [app.common.schema :as sm] [app.common.types.color :as-alias ctc] [app.common.types.grid :as ctg] @@ -24,38 +25,56 @@ [:name :string] [:starting-frame ::sm/uuid]]) +(def schema:flows + [:map-of {:gen/max 2} ::sm/uuid schema:flow]) + (def schema:guide [:map {:title "Guide"} [:id ::sm/uuid] [:axis [::sm/one-of #{:x :y}]] [:position ::sm/safe-number] + ;; FIXME: remove maybe? [:frame-id {:optional true} [:maybe ::sm/uuid]]]) +(def schema:guides + [:map-of {:gen/max 2} ::sm/uuid schema:guide]) + +(def schema:objects + [:map-of {:gen/max 5} ::sm/uuid ::cts/shape]) + +(def schema:comment-thread-position + [:map {:title "CommentThreadPosition"} + [:frame-id ::sm/uuid] + [:position ::gpt/point]]) + (def schema:page [:map {:title "FilePage"} [:id ::sm/uuid] [:name :string] - [:objects - [:map-of {:gen/max 5} ::sm/uuid ::cts/shape]] + [:objects schema:objects] + [:default-grids {:optional true} ::ctg/default-grids] + [:flows {:optional true} schema:flows] + [:guides {:optional true} schema:guides] + [:plugin-data {:optional true} ::ctpg/plugin-data] + [:background {:optional true} ::ctc/rgb-color] + + [:comment-thread-positions {:optional true} + [:map-of ::sm/uuid schema:comment-thread-position]] + [:options - [:map {:title "PageOptions"} - [:background {:optional true} ::ctc/rgb-color] - [:saved-grids {:optional true} ::ctg/saved-grids] - [:flows {:optional true} - [:vector {:gen/max 2} schema:flow]] - [:guides {:optional true} - [:map-of {:gen/max 2} ::sm/uuid schema:guide]] - [:plugin-data {:optional true} ::ctpg/plugin-data]]]]) + ;; DEPERECATED: remove after 2.3 release + [:map {:title "PageOptions"}]]]) (sm/register! ::page schema:page) (sm/register! ::guide schema:guide) (sm/register! ::flow schema:flow) -(def check-page-guide! - (sm/check-fn ::guide)) +(def valid-guide? + (sm/lazy-validator schema:guide)) +;; FIXME: convert to validator (def check-page! - (sm/check-fn ::page)) + (sm/check-fn schema:page)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; INIT & HELPERS @@ -80,25 +99,6 @@ (assoc :id (or id (uuid/next))) (assoc :name (or name "Page 1")))) -;; --- Helpers for flow - -(defn rename-flow - [flow name] - (assoc flow :name name)) - -(defn add-flow - [flows flow] - (conj (or flows []) flow)) - -(defn remove-flow - [flows flow-id] - (d/removev #(= (:id %) flow-id) flows)) - -(defn update-flow - [flows flow-id update-fn] - (let [index (d/index-of-pred flows #(= (:id %) flow-id))] - (update flows index update-fn))) - (defn get-frame-flow [flows frame-id] - (d/seek #(= (:starting-frame %) frame-id) flows)) + (d/seek #(= (:starting-frame %) frame-id) (vals flows))) diff --git a/common/test/common_tests/pages_test.cljc b/common/test/common_tests/pages_test.cljc index 146242c26..38e2ffb2d 100644 --- a/common/test/common_tests/pages_test.cljc +++ b/common/test/common_tests/pages_test.cljc @@ -19,71 +19,6 @@ (binding [ffeat/*current* #{"components/v2"}] (ctf/make-file-data file-id page-id))) -(t/deftest process-change-set-option - (let [file-id (uuid/custom 2 2) - page-id (uuid/custom 1 1) - data (make-file-data file-id page-id)] - (t/testing "Sets option single" - (let [chg {:type :set-option - :page-id page-id - :option :test - :value "test"} - res (ch/process-changes data [chg])] - (t/is (= "test" (get-in res [:pages-index page-id :options :test]))))) - - (t/testing "Sets option nested" - (let [chgs [{:type :set-option - :page-id page-id - :option [:values :test :a] - :value "a"} - {:type :set-option - :page-id page-id - :option [:values :test :b] - :value "b"}] - res (ch/process-changes data chgs)] - (t/is (= {:a "a" :b "b"} - (get-in res [:pages-index page-id :options :values :test]))))) - - (t/testing "Remove option single" - (let [chg {:type :set-option - :page-id page-id - :option :test - :value nil} - res (ch/process-changes data [chg])] - (t/is (empty? (keys (get-in res [:pages-index page-id :options])))))) - - (t/testing "Remove option nested 1" - (let [chgs [{:type :set-option - :page-id page-id - :option [:values :test :a] - :value "a"} - {:type :set-option - :page-id page-id - :option [:values :test :b] - :value "b"} - {:type :set-option - :page-id page-id - :option [:values :test] - :value nil}] - res (ch/process-changes data chgs)] - (t/is (empty? (keys (get-in res [:pages-index page-id :options])))))) - - (t/testing "Remove option nested 2" - (let [chgs [{:type :set-option - :option [:values :test1 :a] - :page-id page-id - :value "a"} - {:type :set-option - :option [:values :test2 :b] - :page-id page-id - :value "b"} - {:type :set-option - :page-id page-id - :option [:values :test2] - :value nil}] - res (ch/process-changes data chgs)] - (t/is (= [:test1] (keys (get-in res [:pages-index page-id :options :values])))))))) - (t/deftest process-change-add-obj (let [file-id (uuid/custom 2 2) page-id (uuid/custom 1 1) diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs index 1a9b1dbae..f73836d65 100644 --- a/frontend/src/app/main/data/comments.cljs +++ b/frontend/src/app/main/data/comments.cljs @@ -65,7 +65,7 @@ (let [position (select-keys thread [:position :frame-id])] (-> state (update :comment-threads assoc id (dissoc thread :comment)) - (update-in [:workspace-data :pages-index page-id :options :comment-threads-position] assoc id position) + (update-in [:workspace-data :pages-index page-id :comment-thread-positions] assoc id position) (cond-> open? (update :comments-local assoc :open id)) (update :comments-local assoc :options nil) @@ -122,7 +122,7 @@ (let [position (select-keys thread [:position :frame-id])] (-> state (update :comment-threads assoc id (dissoc thread :comment)) - (update-in [:viewer :pages page-id :options :comment-threads-position] assoc id position) + (update-in [:viewer :pages page-id :comment-thread-positions] assoc id position) (update :comments-local assoc :open id) (update :comments-local assoc :options nil) (update :comments-local dissoc :draft) @@ -273,7 +273,7 @@ (update [_ state] (let [page-id (:current-page-id state)] (-> state - (update-in [:workspace-data :pages-index page-id :options :comment-threads-position] dissoc id) + (update-in [:workspace-data :pages-index page-id :comment-thread-positions] dissoc id) (update :comments dissoc id) (update :comment-threads dissoc id)))) @@ -299,7 +299,7 @@ (update [_ state] (let [page-id (:current-page-id state)] (-> state - (update-in [:viewer :pages page-id :options :comment-threads-position] dissoc id) + (update-in [:viewer :pages page-id :comment-thread-positions] dissoc id) (update :comments dissoc id) (update :comment-threads dissoc id)))) @@ -356,7 +356,7 @@ [file-id] (dm/assert! (uuid? file-id)) (letfn [(set-comment-threds [state comment-thread] - (let [path [:workspace-data :pages-index (:page-id comment-thread) :options :comment-threads-position (:id comment-thread)] + (let [path [:workspace-data :pages-index (:page-id comment-thread) :comment-thread-positions (:id comment-thread)] thread-position (get-in state path)] (cond-> state (nil? thread-position) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index f6a388de1..e0d8b0ef4 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -568,7 +568,7 @@ (watch [it state _] (let [page (get-in state [:workspace-data :pages-index id]) changes (-> (pcb/empty-changes it) - (pcb/mod-page page name))] + (pcb/mod-page page {:name name}))] (rx/of (dch/commit-changes changes)))))) @@ -2071,7 +2071,7 @@ page (wsh/lookup-page state page-id) changes (-> (pcb/empty-changes it) (pcb/with-page page) - (pcb/set-page-option :background (:color color)))] + (pcb/mod-page {:background (:color color)}))] (rx/of (dch/commit-changes changes))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs index 69e2a77eb..22491abe7 100644 --- a/frontend/src/app/main/data/workspace/comments.cljs +++ b/frontend/src/app/main/data/workspace/comments.cljs @@ -132,21 +132,20 @@ (ptk/reify ::update-comment-thread-position ptk/WatchEvent (watch [it state _] - (let [thread-id (:id thread) - page (wsh/lookup-page state) - page-id (:id page) - objects (wsh/lookup-page-objects state page-id) - new-frame-id (if (nil? frame-id) - (ctst/get-frame-id-by-position objects (gpt/point new-x new-y)) - (:frame-id thread)) - thread (assoc thread - :position (gpt/point new-x new-y) - :frame-id new-frame-id) + (let [page (wsh/lookup-page state) + page-id (:id page) + objects (wsh/lookup-page-objects state page-id) + frame-id (if (nil? frame-id) + (ctst/get-frame-id-by-position objects (gpt/point new-x new-y)) + (:frame-id thread)) - changes - (-> (pcb/empty-changes it) - (pcb/with-page page) - (pcb/update-page-option :comment-threads-position assoc thread-id (select-keys thread [:position :frame-id])))] + thread (-> thread + (assoc :position (gpt/point new-x new-y)) + (assoc :frame-id frame-id)) + + changes (-> (pcb/empty-changes it) + (pcb/with-page page) + (pcb/set-comment-thread-position thread))] (rx/merge (rx/of (dch/commit-changes changes)) @@ -164,25 +163,28 @@ (ptk/reify ::move-frame-comment-threads ptk/WatchEvent (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) + (let [page (wsh/lookup-page state) + objects (get page :objects) - is-frame? (fn [id] (= :frame (get-in objects [id :type]))) + is-frame? (fn [id] (= :frame (get-in objects [id :type]))) frame-ids? (into #{} (filter is-frame?) ids) - object-modifiers (:workspace-modifiers state) + threads-position-map + (get page :comment-thread-positions) - threads-position-map (:comment-threads-position (wsh/lookup-page-options state)) + object-modifiers + (:workspace-modifiers state) build-move-event (fn [comment-thread] - (let [frame (get objects (:frame-id comment-thread)) + (let [frame (get objects (:frame-id comment-thread)) modifiers (get-in object-modifiers [(:frame-id comment-thread) :modifiers]) - frame' (gsh/transform-shape frame modifiers) - moved (gpt/to-vec (gpt/point (:x frame) (:y frame)) - (gpt/point (:x frame') (:y frame'))) - position (get-in threads-position-map [(:id comment-thread) :position]) - new-x (+ (:x position) (:x moved)) - new-y (+ (:y position) (:y moved))] + frame' (gsh/transform-shape frame modifiers) + moved (gpt/to-vec (gpt/point (:x frame) (:y frame)) + (gpt/point (:x frame') (:y frame'))) + position (get-in threads-position-map [(:id comment-thread) :position]) + new-x (+ (:x position) (:x moved)) + new-y (+ (:y position) (:y moved))] (update-comment-thread-position comment-thread [new-x new-y] (:id frame))))] (->> (:comment-threads state) diff --git a/frontend/src/app/main/data/workspace/grid.cljs b/frontend/src/app/main/data/workspace/grid.cljs index beaff9e61..9183bc06c 100644 --- a/frontend/src/app/main/data/workspace/grid.cljs +++ b/frontend/src/app/main/data/workspace/grid.cljs @@ -6,10 +6,10 @@ (ns app.main.data.workspace.grid (:require - [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] + [app.common.types.grid :as ctg] [app.main.data.changes :as dch] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] @@ -20,25 +20,6 @@ ;; Grid ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defonce ^:private default-square-params - {:size 16 - :color {:color clr/info - :opacity 0.4}}) - -(defonce ^:private default-layout-params - {:size 12 - :type :stretch - :item-length nil - :gutter 8 - :margin 0 - :color {:color clr/default-layout - :opacity 0.1}}) - -(defonce default-grid-params - {:square default-square-params - :column default-layout-params - :row default-layout-params}) - (defn add-frame-grid [frame-id] (dm/assert! (uuid? frame-id)) @@ -46,9 +27,9 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - data (get-in state [:workspace-data :pages-index page-id]) - params (or (get-in data [:options :saved-grids :square]) - (:square default-grid-params)) + page (dm/get-in state [:workspace-data :pages-index page-id]) + params (or (dm/get-in page [:grids :square]) + (:square ctg/default-grid-params)) grid {:type :square :params params :display true}] @@ -79,4 +60,4 @@ (rx/of (dch/commit-changes (-> (pcb/empty-changes it) (pcb/with-page page) - (pcb/set-page-option [:saved-grids type] params)))))))) + (pcb/set-default-grid type params)))))))) diff --git a/frontend/src/app/main/data/workspace/guides.cljs b/frontend/src/app/main/data/workspace/guides.cljs index 4e2895bb2..6547d5772 100644 --- a/frontend/src/app/main/data/workspace/guides.cljs +++ b/frontend/src/app/main/data/workspace/guides.cljs @@ -17,18 +17,12 @@ [beicon.v2.core :as rx] [potok.v2.core :as ptk])) -(defn make-update-guide - [guide] - (fn [other] - (cond-> other - (= (:id other) (:id guide)) - (merge guide)))) - (defn update-guides - [guide] + [{:keys [id] :as guide}] + (dm/assert! "expected valid guide" - (ctp/check-page-guide! guide)) + (ctp/valid-guide? guide)) (ptk/reify ::update-guides ev/Event @@ -41,14 +35,15 @@ changes (-> (pcb/empty-changes it) (pcb/with-page page) - (pcb/update-page-option :guides assoc (:id guide) guide))] + (pcb/set-guide id guide))] (rx/of (dwc/commit-changes changes)))))) (defn remove-guide - [guide] + [{:keys [id] :as guide}] + (dm/assert! "expected valid guide" - (ctp/check-page-guide! guide)) + (ctp/valid-guide? guide)) (ptk/reify ::remove-guide ev/Event @@ -57,7 +52,7 @@ ptk/UpdateEvent (update [_ state] (let [sdisj (fnil disj #{})] - (update-in state [:workspace-guides :hover] sdisj (:id guide)))) + (update-in state [:workspace-guides :hover] sdisj id))) ptk/WatchEvent (watch [it state _] @@ -65,18 +60,22 @@ changes (-> (pcb/empty-changes it) (pcb/with-page page) - (pcb/update-page-option :guides dissoc (:id guide)))] + (pcb/set-guide id nil))] (rx/of (dwc/commit-changes changes)))))) (defn remove-guides [ids] + + (dm/assert! + "expected a set of ids" + (every? uuid? ids)) + (ptk/reify ::remove-guides ptk/WatchEvent (watch [_ state _] - (let [page (wsh/lookup-page state) - guides (get-in page [:options :guides] {}) + (let [{:keys [guides] :as page} (wsh/lookup-page state) guides (-> (select-keys guides ids) (vals))] - (rx/from (->> guides (mapv #(remove-guide %)))))))) + (rx/from (mapv remove-guide guides)))))) (defmethod ptk/resolve ::move-frame-guides [_ args] @@ -105,7 +104,7 @@ guide (update guide :position + (get moved (:axis guide)))] (update-guides guide))) - guides (-> state wsh/lookup-page-options :guides vals)] + guides (-> state wsh/lookup-page :guides vals)] (->> guides (filter (comp frame-ids? :frame-id)) diff --git a/frontend/src/app/main/data/workspace/interactions.cljs b/frontend/src/app/main/data/workspace/interactions.cljs index 2fb10ada8..b2387e270 100644 --- a/frontend/src/app/main/data/workspace/interactions.cljs +++ b/frontend/src/app/main/data/workspace/interactions.cljs @@ -43,18 +43,20 @@ (wsh/lookup-page state page-id) (wsh/lookup-page state)) - flows (get-in page [:options :flows] []) - unames (cfh/get-used-names flows) + flows (get page :flows) + unames (cfh/get-used-names (vals flows)) name (or name (cfh/generate-unique-name unames "Flow 1")) - new-flow {:id (or flow-id (uuid/next)) - :name name - :starting-frame starting-frame}] + flow-id (or flow-id (uuid/next)) + + flow {:id flow-id + :name name + :starting-frame starting-frame}] (rx/of (dch/commit-changes (-> (pcb/empty-changes it) (pcb/with-page page) - (pcb/update-page-option :flows ctp/add-flow new-flow))))))))) + (pcb/set-flow flow-id flow))))))))) (defn add-flow-selected-frame [] @@ -79,35 +81,40 @@ (rx/of (dch/commit-changes (-> (pcb/empty-changes it) (pcb/with-page page) - (pcb/update-page-option :flows ctp/remove-flow flow-id))))))))) + (pcb/set-flow flow-id nil))))))))) (defn update-flow [page-id flow-id update-fn] - (dm/assert! (uuid? flow-id)) + + (assert (uuid? flow-id) "expect valid flow-id") + (assert (uuid? page-id) "expect valid page-id") + (ptk/reify ::update-flow ptk/WatchEvent (watch [it state _] (let [page (if page-id (wsh/lookup-page state page-id) - (wsh/lookup-page state))] - (rx/of (dch/commit-changes - (-> (pcb/empty-changes it) - (pcb/with-page page) - (pcb/update-page-option :flows ctp/update-flow flow-id update-fn)))))))) + (wsh/lookup-page state)) + flow (dm/get-in page [:flows flow-id]) + flow (some-> flow update-fn)] + + (when (some? flow) + (rx/of (dch/commit-changes + (-> (pcb/empty-changes it) + (pcb/with-page page) + (pcb/set-flow flow-id flow))))))))) (defn rename-flow [flow-id name] - (dm/assert! (uuid? flow-id)) - (dm/assert! (string? name)) + + (assert (uuid? flow-id) "expected valid flow-id") + (assert (string? name) "expected valid name") + (ptk/reify ::rename-flow ptk/WatchEvent - (watch [it state _] + (watch [_ state _] (let [page (wsh/lookup-page state)] - (rx/of (dch/commit-changes - (-> (pcb/empty-changes it) - (pcb/with-page page) - (pcb/update-page-option :flows ctp/update-flow flow-id - #(ctp/rename-flow % name))))))))) + (rx/of (update-flow (:id page) flow-id #(assoc % :name name))))))) (defn start-rename-flow [id] @@ -153,13 +160,11 @@ ptk/WatchEvent (watch [_ state _] (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) + page (wsh/lookup-page state page-id) + objects (get page :objects) frame (cfh/get-root-frame objects (:id shape)) - flows (get-in state [:workspace-data - :pages-index - page-id - :options - :flows] []) + + flows (get page :objects) flow (ctp/get-frame-flow flows (:id frame))] (rx/concat (rx/of (dwsh/update-shapes [(:id shape)] diff --git a/frontend/src/app/main/data/workspace/state_helpers.cljs b/frontend/src/app/main/data/workspace/state_helpers.cljs index 7249a1f3f..6c55e9da8 100644 --- a/frontend/src/app/main/data/workspace/state_helpers.cljs +++ b/frontend/src/app/main/data/workspace/state_helpers.cljs @@ -20,15 +20,12 @@ ([state page-id] (get-in state [:workspace-data :pages-index page-id]))) -(defn lookup-data-objects - [data page-id] - (dm/get-in data [:pages-index page-id :objects])) - (defn lookup-page-objects ([state] (lookup-page-objects state (:current-page-id state))) ([state page-id] - (dm/get-in state [:workspace-data :pages-index page-id :objects]))) + (-> (lookup-page state page-id) + (get :objects)))) (defn lookup-viewer-objects ([state page-id] @@ -45,12 +42,6 @@ (lookup-page-objects state page-id) (lookup-library-objects state file-id page-id)))) -(defn lookup-page-options - ([state] - (lookup-page-options state (:current-page-id state))) - ([state page-id] - (dm/get-in state [:workspace-data :pages-index page-id :options]))) - (defn lookup-local-components ([state] (dm/get-in state [:workspace-data :components]))) diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs index 625c207c6..a043c3811 100644 --- a/frontend/src/app/main/data/workspace/thumbnails.cljs +++ b/frontend/src/app/main/data/workspace/thumbnails.cljs @@ -182,6 +182,11 @@ [page-id [event [old-data new-data]]] (let [changes (:changes event) + lookup-data-objects + (fn [data page-id] + (dm/get-in data [:pages-index page-id :objects])) + + extract-ids (fn [{:keys [page-id type] :as change}] (case type @@ -193,8 +198,8 @@ get-frame-ids (fn get-frame-ids [id] - (let [old-objects (wsh/lookup-data-objects old-data page-id) - new-objects (wsh/lookup-data-objects new-data page-id) + (let [old-objects (lookup-data-objects old-data page-id) + new-objects (lookup-data-objects new-data page-id) new-shape (get new-objects id) old-shape (get old-objects id) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index c0f32f643..61a26b262 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -281,6 +281,9 @@ (dm/get-in data [:pages-index page-id]))) st/state)) +(def workspace-page-flows + (l/derived #(-> % :flows not-empty) workspace-page)) + (defn workspace-page-objects-by-id [page-id] (l/derived #(wsh/lookup-page-objects % page-id) st/state =)) @@ -343,9 +346,6 @@ (into [] (keep (d/getf objects)) children-ids))) workspace-page-objects =)) -(def workspace-page-options - (l/derived :options workspace-page)) - (def workspace-frames (l/derived ctt/get-frames workspace-page-objects =)) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index a371a67d3..d58ce0fe9 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -211,7 +211,7 @@ shapes (cfh/get-immediate-children objects) dim (calculate-dimensions objects aspect-ratio) vbox (format-viewbox dim) - bgcolor (dm/get-in data [:options :background] default-color) + bgcolor (get data :background default-color) shape-wrapper (mf/use-memo @@ -232,7 +232,7 @@ :fill "none"} (when include-metadata - [:& export/export-page {:id (:id data) :options (:options data)}]) + [:& export/export-page {:page data}]) (let [shapes (->> shapes (remove cfh/frame-shape?) diff --git a/frontend/src/app/main/ui/shapes/export.cljs b/frontend/src/app/main/ui/shapes/export.cljs index 339fa436d..9a8dce9d4 100644 --- a/frontend/src/app/main/ui/shapes/export.cljs +++ b/frontend/src/app/main/ui/shapes/export.cljs @@ -187,14 +187,16 @@ :axis (d/name axis)}])]) (mf/defc export-page - [{:keys [id options]}] - (let [saved-grids (get options :saved-grids) - flows (get options :flows) - guides (get options :guides)] + {::mf/props :obj} + [{:keys [page]}] + (let [id (get page :id) + grids (get page :grids) + flows (get page :flows) + guides (get page :guides)] [:> "penpot:page" #js {:id id} - (when (d/not-empty? saved-grids) + (when (d/not-empty? grids) (let [parse-grid (fn [[type params]] {:type type :params params}) - grids (->> saved-grids (mapv parse-grid))] + grids (mapv parse-grid grids)] [:& export-grid-data {:grids grids}])) (when (d/not-empty? flows) diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index fe72f96b3..a84f44b7d 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -139,7 +139,7 @@ :viewport-size) tpos-ref (mf/with-memo [page-id] - (-> (l/in [:pages page-id :options :comment-threads-position]) + (-> (l/in [:pages page-id :comment-thread-positions]) (l/derived refs/viewer-data))) positions (mf/deref tpos-ref) diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index 9fc794f60..5ac06a3fb 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -221,13 +221,14 @@ (mf/defc flows-menu {::mf/wrap [mf/memo]} [{:keys [page index]}] - (let [flows (dm/get-in page [:options :flows]) - frames (:frames page) - frame (get frames index) - current-flow* (mf/use-state - #(ctp/get-frame-flow flows (:id frame))) + (let [flows (:flows page) + frames (:frames page) - current-flow (deref current-flow*) + frame (get frames index) + current-flow* (mf/use-state + #(ctp/get-frame-flow flows (:id frame))) + + current-flow (deref current-flow*) show-dropdown?* (mf/use-state false) show-dropdown? (deref show-dropdown?*) diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 0d631ac45..d64b6589e 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -373,26 +373,25 @@ :on-click do-lock-shape}])])) (mf/defc context-menu-prototype + {::mf/props :obj} [{:keys [shapes]}] - (let [options (mf/deref refs/workspace-page-options) + (let [flows (mf/deref refs/workspace-page-flows) options-mode (mf/deref refs/options-mode-global) do-add-flow #(st/emit! (dwi/add-flow-selected-frame)) do-remove-flow #(st/emit! (dwi/remove-flow (:id %))) - flows (:flows options) prototype? (= options-mode :prototype) single? (= (count shapes) 1) - has-frame? (->> shapes (d/seek cfh/frame-shape?)) + + has-frame? (d/seek cfh/frame-shape? shapes) is-frame? (and single? has-frame?)] (when (and prototype? is-frame?) - (let [flow (ctp/get-frame-flow flows (-> shapes first :id))] - (if (some? flow) - [:& menu-entry {:title (tr "workspace.shape.menu.delete-flow-start") - :on-click (do-remove-flow flow)}] - - [:& menu-entry {:title (tr "workspace.shape.menu.flow-start") - :on-click do-add-flow}]))))) + (if-let [flow (ctp/get-frame-flow flows (-> shapes first :id))] + [:& menu-entry {:title (tr "workspace.shape.menu.delete-flow-start") + :on-click (do-remove-flow flow)}] + [:& menu-entry {:title (tr "workspace.shape.menu.flow-start") + :on-click do-add-flow}])))) (mf/defc context-menu-layout {::mf/props :obj} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index 7b7e69aed..4b158bf94 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -8,6 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.geom.grid :as gg] + [app.common.types.grid :as ctg] [app.main.data.workspace.grid :as dw] [app.main.refs :as refs] [app.main.store :as st] @@ -22,8 +23,8 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(def workspace-saved-grids - (l/derived :saved-grids refs/workspace-page-options)) +(def lens:default-grids + (l/derived :default-grids refs/workspace-data)) (defn- get-size-options [] [{:value nil :label (tr "workspace.options.grid.auto")} @@ -297,10 +298,16 @@ has-frame-grids? (or (= :multiple frame-grids) (some? (seq frame-grids))) toggle-content (mf/use-fn #(swap! state* not)) + id (:id shape) - saved-grids (mf/deref workspace-saved-grids) - default-grid-params (mf/use-memo (mf/deps saved-grids) #(merge dw/default-grid-params saved-grids)) - handle-create-grid (mf/use-fn (mf/deps id) #(st/emit! (dw/add-frame-grid id)))] + default-grids (mf/deref lens:default-grids) + default-grid-params (mf/with-memo [default-grids] + (merge ctg/default-grid-params default-grids)) + + handle-create-grid + (mf/use-fn + (mf/deps id) + #(st/emit! (dw/add-frame-grid id)))] [:div {:class (stl/css :element-set)} [:& title-bar {:collapsable has-frame-grids? diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index 3a1ba4bd9..4949433e2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -154,19 +154,21 @@ i/remove-icon]])) (mf/defc page-flows + {::mf/props :obj} [{:keys [flows]}] - (when (seq flows) + (when flows [:div {:class (stl/css :interaction-options)} [:& title-bar {:collapsable false :title (tr "workspace.options.flows.flow-starts") :class (stl/css :title-spacing-layout-flow)}] - (for [flow flows] - [:& flow-item {:flow flow :key (str (:id flow))}])])) + (for [[id flow] flows] + [:& flow-item {:flow flow :key (dm/str id)}])])) (mf/defc shape-flows + {::mf/props :obj} [{:keys [flows shape]}] - (when (= (:type shape) :frame) - (let [flow (ctp/get-frame-flow flows (:id shape)) + (when (cfh/frame-shape? shape) + (let [flow (ctp/get-frame-flow flows (:id shape)) add-flow (mf/use-fn #(st/emit! (dwi/add-flow-selected-frame)))] [:div {:class (stl/css :element-set)} @@ -179,8 +181,8 @@ :on-click add-flow} i/add])] - (when flow - [:& flow-item {:flow flow :key (str (:id flow))}])]))) + (when (some? flow) + [:& flow-item {:flow flow :key (dm/str (:id flow))}])]))) (def ^:private corner-center-icon (i/icon-xref :corner-center (stl/css :corner-icon))) @@ -695,11 +697,12 @@ :on-change change-offset-effect}]]]])])])])) (mf/defc interactions-menu - [{:keys [shape] :as props}] - (let [interactions (get shape :interactions []) + {::mf/props :obj} + [{:keys [shape]}] + (let [interactions + (get shape :interactions []) - options (mf/deref refs/workspace-page-options) - flows (:flows options) + flows (mf/deref refs/workspace-page-flows) add-interaction (fn [] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index 791d7d3da..aa3294438 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -9,6 +9,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as clr] + [app.common.data :as d] [app.main.data.workspace :as dw] [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] @@ -16,16 +17,21 @@ [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] + [okulary.core :as l] [rumext.v2 :as mf])) +(def lens:background-color + (-> (l/key :background) + (l/derived refs/workspace-page))) + (mf/defc options {::mf/wrap [mf/memo] ::mf/wrap-props false} [] - (let [options (mf/deref refs/workspace-page-options) - on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %))) - on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options))) - on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))] + (let [background (mf/deref lens:background-color) + on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %))) + on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options))) + on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))] [:div {:class (stl/css :element-set)} [:div {:class (stl/css :element-title)} [:& title-bar {:collapsable false @@ -37,7 +43,7 @@ :disable-opacity true :disable-image true :title (tr "workspace.options.canvas-background") - :color {:color (get options :background clr/canvas) + :color {:color (d/nilv background clr/canvas) :opacity 1} :on-change on-change :on-open on-open diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 789df3efc..934fb8e21 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -92,28 +92,24 @@ vbox' (mf/use-debounce 100 vbox) - ;; CONTEXT - page-id (mf/use-ctx ctx/current-page-id) - ;; DEREFS drawing (mf/deref refs/workspace-drawing) - options (mf/deref refs/workspace-page-options) focus (mf/deref refs/workspace-focus-selected) - objects-ref (mf/use-memo #(refs/workspace-page-objects-by-id page-id)) - objects (mf/deref objects-ref) - base-objects (-> objects (ui-hooks/with-focus-objects focus)) + page (mf/deref refs/workspace-page) + objects (get page :objects) + page-id (get page :id) + background (get page :background clr/canvas) + + base-objects (ui-hooks/with-focus-objects objects focus) modifiers (mf/deref refs/workspace-modifiers) text-modifiers (mf/deref refs/workspace-text-modifier) - objects-modified (mf/with-memo - [base-objects text-modifiers modifiers] + objects-modified (mf/with-memo [base-objects text-modifiers modifiers] (apply-modifiers-to-selected selected base-objects text-modifiers modifiers)) - selected-shapes (->> selected (keep (d/getf objects-modified))) - - background (get options :background clr/canvas) + selected-shapes (keep (d/getf objects-modified) selected) ;; STATE alt? (mf/use-state false) @@ -305,7 +301,6 @@ (when picking-color? [:& pixel-overlay/pixel-overlay {:vport vport :vbox vbox - :options options :layout layout :viewport-ref viewport-ref}])] @@ -338,7 +333,7 @@ [:stop {:offset "100%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]]] (when (dbg/enabled? :show-export-metadata) - [:& use/export-page {:options options}]) + [:& use/export-page {:page page}]) ;; We need a "real" background shape so layer transforms work properly in firefox [:rect {:width (:width vbox 0) @@ -486,7 +481,7 @@ (when show-prototypes? [:& widgets/frame-flows - {:flows (:flows options) + {:flows (:flows page) :objects objects-modified :selected selected :zoom zoom @@ -556,11 +551,11 @@ :show-rulers? show-rulers?}]) (when (and show-rulers? show-grids?) - [:& guides/viewport-guides + [:> guides/viewport-guides* {:zoom zoom :vbox vbox :hover-frame guide-frame - :disabled-guides? disabled-guides? + :disabled-guides disabled-guides? :modifiers modifiers}]) ;; DEBUG LAYOUT DROP-ZONES diff --git a/frontend/src/app/main/ui/workspace/viewport/comments.cljs b/frontend/src/app/main/ui/workspace/viewport/comments.cljs index f75559b5e..0e35d681a 100644 --- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs @@ -41,7 +41,8 @@ positions-ref (mf/with-memo [page-id] - (-> (l/in [:workspace-data :pages-index page-id :options :comment-threads-position]) + ;; FIXME: use lookup helpers here + (-> (l/in [:workspace-data :pages-index page-id :comment-thread-positions]) (l/derived st/state))) positions (mf/deref positions-ref) diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index 79321b508..691ea4a24 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.viewport.guides (:require [app.common.colors :as colors] + [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] @@ -21,6 +22,7 @@ [app.main.ui.formats :as fmt] [app.main.ui.workspace.viewport.rulers :as rulers] [app.util.dom :as dom] + [okulary.core :as l] [rumext.v2 :as mf])) (def guide-width 1) @@ -256,14 +258,15 @@ (and (>= (:position guide) (:y frame)) (<= (:position guide) (+ (:y frame) (:height frame)))))) -(mf/defc guide - {::mf/wrap [mf/memo]} - [{:keys [guide hover? on-guide-change get-hover-frame vbox zoom hover-frame disabled-guides? frame-modifier]}] +(mf/defc guide* + {::mf/wrap [mf/memo] + ::mf/props :obj} + [{:keys [guide is-hover on-guide-change get-hover-frame vbox zoom hover-frame disabled-guides frame-modifier]}] (let [axis (:axis guide) handle-change-position - (mf/use-callback + (mf/use-fn (mf/deps on-guide-change) (fn [changes] (when on-guide-change @@ -296,7 +299,7 @@ (and (cfh/root-frame? frame) (not (ctst/rotated-frame? frame)))) [:g.guide-area {:opacity (when frame-guide-outside? 0)} - (when-not disabled-guides? + (when-not disabled-guides (let [{:keys [x y width height]} (guide-area-axis pos vbox zoom frame axis)] [:rect {:x x :y y @@ -318,7 +321,7 @@ l3-x1 l3-y1 l3-x2 l3-y2]} (guide-line-axis pos vbox frame axis)] [:g - (when (or hover? (:hover @state)) + (when (or is-hover (:hover @state)) [:line {:x1 l1-x1 :y1 l1-y1 :x2 l1-x2 @@ -334,10 +337,10 @@ :y2 l2-y2 :style {:stroke guide-color :stroke-width guide-width - :stroke-opacity (if (or hover? (:hover @state)) + :stroke-opacity (if (or is-hover (:hover @state)) guide-opacity-hover guide-opacity)}}] - (when (or hover? (:hover @state)) + (when (or is-hover (:hover @state)) [:line {:x1 l3-x1 :y1 l3-y1 :x2 l3-x2 @@ -355,11 +358,11 @@ :y2 y2 :style {:stroke guide-color :stroke-width guide-width - :stroke-opacity (if (or hover? (:hover @state)) + :stroke-opacity (if (or is-hover (:hover @state)) guide-opacity-hover guide-opacity)}}])) - (when (or hover? (:hover @state)) + (when (or is-hover (:hover @state)) (let [{:keys [rect-x rect-y rect-width rect-height text-x text-y]} (guide-pill-axis pos vbox zoom axis)] [:g.guide-pill @@ -382,16 +385,17 @@ ;; If the guide is associated to a frame we show the position relative to the frame (fmt/format-number (- pos (if (= axis :x) (:x frame) (:y frame))))]]))]))) -(mf/defc new-guide-area - [{:keys [vbox zoom axis get-hover-frame disabled-guides?]}] +(mf/defc new-guide-area* + {::mf/props :obj} + [{:keys [vbox zoom axis get-hover-frame disabled-guides]}] (let [on-guide-change - (mf/use-callback + (mf/use-fn (mf/deps vbox) (fn [guide] (let [guide (-> guide - (assoc :id (uuid/next) - :axis axis))] + (assoc :id (uuid/next)) + (assoc :axis axis))] (when (guide-inside-vbox? zoom vbox guide) (st/emit! (dw/update-guides guide)))))) @@ -402,10 +406,11 @@ on-lost-pointer-capture on-pointer-move state - frame]} (use-guide on-guide-change get-hover-frame zoom {:axis axis})] + frame]} + (use-guide on-guide-change get-hover-frame zoom {:axis axis})] [:g.new-guides - (when-not disabled-guides? + (when-not disabled-guides (let [{:keys [x y width height]} (guide-creation-area vbox zoom axis)] [:rect {:x x :y y @@ -422,25 +427,25 @@ :pointer-events "fill"}}])) (when (:new-position @state) - [:& guide {:guide {:axis axis - :position (:new-position @state)} - :get-hover-frame get-hover-frame - :vbox vbox - :zoom zoom - :hover? true - :hover-frame frame}])])) + [:& guide* {:guide {:axis axis :position (:new-position @state)} + :get-hover-frame get-hover-frame + :vbox vbox + :zoom zoom + :is-hover true + :hover-frame frame}])])) -(mf/defc viewport-guides - {::mf/wrap [mf/memo]} - [{:keys [zoom vbox hover-frame disabled-guides? modifiers]}] +(def ^:private lens:workspace-guides + (-> (l/key :guides) + (l/derived refs/workspace-page))) - (let [page (mf/deref refs/workspace-page) - - guides (mf/use-memo - (mf/deps page vbox) - #(->> (get-in page [:options :guides] {}) - (vals) - (filter (guide-inside-vbox? zoom vbox)))) +(mf/defc viewport-guides* + {::mf/wrap [mf/memo] + ::mf/props :obj} + [{:keys [zoom vbox hover-frame disabled-guides modifiers]}] + (let [guides (mf/deref lens:workspace-guides) + guides (mf/with-memo [guides vbox] + (->> (vals guides) + (filter (partial guide-inside-vbox? zoom vbox)))) focus (mf/deref refs/workspace-focus-selected) @@ -449,46 +454,42 @@ ;; We use the ref to not redraw every guide everytime the hovering frame change ;; we're only interested to get the frame in the guide we're moving get-hover-frame - (mf/use-callback - (fn [] - (mf/ref-val hover-frame-ref))) + (mf/use-fn + #(mf/ref-val hover-frame-ref)) on-guide-change - (mf/use-callback + (mf/use-fn (mf/deps vbox) (fn [guide] (if (guide-inside-vbox? zoom vbox guide) (st/emit! (dw/update-guides guide)) (st/emit! (dw/remove-guide guide)))))] - (mf/use-effect - (mf/deps hover-frame) - (fn [] - (mf/set-ref-val! hover-frame-ref hover-frame))) + (mf/with-effect [hover-frame] + (mf/set-ref-val! hover-frame-ref hover-frame)) [:g.guides {:pointer-events "none"} - [:& new-guide-area {:vbox vbox - :zoom zoom - :axis :x - :get-hover-frame get-hover-frame - :disabled-guides? disabled-guides?}] + [:> new-guide-area* {:vbox vbox + :zoom zoom + :axis :x + :get-hover-frame get-hover-frame + :disabled-guides disabled-guides}] - [:& new-guide-area {:vbox vbox - :zoom zoom - :axis :y - :get-hover-frame get-hover-frame - :disabled-guides? disabled-guides?}] + [:> new-guide-area* {:vbox vbox + :zoom zoom + :axis :y + :get-hover-frame get-hover-frame + :disabled-guides disabled-guides}] (for [current guides] (when (or (nil? (:frame-id current)) (empty? focus) (contains? focus (:frame-id current))) - [:& guide {:key (str "guide-" (:id current)) + [:> guide* {:key (dm/str "guide-" (:id current)) :guide current :vbox vbox :zoom zoom - :frame-modifier (get-in modifiers [(:frame-id current) :modifiers]) + :frame-modifier (dm/get-in modifiers [(:frame-id current) :modifiers]) :get-hover-frame get-hover-frame :on-guide-change on-guide-change - :disabled-guides? disabled-guides?}]))])) - + :disabled-guides disabled-guides}]))])) diff --git a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs index b97e9fd21..4ac339c48 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -53,10 +53,10 @@ (mf/defc pixel-overlay {::mf/wrap-props false} [props] - (let [vport (unchecked-get props "vport") + (let [vport (unchecked-get props "vport") - viewport-ref (unchecked-get props "viewport-ref") - viewport-node (mf/ref-val viewport-ref) + viewport-ref (unchecked-get props "viewport-ref") + viewport-node (mf/ref-val viewport-ref) canvas (get-offscreen-canvas (:width vport) (:height vport)) canvas-context (.getContext canvas "2d" #js {:willReadFrequently true}) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 1d2ee1948..f1fb8b6ae 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -282,6 +282,7 @@ on-frame-leave (unchecked-get props "on-frame-leave") on-frame-select (unchecked-get props "on-frame-select")] [:g.frame-flows + ;; FIXME: enumerate is not necessary here (for [[index flow] (d/enumerate flows)] (let [frame (get objects (:starting-frame flow))] [:& frame-flow {:key (dm/str (:id frame) "-" index) diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index e65ad121b..a51db3a11 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -126,7 +126,7 @@ :else (let [page (u/proxy->page self)] - (dm/get-in page [:options :plugin-data (keyword "plugin" (str $plugin)) key])))) + (dm/get-in page [:plugin-data (keyword "plugin" (str $plugin)) key])))) (setPluginData [_ key value] @@ -146,7 +146,7 @@ (getPluginDataKeys [self] (let [page (u/proxy->page self)] - (apply array (keys (dm/get-in page [:options :plugin-data (keyword "plugin" (str $plugin))]))))) + (apply array (keys (dm/get-in page [:plugin-data (keyword "plugin" (str $plugin))]))))) (getSharedPluginData [self namespace key] @@ -159,7 +159,7 @@ :else (let [page (u/proxy->page self)] - (dm/get-in page [:options :plugin-data (keyword "shared" namespace) key])))) + (dm/get-in page [:plugin-data (keyword "shared" namespace) key])))) (setSharedPluginData [_ namespace key value] @@ -188,7 +188,7 @@ :else (let [page (u/proxy->page self)] - (apply array (keys (dm/get-in page [:options :plugin-data (keyword "shared" namespace)])))))) + (apply array (keys (dm/get-in page [:plugin-data (keyword "shared" namespace)])))))) (openPage [_] @@ -385,7 +385,7 @@ {:name "background" :enumerable false - :get #(or (-> % u/proxy->page :options :background) cc/canvas) + :get #(or (-> % u/proxy->page :background) cc/canvas) :set (fn [_ value] (cond @@ -401,13 +401,13 @@ {:name "flows" :get (fn [self] - (let [flows (d/nilv (-> (u/proxy->page self) :options :flows) [])] + (let [flows (d/nilv (-> (u/proxy->page self) :flows) [])] (format/format-array #(flow-proxy plugin-id file-id id (:id %)) flows)))} {:name "rulerGuides" :get (fn [self] - (let [guides (-> (u/proxy->page self) :options :guides)] + (let [guides (-> (u/proxy->page self) :guides)] (->> guides (vals) (filter #(nil? (:frame-id %))) diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index a03a1f5a1..81584852f 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -120,7 +120,7 @@ flow-id (obj/get proxy "$id") page (locate-page file-id page-id)] (when (some? page) - (d/seek #(= (:id %) flow-id) (-> page :options :flows))))) + (d/seek #(= (:id %) flow-id) (:flows page))))) (defn proxy->ruler-guide [proxy] diff --git a/frontend/src/app/util/snap_data.cljs b/frontend/src/app/util/snap_data.cljs index 2fef2aa7b..d8fc89cea 100644 --- a/frontend/src/app/util/snap_data.cljs +++ b/frontend/src/app/util/snap_data.cljs @@ -211,11 +211,11 @@ (defn add-page "Adds page information" - [snap-data {:keys [objects options] :as page}] + [snap-data {:keys [objects guides] :as page}] (let [frames (ctst/get-frames objects) shapes (->> (vals (:objects page)) (remove cfh/frame-shape?)) - guides (vals (:guides options)) + guides (vals guides) page-data (as-> {} $ diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index f3b4fd962..cd6f11c8d 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -452,22 +452,28 @@ (defn import-page [context file [page-id page-name content]] - (let [nodes (->> content parser/node-seq) - file-id (:id file) - resolve (:resolve context) + (let [nodes (parser/node-seq content) + file-id (:id file) + resolve (:resolve context) page-data (-> (parser/parse-page-data content) (assoc :name page-name) (assoc :id (resolve page-id))) - flows (->> (get-in page-data [:options :flows]) - (mapv #(update % :starting-frame resolve))) + flows (->> (get page-data :flows) + (update-vals #(update % :starting-frame resolve)) + (not-empty)) - guides (-> (get-in page-data [:options :guides]) - (update-vals #(update % :frame-id resolve))) + guides (-> (get page-data :guides) + (update-vals #(update % :frame-id resolve)) + (not-empty)) - page-data (-> page-data - (d/assoc-in-when [:options :flows] flows) - (d/assoc-in-when [:options :guides] guides)) - file (-> file (fb/add-page page-data)) + page-data (cond-> page-data + flows + (assoc :flows flows) + + guides + (assoc :guides guides)) + + file (fb/add-page file page-data) ;; Preprocess nodes to parallel upload the images. Store the result in a table ;; old-node => node with image diff --git a/frontend/src/app/worker/import/parser.cljs b/frontend/src/app/worker/import/parser.cljs index adeb0dd5a..861e4540f 100644 --- a/frontend/src/app/worker/import/parser.cljs +++ b/frontend/src/app/worker/import/parser.cljs @@ -1136,16 +1136,16 @@ guides (parse-guides node)] (cond-> {} (some? background) - (assoc-in [:options :background] background) + (assoc :background background) (d/not-empty? grids) - (assoc-in [:options :saved-grids] grids) + (assoc :default-grids grids) (d/not-empty? flows) - (assoc-in [:options :flows] flows) + (assoc :flows flows) (d/not-empty? guides) - (assoc-in [:options :guides] guides)))) + (assoc :guides guides)))) (defn parse-interactions [node] diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 161ed28d5..658429c19 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -7,7 +7,6 @@ (ns app.worker.thumbnails (:require ["react-dom/server" :as rds] - [app.common.data.macros :as dm] [app.common.logging :as log] [app.common.uri :as u] [app.config :as cf] @@ -63,7 +62,7 @@ (binding [fonts/loaded-hints (l/atom #{})] (let [objects (:objects page) frame (some->> page :thumbnail-frame-id (get objects)) - background-color (dm/get-in page [:options :background]) + background-color (:background page) element (if frame (mf/element render/frame-svg #js {:objects objects diff --git a/frontend/test/frontend_tests/logic/frame_guides_test.cljs b/frontend/test/frontend_tests/logic/frame_guides_test.cljs index 8d1217973..721220fcd 100644 --- a/frontend/test/frontend_tests/logic/frame_guides_test.cljs +++ b/frontend/test/frontend_tests/logic/frame_guides_test.cljs @@ -46,7 +46,6 @@ page' (cthf/current-page file') guide' (-> page' - :options :guides (vals) (first))] diff --git a/frontend/test/frontend_tests/util_snap_data_test.cljs b/frontend/test/frontend_tests/util_snap_data_test.cljs index bdd42b5af..d988c4e9a 100644 --- a/frontend/test/frontend_tests/util_snap_data_test.cljs +++ b/frontend/test/frontend_tests/util_snap_data_test.cljs @@ -391,9 +391,9 @@ (t/testing "Update global guide" (let [guide {:position 50 :axis :x} - file (-> (fb/create-file "Test") - (fb/add-page {:name "Page 1"}) - (fb/add-guide guide)) + file (-> (fb/create-file "Test") + (fb/add-page {:name "Page 1"}) + (fb/add-guide guide)) guide-id (:last-id file) guide (assoc guide :id guide-id) @@ -403,7 +403,7 @@ frame-id (:last-id file) page (fb/get-current-page file) - data (-> (sd/make-snap-data) (sd/add-page page)) + data (-> (sd/make-snap-data) (sd/add-page page)) new-page (-> (fb/update-guide file (assoc guide :position 150)) (fb/get-current-page))