✨ Add Japanese layout controls and opt-in settings
Enable Japanese layout per file through undoable changes, or for all files through a saved profile preference. Show the controls when the WASM renderer and either setting are active. Add writing mode, orientation, ruby, emphasis, warichu and line fitting controls with icons and English and Japanese translations. Cover the file change, profile preference and control behavior.
@ -62,6 +62,7 @@
|
||||
[:map {:title "ProfileProps" :closed true}
|
||||
[:plugins {:optional true} ctp/schema:plugin-registry]
|
||||
[:renderer {:optional true} [::sm/one-of #{:svg :wasm}]]
|
||||
[:japanese-layout-all-files {:optional true} ::sm/boolean]
|
||||
[:mcp-enabled {:optional true} ::sm/boolean]
|
||||
[:newsletter-updates {:optional true} ::sm/boolean]
|
||||
[:newsletter-news {:optional true} ::sm/boolean]
|
||||
|
||||
@ -164,6 +164,21 @@
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (nil? (:photo-id (:result out))))))))
|
||||
|
||||
(t/deftest update-profile-japanese-layout-setting
|
||||
(let [profile (th/create-profile* 1)
|
||||
params {::th/type :update-profile-props
|
||||
::rpc/profile-id (:id profile)
|
||||
:props {:japanese-layout-all-files true}}
|
||||
out (th/command! params)]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (true? (get-in out [:result :japanese-layout-all-files])))
|
||||
|
||||
(let [params {::th/type :get-profile
|
||||
::rpc/profile-id (:id profile)}
|
||||
out (th/command! params)]
|
||||
(t/is (nil? (:error out)))
|
||||
(t/is (true? (get-in out [:result :props :japanese-layout-all-files]))))))
|
||||
|
||||
(t/deftest profile-deletion-1
|
||||
(let [prof (th/create-profile* 1)
|
||||
file (th/create-file* 1 {:profile-id (:id prof)
|
||||
|
||||
@ -438,7 +438,12 @@
|
||||
[:map {:title "SetTokensSource"}
|
||||
[:type [:= :set-tokens-source]]
|
||||
[:file-id ::sm/uuid]
|
||||
[:library-id [:maybe ::sm/uuid]]]]])
|
||||
[:library-id [:maybe ::sm/uuid]]]]
|
||||
|
||||
[:set-japanese-layout
|
||||
[:map {:title "SetJapaneseLayout"}
|
||||
[:type [:= :set-japanese-layout]]
|
||||
[:enabled ::sm/boolean]]]])
|
||||
|
||||
(def schema:changes
|
||||
[:sequential {:gen/max 5 :gen/min 1} schema:change])
|
||||
@ -1092,6 +1097,10 @@
|
||||
[data {:keys [library-id]}]
|
||||
(cfo/set-tokens-source data library-id))
|
||||
|
||||
(defmethod process-change :set-japanese-layout
|
||||
[data {:keys [enabled]}]
|
||||
(ctf/set-japanese-layout-enabled data enabled))
|
||||
|
||||
;; === Operations
|
||||
|
||||
(def decode-shape-attrs
|
||||
|
||||
@ -1150,6 +1150,18 @@
|
||||
:library-id prev-val})
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn set-japanese-layout
|
||||
[changes enabled?]
|
||||
(assert-file-data! changes)
|
||||
(let [file-data (::file-data (meta changes))
|
||||
previous-enabled (ctf/japanese-layout-enabled? file-data)]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-japanese-layout
|
||||
:enabled enabled?})
|
||||
(update :undo-changes conj {:type :set-japanese-layout
|
||||
:enabled previous-enabled})
|
||||
(apply-changes-local))))
|
||||
|
||||
;; Misc changes
|
||||
|
||||
(defn reorder-children
|
||||
|
||||
@ -77,7 +77,8 @@
|
||||
(def schema:options
|
||||
[:map {:title "FileOptions"}
|
||||
[:components-v2 {:optional true} ::sm/boolean]
|
||||
[:base-font-size {:optional true} :string]])
|
||||
[:base-font-size {:optional true} :string]
|
||||
[:japanese-layout {:optional true} ::sm/boolean]])
|
||||
|
||||
(def schema:data
|
||||
[:map {:title "FileData"}
|
||||
@ -1255,6 +1256,19 @@
|
||||
(assoc-in file-data [:options :base-font-size] base-font-size))
|
||||
|
||||
|
||||
;; Japanese text layout
|
||||
|
||||
(defn japanese-layout-enabled?
|
||||
[file-data]
|
||||
(true? (get-in file-data [:options :japanese-layout])))
|
||||
|
||||
(defn set-japanese-layout-enabled
|
||||
[file-data enabled?]
|
||||
(if enabled?
|
||||
(assoc-in file-data [:options :japanese-layout] true)
|
||||
(d/update-in-when file-data [:options] dissoc :japanese-layout)))
|
||||
|
||||
|
||||
;; Ref Chains
|
||||
(defn get-ref-chain-until-target-ref
|
||||
"Returns a vector with the shape ref chain until target-ref, including itself"
|
||||
|
||||
@ -251,6 +251,26 @@
|
||||
"The parent must use the updated bounds of both children")
|
||||
(assert-idempotent data changes))))))
|
||||
|
||||
(t/deftest set-japanese-layout-file-option
|
||||
(let [file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
data (make-file-data file-id page-id)
|
||||
enabled (ch/process-changes data [{:type :set-japanese-layout
|
||||
:enabled true}])
|
||||
disabled (ch/process-changes enabled [{:type :set-japanese-layout
|
||||
:enabled false}])
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-file-data data)
|
||||
(pcb/set-japanese-layout true))]
|
||||
(t/is (false? (ctf/japanese-layout-enabled? data)))
|
||||
(t/is (true? (ctf/japanese-layout-enabled? enabled)))
|
||||
(t/is (false? (ctf/japanese-layout-enabled? disabled)))
|
||||
(t/is (not (contains? (:options disabled) :japanese-layout)))
|
||||
(t/is (= [{:type :set-japanese-layout :enabled true}]
|
||||
(:redo-changes changes)))
|
||||
(t/is (= '({:type :set-japanese-layout :enabled false})
|
||||
(:undo-changes changes)))))
|
||||
|
||||
(t/deftest add-obj
|
||||
(let [file-id (uuid/custom 2 2)
|
||||
page-id (uuid/custom 1 1)
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2.5 3.5v-2h11v2M2.5 12.5v2h11v-2M5 6.25h1.5v3.5M9 6.25h1.5v3.5H9v-1.75h1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 205 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 4V2h12v2M2 12v2h12v-2M3.5 6H5v4M7.25 6h1.5v4h-1.5V8h1.5M11 6h1.5v4H11m0-2h1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 210 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M5 2.5h6M5 5.5h6M5 8.5h6M5 11.5h6M8 1v13.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 172 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M5 1.5h6v5H5zM4 9.5l7 2.5-7 2.5M8 10.9v2.2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 174 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M5 1.5h6v5H5zM5.5 14l2.5-6 2.5 6M6.5 11.5h3"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 175 B |
3
frontend/resources/images/icons/warichu-none.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M5 2.5h6v4H5zM5 9.5h6v4H5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 156 B |
3
frontend/resources/images/icons/warichu.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M2 2v12M14 2v12M4.5 3.5h2v3h-2zM9.5 3.5h2v3h-2zM4.5 9.5h2v3h-2zM9.5 9.5h2v3h-2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 209 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M1.5 2.5h8m-8 3h8m-8 3h6M13 2v11m-2-2 2 2 2-2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 177 B |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M13.5 1.5v8m-3-8v8m-3-8v6M14 13H3m2-2-2 2 2 2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 177 B |
@ -679,6 +679,17 @@
|
||||
(dm/export layout/toggle-layout-flag)
|
||||
(dm/export layout/remove-layout-flag)
|
||||
|
||||
(defn set-japanese-layout
|
||||
[enabled?]
|
||||
(ptk/reify ::set-japanese-layout
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [file-data (dsh/lookup-file-data state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-file-data file-data)
|
||||
(pcb/set-japanese-layout enabled?))]
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
|
||||
;; --- Profile
|
||||
|
||||
(defn update-nudge
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cph]
|
||||
[app.common.files.tokens :as cfo]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.shape-tree :as ctt]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
@ -289,6 +290,14 @@
|
||||
"Currently working file data on workspace"
|
||||
(l/derived dsh/lookup-file-data st/state))
|
||||
|
||||
(def japanese-layout-config
|
||||
"Japanese layout switches: `:file?` for the workspace file and
|
||||
`:all-files?` from the profile."
|
||||
(l/derived (fn [state]
|
||||
{:file? (ctf/japanese-layout-enabled? (dsh/lookup-file-data state))
|
||||
:all-files? (true? (dm/get-in state [:profile :props :japanese-layout-all-files]))})
|
||||
st/state =))
|
||||
|
||||
(def workspace-file-colors
|
||||
(l/derived (fn [{:keys [id] :as data}]
|
||||
(some-> (:colors data) (update-vals #(assoc % :file-id id))))
|
||||
|
||||
@ -276,6 +276,9 @@
|
||||
(def ^:icon-id text-auto-height "text-auto-height")
|
||||
(def ^:icon-id text-auto-width "text-auto-width")
|
||||
(def ^:icon-id text-bottom "text-bottom")
|
||||
(def ^:icon-id text-combine-upright-all "text-combine-upright-all")
|
||||
(def ^:icon-id text-combine-upright-digits "text-combine-upright-digits")
|
||||
(def ^:icon-id text-combine-upright-none "text-combine-upright-none")
|
||||
(def ^:icon-id text-fixed "text-fixed")
|
||||
(def ^:icon-id text-font-family "text-font-family")
|
||||
(def ^:icon-id text-font-size "text-font-size")
|
||||
@ -287,6 +290,8 @@
|
||||
(def ^:icon-id text-ltr "text-ltr")
|
||||
(def ^:icon-id text-middle "text-middle")
|
||||
(def ^:icon-id text-mixed "text-mixed")
|
||||
(def ^:icon-id text-orientation-mixed "text-orientation-mixed")
|
||||
(def ^:icon-id text-orientation-upright "text-orientation-upright")
|
||||
(def ^:icon-id text-palette "text-palette")
|
||||
(def ^:icon-id text-paragraph "text-paragraph")
|
||||
(def ^:icon-id text-rtl "text-rtl")
|
||||
@ -309,7 +314,11 @@
|
||||
(def ^:icon-id vertical-align-items-start "vertical-align-items-start")
|
||||
(def ^:icon-id view-as-icons "view-as-icons")
|
||||
(def ^:icon-id view-as-list "view-as-list")
|
||||
(def ^:icon-id warichu "warichu")
|
||||
(def ^:icon-id warichu-none "warichu-none")
|
||||
(def ^:icon-id wrap "wrap")
|
||||
(def ^:icon-id writing-mode-horizontal "writing-mode-horizontal")
|
||||
(def ^:icon-id writing-mode-vertical "writing-mode-vertical")
|
||||
|
||||
(def icon-list
|
||||
"A collection of all icons"
|
||||
|
||||
@ -247,6 +247,9 @@
|
||||
(def ^:icon text-auto-height (icon-xref :text-auto-height))
|
||||
(def ^:icon text-auto-width (icon-xref :text-auto-width))
|
||||
(def ^:icon text-bottom (icon-xref :text-bottom))
|
||||
(def ^:icon text-combine-upright-all (icon-xref :text-combine-upright-all))
|
||||
(def ^:icon text-combine-upright-digits (icon-xref :text-combine-upright-digits))
|
||||
(def ^:icon text-combine-upright-none (icon-xref :text-combine-upright-none))
|
||||
(def ^:icon text-fixed (icon-xref :text-fixed))
|
||||
(def ^:icon text-font-family (icon-xref :text-font-family))
|
||||
(def ^:icon text-font-size (icon-xref :text-font-size))
|
||||
@ -258,6 +261,8 @@
|
||||
(def ^:icon text-ltr (icon-xref :text-ltr))
|
||||
(def ^:icon text-middle (icon-xref :text-middle))
|
||||
(def ^:icon text-mixed (icon-xref :text-mixed))
|
||||
(def ^:icon text-orientation-mixed (icon-xref :text-orientation-mixed))
|
||||
(def ^:icon text-orientation-upright (icon-xref :text-orientation-upright))
|
||||
(def ^:icon text-palette (icon-xref :text-palette))
|
||||
(def ^:icon text-paragraph (icon-xref :text-paragraph))
|
||||
(def ^:icon text-rtl (icon-xref :text-rtl))
|
||||
@ -284,7 +289,11 @@
|
||||
(def ^:icon vertical-align-items-start (icon-xref :vertical-align-items-start))
|
||||
(def ^:icon view-as-icons (icon-xref :view-as-icons))
|
||||
(def ^:icon view-as-list (icon-xref :view-as-list))
|
||||
(def ^:icon warichu (icon-xref :warichu))
|
||||
(def ^:icon warichu-none (icon-xref :warichu-none))
|
||||
(def ^:icon wrap (icon-xref :wrap))
|
||||
(def ^:icon writing-mode-horizontal (icon-xref :writing-mode-horizontal))
|
||||
(def ^:icon writing-mode-vertical (icon-xref :writing-mode-vertical))
|
||||
|
||||
(def default
|
||||
"A collection of all icons"
|
||||
|
||||
@ -115,10 +115,35 @@
|
||||
: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 japanese-layout-settings*
|
||||
[{:keys [enabled]}]
|
||||
(let [handle-change
|
||||
(mf/use-fn
|
||||
(fn [enabled?]
|
||||
(st/emit! (ev/event {::ev/name (if enabled?
|
||||
"enable-japanese-layout-all-files"
|
||||
"disable-japanese-layout-all-files")
|
||||
::ev/origin "settings"})
|
||||
(du/update-profile-props
|
||||
{:japanese-layout-all-files enabled?})
|
||||
(ntf/success (tr "notifications.profile-saved")))))]
|
||||
[:section {:class (stl/css :japanese-layout-container)}
|
||||
[:> heading* {:class (stl/css :title)
|
||||
:level 2
|
||||
:typography t/title-large}
|
||||
(tr "dashboard.japanese-layout.title")]
|
||||
[:> text* {:class (stl/css :description) :typography t/body-medium}
|
||||
(tr "dashboard.japanese-layout.description")]
|
||||
[:form {:class (stl/css :japanese-layout-form)}
|
||||
[:> switch* {:label (tr "dashboard.japanese-layout.enable-all-files")
|
||||
:default-checked enabled
|
||||
:on-change handle-change}]]]))
|
||||
|
||||
(mf/defc options-page*
|
||||
[]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
renderer (or (-> profile :props :renderer) :svg)]
|
||||
renderer (or (-> profile :props :renderer) :svg)
|
||||
japanese-layout-enabled (:all-files? (mf/deref refs/japanese-layout-config))]
|
||||
(mf/use-effect
|
||||
#(dom/set-html-title (tr "title.settings.options")))
|
||||
|
||||
@ -132,5 +157,6 @@
|
||||
:id "options-section-title"}
|
||||
(tr "labels.settings")]
|
||||
[:> options-form*]]
|
||||
[:> japanese-layout-settings* {:enabled japanese-layout-enabled}]
|
||||
(when (contains? cf/flags :render-switch)
|
||||
[:> webgl-settings* {:renderer renderer}])]]))
|
||||
|
||||
@ -21,9 +21,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Copied from profile.scss .form-container, but without included nested
|
||||
rules, since we want custom styles for it */
|
||||
.webgl-container {
|
||||
/* Settings sections with standalone controls. */
|
||||
.webgl-container,
|
||||
.japanese-layout-container {
|
||||
display: grid;
|
||||
grid-auto-rows: auto;
|
||||
gap: var(--sp-s);
|
||||
@ -34,6 +34,10 @@
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.japanese-layout-form {
|
||||
padding-block-start: var(--sp-xs);
|
||||
}
|
||||
|
||||
.webgl-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.text.writing-mode :as wm]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
@ -232,8 +233,10 @@
|
||||
(mf/defc preferences-menu*
|
||||
{::mf/private true
|
||||
::mf/wrap [mf/memo]}
|
||||
[{:keys [layout profile toggle-flag on-close toggle-theme toggle-render]}]
|
||||
(let [renderer (or (-> profile :props :renderer) :svg)
|
||||
[{:keys [japanese-layout-enabled japanese-layout-all-files layout profile toggle-flag
|
||||
on-close toggle-theme toggle-render toggle-japanese-layout]}]
|
||||
(let [renderer (or (-> profile :props :renderer) :svg)
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
|
||||
show-nudge-options
|
||||
(mf/use-fn
|
||||
@ -316,6 +319,21 @@
|
||||
:id "file-menu-nudge"}
|
||||
[:span {:class (stl/css :item-name)} (tr "modals.nudge-title")]]
|
||||
|
||||
(when (and (not read-only?)
|
||||
(not japanese-layout-all-files)
|
||||
(wm/vertical-layout-active?))
|
||||
[:> dropdown-menu-item* {:on-click toggle-japanese-layout
|
||||
:class (stl/css :base-menu-item :submenu-item)
|
||||
:on-key-down (fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(toggle-japanese-layout event)))
|
||||
:data-testid "japanese-layout"
|
||||
:id "file-menu-japanese-layout"}
|
||||
[:span {:class (stl/css :item-name)}
|
||||
(if japanese-layout-enabled
|
||||
(tr "workspace.header.menu.disable-japanese-layout")
|
||||
(tr "workspace.header.menu.enable-japanese-layout"))]])
|
||||
|
||||
[:> dropdown-menu-item* {:on-click toggle-theme
|
||||
:class (stl/css :base-menu-item :submenu-item)
|
||||
:on-key-down (fn [event]
|
||||
@ -885,6 +903,8 @@
|
||||
(mf/defc menu*
|
||||
[{:keys [layout file]}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
japanese-layout (mf/deref refs/japanese-layout-config)
|
||||
japanese-layout-enabled (:file? japanese-layout)
|
||||
|
||||
show-menu* (mf/use-state false)
|
||||
show-menu? (deref show-menu*)
|
||||
@ -946,6 +966,15 @@
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (du/toggle-theme))))
|
||||
|
||||
toggle-japanese-layout
|
||||
(mf/use-fn
|
||||
(mf/deps japanese-layout-enabled)
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dw/set-japanese-layout (not japanese-layout-enabled)))
|
||||
(reset! show-menu* false)
|
||||
(reset! selected-sub-menu* nil)))
|
||||
|
||||
toggle-render
|
||||
(mf/use-fn
|
||||
(mf/deps profile)
|
||||
@ -1145,10 +1174,13 @@
|
||||
:preferences
|
||||
[:> preferences-menu* {:layout layout
|
||||
:profile profile
|
||||
:japanese-layout-enabled japanese-layout-enabled
|
||||
:japanese-layout-all-files (:all-files? japanese-layout)
|
||||
:toggle-flag toggle-flag
|
||||
:toggle-theme toggle-theme
|
||||
:toggle-render toggle-render
|
||||
:show-shortcuts show-shortcuts
|
||||
:toggle-japanese-layout toggle-japanese-layout
|
||||
:on-close close-sub-menu}]
|
||||
|
||||
:plugins
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
(ns app.main.ui.workspace.sidebar.options.common
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.store :as st]
|
||||
[app.util.dom :as dom]
|
||||
@ -26,6 +27,20 @@
|
||||
:ref ref}
|
||||
children])))
|
||||
|
||||
(defn radio-selected
|
||||
"Value to select in a radio group for an attribute value: its name, or
|
||||
`default` when unset. Mixed (`:multiple`) values select nothing."
|
||||
([value]
|
||||
(radio-selected value ""))
|
||||
([value default]
|
||||
(cond
|
||||
(= value :multiple) ""
|
||||
(or (nil? value)
|
||||
(and (string? value) (empty? value))) default
|
||||
(keyword? value) (d/name value)
|
||||
(string? value) value
|
||||
:else (str value))))
|
||||
|
||||
(defn emit-value-or-token [value emit-value-fn ids attrs]
|
||||
(if (or (string? value)
|
||||
(number? value)
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
[app.main.ui.ds.controls.shared.searchable-options-dropdown :refer [searchable-options-dropdown*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.workspace.sidebar.options.common :refer [radio-selected]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.text-japanese-layout :as tjl]
|
||||
[app.main.ui.workspace.sidebar.options.menus.token-typography-row :refer [token-typography-row*]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.typography :refer [text-options* typography-entry*]]
|
||||
[app.main.ui.workspace.tokens.management.forms.controls.utils :as csu]
|
||||
@ -52,10 +54,6 @@
|
||||
Evaluated once at module load time; cf/flags is immutable after startup."
|
||||
(contains? cf/flags :token-typography-row))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Sub-components
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(mf/defc text-align-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [options
|
||||
@ -85,14 +83,14 @@
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
|
||||
[:div {:class (stl/css :align-options)}
|
||||
[:> radio-buttons* {:selected (:text-align values)
|
||||
[:> radio-buttons* {:selected (radio-selected (:text-align values))
|
||||
:on-change handle-change
|
||||
:name "align-text-options"
|
||||
:options options}]]))
|
||||
|
||||
(mf/defc text-direction-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [direction (:text-direction values)
|
||||
(let [direction (radio-selected (:text-direction values))
|
||||
options
|
||||
(mf/with-memo []
|
||||
[{:value "ltr"
|
||||
@ -119,7 +117,7 @@
|
||||
|
||||
(mf/defc vertical-align*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [vertical-align (or (:vertical-align values) "top")
|
||||
(let [vertical-align (radio-selected (:vertical-align values) "top")
|
||||
options
|
||||
(mf/with-memo []
|
||||
[{:value "top"
|
||||
@ -151,6 +149,7 @@
|
||||
(mf/defc grow-options*
|
||||
[{:keys [ids values on-blur]}]
|
||||
(let [grow-type (:grow-type values)
|
||||
selected (radio-selected grow-type)
|
||||
editor-instance (mf/deref refs/workspace-editor)
|
||||
options
|
||||
(mf/with-memo []
|
||||
@ -191,14 +190,14 @@
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
|
||||
[:div {:class (stl/css :grow-options)}
|
||||
[:> radio-buttons* {:selected (d/name grow-type)
|
||||
[:> radio-buttons* {:selected selected
|
||||
:on-change handle-change
|
||||
:name "grow-text-options"
|
||||
:options options}]]))
|
||||
|
||||
(mf/defc text-decoration-options*
|
||||
[{:keys [values on-change on-blur token-applied]}]
|
||||
(let [text-decoration (some-> (:text-decoration values) d/name)
|
||||
(let [text-decoration (radio-selected (:text-decoration values))
|
||||
options
|
||||
(mf/with-memo [token-applied]
|
||||
[{:value "underline"
|
||||
@ -222,8 +221,8 @@
|
||||
|
||||
[:div {:class (stl/css :text-decoration-options)}
|
||||
[:> radio-buttons* {:selected (if (= text-decoration "none")
|
||||
nil
|
||||
text-decoration)
|
||||
""
|
||||
(radio-selected text-decoration))
|
||||
:on-change handle-change
|
||||
:name "text-decoration-options"
|
||||
:disabled (and token-typography-row-enabled? (some? token-applied))
|
||||
@ -246,8 +245,10 @@
|
||||
(d/seek #(= (:id %) (uuid/uuid id)))))
|
||||
|
||||
(defn- check-props [n-props o-props]
|
||||
(let [o-values (unchecked-get o-props "values")
|
||||
n-values (unchecked-get n-props "values")]
|
||||
(let [o-values (unchecked-get o-props "values")
|
||||
n-values (unchecked-get n-props "values")
|
||||
o-ruby-values (unchecked-get o-props "rubyValues")
|
||||
n-ruby-values (unchecked-get n-props "rubyValues")]
|
||||
(and (identical? (unchecked-get n-props "ids")
|
||||
(unchecked-get o-props "ids"))
|
||||
(identical? (unchecked-get n-props "type")
|
||||
@ -258,6 +259,9 @@
|
||||
(unchecked-get o-props "fileId"))
|
||||
(identical? (unchecked-get n-props "typographies")
|
||||
(unchecked-get o-props "typographies"))
|
||||
(identical? (unchecked-get n-props "textSelectionActive")
|
||||
(unchecked-get o-props "textSelectionActive"))
|
||||
(= n-ruby-values o-ruby-values)
|
||||
(identical? (get o-values :fills)
|
||||
(get n-values :fills))
|
||||
(identical? (get o-values :font-family)
|
||||
@ -284,6 +288,32 @@
|
||||
(get n-values :text-decoration))
|
||||
(identical? (get o-values :text-direction)
|
||||
(get n-values :text-direction))
|
||||
(identical? (get o-values :writing-mode)
|
||||
(get n-values :writing-mode))
|
||||
(identical? (get o-values :text-orientation)
|
||||
(get n-values :text-orientation))
|
||||
(identical? (get o-values :text-combine-upright)
|
||||
(get n-values :text-combine-upright))
|
||||
(identical? (get o-values :warichu)
|
||||
(get n-values :warichu))
|
||||
(identical? (get o-values :font-features)
|
||||
(get n-values :font-features))
|
||||
(identical? (get o-values :annotation-clearance)
|
||||
(get n-values :annotation-clearance))
|
||||
(identical? (get o-values :text-emphasis)
|
||||
(get n-values :text-emphasis))
|
||||
(identical? (get o-values :ruby)
|
||||
(get n-values :ruby))
|
||||
(identical? (get o-values :ruby-hidden)
|
||||
(get n-values :ruby-hidden))
|
||||
(identical? (get o-values :ruby-size)
|
||||
(get n-values :ruby-size))
|
||||
(identical? (get o-values :ruby-align)
|
||||
(get n-values :ruby-align))
|
||||
(identical? (get o-values :ruby-overhang)
|
||||
(get n-values :ruby-overhang))
|
||||
(identical? (get o-values :ruby-side)
|
||||
(get n-values :ruby-side))
|
||||
(identical? (get o-values :text-transform)
|
||||
(get n-values :text-transform))
|
||||
(identical? (get o-values :typography-ref-file)
|
||||
@ -291,7 +321,9 @@
|
||||
(identical? (get o-values :typography-ref-id)
|
||||
(get n-values :typography-ref-id))
|
||||
(identical? (get o-values :vertical-align)
|
||||
(get n-values :vertical-align)))))
|
||||
(get n-values :vertical-align))
|
||||
(identical? (get o-values :line-adjustment)
|
||||
(get n-values :line-adjustment)))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Main component
|
||||
@ -299,14 +331,20 @@
|
||||
|
||||
(mf/defc text-menu*
|
||||
{::mf/wrap [#(mf/memo' % check-props)]}
|
||||
[{:keys [ids type values applied-tokens libraries file-id typographies]}]
|
||||
[{:keys [ids type values ruby-values text-selection-active
|
||||
applied-tokens libraries file-id typographies]}]
|
||||
|
||||
(let [;; --- UI state
|
||||
menu-state* (mf/use-state {:main-menu true
|
||||
:more-options false})
|
||||
:more-options false
|
||||
:japanese-layout true})
|
||||
menu-state (deref menu-state*)
|
||||
main-menu-open? (:main-menu menu-state)
|
||||
more-options-open? (:more-options menu-state)
|
||||
japanese-layout-open? (:japanese-layout menu-state)
|
||||
|
||||
japanese-layout-config-enabled?
|
||||
(tjl/japanese-layout-config-enabled? (mf/deref refs/japanese-layout-config))
|
||||
|
||||
font-id (or (:font-id values) (:font-id txt/default-typography))
|
||||
|
||||
@ -397,6 +435,10 @@
|
||||
(mf/use-fn
|
||||
#(swap! menu-state* update :more-options not))
|
||||
|
||||
toggle-japanese-layout
|
||||
(mf/use-fn
|
||||
#(swap! menu-state* update :japanese-layout not))
|
||||
|
||||
toggle-token-dropdown
|
||||
(mf/use-fn
|
||||
#(swap! token-dropdown-open* not))
|
||||
@ -427,6 +469,14 @@
|
||||
(fn [attrs]
|
||||
(emit-update! ids attrs)))
|
||||
|
||||
on-ruby-presentation-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids on-change text-selection-active)
|
||||
(fn [attrs]
|
||||
(if text-selection-active
|
||||
(on-change attrs)
|
||||
(st/emit! (dwt/update-all-ruby-presentation ids attrs)))))
|
||||
|
||||
on-convert-to-typography
|
||||
(mf/use-fn
|
||||
(mf/deps values ids file-id emit-update!)
|
||||
@ -485,7 +535,17 @@
|
||||
:values values
|
||||
:on-change on-change
|
||||
:show-recent true
|
||||
:on-blur on-text-blur})]
|
||||
:on-blur on-text-blur})
|
||||
|
||||
japanese-layout-props
|
||||
(mf/props
|
||||
{:ids ids
|
||||
:values values
|
||||
:ruby-values ruby-values
|
||||
:text-selection-active text-selection-active
|
||||
:on-change on-change
|
||||
:on-ruby-presentation-change on-ruby-presentation-change
|
||||
:on-blur on-text-blur})]
|
||||
|
||||
(hooks/use-stream
|
||||
expand-stream
|
||||
@ -503,97 +563,114 @@
|
||||
(when token-dropdown-open?
|
||||
(ts/schedule 0 #(some-> (mf/ref-val dropdown-ref) dom/focus!))))
|
||||
|
||||
[:section {:class (stl/css :element-set)
|
||||
;; Focusing these controls must not exit the v3 text editor (see `keep-editing-on-blur?`).
|
||||
:data-keep-editing-on-blur true
|
||||
:aria-label (tr "workspace.options.text-options.text-section")}
|
||||
[:div {:class (stl/css :element-title)}
|
||||
[:> title-bar* {:collapsable true
|
||||
:collapsed (not main-menu-open?)
|
||||
:on-collapsed toggle-main-menu
|
||||
:title label
|
||||
:class (stl/css :title-spacing-text)}
|
||||
[:*
|
||||
(when (and token-typography-row-enabled? (some? (resolve-delay typography-tokens)) (not typography))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
||||
:on-click toggle-token-dropdown
|
||||
:tooltip-placement "top-left"
|
||||
:icon i/tokens}])
|
||||
(when (and (not typography) (not multiple?) (not applied-token-name))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (if (not font)
|
||||
(tr "workspace.options.font-not-available" (:font-family values))
|
||||
(tr "workspace.options.convert-to-typography"))
|
||||
:on-click on-convert-to-typography
|
||||
:tooltip-placement "top-left"
|
||||
:disabled (not font)
|
||||
:icon i/add}])]]
|
||||
(when (and token-typography-row-enabled? token-dropdown-open?)
|
||||
[:> searchable-options-dropdown* {:on-click on-option-click
|
||||
:id listbox-id
|
||||
:options (resolve-delay dropdown-options)
|
||||
:selected selected-token-id
|
||||
:align "right"
|
||||
:placeholder (tr "workspace.tokens.search-by-token")
|
||||
:ref set-option-ref}])]
|
||||
|
||||
(when main-menu-open?
|
||||
[:div {:class (stl/css :element-content)}
|
||||
(cond
|
||||
(and token-typography-row-enabled? (= :multiple current-token-name) (= typography-id :multiple))
|
||||
[:div {:class (stl/css :multiple-typography)}
|
||||
[:span {:class (stl/css :multiple-text)}
|
||||
(tr "workspace.libraries.text.mixed-tokens-and-assets")]]
|
||||
|
||||
(and token-typography-row-enabled? (= :multiple current-token-name))
|
||||
[:div {:class (stl/css :multiple-typography)}
|
||||
[:span {:class (stl/css :multiple-text)}
|
||||
(tr "workspace.libraries.text.mixed-tokens")]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.libraries.text.multiple-token-tooltip")
|
||||
[:*
|
||||
[:section {:class (stl/css :element-set)
|
||||
;; Focusing these controls must not exit the v3 text editor (see `keep-editing-on-blur?`).
|
||||
:data-keep-editing-on-blur true
|
||||
:aria-label (tr "workspace.options.text-options.text-section")}
|
||||
[:div {:class (stl/css :element-title)}
|
||||
[:> title-bar* {:collapsable true
|
||||
:collapsed (not main-menu-open?)
|
||||
:on-collapsed toggle-main-menu
|
||||
:title label
|
||||
:class (stl/css :title-spacing-text)}
|
||||
[:*
|
||||
(when (and token-typography-row-enabled? (some? (resolve-delay typography-tokens)) (not typography))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "ds.inputs.numeric-input.open-token-list-dropdown")
|
||||
:on-click toggle-token-dropdown
|
||||
:tooltip-placement "top-left"
|
||||
:on-click handle-detach-all-tokens
|
||||
:icon i/detach}]]
|
||||
|
||||
(and token-typography-row-enabled? current-token-name)
|
||||
[:> token-typography-row* {:token-name current-token-name
|
||||
:detach-token detach-token
|
||||
:active-tokens (resolve-delay typography-tokens)}]
|
||||
|
||||
(= typography-id :multiple)
|
||||
[:div {:class (stl/css :multiple-typography)}
|
||||
[:span {:class (stl/css :multiple-text)}
|
||||
(tr "workspace.libraries.text.mixed-typography")]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.libraries.text.multiple-assets-tooltip")
|
||||
:on-click handle-detach-typography
|
||||
:icon i/tokens}])
|
||||
(when (and (not typography) (not multiple?) (not applied-token-name))
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (if (not font)
|
||||
(tr "workspace.options.font-not-available" (:font-family values))
|
||||
(tr "workspace.options.convert-to-typography"))
|
||||
:on-click on-convert-to-typography
|
||||
:tooltip-placement "top-left"
|
||||
:icon i/detach}]]
|
||||
:disabled (not font)
|
||||
:icon i/add}])]]
|
||||
(when (and token-typography-row-enabled? token-dropdown-open?)
|
||||
[:> searchable-options-dropdown* {:on-click on-option-click
|
||||
:id listbox-id
|
||||
:options (resolve-delay dropdown-options)
|
||||
:selected selected-token-id
|
||||
:align "right"
|
||||
:placeholder (tr "workspace.tokens.search-by-token")
|
||||
:ref set-option-ref}])]
|
||||
|
||||
typography
|
||||
[:> typography-entry* {:file-id typography-file-id
|
||||
:typography typography
|
||||
:is-local (= typography-file-id file-id)
|
||||
:on-detach handle-detach-typography
|
||||
:on-change handle-change-typography}]
|
||||
(when main-menu-open?
|
||||
[:div {:class (stl/css :element-content)}
|
||||
(cond
|
||||
(and token-typography-row-enabled? (= :multiple current-token-name) (= typography-id :multiple))
|
||||
[:div {:class (stl/css :multiple-typography)}
|
||||
[:span {:class (stl/css :multiple-text)}
|
||||
(tr "workspace.libraries.text.mixed-tokens-and-assets")]]
|
||||
|
||||
(and token-typography-row-enabled? (= :multiple current-token-name))
|
||||
[:div {:class (stl/css :multiple-typography)}
|
||||
[:span {:class (stl/css :multiple-text)}
|
||||
(tr "workspace.libraries.text.mixed-tokens")]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.libraries.text.multiple-token-tooltip")
|
||||
:tooltip-placement "top-left"
|
||||
:on-click handle-detach-all-tokens
|
||||
:icon i/detach}]]
|
||||
|
||||
(and token-typography-row-enabled? current-token-name)
|
||||
[:> token-typography-row* {:token-name current-token-name
|
||||
:detach-token detach-token
|
||||
:active-tokens (resolve-delay typography-tokens)}]
|
||||
|
||||
:else
|
||||
[:> text-options* common-props])
|
||||
(= typography-id :multiple)
|
||||
[:div {:class (stl/css :multiple-typography)}
|
||||
[:span {:class (stl/css :multiple-text)}
|
||||
(tr "workspace.libraries.text.mixed-typography")]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "workspace.libraries.text.multiple-assets-tooltip")
|
||||
:on-click handle-detach-typography
|
||||
:tooltip-placement "top-left"
|
||||
:icon i/detach}]]
|
||||
|
||||
[:div {:class (stl/css :text-align-options)}
|
||||
[:> text-align-options* common-props]
|
||||
[:> grow-options* common-props]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "labels.options")
|
||||
:data-testid "text-align-options-button"
|
||||
:on-click toggle-more-options
|
||||
:icon i/menu}]]
|
||||
typography
|
||||
[:> typography-entry* {:file-id typography-file-id
|
||||
:typography typography
|
||||
:is-local (= typography-file-id file-id)
|
||||
:on-detach handle-detach-typography
|
||||
:on-change handle-change-typography}]
|
||||
|
||||
(when more-options-open?
|
||||
[:div {:class (stl/css :text-decoration-options)}
|
||||
[:> vertical-align* common-props]
|
||||
[:> text-decoration-options* (mf/spread-props common-props {:token-applied current-token-name})]
|
||||
[:> text-direction-options* common-props]])])]))
|
||||
:else
|
||||
[:> text-options* common-props])
|
||||
|
||||
[:div {:class (stl/css :text-align-options)}
|
||||
[:> text-align-options* common-props]
|
||||
[:> grow-options* common-props]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "labels.options")
|
||||
:data-testid "text-align-options-button"
|
||||
:on-click toggle-more-options
|
||||
:icon i/menu}]]
|
||||
|
||||
(when japanese-layout-config-enabled?
|
||||
[:> tjl/line-adjustment-option* common-props])
|
||||
|
||||
(when more-options-open?
|
||||
[:div {:class (stl/css :text-decoration-options)}
|
||||
[:> vertical-align* common-props]
|
||||
[:> text-decoration-options* (mf/spread-props common-props {:token-applied current-token-name})]
|
||||
[:> text-direction-options* common-props]])])]
|
||||
|
||||
(when japanese-layout-config-enabled?
|
||||
[:section {:class (stl/css :element-set)
|
||||
;; Focusing these controls must not exit the v3 text editor (see `keep-editing-on-blur?`).
|
||||
:data-keep-editing-on-blur true
|
||||
:aria-label (tr "workspace.options.text-options.japanese-layout")}
|
||||
[:div {:class (stl/css :element-title)}
|
||||
[:> title-bar* {:collapsable true
|
||||
:collapsed (not japanese-layout-open?)
|
||||
:on-collapsed toggle-japanese-layout
|
||||
:title (tr "workspace.options.text-options.japanese-layout")
|
||||
:class (stl/css :title-spacing-text)}]]
|
||||
(when japanese-layout-open?
|
||||
[:div {:class (stl/css :element-content)}
|
||||
[:> tjl/japanese-layout-options* japanese-layout-props]])])]))
|
||||
|
||||
@ -0,0 +1,523 @@
|
||||
;; 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 Sucursal en España SL
|
||||
|
||||
(ns app.main.ui.workspace.sidebar.options.menus.text-japanese-layout
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.types.text.japanese-layout :as jl]
|
||||
[app.main.ui.components.title-bar :refer [title-bar*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.controls.input :refer [input*]]
|
||||
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
|
||||
[app.main.ui.ds.controls.select :refer [select*]]
|
||||
[app.main.ui.ds.controls.switch :refer [switch*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options* radio-selected]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.text.writing-mode :as wm]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private mixed-span-values
|
||||
#{:mixed :multiple "mixed" "multiple"})
|
||||
|
||||
(defn- mixed-span-value?
|
||||
[value]
|
||||
(contains? mixed-span-values value))
|
||||
|
||||
(defn- span-input-value
|
||||
[value]
|
||||
(if (mixed-span-value? value)
|
||||
"mixed"
|
||||
(radio-selected value)))
|
||||
|
||||
(defn span-select-value
|
||||
[value default]
|
||||
(if (mixed-span-value? value)
|
||||
"mixed"
|
||||
(radio-selected value default)))
|
||||
|
||||
(defn with-mixed-span-option
|
||||
[options value]
|
||||
(cond-> options
|
||||
(mixed-span-value? value)
|
||||
(conj {:id "mixed"
|
||||
:label (tr "labels.mixed-values")
|
||||
:disabled true
|
||||
:dimmed true})))
|
||||
|
||||
(defn japanese-layout-config-enabled?
|
||||
"True under the WASM renderer when Japanese layout is enabled for the file
|
||||
or in the user's profile. `config` is a `refs/japanese-layout-config`
|
||||
value."
|
||||
[{:keys [file? all-files?]}]
|
||||
(and ^boolean (wm/vertical-layout-active?)
|
||||
(boolean (or file? all-files?))))
|
||||
|
||||
(defn vertical-japanese-layout?
|
||||
"True when the Japanese layout controls are editing vertical text."
|
||||
[values]
|
||||
(= "vertical-rl" (:writing-mode values)))
|
||||
|
||||
(defn proportional-metrics-feature
|
||||
"Proportional metrics feature for the writing mode: `vpal` or `palt`."
|
||||
[writing-mode]
|
||||
(if (= writing-mode "vertical-rl") "vpal" "palt"))
|
||||
|
||||
(defn text-combine-upright-options
|
||||
[text-selection-active translate]
|
||||
(cond-> [{:value "none"
|
||||
:id "none-text-combine-upright"
|
||||
:label (translate "workspace.options.text-options.text-combine-upright-none")
|
||||
:icon i/text-combine-upright-none}]
|
||||
text-selection-active
|
||||
(conj {:value "all"
|
||||
:id "all-text-combine-upright"
|
||||
:label (translate "workspace.options.text-options.text-combine-upright-all")
|
||||
:icon i/text-combine-upright-all})
|
||||
|
||||
true
|
||||
(conj {:value "digits"
|
||||
:id "digits-text-combine-upright"
|
||||
:label (translate "workspace.options.text-options.text-combine-upright-digits")
|
||||
:icon i/text-combine-upright-digits})))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Sub-components
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(mf/defc attr-radio-options*
|
||||
"Radio group bound to one text attribute."
|
||||
[{:keys [values on-change on-blur attr default-value name class options]}]
|
||||
(let [selected (radio-selected (get values attr) default-value)
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps attr on-change on-blur)
|
||||
(fn [value]
|
||||
(on-change {attr value})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
[:div {:class class}
|
||||
[:> radio-buttons* {:selected selected
|
||||
:on-change handle-change
|
||||
:name name
|
||||
:options options}]]))
|
||||
|
||||
(defn writing-mode-options
|
||||
[translate]
|
||||
[{:value "horizontal-tb"
|
||||
:id "horizontal-tb-writing-mode"
|
||||
:label (translate "workspace.options.text-options.writing-mode-horizontal")
|
||||
:icon i/writing-mode-horizontal}
|
||||
{:value "vertical-rl"
|
||||
:id "vertical-rl-writing-mode"
|
||||
:label (translate "workspace.options.text-options.writing-mode-vertical")
|
||||
:icon i/writing-mode-vertical}])
|
||||
|
||||
(defn text-orientation-options
|
||||
[translate]
|
||||
[{:value "mixed"
|
||||
:id "mixed-text-orientation"
|
||||
:label (translate "workspace.options.text-options.text-orientation-mixed")
|
||||
:icon i/text-orientation-mixed}
|
||||
{:value "upright"
|
||||
:id "upright-text-orientation"
|
||||
:label (translate "workspace.options.text-options.text-orientation-upright")
|
||||
:icon i/text-orientation-upright}])
|
||||
|
||||
;; Warichu (割注): renders the selection as two half-size lines in one inline
|
||||
;; position (top/bottom horizontally, right/left vertically).
|
||||
(defn warichu-options
|
||||
[translate]
|
||||
[{:value "none"
|
||||
:id "none-warichu"
|
||||
:label (translate "workspace.options.text-options.warichu-none")
|
||||
:icon i/warichu-none}
|
||||
{:value "warichu"
|
||||
:id "warichu-warichu"
|
||||
:label (translate "workspace.options.text-options.warichu")
|
||||
:icon i/warichu}])
|
||||
|
||||
;; select* matches options by :id, so each id is the stored value.
|
||||
(defn text-combine-upright-count-options
|
||||
[translate]
|
||||
[{:id "digits2"
|
||||
:label (translate "workspace.options.text-options.text-combine-upright-digits-2")}
|
||||
{:id "digits3"
|
||||
:label (translate "workspace.options.text-options.text-combine-upright-digits-3")}
|
||||
{:id "digits"
|
||||
:label (translate "workspace.options.text-options.text-combine-upright-digits-4")}])
|
||||
|
||||
(defn ruby-size-options
|
||||
[translate]
|
||||
[{:id "half" :label (translate "workspace.options.text-options.ruby-size-half")}
|
||||
{:id "third" :label (translate "workspace.options.text-options.ruby-size-third")}
|
||||
{:id "quarter" :label (translate "workspace.options.text-options.ruby-size-quarter")}])
|
||||
|
||||
(defn ruby-align-options
|
||||
[translate]
|
||||
[{:id "space-around" :label (translate "workspace.options.text-options.ruby-align-space-around")}
|
||||
{:id "center" :label (translate "workspace.options.text-options.ruby-align-center")}
|
||||
{:id "start" :label (translate "workspace.options.text-options.ruby-align-start")}
|
||||
{:id "space-between" :label (translate "workspace.options.text-options.ruby-align-space-between")}])
|
||||
|
||||
(defn ruby-overhang-options
|
||||
[translate]
|
||||
[{:id "auto" :label (translate "workspace.options.text-options.ruby-overhang-auto")}
|
||||
{:id "none" :label (translate "workspace.options.text-options.ruby-overhang-none")}])
|
||||
|
||||
(defn ruby-side-options
|
||||
[translate]
|
||||
[{:id "over" :label (translate "workspace.options.text-options.ruby-side-over")}
|
||||
{:id "under" :label (translate "workspace.options.text-options.ruby-side-under")}])
|
||||
|
||||
(mf/defc text-combine-upright-options*
|
||||
;; Digit TCY finds eligible runs itself, so it applies to a whole shape;
|
||||
;; `all` is offered only for a text selection.
|
||||
[{:keys [values on-change on-blur text-selection-active]}]
|
||||
(let [text-combine-upright (radio-selected (:text-combine-upright values)
|
||||
(jl/enum-default :text-combine-upright))
|
||||
selected (if (jl/digit-combine? text-combine-upright) "digits" text-combine-upright)
|
||||
options
|
||||
(mf/with-memo [text-selection-active]
|
||||
(text-combine-upright-options text-selection-active tr))
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps on-change on-blur)
|
||||
(fn [value]
|
||||
(on-change {:text-combine-upright value})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
|
||||
[:div {:class (stl/css :text-combine-upright-options)}
|
||||
[:> radio-buttons* {:selected selected
|
||||
:on-change handle-change
|
||||
:name "text-combine-upright-options"
|
||||
:options options}]]))
|
||||
|
||||
(mf/defc text-combine-upright-count-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [text-combine-upright (radio-selected (:text-combine-upright values)
|
||||
(jl/enum-default :text-combine-upright))
|
||||
digits? (jl/digit-combine? text-combine-upright)
|
||||
options (mf/with-memo [] (text-combine-upright-count-options tr))
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps on-change on-blur)
|
||||
(fn [value]
|
||||
(on-change {:text-combine-upright value})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
|
||||
(when digits?
|
||||
[:div {:class (stl/css :japanese-select-option)}
|
||||
[:span {:class (stl/css :japanese-option-label)}
|
||||
(tr "workspace.options.text-options.text-combine-upright-digits-count")]
|
||||
[:> select* {:default-selected text-combine-upright
|
||||
:aria-label (tr "workspace.options.text-options.text-combine-upright-digits-count")
|
||||
:options options
|
||||
:on-change handle-change}]])))
|
||||
|
||||
(mf/defc ruby-options*
|
||||
[{:keys [values on-change on-blur advanced-open on-toggle-advanced]}]
|
||||
(let [ruby (span-input-value (:ruby values))
|
||||
ruby* (mf/use-state ruby)
|
||||
dirty* (mf/use-state false)
|
||||
value (deref ruby*)
|
||||
dirty? (deref dirty*)
|
||||
|
||||
commit!
|
||||
(mf/use-fn
|
||||
(mf/deps dirty? value on-change on-blur)
|
||||
(fn []
|
||||
(when dirty?
|
||||
(on-change {:ruby value})
|
||||
(reset! dirty* false))
|
||||
(when (some? on-blur) (on-blur))))
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(reset! dirty* true)
|
||||
(reset! ruby* (dom/get-target-val event))))
|
||||
|
||||
handle-key-down
|
||||
(mf/use-fn
|
||||
(mf/deps commit!)
|
||||
(fn [event]
|
||||
(when (= "Enter" (.-key event))
|
||||
(dom/blur! (dom/get-target event)))))]
|
||||
|
||||
(mf/with-effect [ruby]
|
||||
(reset! ruby* ruby)
|
||||
(reset! dirty* false))
|
||||
|
||||
[:div {:class (stl/css :ruby-options)}
|
||||
[:> input* {:class (stl/css :ruby-input)
|
||||
:label (tr "workspace.options.text-options.ruby")
|
||||
:placeholder (tr "workspace.options.text-options.ruby-placeholder")
|
||||
:value value
|
||||
:on-change handle-change
|
||||
:on-blur commit!
|
||||
:on-key-down handle-key-down}]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:selected advanced-open
|
||||
:aria-label (tr "workspace.options.text-options.ruby-advanced-options")
|
||||
:aria-expanded advanced-open
|
||||
:data-testid "ruby-advanced-options-toggle"
|
||||
:on-click on-toggle-advanced
|
||||
:icon i/menu}]]))
|
||||
|
||||
(mf/defc span-select-option*
|
||||
"Select bound to one span attribute, with a disabled entry for mixed values."
|
||||
[{:keys [values on-change on-blur attr default-value label options]}]
|
||||
(let [value (get values attr)
|
||||
selected (span-select-value value default-value)
|
||||
options (with-mixed-span-option options value)
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps attr on-change on-blur)
|
||||
(fn [value]
|
||||
(on-change {attr value})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
[:div {:class (stl/css :japanese-select-option)}
|
||||
[:span {:class (stl/css :japanese-option-label)} label]
|
||||
[:> select* {:default-selected selected
|
||||
:aria-label label
|
||||
:options options
|
||||
:on-change handle-change}]]))
|
||||
|
||||
(defn- ruby-common-props
|
||||
[values on-change on-blur]
|
||||
(mf/props
|
||||
{:values values
|
||||
:on-change on-change
|
||||
:on-blur on-blur}))
|
||||
|
||||
(mf/defc ruby-hidden-option*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [value (:ruby-hidden values)
|
||||
enabled? (cond
|
||||
(mixed-span-value? value) nil
|
||||
(true? value) true
|
||||
:else false)
|
||||
label (tr "workspace.options.text-options.ruby-hidden")
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps on-change on-blur)
|
||||
(fn [checked?]
|
||||
(on-change {:ruby-hidden checked?})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
[:div {:class (stl/css :ruby-hidden-option :japanese-select-option)}
|
||||
[:span {:class (stl/css :japanese-option-label)} label]
|
||||
[:> switch* {:default-checked enabled?
|
||||
:aria-label label
|
||||
:on-change handle-change}]]))
|
||||
|
||||
(mf/defc ruby-customization-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [common-props (ruby-common-props values on-change on-blur)
|
||||
options (mf/with-memo []
|
||||
{:ruby-size (ruby-size-options tr)
|
||||
:ruby-align (ruby-align-options tr)
|
||||
:ruby-overhang (ruby-overhang-options tr)
|
||||
:ruby-side (ruby-side-options tr)})]
|
||||
[:div {:class (stl/css :japanese-layout-controls)}
|
||||
[:> ruby-hidden-option* common-props]
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
{:attr :ruby-size
|
||||
:default-value (jl/enum-default :ruby-size)
|
||||
:label (tr "workspace.options.text-options.ruby-size")
|
||||
:options (:ruby-size options)})]
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
{:attr :ruby-align
|
||||
:default-value (jl/enum-default :ruby-align)
|
||||
:label (tr "workspace.options.text-options.ruby-align")
|
||||
:options (:ruby-align options)})]
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
{:attr :ruby-overhang
|
||||
:default-value (jl/enum-default :ruby-overhang)
|
||||
:label (tr "workspace.options.text-options.ruby-overhang")
|
||||
:options (:ruby-overhang options)})]
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
{:attr :ruby-side
|
||||
:default-value (jl/enum-default :ruby-side)
|
||||
:label (tr "workspace.options.text-options.ruby-side")
|
||||
:options (:ruby-side options)})]]))
|
||||
|
||||
(mf/defc ruby-advanced-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [open* (mf/use-state false)
|
||||
open? (deref open*)
|
||||
toggle-open (mf/use-fn #(swap! open* not))
|
||||
common-props (ruby-common-props values on-change on-blur)]
|
||||
[:div {:class (stl/css :ruby-advanced-options)}
|
||||
[:> ruby-options* (mf/spread-props common-props
|
||||
{:advanced-open open?
|
||||
:on-toggle-advanced toggle-open})]
|
||||
[:> advanced-options* {:class (stl/css :ruby-advanced-content)
|
||||
:is-visible open?}
|
||||
[:> ruby-customization-options* common-props]]]))
|
||||
|
||||
(mf/defc ruby-presentation-options*
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [open* (mf/use-state false)
|
||||
open? (deref open*)
|
||||
toggle-open (mf/use-fn #(swap! open* not))
|
||||
common-props (ruby-common-props values on-change on-blur)]
|
||||
[:div {:class (stl/css :ruby-advanced-options)}
|
||||
[:> title-bar* {:collapsable true
|
||||
:collapsed (not open?)
|
||||
:title (tr "workspace.options.text-options.ruby-advanced-options")
|
||||
:on-collapsed toggle-open
|
||||
:aria-expanded open?
|
||||
:data-testid "ruby-presentation-options-toggle"}]
|
||||
[:> advanced-options* {:class (stl/css :ruby-advanced-content)
|
||||
:is-visible open?}
|
||||
[:> ruby-customization-options* common-props]]]))
|
||||
|
||||
(mf/defc font-features-options*
|
||||
;; Japanese proportional metric alternates, per span: `palt` for
|
||||
;; horizontal text, `vpal` for vertical.
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [writing-mode (:writing-mode values)
|
||||
feature (proportional-metrics-feature writing-mode)
|
||||
value (:font-features values)
|
||||
enabled? (cond
|
||||
(mixed-span-value? value) nil
|
||||
(= feature value) true
|
||||
:else false)
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps feature on-change on-blur)
|
||||
(fn [checked?]
|
||||
(on-change {:font-features (if checked? feature "none")})
|
||||
(when (some? on-blur) (on-blur))))]
|
||||
|
||||
[:div {:class (stl/css :japanese-select-option)}
|
||||
[:span {:class (stl/css :japanese-option-label)}
|
||||
(tr "workspace.options.text-options.font-features")]
|
||||
[:> switch* {:default-checked enabled?
|
||||
:aria-label (tr "workspace.options.text-options.font-features")
|
||||
:on-change handle-change}]]))
|
||||
|
||||
(defn text-emphasis-options
|
||||
([]
|
||||
(text-emphasis-options tr))
|
||||
([translate]
|
||||
[{:id "none"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-none")}
|
||||
{:id "filled-dot"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-filled-dot")}
|
||||
{:id "open-dot"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-open-dot")}
|
||||
{:id "filled-circle"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-filled-circle")}
|
||||
{:id "open-circle"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-open-circle")}
|
||||
{:id "filled-sesame"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-filled-sesame")}
|
||||
{:id "open-sesame"
|
||||
:label (translate "workspace.options.text-options.text-emphasis-open-sesame")}]))
|
||||
|
||||
(defn annotation-clearance-options
|
||||
([]
|
||||
(annotation-clearance-options tr))
|
||||
([translate]
|
||||
[{:id "none"
|
||||
:label (translate "workspace.options.text-options.annotation-clearance-none")}
|
||||
{:id "auto"
|
||||
:label (translate "workspace.options.text-options.annotation-clearance-auto")}]))
|
||||
|
||||
(defn line-adjustment-options
|
||||
([]
|
||||
(line-adjustment-options tr))
|
||||
([translate]
|
||||
[{:id "push-in-first"
|
||||
:label (translate "workspace.options.text-options.line-adjustment-push-in-first")}
|
||||
{:id "push-out-first"
|
||||
:label (translate "workspace.options.text-options.line-adjustment-push-out-first")}
|
||||
{:id "push-out-only"
|
||||
:label (translate "workspace.options.text-options.line-adjustment-push-out-only")}]))
|
||||
|
||||
(mf/defc line-adjustment-option*
|
||||
"Whole-shape setting: how lines slightly too long are fitted."
|
||||
[{:keys [values on-change on-blur]}]
|
||||
(let [options (mf/with-memo [] (line-adjustment-options))]
|
||||
[:> span-select-option* {:values values
|
||||
:on-change on-change
|
||||
:on-blur on-blur
|
||||
:attr :line-adjustment
|
||||
:default-value (jl/enum-default :line-adjustment)
|
||||
:label (tr "workspace.options.text-options.line-adjustment")
|
||||
:options options}]))
|
||||
|
||||
(mf/defc japanese-layout-options*
|
||||
[{:keys [values ruby-values text-selection-active
|
||||
on-change on-ruby-presentation-change on-blur]}]
|
||||
(let [vertical? (vertical-japanese-layout? values)
|
||||
common-props (mf/props
|
||||
{:values values
|
||||
:on-change on-change
|
||||
:on-blur on-blur})
|
||||
ruby-presentation-props (mf/props
|
||||
{:values ruby-values
|
||||
:on-change on-ruby-presentation-change
|
||||
:on-blur on-blur})
|
||||
options (mf/with-memo []
|
||||
{:writing-mode (writing-mode-options tr)
|
||||
:text-orientation (text-orientation-options tr)
|
||||
:warichu (warichu-options tr)
|
||||
:text-emphasis (text-emphasis-options)
|
||||
:annotation-clearance (annotation-clearance-options)})]
|
||||
|
||||
[:div {:class (stl/css :japanese-layout-options)}
|
||||
[:div {:class (stl/css :japanese-layout-controls)}
|
||||
[:div {:class (stl/css :japanese-icon-options)}
|
||||
[:> attr-radio-options* (mf/spread-props common-props
|
||||
{:attr :writing-mode
|
||||
:default-value (jl/enum-default :writing-mode)
|
||||
:name "writing-mode-options"
|
||||
:class (stl/css :writing-mode-options)
|
||||
:options (:writing-mode options)})]
|
||||
(when ^boolean vertical?
|
||||
[:*
|
||||
;; An unset orientation reads as nil, or "" in the v2 editor; both
|
||||
;; select "mixed".
|
||||
[:> attr-radio-options* (mf/spread-props common-props
|
||||
{:attr :text-orientation
|
||||
:default-value (jl/enum-default :text-orientation)
|
||||
:name "text-orientation-options"
|
||||
:class (stl/css :text-orientation-options)
|
||||
:options (:text-orientation options)})]
|
||||
[:> text-combine-upright-options*
|
||||
(mf/spread-props common-props
|
||||
{:text-selection-active text-selection-active})]])
|
||||
(when ^boolean text-selection-active
|
||||
[:> attr-radio-options* (mf/spread-props common-props
|
||||
{:attr :warichu
|
||||
:default-value (jl/enum-default :warichu)
|
||||
:name "warichu-options"
|
||||
:class (stl/css :warichu-options)
|
||||
:options (:warichu options)})])]
|
||||
(when ^boolean vertical?
|
||||
[:> text-combine-upright-count-options* common-props])
|
||||
[:> font-features-options* common-props]
|
||||
;; Emphasis marks (圏点 / bouten) apply to the selected characters.
|
||||
(when ^boolean text-selection-active
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
{:attr :text-emphasis
|
||||
:default-value (jl/enum-default :text-emphasis)
|
||||
:label (tr "workspace.options.text-options.text-emphasis")
|
||||
:options (:text-emphasis options)})])
|
||||
[:> span-select-option* (mf/spread-props common-props
|
||||
{:attr :annotation-clearance
|
||||
:default-value (jl/enum-default :annotation-clearance)
|
||||
:label (tr "workspace.options.text-options.annotation-clearance")
|
||||
:options (:annotation-clearance options)})]
|
||||
(if text-selection-active
|
||||
[:> ruby-advanced-options* common-props]
|
||||
[:> ruby-presentation-options* ruby-presentation-props])]]))
|
||||
@ -0,0 +1,78 @@
|
||||
// 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 Sucursal en España SL
|
||||
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/spacing.scss" as *;
|
||||
|
||||
.writing-mode-options,
|
||||
.text-orientation-options,
|
||||
.text-combine-upright-options,
|
||||
.warichu-options {
|
||||
block-size: $sz-32;
|
||||
}
|
||||
|
||||
.ruby-advanced-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.ruby-options {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.ruby-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ruby-advanced-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-xs);
|
||||
padding: var(--sp-xs);
|
||||
border: $b-1 solid var(--color-background-quaternary);
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
.japanese-layout-options,
|
||||
.japanese-layout-controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.japanese-layout-options {
|
||||
padding-block: var(--sp-xs);
|
||||
}
|
||||
|
||||
.ruby-hidden-option {
|
||||
min-block-size: $sz-32;
|
||||
}
|
||||
|
||||
.japanese-icon-options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.japanese-select-option {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
|
||||
align-items: center;
|
||||
gap: var(--sp-s);
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.japanese-option-label {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
@ -10,6 +10,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.text :as txt]
|
||||
[app.common.types.text.japanese-layout :as jl]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
@ -27,8 +28,30 @@
|
||||
[app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu*]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu*]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu*]]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- dom-text-range-selected?
|
||||
[editor]
|
||||
(when editor
|
||||
(let [selection (.getSelection js/window)
|
||||
element (.-element editor)
|
||||
anchor (some-> selection .-anchorNode)
|
||||
focus (some-> selection .-focusNode)]
|
||||
(and selection
|
||||
(not (.-isCollapsed selection))
|
||||
element
|
||||
anchor
|
||||
focus
|
||||
(.contains element anchor)
|
||||
(.contains element focus)))))
|
||||
|
||||
(defn- draft-text-range-selected?
|
||||
[editor-state]
|
||||
(when editor-state
|
||||
(let [selection (.getSelection editor-state)]
|
||||
(and selection (not (.isCollapsed selection))))))
|
||||
|
||||
(mf/defc options*
|
||||
[{:keys [shape libraries file-id page-id]}]
|
||||
(let [id (dm/get-prop shape :id)
|
||||
@ -128,6 +151,19 @@
|
||||
(when text-editor-v2?
|
||||
editor)
|
||||
|
||||
text-selection-active
|
||||
(boolean
|
||||
(cond
|
||||
text-editor-wasm?
|
||||
(and (= id (wasm.api/text-editor-get-active-shape-id))
|
||||
(wasm.api/text-editor-has-selection?))
|
||||
|
||||
text-editor-v2?
|
||||
(dom-text-range-selected? editor-instance)
|
||||
|
||||
:else
|
||||
(draft-text-range-selected? editor-state)))
|
||||
|
||||
fill-values
|
||||
(dwt/current-text-values
|
||||
{:editor-styles editor-styles
|
||||
@ -154,7 +190,14 @@
|
||||
:editor-state editor-state
|
||||
:editor-instance editor-instance
|
||||
:shape shape
|
||||
:attrs txt/text-node-attrs}))]
|
||||
:attrs txt/text-node-attrs}))
|
||||
|
||||
ruby-values
|
||||
(if text-selection-active
|
||||
(select-keys text-values jl/ruby-presentation-attrs)
|
||||
(dwt/current-ruby-values
|
||||
{:shape shape
|
||||
:attrs jl/ruby-presentation-attrs}))]
|
||||
|
||||
[:*
|
||||
[:> layer-menu* {:ids ids
|
||||
@ -202,6 +245,8 @@
|
||||
:type type
|
||||
:applied-tokens applied-tokens
|
||||
:values text-values
|
||||
:ruby-values ruby-values
|
||||
:text-selection-active text-selection-active
|
||||
:libraries libraries
|
||||
:file-id file-id
|
||||
:typographies typographies}]
|
||||
@ -237,4 +282,3 @@
|
||||
:values (select-keys shape exports-attrs)
|
||||
:page-id page-id
|
||||
:file-id file-id}]]))
|
||||
|
||||
|
||||
@ -140,6 +140,7 @@
|
||||
[frontend-tests.ui.sidebar-scroll-test]
|
||||
[frontend-tests.ui.stroke-menu-test]
|
||||
[frontend-tests.ui.text-attrs-multiple-test]
|
||||
[frontend-tests.ui.text-options-test]
|
||||
[frontend-tests.ui.workspace-libraries-test]
|
||||
[frontend-tests.util-clipboard-test]
|
||||
[frontend-tests.util-object-test]
|
||||
@ -302,6 +303,7 @@
|
||||
'frontend-tests.ui.sidebar-scroll-test
|
||||
'frontend-tests.ui.stroke-menu-test
|
||||
'frontend-tests.ui.text-attrs-multiple-test
|
||||
'frontend-tests.ui.text-options-test
|
||||
'frontend-tests.ui.workspace-libraries-test
|
||||
'frontend-tests.util-clipboard-test
|
||||
'frontend-tests.util-object-test
|
||||
|
||||
248
frontend/test/frontend_tests/ui/text_options_test.cljs
Normal file
@ -0,0 +1,248 @@
|
||||
;; 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 Sucursal en España SL
|
||||
|
||||
(ns frontend-tests.ui.text-options-test
|
||||
(:require
|
||||
["react-dom/server" :as rds]
|
||||
[app.common.types.text.japanese-layout :as jl]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.ui.ds.controls.select :as select]
|
||||
[app.main.ui.shapes.text.html-text :as html-text]
|
||||
[app.main.ui.shapes.text.styles :as text-styles]
|
||||
[app.main.ui.workspace.sidebar.options.common :refer [radio-selected]]
|
||||
[app.main.ui.workspace.sidebar.options.menus.text-japanese-layout :as tjl]
|
||||
[app.util.text.writing-mode :as wm]
|
||||
[cljs.test :as t :include-macros true]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private japanese-span-attrs
|
||||
[:text-combine-upright
|
||||
:text-emphasis
|
||||
:ruby
|
||||
:ruby-hidden
|
||||
:ruby-size
|
||||
:ruby-align
|
||||
:ruby-overhang
|
||||
:ruby-side
|
||||
:warichu
|
||||
:font-features
|
||||
:annotation-clearance])
|
||||
|
||||
|
||||
(t/deftest japanese-layout-controls-follow-file-or-profile-configuration
|
||||
(with-redefs [wm/vertical-layout-active? (constantly true)]
|
||||
(t/is (false? (tjl/japanese-layout-config-enabled? {})))
|
||||
(t/is (false? (tjl/japanese-layout-config-enabled? {:file? false :all-files? false})))
|
||||
(t/is (true? (tjl/japanese-layout-config-enabled? {:file? true :all-files? false})))
|
||||
(t/is (true? (tjl/japanese-layout-config-enabled? {:file? false :all-files? true}))))
|
||||
(with-redefs [wm/vertical-layout-active? (constantly false)]
|
||||
(t/is (false? (tjl/japanese-layout-config-enabled? {:file? true :all-files? true})))))
|
||||
|
||||
(t/deftest text-emphasis-select-reports-and-restores-canonical-values
|
||||
(let [options (tjl/text-emphasis-options identity)
|
||||
reported-id (:id (select/get-option options "filled-dot"))]
|
||||
(t/is (= "filled-dot" reported-id))
|
||||
(t/is (= "filled-dot"
|
||||
(:id (select/get-option options reported-id))))))
|
||||
|
||||
(t/deftest annotation-clearance-select-reports-canonical-values
|
||||
(let [options (tjl/annotation-clearance-options identity)]
|
||||
(t/is (= ["none" "auto"] (mapv :id options)))
|
||||
(t/is (= "auto" (:id (select/get-option options "auto"))))))
|
||||
|
||||
(t/deftest unrestricted-tcy-is-only-offered-for-a-text-selection
|
||||
(t/is (= ["none" "digits"]
|
||||
(mapv :value (tjl/text-combine-upright-options false identity))))
|
||||
(t/is (= ["none" "all" "digits"]
|
||||
(mapv :value (tjl/text-combine-upright-options true identity)))))
|
||||
|
||||
(t/deftest ruby-container-styles-preserve-customization
|
||||
(let [style (text-styles/generate-ruby-container-styles
|
||||
{:ruby-align "space-between"
|
||||
:ruby-overhang "none"
|
||||
:ruby-side "under"})]
|
||||
(t/is (= "space-between" (.-rubyAlign style)))
|
||||
(t/is (= "none" (.-rubyOverhang style)))
|
||||
(t/is (= "under" (.-rubyPosition style)))))
|
||||
|
||||
(t/deftest advanced-furigana-options-are-collapsed-by-default
|
||||
(let [markup (rds/renderToStaticMarkup
|
||||
(mf/element tjl/ruby-presentation-options*
|
||||
#js {:values {}
|
||||
:on-change identity
|
||||
:on-blur identity}))]
|
||||
(t/is (str/includes? markup "data-testid=\"ruby-presentation-options-toggle\""))
|
||||
(t/is (str/includes? markup "aria-expanded=\"false\""))
|
||||
(t/is (str/includes? markup "workspace.options.text-options.ruby-advanced-options"))))
|
||||
|
||||
(t/deftest advanced-furigana-options-include-hide-toggle
|
||||
(let [markup (rds/renderToStaticMarkup
|
||||
(mf/element tjl/ruby-hidden-option*
|
||||
#js {:values {:ruby-hidden true}
|
||||
:on-change identity
|
||||
:on-blur identity}))]
|
||||
(t/is (str/includes? markup "workspace.options.text-options.ruby-hidden"))
|
||||
(t/is (str/includes? markup "role=\"switch\""))
|
||||
(t/is (str/includes? markup "aria-checked=\"true\""))))
|
||||
|
||||
(t/deftest hidden-furigana-renders-base-text-without-ruby-layout
|
||||
(let [markup (rds/renderToStaticMarkup
|
||||
(mf/element html-text/render-text*
|
||||
#js {:node {:text "日"
|
||||
:ruby "にち"
|
||||
:ruby-hidden true}
|
||||
:parent {}
|
||||
:shape {}}))]
|
||||
(t/is (str/includes? markup ">日</span>"))
|
||||
(t/is (not (str/includes? markup "<ruby")))))
|
||||
|
||||
(t/deftest shape-level-furigana-presentation-only-updates-ruby-spans
|
||||
(let [shape {:content
|
||||
{:type "root"
|
||||
:children
|
||||
[{:type "paragraph-set"
|
||||
:children
|
||||
[{:type "paragraph"
|
||||
:children
|
||||
[{:text "日"
|
||||
:ruby "にち"
|
||||
:ruby-hidden false
|
||||
:ruby-size "half"}
|
||||
{:text "本"
|
||||
:ruby ""
|
||||
:ruby-hidden false
|
||||
:ruby-size "quarter"}]}]}]}}
|
||||
values (dwt/current-ruby-values {:shape shape
|
||||
:attrs jl/ruby-presentation-attrs})
|
||||
updated (dwt/update-ruby-presentation-attrs
|
||||
shape {:ruby-hidden true :ruby-size "third"})
|
||||
spans (get-in updated [:content :children 0 :children 0 :children])]
|
||||
(t/is (= "half" (:ruby-size values)))
|
||||
(t/is (false? (:ruby-hidden values)))
|
||||
(t/is (= "third" (:ruby-size (first spans))))
|
||||
(t/is (true? (:ruby-hidden (first spans))))
|
||||
(t/is (= "quarter" (:ruby-size (second spans))))
|
||||
(t/is (false? (:ruby-hidden (second spans))))))
|
||||
|
||||
(t/deftest mixed-span-values-select-a-disabled-mixed-option
|
||||
(let [options (tjl/with-mixed-span-option (tjl/text-emphasis-options identity) :multiple)]
|
||||
(t/is (= "mixed" (tjl/span-select-value :multiple "none")))
|
||||
(t/is (= "none" (tjl/span-select-value nil "none")))
|
||||
(t/is (= "mixed" (:id (last options))))
|
||||
(t/is (true? (:disabled (last options))))
|
||||
(t/is (= options (tjl/with-mixed-span-option options "none"))
|
||||
"an unmixed value adds no entry")))
|
||||
|
||||
(t/deftest mixed-radio-values-select-nothing
|
||||
(t/is (= "" (radio-selected :multiple "none")))
|
||||
(t/is (= "none" (radio-selected nil "none")))
|
||||
(t/is (= "vertical-rl" (radio-selected :vertical-rl))))
|
||||
|
||||
(t/deftest whole-text-selection-reports-every-differing-span-value-as-mixed
|
||||
(let [shape {:content
|
||||
{:type "root"
|
||||
:children
|
||||
[{:type "paragraph-set"
|
||||
:children
|
||||
[{:type "paragraph"
|
||||
:children
|
||||
[{:text "日"
|
||||
:text-combine-upright "digits2"
|
||||
:text-emphasis "filled-dot"
|
||||
:ruby "にち"
|
||||
:ruby-hidden true
|
||||
:ruby-size "third"
|
||||
:ruby-align "center"
|
||||
:ruby-overhang "none"
|
||||
:ruby-side "under"
|
||||
:warichu "warichu"
|
||||
:font-features "palt"
|
||||
:annotation-clearance "auto"}
|
||||
{:text "本"
|
||||
:text-combine-upright "none"
|
||||
:text-emphasis "none"
|
||||
:ruby ""
|
||||
:ruby-hidden false
|
||||
:ruby-size "half"
|
||||
:ruby-align "space-around"
|
||||
:ruby-overhang "auto"
|
||||
:ruby-side "over"
|
||||
:warichu "none"
|
||||
:font-features "none"
|
||||
:annotation-clearance "none"}]}]}]}}
|
||||
values (dwt/current-text-values {:shape shape
|
||||
:attrs japanese-span-attrs})]
|
||||
(t/is (= (zipmap japanese-span-attrs (repeat :multiple)) values))))
|
||||
|
||||
(t/deftest wasm-editor-span-styles-preserve-persisted-vertical-paragraph-values
|
||||
(let [shape {:content
|
||||
{:type "root"
|
||||
:children
|
||||
[{:type "paragraph-set"
|
||||
:children
|
||||
[{:type "paragraph"
|
||||
:writing-mode "vertical-rl"
|
||||
:text-orientation "upright"
|
||||
:children [{:text "12" :text-combine-upright "none"}]}]}]}}
|
||||
editor-styles {:text-combine-upright "digits2"}
|
||||
paragraph-values (dwt/current-paragraph-values
|
||||
{:editor-styles editor-styles
|
||||
:shape shape
|
||||
:attrs [:writing-mode :text-orientation]})
|
||||
text-values (dwt/current-text-values
|
||||
{:editor-styles editor-styles
|
||||
:shape shape
|
||||
:attrs [:text-combine-upright]})]
|
||||
(t/is (= "vertical-rl" (:writing-mode paragraph-values)))
|
||||
(t/is (= "upright" (:text-orientation paragraph-values)))
|
||||
(t/is (= "digits2" (:text-combine-upright text-values)))))
|
||||
|
||||
(t/deftest japanese-controls-distinguish-horizontal-and-vertical-modes
|
||||
(t/is (false? (tjl/vertical-japanese-layout? {})))
|
||||
(t/is (false? (tjl/vertical-japanese-layout?
|
||||
{:writing-mode "horizontal-tb"})))
|
||||
(t/is (true? (tjl/vertical-japanese-layout?
|
||||
{:writing-mode "vertical-rl"})))
|
||||
(t/is (= "palt"
|
||||
(tjl/proportional-metrics-feature "horizontal-tb")))
|
||||
(t/is (= "palt"
|
||||
(tjl/proportional-metrics-feature nil)))
|
||||
(t/is (= "vpal"
|
||||
(tjl/proportional-metrics-feature "vertical-rl"))))
|
||||
|
||||
(t/deftest sidebar-options-offer-the-japanese-enum-values
|
||||
(let [ids #(mapv :id %)
|
||||
values #(mapv :value %)]
|
||||
(t/is (= (:writing-mode jl/enum-values) (values (tjl/writing-mode-options identity))))
|
||||
(t/is (= (:text-orientation jl/enum-values) (values (tjl/text-orientation-options identity))))
|
||||
(t/is (= (:warichu jl/enum-values) (values (tjl/warichu-options identity))))
|
||||
(t/is (= (:text-emphasis jl/enum-values) (ids (tjl/text-emphasis-options identity))))
|
||||
(t/is (= (:annotation-clearance jl/enum-values) (ids (tjl/annotation-clearance-options identity))))
|
||||
(t/is (= (:ruby-size jl/enum-values) (ids (tjl/ruby-size-options identity))))
|
||||
(t/is (= (:ruby-align jl/enum-values) (ids (tjl/ruby-align-options identity))))
|
||||
(t/is (= (:ruby-overhang jl/enum-values) (ids (tjl/ruby-overhang-options identity))))
|
||||
(t/is (= (:ruby-side jl/enum-values) (ids (tjl/ruby-side-options identity))))
|
||||
(t/is (= (:line-adjustment jl/enum-values) (ids (tjl/line-adjustment-options identity))))
|
||||
(t/is (every? #(jl/valid-enum-value? :text-combine-upright %)
|
||||
(values (tjl/text-combine-upright-options true identity))))
|
||||
(t/is (every? jl/digit-combine? (ids (tjl/text-combine-upright-count-options identity))))))
|
||||
|
||||
(t/deftest html-text-drops-vertical-writing-under-a-horizontal-renderer
|
||||
(let [shape {:id (random-uuid) :width 100 :height 100
|
||||
:content {:type "root"
|
||||
:children
|
||||
[{:type "paragraph-set"
|
||||
:children
|
||||
[{:type "paragraph"
|
||||
:writing-mode "vertical-rl"
|
||||
:text-orientation "upright"
|
||||
:children [{:text "縦"}]}]}]}}
|
||||
markup #(rds/renderToStaticMarkup (mf/element html-text/text-shape* #js {:shape shape}))]
|
||||
(with-redefs [wm/vertical-layout-active? (constantly false)]
|
||||
(t/is (not (str/includes? (markup) "vertical-rl"))))
|
||||
(with-redefs [wm/vertical-layout-active? (constantly true)]
|
||||
(t/is (str/includes? (markup) "writing-mode:vertical-rl")))))
|
||||
@ -783,6 +783,18 @@ msgstr "Invite people"
|
||||
msgid "dashboard.invite-profile-disabled"
|
||||
msgstr "You don't have permission to invite people to this team"
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs
|
||||
msgid "dashboard.japanese-layout.description"
|
||||
msgstr "Makes Japanese text layout controls available in every file."
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs
|
||||
msgid "dashboard.japanese-layout.enable-all-files"
|
||||
msgstr "Enable Japanese text layout for all files"
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs
|
||||
msgid "dashboard.japanese-layout.title"
|
||||
msgstr "Japanese text layout"
|
||||
|
||||
#: src/app/main/ui/dashboard/organization_team_switch_menus.cljs:235, src/app/main/ui/dashboard/organization_team_switch_menus.cljs:266
|
||||
msgid "dashboard.leave-organization"
|
||||
msgstr "Leave org"
|
||||
@ -6468,6 +6480,10 @@ msgstr "Radial gradient"
|
||||
msgid "workspace.header.menu.disable-dynamic-alignment"
|
||||
msgstr "Disable dynamic alignment"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs
|
||||
msgid "workspace.header.menu.disable-japanese-layout"
|
||||
msgstr "Disable Japanese text layout"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:254
|
||||
msgid "workspace.header.menu.disable-scale-content"
|
||||
msgstr "Disable proportional scale"
|
||||
@ -6492,6 +6508,10 @@ msgstr "Disable WebGL rendering (beta)"
|
||||
msgid "workspace.header.menu.enable-dynamic-alignment"
|
||||
msgstr "Enable dynamic alignment"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs
|
||||
msgid "workspace.header.menu.enable-japanese-layout"
|
||||
msgstr "Enable Japanese text layout"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:255
|
||||
msgid "workspace.header.menu.enable-scale-content"
|
||||
msgstr "Enable proportional scale"
|
||||
@ -8036,6 +8056,34 @@ msgstr "Align middle"
|
||||
msgid "workspace.options.text-options.align-top"
|
||||
msgstr "Align top"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.annotation-clearance"
|
||||
msgstr "Ann. clearance"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.annotation-clearance-auto"
|
||||
msgstr "Automatic"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment"
|
||||
msgstr "Line adjustment"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment-push-in-first"
|
||||
msgstr "Push in first"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment-push-out-first"
|
||||
msgstr "Push out first"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment-push-out-only"
|
||||
msgstr "Push out only"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.annotation-clearance-none"
|
||||
msgstr "Use line height"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:100
|
||||
msgid "workspace.options.text-options.direction-ltr"
|
||||
msgstr "LTR"
|
||||
@ -8044,6 +8092,22 @@ msgstr "LTR"
|
||||
msgid "workspace.options.text-options.direction-rtl"
|
||||
msgstr "RTL"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features"
|
||||
msgstr "Prop. metrics"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features-none"
|
||||
msgstr "None"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features-palt"
|
||||
msgstr "Horizontal (palt)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features-vpal"
|
||||
msgstr "Vertical (vpal)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:167
|
||||
msgid "workspace.options.text-options.grow-auto-height"
|
||||
msgstr "Auto height"
|
||||
@ -8056,6 +8120,10 @@ msgstr "Auto width"
|
||||
msgid "workspace.options.text-options.grow-fixed"
|
||||
msgstr "Fixed"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.japanese-layout"
|
||||
msgstr "Japanese text layout"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:688
|
||||
msgid "workspace.options.text-options.letter-spacing"
|
||||
msgstr "Letter Spacing"
|
||||
@ -8064,6 +8132,82 @@ msgstr "Letter Spacing"
|
||||
msgid "workspace.options.text-options.line-height"
|
||||
msgstr "Line height"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby"
|
||||
msgstr "Ruby"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-advanced-options"
|
||||
msgstr "Advanced furigana options"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align"
|
||||
msgstr "Ruby alignment"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-center"
|
||||
msgstr "Center"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-space-around"
|
||||
msgstr "Space around"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-space-between"
|
||||
msgstr "Space between"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-start"
|
||||
msgstr "Start"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.ruby-hidden"
|
||||
msgstr "Hide furigana"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-overhang"
|
||||
msgstr "Ruby overhang"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-overhang-auto"
|
||||
msgstr "Auto"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-overhang-none"
|
||||
msgstr "None"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-placeholder"
|
||||
msgstr "Furigana"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-side"
|
||||
msgstr "Ruby side"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-side-over"
|
||||
msgstr "Over / right"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-side-under"
|
||||
msgstr "Under / left"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size"
|
||||
msgstr "Ruby size"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size-half"
|
||||
msgstr "Half"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size-quarter"
|
||||
msgstr "Quarter"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size-third"
|
||||
msgstr "Third"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:212
|
||||
msgid "workspace.options.text-options.strikethrough"
|
||||
msgstr "Strikethrough (%s)"
|
||||
@ -8084,6 +8228,74 @@ msgstr "Align left"
|
||||
msgid "workspace.options.text-options.text-align-right"
|
||||
msgstr "Align right"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-all"
|
||||
msgstr "Tate-chu-yoko"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits"
|
||||
msgstr "Digits"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-2"
|
||||
msgstr "Up to 2 digits"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-3"
|
||||
msgstr "Up to 3 digits"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-4"
|
||||
msgstr "Up to 4 digits"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-count"
|
||||
msgstr "Digit count"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-none"
|
||||
msgstr "Normal"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis"
|
||||
msgstr "Emphasis marks"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-filled-circle"
|
||||
msgstr "Filled circle"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-filled-dot"
|
||||
msgstr "Filled dot"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-filled-sesame"
|
||||
msgstr "Filled sesame"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-none"
|
||||
msgstr "None"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-open-circle"
|
||||
msgstr "Open circle"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-open-dot"
|
||||
msgstr "Open dot"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-open-sesame"
|
||||
msgstr "Open sesame"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-orientation-mixed"
|
||||
msgstr "Mixed"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-orientation-upright"
|
||||
msgstr "Upright"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:509
|
||||
msgid "workspace.options.text-options.text-section"
|
||||
msgstr "Text section"
|
||||
@ -8104,6 +8316,22 @@ msgstr "Selection text"
|
||||
msgid "workspace.options.text-options.underline"
|
||||
msgstr "Underline (%s)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.warichu"
|
||||
msgstr "Warichu"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.warichu-none"
|
||||
msgstr "Normal"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.writing-mode-horizontal"
|
||||
msgstr "Horizontal"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.writing-mode-vertical"
|
||||
msgstr "Vertical (right to left)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:788
|
||||
msgid "workspace.options.use-play-button"
|
||||
msgstr "Use the play button at the header to run the prototype view."
|
||||
|
||||
@ -777,6 +777,18 @@ msgstr "メンバーを招待"
|
||||
msgid "dashboard.invite-profile-disabled"
|
||||
msgstr "このチームにユーザーを招待する権限がありません"
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs
|
||||
msgid "dashboard.japanese-layout.description"
|
||||
msgstr "すべてのファイルで日本語組版コントロールを利用できるようにします。"
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs
|
||||
msgid "dashboard.japanese-layout.enable-all-files"
|
||||
msgstr "すべてのファイルで日本語組版を有効にする"
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs
|
||||
msgid "dashboard.japanese-layout.title"
|
||||
msgstr "日本語組版"
|
||||
|
||||
#: src/app/main/ui/dashboard/organization_team_switch_menus.cljs:235, src/app/main/ui/dashboard/organization_team_switch_menus.cljs:266
|
||||
msgid "dashboard.leave-organization"
|
||||
msgstr "組織から退出"
|
||||
@ -6168,6 +6180,10 @@ msgstr "放射状グラデーション"
|
||||
msgid "workspace.header.menu.disable-dynamic-alignment"
|
||||
msgstr "動的整列を無効化"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs
|
||||
msgid "workspace.header.menu.disable-japanese-layout"
|
||||
msgstr "日本語組版を無効にする"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:254
|
||||
msgid "workspace.header.menu.disable-scale-content"
|
||||
msgstr "比率を保った拡大縮小を無効化"
|
||||
@ -6192,6 +6208,10 @@ msgstr "WebGL レンダリングを無効化(ベータ)"
|
||||
msgid "workspace.header.menu.enable-dynamic-alignment"
|
||||
msgstr "動的整列を有効化"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs
|
||||
msgid "workspace.header.menu.enable-japanese-layout"
|
||||
msgstr "日本語組版を有効にする"
|
||||
|
||||
#: src/app/main/ui/workspace/main_menu.cljs:255
|
||||
msgid "workspace.header.menu.enable-scale-content"
|
||||
msgstr "比率を保った拡大縮小を有効化"
|
||||
@ -7688,6 +7708,34 @@ msgstr "上下中央揃え"
|
||||
msgid "workspace.options.text-options.align-top"
|
||||
msgstr "上揃え"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.annotation-clearance"
|
||||
msgstr "注釈の間隔"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.annotation-clearance-auto"
|
||||
msgstr "自動"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment"
|
||||
msgstr "禁則調整方式"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment-push-in-first"
|
||||
msgstr "追い込み優先"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment-push-out-first"
|
||||
msgstr "追い出し優先"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.line-adjustment-push-out-only"
|
||||
msgstr "追い出しのみ"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.annotation-clearance-none"
|
||||
msgstr "行送りを使用"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:100
|
||||
msgid "workspace.options.text-options.direction-ltr"
|
||||
msgstr "LTR"
|
||||
@ -7696,6 +7744,22 @@ msgstr "LTR"
|
||||
msgid "workspace.options.text-options.direction-rtl"
|
||||
msgstr "RTL"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features"
|
||||
msgstr "プロポーショナルメトリクス"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features-none"
|
||||
msgstr "なし"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features-palt"
|
||||
msgstr "横組み(palt)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.font-features-vpal"
|
||||
msgstr "縦組み(vpal)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:167
|
||||
msgid "workspace.options.text-options.grow-auto-height"
|
||||
msgstr "高さの自動調整"
|
||||
@ -7708,6 +7772,10 @@ msgstr "幅の自動調整"
|
||||
msgid "workspace.options.text-options.grow-fixed"
|
||||
msgstr "固定"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.japanese-layout"
|
||||
msgstr "日本語組版"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:688
|
||||
msgid "workspace.options.text-options.letter-spacing"
|
||||
msgstr "文字間隔"
|
||||
@ -7716,6 +7784,82 @@ msgstr "文字間隔"
|
||||
msgid "workspace.options.text-options.line-height"
|
||||
msgstr "行の高さ"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby"
|
||||
msgstr "ルビ"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-advanced-options"
|
||||
msgstr "ふりがなの詳細設定"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align"
|
||||
msgstr "ルビの配置"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-center"
|
||||
msgstr "中央"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-space-around"
|
||||
msgstr "均等割り"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-space-between"
|
||||
msgstr "両端揃え"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-align-start"
|
||||
msgstr "先頭"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text_japanese_layout.cljs
|
||||
msgid "workspace.options.text-options.ruby-hidden"
|
||||
msgstr "ふりがなを非表示"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-overhang"
|
||||
msgstr "ルビのはみ出し"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-overhang-auto"
|
||||
msgstr "自動"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-overhang-none"
|
||||
msgstr "なし"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-placeholder"
|
||||
msgstr "ふりがな"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-side"
|
||||
msgstr "ルビの側"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-side-over"
|
||||
msgstr "上/右"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-side-under"
|
||||
msgstr "下/左"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size"
|
||||
msgstr "ルビの大きさ"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size-half"
|
||||
msgstr "二分"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size-quarter"
|
||||
msgstr "四分"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.ruby-size-third"
|
||||
msgstr "三分"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:212
|
||||
msgid "workspace.options.text-options.strikethrough"
|
||||
msgstr "取り消し線(%s)"
|
||||
@ -7736,6 +7880,74 @@ msgstr "左揃え"
|
||||
msgid "workspace.options.text-options.text-align-right"
|
||||
msgstr "右揃え"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-all"
|
||||
msgstr "縦中横"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits"
|
||||
msgstr "数字のみ"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-2"
|
||||
msgstr "2桁まで"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-3"
|
||||
msgstr "3桁まで"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-4"
|
||||
msgstr "4桁まで"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-digits-count"
|
||||
msgstr "桁数"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-combine-upright-none"
|
||||
msgstr "通常"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis"
|
||||
msgstr "圏点"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-filled-circle"
|
||||
msgstr "黒丸(大)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-filled-dot"
|
||||
msgstr "黒丸"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-filled-sesame"
|
||||
msgstr "ゴマ点(黒)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-none"
|
||||
msgstr "なし"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-open-circle"
|
||||
msgstr "白丸(大)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-open-dot"
|
||||
msgstr "白丸"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-emphasis-open-sesame"
|
||||
msgstr "ゴマ点(白)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-orientation-mixed"
|
||||
msgstr "混在"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.text-orientation-upright"
|
||||
msgstr "正立"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs:509
|
||||
msgid "workspace.options.text-options.text-section"
|
||||
msgstr "テキストセクション"
|
||||
@ -7756,6 +7968,22 @@ msgstr "選択範囲のテキスト"
|
||||
msgid "workspace.options.text-options.underline"
|
||||
msgstr "下線(%s)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.warichu"
|
||||
msgstr "割注"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.warichu-none"
|
||||
msgstr "通常"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.writing-mode-horizontal"
|
||||
msgstr "横書き"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/text.cljs
|
||||
msgid "workspace.options.text-options.writing-mode-vertical"
|
||||
msgstr "縦書き(右から左)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs:788
|
||||
msgid "workspace.options.use-play-button"
|
||||
msgstr "ヘッダーの再生ボタンを使ってプロトタイプを表示してください。"
|
||||
|
||||