Add base font fallback (#6468)

*  Add base font fallback

* ♻️ Add asserts to change-builder

* 🐛 Change fn name
This commit is contained in:
Eva Marco 2025-05-20 17:27:04 +02:00 committed by GitHub
parent 965b22718f
commit 8f7c63d6e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 394 additions and 58 deletions

View file

@ -616,6 +616,7 @@
(watch [it state _]
(let [page (dsh/lookup-page state id)
changes (-> (pcb/empty-changes it)
(pcb/with-page page)
(pcb/mod-page page {:name name}))]
(rx/of (dch/commit-changes changes))))))

View file

@ -0,0 +1,25 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.data.workspace.tokens.typography
(:require
[app.common.data.macros :as dm]
[app.common.files.changes-builder :as pcb]
[app.main.data.changes :as dch]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
(defn set-base-font-size [base-font-size]
(ptk/reify ::set-base-font-size
ptk/WatchEvent
(watch [it state _]
(let [file-id (dm/get-in state [:workspace :current-file-id])
file-data (dm/get-in state [:files file-id :data])
changes (-> (pcb/empty-changes it)
(pcb/with-file-data file-data)
(pcb/set-base-font-size base-font-size))]
(rx/of
(dch/commit-changes changes))))))

View file

@ -16,6 +16,7 @@
[:map
[:class {:optional true} :string]
[:icon-class {:optional true} :string]
[:tooltip-id {:optional true} :string]
[:icon
[:and :string [:fn #(contains? icon-list %)]]]
[:aria-label :string]
@ -25,7 +26,7 @@
(mf/defc icon-button*
{::mf/props :obj
::mf/schema schema:icon-button}
[{:keys [class icon icon-class variant aria-label children] :rest props}]
[{:keys [class icon icon-class variant aria-label children tooltip-id] :rest props}]
(let [variant (or variant "primary")
class (dm/str class " " (stl/css-case :icon-button true
:icon-button-primary (= variant "primary")
@ -33,5 +34,10 @@
:icon-button-ghost (= variant "ghost")
:icon-button-action (= variant "action")
:icon-button-destructive (= variant "destructive")))
props (mf/spread-props props {:class class :title aria-label})]
[:> "button" props [:> icon* {:icon-id icon :aria-label aria-label :class icon-class}] children]))
props (if (some? tooltip-id)
(mf/spread-props props {:class class
:aria-describedby tooltip-id})
(mf/spread-props props {:class class
:aria-label aria-label
:title aria-label}))]
[:> "button" props [:> icon* {:icon-id icon :aria-hidden true :class icon-class}] children]))

View file

@ -231,6 +231,7 @@
(def ^:icon-id row-reverse "row-reverse")
(def ^:icon-id search "search")
(def ^:icon-id separate-nodes "separate-nodes")
(def ^:icon-id settings "settings")
(def ^:icon-id shown "shown")
(def ^:icon-id size-horizontal "size-horizontal")
(def ^:icon-id size-vertical "size-vertical")

View file

@ -208,6 +208,7 @@
(def ^:icon row-reverse (icon-xref :row-reverse))
(def ^:icon search (icon-xref :search))
(def ^:icon separate-nodes (icon-xref :separate-nodes))
(def ^:icon settings (icon-xref :settings))
(def ^:icon share (icon-xref :share))
(def ^:icon shown (icon-xref :shown))
(def ^:icon size-horizontal (icon-xref :size-horizontal))

View file

@ -34,6 +34,7 @@
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
[app.main.ui.workspace.tokens.modals]
[app.main.ui.workspace.tokens.modals.import]
[app.main.ui.workspace.tokens.modals.settings]
[app.main.ui.workspace.tokens.modals.themes]
[app.main.ui.workspace.viewport :refer [viewport*]]
[app.util.debug :as dbg]

View file

@ -277,22 +277,21 @@
[:> icon-button* {:variant "ghost"
:aria-label (tr "labels.close")
:on-click on-close-history
:icon "close"}])]
:icon "close"}])
tabs (mf/object
[{:label (tr "workspace.versions.tab.history")
:id "history"
:content versions-tab}
{:label (tr "workspace.versions.tab.actions")
:id "actions"
:content history-tab}])]
(let [tabs (mf/object
[{:label (tr "workspace.versions.tab.history")
:id "history"
:content versions-tab}
{:label (tr "workspace.versions.tab.actions")
:id "actions"
:content history-tab}])]
[:> tab-switcher*
{:tabs tabs
:default-selected "history"
:class (stl/css :left-sidebar-tabs)
:action-button-position "end"
:action-button button}]))
[:> tab-switcher*
{:tabs tabs
:default-selected "history"
:class (stl/css :left-sidebar-tabs)
:action-button-position "end"
:action-button button}])
:else
[:> options-toolbox* props])]]]))

View file

@ -0,0 +1,117 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.tokens.modals.settings
(:require-macros [app.main.style :as stl])
(:require
[app.common.types.file :as ctf]
[app.main.data.modal :as modal]
[app.main.data.workspace.tokens.typography :as wtt]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.input :refer [input*]]
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
[app.main.ui.ds.foundations.typography :as t]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.keyboard :as k]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
(mf/defc token-settings-modal*
{::mf/wrap-props false}
[]
(let [file-data (deref refs/workspace-data)
base-font-size* (mf/use-state #(ctf/get-base-font-size file-data))
base-font-size (deref base-font-size*)
valid?* (mf/use-state true)
is-valid (deref valid?*)
is-valid?
(fn [value]
(boolean (re-matches #"^\d+(\.\d+)?(px)?$" value)))
hint-message (if is-valid
(str "1rem = " base-font-size)
(tr "workspace.token.base-font-size.error"))
on-change-base-font-size
(mf/use-fn
(mf/deps base-font-size*)
(fn [e]
(let [value (dom/get-target-val e)]
(reset! valid?* (is-valid? value))
(when (is-valid? value)
(let [unit-value (if (str/ends-with? value "px")
value
(str value "px"))]
(reset! base-font-size* unit-value))))))
on-set-font
(mf/use-fn
(mf/deps base-font-size)
(fn []
(st/emit! (wtt/set-base-font-size base-font-size)
(modal/hide))))
handle-key-down
(mf/use-fn
(mf/deps base-font-size is-valid)
(fn [e]
(when (and (k/enter? e) is-valid)
(on-set-font))))]
[:div {:class (stl/css :setting-modal-overlay)
:data-testid "token-font-settings-modal"}
[:div {:class (stl/css :setting-modal)}
[:> icon-button* {:on-click modal/hide!
:class (stl/css :close-btn)
:icon i/close
:variant "action"
:aria-label (tr "labels.close")}]
[:div {:class (stl/css :settings-modal-layout)}
[:> heading* {:level 2
:typography t/headline-medium
:class (stl/css :settings-modal-title)}
(tr "workspace.token.settings")]
[:div {:class (stl/css :settings-modal-content)}
[:div {:class (stl/css :settings-modal-subtitle-wrapper)}
[:> text* {:as "span" :typography t/body-large :class (stl/css :settings-subtitle)}
(tr "workspace.token.base-font-size")]
[:> icon* {:icon-id "info"}]]
[:> text* {:as "span" :typography t/body-medium :class (stl/css :settings-modal-description)}
(tr "workspace.token.setting-description")]
[:> input* {:type "text"
:placeholder "16"
:default-value base-font-size
:hint-message hint-message
:hint-type (if is-valid "hint" "error")
:on-key-down handle-key-down
:on-change on-change-base-font-size}]
[:div {:class (stl/css :settings-modal-actions)}
[:> button* {:on-click modal/hide!
:variant "secondary"}
(tr "labels.cancel")]
[:> button* {:on-click on-set-font
:disabled (not is-valid)
:variant "primary"}
(tr "labels.save")]]]]]]))
(mf/defc base-font-size-modal
{::mf/register modal/components
::mf/register-as :tokens/base-font-size}
[]
[:> token-settings-modal*])

View file

@ -0,0 +1,55 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@use "../../../ds/spacing.scss" as *;
@import "refactor/common-refactor.scss";
.setting-modal-overlay {
@extend .modal-overlay-base;
}
.setting-modal {
@extend .modal-container-base;
}
.close-btn {
@extend .modal-close-btn-base;
}
.settings-modal-layout {
display: grid;
grid-template-rows: auto 1fr;
gap: var(--sp-xxl);
}
.settings-modal-title {
color: var(--color-foreground-primary);
}
.settings-modal-content {
display: grid;
grid-template-rows: auto 1fr auto;
gap: var(--sp-m);
}
.settings-modal-subtitle-wrapper {
color: var(--color-foreground-primary);
display: flex;
align-items: center;
gap: var(--sp-s);
}
.settings-modal-description,
.settings-modal-resume {
color: var(--color-foreground-secondary);
}
.settings-modal-actions {
display: flex;
justify-content: flex-end;
gap: var(--sp-s);
}

View file

@ -25,6 +25,7 @@
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.main.ui.ds.tooltip.tooltip :refer [tooltip*]]
[app.main.ui.hooks :as h]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
@ -384,10 +385,17 @@
(json/encode :key-fn identity))]
(->> (wapi/create-blob (or tokens-json "{}") "application/json")
(dom/trigger-download "tokens.json")))))
on-modal-show
(mf/use-fn
(fn []
(modal/show! :tokens/import {})))]
(modal/show! :tokens/import {})))
open-settings-modal
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(modal/show! :tokens/base-font-size {})))]
[:div {:class (stl/css :import-export-button-wrapper)}
[:> button* {:on-click open-menu
@ -404,7 +412,15 @@
[:div (tr "labels.import")]]])
[:> dropdown-menu-item* {:class (stl/css :import-export-menu-item)
:on-click on-export}
(tr "labels.export")]]]))
(tr "labels.export")]]
[:> tooltip* {:tooltip-content "Tokens settings"
:id "button-setting"}
[:> icon-button* {:variant "secondary"
:icon "settings"
:tooltip-id "button-setting"
:aria-label "Settings"
:on-click open-settings-modal}]]]))
(mf/defc tokens-sidebar-tab*
{::mf/wrap [mf/memo]}

View file

@ -5,6 +5,7 @@
// Copyright (c) KALEIDOS INC
@use "../../ds/typography.scss" as *;
@use "../../ds/spacing.scss" as *;
@import "refactor/common-refactor.scss";
.sidebar-wrapper {
@ -28,20 +29,20 @@
.tokens-section-wrapper {
height: 100%;
padding-left: $s-12;
padding-left: var(--sp-m);
overflow-y: auto;
scrollbar-gutter: stable;
}
.sets-sidebar {
position: relative;
padding-block-end: $s-16;
padding-block-end: var(--sp-l);
}
.themes-header,
.sets-header-container {
@include use-typography("headline-small");
padding: $s-8;
padding: var(--sp-s);
color: var(--title-foreground-color);
word-break: break-word;
}
@ -50,8 +51,8 @@
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: $s-4;
margin-block-start: $s-8;
gap: var(--sp-xs);
margin-block-start: var(--sp-s);
}
.sets-header {
@ -64,7 +65,7 @@
color: var(--color-foreground-secondary);
display: flex;
align-items: center;
gap: $s-4;
gap: var(--sp-xs);
}
.sets-header-status-text {
@ -72,11 +73,11 @@
}
.themes-wrapper {
padding: $s-12 0 0 $s-12;
padding: var(--sp-m) 0 0 var(--sp-m);
}
.empty-theme-wrapper {
padding: $s-12;
padding: var(--sp-m);
color: var(--color-foreground-secondary);
}
@ -84,8 +85,8 @@
display: flex;
align-items: center;
justify-content: space-between;
margin-left: $s-12;
padding-top: $s-12;
margin-left: var(--sp-m);
padding-top: var(--sp-m);
color: var(--layer-row-foreground-color);
}
@ -95,20 +96,20 @@
.token-pills-wrapper {
display: flex;
gap: $s-4;
gap: var(--sp-xs);
flex-wrap: wrap;
}
.section-text-icon {
font-size: $fs-12;
width: $s-16;
height: $s-16;
width: var(--sp-l);
height: var(--sp-l);
display: flex;
place-content: center;
}
.section-icon {
margin-right: $s-4;
margin-right: var(--sp-xs);
// Align better with the label
translate: 0px -1px;
}
@ -116,10 +117,11 @@
.import-export-button-wrapper {
position: relative;
display: flex;
gap: var(--sp-s);
flex-direction: row;
align-items: end;
justify-content: end;
padding: $s-8;
padding: var(--sp-s);
background-color: var(--color-background-primary);
box-shadow: var(--el-shadow-dark);
}
@ -129,9 +131,9 @@
display: flex;
align-items: center;
justify-content: end;
padding: $s-6 $s-8;
padding: $s-6 var(--sp-s);
text-transform: uppercase;
gap: $s-8;
gap: var(--sp-s);
background-color: var(--color-background-primary);
box-shadow: var(--el-shadow-dark);