Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2024-02-29 12:53:08 +01:00
commit a109673654
86 changed files with 740 additions and 561 deletions

View file

@ -6,11 +6,11 @@
(ns user (ns user
(:require (:require
[app.common.pprint :as pp]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.common.schema.desc-js-like :as smdj] [app.common.schema.desc-js-like :as smdj]
[app.common.schema.desc-native :as smdn] [app.common.schema.desc-native :as smdn]
[app.common.schema.generators :as sg] [app.common.schema.generators :as sg]
[app.common.pprint :as pp]
[clojure.java.io :as io] [clojure.java.io :as io]
[clojure.pprint :refer [pprint print-table]] [clojure.pprint :refer [pprint print-table]]
[clojure.repl :refer :all] [clojure.repl :refer :all]

View file

@ -13,25 +13,22 @@
[cuerdas.core :as str])) [cuerdas.core :as str]))
(def black "#000000") (def black "#000000")
(def canvas "#E8E9EA")
(def default-layout "#DE4762") (def default-layout "#DE4762")
(def gray-10 "#E3E3E3")
(def gray-20 "#B1B2B5") (def gray-20 "#B1B2B5")
(def gray-30 "#7B7D85")
(def gray-40 "#64666A")
(def gray-50 "#303236")
(def info "#59B9E2") (def info "#59B9E2")
(def test "#fabada") (def test "#fabada")
(def white "#FFFFFF") (def white "#FFFFFF")
(def primary "#31EFB8")
(def danger "#E65244")
(def warning "#FC8802") (def warning "#FC8802")
;; new-css-system colors ;; new-css-system colors
(def new-primary "#91fadb") (def new-primary "#7efff5")
(def new-danger "#ff4986") (def new-danger "#ff3277")
(def new-warning "#ff9b49") (def new-warning "#fe4811")
(def canvas-background "#1d1f20") (def new-primary-light "#6911d4")
(def background-quaternary "#2e3434")
(def background-quaternary-light "#eef0f2")
(def canvas "#E8E9EA")
(def names (def names
{"aliceblue" "#f0f8ff" {"aliceblue" "#f0f8ff"

View file

@ -749,21 +749,23 @@
(defmulti components-changed (fn [_ change] (:type change))) (defmulti components-changed (fn [_ change] (:type change)))
(defmethod components-changed :mod-obj (defmethod components-changed :mod-obj
[file-data {:keys [id page-id _component-id operations]}] [file-data {:keys [id page-id component-id operations]}]
(when page-id (let [need-sync? (fn [operation]
(let [page (ctpl/get-page file-data page-id) ; We need to trigger a sync if the shape has changed any
shape-and-parents (map #(ctn/get-shape page %) ; attribute that participates in components synchronization.
(cons id (cfh/get-parent-ids (:objects page) id))) (and (= (:type operation) :set)
need-sync? (fn [operation] (get ctk/sync-attrs (:attr operation))))
; We need to trigger a sync if the shape has changed any any-sync? (some need-sync? operations)]
; attribute that participates in components synchronization. (when any-sync?
(and (= (:type operation) :set) (if page-id
(get ctk/sync-attrs (:attr operation)))) (let [page (ctpl/get-page file-data page-id)
any-sync? (some need-sync? operations)] shape-and-parents (map #(ctn/get-shape page %)
(when any-sync? (cons id (cfh/get-parent-ids (:objects page) id)))
(let [xform (comp (filter :main-instance) ; Select shapes that are main component instances xform (comp (filter :main-instance) ; Select shapes that are main component instances
(map :component-id))] (map :component-id))]
(into #{} xform shape-and-parents)))))) (into #{} xform shape-and-parents))
(when component-id
#{component-id})))))
(defmethod components-changed :mov-objects (defmethod components-changed :mov-objects
[file-data {:keys [page-id _component-id parent-id shapes] :as change}] [file-data {:keys [page-id _component-id parent-id shapes] :as change}]

View file

@ -8,7 +8,8 @@
(:require (:require
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.rect :as grc] [app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh])) [app.common.geom.shapes :as gsh]
[app.common.geom.shapes.points :as gpo]))
;; --- Alignment ;; --- Alignment
@ -30,6 +31,23 @@
(- (:y align-pos) (:y wrapper-rect)))] (- (:y align-pos) (:y wrapper-rect)))]
(gsh/move shape delta))) (gsh/move shape delta)))
(defn align-to-parent
"Does the same calc as align-to-rect but relative to a parent shape."
[shape parent axis]
(let [parent-bounds (:points parent)
wrapper-rect
(-> (gsh/transform-points (:points shape) (gsh/shape->center parent) (:transform-inverse parent))
(grc/points->rect))
align-pos (calc-align-pos wrapper-rect (:selrect parent) axis)
xv #(gpo/start-hv parent-bounds %)
yv #(gpo/start-vv parent-bounds %)
delta (-> (xv (- (:x align-pos) (:x wrapper-rect)))
(gpt/add (yv (- (:y align-pos) (:y wrapper-rect)))))]
(gsh/move shape delta)))
(defn calc-align-pos (defn calc-align-pos
[wrapper-rect rect axis] [wrapper-rect rect axis]
(case axis (case axis

View file

@ -211,7 +211,7 @@
([{:keys [type metadata] :as shape} objects] ([{:keys [type metadata] :as shape} objects]
(assert (map? objects)) (assert (map? objects))
(case type (case type
:group (:group :frame)
(group-to-path shape objects) (group-to-path shape objects)
:bool :bool

View file

@ -103,6 +103,12 @@
(concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data)) (concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data))
(map #(ctn/make-container % :component) (ctkl/components-seq file-data)))) (map #(ctn/make-container % :component) (ctkl/components-seq file-data))))
(defn object-containers-seq
"Generate a sequence of all pages and all deleted components (all those components that have :objects), wrapped as containers"
[file-data]
(concat (map #(ctn/make-container % :page) (ctpl/pages-seq file-data))
(map #(ctn/make-container % :component) (ctkl/deleted-components-seq file-data))))
(defn update-container (defn update-container
"Update a container inside the file, it can be a page or a component" "Update a container inside the file, it can be a page or a component"
[file-data container f] [file-data container f]

View file

@ -247,6 +247,16 @@ function templatePipeline(options) {
gulpSass.compiler = sass; gulpSass.compiler = sass;
gulp.task("scss:clean", async function (next) {
try {
await rimraf("./resources/public/.tmp");
await rimraf("./resources/public/css");
} finally {
next();
}
});
gulp.task("scss:modules", function () { gulp.task("scss:modules", function () {
return gulp return gulp
.src(["src/**/**.scss"]) .src(["src/**/**.scss"])
@ -314,7 +324,10 @@ gulp.task("scss:touch:modules", function() {
return gulp.src("src/**/**.scss").pipe(touch()); return gulp.src("src/**/**.scss").pipe(touch());
}); });
gulp.task("scss", gulp.series("scss:main", "scss:modules", "scss:concat", "scss:touch:main")); gulp.task("scss", gulp.series("scss:main",
"scss:modules",
"scss:concat",
"scss:touch:main"));
gulp.task("svg:sprite:icons", function () { gulp.task("svg:sprite:icons", function () {
return gulp return gulp
@ -419,9 +432,18 @@ gulp.task("clean:dist", function (next) {
}); });
gulp.task("build:styles", gulp.parallel("scss")); gulp.task("build:styles", gulp.parallel("scss"));
gulp.task("build:assets", gulp.parallel("polyfills", "templates", "copy:assets"));
gulp.task("watch", gulp.series("dev:dirs", "build:styles", "build:assets", "watch:main")); gulp.task("build:assets",
gulp.parallel("polyfills",
"templates",
"copy:assets"));
gulp.task("watch",
gulp.series("dev:dirs",
"scss:clean",
"build:styles",
"build:assets",
"watch:main"));
gulp.task("build:copy", function () { gulp.task("build:copy", function () {
return gulp.src("./resources/public/**/*").pipe(gulp.dest("./target/dist/")); return gulp.src("./resources/public/**/*").pipe(gulp.dest("./target/dist/"));

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 .667h12M12 5.5A1.5 1.5 0 0010.5 4h-5A1.5 1.5 0 004 5.5v1A1.5 1.5 0 005.5 8h5A1.5 1.5 0 0012 6.5v-1zm0 7.333a1.5 1.5 0 00-1.5-1.5h-5a1.5 1.5 0 00-1.5 1.5v1a1.5 1.5 0 001.5 1.5h5a1.5 1.5 0 001.5-1.5v-1z"/> <path d="M2 15.333h12M12 10.5a1.5 1.5 0 01-1.5 1.5h-5A1.5 1.5 0 014 10.5v-1A1.5 1.5 0 015.5 8h5A1.5 1.5 0 0112 9.5v1zm0-7.333a1.5 1.5 0 01-1.5 1.5h-5a1.5 1.5 0 01-1.5-1.5v-1a1.5 1.5 0 011.5-1.5h5a1.5 1.5 0 011.5 1.5v1z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 333 B

After

Width:  |  Height:  |  Size: 339 B

Before After
Before After

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 15.333h12M12 10.5a1.5 1.5 0 01-1.5 1.5h-5A1.5 1.5 0 014 10.5v-1A1.5 1.5 0 015.5 8h5A1.5 1.5 0 0112 9.5v1zm0-7.333a1.5 1.5 0 01-1.5 1.5h-5a1.5 1.5 0 01-1.5-1.5v-1a1.5 1.5 0 011.5-1.5h5a1.5 1.5 0 011.5 1.5v1z"/> <path d="M2 .667h12M12 5.5A1.5 1.5 0 0010.5 4h-5A1.5 1.5 0 004 5.5v1A1.5 1.5 0 005.5 8h5A1.5 1.5 0 0012 6.5v-1zm0 7.333a1.5 1.5 0 00-1.5-1.5h-5a1.5 1.5 0 00-1.5 1.5v1a1.5 1.5 0 001.5 1.5h5a1.5 1.5 0 001.5-1.5v-1z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 333 B

Before After
Before After

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M15.5 7.617h-14m14 0l-6.008 4.996M15.5 7.617L9.492 2.613"/>
</svg>

After

Width:  |  Height:  |  Size: 186 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M5.8 8a4.7 4.7 0 109.4 0 4.7 4.7 0 00-9.4 0zm0 0H1.5m5.643 1.68h.396m1.184 1.677h.395M7.143 6.321h.396m1.184 1.68h.395m1.185 1.678h.394m1.185 1.678h.396M8.723 4.643h.395m1.185 1.678h.394m1.185 1.68h.396m1.184 1.678h.395m-1.974-5.036h.395m1.184 1.678h.395"/>
</svg>

After

Width:  |  Height:  |  Size: 384 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M6.888 9.656h.391m1.168 1.656h.39M6.888 6.344h.391M8.447 8h.39m1.168 1.656h.39m1.168 1.656h.391M8.447 4.688h.39m1.168 1.656h.39M11.563 8h.391m1.169 1.656h.389m-1.947-4.968h.389m1.169 1.656h.389M1.5 8H5m-.025.18l5.045 5.045a.254.254 0 00.36 0l5.045-5.045a.255.255 0 00.056-.277.255.255 0 00-.056-.083L10.38 2.775a.253.253 0 00-.36 0L4.975 7.82a.253.253 0 000 .36z"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M7.167 9.667h.393m1.176 1.666h.392m-1.961-5h.393M8.736 8h.392m1.176 1.667h.392m1.176 1.666h.393M8.736 4.667h.392m1.176 1.666h.392M11.872 8h.393m1.176 1.667h.392m-1.96-5h.392m1.176 1.666h.392M1.5 8h5m0-4h8v8h-8V4z"/>
</svg>

After

Width:  |  Height:  |  Size: 342 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M.833 4h10.098c2.34 0 4.236 1.791 4.236 4s-1.896 4-4.236 4H.833"/>
</svg>

After

Width:  |  Height:  |  Size: 193 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M.833 4h14.334v8H.833"/>
</svg>

After

Width:  |  Height:  |  Size: 153 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M7.633 9.627h.374m1.117 1.627h.372M7.633 6.373h.374M9.124 8h.372m1.117 1.627h.372M9.124 4.746h.372m1.117 1.627h.372M12.102 8h.373M1.5 8l5.5.004m7.88-.225l-7.494-4.74a.246.246 0 00-.256-.006.262.262 0 00-.13.227v9.48c0 .094.05.181.13.227.08.046.178.044.256-.006l7.494-4.74A.26.26 0 0015 8a.26.26 0 00-.12-.221z"/>
</svg>

After

Width:  |  Height:  |  Size: 441 B

View file

@ -63,7 +63,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [stoper-s (rx/filter (ptk/type? ::finalize) stream) (let [stopper (rx/filter (ptk/type? ::finalize) stream)
profile-id (:profile-id state)] profile-id (:profile-id state)]
(->> (rx/merge (->> (rx/merge
@ -92,7 +92,7 @@
(rx/filter #(= id (:id %))) (rx/filter #(= id (:id %)))
(rx/map du/set-current-team))) (rx/map du/set-current-team)))
(rx/take-until stoper-s)))))) (rx/take-until stopper))))))
(defn finalize (defn finalize
[params] [params]

View file

@ -234,7 +234,7 @@
ptk/EffectEvent ptk/EffectEvent
(effect [_ _ stream] (effect [_ _ stream]
(let [session (atom nil) (let [session (atom nil)
stoper (rx/filter (ptk/type? ::initialize) stream) stopper (rx/filter (ptk/type? ::initialize) stream)
buffer (atom #queue []) buffer (atom #queue [])
profile (->> (rx/from-atom storage {:emit-current-value? true}) profile (->> (rx/from-atom storage {:emit-current-value? true})
(rx/map :profile) (rx/map :profile)
@ -259,7 +259,7 @@
(rx/tap (fn [_] (rx/tap (fn [_]
(l/debug :hint "events chunk persisted" :total (count chunk)))) (l/debug :hint "events chunk persisted" :total (count chunk))))
(rx/map (constantly chunk)))))) (rx/map (constantly chunk))))))
(rx/take-until stoper) (rx/take-until stopper)
(rx/subs! (fn [chunk] (rx/subs! (fn [chunk]
(swap! buffer remove-from-buffer (count chunk))) (swap! buffer remove-from-buffer (count chunk)))
(fn [cause] (fn [cause]
@ -290,7 +290,7 @@
(swap! buffer append-to-buffer event))) (swap! buffer append-to-buffer event)))
(rx/switch-map #(rx/timer (inst-ms session-timeout))) (rx/switch-map #(rx/timer (inst-ms session-timeout)))
(rx/take-until stoper) (rx/take-until stopper)
(rx/subs! (fn [_] (rx/subs! (fn [_]
(l/debug :hint "session reinitialized") (l/debug :hint "session reinitialized")
(reset! session nil)) (reset! session nil))

View file

@ -209,7 +209,7 @@
(rx/filter #(= @resource-id (:resource-id %))) (rx/filter #(= @resource-id (:resource-id %)))
(rx/share)) (rx/share))
stoper stopper
(rx/filter #(or (= "ended" (:status %)) (rx/filter #(or (= "ended" (:status %))
(= "error" (:status %))) (= "error" (:status %)))
progress-stream)] progress-stream)]
@ -228,12 +228,12 @@
(initialize-export-status exports cmd resource)))) (initialize-export-status exports cmd resource))))
;; We proceed to update the export state with incoming ;; We proceed to update the export state with incoming
;; progress updates. We delay the stoper for give some time ;; progress updates. We delay the stopper for give some time
;; to update the status with ended or errored status before ;; to update the status with ended or errored status before
;; close the stream. ;; close the stream.
(->> progress-stream (->> progress-stream
(rx/map update-export-status) (rx/map update-export-status)
(rx/take-until (rx/delay 500 stoper)) (rx/take-until (rx/delay 500 stopper))
(rx/finalize (fn [] (rx/finalize (fn []
(swap! st/ongoing-tasks disj :export)))) (swap! st/ongoing-tasks disj :export))))
@ -246,7 +246,7 @@
(rx/take 1) (rx/take 1)
(rx/delay default-timeout) (rx/delay default-timeout)
(rx/map #(clear-export-state @resource-id)) (rx/map #(clear-export-state @resource-id))
(rx/take-until (rx/delay 6000 stoper)))))))) (rx/take-until (rx/delay 6000 stopper))))))))
(defn retry-last-export (defn retry-last-export
[] []

View file

@ -61,16 +61,16 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(rx/merge (rx/merge
(let [stoper (rx/filter (ptk/type? ::hide) stream)] (let [stopper (rx/filter (ptk/type? ::hide) stream)]
(->> stream (->> stream
(rx/filter (ptk/type? :app.util.router/navigate)) (rx/filter (ptk/type? :app.util.router/navigate))
(rx/map (constantly hide)) (rx/map (constantly hide))
(rx/take-until stoper))) (rx/take-until stopper)))
(when (:timeout data) (when (:timeout data)
(let [stoper (rx/filter (ptk/type? ::show) stream)] (let [stopper (rx/filter (ptk/type? ::show) stream)]
(->> (rx/of hide) (->> (rx/of hide)
(rx/delay (:timeout data)) (rx/delay (:timeout data))
(rx/take-until stoper)))))))) (rx/take-until stopper))))))))
(def hide (def hide
(ptk/reify ::hide (ptk/reify ::hide
@ -80,10 +80,10 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stoper (rx/filter (ptk/type? ::show) stream)] (let [stopper (rx/filter (ptk/type? ::show) stream)]
(->> (rx/of #(dissoc % :message)) (->> (rx/of #(dissoc % :message))
(rx/delay default-animation-timeout) (rx/delay default-animation-timeout)
(rx/take-until stoper)))))) (rx/take-until stopper))))))
(defn hide-tag (defn hide-tag
[tag] [tag]

View file

@ -51,9 +51,9 @@
(vreset! ws-conn ws) (vreset! ws-conn ws)
(let [stoper (rx/merge (let [stopper (rx/merge
(rx/filter (ptk/type? ::finalize) stream) (rx/filter (ptk/type? ::finalize) stream)
(rx/filter (ptk/type? ::initialize) stream))] (rx/filter (ptk/type? ::initialize) stream))]
(->> (rx/merge (->> (rx/merge
(rx/of #(assoc % :ws-conn ws)) (rx/of #(assoc % :ws-conn ws))
@ -64,7 +64,7 @@
(->> (ws/get-rcv-stream ws) (->> (ws/get-rcv-stream ws)
(rx/filter ws/opened-event?) (rx/filter ws/opened-event?)
(rx/map (fn [_] (ptk/data-event ::opened {}))))) (rx/map (fn [_] (ptk/data-event ::opened {})))))
(rx/take-until stoper))))))) (rx/take-until stopper)))))))
;; --- Finalize Websocket ;; --- Finalize Websocket

View file

@ -41,7 +41,6 @@
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.collapse :as dwco] [app.main.data.workspace.collapse :as dwco]
[app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.drawing :as dwd]
[app.main.data.workspace.drawing.common :as dwdc]
[app.main.data.workspace.edition :as dwe] [app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.fix-bool-contents :as fbc] [app.main.data.workspace.fix-bool-contents :as fbc]
[app.main.data.workspace.fix-broken-shapes :as fbs] [app.main.data.workspace.fix-broken-shapes :as fbs]
@ -153,7 +152,7 @@
(watch [_ _ stream] (watch [_ _ stream]
(let [team-id (:id team) (let [team-id (:id team)
file-id (:id file) file-id (:id file)
stoper-s (rx/filter (ptk/type? ::bundle-fetched) stream)] stopper (rx/filter (ptk/type? ::bundle-fetched) stream)]
(->> (rx/concat (->> (rx/concat
;; Initialize notifications ;; Initialize notifications
@ -204,7 +203,7 @@
(rx/of (with-meta (workspace-initialized) (rx/of (with-meta (workspace-initialized)
{:file-id file-id}))) {:file-id file-id})))
(rx/take-until stoper-s)))))) (rx/take-until stopper))))))
(defn- libraries-fetched (defn- libraries-fetched
[libraries] [libraries]
@ -1080,7 +1079,7 @@
(let [object (get objects object-id) (let [object (get objects object-id)
parent-id (:parent-id (get objects object-id)) parent-id (:parent-id (get objects object-id))
parent (get objects parent-id)] parent (get objects parent-id)]
[(gal/align-to-rect object parent axis)])) [(gal/align-to-parent object parent axis)]))
(defn align-objects-list (defn align-objects-list
[objects selected axis] [objects selected axis]
@ -2138,7 +2137,6 @@
(watch [_ _ _] (watch [_ _ _]
(if read-only? (if read-only?
(rx/of :interrupt (rx/of :interrupt
(dwdc/clear-drawing)
(remove-layout-flag :colorpalette) (remove-layout-flag :colorpalette)
(remove-layout-flag :textpalette)) (remove-layout-flag :textpalette))
(rx/empty))))) (rx/empty)))))

View file

@ -526,9 +526,9 @@
(ptk/reify ::initialize-colorpicker (ptk/reify ::initialize-colorpicker
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stoper (rx/merge (let [stopper (rx/merge
(rx/filter (ptk/type? ::finalize-colorpicker) stream) (rx/filter (ptk/type? ::finalize-colorpicker) stream)
(rx/filter (ptk/type? ::initialize-colorpicker) stream))] (rx/filter (ptk/type? ::initialize-colorpicker) stream))]
(->> (rx/merge (->> (rx/merge
(->> stream (->> stream
@ -537,7 +537,7 @@
(rx/filter (ptk/type? ::update-colorpicker-color) stream) (rx/filter (ptk/type? ::update-colorpicker-color) stream)
(rx/filter (ptk/type? ::activate-colorpicker-gradient) stream)) (rx/filter (ptk/type? ::activate-colorpicker-gradient) stream))
(rx/map (constantly (colorpicker-onchange-runner on-change))) (rx/map (constantly (colorpicker-onchange-runner on-change)))
(rx/take-until stoper)))) (rx/take-until stopper))))
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]

View file

@ -34,7 +34,7 @@
(ptk/reify ::initialize-comments (ptk/reify ::initialize-comments
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stoper (rx/filter #(= ::finalize %) stream)] (let [stopper (rx/filter #(= ::finalize %) stream)]
(rx/merge (rx/merge
(rx/of (dcm/retrieve-comment-threads file-id)) (rx/of (dcm/retrieve-comment-threads file-id))
(->> stream (->> stream
@ -45,11 +45,11 @@
(rx/filter (fn [[_ space]] (not space))) (rx/filter (fn [[_ space]] (not space)))
(rx/map first) (rx/map first)
(rx/map handle-comment-layer-click) (rx/map handle-comment-layer-click)
(rx/take-until stoper)) (rx/take-until stopper))
(->> stream (->> stream
(rx/filter dwco/interrupt?) (rx/filter dwco/interrupt?)
(rx/map handle-interrupt) (rx/map handle-interrupt)
(rx/take-until stoper))))))) (rx/take-until stopper)))))))
(defn- handle-interrupt (defn- handle-interrupt
[] []

View file

@ -38,8 +38,7 @@
(watch [_ _ stream] (watch [_ _ stream]
(rx/merge (rx/merge
(when (= tool :path) (when (= tool :path)
(rx/of (start-drawing :path) (rx/of (start-drawing :path)))
(dwc/hide-toolbar)))
(when (= tool :curve) (when (= tool :curve)
(let [stopper (rx/filter dwc/interrupt? stream)] (let [stopper (rx/filter dwc/interrupt? stream)]

View file

@ -78,12 +78,12 @@
(ptk/reify ::handle-drawing (ptk/reify ::handle-drawing
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [stoper (rx/merge (let [stopper (rx/merge
(->> stream (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
(->> stream (->> stream
(rx/filter #(= % :interrupt)))) (rx/filter #(= % :interrupt))))
layout (get state :workspace-layout) layout (get state :workspace-layout)
zoom (dm/get-in state [:workspace-local :zoom] 1) zoom (dm/get-in state [:workspace-local :zoom] 1)
@ -131,7 +131,7 @@
(rx/filter #(> (gpt/distance % initial) (/ 2 zoom))) (rx/filter #(> (gpt/distance % initial) (/ 2 zoom)))
;; Take until before the snap calculation otherwise we could cancel the snap in the worker ;; Take until before the snap calculation otherwise we could cancel the snap in the worker
;; and its a problem for fast moving drawing ;; and its a problem for fast moving drawing
(rx/take-until stoper) (rx/take-until stopper)
(rx/with-latest-from ms/mouse-position-shift ms/mouse-position-mod) (rx/with-latest-from ms/mouse-position-shift ms/mouse-position-mod)
(rx/switch-map (rx/switch-map
(fn [[point :as current]] (fn [[point :as current]]

View file

@ -28,7 +28,7 @@
(def simplify-tolerance 0.3) (def simplify-tolerance 0.3)
(defn stoper-event? (defn stopper-event?
[{:keys [type] :as event}] [{:keys [type] :as event}]
(and (mse/mouse-event? event) (and (mse/mouse-event? event)
(= type :up))) (= type :up)))
@ -104,7 +104,7 @@
(ptk/reify ::handle-drawing (ptk/reify ::handle-drawing
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stoper (rx/filter stoper-event? stream) (let [stopper (rx/filter stopper-event? stream)
mouse (rx/sample 10 ms/mouse-position) mouse (rx/sample 10 ms/mouse-position)
shape (cts/setup-shape {:type :path shape (cts/setup-shape {:type :path
:initialized? true :initialized? true
@ -115,7 +115,7 @@
(rx/of #(update % :workspace-drawing assoc :object shape)) (rx/of #(update % :workspace-drawing assoc :object shape))
(->> mouse (->> mouse
(rx/map insert-point) (rx/map insert-point)
(rx/take-until stoper)) (rx/take-until stopper))
(rx/of (rx/of
(setup-frame) (setup-frame)
(finish-drawing) (finish-drawing)

View file

@ -7,8 +7,7 @@
(ns app.main.data.workspace.edition (ns app.main.data.workspace.edition
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.shape.layout :as ctl] [app.main.data.workspace.path.common :as dwpc]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -33,25 +32,27 @@
state))) state)))
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ _ stream]
(let [objects (wsh/lookup-page-objects state)] (->> stream
(rx/concat (rx/filter interrupt?)
(if (ctl/grid-layout? objects id) (rx/take 1)
(rx/of (dwc/hide-toolbar)) (rx/map clear-edition-mode)))))
(rx/empty))
(->> stream
(rx/filter interrupt?)
(rx/take 1)
(rx/map (constantly clear-edition-mode))))))))
;; If these event change modules review /src/app/main/data/workspace/path/undo.cljs ;; If these event change modules review /src/app/main/data/workspace/path/undo.cljs
(def clear-edition-mode (defn clear-edition-mode
[]
(ptk/reify ::clear-edition-mode (ptk/reify ::clear-edition-mode
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state
(update :workspace-local dissoc :edition)
(update :workspace-drawing dissoc :tool :object :lock)
(dissoc :workspace-grid-edition)))
ptk/WatchEvent
(watch [_ state _]
(let [id (get-in state [:workspace-local :edition])] (let [id (get-in state [:workspace-local :edition])]
(-> state (rx/concat
(update :workspace-local dissoc :edition) (when (some? id)
(dissoc :workspace-grid-edition) (dwpc/finish-path)))))))
(assoc-in [:workspace-local :hide-toolbar] false)
(cond-> (some? id) (update-in [:workspace-local :edit-path] dissoc id)))))))

View file

@ -317,10 +317,10 @@
(let [file (wsh/get-file state file-id) (let [file (wsh/get-file state file-id)
components-v2 (get-in file [:options :components-v2])] components-v2 (get-in file [:options :components-v2])]
(loop [pages (vals (get file :pages-index)) (loop [containers (ctf/object-containers-seq file)
changes (pcb/empty-changes it)] changes (pcb/empty-changes it)]
(if-let [page (first pages)] (if-let [container (first containers)]
(recur (next pages) (recur (next containers)
(pcb/concat-changes (pcb/concat-changes
changes changes
(generate-sync-container it (generate-sync-container it
@ -328,7 +328,7 @@
asset-id asset-id
library-id library-id
state state
(cfh/make-container page :page) container
components-v2))) components-v2)))
changes)))) changes))))
@ -597,9 +597,7 @@
(log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?) (log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?)
(let [shape-inst (ctn/get-shape container shape-id) (let [shape-inst (ctn/get-shape container shape-id)
library (dm/get-in libraries [(:component-file shape-inst) :data]) library (dm/get-in libraries [(:component-file shape-inst) :data])
component (or (ctkl/get-component library (:component-id shape-inst)) component (ctkl/get-component library (:component-id shape-inst) true)]
(and reset?
(ctkl/get-deleted-component library (:component-id shape-inst))))]
(if (and (ctk/in-component-copy? shape-inst) (if (and (ctk/in-component-copy? shape-inst)
(or (ctf/direct-copy? shape-inst component container nil libraries) reset?)) ; In a normal sync, we don't want to sync remote mains, only direct/near (or (ctf/direct-copy? shape-inst component container nil libraries) reset?)) ; In a normal sync, we don't want to sync remote mains, only direct/near
(let [redirect-shaperef (partial redirect-shaperef container libraries) (let [redirect-shaperef (partial redirect-shaperef container libraries)

View file

@ -38,7 +38,7 @@
(ptk/reify ::initialize (ptk/reify ::initialize
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [stoper (rx/filter (ptk/type? ::finalize) stream) (let [stopper (rx/filter (ptk/type? ::finalize) stream)
profile-id (:profile-id state) profile-id (:profile-id state)
initmsg [{:type :subscribe-file initmsg [{:type :subscribe-file
@ -87,7 +87,7 @@
(rx/pipe (rxs/throttle 100)) (rx/pipe (rxs/throttle 100))
(rx/map #(handle-pointer-send file-id (:pt %))))) (rx/map #(handle-pointer-send file-id (:pt %)))))
(rx/take-until stoper))] (rx/take-until stopper))]
(rx/concat stream (rx/of (dws/send endmsg))))))) (rx/concat stream (rx/of (dws/send endmsg)))))))

View file

@ -16,7 +16,6 @@
[app.common.types.shape-tree :as ctst] [app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.drawing.common :as dwdc] [app.main.data.workspace.drawing.common :as dwdc]
[app.main.data.workspace.edition :as dwe] [app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.changes :as changes]
@ -166,16 +165,16 @@
(ptk/reify ::start-path-from-point (ptk/reify ::start-path-from-point
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [stoper (rx/merge (let [stopper (rx/merge
(->> stream (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
(->> stream (->> stream
(rx/filter helpers/end-path-event?))) (rx/filter helpers/end-path-event?)))
drag-events (->> (streams/position-stream state) drag-events (->> (streams/position-stream state)
(rx/map #(drag-handler %)) (rx/map #(drag-handler %))
(rx/take-until stoper))] (rx/take-until stopper))]
(rx/concat (rx/concat
(rx/of (add-node position)) (rx/of (add-node position))
(streams/drag-stream (streams/drag-stream
@ -197,16 +196,16 @@
"should be a pointer" "should be a pointer"
(gpt/point? down-event)) (gpt/point? down-event))
(let [stoper (rx/merge (let [stopper (rx/merge
(->> stream (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
(->> stream (->> stream
(rx/filter helpers/end-path-event?))) (rx/filter helpers/end-path-event?)))
drag-events (->> (streams/position-stream state) drag-events (->> (streams/position-stream state)
(rx/map #(drag-handler %)) (rx/map #(drag-handler %))
(rx/take-until stoper))] (rx/take-until stopper))]
(rx/concat (rx/concat
(rx/of (add-node down-event)) (rx/of (add-node down-event))
(streams/drag-stream (streams/drag-stream
@ -307,10 +306,8 @@
(ptk/reify ::handle-new-shape (ptk/reify ::handle-new-shape
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [id (st/get-path-id state) (let [shape (cts/setup-shape {:type :path})]
shape (cts/setup-shape {:type :path})]
(-> state (-> state
(assoc-in [:workspace-local :edit-path id :snap-toggled] false)
(update :workspace-drawing assoc :object shape)))) (update :workspace-drawing assoc :object shape))))
ptk/WatchEvent ptk/WatchEvent
@ -357,13 +354,14 @@
(let [id (st/get-path-id state) (let [id (st/get-path-id state)
content (st/get-path state :content) content (st/get-path state :content)
old-content (get-in state [:workspace-local :edit-path id :old-content]) old-content (get-in state [:workspace-local :edit-path id :old-content])
mode (get-in state [:workspace-local :edit-path id :edit-mode])] mode (get-in state [:workspace-local :edit-path id :edit-mode])
empty-content? (empty? content)]
(cond (cond
(not= content old-content) (rx/of (changes/save-path-content) (and (not= content old-content) (not empty-content?)) (rx/of (changes/save-path-content))
(start-draw-mode))
(= mode :draw) (rx/of :interrupt) (= mode :draw) (rx/of :interrupt)
:else (rx/of (common/finish-path))))))) :else (rx/of
(common/finish-path)
(dwdc/clear-drawing)))))))
(defn change-edit-mode [mode] (defn change-edit-mode [mode]
(ptk/reify ::change-edit-mode (ptk/reify ::change-edit-mode
@ -378,8 +376,7 @@
(let [id (st/get-path-id state)] (let [id (st/get-path-id state)]
(cond (cond
(and id (= :move mode)) (rx/of (common/finish-path)) (and id (= :move mode)) (rx/of (common/finish-path))
(and id (= :draw mode)) (rx/of (dwc/hide-toolbar) (and id (= :draw mode)) (rx/of (start-draw-mode))
(start-draw-mode))
:else (rx/empty)))))) :else (rx/empty))))))
(defn reset-last-handler (defn reset-last-handler

View file

@ -15,7 +15,6 @@
[app.common.svg.path.shapes-to-path :as upsp] [app.common.svg.path.shapes-to-path :as upsp]
[app.common.svg.path.subpath :as ups] [app.common.svg.path.subpath :as ups]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.edition :as dwe] [app.main.data.workspace.edition :as dwe]
[app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.changes :as changes]
[app.main.data.workspace.path.drawing :as drawing] [app.main.data.workspace.path.drawing :as drawing]
@ -68,7 +67,7 @@
(let [changes (changes/generate-path-changes it objects page-id shape (:content shape) new-content)] (let [changes (changes/generate-path-changes it objects page-id shape (:content shape) new-content)]
(if (empty? new-content) (if (empty? new-content)
(rx/of (dch/commit-changes changes) (rx/of (dch/commit-changes changes)
dwe/clear-edition-mode) (dwe/clear-edition-mode))
(rx/of (dch/commit-changes changes) (rx/of (dch/commit-changes changes)
(selection/update-selection point-change) (selection/update-selection point-change)
(fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler)))))))))) (fn [state] (update-in state [:workspace-local :edit-path id] dissoc :content-modifiers :moving-nodes :moving-handler))))))))))
@ -319,8 +318,7 @@
(= (ptk/type %) ::start-path-edit)))) (= (ptk/type %) ::start-path-edit))))
interrupt (->> stream (rx/filter #(= % :interrupt)) (rx/take 1))] interrupt (->> stream (rx/filter #(= % :interrupt)) (rx/take 1))]
(rx/concat (rx/concat
(rx/of (dwc/hide-toolbar) (rx/of (undo/start-path-undo)
(undo/start-path-undo)
(drawing/change-edit-mode mode)) (drawing/change-edit-mode mode))
(->> interrupt (->> interrupt
(rx/map #(stop-path-edit id)) (rx/map #(stop-path-edit id))

View file

@ -120,12 +120,12 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [zoom (get-in state [:workspace-local :zoom] 1) (let [zoom (get-in state [:workspace-local :zoom] 1)
stoper (rx/merge stopper (rx/merge
(->> stream (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
(->> stream (->> stream
(rx/filter dwc/interrupt?))) (rx/filter dwc/interrupt?)))
from-p @ms/mouse-position] from-p @ms/mouse-position]
(rx/concat (rx/concat
@ -133,7 +133,7 @@
(rx/map #(grc/points->rect [from-p %])) (rx/map #(grc/points->rect [from-p %]))
(rx/filter (partial valid-rect? zoom)) (rx/filter (partial valid-rect? zoom))
(rx/map update-area-selection) (rx/map update-area-selection)
(rx/take-until stoper)) (rx/take-until stopper))
(rx/of (select-node-area shift?) (rx/of (select-node-area shift?)
(clear-area-selection)))))))) (clear-area-selection))))))))

View file

@ -8,7 +8,6 @@
(:require (:require
[app.main.data.shortcuts :as ds] [app.main.data.shortcuts :as ds]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.path :as drp] [app.main.data.workspace.path :as drp]
[app.main.store :as st] [app.main.store :as st]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -24,16 +23,12 @@
(ptk/reify ::esc-pressed (ptk/reify ::esc-pressed
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
;; Not interrupt when we're editing a path ;; Not interrupt when we're editing a path
(let [edition-id (or (get-in state [:workspace-drawing :object :id]) (let [edition-id (or (get-in state [:workspace-drawing :object :id])
(get-in state [:workspace-local :edition])) (get-in state [:workspace-local :edition]))
content (get-in state [:workspace-drawing :object :content])
path-edit-mode (get-in state [:workspace-local :edit-path edition-id :edit-mode])] path-edit-mode (get-in state [:workspace-local :edit-path edition-id :edit-mode])]
(if-not (= :draw path-edit-mode) (when-not (= :draw path-edit-mode)
(rx/of :interrupt) (rx/of :interrupt))))))
(if (<= (count content) 1)
(rx/of (dwc/show-toolbar))
(rx/empty)))))))
(def shortcuts (def shortcuts
{:move-nodes {:tooltip "M" {:move-nodes {:tooltip "M"

View file

@ -6,13 +6,48 @@
(ns app.main.data.workspace.path.state (ns app.main.data.workspace.path.state
(:require (:require
[app.common.data.macros :as dm]
[app.common.files.helpers :as cph]
[app.common.svg.path.shapes-to-path :as upsp])) [app.common.svg.path.shapes-to-path :as upsp]))
(defn path-editing?
"Returns true if we're editing a path or creating a new one."
[{local :workspace-local
drawing :workspace-drawing}]
(let [selected (:selected local)
edition (:edition local)
drawing-obj (:object drawing)
drawing-tool (:tool drawing)
edit-path? (dm/get-in local [:edit-path edition])
shape (or drawing-obj (first selected))
shape-id (:id shape)
single? (= (count selected) 1)
editing? (and (some? shape-id)
(some? edition)
(= shape-id edition))
;; we need to check if we're drawing a new object but we're
;; not using the pencil tool.
draw-path? (and (some? drawing-obj)
(cph/path-shape? drawing-obj)
(not= :curve drawing-tool))]
(or (and ^boolean single?
^boolean editing?
(and (not (cph/text-shape? shape))
(not (cph/frame-shape? shape))))
draw-path?
edit-path?)))
(defn get-path-id (defn get-path-id
"Retrieves the currently editing path id" "Retrieves the currently editing path id"
[state] [state]
(or (get-in state [:workspace-local :edition]) (or (dm/get-in state [:workspace-local :edition])
(get-in state [:workspace-drawing :object :id]))) (dm/get-in state [:workspace-drawing :object :id])))
(defn get-path-location (defn get-path-location
[state & ks] [state & ks]

View file

@ -52,19 +52,19 @@
start (-> @ms/mouse-position to-pixel-snap) start (-> @ms/mouse-position to-pixel-snap)
stoper (rx/merge stopper (rx/merge
(->> st/stream (->> st/stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
(->> st/stream (->> st/stream
(rx/filter finish-edition?))) (rx/filter finish-edition?)))
position-stream position-stream
(->> ms/mouse-position (->> ms/mouse-position
(rx/map to-pixel-snap) (rx/map to-pixel-snap)
(rx/filter (dragging? start zoom)) (rx/filter (dragging? start zoom))
(rx/take 1) (rx/take 1)
(rx/take-until stoper))] (rx/take-until stopper))]
(rx/merge (rx/merge
(->> position-stream (->> position-stream

View file

@ -40,7 +40,7 @@
(rx/of (dch/update-shapes [id] upsp/convert-to-path)) (rx/of (dch/update-shapes [id] upsp/convert-to-path))
(rx/of (dch/commit-changes changes) (rx/of (dch/commit-changes changes)
(when (empty? new-content) (when (empty? new-content)
dwe/clear-edition-mode)))))))))) (dwe/clear-edition-mode)))))))))))
(defn make-corner (defn make-corner
([] ([]

View file

@ -9,7 +9,9 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.undo-stack :as u] [app.common.data.undo-stack :as u]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.path.changes :as changes] [app.main.data.workspace.path.changes :as changes]
[app.main.data.workspace.path.common :as common]
[app.main.data.workspace.path.state :as st] [app.main.data.workspace.path.state :as st]
[app.main.store :as store] [app.main.store :as store]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -65,8 +67,14 @@
undo-stack))))) undo-stack)))))
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ state _]
(rx/of (changes/save-path-content {:preserve-move-to true}))))) (let [id (st/get-path-id state)
undo-stack (get-in state [:workspace-local :edit-path id :undo-stack])]
(if (> (:index undo-stack) 0)
(rx/of (changes/save-path-content {:preserve-move-to true}))
(rx/of (changes/save-path-content {:preserve-move-to true})
(common/finish-path)
(dwc/show-toolbar)))))))
(defn redo-path [] (defn redo-path []
(ptk/reify ::redo-path (ptk/reify ::redo-path

View file

@ -37,7 +37,7 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(log/debug :hint "initialize persistence") (log/debug :hint "initialize persistence")
(let [stoper (rx/filter (ptk/type? ::initialize-persistence) stream) (let [stopper (rx/filter (ptk/type? ::initialize-persistence) stream)
commits (l/atom []) commits (l/atom [])
saving? (l/atom false) saving? (l/atom false)
@ -53,7 +53,7 @@
on-dirty on-dirty
(fn [] (fn []
;; Enable reload stoper ;; Enable reload stopper
(swap! st/ongoing-tasks conj :workspace-change) (swap! st/ongoing-tasks conj :workspace-change)
(st/emit! (update-persistence-status {:status :pending}))) (st/emit! (update-persistence-status {:status :pending})))
@ -64,7 +64,7 @@
on-saved on-saved
(fn [] (fn []
;; Disable reload stoper ;; Disable reload stopper
(swap! st/ongoing-tasks disj :workspace-change) (swap! st/ongoing-tasks disj :workspace-change)
(st/emit! (update-persistence-status {:status :saved})) (st/emit! (update-persistence-status {:status :saved}))
(reset! saving? false))] (reset! saving? false))]
@ -82,7 +82,7 @@
(assoc :file-id file-id)))) (assoc :file-id file-id))))
(rx/observe-on :async) (rx/observe-on :async)
(rx/tap #(swap! commits conj %)) (rx/tap #(swap! commits conj %))
(rx/take-until (rx/delay 100 stoper)) (rx/take-until (rx/delay 100 stopper))
(rx/finalize (fn [] (rx/finalize (fn []
(log/debug :hint "finalize persistence: changes watcher")))) (log/debug :hint "finalize persistence: changes watcher"))))
@ -115,7 +115,7 @@
(rx/tap on-saved) (rx/tap on-saved)
(rx/ignore))) (rx/ignore)))
(rx/empty)))) (rx/empty))))
(rx/take-until (rx/delay 100 stoper)) (rx/take-until (rx/delay 100 stopper))
(rx/finalize (fn [] (rx/finalize (fn []
(log/debug :hint "finalize persistence: save loop")))) (log/debug :hint "finalize persistence: save loop"))))
@ -126,7 +126,7 @@
(rx/filter library-file?) (rx/filter library-file?)
(rx/filter (complement #(empty? (:changes %)))) (rx/filter (complement #(empty? (:changes %))))
(rx/map persist-synchronous-changes) (rx/map persist-synchronous-changes)
(rx/take-until (rx/delay 100 stoper)) (rx/take-until (rx/delay 100 stopper))
(rx/finalize (fn [] (rx/finalize (fn []
(log/debug :hint "finalize persistence: synchronous save loop"))))))))) (log/debug :hint "finalize persistence: synchronous save loop")))))))))

View file

@ -64,12 +64,12 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [zoom (dm/get-in state [:workspace-local :zoom] 1) (let [zoom (dm/get-in state [:workspace-local :zoom] 1)
stoper (rx/merge stopper (rx/merge
(->> stream (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
(->> stream (->> stream
(rx/filter interrupt?))) (rx/filter interrupt?)))
init-position @ms/mouse-position init-position @ms/mouse-position
@ -99,7 +99,7 @@
(rx/scan calculate-selrect init-selrect) (rx/scan calculate-selrect init-selrect)
(rx/filter #(or (> (dm/get-prop % :width) (/ 10 zoom)) (rx/filter #(or (> (dm/get-prop % :width) (/ 10 zoom))
(> (dm/get-prop % :height) (/ 10 zoom)))) (> (dm/get-prop % :height) (/ 10 zoom))))
(rx/take-until stoper))] (rx/take-until stopper))]
(rx/concat (rx/concat
(if preserve? (if preserve?
@ -667,9 +667,9 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stoper (rx/filter (ptk/type? ::memorize-duplicated) stream)] (let [stopper (rx/filter (ptk/type? ::memorize-duplicated) stream)]
(->> (rx/timer 10000) ;; This time may be adjusted after some user testing. (->> (rx/timer 10000) ;; This time may be adjusted after some user testing.
(rx/take-until stoper) (rx/take-until stopper)
(rx/map clear-memorize-duplicated)))))) (rx/map clear-memorize-duplicated))))))
(defn calc-duplicate-delta (defn calc-duplicate-delta

View file

@ -228,13 +228,13 @@
:subsections [:text-editor] :subsections [:text-editor]
:fn #(update-attrs-when-no-readonly {:text-decoration "toggle-line-through"})} :fn #(update-attrs-when-no-readonly {:text-decoration "toggle-line-through"})}
:font-size-inc {:tooltip (ds/meta-shift ds/up-arrow) :font-size-inc {:tooltip (ds/meta-shift ds/right-arrow)
:command (ds/c-mod "shift+up") :command (ds/c-mod "shift+right")
:subsections [:text-editor] :subsections [:text-editor]
:fn #(update-attrs-when-no-readonly {:font-size-inc true})} :fn #(update-attrs-when-no-readonly {:font-size-inc true})}
:font-size-dec {:tooltip (ds/meta-shift ds/down-arrow) :font-size-dec {:tooltip (ds/meta-shift ds/left-arrow)
:command (ds/c-mod "shift+down") :command (ds/c-mod "shift+left")
:subsections [:text-editor] :subsections [:text-editor]
:fn #(update-attrs-when-no-readonly {:font-size-dec true})} :fn #(update-attrs-when-no-readonly {:font-size-dec true})}

View file

@ -370,9 +370,9 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stoper (->> stream (let [stopper (->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-up-event?)) (rx/filter mse/mouse-up-event?))
group (gsh/shapes->rect shapes) group (gsh/shapes->rect shapes)
group-center (grc/rect->center group) group-center (grc/rect->center group)
@ -399,7 +399,7 @@
(fn [[pos mod? shift?]] (fn [[pos mod? shift?]]
(let [delta-angle (calculate-angle pos mod? shift?)] (let [delta-angle (calculate-angle pos mod? shift?)]
(dwm/set-rotation-modifiers delta-angle shapes group-center)))) (dwm/set-rotation-modifiers delta-angle shapes group-center))))
(rx/take-until stoper)) (rx/take-until stopper))
(rx/of (dwm/apply-modifiers) (rx/of (dwm/apply-modifiers)
(finish-transform))))))) (finish-transform)))))))

View file

@ -196,9 +196,6 @@
(def context-menu (def context-menu
(l/derived :context-menu workspace-local)) (l/derived :context-menu workspace-local))
(def toolbar-visibility
(l/derived :hide-toolbar workspace-local))
;; page item that it is being edited ;; page item that it is being edited
(def editing-page-item (def editing-page-item
(l/derived :page-item workspace-local)) (l/derived :page-item workspace-local))

View file

@ -32,7 +32,7 @@
ref (gobj/get props "container") ref (gobj/get props "container")
ids (gobj/get props "ids") ids (gobj/get props "ids")
list-class (gobj/get props "list-class") list-class (gobj/get props "list-class")
ids (filter some? ids) ids (filter some? ids)
on-click on-click
(fn [event] (fn [event]
(let [target (dom/get-target event) (let [target (dom/get-target event)
@ -69,7 +69,7 @@
actual-index (d/index-of ids actual-id) actual-index (d/index-of ids actual-id)
previous-id (if (= 0 actual-index) previous-id (if (= 0 actual-index)
(last ids) (last ids)
(nth ids (- actual-index 1)))] (get ids (- actual-index 1) (last ids)))]
(dom/focus! (dom/get-element previous-id)))) (dom/focus! (dom/get-element previous-id))))
(when (kbd/down-arrow? event) (when (kbd/down-arrow? event)
@ -78,8 +78,9 @@
actual-index (d/index-of ids actual-id) actual-index (d/index-of ids actual-id)
next-id (if (= (- len 1) actual-index) next-id (if (= (- len 1) actual-index)
(first ids) (first ids)
(nth ids (+ 1 actual-index)))] (get ids (+ 1 actual-index) (first ids)))
(dom/focus! (dom/get-element next-id)))) node-item (dom/get-element next-id)]
(dom/focus! node-item)))
(when (kbd/tab? event) (when (kbd/tab? event)
(on-close))))] (on-close))))]
@ -100,5 +101,10 @@
(assert (fn? (gobj/get props "on-close")) "missing `on-close` prop") (assert (fn? (gobj/get props "on-close")) "missing `on-close` prop")
(assert (boolean? (gobj/get props "show")) "missing `show` prop") (assert (boolean? (gobj/get props "show")) "missing `show` prop")
(when (gobj/get props "show") (let [ids (obj/get props "ids")
(mf/element dropdown-menu' props))) ids (d/nilv ids (->> (obj/get props "children")
(keep #(obj/get-in % ["props" "id"]))))]
(when (gobj/get props "show")
(mf/element
dropdown-menu'
(mf/spread-props props {:ids ids})))))

View file

@ -14,6 +14,8 @@
} }
.radio-icon { .radio-icon {
--radio-icon-border-color: var(--radio-btn-border-color);
@include buttonStyle; @include buttonStyle;
@include flexCenter; @include flexCenter;
@include focusRadio; @include focusRadio;
@ -21,6 +23,8 @@
flex-grow: 1; flex-grow: 1;
border-radius: $s-8; border-radius: $s-8;
box-sizing: border-box; box-sizing: border-box;
border: $br-2 solid var(--radio-icon-border-color);
input { input {
display: none; display: none;
} }
@ -37,20 +41,31 @@
stroke: var(--radio-btn-foreground-color-selected); stroke: var(--radio-btn-foreground-color-selected);
} }
} }
}
&.checked { .checked {
background-color: var(--radio-btn-background-color-selected); --radio-icon-border-color: var(--radio-btn-border-color-selected);
border-color: var(--radio-btn-border-color-selected);
svg { background-color: var(--radio-btn-background-color-selected);
stroke: var(--radio-btn-foreground-color-selected); svg {
} stroke: var(--radio-btn-foreground-color-selected);
.title-name {
color: var(--radio-btn-foreground-color-selected);
}
} }
.title-name {
color: var(--radio-btn-foreground-color-selected);
}
}
&.disabled { .disabled {
cursor: default; cursor: default;
background-color: transparent;
border: $s-2 solid transparent;
svg {
stroke: var(--button-foreground-color-disabled);
}
.title-name {
color: var(--button-foreground-color-disabled);
}
&:hover {
background-color: transparent; background-color: transparent;
border: $s-2 solid transparent; border: $s-2 solid transparent;
svg { svg {
@ -59,15 +74,5 @@
.title-name { .title-name {
color: var(--button-foreground-color-disabled); color: var(--button-foreground-color-disabled);
} }
&:hover {
background-color: transparent;
border: $s-2 solid transparent;
svg {
stroke: var(--button-foreground-color-disabled);
}
.title-name {
color: var(--button-foreground-color-disabled);
}
}
} }
} }

View file

@ -196,57 +196,69 @@
open-menu? (mf/use-state false) open-menu? (mf/use-state false)
edit? (mf/use-state false) edit? (mf/use-state false)
state* (mf/use-var (:font-family font)) state* (mf/use-state (:font-family font))
font-family (deref state*) font-family (deref state*)
on-change on-change
(fn [event] (mf/use-callback
(reset! state* (dom/get-target-val event))) (fn [event]
(reset! state* (dom/get-target-val event))))
on-save on-save
(fn [_] (mf/use-callback
(let [font-family font-family] (mf/deps font-family)
(when-not (str/blank? font-family) (fn [_]
(st/emit! (df/update-font (when-not (str/blank? font-family)
{:id font-id (st/emit! (df/update-font {:id font-id :name font-family})))
:name font-family}))) (reset! edit? false)))
(reset! edit? false)))
on-key-down on-key-down
(fn [event] (mf/use-callback
(when (kbd/enter? event) (mf/deps on-save)
(on-save event))) (fn [event]
(when (kbd/enter? event)
(on-save event))))
on-cancel on-cancel
(fn [_] (mf/use-callback
(reset! edit? false) (fn [_]
(reset! state* (:font-family font))) (reset! edit? false)
(reset! state* (:font-family font))))
delete-font-fn delete-font-fn
(fn [] (st/emit! (df/delete-font font-id))) (mf/use-callback
(mf/deps font-id)
(fn []
(st/emit! (df/delete-font font-id))))
delete-variant-fn delete-variant-fn
(fn [id] (st/emit! (df/delete-font-variant id))) (mf/use-callback
(fn [id]
(st/emit! (df/delete-font-variant id))))
on-delete on-delete
(fn [] (mf/use-callback
(st/emit! (modal/show (mf/deps delete-font-fn)
{:type :confirm (fn []
:title (tr "modals.delete-font.title") (st/emit! (modal/show
:message (tr "modals.delete-font.message") {:type :confirm
:accept-label (tr "labels.delete") :title (tr "modals.delete-font.title")
:on-accept (fn [_props] (delete-font-fn))}))) :message (tr "modals.delete-font.message")
:accept-label (tr "labels.delete")
:on-accept (fn [_props] (delete-font-fn))}))))
on-delete-variant on-delete-variant
(fn [id] (mf/use-callback
(st/emit! (modal/show (mf/deps delete-variant-fn)
{:type :confirm (fn [id]
:title (tr "modals.delete-font-variant.title") (st/emit! (modal/show
:message (tr "modals.delete-font-variant.message") {:type :confirm
:accept-label (tr "labels.delete") :title (tr "modals.delete-font-variant.title")
:on-accept (fn [_props] :message (tr "modals.delete-font-variant.message")
(delete-variant-fn id))})))] :accept-label (tr "labels.delete")
:on-accept (fn [_props]
(delete-variant-fn id))}))))]
[:div {:class (stl/css :font-item :table-row)} [:div {:class (stl/css :font-item :table-row)}
[:div {:class (stl/css :table-field :family)} [:div {:class (stl/css :table-field :family)}

View file

@ -95,6 +95,9 @@
;; --- Grid Item Library ;; --- Grid Item Library
(def ^:private menu-icon
(i/icon-xref :menu-refactor (stl/css :menu-icon)))
(mf/defc grid-item-library (mf/defc grid-item-library
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [file] :as props}] [{:keys [file] :as props}]
@ -381,7 +384,7 @@
(when (kbd/enter? event) (when (kbd/enter? event)
(dom/stop-propagation event) (dom/stop-propagation event)
(on-menu-click event)))} (on-menu-click event)))}
i/actions menu-icon
(when (and selected? file-menu-open?) (when (and selected? file-menu-open?)
[:& file-menu {:files (vals selected-files) [:& file-menu {:files (vals selected-files)
:show? (:menu-open dashboard-local) :show? (:menu-open dashboard-local)

View file

@ -220,40 +220,40 @@ $thumbnail-default-height: $s-168; // Default width
span { span {
color: $db-secondary; color: $db-secondary;
} }
}
.project-th-icon { .project-th-icon {
align-items: center; align-items: center;
display: flex; display: flex;
margin-right: $s-8; margin-right: $s-8;
margin-top: 0; margin-top: 0;
}
&.menu { .menu {
align-items: flex-end; align-items: flex-end;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: $s-32; height: $s-32;
justify-content: center; justify-content: center;
margin-right: 0; margin-right: 0;
margin-top: $s-20; margin-top: $s-20;
width: 100%; width: 100%;
--menu-icon-color: var(--button-tertiary-foreground-color-rest);
> svg { &:hover,
fill: $df-secondary; &:focus {
margin-right: 0; --menu-icon-color: var(--button-tertiary-foreground-color-hover);
height: $s-16;
width: $s-16;
}
&:hover,
&:focus {
> svg {
fill: $da-tertiary;
}
}
}
} }
} }
.menu-icon {
stroke: var(--menu-icon-color);
fill: none;
margin-right: 0;
height: $s-16;
width: $s-16;
}
.project-th-actions.force-display { .project-th-actions.force-display {
opacity: 1; opacity: 1;
} }

View file

@ -34,6 +34,9 @@
[potok.v2.core :as ptk] [potok.v2.core :as ptk]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def ^:private show-more-icon
(i/icon-xref :arrow-refactor (stl/css :show-more-icon)))
(mf/defc header (mf/defc header
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[] []
@ -314,7 +317,7 @@
:aria-label (tr "dashboard.new-file") :aria-label (tr "dashboard.new-file")
:data-test "project-new-file" :data-test "project-new-file"
:on-key-down handle-create-click} :on-key-down handle-create-click}
i/close] i/add-refactor]
[:button [:button
{:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom) {:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom)
@ -323,7 +326,7 @@
:aria-label (tr "dashboard.options") :aria-label (tr "dashboard.options")
:data-test "project-options" :data-test "project-options"
:on-key-down handle-menu-click} :on-key-down handle-menu-click}
i/actions]]]] i/menu-refactor]]]]
[:div {:class (stl/css :grid-container) :ref rowref} [:div {:class (stl/css :grid-container) :ref rowref}
[:& line-grid [:& line-grid
@ -343,7 +346,7 @@
(when (kbd/enter? event) (when (kbd/enter? event)
(on-nav)))} (on-nav)))}
[:div {:class (stl/css :placeholder-label)} (tr "dashboard.show-all-files")] [:div {:class (stl/css :placeholder-label)} (tr "dashboard.show-all-files")]
[:div {:class (stl/css :placeholder-icon)} i/arrow-down]])])) show-more-icon])]))
(def recent-files-ref (def recent-files-ref

View file

@ -51,31 +51,6 @@
min-height: $s-32; min-height: $s-32;
margin-left: $s-8; margin-left: $s-8;
} }
.show-more {
align-items: center;
color: $df-secondary;
display: flex;
font-size: $fs-14;
justify-content: space-between;
cursor: pointer;
background-color: transparent;
border: none;
.placeholder-icon {
transform: rotate(-90deg);
margin-left: $s-12;
svg {
height: $s-16;
width: $s-16;
fill: $df-secondary;
}
}
&:hover {
color: $da-tertiary;
svg {
fill: $da-tertiary;
}
}
}
.btn-secondary { .btn-secondary {
border: none; border: none;
@ -137,37 +112,35 @@
opacity: 1; opacity: 1;
} }
} }
}
.show-more { .show-more {
align-items: center; display: flex;
color: $df-secondary; align-items: center;
display: flex; column-gap: $s-12;
font-size: $fs-14;
justify-content: space-between; color: $df-secondary;
cursor: pointer; font-size: $fs-14;
background-color: transparent; justify-content: space-between;
border: none; cursor: pointer;
position: absolute; background-color: transparent;
top: $s-8; border: none;
right: $s-52; position: absolute;
.placeholder-icon { top: $s-8;
transform: rotate(-90deg); right: $s-52;
margin-left: $s-8;
svg { &:hover {
height: $s-16; color: $da-tertiary;
width: $s-16;
fill: $df-secondary;
}
}
&:hover {
color: $da-tertiary;
svg {
fill: $da-tertiary;
}
}
} }
} }
.show-more-icon {
height: $s-16;
width: $s-16;
fill: none;
stroke: currentColor;
}
.team-hero { .team-hero {
background-color: $db-tertiary; background-color: $db-tertiary;
border-radius: $br-8; border-radius: $br-8;

View file

@ -25,6 +25,15 @@
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def ^:private neutral-icon
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
(def ^:private error-icon
(i/icon-xref :delete-text-refactor (stl/css :icon)))
(def ^:private close-icon
(i/icon-xref :close-refactor (stl/css :close-icon)))
(mf/defc export-multiple-dialog (mf/defc export-multiple-dialog
[{:keys [exports title cmd no-selection]}] [{:keys [exports title cmd no-selection]}]
(let [lstate (mf/deref refs/export) (let [lstate (mf/deref refs/export)
@ -198,25 +207,34 @@
(mf/defc export-progress-widget (mf/defc export-progress-widget
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[] []
(let [state (mf/deref refs/export) (let [state (mf/deref refs/export)
error? (:error state) profile (mf/deref refs/profile)
healthy? (:healthy? state) theme (or (:theme profile) "default")
detail-visible? (:detail-visible state) is-default-theme? (= "default" theme)
widget-visible? (:widget-visible state) error? (:error state)
progress (:progress state) healthy? (:healthy? state)
exports (:exports state) detail-visible? (:detail-visible state)
total (count exports) widget-visible? (:widget-visible state)
complete? (= progress total) progress (:progress state)
circ (* 2 Math/PI 12) exports (:exports state)
pct (- circ (* circ (/ progress total))) total (count exports)
complete? (= progress total)
circ (* 2 Math/PI 12)
pct (- circ (* circ (/ progress total)))
pwidth (if error? pwidth (if error?
280 280
(/ (* progress 280) total)) (/ (* progress 280) total))
color (cond color (cond
error? clr/new-danger error? clr/new-danger
healthy? clr/new-primary healthy? (if is-default-theme?
clr/new-primary
clr/new-primary-light)
(not healthy?) clr/new-warning) (not healthy?) clr/new-warning)
background-clr (if is-default-theme?
clr/background-quaternary
clr/background-quaternary-light)
title (cond title (cond
error? (tr "workspace.options.exporting-object-error") error? (tr "workspace.options.exporting-object-error")
complete? (tr "workspace.options.exporting-complete") complete? (tr "workspace.options.exporting-complete")
@ -233,57 +251,60 @@
(when widget-visible? (when widget-visible?
[:div {:class (stl/css :export-progress-widget) [:div {:class (stl/css :export-progress-widget)
:on-click toggle-detail-visibility} :on-click toggle-detail-visibility}
[:svg {:width "32" :height "32"} [:svg {:width "24" :height "24"}
[:circle {:r "12" [:circle {:r "10"
:cx "16" :cx "12"
:cy "16" :cy "12"
:fill "transparent" :fill "transparent"
:stroke clr/gray-40 :stroke background-clr
:stroke-width "4"}] :stroke-width "4"}]
[:circle {:r "12" [:circle {:r "10"
:cx "16" :cx "12"
:cy "16" :cy "12"
:fill "transparent" :fill "transparent"
:stroke color :stroke color
:stroke-width "4" :stroke-width "4"
:stroke-dasharray (dm/str circ " " circ) :stroke-dasharray (dm/str circ " " circ)
:stroke-dashoffset pct :stroke-dashoffset pct
:transform "rotate(-90 16,16)" :transform "rotate(-90 12,12)"
:style {:transition "stroke-dashoffset 1s ease-in-out"}}]]]) :style {:transition "stroke-dashoffset 1s ease-in-out"}}]]])
(when detail-visible? (when detail-visible?
[:div {:class (stl/css :export-progress-modal-overlay)} [:div {:class (stl/css-case :export-progress-modal true
[:div {:class (stl/css :export-progress-modal-container)} :has-error error?)}
[:div {:class (stl/css :export-progress-modal-header)} (if error?
[:p {:class (stl/css :export-progress-modal-title)} error-icon
[:span {:class (stl/css :title-text)} neutral-icon)
title]
(if error?
[:button {:class (stl/css :retry-btn)
:on-click retry-last-export}
(tr "workspace.options.retry")]
[:p {:class (stl/css :progress)} [:p {:class (stl/css :export-progress-title)}
(dm/str progress " / " total)])] title
(if error?
[:button {:class (stl/css :retry-btn)
:on-click retry-last-export}
(tr "workspace.options.retry")]
[:button {:class (stl/css :modal-close-button) [:p {:class (stl/css :progress)}
:on-click toggle-detail-visibility} (dm/str progress " / " total)])]
i/close-refactor]]
[:svg {:class (stl/css :progress-bar) [:button {:class (stl/css :progress-close-button)
:height 5 :on-click toggle-detail-visibility}
:width 280} close-icon]
[:g
[:path {:d "M0 0 L280 0" (when-not error?
:stroke clr/black [:svg {:class (stl/css :progress-bar)
:stroke-width 30}] :height 4
[:path {:d (dm/str "M0 0 L280 0") :width 280}
:stroke color [:g
:stroke-width 30 [:path {:d "M0 0 L280 0"
:fill "transparent" :stroke background-clr
:stroke-dasharray 280 :stroke-width 30}]
:stroke-dashoffset (- 280 pwidth) [:path {:d (dm/str "M0 0 L280 0")
:style {:transition "stroke-dashoffset 1s ease-in-out"}}]]]]])])) :stroke color
:stroke-width 30
:fill "transparent"
:stroke-dasharray 280
:stroke-dashoffset (- 280 pwidth)
:style {:transition "stroke-dashoffset 1s ease-in-out"}}]]])])]))
(def ^:const options [:all :merge :detach]) (def ^:const options [:all :merge :detach])

View file

@ -6,69 +6,101 @@
@import "refactor/common-refactor.scss"; @import "refactor/common-refactor.scss";
.export-progress-modal-overlay { // PROGRESS WIDGET
display: flex; .export-progress-widget {
justify-content: center; @include flexCenter;
position: fixed; width: $s-28;
height: $s-28;
}
// PROGRESS MODAL
.export-progress-modal {
--export-modal-bg-color: var(--alert-background-color-default);
--export-modal-fg-color: var(--alert-text-foreground-color-default);
--export-modal-icon-color: var(--alert-icon-foreground-color-default);
--export-modal-border-color: var(--alert-border-color-default);
position: absolute;
right: $s-16; right: $s-16;
top: $s-48; top: $s-48;
background-color: var(--modal-background-color); display: grid;
grid-template-columns: $s-24 1fr $s-24;
grid-template-areas:
"icon text close"
"bar bar bar";
gap: $s-4 $s-8;
padding-block-start: $s-8;
background-color: var(--export-modal-bg-color);
border: $s-1 solid var(--export-modal-border-color);
border-radius: $br-8; border-radius: $br-8;
z-index: $z-index-20; z-index: $z-index-modal;
overflow: hidden; overflow: hidden;
} }
.export-progress-modal-container { .has-error {
display: flex; --export-modal-bg-color: var(--alert-background-color-error);
flex-direction: column; --export-modal-fg-color: var(--alert-text-foreground-color-error);
justify-content: space-around; --export-modal-icon-color: var(--alert-icon-foreground-color-error);
height: 100%; --export-modal-border-color: var(--alert-border-color-error);
width: 100%; grid-template-areas: "icon text close";
} gap: $s-8;
.export-progress-modal-header { padding-block: $s-8;
display: flex;
align-items: center;
justify-content: stretch;
padding: $s-8;
} }
.export-progress-modal-title { .icon {
display: flex; @extend .button-icon;
flex-grow: 1; grid-area: icon;
padding: 0; align-self: center;
margin: 0; margin-inline-start: $s-8;
stroke: var(--export-modal-icon-color);
} }
.title-text { .export-progress-title {
@include flexCenter; @include bodyMedTipography;
@include bodyLargeTypography; display: grid;
grid-template-columns: auto 1fr;
gap: $s-8;
grid-area: text;
align-self: center;
padding: 0; padding: 0;
margin: 0; margin: 0;
color: var(--modal-title-foreground-color); color: var(--export-modal-fg-color);
padding-left: $s-4;
} }
.progress { .progress {
@include bodyLargeTypography; @include bodyMedTipography;
padding-left: $s-8; padding-left: $s-8;
margin: 0; margin: 0;
align-self: center;
color: var(--modal-text-foreground-color); color: var(--modal-text-foreground-color);
} }
.retry-btn { .retry-btn {
@extend .button-tertiary; @include buttonStyle;
@include bodyMedTipography; @include bodyMedTipography;
display: inline;
text-align: left;
color: var(--modal-link-foreground-color);
margin: 0;
padding: 0;
} }
.modal-close-button { .progress-close-button {
@extend .button-tertiary; @include buttonStyle;
svg { padding: 0;
@extend .button-icon-small; margin-inline-end: $s-8;
stroke: var(--icon-foreground);
}
} }
.close-icon {
@extend .button-icon;
stroke: var(--export-modal-icon-color);
}
.progress-bar { .progress-bar {
margin-top: 0; margin-top: 0;
grid-area: bar;
} }
// EXPORT MODAL
.modal-overlay { .modal-overlay {
@extend .modal-overlay-base; @extend .modal-overlay-base;
&.transparent { &.transparent {

View file

@ -441,6 +441,13 @@
(def ^:icon status-update-refactor (icon-xref :status-update-refactor)) (def ^:icon status-update-refactor (icon-xref :status-update-refactor))
(def ^:icon status-tick-refactor (icon-xref :status-tick-refactor)) (def ^:icon status-tick-refactor (icon-xref :status-tick-refactor))
(def ^:icon status-wrong-refactor (icon-xref :status-wrong-refactor)) (def ^:icon status-wrong-refactor (icon-xref :status-wrong-refactor))
(def ^:icon stroke-arrow-refactor (icon-xref :stroke-arrow-refactor))
(def ^:icon stroke-circle-refactor (icon-xref :stroke-circle-refactor))
(def ^:icon stroke-diamond-refactor (icon-xref :stroke-diamond-refactor))
(def ^:icon stroke-rectangle-refactor (icon-xref :stroke-rectangle-refactor))
(def ^:icon stroke-rounded-refactor (icon-xref :stroke-rounded-refactor))
(def ^:icon stroke-squared-refactor (icon-xref :stroke-squared-refactor))
(def ^:icon stroke-triangle-refactor (icon-xref :stroke-triangle-refactor))
(def ^:icon stroke-size-refactor (icon-xref :stroke-size-refactor)) (def ^:icon stroke-size-refactor (icon-xref :stroke-size-refactor))
(def ^:icon svg-refactor (icon-xref :svg-refactor)) (def ^:icon svg-refactor (icon-xref :svg-refactor))
(def ^:icon swatches-refactor (icon-xref :swatches-refactor)) (def ^:icon swatches-refactor (icon-xref :swatches-refactor))

View file

@ -29,13 +29,12 @@
:links (:links message) :links (:links message)
:content (:content message)} :content (:content message)}
context-message {:actions (:actions message) context-message {:type (or (:type message) :info)
:links (:links message) :links (:links message)
:content (:content message)} :content (:content message)}
;; TODO review this options is-toast-msg (or (= :toast (:notification-type message)) (some? (:timeout message)))
is-toast-msg (or (= :toast (:notification-type message)) (some? (:timeout message))) is-inline-msg (or (= :inline (:notification-type message)) (and (some? (:position message)) (= :floating (:position message))))]
is-inline-msg (or (= :inline (:notification-type message)) (and (some? (:position message)) (= :floating (:position message))))]
(when message (when message
(cond (cond

View file

@ -56,14 +56,13 @@
[:div {:class (stl/css :context-text) [:div {:class (stl/css :context-text)
:dangerouslySetInnerHTML (when is-html #js {:__html content})} :dangerouslySetInnerHTML (when is-html #js {:__html content})}
(when-not is-html (when-not is-html
content)] [:*
content
(when (some? links) (when (some? links)
[:nav {:class (stl/css :link-nav)} (for [[index link] (d/enumerate links)]
(for [[index link] (d/enumerate links)] ;; TODO Review this component
;; TODO Review this component [:& lb/link-button {:class (stl/css :link)
[:& lb/link-button {:class (stl/css :link) :on-click (:callback link)
:on-click (:callback link) :value (:label link)
:value (:label link) :key (dm/str "link-" index)}]))])]])
:key (dm/str "link-" index)}])])])

View file

@ -7,16 +7,18 @@
@import "refactor/common-refactor.scss"; @import "refactor/common-refactor.scss";
.context-notification { .context-notification {
---context-notification-bg-color: var(--alert-background-color-default); --context-notification-bg-color: var(--alert-background-color-default);
--context-notification-fg-color: var(--alert-text-foreground-color-default); --context-notification-fg-color: var(--alert-text-foreground-color-default);
--context-notification-icon-color: var(--alert-icon-foreground-color-default); --context-notification-icon-color: var(--alert-icon-foreground-color-default);
--context-notification-border-color: var(--alert-border-color-default); --context-notification-border-color: var(--alert-border-color-default);
box-sizing: border-box;
display: grid; display: grid;
grid-template-columns: $s-16 auto 1fr; grid-template-columns: $s-16 1fr;
gap: $s-8; gap: $s-8;
min-height: $s-32; min-height: $s-32;
height: fit-content;
width: 100%; width: 100%;
padding: $s-8 $s-8 $s-8 $s-16; padding: $s-8;
border: $s-1 solid var(--context-notification-border-color); border: $s-1 solid var(--context-notification-border-color);
border-radius: $br-8; border-radius: $br-8;
background-color: var(--context-notification-bg-color); background-color: var(--context-notification-bg-color);
@ -63,12 +65,6 @@
stroke: var(--context-notification-icon-color); stroke: var(--context-notification-icon-color);
} }
.link-nav {
align-self: center;
height: $s-24;
margin: 0;
}
.context-text { .context-text {
@include bodyMedTipography; @include bodyMedTipography;
align-self: center; align-self: center;
@ -84,6 +80,8 @@
.contain-html .context-text a { .contain-html .context-text a {
@include bodyMedTipography; @include bodyMedTipography;
align-self: center; align-self: center;
display: inline;
text-align: left;
height: $s-16; height: $s-16;
margin: 0; margin: 0;
color: var(--modal-link-foreground-color); color: var(--modal-link-foreground-color);

View file

@ -11,11 +11,8 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.ui.components.link-button :as lb] [app.main.ui.components.link-button :as lb]
[app.main.ui.icons :as i]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def ^:private neutral-icon
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
(mf/defc inline-notification (mf/defc inline-notification
@ -25,18 +22,17 @@
{::mf/props :obj} {::mf/props :obj}
[{:keys [content actions links] :as props}] [{:keys [content actions links] :as props}]
[:aside {:class (stl/css :inline-notification)} [:aside {:class (stl/css :inline-notification)}
neutral-icon
[:div {:class (stl/css :inline-text)} [:div {:class (stl/css :inline-text)}
content]
(when (some? links) content
[:nav {:class (stl/css :link-nav)}
(for [[index link] (d/enumerate links)] (when (some? links)
[:& lb/link-button {:key (dm/str "link-" index) [:nav {:class (stl/css :link-nav)}
:class (stl/css :link) (for [[index link] (d/enumerate links)]
:on-click (:callback link) [:& lb/link-button {:key (dm/str "link-" index)
:value (:label link)}])]) :class (stl/css :link)
:on-click (:callback link)
:value (:label link)}])])]
[:div {:class (stl/css :actions)} [:div {:class (stl/css :actions)}
(for [action actions] (for [action actions]

View file

@ -9,7 +9,6 @@
.inline-notification { .inline-notification {
--inline-notification-bg-color: var(--alert-background-color-default); --inline-notification-bg-color: var(--alert-background-color-default);
--inline-notification-fg-color: var(--alert-text-foreground-color-default); --inline-notification-fg-color: var(--alert-text-foreground-color-default);
--inline-notification-icon-color: var(--alert-icon-foreground-color-default);
--inline-notification-border-color: var(--alert-border-color-default); --inline-notification-border-color: var(--alert-border-color-default);
@include alertShadow; @include alertShadow;
position: absolute; position: absolute;
@ -17,12 +16,13 @@
left: 0; left: 0;
right: 0; right: 0;
display: grid; display: grid;
grid-template-columns: $s-16 auto 1fr auto; grid-template-columns: 1fr auto;
gap: $s-8; gap: $s-24;
min-height: $s-48; min-height: $s-48;
min-width: $s-640; min-width: $s-640;
max-width: $s-712; width: fit-content;
padding: $s-8 $s-8 $s-8 $s-16; max-width: $s-960;
padding: $s-8;
margin-inline: auto; margin-inline: auto;
border: $s-1 solid var(--inline-notification-border-color); border: $s-1 solid var(--inline-notification-border-color);
border-radius: $br-8; border-radius: $br-8;
@ -31,17 +31,15 @@
color: var(--inline-notification-fg-color); color: var(--inline-notification-fg-color);
} }
.icon {
@extend .button-icon;
height: 100%;
stroke: var(--inline-notification-icon-color);
}
.inline-text { .inline-text {
@include bodyMedTipography; @include bodyMedTipography;
align-self: center; align-self: center;
} }
.link-nav {
display: inline;
}
.link { .link {
@include bodyMedTipography; @include bodyMedTipography;
margin: 0; margin: 0;
@ -53,15 +51,16 @@
display: grid; display: grid;
grid-template-columns: none; grid-template-columns: none;
grid-auto-flow: column; grid-auto-flow: column;
gap: $s-8;
align-self: center; align-self: center;
gap: $s-8;
} }
.action-btn { .action-btn {
@extend .button-tertiary; @extend .button-secondary;
@include uppercaseTitleTipography; @include uppercaseTitleTipography;
min-height: $s-32; min-height: $s-32;
min-width: $s-32; min-width: $s-32;
width: fit-content;
padding: $s-8 $s-24; padding: $s-8 $s-24;
border: $s-1 solid transparent; border: $s-1 solid transparent;
} }

View file

@ -49,7 +49,6 @@
[{:keys [type content on-close links] :as props}] [{:keys [type content on-close links] :as props}]
[:aside {:class (stl/css-case :toast-notification true [:aside {:class (stl/css-case :toast-notification true
:with-links (some? links)
:warning (= type :warning) :warning (= type :warning)
:error (= type :error) :error (= type :error)
:success (= type :success) :success (= type :success)
@ -58,15 +57,16 @@
(get-icon-by-type type) (get-icon-by-type type)
[:div {:class (stl/css :text)} [:div {:class (stl/css :text)}
content] content
(when (some? links)
[:nav {:class (stl/css :link-nav)}
(for [[index link] (d/enumerate links)]
[:& lb/link-button {:key (dm/str "link-" index)
:class (stl/css :link)
:on-click (:callback link)
:value (:label link)}])])]
(when (some? links)
[:nav {:class (stl/css :link-nav)}
(for [[index link] (d/enumerate links)]
[:& lb/link-button {:key (dm/str "link-" index)
:class (stl/css :link)
:on-click (:callback link)
:value (:label link)}])])
[:button {:class (stl/css :btn-close) [:button {:class (stl/css :btn-close)
:on-click on-close} :on-click on-close}

View file

@ -19,9 +19,9 @@
grid-template-columns: $s-16 1fr auto; grid-template-columns: $s-16 1fr auto;
gap: $s-8; gap: $s-8;
min-height: $s-32; min-height: $s-32;
min-width: $s-500; min-width: $s-228;
max-width: calc(10 * $s-100); max-width: $s-400;
padding: $s-8 $s-8 $s-8 $s-16; padding: $s-8;
border: $s-1 solid var(--toast-notification-border-color); border: $s-1 solid var(--toast-notification-border-color);
background-color: var(--toast-notification-bg-color); background-color: var(--toast-notification-bg-color);
border-radius: $br-8; border-radius: $br-8;
@ -29,10 +29,6 @@
z-index: $z-index-alert; z-index: $z-index-alert;
} }
.with-links {
grid-template-columns: $s-16 auto 1fr auto;
}
.warning { .warning {
--toast-notification-bg-color: var(--alert-background-color-warning); --toast-notification-bg-color: var(--alert-background-color-warning);
--toast-notification-fg-color: var(--alert-text-foreground-color-warning); --toast-notification-fg-color: var(--alert-text-foreground-color-warning);
@ -69,7 +65,7 @@
} }
.link-nav { .link-nav {
height: $s-24; display: inline;
} }
.link { .link {
@ -80,7 +76,7 @@
.icon { .icon {
@extend .button-icon; @extend .button-icon;
height: 100%; align-self: flex-start;
stroke: var(--toast-notification-icon-color); stroke: var(--toast-notification-icon-color);
} }
@ -91,9 +87,10 @@
.btn-close { .btn-close {
@include buttonStyle; @include buttonStyle;
@include flexCenter; align-self: flex-start;
height: 100%; width: $s-16;
min-width: $s-32; margin: 0;
padding: 0;
background-color: transparent; background-color: transparent;
} }

View file

@ -20,16 +20,15 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
max-width: $s-368; max-width: $s-500;
margin-bottom: $s-32; margin-bottom: $s-32;
width: $s-580; width: $s-580;
margin: $s-80 auto auto $s-120; margin: $s-80 auto $s-120 auto;
justify-content: center; justify-content: center;
form { form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: $s-500;
.btn-secondary { .btn-secondary {
width: 100%; width: 100%;

View file

@ -97,7 +97,10 @@
(obj/set! "fill" (str "url(#fill-" index "-" render-id ")")))} (obj/set! "fill" (str "url(#fill-" index "-" render-id ")")))}
(cond-> browser-props (cond-> browser-props
(obj/merge! browser-props))) (obj/merge! browser-props)))
shape (assoc shape :fills (:fills data))] shape (assoc shape :fills (:fills data))
;; Need to create new render-id per text-block
render-id (dm/str render-id "-" index)]
[:& (mf/provider muc/render-id) {:key index :value render-id} [:& (mf/provider muc/render-id) {:key index :value render-id}
[:& shape-custom-strokes {:shape shape :position index :render-id render-id} [:& shape-custom-strokes {:shape shape :position index :render-id render-id}

View file

@ -161,6 +161,8 @@
#(st/emit! dv/zoom-to-fit))] #(st/emit! dv/zoom-to-fit))]
[:div {:class (stl/css :options-zone)} [:div {:class (stl/css :options-zone)}
[:& export-progress-widget]
(case section (case section
:interactions [:* :interactions [:*
(when index (when index
@ -169,8 +171,6 @@
:comments [:& comments-menu] :comments [:& comments-menu]
[:div {:class (stl/css :view-options)}]) [:div {:class (stl/css :view-options)}])
[:& export-progress-widget]
[:& zoom-widget [:& zoom-widget
{:zoom zoom {:zoom zoom
:on-increase handle-increase :on-increase handle-increase

View file

@ -18,6 +18,7 @@
[:& title-bar {:collapsable false [:& title-bar {:collapsable false
:title (tr "workspace.options.component.annotation") :title (tr "workspace.options.component.annotation")
:class (stl/css :title-spacing-annotation)} :class (stl/css :title-spacing-annotation)}
[:& copy-button {:data content}]] [:& copy-button {:data content
:class (stl/css :copy-btn-title)}]]
[:div {:class (stl/css :annotation-content)} content]]) [:div {:class (stl/css :annotation-content)} content]])

View file

@ -18,3 +18,7 @@
@include bodyMedTipography; @include bodyMedTipography;
color: var(--entry-foreground-color); color: var(--entry-foreground-color);
} }
.copy-btn-title {
max-width: $s-28;
}

View file

@ -109,7 +109,9 @@
[:span {:class (stl/css :layer-title)} (:name first-shape)]])] [:span {:class (stl/css :layer-title)} (:name first-shape)]])]
[:div {:class (stl/css :inspect-content)} [:div {:class (stl/css :inspect-content)}
[:& tab-container {:on-change-tab handle-change-tab [:& tab-container {:on-change-tab handle-change-tab
:selected @section} :selected @section
:content-class (stl/css :tab-content)
:header-class (stl/css :tab-header)}
[:& tab-element {:id :info :title (tr "inspect.tabs.info")} [:& tab-element {:id :info :title (tr "inspect.tabs.info")}
[:& attributes {:page-id page-id [:& attributes {:page-id page-id
:objects objects :objects objects

View file

@ -96,3 +96,11 @@
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.tab-content {
scrollbar-gutter: stable;
}
.tab-header {
margin-right: $s-12;
}

View file

@ -34,6 +34,7 @@
} }
} }
} }
.active-users-opened { .active-users-opened {
position: absolute; position: absolute;
right: calc(-1 * $s-2); right: calc(-1 * $s-2);

View file

@ -171,7 +171,7 @@
(mf/use-fn (mf/use-fn
(fn [] (fn []
(st/emit! :interrupt (st/emit! :interrupt
dw/clear-edition-mode) (dw/clear-edition-mode))
;; Delay so anything that launched :interrupt can finish ;; Delay so anything that launched :interrupt can finish
(ts/schedule 100 #(st/emit! (dw/select-for-drawing :comments))))) (ts/schedule 100 #(st/emit! (dw/select-for-drawing :comments)))))
@ -203,8 +203,9 @@
[:& persistence-state-widget] [:& persistence-state-widget]
[:div {:class (stl/css :separator)}] [:& export-progress-widget]
[:div {:class (stl/css :separator)}]
[:div {:class (stl/css :zoom-section)} [:div {:class (stl/css :zoom-section)}
[:& zoom-widget-workspace [:& zoom-widget-workspace
@ -215,8 +216,6 @@
:on-zoom-fit on-zoom-fit :on-zoom-fit on-zoom-fit
:on-zoom-selected on-zoom-selected}]] :on-zoom-selected on-zoom-selected}]]
[:& export-progress-widget]
[:div {:class (stl/css :comments-section)} [:div {:class (stl/css :comments-section)}
[:button {:title (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment)) [:button {:title (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))
:aria-label (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment)) :aria-label (tr "workspace.toolbar.comments" (sc/get-tooltip :add-comment))

View file

@ -37,6 +37,8 @@
border-radius: $br-8; border-radius: $br-8;
.label { .label {
@include bodyMedTipography; @include bodyMedTipography;
height: 100%;
padding: $s-8 0;
color: var(--button-tertiary-foreground-color-rest); color: var(--button-tertiary-foreground-color-rest);
} }
@ -180,14 +182,12 @@
.status-icon { .status-icon {
@include flexCenter; @include flexCenter;
width: $s-16; width: $s-24;
height: $s-16; height: $s-24;
margin: 0; margin: 0;
border-radius: $br-circle; border-radius: $br-circle;
svg { svg {
@extend .button-icon; @extend .button-icon;
height: $s-12;
width: $s-12;
stroke: var(--status-widget-icon-foreground-color); stroke: var(--status-widget-icon-foreground-color);
} }
} }

View file

@ -13,7 +13,7 @@
[okulary.core :as l] [okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def primary-color "var(--color-accent-tertiary)") (def accent-color "var(--color-accent-tertiary)")
(def secondary-color "var(--color-accent-quaternary)") (def secondary-color "var(--color-accent-quaternary)")
(def black-color "var(--app-black)") (def black-color "var(--app-black)")
(def white-color "var(--app-white)") (def white-color "var(--app-white)")

View file

@ -89,8 +89,8 @@
:style {:stroke-width (/ point-radius-stroke-width zoom) :style {:stroke-width (/ point-radius-stroke-width zoom)
:stroke (cond (or selected? hover?) pc/black-color :stroke (cond (or selected? hover?) pc/black-color
preview? pc/secondary-color preview? pc/secondary-color
:else pc/primary-color) :else pc/accent-color)
:fill (cond selected? pc/primary-color :fill (cond selected? pc/accent-color
:else pc/white-color)}}] :else pc/white-color)}}]
[:circle {:cx x [:circle {:cx x
:cy y :cy y
@ -150,8 +150,8 @@
:style {:stroke-width (/ handler-stroke-width zoom) :style {:stroke-width (/ handler-stroke-width zoom)
:stroke (cond (or selected? hover?) pc/black-color :stroke (cond (or selected? hover?) pc/black-color
:else pc/primary-color) :else pc/accent-color)
:fill (cond selected? pc/primary-color :fill (cond selected? pc/accent-color
:else pc/white-color)}}] :else pc/white-color)}}]
[:circle {:cx x [:circle {:cx x
:cy y :cy y
@ -288,7 +288,7 @@
[:g.path-editor {:ref editor-ref} [:g.path-editor {:ref editor-ref}
[:path {:d (upf/format-path content) [:path {:d (upf/format-path content)
:style {:fill "none" :style {:fill "none"
:stroke pc/primary-color :stroke pc/accent-color
:strokeWidth (/ 1 zoom)}}] :strokeWidth (/ 1 zoom)}}]
(when (and preview (not drag-handler)) (when (and preview (not drag-handler))
[:& path-preview {:command preview [:& path-preview {:command preview

View file

@ -122,8 +122,7 @@
(fn [event] (fn [event]
(dom/stop-propagation event) (dom/stop-propagation event)
(when (kbd/esc? event) (when (kbd/esc? event)
(st/emit! :interrupt) (st/emit! :interrupt (dw/clear-edition-mode))))
(st/emit! dw/clear-edition-mode)))
on-mount on-mount
(fn [] (fn []

View file

@ -104,7 +104,7 @@
{:on-change-tab on-change-tab {:on-change-tab on-change-tab
:selected section :selected section
:collapsable false :collapsable false
:content-class (stl/css :content-class) :content-class (stl/css-case :content-class true :inspect (= section :inspect))
:header-class (stl/css :tab-spacing)} :header-class (stl/css :tab-spacing)}
[:& tab-element {:id :design [:& tab-element {:id :design
:title (tr "workspace.options.design")} :title (tr "workspace.options.design")}

View file

@ -34,3 +34,7 @@
gap: $s-8; gap: $s-8;
padding-top: $s-8; padding-top: $s-8;
} }
.inspect {
scrollbar-gutter: unset;
}

View file

@ -1279,7 +1279,7 @@
[:button {:on-click open-grid-help [:button {:on-click open-grid-help
:class (stl/css :help-button)} i/help-refactor] :class (stl/css :help-button)} i/help-refactor]
[:button {:class (stl/css :exit-btn) [:button {:class (stl/css :exit-btn)
:on-click #(st/emit! udw/clear-edition-mode)} :on-click #(st/emit! (udw/clear-edition-mode))}
(tr "workspace.layout_grid.editor.options.exit")]] (tr "workspace.layout_grid.editor.options.exit")]]
[:div {:class (stl/css :row :first-row)} [:div {:class (stl/css :row :first-row)}

View file

@ -123,14 +123,14 @@
stroke-caps-options stroke-caps-options
[{:value nil :label (tr "workspace.options.stroke-cap.none")} [{:value nil :label (tr "workspace.options.stroke-cap.none")}
:separator :separator
{:value :line-arrow :label (tr "workspace.options.stroke-cap.line-arrow-short") :icon :cap-line-arrow} {:value :line-arrow :label (tr "workspace.options.stroke-cap.line-arrow-short") :icon :stroke-arrow-refactor}
{:value :triangle-arrow :label (tr "workspace.options.stroke-cap.triangle-arrow-short") :icon :cap-triangle-arrow} {:value :triangle-arrow :label (tr "workspace.options.stroke-cap.triangle-arrow-short") :icon :stroke-triangle-refactor}
{:value :square-marker :label (tr "workspace.options.stroke-cap.square-marker-short") :icon :cap-square-marker} {:value :square-marker :label (tr "workspace.options.stroke-cap.square-marker-short") :icon :stroke-rectangle-refactor}
{:value :circle-marker :label (tr "workspace.options.stroke-cap.circle-marker-short") :icon :cap-circle-marker} {:value :circle-marker :label (tr "workspace.options.stroke-cap.circle-marker-short") :icon :stroke-circle-refactor}
{:value :diamond-marker :label (tr "workspace.options.stroke-cap.diamond-marker-short") :icon :cap-diamond-marker} {:value :diamond-marker :label (tr "workspace.options.stroke-cap.diamond-marker-short") :icon :stroke-diamond-refactor}
:separator :separator
{:value :round :label (tr "workspace.options.stroke-cap.round") :icon :cap-round} {:value :round :label (tr "workspace.options.stroke-cap.round") :icon :stroke-rounded-refactor}
{:value :square :label (tr "workspace.options.stroke-cap.square") :icon :cap-square}] {:value :square :label (tr "workspace.options.stroke-cap.square") :icon :stroke-squared-refactor}]
on-cap-switch on-cap-switch
(mf/use-callback (mf/use-callback

View file

@ -7,12 +7,14 @@
(ns app.main.ui.workspace.top-toolbar (ns app.main.ui.workspace.top-toolbar
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.media :as cm] [app.common.media :as cm]
[app.main.data.events :as ev] [app.main.data.events :as ev]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.media :as dwm] [app.main.data.workspace.media :as dwm]
[app.main.data.workspace.path.state :as pst]
[app.main.data.workspace.shortcuts :as sc] [app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
@ -22,6 +24,7 @@
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.timers :as ts] [app.util.timers :as ts]
[okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc image-upload (mf/defc image-upload
@ -33,7 +36,7 @@
on-click on-click
(mf/use-fn (mf/use-fn
(fn [] (fn []
(st/emit! :interrupt dw/clear-edition-mode) (st/emit! :interrupt (dw/clear-edition-mode))
(dom/click (mf/ref-val ref)))) (dom/click (mf/ref-val ref))))
on-selected on-selected
@ -53,7 +56,8 @@
[:button [:button
{:title (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image)) {:title (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
:aria-label (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image)) :aria-label (tr "workspace.toolbar.image" (sc/get-tooltip :insert-image))
:on-click on-click} :on-click on-click
:class (stl/css :main-toolbar-options-button)}
i/img-refactor i/img-refactor
[:& file-uploader [:& file-uploader
{:input-id "image-upload" {:input-id "image-upload"
@ -62,6 +66,15 @@
:ref ref :ref ref
:on-selected on-selected}]]])) :on-selected on-selected}]]]))
(def toolbar-hidden
(l/derived
(fn [state]
(let [visibility (dm/get-in state [:workspace-local :hide-toolbar])
editing? (pst/path-editing? state)
hidden? (if editing? true visibility)]
hidden?))
st/state))
(mf/defc top-toolbar (mf/defc top-toolbar
{::mf/wrap [mf/memo] {::mf/wrap [mf/memo]
::mf/wrap-props false} ::mf/wrap-props false}
@ -72,7 +85,7 @@
read-only? (mf/use-ctx ctx/workspace-read-only?) read-only? (mf/use-ctx ctx/workspace-read-only?)
rulers? (mf/deref refs/rulers?) rulers? (mf/deref refs/rulers?)
hide-toolbar? (mf/deref refs/toolbar-visibility) hide-toolbar? (mf/deref toolbar-hidden)
interrupt interrupt
(mf/use-fn #(st/emit! :interrupt)) (mf/use-fn #(st/emit! :interrupt))
@ -83,8 +96,7 @@
(let [tool (-> (dom/get-current-target event) (let [tool (-> (dom/get-current-target event)
(dom/get-data "tool") (dom/get-data "tool")
(keyword))] (keyword))]
(st/emit! :interrupt (st/emit! :interrupt (dw/clear-edition-mode))
dw/clear-edition-mode)
;; Delay so anything that launched :interrupt can finish ;; Delay so anything that launched :interrupt can finish
(ts/schedule 100 #(st/emit! (dw/select-for-drawing tool)))))) (ts/schedule 100 #(st/emit! (dw/select-for-drawing tool))))))
@ -114,7 +126,8 @@
[:button [:button
{:title (tr "workspace.toolbar.move" (sc/get-tooltip :move)) {:title (tr "workspace.toolbar.move" (sc/get-tooltip :move))
:aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move)) :aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move))
:class (stl/css-case :selected (and (nil? selected-drawtool) :class (stl/css-case :main-toolbar-options-button true
:selected (and (nil? selected-drawtool)
(not edition))) (not edition)))
:on-click interrupt} :on-click interrupt}
i/move-refactor]] i/move-refactor]]
@ -123,7 +136,7 @@
[:button [:button
{:title (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame)) {:title (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
:aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame)) :aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
:class (stl/css-case :selected (= selected-drawtool :frame)) :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :frame))
:on-click select-drawtool :on-click select-drawtool
:data-tool "frame" :data-tool "frame"
:data-test "artboard-btn"} :data-test "artboard-btn"}
@ -132,7 +145,7 @@
[:button [:button
{:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) {:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
:aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) :aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
:class (stl/css-case :selected (= selected-drawtool :rect)) :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :rect))
:on-click select-drawtool :on-click select-drawtool
:data-tool "rect" :data-tool "rect"
:data-test "rect-btn"} :data-test "rect-btn"}
@ -141,7 +154,7 @@
[:button [:button
{:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) {:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
:aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) :aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
:class (stl/css-case :selected (= selected-drawtool :circle)) :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :circle))
:on-click select-drawtool :on-click select-drawtool
:data-tool "circle" :data-tool "circle"
:data-test "ellipse-btn"} :data-test "ellipse-btn"}
@ -150,7 +163,7 @@
[:button [:button
{:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) {:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
:aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) :aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
:class (stl/css-case :selected (= selected-drawtool :text)) :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :text))
:on-click select-drawtool :on-click select-drawtool
:data-tool "text"} :data-tool "text"}
i/text-refactor]] i/text-refactor]]
@ -161,7 +174,7 @@
[:button [:button
{:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) {:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
:aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) :aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
:class (stl/css-case :selected (= selected-drawtool :curve)) :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :curve))
:on-click select-drawtool :on-click select-drawtool
:data-tool "curve" :data-tool "curve"
:data-test "curve-btn"} :data-test "curve-btn"}
@ -170,7 +183,7 @@
[:button [:button
{:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) {:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
:aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) :aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
:class (stl/css-case :selected (= selected-drawtool :path)) :class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :path))
:on-click select-drawtool :on-click select-drawtool
:data-tool "path" :data-tool "path"
:data-test "path-btn"} :data-test "path-btn"}
@ -180,7 +193,7 @@
[:li [:li
[:button [:button
{:title "Debugging tool" {:title "Debugging tool"
:class (stl/css-case :selected (contains? layout :debug-panel)) :class (stl/css-case :main-toolbar-options-button true :selected (contains? layout :debug-panel))
:on-click toggle-debug-panel} :on-click toggle-debug-panel}
i/bug-refactor]])]] i/bug-refactor]])]]

View file

@ -48,25 +48,24 @@
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
li { li {
position: relative; position: relative;
}
}
button { .main-toolbar-options-button {
@extend .button-tertiary; @extend .button-tertiary;
height: $s-36; height: $s-36;
width: $s-36; width: $s-36;
flex-shrink: 0; flex-shrink: 0;
border-radius: $s-8; border-radius: $s-8;
border: none; margin: 0 $s-2;
margin: 0 $s-2;
svg { svg {
@extend .button-icon; @extend .button-icon;
stroke: var(--color-foreground-secondary); stroke: var(--color-foreground-secondary);
} }
&.selected { &.selected {
@extend .button-icon-selected; @extend .button-icon-selected;
}
}
} }
} }

View file

@ -90,7 +90,7 @@
::dwsp/interrupt) ::dwsp/interrupt)
(when (and (not= edition id) (or text-editing? grid-editing?)) (when (and (not= edition id) (or text-editing? grid-editing?))
(st/emit! dw/clear-edition-mode)) (st/emit! (dw/clear-edition-mode)))
(when (and (not text-editing?) (when (and (not text-editing?)
(not blocked) (not blocked)

View file

@ -8,6 +8,7 @@
"Drawing components." "Drawing components."
(:require (:require
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.shape :as cts]
[app.main.ui.shapes.path :refer [path-shape]] [app.main.ui.shapes.path :refer [path-shape]]
[app.main.ui.workspace.shapes :as shapes] [app.main.ui.workspace.shapes :as shapes]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor]] [app.main.ui.workspace.shapes.path.editor :refer [path-editor]]
@ -19,14 +20,16 @@
(mf/defc draw-area (mf/defc draw-area
[{:keys [shape zoom tool] :as props}] [{:keys [shape zoom tool] :as props}]
[:g.draw-area ;; Prevent rendering something that it's not a shape.
[:g {:style {:pointer-events "none"}} (when (cts/shape? shape)
[:& shapes/shape-wrapper {:shape shape}]] [:g.draw-area
[:g {:style {:pointer-events "none"}}
[:& shapes/shape-wrapper {:shape shape}]]
(case tool (case tool
:path [:& path-editor {:shape shape :zoom zoom}] :path [:& path-editor {:shape shape :zoom zoom}]
:curve [:& path-shape {:shape shape :zoom zoom}] :curve [:& path-shape {:shape shape :zoom zoom}]
#_:default [:& generic-draw-area {:shape shape :zoom zoom}])]) #_:default [:& generic-draw-area {:shape shape :zoom zoom}])]))
(mf/defc generic-draw-area (mf/defc generic-draw-area
[{:keys [shape zoom]}] [{:keys [shape zoom]}]

View file

@ -61,7 +61,7 @@
:on-click #(st/emit! (dwge/locate-board (:id shape)))} :on-click #(st/emit! (dwge/locate-board (:id shape)))}
(tr "workspace.layout_grid.editor.top-bar.locate")] (tr "workspace.layout_grid.editor.top-bar.locate")]
[:button {:class (stl/css :done-btn) [:button {:class (stl/css :done-btn)
:on-click #(st/emit! dw/clear-edition-mode)} :on-click #(st/emit! (dw/clear-edition-mode))}
(tr "workspace.layout_grid.editor.top-bar.done")]]]) (tr "workspace.layout_grid.editor.top-bar.done")]]])
(mf/defc grid-editor-frame (mf/defc grid-editor-frame

View file

@ -26,7 +26,7 @@
(def guide-width 1) (def guide-width 1)
(def guide-opacity 0.7) (def guide-opacity 0.7)
(def guide-opacity-hover 1) (def guide-opacity-hover 1)
(def guide-color colors/primary) (def guide-color colors/new-primary)
(def guide-pill-width 34) (def guide-pill-width 34)
(def guide-pill-height 20) (def guide-pill-height 20)
(def guide-pill-corner-radius 4) (def guide-pill-corner-radius 4)

View file

@ -154,7 +154,9 @@
;; These extra operations ensure that we are selecting a frame its initial location is rendered in the ruler ;; These extra operations ensure that we are selecting a frame its initial location is rendered in the ruler
minv (+ minv (mod offset step)) minv (+ minv (mod offset step))
maxv (+ maxv (mod offset step))] maxv (+ maxv (mod offset step))
rulers-width (* rulers-width zoom-inverse)]
[:g.rulers {:clipPath (str "url(#" clip-id ")")} [:g.rulers {:clipPath (str "url(#" clip-id ")")}
[:defs [:defs

View file

@ -69,7 +69,7 @@
[:& view-only-actions] [:& view-only-actions]
path-edition? path-edition?
[:div.viewport-actions [:div {:class (stl/css :viewport-actions)}
[:& path-actions {:shape shape}]] [:& path-actions {:shape shape}]]
grid-edition? grid-edition?

View file

@ -149,7 +149,7 @@
ptk/EffectEvent ptk/EffectEvent
(effect [_ state stream] (effect [_ state stream]
(let [stoper (rx/filter (ptk/type? ::initialize-history) stream) (let [stopper (rx/filter (ptk/type? ::initialize-history) stream)
history (:history state) history (:history state)
router (:router state)] router (:router state)]
(ts/schedule #(on-change router (.getToken ^js history))) (ts/schedule #(on-change router (.getToken ^js history)))
@ -158,5 +158,5 @@
(fn [] (fn []
(bhistory/disable! history) (bhistory/disable! history)
(e/unlistenByKey key))))) (e/unlistenByKey key)))))
(rx/take-until stoper) (rx/take-until stopper)
(rx/subs! #(on-change router %))))))) (rx/subs! #(on-change router %)))))))