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

This commit is contained in:
Andrey Antukh 2024-01-09 09:56:55 +01:00
commit e48bfb5d94
16 changed files with 628 additions and 381 deletions

View File

@ -88,6 +88,7 @@
--button-constraint-border-color-rest: var(--color-background-tertiary); --button-constraint-border-color-rest: var(--color-background-tertiary);
--button-constraint-border-color-hover: var(--color-accent-primary-muted); --button-constraint-border-color-hover: var(--color-accent-primary-muted);
--button-constraint-background-color-hover: var(--color-accent-primary); --button-constraint-background-color-hover: var(--color-accent-primary);
--constraint-widget-background-color: var(--color-background-tertiary); --constraint-widget-background-color: var(--color-background-tertiary);
--constraint-center-area-background-color: var(--color-background-primary); --constraint-center-area-background-color: var(--color-background-primary);
@ -138,6 +139,8 @@
// ICONS // ICONS
--icon-foreground: var(--color-foreground-secondary); --icon-foreground: var(--color-foreground-secondary);
--icon-foreground-hover: var(--color-foreground-primary); --icon-foreground-hover: var(--color-foreground-primary);
--icon-foreground-accept: var(--ok-color);
--icon-foreground-discard: var(--error-color);
// INPUTS, SELECTS, DROPDOWNS // INPUTS, SELECTS, DROPDOWNS
--input-background-color: var(--color-background-tertiary); --input-background-color: var(--color-background-tertiary);

View File

@ -811,12 +811,7 @@
(ptk/reify ::update-component-thumbnail (ptk/reify ::update-component-thumbnail
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(rx/of (update-component-thumbnail-sync state component-id file-id "component")) (rx/of (update-component-thumbnail-sync state component-id file-id "component")))))
#_(let [data (get state :workspace-data)
component (ctkl/get-component data component-id)
page-id (:main-instance-page component)
root-id (:main-instance-id component)]
(rx/of (dwt/request-thumbnail file-id page-id root-id "component"))))))
(defn- find-shape-index (defn- find-shape-index
[objects id shape-id] [objects id shape-id]

View File

@ -10,7 +10,6 @@
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
[app.common.logging :as l] [app.common.logging :as l]
[app.common.thumbnails :as thc] [app.common.thumbnails :as thc]
[app.common.uuid :as uuid]
[app.main.data.workspace.changes :as dch] [app.main.data.workspace.changes :as dch]
[app.main.data.workspace.notifications :as-alias wnt] [app.main.data.workspace.notifications :as-alias wnt]
[app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.state-helpers :as wsh]
@ -183,7 +182,7 @@
(rx/filter (ptk/type? ::clear-thumbnail)) (rx/filter (ptk/type? ::clear-thumbnail))
(rx/filter #(= (deref %) object-id))))))))) (rx/filter #(= (deref %) object-id)))))))))
(defn- extract-frame-changes (defn- extract-root-frame-changes
"Process a changes set in a commit to extract the frames that are changing" "Process a changes set in a commit to extract the frames that are changing"
[page-id [event [old-data new-data]]] [page-id [event [old-data new-data]]]
(let [changes (-> event deref :changes) (let [changes (-> event deref :changes)
@ -209,10 +208,10 @@
new-frame-id (if (cfh/frame-shape? new-shape) id (:frame-id new-shape))] new-frame-id (if (cfh/frame-shape? new-shape) id (:frame-id new-shape))]
(cond-> #{} (cond-> #{}
(and (some? old-frame-id) (not= uuid/zero old-frame-id)) (cfh/root-frame? old-objects old-frame-id)
(conj old-frame-id) (conj old-frame-id)
(and (some? new-frame-id) (not= uuid/zero new-frame-id)) (cfh/root-frame? new-objects new-frame-id)
(conj new-frame-id))))] (conj new-frame-id))))]
(into #{} (into #{}
@ -251,16 +250,16 @@
(rx/filter dch/commit-changes?) (rx/filter dch/commit-changes?)
(rx/observe-on :async) (rx/observe-on :async)
(rx/with-latest-from workspace-data-s) (rx/with-latest-from workspace-data-s)
(rx/merge-map (partial extract-frame-changes page-id)) (rx/merge-map (partial extract-root-frame-changes page-id))
(rx/tap #(l/trc :hint "inconming change" :origin "local" :frame-id (dm/str %)))) (rx/tap #(l/trc :hint "incoming change" :origin "local" :frame-id (dm/str %))))
;; NOTIFICATIONS CHANGES ;; NOTIFICATIONS CHANGES
(->> stream (->> stream
(rx/filter (ptk/type? ::wnt/handle-file-change)) (rx/filter (ptk/type? ::wnt/handle-file-change))
(rx/observe-on :async) (rx/observe-on :async)
(rx/with-latest-from workspace-data-s) (rx/with-latest-from workspace-data-s)
(rx/merge-map (partial extract-frame-changes page-id)) (rx/merge-map (partial extract-root-frame-changes page-id))
(rx/tap #(l/trc :hint "inconming change" :origin "notifications" :frame-id (dm/str %)))) (rx/tap #(l/trc :hint "incoming change" :origin "notifications" :frame-id (dm/str %))))
;; PERSISTENCE CHANGES ;; PERSISTENCE CHANGES
(->> stream (->> stream
@ -270,7 +269,7 @@
(and (= file-id file-id) (and (= file-id file-id)
(= page-id page-id)))) (= page-id page-id))))
(rx/map (fn [[_ _ frame-id]] frame-id)) (rx/map (fn [[_ _ frame-id]] frame-id))
(rx/tap #(l/trc :hint "inconming change" :origin "persistence" :frame-id (dm/str %))))) (rx/tap #(l/trc :hint "incoming change" :origin "persistence" :frame-id (dm/str %)))))
(rx/share)) (rx/share))
@ -285,15 +284,13 @@
;; and interrupt any ongoing update-thumbnail process ;; and interrupt any ongoing update-thumbnail process
;; related to current frame-id ;; related to current frame-id
(->> changes-s (->> changes-s
(rx/map (fn [frame-id] (rx/map #(clear-thumbnail file-id page-id % "frame")))
(clear-thumbnail file-id page-id frame-id "frame"))))
;; Generate thumbnails in batchs, once user becomes ;; Generate thumbnails in batchs, once user becomes
;; inactive for some instant ;; inactive for some instant
(->> changes-s (->> changes-s
(rx/buffer-until notifier-s) (rx/buffer-until notifier-s)
(rx/mapcat #(into #{} %)) (rx/mapcat #(into #{} %))
(rx/map (fn [frame-id] (rx/map #(request-thumbnail file-id page-id % "frame"))))
(request-thumbnail file-id page-id frame-id "frame")))))
(rx/take-until stopper-s)))))) (rx/take-until stopper-s))))))

View File

@ -7,13 +7,15 @@
(ns app.main.ui.dashboard.fonts (ns app.main.ui.dashboard.fonts
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm]
[app.common.media :as cm] [app.common.media :as cm]
[app.main.data.fonts :as df] [app.main.data.fonts :as df]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
[app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.file-uploader :refer [file-uploader]]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.util.dom :as dom] [app.util.dom :as dom]
@ -53,33 +55,34 @@
(mf/defc fonts-upload (mf/defc fonts-upload
[{:keys [team installed-fonts] :as props}] [{:keys [team installed-fonts] :as props}]
(let [fonts (mf/use-state {}) (let [fonts* (mf/use-state {})
fonts (deref fonts*)
input-ref (mf/use-ref) input-ref (mf/use-ref)
uploading (mf/use-state #{}) uploading (mf/use-state #{})
on-click handle-click
(mf/use-callback #(dom/click (mf/ref-val input-ref))) (mf/use-fn #(dom/click (mf/ref-val input-ref)))
on-selected handle-selected
(mf/use-callback (mf/use-fn
(mf/deps team installed-fonts) (mf/deps team installed-fonts)
(fn [blobs] (fn [blobs]
(->> (df/process-upload blobs (:id team)) (->> (df/process-upload blobs (:id team))
(rx/subs! (fn [result] (rx/subs! (fn [result]
(swap! fonts df/merge-and-group-fonts installed-fonts result)) (swap! fonts* df/merge-and-group-fonts installed-fonts result))
(fn [error] (fn [error]
(js/console.error "error" error)))))) (js/console.error "error" error))))))
on-upload on-upload
(mf/use-callback (mf/use-fn
(mf/deps team) (mf/deps team)
(fn [item] (fn [item]
(swap! uploading conj (:id item)) (swap! uploading conj (:id item))
(->> (rp/cmd! :create-font-variant item) (->> (rp/cmd! :create-font-variant item)
(rx/delay-at-least 2000) (rx/delay-at-least 2000)
(rx/subs! (fn [font] (rx/subs! (fn [font]
(swap! fonts dissoc (:id item)) (swap! fonts* dissoc (:id item))
(swap! uploading disj (:id item)) (swap! uploading disj (:id item))
(st/emit! (df/add-font font))) (st/emit! (df/add-font font)))
(fn [error] (fn [error]
@ -92,25 +95,25 @@
on-blur-name on-blur-name
(fn [id event] (fn [id event]
(let [name (dom/get-target-val event)] (let [name (dom/get-target-val event)]
(swap! fonts df/rename-and-regroup id name installed-fonts))) (swap! fonts* df/rename-and-regroup id name installed-fonts)))
on-delete on-delete
(mf/use-callback (mf/use-fn
(mf/deps team) (mf/deps team)
(fn [{:keys [id] :as item}] (fn [{:keys [id] :as item}]
(swap! fonts dissoc id))) (swap! fonts* dissoc id)))
on-dismiss-all on-dismiss-all
(fn [items] (fn [items]
(run! on-delete items)) (run! on-delete items))
problematic-fonts? (some :height-warning? (vals @fonts)) problematic-fonts? (some :height-warning? (vals fonts))
handle-upload-all handle-upload-all
(mf/use-callback (mf/deps @fonts) #(on-upload-all (vals @fonts))) (mf/use-fn (mf/deps fonts) #(on-upload-all (vals fonts)))
handle-dismiss-all handle-dismiss-all
(mf/use-callback (mf/deps @fonts) #(on-dismiss-all (vals @fonts)))] (mf/use-fn (mf/deps fonts) #(on-dismiss-all (vals fonts)))]
[:div {:class (stl/css :dashboard-fonts-upload)} [:div {:class (stl/css :dashboard-fonts-upload)}
[:div {:class (stl/css :dashboard-fonts-hero)} [:div {:class (stl/css :dashboard-fonts-hero)}
@ -118,45 +121,47 @@
[:h2 (tr "labels.upload-custom-fonts")] [:h2 (tr "labels.upload-custom-fonts")]
[:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}] [:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}]
[:button [:button {:class (stl/css :btn-primary)
{:class (stl/css :btn-primary) :on-click handle-click
:on-click on-click :tab-index "0"}
:tab-index "0"}
[:span (tr "labels.add-custom-font")] [:span (tr "labels.add-custom-font")]
[:& file-uploader {:input-id "font-upload" [:& file-uploader {:input-id "font-upload"
:accept cm/str-font-types :accept cm/str-font-types
:multi true :multi true
:ref input-ref :ref input-ref
:on-selected on-selected}]] :on-selected handle-selected}]]
[:div {:class (stl/css :banner)} [:div {:class (stl/css :banner)}
[:div {:class (stl/css :icon)} i/msg-info] [:div {:class (stl/css :icon)} i/msg-neutral-refactor]
[:div {:class (stl/css :content)} [:div {:class (stl/css :content)}
[:& i18n/tr-html {:tag-name "span" [:& i18n/tr-html {:tag-name "span"
:label "dashboard.fonts.hero-text2"}]]] :label "dashboard.fonts.hero-text2"}]]]
(when problematic-fonts? (when problematic-fonts?
[:div {:class (stl/css :banner :warning)} [:div {:class (stl/css :banner :warning)}
[:div {:class (stl/css :icon)} i/msg-warning] [:div {:class (stl/css :icon)} i/msg-warning-refactor]
[:div {:class (stl/css :content)} [:div {:class (stl/css :content)}
[:& i18n/tr-html {:tag-name "span" [:& i18n/tr-html {:tag-name "span"
:label "dashboard.fonts.warning-text"}]]])]] :label "dashboard.fonts.warning-text"}]]])]]
[:* [:*
(when (some? (vals @fonts)) (when (some? (vals fonts))
[:div {:class (stl/css :font-item :table-row)} [:div {:class (stl/css :font-item :table-row)}
[:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))] [:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals fonts))))]
[:div {:class (stl/css :table-field :options)} [:div {:class (stl/css :table-field :options)}
[:button {:class (stl/css :btn-primary) [:button {:class (stl/css :btn-primary)
:on-click handle-upload-all :data-test "upload-all"} :on-click handle-upload-all
:data-test "upload-all"}
[:span (tr "dashboard.fonts.upload-all")]] [:span (tr "dashboard.fonts.upload-all")]]
[:button {:class (stl/css :btn-secondary) [:button {:class (stl/css :btn-secondary)
:on-click handle-dismiss-all :data-test "dismiss-all"} :on-click handle-dismiss-all
:data-test "dismiss-all"}
[:span (tr "dashboard.fonts.dismiss-all")]]]]) [:span (tr "dashboard.fonts.dismiss-all")]]]])
(for [item (sort-by :font-family (vals @fonts))] (for [item (sort-by :font-family (vals fonts))]
(let [uploading? (contains? @uploading (:id item))] (let [uploading? (contains? @uploading (:id item))]
[:div {:class (stl/css :font-item :table-row) :key (:id item)} [:div {:class (stl/css :font-item :table-row)
:key (:id item)}
[:div {:class (stl/css :table-field :family)} [:div {:class (stl/css :table-field :family)}
[:input {:type "text" [:input {:type "text"
:on-blur #(on-blur-name (:id item) %) :on-blur #(on-blur-name (:id item) %)
@ -167,44 +172,45 @@
[:div {:class (stl/css :table-field :filenames)} [:div {:class (stl/css :table-field :filenames)}
(for [item (:names item)] (for [item (:names item)]
[:span item])] [:span {:key (dm/str "name-" item)} item])]
[:div {:class (stl/css :table-field :options)} [:div {:class (stl/css :table-field :options)}
(when (:height-warning? item) (when (:height-warning? item)
[:span {:class (stl/css :icon :failure)} i/msg-warning]) [:span {:class (stl/css :icon :failure)} i/msg-warning-refactor])
[:button [:button {:on-click #(on-upload item)
{:on-click #(on-upload item) :class (stl/css-case :btn-primary true
:class (stl/css-case :btn-primary true :upload-button true
:upload-button true :disabled uploading?)
:disabled uploading?) :disabled uploading?}
:disabled uploading?}
(if uploading? (if uploading?
(tr "labels.uploading") (tr "labels.uploading")
(tr "labels.upload"))] (tr "labels.upload"))]
[:span {:class (stl/css :icon :close) [:span {:class (stl/css :icon :close)
:on-click #(on-delete item)} i/close]]]))]])) :on-click #(on-delete item)} i/close-refactor]]]))]]))
(mf/defc installed-font (mf/defc installed-font
[{:keys [font-id variants] :as props}] [{:keys [font-id variants] :as props}]
(let [font (first variants) (let [font (first variants)
variants (sort-by (fn [item] variants (sort-by (fn [item]
[(:font-weight item) [(:font-weight item)
(if (= "normal" (:font-style item)) 1 2)]) (if (= "normal" (:font-style item)) 1 2)])
variants) variants)
open-menu? (mf/use-state false)
edit? (mf/use-state false)
state* (mf/use-var (:font-family font))
font-family (deref state*)
open-menu? (mf/use-state false)
edit? (mf/use-state false)
state (mf/use-var (:font-family font))
on-change on-change
(fn [event] (fn [event]
(reset! state (dom/get-target-val event))) (reset! state* (dom/get-target-val event)))
on-save on-save
(fn [_] (fn [_]
(let [font-family @state] (let [font-family font-family]
(when-not (str/blank? font-family) (when-not (str/blank? font-family)
(st/emit! (df/update-font (st/emit! (df/update-font
{:id font-id {:id font-id
@ -219,7 +225,7 @@
on-cancel on-cancel
(fn [_] (fn [_]
(reset! edit? false) (reset! edit? false)
(reset! state (:font-family font))) (reset! state* (:font-family font)))
delete-font-fn delete-font-fn
(fn [] (st/emit! (df/delete-font font-id))) (fn [] (st/emit! (df/delete-font font-id)))
@ -250,43 +256,51 @@
[:div {:class (stl/css :table-field :family)} [:div {:class (stl/css :table-field :family)}
(if @edit? (if @edit?
[:input {:type "text" [:input {:type "text"
:default-value @state :default-value font-family
:on-key-down on-key-down :on-key-down on-key-down
:on-change on-change}] :on-change on-change}]
[:span (:font-family font)])] [:span (:font-family font)])]
[:div {:class (stl/css :table-field :variants)} [:div {:class (stl/css :table-field :variants)}
(for [item variants] (for [item variants]
[:div {:class (stl/css :variant)} [:div {:class (stl/css :variant)
:key (dm/str (:id item) "-variant")}
[:span {:class (stl/css :label)} [:span {:class (stl/css :label)}
[:& font-variant-display-name {:variant item}]] [:& font-variant-display-name {:variant item}]]
[:span [:span
{:class (stl/css :icon :close) {:class (stl/css :icon :close)
:on-click #(on-delete-variant (:id item))} :on-click #(on-delete-variant (:id item))}
i/plus]])] i/add-refactor]])]
(if @edit? (if @edit?
[:div {:class (stl/css :table-field :options)} [:div {:class (stl/css :table-field :options)}
[:button [:button
{:disabled (str/blank? @state) {:disabled (str/blank? font-family)
:on-click on-save :on-click on-save
:class (stl/css-case :btn-primary true :class (stl/css-case :btn-primary true
:btn-disabled (str/blank? @state))} :btn-disabled (str/blank? font-family))}
(tr "labels.save")] (tr "labels.save")]
[:button {:class (stl/css :icon :close) [:button {:class (stl/css :icon :close)
:on-click on-cancel} i/close]] :on-click on-cancel} i/close-refactor]]
[:div {:class (stl/css :table-field :options)} [:div {:class (stl/css :table-field :options)}
[:span {:class (stl/css :icon) [:span {:class (stl/css :icon)
:on-click #(reset! open-menu? true)} i/actions] :on-click #(reset! open-menu? true)}
[:& context-menu i/menu-refactor]
{:on-close #(reset! open-menu? false)
:show @open-menu? [:& context-menu-a11y {:on-close #(reset! open-menu? false)
:fixed? false :show @open-menu?
:top -15 :fixed? false
:left -115 :min-width? true
:options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"] :top -15
[(tr "labels.delete") on-delete nil "font-delete"]]}]])])) :left -115
:options [{:option-name (tr "labels.edit")
:id "font-edit"
:option-handler #(reset! edit? true)}
{:option-name (tr "labels.delete")
:id "font-delete"
:option-handler on-delete}]
:workspace? false}]])]))
(mf/defc installed-fonts (mf/defc installed-fonts
@ -297,7 +311,7 @@
#(str/includes? (str/lower (:font-family %)) @sterm) #(str/includes? (str/lower (:font-family %)) @sterm)
on-change on-change
(mf/use-callback (mf/use-fn
(fn [event] (fn [event]
(let [val (dom/get-target-val event)] (let [val (dom/get-target-val event)]
(reset! sterm (str/lower val)))))] (reset! sterm (str/lower val)))))]
@ -317,7 +331,7 @@
(for [[font-id variants] (->> (vals fonts) (for [[font-id variants] (->> (vals fonts)
(filter matches?) (filter matches?)
(group-by :font-id))] (group-by :font-id))]
[:& installed-font {:key (str font-id) [:& installed-font {:key (dm/str font-id "-installed")
:font-id font-id :font-id font-id
:variants variants}]) :variants variants}])
@ -328,7 +342,7 @@
:else :else
[:div {:class (stl/css :fonts-placeholder)} [:div {:class (stl/css :fonts-placeholder)}
[:div {:class (stl/css :icon)} i/text] [:div {:class (stl/css :icon)} i/text-refactor]
[:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]])])) [:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]])]))
(mf/defc fonts-page (mf/defc fonts-page

View File

@ -17,6 +17,8 @@
.btn-primary { .btn-primary {
font-size: $fs-11; font-size: $fs-11;
height: $s-32;
min-width: $s-100;
} }
} }
@ -150,7 +152,7 @@
&:hover { &:hover {
.icon svg { .icon svg {
fill: $df-secondary; stroke: $df-secondary;
} }
} }
} }
@ -187,21 +189,20 @@
&.failure { &.failure {
margin-right: $s-12; margin-right: $s-12;
svg { svg {
fill: var(--warning-color); stroke: var(--warning-color);
} }
} }
svg { svg {
width: $s-16; width: $s-16;
height: $s-16; height: $s-16;
fill: $df-secondary; stroke: $df-secondary;
} }
&.close { &.close {
background: none; background: none;
border: none; border: none;
svg { svg {
transform: rotate(45deg); stroke: $df-secondary;
fill: $df-secondary;
} }
} }
} }
@ -273,7 +274,7 @@
padding-top: $s-12; padding-top: $s-12;
svg { svg {
fill: $df-secondary; stroke: $df-secondary;
height: $s-20; height: $s-20;
width: $s-20; width: $s-20;
} }
@ -287,7 +288,7 @@
&.warning { &.warning {
background-color: $db-cuaternary; background-color: $db-cuaternary;
.icon svg { .icon svg {
fill: var(--warning-color); stroke: var(--warning-color);
} }
} }
} }
@ -310,7 +311,7 @@
width: 100%; width: 100%;
.icon svg { .icon svg {
fill: $df-secondary; stroke: $df-secondary;
width: $s-32; width: $s-32;
height: $s-32; height: $s-32;
} }

View File

@ -324,14 +324,14 @@
(mf/use-fn (mf/use-fn
(fn [event] (fn [event]
(let [origin (dom/get-target event) (let [origin (dom/get-target event)
over-section? (dom/class? origin "viewer-section") over-section? (dom/get-data origin "viewer-section")
layout (dom/get-element "viewer-layout") layout (dom/get-element "viewer-layout")
has-force? (dom/class? layout "force-visible")] has-force? (dom/get-data layout "force-visible")]
(when over-section? (when over-section?
(if has-force? (if (= has-force? "true")
(dom/remove-class! layout "force-visible") (dom/set-data! layout "force-visible" false)
(dom/add-class! layout "force-visible")))))) (dom/set-data! layout "force-visible" true))))))
on-click on-click
(mf/use-fn (mf/use-fn
@ -351,10 +351,11 @@
(mf/use-fn (mf/use-fn
(fn [event] (fn [event]
(let [event (.getBrowserEvent ^js event) (let [event (.getBrowserEvent ^js event)
wrapper (dom/get-element-by-class "inspect-svg-wrapper") wrapper (dom/get-element "inspect-svg-wrapper")
section (dom/get-element-by-class "inspect-svg-container") section (dom/get-element "inspect-svg-container")
target (.-target event)] target (.-target event)]
(when (or (dom/child? target wrapper) (dom/class? target "inspect-svg-container")) ;; TODO: Reemplazar el dom/class? por un data-attribute
(when (or (dom/child? target wrapper) (dom/id? target "inspect-svg-container"))
(let [norm-event ^js (nw/normalize-wheel event) (let [norm-event ^js (nw/normalize-wheel event)
mod? (kbd/mod? event) mod? (kbd/mod? event)
shift? (kbd/shift? event) shift? (kbd/shift? event)
@ -516,8 +517,9 @@
{:class (stl/css-case {:class (stl/css-case
:force-visible (:show-thumbnails local) :force-visible (:show-thumbnails local)
:viewer-layout (not= section :inspect) :viewer-layout (not= section :inspect)
:inspect-layout (= section :inspect) :inspect-layout (= section :inspect))
:fullscreen fullscreen?)} :data-fullscreen fullscreen?
:data-force-visible (:show-thumbnails local)}
[:div {:class (stl/css :viewer-content)} [:div {:class (stl/css :viewer-content)}
[:& header/header {:project project [:& header/header {:project project
@ -542,6 +544,7 @@
[:section {:id "viewer-section" [:section {:id "viewer-section"
:ref viewer-section-ref :ref viewer-section-ref
:data-viewer-section true
:class (stl/css-case :viewer-section true :class (stl/css-case :viewer-section true
:fulscreen fullscreen?) :fulscreen fullscreen?)
:on-click click-on-screen} :on-click click-on-screen}

View File

@ -101,7 +101,7 @@
width: 100%; width: 100%;
height: $s-40; height: $s-40;
padding-right: 0 $s-8 $s-40 $s-8; padding-right: 0 $s-8 $s-40 $s-8;
transition: bottom 400ms ease 300ms; transition: transform 400ms ease 300ms;
z-index: $z-index-2; z-index: $z-index-2;
} }
@ -178,3 +178,12 @@
:global(svg#loader-pencil) { :global(svg#loader-pencil) {
fill: var(--icon-foreground); fill: var(--icon-foreground);
} }
/** FULLSCREEN */
[data-fullscreen="true"] .viewer-bottom {
transform: translateY($s-40);
}
[data-force-visible="true"] .viewer-bottom {
transform: translateY(0);
}

View File

@ -283,7 +283,8 @@
(st/emit! (dv/go-to-section section)) (st/emit! (dv/go-to-section section))
(open-login-dialog)))))] (open-login-dialog)))))]
[:header {:class (stl/css :viewer-header)} [:header {:class (stl/css-case :viewer-header true
:fullscreen (mf/deref fullscreen-ref))}
[:div {:class (stl/css :nav-zone)} [:div {:class (stl/css :nav-zone)}
;; If the user doesn't have permission we disable the link ;; If the user doesn't have permission we disable the link
[:a {:class (stl/css :home-link) [:a {:class (stl/css :home-link)

View File

@ -18,6 +18,7 @@
height: $s-48; height: $s-48;
width: 100vw; width: 100vw;
padding: $s-8 $s-12; padding: $s-8 $s-12;
transition: transform 400ms ease 300ms;
background-color: var(--panel-background-color); background-color: var(--panel-background-color);
} }
@ -300,3 +301,12 @@
} }
} }
} }
/** FULLSCREEN */
[data-fullscreen="true"] .viewer-header {
transform: translateY(-$s-48);
}
[data-force-visible="true"] .viewer-header {
transform: translateY(0);
}

View File

@ -94,12 +94,12 @@
[:& left-sidebar {:frame frame [:& left-sidebar {:frame frame
:local local :local local
:page page}] :page page}]
[:div {:class (stl/css :inspect-svg-wrapper) [:div#inspect-svg-wrapper {:class (stl/css :inspect-svg-wrapper)
:data-value (pr-str (:id frame)) :data-value (pr-str (:id frame))
:on-click handle-select-frame} :on-click handle-select-frame}
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}] [:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}]
[:div {:class (stl/css :inspect-svg-container) [:div#inspect-svg-container {:class (stl/css :inspect-svg-container)
:ref inspect-svg-container-ref} :ref inspect-svg-container-ref}
[:& render-frame-svg {:frame frame :page page :local local :size size}]]] [:& render-frame-svg {:frame frame :page page :local local :size size}]]]
[:div {:class (stl/css-case :sidebar-container true [:div {:class (stl/css-case :sidebar-container true

View File

@ -118,12 +118,12 @@
tries-ref (mf/use-ref 0) tries-ref (mf/use-ref 0)
imposter-ref (mf/use-ref nil) imposter-ref (mf/use-ref nil)
imposter-loaded-ref (mf/use-ref false) imposter-loaded (mf/use-state false)
task-ref (mf/use-ref nil) task-ref (mf/use-ref nil)
on-load (mf/use-fn (fn [] on-load (mf/use-fn (fn []
(mf/set-ref-val! tries-ref 0) (mf/set-ref-val! tries-ref 0)
(mf/set-ref-val! imposter-loaded-ref true))) (reset! imposter-loaded true)))
on-error (mf/use-fn on-error (mf/use-fn
(fn [] (fn []
(let [current-tries (mf/ref-val tries-ref) (let [current-tries (mf/ref-val tries-ref)
@ -158,7 +158,7 @@
:opacity (when ^boolean hidden? 0)} :opacity (when ^boolean hidden? 0)}
;; When there is no thumbnail, we generate a empty rect. ;; When there is no thumbnail, we generate a empty rect.
(when (and (not ^boolean content-visible?) (not (mf/ref-val imposter-loaded-ref))) (when (and (not ^boolean content-visible?) (not @imposter-loaded))
[:g.frame-placeholder [:g.frame-placeholder
[:rect {:x x [:rect {:x x
:y y :y y

View File

@ -106,46 +106,66 @@
(fn [] (st/emit! (dw/set-annotations-id-for-create nil))))) ;; cleanup set-annotationsid-for-create on unload (fn [] (st/emit! (dw/set-annotations-id-for-create nil))))) ;; cleanup set-annotationsid-for-create on unload
(when (or creating? annotation) (when (or creating? annotation)
[:div.component-annotation {:class (dom/classnames :editing @editing? :creating creating?)} [:div {:class (stl/css-case :component-annotation true
[:div.title {:class (dom/classnames :expandeable (not (or @editing? creating?))) :editing @editing?
:on-click #(expand (not annotations-expanded?))} :creating creating?)}
[:div (if (or @editing? creating?) [:div {:class (stl/css-case :annotation-title true
(if @editing? :expandeable (not (or @editing? creating?))
(tr "workspace.options.component.edit-annotation") :expanded annotations-expanded?)
(tr "workspace.options.component.create-annotation")) :on-click #(expand (not annotations-expanded?))}
[:* (if annotations-expanded?
[:div.expand i/arrow-down] (if (or @editing? creating?)
[:div.expand i/arrow-slide]) [:span {:class (stl/css :annotation-text)}
(tr "workspace.options.component.annotation")])] (if @editing?
[:div (tr "workspace.options.component.edit-annotation")
(tr "workspace.options.component.create-annotation"))]
[:*
[:span {:class (stl/css-case :icon-arrow true
:expanded annotations-expanded?)}
i/arrow-refactor]
[:span {:class (stl/css :annotation-text)}
(tr "workspace.options.component.annotation")]])
[:div {:class (stl/css :icons-wrapper)}
(when (and main-instance? annotations-expanded?) (when (and main-instance? annotations-expanded?)
(if (or @editing? creating?) (if (or @editing? creating?)
[:* [:*
[:div.icon {:title (if creating? (tr "labels.create") (tr "labels.save")) [:div {:title (if creating? (tr "labels.create") (tr "labels.save"))
:on-click save :on-click save
:class (dom/classnames :hidden @invalid-text?)} i/tick] :class (stl/css-case :icon true
[:div.icon {:title (tr "labels.discard") :icon-tick true
:on-click discard} i/cross]] :hidden @invalid-text?)}
[:* i/tick-refactor]
[:div.icon {:title (tr "labels.edit") [:div {:class (stl/css :icon :icon-cross)
:on-click edit} i/pencil] :title (tr "labels.discard")
[:div.icon {:title (tr "labels.delete") :on-click discard}
:on-click on-delete-annotation} i/trash]]))]] i/close-refactor]]
[:div {:class (dom/classnames :hidden (not annotations-expanded?))} [:*
[:div.grow-wrap [:div {:class (stl/css :icon :icon-edit)
[:div.texarea-copy] :title (tr "labels.edit")
:on-click edit}
i/curve-refactor]
[:div {:class (stl/css :icon :icon-trash)
:title (tr "labels.delete")
:on-click on-delete-annotation}
i/delete-refactor]]))]]
[:div {:class (stl/css-case :hidden (not annotations-expanded?))}
[:div {:class (stl/css :grow-wrap)}
[:div {:class (stl/css :texarea-copy)}]
[:textarea [:textarea
{:ref textarea-ref {:ref textarea-ref
:id "annotation-textarea" :id "annotation-textarea"
:data-debug annotation :data-debug annotation
:auto-focus true :auto-focus (or @editing? creating?)
:maxLength 300 :maxLength 300
:on-input autogrow :on-input autogrow
:default-value annotation :default-value annotation
:read-only (not (or creating? @editing?))}]] :read-only (not (or creating? @editing?))}]]
(when (or @editing? creating?) (when (or @editing? creating?)
[:div.counter (str @size "/300")])]]))) [:div {:class (stl/css :counter)} (str @size "/300")])]])))
(mf/defc component-swap-item (mf/defc component-swap-item
{::mf/wrap-props false} {::mf/wrap-props false}
@ -157,22 +177,21 @@
(st/emit! (dwl/component-multi-swap shapes file-id (:id item))))) (st/emit! (dwl/component-multi-swap shapes file-id (:id item)))))
item-ref (mf/use-ref) item-ref (mf/use-ref)
visible? (h/use-visible item-ref :once? true)] visible? (h/use-visible item-ref :once? true)]
[:div [:div {:ref item-ref
{:ref item-ref :title (if is-search (:full-name item) (:name item))
:title (if is-search (:full-name item) (:name item)) :class (stl/css-case :component-item (not listing-thumbs)
:class (stl/css-case :component-item (not listing-thumbs) :grid-cell listing-thumbs
:grid-cell listing-thumbs :selected (= (:id item) component-id)
:selected (= (:id item) component-id) :disabled loop)
:disabled loop) :key (str "swap-item-" (:id item))
:key (str "swap-item-" (:id item)) :on-click on-select-component}
:on-click on-select-component}
(when visible? (when visible?
[:& cmm/component-item-thumbnail {:file-id (:file-id item) [:& cmm/component-item-thumbnail {:file-id (:file-id item)
:root-shape root-shape :root-shape root-shape
:component item :component item
:container container}]) :container container}])
[:span [:span {:class (stl/css-case :component-name true
{:class (stl/css-case :component-name true :selected (= (:id item) component-id))} :selected (= (:id item) component-id))}
(if is-search (:full-name item) (:name item))]])) (if is-search (:full-name item) (:name item))]]))
(mf/defc component-group-item (mf/defc component-group-item
@ -185,9 +204,11 @@
:title group-name} :title group-name}
[:div [:div
(when-not (str/blank? path) (when-not (str/blank? path)
[:span {:class (stl/css :component-group-path)} (str "\u00A0/\u00A0" path)]) [:span {:class (stl/css :component-group-path)}
[:span {:class (stl/css :component-group-name)} (cfh/last-path group-name)]] (str "\u00A0/\u00A0" path)])
[:span i/arrow-slide]])) [:span {:class (stl/css :component-group-name)}
(cfh/last-path group-name)]]
[:span i/arrow-refactor]]))
(mf/defc component-swap (mf/defc component-swap
[{:keys [shapes] :as props}] [{:keys [shapes] :as props}]
@ -328,11 +349,10 @@
:icon (mf/html [:span {:class (stl/css :search-icon)} i/search-refactor])}]] :icon (mf/html [:span {:class (stl/css :search-icon)} i/search-refactor])}]]
[:div {:class (stl/css :select-field)} [:div {:class (stl/css :select-field)}
[:& select [:& select {:class (stl/css :select-library)
{:class (stl/css :select-library) :default-value current-library-id
:default-value current-library-id :options libraries-options
:options libraries-options :on-change on-library-change}]]
:on-change on-library-change}]]
[:div {:class (stl/css :library-name)} current-library-name] [:div {:class (stl/css :library-name)} current-library-name]
@ -356,7 +376,7 @@
[:button {:class (stl/css :component-path) [:button {:class (stl/css :component-path)
:on-click on-go-back :on-click on-go-back
:title (:path filters)} :title (:path filters)}
[:span i/arrow-slide] [:span i/arrow-refactor]
[:span (:path filters)]]) [:span (:path filters)]])
(when (empty? items) (when (empty? items)
@ -462,7 +482,7 @@
(if swap-opened? (if swap-opened?
[:button {:class (stl/css :title-back) [:button {:class (stl/css :title-back)
:on-click on-component-back} :on-click on-component-back}
[:span i/arrow-slide] [:span i/arrow-refactor]
[:span (tr "workspace.options.component")]] [:span (tr "workspace.options.component")]]
[:& title-bar {:collapsable? true [:& title-bar {:collapsable? true
:collapsed? (not open?) :collapsed? (not open?)
@ -473,7 +493,9 @@
(when open? (when open?
[:div {:class (stl/css :element-content)} [:div {:class (stl/css :element-content)}
[:div {:class (stl/css :component-wrapper)} [:div {:class (stl/css :component-wrapper)}
[:div {:class (stl/css-case :component-name-wrapper true :with-main (and can-swap? (not multi)) :swappeable (and can-swap? (not swap-opened?))) [:div {:class (stl/css-case :component-name-wrapper true
:with-main (and can-swap? (not multi))
:swappeable (and can-swap? (not swap-opened?)))
:on-click open-component-panel} :on-click open-component-panel}
[:span {:class (stl/css :component-icon)} [:span {:class (stl/css :component-icon)}
(if main-instance? (if main-instance?

View File

@ -7,249 +7,260 @@
@import "refactor/common-refactor.scss"; @import "refactor/common-refactor.scss";
.element-set { .element-set {
margin: 0; margin: 0;
.element-content { }
@include flexColumn;
margin-bottom: $s-8;
.component-wrapper {
display: flex;
margin: 0 $s-4 0 $s-8;
.component-name-wrapper {
@extend .asset-element;
@include flexRow;
flex-grow: 1;
height: 100%;
width: 100%;
flex-wrap: wrap;
padding: 0 0 0 $s-12;
margin-top: $s-8;
&.with-main { .element-content {
padding-bottom: $s-12; @include flexColumn;
} margin-bottom: $s-8;
}
.component-icon { .component-wrapper {
@include flexCenter; display: flex;
height: $s-24; margin: 0 $s-4 0 $s-8;
width: $s-24; }
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
}
}
.component-name {
@include titleTipography;
@include textEllipsis;
width: 70%;
flex-grow: 2;
margin-left: $s-8;
}
.component-parent-name {
@include titleTipography;
@include textEllipsis;
padding-left: $s-36;
color: var(--title-foreground-color);
}
}
.swappeable {
cursor: pointer;
}
.component-actions {
position: relative;
.menu-btn { .component-name-wrapper {
@extend .button-tertiary; @extend .asset-element;
height: $s-32; @include flexRow;
width: $s-28; flex-grow: 1;
svg { height: 100%;
@extend .button-icon; width: 100%;
} flex-wrap: wrap;
} padding: 0 0 0 $s-12;
.custom-select-dropdown { margin-top: $s-8;
@extend .dropdown-wrapper;
right: 0; &.with-main {
left: unset; padding-bottom: $s-12;
width: $s-252;
.dropdown-element {
@extend .dropdown-element-base;
}
}
}
}
} }
}
.title-back { .component-icon {
@include tabTitleTipography; @include flexCenter;
cursor: pointer; height: $s-24;
width: 100%; width: $s-24;
background-color: var(--title-background-color); svg {
color: var(--title-foreground-color); @extend .button-icon;
text-align: left; stroke: var(--icon-foreground);
border: 0; }
margin-bottom: $s-16; }
.component-name {
@include titleTipography;
@include textEllipsis;
width: 70%;
flex-grow: 2;
margin-left: $s-8;
}
.component-parent-name {
@include titleTipography;
@include textEllipsis;
padding-left: $s-36;
color: var(--title-foreground-color);
}
.swappeable {
cursor: pointer;
}
.component-actions {
position: relative;
}
.menu-btn {
@extend .button-tertiary;
height: $s-32;
width: $s-28;
svg {
@extend .button-icon;
}
}
.custom-select-dropdown {
@extend .dropdown-wrapper;
right: 0;
left: unset;
width: $s-252;
}
.dropdown-element {
@extend .dropdown-element-base;
}
.title-back {
@include tabTitleTipography;
cursor: pointer;
width: 100%;
background-color: var(--title-background-color);
color: var(--title-foreground-color);
text-align: left;
border: 0;
margin-bottom: $s-16;
svg {
height: $s-8;
width: $s-8;
stroke: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
}
}
.search-field {
display: flex;
align-items: center;
height: $s-32;
margin: $s-16 $s-4 $s-4 $s-12;
border-radius: $br-8;
font-family: "worksans", sans-serif;
background-color: var(--input-background-color);
}
.search-box {
align-items: center;
display: flex;
width: 100%;
}
.icon-wrapper {
display: flex;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
.input-text {
@include removeInputStyle;
height: $s-32;
width: 100%;
margin: 0;
padding: $s-4;
border: 0;
font-size: $fs-12;
color: var(--input-foreground-color-active);
&::placeholder {
color: var(--input-foreground-color-disabled);
}
&:focus-visible {
border-color: var(--input-border-outline-color-active);
}
}
.clear-btn {
@include buttonStyle;
@include flexCenter;
height: $s-16;
width: $s-16;
.clear-icon {
@include flexCenter;
svg { svg {
height: $s-8; @extend .button-icon-small;
width: $s-8; stroke: var(--icon-foreground);
fill: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
} }
} }
}
.component-swap { .search-icon {
.search-field { @include flexCenter;
display: flex; width: $s-28;
align-items: center; svg {
height: $s-32; @extend .button-icon-small;
margin: $s-16 $s-4 $s-4 $s-12; stroke: var(--icon-foreground);
border-radius: $br-8; }
font-family: "worksans", sans-serif; }
background-color: var(--input-background-color);
.search-box {
align-items: center;
display: flex;
width: 100%;
.icon-wrapper { .select-field {
display: flex; margin: $s-8 $s-4 0 $s-12;
svg { }
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
.input-text { .select-library {
@include removeInputStyle; padding-left: $s-20;
height: $s-32; }
width: 100%;
margin: 0;
padding: $s-4;
border: 0;
font-size: $fs-12;
color: var(--input-foreground-color-active);
&::placeholder {
color: var(--input-foreground-color-disabled);
}
&:focus-visible {
border-color: var(--input-border-outline-color-active);
}
}
.clear-btn {
@include buttonStyle;
@include flexCenter;
height: $s-16;
width: $s-16;
.clear-icon {
@include flexCenter;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
}
}
.search-icon {
@include flexCenter;
width: $s-28;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
}
.select-field { .listing-options-wrapper {
margin: $s-8 $s-4 0 $s-12; width: 100%;
} }
.select-library { .listing-options {
padding-left: $s-20; margin-left: auto;
} margin-right: $s-4;
}
.listing-options-wrapper { .component-path {
width: 100%; @include titleTipography;
} @include textEllipsis;
text-align: left;
cursor: pointer;
width: 100%;
background-color: var(--title-background-color);
color: var(--title-foreground-color);
border: 0;
margin: $s-16 0 $s-12 0;
padding: 0 $s-16 0 $s-24;
svg {
height: $s-8;
width: $s-8;
stroke: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
}
}
.listing-options { .component-path-empty {
margin-left: auto; height: $s-16;
margin-right: $s-4; }
}
.component-path { .component-list-empty {
@include titleTipography; @include titleTipography;
@include textEllipsis; margin: 0 $s-4 0 $s-8;
text-align: left; }
cursor: pointer;
width: 100%;
background-color: var(--title-background-color);
color: var(--title-foreground-color);
border: 0;
margin: $s-16 0 $s-12 0;
padding: 0 $s-16 0 $s-24;
svg {
height: $s-8;
width: $s-8;
fill: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
}
}
.component-path-empty { .component-list {
height: $s-16; margin: 0 $s-4 0 $s-8;
} }
.component-list-empty { .component-item {
@include titleTipography; display: flex;
margin: 0 $s-4 0 $s-8; align-items: center;
} margin-bottom: $s-4;
font-size: $s-12;
cursor: pointer;
width: 100%;
height: $s-36;
border-radius: $br-8;
background-color: var(--assets-item-background-color);
color: var(--assets-item-name-foreground-color);
.component-list { .component-name {
margin: 0 $s-4 0 $s-8; @include textEllipsis;
.component-item { width: 80%;
display: flex; }
align-items: center;
margin-bottom: $s-4;
font-size: $s-12;
cursor: pointer;
width: 100%;
height: $s-36;
border-radius: $br-8;
background-color: var(--assets-item-background-color);
color: var(--assets-item-name-foreground-color);
.component-name { svg,
@include textEllipsis; img {
width: 80%; background-color: var(--assets-component-background-color);
} border-radius: $br-8;
height: $s-32;
width: $s-32;
margin: $s-2 $s-8 $s-2 $s-2;
}
svg, .selected {
img { color: var(--assets-item-name-foreground-color-hover);
background-color: var(--assets-component-background-color); }
border-radius: $br-8;
height: $s-32;
width: $s-32;
margin: $s-2 $s-8 $s-2 $s-2;
}
.selected { &:hover {
color: var(--assets-item-name-foreground-color-hover); color: var(--assets-item-name-foreground-color-hover);
} background-color: var(--assets-item-background-color-hover);
}
&:hover { &.disabled {
color: var(--assets-item-name-foreground-color-hover); cursor: auto;
background-color: var(--assets-item-background-color-hover); color: var(--assets-item-name-foreground-color-disabled);
} background-color: var(--assets-item-background-color);
&.disabled { svg {
cursor: auto; cursor: auto;
color: var(--assets-item-name-foreground-color-disabled);
background-color: var(--assets-item-background-color);
svg {
cursor: auto;
}
}
}
} }
} }
} }
@ -390,3 +401,172 @@
cursor: pointer; cursor: pointer;
} }
} }
// Component annotation
.component-annotation {
@include titleTipography;
color: var(--entry-foreground-color);
border-radius: $br-8;
.annotation-title {
display: flex;
align-items: center;
height: $s-32;
&.expanded {
border-bottom: $s-1 solid var(--entry-border-color-disabled);
}
&.expandeable {
cursor: pointer;
}
div {
display: flex;
align-items: center;
line-height: 2.5;
}
.icon-arrow {
@include flexCenter;
width: $s-28;
height: $s-32;
display: flex;
margin: 0;
padding: 0;
cursor: pointer;
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
width: $s-16;
height: $s-16;
}
&.expanded svg {
transform: rotate(90deg);
}
}
.icon {
@include flexCenter;
width: $s-28;
height: $s-32;
border-radius: $br-8;
display: none;
margin: 0;
padding: 0;
cursor: pointer;
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
width: $s-16;
height: $s-16;
}
&.icon-tick:hover,
&.icon-edit:hover {
svg {
stroke: var(--icon-foreground-accept);
}
}
&.icon-cross:hover,
&.icon-trash:hover {
svg {
stroke: var(--icon-foreground-discard);
}
}
}
.annotation-text {
flex-grow: 1;
margin-left: $s-12;
}
&:hover {
.icon {
display: flex;
}
}
}
&.editing {
border: $s-1 solid var(--input-border-color-success);
.annotation-title {
border-bottom: $s-1 solid var(--entry-border-color-disabled);
.icon {
display: flex;
}
}
textarea {
min-height: $s-252;
}
}
&.creating {
border: $s-1 solid var(--input-border-color-success);
.annotation-title .icon {
display: flex;
}
textarea {
min-height: $s-252;
}
}
.hidden {
display: none;
svg {
display: none;
}
}
.counter {
@include titleTipography;
text-align: right;
color: var(--entry-foreground-color);
margin: 0 $s-8 $s-8 0;
}
// Auto growing text
.grow-wrap {
// easy way to plop the elements on top of each other and have them both sized based on the tallest one's height
display: grid;
&:after {
// The space is needed to preventy jumpy behavior
content: attr(data-replicated-value) " ";
white-space: pre-wrap;
visibility: hidden;
}
textarea {
background-color: var(--input-background-color-active);
color: var(--input-foreground-color-active);
padding: $s-12;
border: none;
overflow: hidden;
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
resize: none; /*remove the resize handle on the bottom right*/
}
textarea,
&:after {
/* Identical styling required!! */
font: inherit;
overflow-wrap: anywhere;
padding: 10px;
/* Place on top of each other */
grid-area: 1 / 1 / 2 / 2;
}
}
}

View File

@ -38,6 +38,7 @@
@include titleTipography; @include titleTipography;
height: $s-20; height: $s-20;
padding: $s-4 $s-6; padding: $s-4 $s-6;
margin-right: $s-12;
border: $s-1 solid var(--tag-background-color); border: $s-1 solid var(--tag-background-color);
border-radius: $br-6; border-radius: $br-6;
color: var(--tag-background-color); color: var(--tag-background-color);

View File

@ -547,6 +547,11 @@
[] []
(partition 2 params)))) (partition 2 params))))
(defn ^boolean id?
[node id]
(when (some? node)
(= (.-id ^js node) id)))
(defn ^boolean class? [node class-name] (defn ^boolean class? [node class-name]
(when (some? node) (when (some? node)
(let [class-list (.-classList ^js node)] (let [class-list (.-classList ^js node)]

View File

@ -243,6 +243,12 @@
(prn (str (:name frame) " - " (:id frame)))) (prn (str (:name frame) " - " (:id frame))))
nil)) nil))
(defn ^:export select-by-object-id
[object-id]
(let [[_ page-id shape-id _] (str/split object-id #"/")]
(st/emit! (dw/go-to-page (uuid/uuid page-id)))
(st/emit! (dws/select-shape (uuid/uuid shape-id)))))
(defn ^:export select-by-id (defn ^:export select-by-id
[shape-id] [shape-id]
(st/emit! (dws/select-shape (uuid/uuid shape-id)))) (st/emit! (dws/select-shape (uuid/uuid shape-id))))