diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 248563ef8..7c60ad412 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -1076,14 +1076,13 @@ (->> (cells-seq parent :sort? true) (reduce (fn [[parent auto?] cell] - (let [[cell auto?] (cond (and (empty? (:shapes cell)) (= :manual (:position cell)) (= (:row-span cell) 1) (= (:column-span cell) 1)) - [(assoc cell :position :auto) false] + [cell false] (and (or (not= (:row-span cell) 1) (not= (:column-span cell) 1)) diff --git a/frontend/resources/images/icons/exit-refactor.svg b/frontend/resources/images/icons/exit-refactor.svg new file mode 100644 index 000000000..9b80aa590 --- /dev/null +++ b/frontend/resources/images/icons/exit-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index b7d4b6858..61a1c4c49 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -848,6 +848,7 @@ color: var(--title-foreground-color-hover); background-color: var(--menu-background-color); border: $s-2 solid var(--panel-border-color); + margin: 0; } .menu-item-base { diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index d4f854702..eb1116b7f 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -155,6 +155,7 @@ --icon-foreground-hover: var(--color-foreground-primary); --icon-foreground-accept: var(--status-color-success-500); --icon-foreground-discard: var(--status-color-error-500); + --icon-foreground-active: var(--color-accent-primary); // INPUTS, SELECTS, DROPDOWNS @@ -201,6 +202,7 @@ --menu-background-color: var(--color-background-tertiary); --menu-foreground-color: var(--color-foreground-primary); + --menu-icon-foreground-color: var(--color-foreground-secondary); --menu-background-color-selected: var(--color-background-tertiary); --menu-background-color-hover: var(--color-background-quaternary); --menu-foreground-color-hover: var(--color-foreground-primary); @@ -358,6 +360,11 @@ --search-bar-background-color: var(--color-background-primary); --search-bar-input-background-color: var(--color-background-tertiary); --search-bar-input-border-color: var(--color-background-tertiary); + --search-bar-input-border-color-focus: var(--color-accent-primary); + --search-bar-placeholder-foreground-color: var(--color-foreground-secondary); + --search-bar-foreground-color: var(--color-foreground-primary); + --search-bar-icon-foreground-color: var(--color-foreground-secondary); + --search-bar-icon-foreground-color-hover: var(--color-accent-primary); --pill-background-color: var(--color-background-tertiary); --pill-foreground-color: var(--color-foreground-primary); @@ -369,6 +376,8 @@ --resize-area-background-color: var(--color-background-primary); --resize-area-border-color: var(--color-background-quaternary); + --profile-section-background-color: var(--color-background-tertiary); + --flow-tag-background-color: var(--color-background-tertiary); --flow-tag-foreground-color: var(--color-foreground-secondary); --flow-tag-background-color-hover: var(--color-background-quaternary); @@ -393,6 +402,14 @@ // NEW TEAM BUTTON // TODO: we should not put these functional tokens here, but rather in the components they belong to --new-team-button-background-color: var(--color-background-primary); + + //DASHBOARD + --sidebar-element-foreground-color: var(--color-foreground-secondary); + --sidebar-element-background-color-hover: var(--color-background-secondary); + --sidebar-element-foreground-color-hover: var(--color-accent-primary); + --sidebar-element-background-color-selected: var(--color-background-quaternary); + --sidebar-element-foreground-color-selected: var(--color-accent-primary); + --profile-foreground-color: var(--color-foreground-primary); } #app { diff --git a/frontend/src/app/main/data/media.cljs b/frontend/src/app/main/data/media.cljs index bb1a82e39..e78892bb1 100644 --- a/frontend/src/app/main/data/media.cljs +++ b/frontend/src/app/main/data/media.cljs @@ -47,6 +47,7 @@ (defn notify-start-loading [] (st/emit! (msg/show {:content (tr "media.loading") + :notification-type :toast :type :info :timeout nil}))) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 65f456cbc..c24d1d469 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -808,7 +808,7 @@ component (ctkl/get-component data component-id) page-id (:main-instance-page component) root-id (:main-instance-id component)] - (dwt/request-thumbnail file-id page-id root-id tag))) + (dwt/request-thumbnail file-id page-id root-id tag "update-component-thumbnail-sync"))) (defn update-component-sync ([shape-id file-id] (update-component-sync shape-id file-id nil)) diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index 3dc6c8d7a..693207d87 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -211,6 +211,7 @@ (watch [_ _ _] (rx/concat (rx/of (msg/show {:content (tr "media.loading") + :notification-type :toast :type :info :timeout nil :tag :media-loading})) @@ -440,6 +441,7 @@ (rx/concat (rx/of (msg/show {:content (tr "media.loading") + :notification-type :toast :type :info :timeout nil :tag :media-loading})) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 3dabed931..a38962aa9 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -573,6 +573,7 @@ (> (:row-span cell) 1) (> (:column-span cell) 1)) (-> (d/update-in-when [:layout-grid-cells cell-id] assoc :shapes [] :position :auto) + (d/update-in-when [:layout-grid-cells cell-id] dissoc :area-name) (ctl/resize-cell-area (:row cell) (:column cell) (:row cell) (:column cell) 1 1) (ctl/assign-cells objects))))) shape)) @@ -585,6 +586,7 @@ (cond-> shape (contains? #{:area :auto} (:position cell)) (-> (d/assoc-in-when [:layout-grid-cells cell-id :position] :manual) + (d/update-in-when [:layout-grid-cells cell-id] dissoc :area-name) (ctl/assign-cells objects))))) shape)) diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs index b1328b98a..e2cb1cacc 100644 --- a/frontend/src/app/main/data/workspace/thumbnails.cljs +++ b/frontend/src/app/main/data/workspace/thumbnails.cljs @@ -58,15 +58,17 @@ (defn request-thumbnail "Enqueues a request to generate a thumbnail for the given ids." - [file-id page-id shape-id tag] - (ptk/reify ::request-thumbnail - ptk/EffectEvent - (effect [_ _ _] - (l/dbg :hint "request thumbnail" :file-id file-id :page-id page-id :shape-id shape-id :tag tag) - (q/enqueue-unique - queue - (create-request file-id page-id shape-id tag) - (partial find-request file-id page-id shape-id tag))))) + ([file-id page-id shape-id tag] + (request-thumbnail file-id page-id shape-id tag "unknown")) + ([file-id page-id shape-id tag requester] + (ptk/reify ::request-thumbnail + ptk/EffectEvent + (effect [_ _ _] + (l/dbg :hint "request thumbnail" :requester requester :file-id file-id :page-id page-id :shape-id shape-id :tag tag) + (q/enqueue-unique + queue + (create-request file-id page-id shape-id tag) + (partial find-request file-id page-id shape-id tag)))))) ;; This function first renders the HTML calling `render/render-frame` that ;; returns HTML as a string, then we send that data to the iframe rasterizer @@ -291,6 +293,6 @@ (->> all-changes-s (rx/buffer-until notifier-s) (rx/mapcat #(into #{} %)) - (rx/map #(request-thumbnail file-id page-id % "frame")))) + (rx/map #(request-thumbnail file-id page-id % "frame" "watch-state-changes")))) (rx/take-until stopper-s)))))) diff --git a/frontend/src/app/main/errors.cljs b/frontend/src/app/main/errors.cljs index a16bd93f0..542b41bce 100644 --- a/frontend/src/app/main/errors.cljs +++ b/frontend/src/app/main/errors.cljs @@ -124,6 +124,7 @@ (let [message (tr "errors.paste-data-validation")] (st/async-emit! (msg/show {:content message + :notification-type :toast :type :error :timeout 3000}))) @@ -138,6 +139,7 @@ [error] (ts/schedule #(st/emit! (msg/show {:content "Internal Assertion Error" + :notification-type :toast :type :error :timeout 3000}))) @@ -153,6 +155,7 @@ (ts/schedule #(st/emit! (msg/show {:content "Something wrong has happened (on worker)." + :notification-type :toast :type :error :timeout 3000}))) @@ -166,6 +169,7 @@ [_] (ts/schedule #(st/emit! (msg/show {:content "SVG is invalid or malformed" + :notification-type :toast :type :error :timeout 3000})))) @@ -174,6 +178,7 @@ [_] (ts/schedule #(st/emit! (msg/show {:content "There was an error with the comment" + :notification-type :toast :type :error :timeout 3000})))) diff --git a/frontend/src/app/main/fonts.cljs b/frontend/src/app/main/fonts.cljs index f934966d9..a17201124 100644 --- a/frontend/src/app/main/fonts.cljs +++ b/frontend/src/app/main/fonts.cljs @@ -18,7 +18,6 @@ [app.util.http :as http] [app.util.object :as obj] [beicon.v2.core :as rx] - [clojure.set :as set] [cuerdas.core :as str] [lambdaisland.uri :as u] [okulary.core :as l] @@ -273,13 +272,17 @@ (defn get-content-fonts "Extracts the fonts used by the content of a text shape" - [{font-id :font-id children :children :as content}] - (let [current-font - (if (some? font-id) - #{(select-keys content [:font-id :font-variant-id])} - #{(select-keys txt/default-text-attrs [:font-id :font-variant-id])}) - children-font (->> children (mapv get-content-fonts))] - (reduce set/union (conj children-font current-font)))) + [content] + (->> (txt/node-seq content) + (filter txt/is-text-node?) + (reduce + (fn [result {:keys [font-id] :as node}] + (let [current-font + (if (some? font-id) + (select-keys node [:font-id :font-variant-id]) + (select-keys txt/default-text-attrs [:font-id :font-variant-id]))] + (conj result current-font))) + #{}))) (defn fetch-font-css "Given a font and the variant-id, retrieves the fontface CSS" diff --git a/frontend/src/app/main/ui/components/link.cljs b/frontend/src/app/main/ui/components/link.cljs index ddaad5361..4c48681bb 100644 --- a/frontend/src/app/main/ui/components/link.cljs +++ b/frontend/src/app/main/ui/components/link.cljs @@ -12,10 +12,10 @@ (mf/defc link {::mf/wrap-props false} - [{:keys [action klass data-test keyboard-action children]}] + [{:keys [action class data-test keyboard-action children]}] (let [keyboard-action (d/nilv keyboard-action action)] [:a {:on-click action - :class klass + :class class :on-key-down (fn [event] (when ^boolean (kbd/enter? event) (keyboard-action event))) diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index dffd26c78..1a93e3a64 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -24,7 +24,7 @@ [app.main.ui.dashboard.inline-edition :refer [inline-edition]] [app.main.ui.dashboard.project-menu :refer [project-menu]] [app.main.ui.dashboard.team-form] - [app.main.ui.icons :as i] + [app.main.ui.icons :as i :refer [icon-xref]] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] [app.util.i18n :as i18n :refer [tr]] @@ -39,6 +39,33 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) +(def ^:private clear-search-icon + (icon-xref :delete-text-refactor (stl/css :clear-search-icon))) + +(def ^:private search-icon + (icon-xref :search-refactor (stl/css :search-icon))) + +(def ^:private tick-icon + (icon-xref :tick-refactor (stl/css :tick-icon))) + +(def ^:private logo-icon + (icon-xref :logo-refactor (stl/css :logo-icon))) + +(def ^:private add-icon + (icon-xref :add-refactor (stl/css :add-icon))) + +(def ^:private arrow-icon + (icon-xref :arrow-refactor (stl/css :arrow-icon))) + +(def ^:private menu-icon + (icon-xref :menu-refactor (stl/css :menu-icon))) + +(def ^:private pin-icon + (icon-xref :pin-refactor (stl/css :pin-icon))) + +(def ^:private exit-icon + (icon-xref :exit-refactor (stl/css :exit-icon))) + (mf/defc sidebar-project [{:keys [item selected?] :as props}] (let [dstate (mf/deref refs/dashboard-local) @@ -54,13 +81,13 @@ local @local* on-click - (mf/use-callback + (mf/use-fn (mf/deps item) (fn [] (st/emit! (dd/go-to-files (:id item))))) on-key-down - (mf/use-callback + (mf/use-fn (mf/deps item) (fn [event] (when (kbd/enter? event) @@ -74,7 +101,7 @@ (dom/set-attribute! project-title "tabindex" "-1"))))))))) on-menu-click - (mf/use-callback + (mf/use-fn (fn [event] (let [position (dom/get-client-position event)] (dom/prevent-default event) @@ -83,13 +110,13 @@ :menu-pos position)))) on-menu-close - (mf/use-callback #(swap! local* assoc :menu-open false)) + (mf/use-fn #(swap! local* assoc :menu-open false)) on-edit-open - (mf/use-callback #(swap! local* assoc :edition? true)) + (mf/use-fn #(swap! local* assoc :edition? true)) on-edit - (mf/use-callback + (mf/use-fn (mf/deps item) (fn [name] (when-not (str/blank? name) @@ -98,7 +125,7 @@ (swap! local* assoc :edition? false))) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps selected-project) (fn [e] (when (dnd/has-type? e "penpot/files") @@ -108,25 +135,25 @@ (swap! local* assoc :dragging? true)))))) on-drag-over - (mf/use-callback + (mf/use-fn (fn [e] (when (dnd/has-type? e "penpot/files") (dom/prevent-default e)))) on-drag-leave - (mf/use-callback + (mf/use-fn (fn [e] (when-not (dnd/from-child? e) (swap! local* assoc :dragging? false)))) on-drop-success - (mf/use-callback + (mf/use-fn (mf/deps (:id item)) #(st/emit! (msg/success (tr "dashboard.success-move-file")) (dd/go-to-files (:id item)))) on-drop - (mf/use-callback + (mf/use-fn (mf/deps item selected-files) (fn [_] (swap! local* assoc :dragging? false) @@ -139,6 +166,7 @@ [:* [:li {:tab-index "0" :class (stl/css-case :project-element true + :sidebar-nav-item true :current selected? :dragging (:dragging? local)) :on-click on-click @@ -167,19 +195,19 @@ emit! (mf/use-memo #(f/debounce st/emit! 500)) on-search-blur - (mf/use-callback + (mf/use-fn (fn [_] (reset! focused? false))) on-search-change - (mf/use-callback + (mf/use-fn (mf/deps team-id) (fn [event] (let [value (dom/get-target-val event)] (emit! (dd/go-to-search value))))) on-clear-click - (mf/use-callback + (mf/use-fn (mf/deps team-id) (fn [e] (let [search-input (dom/get-element "search-input")] @@ -190,7 +218,7 @@ (dom/stop-propagation e)))) on-key-press - (mf/use-callback + (mf/use-fn (fn [e] (when (kbd/enter? e) (ts/schedule-on-idle @@ -204,94 +232,107 @@ (dom/stop-propagation e)))) handle-clear-search - (mf/use-callback + (mf/use-fn (mf/deps on-clear-click) (fn [event] (when (kbd/enter? event) (on-clear-click event))))] [:form {:class (stl/css :sidebar-search)} - [:input - {:class (stl/css :input-text) - :key "images-search-box" - :id "search-input" - :type "text" - :aria-label (tr "dashboard.search-placeholder") - :placeholder (tr "dashboard.search-placeholder") - :default-value search-term - :auto-complete "off" - ;; :on-focus on-search-focus - :on-blur on-search-blur - :on-change on-search-change - :on-key-press on-key-press - :ref #(when % (set! (.-value %) search-term))}] + [:input {:class (stl/css :input-text) + :key "images-search-box" + :id "search-input" + :type "text" + :aria-label (tr "dashboard.search-placeholder") + :placeholder (tr "dashboard.search-placeholder") + :default-value search-term + :auto-complete "off" + ;; :on-focus on-search-focus + :on-blur on-search-blur + :on-change on-search-change + :on-key-press on-key-press + :ref #(when % (set! (.-value %) search-term))}] (if (or @focused? (seq search-term)) - [:div - {:class (stl/css :clear-search) - :tab-index "0" - :on-click on-clear-click - :on-key-down handle-clear-search} - i/close] + [:button {:class (stl/css :search-btn :clear-search-btn) + :tab-index "0" + :on-click on-clear-click + :on-key-down handle-clear-search} + clear-search-icon] - [:div - {:class (stl/css :search) - :on-click on-clear-click} - i/search])])) + [:button {:class (stl/css :search-btn) + :on-click on-clear-click} + search-icon])])) (mf/defc teams-selector-dropdown-items {::mf/wrap-props false} [{:keys [team profile teams] :as props}] (let [on-create-clicked - (mf/use-callback + (mf/use-fn #(st/emit! (modal/show :team-form {}))) team-selected - (mf/use-callback - (fn [team-id] - (st/emit! (dd/go-to-projects team-id)))) + (mf/use-fn + (fn [event] + (let [team-id (-> (dom/get-current-target event) + (dom/get-data "value"))] + (st/emit! (dd/go-to-projects team-id))))) handle-select-default - (fn [event] - (when (kbd/enter? event) - (team-selected (:default-team-id profile) event))) + (mf/use-fn + (mf/deps profile team-selected) + (fn [event] + (when (kbd/enter? event) + (team-selected (:default-team-id profile) event)))) handle-select-team - (fn [id event] - (when (kbd/enter? event) - (team-selected id event)))] + (mf/use-fn + (mf/deps team-selected) + (fn [event] + (when (kbd/enter? event) + (team-selected event)))) + + handle-creation-key-down + (mf/use-fn + (mf/deps on-create-clicked) + (fn [event] + (when (kbd/enter? event) + (on-create-clicked event))))] [:* - [:> dropdown-menu-item* {:on-click (partial team-selected (:default-team-id profile)) + [:> dropdown-menu-item* {:on-click team-selected + :data-value (:default-team-id profile) :on-key-down handle-select-default :id "teams-selector-default-team" - :class (stl/css :team-name)} - [:span {:class (stl/css :team-icon)} i/logo-icon] + :class (stl/css :team-dropdown-item)} + [:span {:class (stl/css :penpot-icon)} i/logo-icon] + [:span {:class (stl/css :team-text)} (tr "dashboard.your-penpot")] (when (= (:default-team-id profile) (:id team)) - [:span {:class (stl/css :icon)} i/tick])] + tick-icon)] (for [team-item (remove :is-default (vals teams))] - [:> dropdown-menu-item* {:on-click (partial team-selected (:id team-item)) - :on-key-down (partial handle-select-team (:id team-item)) + [:> dropdown-menu-item* {:on-click team-selected + :data-value (:id team-item) + :on-key-down handle-select-team :id (str "teams-selector-" (:id team-item)) - :class (stl/css :team-name) + :class (stl/css :team-dropdown-item) :key (str "teams-selector-" (:id team-item))} - [:span {:class (stl/css :team-icon)} - [:img {:src (cf/resolve-team-photo-url team-item) - :alt (:name team-item)}]] + [:img {:src (cf/resolve-team-photo-url team-item) + :class (stl/css :team-picture) + :alt (:name team-item)}] [:span {:class (stl/css :team-text) :title (:name team-item)} (:name team-item)] (when (= (:id team-item) (:id team)) - [:span {:class (stl/css :icon)} i/tick])]) - [:hr {:role "separator"}] + tick-icon)]) + + [:hr {:role "separator" + :class (stl/css :team-separator)}] [:> dropdown-menu-item* {:on-click on-create-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-create-clicked event))) + :on-key-down handle-creation-key-down :id "teams-selector-create-team" - :class (stl/css :team-name :action)} - [:span {:class (stl/css :team-icon :new-team)} i/close] + :class (stl/css :team-dropdown-item :action)} + [:span {:class (stl/css :icon-wrapper)} add-icon] [:span {:class (stl/css :team-text)} (tr "dashboard.create-new-team")]]])) (s/def ::member-id ::us/uuid) @@ -330,130 +371,200 @@ (rx/throw error))) leave-fn - (fn [member-id] - (let [params (cond-> {} (uuid? member-id) (assoc :reassign-to member-id))] - (st/emit! (dd/leave-team (with-meta params - {:on-success on-success - :on-error on-error}))))) + (mf/use-fn + (mf/deps on-success on-error) + (fn [member-id] + (let [params (cond-> {} (uuid? member-id) (assoc :reassign-to member-id))] + (st/emit! (dd/leave-team (with-meta params + {:on-success on-success + :on-error on-error})))))) delete-fn - (fn [] - (st/emit! (dd/delete-team (with-meta team {:on-success on-success - :on-error on-error})))) + (mf/use-fn + (mf/deps team on-success on-error) + (fn [] + (st/emit! (dd/delete-team (with-meta team {:on-success on-success + :on-error on-error}))))) on-rename-clicked - (fn [] - (st/emit! (modal/show :team-form {:team team}))) + (mf/use-fn + (mf/deps team) + (fn [] + (st/emit! (modal/show :team-form {:team team})))) on-leave-clicked - #(st/emit! (modal/show - {:type :confirm - :title (tr "modals.leave-confirm.title") - :message (tr "modals.leave-confirm.message") - :accept-label (tr "modals.leave-confirm.accept") - :on-accept leave-fn})) + (mf/use-fn + (mf/deps leave-fn) + #(st/emit! (modal/show + {:type :confirm + :title (tr "modals.leave-confirm.title") + :message (tr "modals.leave-confirm.message") + :accept-label (tr "modals.leave-confirm.accept") + :on-accept leave-fn}))) on-leave-as-owner-clicked - (fn [] - (st/emit! (dd/fetch-team-members (:id team)) - (modal/show - {:type :leave-and-reassign - :profile profile - :team team - :accept leave-fn}))) + (mf/use-fn + (mf/deps team profile leave-fn) + (fn [] + (st/emit! (dd/fetch-team-members (:id team)) + (modal/show + {:type :leave-and-reassign + :profile profile + :team team + :accept leave-fn})))) leave-and-close - #(st/emit! (modal/show - {:type :confirm - :title (tr "modals.leave-confirm.title") - :message (tr "modals.leave-and-close-confirm.message" (:name team)) - :scd-message (tr "modals.leave-and-close-confirm.hint") - :accept-label (tr "modals.leave-confirm.accept") - :on-accept delete-fn})) + (mf/use-fn + (mf/deps team delete-fn) + #(st/emit! (modal/show + {:type :confirm + :title (tr "modals.leave-confirm.title") + :message (tr "modals.leave-and-close-confirm.message" (:name team)) + :scd-message (tr "modals.leave-and-close-confirm.hint") + :accept-label (tr "modals.leave-confirm.accept") + :on-accept delete-fn}))) on-delete-clicked - #(st/emit! - (modal/show - {:type :confirm - :title (tr "modals.delete-team-confirm.title") - :message (tr "modals.delete-team-confirm.message") - :accept-label (tr "modals.delete-team-confirm.accept") - :on-accept delete-fn}))] + (mf/use-fn + (mf/deps delete-fn) + #(st/emit! + (modal/show + {:type :confirm + :title (tr "modals.delete-team-confirm.title") + :message (tr "modals.delete-team-confirm.message") + :accept-label (tr "modals.delete-team-confirm.accept") + :on-accept delete-fn}))) + + handle-members + (mf/use-fn + (mf/deps go-members) + (fn [event] + (when (kbd/enter? event) + (go-members)))) + + handle-invitations + (mf/use-fn + (mf/deps go-invitations) + (fn [event] + (when (kbd/enter? event) + (go-invitations)))) + + handle-webhooks + (mf/use-fn + (mf/deps go-webhooks) + (fn [event] + (when (kbd/enter? event) + (go-webhooks)))) + + handle-settings + (mf/use-fn + (mf/deps go-settings) + (fn [event] + (when (kbd/enter? event) + (go-settings)))) + + + handle-rename + (mf/use-fn + (mf/deps on-rename-clicked) + (fn [event] + (when (kbd/enter? event) + (on-rename-clicked)))) + + + handle-leave-and-close + (mf/use-fn + (mf/deps leave-and-close) + (fn [event] + (when (kbd/enter? event) + (leave-and-close)))) + + handle-leave-as-owner-clicked + (mf/use-fn + (mf/deps on-leave-as-owner-clicked) + (fn [event] + (when (kbd/enter? event) + (on-leave-as-owner-clicked)))) + + + handle-on-leave-clicked + (mf/use-fn + (mf/deps on-leave-clicked) + (fn [event] + (when (kbd/enter? event) + (on-leave-clicked)))) + + handle-on-delete-clicked + (mf/use-fn + (mf/deps on-delete-clicked) + (fn [event] + (when (kbd/enter? event) + (on-delete-clicked))))] [:* [:> dropdown-menu-item* {:on-click go-members - :on-key-down (fn [event] - (when (kbd/enter? event) - (go-members))) + :on-key-down handle-members + :className (stl/css :team-options-item) :id "teams-options-members" :data-test "team-members"} (tr "labels.members")] [:> dropdown-menu-item* {:on-click go-invitations - :on-key-down (fn [event] - (when (kbd/enter? event) - (go-invitations))) + :on-key-down handle-invitations + :className (stl/css :team-options-item) :id "teams-options-invitations" :data-test "team-invitations"} (tr "labels.invitations")] (when (contains? cf/flags :webhooks) [:> dropdown-menu-item* {:on-click go-webhooks - :on-key-down (fn [event] - (when (kbd/enter? event) - (go-webhooks))) + :on-key-down handle-webhooks + :className (stl/css :team-options-item) :id "teams-options-webhooks"} (tr "labels.webhooks")]) [:> dropdown-menu-item* {:on-click go-settings - :on-key-down (fn [event] - (when (kbd/enter? event) - (go-settings))) + :on-key-down handle-settings + :className (stl/css :team-options-item) :id "teams-options-settings" :data-test "team-settings"} (tr "labels.settings")] - [:hr] + [:hr {:class (stl/css :team-option-separator)}] (when can-rename? [:> dropdown-menu-item* {:on-click on-rename-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-rename-clicked))) + :on-key-down handle-rename :id "teams-options-rename" + :className (stl/css :team-options-item) :data-test "rename-team"} (tr "labels.rename")]) (cond (= (count members) 1) [:> dropdown-menu-item* {:on-click leave-and-close - :on-key-down (fn [event] - (when (kbd/enter? event) - (leave-and-close))) + :on-key-down handle-leave-and-close + :className (stl/css :team-options-item) :id "teams-options-leave-team"} (tr "dashboard.leave-team")] (get-in team [:permissions :is-owner]) [:> dropdown-menu-item* {:on-click on-leave-as-owner-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-leave-as-owner-clicked))) + :on-key-down handle-leave-as-owner-clicked :id "teams-options-leave-team" + :className (stl/css :team-options-item) :data-test "leave-team"} (tr "dashboard.leave-team")] (> (count members) 1) [:> dropdown-menu-item* {:on-click on-leave-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-leave-clicked))) + :on-key-down handle-on-leave-clicked + :className (stl/css :team-options-item) :id "teams-options-leave-team"} (tr "dashboard.leave-team")]) (when (get-in team [:permissions :is-owner]) [:> dropdown-menu-item* {:on-click on-delete-clicked - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-delete-clicked))) + :on-key-down handle-on-delete-clicked :id "teams-options-delete-team" - :class (stl/css :warning) + :className (stl/css :team-options-item :warning) :data-test "delete-team"} (tr "dashboard.delete-team")])])) @@ -495,6 +606,10 @@ (when first-element (dom/focus! first-element))))))) + close-team-opts-ddwn + (mf/use-fn + #(reset! show-team-opts-ddwn? false)) + handle-show-opts-click (fn [event] (dom/stop-propagation event) @@ -519,34 +634,32 @@ [:div {:class (stl/css :sidebar-team-switch)} [:div {:class (stl/css :switch-content)} - [:button - {:class (stl/css :current-team) - :tab-index "0" - :on-click handle-show-team-click - :on-key-down handle-show-team-keydown} - + [:button {:class (stl/css :current-team) + :on-click handle-show-team-click + :on-key-down handle-show-team-keydown} (if (:is-default team) [:div {:class (stl/css :team-name)} - [:span {:class (stl/css :team-icon)} i/logo-icon] + [:span {:class (stl/css :penpot-icon)} i/logo-icon] [:span {:class (stl/css :team-text)} (tr "dashboard.default-team-name")]] + [:div {:class (stl/css :team-name)} - [:span {:class (stl/css :team-icon)} - [:img {:src (cf/resolve-team-photo-url team) - :alt (:name team)}]] + [:img {:src (cf/resolve-team-photo-url team) + :class (stl/css :team-picture) + :alt (:name team)}] [:span {:class (stl/css :team-text) :title (:name team)} (:name team)]]) - [:span {:class (stl/css :switch-icon)} i/arrow-down]] + arrow-icon] (when-not (:is-default team) - [:button - {:class (stl/css :switch-options) - :on-click handle-show-opts-click - :tab-index "0" - :on-key-down handle-show-opts-keydown} - i/actions])] + [:button {:class (stl/css :switch-options) + :on-click handle-show-opts-click + :tab-index "0" + :on-key-down handle-show-opts-keydown} + menu-icon])] + + ;; Teams Dropdown - ;; Teams Dropdown [:& dropdown-menu {:show @show-teams-ddwn? :on-close handle-close-team :ids ids @@ -557,7 +670,7 @@ :teams teams}]] [:& dropdown-menu {:show @show-team-opts-ddwn? - :on-close #(reset! show-team-opts-ddwn? false) + :on-close close-team-opts-ddwn :ids options-ids :list-class (stl/css :dropdown :options-dropdown)} [:& team-options-dropdown {:team team @@ -577,12 +690,12 @@ (= (:id project) default-project-id)) go-projects - (mf/use-callback + (mf/use-fn (mf/deps team) #(st/emit! (rt/nav :dashboard-projects {:team-id (:id team)}))) go-projects-with-key - (mf/use-callback + (mf/use-fn (mf/deps team) #(st/emit! (rt/nav :dashboard-projects {:team-id (:id team)}) (ts/schedule-on-idle @@ -594,12 +707,12 @@ (dom/set-attribute! projects-title "tabindex" "-1"))))))) go-fonts - (mf/use-callback + (mf/use-fn (mf/deps team) #(st/emit! (rt/nav :dashboard-fonts {:team-id (:id team)}))) go-fonts-with-key - (mf/use-callback + (mf/use-fn (mf/deps team) #(st/emit! (rt/nav :dashboard-fonts {:team-id (:id team)}) (ts/schedule-on-idle @@ -610,7 +723,7 @@ (dom/focus! font-title) (dom/set-attribute! font-title "tabindex" "-1"))))))) go-drafts - (mf/use-callback + (mf/use-fn (mf/deps team default-project-id) (fn [] (st/emit! (rt/nav :dashboard-files @@ -618,7 +731,7 @@ :project-id default-project-id})))) go-drafts-with-key - (mf/use-callback + (mf/use-fn (mf/deps team default-project-id) #(st/emit! (rt/nav :dashboard-files {:team-id (:id team) :project-id default-project-id}) @@ -631,12 +744,12 @@ (dom/set-attribute! drafts-title "tabindex" "-1"))))))) go-libs - (mf/use-callback + (mf/use-fn (mf/deps team) #(st/emit! (rt/nav :dashboard-libraries {:team-id (:id team)}))) go-libs-with-key - (mf/use-callback + (mf/use-fn (mf/deps team) #(st/emit! (rt/nav :dashboard-libraries {:team-id (:id team)}) (ts/schedule-on-idle @@ -653,45 +766,51 @@ [:div {:class (stl/css :sidebar-content)} [:& sidebar-team-switch {:team team :profile profile}] - [:hr] + [:& sidebar-search {:search-term search-term :team-id (:id team)}] [:div {:class (stl/css :sidebar-content-section)} - [:ul {:class (stl/css :sidebar-nav :no-overflow)} - [:li - {:class (stl/css :recent-projects) - :class-name (when projects? (stl/css :current))} + [:ul {:class (stl/css :sidebar-nav)} + [:li {:class (stl/css-case :recent-projects true + :sidebar-nav-item true + :current projects?)} [:& link {:action go-projects + :class (stl/css :sidebar-link) :keyboard-action go-projects-with-key} [:span {:class (stl/css :element-title)} (tr "labels.projects")]]] - [:li {:class-name (when drafts? (stl/css :current))} + [:li {:class (stl/css-case :current drafts? + :sidebar-nav-item true)} [:& link {:action go-drafts + :class (stl/css :sidebar-link) :keyboard-action go-drafts-with-key} [:span {:class (stl/css :element-title)} (tr "labels.drafts")]]] - [:li {:class-name (when libs? (stl/css :current))} + [:li {:class (stl/css-case :current libs? + :sidebar-nav-item true)} [:& link {:action go-libs + :class (stl/css :sidebar-link) :keyboard-action go-libs-with-key} [:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]] - [:hr] [:div {:class (stl/css :sidebar-content-section)} - [:ul {:class (stl/css :sidebar-nav :no-overflow)} - [:li {:class-name (when fonts? (stl/css :current))} + [:ul {:class (stl/css :sidebar-nav)} + [:li {:class (stl/css-case :sidebar-nav-item true + :current fonts?)} [:& link {:action go-fonts + :class (stl/css :sidebar-link) :keyboard-action go-fonts-with-key :data-test "fonts"} [:span {:class (stl/css :element-title)} (tr "labels.fonts")]]]]] - [:hr] + [:div {:class (stl/css :sidebar-content-section) :data-test "pinned-projects"} (if (seq pinned-projects) - [:ul {:class (stl/css :sidebar-nav)} + [:ul {:class (stl/css :sidebar-nav :pinned-projects)} (for [item pinned-projects] [:& sidebar-project {:item item @@ -700,25 +819,26 @@ :team-id (:id team) :selected? (= (:id item) (:id project))}])] [:div {:class (stl/css :sidebar-empty-placeholder)} - [:span {:class (stl/css :icon)} i/pin-refactor] - [:span {:class (stl/css :text)} (tr "dashboard.no-projects-placeholder")]])]])) + pin-icon + [:span {:class (stl/css :empty-text)} (tr "dashboard.no-projects-placeholder")]])]])) (mf/defc profile-section [{:keys [profile team] :as props}] - (let [show (mf/use-state false) + (let [show* (mf/use-state false) + show (deref show*) photo (cf/resolve-profile-photo-url profile) on-click - (mf/use-callback + (mf/use-fn (fn [section event] (dom/stop-propagation event) - (reset! show false) + (reset! show* false) (if (keyword? section) (st/emit! (rt/nav section)) (st/emit! section)))) show-release-notes - (mf/use-callback + (mf/use-fn (fn [event] (let [version (:main cf/version)] (st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version version})) @@ -730,48 +850,48 @@ show-comments? @show-comments* handle-hide-comments - (mf/use-callback + (mf/use-fn (fn [] (reset! show-comments* false))) handle-show-comments - (mf/use-callback + (mf/use-fn (fn [] (reset! show-comments* true))) handle-click - (mf/use-callback + (mf/use-fn (fn [event] (dom/stop-propagation event) - (swap! show not))) + (swap! show* not))) handle-key-down - (mf/use-callback + (mf/use-fn (fn [event] (when (kbd/enter? event) - (reset! show true)))) + (reset! show* true)))) handle-close (fn [event] (dom/stop-propagation event) - (reset! show false)) + (reset! show* false)) handle-key-down-profile - (mf/use-callback + (mf/use-fn (mf/deps on-click) (fn [event] (when (kbd/enter? event) (on-click :settings-profile event)))) handle-click-url - (mf/use-callback + (mf/use-fn (fn [event] (let [url (-> (dom/get-current-target event) (dom/get-data "url"))] (dom/open-new-window url)))) handle-keydown-url - (mf/use-callback + (mf/use-fn (fn [event] (let [url (-> (dom/get-current-target event) (dom/get-data "url"))] @@ -779,35 +899,41 @@ (dom/open-new-window url))))) handle-show-release-notes - (mf/use-callback + (mf/use-fn (mf/deps show-release-notes) (fn [event] (when (kbd/enter? event) (show-release-notes)))) handle-feedback-click - (mf/use-callback + (mf/use-fn (mf/deps on-click) #(on-click :settings-feedback %)) handle-feedback-keydown - (mf/use-callback + (mf/use-fn (mf/deps on-click) (fn [event] (when (kbd/enter? event) (on-click :settings-feedback event)))) handle-logout-click - (mf/use-callback + (mf/use-fn (mf/deps on-click) #(on-click (du/logout) %)) handle-logout-keydown - (mf/use-callback + (mf/use-fn (mf/deps on-click) (fn [event] (when (kbd/enter? event) - (on-click (du/logout) event))))] + (on-click (du/logout) event)))) + + handle-set-profile + (mf/use-fn + (mf/deps on-click) + (fn [event] + (on-click :settings-profile event)))] [:* (when (and team profile) @@ -825,77 +951,89 @@ :on-key-down handle-key-down :data-test "profile-btn"} [:img {:src photo + :class (stl/css :profile-img) :alt (:fullname profile)}] - [:span (:fullname profile)]] + [:span {:class (stl/css :profile-fullname)} (:fullname profile)]] - [:& dropdown-menu {:on-close handle-close :show @show} - [:ul {:class (stl/css :dropdown)} - [:li {:tab-index (if @show "0" "-1") - :on-click (partial on-click :settings-profile) - :on-key-down handle-key-down-profile - :data-test "profile-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.your-account")]] + [:& dropdown-menu {:on-close handle-close :show show :list-class (stl/css :profile-dropdown)} + [:li {:tab-index (if show "0" "-1") + :class (stl/css :profile-dropdown-item) + :on-click handle-set-profile + :on-key-down handle-key-down-profile + :data-test "profile-profile-opt"} + (tr "labels.your-account")] - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :data-url "https://help.penpot.app" - :on-click handle-click-url - :on-key-down handle-keydown-url - :data-test "help-center-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.help-center")]] + [:li {:class (stl/css :profile-separator)}] - [:li {:tab-index (if @show "0" "-1") - :data-url "https://community.penpot.app" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "labels.community")]] + [:li {:class (stl/css :profile-dropdown-item) + :tab-index (if show "0" "-1") + :data-url "https://help.penpot.app" + :on-click handle-click-url + :on-key-down handle-keydown-url + :data-test "help-center-profile-opt"} + (tr "labels.help-center")] - [:li {:tab-index (if @show "0" "-1") - :data-url "https://www.youtube.com/c/Penpot" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "labels.tutorials")]] + [:li {:tab-index (if show "0" "-1") + :class (stl/css :profile-dropdown-item) + :data-url "https://community.penpot.app" + :on-click handle-click-url + :on-key-down handle-keydown-url} + (tr "labels.community")] - [:li {:tab-index (if @show "0" "-1") - :on-click show-release-notes - :on-key-down handle-show-release-notes} - [:span {:class (stl/css :text)} (tr "labels.release-notes")]] + [:li {:tab-index (if show "0" "-1") + :class (stl/css :profile-dropdown-item) + :data-url "https://www.youtube.com/c/Penpot" + :on-click handle-click-url + :on-key-down handle-keydown-url} + (tr "labels.tutorials")] - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :data-url "https://penpot.app/libraries-templates" - :on-click handle-click-url - :on-key-down handle-keydown-url - :data-test "libraries-templates-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.libraries-and-templates")]] + [:li {:tab-index (if show "0" "-1") + :class (stl/css :profile-dropdown-item) + :on-click show-release-notes + :on-key-down handle-show-release-notes} + (tr "labels.release-notes")] - [:li {:tab-index (if @show "0" "-1") - :data-url "https://github.com/penpot/penpot" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "labels.github-repo")]] + [:li {:class (stl/css :profile-separator)}] - [:li {:tab-index (if @show "0" "-1") - :data-url "https://penpot.app/terms" - :on-click handle-click-url - :on-key-down handle-keydown-url} - [:span {:class (stl/css :text)} (tr "auth.terms-of-service")]] + [:li {:class (stl/css :profile-dropdown-item) + :tab-index (if show "0" "-1") + :data-url "https://penpot.app/libraries-templates" + :on-click handle-click-url + :on-key-down handle-keydown-url + :data-test "libraries-templates-profile-opt"} + (tr "labels.libraries-and-templates")] - (when (contains? cf/flags :user-feedback) - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :on-click handle-feedback-click - :on-key-down handle-feedback-keydown - :data-test "feedback-profile-opt"} - [:span {:class (stl/css :text)} (tr "labels.give-feedback")]]) + [:li {:tab-index (if show "0" "-1") + :class (stl/css :profile-dropdown-item) + :data-url "https://github.com/penpot/penpot" + :on-click handle-click-url + :on-key-down handle-keydown-url} + (tr "labels.github-repo")] - [:li {:class (stl/css :separator) - :tab-index (if @show "0" "-1") - :on-click handle-logout-click - :on-key-down handle-logout-keydown - :data-test "logout-profile-opt"} - [:span {:class (stl/css :icon)} i/exit] - [:span {:class (stl/css :text)} (tr "labels.logout")]]]] + [:li {:tab-index (if show "0" "-1") + :class (stl/css :profile-dropdown-item) + :data-url "https://penpot.app/terms" + :on-click handle-click-url + :on-key-down handle-keydown-url} + (tr "auth.terms-of-service")] + + [:li {:class (stl/css :profile-separator)}] + + (when (contains? cf/flags :user-feedback) + [:li {:class (stl/css :profile-dropdown-item) + :tab-index (if show "0" "-1") + :on-click handle-feedback-click + :on-key-down handle-feedback-keydown + :data-test "feedback-profile-opt"} + (tr "labels.give-feedback")]) + + [:li {:class (stl/css :profile-dropdown-item :item-with-icon) + :tab-index (if show "0" "-1") + :on-click handle-logout-click + :on-key-down handle-logout-keydown + :data-test "logout-profile-opt"} + exit-icon + (tr "labels.logout")]] (when (and team profile) [:& comments-icon diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss index 2623cc516..c6cea273a 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.scss +++ b/frontend/src/app/main/ui/dashboard/sidebar.scss @@ -7,498 +7,375 @@ @use "common/refactor/common-refactor.scss" as *; @use "common/refactor/common-dashboard"; +// SIDEBAR COMPONENT .dashboard-sidebar { grid-row: 1 / span 2; grid-column: 1 / span 2; - - background-color: var(--panel-background-color); - border-right: $s-1 solid $db-quaternary; - margin: 0 $s-16 0 0; + display: grid; + grid-template-rows: 1fr auto; + height: 100%; + width: 100%; padding: $s-16 0 0 0; - + margin: 0 $s-16 0 0; + border-right: $s-1 solid var(--panel-border-color); + background-color: var(--panel-background-color); z-index: $z-index-1; - display: flex; - flex-direction: column; - height: 100%; } +//SIDEBAR CONTENT COMPONENT .sidebar-content { - display: flex; - flex-direction: column; + display: grid; + grid-template-rows: auto auto auto auto 1fr; + gap: $s-24; height: 100%; - overflow-y: auto; padding: 0; - - hr { - border-color: transparent; - margin: $s-12 $s-16; - } + overflow-y: auto; } +// SIDEBAR TEAM SWITCH .sidebar-team-switch { position: relative; - display: flex; margin: $s-4 $s-16; - - .switch-content { - background-color: $db-tertiary; - border-radius: $br-8; - height: $s-48; - display: flex; - width: 100%; - border: $s-1 solid $db-tertiary; - align-items: center; - - svg { - fill: #8f9da3; - } - } - - .switch-icon { - display: flex; - align-items: center; - justify-content: center; - - svg { - fill: $df-secondary; - width: $s-12; - height: $s-12; - } - } - - .current-team { - height: 100%; - cursor: pointer; - display: flex; - align-items: center; - flex-grow: 1; - font-size: $fs-14; - padding: 0 $s-12; - background-color: transparent; - border: none; - } - - .team-name { - flex-grow: 1; - display: flex; - height: $s-40; - align-items: center; - } - - .team-text { - color: $df-primary; - width: $s-144; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - text-align: left; - } - - .team-icon { - display: flex; - align-items: center; - padding-right: $s-12; - - img { - border-radius: 50%; - flex-shrink: 0; - height: $s-24; - width: $s-24; - } - - svg { - width: $s-24; - height: $s-24; - } - } - - .switch-options { - @include buttonStyle; - @include flexCenter; - max-width: $s-24; - min-width: $s-28; - height: 100%; - border-left: $s-1 solid $db-primary; - background-color: transparent; - - svg { - fill: $df-secondary; - width: $s-16; - height: $s-12; - } - } - - .dropdown { - right: $s-2; - top: $s-52; - max-height: $s-480; - &:not(.teams-dropdown) { - min-width: $s-160; - } - } } -.dropdown { - @include menuShadow; - position: absolute; - z-index: $z-index-4; - background-color: $db-tertiary; - border: $s-1 solid $db-quaternary; +.switch-content { + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + height: $s-48; + width: 100%; border-radius: $br-8; + border: $s-1 solid var(--menu-background-color); + background-color: var(--menu-background-color); +} - .separator { - border-color: transparent; - margin-top: $s-12; - } +.current-team { + @include buttonStyle; + display: grid; + align-items: center; + grid-template-columns: 1fr auto; + gap: $s-8; + height: 100%; + padding: 0 $s-12; +} - li { - border-radius: $br-8; - height: $s-40; - margin: $s-6; +.team-name { + display: grid; + align-items: center; + grid-template-columns: auto 1fr; + gap: $s-12; + height: $s-40; +} - display: flex; - align-items: center; - cursor: pointer; - font-size: $fs-14; - padding: $s-6 $s-16; +.team-text { + @include textEllipsis; + @include smallTitleTipography; + width: $s-144; + text-align: left; + color: var(--menu-foreground-color-hover); +} - .warning { - color: var(--element-foreground-warning); - } - - &:hover { - background-color: $db-quaternary; - } - svg { - height: $s-12; - width: $s-12; - } - } - - hr { - border-color: transparent; - margin: 0; - } - - &.options-dropdown { - li { - color: $df-primary; - &.warning { - color: var(--element-foreground-warning); - } - } +// This icon still use the old svg +.penpot-icon { + @include flexCenter; + svg { + fill: var(--icon-foreground); + width: $s-24; + height: $s-24; } } +.team-picture { + @include flexCenter; + border-radius: 50%; + height: $s-24; + width: $s-24; +} + +.arrow-icon { + @extend .button-icon; + transform: rotate(90deg); + stroke: var(--icon-foreground); +} + +.switch-options { + @include buttonStyle; + @include flexCenter; + max-width: $s-24; + min-width: $s-28; + height: 100%; + border-left: $s-1 solid var(--panel-background-color); + background-color: transparent; +} + +.menu-icon { + @extend .button-icon; + stroke: var(--icon-foreground); +} + +// DROPDOWNS + .teams-dropdown { - background-color: $db-tertiary; - border-radius: $br-8; - border: $s-1 solid $db-quaternary; - min-width: $s-248; - + @extend .menu-dropdown; left: 0; top: $s-52; - + height: fit-content; max-height: $s-480; + min-width: $s-248; + width: 100%; overflow-x: hidden; overflow-y: auto; +} - li { - border-radius: $br-8; - height: $s-40; - padding: 0 $s-6; - margin: $s-6; +.team-dropdown-item { + @extend .menu-item-base; + display: grid; + grid-template-columns: $s-24 1fr auto; + gap: $s-8; + height: $s-40; +} - svg { - fill: $df-secondary; +.action { + --sidebar-action-icon-color: var(--icon-foreground); + --sidebar-icon-backgroun-color: var(--color-background-secondary); + &:hover { + --sidebar-action-icon-color: var(--color-background-secondary); + --sidebar-icon-backgroun-color: var(--color-accent-primary); + } +} + +.icon-wrapper { + @include flexCenter; + width: $s-24; + height: $s-24; + margin-right: $s-12; + border-radius: 50%; + background-color: var(--sidebar-icon-backgroun-color); +} + +.add-icon { + @extend .button-icon; + width: $s-24; + height: $s-24; + stroke: var(--sidebar-action-icon-color); +} + +.team-separator { + border-top: $s-1 solid var(--dropdown-separator-color); + margin: 0; +} + +.tick-icon { + @extend .button-icon-small; + stroke: var(--icon-foreground); +} + +.options-dropdown { + @extend .menu-dropdown; + right: $s-2; + top: $s-52; + max-height: $s-480; + &:not(.teams-dropdown) { + min-width: $s-160; + } +} + +.team-options-item { + @extend .menu-item-base; + height: $s-40; +} + +.team-option-separator { + height: $s-1; + margin: 0; + border-top: $s-1 solid var(--dropdown-separator-color); +} + +// Sections +.sidebar-nav { + margin: 0; + user-select: none; + overflow: none; +} + +.pinned-projects { + overflow-y: auto; +} + +.sidebar-nav-item { + cursor: pointer; + &:hover { + background-color: var(--sidebar-element-background-color-hover); + span { + color: var(--sidebar-element-foreground-color-hover); } + } - &:hover { - background-color: $db-quaternary; - .team-icon { - &.new-team { - background-color: $da-primary; - color: $db-primary; - svg { - fill: $db-secondary; - } - } - } - } - .team-icon { - display: flex; - align-items: center; - } - .team-text { - color: $df-primary; - width: $s-168; - } - - &.action { - .team-icon { - background-color: #2e3434; - background-color: var(--new-team-button-background-color); - border-radius: 50%; - height: $s-24; - margin-right: $s-12; - padding: $s-6; - width: $s-24; - - svg { - height: $s-12; - width: $s-12; - } - } + &.current { + background-color: var(--sidebar-element-background-color-selected); + .element-title { + color: var(--sidebar-element-foreground-color-selected); } } } +.recent-projects svg { + stroke: var(--main-icon-foreground); +} + +.sidebar-link { + display: block; + padding: $s-8 $s-8 $s-8 $s-24; + font-weight: $fw400; + width: 100%; + &:hover { + text-decoration: none; + } +} + +.project-element { + padding: $s-8 $s-8 $s-8 $s-24; +} + +.element-title { + @include textEllipsis; + color: var(--sidebar-element-foreground-color); + font-size: $fs-14; +} + +// Pinned projects + .sidebar-empty-placeholder { padding: $s-12; - color: $df-secondary; + color: var(--empty-message-foreground-color); display: flex; align-items: center; - - .icon { - padding: 0 $s-12; - svg { - fill: none; - stroke: currentColor; - width: $s-12; - height: $s-12; - } - } - .text { - font-size: $fs-12; - } } +.pin-icon { + @extend .button-icon-small; + stroke: var(--icon-foreground); + margin: 0 $s-12; +} + +.empty-text { + font-size: $fs-12; +} + +// Search + .sidebar-search { + position: relative; + display: grid; + grid-template-columns: 1fr; align-items: center; border: $s-1 solid transparent; - display: flex; - margin: $s-6 $s-16; - - background-color: $db-tertiary; + margin: 0 $s-16; border-radius: $br-8; - margin-bottom: $s-32; - margin-top: 0; - position: relative; + background-color: var(--search-bar-input-background-color); +} - .input-text { - background: transparent; - border: 0; - font-size: $fs-14; - margin: 0; - width: 100%; - height: $s-40; +.input-text { + @include smallTitleTipography; + height: $s-40; + width: 100%; + padding: $s-6 $s-12; + margin: 0; + border: transparent; + border-radius: $br-8; + background: transparent; + color: var(--search-bar-foreground-color); - border-radius: $br-8; - color: $df-primary; - max-width: 100%; - padding: $s-6 $s-12; - - &:focus, - &:focus-within { - border: $s-1 solid $da-primary; - } + &:focus, + &:focus-within, + &:focus-visible { + outline: none; + border: $s-1 solid var(--search-bar-input-border-color-focus); } ::placeholder { - color: $df-secondary; - } - - .search, - .clear-search { - align-items: center; - cursor: pointer; - display: flex; - height: $s-24; - margin-left: auto; - padding: 0 $s-8; - width: $s-32; - - position: absolute; - top: calc(50% - $s-12); - right: $s-2; - - svg { - fill: $df-secondary; - height: $s-16; - width: $s-16; - } - } - - .clear-search svg { - transform: rotate(45deg); - - &:hover { - fill: $da-primary; - } + color: var(--search-bar-placeholder-foreground-color); } } -.sidebar-nav { - display: flex; - flex-direction: column; - overflow-y: auto; - margin: 0; - user-select: none; - - &.no-overflow { - overflow: unset; - } - - & > li { - align-items: center; - cursor: pointer; - display: flex; - flex-shrink: 0; - - &.project-element { - padding: $s-8 $s-8 $s-8 $s-24; - } - - a { - padding: $s-8 $s-8 $s-8 $s-24; - font-weight: $fw400; - width: 100%; - &:hover { - text-decoration: none; - } - } - - svg { - fill: $db-secondary; - margin-right: $s-8; - height: $s-12; - width: $s-12; - } - - .element-title { - color: $df-secondary; - font-size: $fs-14; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - &.recent-projects { - svg { - fill: $df-primary; - } - } - - input.element-title { - border: 0; - height: $s-32; - padding: $s-6; - margin: 0; - width: 100%; - background-color: $df-primary; - } - - .close { - background-color: $df-primary; - cursor: pointer; - padding-left: $s-6; - - svg { - fill: $df-secondary; - height: $s-16; - transform: rotate(45deg) translateY(7px); - width: $s-16; - margin: 0; - } - } - - .element-subtitle { - color: $df-secondary; - font-style: italic; - } - - &:hover { - background-color: $db-secondary; - span { - color: $da-primary; - } - } - - &.current { - background-color: $db-quaternary; - .element-title { - color: $da-primary; - } - } - } +.search-btn { + @include buttonStyle; + @include flexCenter; + position: absolute; + right: 0; + height: $s-24; + width: $s-32; + padding: 0 $s-8; } +.search-icon, +.clear-search-btn { + @extend .button-icon; + --sidebar-search-foreground-color: var(--search-bar-icon-foreground-color); + stroke: var(--sidebar-search-foreground-color); +} + +.clear-search-btn:hover { + --sidebar-search-foreground-color: var(--search-bar-icon-foreground-color-hover); +} + +// Profile .profile-section { - align-items: center; - cursor: pointer; - display: flex; - padding: $s-12 $s-16; position: relative; - - background-color: $db-tertiary; - border-top: $s-1 solid $db-quaternary; - - .profile { - align-items: center; - cursor: pointer; - display: flex; - flex-grow: 1; - - span { - @include text-ellipsis; - color: $df-primary; - margin: $s-12; - font-size: $fs-14; - max-width: $s-160; - } - - img { - border-radius: 50%; - flex-shrink: 0; - height: $s-40; - width: $s-40; - } - svg { - height: $s-12; - margin-left: auto; - margin-right: $s-8; - width: $s-12; - } - } - - .dropdown { - left: $s-16; - bottom: $s-44; - background-color: var(--profile-drowpdown-background-color); - border: $s-1 solid $db-tertiary; - border-radius: $br-8; - min-width: $s-252; - - @include animation(0, 0.2s, fadeInUp); - - li { - font-size: $fs-14; - padding: $s-8 $s-16; - - svg { - fill: $df-secondary; - margin-right: $s-8; - - height: $s-12; - width: $s-12; - } - - .text { - color: $df-primary; - } - - &.separator { - border-top: $s-1 solid transparent; - } - } - } + display: grid; + grid-template-columns: 1fr auto; + padding: $s-12 $s-16; + border-top: $s-1 solid var(--panel-border-color); + background-color: var(--profile-section-background-color); + cursor: pointer; +} + +.profile { + display: grid; + grid-template-columns: auto 1fr; + gap: $s-8; + cursor: pointer; +} + +.profile-fullname { + @include smallTitleTipography; + @include text-ellipsis; + align-self: center; + max-width: $s-160; + color: var(--profile-foreground-color); +} + +.profile-img { + height: $s-40; + width: $s-40; + border-radius: $br-circle; +} + +.profile-dropdown { + @extend .menu-dropdown; + left: $s-16; + bottom: $s-72; + min-width: $s-252; + // TODO ADD animation fadeInUp +} + +.profile-dropdown-item { + @extend .menu-item-base; + @include smallTitleTipography; + height: $s-40; + padding: $s-8 $s-16; +} + +.profile-separator { + height: $s-6; +} + +.item-with-icon { + display: grid; + grid-template-columns: auto 1fr; + gap: $s-8; +} + +.exit-icon { + @extend .button-icon; + stroke: var(--icon-foreground); } diff --git a/frontend/src/app/main/ui/dashboard/team_form.cljs b/frontend/src/app/main/ui/dashboard/team_form.cljs index ff500666d..e93244e53 100644 --- a/frontend/src/app/main/ui/dashboard/team_form.cljs +++ b/frontend/src/app/main/ui/dashboard/team_form.cljs @@ -89,7 +89,9 @@ [:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-container)} - [:& fm/form {:form form :on-submit on-submit} + [:& fm/form {:form form + :on-submit on-submit + :class (stl/css :team-form)} [:div {:class (stl/css :modal-header)} (if team diff --git a/frontend/src/app/main/ui/dashboard/team_form.scss b/frontend/src/app/main/ui/dashboard/team_form.scss index dfca8099e..2545950f8 100644 --- a/frontend/src/app/main/ui/dashboard/team_form.scss +++ b/frontend/src/app/main/ui/dashboard/team_form.scss @@ -31,6 +31,10 @@ margin-bottom: $s-24; } +.team-form { + min-width: $s-400; +} + .group-name-input { @extend .input-element-label; label { @@ -44,7 +48,6 @@ input { @include bodySmallTypography; - margin-top: $s-8; } } } diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index be6dd7ab9..198a03515 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -348,6 +348,7 @@ (def ^:icon easing-ease-in-out-refactor (icon-xref :easing-ease-in-out-refactor)) (def ^:icon effects-refactor (icon-xref :effects-refactor)) (def ^:icon elipse-refactor (icon-xref :elipse-refactor)) +(def ^:icon exit-refactor (icon-xref :exit-refactor)) (def ^:icon expand-refactor (icon-xref :expand-refactor)) (def ^:icon feedback-refactor (icon-xref :feedback-refactor)) (def ^:icon fill-content-refactor (icon-xref :fill-content-refactor)) @@ -394,6 +395,7 @@ (def ^:icon layers-refactor (icon-xref :layers-refactor)) (def ^:icon locate-refactor (icon-xref :locate-refactor)) (def ^:icon lock-refactor (icon-xref :lock-refactor)) +(def ^:icon logo-refactor (icon-xref :penpot-logo-icon)) ;; This icon will not change (def ^:icon library-refactor (icon-xref :library-refactor)) (def ^:icon margin-bottom-refactor (icon-xref :margin-bottom-refactor)) (def ^:icon margin-left-refactor (icon-xref :margin-left-refactor)) diff --git a/frontend/src/app/main/ui/messages.cljs b/frontend/src/app/main/ui/messages.cljs index 56c481fb2..00df9c3f3 100644 --- a/frontend/src/app/main/ui/messages.cljs +++ b/frontend/src/app/main/ui/messages.cljs @@ -33,6 +33,7 @@ :links (:links message) :content (:content message)} + is-context-msg (and (nil? (:timeout message)) (nil? (:actions 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))))] @@ -42,5 +43,7 @@ [:& toast-notification toast-message] is-inline-msg [:& inline-notification inline-message] + is-context-msg + [:& context-notification context-message] :else - [:& context-notification context-message])))) + [:& toast-notification toast-message])))) diff --git a/frontend/src/app/main/ui/notifications/toast_notification.scss b/frontend/src/app/main/ui/notifications/toast_notification.scss index dfa67bc1e..6626fc119 100644 --- a/frontend/src/app/main/ui/notifications/toast_notification.scss +++ b/frontend/src/app/main/ui/notifications/toast_notification.scss @@ -44,10 +44,10 @@ } .info { - --bg-color: var(--alert-background-color-info); - --fg-color: var(--alert-text-foreground-color-info); - --icon-color: var(--alert-icon-foreground-color-info); - --border-color: var(--alert-border-color-info); + --toast-notification-bg-color: var(--alert-background-color-info); + --toast-notification-fg-color: var(--alert-text-foreground-color-info); + --toast-notification-icon-color: var(--alert-icon-foreground-color-info); + --toast-notification-border-color: var(--alert-border-color-info); } .default { diff --git a/frontend/src/app/main/ui/shapes/text/styles.cljs b/frontend/src/app/main/ui/shapes/text/styles.cljs index 0b4e325d9..534b786e4 100644 --- a/frontend/src/app/main/ui/shapes/text/styles.cljs +++ b/frontend/src/app/main/ui/shapes/text/styles.cljs @@ -21,7 +21,6 @@ (let [valign (:vertical-align node "top") base #js {:height (fmt/format-pixels height) :width (fmt/format-pixels width) - :fontFamily "sourcesanspro" :display "flex" :whiteSpace "break-spaces"}] (cond-> base diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index 8a7961a8b..a937eada3 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -135,6 +135,7 @@ (fn [_] (wapi/write-to-clipboard current-link) (st/emit! (msg/show {:type :info + :notification-type :toast :content (tr "common.share-link.link-copied-success") :timeout 1000}))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index d7a3d0e23..cd60ec811 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -107,9 +107,9 @@ (-> (image-size href) (p/then (fn [{:keys [width height]}] - (when (or (not (mth/close? width fixed-width 2)) - (not (mth/close? height fixed-height 2))) - (st/emit! (dwt/request-thumbnail file-id page-id frame-id "frame")))))))) + (when (or (not (mth/close? width fixed-width 5)) + (not (mth/close? height fixed-height 5))) + (st/emit! (dwt/request-thumbnail file-id page-id frame-id "frame" "check-thumbnail-size")))))))) (defn root-frame-wrapper-factory [shape-wrapper] @@ -175,7 +175,7 @@ (mf/with-effect [] (when-not (some? thumbnail-uri) (tm/schedule-on-idle - #(st/emit! (dwt/request-thumbnail file-id page-id frame-id "frame")))) + #(st/emit! (dwt/request-thumbnail file-id page-id frame-id "frame" "root-frame")))) #(when-let [task (mf/ref-val task-ref)] (d/close! task))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs index 333e4e2fa..5dc91dba6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs @@ -224,10 +224,10 @@ :on-double-click rename-color-clicked} (if (= (:name color) default-name) - [:span {:class (stl/css :default-name-only)} default-name] + [:span {:class (stl/css :default-name)} default-name] [:* - [:span {:class (stl/css :name)} (:name color)] - [:span {:class (stl/css :default-name)} default-name]])]) + (:name color) + [:span {:class (stl/css :default-name :default-name-with-color)} default-name]])]) (when local? [:& cmm/assets-context-menu diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss index daca6b778..ae7193502 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss @@ -6,10 +6,15 @@ @import "refactor/common-refactor.scss"; +// TODO: we should be using subgrid in the common "assets component" to avoid +// using this SCSS variable here (we cannot use a CSS var in this CSS module because +// the elements are not part of the same cascade). +$assets-button-width: $s-28; + .assets-btn { @extend .button-tertiary; height: $s-32; - width: $s-28; + width: $assets-button-width; padding: 0; border-radius: $br-8; svg { @@ -28,10 +33,12 @@ .asset-list-item { position: relative; - display: flex; + display: grid; + grid-template-columns: auto 1fr #{$assets-button-width}; align-items: center; height: $s-32; padding: $s-8; + padding-inline-end: 0; margin-bottom: $s-4; border-radius: $br-8; background-color: var(--assets-item-background-color); @@ -48,7 +55,6 @@ @include bodySmallTypography; @include removeInputStyle; flex-grow: 1; - height: $s-28; max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size))); margin: 0; color: var(--layer-row-foreground-color); @@ -63,25 +69,23 @@ @include flexCenter; height: 100%; justify-content: flex-start; - margin-right: $s-4; + margin-inline-end: $s-4; } .name-block { @include bodySmallTypography; - display: grid; - grid-template-columns: auto 1fr; + @include textEllipsis; margin: 0; - overflow: hidden; - .default-name-only, - .name { - color: var(--assets-item-name-foreground-color); - margin-right: $s-6; - @include textEllipsis; - } - .default-name { - min-width: 0; - color: var(--assets-item-name-foreground-color-rest); - } + color: var(--assets-item-name-foreground-color); +} + +.default-name { + margin-inline-start: $s-4; + color: var(--assets-item-name-foreground-color-rest); +} + +.default-name-with-color { + margin-left: $s-6; } .element-name { diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index fcef93100..d9e543d19 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -380,7 +380,8 @@ {:value "" :label (tr "workspace.options.interaction-none")})] destination-options (mf/with-memo [frames-opts default-opts] - (d/concat-vec default-opts frames-opts)) + (let [sorted-frames-opts (sort-by :label frames-opts)] + (d/concat-vec default-opts sorted-frames-opts))) shape-parents-opts (get-shared-frames-options shape-parents) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 9cad839b3..3a4413989 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -918,8 +918,11 @@ on-gap-change (fn [multiple? type val] (let [val (mth/finite val 0)] - (if ^boolean multiple? + (cond + ^boolean multiple? (st/emit! (dwsl/update-layout ids {:layout-gap {:row-gap val :column-gap val}})) + + (some? type) (st/emit! (dwsl/update-layout ids {:layout-gap {type val}}))))) ;; Padding @@ -941,7 +944,7 @@ (and (= type :simple) (= prop :p2)) (st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}})) - :else + (some? prop) (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}})))))) ;; Grid-direction @@ -1126,16 +1129,16 @@ :on-change on-column-justify-change}] [:& justify-grid-row {:is-column false :value grid-justify-content-row - :on-change on-row-justify-change}]]] - [:div {:class (stl/css :row)} - [:& gap-section {:on-change on-gap-change - :value (:layout-gap values)}]] + :on-change on-row-justify-change}]] - [:div {:class (stl/css :row :padding-section)} - [:& padding-section {:value (:layout-padding values) - :type (:layout-padding-type values) - :on-change-style on-padding-type-change - :on-change on-padding-change}]] + [:div {:class (stl/css :row)} + [:& gap-section {:on-change on-gap-change + :value (:layout-gap values)}]] + [:div {:class (stl/css :row :padding-section)} + [:& padding-section {:value (:layout-padding values) + :type (:layout-padding-type values) + :on-change-style on-padding-type-change + :on-change on-padding-change}]]] nil))])) @@ -1156,9 +1159,10 @@ (mf/use-fn (mf/deps ids) (fn [multiple? type val] - (if multiple? - (st/emit! (dwsl/update-layout ids {:layout-gap {:row-gap val :column-gap val}})) - (st/emit! (dwsl/update-layout ids {:layout-gap {type val}}))))) + (let [val (mth/finite val 0)] + (if multiple? + (st/emit! (dwsl/update-layout ids {:layout-gap {:row-gap val :column-gap val}})) + (st/emit! (dwsl/update-layout ids {:layout-gap {type val}})))))) ;; Padding on-padding-type-change @@ -1169,15 +1173,16 @@ on-padding-change (fn [type prop val] - (cond - (and (= type :simple) (= prop :p1)) - (st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}})) + (let [val (mth/finite val 0)] + (cond + (and (= type :simple) (= prop :p1)) + (st/emit! (dwsl/update-layout ids {:layout-padding {:p1 val :p3 val}})) - (and (= type :simple) (= prop :p2)) - (st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}})) + (and (= type :simple) (= prop :p2)) + (st/emit! (dwsl/update-layout ids {:layout-padding {:p2 val :p4 val}})) - :else - (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}})))) + :else + (st/emit! (dwsl/update-layout ids {:layout-padding {prop val}}))))) ;; Align grid align-items-row (:layout-align-items values) @@ -1308,7 +1313,8 @@ :on-change on-row-justify-change}] [:button {:on-click handle-locate-grid - :class (stl/css :locate-button)} + :class (stl/css :locate-button) + :title (tr "workspace.layout_grid.editor.top-bar.locate.tooltip")} i/locate-refactor]] [:div {:class (stl/css :row)} diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 745631167..4621560a7 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -736,20 +736,23 @@ [track-type value] (cond (str/ends-with? value "%") - [:percent value-int] + [:percent (d/nilv value-int 50)] (str/ends-with? value "FR") - [:flex value-int] + [:flex (d/nilv value-int 1)] (some? value-int) - [:fixed value-int] + [:fixed (d/nilv value-int 100)] - (or (= value "AUTO") (= "" value)) - [:auto nil])] + :else + [:auto nil]) + track-data (when (some? track-type) {:type track-type :value value})] + + (dom/set-value! (mf/ref-val track-input-ref) (format-size track-data)) (if (some? track-type) - (do (st/emit! (dwsl/change-layout-track [(:id shape)] type index {:type track-type :value value})) - (dom/set-data! target "default-value" (format-size {:type track-type :value value}))) + (do (st/emit! (dwsl/change-layout-track [(:id shape)] type index track-data)) + (dom/set-data! target "default-value" (format-size track-data))) (obj/set! target "value" (dom/get-attribute target "data-default-value")))))) handle-keydown-track-input diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 152c70665..b1a01bb1a 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3508,6 +3508,9 @@ msgstr "Editing grid" msgid "workspace.layout_grid.editor.top-bar.locate" msgstr "Locate" +msgid "workspace.layout_grid.editor.top-bar.locate.tooltip" +msgstr "Locate grid layout" + msgid "workspace.layout_grid.editor.top-bar.done" msgstr "Done" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index d86462b92..5ce93d9b9 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3570,6 +3570,9 @@ msgstr "Editando rejilla" msgid "workspace.layout_grid.editor.top-bar.locate" msgstr "Mostrar" +msgid "workspace.layout_grid.editor.top-bar.locate.tooltip" +msgstr "Mostrar grid layout" + msgid "workspace.layout_grid.editor.top-bar.done" msgstr "Hecho"