diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index 0c1db4d050..18daa1480b 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -15,7 +15,7 @@ :hooks {:analyze-call {app.common.data.macros/export hooks.export/export - potok.core/reify hooks.export/potok-reify + potok.v2.core/reify hooks.export/potok-reify app.util.services/defmethod hooks.export/service-defmethod app.common.record/defrecord hooks.export/penpot-defrecord app.db/with-atomic hooks.export/penpot-with-atomic diff --git a/backend/resources/log4j2-devenv.xml b/backend/resources/log4j2-devenv.xml index 4fd93925c9..a37eb18010 100644 --- a/backend/resources/log4j2-devenv.xml +++ b/backend/resources/log4j2-devenv.xml @@ -30,7 +30,6 @@ - diff --git a/backend/src/app/features/components_v2.clj b/backend/src/app/features/components_v2.clj index 19b4f0b9df..99074dd598 100644 --- a/backend/src/app/features/components_v2.clj +++ b/backend/src/app/features/components_v2.clj @@ -9,7 +9,6 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.exceptions :as ex] - [app.common.features :as cfeat] [app.common.files.changes :as cp] [app.common.files.changes-builder :as fcb] [app.common.files.helpers :as cfh] @@ -769,12 +768,13 @@ fdata (migrate-graphics fdata)] (update fdata :options assoc :components-v2 true))))) -(defn- prepare-fdata - [fdata id] - (-> fdata - (assoc :id id) - (fdata/process-pointers deref) - (fmg/migrate-data))) +(defn- get-file + [system id] + (binding [pmap/*load-fn* (partial fdata/load-pointer system id)] + (-> (files/get-file system id :migrate? false) + (update :data assoc :id id) + (update :data fdata/process-pointers deref) + (fmg/migrate-file)))) (defn- validate-file! [file libs throw-on-validate?] @@ -788,18 +788,10 @@ (defn- process-file [{:keys [::db/conn] :as system} id & {:keys [validate? throw-on-validate?]}] - (let [file (binding [cfeat/*new* (atom #{}) - pmap/*load-fn* (partial fdata/load-pointer system id)] - (-> (files/get-file system id :migrate? false) - (update :data prepare-fdata id) - (update :features into (deref cfeat/*new*)) - (update :features cfeat/migrate-legacy-features))) + (let [file (get-file system id) libs (->> (files/get-file-libraries conn id) - (into [file] (map (fn [{:keys [id]}] - (binding [pmap/*load-fn* (partial fdata/load-pointer system id)] - (-> (files/get-file system id :migrate? false) - (update :data prepare-fdata id)))))) + (into [file] (comp (map :id) (map (partial get-file system)))) (d/index-by :id)) file (-> file diff --git a/backend/src/app/http/errors.clj b/backend/src/app/http/errors.clj index 0e8e065ad2..580cd67039 100644 --- a/backend/src/app/http/errors.clj +++ b/backend/src/app/http/errors.clj @@ -81,6 +81,7 @@ (cond (or (= code :spec-validation) (= code :params-validation) + (= code :schema-validation) (= code :data-validation)) (let [explain (ex/explain data)] {::rres/status 400 diff --git a/backend/src/app/rpc/commands/binfile.clj b/backend/src/app/rpc/commands/binfile.clj index 13a16c2770..7e7327b32e 100644 --- a/backend/src/app/rpc/commands/binfile.clj +++ b/backend/src/app/rpc/commands/binfile.clj @@ -11,7 +11,7 @@ [app.common.exceptions :as ex] [app.common.features :as cfeat] [app.common.files.defaults :as cfd] - [app.common.files.migrations :as pmg] + [app.common.files.migrations :as fmg] [app.common.files.validate :as fval] [app.common.fressian :as fres] [app.common.logging :as l] @@ -701,23 +701,29 @@ (update :object-id #(str/replace-first % #"^(.*?)/" (str file-id "/"))))) thumbnails)) -(defn- process-fdata - [fdata id] - (-> fdata - (dissoc :recent-colors) - (assoc :id id) - (cond-> (> (:version fdata) cfd/version) - (assoc :version cfd/version)) - ;; FIXME: We're temporarily activating all - ;; migrations because a problem in the - ;; environments messed up with the version - ;; numbers When this problem is fixed delete - ;; the following line - (assoc :version 22) - (pmg/migrate-data) - (update :pages-index relink-shapes) - (update :components relink-shapes) - (update :media relink-media))) +(defn- process-file + [{:keys [id] :as file}] + (-> file + (update :data (fn [fdata] + (-> fdata + (assoc :id id) + (dissoc :recent-colors) + (cond-> (> (:version fdata) cfd/version) + (assoc :version cfd/version)) + ;; FIXME: We're temporarily activating all + ;; migrations because a problem in the + ;; environments messed up with the version + ;; numbers When this problem is fixed delete + ;; the following line + (cond-> (> (:version fdata) 22) + (assoc :version 22))))) + (fmg/migrate-file) + (update :data (fn [fdata] + (-> fdata + (update :pages-index relink-shapes) + (update :components relink-shapes) + (update :media relink-media) + (d/without-nils)))))) (defmethod read-section :v1/files @@ -730,19 +736,7 @@ file-id (:id file) file-id' (lookup-index file-id) - thumbnails (:thumbnails file) - file (update file :features cfeat/migrate-legacy-features) - - features (-> enabled-features - (set/difference cfeat/frontend-only-features) - (set/union (cfeat/check-supported-features! (:features file))))] - - ;; All features that are enabled and requires explicit migration - ;; are added to the state for a posterior migration step - (doseq [feature (-> enabled-features - (set/difference cfeat/no-migration-features) - (set/difference (:features file)))] - (vswap! *state* update :pending-to-migrate (fnil conj []) [feature file-id'])) + thumbnails (:thumbnails file)] (when (not= file-id expected-file-id) (ex/raise :type :validation @@ -773,16 +767,28 @@ (l/dbg :hint "update media references" ::l/sync? true) (vswap! *state* update :media into (map #(update % :id lookup-index)) media)) - (let [file (binding [cfeat/*new* (atom #{})] - (-> file - (assoc :id file-id') - (assoc :features features) - (assoc :project-id project-id) - (assoc :created-at timestamp) - (assoc :modified-at timestamp) - (dissoc :thumbnails) - (update :data process-fdata file-id') - (update :features into (deref cfeat/*new*)))) + (let [file (-> file + (assoc :id file-id') + (process-file)) + + ;; All features that are enabled and requires explicit migration are + ;; added to the state for a posterior migration step. + _ (doseq [feature (-> enabled-features + (set/difference cfeat/no-migration-features) + (set/difference (:features file)))] + (vswap! *state* update :pending-to-migrate (fnil conj []) [feature file-id'])) + + file (-> file + (assoc :project-id project-id) + (assoc :created-at timestamp) + (assoc :modified-at timestamp) + (dissoc :thumbnails) + (update :features + (fn [features] + (let [features (cfeat/check-supported-features! features)] + (-> enabled-features + (set/difference cfeat/frontend-only-features) + (set/union features)))))) _ (when (contains? cf/flags :file-schema-validation) (fval/validate-file-schema! file)) @@ -803,7 +809,6 @@ file)) file) - file (-> file (update :features #(db/create-array conn "text" %)) (update :data blob/encode))] diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index a0cc12e438..096e961957 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -224,11 +224,8 @@ (defn- migrate-file [{:keys [::db/conn] :as cfg} {:keys [id] :as file}] (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id) - pmap/*tracked* (pmap/create-tracked) - cfeat/*new* (atom #{})] - (let [file (-> (fmg/migrate-file file) - (update :features into (deref cfeat/*new*)) - (update :features cfeat/migrate-legacy-features))] + pmap/*tracked* (pmap/create-tracked)] + (let [file (fmg/migrate-file file)] ;; NOTE: when file is migrated, we break the rule of no perform ;; mutations on get operations and update the file with all @@ -250,11 +247,13 @@ file))) (defn get-file - [{:keys [::db/conn] :as cfg} id & {:keys [project-id migrate? + [{:keys [::db/conn] :as cfg} id & {:keys [project-id + migrate? include-deleted? lock-for-update?] :or {include-deleted? false - lock-for-update? false}}] + lock-for-update? false + migrate? true}}] (dm/assert! "expected cfg with valid connection" (db/connection-map? cfg)) diff --git a/backend/src/app/rpc/commands/files_thumbnails.clj b/backend/src/app/rpc/commands/files_thumbnails.clj index c60338349f..19f36072f4 100644 --- a/backend/src/app/rpc/commands/files_thumbnails.clj +++ b/backend/src/app/rpc/commands/files_thumbnails.clj @@ -10,6 +10,7 @@ [app.common.data.macros :as dm] [app.common.features :as cfeat] [app.common.files.helpers :as cfh] + [app.common.files.migrations :as fmg] [app.common.geom.shapes :as gsh] [app.common.schema :as sm] [app.common.thumbnails :as thc] @@ -105,24 +106,12 @@ (letfn [;; function responsible on finding the frame marked to be ;; used as thumbnail; the returned frame always have ;; the :page-id set to the page that it belongs. - - (get-thumbnail-frame [file] - ;; NOTE: this is a hack for avoid perform blocking - ;; operation inside the for loop, clojure lazy-seq uses - ;; synchronized blocks that does not plays well with - ;; virtual threads where all rpc methods calls are - ;; dispatched, so we need to perform the load operation - ;; first. This operation forces all pointer maps load into - ;; the memory. - ;; - ;; FIXME: this is no longer true with clojure>=1.12 - (let [{:keys [data]} (update file :data feat.fdata/process-pointers pmap/load!)] - ;; Then proceed to find the frame set for thumbnail - (d/seek #(or (:use-for-thumbnail %) - (:use-for-thumbnail? %)) ; NOTE: backward comp (remove on v1.21) - (for [page (-> data :pages-index vals) - frame (-> page :objects ctt/get-frames)] - (assoc frame :page-id (:id page)))))) + (get-thumbnail-frame [{:keys [data]}] + (d/seek #(or (:use-for-thumbnail %) + (:use-for-thumbnail? %)) ; NOTE: backward comp (remove on v1.21) + (for [page (-> data :pages-index vals) + frame (-> page :objects ctt/get-frames)] + (assoc frame :page-id (:id page))))) ;; function responsible to filter objects data structure of ;; all unneeded shapes if a concrete frame is provided. If no @@ -166,30 +155,29 @@ objects)))] - (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)] - (let [frame (get-thumbnail-frame file) - frame-id (:id frame) - page-id (or (:page-id frame) - (-> data :pages first)) + (let [frame (get-thumbnail-frame file) + frame-id (:id frame) + page-id (or (:page-id frame) + (-> data :pages first)) - page (dm/get-in data [:pages-index page-id]) - page (cond-> page (pmap/pointer-map? page) deref) - frame-ids (if (some? frame) (list frame-id) (map :id (ctt/get-frames (:objects page)))) + page (dm/get-in data [:pages-index page-id]) + page (cond-> page (pmap/pointer-map? page) deref) + frame-ids (if (some? frame) (list frame-id) (map :id (ctt/get-frames (:objects page)))) - obj-ids (map #(thc/fmt-object-id (:id file) page-id % "frame") frame-ids) - thumbs (get-object-thumbnails conn id obj-ids)] + obj-ids (map #(thc/fmt-object-id (:id file) page-id % "frame") frame-ids) + thumbs (get-object-thumbnails conn id obj-ids)] - (cond-> page - ;; If we have frame, we need to specify it on the page level - ;; and remove the all other unrelated objects. - (some? frame-id) - (-> (assoc :thumbnail-frame-id frame-id) - (update :objects filter-objects frame-id)) + (cond-> page + ;; If we have frame, we need to specify it on the page level + ;; and remove the all other unrelated objects. + (some? frame-id) + (-> (assoc :thumbnail-frame-id frame-id) + (update :objects filter-objects frame-id)) - ;; Assoc the available thumbnails and prune not visible shapes - ;; for avoid transfer unnecessary data. - :always - (update :objects assoc-thumbnails page-id thumbs)))))) + ;; Assoc the available thumbnails and prune not visible shapes + ;; for avoid transfer unnecessary data. + :always + (update :objects assoc-thumbnails page-id thumbs))))) (def ^:private schema:get-file-data-for-thumbnail @@ -221,7 +209,10 @@ :profile-id profile-id :file-id file-id) - file (files/get-file cfg file-id)] + file (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg file-id)] + (-> (files/get-file cfg file-id :migrate? false) + (update :data feat.fdata/process-pointers deref) + (fmg/migrate-file)))] (-> (cfeat/get-team-enabled-features cf/flags team) (cfeat/check-client-features! (:features params)) diff --git a/backend/src/app/rpc/commands/management.clj b/backend/src/app/rpc/commands/management.clj index 2928830ca6..80287e9aeb 100644 --- a/backend/src/app/rpc/commands/management.clj +++ b/backend/src/app/rpc/commands/management.clj @@ -106,41 +106,34 @@ media media)) - (update-fdata [fdata new-id] - (-> fdata - (assoc :id new-id) - (feat.fdata/process-pointers deref) - (pmg/migrate-data) - (update :pages-index relink-shapes) - (update :components relink-shapes) - (update :media relink-media) - (d/without-nils)))] + (process-file [{:keys [id] :as file}] + (-> file + (update :data assoc :id id) + (update :data feat.fdata/process-pointers deref) + (pmg/migrate-file) + (update :data (fn [data] + (-> data + (update :pages-index relink-shapes) + (update :components relink-shapes) + (update :media relink-media) + (d/without-nils))))))] - (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id) - pmap/*tracked* (pmap/create-tracked) - cfeat/*new* (atom #{})] + (let [new-id (get index id) + file (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id)] + (-> (assoc file :id new-id) + (process-file))) - (let [new-id (get index id) - file (binding [pmap/*load-fn* (partial feat.fdata/load-pointer cfg id) - cfeat/*new* (atom #{})] - (-> file - (assoc :id new-id) - (update :data update-fdata new-id) - (update :features into (deref cfeat/*new*)) - (update :features cfeat/migrate-legacy-features))) + file (if (contains? (:features file) "fdata/objects-map") + (feat.fdata/enable-objects-map file) + file) - file (if (contains? (:features file) "fdata/objects-map") - (feat.fdata/enable-objects-map file) - file) - - file (if (contains? (:features file) "fdata/pointer-map") - (binding [pmap/*tracked* (pmap/create-tracked)] - (let [file (feat.fdata/enable-pointer-map file)] - (feat.fdata/persist-pointers! cfg (:id file)) - file)) - file)] - - file)))) + file (if (contains? (:features file) "fdata/pointer-map") + (binding [pmap/*tracked* (pmap/create-tracked)] + (let [file (feat.fdata/enable-pointer-map file)] + (feat.fdata/persist-pointers! cfg (:id file)) + file)) + file)] + file))) (def sql:get-used-libraries "select flr.* diff --git a/backend/src/app/rpc/commands/search.clj b/backend/src/app/rpc/commands/search.clj index 1c4026d6db..5710156458 100644 --- a/backend/src/app/rpc/commands/search.clj +++ b/backend/src/app/rpc/commands/search.clj @@ -9,6 +9,7 @@ [app.common.spec :as us] [app.db :as db] [app.rpc :as-alias rpc] + [app.rpc.commands.files :refer [resolve-public-uri]] [app.rpc.doc :as-alias doc] [app.util.services :as sv] [clojure.spec.alpha :as s])) @@ -37,12 +38,15 @@ ) select distinct f.id, + f.revn, f.project_id, f.created_at, f.modified_at, f.name, - f.is_shared + f.is_shared, + ft.media_id from file as f + left join file_thumbnail as ft on (ft.file_id = f.id and ft.revn = f.revn) inner join projects as pr on (f.project_id = pr.id) where f.name ilike ('%' || ? || '%') and (f.deleted_at is null or f.deleted_at > now()) @@ -50,10 +54,16 @@ (defn search-files [conn profile-id team-id search-term] - (db/exec! conn [sql:search-files - profile-id team-id - profile-id team-id - search-term])) + (->> (db/exec! conn [sql:search-files + profile-id team-id + profile-id team-id + search-term]) + (mapv (fn [row] + (if-let [media-id (:media-id row)] + (-> row + (dissoc :media-id) + (assoc :thumbnail-uri (resolve-public-uri media-id))) + (dissoc row :media-id)))))) (s/def ::team-id ::us/uuid) (s/def ::search-files ::us/string) diff --git a/backend/src/app/util/websocket.clj b/backend/src/app/util/websocket.clj index 094ec37c38..38276e743c 100644 --- a/backend/src/app/util/websocket.clj +++ b/backend/src/app/util/websocket.clj @@ -103,7 +103,7 @@ {:on-open (fn on-open [channel] - (l/trace :fn "on-open" :conn-id id :channel channel) + (l/dbg :fn "on-open" :conn-id (str id)) (let [options (-> options (assoc ::channel channel) (on-connect)) @@ -114,10 +114,10 @@ :on-close (fn on-close [_channel code reason] - (l/info :fn "on-ws-terminate" - :conn-id id - :code code - :reason reason) + (l/dbg :fn "on-close" + :conn-id (str id) + :code code + :reason reason) (sp/close! close-ch)) :on-error @@ -132,18 +132,19 @@ :on-pong (fn on-pong [_channel data] - (l/trace :fn "on-pong" :data data) (sp/put! hbeat-ch data))})) (defn- handle-ping! [{:keys [::id ::beats ::channel] :as wsp} beat-id] - (l/trace :hint "send ping" :beat beat-id :conn-id id) + (l/trc :hint "send ping" :beat beat-id :conn-id (str id)) (rws/ping channel (encode-beat beat-id)) (let [issued (swap! beats conj (long beat-id))] (not (>= (count issued) max-missed-heartbeats)))) (defn- start-io-loop! - [{:keys [::id ::close-ch ::input-ch ::output-ch ::heartbeat-ch ::channel ::handler ::beats ::on-rcv-message ::on-snd-message] :as wsp}] + [{:keys [::id ::close-ch ::input-ch ::output-ch ::heartbeat-ch + ::channel ::handler ::beats ::on-rcv-message ::on-snd-message] + :as wsp}] (try (handler wsp {:type :open}) (loop [i 0] @@ -154,14 +155,16 @@ (identical? p ping-ch) (if (handle-ping! wsp i) (recur (inc i)) - (rws/close channel 8802 "missing to many pings")) + (do + (l/trc :hint "closing" :reason "missing to many pings") + (rws/close channel 8802 "missing to many pings"))) (or (identical? p close-ch) (nil? msg)) (do :nothing) (identical? p heartbeat-ch) (let [beat (decode-beat msg)] - ;; (l/trace :hint "pong" :beat beat :conn-id id) + (l/trc :hint "pong received" :beat beat :conn-id (str id)) (swap! beats disj beat) (recur i)) @@ -179,7 +182,6 @@ (identical? p output-ch) (let [message (on-snd-message msg) message (t/encode-str message {:type :json-verbose})] - ;; (l/trace :hint "writing message to output" :message msg) (rws/send channel message) (recur i)))))) @@ -188,12 +190,12 @@ (catch java.io.IOException _) (catch InterruptedException _cause - (l/debug :hint "websocket thread interrumpted" :conn-id id)) + (l/dbg :hint "websocket thread interrumpted" :conn-id id)) (catch Throwable cause - (l/error :hint "unhandled exception on websocket thread" - :conn-id id - :cause cause)) + (l/err :hint "unhandled exception on websocket thread" + :conn-id id + :cause cause)) (finally (try (handler wsp {:type :close}) @@ -212,4 +214,4 @@ (catch Throwable cause (throw cause))) - (l/trace :hint "websocket thread terminated" :conn-id id)))) + (l/trc :hint "websocket thread terminated" :conn-id id)))) diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index aa69184402..7efc11c311 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -358,13 +358,13 @@ (defn changed-attrs "Returns the list of attributes that will change when `update-fn` is applied" - [object update-fn {:keys [attrs]}] + [object objects update-fn {:keys [attrs]}] (let [changed? (fn [old new attr] (let [old-val (get old attr) new-val (get new attr)] (not= old-val new-val))) - new-obj (update-fn object)] + new-obj (update-fn object objects)] (when-not (= object new-obj) (let [attrs (or attrs (d/concat-set (keys object) (keys new-obj)))] (filter (partial changed? object new-obj) attrs))))) @@ -412,7 +412,7 @@ update-shape (fn [changes id] (let [old-obj (get objects id) - new-obj (update-fn old-obj)] + new-obj (update-fn old-obj objects)] (if (= old-obj new-obj) changes (let [[rops uops] (-> (or attrs (d/concat-set (keys old-obj) (keys new-obj))) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 9411566f19..f26a689f4a 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -42,18 +42,21 @@ (reduce migrate-fn data (range (:version data 0) to-version)))))) (defn migrate-file - [{:keys [id data] :as file}] - (let [data (assoc data :id id)] - (-> file - (assoc ::orig-version (:version data)) - (assoc :data (migrate-data data))))) + [{:keys [id data features] :as file}] + (binding [cfeat/*new* (atom #{})] + (let [file (-> file + (update :data assoc :id id) + (update :data migrate-data) + (update :features (fnil into #{}) (deref cfeat/*new*)) + (update :features cfeat/migrate-legacy-features))] + (if (or (not= (:version data) (:version (:data file))) + (not= features (:features file))) + (vary-meta file assoc ::migrated true) + file)))) (defn migrated? - [{:keys [data] :as file}] - (or (::migrated file) - (let [version (:version data)] - (> version - (::orig-version file version))))) + [file] + (true? (-> file meta ::migrated))) ;; Default handler, noop (defmethod migrate :default [data] data) diff --git a/common/src/app/common/geom/rect.cljc b/common/src/app/common/geom/rect.cljc index 62222b707f..5fa77b8d3d 100644 --- a/common/src/app/common/geom/rect.cljc +++ b/common/src/app/common/geom/rect.cljc @@ -353,3 +353,19 @@ (mth/max by1 y1) (mth/min bx2 x2) (mth/min by2 y2))))) +(defn fix-aspect-ratio + [bounds aspect-ratio] + (if aspect-ratio + (let [width (dm/get-prop bounds :width) + height (dm/get-prop bounds :height) + target-height (* width aspect-ratio) + target-width (* height (/ 1 aspect-ratio))] + (cond-> bounds + (> target-height height) + (-> (assoc :height target-height) + (update :y - (/ (- target-height height ) 2))) + + (< target-height height) + (-> (assoc :width target-width) + (update :x - (/ (- target-width width ) 2))))) + bounds)) diff --git a/common/src/app/common/thumbnails.cljc b/common/src/app/common/thumbnails.cljc index 8ab11c8ad9..90eb310a0c 100644 --- a/common/src/app/common/thumbnails.cljc +++ b/common/src/app/common/thumbnails.cljc @@ -1,7 +1,18 @@ (ns app.common.thumbnails - (:require [cuerdas.core :as str])) + (:require + [app.common.uuid :as uuid] + [cuerdas.core :as str])) (defn fmt-object-id "Returns ids formatted as a string (object-id)" [file-id page-id frame-id tag] (str/ffmt "%/%/%/%" file-id page-id frame-id tag)) + +(defn file-id? + "Returns ids formatted as a string (file-id)" + [object-id file-id] + (str/starts-with? object-id (str/concat file-id "/"))) + +(defn get-file-id + [object-id] + (uuid/uuid (str/slice object-id 0 (str/index-of object-id "/")))) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index f384c96e30..30a866b76a 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -676,7 +676,7 @@ [id cell]))) (defn remove-grid-column - [parent index] + [parent index objects] (let [track-num (inc index) @@ -692,10 +692,10 @@ (-> parent (update :layout-grid-columns d/remove-at-index index) (update :layout-grid-cells update-cells) - (assign-cells)))) + (assign-cells objects)))) (defn remove-grid-row - [parent index] + [parent index objects] (let [track-num (inc index) decrease-track-num (make-decrease-track-num :row :row-span track-num) @@ -710,7 +710,7 @@ (-> parent (update :layout-grid-rows d/remove-at-index index) (update :layout-grid-cells update-cells) - (assign-cells)))) + (assign-cells objects)))) (defn- reorder-grid-tracks "Swap the positions of the tracks info" @@ -781,6 +781,7 @@ parent (reorder-grid-tracks parent tracks-props from-index to-index)] + (cond-> parent move-content? (swap-track-content prop from-track to-track)))) @@ -828,14 +829,24 @@ (defn check-deassigned-cells "Clean the cells whith shapes that are no longer in the layout" - [parent] + [parent objects] - (let [child? (set (:shapes parent)) - cells (update-vals - (:layout-grid-cells parent) - (fn [cell] (update cell :shapes #(filterv child? %))))] + (let [child-set (set (:shapes parent)) - (assoc parent :layout-grid-cells cells))) + assigned? + (fn [id] + (and (contains? child-set id) + (not (position-absolute? objects id)))) + + cells + (update-vals + (:layout-grid-cells parent) + (fn [cell] + (-> cell + (update :shapes #(filterv assigned? %)))))] + + (-> parent + (assoc :layout-grid-cells cells)))) (defn overlapping-cells "Find overlapping cells" @@ -902,12 +913,12 @@ ;; - Shape duplication ;; - (maybe) create group/frames. This case will assigna a cell that had one of its children (defn assign-cells - [parent] + [parent objects] (let [;; TODO: Remove this, shouldn't be happening ;;overlaps (overlapping-cells parent) ;;_ (when (not (empty? overlaps)) ;; (.warn js/console "OVERLAPS" overlaps)) - parent (cond-> (check-deassigned-cells parent) + parent (cond-> (check-deassigned-cells parent objects) #_(d/not-empty? overlaps) #_(fix-overlaps overlaps)) @@ -915,7 +926,9 @@ (into #{} (mapcat (comp :shapes second)) (:layout-grid-cells parent)) no-cell-shapes - (->> (:shapes parent) (remove shape-has-cell?)) + (->> (:shapes parent) + (remove shape-has-cell?) + (remove (partial position-absolute? objects))) parent (position-auto-shapes parent)] @@ -1174,7 +1187,7 @@ (let [;; Temporary remove the children when moving them frame (-> frame (update :shapes #(d/removev children %)) - (assign-cells)) + (assign-cells objects)) children (->> children (remove #(position-absolute? objects %)))] @@ -1182,7 +1195,7 @@ (update :shapes d/concat-vec children) (cond-> (some? cell) (push-into-cell children row column)) - (assign-cells)))) + (assign-cells objects)))) (defn add-children-to-index [parent ids objects to-index] diff --git a/frontend/deps.edn b/frontend/deps.edn index b30b74b78f..c96ab0a3ee 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -6,10 +6,17 @@ org.clojure/clojure {:mvn/version "1.11.1"} binaryage/devtools {:mvn/version "RELEASE"} metosin/reitit-core {:mvn/version "0.5.18"} - - funcool/beicon {:mvn/version "2021.07.05-1"} funcool/okulary {:mvn/version "2022.04.11-16"} - funcool/potok {:mvn/version "2022.12.16-71"} + + funcool/potok2 + {:git/tag "v2.0" + :git/sha "2bb377b" + :git/url "https://github.com/funcool/potok.git"} + + funcool/beicon2 + {:git/tag "v2.0" + :git/sha "e7135e0" + :git/url "https://github.com/funcool/beicon.git"} funcool/rumext {:git/tag "v2.7" diff --git a/frontend/package.json b/frontend/package.json index 2b9c7213a9..fd42e11cd3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,6 +46,7 @@ "@storybook/react": "^7.5.3", "@storybook/react-vite": "^7.5.3", "@storybook/testing-library": "^0.2.2", + "@types/node": "^20.10.5", "animate.css": "^4.1.1", "autoprefixer": "^10.4.15", "concurrently": "^8.2.2", @@ -73,6 +74,7 @@ "sass": "^1.66.1", "shadow-cljs": "2.26.2", "storybook": "^7.5.3", + "typescript": "^5.3.3", "vite": "^5.0.2" }, "dependencies": { @@ -90,7 +92,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-virtualized": "^9.22.3", - "rxjs": "~7.8.1", + "rxjs": "8.0.0-alpha.13", "sax": "^1.2.4", "source-map-support": "^0.5.21", "tdigest": "^0.1.2", diff --git a/frontend/resources/fonts/RobotoMono-Regular.ttf b/frontend/resources/fonts/RobotoMono-Regular.ttf new file mode 100644 index 0000000000..6df2b25360 Binary files /dev/null and b/frontend/resources/fonts/RobotoMono-Regular.ttf differ diff --git a/frontend/resources/fonts/SpaceMono-Bold.ttf b/frontend/resources/fonts/SpaceMono-Bold.ttf deleted file mode 100644 index 20e3449515..0000000000 Binary files a/frontend/resources/fonts/SpaceMono-Bold.ttf and /dev/null differ diff --git a/frontend/resources/fonts/SpaceMono-BoldItalic.ttf b/frontend/resources/fonts/SpaceMono-BoldItalic.ttf deleted file mode 100644 index ff2ea5a5c2..0000000000 Binary files a/frontend/resources/fonts/SpaceMono-BoldItalic.ttf and /dev/null differ diff --git a/frontend/resources/fonts/SpaceMono-Italic.ttf b/frontend/resources/fonts/SpaceMono-Italic.ttf deleted file mode 100644 index f36282f261..0000000000 Binary files a/frontend/resources/fonts/SpaceMono-Italic.ttf and /dev/null differ diff --git a/frontend/resources/fonts/SpaceMono-Regular.ttf b/frontend/resources/fonts/SpaceMono-Regular.ttf deleted file mode 100644 index 04e56b923f..0000000000 Binary files a/frontend/resources/fonts/SpaceMono-Regular.ttf and /dev/null differ diff --git a/frontend/resources/images/icons/expand-refactor.svg b/frontend/resources/images/icons/expand-refactor.svg new file mode 100644 index 0000000000..e63fd74c87 --- /dev/null +++ b/frontend/resources/images/icons/expand-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/login-illustration.svg b/frontend/resources/images/icons/login-illustration.svg index a10e27fd94..6e6b7394a3 100644 --- a/frontend/resources/images/icons/login-illustration.svg +++ b/frontend/resources/images/icons/login-illustration.svg @@ -1,666 +1,686 @@ - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + - - + + + + - - - - + + + - - - + - + + - - - - - + + - - + + - - - + + + - - - + + + - - + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - - + + + + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + - - - + + + + + - - + + + - - + + - - - - + + + + + + + + + + + + + + - + - + - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - - + + - + - - + + - + - + - + - - + + - + - - + + - + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - + + + + + diff --git a/frontend/resources/images/icons/reload-refactor.svg b/frontend/resources/images/icons/reload-refactor.svg new file mode 100644 index 0000000000..e1ac593b76 --- /dev/null +++ b/frontend/resources/images/icons/reload-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index cd3b867629..944fa8e522 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -148,6 +148,7 @@ stroke: var(--button-tertiary-foreground-color-active); } } + &:global(.disabled), &[disabled], &:disabled { diff --git a/frontend/resources/styles/common/refactor/color-defs.scss b/frontend/resources/styles/common/refactor/color-defs.scss index 17da351a1e..b7438f76d3 100644 --- a/frontend/resources/styles/common/refactor/color-defs.scss +++ b/frontend/resources/styles/common/refactor/color-defs.scss @@ -4,7 +4,7 @@ // // Copyright (c) KALEIDOS INC -@use "sass:color" as color; +@use "sass:color"; :root { // DARK @@ -31,10 +31,12 @@ --light-gray-1: #fff; --light-gray-2: #e8eaee; --light-gray-2-30: rgba(232, 234, 238, 0.3); + --light-gray-2-80: rgba(232, 234, 238, 0.8); --light-gray-3: #f3f4f6; --light-gray-4: #eef0f2; --black: #000; --off-black: #495e74; + --off-black-30: #{color.change(#495e74, $alpha: 0.3)}; --purple: #6911d4; --purple-30: rgba(105, 17, 212, 0.2); --blue: #1345aa; diff --git a/frontend/resources/styles/common/refactor/common-dashboard.scss b/frontend/resources/styles/common/refactor/common-dashboard.scss index dc0a728e01..f2de6c4eca 100644 --- a/frontend/resources/styles/common/refactor/common-dashboard.scss +++ b/frontend/resources/styles/common/refactor/common-dashboard.scss @@ -157,6 +157,8 @@ .btn-primary { @extend .button-primary; text-transform: uppercase; + font-size: $fs-14; + font-weight: $fw400; } .btn-secondary { diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index c68d1d650c..559d779c9a 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -179,7 +179,7 @@ --menu-shortcut-foreground-color: var(--color-foreground-secondary); --menu-shortcut-foreground-color-selected: var(--color-foreground-primary); --menu-shortcut-foreground-color-hover: var(--color-foreground-primary); - --menu-shadow-color: var(--color-background-subtle); + --menu-shadow-color: var(--shadow-color); --menu-background-color-disabled: var(--color-background-primary); --menu-foreground-color-disabled: var(--color-foreground-secondary); --menu-border-color-disabled: var(--color-background-quaternary); @@ -297,4 +297,13 @@ --tag-background-color: var(--color-accent-primary); --link-foreground-color: var(--color-accent-primary); + + // VIEWER + --viewer-background-color: var(--color-background-secondary); + --viewer-paginator-background-color: var(--color-background-tertiary); + --viewer-controls-background-color: var(--color-background-primary); + --viewer-inspect-border-color: var(--color-background-tertiary); + --viewer-thumbnails-control-foreground-color: var(--color-foreground-secondary); + --viewer-thumbnail-border-color: var(--color-accent-primary); + --viewer-thumbnail-background-color-selected: var(--color-accent-primary-muted); } diff --git a/frontend/resources/styles/common/refactor/mixins.scss b/frontend/resources/styles/common/refactor/mixins.scss index 583ee3a73a..c2f2ce7561 100644 --- a/frontend/resources/styles/common/refactor/mixins.scss +++ b/frontend/resources/styles/common/refactor/mixins.scss @@ -63,6 +63,13 @@ line-height: 1.2; } +@mixin codeTypography { + font-family: "robotomono", monospace; + font-size: $fs-12; + font-weight: $fw400; + line-height: 1.2; +} + @mixin textEllipsis { max-width: 99%; overflow: hidden; diff --git a/frontend/resources/styles/common/refactor/themes/default-theme.scss b/frontend/resources/styles/common/refactor/themes/default-theme.scss index f5d10bad96..20b8067dd6 100644 --- a/frontend/resources/styles/common/refactor/themes/default-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/default-theme.scss @@ -21,6 +21,7 @@ --color-accent-primary-muted: var(--green-30); --color-accent-secondary: var(--lilac); --color-accent-tertiary: var(--strong-green); + --overlay-color: rgba(0, 0, 0, 0.4); --ok-color: var(--dark-ok-color); --warning-color: var(--dark-warning-color); @@ -28,5 +29,8 @@ --error-color: var(--dark-error-color); --canvas-color: var(--color-canvas); + --shadow-color: var(--dark-gray-2-30); + --radio-button-box-shadow: 0 0 0 1px var(--dark-gray-2-30) inset; + @include meta.load-css("hljs-dark-theme"); } diff --git a/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss b/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss index 5ae417d47e..ddfa3a09e7 100644 --- a/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss @@ -1,98 +1,124 @@ -/** - * Panda Syntax Theme for Highlight.js - * Based on: https://github.com/tinkertrain/panda-syntax-vscode - * Author: Annmarie Switzer - */ +/*! + Theme: GitHub Dark Dimmed + Description: Dark dimmed theme as seen on github.com + Author: github.com + Maintainer: @Hirse + Updated: 2021-05-15 + + Colors taken from GitHub's CSS +*/ .hljs { - color: #e6e6e6; - background: #2a2c2d; + color: #adbac7; + background: #22272e; +} + +.hljs-doctag, +.hljs-keyword, +.hljs-meta .hljs-keyword, +.hljs-template-tag, +.hljs-template-variable, +.hljs-type, +.hljs-variable.language_ { + /* prettylights-syntax-keyword */ + color: #f47067; +} + +.hljs-title, +.hljs-title.class_, +.hljs-title.class_.inherited__, +.hljs-title.function_ { + /* prettylights-syntax-entity */ + color: #dcbdfb; +} + +.hljs-attr, +.hljs-attribute, +.hljs-literal, +.hljs-meta, +.hljs-number, +.hljs-operator, +.hljs-variable, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-selector-id { + /* prettylights-syntax-constant */ + color: #6cb6ff; +} + +.hljs-regexp, +.hljs-string, +.hljs-meta .hljs-string { + /* prettylights-syntax-string */ + color: #96d0ff; +} + +.hljs-built_in, +.hljs-symbol { + /* prettylights-syntax-variable */ + color: #f69d50; +} + +.hljs-comment, +.hljs-code, +.hljs-formula { + /* prettylights-syntax-comment */ + color: #768390; +} + +.hljs-name, +.hljs-quote, +.hljs-selector-tag, +.hljs-selector-pseudo { + /* prettylights-syntax-entity-tag */ + color: #8ddb8c; +} + +.hljs-subst { + /* prettylights-syntax-storage-modifier-import */ + color: #adbac7; +} + +.hljs-section { + /* prettylights-syntax-markup-heading */ + color: #316dca; + font-weight: bold; +} + +.hljs-bullet { + /* prettylights-syntax-markup-list */ + color: #eac55f; } .hljs-emphasis { + /* prettylights-syntax-markup-italic */ + color: #adbac7; font-style: italic; } .hljs-strong { + /* prettylights-syntax-markup-bold */ + color: #adbac7; font-weight: bold; } -.hljs-link { - text-decoration: underline; +.hljs-addition { + /* prettylights-syntax-markup-inserted */ + color: #b4f1b4; + background-color: #1b4721; } -.hljs-comment, -.hljs-quote { - color: #bbbbbb; - font-style: italic; -} - -.hljs-params { - color: #bbbbbb; -} - -.hljs-punctuation, -.hljs-attr { - color: #e6e6e6; -} - -.hljs-selector-tag, -.hljs-name, -.hljs-meta { - color: #ff4b82; -} - -.hljs-operator, -.hljs-char.escape_ { - color: #b084eb; -} - -.hljs-keyword, .hljs-deletion { - color: #ff75b5; + /* prettylights-syntax-markup-deleted */ + color: #ffd8d3; + background-color: #78191b; } -.hljs-regexp, -.hljs-selector-pseudo, -.hljs-selector-attr, -.hljs-variable.language_ { - color: #ff9ac1; -} - -.hljs-subst, -.hljs-property, -.hljs-code, -.hljs-formula, -.hljs-section, -.hljs-title.function_ { - color: #45a9f9; -} - -.hljs-string, -.hljs-symbol, -.hljs-bullet, -.hljs-addition, -.hljs-selector-class, -.hljs-title.class_, -.hljs-title.class_.inherited__, -.hljs-meta .hljs-string { - color: #19f9d8; -} - -.hljs-variable, -.hljs-template-variable, -.hljs-number, -.hljs-literal, -.hljs-type, +.hljs-char.escape_, .hljs-link, -.hljs-built_in, -.hljs-title, -.hljs-selector-id, -.hljs-tag, -.hljs-doctag, -.hljs-attribute, -.hljs-template-tag, -.hljs-meta .hljs-keyword, -.hljs-punctuation { - color: #ffb86c; +.hljs-params, +.hljs-property, +.hljs-punctuation, +.hljs-tag { + /* purposely ignored */ } diff --git a/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss b/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss index 615abdd13a..ea2d601f76 100644 --- a/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss @@ -1,94 +1,126 @@ -/** - * Panda Syntax Theme for Highlight.js - * Based on: https://github.com/tinkertrain/panda-syntax-vscode - * Author: Annmarie Switzer - */ +/*! + Theme: GitHub + Description: Light theme as seen on github.com + Author: github.com + Maintainer: @Hirse + Updated: 2021-05-15 + + Outdated base version: https://github.com/primer/github-syntax-light + Current colors taken from GitHub's CSS +*/ .hljs { - color: #2a2c2d; - background: #e6e6e6; + color: #24292e; + background: #ffffff; +} + +.hljs-doctag, +.hljs-keyword, +.hljs-meta .hljs-keyword, +.hljs-template-tag, +.hljs-template-variable, +.hljs-type, +.hljs-variable.language_ { + /* prettylights-syntax-keyword */ + color: #d73a49; +} + +.hljs-title, +.hljs-title.class_, +.hljs-title.class_.inherited__, +.hljs-title.function_ { + /* prettylights-syntax-entity */ + color: #6f42c1; +} + +.hljs-attr, +.hljs-attribute, +.hljs-literal, +.hljs-meta, +.hljs-number, +.hljs-operator, +.hljs-variable, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-selector-id { + /* prettylights-syntax-constant */ + color: #005cc5; +} + +.hljs-regexp, +.hljs-string, +.hljs-meta .hljs-string { + /* prettylights-syntax-string */ + color: #032f62; +} + +.hljs-built_in, +.hljs-symbol { + /* prettylights-syntax-variable */ + color: #e36209; +} + +.hljs-comment, +.hljs-code, +.hljs-formula { + /* prettylights-syntax-comment */ + color: #6a737d; +} + +.hljs-name, +.hljs-quote, +.hljs-selector-tag, +.hljs-selector-pseudo { + /* prettylights-syntax-entity-tag */ + color: #22863a; +} + +.hljs-subst { + /* prettylights-syntax-storage-modifier-import */ + color: #24292e; +} + +.hljs-section { + /* prettylights-syntax-markup-heading */ + color: #005cc5; + font-weight: bold; +} + +.hljs-bullet { + /* prettylights-syntax-markup-list */ + color: #735c0f; } .hljs-emphasis { + /* prettylights-syntax-markup-italic */ + color: #24292e; font-style: italic; } .hljs-strong { + /* prettylights-syntax-markup-bold */ + color: #24292e; font-weight: bold; } -.hljs-link { - text-decoration: underline; +.hljs-addition { + /* prettylights-syntax-markup-inserted */ + color: #22863a; + background-color: #f0fff4; } -.hljs-comment, -.hljs-quote { - color: #676b79; - font-style: italic; -} - -.hljs-params { - color: #676b79; -} - -.hljs-punctuation, -.hljs-attr { - color: #2a2c2d; -} - -.hljs-selector-tag, -.hljs-name, -.hljs-meta, -.hljs-operator, -.hljs-char.escape_ { - color: #c56200; -} - -.hljs-keyword, .hljs-deletion { - color: #d92792; + /* prettylights-syntax-markup-deleted */ + color: #b31d28; + background-color: #ffeef0; } -.hljs-regexp, -.hljs-selector-pseudo, -.hljs-selector-attr, -.hljs-variable.language_ { - color: #cc5e91; -} - -.hljs-subst, -.hljs-property, -.hljs-code, -.hljs-formula, -.hljs-section, -.hljs-title.function_ { - color: #3787c7; -} - -.hljs-string, -.hljs-symbol, -.hljs-bullet, -.hljs-addition, -.hljs-selector-class, -.hljs-title.class_, -.hljs-title.class_.inherited__, -.hljs-meta .hljs-string { - color: #0d7d6c; -} - -.hljs-variable, -.hljs-template-variable, -.hljs-number, -.hljs-literal, -.hljs-type, +.hljs-char.escape_, .hljs-link, -.hljs-built_in, -.hljs-title, -.hljs-selector-id, -.hljs-tag, -.hljs-doctag, -.hljs-attribute, -.hljs-template-tag, -.hljs-meta .hljs-keyword { - color: #7641bb; +.hljs-params, +.hljs-property, +.hljs-punctuation, +.hljs-tag { + /* purposely ignored */ + color: #6a737d; } diff --git a/frontend/resources/styles/common/refactor/themes/light-theme.scss b/frontend/resources/styles/common/refactor/themes/light-theme.scss index 60c904f106..bbfc3337d2 100644 --- a/frontend/resources/styles/common/refactor/themes/light-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/light-theme.scss @@ -21,11 +21,16 @@ --color-accent-primary-muted: var(--purple-30); --color-accent-secondary: var(--blue); --color-accent-tertiary: var(--strong-purple); + + --overlay-color: rgba(255, 255, 255, 0.4); --ok-color: var(--light-ok-color); --warning-color: var(--light-warning-color); --pending-color: var(--light-pending-color); --error-color: var(--light-error-color); --canvas-color: var(--color-canvas); + --shadow-color: var(--off-black-30); + --radio-button-box-shadow: 0 0 0 1px var(--light-gray-2) inset; + @include meta.load-css("hljs-light-theme"); } diff --git a/frontend/src/app/libs/file_builder.cljs b/frontend/src/app/libs/file_builder.cljs index 12d8500ab9..a1605bfdd3 100644 --- a/frontend/src/app/libs/file_builder.cljs +++ b/frontend/src/app/libs/file_builder.cljs @@ -16,7 +16,7 @@ [app.util.webapi :as wapi] [app.util.zip :as uz] [app.worker.export :as e] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str])) (defn parse-data [data] @@ -55,7 +55,7 @@ (->> (rx/from (vals media)) (rx/map #(assoc % :file-id file-id)) - (rx/flat-map + (rx/merge-map (fn [media] (let [file-path (str/concat file-id "/media/" (:id media) (cm/mtype->extension (:mtype media))) blob (data-uri->blob (:uri media))] @@ -79,38 +79,38 @@ render-stream (->> files-stream - (rx/flat-map vals) - (rx/flat-map e/process-pages) + (rx/merge-map vals) + (rx/merge-map e/process-pages) (rx/observe-on :async) - (rx/flat-map e/get-page-data) + (rx/merge-map e/get-page-data) (rx/share)) colors-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/map #(vector (:id %) (get-in % [:data :colors]))) (rx/filter #(d/not-empty? (second %))) (rx/map e/parse-library-color)) typographies-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/map #(vector (:id %) (get-in % [:data :typographies]))) (rx/filter #(d/not-empty? (second %))) (rx/map e/parse-library-typographies)) media-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/map #(vector (:id %) (get-in % [:data :media]))) (rx/filter #(d/not-empty? (second %))) - (rx/flat-map parse-library-media)) + (rx/merge-map parse-library-media)) components-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/filter #(d/not-empty? (ctkl/components-seq (:data %)))) - (rx/flat-map e/parse-library-components)) + (rx/merge-map e/parse-library-components)) pages-stream (->> render-stream @@ -132,7 +132,7 @@ typographies-stream) (rx/reduce conj []) (rx/with-latest-from files-stream) - (rx/flat-map (fn [[data _]] + (rx/merge-map (fn [[data _]] (->> (uz/compress-files data) (rx/map #(vector file %))))))))) diff --git a/frontend/src/app/libs/render.cljs b/frontend/src/app/libs/render.cljs index 93f0e54059..9021bb810e 100644 --- a/frontend/src/app/libs/render.cljs +++ b/frontend/src/app/libs/render.cljs @@ -8,7 +8,7 @@ (:require [app.common.uuid :as uuid] [app.main.render :as r] - [beicon.core :as rx] + [beicon.v2.core :as rx] [promesa.core :as p])) (defn render-page-export @@ -22,7 +22,7 @@ (fn [resolve reject] (->> (r/render-page data) (rx/take 1) - (rx/subs resolve reject))) ))) + (rx/subs! resolve reject))) ))) (defn exports [] #js {:renderPage render-page-export}) diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs index 93aea3d183..7ed4bd059e 100644 --- a/frontend/src/app/main.cljs +++ b/frontend/src/app/main.cljs @@ -28,10 +28,10 @@ [app.util.dom :as dom] [app.util.i18n :as i18n] [app.util.theme :as theme] - [beicon.core :as rx] + [beicon.v2.core :as rx] [debug] [features] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (log/setup! {:app :info}) diff --git a/frontend/src/app/main/broadcast.cljs b/frontend/src/app/main/broadcast.cljs index b83f2fa91e..33e12f12a6 100644 --- a/frontend/src/app/main/broadcast.cljs +++ b/frontend/src/app/main/broadcast.cljs @@ -9,8 +9,8 @@ (:require [app.common.exceptions :as ex] [app.common.transit :as t] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defrecord BroadcastMessage [id type data] cljs.core/IDeref diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs index d491261571..273aeaf2fa 100644 --- a/frontend/src/app/main/data/comments.cljs +++ b/frontend/src/app/main/data/comments.cljs @@ -14,8 +14,8 @@ [app.common.uuid :as uuid] [app.main.data.workspace.state-helpers :as wsh] [app.main.repo :as rp] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (def ^:private schema:comment-thread (sm/define diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs index baa380b7d3..847d2b7a35 100644 --- a/frontend/src/app/main/data/common.cljs +++ b/frontend/src/app/main/data/common.cljs @@ -14,8 +14,8 @@ [app.main.features :as features] [app.main.repo :as rp] [app.util.i18n :refer [tr]] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SHARE LINK @@ -106,9 +106,8 @@ (:typography-count summary))] (modal/show {:type :confirm - :message "" :title (tr "modals.add-shared-confirm.message" (:name summary)) - :hint (if (zero? count) (tr "modals.add-shared-confirm-empty.hint") (tr "modals.add-shared-confirm.hint")) + :message (if (zero? count) (tr "modals.add-shared-confirm-empty.hint") (tr "modals.add-shared-confirm.hint")) :cancel-label (if (zero? count) (tr "labels.cancel") :omit) :accept-label (tr "modals.add-shared-confirm.accept") :accept-style :primary diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index 9e723ca20b..30787180ba 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -30,9 +30,9 @@ [app.util.time :as dt] [app.util.timers :as tm] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (log/set-level! :warn) @@ -419,7 +419,7 @@ (rx/map di/validate-file) (rx/map prepare) (rx/mapcat #(rp/cmd! :update-team-photo %)) - (rx/do on-success) + (rx/tap on-success) (rx/map du/fetch-teams) (rx/catch on-error)))))) @@ -831,9 +831,15 @@ (ptk/reify ::set-file-thumbnail ptk/UpdateEvent (update [_ state] - (-> state - (d/update-in-when [:dashboard-files file-id] assoc :thumbnail-uri thumbnail-uri) - (d/update-in-when [:dashboard-recent-files file-id] assoc :thumbnail-uri thumbnail-uri))))) + (letfn [(update-search-files [files] + (->> files + (mapv #(cond-> % + (= file-id (:id %)) + (assoc :thumbnail-uri thumbnail-uri)))))] + (-> state + (d/update-in-when [:dashboard-files file-id] assoc :thumbnail-uri thumbnail-uri) + (d/update-in-when [:dashboard-recent-files file-id] assoc :thumbnail-uri thumbnail-uri) + (d/update-when :dashboard-search-result update-search-files)))))) ;; --- EVENT: create-file diff --git a/frontend/src/app/main/data/events.cljs b/frontend/src/app/main/data/events.cljs index 28eca73842..9fc8bcea54 100644 --- a/frontend/src/app/main/data/events.cljs +++ b/frontend/src/app/main/data/events.cljs @@ -17,9 +17,10 @@ [app.util.object :as obj] [app.util.storage :refer [storage]] [app.util.time :as dt] - [beicon.core :as rx] + [beicon.v2.core :as rx] + [beicon.v2.operators :as rxo] [lambdaisland.uri :as u] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (l/set-level! :info) @@ -238,7 +239,7 @@ profile (->> (rx/from-atom storage {:emit-current-value? true}) (rx/map :profile) (rx/map :id) - (rx/dedupe))] + (rx/pipe (rxo/distinct-contiguous)))] (l/debug :hint "event instrumentation initialized") @@ -259,12 +260,12 @@ (l/debug :hint "events chunk persisted" :total (count chunk)))) (rx/map (constantly chunk)))))) (rx/take-until stoper) - (rx/subs (fn [chunk] - (swap! buffer remove-from-buffer (count chunk))) - (fn [cause] - (l/error :hint "unexpected error on audit persistence" :cause cause)) - (fn [] - (l/debug :hint "audit persistence terminated")))) + (rx/subs! (fn [chunk] + (swap! buffer remove-from-buffer (count chunk))) + (fn [cause] + (l/error :hint "unexpected error on audit persistence" :cause cause)) + (fn [] + (l/debug :hint "audit persistence terminated")))) (->> stream (rx/with-latest-from profile) @@ -290,10 +291,10 @@ (rx/switch-map #(rx/timer (inst-ms session-timeout))) (rx/take-until stoper) - (rx/subs (fn [_] - (l/debug :hint "session reinitialized") - (reset! session nil)) - (fn [cause] - (l/error :hint "error on event batching stream" :cause cause)) - (fn [] - (l/debug :hitn "events batching stream terminated"))))))))) + (rx/subs! (fn [_] + (l/debug :hint "session reinitialized") + (reset! session nil)) + (fn [cause] + (l/error :hint "error on event batching stream" :cause cause)) + (fn [] + (l/debug :hitn "events batching stream terminated"))))))))) diff --git a/frontend/src/app/main/data/exports.cljs b/frontend/src/app/main/data/exports.cljs index 729d5d74f7..675f1d4d96 100644 --- a/frontend/src/app/main/data/exports.cljs +++ b/frontend/src/app/main/data/exports.cljs @@ -15,8 +15,8 @@ [app.util.dom :as dom] [app.util.time :as dt] [app.util.websocket :as ws] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (def default-timeout 5000) diff --git a/frontend/src/app/main/data/fonts.cljs b/frontend/src/app/main/data/fonts.cljs index d3a499ebac..5c9e3837dc 100644 --- a/frontend/src/app/main/data/fonts.cljs +++ b/frontend/src/app/main/data/fonts.cljs @@ -19,9 +19,9 @@ [app.util.i18n :refer [tr]] [app.util.storage :refer [storage]] [app.util.webapi :as wa] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General purpose events & IMPL diff --git a/frontend/src/app/main/data/media.cljs b/frontend/src/app/main/data/media.cljs index da1049ecf7..7fc52b00c2 100644 --- a/frontend/src/app/main/data/media.cljs +++ b/frontend/src/app/main/data/media.cljs @@ -11,7 +11,7 @@ [app.main.data.messages :as dm] [app.main.store :as st] [app.util.i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [cuerdas.core :as str])) diff --git a/frontend/src/app/main/data/messages.cljs b/frontend/src/app/main/data/messages.cljs index d792b7b175..cce2346996 100644 --- a/frontend/src/app/main/data/messages.cljs +++ b/frontend/src/app/main/data/messages.cljs @@ -9,8 +9,8 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.schema :as sm] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (declare hide) (declare show) diff --git a/frontend/src/app/main/data/modal.cljs b/frontend/src/app/main/data/modal.cljs index fe7055297e..5b5b79524a 100644 --- a/frontend/src/app/main/data/modal.cljs +++ b/frontend/src/app/main/data/modal.cljs @@ -10,7 +10,7 @@ [app.common.uuid :as uuid] [app.main.store :as st] [cljs.core :as c] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defonce components (atom {})) diff --git a/frontend/src/app/main/data/preview.cljs b/frontend/src/app/main/data/preview.cljs index 6d78446ed2..4529293856 100644 --- a/frontend/src/app/main/data/preview.cljs +++ b/frontend/src/app/main/data/preview.cljs @@ -16,10 +16,10 @@ [app.main.refs :as refs] [app.util.code-gen :as cg] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (def style-type "css") (def markup-type "html") @@ -80,7 +80,7 @@ (rx/merge-map fonts/fetch-font-css) (rx/reduce conj []) (rx/map #(str/join "\n" %)) - (rx/subs + (rx/subs! (fn [fontfaces-css] (let [style-code (dm/str diff --git a/frontend/src/app/main/data/shortcuts.cljs b/frontend/src/app/main/data/shortcuts.cljs index 4e679c37b7..55ea364a3a 100644 --- a/frontend/src/app/main/data/shortcuts.cljs +++ b/frontend/src/app/main/data/shortcuts.cljs @@ -13,7 +13,7 @@ [app.common.schema :as sm] [app.config :as cf] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (log/set-level! :warn) diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index 2d085c8edf..f29223841c 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -21,8 +21,8 @@ [app.util.i18n :as i18n] [app.util.router :as rt] [app.util.storage :refer [storage]] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; --- SCHEMAS @@ -434,7 +434,7 @@ (rx/map di/validate-file) (rx/map prepare) (rx/mapcat #(rp/cmd! :update-profile-photo %)) - (rx/do on-success) + (rx/tap on-success) (rx/map (constantly (fetch-profile))) (rx/catch on-error)))))) diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index 997ee96071..e8c00c8acc 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -21,8 +21,8 @@ [app.main.repo :as rp] [app.util.globals :as ug] [app.util.router :as rt] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; --- Local State Initialization diff --git a/frontend/src/app/main/data/websocket.cljs b/frontend/src/app/main/data/websocket.cljs index 7526ea8ca4..b7ec7c2db7 100644 --- a/frontend/src/app/main/data/websocket.cljs +++ b/frontend/src/app/main/data/websocket.cljs @@ -11,8 +11,8 @@ [app.common.uri :as u] [app.config :as cf] [app.util.websocket :as ws] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (l/set-level! :error) @@ -44,7 +44,7 @@ (ptk/reify ::initialize ptk/WatchEvent (watch [_ state stream] - (l/trace :hint "event:initialize" :fn "watch") + (l/trace :hint "initialize" :fn "watch") (let [sid (:session-id state) uri (prepare-uri {:session-id sid}) ws (ws/create uri)] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 16d848a275..edb21077c4 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -78,10 +78,10 @@ [app.util.router :as rt] [app.util.timers :as tm] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (def default-workspace-local {:zoom 1}) @@ -444,7 +444,7 @@ uris (into #{} xform (wsh/lookup-page-objects state page-id))] (->> (rx/from uris) - (rx/subs #(http/fetch-data-uri % false))))))) + (rx/subs! #(http/fetch-data-uri % false))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Workspace Page CRUD @@ -872,10 +872,10 @@ (pcb/update-shapes [parent-id] #(ctl/add-children-to-index % ids objects to-index))) (pcb/update-shapes parents - (fn [parent] + (fn [parent objects] (cond-> parent (ctl/grid-layout? parent) - (ctl/assign-cells)))) + (ctl/assign-cells objects)))) (pcb/reorder-grid-children parents) diff --git a/frontend/src/app/main/data/workspace/bool.cljs b/frontend/src/app/main/data/workspace/bool.cljs index 971b543f70..ac9e06dee4 100644 --- a/frontend/src/app/main/data/workspace/bool.cljs +++ b/frontend/src/app/main/data/workspace/bool.cljs @@ -18,9 +18,9 @@ [app.main.data.workspace.changes :as dch] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn selected-shapes-idx [state] diff --git a/frontend/src/app/main/data/workspace/changes.cljs b/frontend/src/app/main/data/workspace/changes.cljs index 9968f9305f..9b7f1c54dc 100644 --- a/frontend/src/app/main/data/workspace/changes.cljs +++ b/frontend/src/app/main/data/workspace/changes.cljs @@ -20,8 +20,8 @@ [app.main.data.workspace.undo :as dwu] [app.main.store :as st] [app.main.worker :as uw] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; Change this to :info :debug or :trace to debug this module (log/set-level! :warn) @@ -70,7 +70,7 @@ update-layout-ids (->> ids (map (d/getf objects)) - (filter #(some update-layout-attr? (pcb/changed-attrs % update-fn {:attrs attrs}))) + (filter #(some update-layout-attr? (pcb/changed-attrs % objects update-fn {:attrs attrs}))) (map :id)) changes (reduce diff --git a/frontend/src/app/main/data/workspace/collapse.cljs b/frontend/src/app/main/data/workspace/collapse.cljs index bd8ab1766f..07bd85838a 100644 --- a/frontend/src/app/main/data/workspace/collapse.cljs +++ b/frontend/src/app/main/data/workspace/collapse.cljs @@ -8,7 +8,7 @@ (:require [app.common.files.helpers :as cfh] [app.common.uuid :as uuid] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;; --- Shape attrs (Layers Sidebar) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 94f03694a2..a89467786e 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -23,8 +23,8 @@ [app.main.data.workspace.undo :as dwu] [app.util.color :as uc] [app.util.storage :refer [storage]] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; A set of keys that are used for shared state identifiers (def ^:const colorpicker-selected-broadcast-key ::colorpicker-selected) @@ -353,7 +353,7 @@ ;; Stream that updates the stroke/width and stops if `esc` pressed (->> sub (rx/take-until stop?) - (rx/flat-map update-events)) + (rx/merge-map update-events)) ;; Hide the modal if the stop event is emitted (->> stop? diff --git a/frontend/src/app/main/data/workspace/comments.cljs b/frontend/src/app/main/data/workspace/comments.cljs index 3c3f71f74e..ed0734e707 100644 --- a/frontend/src/app/main/data/workspace/comments.cljs +++ b/frontend/src/app/main/data/workspace/comments.cljs @@ -22,8 +22,8 @@ [app.main.streams :as ms] [app.util.mouse :as mse] [app.util.router :as rt] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (declare handle-interrupt) (declare handle-comment-layer-click) diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index 994a0d0dee..19c610c140 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -13,8 +13,8 @@ [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.util.router :as rt] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; Change this to :info :debug or :trace to debug this module (log/set-level! :warn) diff --git a/frontend/src/app/main/data/workspace/drawing.cljs b/frontend/src/app/main/data/workspace/drawing.cljs index a12d2991a8..0254cd2913 100644 --- a/frontend/src/app/main/data/workspace/drawing.cljs +++ b/frontend/src/app/main/data/workspace/drawing.cljs @@ -14,8 +14,8 @@ [app.main.data.workspace.drawing.common :as common] [app.main.data.workspace.drawing.curve :as curve] [app.main.data.workspace.path :as path] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (declare start-drawing) (declare handle-drawing) diff --git a/frontend/src/app/main/data/workspace/drawing/box.cljs b/frontend/src/app/main/data/workspace/drawing/box.cljs index d8ccdf4c92..1823ebd223 100644 --- a/frontend/src/app/main/data/workspace/drawing/box.cljs +++ b/frontend/src/app/main/data/workspace/drawing/box.cljs @@ -24,9 +24,10 @@ [app.main.data.workspace.state-helpers :as wsh] [app.main.snap :as snap] [app.main.streams :as ms] + [app.util.array :as array] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn adjust-ratio [point initial] @@ -128,12 +129,11 @@ (->> ms/mouse-position (rx/filter #(> (gpt/distance % initial) (/ 2 zoom))) - (rx/with-latest vector ms/mouse-position-shift) - (rx/with-latest conj ms/mouse-position-mod) + (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-mod) (rx/switch-map (fn [[point :as current]] (->> (snap/closest-snap-point page-id [shape] objects layout zoom focus point) - (rx/map #(conj current %))))) + (rx/map (partial array/conj current))))) (rx/map (fn [[_ shift? mod? point]] #(update-drawing % initial (cond-> point snap-pixel? (gpt/round-step snap-prec)) shift? mod?))))) diff --git a/frontend/src/app/main/data/workspace/drawing/common.cljs b/frontend/src/app/main/data/workspace/drawing/common.cljs index 455f49330d..4865d0c4c0 100644 --- a/frontend/src/app/main/data/workspace/drawing/common.cljs +++ b/frontend/src/app/main/data/workspace/drawing/common.cljs @@ -16,8 +16,8 @@ [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.worker :as uw] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn clear-drawing [] diff --git a/frontend/src/app/main/data/workspace/drawing/curve.cljs b/frontend/src/app/main/data/workspace/drawing/curve.cljs index f770782812..c223df896a 100644 --- a/frontend/src/app/main/data/workspace/drawing/curve.cljs +++ b/frontend/src/app/main/data/workspace/drawing/curve.cljs @@ -23,8 +23,8 @@ [app.main.streams :as ms] [app.util.mouse :as mse] [app.util.path.simplify-curve :as ups] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (def simplify-tolerance 0.3) diff --git a/frontend/src/app/main/data/workspace/edition.cljs b/frontend/src/app/main/data/workspace/edition.cljs index f5e3b3486b..781629a3f7 100644 --- a/frontend/src/app/main/data/workspace/edition.cljs +++ b/frontend/src/app/main/data/workspace/edition.cljs @@ -10,8 +10,8 @@ [app.common.types.shape.layout :as ctl] [app.main.data.workspace.common :as dwc] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn interrupt? [e] (= e :interrupt)) diff --git a/frontend/src/app/main/data/workspace/fix_bool_contents.cljs b/frontend/src/app/main/data/workspace/fix_bool_contents.cljs index 63a54e7d79..8d0ac516ea 100644 --- a/frontend/src/app/main/data/workspace/fix_bool_contents.cljs +++ b/frontend/src/app/main/data/workspace/fix_bool_contents.cljs @@ -10,8 +10,8 @@ [app.common.geom.shapes :as gsh] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; This event will update the file so the boolean data has a pre-generated path data ;; to increase performance. diff --git a/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs b/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs index 9e2e28af38..c110de09b0 100644 --- a/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs +++ b/frontend/src/app/main/data/workspace/fix_broken_shapes.cljs @@ -7,8 +7,8 @@ (ns app.main.data.workspace.fix-broken-shapes (:require [app.main.data.workspace.changes :as dch] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn- generate-broken-link-changes [attr {:keys [objects id] :as container}] diff --git a/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs b/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs index b5fa36a1eb..06fb376214 100644 --- a/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs +++ b/frontend/src/app/main/data/workspace/fix_deleted_fonts.cljs @@ -12,8 +12,8 @@ [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] [app.main.fonts :as fonts] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; This event will update the file so the texts with non existing custom fonts try to be fixed. ;; This can happen when: diff --git a/frontend/src/app/main/data/workspace/grid.cljs b/frontend/src/app/main/data/workspace/grid.cljs index bf5ed9207e..d8e8b93db9 100644 --- a/frontend/src/app/main/data/workspace/grid.cljs +++ b/frontend/src/app/main/data/workspace/grid.cljs @@ -12,8 +12,8 @@ [app.common.files.changes-builder :as pcb] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Grid diff --git a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs index 5512447b5d..dc6e99fa59 100644 --- a/frontend/src/app/main/data/workspace/grid_layout/editor.cljs +++ b/frontend/src/app/main/data/workspace/grid_layout/editor.cljs @@ -9,7 +9,7 @@ [app.common.geom.rect :as grc] [app.common.types.shape.layout :as ctl] [app.main.data.workspace.state-helpers :as wsh] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn hover-grid-cell [grid-id cell-id add-to-set] diff --git a/frontend/src/app/main/data/workspace/grid_layout/shortcuts.cljs b/frontend/src/app/main/data/workspace/grid_layout/shortcuts.cljs index d003186a86..078858fd72 100644 --- a/frontend/src/app/main/data/workspace/grid_layout/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/grid_layout/shortcuts.cljs @@ -10,8 +10,8 @@ [app.main.data.workspace :as dw] [app.main.data.workspace.common :as dwc] [app.main.store :as st] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Shortcuts diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 76e8e0df16..656173f5e4 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -19,8 +19,8 @@ [app.main.data.workspace.selection :as dws] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn shapes-for-grouping [objects selected] diff --git a/frontend/src/app/main/data/workspace/guides.cljs b/frontend/src/app/main/data/workspace/guides.cljs index 9e4fc3e6fa..5df3d41a09 100644 --- a/frontend/src/app/main/data/workspace/guides.cljs +++ b/frontend/src/app/main/data/workspace/guides.cljs @@ -13,8 +13,8 @@ [app.common.types.page :as ctp] [app.main.data.workspace.changes :as dwc] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn make-update-guide [guide] (fn [other] diff --git a/frontend/src/app/main/data/workspace/highlight.cljs b/frontend/src/app/main/data/workspace/highlight.cljs index f9191ccebd..6f91445bae 100644 --- a/frontend/src/app/main/data/workspace/highlight.cljs +++ b/frontend/src/app/main/data/workspace/highlight.cljs @@ -8,7 +8,7 @@ (:require [app.common.data.macros :as dm] [clojure.set :as set] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;; --- Manage shape's highlight status diff --git a/frontend/src/app/main/data/workspace/interactions.cljs b/frontend/src/app/main/data/workspace/interactions.cljs index a7610d2e5c..ab25849403 100644 --- a/frontend/src/app/main/data/workspace/interactions.cljs +++ b/frontend/src/app/main/data/workspace/interactions.cljs @@ -20,8 +20,8 @@ [app.main.data.workspace.undo :as dwu] [app.main.streams :as ms] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; --- Flows diff --git a/frontend/src/app/main/data/workspace/layers.cljs b/frontend/src/app/main/data/workspace/layers.cljs index 9b6423d31e..afde3c03a0 100644 --- a/frontend/src/app/main/data/workspace/layers.cljs +++ b/frontend/src/app/main/data/workspace/layers.cljs @@ -11,9 +11,9 @@ [app.common.math :as mth] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;; -- Opacity ---------------------------------------------------------- diff --git a/frontend/src/app/main/data/workspace/layout.cljs b/frontend/src/app/main/data/workspace/layout.cljs index 16fdb7f281..5b7209c670 100644 --- a/frontend/src/app/main/data/workspace/layout.cljs +++ b/frontend/src/app/main/data/workspace/layout.cljs @@ -10,7 +10,7 @@ [app.common.data.macros :as dm] [app.util.storage :refer [storage]] [clojure.set :as set] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (def valid-flags #{:sitemap diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 2b7cf15344..9d11f48e72 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -45,9 +45,9 @@ [app.util.i18n :refer [tr]] [app.util.router :as rt] [app.util.time :as dt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default (log/set-level! :warn) @@ -754,6 +754,18 @@ (dch/commit-changes (assoc nonlocal-changes :file-id file-id))))))))))) +(defn- update-component-thumbnail-sync + [state component-id file-id tag] + (let [current-file-id (:current-file-id state) + current-file? (= current-file-id file-id) + data (if current-file? + (get state :workspace-data) + (get-in state [:workspace-libraries file-id :data])) + component (ctkl/get-component data component-id) + page-id (:main-instance-page component) + root-id (:main-instance-id component)] + (dwt/request-thumbnail file-id page-id root-id tag))) + (defn update-component-sync ([shape-id file-id] (update-component-sync shape-id file-id nil)) ([shape-id file-id undo-group] @@ -761,14 +773,18 @@ ptk/WatchEvent (watch [_ state _] (let [current-file-id (:current-file-id state) + current-file? (= current-file-id file-id) page (wsh/lookup-page state) shape (ctn/get-shape page shape-id) + component-id (:component-id shape) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (update-component shape-id undo-group) (sync-file current-file-id file-id :components (:component-id shape) undo-group) - (when (not= current-file-id file-id) + (update-component-thumbnail-sync state component-id file-id "frame") + (update-component-thumbnail-sync state component-id file-id "component") + (when (not current-file?) (sync-file file-id file-id :components (:component-id shape) undo-group)) (dwu/commit-undo-transaction undo-id))))))) @@ -795,7 +811,8 @@ (ptk/reify ::update-component-thumbnail ptk/WatchEvent (watch [_ state _] - (let [data (get state :workspace-data) + (rx/of (update-component-thumbnail-sync state component-id file-id "component")) + #_(let [data (get state :workspace-data) component (ctkl/get-component data component-id) page-id (:main-instance-page component) root-id (:main-instance-id component)] diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index c559be6193..3037b9f893 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -182,10 +182,10 @@ (-> changes (pcb/update-shapes [(:parent-id first-shape)] - (fn [shape] + (fn [shape objects] (-> shape (ctl/push-into-cell [(:id first-shape)] row column) - (ctl/assign-cells)))) + (ctl/assign-cells objects)))) (pcb/reorder-grid-children [(:parent-id first-shape)]))) changes) diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index 984a073e5f..5369e376ac 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -30,9 +30,9 @@ [app.main.store :as st] [app.util.http :as http] [app.util.i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk] + [potok.v2.core :as ptk] [promesa.core :as p] [tubax.core :as tubax])) @@ -122,13 +122,13 @@ (->> (rx/from uris) (rx/filter (comp not svg-url?)) (rx/mapcat upload) - (rx/do on-image)) + (rx/tap on-image)) (->> (rx/from uris) (rx/filter svg-url?) (rx/merge-map (partial fetch-svg name)) (rx/merge-map svg->clj) - (rx/do on-svg))))) + (rx/tap on-svg))))) (defn- process-blobs [{:keys [file-id local? name blobs force-media on-image on-svg]}] @@ -154,14 +154,14 @@ (rx/filter (comp not svg-blob?)) (rx/map prepare-blob) (rx/mapcat #(rp/cmd! :upload-file-media-object %)) - (rx/do on-image)) + (rx/tap on-image)) (->> (rx/from blobs) (rx/map dmm/validate-file) (rx/filter svg-blob?) (rx/merge-map extract-content) (rx/merge-map svg->clj) - (rx/do on-svg))))) + (rx/tap on-svg))))) (defn handle-media-error [error on-error] (if (ex/ex-info? error) @@ -278,7 +278,7 @@ (rx/map dmm/validate-file) (rx/map prepare) (rx/mapcat #(rp/cmd! :upload-file-media-object %)) - (rx/do on-upload-success) + (rx/tap on-upload-success) (rx/catch handle-media-error)))))) ;; --- Upload File Media objects @@ -423,7 +423,7 @@ :timeout nil :tag :media-loading})) (->> (rp/cmd! :clone-file-media-object params) - (rx/do on-success) + (rx/tap on-success) (rx/catch on-error) (rx/finalize #(st/emit! (msg/hide-tag :media-loading))))))))) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 4e36feefa1..dcdd9c4fa4 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -27,8 +27,8 @@ [app.main.data.workspace.guides :as-alias dwg] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; -- temporary modifiers ------------------------------------------- @@ -191,14 +191,14 @@ ;; Temporary remove the children when moving them frame (-> frame (update :shapes #(d/removev ids %)) - (ctl/assign-cells)) + (ctl/assign-cells objects)) ids (->> ids (remove #(ctl/position-absolute? objects %))) frame (-> frame (update :shapes d/concat-vec ids) (cond-> (some? cell) (ctl/push-into-cell ids row column)) - (ctl/assign-cells))] + (ctl/assign-cells objects))] (-> modifiers (ctm/change-property :layout-grid-rows (:layout-grid-rows frame)) diff --git a/frontend/src/app/main/data/workspace/notifications.cljs b/frontend/src/app/main/data/workspace/notifications.cljs index 8a88ddf705..e3578b0f34 100644 --- a/frontend/src/app/main/data/workspace/notifications.cljs +++ b/frontend/src/app/main/data/workspace/notifications.cljs @@ -19,10 +19,11 @@ [app.util.globals :refer [global]] [app.util.mouse :as mse] [app.util.object :as obj] + [app.util.rxops :as rxs] [app.util.time :as dt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (declare process-message) (declare handle-presence) @@ -82,7 +83,7 @@ ;; position changes. (->> stream (rx/filter mse/pointer-event?) - (rx/sample 50) + (rx/pipe (rxs/throttle 100)) (rx/map #(handle-pointer-send file-id (:pt %))))) (rx/take-until stoper))] diff --git a/frontend/src/app/main/data/workspace/path/changes.cljs b/frontend/src/app/main/data/workspace/path/changes.cljs index 21990a28bd..dd188e72e3 100644 --- a/frontend/src/app/main/data/workspace/path/changes.cljs +++ b/frontend/src/app/main/data/workspace/path/changes.cljs @@ -13,8 +13,8 @@ [app.main.data.workspace.path.helpers :as helpers] [app.main.data.workspace.path.state :as st] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn generate-path-changes "Generates changes to update the new content of the shape" diff --git a/frontend/src/app/main/data/workspace/path/common.cljs b/frontend/src/app/main/data/workspace/path/common.cljs index 6bfd0d0000..6892484127 100644 --- a/frontend/src/app/main/data/workspace/path/common.cljs +++ b/frontend/src/app/main/data/workspace/path/common.cljs @@ -8,7 +8,7 @@ (:require [app.common.schema :as sm] [app.main.data.workspace.path.state :as st] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (def valid-commands #{:move-to diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index 912a90718d..64007cc8fa 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -27,8 +27,8 @@ [app.main.data.workspace.path.undo :as undo] [app.main.data.workspace.state-helpers :as wsh] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (declare change-edit-mode) @@ -46,7 +46,8 @@ command (helpers/next-node shape position last-point prev-handler)] (assoc-in state [:workspace-local :edit-path id :preview] command))))) -(defn add-node [{:keys [x y shift?]}] +(defn add-node + [{:keys [x y shift?]}] (ptk/reify ::add-node ptk/UpdateEvent (update [_ state] @@ -135,7 +136,7 @@ (first handlers)) drag-events-stream - (->> (streams/position-stream) + (->> (streams/position-stream state) (rx/map #(drag-handler position idx prefix %)) (rx/take-until (rx/merge @@ -164,7 +165,7 @@ (defn start-path-from-point [position] (ptk/reify ::start-path-from-point ptk/WatchEvent - (watch [_ _ stream] + (watch [_ state stream] (let [stoper (rx/merge (->> stream (rx/filter mse/mouse-event?) @@ -172,7 +173,7 @@ (->> stream (rx/filter helpers/end-path-event?))) - drag-events (->> (streams/position-stream) + drag-events (->> (streams/position-stream state) (rx/map #(drag-handler %)) (rx/take-until stoper))] (rx/concat @@ -190,7 +191,12 @@ (rx/merge-map #(rx/empty)))) (defn make-drag-stream - [stream down-event] + [state stream down-event] + + (dm/assert! + "should be a pointer" + (gpt/point? down-event)) + (let [stoper (rx/merge (->> stream (rx/filter mse/mouse-event?) @@ -198,7 +204,7 @@ (->> stream (rx/filter helpers/end-path-event?))) - drag-events (->> (streams/position-stream) + drag-events (->> (streams/position-stream state) (rx/map #(drag-handler %)) (rx/take-until stoper))] (rx/concat @@ -217,7 +223,7 @@ (assoc-in state [:workspace-local :edit-path id :edit-mode] :draw))) ptk/WatchEvent - (watch [_ _ stream] + (watch [_ state stream] (let [mouse-down (->> stream (rx/filter mse/mouse-event?) (rx/filter mse/mouse-down-event?)) @@ -226,7 +232,7 @@ ;; Mouse move preview mousemove-events - (->> (streams/position-stream) + (->> (streams/position-stream state) (rx/take-until end-path-events) (rx/map #(preview-next-point %))) @@ -234,12 +240,13 @@ mousedown-events (->> mouse-down (rx/take-until end-path-events) - (rx/with-latest merge (streams/position-stream)) - + ;; We just ignore the mouse event and stream down the + ;; last position event + (rx/with-latest-from #(-> %2) (streams/position-stream state)) ;; We change to the stream that emits the first event (rx/switch-map #(rx/race (make-node-events-stream stream) - (make-drag-stream stream %))))] + (make-drag-stream state stream %))))] (rx/concat (rx/of (undo/start-path-undo)) diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index 31080603cf..8f83f67eef 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -28,8 +28,8 @@ [app.main.streams :as ms] [app.util.mouse :as mse] [app.util.path.tools :as upt] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn modify-handler [id index prefix dx dy match-opposite?] (ptk/reify ::modify-handler diff --git a/frontend/src/app/main/data/workspace/path/helpers.cljs b/frontend/src/app/main/data/workspace/path/helpers.cljs index 4249c23fec..feb898abbc 100644 --- a/frontend/src/app/main/data/workspace/path/helpers.cljs +++ b/frontend/src/app/main/data/workspace/path/helpers.cljs @@ -15,7 +15,7 @@ [app.common.svg.path.subpath :as ups] [app.main.data.workspace.path.common :as common] [app.util.mouse :as mse] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn end-path-event? [event] diff --git a/frontend/src/app/main/data/workspace/path/selection.cljs b/frontend/src/app/main/data/workspace/path/selection.cljs index 24b7b0bf4c..c60c13f4a5 100644 --- a/frontend/src/app/main/data/workspace/path/selection.cljs +++ b/frontend/src/app/main/data/workspace/path/selection.cljs @@ -14,8 +14,8 @@ [app.main.data.workspace.path.state :as st] [app.main.streams :as ms] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn path-pointer-enter [position] (ptk/reify ::path-pointer-enter diff --git a/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs b/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs index 56e02a4f36..c73ad3dfca 100644 --- a/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs +++ b/frontend/src/app/main/data/workspace/path/shapes_to_path.cljs @@ -12,8 +12,8 @@ [app.common.types.container :as ctn] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn convert-selected-to-path [] (ptk/reify ::convert-selected-to-path diff --git a/frontend/src/app/main/data/workspace/path/shortcuts.cljs b/frontend/src/app/main/data/workspace/path/shortcuts.cljs index 1b307e88b7..ffbf365784 100644 --- a/frontend/src/app/main/data/workspace/path/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/path/shortcuts.cljs @@ -10,8 +10,8 @@ [app.main.data.workspace :as dw] [app.main.data.workspace.path :as drp] [app.main.store :as st] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Shortcuts diff --git a/frontend/src/app/main/data/workspace/path/streams.cljs b/frontend/src/app/main/data/workspace/path/streams.cljs index 264a145a12..3c429d666b 100644 --- a/frontend/src/app/main/data/workspace/path/streams.cljs +++ b/frontend/src/app/main/data/workspace/path/streams.cljs @@ -15,9 +15,9 @@ [app.main.store :as st] [app.main.streams :as ms] [app.util.mouse :as mse] - [beicon.core :as rx] + [beicon.v2.core :as rx] [okulary.core :as l] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defonce drag-threshold 5) @@ -115,7 +115,6 @@ (defn move-handler-stream [start-point node handler opposite points] - (let [zoom (get-in @st/state [:workspace-local :zoom] 1) ranges (snap/create-ranges points) d-pos (/ snap/snap-path-accuracy zoom) @@ -145,16 +144,20 @@ (let [snap (snap/get-snap-delta [handler] ranges d-pos)] (merge position (gpt/add position snap))))) position))] + (->> ms/mouse-position (rx/map to-pixel-snap) - (rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %)))) - (rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %)))) + (rx/with-latest-from + (fn [position shift? alt?] + (assoc position :shift? shift? :alt? alt?)) + ms/mouse-position-shift + ms/mouse-position-alt) (rx/with-latest-from (snap-toggled-stream)) (rx/map check-path-snap)))) (defn position-stream - [] - (let [zoom (get-in @st/state [:workspace-local :zoom] 1) + [state] + (let [zoom (get-in state [:workspace-local :zoom] 1) d-pos (/ snap/snap-path-accuracy zoom) get-content #(pst/get-path % :content) @@ -169,12 +172,14 @@ (->> ms/mouse-position (rx/map to-pixel-snap) - (rx/with-latest vector ranges-stream) - (rx/with-latest-from (snap-toggled-stream)) - (rx/map (fn [[[position ranges] snap-toggled]] + (rx/with-latest-from ranges-stream (snap-toggled-stream)) + (rx/map (fn [[position ranges snap-toggled]] (if snap-toggled (let [snap (snap/get-snap-delta [position] ranges d-pos)] (gpt/add position snap)) position))) - (rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %)))) - (rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %))))))) + (rx/with-latest-from + (fn [position shift? alt?] + (assoc position :shift? shift? :alt? alt?)) + ms/mouse-position-shift + ms/mouse-position-alt)))) diff --git a/frontend/src/app/main/data/workspace/path/tools.cljs b/frontend/src/app/main/data/workspace/path/tools.cljs index 9743a3c8a7..b302655f81 100644 --- a/frontend/src/app/main/data/workspace/path/tools.cljs +++ b/frontend/src/app/main/data/workspace/path/tools.cljs @@ -14,8 +14,8 @@ [app.main.data.workspace.path.state :as st] [app.main.data.workspace.state-helpers :as wsh] [app.util.path.tools :as upt] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn process-path-tool "Generic function that executes path transformations with the content and selected nodes" diff --git a/frontend/src/app/main/data/workspace/path/undo.cljs b/frontend/src/app/main/data/workspace/path/undo.cljs index 2819cc48fe..754490dda2 100644 --- a/frontend/src/app/main/data/workspace/path/undo.cljs +++ b/frontend/src/app/main/data/workspace/path/undo.cljs @@ -12,9 +12,9 @@ [app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.state :as st] [app.main.store :as store] - [beicon.core :as rx] + [beicon.v2.core :as rx] [okulary.core :as l] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn undo-event? [event] diff --git a/frontend/src/app/main/data/workspace/persistence.cljs b/frontend/src/app/main/data/workspace/persistence.cljs index 509defdeb9..dd056da35a 100644 --- a/frontend/src/app/main/data/workspace/persistence.cljs +++ b/frontend/src/app/main/data/workspace/persistence.cljs @@ -18,9 +18,9 @@ [app.main.store :as st] [app.util.router :as rt] [app.util.time :as dt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [okulary.core :as l] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (log/set-level! :info) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 7e3638292c..497202d7c4 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -36,10 +36,11 @@ [app.main.streams :as ms] [app.main.worker :as uw] [app.util.mouse :as mse] - [beicon.core :as rx] + [beicon.v2.core :as rx] + [beicon.v2.operators :as rxo] [clojure.set :as set] [linked.set :as lks] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn interrupt? [e] @@ -111,8 +112,8 @@ (->> selrect-stream (rx/buffer-time 100) - (rx/map #(last %)) - (rx/dedupe) + (rx/map last) + (rx/pipe (rxo/distinct-contiguous)) (rx/map #(select-shapes-by-current-selrect preserve? ignore-groups?)))) (->> (rx/of (update-selrect nil)) @@ -498,7 +499,8 @@ changes (-> (pcb/add-object changes new-obj {:ignore-touched (and duplicating-component? child?)}) (pcb/amend-last-change #(assoc % :old-id (:id obj))) (cond-> (ctl/grid-layout? objects (:parent-id obj)) - (-> (pcb/update-shapes [(:parent-id obj)] (fn [shape] (-> shape ctl/assign-cells ctl/check-deassigned-cells))) + (-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells) + (pcb/update-shapes [(:parent-id obj)] ctl/check-deassigned-cells) (pcb/reorder-grid-children [(:parent-id obj)])))) changes (cond-> changes diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index ea9b6c5fa8..f13c523819 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -24,8 +24,8 @@ [app.main.data.workspace.shapes :as dws] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (def layout-keys [:layout @@ -79,16 +79,13 @@ (-> shape (merge initial-layout-data) - ;; (cond-> (= type :grid) (-> ctl/assign-cells ctl/reorder-grid-children)) ;; If the original shape is not a frame we set clip content and show-viewer to false (cond-> (not from-frame?) (assoc :show-content true :hide-in-viewer true))) params (calculate-params objects (cfh/get-immediate-children objects (:id shape)) shape)] - (cond-> (merge shape params) - (= type :grid) (-> ctl/assign-cells ctl/reorder-grid-children))) - ))) + (= type :grid) (-> (ctl/assign-cells objects) ctl/reorder-grid-children)))))) ;; Never call this directly but through the data-event `:layout/update` ;; Otherwise a lot of cycle dependencies could be generated @@ -277,10 +274,10 @@ (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes ids - (fn [shape] + (fn [shape objects] (case type - :row (ctl/remove-grid-row shape index) - :column (ctl/remove-grid-column shape index)))) + :row (ctl/remove-grid-row shape index objects) + :column (ctl/remove-grid-column shape index objects)))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -435,11 +432,11 @@ (dwc/update-shapes children-ids (partial fix-child-sizing objects changes)) (dwc/update-shapes parent-ids - (fn [parent] + (fn [parent objects] (-> parent (fix-parent-sizing objects (set ids) changes) (cond-> (ctl/grid-layout? parent) - (ctl/assign-cells))))) + (ctl/assign-cells objects))))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -475,10 +472,9 @@ (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes [layout-id] - (fn [shape] + (fn [shape objects] (case mode :auto ;; change the manual cells and move to auto @@ -492,7 +488,7 @@ (> (:column-span cell) 1)) (-> (d/update-in-when [:layout-grid-cells cell-id] assoc :shapes [] :position :auto) (ctl/resize-cell-area (:row cell) (:column cell) (:row cell) (:column cell) 1 1) - (ctl/assign-cells))))) + (ctl/assign-cells objects))))) shape)) :manual @@ -503,7 +499,7 @@ (cond-> shape (contains? #{:area :auto} (:position cell)) (-> (d/assoc-in-when [:layout-grid-cells cell-id :position] :manual) - (ctl/assign-cells))))) + (ctl/assign-cells objects))))) shape)) :area @@ -522,7 +518,7 @@ first-column (inc (- last-row first-row)) (inc (- last-column first-column))) - (ctl/assign-cells))] + (ctl/assign-cells objects))] (-> shape (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area)))))) @@ -535,8 +531,9 @@ (ptk/reify ::update-grid-cell-position ptk/WatchEvent - (watch [_ _ _] - (let [undo-id (js/Symbol)] + (watch [_ state _] + (let [objects (wsh/lookup-page-objects state) + undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) (dwc/update-shapes @@ -550,6 +547,6 @@ (ctl/resize-cell-area (:row prev-data) (:column prev-data) (:row new-data) (:column new-data) (:row-span new-data) (:column-span new-data)) - (ctl/assign-cells))))) + (ctl/assign-cells objects))))) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index f83eab3a1b..3bfe0e2666 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -24,8 +24,8 @@ [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.features :as features] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn add-shape ([shape] diff --git a/frontend/src/app/main/data/workspace/specialized_panel.cljs b/frontend/src/app/main/data/workspace/specialized_panel.cljs index 467c670775..41f25f14f8 100644 --- a/frontend/src/app/main/data/workspace/specialized_panel.cljs +++ b/frontend/src/app/main/data/workspace/specialized_panel.cljs @@ -9,8 +9,8 @@ [app.common.data :as d] [app.main.data.workspace.common :as-alias dwc] [app.main.data.workspace.state-helpers :as wsh] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn interrupt? [e] (or (= e :interrupt) (= e ::interrupt))) diff --git a/frontend/src/app/main/data/workspace/state_helpers.cljs b/frontend/src/app/main/data/workspace/state_helpers.cljs index 6526610447..c33f62d183 100644 --- a/frontend/src/app/main/data/workspace/state_helpers.cljs +++ b/frontend/src/app/main/data/workspace/state_helpers.cljs @@ -34,6 +34,17 @@ ([state page-id] (dm/get-in state [:viewer :pages page-id :objects]))) +(defn lookup-library-objects + [state file-id page-id] + (dm/get-in state [:workspace-libraries file-id :data :pages-index page-id :objects])) + +(defn lookup-objects + [state file-id page-id] + (let [current-file? (= file-id (:current-file-id state))] + (if ^boolean current-file? + (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))) diff --git a/frontend/src/app/main/data/workspace/svg_upload.cljs b/frontend/src/app/main/data/workspace/svg_upload.cljs index b0af4608bc..d0a262312e 100644 --- a/frontend/src/app/main/data/workspace/svg_upload.cljs +++ b/frontend/src/app/main/data/workspace/svg_upload.cljs @@ -19,9 +19,9 @@ [app.main.data.workspace.undo :as dwu] [app.main.repo :as rp] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn extract-name [href] (let [query-idx (str/last-index-of href "?") diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 9f9988e212..7673101300 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -29,9 +29,9 @@ [app.util.router :as rt] [app.util.text-editor :as ted] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;; -- Attrs diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs index 774c734268..5770542314 100644 --- a/frontend/src/app/main/data/workspace/thumbnails.cljs +++ b/frontend/src/app/main/data/workspace/thumbnails.cljs @@ -24,8 +24,8 @@ [app.util.time :as tp] [app.util.timers :as tm] [app.util.webapi :as wapi] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (l/set-level! :info) @@ -78,7 +78,7 @@ (let [object-id (or object-id (thc/fmt-object-id file-id page-id frame-id tag)) tp (tp/tpoint-ms) - objects (wsh/lookup-page-objects state page-id) + objects (wsh/lookup-objects state file-id page-id) shape (get objects frame-id)] (->> (render/render-frame objects shape object-id) @@ -116,11 +116,16 @@ (ptk/reify ::assoc-thumbnail ptk/UpdateEvent (update [_ state] - (let [prev-uri (dm/get-in state [:workspace-thumbnails object-id])] + (let [prev-uri (dm/get-in state [:workspace-thumbnails object-id]) + current-file-id (:current-file-id state)] (some->> prev-uri (vreset! prev-uri*)) (l/trc :hint "assoc thumbnail" :object-id object-id :uri uri) - (update state :workspace-thumbnails assoc object-id uri))) + #_(update state :workspace-thumbnails assoc object-id uri) + (if (thc/file-id? object-id current-file-id) + (update state :workspace-thumbnails assoc object-id uri) + (let [file-id (thc/get-file-id object-id)] + (update-in state [:workspace-libraries file-id :thumbnails] assoc object-id uri))))) ptk/EffectEvent (effect [_ _ _] @@ -246,7 +251,7 @@ (rx/filter dch/commit-changes?) (rx/observe-on :async) (rx/with-latest-from workspace-data-s) - (rx/flat-map (partial extract-frame-changes page-id)) + (rx/merge-map (partial extract-frame-changes page-id)) (rx/tap #(l/trc :hint "inconming change" :origin "local" :frame-id (dm/str %)))) ;; NOTIFICATIONS CHANGES @@ -254,7 +259,7 @@ (rx/filter (ptk/type? ::wnt/handle-file-change)) (rx/observe-on :async) (rx/with-latest-from workspace-data-s) - (rx/flat-map (partial extract-frame-changes page-id)) + (rx/merge-map (partial extract-frame-changes page-id)) (rx/tap #(l/trc :hint "inconming change" :origin "notifications" :frame-id (dm/str %)))) ;; PERSISTENCE CHANGES diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 580d06367f..5cc82e5b07 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -32,11 +32,12 @@ [app.main.data.workspace.undo :as dwu] [app.main.snap :as snap] [app.main.streams :as ms] + [app.util.array :as array] [app.util.dom :as dom] [app.util.keyboard :as kbd] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) ;; -- Helpers -------------------------------------------------------- @@ -109,7 +110,7 @@ "Enter mouse resize mode, until mouse button is released." [handler ids shape] (letfn [(resize - [shape initial layout [point lock? center? point-snap]] + [shape initial layout [point lock? center? point-snap]] (let [{:keys [width height]} (:selrect shape) {:keys [rotation]} shape @@ -333,10 +334,9 @@ angle))] (rx/concat (->> ms/mouse-position - (rx/with-latest vector ms/mouse-position-mod) - (rx/with-latest vector ms/mouse-position-shift) + (rx/with-latest-from ms/mouse-position-mod ms/mouse-position-shift) (rx/map - (fn [[[pos mod?] shift?]] + (fn [[pos mod? shift?]] (let [delta-angle (calculate-angle pos mod? shift?)] (dwm/set-rotation-modifiers delta-angle shapes group-center)))) (rx/take-until stoper)) @@ -354,8 +354,8 @@ objects (wsh/lookup-page-objects state page-id) shapes (->> ids (map #(get objects %)))] (rx/concat - (rx/of (dwm/set-delta-rotation-modifiers rotation shapes)) - (rx/of (dwm/apply-modifiers))))))) + (rx/of (dwm/set-delta-rotation-modifiers rotation shapes)) + (rx/of (dwm/apply-modifiers))))))) ;; -- Move ---------------------------------------------------------- @@ -395,7 +395,7 @@ (rx/map #(gpt/length %)) (rx/filter #(> % (/ 10 zoom))) (rx/take 1) - (rx/with-latest vector ms/mouse-position-alt) + (rx/with-latest-from ms/mouse-position-alt) (rx/mapcat (fn [[_ alt?]] (rx/concat @@ -480,22 +480,23 @@ ;; We send the nil first so the stream is not waiting for the first value (rx/of nil) (->> position + ;; FIXME: performance throttle (rx/throttle 20) (rx/switch-map (fn [pos] (->> (snap/closest-snap-move page-id shapes objects layout zoom focus pos) - (rx/map #(vector pos %)))))))] + (rx/map #(array pos %)))))))] (if (empty? shapes) (rx/of (finish-transform)) (let [move-stream (->> position ;; We ask for the snap position but we continue even if the result is not available - (rx/with-latest vector snap-delta) + (rx/with-latest-from snap-delta) ;; We try to use the previous snap so we don't have to wait for the result of the new (rx/map snap/correct-snap-point) - (rx/with-latest vector ms/mouse-position-mod) + (rx/with-latest-from ms/mouse-position-mod) (rx/map (fn [[move-vector mod?]] @@ -506,16 +507,16 @@ grid-layout? (ctl/grid-layout? objects target-frame) drop-index (when flex-layout? (gslf/get-drop-index target-frame objects position)) cell-data (when (and grid-layout? (not mod?)) (gslg/get-drop-cell target-frame objects position))] - [move-vector target-frame drop-index cell-data]))) + (array move-vector target-frame drop-index cell-data)))) (rx/take-until stopper))] (rx/merge ;; Temporary modifiers stream (->> move-stream - (rx/with-latest-from ms/mouse-position-shift) + (rx/with-latest-from array/conj ms/mouse-position-shift) (rx/map - (fn [[[move-vector target-frame drop-index cell-data] shift?]] + (fn [[move-vector target-frame drop-index cell-data shift?]] (let [x-disp? (> (mth/abs (:x move-vector)) (mth/abs (:y move-vector))) [move-vector snap-ignore-axis] (cond @@ -538,15 +539,15 @@ (dwm/set-modifiers false false {:snap-ignore-axis snap-ignore-axis})))))) (->> move-stream - (rx/with-latest-from ms/mouse-position-alt) - (rx/filter (fn [[_ alt?]] alt?)) - (rx/take 1) - (rx/mapcat - (fn [[_ alt?]] - (if (and (not duplicate-move-started?) alt?) - (rx/of (start-move-duplicate from-position) - (dws/duplicate-selected false true)) - (rx/empty))))) + (rx/with-latest-from ms/mouse-position-alt) + (rx/filter (fn [[_ alt?]] alt?)) + (rx/take 1) + (rx/mapcat + (fn [[_ alt?]] + (if (and (not duplicate-move-started?) alt?) + (rx/of (start-move-duplicate from-position) + (dws/duplicate-selected false true)) + (rx/empty))))) (->> move-stream (rx/map (comp set-ghost-displacement first))) @@ -629,7 +630,7 @@ (-> changes (pcb/update-shapes [(:id parent)] (fn [shape] (-> shape (assoc :layout-grid-cells layout-grid-cells) - (ctl/assign-cells)))) + (ctl/assign-cells objects)))) (pcb/reorder-grid-children [(:id parent)])))) changes @@ -743,7 +744,7 @@ cpos (gpt/point (:x bbox) (:y bbox)) pos (gpt/point (or (:x position) (:x bbox)) - (or (:y position) (:y bbox))) + (or (:y position) (:y bbox))) delta (gpt/subtract pos cpos) diff --git a/frontend/src/app/main/data/workspace/undo.cljs b/frontend/src/app/main/data/workspace/undo.cljs index 7bc8b61fd0..3c6036c8f0 100644 --- a/frontend/src/app/main/data/workspace/undo.cljs +++ b/frontend/src/app/main/data/workspace/undo.cljs @@ -12,8 +12,8 @@ [app.common.logging :as log] [app.common.schema :as sm] [app.util.time :as dt] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (def discard-transaction-time-millis (* 20 1000)) diff --git a/frontend/src/app/main/data/workspace/viewport.cljs b/frontend/src/app/main/data/workspace/viewport.cljs index 1bbb48ccf0..55eadd321a 100644 --- a/frontend/src/app/main/data/workspace/viewport.cljs +++ b/frontend/src/app/main/data/workspace/viewport.cljs @@ -16,8 +16,8 @@ [app.common.math :as mth] [app.main.data.workspace.state-helpers :as wsh] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn initialize-viewport [{:keys [width height] :as size}] diff --git a/frontend/src/app/main/data/workspace/zoom.cljs b/frontend/src/app/main/data/workspace/zoom.cljs index 8aba81a0b5..379776ede7 100644 --- a/frontend/src/app/main/data/workspace/zoom.cljs +++ b/frontend/src/app/main/data/workspace/zoom.cljs @@ -15,8 +15,8 @@ [app.main.data.workspace.state-helpers :as wsh] [app.main.streams :as ms] [app.util.mouse :as mse] - [beicon.core :as rx] - [potok.core :as ptk])) + [beicon.v2.core :as rx] + [potok.v2.core :as ptk])) (defn- impl-update-zoom [{:keys [vbox] :as local} center zoom] diff --git a/frontend/src/app/main/errors.cljs b/frontend/src/app/main/errors.cljs index 58d1dc7e3c..ed0ad65980 100644 --- a/frontend/src/app/main/errors.cljs +++ b/frontend/src/app/main/errors.cljs @@ -20,7 +20,7 @@ [app.util.storage :refer [storage]] [app.util.timers :as ts] [cuerdas.core :as str] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (defn- print-data! [data] diff --git a/frontend/src/app/main/features.cljs b/frontend/src/app/main/features.cljs index 9c6ff683ed..51b30ed177 100644 --- a/frontend/src/app/main/features.cljs +++ b/frontend/src/app/main/features.cljs @@ -12,11 +12,11 @@ [app.common.logging :as log] [app.config :as cf] [app.main.store :as st] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] [cuerdas.core :as str] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (log/set-level! :trace) @@ -32,11 +32,11 @@ (defn get-team-enabled-features [state] - (let [runtime-features (set/intersection (:features/runtime state #{}) - cfeat/no-migration-features)] - (-> global-enabled-features - (set/union runtime-features) - (set/union (:features/team state #{}))))) + (-> global-enabled-features + (set/union (:features/runtime state #{})) + (set/intersection cfeat/no-migration-features) + (set/union cfeat/default-enabled-features) + (set/union (:features/team state #{})))) (def features-ref (l/derived get-team-enabled-features st/state =)) @@ -99,7 +99,7 @@ ptk/UpdateEvent (update [_ state] (let [runtime-features (get state :features/runtime #{}) - team-features (into cfeat/default-enabled-features + team-features (into #{} cfeat/xf-supported-features team-features)] (-> state diff --git a/frontend/src/app/main/features/pointer_map.cljs b/frontend/src/app/main/features/pointer_map.cljs index 842ae418a1..993427e554 100644 --- a/frontend/src/app/main/features/pointer_map.cljs +++ b/frontend/src/app/main/features/pointer_map.cljs @@ -9,7 +9,7 @@ (:require [app.common.transit :as t] [app.main.repo :as rp] - [beicon.core :as rx])) + [beicon.v2.core :as rx])) (defn resolve-file [{:keys [id data] :as file}] diff --git a/frontend/src/app/main/fonts.cljs b/frontend/src/app/main/fonts.cljs index 905762bedd..889f1c7f7f 100644 --- a/frontend/src/app/main/fonts.cljs +++ b/frontend/src/app/main/fonts.cljs @@ -17,7 +17,7 @@ [app.util.globals :as globals] [app.util.http :as http] [app.util.object :as obj] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] [cuerdas.core :as str] [lambdaisland.uri :as u] @@ -144,7 +144,7 @@ (->> (fetch-gfont-css url) (rx/map process-gfont-css) (rx/tap #(on-loaded id)) - (rx/subs (partial add-font-css! id))) + (rx/subs! (partial add-font-css! id))) nil))) ;; --- LOADER: CUSTOM diff --git a/frontend/src/app/main/rasterizer.cljs b/frontend/src/app/main/rasterizer.cljs index 4479155db1..6fcb4dc8a8 100644 --- a/frontend/src/app/main/rasterizer.cljs +++ b/frontend/src/app/main/rasterizer.cljs @@ -18,7 +18,7 @@ [app.config :as cf] [app.util.dom :as dom] [app.util.http :as http] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str])) (defonce ready? false) @@ -123,18 +123,18 @@ (log/err :hint "rasterizer iframe blocked by adblocker" :origin origin :cause cause) (rx/of false))) - (rx/subs (fn [allowed?] - (if allowed? - (do - (dom/append-child! js/document.body iframe) - (set! instance iframe)) + (rx/subs! (fn [allowed?] + (if allowed? + (do + (dom/append-child! js/document.body iframe) + (set! instance iframe)) - (let [new-origin (dm/str (assoc cf/public-uri :path "/rasterizer.html"))] - (log/warn :hint "fallback to main domain" :origin new-origin) + (let [new-origin (dm/str (assoc cf/public-uri :path "/rasterizer.html"))] + (log/warn :hint "fallback to main domain" :origin new-origin) - (dom/set-attribute! iframe "src" new-origin) - (dom/append-child! js/document.body iframe) + (dom/set-attribute! iframe "src" new-origin) + (dom/append-child! js/document.body iframe) - (set! origin new-origin) - (set! cf/rasterizer-uri cf/public-uri) - (set! instance iframe)))))))) + (set! origin new-origin) + (set! cf/rasterizer-uri cf/public-uri) + (set! instance iframe)))))))) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 3ea0e1d341..5b8620b462 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -48,7 +48,7 @@ [app.util.strings :as ust] [app.util.thumbnails :as th] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -66,16 +66,18 @@ :fill color}]) (defn- calculate-dimensions - [objects] - (let [bounds (->> (ctst/get-root-objects objects) - (map (partial gsb/get-object-bounds objects)) - (grc/join-rects))] + [objects aspect-ratio] + (let [bounds + (->> (ctst/get-root-objects objects) + (map (partial gsb/get-object-bounds objects)) + (grc/join-rects))] (-> bounds (update :x mth/finite 0) (update :y mth/finite 0) (update :width mth/finite 100000) (update :height mth/finite 100000) - (grc/update-rect :position)))) + (grc/update-rect :position) + (grc/fix-aspect-ratio aspect-ratio)))) (declare shape-wrapper-factory) @@ -194,11 +196,11 @@ (mf/defc page-svg {::mf/wrap [mf/memo]} - [{:keys [data use-thumbnails embed include-metadata] :as props + [{:keys [data use-thumbnails embed include-metadata aspect-ratio] :as props :or {embed false include-metadata false}}] (let [objects (:objects data) shapes (cfh/get-immediate-children objects) - dim (calculate-dimensions objects) + dim (calculate-dimensions objects aspect-ratio) vbox (format-viewbox dim) bgcolor (dm/get-in data [:options :background] default-color) @@ -253,11 +255,14 @@ ;; the viewer and inspector (mf/defc frame-svg {::mf/wrap [mf/memo]} - [{:keys [objects frame zoom use-thumbnails] :or {zoom 1} :as props}] + [{:keys [objects frame zoom use-thumbnails aspect-ratio background-color] :or {zoom 1} :as props}] (let [frame-id (:id frame) + + bgcolor (d/nilv background-color default-color) include-metadata (mf/use-ctx export/include-metadata-ctx) - bounds (gsb/get-object-bounds objects frame) + bounds (-> (gsb/get-object-bounds objects frame) + (grc/fix-aspect-ratio aspect-ratio)) ;; Bounds without shadows/blur will be the bounds of the thumbnail bounds2 (gsb/get-object-bounds objects (dissoc frame :shadow :blur)) @@ -305,6 +310,7 @@ :xmlns "http://www.w3.org/2000/svg" :xmlnsXlink "http://www.w3.org/1999/xlink" :xmlns:penpot (when include-metadata "https://penpot.app/xmlns") + :style {:background bgcolor} :fill "none"} [:& shape-wrapper {:shape frame}]]])) @@ -411,11 +417,14 @@ :xmlns "http://www.w3.org/2000/svg" :xmlnsXlink "http://www.w3.org/1999/xlink" :fill "none"} - [:foreignObject {:x 0 :y 0 :width width :height height } - [:img {:src thumbnail-uri - :on-error on-error - :loading "lazy" - :decoding "async"}]] + [:image {:x 0 + :y 0 + :width width + :height height + :href thumbnail-uri + :on-error on-error + :loading "lazy" + :decoding "async"}] (when show-grids? [:& empty-grids {:root-shape-id root-shape-id :objects objects}])]))) @@ -544,7 +553,7 @@ (mapcat get-image-data))] (->> (rx/from images) (rx/map #(cfg/resolve-file-media %)) - (rx/flat-map http/fetch-data-uri)))) + (rx/merge-map http/fetch-data-uri)))) (defn populate-fonts-cache [objects] (let [texts (->> objects @@ -555,10 +564,10 @@ (->> (rx/from texts) (rx/map fonts/get-content-fonts) (rx/reduce set/union #{}) - (rx/flat-map identity) - (rx/flat-map fonts/fetch-font-css) - (rx/flat-map fonts/extract-fontface-urls) - (rx/flat-map http/fetch-data-uri)))) + (rx/merge-map identity) + (rx/merge-map fonts/fetch-font-css) + (rx/merge-map fonts/extract-fontface-urls) + (rx/merge-map http/fetch-data-uri)))) (defn render-page [data] @@ -603,7 +612,7 @@ (render-frame objects shape object-id nil)) ([objects shape object-id options] (if (some? shape) - (let [fonts (ff/shape->fonts shape objects) + (let [fonts (ff/shape->fonts shape objects) bounds (gsb/get-object-bounds objects shape) @@ -617,8 +626,8 @@ viewbox (str/ffmt "% % % %" x y width height) - [fixed-width - fixed-height] (th/get-relative-size width height) + [fixed-width fixed-height] (th/get-relative-size width height) + [component-width component-height] (th/get-proportional-size width height 140 140) data (with-redefs [cfg/public-uri cfg/rasterizer-uri] (rds/renderToStaticMarkup @@ -630,7 +639,8 @@ :x x :y y :width width - :height height})))] + :height height}))) + component? (str/ends-with? object-id "/component")] (->> (fonts/render-font-styles-cached fonts) (rx/catch (fn [cause] @@ -640,9 +650,8 @@ (rx/map (fn [styles] {:id object-id :data data - :viewbox viewbox - :width fixed-width - :height fixed-height + :width (if component? component-width fixed-width) + :height (if component? component-height fixed-height) :styles styles})))) (do diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs index e99f9a4612..a38298143b 100644 --- a/frontend/src/app/main/repo.cljs +++ b/frontend/src/app/main/repo.cljs @@ -12,7 +12,7 @@ [app.config :as cf] [app.util.http :as http] [app.util.sse :as sse] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str])) (defn handle-response diff --git a/frontend/src/app/main/snap.cljs b/frontend/src/app/main/snap.cljs index 0735eebe11..1b7cf7c9e0 100644 --- a/frontend/src/app/main/snap.cljs +++ b/frontend/src/app/main/snap.cljs @@ -19,7 +19,7 @@ [app.main.refs :as refs] [app.main.worker :as uw] [app.util.range-tree :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set])) (def ^:const snap-accuracy 10) diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index 906702b84d..46e77f4d78 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -9,9 +9,10 @@ [app.common.logging :as log] [app.util.object :as obj] [app.util.timers :as tm] - [beicon.core :as rx] + [beicon.v2.core :as rx] + [beicon.v2.operators :as rxo] [okulary.core :as l] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (log/set-level! :info) @@ -65,7 +66,7 @@ (->> stream (rx/filter (ptk/type? :app.main.data.workspace.changes/commit-changes)) (rx/map #(-> % deref :hint-origin str)) - (rx/dedupe)) + (rx/pipe (rxo/distinct-contiguous))) (->> stream (rx/map ptk/type) (rx/filter #(contains? allowed %)) @@ -75,7 +76,7 @@ (> (count buffer) 20) (pop))) #queue []) - (rx/subs #(reset! buffer (vec %)))) + (rx/subs! #(reset! buffer (vec %)))) buffer)) (defn emit! diff --git a/frontend/src/app/main/streams.cljs b/frontend/src/app/main/streams.cljs index b17f5808d4..536e98b661 100644 --- a/frontend/src/app/main/streams.cljs +++ b/frontend/src/app/main/streams.cljs @@ -12,7 +12,8 @@ [app.util.globals :as globals] [app.util.keyboard :as kbd] [app.util.mouse :as mse] - [beicon.core :as rx])) + [beicon.v2.core :as rx] + [beicon.v2.operators :as rxo])) ;; --- User Events @@ -33,23 +34,23 @@ ob (->> pointer (rx/filter #(= :viewport (mse/get-pointer-source %))) (rx/map mse/get-pointer-position))] - (rx/subscribe-with ob sub) + (rx/sub! ob sub) sub)) (defonce mouse-position-ctrl (let [sub (rx/behavior-subject nil) ob (->> pointer (rx/map mse/get-pointer-ctrl-mod) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce mouse-position-meta (let [sub (rx/behavior-subject nil) ob (->> pointer (rx/map mse/get-pointer-meta-mod) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce mouse-position-mod @@ -61,16 +62,16 @@ (let [sub (rx/behavior-subject nil) ob (->> pointer (rx/map mse/get-pointer-shift-mod) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce mouse-position-alt (let [sub (rx/behavior-subject nil) ob (->> pointer (rx/map mse/get-pointer-alt-mod) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce ^:private window-blur @@ -93,8 +94,8 @@ ;; registering the key pressed but on blurring the ;; window (unfocus) the key down is never arrived. (rx/merge window-blur) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce keyboard-ctrl @@ -107,8 +108,8 @@ ;; registering the key pressed but on blurring the ;; window (unfocus) the key down is never arrived. (rx/merge window-blur) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce keyboard-meta @@ -121,8 +122,8 @@ ;; registering the key pressed but on blurring the ;; window (unfocus) the key down is never arrived. (rx/merge window-blur) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) (defonce keyboard-mod @@ -136,6 +137,6 @@ (rx/filter kbd/space?) (rx/filter (complement kbd/editing-event?)) (rx/map kbd/key-down-event?) - (rx/dedupe))] - (rx/subscribe-with ob sub) + (rx/pipe (rxo/distinct-contiguous)))] + (rx/sub! ob sub) sub)) diff --git a/frontend/src/app/main/ui/alert.scss b/frontend/src/app/main/ui/alert.scss index fd7eee9a4a..066381d194 100644 --- a/frontend/src/app/main/ui/alert.scss +++ b/frontend/src/app/main/ui/alert.scss @@ -26,10 +26,7 @@ .modal-content { @include titleTipography; margin-bottom: $s-24; - .modal-msg, - .modal-scd-msg, - .modal-hint, - .modal-subtitle { + .modal-hint { @include titleTipography; } } @@ -49,3 +46,11 @@ } } } + +.modal-scd-msg, +.modal-subtitle, +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} diff --git a/frontend/src/app/main/ui/auth.scss b/frontend/src/app/main/ui/auth.scss index 7a9b9aa19c..ae955b0625 100644 --- a/frontend/src/app/main/ui/auth.scss +++ b/frontend/src/app/main/ui/auth.scss @@ -15,6 +15,7 @@ height: 100%; padding: $s-32; width: 100%; + overflow: auto; &.no-illustration { display: flex; diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index bc64bdf756..249ed8e99e 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -25,7 +25,7 @@ [app.util.i18n :refer [tr]] [app.util.keyboard :as k] [app.util.router :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [rumext.v2 :as mf])) @@ -40,7 +40,7 @@ [event provider params] (dom/prevent-default event) (->> (rp/cmd! :login-with-oidc (assoc params :provider provider)) - (rx/subs (fn [{:keys [redirect-uri] :as rsp}] + (rx/subs! (fn [{:keys [redirect-uri] :as rsp}] (if redirect-uri (.replace js/location redirect-uri) (log/error :hint "unexpected response from OIDC method" @@ -60,7 +60,7 @@ (dom/stop-propagation event) (let [{:keys [on-error]} (meta params)] (->> (rp/cmd! :login-with-ldap params) - (rx/subs (fn [profile] + (rx/subs! (fn [profile] (if-let [token (:invitation-token profile)] (st/emit! (rt/nav :auth-verify-token {} {:token token})) (st/emit! (du/login-from-token {:profile profile})))) @@ -93,10 +93,9 @@ (assoc :message (tr "errors.email-invalid")))))) (mf/defc login-form - [{:keys [params on-success-callback] :as props}] + [{:keys [params on-success-callback origin] :as props}] (let [new-css-system (mf/use-ctx ctx/new-css-system) initial (mf/use-memo (mf/deps params) (constantly params)) - error (mf/use-state false) form (fm/use-form :spec ::login-form :validators [handle-error-messages] @@ -152,7 +151,12 @@ (let [params (:clean-data @form)] (login-with-ldap event (with-meta params {:on-error on-error - :on-success on-success})))))] + :on-success on-success}))))) + + on-recovery-request + (mf/use-fn + #(st/emit! (rt/nav :auth-recovery-request)))] + (if new-css-system [:* (when-let [message @error] @@ -178,10 +182,11 @@ :label (tr "auth.password") :class (stl/css :form-field)}]] - (when (or (contains? cf/flags :login) - (contains? cf/flags :login-with-password)) + (when (and (not= origin :viewer) + (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password))) [:div {:class (stl/css :fields-row :forgot-password)} - [:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request)) + [:& lk/link {:action on-recovery-request :data-test "forgot-password"} (tr "auth.forgot-password")]]) @@ -198,6 +203,7 @@ {:label (tr "auth.login-with-ldap-submit") :on-click on-submit-ldap}])]]] + ;; OLD [:* (when-let [message @error] @@ -271,7 +277,7 @@ :icon i/brand-openid :label (tr "auth.login-with-oidc-submit") :class (stl/css :login-btn :btn-oidc-auth)}])] - + [:div.auth-buttons (when (contains? cf/flags :login-with-google) [:& bl/button-link {:on-click login-with-google @@ -299,28 +305,36 @@ (mf/defc login-button-oidc [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + login-oidc + (mf/use-fn + (mf/deps params) + (fn [event] + (login-with-oidc event :oidc params))) + + handle-key-down + (mf/use-fn + (fn [event] + (when (k/enter? event) + (login-oidc event))))] (if new-css-system (when (contains? cf/flags :login-with-oidc) [:div {:class (stl/css :link-entry :link-oidc)} [:a {:tab-index "0" - :on-key-down (fn [event] - (when (k/enter? event) - (login-with-oidc event :oidc params))) - :on-click #(login-with-oidc % :oidc params)} + :on-key-down handle-key-down + :on-click login-oidc} (tr "auth.login-with-oidc-submit")]]) - + + ;; OLD (when (contains? cf/flags :login-with-oidc) [:div.link-entry.link-oidc [:a {:tab-index "0" - :on-key-down (fn [event] - (when (k/enter? event) - (login-with-oidc event :oidc params))) - :on-click #(login-with-oidc % :oidc params)} + :on-key-down handle-key-down + :on-click login-oidc} (tr "auth.login-with-oidc-submit")]])))) (mf/defc login-methods - [{:keys [params on-success-callback] :as props}] + [{:keys [params on-success-callback origin] :as props}] (let [new-css-system (mf/use-ctx ctx/new-css-system)] (if new-css-system [:* @@ -336,7 +350,7 @@ (when (or (contains? cf/flags :login) (contains? cf/flags :login-with-password) (contains? cf/flags :login-with-ldap)) - [:& login-form {:params params :on-success-callback on-success-callback}])] + [:& login-form {:params params :on-success-callback on-success-callback :origin origin}])] ;; OLD [:* @@ -364,7 +378,19 @@ (mf/defc login-page [{:keys [params] :as props}] - (let [new-css-system (mf/use-ctx ctx/new-css-system)] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + go-register + (mf/use-fn + #(st/emit! (rt/nav :auth-register {} params))) + + on-pass-recovery + (mf/use-fn + #(st/emit! (rt/nav :auth-recovery-request))) + + on-create-demo-profile + (mf/use-fn + #(st/emit! (du/create-demo-profile)))] + (if new-css-system [:div {:class (stl/css :auth-form)} [:h1 {:class (stl/css :auth-title) @@ -375,17 +401,24 @@ [:& login-methods {:params params}] [:div {:class (stl/css :links)} + (when (or (contains? cf/flags :login) + (contains? cf/flags :login-with-password)) + [:div {:class (stl/css :link-entry :register)} + [:& lk/link {:action on-pass-recovery + :data-test "forgot-password"} + (tr "auth.forgot-password")]]) + (when (contains? cf/flags :registration) [:div {:class (stl/css :link-entry :register)} [:span (tr "auth.register") " "] - [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params)) + [:& lk/link {:action go-register :data-test "register-submit"} (tr "auth.register-submit")]])] (when (contains? cf/flags :demo-users) [:div {:class (stl/css :link-entry :demo-account)} [:span (tr "auth.create-demo-profile") " "] - [:& lk/link {:action #(st/emit! (du/create-demo-profile)) + [:& lk/link {:action on-create-demo-profile :data-test "demo-account-link"} (tr "auth.create-demo-account")]])] @@ -400,14 +433,14 @@ (when (or (contains? cf/flags :login) (contains? cf/flags :login-with-password)) [:div.link-entry - [:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request)) + [:& lk/link {:action on-pass-recovery :data-test "forgot-password"} (tr "auth.forgot-password")]]) (when (contains? cf/flags :registration) [:div.link-entry [:span (tr "auth.register") " "] - [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params)) + [:& lk/link {:action go-register :data-test "register-submit"} (tr "auth.register-submit")]])] @@ -415,7 +448,7 @@ [:div.links.demo [:div.link-entry [:span (tr "auth.create-demo-profile") " "] - [:& lk/link {:action #(st/emit! (du/create-demo-profile)) + [:& lk/link {:action on-create-demo-profile :data-test "demo-account-link"} (tr "auth.create-demo-account")]]])]]))) diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index 04202336d5..f9138025ff 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -18,7 +18,7 @@ [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index da8f5277ab..432c852ae4 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -22,7 +22,7 @@ [app.main.ui.messages :as msgs] [app.util.i18n :refer [tr tr-html]] [app.util.router :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [rumext.v2 :as mf])) @@ -109,7 +109,7 @@ (->> (rp/cmd! :prepare-register-profile cdata) (rx/map #(merge % params)) (rx/finalize #(reset! submitted? false)) - (rx/subs + (rx/subs! on-success (partial handle-prepare-register-error form))))))] @@ -303,7 +303,7 @@ (let [params (:clean-data @form)] (->> (rp/cmd! :register-profile params) (rx/finalize #(reset! submitted? false)) - (rx/subs on-success + (rx/subs! on-success (partial handle-register-error form))))))] (if new-css-system @@ -375,7 +375,7 @@ [:div {:class (stl/css :link-entry :go-back)} [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))} (tr "labels.go-back")]]]] - + ;; OLD [:div.form-container [:h1 {:data-test "register-title"} (tr "auth.register-title")] diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs index c8f917cb95..db8f7745ac 100644 --- a/frontend/src/app/main/ui/auth/verify_token.cljs +++ b/frontend/src/app/main/ui/auth/verify_token.cljs @@ -18,7 +18,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (defmulti handle-token (fn [token] (:iss token))) @@ -69,7 +69,7 @@ (mf/with-effect [] (dom/set-html-title (tr "title.default")) (->> (rp/cmd! :verify-token {:token token}) - (rx/subs + (rx/subs! (fn [tdata] (handle-token tdata)) (fn [{:keys [type code] :as error}] diff --git a/frontend/src/app/main/ui/components/color_bullet_new.cljs b/frontend/src/app/main/ui/components/color_bullet_new.cljs index 4281edf62d..6af3f502b4 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.cljs +++ b/frontend/src/app/main/ui/components/color_bullet_new.cljs @@ -17,11 +17,13 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [{:keys [color on-click mini? area]}] - (let [on-click (mf/use-fn - (mf/deps color on-click) - (fn [event] - (when (fn? on-click) - (^function on-click color event))))] + (let [read-only? (nil? on-click) + on-click + (mf/use-fn + (mf/deps color on-click) + (fn [event] + (when (fn? on-click) + (^function on-click color event))))] (if (uc/multiple? color) [:div {:on-click on-click :class (stl/css :color-bullet :multiple)}] @@ -39,7 +41,9 @@ :is-not-library-color (nil? id) :is-gradient (some? gradient) :is-transparent (and opacity (> 1 opacity)) - :grid-area area) + :grid-area area + :read-only read-only?) + :data-readonly (str read-only?) :on-click on-click} (cond diff --git a/frontend/src/app/main/ui/components/color_bullet_new.scss b/frontend/src/app/main/ui/components/color_bullet_new.scss index 7703ebf41b..9da0251159 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.scss +++ b/frontend/src/app/main/ui/components/color_bullet_new.scss @@ -64,7 +64,7 @@ height: 100%; background-color: var(--color-bullet-background-color); } - &:hover { + &:hover:not(.read-only) { border: $s-2 solid var(--color-bullet-border-color-selected); } } @@ -87,6 +87,7 @@ @include inspectValue; color: var(--palette-text-color); height: $s-16; + text-align: center; } .no-text { diff --git a/frontend/src/app/main/ui/components/copy_button.cljs b/frontend/src/app/main/ui/components/copy_button.cljs index 745567979f..49cb7f63e3 100644 --- a/frontend/src/app/main/ui/components/copy_button.cljs +++ b/frontend/src/app/main/ui/components/copy_button.cljs @@ -12,7 +12,7 @@ [app.main.ui.icons :as i] [app.util.timers :as timers] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (mf/defc copy-button [{:keys [data on-copied children class]}] diff --git a/frontend/src/app/main/ui/components/radio_buttons.scss b/frontend/src/app/main/ui/components/radio_buttons.scss index 4076cb9d0c..51b81415e7 100644 --- a/frontend/src/app/main/ui/components/radio_buttons.scss +++ b/frontend/src/app/main/ui/components/radio_buttons.scss @@ -40,6 +40,7 @@ &.checked { border: none; background-color: var(--radio-btn-background-color-selected); + box-shadow: var(--radio-button-box-shadow); svg { stroke: var(--radio-btn-foreground-color-selected); } diff --git a/frontend/src/app/main/ui/components/title_bar.scss b/frontend/src/app/main/ui/components/title_bar.scss index d69d8affaa..acea5d58f4 100644 --- a/frontend/src/app/main/ui/components/title_bar.scss +++ b/frontend/src/app/main/ui/components/title_bar.scss @@ -24,6 +24,7 @@ height: 100%; min-height: $s-32; color: var(--title-foreground-color); + overflow: hidden; } .title-only { margin-left: $s-8; @@ -36,6 +37,7 @@ padding: 0; color: var(--title-foreground-color); stroke: var(--title-foreground-color); + overflow: hidden; .toggle-btn { @include buttonStyle; display: flex; @@ -44,6 +46,7 @@ padding: 0; color: var(--title-foreground-color); stroke: var(--title-foreground-color); + overflow: hidden; .collapsabled-icon { @include flexCenter; height: $s-24; diff --git a/frontend/src/app/main/ui/confirm.scss b/frontend/src/app/main/ui/confirm.scss index 84b9b7ae60..7d01aff684 100644 --- a/frontend/src/app/main/ui/confirm.scss +++ b/frontend/src/app/main/ui/confirm.scss @@ -26,11 +26,6 @@ .modal-content { @include titleTipography; margin-bottom: $s-24; - .modal-msg, - .modal-scd-msg, - .modal-subtitle { - @include titleTipography; - } .component-list { .modal-item-element { @include flexRow; @@ -68,3 +63,11 @@ } } } + +.modal-scd-msg, +.modal-subtitle, +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index 54894422e0..6905c68bc0 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -65,7 +65,6 @@ (d/seek :is-default) (:id))) - on-resize (mf/use-fn (fn [_] @@ -256,7 +255,7 @@ :section section :search-term search-term :team team}])])]] - + [:& (mf/provider ctx/current-team-id) {:value team-id} [:& (mf/provider ctx/current-project-id) {:value project-id} ;; NOTE: dashboard events and other related functions assumes diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs index 9f3b4e28a7..45c4d75d60 100644 --- a/frontend/src/app/main/ui/dashboard/comments.cljs +++ b/frontend/src/app/main/ui/dashboard/comments.cljs @@ -19,7 +19,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc comments-icon diff --git a/frontend/src/app/main/ui/dashboard/export.cljs b/frontend/src/app/main/ui/dashboard/export.cljs index 7f6c300282..d1ff72b124 100644 --- a/frontend/src/app/main/ui/dashboard/export.cljs +++ b/frontend/src/app/main/ui/dashboard/export.cljs @@ -16,7 +16,7 @@ [app.main.worker :as uw] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (def ^:const options [:all :merge :detach]) @@ -101,8 +101,9 @@ :features features :export-type selected :files files}) - (rx/delay-emit 1000) - (rx/subs + (rx/mapcat #(->> (rx/of %) + (rx/delay 1000))) + (rx/subs! (fn [msg] (cond (= :error (:type msg)) diff --git a/frontend/src/app/main/ui/dashboard/export.scss b/frontend/src/app/main/ui/dashboard/export.scss index 47a4888bd6..6d092f1679 100644 --- a/frontend/src/app/main/ui/dashboard/export.scss +++ b/frontend/src/app/main/ui/dashboard/export.scss @@ -25,11 +25,6 @@ .modal-content { @include titleTipography; margin-bottom: $s-24; - .modal-msg, - .modal-scd-msg, - .modal-subtitle { - @include titleTipography; - } .export-option { @extend .input-checkbox; width: 100%; @@ -68,6 +63,14 @@ } } +.modal-scd-msg, +.modal-subtitle, +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} + .file-entry { .file-name { @include flexRow; diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index cfd6b748f6..d0ebba7aac 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -18,8 +18,8 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] - [beicon.core :as rx] - [potok.core :as ptk] + [beicon.v2.core :as rx] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (defn get-project-name @@ -195,7 +195,7 @@ (when show? (->> (rp/cmd! :get-all-projects) (rx/map group-by-team) - (rx/subs #(when (mf/ref-val mounted-ref) + (rx/subs! #(when (mf/ref-val mounted-ref) (reset! teams %))))))) (when current-team diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index f81d194f5a..30cfa5f392 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -20,7 +20,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -75,7 +75,7 @@ (mf/deps team installed-fonts) (fn [blobs] (->> (df/process-upload blobs (:id team)) - (rx/subs (fn [result] + (rx/subs! (fn [result] (swap! fonts df/merge-and-group-fonts installed-fonts result)) (fn [error] (js/console.error "error" error)))))) @@ -87,7 +87,7 @@ (swap! uploading conj (:id item)) (->> (rp/cmd! :create-font-variant item) (rx/delay-at-least 2000) - (rx/subs (fn [font] + (rx/subs! (fn [font] (swap! fonts dissoc (:id item)) (swap! uploading disj (:id item)) (st/emit! (df/add-font font))) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 66a3f98601..57108c88b2 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -35,7 +35,7 @@ [app.util.keyboard :as kbd] [app.util.time :as dt] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -61,7 +61,7 @@ (rx/map (fn [styles] (assoc result :styles styles - :width 250)))))) + :width 252)))))) (rx/mapcat thr/render) (rx/mapcat (partial persist-thumbnail file-id revn)))) @@ -75,7 +75,7 @@ (mf/with-effect [file-id revn visible? thumbnail-uri] (when (and visible? (not thumbnail-uri)) (->> (ask-for-thumbnail file-id revn) - (rx/subs (fn [url] + (rx/subs! (fn [url] (st/emit! (dd/set-file-thumbnail file-id url))) (fn [cause] (log/error :hint "unable to render thumbnail" diff --git a/frontend/src/app/main/ui/dashboard/grid.scss b/frontend/src/app/main/ui/dashboard/grid.scss index 55d63faee8..818b7fdce6 100644 --- a/frontend/src/app/main/ui/dashboard/grid.scss +++ b/frontend/src/app/main/ui/dashboard/grid.scss @@ -7,7 +7,7 @@ @import "refactor/common-refactor.scss"; $thumbnail-default-width: $s-252; // Default width -$thumbnail-aspect-ration: #{2 / 3}; // Ratio 2:3 +$thumbnail-default-height: $s-168; // Default width .dashboard-grid { font-size: $fs-14; @@ -44,10 +44,12 @@ $thumbnail-aspect-ration: #{2 / 3}; // Ratio 2:3 } .grid-item-th { - border-radius: $br-4; + border-radius: $br-8; text-align: initial; width: var(--th-width, #{$thumbnail-default-width}); - height: calc(var(--th-width, #{$thumbnail-default-width}) * #{$thumbnail-aspect-ration}); + height: var(--th-height, #{$thumbnail-default-height}); + background-size: cover; + overflow: hidden; img { object-fit: contain; @@ -59,7 +61,7 @@ $thumbnail-aspect-ration: #{2 / 3}; // Ratio 2:3 outline: $br-4 solid $da-primary; text-align: initial; width: calc(var(--th-width) + $s-12); - height: calc(var(--th-width, #{$thumbnail-default-width}) * #{$thumbnail-aspect-ration}); + height: var(--th-height, #{$thumbnail-default-height}); } &.overlay { @@ -131,10 +133,10 @@ $thumbnail-aspect-ration: #{2 / 3}; // Ratio 2:3 .item-badge { background-color: $da-primary; border: none; - border-radius: $br-4; + border-radius: $br-6; position: absolute; - top: $s-8; - right: $s-8; + top: $s-12; + right: $s-12; height: $s-32; width: $s-32; display: flex; @@ -258,17 +260,10 @@ $thumbnail-aspect-ration: #{2 / 3}; // Ratio 2:3 .grid-item-th { border-radius: $br-4; cursor: pointer; - - background-position: center; - background-size: auto 80%; - background-repeat: no-repeat; - height: 100%; overflow: hidden; position: relative; width: 100%; - - background-color: var(--canvas-color); display: flex; justify-content: center; flex-direction: row; @@ -283,8 +278,9 @@ $thumbnail-aspect-ration: #{2 / 3}; // Ratio 2:3 width: 100%; } - svg#loader-pencil { - fill: $db-cuaternary; + :global(svg#loader-pencil) { + stroke: $db-cuaternary; + width: calc(var(--th-width, #{$thumbnail-default-width}) * 0.25); } } diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index 426843edbf..d0d4b4d2c5 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -25,9 +25,9 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (log/set-level! :debug) @@ -319,9 +319,9 @@ (->> (uw/ask-many! {:cmd :analyze-import :files files}) - (rx/delay-emit emit-delay) + (rx/mapcat #(rx/delay emit-delay (rx/of %))) (rx/filter some?) - (rx/subs + (rx/subs! (fn [{:keys [uri data error type] :as msg}] (if (some? error) (swap! state update :files set-analyze-error uri) @@ -337,7 +337,7 @@ :project-id project-id :files files :features @features/features-ref}) - (rx/subs + (rx/subs! (fn [{:keys [file-id status message errors] :as msg}] (swap! state update :files update-status file-id status message errors)))))) @@ -351,17 +351,15 @@ on-template-cloned-success (fn [] - (swap! state - (fn [state] - (-> state - (assoc :status :importing :importing-templates 0)))) + (swap! state assoc :status :importing :importing-templates 0) (st/emit! (dd/fetch-recent-files))) on-template-cloned-error (fn [cause] - (errors/print-cause! "Template Clone Error" cause) - (st/emit! (modal/hide) - (msg/error (tr "dashboard.libraries-and-templates.import-error")))) + (swap! state assoc :status :error :importing-templates 0) + (errors/print-error! cause) + (rx/of (modal/hide) + (msg/error (tr "dashboard.libraries-and-templates.import-error")))) continue-files (fn [] diff --git a/frontend/src/app/main/ui/dashboard/import.scss b/frontend/src/app/main/ui/dashboard/import.scss index a8c8baf22c..3ed738462e 100644 --- a/frontend/src/app/main/ui/dashboard/import.scss +++ b/frontend/src/app/main/ui/dashboard/import.scss @@ -26,11 +26,6 @@ .modal-content { @include titleTipography; margin-bottom: $s-24; - .modal-msg, - .modal-scd-msg, - .modal-subtitle { - @include titleTipography; - } .feedback-banner { @include flexRow; height: $s-32; @@ -79,6 +74,14 @@ } } +.modal-scd-msg, +.modal-subtitle, +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} + .file-entry { .file-name { @include flexRow; diff --git a/frontend/src/app/main/ui/dashboard/placeholder.scss b/frontend/src/app/main/ui/dashboard/placeholder.scss index 9b10a5a091..829ad1d530 100644 --- a/frontend/src/app/main/ui/dashboard/placeholder.scss +++ b/frontend/src/app/main/ui/dashboard/placeholder.scss @@ -65,7 +65,7 @@ text-transform: uppercase; border: $s-2 solid transparent; width: var(--th-width, #{g.$thumbnail-default-width}); - height: calc(var(--th-width, #{g.$thumbnail-default-width}) * #{g.$thumbnail-aspect-ration}); + height: var(--th-height, #{g.$thumbnail-default-height}); svg { width: $s-32; diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 545d9c0aa9..572c72f778 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -15,6 +15,7 @@ [app.main.data.messages :as msg] [app.main.data.modal :as modal] [app.main.data.users :as du] + [app.main.errors :as errors] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.context :as ctx] @@ -30,7 +31,7 @@ [app.util.time :as dt] [cuerdas.core :as str] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc header @@ -138,10 +139,10 @@ on-template-cloned-error (mf/use-fn - (fn [] - (swap! state #(assoc % :status :waiting)) - (st/emit! - (msg/error (tr "dashboard.libraries-and-templates.import-error"))))) + (fn [cause] + (swap! state assoc :status :error) + (errors/print-error! cause) + (st/emit! (msg/error (tr "dashboard.libraries-and-templates.import-error"))))) download-tutorial (mf/use-fn diff --git a/frontend/src/app/main/ui/dashboard/projects.scss b/frontend/src/app/main/ui/dashboard/projects.scss index da1e4d4ffc..8dcf8e9406 100644 --- a/frontend/src/app/main/ui/dashboard/projects.scss +++ b/frontend/src/app/main/ui/dashboard/projects.scss @@ -33,7 +33,6 @@ .project { align-items: center; - background: $df-primary; border-radius: $br-4; display: flex; flex-direction: row; @@ -87,8 +86,8 @@ cursor: pointer; font-size: $fs-16; line-height: 0.8; - font-weight: $fw700; - color: $db-secondary; + font-weight: $fw400; + color: $df-primary; margin-right: $s-4; margin-right: $s-12; } @@ -98,7 +97,7 @@ font-size: $fs-14; line-height: 1.15; font-weight: $fw400; - color: $db-primary; + color: $df-secondary; @media (max-width: 760px) { display: none; } @@ -109,6 +108,9 @@ opacity: 1; margin-left: $s-32; + svg { + fill: $df-primary; + } .btn-small { height: $s-32; margin: 0 $s-8; @@ -139,7 +141,7 @@ &.active { svg { - fill: $db-tertiary; + fill: $da-primary; } } } @@ -188,28 +190,6 @@ } } -.dashboard-project-row .project { - background-color: transparent; - - h2 { - color: $df-primary; - font-weight: 400; - } - span, - .info, - .recent-files-row-title-info { - color: $df-secondary; - } - .project-actions { - svg { - fill: $df-primary; - } - .pin-icon svg { - fill: $df-secondary; - } - } -} - .team-hero { background-color: $db-tertiary; border-radius: $br-8; diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 8b469639a6..4b61fb2bab 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -33,10 +33,10 @@ [app.util.object :as obj] [app.util.router :as rt] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [goog.functions :as f] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc sidebar-project diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss index 8d357be395..ba97239eaa 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.scss +++ b/frontend/src/app/main/ui/dashboard/sidebar.scss @@ -335,7 +335,7 @@ transform: rotate(45deg); &:hover { - fill: var(--warning-color); + fill: $da-primary; } } } @@ -420,7 +420,10 @@ } &:hover { - background-color: $db-cuaternary; + background-color: $db-secondary; + span { + color: $da-primary; + } } &.current { diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 919675791d..2f4f57a65d 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -27,7 +27,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [cuerdas.core :as str] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/dashboard/team_form.cljs b/frontend/src/app/main/ui/dashboard/team_form.cljs index 5333e72253..08a8d1df89 100644 --- a/frontend/src/app/main/ui/dashboard/team_form.cljs +++ b/frontend/src/app/main/ui/dashboard/team_form.cljs @@ -17,7 +17,7 @@ [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/dashboard/templates.cljs b/frontend/src/app/main/ui/dashboard/templates.cljs index 0bd2394cd9..c733d4f3e5 100644 --- a/frontend/src/app/main/ui/dashboard/templates.cljs +++ b/frontend/src/app/main/ui/dashboard/templates.cljs @@ -23,7 +23,7 @@ [app.util.keyboard :as kbd] [app.util.router :as rt] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def builtin-templates diff --git a/frontend/src/app/main/ui/delete_shared.cljs b/frontend/src/app/main/ui/delete_shared.cljs index 1fb568b961..a1e341f45a 100644 --- a/frontend/src/app/main/ui/delete_shared.cljs +++ b/frontend/src/app/main/ui/delete_shared.cljs @@ -16,7 +16,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as k] - [beicon.core :as rx] + [beicon.v2.core :as rx] [goog.events :as events] [rumext.v2 :as mf])) @@ -85,7 +85,7 @@ (rx/mapcat identity) (rx/map (juxt :id :name)) (rx/reduce conj []) - (rx/subs #(reset! references* %)))) + (rx/subs! #(reset! references* %)))) (mf/with-effect [accept-fn] (letfn [(on-keydown [event] diff --git a/frontend/src/app/main/ui/delete_shared.scss b/frontend/src/app/main/ui/delete_shared.scss index 17c2531a79..caa20bdcbb 100644 --- a/frontend/src/app/main/ui/delete_shared.scss +++ b/frontend/src/app/main/ui/delete_shared.scss @@ -26,11 +26,6 @@ .modal-content { @include titleTipography; margin-bottom: $s-24; - .modal-msg, - .modal-scd-msg, - .modal-subtitle { - @include titleTipography; - } .modal-hint { @extend .modal-hint-base; } @@ -57,3 +52,11 @@ } } } + +.modal-scd-msg, +.modal-subtitle, +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} diff --git a/frontend/src/app/main/ui/export.cljs b/frontend/src/app/main/ui/export.cljs index 710e5efc52..4362654995 100644 --- a/frontend/src/app/main/ui/export.cljs +++ b/frontend/src/app/main/ui/export.cljs @@ -55,8 +55,12 @@ :cmd cmd}))) on-toggle-enabled - (fn [index] - (swap! exports update-in [index :enabled] not)) + (mf/use-fn + (mf/deps exports) + (fn [event] + (let [index (-> (dom/get-current-target event) + (dom/get-data "value"))] + (swap! exports update-in [index :enabled] not)))) change-all (fn [_] @@ -65,9 +69,8 @@ (if new-css-system [:div {:class (stl/css :modal-overlay)} - [:div.modal-container.export-multiple-dialog - {:class (stl/css-case :modal-container true - :empty (empty? all-exports))} + [:div {:class (stl/css-case :modal-container true + :empty (empty? all-exports))} [:div {:class (stl/css :modal-header)} [:h2 {:class (stl/css :modal-title)} title] @@ -84,55 +87,58 @@ :on-click change-all} [:span {:class (stl/css :checkbox-wrapper)} (cond - all-checked? [:span {:class (stl/css-case :checkbox-icon2 true + all-checked? [:span {:class (stl/css-case :checkobox-tick true :global/checked true)} i/tick-refactor] - all-unchecked? [:span {:class (stl/css-case :checkbox-icon2 true + all-unchecked? [:span {:class (stl/css-case :checkobox-tick true :global/uncheked true)}] - :else [:span {:class (stl/css-case :checkbox-icon2 true + :else [:span {:class (stl/css-case :checkobox-tick true :global/intermediate true)} i/remove-refactor])]] - [:div {:class (stl/css :selection-title)} (tr "dashboard.export-multiple.selected" - (c (count enabled-exports)) - (c (count all-exports)))]] + [:div {:class (stl/css :selection-title)} + (tr "dashboard.export-multiple.selected" + (c (count enabled-exports)) + (c (count all-exports)))]] [:div {:class (stl/css :selection-wrapper)} [:div {:class (stl/css-case :selection-list true :selection-shadow (> (count all-exports) 8))} - (for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)] - (let [{:keys [x y width height]} (:selrect shape)] - [:div {:class (stl/css :selection-row)} - [:button {:class (stl/css :selection-btn) - :on-click #(on-toggle-enabled index)} - [:span {:class (stl/css :checkbox-wrapper)} - (if (:enabled export) - [:span {:class (stl/css-case :checkbox-icon2 true - :global/checked true)} i/tick-refactor] - [:span {:class (stl/css-case :checkbox-icon2 true - :global/uncheked true)}])] + (for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)] + (let [{:keys [x y width height]} (:selrect shape)] + [:div {:class (stl/css :selection-row) + :key (:id shape)} + [:button {:class (stl/css :selection-btn) + :data-value index + :on-click on-toggle-enabled} + [:span {:class (stl/css :checkbox-wrapper)} + (if (:enabled export) + [:span {:class (stl/css-case :checkobox-tick true + :global/checked true)} i/tick-refactor] + [:span {:class (stl/css-case :checkobox-tick true + :global/uncheked true)}])] - [:div {:class (stl/css :image-wrapper)} - (if (some? (:thumbnail shape)) - [:img {:src (:thumbnail shape)}] - [:svg {:view-box (dm/str x " " y " " width " " height) - :width 24 - :height 20 - :version "1.1" - :xmlns "http://www.w3.org/2000/svg" - :xmlnsXlink "http://www.w3.org/1999/xlink" + [:div {:class (stl/css :image-wrapper)} + (if (some? (:thumbnail shape)) + [:img {:src (:thumbnail shape)}] + [:svg {:view-box (dm/str x " " y " " width " " height) + :width 24 + :height 20 + :version "1.1" + :xmlns "http://www.w3.org/2000/svg" + :xmlnsXlink "http://www.w3.org/1999/xlink" ;; Fix Chromium bug about color of html texts ;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5 - :style {:-webkit-print-color-adjust :exact} - :fill "none"} + :style {:-webkit-print-color-adjust :exact} + :fill "none"} - [:& shape-wrapper {:shape shape}]])] + [:& shape-wrapper {:shape shape}]])] - [:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))] - (when (:scale export) - [:div {:class (stl/css :selection-scale)} - (dm/str (ust/format-precision (* width (:scale export)) 2) "x" - (ust/format-precision (* height (:scale export)) 2) "px ")]) + [:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))] + (when (:scale export) + [:div {:class (stl/css :selection-scale)} + (dm/str (ust/format-precision (* width (:scale export)) 2) "px" + (ust/format-precision (* height (:scale export)) 2) "px")]) - (when (:type export) - [:div {:class (stl/css :selection-extension)} - (-> export :type d/name str/upper)])]]))]]] + (when (:type export) + [:div {:class (stl/css :selection-extension)} + (-> export :type d/name str/upper)])]]))]]] [:& no-selection])] @@ -187,7 +193,8 @@ (for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)] (let [{:keys [x y width height]} (:selrect shape)] [:div.row - [:div.field.check {:on-click #(on-toggle-enabled index)} + [:div.field.check {:data-value index + :on-click on-toggle-enabled} (if (:enabled export) [:span.checked i/checkbox-checked] [:span.unchecked i/checkbox-unchecked])] @@ -210,7 +217,7 @@ [:div.field.name (cond-> (:name shape) suffix (str suffix))] (when (:scale export) - [:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "x" + [:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "px" (ust/format-precision (* height (:scale export)) 2) "px ")]) (when (:type export) diff --git a/frontend/src/app/main/ui/export.scss b/frontend/src/app/main/ui/export.scss index 01a15889a3..a958a0dc88 100644 --- a/frontend/src/app/main/ui/export.scss +++ b/frontend/src/app/main/ui/export.scss @@ -89,10 +89,7 @@ .no-selection { @include titleTipography; margin-bottom: $s-24; - .modal-msg, - .modal-scd-msg, - .modal-hint, - .modal-subtitle { + .modal-hint { @include titleTipography; color: var(--modal-text-foreground-color); } @@ -164,7 +161,7 @@ height: $s-24; width: $s-24; padding: 0; - .checkbox-icon2 { + .checkobox-tick { @extend .checkbox-icon; } } @@ -223,3 +220,11 @@ } } } + +.modal-scd-msg, +.modal-subtitle, +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} diff --git a/frontend/src/app/main/ui/hooks.cljs b/frontend/src/app/main/ui/hooks.cljs index d15a87185c..79bf1fa81c 100644 --- a/frontend/src/app/main/ui/hooks.cljs +++ b/frontend/src/app/main/ui/hooks.cljs @@ -19,7 +19,8 @@ [app.util.storage :refer [storage]] [app.util.timers :as ts] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] + [beicon.v2.operators :as rxo] [goog.functions :as f] [rumext.v2 :as mf])) @@ -35,8 +36,8 @@ (let [[state reset-state!] (mf/useState #(if (satisfies? IDeref ob) @ob nil))] (mf/useEffect (fn [] - (let [sub (rx/subscribe ob #(reset-state! %))] - #(rx/cancel! sub))) + (let [sub (rx/sub! ob #(reset-state! %))] + #(rx/dispose! sub))) #js [ob]) state)) @@ -106,7 +107,7 @@ cleanup (fn [] - (some-> (:subscr @state) rx/unsub!) + (some-> (:subscr @state) rx/dispose!) (swap! state (fn [state] (-> state (cancel-timer) @@ -217,7 +218,7 @@ (mf/use-effect deps (fn [] - (let [sub (->> stream (rx/subs on-subscribe))] + (let [sub (->> stream (rx/subs! on-subscribe))] #(rx/dispose! sub)))))) ;; https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state @@ -339,8 +340,8 @@ intersecting?))) - (rx/dedupe)) - subs (rx/subscribe stream update-state!)] + (rx/pipe (rxo/distinct-contiguous))) + subs (rx/sub! stream update-state!)] (.observe ^js @intersection-observer node) (fn [] (.unobserve ^js @intersection-observer node) @@ -367,19 +368,23 @@ limit (mth/max 1 limit) th-size (when width - (- (/ (- width 32 (* (dec limit) 24)) limit) 12))] + (mth/floor (- (/ (- width 32 (* (dec limit) 24)) limit) 12))) + + ;; Need an even value + th-size (if (odd? (int th-size)) (- th-size 1) th-size)] (mf/with-effect [th-size] (when th-size (let [node (mf/ref-val rowref)] - (.setProperty (.-style node) "--th-width" (str th-size "px"))))) + (.setProperty (.-style node) "--th-width" (str th-size "px")) + (.setProperty (.-style node) "--th-height" (str (mth/ceil (* th-size (/ 2 3))) "px"))))) (mf/with-effect [] (let [node (mf/ref-val rowref) mnt? (volatile! true) sub (->> (wapi/observe-resize node) - (rx/subs (fn [entries] + (rx/subs! (fn [entries] (let [row (first entries) row-rect (.-contentRect ^js row) row-width (.-width ^js row-rect)] diff --git a/frontend/src/app/main/ui/hooks/resize.cljs b/frontend/src/app/main/ui/hooks/resize.cljs index a5ad1f9bec..148cdf773d 100644 --- a/frontend/src/app/main/ui/hooks/resize.cljs +++ b/frontend/src/app/main/ui/hooks/resize.cljs @@ -24,62 +24,72 @@ (set! last-resize-type type)) (defn use-resize-hook - [key initial min-val max-val axis negate? resize-type] + ([key initial min-val max-val axis negate? resize-type] + (use-resize-hook key initial min-val max-val axis negate? resize-type nil)) - (let [current-file-id (mf/use-ctx ctx/current-file-id) - size-state (mf/use-state (or (get-in @storage [::saved-resize current-file-id key]) initial)) - parent-ref (mf/use-ref nil) + ([key initial min-val max-val axis negate? resize-type on-change-size] + (let [current-file-id (mf/use-ctx ctx/current-file-id) + size-state (mf/use-state (or (get-in @storage [::saved-resize current-file-id key]) initial)) + parent-ref (mf/use-ref nil) - dragging-ref (mf/use-ref false) - start-size-ref (mf/use-ref nil) - start-ref (mf/use-ref nil) + dragging-ref (mf/use-ref false) + start-size-ref (mf/use-ref nil) + start-ref (mf/use-ref nil) - on-pointer-down - (mf/use-callback - (mf/deps @size-state) - (fn [event] - (dom/capture-pointer event) - (mf/set-ref-val! start-size-ref @size-state) - (mf/set-ref-val! dragging-ref true) - (mf/set-ref-val! start-ref (dom/get-client-position event)) - (set! last-resize-type resize-type))) + on-pointer-down + (mf/use-callback + (mf/deps @size-state) + (fn [event] + (dom/capture-pointer event) + (mf/set-ref-val! start-size-ref @size-state) + (mf/set-ref-val! dragging-ref true) + (mf/set-ref-val! start-ref (dom/get-client-position event)) + (set! last-resize-type resize-type))) - on-lost-pointer-capture - (mf/use-callback - (fn [event] - (dom/release-pointer event) - (mf/set-ref-val! start-size-ref nil) - (mf/set-ref-val! dragging-ref false) - (mf/set-ref-val! start-ref nil) - (set! last-resize-type nil))) + on-lost-pointer-capture + (mf/use-callback + (fn [event] + (dom/release-pointer event) + (mf/set-ref-val! start-size-ref nil) + (mf/set-ref-val! dragging-ref false) + (mf/set-ref-val! start-ref nil) + (set! last-resize-type nil))) - on-pointer-move - (mf/use-callback - (mf/deps min-val max-val negate?) - (fn [event] - (when (mf/ref-val dragging-ref) - (let [start (mf/ref-val start-ref) - pos (dom/get-client-position event) - delta (-> (gpt/to-vec start pos) - (cond-> negate? gpt/negate) - (get axis)) - start-size (mf/ref-val start-size-ref) - new-size (-> (+ start-size delta) (max min-val) (min max-val))] - (reset! size-state new-size) - (swap! storage assoc-in [::saved-resize current-file-id key] new-size))))) + on-pointer-move + (mf/use-callback + (mf/deps min-val max-val negate?) + (fn [event] + (when (mf/ref-val dragging-ref) + (let [start (mf/ref-val start-ref) + pos (dom/get-client-position event) + delta (-> (gpt/to-vec start pos) + (cond-> negate? gpt/negate) + (get axis)) + start-size (mf/ref-val start-size-ref) + new-size (-> (+ start-size delta) (max min-val) (min max-val))] + (reset! size-state new-size) + (swap! storage assoc-in [::saved-resize current-file-id key] new-size) + (when on-change-size (on-change-size new-size)))))) - set-size - (mf/use-callback - (fn [new-size] - (let [new-size (mth/clamp new-size min-val max-val)] - (reset! size-state new-size) - (swap! storage assoc-in [::saved-resize current-file-id key] new-size))))] - {:on-pointer-down on-pointer-down - :on-lost-pointer-capture on-lost-pointer-capture - :on-pointer-move on-pointer-move - :parent-ref parent-ref - :set-size set-size - :size @size-state})) + set-size + (mf/use-callback + (mf/deps on-change-size) + (fn [new-size] + (let [new-size (mth/clamp new-size min-val max-val)] + (reset! size-state new-size) + (swap! storage assoc-in [::saved-resize current-file-id key] new-size) + (when on-change-size (on-change-size new-size)))))] + + (mf/use-effect + (fn [] + (when on-change-size (on-change-size @size-state)))) + + {:on-pointer-down on-pointer-down + :on-lost-pointer-capture on-lost-pointer-capture + :on-pointer-move on-pointer-move + :parent-ref parent-ref + :set-size set-size + :size @size-state}))) (defn use-resize-observer [callback] diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 610eec75e7..96ebebf051 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -339,6 +339,7 @@ (def easing-ease-in-out-refactor (icon-xref :easing-ease-in-out-refactor)) (def effects-refactor (icon-xref :effects-refactor)) (def elipse-refactor (icon-xref :elipse-refactor)) +(def expand-refactor (icon-xref :expand-refactor)) (def fill-content-refactor (icon-xref :fill-content-refactor)) (def filter-refactor (icon-xref :filter-refactor)) (def fixed-width-refactor (icon-xref :fixed-width-refactor)) @@ -414,6 +415,7 @@ (def picker-refactor (icon-xref :picker-refactor)) (def play-refactor (icon-xref :play-refactor)) (def rectangle-refactor (icon-xref :rectangle-refactor)) +(def reload-refactor (icon-xref :reload-refactor)) (def remove-refactor (icon-xref :remove-refactor)) (def rgba-refactor (icon-xref :rgba-refactor)) (def rgba-complementary-refactor (icon-xref :rgba-complementary-refactor)) diff --git a/frontend/src/app/main/ui/onboarding.cljs b/frontend/src/app/main/ui/onboarding.cljs index d29b8540cb..8b9801d8a1 100644 --- a/frontend/src/app/main/ui/onboarding.cljs +++ b/frontend/src/app/main/ui/onboarding.cljs @@ -20,7 +20,7 @@ [app.main.ui.onboarding.templates] [app.util.i18n :as i18n :refer [tr]] [app.util.timers :as tm] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) ;; --- ONBOARDING LIGHTBOX diff --git a/frontend/src/app/main/ui/onboarding/team_choice.cljs b/frontend/src/app/main/ui/onboarding/team_choice.cljs index c71c624109..bb2d5c977c 100644 --- a/frontend/src/app/main/ui/onboarding/team_choice.cljs +++ b/frontend/src/app/main/ui/onboarding/team_choice.cljs @@ -21,7 +21,7 @@ [app.util.router :as rt] [app.util.timers :as tm] [cljs.spec.alpha :as s] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (s/def ::name ::us/not-empty-string) diff --git a/frontend/src/app/main/ui/onboarding/templates.cljs b/frontend/src/app/main/ui/onboarding/templates.cljs index 2ce17a7d8d..1744f69c73 100644 --- a/frontend/src/app/main/ui/onboarding/templates.cljs +++ b/frontend/src/app/main/ui/onboarding/templates.cljs @@ -16,7 +16,7 @@ [app.util.http :as http] [app.util.i18n :as i18n :refer [tr]] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (mf/defc template-item @@ -39,7 +39,7 @@ (fn [] (reset! downloading? true) (->> (http/send! {:method :get :uri link :response-type :blob :mode :no-cors}) - (rx/subs (fn [{:keys [body] :as response}] + (rx/subs! (fn [{:keys [body] :as response}] (open-import-modal {:name name :uri (wapi/create-uri body)})) (fn [error] (js/console.log "error" error)) diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs index 20a103ccb8..1a796f32d8 100644 --- a/frontend/src/app/main/ui/routes.cljs +++ b/frontend/src/app/main/ui/routes.cljs @@ -14,9 +14,9 @@ [app.main.repo :as rp] [app.main.store :as st] [app.util.router :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (s/def ::page-id ::us/uuid) (s/def ::file-id ::us/uuid) @@ -112,7 +112,7 @@ ;; some race conditions that causes unexpected redirects on ;; invitations workflows (and probably other cases). (->> (rp/cmd! :get-profile) - (rx/subs (fn [{:keys [id] :as profile}] + (rx/subs! (fn [{:keys [id] :as profile}] (cond (= id uuid/zero) (st/emit! (rt/nav :auth-login)) diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index 6cd6ae69f3..08ab6ea6f7 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -20,7 +20,7 @@ [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.i18n :as i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/settings/delete_account.cljs b/frontend/src/app/main/ui/settings/delete_account.cljs index 5f13bcf85f..a9c26b7305 100644 --- a/frontend/src/app/main/ui/settings/delete_account.cljs +++ b/frontend/src/app/main/ui/settings/delete_account.cljs @@ -15,7 +15,7 @@ [app.main.ui.icons :as i] [app.main.ui.messages :as msgs] [app.util.i18n :as i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (defn on-error diff --git a/frontend/src/app/main/ui/settings/feedback.cljs b/frontend/src/app/main/ui/settings/feedback.cljs index d8e41518bd..46bbc1e1bf 100644 --- a/frontend/src/app/main/ui/settings/feedback.cljs +++ b/frontend/src/app/main/ui/settings/feedback.cljs @@ -17,7 +17,7 @@ [app.main.ui.context :as ctx] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.spec.alpha :as s] [rumext.v2 :as mf])) @@ -60,7 +60,7 @@ (reset! loading true) (let [data (:clean-data @form)] (->> (rp/cmd! :send-user-feedback data) - (rx/subs on-succes on-error)))))] + (rx/subs! on-succes on-error)))))] (if new-css-system [:& fm/form {:class (stl/css :feedback-form) diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index cb13feab08..5d3fc8c8b7 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -18,7 +18,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.router :as rt] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc sidebar-content diff --git a/frontend/src/app/main/ui/shapes/embed.cljs b/frontend/src/app/main/ui/shapes/embed.cljs index 8d0f04b399..4e9fe7d498 100644 --- a/frontend/src/app/main/ui/shapes/embed.cljs +++ b/frontend/src/app/main/ui/shapes/embed.cljs @@ -8,7 +8,7 @@ (:require [app.main.ui.hooks :as hooks] [app.util.http :as http] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (def context (mf/create-context false)) @@ -37,7 +37,7 @@ (rx/filter some?) (url-mapping) (rx/reduce conj {}) - (rx/subs (fn [data] + (rx/subs! (fn [data] (when-not (= data (mf/ref-val uri-data)) (mf/set-ref-val! uri-data data) (reset! state inc)))))] diff --git a/frontend/src/app/main/ui/shapes/text/fontfaces.cljs b/frontend/src/app/main/ui/shapes/text/fontfaces.cljs index 44a12e8c07..ceca03f536 100644 --- a/frontend/src/app/main/ui/shapes/text/fontfaces.cljs +++ b/frontend/src/app/main/ui/shapes/text/fontfaces.cljs @@ -10,7 +10,7 @@ [app.common.files.helpers :as cfh] [app.main.fonts :as fonts] [app.util.object :as obj] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -28,7 +28,7 @@ (->> (rx/from fonts) (rx/merge-map fonts/fetch-font-css) (rx/reduce conj []) - (rx/subs + (rx/subs! (fn [result] (let [css (str/join "\n" result)] (when-not (= (mf/ref-val fonts-css-ref) css) diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index 366453dd05..37577d56f5 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.viewer (:import goog.events.EventType) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -91,29 +92,57 @@ :vbox (str "0 0 " width " " height)}))) (mf/defc viewer-pagination - [{:keys [index num-frames left-bar right-bar] :as props}] - [:* - (when (pos? index) - [:div.viewer-go-prev {:class (when left-bar "left-bar")} - [:div.arrow {:on-click #(st/emit! dv/select-prev-frame)} i/go-prev]]) - (when (< (+ index 1) num-frames) - [:div.viewer-go-next {:class (when right-bar "right-bar")} - [:div.arrow {:on-click #(st/emit! dv/select-next-frame)} i/go-next]]) - [:div.viewer-bottom {:class (when left-bar "left-bar")} - [:div.reset {:on-click #(st/emit! dv/select-first-frame)} i/reset] - [:div.counter (str/join " / " [(+ index 1) num-frames])] - [:span]]]) + [{:keys [index num-frames left-bar right-bar comment-sidebar] :as props}] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + go-prev-frame (mf/use-fn #(st/emit! dv/select-prev-frame)) + go-next-frame (mf/use-fn #(st/emit! dv/select-next-frame)) + go-first-frame (mf/use-fn #(st/emit! dv/select-first-frame))] + (if new-css-system + [:* + (when (pos? index) + [:button {:class (stl/css-case :viewer-go-prev true + :left-bar left-bar) + :on-click go-prev-frame} + i/arrow-refactor]) + (when (< (+ index 1) num-frames) + [:button {:class (stl/css-case :viewer-go-next true + :comment-sidebar comment-sidebar + :right-bar right-bar) + :on-click go-next-frame} + i/arrow-refactor]) + [:div {:class (stl/css-case :viewer-bottom true + :left-bar left-bar)} + [:button {:on-click go-first-frame + :class (stl/css :reset-button)} + i/reload-refactor] + [:span {:class (stl/css :counter)} + (str/join " / " [(+ index 1) num-frames])] + [:span]]] + + + ;; OLD + [:* + (when (pos? index) + [:div.viewer-go-prev {:class (when left-bar "left-bar")} + [:div.arrow {:on-click go-prev-frame} i/go-prev]]) + (when (< (+ index 1) num-frames) + [:div.viewer-go-next {:class (when right-bar "right-bar")} + [:div.arrow {:on-click go-next-frame} i/go-next]]) + [:div.viewer-bottom {:class (when left-bar "left-bar")} + [:div.reset {:on-click go-first-frame} i/reset] + [:div.counter (str/join " / " [(+ index 1) num-frames])] + [:span]]]))) (mf/defc viewer-pagination-and-sidebar {::mf/wrap [mf/memo]} [{:keys [section index users frame page]}] (let [comments-local (mf/deref refs/comments-local) show-sidebar? (and (= section :comments) (:show-sidebar? comments-local))] - [:* + [:* [:& viewer-pagination {:index index :num-frames (count (:frames page)) - :right-bar show-sidebar?}] + :comment-sidebar show-sidebar?}] (when show-sidebar? [:& comments-sidebar @@ -172,72 +201,138 @@ :page page :interactions-mode interactions-mode}]]])) - (mf/defc viewer-wrapper {::mf/wrap-props false} [{:keys [wrapper-size orig-frame orig-viewport-ref orig-size page file users current-viewport-ref size frame interactions-mode overlays zoom section index]}] - [:* - [:& viewer-pagination-and-sidebar - {:section section - :index index - :page page - :users users - :frame frame - :interactions-mode interactions-mode}] + (let [new-css-system (mf/use-ctx ctx/new-css-system)] + (if new-css-system + [:* + [:& viewer-pagination-and-sidebar + {:section section + :index index + :page page + :users users + :frame frame + :interactions-mode interactions-mode}] - [:div.viewer-wrapper - {:style {:width (:width wrapper-size) - :height (:height wrapper-size)}} - [:div.viewer-clipper - (when orig-frame - [:div.viewport-container - {:ref orig-viewport-ref - :style {:width (:width orig-size) - :height (:height orig-size) - :position "relative"}} + [:div {:class (stl/css :viewer-wrapper) + :style {:width (:width wrapper-size) + :height (:height wrapper-size)}} + [:div {:class (stl/css :viewer-clipper)} - [:& interactions/viewport - {:frame orig-frame - :base-frame orig-frame - :frame-offset (gpt/point 0 0) - :size orig-size - :page page - :users users - :interactions-mode interactions-mode}]]) + (when orig-frame + [:div {:class (stl/css :viewport-container) + :ref orig-viewport-ref + :style {:width (:width orig-size) + :height (:height orig-size) + :position "relative"}} - [:div.viewport-container - {:ref current-viewport-ref - :style {:width (:width size) - :height (:height size) - :position "relative"}} + [:& interactions/viewport + {:frame orig-frame + :base-frame orig-frame + :frame-offset (gpt/point 0 0) + :size orig-size + :page page + :users users + :interactions-mode interactions-mode}]]) - [:& interactions/viewport - {:frame frame - :base-frame frame - :frame-offset (gpt/point 0 0) - :size size - :page page - :interactions-mode interactions-mode}] + [:div {:class (stl/css :viewport-container) + :ref current-viewport-ref + :style {:width (:width size) + :height (:height size) + :position "relative"}} - (for [overlay overlays] - [:& viewer-overlay - {:overlay overlay - :key (dm/str (:id overlay)) - :page page - :frame frame - :zoom zoom - :wrapper-size wrapper-size - :interactions-mode interactions-mode}])]] + [:& interactions/viewport + {:frame frame + :base-frame frame + :frame-offset (gpt/point 0 0) + :size size + :page page + :interactions-mode interactions-mode}] + + (for [overlay overlays] + [:& viewer-overlay + {:overlay overlay + :key (dm/str (:id overlay)) + :page page + :frame frame + :zoom zoom + :wrapper-size wrapper-size + :interactions-mode interactions-mode}])]] - (when (= section :comments) - [:& comments-layer {:file file - :users users - :frame frame - :page page - :zoom zoom}])]]) + (when (= section :comments) + [:& comments-layer {:file file + :users users + :frame frame + :page page + :zoom zoom}])]] + + + + ;; OLD + [:* + [:& viewer-pagination-and-sidebar + {:section section + :index index + :page page + :users users + :frame frame + :interactions-mode interactions-mode}] + + [:div.viewer-wrapper + {:style {:width (:width wrapper-size) + :height (:height wrapper-size)}} + [:div.viewer-clipper + (when orig-frame + [:div.viewport-container + {:ref orig-viewport-ref + :style {:width (:width orig-size) + :height (:height orig-size) + :position "relative"}} + + [:& interactions/viewport + {:frame orig-frame + :base-frame orig-frame + :frame-offset (gpt/point 0 0) + :size orig-size + :page page + :users users + :interactions-mode interactions-mode}]]) + + [:div.viewport-container + {:ref current-viewport-ref + :style {:width (:width size) + :height (:height size) + :position "relative"}} + + [:& interactions/viewport + {:frame frame + :base-frame frame + :frame-offset (gpt/point 0 0) + :size size + :page page + :interactions-mode interactions-mode}] + + (for [overlay overlays] + [:& viewer-overlay + {:overlay overlay + :key (dm/str (:id overlay)) + :page page + :frame frame + :zoom zoom + :wrapper-size wrapper-size + :interactions-mode interactions-mode}])]] + + + (when (= section :comments) + [:& comments-layer {:file file + :users users + :frame frame + :page page + :zoom zoom}])]]))) (mf/defc viewer [{:keys [params data]}] @@ -245,6 +340,8 @@ (let [{:keys [page-id share-id section index interactions-mode]} params {:keys [file users project permissions]} data + new-css-system (mf/use-ctx ctx/new-css-system) + allowed (or (= section :interactions) (and (= section :comments) @@ -311,7 +408,7 @@ (calculate-wrapper size orig-size zoom)) click-on-screen - (mf/use-callback + (mf/use-fn (fn [event] (let [origin (dom/get-target event) over-section? (dom/class? origin "viewer-section") @@ -360,9 +457,13 @@ (if shift? (dom/set-h-scroll-pos! section new-scroll-pos) (dom/set-scroll-pos! section new-scroll-pos))))))))) + on-thumbnails-close + (mf/use-fn + #(st/emit! dv/close-thumbnails-panel)) + on-exit-fullscreen - (mf/use-callback + (mf/use-fn (fn [] (when (not (dom/fullscreen?)) (st/emit! (dv/exit-fullscreen)))))] @@ -441,7 +542,7 @@ nil) ;; Navigate animation needs to be started after navigation ;; is complete, and we have the next page index. - (let [nav-animation (d/seek #(= (:kind %) :go-to-frame) (vals current-animations))] + (let [nav-animation (d/seek #(= (:kind %) :go-to-frame) (vals current-animations))] (when nav-animation (let [orig-viewport (mf/ref-val orig-viewport-ref) current-viewport (mf/ref-val current-viewport-ref)] @@ -498,76 +599,153 @@ fonts (into #{} (keep :font-id) text-nodes)] (run! fonts/ensure-loaded! fonts)))) - [:div#viewer-layout - {:class (dom/classnames - :force-visible (:show-thumbnails local) - :viewer-layout (not= section :inspect) - :inspect-layout (= section :inspect) - :fullscreen fullscreen?)} + (if new-css-system + [:div#viewer-layout + {:class (stl/css-case + :force-visible (:show-thumbnails local) + :viewer-layout (not= section :inspect) + :inspect-layout (= section :inspect) + :fullscreen fullscreen?)} - [:div.viewer-content - [:& header/header {:project project - :index index - :file file - :page page - :frame frame - :permissions permissions - :zoom zoom - :section section - :interactions-mode interactions-mode}] - [:div.thumbnail-close {:on-click #(st/emit! dv/close-thumbnails-panel) - :class (dom/classnames :invisible (not (:show-thumbnails local false)))}] - [:& thumbnails-panel {:frames frames - :show? (:show-thumbnails local false) - :page page - :index index - :thumbnail-data (:thumbnails file)}] - [:section.viewer-section {:id "viewer-section" - :ref viewer-section-ref - :class (if fullscreen? "fullscreen" "") - :on-click click-on-screen} - (cond - (empty? frames) - [:section.empty-state - [:span (tr "viewer.empty-state")]] + [:div {:class (stl/css :viewer-content)} + [:& header/header {:project project + :index index + :file file + :page page + :frame frame + :permissions permissions + :zoom zoom + :section section + :interactions-mode interactions-mode}] - (nil? frame) - [:section.empty-state - (when (some? index) - [:span (tr "viewer.frame-not-found")])] + [:button {:on-click on-thumbnails-close + :class (stl/css-case :thumbnails-close true + :invisible (not (:show-thumbnails local false)))}] - (some? frame) - (if (= :inspect section) - [:& inspect/viewport - {:frame frame - :page page - :file file - :section section - :local local - :size size - :index index - :viewer-pagination viewer-pagination - :interactions-mode interactions-mode - :share-id share-id}] + [:& thumbnails-panel {:frames frames + :show? (:show-thumbnails local false) + :page page + :index index + :thumbnail-data (:thumbnails file)}] + + [:section {:id "viewer-section" + :ref viewer-section-ref + :class (stl/css-case :viewer-section true + :fulscreen fullscreen?) + :on-click click-on-screen} + (cond + (empty? frames) + [:section {:class (stl/css :empty-state)} + [:span (tr "viewer.empty-state")]] + + (nil? frame) + [:section {:class (stl/css :empty-state)} + (when (some? index) + [:span (tr "viewer.frame-not-found")])] + + (some? frame) + (if (= :inspect section) + [:& inspect/viewport + {:frame frame + :page page + :file file + :section section + :local local + :size size + :index index + :viewer-pagination viewer-pagination + :interactions-mode interactions-mode + :share-id share-id}] + + [:& (mf/provider ctx/current-zoom) {:value zoom} + [:& viewer-wrapper + {:wrapper-size wrapper-size + :orig-frame orig-frame + :orig-viewport-ref orig-viewport-ref + :orig-size orig-size + :page page + :file file + :users users + :current-viewport-ref current-viewport-ref + :size size + :frame frame + :interactions-mode interactions-mode + :overlays overlays + :zoom zoom + :section section + :index index}]]))]]] + + ;; OLD + [:div#viewer-layout + {:class (dom/classnames + :force-visible (:show-thumbnails local) + :viewer-layout (not= section :inspect) + :inspect-layout (= section :inspect) + :fullscreen fullscreen?)} + + [:div.viewer-content + [:& header/header {:project project + :index index + :file file + :page page + :frame frame + :permissions permissions + :zoom zoom + :section section + :interactions-mode interactions-mode}] + [:div.thumbnail-close {:on-click on-thumbnails-close + :class (dom/classnames :invisible (not (:show-thumbnails local false)))}] + [:& thumbnails-panel {:frames frames + :show? (:show-thumbnails local false) + :page page + :index index + :thumbnail-data (:thumbnails file)}] + [:section.viewer-section {:id "viewer-section" + :ref viewer-section-ref + :class (if fullscreen? "fullscreen" "") + :on-click click-on-screen} + (cond + (empty? frames) + [:section.empty-state + [:span (tr "viewer.empty-state")]] + + (nil? frame) + [:section.empty-state + (when (some? index) + [:span (tr "viewer.frame-not-found")])] + + (some? frame) + (if (= :inspect section) + [:& inspect/viewport + {:frame frame + :page page + :file file + :section section + :local local + :size size + :index index + :viewer-pagination viewer-pagination + :interactions-mode interactions-mode + :share-id share-id}] - [:& (mf/provider ctx/current-zoom) {:value zoom} - [:& viewer-wrapper - {:wrapper-size wrapper-size - :orig-frame orig-frame - :orig-viewport-ref orig-viewport-ref - :orig-size orig-size - :page page - :file file - :users users - :current-viewport-ref current-viewport-ref - :size size - :frame frame - :interactions-mode interactions-mode - :overlays overlays - :zoom zoom - :section section - :index index}]]))]]])) + [:& (mf/provider ctx/current-zoom) {:value zoom} + [:& viewer-wrapper + {:wrapper-size wrapper-size + :orig-frame orig-frame + :orig-viewport-ref orig-viewport-ref + :orig-size orig-size + :page page + :file file + :users users + :current-viewport-ref current-viewport-ref + :size size + :frame frame + :interactions-mode interactions-mode + :overlays overlays + :zoom zoom + :section section + :index index}]]))]]]))) ;; --- Component: Viewer Page diff --git a/frontend/src/app/main/ui/viewer.scss b/frontend/src/app/main/ui/viewer.scss new file mode 100644 index 0000000000..7825fe3a46 --- /dev/null +++ b/frontend/src/app/main/ui/viewer.scss @@ -0,0 +1,142 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "common/refactor/common-refactor.scss" as *; + +.viewer-layout { + height: 100vh; + display: grid; + grid-template-rows: $s-48 auto; + grid-template-columns: 1fr; + user-select: none; +} + +.viewer-content { + grid-row: 2 / span 1; + display: grid; + grid-template-rows: $s-252 auto; + grid-template-columns: 1fr; + background-color: var(--viewer-background-color); +} + +.viewer-header { + grid-row: 1 / span 1; +} + +.inspect-layout { + display: grid; + grid-template-rows: $s-48 auto; + grid-template-columns: 1fr; + height: 100vh; + margin-top: 0; + user-select: none; +} + +.thumbnails-close { + @include buttonStyle; + grid-row: 1 / span 2; + grid-column: 1 / span 1; + z-index: $z-index-10; + background-color: var(--overlay-color); +} + +.thumbnails-close.invisible { + display: none; +} + +.viewer-section { + grid-row: 1 / span 2; + grid-column: 1 / span 1; + display: flex; + align-items: center; + flex-wrap: nowrap; + height: calc(100vh - $s-48); + flex-flow: wrap; + overflow: auto; +} +.inspect-layout .viewer-section { + flex-wrap: nowrap; + margin-top: 0; + height: 100%; +} + +.viewer-go-prev, +.viewer-go-next { + @extend .button-secondary; + @include flexCenter; + position: absolute; + right: $s-8; + height: $s-64; + width: $s-32; + top: calc(50vh - $s-32); + z-index: $z-index-2; + background-color: var(--viewer-controls-background-color); + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + +.viewer-go-next.comment-sidebar { + right: $s-264; +} + +.viewer-go-prev { + left: $s-8; + right: unset; + svg { + transform: rotate(180deg); + } +} + +.viewer-bottom { + position: fixed; + bottom: 0; + display: flex; + align-items: flex-start; + justify-content: space-between; + width: 100%; + height: $s-40; + padding-right: 0 $s-8 $s-40 $s-8; + transition: bottom 400ms ease 300ms; + z-index: $z-index-2; +} + +.reset-button { + @extend .button-secondary; + @include flexCenter; + height: $s-32; + width: $s-28; + margin-left: $s-8; + background-color: var(--viewer-controls-background-color); + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + +.counter { + @include flexCenter; + @include titleTipography; + border-radius: $br-8; + width: $s-64; + height: $s-32; + background-color: var(--viewer-controls-background-color); +} + +.viewer-wrapper { + position: relative; + margin: 0 auto; +} + +.viewer-clipper { + display: grid; + grid-template-rows: 1fr; + grid-template-columns: 1fr; + justify-items: center; + align-items: center; + overflow: hidden; +} diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index 242da7cba1..b9eed98bfd 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -5,7 +5,9 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.comments + (:require-macros [app.main.style :as stl]) (:require + [app.common.data :as d] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.rect :as grc] @@ -16,6 +18,7 @@ [app.main.store :as st] [app.main.ui.comments :as cmt] [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.comments :as wc] [app.util.dom :as dom] @@ -28,55 +31,126 @@ ::mf/wrap-props false} [] (let [{cmode :mode cshow :show show-sidebar? :show-sidebar?} (mf/deref refs/comments-local) - + new-css-system (mf/use-ctx ctx/new-css-system) show-dropdown? (mf/use-state false) toggle-dropdown (mf/use-fn #(swap! show-dropdown? not)) hide-dropdown (mf/use-fn #(reset! show-dropdown? false)) update-mode (mf/use-callback - (fn [mode] - (st/emit! (dcm/update-filters {:mode mode})))) + (fn [event] + (let [mode (-> (dom/get-current-target event) + (dom/get-data "value") + (keyword))] + (st/emit! (dcm/update-filters {:mode mode}))))) update-show (mf/use-callback - (fn [mode] - (st/emit! (dcm/update-filters {:show mode})))) + (fn [event] + (let [mode (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string))] + (st/emit! (dcm/update-filters {:show mode}))))) update-options (mf/use-callback - (fn [mode] - (st/emit! (dcm/update-options {:show-sidebar? mode}))))] + (fn [event] + (let [mode (-> (dom/get-target event) + (dom/get-data "value") + (boolean))] + (st/emit! (dcm/update-options {:show-sidebar? mode})))))] - [:div.view-options {:on-click toggle-dropdown} - [:span.label (tr "labels.comments")] - [:span.icon i/arrow-down] - [:& dropdown {:show @show-dropdown? - :on-close hide-dropdown} + (if new-css-system + [:div {:class (stl/css :view-options) + :on-click toggle-dropdown} + [:span {:class (stl/css :dropdown-title)} + (tr "labels.comments")] + [:span {:class (stl/css :icon-dropdown)} + i/arrow-refactor] + [:& dropdown {:show @show-dropdown? + :on-close hide-dropdown} + [:ul {:class (stl/css :dropdown)} + [:li {:class (stl/css-case :dropdown-element true + :selected (or (= :all cmode) (nil? cmode))) + :data-value :all + :on-click update-mode} - [:ul.dropdown.with-check - [:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode))) - :on-click #(update-mode :all)} - [:span.icon i/tick] - [:span.label (tr "labels.show-all-comments")]] + [:span {:class (stl/css :label)} (tr "labels.show-all-comments")] + (when (or (= :all cmode) (nil? cmode)) + [:span {:class (stl/css :icon)} i/tick-refactor])] - [:li {:class (dom/classnames :selected (= :yours cmode)) - :on-click #(update-mode :yours)} - [:span.icon i/tick] - [:span.label (tr "labels.show-your-comments")]] + [:li {:class (stl/css-case :dropdown-element true + :selected (= :yours cmode)) + :data-value :yours + :on-click update-mode} - [:hr] + [:span {:class (stl/css :label)} + (tr "labels.show-your-comments")] - [:li {:class (dom/classnames :selected (= :pending cshow)) - :on-click #(update-show (if (= :pending cshow) :all :pending))} - [:span.icon i/tick] - [:span.label (tr "labels.hide-resolved-comments")]] + (when (= :yours cmode) + [:span {:class (stl/css :icon)} + i/tick-refactor])] - [:hr] - [:li {:class (dom/classnames :selected show-sidebar?) - :on-click #(update-options (not show-sidebar?))} - [:span.icon i/tick] - [:span.label (tr "labels.show-comments-list")]]]]])) + [:li {:class (stl/css :separator)}] + + [:li {:class (stl/css-case :dropdown-element true + :selected (= :pending cshow)) + :data-value (if (= :pending cshow) :all :pending) + :on-click update-show} + + [:span {:class (stl/css :label)} + (tr "labels.hide-resolved-comments")] + (when (= :pending cshow) + [:span {:class (stl/css :icon)} + i/tick-refactor])] + + [:li {:class (stl/css :separator)}] + + [:li {:class (stl/css-case :dropdown-element true + :selected show-sidebar?) + :data-value (not show-sidebar?) + :on-click update-options} + + [:span {:class (stl/css :label)} (tr "labels.show-comments-list")] + (when show-sidebar? + [:span {:class (stl/css :icon)} i/tick-refactor])]]]] + + + + ; OLD + [:div.view-options {:on-click toggle-dropdown} + [:span.label (tr "labels.comments")] + [:span.icon i/arrow-down] + [:& dropdown {:show @show-dropdown? + :on-close hide-dropdown} + + [:ul.dropdown.with-check + [:li {:class (dom/classnames :selected (or (= :all cmode) (nil? cmode))) + :data-value :all + :on-click update-mode} + [:span.icon i/tick] + [:span.label (tr "labels.show-all-comments")]] + + [:li {:class (dom/classnames :selected (= :yours cmode)) + :data-value :yours + :on-click update-mode} + [:span.icon i/tick] + [:span.label (tr "labels.show-your-comments")]] + + [:hr] + + [:li {:class (dom/classnames :selected (= :pending cshow)) + :data-value (if (= :pending cshow) :all :pending) + :on-click update-show} + [:span.icon i/tick] + [:span.label (tr "labels.hide-resolved-comments")]] + + [:hr] + [:li {:class (dom/classnames :selected show-sidebar?) + :data-value (not show-sidebar?) + :on-click update-options} + [:span.icon i/tick] + [:span.label (tr "labels.show-comments-list")]]]]]))) (defn- update-thread-position [positions {:keys [id] :as thread}] @@ -88,7 +162,8 @@ (mf/defc comments-layer [{:keys [zoom file users frame page] :as props}] - (let [profile (mf/deref refs/profile) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + profile (mf/deref refs/profile) local (mf/deref refs/comments-local) open-thread-id (:open local) @@ -159,43 +234,81 @@ (st/emit! (dcm/create-thread-on-viewer params) (dcm/close-thread)))))] - [:div.comments-section {:on-click on-click} - [:div.viewer-comments-container - [:div.threads - (for [item threads] - [:& cmt/thread-bubble - {:thread item - :position-modifier modifier1 - :zoom zoom - :on-click on-bubble-click - :open? (= (:id item) (:open local)) - :key (:seqn item) - :origin :viewer}]) + (if new-css-system + [:div {:class (stl/css :comments-section) + :on-click on-click} + [:div {:class (stl/css :viewer-comments-container)} + [:div {:class (stl/css :threads)} + (for [item threads] + [:& cmt/thread-bubble + {:thread item + :position-modifier modifier1 + :zoom zoom + :on-click on-bubble-click + :open? (= (:id item) (:open local)) + :key (:seqn item) + :origin :viewer}]) - (when-let [thread (get threads-map open-thread-id)] - [:& cmt/thread-comments - {:thread thread - :position-modifier modifier1 - :users users - :zoom zoom}]) + (when-let [thread (get threads-map open-thread-id)] + [:& cmt/thread-comments + {:thread thread + :position-modifier modifier1 + :users users + :zoom zoom}]) - (when-let [draft (:draft local)] - [:& cmt/draft-thread - {:draft draft - :position-modifier modifier1 - :on-cancel on-draft-cancel - :on-submit on-draft-submit - :zoom zoom}])]]])) + (when-let [draft (:draft local)] + [:& cmt/draft-thread + {:draft draft + :position-modifier modifier1 + :on-cancel on-draft-cancel + :on-submit on-draft-submit + :zoom zoom}])]]] + + + [:div.comments-section {:on-click on-click} + [:div.viewer-comments-container + [:div.threads + (for [item threads] + [:& cmt/thread-bubble + {:thread item + :position-modifier modifier1 + :zoom zoom + :on-click on-bubble-click + :open? (= (:id item) (:open local)) + :key (:seqn item) + :origin :viewer}]) + + (when-let [thread (get threads-map open-thread-id)] + [:& cmt/thread-comments + {:thread thread + :position-modifier modifier1 + :users users + :zoom zoom}]) + + (when-let [draft (:draft local)] + [:& cmt/draft-thread + {:draft draft + :position-modifier modifier1 + :on-cancel on-draft-cancel + :on-submit on-draft-submit + :zoom zoom}])]]]))) (mf/defc comments-sidebar [{:keys [users frame page]}] - (let [profile (mf/deref refs/profile) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + profile (mf/deref refs/profile) local (mf/deref refs/comments-local) threads-map (mf/deref refs/comment-threads) threads (->> (vals threads-map) (dcm/apply-filters local profile) (filter (fn [{:keys [position]}] (gsh/has-point? frame position))))] - [:aside.settings-bar.settings-bar-right.comments-right-sidebar - [:div.settings-bar-inside - [:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]])) + (if new-css-system + [:aside {:class (stl/css :comments-sidebar)} + [:div {:class (stl/css :settings-bar-inside)} + [:& wc/comments-sidebar {:from-viewer true :users users :threads threads :page-id (:id page)}]]] + + + [:aside.settings-bar.settings-bar-right.comments-right-sidebar + [:div.settings-bar-inside + [:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]]))) diff --git a/frontend/src/app/main/ui/viewer/comments.scss b/frontend/src/app/main/ui/viewer/comments.scss new file mode 100644 index 0000000000..7dbbfcc831 --- /dev/null +++ b/frontend/src/app/main/ui/viewer/comments.scss @@ -0,0 +1,119 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "common/refactor/common-refactor.scss" as *; + +// COMMENT DROPDOWN ON HEADER +.view-options { + @include titleTipography; + display: flex; + align-items: center; + position: relative; + gap: $s-4; + height: $s-32; + padding: $s-8; + border-radius: $br-8; + background-color: var(--input-background-color); + cursor: pointer; +} + +.dropdown { + @extend .menu-dropdown; + right: $s-2; + top: calc($s-2 + $s-48); + width: $s-272; + padding: $s-6; +} + +.dropdown-title { + @include titleTipography; + flex-grow: 1; + color: var(--input-foreground-color-active); +} + +.label { + flex-grow: 1; + color: var(--input-foreground-color); +} + +.icon, +.icon-dropdown { + @include flexCenter; + height: 100%; + width: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } +} + +.icon-dropdown svg { + transform: rotate(90deg); +} + +.dropdown-element { + @extend .dropdown-element-base; + .icon { + @include flexCenter; + height: 100%; + width: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + } + &:hover .label { + color: var(--input-foreground-color-active); + } +} + +.dropdown-element.selected { + .label { + color: var(--input-foreground-color-active); + } + .icon svg { + stroke: var(--input-foreground-color); + } +} + +.separator { + height: $s-8; +} + +// FLOATING COMMENT +.viewer-comments-container { + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: $z-index-1; +} + +.threads { + position: absolute; + top: 0px; + left: 0px; +} + +//COMMENT SIDEBAR +.comments-sidebar { + position: absolute; + right: 0; + top: $s-44; + width: $s-256; + height: calc(100vh - $s-48); + z-index: $z-index-10; + background-color: var(--panel-background-color); +} + +.settings-bar-inside { + overflow-y: auto; +} + +.comments-section { + background-color: var(--panel-background-color); +} diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs index 156e21d950..83bf05914a 100644 --- a/frontend/src/app/main/ui/viewer/header.cljs +++ b/frontend/src/app/main/ui/viewer/header.cljs @@ -5,13 +5,16 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.header + (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] [app.main.data.modal :as modal] + [app.main.data.shortcuts :as scd] [app.main.data.viewer :as dv] [app.main.data.viewer.shortcuts :as sc] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.context :as ctx] [app.main.ui.export :refer [export-progress-widget]] [app.main.ui.formats :as fmt] [app.main.ui.icons :as i] @@ -41,40 +44,120 @@ on-zoom-fit on-zoom-fill] :as props}] - (let [show-dropdown? (mf/use-state false)] - [:div.zoom-widget {:on-click - (fn [event] - (dom/stop-propagation event) - (reset! show-dropdown? true))} - [:span.label (fmt/format-percent zoom)] - [:span.icon i/arrow-down] - [:& dropdown {:show @show-dropdown? - :on-close #(reset! show-dropdown? false)} - [:ul.dropdown - [:li.basic-zoom-bar - [:span.zoom-btns - [:button {:on-click (fn [event] - (dom/stop-propagation event) - (dom/prevent-default event) - (on-decrease))} "-"] - [:p.zoom-size (fmt/format-percent zoom)] - [:button {:on-click (fn [event] - (dom/stop-propagation event) - (dom/prevent-default event) - (on-increase))} "+"]] - [:button.reset-btn {:on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]] - [:li.separator] - [:li {:on-click on-zoom-fit} - (tr "workspace.header.zoom-fit") [:span (sc/get-tooltip :toggle-zoom-style)]] - [:li {:on-click on-zoom-fill} - (tr "workspace.header.zoom-fill") [:span (sc/get-tooltip :toggle-zoom-style)]] - [:li {:on-click on-fullscreen} - (tr "workspace.header.zoom-full-screen") [:span (sc/get-tooltip :toggle-fullscreen)]]]]])) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + open* (mf/use-state false) + open? (deref open*) + open-dropdown + (mf/use-fn + (fn [event] + (dom/stop-propagation event) + (reset! open* true))) + + close-dropdown + (mf/use-fn + (fn [event] + (dom/stop-propagation event) + (reset! open* false))) + + on-increase + (mf/use-fn + (mf/deps on-increase) + (fn [event] + (dom/stop-propagation event) + (on-increase))) + + on-decrease + (mf/use-fn + (mf/deps on-decrease) + (fn [event] + (dom/stop-propagation event) + (on-decrease))) + + show-dropdown? (mf/use-state false)] + + (if new-css-system + [:div {:class (stl/css-case :zoom-widget true + :selected open?) + :on-click open-dropdown + :title (tr "workspace.header.zoom")} + [:span {:class (stl/css :label)} (fmt/format-percent zoom)] + [:& dropdown {:show open? + :on-close close-dropdown} + [:ul {:class (stl/css :dropdown)} + [:li {:class (stl/css :basic-zoom-bar)} + [:span {:class (stl/css :zoom-btns)} + [:button {:class (stl/css :zoom-btn) + :on-click on-decrease} + [:span {:class (stl/css :zoom-icon)} + i/remove-refactor]] + [:p {:class (stl/css :zoom-text)} + (fmt/format-percent zoom)] + [:button {:class (stl/css :zoom-btn) + :on-click on-increase} + [:span {:class (stl/css :zoom-icon)} + i/add-refactor]]] + [:button {:class (stl/css :reset-btn) + :on-click on-zoom-reset} + (tr "workspace.header.reset-zoom")]] + + [:li {:class (stl/css :zoom-option) + :on-click on-zoom-fit} + (tr "workspace.header.zoom-fit") + [:span {:class (stl/css :shortcuts)} + (for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))] + [:span {:class (stl/css :shortcut-key) + :key (str "zoom-fit-" sc)} sc])]] + [:li {:class (stl/css :zoom-option) + :on-click on-zoom-fill} + (tr "workspace.header.zoom-fill") + [:span {:class (stl/css :shortcuts)} + (for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))] + [:span {:class (stl/css :shortcut-key) + :key (str "zoom-fill-" sc)} sc])]] + [:li {:class (stl/css :zoom-option) + :on-click on-fullscreen} + (tr "workspace.header.zoom-full-screen") + [:span {:class (stl/css :shortcuts)} + (for [sc (scd/split-sc (sc/get-tooltip :toggle-fullscreen))] + [:span {:class (stl/css :shortcut-key) + :key (str "zoom-fullscreen-" sc)} sc])]]]]] + + + ;; OLD + [:div.zoom-widget {:on-click + (fn [event] + (dom/stop-propagation event) + (reset! show-dropdown? true))} + [:span.label (fmt/format-percent zoom)] + [:span.icon i/arrow-down] + [:& dropdown {:show @show-dropdown? + :on-close #(reset! show-dropdown? false)} + [:ul.dropdown + [:li.basic-zoom-bar + [:span.zoom-btns + [:button {:on-click (fn [event] + (dom/stop-propagation event) + (dom/prevent-default event) + (on-decrease))} "-"] + [:p.zoom-size (fmt/format-percent zoom)] + [:button {:on-click (fn [event] + (dom/stop-propagation event) + (dom/prevent-default event) + (on-increase))} "+"]] + [:button.reset-btn {:on-click on-zoom-reset} (tr "workspace.header.reset-zoom")]] + [:li.separator] + [:li {:on-click on-zoom-fit} + (tr "workspace.header.zoom-fit") [:span (sc/get-tooltip :toggle-zoom-style)]] + [:li {:on-click on-zoom-fill} + (tr "workspace.header.zoom-fill") [:span (sc/get-tooltip :toggle-zoom-style)]] + [:li {:on-click on-fullscreen} + (tr "workspace.header.zoom-full-screen") [:span (sc/get-tooltip :toggle-fullscreen)]]]]]))) (mf/defc header-options [{:keys [section zoom page file index permissions interactions-mode]}] - (let [fullscreen? (mf/deref fullscreen-ref) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + fullscreen? (mf/deref fullscreen-ref) toggle-fullscreen (mf/use-callback @@ -91,49 +174,114 @@ (mf/deps page) (fn [] (modal/show! :share-link {:page page :file file}) - (modal/allow-click-outside!)))] + (modal/allow-click-outside!))) - [:div.options-zone - (case section - :interactions [:* - (when index - [:& flows-menu {:page page :index index}]) - [:& interactions-menu {:interactions-mode interactions-mode}]] - :comments [:& comments-menu] + handle-increase + (mf/use-fn + #(st/emit! dv/increase-zoom)) - [:div.view-options]) + handle-decrease + (mf/use-fn + #(st/emit! dv/decrease-zoom)) - [:& export-progress-widget] - [:& zoom-widget - {:zoom zoom - :on-increase #(st/emit! dv/increase-zoom) - :on-decrease #(st/emit! dv/decrease-zoom) - :on-zoom-reset #(st/emit! dv/reset-zoom) - :on-zoom-fill #(st/emit! dv/zoom-to-fill) - :on-zoom-fit #(st/emit! dv/zoom-to-fit) - :on-fullscreen toggle-fullscreen}] + handle-zoom-reset + (mf/use-fn + #(st/emit! dv/reset-zoom)) - [:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left - {:alt (tr "viewer.header.fullscreen") - :on-click toggle-fullscreen} - (if fullscreen? - i/full-screen-off - i/full-screen)] + handle-zoom-fill + (mf/use-fn + #(st/emit! dv/zoom-to-fill)) - (when (:is-admin permissions) - [:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]]) + handle-zoom-fit + (mf/use-fn + #(st/emit! dv/zoom-to-fit))] - (when (:can-edit permissions) - [:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")]) + (if new-css-system + [:div {:class (stl/css :options-zone)} + (case section + :interactions [:* + (when index + [:& flows-menu {:page page :index index}]) + [:& interactions-menu {:interactions-mode interactions-mode}]] + :comments [:& comments-menu] + [:div {:class (stl/css :view-options)}]) - (when-not (:is-logged permissions) - [:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])])) + [:& export-progress-widget] + + [:& zoom-widget + {:zoom zoom + :on-increase handle-increase + :on-decrease handle-decrease + :on-zoom-reset handle-zoom-reset + :on-zoom-fill handle-zoom-fill + :on-zoom-fit handle-zoom-fit + :on-fullscreen toggle-fullscreen}] + + (when (:can-edit permissions) + [:span {:on-click go-to-workspace + :class (stl/css :edit-btn)} + i/curve-refactor]) + + [:span {:title (tr "viewer.header.fullscreen") + :class (stl/css-case :fullscreen-btn true + :selected fullscreen?) + :on-click toggle-fullscreen} + i/expand-refactor] + + (when (:is-admin permissions) + [:button {:on-click open-share-dialog + :class (stl/css :share-btn)} + (tr "labels.share")]) + + (when-not (:is-logged permissions) + [:span {:on-click open-login-dialog + :class (stl/css :go-log-btn)} (tr "labels.log-or-sign")])] + + + ;; OLD + [:div.options-zone + (case section + :interactions [:* + (when index + [:& flows-menu {:page page :index index}]) + [:& interactions-menu {:interactions-mode interactions-mode}]] + :comments [:& comments-menu] + + [:div.view-options]) + + [:& export-progress-widget] + [:& zoom-widget + {:zoom zoom + :on-increase handle-increase + :on-decrease handle-decrease + :on-zoom-reset handle-zoom-reset + :on-zoom-fill handle-zoom-fill + :on-zoom-fit handle-zoom-fit + :on-fullscreen toggle-fullscreen}] + + [:span.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left + {:alt (tr "viewer.header.fullscreen") + :on-click toggle-fullscreen} + (if fullscreen? + i/full-screen-off + i/full-screen)] + + (when (:is-admin permissions) + [:span.btn-primary.tooltip.tooltip-bottom-left {:on-click open-share-dialog :alt (tr "labels.share-prototype")} i/export [:span (tr "labels.share-prototype")]]) + + (when (:can-edit permissions) + [:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")]) + + (when-not (:is-logged permissions) + [:span.btn-text-dark {:on-click open-login-dialog} (tr "labels.log-or-sign")])]))) (mf/defc header-sitemap [{:keys [project file page frame] :as props}] - (let [project-name (:name project) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + project-name (:name project) file-name (:name file) page-name (:name page) + page-id (:id page) frame-name (:name frame) show-dropdown? (mf/use-state false) @@ -158,88 +306,181 @@ (st/emit! (dv/go-to-page page-id)) (reset! show-dropdown? false)))] - [:div.sitemap-zone {:alt (tr "viewer.header.sitemap")} - [:div.breadcrumb - {:on-click open-dropdown} - [:span.project-name project-name] - [:span "/"] - [:span.file-name file-name] - [:span "/"] - - [:span.page-name page-name] + (if new-css-system + [:div {:class (stl/css :sitemap-zone) + :title (tr "viewer.header.sitemap")} + [:span {:class (stl/css :project-name)} project-name] + [:div {:class (stl/css :sitemap-text)} + [:div {:class (stl/css :breadcrumb) + :on-click open-dropdown} + [:span {:class (stl/css :breadcrumb-text)} + (dm/str file-name " / " page-name)] + [:span {:class (stl/css :icon)} i/arrow-refactor] + [:span "/"] + [:& dropdown {:show @show-dropdown? + :on-close close-dropdown} + [:ul {:class (stl/css :dropdown-sitemap)} + (for [id (get-in file [:data :pages])] + [:li {:class (stl/css-case :dropdown-element true + :selected (= page-id id)) + :id (str id) + :key (str id) + :on-click (partial navigate-to id)} + [:span {:class (stl/css :label)} + (get-in file [:data :pages-index id :name])] + (when (= page-id id) + [:span {:class (stl/css :icon-check)} i/tick-refactor])])]]] + [:div {:class (stl/css :current-frame) + :on-click toggle-thumbnails} + [:span {:class (stl/css :frame-name)} frame-name] + [:span {:class (stl/css :icon)} i/arrow-refactor]]]] - [:& dropdown {:show @show-dropdown? - :on-close close-dropdown} - [:ul.dropdown - (for [id (get-in file [:data :pages])] - [:li {:id (str id) - :key (str id) - :on-click (partial navigate-to id)} - (get-in file [:data :pages-index id :name])])]]] + ;; OLD + [:div.sitemap-zone {:alt (tr "viewer.header.sitemap")} + [:div.breadcrumb + {:on-click open-dropdown} + [:span.project-name project-name] + [:span "/"] + [:span.file-name file-name] + [:span "/"] - [:span.icon {:on-click open-dropdown} i/arrow-down] - [:div.current-frame - {:on-click toggle-thumbnails} - [:span.label "/"] - [:span.label frame-name]] - [:span.icon {:on-click toggle-thumbnails} i/arrow-down]])) + [:span.page-name page-name] + [:& dropdown {:show @show-dropdown? + :on-close close-dropdown} + [:ul.dropdown + (for [id (get-in file [:data :pages])] + [:li {:id (str id) + :key (str id) + :on-click (partial navigate-to id)} + (get-in file [:data :pages-index id :name])])]]] + [:span.icon {:on-click open-dropdown} i/arrow-down] + [:div.current-frame + {:on-click toggle-thumbnails} + [:span.label "/"] + [:span.label frame-name]] + [:span.icon {:on-click toggle-thumbnails} i/arrow-down]]))) (mf/defc header [{:keys [project file page frame zoom section permissions index interactions-mode]}] - (let [go-to-dashboard - #(st/emit! (dv/go-to-dashboard)) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + go-to-dashboard + (mf/use-fn + #(st/emit! (dv/go-to-dashboard))) go-to-inspect - (fn[] - (if (:is-logged permissions) - (st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect)) - (open-login-dialog))) + (mf/use-fn + (mf/deps permissions) + (fn [] + (if (:is-logged permissions) + (st/emit! dv/close-thumbnails-panel (dv/go-to-section :inspect)) + (open-login-dialog)))) navigate - (fn [section] - (if (or (= section :interactions) (:is-logged permissions)) - (st/emit! (dv/go-to-section section)) - (open-login-dialog)))] + (mf/use-fn + (mf/deps permissions) + (fn [event] + (let [section (-> (dom/get-current-target event) + (dom/get-data "value") + (keyword))] - [:header.viewer-header - [:div.nav-zone - ;; If the user doesn't have permission we disable the link - [:div.main-icon {:style {:cursor (when-not (:can-edit permissions) "auto")}} - [:a {:on-click go-to-dashboard - :style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]] + (if (or (= section :interactions) (:is-logged permissions)) + (st/emit! (dv/go-to-section section)) + (open-login-dialog)))))] - [:& header-sitemap {:project project :file file :page page :frame frame :index index}]] + (if new-css-system + [:header {:class (stl/css :viewer-header)} + [:div {:class (stl/css :nav-zone)} + ;; If the user doesn't have permission we disable the link + [:a {:class (stl/css :home-link) + :on-click go-to-dashboard + :style {:cursor (when-not (:can-edit permissions) "auto") + :pointer-events (when-not (:can-edit permissions) "none")}} + [:span {:class (stl/css :logo-icon)} + i/logo-icon]] - [:div.mode-zone - [:button.mode-zone-button.tooltip.tooltip-bottom - {:on-click #(navigate :interactions) - :class (dom/classnames :active (= section :interactions)) - :alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))} - i/play] + [:& header-sitemap {:project project + :file file + :page page + :frame frame + :index index}]] - (when (or (:can-edit permissions) - (= (:who-comment permissions) "all")) + [:div {:class (stl/css :mode-zone)} + [:button {:on-click navigate + :data-value :interactions + :class (stl/css-case :mode-zone-btn true + :selected (= section :interactions)) + :title (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))} + i/play-refactor] + + (when (or (:can-edit permissions) + (= (:who-comment permissions) "all")) + [:button {:on-click navigate + :data-value :comments + :class (stl/css-case :mode-zone-btn true + :selected (= section :comments)) + :title (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))} + i/comments-refactor]) + + (when (or (= (:type permissions) :membership) + (and (= (:type permissions) :share-link) + (= (:who-inspect permissions) "all"))) + [:button {:on-click go-to-inspect + :class (stl/css-case :mode-zone-btn true + :selected (= section :inspect)) + :title (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))} + i/code-refactor])] + + [:& header-options {:section section + :permissions permissions + :page page + :file file + :index index + :zoom zoom + :interactions-mode interactions-mode}]] + + + ;; OLD + [:header.viewer-header + [:div.nav-zone + ;; If the user doesn't have permission we disable the link + [:div.main-icon {:style {:cursor (when-not (:can-edit permissions) "auto")}} + [:a {:on-click go-to-dashboard + :style {:pointer-events (when-not (:can-edit permissions) "none")}} i/logo-icon]] + + [:& header-sitemap {:project project :file file :page page :frame frame :index index}]] + + [:div.mode-zone [:button.mode-zone-button.tooltip.tooltip-bottom - {:on-click #(navigate :comments) - :class (dom/classnames :active (= section :comments)) - :alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))} - i/chat]) + {:on-click navigate + :data-value :interactions + :class (dom/classnames :active (= section :interactions)) + :alt (tr "viewer.header.interactions-section" (sc/get-tooltip :open-interactions))} + i/play] - (when (or (= (:type permissions) :membership) - (and (= (:type permissions) :share-link) - (= (:who-inspect permissions) "all"))) - [:button.mode-zone-button.tooltip.tooltip-bottom - {:on-click go-to-inspect - :class (dom/classnames :active (= section :inspect)) - :alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))} - i/code])] + (when (or (:can-edit permissions) + (= (:who-comment permissions) "all")) + [:button.mode-zone-button.tooltip.tooltip-bottom + {:on-click navigate + :data-value :comments + :class (dom/classnames :active (= section :comments)) + :alt (tr "viewer.header.comments-section" (sc/get-tooltip :open-comments))} + i/chat]) - [:& header-options {:section section - :permissions permissions - :page page - :file file - :index index - :zoom zoom - :interactions-mode interactions-mode}]])) + (when (or (= (:type permissions) :membership) + (and (= (:type permissions) :share-link) + (= (:who-inspect permissions) "all"))) + [:button.mode-zone-button.tooltip.tooltip-bottom + {:on-click go-to-inspect + :class (dom/classnames :active (= section :inspect)) + :alt (tr "viewer.header.inspect-section" (sc/get-tooltip :open-inspect))} + i/code])] + + [:& header-options {:section section + :permissions permissions + :page page + :file file + :index index + :zoom zoom + :interactions-mode interactions-mode}]]))) diff --git a/frontend/src/app/main/ui/viewer/header.scss b/frontend/src/app/main/ui/viewer/header.scss new file mode 100644 index 0000000000..a0dde598dc --- /dev/null +++ b/frontend/src/app/main/ui/viewer/header.scss @@ -0,0 +1,301 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "common/refactor/common-refactor.scss" as *; + +.viewer-header { + position: absolute; + top: 0; + grid-column: 1 / span 1; + grid-row: 1 / span 1; + display: grid; + grid-template-columns: 1fr $s-92 1fr; + justify-content: space-between; + align-items: center; + height: $s-48; + width: 100vw; + padding: $s-8 $s-12; + background-color: var(--panel-background-color); +} + +// FILE NAVIGATION + +.nav-zone { + display: flex; + justify-content: flex-start; + flex-basis: min-content; + width: 100%; + gap: $s-12; +} + +.home-link { + padding: 0; +} + +.logo-icon { + @include flexCenter; + width: $s-32; + height: $s-32; + svg { + width: $s-28; + fill: var(--icon-foreground-hover); + } +} + +.sitemap-zone { + @include flexColumn; + position: relative; + width: 100%; +} + +.project-name { + @include tabTitleTipography; +} + +.sitemap-text { + @include flexRow; +} + +.breadcrumb { + @include titleTipography; + @include flexRow; + color: var(--title-foreground-color); + cursor: pointer; +} + +.breadcrumb-text { + @include textEllipsis; + max-width: 12vw; // This is a fallback + max-width: 12cqw; // This is a unit refered to container +} + +.icon { + @include flexCenter; + height: $s-16; + width: $s-16; + svg { + @extend .button-icon-small; + transform: rotate(90deg); + stroke: var(--icon-foreground); + } +} + +.dropdown { + position: absolute; +} + +.dropdown-sitemap { + @extend .menu-dropdown; + left: 0; + top: calc($s-2 + $s-48); + width: $s-272; + padding: $s-6; +} + +.dropdown-element { + @extend .dropdown-element-base; + .icon-check { + @include flexCenter; + height: 100%; + width: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + } + &:hover .label { + color: var(--input-foreground-color-active); + } +} + +.current-frame { + @include titleTipography; + @include flexRow; + flex-grow: 1; + color: var(--title-foreground-color-hover); + cursor: pointer; + .icon svg { + stroke: var(--title-foreground-color-hover); + } +} + +.frame-name { + @include textEllipsis; + max-width: 17vw; // This is a fallback + max-width: 17cqw; // This is a unit refered to container +} + +// SECTION BUTTONS +.mode-zone { + @include flexRow; + height: 100%; +} + +.mode-zone-btn { + @extend .button-tertiary; + @include flexCenter; + height: $s-32; + width: $s-28; + padding: 0; + svg { + @extend .button-icon; + } +} + +.selected { + @extend .button-icon-selected; +} + +// OPTION AREA +.options-zone { + @include flexRow; + position: relative; + justify-content: flex-end; + gap: $s-8; + z-index: $z-index-10; +} + +.view-options { + position: relative; + display: flex; + align-items: center; + cursor: pointer; +} + +.fullscreen-btn { + @extend .button-tertiary; + @include flexCenter; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + +.share-btn { + @extend .button-primary; + height: $s-32; + min-width: $s-72; + margin-left: $s-4; +} + +.edit-btn { + @extend .button-tertiary; + @include flexCenter; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + +.go-log-btn { + @extend .button-tertiary; + @include titleTipography; + height: $s-32; + padding: 0 $s-8; + border-radius: $br-8; + color: var(--button-tertiary-foreground-color-rest); +} + +// ZOOM WIDGET +.zoom-widget { + @include buttonStyle; + @include flexCenter; + height: $s-28; + min-width: $s-64; + border-radius: $br-8; + .label { + @include titleTipography; + color: var(--button-tertiary-foreground-color-rest); + } + + &:hover { + .label { + color: var(--button-tertiary-foreground-color-focus); + } + } + &.selected { + .label { + color: var(--button-tertiary-foreground-color-focus); + } + } +} + +.dropdown { + @extend .menu-dropdown; + right: $s-2; + top: calc($s-2 + $s-48); + width: $s-272; +} + +.basic-zoom-bar { + display: flex; + justify-content: space-between; + padding: $s-6; + cursor: auto; +} + +.zoom-btns { + display: flex; +} + +.zoom-btn { + @extend .button-tertiary; + height: $s-28; + width: $s-28; + border-radius: $br-8; + .zoom-icon { + @include flexCenter; + width: $s-24; + height: $s-32; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } + &:hover { + .zoom-icon svg { + stroke: var(--button-tertiary-foreground-color-hover); + } + } +} + +.zoom-text { + @include flexCenter; + height: 100%; + min-width: $s-64; + padding: 0; + margin: 0 $s-2; + color: var(--modal-title-foreground-color); +} + +.reset-btn { + @extend .button-tertiary; + color: var(--button-tertiary-foreground-color-hover); + height: $s-28; + border-radius: $br-8; +} + +.zoom-option { + @extend .menu-item; + .shortcuts { + @extend .shortcut; + .shortcut-key { + @extend .shortcut-key; + } + } + &:hover { + color: var(--menu-foreground-color-hover); + .shortcuts { + .shortcut-key { + color: var(--menu-foreground-color-hover); + } + } + } +} diff --git a/frontend/src/app/main/ui/viewer/inspect.cljs b/frontend/src/app/main/ui/viewer/inspect.cljs index 576cbe06b7..9624d480dd 100644 --- a/frontend/src/app/main/ui/viewer/inspect.cljs +++ b/frontend/src/app/main/ui/viewer/inspect.cljs @@ -5,10 +5,13 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.inspect + (:require-macros [app.main.style :as stl]) (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.main.data.viewer :as dv] [app.main.store :as st] + [app.main.ui.context :as ctx] [app.main.ui.hooks.resize :refer [use-resize-hook]] [app.main.ui.viewer.inspect.left-sidebar :refer [left-sidebar]] [app.main.ui.viewer.inspect.render :refer [render-frame-svg]] @@ -20,25 +23,27 @@ (:import goog.events.EventType)) (defn handle-select-frame - [frame] - (fn [event] + [event] + (let [frame-id (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string)) + origin (dom/get-target event) + over-section? (dom/class? origin "inspect-svg-container") + layout (dom/get-element "viewer-layout") + has-force? (dom/class? layout "force-visible")] + (dom/prevent-default event) (dom/stop-propagation event) - (st/emit! (dv/select-shape (:id frame))) - - (let [origin (dom/get-target event) - over-section? (dom/class? origin "inspect-svg-container") - layout (dom/get-element "viewer-layout") - has-force? (dom/class? layout "force-visible")] - - (when over-section? - (if has-force? - (dom/remove-class! layout "force-visible") - (dom/add-class! layout "force-visible")))))) + (st/emit! (dv/select-shape frame-id)) + (when over-section? + (if has-force? + (dom/remove-class! layout "force-visible") + (dom/add-class! layout "force-visible"))))) (mf/defc viewport [{:keys [local file page frame index viewer-pagination size share-id]}] - (let [inspect-svg-container-ref (mf/use-ref nil) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + inspect-svg-container-ref (mf/use-ref nil) current-section* (mf/use-state :info) current-section (deref current-section*) @@ -77,7 +82,8 @@ handle-expand (mf/use-callback (mf/deps right-size) - #(set-right-size (if (> right-size 276) 276 768)))] + (fn[] + (set-right-size (if (> right-size 276) 276 768))))] (mf/use-effect on-mount) @@ -86,26 +92,60 @@ (fn [] (st/emit! (dv/select-shape (:id frame))))) - [:* - [:& left-sidebar {:frame frame - :local local - :page page}] - [:div.inspect-svg-wrapper {:on-click (handle-select-frame frame)} - [:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}] - [:div.inspect-svg-container {:ref inspect-svg-container-ref} - [:& render-frame-svg {:frame frame :page page :local local :size size}]]] + (if new-css-system + [:* + [:& left-sidebar {:frame frame + :local local + :page page}] + [:div {:class (stl/css :inspect-svg-wrapper) + :data-value (pr-str (:id frame)) + :on-click handle-select-frame} + [:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}] + [:div {:class (stl/css :inspect-svg-container) + :ref inspect-svg-container-ref} + [:& render-frame-svg {:frame frame :page page :local local :size size}]]] - [:div.sidebar-container - {:class (when (not can-be-expanded?) "not-expand") - :style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}} - [:div.resize-area - {:on-pointer-down on-pointer-down - :on-lost-pointer-capture on-lost-pointer-capture - :on-pointer-move on-pointer-move}] - [:& right-sidebar {:frame frame - :selected (:selected local) - :page page - :file file - :on-change-section handle-change-section - :on-expand handle-expand - :share-id share-id}]]])) + [:div {:class (stl/css-case :sidebar-container true + :not-expand (not can-be-expanded?) + :expanded can-be-expanded?) + + :style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}} + (when can-be-expanded? + [:div {:class (stl/css :resize-area) + :on-pointer-down on-pointer-down + :on-lost-pointer-capture on-lost-pointer-capture + :on-pointer-move on-pointer-move}]) + [:& right-sidebar {:frame frame + :selected (:selected local) + :page page + :file file + :on-change-section handle-change-section + :on-expand handle-expand + :share-id share-id}]]] + + + ;;OLD + [:* + [:& left-sidebar {:frame frame + :local local + :page page}] + [:div.inspect-svg-wrapper {:data-value (pr-str (:id frame)) + :on-click handle-select-frame} + [:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}] + [:div.inspect-svg-container {:ref inspect-svg-container-ref} + [:& render-frame-svg {:frame frame :page page :local local :size size}]]] + + [:div.sidebar-container + {:class (when (not can-be-expanded?) "not-expand") + :style #js {"--width" (when can-be-expanded? (dm/str right-size "px"))}} + [:div.resize-area + {:on-pointer-down on-pointer-down + :on-lost-pointer-capture on-lost-pointer-capture + :on-pointer-move on-pointer-move}] + [:& right-sidebar {:frame frame + :selected (:selected local) + :page page + :file file + :on-change-section handle-change-section + :on-expand handle-expand + :share-id share-id}]]]))) diff --git a/frontend/src/app/main/ui/viewer/inspect.scss b/frontend/src/app/main/ui/viewer/inspect.scss new file mode 100644 index 0000000000..340003ce92 --- /dev/null +++ b/frontend/src/app/main/ui/viewer/inspect.scss @@ -0,0 +1,56 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "common/refactor/common-refactor.scss" as *; + +$width-settings-bar: $s-276; +$width-settings-bar-max: $s-500; + +.inspect-svg-wrapper { + @include flexCenter; + position: relative; + flex-direction: column; + flex: 1; + width: 100%; + height: 100%; + overflow: hidden; +} + +.inspect-svg-container { + display: grid; + align-items: center; + justify-content: safe center; + width: 100%; + height: 100%; + margin: 0 auto; + overflow: auto; +} + +.sidebar-container { + position: relative; + align-self: flex-start; + width: $width-settings-bar; + + background-color: var(--panel-background-color); + border-top: $s-1 solid var(--search-bar-input-border-color); +} + +.not-expand { + max-width: $width-settings-bar; +} + +.expanded { + width: var(--width, $width-settings-bar); +} + +.resize-area { + position: absolute; + left: 0; + width: $s-8; + height: 100%; + z-index: $z-index-10; + cursor: ew-resize; +} diff --git a/frontend/src/app/main/ui/viewer/inspect/code.cljs b/frontend/src/app/main/ui/viewer/inspect/code.cljs index ca54120fd3..b91b7df99c 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/code.cljs @@ -30,9 +30,9 @@ [app.util.dom :as dom] [app.util.http :as http] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def embed-images? true) @@ -224,7 +224,7 @@ #(->> (rx/from fonts) (rx/merge-map fonts/fetch-font-css) (rx/reduce conj []) - (rx/subs + (rx/subs! (fn [result] (let [css (str/join "\n" result)] (reset! fontfaces-css* css)))))) @@ -237,7 +237,7 @@ (->> (http/fetch-data-uri uri true) (rx/catch (fn [_] (rx/of (hash-map uri uri))))))) (rx/reduce conj {}) - (rx/subs + (rx/subs! (fn [result] (reset! images-data* result))))) @@ -261,7 +261,10 @@ :collapsabled-icon true :rotated collapsed-css?)} i/arrow-refactor]] - [:span {:class (stl/css :code-lang)} "CSS"] + + [:& select {:default-value style-type + :class (stl/css :code-lang-select) + :options [{:label "CSS" :value "css"}]}] [:div {:class (stl/css :action-btns)} [:button {:class (stl/css :expand-button) diff --git a/frontend/src/app/main/ui/viewer/inspect/code.scss b/frontend/src/app/main/ui/viewer/inspect/code.scss index 1eb6f5db3d..3524f40a03 100644 --- a/frontend/src/app/main/ui/viewer/inspect/code.scss +++ b/frontend/src/app/main/ui/viewer/inspect/code.scss @@ -7,6 +7,12 @@ @import "refactor/common-refactor.scss"; .element-options { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + padding-bottom: $s-16; + .attributes-block { .download-button { @extend .button-secondary; @@ -17,46 +23,67 @@ } } .code-block { + @include codeTypography; + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + min-height: 0; + overflow: hidden; padding: 0 $s-4 $s-8 0; - .code-row-lang { - display: flex; - justify-content: space-between; - gap: $s-4; - width: 100%; - .code-lang { - @include tabTitleTipography; - display: flex; - align-items: center; - } - .action-btns { - display: flex; - gap: $s-4; - flex: 1; - justify-content: end; - .expand-button { - @extend .button-tertiary; - height: $s-32; - width: $s-28; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - } - } - } - .code-lang-select { - @include tabTitleTipography; - width: $s-92; - border: $s-1 solid transparent; - background-color: transparent; - color: var(--menu-foreground-color-disabled); - } + pre { + border-radius: $br-8; + padding: $s-16; + max-height: var(--code-height); + overflow: auto; + height: 100%; } - .code-row-display { - margin-bottom: $s-8; + // Overrides background setted in the theme + :global(.hljs) { + background: $db-tertiary; } } + .code-row-lang { + display: flex; + justify-content: space-between; + gap: $s-4; + width: 100%; + } + .code-lang { + @include tabTitleTipography; + display: flex; + align-items: center; + } + .action-btns { + display: flex; + gap: $s-4; + flex: 1; + justify-content: end; + .expand-button { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } + } + .code-lang-select { + @include tabTitleTipography; + width: $s-72; + border: $s-1 solid transparent; + background-color: transparent; + color: var(--menu-foreground-color-disabled); + } + .code-row-display { + flex: 1; + min-height: 0; + overflow: hidden; + padding-bottom: $s-8; + } } .toggle-btn { diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs index bf42b3e7b1..d5fe584b74 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs @@ -87,8 +87,8 @@ (handle-change-tab :info)))) (if new-css-system - [:aside {:class (stl/css :settings-bar-right)} - + [:aside {:class (stl/css-case :settings-bar-right true + :viewer-code (= from :inspect))} (if (seq shapes) [:div {:class (stl/css :tool-windows)} [:div {:class (stl/css :shape-row)} diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss index de3e6d54cb..13bf37facb 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.scss @@ -9,11 +9,13 @@ .settings-bar-right { min-width: $s-252; width: 100%; - height: 100%; + height: 100vh; position: relative; left: unset; right: unset; grid-area: right-sidebar; + padding-top: $s-8; + padding-left: $s-12; .tool-windows { height: 100%; display: flex; @@ -64,9 +66,11 @@ padding: $s-8 $s-24; } } - .inspect-content { flex: 1; overflow: hidden; } + &.viewer-code { + height: calc(100vh - $s-48); + } } diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index 6e56455384..c570f091a2 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.interactions + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -18,6 +19,7 @@ [app.main.data.viewer :as dv] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.viewer.shapes :as shapes] @@ -191,77 +193,144 @@ (mf/defc flows-menu {::mf/wrap [mf/memo]} [{:keys [page index]}] - (let [flows (dm/get-in page [:options :flows]) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + 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))) + current-flow* (mf/use-state + #(ctp/get-frame-flow flows (:id frame))) - show-dropdown? (mf/use-state false) - toggle-dropdown (mf/use-fn #(swap! show-dropdown? not)) - hide-dropdown (mf/use-fn #(reset! show-dropdown? false)) + current-flow (deref current-flow*) + + show-dropdown?* (mf/use-state false) + show-dropdown? (deref show-dropdown?*) + toggle-dropdown (mf/use-fn #(swap! show-dropdown?* not)) + hide-dropdown (mf/use-fn #(reset! show-dropdown?* false)) select-flow (mf/use-callback - (fn [flow] - (reset! current-flow flow) - (st/emit! (dv/go-to-frame (:starting-frame flow)))))] + (fn [event] + (let [flow (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string))] + (reset! current-flow* flow) + (st/emit! (dv/go-to-frame (:starting-frame flow))))))] (when (seq flows) - [:div.view-options {:on-click toggle-dropdown} - [:span.icon i/play] - [:span.label (:name @current-flow)] - [:span.icon i/arrow-down] - [:& dropdown {:show @show-dropdown? - :on-close hide-dropdown} - [:ul.dropdown.with-check - (for [[index flow] (d/enumerate flows)] - [:li {:key (dm/str "flow-" (:id flow) "-" index) - :class (dom/classnames :selected (= (:id flow) (:id @current-flow))) - :on-click #(select-flow flow)} - [:span.icon i/tick] - [:span.label (:name flow)]])]]]))) + (if new-css-system + [:div {:on-click toggle-dropdown + :class (stl/css :view-options)} + [:span {:class (stl/css :icon)} i/play-refactor] + [:span {:class (stl/css :dropdown-title)} (:name current-flow)] + [:span {:class (stl/css :icon-dropdown)} i/arrow-refactor] + [:& dropdown {:show show-dropdown? + :on-close hide-dropdown} + [:ul {:class (stl/css :dropdown)} + (for [[index flow] (d/enumerate flows)] + [:li {:key (dm/str "flow-" (:id flow) "-" index) + :class (stl/css-case :dropdown-element true + :selected (= (:id flow) (:id current-flow))) + ;; This is not a best practise, is not very performant Do not reproduce + :data-value (pr-str flow) + :on-click select-flow} + [:span {:class (stl/css :label)} (:name flow)] + (when (= (:id flow) (:id current-flow)) + [:span {:class (stl/css :icon)} i/tick-refactor])])]]] + + ;; OLD + [:div.view-options {:on-click toggle-dropdown} + [:span.icon i/play] + [:span.label (:name current-flow)] + [:span.icon i/arrow-down] + [:& dropdown {:show show-dropdown? + :on-close hide-dropdown} + [:ul.dropdown.with-check + (for [[index flow] (d/enumerate flows)] + [:li {:key (dm/str "flow-" (:id flow) "-" index) + :class (dom/classnames :selected (= (:id flow) (:id current-flow))) + ;; This is not a best practise, is not very performant Do not reproduce + :data-value (pr-str flow) + :on-click select-flow} + [:span.icon i/tick] + [:span.label (:name flow)]])]]])))) (mf/defc interactions-menu [{:keys [interactions-mode]}] - (let [show-dropdown? (mf/use-state false) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + show-dropdown? (mf/use-state false) toggle-dropdown (mf/use-fn #(swap! show-dropdown? not)) hide-dropdown (mf/use-fn #(reset! show-dropdown? false)) select-mode (mf/use-fn - (fn [event] - (let [mode (some-> (dom/get-current-target event) - (dom/get-data "mode") - (keyword))] - (dom/stop-propagation event) - (st/emit! (dv/set-interactions-mode mode)))))] + (fn [event] + (let [mode (some-> (dom/get-current-target event) + (dom/get-data "mode") + (keyword))] + (dom/stop-propagation event) + (st/emit! (dv/set-interactions-mode mode)))))] + (if new-css-system + [:div {:on-click toggle-dropdown + :class (stl/css :view-options)} + [:span {:class (stl/css :dropdown-title)} (tr "viewer.header.interactions")] + [:span {:class (stl/css :icon-dropdown)} i/arrow-refactor] + [:& dropdown {:show @show-dropdown? + :on-close hide-dropdown} + [:ul {:class (stl/css :dropdown)} + [:li {:class (stl/css-case :dropdown-element true + :selected (= interactions-mode :hide)) + :on-click select-mode + :data-mode :hide} - [:div.view-options {:on-click toggle-dropdown} - [:span.label (tr "viewer.header.interactions")] - [:span.icon i/arrow-down] - [:& dropdown {:show @show-dropdown? - :on-close hide-dropdown} - [:ul.dropdown.with-check - [:li {:class (dom/classnames :selected (= interactions-mode :hide)) - :on-click select-mode - :data-mode :hide} - [:span.icon i/tick] - [:span.label (tr "viewer.header.dont-show-interactions")]] + [:span {:class (stl/css :label)} (tr "viewer.header.dont-show-interactions")] + (when (= interactions-mode :hide) + [:span {:class (stl/css :icon)} i/tick-refactor])] - [:li {:class (dom/classnames :selected (= interactions-mode :show)) - :on-click select-mode - :data-mode :show} - [:span.icon i/tick] - [:span.label (tr "viewer.header.show-interactions")]] + [:li {:class (stl/css-case :dropdown-element true + :selected (= interactions-mode :show)) + :on-click select-mode + :data-mode :show} + [:span {:class (stl/css :label)} (tr "viewer.header.show-interactions")] + (when (= interactions-mode :show) + [:span {:class (stl/css :icon)} i/tick-refactor])] - [:li {:class (dom/classnames :selected (= interactions-mode :show-on-click)) - :on-click select-mode - :data-mode :show-on-click} - [:span.icon i/tick] - [:span.label (tr "viewer.header.show-interactions-on-click")]]]]])) + [:li {:class (stl/css-case :dropdown-element true + :selected (= interactions-mode :show-on-click)) + :on-click select-mode + :data-mode :show-on-click} + + [:span {:class (stl/css :label)} (tr "viewer.header.show-interactions-on-click")] + (when (= interactions-mode :show-on-click) + [:span {:class (stl/css :icon)} i/tick-refactor])]]]] + + + + [:div.view-options {:on-click toggle-dropdown} + [:span.label (tr "viewer.header.interactions")] + [:span.icon i/arrow-down] + [:& dropdown {:show @show-dropdown? + :on-close hide-dropdown} + [:ul.dropdown.with-check + [:li {:class (dom/classnames :selected (= interactions-mode :hide)) + :on-click select-mode + :data-mode :hide} + [:span.icon i/tick] + [:span.label (tr "viewer.header.dont-show-interactions")]] + + [:li {:class (dom/classnames :selected (= interactions-mode :show)) + :on-click select-mode + :data-mode :show} + [:span.icon i/tick] + [:span.label (tr "viewer.header.show-interactions")]] + + [:li {:class (dom/classnames :selected (= interactions-mode :show-on-click)) + :on-click select-mode + :data-mode :show-on-click} + [:span.icon i/tick] + [:span.label (tr "viewer.header.show-interactions-on-click")]]]]]))) + (defn animate-go-to-frame [animation current-viewport orig-viewport current-size orig-size wrapper-size] (case (:animation-type animation) diff --git a/frontend/src/app/main/ui/viewer/interactions.scss b/frontend/src/app/main/ui/viewer/interactions.scss new file mode 100644 index 0000000000..07b12e3af1 --- /dev/null +++ b/frontend/src/app/main/ui/viewer/interactions.scss @@ -0,0 +1,80 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "common/refactor/common-refactor.scss" as *; + +.view-options { + @include titleTipography; + display: flex; + align-items: center; + position: relative; + gap: $s-4; + height: $s-32; + border-radius: $br-8; + background-color: var(--input-background-color); + padding: $s-8; + cursor: pointer; +} +.dropdown-title { + @include titleTipography; + flex-grow: 1; + color: var(--input-foreground-color-active); +} + +.label { + flex-grow: 1; + color: var(--input-foreground-color); +} + +.dropdown { + @extend .menu-dropdown; + right: $s-2; + top: calc($s-2 + $s-48); + width: $s-272; + padding: $s-6; +} + +.dropdown-element { + @extend .dropdown-element-base; + .icon { + @include flexCenter; + height: 100%; + width: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + } + &:hover .label { + color: var(--input-foreground-color-active); + } +} + +.dropdown-element.selected { + .label { + color: var(--input-foreground-color-active); + } + .icon svg { + stroke: var(--input-foreground-color); + } +} + +.icon, +.icon-dropdown { + @include flexCenter; + height: 100%; + width: $s-16; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } +} + +.icon-dropdown svg { + transform: rotate(90deg); +} + +// breakpoint 1013px diff --git a/frontend/src/app/main/ui/viewer/login.cljs b/frontend/src/app/main/ui/viewer/login.cljs index 46054f8f8a..375066e137 100644 --- a/frontend/src/app/main/ui/viewer/login.cljs +++ b/frontend/src/app/main/ui/viewer/login.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.login + (:require-macros [app.main.style :as stl]) (:require [app.common.logging :as log] [app.main.data.modal :as modal] @@ -13,6 +14,7 @@ [app.main.ui.auth.login :refer [login-methods]] [app.main.ui.auth.recovery-request :refer [recovery-request-page]] [app.main.ui.auth.register :refer [register-methods register-validate-form register-success-page]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -25,15 +27,31 @@ {::mf/register modal/components ::mf/register-as :login-register} [_] - (let [uri (. (. js/document -location) -href) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + uri (. (. js/document -location) -href) user-email (mf/use-state "") register-token (mf/use-state "") - current-section (mf/use-state :login) - set-current-section (mf/use-fn #(reset! current-section %)) + + current-section* (mf/use-state :login) + current-section (deref current-section*) + + set-current-section + (mf/use-fn #(reset! current-section* %)) + + set-section + (mf/use-fn + (fn [event] + (let [section (-> (dom/get-current-target event) + (dom/get-data "value") + (keyword))] + (set-current-section section)))) + + go-back-to-login (mf/use-fn #(set-current-section :login)) + main-section (or - (= @current-section :login) - (= @current-section :register) - (= @current-section :register-validate)) + (= current-section :login) + (= current-section :register) + (= current-section :register-validate)) close (fn [event] (dom/prevent-default event) @@ -49,57 +67,118 @@ (fn [data] (reset! register-token (:token data)) (set-current-section :register-validate))] + (mf/with-effect [] (swap! storage assoc :redirect-url uri)) - [:div.modal-overlay - [:div.modal-container.login-register - [:div.title - [:div.modal-close-button {:on-click close :title (tr "labels.close")} - i/close] - (when main-section - [:h2 (tr "labels.continue-with-penpot")])] - [:div.modal-bottom.auth-content + (if new-css-system + [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css :modal-container)} + [:div {:class (stl/css :modal-header)} + [:h2 {:class (stl/css :modal-title)} (tr "labels.continue-with-penpot")] + [:button {:class (stl/css :modal-close-btn) + :title (tr "labels.close") + :on-click close} i/close-refactor]] - (case @current-section - :login - [:div.generic-form.login-form - [:div.form-container - [:& login-methods {:on-success-callback success-login}] - [:div.links - [:div.link-entry - [:a {:on-click #(set-current-section :recovery-request)} - (tr "auth.forgot-password")]] - [:div.link-entry - [:span (tr "auth.register") " "] - [:a {:on-click #(set-current-section :register)} - (tr "auth.register-submit")]]]]] + [:div {:class (stl/css :modal-content)} - :register - [:div.form-container - [:& register-methods {:on-success-callback success-register}] - [:div.links - [:div.link-entry - [:span (tr "auth.already-have-account") " "] - [:a {:on-click #(set-current-section :login)} - (tr "auth.login-here")]]]] + (case current-section + :login + [:div {:class (stl/css :form-container)} + [:& login-methods {:on-success-callback success-login :origin :viewer}] + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:a {:on-click set-section + :data-value :recovery-request} + (tr "auth.forgot-password")]] + [:div {:class (stl/css :link-entry)} + [:span (tr "auth.register") " "] + [:a {:on-click set-section + :data-value :register} + (tr "auth.register-submit")]]]] - :register-validate - [:div.form-container - [:& register-validate-form {:params {:token @register-token} + :register + [:div {:class (stl/css :form-container)} + [:& register-methods {:on-success-callback success-register}] + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:span (tr "auth.already-have-account") " "] + [:a {:on-click set-section + :data-value :login} + (tr "auth.login-here")]]]] + + :register-validate + [:div {:class (stl/css :form-container)} + [:& register-validate-form {:params {:token @register-token} + :on-success-callback success-email-sent}] + [:div {:class (stl/css :links)} + [:div {:class (stl/css :link-entry)} + [:a {:on-click set-section + :data-value :register} + (tr "labels.go-back")]]]] + + :recovery-request + [:& recovery-request-page {:go-back-callback go-back-to-login :on-success-callback success-email-sent}] - [:div.links - [:div.link-entry - [:a {:on-click #(set-current-section :register)} - (tr "labels.go-back")]]]] + :email-sent + [:div {:class (stl/css :form-container)} + [:& register-success-page {:params {:email @user-email}}]]) - :recovery-request - [:& recovery-request-page {:go-back-callback #(set-current-section :login) - :on-success-callback success-email-sent}] - :email-sent - [:div.form-container - [:& register-success-page {:params {:email @user-email}}]])] + (when main-section + [:div {:class (stl/css :links)} + [:& terms-login]])]]] - (when main-section - [:div.modal-footer.links - [:& terms-login]])]])) + + ;;OLD + [:div.modal-overlay + [:div.modal-container.login-register + [:div.title + [:div.modal-close-button {:on-click close :title (tr "labels.close")} + i/close] + (when main-section + [:h2 (tr "labels.continue-with-penpot")])] + + [:div.modal-bottom.auth-content + + (case current-section + :login + [:div.generic-form.login-form + [:div.form-container + [:& login-methods {:on-success-callback success-login}] + [:div.links + [:div.link-entry + [:a {:on-click #(set-current-section :recovery-request)} + (tr "auth.forgot-password")]] + [:div.link-entry + [:span (tr "auth.register") " "] + [:a {:on-click #(set-current-section :register)} + (tr "auth.register-submit")]]]]] + + :register + [:div.form-container + [:& register-methods {:on-success-callback success-register}] + [:div.links + [:div.link-entry + [:span (tr "auth.already-have-account") " "] + [:a {:on-click #(set-current-section :login)} + (tr "auth.login-here")]]]] + + :register-validate + [:div.form-container + [:& register-validate-form {:params {:token @register-token} + :on-success-callback success-email-sent}] + [:div.links + [:div.link-entry + [:a {:on-click #(set-current-section :register)} + (tr "labels.go-back")]]]] + + :recovery-request + [:& recovery-request-page {:go-back-callback #(set-current-section :login) + :on-success-callback success-email-sent}] + :email-sent + [:div.form-container + [:& register-success-page {:params {:email @user-email}}]])] + + (when main-section + [:div.modal-footer.links + [:& terms-login]])]]))) diff --git a/frontend/src/app/main/ui/viewer/login.scss b/frontend/src/app/main/ui/viewer/login.scss new file mode 100644 index 0000000000..6e39b53f67 --- /dev/null +++ b/frontend/src/app/main/ui/viewer/login.scss @@ -0,0 +1,73 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@import "refactor/common-refactor.scss"; + +.modal-overlay { + @extend .modal-overlay-base; +} + +.modal-container { + @extend .modal-container-base; +} + +.modal-header { + margin-bottom: $s-24; +} + +.modal-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-btn { + @extend .modal-close-btn-base; +} + +.modal-content { + @include flexColumn; + @include titleTipography; + gap: $s-24; + max-height: $s-400; + width: $s-368; + overflow: hidden auto; + form { + display: flex; + flex-direction: column; + margin-bottom: 1.5rem; + gap: 0.75rem; + } +} + +.form-container { + display: flex; + justify-content: center; + flex-direction: column; + max-width: $s-368; +} + +.links { + position: relative; +} + +.link-entry { + display: flex; + flex-direction: column; + gap: $s-12; + + span { + text-align: center; + font-size: $fs-14; + color: var(--modal-text-foreground-color); + margin-top: $s-12; + } + a { + @extend .button-secondary; + height: $s-40; + text-transform: uppercase; + font-size: $fs-11; + } +} diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index a6662fa160..41bd3ed204 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.share-link + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -16,12 +17,14 @@ [app.main.data.modal :as modal] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.select :refer [select]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [app.util.webapi :as wapi] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (log/set-level! :warn) @@ -37,7 +40,8 @@ ::mf/register-as :share-link ::mf/wrap-props false} [{:keys [file page]}] - (let [current-page page + (let [new-css-system (mf/use-ctx ctx/new-css-system) + current-page page current-page-id (:id page) slinks (mf/deref refs/share-links) router (mf/deref refs/router) @@ -151,135 +155,284 @@ (fn [_] (swap! perms-visible* not)) - on-who-change - (fn [type event] - (let [target (dom/get-target event) - value (dom/get-value target) - value (keyword value)] - (reset! confirm* false) - (if (= type :comment) - (swap! options* assoc :who-comment (d/name value)) - (swap! options* assoc :who-inspect (d/name value)))))] + on-inspect-change + (fn [value] + (reset! confirm* false) + (swap! options* assoc :who-inspect value)) + + on-comment-change + (fn [value] + (reset! confirm* false) + (swap! options* assoc :who-comment value))] + + (if new-css-system + [:div {:class (stl/css :share-modal)} + [:div {:class (stl/css :share-link-dialog)} + [:div {:class (stl/css :share-link-header)} + [:h2 {:class (stl/css :share-link-title)} + (tr "common.share-link.title")] + [:button {:class (stl/css :modal-close-button) + :on-click on-close + :title (tr "labels.close")} + i/close-refactor]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :share-link-section)} + (when (and (not confirm?) (some? current-link)) + [:div {:class (stl/css :custon-input-wrapper)} + [:input {:class (stl/css :input-text) + :type "text" + :value (or current-link "") + :placeholder (tr "common.share-link.placeholder") + :read-only true}] + + [:button {:class (stl/css :copy-button) + :title (tr "viewer.header.share.copy-link") + :on-click copy-link} + i/clipboard-refactor]]) + + [:div {:class (stl/css :hint-wrapper)} + (when (not ^boolean confirm?) + [:div {:class (stl/css :hint)} (tr "common.share-link.permissions-hint")]) + (cond + (true? confirm?) + [:div {:class (stl/css :confirm-dialog)} + [:div {:class (stl/css :description)} + (tr "common.share-link.confirm-deletion-link-description")] + [:div {:class (stl/css :actions)} + [:input {:type "button" + :class (stl/css :button-cancel) + :on-click #(reset! confirm* false) + :value (tr "labels.cancel")}] + [:input {:type "button" + :class (stl/css :button-danger) + :on-click delete-link + :value (tr "common.share-link.destroy-link")}]]] + + (some? current-link) + [:input + {:type "button" + :class (stl/css :button-danger) + :on-click try-delete-link + :value (tr "common.share-link.destroy-link")}] + + :else + [:input + {:type "button" + :class (stl/css :button-active) + :on-click create-link + :value (tr "common.share-link.get-link")}])]] + - [:div.modal-overlay.transparent.share-modal - [:div.modal-container.share-link-dialog - [:div.modal-content.initial - [:div.title - [:h2 (tr "common.share-link.title")] - [:div.modal-close-button - {:on-click on-close - :title (tr "labels.close")} - i/close]]] - [:div.modal-content - [:div.share-link-section - (when (and (not confirm?) (some? current-link)) - [:div.custom-input.with-icon - [:input {:type "text" - :value (or current-link "") - :placeholder (tr "common.share-link.placeholder") - :read-only true}] - [:div.help-icon {:title (tr "viewer.header.share.copy-link") - :on-click copy-link} - i/copy]]) - [:div.hint-wrapper (when (not ^boolean confirm?) - [:div.hint (tr "common.share-link.permissions-hint")]) - (cond - (true? confirm?) - [:div.confirm-dialog - [:div.description (tr "common.share-link.confirm-deletion-link-description")] - [:div.actions + [:div {:class (stl/css :permissions-section)} + [:button {:class (stl/css :manage-permissions) + :on-click toggle-perms-visibility} + [:span {:class (stl/css-case :icon true + :rotated perms-visible?)} + i/arrow-refactor] + (tr "common.share-link.manage-ops")] + + (when ^boolean perms-visible? + [:* + (let [all-selected? (:all-pages options) + pages (->> (get-in file [:data :pages]) + (map #(get-in file [:data :pages-index %]))) + selected (:pages options)] + [:div {:class (stl/css :view-mode)} + [:div {:class (stl/css :subtitle)} + (tr "common.share-link.permissions-pages")] + [:div {:class (stl/css :items)} + (if (= 1 (count pages)) + + [:div {:class (stl/css :checkbox-wrapper)} + [:input {:type "checkbox" + :id (dm/str "page-" current-page-id) + :data-page-id (dm/str current-page-id) + :on-change on-mark-checked-page + :checked true}] + [:label {:for (str "page-" current-page-id)} (:name current-page)] + [:span {:class (stl/css-case :checkobox-tick true + :global/checked true)} + i/status-tick-refactor] + [:span (str " " (tr "common.share-link.current-tag"))]] + + [:* + [:div {:class (stl/css :select-all-row)} + [:div {:class (stl/css :checkbox-wrapper)} + [:label {:for "view-all" + :class (stl/css :select-all-label)} + [:span {:class (stl/css-case :global/checked all-selected?)} + (when all-selected? + i/status-tick-refactor)] + (tr "common.share-link.view-all") + [:input {:type "checkbox" + :id "view-all" + :checked all-selected? + :name "pages-mode" + :on-change on-toggle-all}]]] + + [:span {:class (stl/css :count-pages)} + (tr "common.share-link.page-shared" (i18n/c (count selected)))]] + + [:ul {:class (stl/css :pages-selection)} + (for [{:keys [id name]} pages] + [:li {:class (stl/css :checkbox-wrapper) + :key (dm/str id)} + [:label {:for (dm/str "page-" id)} + [:span {:class (stl/css-case :global/checked (contains? selected id))} + (when (contains? selected id) + i/status-tick-refactor)] + name + (when (= current-page-id id) + [:div {:class (stl/css :current-tag)} (dm/str " " (tr "common.share-link.current-tag"))]) + [:input {:type "checkbox" + :id (dm/str "page-" id) + :data-page-id (dm/str id) + :on-change on-mark-checked-page + :checked (contains? selected id)}]]])]])]]) + + [:div {:class (stl/css :access-mode)} + [:div {:class (stl/css :subtitle)} + (tr "common.share-link.permissions-can-comment")] + [:div {:class (stl/css :items)} + [:& select + {:class (stl/css :who-comment-select) + :default-value (dm/str (:who-comment options)) + :options [{:value "team" :label (tr "common.share-link.team-members")} + {:value "all" :label (tr "common.share-link.all-users")}] + :on-change on-comment-change}]]] + [:div {:class (stl/css :inspect-mode)} + [:div {:class (stl/css :subtitle)} + (tr "common.share-link.permissions-can-inspect")] + [:div {:class (stl/css :items)} + [:& select + {:class (stl/css :who-inspect-select) + :default-value (dm/str (:who-inspect options)) + :options [{:value "team" :label (tr "common.share-link.team-members")} + {:value "all" :label (tr "common.share-link.all-users")}] + :on-change on-inspect-change}]]]])])]]] + + + ;;OLD + [:div.modal-overlay.transparent.share-modal + [:div.modal-container.share-link-dialog + [:div.modal-content.initial + [:div.title + [:h2 (tr "common.share-link.title")] + [:div.modal-close-button + {:on-click on-close + :title (tr "labels.close")} + i/close]]] + [:div.modal-content + [:div.share-link-section + (when (and (not confirm?) (some? current-link)) + [:div.custom-input.with-icon + [:input {:type "text" + :value (or current-link "") + :placeholder (tr "common.share-link.placeholder") + :read-only true}] + [:div.help-icon {:title (tr "viewer.header.share.copy-link") + :on-click copy-link} + i/copy]]) + [:div.hint-wrapper + (when (not ^boolean confirm?) + [:div.hint (tr "common.share-link.permissions-hint")]) + (cond + (true? confirm?) + [:div.confirm-dialog + [:div.description (tr "common.share-link.confirm-deletion-link-description")] + [:div.actions + [:input.btn-secondary + {:type "button" + :on-click #(reset! confirm* false) + :value (tr "labels.cancel")}] + [:input.btn-danger + {:type "button" + :on-click delete-link + :value (tr "common.share-link.destroy-link")}]]] + + (some? current-link) [:input.btn-secondary {:type "button" - :on-click #(reset! confirm* false) - :value (tr "labels.cancel")}] - [:input.btn-danger + :class "primary" + :on-click try-delete-link + :value (tr "common.share-link.destroy-link")}] + + :else + [:input.btn-primary {:type "button" - :on-click delete-link - :value (tr "common.share-link.destroy-link")}]]] - - (some? current-link) - [:input.btn-secondary - {:type "button" - :class "primary" - :on-click try-delete-link - :value (tr "common.share-link.destroy-link")}] - - :else - [:input.btn-primary - {:type "button" - :class "primary" - :on-click create-link - :value (tr "common.share-link.get-link")}])]]] - [:div.modal-content.ops-section - [:div.manage-permissions - {:on-click toggle-perms-visibility} - [:span.icon i/picker-hsv] - [:div.title (tr "common.share-link.manage-ops")]] - (when ^boolean perms-visible? - [:* - (let [all-selected? (:all-pages options) - pages (->> (get-in file [:data :pages]) - (map #(get-in file [:data :pages-index %]))) - selected (:pages options)] - [:* - [:div.view-mode - [:div.subtitle - [:span.icon i/play] - (tr "common.share-link.permissions-pages")] - [:div.items - (if (= 1 (count pages)) - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id (dm/str "page-" current-page-id) - :data-page-id (dm/str current-page-id) - :on-change on-mark-checked-page - :checked true}] - [:label {:for (str "page-" current-page-id)} (:name current-page)] - [:span (str " " (tr "common.share-link.current-tag"))]] - - [:* - [:div.row + :class "primary" + :on-click create-link + :value (tr "common.share-link.get-link")}])]]] + [:div.modal-content.ops-section + [:div.manage-permissions + {:on-click toggle-perms-visibility} + [:span.icon i/picker-hsv] + [:div.title (tr "common.share-link.manage-ops")]] + (when ^boolean perms-visible? + [:* + (let [all-selected? (:all-pages options) + pages (->> (get-in file [:data :pages]) + (map #(get-in file [:data :pages-index %]))) + selected (:pages options)] + [:* + [:div.view-mode + [:div.subtitle + [:span.icon i/play] + (tr "common.share-link.permissions-pages")] + [:div.items + (if (= 1 (count pages)) [:div.input-checkbox.check-primary [:input {:type "checkbox" - :id "view-all" - :checked all-selected? - :name "pages-mode" - :on-change on-toggle-all}] - [:label {:for "view-all"} (tr "common.share-link.view-all")]] - [:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]] + :id (dm/str "page-" current-page-id) + :data-page-id (dm/str current-page-id) + :on-change on-mark-checked-page + :checked true}] + [:label {:for (str "page-" current-page-id)} (:name current-page)] + [:span (str " " (tr "common.share-link.current-tag"))]] - [:ul.pages-selection - (for [{:keys [id name]} pages] - [:li.input-checkbox.check-primary {:key (dm/str id)} + [:* + [:div.row + [:div.input-checkbox.check-primary [:input {:type "checkbox" - :id (dm/str "page-" id) - :data-page-id (dm/str id) - :on-change on-mark-checked-page - :checked (contains? selected id)}] - (if (= current-page-id id) - [:* - [:label {:for (dm/str "page-" id)} name] - [:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]] - [:label {:for (dm/str "page-" id)} name])])]])]]]) - [:div.access-mode - [:div.subtitle - [:span.icon i/chat] - (tr "common.share-link.permissions-can-comment")] - [:div.items - [:select.input-select {:on-change (partial on-who-change :comment) - :value (:who-comment options)} - [:option {:value "team"} (tr "common.share-link.team-members")] - [:option {:value "all"} (tr "common.share-link.all-users")]]]] - [:div.inspect-mode - [:div.subtitle - [:span.icon i/code] - (tr "common.share-link.permissions-can-inspect")] - [:div.items - [:select.input-select {:on-change (partial on-who-change :inspect) - :value (:who-inspect options)} - [:option {:value "team"} (tr "common.share-link.team-members")] - [:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]])) + :id "view-all" + :checked all-selected? + :name "pages-mode" + :on-change on-toggle-all}] + [:label {:for "view-all"} (tr "common.share-link.view-all")]] + [:span.count-pages (tr "common.share-link.page-shared" (i18n/c (count selected)))]] + + [:ul.pages-selection + (for [{:keys [id name]} pages] + [:li.input-checkbox.check-primary {:key (dm/str id)} + [:input {:type "checkbox" + :id (dm/str "page-" id) + :data-page-id (dm/str id) + :on-change on-mark-checked-page + :checked (contains? selected id)}] + (if (= current-page-id id) + [:* + [:label {:for (dm/str "page-" id)} name] + [:span.current-tag (dm/str " " (tr "common.share-link.current-tag"))]] + [:label {:for (dm/str "page-" id)} name])])]])]]]) + [:div.access-mode + [:div.subtitle + [:span.icon i/chat] + (tr "common.share-link.permissions-can-comment")] + [:div.items + [:select.input-select {:on-change on-comment-change + :value (:who-comment options)} + [:option {:value "team"} (tr "common.share-link.team-members")] + [:option {:value "all"} (tr "common.share-link.all-users")]]]] + [:div.inspect-mode + [:div.subtitle + [:span.icon i/code] + (tr "common.share-link.permissions-can-inspect")] + [:div.items + [:select.input-select {:on-change on-inspect-change + :value (:who-inspect options)} + [:option {:value "team"} (tr "common.share-link.team-members")] + [:option {:value "all"} (tr "common.share-link.all-users")]]]]])]]]))) diff --git a/frontend/src/app/main/ui/viewer/share_link.scss b/frontend/src/app/main/ui/viewer/share_link.scss new file mode 100644 index 0000000000..dc0fbc7b4e --- /dev/null +++ b/frontend/src/app/main/ui/viewer/share_link.scss @@ -0,0 +1,176 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@import "refactor/common-refactor.scss"; + +.share-modal { + display: block; + position: absolute; + top: $s-52; + right: $s-12; + left: calc(100vw - $s-512); + z-index: $z-index-modal; +} +.share-link-dialog { + @extend .modal-container-base; + min-height: unset; +} + +.share-link-header { + margin-bottom: $s-24; +} + +.share-link-title { + @include tabTitleTipography; + color: var(--modal-title-foreground-color); +} + +.modal-close-button { + @extend .modal-close-btn-base; +} + +.modal-content { + @include titleTipography; + @include flexColumn; + gap: $s-24; +} + +.share-link-section { + @include flexColumn; + gap: $s-8; +} + +.hint-wrapper { + @include flexRow; +} +.hint { + flex-grow: 1; +} +.custon-input-wrapper { + @include flexRow; + border-radius: $br-8; + height: $s-32; + width: 100%; + background-color: var(--input-background-color); +} + +.input-text { + @extend .input-element; + color: var(--input-foreground-color-active); + padding-left: $s-8; + margin: 0; + flex-grow: 1; + &:focus { + outline: none; + border: $s-1 solid var(--input-border-color-active); + } +} +.copy-button { + @extend .button-secondary; + @include flexRow; + gap: $s-8; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground-hover); + } +} + +.description { + @include titleTipography; + margin-bottom: $s-24; +} + +.actions { + @include flexRow; + justify-content: flex-end; +} + +.button-active { + @extend .modal-accept-btn; +} +.button-cancel { + @extend .modal-cancel-btn; +} +.button-danger { + @extend .modal-danger-btn; +} + +.permissions-section { + @include flexColumn; + gap: $s-8; +} + +.manage-permissions { + @include buttonStyle; + @include tabTitleTipography; + color: var(--menu-foreground-color-rest); + height: $s-32; + display: flex; + align-items: center; + padding: 0; +} + +.icon { + @include flexCenter; + margin-right: $s-6; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + &.rotated { + transform: rotate(90deg); + } +} +.view-mode, +.access-mode, +.inspect-mode { + display: flex; + width: 100%; +} +.subtitle { + color: var(--modal-text-foreground-color); + display: flex; + align-items: center; + justify-content: flex-start; + width: $s-136; + height: $s-32; +} + +.items { + flex-grow: 1; + color: var(--input-foreground-color-active); +} +.select-all-row { + @include flexRow; + justify-content: space-between; + height: $s-32; + border-bottom: $s-1 solid var(--input-border-color-disabled); +} +.select-all-label { + color: var(--input-foreground-color-active); +} +.pages-selection { + margin: 0; + li { + border-bottom: $s-1 solid var(--input-border-color-disabled); + } + li:last-child { + border-bottom: none; + } +} +.count-pages, +.current-tag { + @include titleTipography; + color: var(--input-foreground-color); +} + +.checkbox-wrapper { + @extend .input-checkbox; + height: $s-32; + padding: 0; +} diff --git a/frontend/src/app/main/ui/viewer/thumbnails.cljs b/frontend/src/app/main/ui/viewer/thumbnails.cljs index 086cbe0479..8e95c5727d 100644 --- a/frontend/src/app/main/ui/viewer/thumbnails.cljs +++ b/frontend/src/app/main/ui/viewer/thumbnails.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.viewer.thumbnails + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -13,6 +14,7 @@ [app.main.data.viewer :as dv] [app.main.render :as render] [app.main.store :as st] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -22,7 +24,8 @@ (mf/defc thumbnails-content [{:keys [children expanded? total] :as props}] - (let [container (mf/use-ref) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + container (mf/use-ref) width (mf/use-var (.. js/document -documentElement -clientWidth)) element-width (mf/use-var 152) @@ -56,45 +59,96 @@ (reset! width (obj/get dom "clientWidth"))))] (mf/use-effect on-mount) - (if expanded? - [:div.thumbnails-content - [:div.thumbnails-list-expanded children]] - [:div.thumbnails-content - [:div.left-scroll-handler {:on-click on-left-arrow-click} i/arrow-slide] - [:div.right-scroll-handler {:on-click on-right-arrow-click} i/arrow-slide] - [:div.thumbnails-list {:ref container :on-wheel on-scroll} - [:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}} - children]]]))) + (if new-css-system + (if expanded? + [:div {:class (stl/css :thumbnails-content)} + [:div {:class (stl/css :thumbnails-list-expanded)} children]] + + [:div {:class (stl/css :thumbnails-content)} + [:button {:class (stl/css :left-scroll-handler) + :on-click on-left-arrow-click} i/arrow-refactor] + [:button {:class (stl/css :right-scroll-handler) + :on-click on-right-arrow-click} i/arrow-refactor] + + [:div {:class (stl/css :thumbnails-list) + :ref container + :on-wheel on-scroll} + [:div {:class (stl/css :thumbnails-list-inside) + :style {:right (str (* @offset 152) "px")}} + children]]]) + + + + (if expanded? + [:div.thumbnails-content + [:div.thumbnails-list-expanded children]] + + [:div.thumbnails-content + [:div.left-scroll-handler {:on-click on-left-arrow-click} i/arrow-slide] + [:div.right-scroll-handler {:on-click on-right-arrow-click} i/arrow-slide] + [:div.thumbnails-list {:ref container :on-wheel on-scroll} + [:div.thumbnails-list-inside {:style {:right (str (* @offset 152) "px")}} + children]]])))) (mf/defc thumbnails-summary [{:keys [on-toggle-expand on-close total] :as props}] - [:div.thumbnails-summary - [:span.counter (tr "labels.num-of-frames" (i18n/c total))] - [:span.buttons - [:span.btn-expand {:on-click on-toggle-expand} i/arrow-down] - [:span.btn-close {:on-click on-close} i/close]]]) + (let [new-css-system (mf/use-ctx ctx/new-css-system)] + (if new-css-system + [:div {:class (stl/css :thumbnails-summary)} + [:span {:class (stl/css :counter)} + (tr "labels.num-of-frames" (i18n/c total))] + [:span {:class (stl/css :actions)} + [:button {:class (stl/css :expand-btn) + :on-click on-toggle-expand} i/arrow-refactor] + [:button {:class (stl/css :close-btn) + :on-click on-close} i/close-refactor]]] + + + [:div.thumbnails-summary + [:span.counter (tr "labels.num-of-frames" (i18n/c total))] + [:span.buttons + [:span.btn-expand {:on-click on-toggle-expand} i/arrow-down] + [:span.btn-close {:on-click on-close} i/close]]]))) (mf/defc thumbnail-item {::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]} [{:keys [selected? frame on-click index objects page-id thumbnail-data]}] - (let [children-ids (cfh/get-children-ids objects (:id frame)) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + children-ids (cfh/get-children-ids objects (:id frame)) children-bounds (gsh/shapes->rect (concat [frame] (->> children-ids (keep (d/getf objects)))))] - [:div.thumbnail-item {:on-click #(on-click % index)} - [:div.thumbnail-preview - {:class (dom/classnames :selected selected?)} - [:& render/frame-svg {:frame (-> frame - (assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame)))) - (assoc :children-bounds children-bounds)) - :objects objects - :use-thumbnails true}]] - [:div.thumbnail-info - [:span.name {:title (:name frame)} (:name frame)]]])) + + (if new-css-system + [:button {:class (stl/css :thumbnail-item) + :on-click #(on-click % index)} + [:div {:class (stl/css-case :thumbnail-preview true + :selected selected?)} + [:& render/frame-svg {:frame (-> frame + (assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame)))) + (assoc :children-bounds children-bounds)) + :objects objects + :use-thumbnails true}]] + [:div {:class (stl/css :thumbnail-info) + :title (:name frame)} + (:name frame)]] + + + [:div.thumbnail-item {:on-click #(on-click % index)} + [:div.thumbnail-preview + {:class (dom/classnames :selected selected?)} + [:& render/frame-svg {:frame (-> frame + (assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame)))) + (assoc :children-bounds children-bounds)) + :objects objects + :use-thumbnails true}]] + [:div.thumbnail-info + [:span.name {:title (:name frame)} (:name frame)]]]))) (mf/defc thumbnails-panel [{:keys [frames page index show? thumbnail-data] :as props}] - (let [expanded? (mf/use-state false) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + expanded? (mf/use-state false) container (mf/use-ref) objects (:objects page) @@ -109,24 +163,48 @@ (st/emit! (dv/go-to-frame-by-index index)) (when @expanded? (on-close))))] + (if new-css-system + [:section + {:class (stl/css-case :viewer-thumbnails true + :expanded @expanded?) + ;; This is better as an inline-style so it won't make a reflow of every frame inside + :style {:display (when (not show?) "none")} + :ref container} - [:section.viewer-thumbnails - {;; This is better as an inline-style so it won't make a reflow of every frame inside - :style {:display (when (not show?) "none")} - :class (dom/classnames :expanded @expanded?) - :ref container} + [:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not) + :on-close on-close + :total (count frames)}] + [:& thumbnails-content {:expanded? @expanded? + :total (count frames)} + (for [[i frame] (d/enumerate frames)] + [:& thumbnail-item {:index i + :key (dm/str (:id frame) "-" i) + :frame frame + :page-id (:id page) + :objects objects + :on-click on-item-click + :selected? (= i index) + :thumbnail-data thumbnail-data}])]] - [:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not) - :on-close on-close - :total (count frames)}] - [:& thumbnails-content {:expanded? @expanded? - :total (count frames)} - (for [[i frame] (d/enumerate frames)] - [:& thumbnail-item {:index i - :key (dm/str (:id frame) "-" i) - :frame frame - :page-id (:id page) - :objects objects - :on-click on-item-click - :selected? (= i index) - :thumbnail-data thumbnail-data}])]])) + + + [:section.viewer-thumbnails + {;; This is better as an inline-style so it won't make a reflow of every frame inside + :style {:display (when (not show?) "none")} + :class (dom/classnames :expanded @expanded?) + :ref container} + + [:& thumbnails-summary {:on-toggle-expand #(swap! expanded? not) + :on-close on-close + :total (count frames)}] + [:& thumbnails-content {:expanded? @expanded? + :total (count frames)} + (for [[i frame] (d/enumerate frames)] + [:& thumbnail-item {:index i + :key (dm/str (:id frame) "-" i) + :frame frame + :page-id (:id page) + :objects objects + :on-click on-item-click + :selected? (= i index) + :thumbnail-data thumbnail-data}])]]))) diff --git a/frontend/src/app/main/ui/viewer/thumbnails.scss b/frontend/src/app/main/ui/viewer/thumbnails.scss new file mode 100644 index 0000000000..982a9b4687 --- /dev/null +++ b/frontend/src/app/main/ui/viewer/thumbnails.scss @@ -0,0 +1,152 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) KALEIDOS INC + +@use "common/refactor/common-refactor.scss" as *; + +.viewer-thumbnails { + background-color: var(--viewer-background-color); + grid-row: 1 / span 1; + grid-column: 1 / span 1; + overflow: hidden; + display: flex; + flex-direction: column; + z-index: $z-index-10; +} + +.expanded { + grid-row: 1 / span 2; + + .expand-btn svg { + transform: rotate(-90deg); + } +} + +.thumbnails-summary { + display: flex; + justify-content: space-between; + align-items: center; + height: $s-32; + margin: $s-24 $s-24 0 $s-24; +} + +.counter { + @include titleTipography; + color: var(--viewer-thumbnails-control-foreground-color); +} + +.actions { + @include flexRow; + width: $s-60; +} + +.expand-btn, +.close-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } +} + +.expand-btn svg { + transform: rotate(90deg); +} + +.thumbnails-content { + display: grid; + grid-template-columns: $s-40 auto $s-40; + grid-template-rows: auto; +} + +.thumbnails-list-expanded { + grid-column: 1 / span 3; + grid-row: 1 / span 1; + display: flex; + flex-wrap: wrap; + overflow: hidden; +} + +.right-scroll-handler, +.left-scroll-handler { + @extend .button-tertiary; + @include flexCenter; + grid-column: 3 / span 1; + grid-row: 1 / span 1; + width: $s-32; + height: $s-60; + margin: auto 0; + z-index: $z-index-10; + opacity: 0; + &:hover { + opacity: 1; + } + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +} + +.left-scroll-handler { + grid-column: 1 / span 1; + grid-row: 1 / span 1; + svg { + transform: rotate(180deg); + } +} + +.thumbnails-list { + grid-column: 1 / span 3; + grid-row: 1 / span 1; + display: flex; + flex-wrap: nowrap; + overflow: hidden; +} + +.thumbnails-list-inside { + display: flex; + position: relative; +} + +.thumbnail-item { + @include buttonStyle; + display: flex; + flex-direction: column; + padding: $s-16; +} + +.thumbnail-preview { + @include flexCenter; + width: $s-132; + min-height: $s-132; + height: $s-132; + padding: $s-4; + + svg { + width: 100%; + height: 100%; + } + + &.selected { + background-color: var(--viewer-thumbnail-background-color-selected); + border-radius: $br-8; + } + + &:hover { + border: $s-1 solid var(--viewer-thumbnail-border-color); + border-radius: $br-8; + } +} + +.thumbnail-info { + @include titleTipography; + @include textEllipsis; + text-align: center; + color: var(--viewer-thumbnails-control-foreground-color); + padding: $s-8 0; + width: 100%; + max-width: $s-132; +} diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index 4f015168bf..592d614a94 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -61,7 +61,8 @@ (mf/defc workspace-content {::mf/wrap-props false} [{:keys [file layout page-id wglobal]}] - (let [selected (mf/deref refs/selected-shapes) + (let [palete-size (mf/use-state nil) + selected (mf/deref refs/selected-shapes) {:keys [vport] :as wlocal} (mf/deref refs/workspace-local) {:keys [options-mode]} wglobal @@ -78,11 +79,17 @@ (when (and vport (not= size vport)) (st/emit! (dw/update-viewport-size resize-type size))))) + on-resize-palette + (mf/use-fn + (fn [size] + (reset! palete-size size))) + node-ref (use-resize-observer on-resize)] [:* (if new-css-system (when (not hide-ui?) - [:& palette {:layout layout}]) + [:& palette {:layout layout + :on-change-palette-size on-resize-palette}]) [:* (when (and colorpalette? (not hide-ui?)) [:& colorpalette]) @@ -107,7 +114,10 @@ :wlocal wlocal :wglobal wglobal :selected selected - :layout layout}]]] + :layout layout + :palete-size + (when (and (or colorpalette? textpalette?) (not hide-ui?)) + @palete-size)}]]] (when-not hide-ui? [:* diff --git a/frontend/src/app/main/ui/workspace.scss b/frontend/src/app/main/ui/workspace.scss index ab26cbdbbf..1665f7dc3b 100644 --- a/frontend/src/app/main/ui/workspace.scss +++ b/frontend/src/app/main/ui/workspace.scss @@ -12,7 +12,7 @@ @include font-face("worksans", "WorkSans-Bold", bold); // Space mono -@include font-face("spacemono", "SpaceMono-Regular", normal); +@include font-face("robotomono", "RobotoMono-Regular", normal); :global(:root) { --s-4: 0.25rem; diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs index ca7a4d4e82..121ca11d98 100644 --- a/frontend/src/app/main/ui/workspace/comments.cljs +++ b/frontend/src/app/main/ui/workspace/comments.cljs @@ -86,12 +86,10 @@ [:li {:class (dom/classnames :selected (= :pending cshow)) :on-click update-show} [:span.icon i/tick] - [:span.label (tr "labels.hide-resolved-comments")]]]) - - )) + [:span.label (tr "labels.hide-resolved-comments")]]]))) (mf/defc comments-sidebar - [{:keys [users threads page-id]}] + [{:keys [users threads page-id from-viewer]}] (let [new-css-system (mf/use-ctx ctx/new-css-system) threads-map (mf/deref refs/threads-ref) profile (mf/deref refs/profile) @@ -111,8 +109,11 @@ close-section (mf/use-fn - (mf/deps) - #(st/emit! :interrupt (dw/deselect-all true))) + (mf/deps from-viewer) + (fn [] + (if from-viewer + (st/emit! (dcm/update-options {:show-sidebar? false})) + (st/emit! :interrupt (dw/deselect-all true))))) tgroups (->> threads (dcm/group-threads-by-page)) @@ -121,7 +122,6 @@ toggle-mode-selector (mf/use-fn - (mf/deps) (fn [event] (dom/stop-propagation event) (swap! state* not))) @@ -147,18 +147,17 @@ :on-click close-section} i/close-refactor]] - (when (seq tgroups) - [:button {:class (stl/css :mode-dropdown-wrapper) - :on-click toggle-mode-selector} + [:button {:class (stl/css :mode-dropdown-wrapper) + :on-click toggle-mode-selector} - [:span {:class (stl/css :mode-label)} (case (:mode local) - (nil :all) (tr "labels.show-all-comments") - :yours (tr "labels.show-your-comments"))] - [:div {:class (stl/css :icon)} i/arrow-refactor]] + [:span {:class (stl/css :mode-label)} (case (:mode local) + (nil :all) (tr "labels.show-all-comments") + :yours (tr "labels.show-your-comments"))] + [:div {:class (stl/css :icon)} i/arrow-refactor]] - [:& dropdown {:show options? - :on-close #(reset! state* false)} - [:& sidebar-options {:local local}]]) + [:& dropdown {:show options? + :on-close #(reset! state* false)} + [:& sidebar-options {:local local}]] [:div {:class (stl/css :comments-section-content)} diff --git a/frontend/src/app/main/ui/workspace/header.cljs b/frontend/src/app/main/ui/workspace/header.cljs index d9e9ba1247..ed1f369f71 100644 --- a/frontend/src/app/main/ui/workspace/header.cljs +++ b/frontend/src/app/main/ui/workspace/header.cljs @@ -31,10 +31,10 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.router :as rt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def ref:workspace-persistence @@ -393,12 +393,12 @@ :num-files 1})) (->> (rx/of file) - (rx/flat-map + (rx/merge-map (fn [file] (->> (rp/cmd! :has-file-libraries {:file-id (:id file)}) (rx/map #(assoc file :has-libraries? %))))) (rx/reduce conj []) - (rx/subs + (rx/subs! (fn [files] (modal/show! {:type :export diff --git a/frontend/src/app/main/ui/workspace/left_header.cljs b/frontend/src/app/main/ui/workspace/left_header.cljs index 28af7d7ec8..4ff00abcaa 100644 --- a/frontend/src/app/main/ui/workspace/left_header.cljs +++ b/frontend/src/app/main/ui/workspace/left_header.cljs @@ -31,7 +31,7 @@ [app.util.keyboard :as kbd] [app.util.router :as rt] [cuerdas.core :as str] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) ;; --- Header menu and submenus diff --git a/frontend/src/app/main/ui/workspace/left_header.scss b/frontend/src/app/main/ui/workspace/left_header.scss index b89a2c0e26..0e90f6ca43 100644 --- a/frontend/src/app/main/ui/workspace/left_header.scss +++ b/frontend/src/app/main/ui/workspace/left_header.scss @@ -93,7 +93,9 @@ cursor: pointer; } .separator { - height: $s-12; + margin-top: $s-8; + height: $s-4; + border-top: 1px solid $db-secondary; } .shortcut { @extend .shortcut; diff --git a/frontend/src/app/main/ui/workspace/nudge.scss b/frontend/src/app/main/ui/workspace/nudge.scss index 042f64c2fb..ff8f775a28 100644 --- a/frontend/src/app/main/ui/workspace/nudge.scss +++ b/frontend/src/app/main/ui/workspace/nudge.scss @@ -28,9 +28,6 @@ gap: $s-24; @include titleTipography; margin-bottom: $s-24; - .modal-msg { - @include titleTipography; - } .input-wrapper { @extend .input-with-label; label { @@ -40,3 +37,9 @@ } } } + +.modal-msg { + @include titleTipography; + color: var(--modal-text-foreground-color); + line-height: 1.5; +} diff --git a/frontend/src/app/main/ui/workspace/palette.cljs b/frontend/src/app/main/ui/workspace/palette.cljs index 14d8f8d497..431443cfea 100644 --- a/frontend/src/app/main/ui/workspace/palette.cljs +++ b/frontend/src/app/main/ui/workspace/palette.cljs @@ -46,7 +46,7 @@ "paddingRight" "calc(var(--s-4) * 70)"})) (mf/defc palette - [{:keys [layout]}] + [{:keys [layout on-change-palette-size]}] (let [color-palette? (:colorpalette layout) text-palette? (:textpalette layout) workspace-read-only? (mf/use-ctx ctx/workspace-read-only?) @@ -57,10 +57,11 @@ on-select (mf/use-fn #(reset! selected %)) rulers? (mf/deref refs/rules?) {:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]} - (r/use-resize-hook :palette 72 54 80 :y true :bottom) + (r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-palette-size) vport (mf/deref viewport) vport-width (:width vport) + on-resize (mf/use-callback (fn [_] @@ -98,10 +99,11 @@ any-palette? (or color-palette? text-palette?) - size-classname (cond - (<= size 64) (css :small-palette) - (<= size 72) (css :mid-palette) - (<= size 80) (css :big-palette))] + size-classname + (cond + (<= size 64) (css :small-palette) + (<= size 72) (css :mid-palette) + (<= size 80) (css :big-palette))] (mf/with-effect [] (let [key1 (events/listen js/window "resize" on-resize)] diff --git a/frontend/src/app/main/ui/workspace/presence.cljs b/frontend/src/app/main/ui/workspace/presence.cljs index 393e4fa824..cf2af95cf6 100644 --- a/frontend/src/app/main/ui/workspace/presence.cljs +++ b/frontend/src/app/main/ui/workspace/presence.cljs @@ -8,6 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.config :as cfg] [app.main.refs :as refs] [app.main.ui.context :as ctx] @@ -49,15 +50,13 @@ (if new-css-system [:* - (when (and (< 2 num-users) open?) + (when (and (> num-users 2) open?) [:button {:id "users-close" :class (stl/css :active-users-opened) :on-click close-users-widget :on-blur close-users-widget} [:ul {:class (stl/css :active-users-list)} - (when (< 2 num-users) - [:li [:span {:class (stl/css :users-num)} num-users]]) (for [session user-ids] [:& session-widget {:session session @@ -69,7 +68,7 @@ :on-click open-users-widget} [:ul {:class (stl/css :active-users-list)} - (when (< 2 num-users) [:span {:class (stl/css :users-num)} num-users]) + (when (> num-users 2) [:span {:class (stl/css :users-num)} (dm/str "+" (- num-users 2))]) (for [[index session] (d/enumerate first-users)] [:& session-widget {:session session diff --git a/frontend/src/app/main/ui/workspace/right_header.cljs b/frontend/src/app/main/ui/workspace/right_header.cljs index 78b410c610..0e46f05cae 100644 --- a/frontend/src/app/main/ui/workspace/right_header.cljs +++ b/frontend/src/app/main/ui/workspace/right_header.cljs @@ -126,14 +126,14 @@ (tr "workspace.header.zoom-fit-all") [:span {:class (stl/css :shortcuts)} (for [sc (scd/split-sc (sc/get-tooltip :fit-all))] - [:span {:class (dom/classnames (stl/css :shortcut-key) true) + [:span {:class (stl/css :shortcut-key) :key (str "zoom-fit-" sc)} sc])]] [:li {:class (stl/css :zoom-option) :on-click on-zoom-selected} (tr "workspace.header.zoom-selected") [:span {:class (stl/css :shortcuts)} (for [sc (scd/split-sc (sc/get-tooltip :zoom-selected))] - [:span {:class (dom/classnames (stl/css :shortcut-key) true) + [:span {:class (stl/css :shortcut-key) :key (str "zoom-selected-" sc)} sc])]]]]])) ;; --- Header Component @@ -203,6 +203,8 @@ [:& persistence-state-widget] + [:div {:class (stl/css :separator)}] + [:div {:class (stl/css :zoom-section)} [:& zoom-widget-workspace diff --git a/frontend/src/app/main/ui/workspace/right_header.scss b/frontend/src/app/main/ui/workspace/right_header.scss index d5f2d457f6..6b54cb3905 100644 --- a/frontend/src/app/main/ui/workspace/right_header.scss +++ b/frontend/src/app/main/ui/workspace/right_header.scss @@ -11,7 +11,7 @@ align-items: center; min-width: $s-256; padding: $s-8; - gap: $s-2; + gap: $s-8; background-color: var(--panel-background-color); .users-section { position: relative; @@ -19,6 +19,9 @@ max-width: $s-72; padding: $s-4 $s-6; } + .separator { + flex: 1; + } .zoom-section { .zoom-widget { @include buttonStyle; @@ -27,6 +30,7 @@ justify-content: center; height: $s-28; max-width: $s-48; + width: $s-48; border-radius: $br-8; .label { @include titleTipography; diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs index 85d5932a63..9ea7a1f6c8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs @@ -30,7 +30,7 @@ [app.util.keyboard :as kbd] [cuerdas.core :as str] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc color-item diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss index 022a05ab54..aed7ab1197 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss @@ -88,8 +88,6 @@ } .drop-space { height: $s-12; - border-radius: $br-8; - background-color: var(--assets-item-background-color); } .dragging { position: absolute; diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs index 43d329737a..141a83a68f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs @@ -273,11 +273,14 @@ [file-id component] (let [page-id (:main-instance-page component) root-id (:main-instance-id component) - object-id (thc/fmt-object-id file-id page-id root-id "component")] - (if (= file-id (:id @refs/workspace-file)) + object-id (thc/fmt-object-id file-id page-id root-id "component") + current-file? (= file-id (:id @refs/workspace-file))] + + (if current-file? (mf/deref (refs/workspace-thumbnail-by-id object-id)) - (let [thumbnails (dm/get-in @refs/workspace-libraries [file-id :thumbnails (dm/str object-id)])] - thumbnails)))) + (let [libraries @refs/workspace-libraries + thumbnail (dm/get-in libraries [file-id :thumbnails object-id])] + thumbnail)))) (mf/defc component-item-thumbnail "Component that renders the thumbnail image or the original SVG." diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index e9b1c7f776..aa8dbccbc0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -33,7 +33,7 @@ [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def drag-data* (atom {:local? false})) @@ -95,7 +95,7 @@ on-component-click (mf/use-fn - (mf/deps component-id) + (mf/deps component-id on-asset-click) (fn [event] (dom/stop-propagation event) (on-asset-click component-id unselect-all event))) @@ -141,7 +141,7 @@ on-context-menu (mf/use-fn - (mf/deps component-id) + (mf/deps on-context-menu component-id) (partial on-context-menu component-id))] (if ^boolean new-css-system @@ -449,6 +449,7 @@ toggle-list-style (mf/use-ctx cmm/assets-toggle-list-style) selected (:components selected) + selected-full (into #{} (filter #(contains? selected (:id %))) components) multi-components? (> (count selected) 1) multi-assets? (or (seq (:graphics selected)) @@ -519,6 +520,7 @@ (mf/use-fn (mf/deps selected on-clear-selection read-only?) (fn [component-id event] + (dom/stop-propagation event) (dom/prevent-default event) (let [pos (dom/get-client-position event)] diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss index 7415ecf14e..50753ed7ba 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss @@ -9,8 +9,6 @@ .component-group { .drop-space { height: $s-12; - border-radius: $br-8; - background-color: var(--color-foreground-secondary); } .asset-grid { display: grid; @@ -22,7 +20,7 @@ @include flexCenter; position: relative; padding: $s-8; - border: $s-2 solid transparent; + border: $s-4 solid transparent; border-radius: $br-8; background-color: var(--color-foreground-secondary); overflow: hidden; @@ -100,7 +98,7 @@ } &.selected { - border: $s-1 solid var(--assets-item-border-color); + border: $s-4 solid var(--assets-item-border-color); } } .grid-placeholder { diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs index 7291a15442..0bb270ec3a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs @@ -31,7 +31,7 @@ [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc graphics-item diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss index 9a0cc186f2..48b103eb4e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss @@ -9,8 +9,6 @@ .graphics-group { .drop-space { height: $s-12; - border-radius: $br-8; - background-color: var(--color-foreground-secondary); } .asset-grid { display: grid; diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss index 5c5e199ed2..01a0bb172d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss @@ -22,8 +22,6 @@ padding: 0 0 0 $s-4; .drop-space { height: $s-12; - border-radius: $br-8; - background-color: var(--assets-item-background-color); } .grid-placeholder { height: $s-2; diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs index ea01a4baee..400dc5adbf 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.cljs @@ -28,7 +28,7 @@ [app.util.i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [okulary.core :as l] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index 31f7faf2ac..948c5228f4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -198,6 +198,7 @@ :checked (not hide-fill-on-export?) :on-change on-change-show-fill-on-export}]]])])] + ;; OLD [:div.element-set [:div.element-set-title [:span label] 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 f8a77d6b26..2f326dddfb 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 @@ -180,108 +180,109 @@ :on-click on-remove} i/remove-refactor]]] - [:& advanced-options {:class (stl/css :grid-advanced-options) - :visible? open? - :on-close toggle-advanced-options} - ;; square - (when (= :square type) - [:div {:class (stl/css :square-row)} - [:div {:class (stl/css :advanced-row)} - [:& color-row {:color (:color params) - :title (tr "workspace.options.grid.params.color") - :disable-gradient true - :disable-image true - :on-change handle-change-color - :on-detach handle-detach-color}] - [:button {:class (stl/css-case :show-more-options true - :selected show-more-options?) - :on-click toggle-more-options} - i/menu-refactor]] - (when show-more-options? - [:div {:class (stl/css :second-row)} - [:button {:class (stl/css-case :btn-options true - :disabled is-default) - :disabled is-default - :on-click handle-use-default} - [:span (tr "workspace.options.grid.params.use-default")]] - [:button {:class (stl/css-case :btn-options true - :disabled is-default) - :disabled is-default - :on-click handle-set-as-default} - [:span (tr "workspace.options.grid.params.set-default")]]])]) + (when (:display grid) + [:& advanced-options {:class (stl/css :grid-advanced-options) + :visible? open? + :on-close toggle-advanced-options} + ;; square + (when (= :square type) + [:div {:class (stl/css :square-row)} + [:div {:class (stl/css :advanced-row)} + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :disable-image true + :on-change handle-change-color + :on-detach handle-detach-color}] + [:button {:class (stl/css-case :show-more-options true + :selected show-more-options?) + :on-click toggle-more-options} + i/menu-refactor]] + (when show-more-options? + [:div {:class (stl/css :second-row)} + [:button {:class (stl/css-case :btn-options true + :disabled is-default) + :disabled is-default + :on-click handle-use-default} + [:span (tr "workspace.options.grid.params.use-default")]] + [:button {:class (stl/css-case :btn-options true + :disabled is-default) + :disabled is-default + :on-click handle-set-as-default} + [:span (tr "workspace.options.grid.params.set-default")]]])]) - (when (or (= :column type) (= :row type)) - [:div {:class (stl/css :column-row)} - [:div {:class (stl/css :advanced-row)} - [:div {:class (stl/css :orientation-select-wrapper)} - [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :default-value (:type params) - :class (stl/css :orientation-select) - :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} - {:value :left :label (if (= type :row) - (tr "workspace.options.grid.params.type.top") - (tr "workspace.options.grid.params.type.left"))} - {:value :center :label (tr "workspace.options.grid.params.type.center")} - {:value :right :label (if (= type :row) - (tr "workspace.options.grid.params.type.bottom") - (tr "workspace.options.grid.params.type.right"))}] - :on-change (handle-change :params :type)}]] + (when (or (= :column type) (= :row type)) + [:div {:class (stl/css :column-row)} + [:div {:class (stl/css :advanced-row)} + [:div {:class (stl/css :orientation-select-wrapper)} + [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value (:type params) + :class (stl/css :orientation-select) + :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} + {:value :left :label (if (= type :row) + (tr "workspace.options.grid.params.type.top") + (tr "workspace.options.grid.params.type.left"))} + {:value :center :label (tr "workspace.options.grid.params.type.center")} + {:value :right :label (if (= type :row) + (tr "workspace.options.grid.params.type.bottom") + (tr "workspace.options.grid.params.type.right"))}] + :on-change (handle-change :params :type)}]] - [:div {:class (stl/css :color-wrapper)} - [:& color-row {:color (:color params) - :title (tr "workspace.options.grid.params.color") - :disable-gradient true - :disable-image true - :on-change handle-change-color - :on-detach handle-detach-color}]]] + [:div {:class (stl/css :color-wrapper)} + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :disable-image true + :on-change handle-change-color + :on-detach handle-detach-color}]]] - [:div {:class (stl/css :advanced-row)} - [:div {:class (stl/css :height) - :title (if (= :row type) - (tr "workspace.options.grid.params.height") - (tr "workspace.options.grid.params.width"))} - [:span {:class (stl/css :icon-text)} - (if (= :row type) - "H" - "W")] - [:> numeric-input* {:placeholder "Auto" - :on-change handle-change-item-length - :nillable true - :className (stl/css :numeric-input) - :value (or (:item-length params) "")}]] + [:div {:class (stl/css :advanced-row)} + [:div {:class (stl/css :height) + :title (if (= :row type) + (tr "workspace.options.grid.params.height") + (tr "workspace.options.grid.params.width"))} + [:span {:class (stl/css :icon-text)} + (if (= :row type) + "H" + "W")] + [:> numeric-input* {:placeholder "Auto" + :on-change handle-change-item-length + :nillable true + :className (stl/css :numeric-input) + :value (or (:item-length params) "")}]] - [:div {:class (stl/css :gutter) - :title (tr "workspace.options.grid.params.gutter")} - [:span {:class (stl/css-case :icon true - :rotated (= type :row))} i/gap-horizontal-refactor] - [:> numeric-input* {:placeholder "0" - :on-change (handle-change :params :gutter) - :nillable true - :className (stl/css :numeric-input) - :value (or (:gutter params) 0)}]] + [:div {:class (stl/css :gutter) + :title (tr "workspace.options.grid.params.gutter")} + [:span {:class (stl/css-case :icon true + :rotated (= type :row))} i/gap-horizontal-refactor] + [:> numeric-input* {:placeholder "0" + :on-change (handle-change :params :gutter) + :nillable true + :className (stl/css :numeric-input) + :value (or (:gutter params) 0)}]] - [:div {:class (stl/css :margin) - :title (tr "workspace.options.grid.params.margin")} - [:span {:class (stl/css-case :icon true - :rotated (= type :column))} i/grid-margin-refactor] - [:> numeric-input* {:placeholder "0" - :on-change (handle-change :params :margin) - :nillable true - :className (stl/css :numeric-input) - :value (or (:margin params) 0)}]] + [:div {:class (stl/css :margin) + :title (tr "workspace.options.grid.params.margin")} + [:span {:class (stl/css-case :icon true + :rotated (= type :column))} i/grid-margin-refactor] + [:> numeric-input* {:placeholder "0" + :on-change (handle-change :params :margin) + :nillable true + :className (stl/css :numeric-input) + :value (or (:margin params) 0)}]] - [:button {:class (stl/css-case :show-more-options true - :selected show-more-options?) - :on-click toggle-more-options} - i/menu-refactor] - (when show-more-options? - [:div {:class (stl/css :more-options)} - [:button {:disabled is-default - :class (stl/css :option-btn) - :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] - [:button {:disabled is-default - :class (stl/css :option-btn) - :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]])]])]] + [:button {:class (stl/css-case :show-more-options true + :selected show-more-options?) + :on-click toggle-more-options} + i/menu-refactor] + (when show-more-options? + [:div {:class (stl/css :more-options)} + [:button {:disabled is-default + :class (stl/css :option-btn) + :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] + [:button {:disabled is-default + :class (stl/css :option-btn) + :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]])]])])] [:div.grid-option [:div.grid-option-main {:style {:display (when open? "none")}} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss index 78b905d5e3..4e7d12708c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.scss @@ -25,6 +25,7 @@ } .help-content { + padding: $s-20; .help-group { margin-bottom: $s-40; .interactions-help-icon { diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 07d5f2c2fd..8138f0a3e4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -1389,10 +1389,6 @@ :class (stl/css-case :title-spacing-layout (not has-layout?))} (if (and (not multiple) (:layout values)) [:div {:class (stl/css :title-actions)} - [:button {:class (stl/css :remove-layout) - :on-click on-remove-layout} - i/remove-refactor] - (when ^boolean grid-enabled? [:* [:button {:class (stl/css :add-layout) @@ -1402,7 +1398,11 @@ [:& dropdown {:show show-layout-dropdown? :on-close handle-close-layout-options} [:div {:class (stl/css :layout-options)} [:button {:class (stl/css :layout-option) :on-click set-flex} "Flex layout"] - [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]])] + [:button {:class (stl/css :layout-option) :on-click set-grid} "Grid layout"]]]]) + + [:button {:class (stl/css :remove-layout) + :on-click on-remove-layout} + i/remove-refactor]] [:div {:class (stl/css :title-actions)} (if ^boolean grid-enabled? diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index 08a30d7093..c5adb9a4fc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -221,14 +221,16 @@ :select-on-focus select-on-focus :on-blur on-blur}]] - [:div {:class (stl/css :select-wrapper)} + [:div {:class (stl/css :select-wrapper) + :data-test "stroke.alignment"} [:& select {:default-value stroke-alignment :options stroke-alignment-options :on-change on-alignment-change}]] (when-not disable-stroke-style - [:div {:class (stl/css :select-wrapper)} + [:div {:class (stl/css :select-wrapper) + :data-test "stroke.style"} [:& select {:default-value stroke-style :options stroke-style-options diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs index 40337bdc55..4b5e528467 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs @@ -50,11 +50,21 @@ [:& layer-menu {:ids ids :type type :values layer-values}] + [:& measures-menu {:ids ids :type type :values measure-values :shape shape}] - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids ids + :values constraint-values}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options @@ -71,10 +81,6 @@ :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu {:ids ids - :values constraint-values}]) - [:& fill-menu {:ids ids :type type :values (select-keys shape fill-attrs)}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs index bf2128d878..d37d6a4de8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs @@ -52,11 +52,21 @@ [:& layer-menu {:ids ids :type type :values layer-values}] + [:& measures-menu {:ids ids :type type :values measure-values :shape shape}] - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids ids + :values constraint-values}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options @@ -72,9 +82,6 @@ :is-flex-parent? is-flex-parent? :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu {:ids ids - :values constraint-values}]) [:& fill-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 6a3110123e..e792751a2b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -62,11 +62,18 @@ :values measure-values :type type :shape shape}] + [:& component-menu {:shapes [shape]}] - (when (or (not is-layout-child?) is-layout-child-absolute?) + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) [:& constraints-menu {:ids ids :values constraint-values}]) - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index 2a65a3e692..2b661b1096 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -74,7 +74,15 @@ [:& layer-menu {:type type :ids layer-ids :values layer-values}] [:& measures-menu {:type type :ids measure-ids :values measure-values :shape shape}] [:& component-menu {:shapes [shape]}] ;;remove this in components-v2 - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids constraint-ids :values constraint-values}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options @@ -91,9 +99,6 @@ :is-grid-parent? is-grid-parent? :values layout-item-values}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu {:ids constraint-ids :values constraint-values}]) - (when-not (empty? fill-ids) [:& fill-menu {:type type :ids fill-ids :values fill-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs index 0e08630bce..6ae27dc027 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs @@ -52,11 +52,21 @@ [:& layer-menu {:ids ids :type type :values layer-values}] + [:& measures-menu {:ids ids :type type :values measure-values :shape shape}] - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids ids + :values constraint-values}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options @@ -73,12 +83,6 @@ :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu {:ids ids - :values constraint-values}]) - - - [:& fill-menu {:ids ids :type type :values fill-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 174e6f6c67..8309844a76 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -359,8 +359,14 @@ (when-not (empty? components) [:& component-menu {:shapes components}]) - [:& layout-container-menu {:type type :ids layout-container-ids :values layout-container-values :multiple true}] + (when-not (or (empty? constraint-ids) ^boolean is-layout-child?) + [:& constraints-menu {:ids constraint-ids :values constraint-values}]) + [:& layout-container-menu + {:type type + :ids layout-container-ids + :values layout-container-values + :multiple true}] (when (or is-layout-child? has-flex-layout-container?) [:& layout-item-menu @@ -372,9 +378,6 @@ :is-grid-parent? is-grid-parent? :values layout-item-values}]) - (when-not (or (empty? constraint-ids) is-layout-child?) - [:& constraints-menu {:ids constraint-ids :values constraint-values}]) - (when-not (empty? text-ids) [:& ot/text-menu {:type type :ids text-ids :values text-values}]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs index 776e7f3272..b803916beb 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs @@ -56,7 +56,16 @@ :type type :values measure-values :shape shape}] - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids ids + :values constraint-values}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options @@ -72,9 +81,6 @@ :is-flex-parent? is-flex-parent? :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu {:ids ids - :values constraint-values}]) [:& fill-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 33fbc28627..aed851d0f0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -59,6 +59,11 @@ :type type :values measure-values :shape shape}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids ids + :values constraint-values}]) + [:& layout-container-menu {:type type :ids ids @@ -80,13 +85,6 @@ :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not ^boolean is-layout-child?) - ^boolean is-layout-child-absolute?) - [:& constraints-menu {:ids ids - :values constraint-values}]) - - - [:& fill-menu {:ids ids :type type :values fill-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index 66ff3f5743..87a2620e2c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -128,12 +128,21 @@ :type type :values measure-values :shape shape}] - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu {:ids ids + :values constraint-values}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) - [:& grid-cell/options - {:shape (first parents) - :cell (ctl/get-cell-by-shape-id (first parents) (first ids))}]) + [:& grid-cell/options + {:shape (first parents) + :cell (ctl/get-cell-by-shape-id (first parents) (first ids))}]) (when is-layout-child? [:& layout-item-menu @@ -145,10 +154,6 @@ :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu {:ids ids - :values constraint-values}]) - [:& fill-menu {:ids ids :type type :values fill-values}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 4fa04b35f0..990c8bfe74 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -91,12 +91,23 @@ :type type :values (select-keys shape measure-attrs) :shape shape}] - [:& layout-container-menu {:type type :ids [(:id shape)] :values layout-container-values :multiple false}] + + (when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?) + [:& constraints-menu + {:ids ids + :values (select-keys shape constraint-attrs)}]) + + [:& layout-container-menu + {:type type + :ids [(:id shape)] + :values layout-container-values + :multiple false}] (when (and (= (count ids) 1) is-layout-child? is-grid-parent?) [:& grid-cell/options {:shape (first parents) :cell (ctl/get-cell-by-shape-id (first parents) (first ids))}]) + (when is-layout-child? [:& layout-item-menu {:ids ids @@ -107,13 +118,6 @@ :is-grid-parent? is-grid-parent? :shape shape}]) - (when (or (not is-layout-child?) is-layout-child-absolute?) - [:& constraints-menu - {:ids ids - :values (select-keys shape constraint-attrs)}]) - - - [:& text-menu {:ids ids :type type diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index 5d679fe36b..6933fb1c85 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -46,7 +46,7 @@ [app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]] [app.main.ui.workspace.viewport.widgets :as widgets] [app.util.debug :as dbg] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) ;; --- Viewport @@ -69,7 +69,7 @@ selected)) (mf/defc viewport - [{:keys [selected wglobal wlocal layout file] :as props}] + [{:keys [selected wglobal wlocal layout file palete-size] :as props}] (let [;; When adding data from workspace-local revisit `app.main.ui.workspace` to check ;; that the new parameter is sent {:keys [edit-path @@ -535,7 +535,8 @@ [:& scroll-bars/viewport-scrollbars {:objects base-objects :zoom zoom - :vbox vbox}] + :vbox vbox + :bottom-padding (when palete-size (+ palete-size 8))}] (when-not hide-ui? [:& rules/rules diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 82b983c0be..64fe00e77f 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -30,7 +30,7 @@ [app.util.object :as obj] [app.util.timers :as timers] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index 6fd05d586c..f1cb78ee2e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -17,7 +17,7 @@ [app.main.store :as st] [app.util.dom :as dom] [app.util.mouse :as mse] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -157,7 +157,7 @@ (rx/filter mse/pointer-event?) (rx/filter #(= :viewport (mse/get-pointer-source %))) (rx/map mse/get-pointer-position) - (rx/subs + (rx/subs! (fn [pt] (case @moving-point :from-p (when on-change-start (on-change-start pt)) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 2a2c0aa9c2..8066696b00 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -196,13 +196,13 @@ {::mf/wrap-props false} [props] (let [shape (unchecked-get props "shape") - x (unchecked-get props "x") y (unchecked-get props "y") width (unchecked-get props "width") height (unchecked-get props "height") handler (unchecked-get props "handler") + objects (mf/deref refs/workspace-page-objects) {cell-id :id} (unchecked-get props "cell") {:keys [row column row-span column-span]} (get-in shape [:layout-grid-cells cell-id]) @@ -237,7 +237,7 @@ shape (-> (ctl/resize-cell-area shape row column new-row new-column new-row-span new-column-span) - (ctl/assign-cells)) + (ctl/assign-cells objects)) modifiers (-> (ctm/empty) diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index d4fd7b19ad..c195917cfe 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -32,7 +32,8 @@ [app.util.dom :as dom] [app.util.globals :as globals] [app.util.keyboard :as kbd] - [beicon.core :as rx] + [beicon.v2.core :as rx] + [beicon.v2.operators :as rxo] [goog.events :as events] [rumext.v2 :as mf]) (:import goog.events.EventType)) @@ -112,7 +113,7 @@ ^boolean (kbd/underscore? kevent) ^boolean (kbd/equals? kevent) ^boolean (kbd/plus? kevent)))) - (rx/dedupe))) + (rx/pipe (rxo/distinct-contiguous)))) kbd-shift-s (mf/with-memo [] @@ -120,7 +121,7 @@ (rx/filter kbd/shift-key?) (rx/filter (complement kbd/editing-event?)) (rx/map kbd/key-down-event?) - (rx/dedupe))) + (rx/pipe (rxo/distinct-contiguous)))) kbd-z-s (mf/with-memo [] @@ -128,7 +129,7 @@ (rx/filter kbd/z?) (rx/filter (complement kbd/editing-event?)) (rx/map kbd/key-down-event?) - (rx/dedupe)))] + (rx/pipe (rxo/distinct-contiguous))))] (hooks/use-stream ms/keyboard-alt (partial reset! alt*)) (hooks/use-stream ms/keyboard-space (partial reset! space*)) 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 36601aaf41..fb295276f0 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -18,7 +18,7 @@ [app.util.dom :as dom] [app.util.keyboard :as kbd] [app.util.object :as obj] - [beicon.core :as rx] + [beicon.v2.core :as rx] [goog.events :as events] [rumext.v2 :as mf]) (:import goog.events.EventType)) @@ -144,7 +144,7 @@ (assoc result :styles styles))) (rx/mapcat thr/render-node) - (rx/subs (fn [image-bitmap] + (rx/subs! (fn [image-bitmap] (.drawImage canvas-context image-bitmap 0 0) (let [width (unchecked-get canvas "width") height (unchecked-get canvas "height") @@ -168,7 +168,7 @@ (fn [] (let [sub (->> update-str (rx/debounce 10) - (rx/subs handle-draw-picker-canvas))] + (rx/subs! handle-draw-picker-canvas))] #(rx/dispose! sub)))) (mf/use-effect diff --git a/frontend/src/app/main/ui/workspace/viewport/presence.cljs b/frontend/src/app/main/ui/workspace/viewport/presence.cljs index 0aa64ade46..bf4af1a0a5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/presence.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/presence.cljs @@ -9,7 +9,7 @@ [app.main.refs :as refs] [app.util.time :as dt] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [rumext.v2 :as mf])) diff --git a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs index 6ba171943f..1dd7a6f79e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs @@ -28,7 +28,7 @@ (mf/defc viewport-scrollbars {::mf/wrap [mf/memo]} - [{:keys [objects zoom vbox]}] + [{:keys [objects zoom vbox bottom-padding]}] (let [v-scrolling? (mf/use-state false) h-scrolling? (mf/use-state false) @@ -56,6 +56,11 @@ (cfh/get-immediate-children) (gsh/shapes->rect))) + ;; Padding for bottom palette + vbox (cond-> vbox + (some? bottom-padding) + (update :height - (/ bottom-padding zoom))) + inv-zoom (/ 1 zoom) vbox-height (- (:height vbox) (* inv-zoom scroll-height)) vbox-width (- (:width vbox) (* inv-zoom scroll-width)) @@ -65,6 +70,7 @@ (max 0) (* vbox-height) (/ (:height base-objects-rect))) + ;; left space hidden because of the scroll left-offset (-> (- vbox-x (:x base-objects-rect)) (max 0) diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs index d379308393..f0739fbc2c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs @@ -15,7 +15,7 @@ [app.main.refs :as refs] [app.main.snap :as ams] [app.main.ui.formats :as fmt] - [beicon.core :as rx] + [beicon.v2.core :as rx] [clojure.set :as set] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -256,7 +256,7 @@ ;; know it is a static value and will not go to ;; change (rx/switch-map (partial query-worker page-id coord)) - (rx/subs (fn [[lt-shapes gt-shapes]] + (rx/subs! (fn [[lt-shapes gt-shapes]] (reset! lt-shapes* lt-shapes) (reset! gt-shapes* gt-shapes))))] ;; On unmount dispose diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index d7f891a238..a65ab03668 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -13,7 +13,7 @@ [app.common.geom.snap :as sp] [app.common.types.shape.layout :as ctl] [app.main.snap :as snap] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (def ^:private line-color "var(--color-snap)") @@ -56,12 +56,12 @@ frame-id (snap/snap-frame-id shapes)] (->> (rx/of bounds) - (rx/flat-map + (rx/merge-map (fn [bounds] (->> (sp/rect->snap-points bounds) (map #(vector frame-id %))))) - (rx/flat-map + (rx/merge-map (fn [[frame-id point]] (->> (snap/get-snap-points page-id frame-id remove-snap? zoom point coord) (rx/map #(mapcat second %)) @@ -124,7 +124,7 @@ (fn [result] (apply d/concat-vec (seq result)))) - (rx/subs + (rx/subs! (fn [data] (let [rs (filter (fn [[_ snaps _]] (> (count snaps) 0)) data)] (reset! state rs)))))] diff --git a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs index cba3e74a2e..c3efb32784 100644 --- a/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/top_bar.cljs @@ -35,9 +35,7 @@ [:& i18n/tr-html {:tag-name "span" :label "workspace.top-bar.read-only"}]] [:button {:class (stl/css :done-btn) - :on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")] - [:button {:class (stl/css :close-btn) - :on-click handle-close-view-mode} i/close-refactor]]] + :on-click handle-close-view-mode} (tr "workspace.top-bar.read-only.done")]]] ;; OLD [:div.viewport-actions diff --git a/frontend/src/app/main/ui/workspace/viewport/top_bar.scss b/frontend/src/app/main/ui/workspace/viewport/top_bar.scss index 67114b50e4..4b615961a1 100644 --- a/frontend/src/app/main/ui/workspace/viewport/top_bar.scss +++ b/frontend/src/app/main/ui/workspace/viewport/top_bar.scss @@ -22,7 +22,7 @@ margin-left: -50%; padding: $s-8; pointer-events: initial; - width: $s-512; + width: $s-400; } .viewport-actions-title { diff --git a/frontend/src/app/rasterizer.cljs b/frontend/src/app/rasterizer.cljs index 3244b14302..d6eeb474ca 100644 --- a/frontend/src/app/rasterizer.cljs +++ b/frontend/src/app/rasterizer.cljs @@ -17,7 +17,7 @@ [app.util.http :as http] [app.util.object :as obj] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str])) (log/set-level! :info) @@ -229,7 +229,7 @@ (when (and (some? payload) (= scope "penpot/rasterizer")) (->> (render payload) - (rx/subs (partial send-success! id) + (rx/subs! (partial send-success! id) (partial send-failure! id)))))))) (defn- listen diff --git a/frontend/src/app/render.cljs b/frontend/src/app/render.cljs index 1bb1d13879..f3f13a0985 100644 --- a/frontend/src/app/render.cljs +++ b/frontend/src/app/render.cljs @@ -21,11 +21,11 @@ [app.main.store :as st] [app.util.dom :as dom] [app.util.globals :as glob] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [garden.core :refer [css]] [okulary.core :as l] - [potok.core :as ptk] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (log/setup! {:app :info}) diff --git a/frontend/src/app/util/array.cljs b/frontend/src/app/util/array.cljs index fa128c37e4..2c85375e9e 100644 --- a/frontend/src/app/util/array.cljs +++ b/frontend/src/app/util/array.cljs @@ -6,10 +6,15 @@ (ns app.util.array "A collection of helpers for work with javascript arrays." - (:refer-clojure :exclude [conj!])) + (:refer-clojure :exclude [conj! conj])) + +(defn conj + "A conj like function for js arrays." + [a v] + (js* "[...~{}, ~{}]" a v)) (defn conj! - "A conj like function for js arrays." + "A conj! like function for js arrays." [a v] (.push ^js a v) a) diff --git a/frontend/src/app/util/cache.cljs b/frontend/src/app/util/cache.cljs index fcb54c9174..61cd08adcc 100644 --- a/frontend/src/app/util/cache.cljs +++ b/frontend/src/app/util/cache.cljs @@ -7,7 +7,7 @@ (ns app.util.cache (:require [app.util.time :as dt] - [beicon.core :as rx])) + [beicon.v2.core :as rx])) (defonce cache (atom {})) (defonce pending (atom {})) diff --git a/frontend/src/app/util/http.cljs b/frontend/src/app/util/http.cljs index 35c8ae485d..220128bdf6 100644 --- a/frontend/src/app/util/http.cljs +++ b/frontend/src/app/util/http.cljs @@ -15,7 +15,7 @@ [app.util.globals :as globals] [app.util.time :as dt] [app.util.webapi :as wapi] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [promesa.core :as p])) @@ -58,7 +58,7 @@ :or {mode :cors headers {} credentials "same-origin"}}] - (rx/Observable.create + (rx/create (fn [subscriber] (let [controller (js/AbortController.) signal (.-signal ^js controller) @@ -172,7 +172,7 @@ (p/create (fn [resolve reject] (->> (rx/take 1 observable) - (rx/subs resolve reject))))) + (rx/subs! resolve reject))))) (defn fetch-data-uri ([uri] diff --git a/frontend/src/app/util/router.cljs b/frontend/src/app/util/router.cljs index 2fd4b738d5..83284596a1 100644 --- a/frontend/src/app/util/router.cljs +++ b/frontend/src/app/util/router.cljs @@ -12,9 +12,9 @@ [app.util.browser-history :as bhistory] [app.util.dom :as dom] [app.util.timers :as ts] - [beicon.core :as rx] + [beicon.v2.core :as rx] [goog.events :as e] - [potok.core :as ptk] + [potok.v2.core :as ptk] [reitit.core :as r])) ;; --- Router API @@ -159,4 +159,4 @@ (bhistory/disable! history) (e/unlistenByKey key))))) (rx/take-until stoper) - (rx/subs #(on-change router %))))))) + (rx/subs! #(on-change router %))))))) diff --git a/frontend/src/app/util/rxops.cljs b/frontend/src/app/util/rxops.cljs new file mode 100644 index 0000000000..f085d037e7 --- /dev/null +++ b/frontend/src/app/util/rxops.cljs @@ -0,0 +1,72 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.util.rxops + (:require + [beicon.v2.core :as rx])) + +(defn- throttle-fn + [delay f] + (let [state + #js {:lastExecTime 0 + :timeoutId nil + :context nil + :args nil} + + execute-fn + (fn [] + (let [context (.-context ^js state) + args (.-args ^js state)] + (.apply f context args) + (set! (.-lastExecTime state) (js/Date.now)) + (set! (.-timeoutId state) nil))) + + wrapped-fn + (fn [] + (let [ctime (js/Date.now) + ltime (.-lastExecTime ^js state) + args (js-arguments)] + + (this-as this + (set! (.-context state) this) + (set! (.-args state) args)) + + (let [timeout-id (.-timeoutId state)] + (if (>= (- ctime ltime) delay) + (do + (when ^boolean timeout-id + (js/clearTimeout timeout-id) + (set! (.-timeoutId state) nil)) + (execute-fn)) + + (when-not ^boolean timeout-id + (set! (.-timeoutId state) + (js/setTimeout execute-fn (- delay ctime ltime))))))))] + + (specify! wrapped-fn + rx/IDisposable + (-dispose [_] + (js/clearTimeout (.-timeoutId state)) + (set! (.-lastExecTime state) 0) + (set! (.-timeoutId state) nil))))) + + +(defn throttle + "High performance rxjs throttle operation. It does not saturates the + macro-task queue of the js runtime on long burst of mouse + movements." + [delay] + (fn [source] + (rx/create + (fn [subs] + (let [next-fn (throttle-fn delay (partial rx/push! subs)) + error-fn (fn [cause] + (rx/dispose! next-fn) + (rx/error! subs cause)) + end-fn (fn [] + (rx/dispose! next-fn) + (rx/end! subs))] + (rx/sub! source next-fn error-fn end-fn)))))) diff --git a/frontend/src/app/util/sse.cljs b/frontend/src/app/util/sse.cljs index 222e1bda7f..0913f052ae 100644 --- a/frontend/src/app/util/sse.cljs +++ b/frontend/src/app/util/sse.cljs @@ -7,7 +7,7 @@ (ns app.util.sse (:require ["eventsource-parser/stream" :as sse] - [beicon.core :as rx])) + [beicon.v2.core :as rx])) (defn create-stream [^js/ReadableStream stream] diff --git a/frontend/src/app/util/theme.cljs b/frontend/src/app/util/theme.cljs index e962bcbf1d..a31c79f832 100644 --- a/frontend/src/app/util/theme.cljs +++ b/frontend/src/app/util/theme.cljs @@ -11,7 +11,7 @@ [app.config :as cfg] [app.util.dom :as dom] [app.util.storage :refer [storage]] - [beicon.core :as rx] + [beicon.v2.core :as rx] [rumext.v2 :as mf])) (defonce theme (get @storage ::theme cfg/default-theme)) diff --git a/frontend/src/app/util/timers.cljs b/frontend/src/app/util/timers.cljs index 0e5a01c33d..f3e4bd436b 100644 --- a/frontend/src/app/util/timers.cljs +++ b/frontend/src/app/util/timers.cljs @@ -7,7 +7,7 @@ (ns app.util.timers (:require [app.common.data :as d] - [beicon.core :as rx] + [beicon.v2.core :as rx] [promesa.core :as p])) (defn schedule diff --git a/frontend/src/app/util/webapi.cljs b/frontend/src/app/util/webapi.cljs index 97994f2406..9d1ba5c2e1 100644 --- a/frontend/src/app/util/webapi.cljs +++ b/frontend/src/app/util/webapi.cljs @@ -11,7 +11,7 @@ [app.common.exceptions :as ex] [app.common.logging :as log] [app.util.object :as obj] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [promesa.core :as p])) @@ -247,7 +247,7 @@ (fn [blob] (->> (read-file-as-data-url blob) (rx/catch (fn [err] (reject err))) - (rx/subs (fn [result] (resolve result))))))) + (rx/subs! (fn [result] (resolve result))))))) (catch :default e (reject e)))))) diff --git a/frontend/src/app/util/websocket.cljs b/frontend/src/app/util/websocket.cljs index 61187b2a6c..016eb9c0ae 100644 --- a/frontend/src/app/util/websocket.cljs +++ b/frontend/src/app/util/websocket.cljs @@ -8,7 +8,7 @@ "A interface to webworkers exposed functionality." (:require [app.common.transit :as t] - [beicon.core :as rx] + [beicon.v2.core :as rx] [goog.events :as ev]) (:import goog.net.WebSocket diff --git a/frontend/src/app/util/worker.cljs b/frontend/src/app/util/worker.cljs index 2100b58508..f1b27cc7c6 100644 --- a/frontend/src/app/util/worker.cljs +++ b/frontend/src/app/util/worker.cljs @@ -10,7 +10,7 @@ [app.common.uuid :as uuid] [app.util.object :as obj] [app.worker.messages :as wm] - [beicon.core :as rx])) + [beicon.v2.core :as rx])) (declare handle-response) (defrecord Worker [instance stream]) diff --git a/frontend/src/app/util/zip.cljs b/frontend/src/app/util/zip.cljs index fbb0b27872..bf1995a690 100644 --- a/frontend/src/app/util/zip.cljs +++ b/frontend/src/app/util/zip.cljs @@ -9,7 +9,7 @@ (:require ["jszip" :as zip] [app.util.http :as http] - [beicon.core :as rx] + [beicon.v2.core :as rx] [promesa.core :as p])) (defn compress-files @@ -29,7 +29,7 @@ :response-type :blob :method :get}) (rx/map :body) - (rx/flat-map zip/loadAsync))) + (rx/merge-map zip/loadAsync))) (defn- process-file [entry path type] @@ -65,4 +65,4 @@ (.forEach zip get-file) (->> (rx/from (p/all @promises)) - (rx/flat-map identity)))) + (rx/merge-map identity)))) diff --git a/frontend/src/app/worker.cljs b/frontend/src/app/worker.cljs index 9ee1e1e698..8ca98681b3 100644 --- a/frontend/src/app/worker.cljs +++ b/frontend/src/app/worker.cljs @@ -17,7 +17,7 @@ [app.worker.selection] [app.worker.snaps] [app.worker.thumbnails] - [beicon.core :as rx] + [beicon.v2.core :as rx] [promesa.core :as p])) (log/setup! {:app :info}) @@ -130,7 +130,7 @@ ;; 1ms debounce, after 1ms without messages will process the buffer (rx/debounce 1) - (rx/subs (fn [[messages dropped last]] + (rx/subs! (fn [[messages dropped last]] ;; Send back the dropped messages replies (doseq [msg dropped] (drop-message msg)) diff --git a/frontend/src/app/worker/export.cljs b/frontend/src/app/worker/export.cljs index 43f8a5e9a8..7425135f35 100644 --- a/frontend/src/app/worker/export.cljs +++ b/frontend/src/app/worker/export.cljs @@ -20,7 +20,7 @@ [app.util.webapi :as wapi] [app.util.zip :as uz] [app.worker.impl :as impl] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str])) (def ^:const current-version 2) @@ -139,7 +139,7 @@ (->> (rx/from (vals media)) (rx/map #(assoc % :file-id file-id)) - (rx/flat-map + (rx/merge-map (fn [media] (let [file-path (str/concat file-id "/media/" (:id media) (cm/mtype->extension (:mtype media)))] (->> (http/send! @@ -345,44 +345,44 @@ render-stream (->> files-stream - (rx/flat-map vals) - (rx/flat-map process-pages) + (rx/merge-map vals) + (rx/merge-map process-pages) (rx/observe-on :async) - (rx/flat-map get-page-data) + (rx/merge-map get-page-data) (rx/share)) colors-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/map #(vector (:id %) (get-in % [:data :colors]))) (rx/filter #(d/not-empty? (second %))) (rx/map parse-library-color)) typographies-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/map #(vector (:id %) (get-in % [:data :typographies]))) (rx/filter #(d/not-empty? (second %))) (rx/map parse-library-typographies)) media-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/map #(vector (:id %) (get-in % [:data :media]))) (rx/filter #(d/not-empty? (second %))) - (rx/flat-map parse-library-media)) + (rx/merge-map parse-library-media)) components-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/filter #(d/not-empty? (ctkl/components-seq (:data %)))) - (rx/flat-map parse-library-components)) + (rx/merge-map parse-library-components)) deleted-components-stream (->> files-stream - (rx/flat-map vals) + (rx/merge-map vals) (rx/filter #(d/not-empty? (get-in % [:data :deleted-components]))) - (rx/flat-map parse-deleted-components)) + (rx/merge-map parse-deleted-components)) pages-stream (->> render-stream @@ -405,7 +405,7 @@ typographies-stream) (rx/reduce conj []) (rx/with-latest-from files-stream) - (rx/flat-map (fn [[data files]] + (rx/merge-map (fn [[data files]] (->> (uz/compress-files data) (rx/map #(vector (get files file-id) %))))))))) diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index bccb975ea0..96bd5d7b93 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -26,7 +26,7 @@ [app.util.webapi :as wapi] [app.util.zip :as uz] [app.worker.impl :as impl] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cuerdas.core :as str] [tubax.core :as tubax])) @@ -147,7 +147,7 @@ libraries (->> context :libraries (mapv resolve))] (->> (rx/from libraries) (rx/map #(hash-map :file-id file-id :library-id %)) - (rx/flat-map (partial rp/cmd! :link-file-to-library))))) + (rx/merge-map (partial rp/cmd! :link-file-to-library))))) (defn send-changes "Creates batches of changes to be sent to the backend" @@ -197,7 +197,7 @@ :content blob :is-local true})) (rx/tap #(progress! context :upload-media name)) - (rx/flat-map #(rp/cmd! :upload-file-media-object %)))) + (rx/merge-map #(rp/cmd! :upload-file-media-object %)))) (defn resolve-text-content [node context] (let [resolve (:resolve context)] @@ -408,7 +408,7 @@ (rx/reduce conj {}))] (->> pre-process-images - (rx/flat-map + (rx/merge-map (fn [pre-proc] (->> (rx/from nodes) (rx/filter cip/shape?) @@ -510,7 +510,7 @@ (assoc :id (resolve id)))] (fb/add-library-color file color)))] (->> (get-file context :colors) - (rx/flat-map (comp d/kebab-keys cip/string->uuid)) + (rx/merge-map (comp d/kebab-keys cip/string->uuid)) (rx/reduce add-color file))) (rx/of file))) @@ -520,7 +520,7 @@ (if (:has-typographies context) (let [resolve (:resolve context)] (->> (get-file context :typographies) - (rx/flat-map (comp d/kebab-keys cip/string->uuid)) + (rx/merge-map (comp d/kebab-keys cip/string->uuid)) (rx/map (fn [[id typography]] (-> typography (d/kebab-keys) @@ -534,7 +534,7 @@ (if (:has-media context) (let [resolve (:resolve context)] (->> (get-file context :media-list) - (rx/flat-map (comp d/kebab-keys cip/string->uuid)) + (rx/merge-map (comp d/kebab-keys cip/string->uuid)) (rx/mapcat (fn [[id media]] (let [media (assoc media :id (resolve id))] @@ -562,7 +562,7 @@ (filter #(= :symbol (:tag %)))))] (->> (get-file context :components) - (rx/flat-map split-components) + (rx/merge-map split-components) (rx/concat-reduce (partial import-component context) file))) (rx/of file))) @@ -574,7 +574,7 @@ (filter #(= :symbol (:tag %)))))] (->> (get-file context :deleted-components) - (rx/flat-map split-components) + (rx/merge-map split-components) (rx/concat-reduce (partial import-deleted-component context) file))) (rx/of file))) @@ -585,18 +585,18 @@ context (assoc context :progress progress-str)] [progress-str (->> (rx/of file) - (rx/flat-map (partial process-pages context)) + (rx/merge-map (partial process-pages context)) (rx/tap #(progress! context :process-colors)) - (rx/flat-map (partial process-library-colors context)) + (rx/merge-map (partial process-library-colors context)) (rx/tap #(progress! context :process-typographies)) - (rx/flat-map (partial process-library-typographies context)) + (rx/merge-map (partial process-library-typographies context)) (rx/tap #(progress! context :process-media)) - (rx/flat-map (partial process-library-media context)) + (rx/merge-map (partial process-library-media context)) (rx/tap #(progress! context :process-components)) - (rx/flat-map (partial process-library-components context)) + (rx/merge-map (partial process-library-components context)) (rx/tap #(progress! context :process-deleted-components)) - (rx/flat-map (partial process-deleted-components context)) - (rx/flat-map (partial send-changes context)) + (rx/merge-map (partial process-deleted-components context)) + (rx/merge-map (partial send-changes context)) (rx/tap #(rx/end! progress-str)))])) (defn create-files @@ -606,13 +606,13 @@ (rx/concat (->> (rx/from files) (rx/map #(merge context %)) - (rx/flat-map (fn [context] + (rx/merge-map (fn [context] (->> (create-file context features) (rx/map #(vector % (first (get data (:file-id context))))))))) (->> (rx/from files) (rx/map #(merge context %)) - (rx/flat-map link-file-libraries) + (rx/merge-map link-file-libraries) (rx/ignore))))) (defn parse-mtype [ba] @@ -627,7 +627,7 @@ [{:keys [files]}] (->> (rx/from files) - (rx/flat-map + (rx/merge-map (fn [file] (let [st (->> (http/send! {:uri (:uri file) @@ -642,8 +642,8 @@ (->> (rx/merge (->> st (rx/filter (fn [data] (= "application/zip" (:type data)))) - (rx/flat-map #(zip/loadAsync (:body %))) - (rx/flat-map #(get-file {:zip %} :manifest)) + (rx/merge-map #(zip/loadAsync (:body %))) + (rx/merge-map #(get-file {:zip %} :manifest)) (rx/map (comp d/kebab-keys cip/string->uuid)) (rx/map #(hash-map :uri (:uri file) :data % :type "application/zip"))) (->> st @@ -677,7 +677,7 @@ (rx/merge (->> (create-files context zip-files) - (rx/flat-map + (rx/merge-map (fn [[file data]] (->> (uz/load-from-url (:uri data)) (rx/map #(-> context (assoc :zip %) (merge data))) @@ -703,7 +703,7 @@ :error-data (ex-data cause)}))))))) (->> (rx/from binary-files) - (rx/flat-map + (rx/merge-map (fn [data] (->> (http/send! {:uri (:uri data) @@ -726,16 +726,13 @@ (log/error :hint "unexpected error on import process" :project-id project-id ::log/sync? true) - - (when (map? cause) + (let [edata (if (map? cause) cause (ex-data cause))] (println "Error data:") - (pp/pprint (dissoc cause :explain) {:level 2 :length 10})) + (pp/pprint (dissoc edata :explain) {:level 2 :length 10}) - (when (string? (:explain cause)) - (js/console.log (:explain cause))) + (when (string? (:explain edata)) + (js/console.log (:explain edata))) - (rx/of {:status :import-error - :file-id (:file-id data) - :error (:hint cause) - :error-data cause})))))))))) + (rx/of {:status :import-error + :file-id (:file-id data)}))))))))))) diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 3e3cbbfef8..0c548b52d6 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -7,6 +7,7 @@ (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] @@ -14,7 +15,7 @@ [app.main.render :as render] [app.util.http :as http] [app.worker.impl :as impl] - [beicon.core :as rx] + [beicon.v2.core :as rx] [okulary.core :as l] [rumext.v2 :as mf])) @@ -62,16 +63,27 @@ (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]) element (if frame - (mf/element render/frame-svg #js {:objects objects :frame frame :use-thumbnails true}) - (mf/element render/page-svg #js {:data page :use-thumbnails true :embed true})) + (mf/element render/frame-svg #js + {:objects objects + :frame frame + :use-thumbnails true + :background-color background-color + :aspect-ratio (/ 2 3)}) + + (mf/element render/page-svg #js + {:data page + :use-thumbnails true + :embed true + :aspect-ratio (/ 2 3)})) data (rds/renderToStaticMarkup element)] {:data data :fonts @fonts/loaded-hints :file-id file-id :revn revn})) (catch :default cause - (js/console.error "unexpected erorr on rendering thumbnail" cause) + (js/console.error "unexpected error on rendering thumbnail" cause) nil))) (defmethod impl/handler :thumbnails/generate-for-file diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index a3132c9ae1..4b1058f618 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -34,10 +34,10 @@ [app.util.http :as http] [app.util.object :as obj] [app.util.timers :as timers] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.pprint :refer [pprint]] [cuerdas.core :as str] - [potok.core :as ptk] + [potok.v2.core :as ptk] [promesa.core :as p])) (l/set-level! :debug) @@ -289,7 +289,7 @@ (rx/filter ptk/event?) (rx/filter (fn [s] (and (dbg/enabled? :events) (not (debug-exclude-events (ptk/type s)))))) - (rx/subs #(println "[stream]: " (ptk/repr-event %)))))) + (rx/subs! #(println "[stream]: " (ptk/repr-event %)))))) (defn ^:export apply-changes "Takes a Transit JSON changes" @@ -432,7 +432,7 @@ (->> (rp/cmd! :update-file params) - (rx/subs (fn [_] + (rx/subs! (fn [_] (when reload? (dom/reload-current-window))) (fn [cause] @@ -463,7 +463,7 @@ :query {:file-id file-id}}) (rx/map http/conditional-decode-transit) (rx/mapcat rp/handle-response) - (rx/subs (fn [result] + (rx/subs! (fn [result] (let [result (map (fn [row] (update row :id str)) result)] @@ -481,7 +481,7 @@ :body (http/transit-data {:file-id file-id :label label})}) (rx/map http/conditional-decode-transit) (rx/mapcat rp/handle-response) - (rx/subs (fn [{:keys [id]}] + (rx/subs! (fn [{:keys [id]}] (println "Snapshot saved:" (str id))) (fn [cause] (js/console.log "EE:" cause)))))) @@ -496,7 +496,7 @@ :body (http/transit-data {:file-id file-id :id id})}) (rx/map http/conditional-decode-transit) (rx/mapcat rp/handle-response) - (rx/subs (fn [_] + (rx/subs! (fn [_] (println "Snapshot restored " id) #_(.reload js/location)) (fn [cause] diff --git a/frontend/test/frontend_tests/helpers/events.cljs b/frontend/test/frontend_tests/helpers/events.cljs index 62c4b47f30..21353f768c 100644 --- a/frontend/test/frontend_tests/helpers/events.cljs +++ b/frontend/test/frontend_tests/helpers/events.cljs @@ -12,9 +12,9 @@ [app.common.schema :as sm] [app.common.uuid :as uuid] [app.main.data.workspace :as dw] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.test :as t] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) ;; ---- Helpers to manage global events @@ -26,48 +26,48 @@ (pp/pprint (sm/humanize-explain data)))) (defn prepare-store - "Create a store with the given initial state. Wait until - a :the/end event occurs, and then call the function with - the final state at this point." - [state done completed-cb] - (let [store (ptk/store {:state state :on-error on-error}) - stream (ptk/input-stream store) - stream (->> stream - (rx/take-until (rx/filter #(= :the/end %) stream)) - (rx/last) - (rx/do (fn [] - (completed-cb @store))) - (rx/subs (fn [_] (done)) - (fn [cause] - (js/console.log "[error]:" cause)) - (fn [_] - (js/console.log "[complete]"))))] - store)) + "Create a store with the given initial state. Wait until a :the/end + event occurs, and then call the function with the final state at + this point." + [state done completed-cb] + (let [store (ptk/store {:state state :on-error on-error}) + stream (ptk/input-stream store) + stream (->> stream + (rx/take-until (rx/filter #(= :the/end %) stream)) + (rx/last) + (rx/tap (fn [] + (completed-cb @store))) + (rx/subs! (fn [_] (done)) + (fn [cause] + (js/console.log "[error]:" cause)) + (fn [_] + (js/console.log "[complete]"))))] + store)) ;; Remove definitely when we ensure that the above method works ;; well in more advanced tests. #_(defn do-update - "Execute an update event and returns the new state." - [event state] - (ptk/update event state)) + "Execute an update event and returns the new state." + [event state] + (ptk/update event state)) #_(defn do-watch - "Execute a watch event and return an observable, that + "Execute a watch event and return an observable, that emits once a list with all new events." - [event state] - (->> (ptk/watch event state nil) - (rx/reduce conj []))) + [event state] + (->> (ptk/watch event state nil) + (rx/reduce conj []))) #_(defn do-watch-update - "Execute a watch event and return an observable, that + "Execute a watch event and return an observable, that emits once the new state, after all new events applied in sequence (considering they are all update events)." - [event state] - (->> (do-watch event state) - (rx/map (fn [new-events] - (reduce - (fn [new-state new-event] - (do-update new-event new-state)) - state - new-events))))) + [event state] + (->> (do-watch event state) + (rx/map (fn [new-events] + (reduce + (fn [new-state new-event] + (do-update new-event new-state)) + state + new-events))))) diff --git a/frontend/test/frontend_tests/helpers_shapes_test.cljs b/frontend/test/frontend_tests/helpers_shapes_test.cljs index 6d0a589eec..8b01ad7a19 100644 --- a/frontend/test/frontend_tests/helpers_shapes_test.cljs +++ b/frontend/test/frontend_tests/helpers_shapes_test.cljs @@ -10,7 +10,7 @@ [app.common.data :as d] [app.common.geom.point :as gpt] [app.main.data.workspace.libraries :as dwl] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.pprint :refer [pprint]] [cljs.test :as t :include-macros true] [clojure.stacktrace :as stk] @@ -18,7 +18,7 @@ [frontend-tests.helpers.libraries :as thl] [frontend-tests.helpers.pages :as thp] [linked.core :as lks] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (t/use-fixtures :each {:before thp/reset-idmap!}) diff --git a/frontend/test/frontend_tests/state_components_sync_test.cljs b/frontend/test/frontend_tests/state_components_sync_test.cljs index aa2c50fb9e..bfdbdedc8b 100644 --- a/frontend/test/frontend_tests/state_components_sync_test.cljs +++ b/frontend/test/frontend_tests/state_components_sync_test.cljs @@ -17,7 +17,7 @@ [frontend-tests.helpers.events :as the] [frontend-tests.helpers.libraries :as thl] [frontend-tests.helpers.pages :as thp] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (t/use-fixtures :each {:before thp/reset-idmap!}) diff --git a/frontend/test/frontend_tests/state_components_test.cljs b/frontend/test/frontend_tests/state_components_test.cljs index a5e006a301..6b6dca73ec 100644 --- a/frontend/test/frontend_tests/state_components_test.cljs +++ b/frontend/test/frontend_tests/state_components_test.cljs @@ -13,7 +13,7 @@ [frontend-tests.helpers.libraries :as thl] [frontend-tests.helpers.pages :as thp] [linked.core :as lks] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (t/use-fixtures :each {:before thp/reset-idmap!}) diff --git a/frontend/test/frontend_tests/test_helpers_shapes.cljs b/frontend/test/frontend_tests/test_helpers_shapes.cljs index 1efd72a058..45921648ec 100644 --- a/frontend/test/frontend_tests/test_helpers_shapes.cljs +++ b/frontend/test/frontend_tests/test_helpers_shapes.cljs @@ -7,12 +7,12 @@ [app.test-helpers.events :as the] [app.test-helpers.libraries :as thl] [app.test-helpers.pages :as thp] - [beicon.core :as rx] + [beicon.v2.core :as rx] [cljs.pprint :refer [pprint]] [cljs.test :as t :include-macros true] [clojure.stacktrace :as stk] [linked.core :as lks] - [potok.core :as ptk])) + [potok.v2.core :as ptk])) (t/use-fixtures :each {:before thp/reset-idmap!}) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 1c5e97d907..f1206c084c 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1637,6 +1637,9 @@ msgstr "Settings" msgid "labels.share-prototype" msgstr "Share prototype" +msgid "labels.share" +msgstr "Share" + #: src/app/main/ui/dashboard/sidebar.cljs msgid "labels.shared-libraries" msgstr "Libraries" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 218fdad3c3..7b4e5b85ed 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1673,6 +1673,9 @@ msgstr "Configuración" msgid "labels.share-prototype" msgstr "Compartir prototipo" +msgid "labels.share" +msgstr "Compartir" + #: src/app/main/ui/dashboard/sidebar.cljs msgid "labels.shared-libraries" msgstr "Bibliotecas" diff --git a/frontend/vendor/beicon/impl/rxjs.cljs b/frontend/vendor/beicon/impl/rxjs.cljs deleted file mode 100644 index 6fa0bcfa09..0000000000 --- a/frontend/vendor/beicon/impl/rxjs.cljs +++ /dev/null @@ -1,4 +0,0 @@ -(ns beicon.impl.rxjs - (:require ["rxjs" :as rx])) - -(goog/exportSymbol "rxjsMain" rx) diff --git a/frontend/vendor/beicon/impl/rxjs_operators.cljs b/frontend/vendor/beicon/impl/rxjs_operators.cljs deleted file mode 100644 index 22b4e2313d..0000000000 --- a/frontend/vendor/beicon/impl/rxjs_operators.cljs +++ /dev/null @@ -1,4 +0,0 @@ -(ns beicon.impl.rxjs-operators - (:require ["rxjs/operators" :as rxop])) - -(goog/exportSymbol "rxjsOperators" rxop) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index f50dbb9699..21b825e1a3 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -4018,6 +4018,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^20.10.5": + version: 20.10.5 + resolution: "@types/node@npm:20.10.5" + dependencies: + undici-types: "npm:~5.26.4" + checksum: be30609aae0bfe492097815f166ccc07f465220cb604647fa4e5ec05a1d16c012a41b82b5f11ecfe2485cbb479d4d20384b95b809ca0bcff6d94d5bbafa645bb + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.4 resolution: "@types/normalize-package-data@npm:2.4.4" @@ -7580,6 +7589,7 @@ __metadata: "@storybook/react": "npm:^7.5.3" "@storybook/react-vite": "npm:^7.5.3" "@storybook/testing-library": "npm:^0.2.2" + "@types/node": "npm:^20.10.5" animate.css: "npm:^4.1.1" autoprefixer: "npm:^10.4.15" concurrently: "npm:^8.2.2" @@ -7618,13 +7628,14 @@ __metadata: react-dom: "npm:^18.2.0" react-virtualized: "npm:^9.22.3" rimraf: "npm:^5.0.1" - rxjs: "npm:~7.8.1" + rxjs: "npm:8.0.0-alpha.13" sass: "npm:^1.66.1" sax: "npm:^1.2.4" shadow-cljs: "npm:2.26.2" source-map-support: "npm:^0.5.21" storybook: "npm:^7.5.3" tdigest: "npm:^0.1.2" + typescript: "npm:^5.3.3" ua-parser-js: "npm:^1.0.32" vite: "npm:^5.0.2" xregexp: "npm:^5.1.1" @@ -12516,7 +12527,17 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:^7.8.1, rxjs@npm:~7.8.1": +"rxjs@npm:8.0.0-alpha.13": + version: 8.0.0-alpha.13 + resolution: "rxjs@npm:8.0.0-alpha.13" + peerDependencies: + "@types/node": ^20.6.3 + typescript: ^5.2.2 + checksum: d3d8a395e7b92158d621d686b819aa5be480f5c17155f695506b9a70a32af886962d23d4040a1d1611d815abe0ba0fd4929b3687da75a62a03a1e90e5b616464 + languageName: node + linkType: hard + +"rxjs@npm:^7.8.1": version: 7.8.1 resolution: "rxjs@npm:7.8.1" dependencies: @@ -13922,6 +13943,26 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.3.3": + version: 5.3.3 + resolution: "typescript@npm:5.3.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: e33cef99d82573624fc0f854a2980322714986bc35b9cb4d1ce736ed182aeab78e2cb32b385efa493b2a976ef52c53e20d6c6918312353a91850e2b76f1ea44f + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin": + version: 5.3.3 + resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin::version=5.3.3&hash=e012d7" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500 + languageName: node + linkType: hard + "ua-parser-js@npm:^0.7.18": version: 0.7.37 resolution: "ua-parser-js@npm:0.7.37"