diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc index 62ce48aa9a..225aa88558 100644 --- a/common/src/app/common/flags.cljc +++ b/common/src/app/common/flags.cljc @@ -145,6 +145,8 @@ ;; Show WASM renderer info label (hidden by default). :render-wasm-info :render-switch + ;; Enables the UI scale setting (PoC: 1x / 1.25x) + :ui-scale :hide-release-modal :subscriptions :subscriptions-old diff --git a/frontend/resources/styles/common/base.scss b/frontend/resources/styles/common/base.scss index 41d79a0bf4..d4f1d47f36 100644 --- a/frontend/resources/styles/common/base.scss +++ b/frontend/resources/styles/common/base.scss @@ -18,6 +18,15 @@ $lh-115: 1.15; $lh-133: 1.33; $size-4: 1rem; +// UI scale: `--ui-scale` is driven from the user profile prop `:ui-scale` +// (see app.main.ui/app). Because DS tokens are `rem`-based, scaling the root +// font-size uniformly scales the whole UI. The viewport/rulers are excluded +// separately (they don't rely on this root font-size). +:root { + --ui-scale: 1; + font-size: calc(100% * var(--ui-scale)); +} + body { background-color: var(--color-background-primary); color: var(--color-foreground-primary); diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index d3216efd70..81e7b25db3 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -370,13 +370,21 @@ (mf/defc app [] - (let [route (mf/deref refs/route) - edata (mf/deref refs/exception) - profile (mf/deref refs/profile)] + (let [route (mf/deref refs/route) + edata (mf/deref refs/exception) + profile (mf/deref refs/profile) + ui-scale (if (contains? cf/flags :ui-scale) + (or (-> profile :props :ui-scale) 1.0) + 1.0)] ;; initialize themes (theme/use-initialize profile) + ;; Apply the UI scale by exposing it as the `--ui-scale` custom property + ;; on the root element, which drives the root font-size (see base.scss). + (mf/with-effect [ui-scale] + (dom/set-css-property! (.-documentElement js/document) "--ui-scale" (str ui-scale))) + (dom/prevent-browser-gesture-navigation!) [:& (mf/provider ctx/current-route) {:value route} diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs index aca2ef130c..1867e91472 100644 --- a/frontend/src/app/main/ui/settings/options.cljs +++ b/frontend/src/app/main/ui/settings/options.cljs @@ -15,6 +15,7 @@ [app.main.router :as rt] [app.main.store :as st] [app.main.ui.components.forms :as fm] + [app.main.ui.ds.controls.select :refer [select*]] [app.main.ui.ds.controls.switch :refer [switch*]] [app.main.ui.ds.foundations.assets.icon :refer [icon*]] [app.main.ui.ds.foundations.typography :as t] @@ -115,10 +116,32 @@ :on-change handle-render-change}]] [:> text* {:typography t/body-medium :class (stl/css :feedback)} [:a {:href "#" :on-click go-settings-feedback :class (stl/css :link)} (tr "dashboard.webgl-switch.feedback") [:> icon* {:icon-id "arrow-up-right" :size "s"}]]]])) +(mf/defc ui-scale-settings* + [{:keys [ui-scale]}] + (let [selected (if (= ui-scale 1.15) "1.15" "1") + handle-scale-change + (mf/use-fn + (fn [value] + (let [scale (if (= value "1.15") 1.15 1.0)] + (st/emit! (ev/event {::ev/name "change-ui-scale" + ::ev/origin "settings" + :scale scale}) + (du/update-profile-props {:ui-scale scale}) + (ntf/success (tr "dashboard.ui-scale.updated"))))))] + [:section {:class (stl/css :ui-scale-container)} + [:header {:class (stl/css :ui-scale-header)} + [:> heading* {:class (stl/css :title) :level 2 :typography t/title-large} (tr "dashboard.ui-scale.title")]] + [:> text* {:class (stl/css :description) :typography t/body-medium} (tr "dashboard.ui-scale.description")] + [:> select* {:default-selected selected + :options [{:id "1" :label (tr "dashboard.ui-scale.1x")} + {:id "1.15" :label (tr "dashboard.ui-scale.115x")}] + :on-change handle-scale-change}]])) + (mf/defc options-page* [] - (let [profile (mf/deref refs/profile) - renderer (or (-> profile :props :renderer) :svg)] + (let [profile (mf/deref refs/profile) + renderer (or (-> profile :props :renderer) :svg) + ui-scale (or (-> profile :props :ui-scale) 1.0)] (mf/use-effect #(dom/set-html-title (tr "title.settings.options"))) @@ -128,4 +151,6 @@ [:h2 (tr "labels.settings")] [:> options-form*]] (when (contains? cf/flags :render-switch) - [:> webgl-settings* {:renderer renderer}])]])) + [:> webgl-settings* {:renderer renderer}]) + (when (contains? cf/flags :ui-scale) + [:> ui-scale-settings* {:ui-scale ui-scale}])]])) diff --git a/frontend/src/app/main/ui/settings/options.scss b/frontend/src/app/main/ui/settings/options.scss index d5755e6062..f23c72a7ad 100644 --- a/frontend/src/app/main/ui/settings/options.scss +++ b/frontend/src/app/main/ui/settings/options.scss @@ -23,7 +23,7 @@ /* Copied from profile.scss .form-container, but without included nested rules, since we want custom styles for it */ -.webgl-container { +.webgl-container, .ui-scale-container { display: grid; grid-auto-rows: auto; gap: var(--sp-s); @@ -34,13 +34,17 @@ color: var(--color-foreground-primary); } -.webgl-header { +.webgl-header, .ui-scale-header { display: flex; flex-direction: row; align-items: baseline; gap: var(--sp-m); } +.ui-scale-container { + padding-block-end: var(--sp-xxxl); +} + .description { color: var(--color-foreground-secondary); } diff --git a/frontend/translations/en.po b/frontend/translations/en.po index ea0d60d7ec..2af557e472 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1328,6 +1328,26 @@ msgstr "No limits on creativity" msgid "dashboard.upgrade-plan.penpot-free" msgstr "Penpot Free" +#: src/app/main/ui/settings/options.cljs:135 +msgid "dashboard.ui-scale.115x" +msgstr "1.15x (Medium)" + +#: src/app/main/ui/settings/options.cljs:135 +msgid "dashboard.ui-scale.1x" +msgstr "1x (Default)" + +#: src/app/main/ui/settings/options.cljs:133 +msgid "dashboard.ui-scale.description" +msgstr "Scale the Penpot interface. This does not affect the design canvas." + +#: src/app/main/ui/settings/options.cljs:132 +msgid "dashboard.ui-scale.title" +msgstr "UI scale" + +#: src/app/main/ui/settings/options.cljs:129 +msgid "dashboard.ui-scale.updated" +msgstr "UI scale was updated" + #, unused msgid "dashboard.user-no-longer-belong-org" msgstr "You are no longer a member of the organization %s"