This commit is contained in:
Alejandro Alonso
2025-07-18 08:03:50 +02:00
parent 2e3cdd872c
commit f3f3190881
9 changed files with 203 additions and 86 deletions

View File

@@ -1243,6 +1243,24 @@
(update [_ state]
(reduce #(update %1 :workspace-preview-blend dissoc %2) state ids))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Preview fonts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn set-preview-font
[ids font-data]
(ptk/reify ::set-preview-font
ptk/UpdateEvent
(update [_ state]
(reduce #(assoc-in %1 [:workspace-preview-font %2] font-data) state ids))))
(defn unset-preview-font
[ids]
(ptk/reify ::unset-preview-font
ptk/UpdateEvent
(update [_ state]
(reduce #(update %1 :workspace-preview-font dissoc %2) state ids))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Components
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1386,3 +1404,9 @@
(dm/export dwpg/duplicate-page)
(dm/export dwpg/rename-page)
(dm/export dwpg/delete-page)
;; Preview
;; (dm/export set-preview-blend-mode)
;; (dm/export unset-preview-blend-mode)
;; (dm/export set-preview-font)
;; (dm/export unset-preview-font)

View File

@@ -634,6 +634,12 @@
(defn workspace-preview-blend-by-id [id]
(l/derived (l/key id) workspace-preview-blend =))
(def workspace-preview-font
(l/derived :workspace-preview-font st/state))
(defn workspace-preview-font-by-id [id]
(l/derived (l/key id) workspace-preview-font =))
(def specialized-panel
(l/derived :specialized-panel st/state))

View File

@@ -22,9 +22,10 @@
parent (obj/get props "parent")
shape (obj/get props "shape")
text (:text node)
shape-id (:id shape)
style (if (= text "")
(sts/generate-text-styles shape parent)
(sts/generate-text-styles shape node))]
(sts/generate-text-styles shape-id parent)
(sts/generate-text-styles shape-id node))]
[:span.text-node {:style style}
(if (= text "") "\u00A0" text)]))

View File

@@ -13,6 +13,12 @@
[app.util.object :as obj]
[rumext.v2 :as mf]))
(defn generate-styles
[shape parent node]
(let [shape-id (:id shape)]
{:parent (sts/generate-text-styles shape-id parent)
:node (sts/generate-text-styles shape-id node)}))
(mf/defc render-text
{::mf/wrap-props false}
[props]

View File

@@ -14,7 +14,9 @@
[app.main.ui.formats :as fmt]
[app.util.color :as uc]
[app.util.object :as obj]
[cuerdas.core :as str]))
[cuerdas.core :as str]
[app.main.refs :as refs]
[rumext.v2 :as mf]))
(defn generate-root-styles
([props node]
@@ -66,88 +68,104 @@
(some? text-align) (obj/set! "textAlign" text-align))))
(defn generate-text-styles
([shape data]
(generate-text-styles shape data nil))
([{:keys [grow-type] :as shape} data {:keys [show-text?] :or {show-text? true}}]
([shape-id data show-text? grow-type preview-font]
(let [letter-spacing (:letter-spacing data 0)
text-decoration (:text-decoration data)
text-transform (:text-transform data)
text-decoration (:text-decoration data)
text-transform (:text-transform data)
font-id (or (:font-id data)
(:font-id txt/default-text-attrs))
font-id (or (:font-id data)
(:font-id txt/default-text-attrs))
font-variant-id (:font-variant-id data)
font-variant-id (:font-variant-id data)
font-size (:font-size data)
font-size (:font-size data)
fill-color (or (-> data :fills first :fill-color) (:fill-color data))
fill-opacity (or (-> data :fills first :fill-opacity) (:fill-opacity data))
fill-gradient (or (-> data :fills first :fill-color-gradient) (:fill-color-gradient data))
fill-color (or (-> data :fills first :fill-color) (:fill-color data))
fill-opacity (or (-> data :fills first :fill-opacity) (:fill-opacity data))
fill-gradient (or (-> data :fills first :fill-color-gradient) (:fill-color-gradient data))
[r g b a] (cc/hex->rgba fill-color fill-opacity)
text-color (when (and (some? fill-color) (some? fill-opacity))
(str/format "rgba(%s, %s, %s, %s)" r g b a))
[r g b a] (cc/hex->rgba fill-color fill-opacity)
text-color (when (and (some? fill-color) (some? fill-opacity))
(str/format "rgba(%s, %s, %s, %s)" r g b a))
gradient? (some? fill-gradient)
gradient? (some? fill-gradient)
text-color (if gradient?
(uc/color->background {:gradient fill-gradient})
text-color)
text-color (if gradient?
(uc/color->background {:gradient fill-gradient})
text-color)
fontsdb (deref fonts/fontsdb)
fontsdb (deref fonts/fontsdb)
base #js {:textDecoration text-decoration
:textTransform text-transform
:fontSize font-size
:color (if (and show-text? (not gradient?)) text-color "transparent")
:background (when (and show-text? gradient?) text-color)
:caretColor (if (and (not gradient?) text-color) text-color "black")
:overflowWrap "initial"
:lineBreak "auto"
:whiteSpace "break-spaces"
:textRendering "geometricPrecision"}
fills
(cond
;; DEPRECATED: still here for backward compatibility with
;; old penpot files that still has a single color.
(or (some? (:fill-color data))
(some? (:fill-opacity data))
(some? (:fill-color-gradient data)))
[(d/without-nils (select-keys data [:fill-color :fill-opacity :fill-color-gradient
:fill-color-ref-id :fill-color-ref-file]))]
_ (js/console.log "Preview font for" shape-id ":" preview-font)
(nil? (:fills data))
[{:fill-color "#000000" :fill-opacity 1}]
base #js {:textDecoration text-decoration
:textTransform text-transform
:fontSize font-size
:color (if (and show-text? (not gradient?)) text-color "transparent")
:background (when (and show-text? gradient?) text-color)
:caretColor (if (and (not gradient?) text-color) text-color "black")
:overflowWrap "initial"
:lineBreak "auto"
:whiteSpace "break-spaces"
:textRendering "geometricPrecision"}
fills
(cond
;; DEPRECATED: still here for backward compatibility with
;; old penpot files that still has a single color.
(or (some? (:fill-color data))
(some? (:fill-opacity data))
(some? (:fill-color-gradient data)))
[(d/without-nils (select-keys data [:fill-color :fill-opacity :fill-color-gradient
:fill-color-ref-id :fill-color-ref-file]))]
:else
(:fills data))
(nil? (:fills data))
[{:fill-color "#000000" :fill-opacity 1}]
font (some->> font-id (get fontsdb))
:else
(:fills data))
[font-family font-style font-weight]
(when (some? font)
(let [font-variant (d/seek #(= font-variant-id (:id %)) (:variants font))]
[(str/quote (or (:family font) (:font-family data)))
(or (:style font-variant) (:font-style data))
(or (:weight font-variant) (:font-weight data))]))
font (some->> font-id (get fontsdb))
base (obj/set! base "--font-id" font-id)]
[font-family font-style font-weight]
(if (some? preview-font)
;; Use preview font data
[(str/quote (:font-family preview-font))
(:font-style preview-font)
(:font-weight preview-font)]
;; Use regular font data
(when (some? font)
(let [font-variant (d/seek #(= font-variant-id (:id %)) (:variants font))]
[(str/quote (or (:family font) (:font-family data)))
(or (:style font-variant) (:font-style data))
(or (:weight font-variant) (:font-weight data))])))
(cond-> base
(some? fills)
(obj/set! "--fills" (transit/encode-str fills))
base (obj/set! base "--font-id" font-id)]
(and (string? letter-spacing) (pos? (alength letter-spacing)))
(obj/set! "letterSpacing" (str letter-spacing "px"))
(cond-> base
(some? fills)
(obj/set! "--fills" (transit/encode-str fills))
(and (string? font-size) (pos? (alength font-size)))
(obj/set! "fontSize" (str font-size "px"))
(and (string? letter-spacing) (pos? (alength letter-spacing)))
(obj/set! "letterSpacing" (str letter-spacing "px"))
(some? font)
(-> (obj/set! "fontFamily" font-family)
(obj/set! "fontStyle" font-style)
(obj/set! "fontWeight" font-weight))
(and (string? font-size) (pos? (alength font-size)))
(obj/set! "fontSize" (str font-size "px"))
(= grow-type :auto-width)
(obj/set! "whiteSpace" "pre")))))
(some? font)
(-> (obj/set! "fontFamily" font-family)
(obj/set! "fontStyle" font-style)
(obj/set! "fontWeight" font-weight))
(= grow-type :auto-width)
(obj/set! "whiteSpace" "pre"))))
;; Backward compatibility
([shape data]
(let [shape-id (:id shape)
preview-font (mf/deref (refs/workspace-preview-font-by-id shape-id))]
(generate-text-styles shape-id data true nil preview-font)))
([shape data {:keys [show-text?] :or {show-text? true}}]
(let [shape-id (:id shape)
preview-font (mf/deref (refs/workspace-preview-font-by-id shape-id))]
(generate-text-styles shape-id data show-text? nil preview-font))))

View File

@@ -16,7 +16,8 @@
[app.main.ui.shapes.fills :as fills]
[app.main.ui.shapes.gradients :as grad]
[app.util.object :as obj]
[rumext.v2 :as mf]))
[rumext.v2 :as mf]
[app.main.refs :as refs]))
(def fill-attrs [:fill-color :fill-color-gradient :fill-opacity])
@@ -42,6 +43,8 @@
{:keys [x y width height position-data]} shape
preview-font (mf/deref (app.main.refs/workspace-preview-font-by-id (:id shape)))
transform (gsh/transform-str shape)
;; These position attributes are not really necessary but they are convenient for for the export
@@ -73,6 +76,14 @@
(for [[index data] (d/enumerate position-data)]
(let [rtl? (= "rtl" (:direction data))
;; --- PREVIEW FONT OVERRIDE ---
data (if preview-font
(merge data
{:font-family (:font-family preview-font)
:font-weight (:font-weight preview-font)
:font-style (:font-style preview-font)})
data)
browser-props
(cond
(cf/check-browser? :safari)

View File

@@ -66,7 +66,7 @@
(.toJS)
(js->clj :keywordize-keys true))
(txt/styles-to-attrs styles))]
(sts/generate-text-styles shape data {:show-text? false})))
(sts/generate-text-styles (:id shape) data {:show-text? false})))
(def default-decorator
(ted/create-decorator "PENPOT_SELECTION" selection-component))

View File

@@ -16,6 +16,7 @@
[app.main.data.common :as dcm]
[app.main.data.fonts :as fts]
[app.main.data.shortcuts :as dsc]
[app.main.data.workspace :as dw]
[app.main.features :as features]
[app.main.fonts :as fonts]
[app.main.refs :as refs]
@@ -60,9 +61,17 @@
(mf/defc font-item*
{::mf/wrap [mf/memo]}
[{:keys [font is-current on-click style]}]
[{:keys [font is-current on-click style on-hover on-leave]}]
(let [item-ref (mf/use-ref)
on-click (mf/use-fn (mf/deps font) #(on-click font))]
on-click (mf/use-fn (mf/deps font) #(on-click font))
on-mouse-enter (mf/use-fn (mf/deps font on-hover)
(fn []
(js/console.log "Mouse enter on font" (:name font))
(when on-hover (on-hover font))))
on-mouse-leave (mf/use-fn (mf/deps on-leave)
(fn []
(js/console.log "Mouse leave on font")
(when on-leave (on-leave))))]
(mf/use-effect
(mf/deps is-current)
@@ -75,7 +84,9 @@
[:div {:class (stl/css :font-wrapper)
:style style
:ref item-ref
:on-click on-click}
:on-click on-click
:on-mouse-enter on-mouse-enter
:on-mouse-leave on-mouse-leave}
[:div {:class (stl/css-case :font-item true
:selected is-current)}
[:span {:class (stl/css :label)} (:name font)]
@@ -95,7 +106,7 @@
(into [] xform fonts)))
(mf/defc font-selector*
[{:keys [on-select on-close current-font show-recent full-size]}]
[{:keys [on-select on-close current-font show-recent full-size ids]}]
(let [selected (mf/use-state current-font)
state* (mf/use-state
#(do {:term "" :backends #{}}))
@@ -112,9 +123,14 @@
recent-fonts (mf/with-memo [state recent-fonts]
(filter-fonts state recent-fonts))
full-size? (boolean (and full-size show-recent))
;; --- NEW: auto-select first font on search ---
_auto-select-first
(mf/with-effect [(:term state) fonts]
(when (and (seq fonts) (not (str/blank? (:term state))))
(reset! selected (first fonts))))
select-next
(mf/use-fn
(mf/deps fonts)
@@ -133,13 +149,13 @@
on-key-down
(mf/use-fn
(mf/deps fonts)
(mf/deps fonts selected)
(fn [event]
(cond
(kbd/up-arrow? event) (select-prev event)
(kbd/down-arrow? event) (select-next event)
(kbd/esc? event) (on-close)
(kbd/enter? event) (on-close)
(kbd/enter? event) (do (on-select @selected) (on-close))
:else (dom/focus! (mf/ref-val input)))))
on-filter-change
@@ -152,7 +168,36 @@
(mf/deps on-select on-close)
(fn [font]
(on-select font)
(on-close)))]
(on-close)))
;; Preview font handlers
on-font-hover
(mf/use-fn
(mf/deps ids)
(fn [font]
(js/console.log "Font hover triggered" font ids)
(when (and ids (seq ids))
(let [{:keys [family] :as font-data} font
{:keys [id name weight style]} (fonts/get-default-variant font)]
(js/console.log "Setting preview font" {:font-id (:id font)
:font-family family
:font-variant-id (or id name)
:font-weight weight
:font-style style})
(st/emit! (dw/set-preview-font ids {:font-id (:id font)
:font-family family
:font-variant-id (or id name)
:font-weight weight
:font-style style}))))))
on-font-leave
(mf/use-fn
(mf/deps ids)
(fn [_]
(js/console.log "Font leave triggered" ids)
(when (and ids (seq ids))
(js/console.log "Unsetting preview font")
(st/emit! (dw/unset-preview-font ids)))))]
(mf/with-effect [fonts]
(let [key (events/listen js/document "keydown" on-key-down)]
@@ -163,8 +208,9 @@
(when-let [index (:index @selected)]
(.scrollToRow ^js inst index))))
(mf/with-effect [@selected]
(on-select @selected))
;; Removed the effect that was calling on-select automatically
;; (mf/with-effect [@selected]
;; (on-select @selected))
(mf/with-effect []
(st/emit! (dsc/push-shortcuts :typography {}))
@@ -193,6 +239,8 @@
:font font
:style {}
:on-click on-select-and-close
:on-hover on-font-hover
:on-leave on-font-leave
:is-current (= (:id font) (:id @selected))}])])]
[:div {:class (stl/css-case :fonts-list true
@@ -201,7 +249,7 @@
(fn [props]
(let [width (unchecked-get props "width")
height (unchecked-get props "height")
render #(row-renderer fonts @selected on-select-and-close %)]
render #(row-renderer fonts @selected on-select-and-close on-font-hover on-font-leave %)]
(mf/html
[:> rvt/List #js {:height height
:ref flist
@@ -211,7 +259,7 @@
:rowRenderer render}])))]]]]))
(defn row-renderer
[fonts selected on-select props]
[fonts selected on-select on-hover on-leave props]
(let [index (unchecked-get props "index")
key (unchecked-get props "key")
style (unchecked-get props "style")
@@ -221,11 +269,13 @@
:font font
:style style
:on-click on-select
:on-hover on-hover
:on-leave on-leave
:is-current (= (:id font) (:id selected))}])))
(mf/defc font-options
{::mf/wrap-props false}
[{:keys [values on-change on-blur show-recent full-size-selector]}]
[{:keys [values on-change on-blur show-recent full-size-selector ids]}]
(let [{:keys [font-id font-size font-variant-id]} values
font-id (or font-id (:font-id txt/default-text-attrs))
@@ -297,7 +347,8 @@
:on-close on-font-selector-close
:on-select on-font-select
:full-size full-size-selector
:show-recent show-recent}])
:show-recent show-recent
:ids ids}])
[:div {:class (stl/css :font-option)
:title (tr "inspect.attributes.typography.font-family")

View File

@@ -220,7 +220,7 @@ body {
(:paragraph "paragraph")
(sts/generate-paragraph-styles shape node)
(sts/generate-text-styles shape node))]
(sts/generate-text-styles (:id shape) node))]
(dm/fmt
".% {\n%\n}"
(dm/str shape-selector " ." (:$id node))