0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-11 23:31:21 -05:00

Thumbnails for clipped and nested artboards

This commit is contained in:
alonso.torres 2022-06-08 17:50:40 +02:00
parent 0bb0063be4
commit a4cc57886b
8 changed files with 119 additions and 53 deletions

View file

@ -14,6 +14,8 @@
[app.common.uuid :as uuid]
[cuerdas.core :as str]))
(declare reduce-objects)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GENERIC SHAPE SELECTORS AND PREDICATES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -187,12 +189,21 @@
function of `get-immediate-children` for performance reasons. This
function is executed in the render hot path."
[objects]
(let [lookup (d/getf objects)
xform (comp (keep lookup)
(filter frame-shape?)
(map :id))]
(->> (:shapes (lookup uuid/zero))
(into [] xform))))
(let [add-frame
(fn [result shape]
(cond-> result
(frame-shape? shape)
(conj (:id shape))))]
(reduce-objects objects (complement frame-shape?) add-frame [])))
(defn get-root-shapes-ids
[objects]
(let [add-shape
(fn [result shape]
(cond-> result
(not (frame-shape? shape))
(conj (:id shape))))]
(reduce-objects objects (complement frame-shape?) add-shape [])))
(defn get-root-frames
"Retrieves all frame objects as vector. It is not implemented in
@ -631,3 +642,28 @@
[objects parent-id candidate-child-id]
(let [parents (get-parents-seq objects candidate-child-id)]
(some? (d/seek #(= % parent-id) parents))))
(defn reduce-objects
([objects reducer-fn init-val]
(reduce-objects objects nil reducer-fn init-val))
([objects check-children? reducer-fn init-val]
(let [root-children (get-in objects [uuid/zero :shapes])]
(if (empty? root-children)
init-val
(loop [current-val init-val
current-id (first root-children)
pending-ids (rest root-children)]
(let [current-shape (get objects current-id)
next-val (reducer-fn current-val current-shape)
next-pending-ids
(if (or (nil? check-children?) (check-children? current-shape))
(concat (or (:shapes current-shape) []) pending-ids)
pending-ids)]
(if (empty? next-pending-ids)
next-val
(recur next-val (first next-pending-ids) (rest next-pending-ids)))))))))

View file

@ -270,6 +270,14 @@
(into [] (keep (d/getf objects)) children-ids)))
workspace-page-objects =))
(defn all-children-objects
[id]
(l/derived
(fn [objects]
(let [children-ids (cph/get-children-ids objects id)]
(into [] (keep (d/getf objects)) children-ids)))
workspace-page-objects =))
(def workspace-page-options
(l/derived :options workspace-page))

View file

@ -21,4 +21,5 @@
(def current-project-id (mf/create-context nil))
(def current-page-id (mf/create-context nil))
(def current-file-id (mf/create-context nil))
(def scroll-ctx (mf/create-context nil))
(def scroll-ctx (mf/create-context nil))
(def active-frames-ctx (mf/create-context nil))

View file

@ -45,7 +45,8 @@
(mf/defc frame-thumbnail
{::mf/wrap-props false}
[props]
(let [shape (obj/get props "shape")]
(let [shape (obj/get props "shape")
bounds (or (obj/get props "bounds") (:selrect shape))]
(when (:thumbnail shape)
(let [{:keys [x y width height show-content]} shape
transform (gsh/transform-str shape)
@ -72,10 +73,10 @@
[:image.frame-thumbnail
{:id (dm/str "thumbnail-" (:id shape))
:href (:thumbnail shape)
:x (:x shape)
:y (:y shape)
:width (:width shape)
:height (:height shape)
:x (:x bounds)
:y (:y bounds)
:width (:width bounds)
:height (:height bounds)
;; DEBUG
:style {:filter (when (debug? :thumbnails) "sepia(1)")}}]]

View file

@ -6,9 +6,9 @@
(ns app.main.ui.viewer.comments
(:require
[app.common.geom.shapes :as gsh]
[app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.main.data.comments :as dcm]
[app.main.data.events :as ev]
[app.main.refs :as refs]

View file

@ -13,6 +13,7 @@
common."
(:require
[app.common.pages.helpers :as cph]
[app.main.ui.context :as ctx]
[app.main.ui.shapes.circle :as circle]
[app.main.ui.shapes.image :as image]
[app.main.ui.shapes.rect :as rect]
@ -52,7 +53,8 @@
(mf/use-memo
(mf/deps objects)
#(cph/objects-by-frame objects))]
[:*
[:& (mf/provider ctx/active-frames-ctx) {:value active-frames}
;; Render font faces only for shapes that are part of the root
;; frame but don't belongs to any other frame.
(let [xform (comp
@ -75,7 +77,15 @@
::mf/wrap-props false}
[props]
(let [shape (obj/get props "shape")
opts #js {:shape shape}]
active-frames
(when (cph/root-frame? shape) (mf/use-ctx ctx/active-frames-ctx))
thumbnail?
(and (some? active-frames)
(not (contains? active-frames (:id shape))))
opts #js {:shape shape :thumbnail? thumbnail?}]
(when (and (some? shape) (not (:hidden shape)))
[:*
(case (:type shape)

View file

@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.main.data.workspace.thumbnails :as dwt]
[app.main.refs :as refs]
@ -54,7 +55,7 @@
(defn use-render-thumbnail
"Hook that will create the thumbnail thata"
[page-id {:keys [id x y width height] :as shape} node-ref rendered? disable? force-render]
[page-id {:keys [id] :as shape} node-ref rendered? disable? force-render]
(let [frame-canvas-ref (mf/use-ref nil)
frame-image-ref (mf/use-ref nil)
@ -63,13 +64,21 @@
regenerate-thumbnail (mf/use-var false)
fixed-width (mth/clamp (:width shape) 250 2000)
fixed-height (/ (* (:height shape) fixed-width) (:width shape))
all-children-ref (mf/use-memo (mf/deps id) #(refs/all-children-objects id))
all-children (mf/deref all-children-ref)
{:keys [x y width height] :as shape-bb}
(if (:show-content shape)
(gsh/selection-rect all-children)
(-> shape :points gsh/points->selrect))
fixed-width (mth/clamp width 250 2000)
fixed-height (/ (* height fixed-width) width)
image-url (mf/use-state nil)
observer-ref (mf/use-var nil)
shape-ref (hooks/use-update-var shape)
shape-bb-ref (hooks/use-update-var shape-bb)
updates-str (mf/use-memo #(rx/subject))
@ -101,7 +110,8 @@
(fn []
(let [node @node-ref
frame-html (dom/node->xml node)
{:keys [x y width height]} @shape-ref
{:keys [x y width height]} @shape-bb-ref
style-node (dom/query (dm/str "#frame-container-" (:id shape) " style"))
style-str (or (-> style-node dom/node->xml) "")
@ -201,6 +211,7 @@
(mf/html
[:*
[:> frame/frame-thumbnail {:key (dm/str (:id shape))
:bounds shape-bb
:shape (cond-> shape
(some? thumbnail-data)
(assoc :thumbnail thumbnail-data))}]
@ -220,9 +231,9 @@
(when (some? @image-url)
[:image {:ref frame-image-ref
:x (:x shape)
:y (:y shape)
:x x
:y y
:href @image-url
:width (:width shape)
:height (:height shape)
:width width
:height height
:on-load on-image-load}])])]))

View file

@ -10,7 +10,6 @@
[app.common.geom.shapes :as gsh]
[app.common.pages :as cp]
[app.common.pages.helpers :as cph]
[app.common.uuid :as uuid]
[app.main.data.shortcuts :as dsc]
[app.main.data.workspace :as dw]
[app.main.data.workspace.path.shortcuts :as psc]
@ -189,23 +188,28 @@
grouped? (fn [id] (contains? #{:group :bool} (get-in objects [id :type])))
selected-with-parents
(into #{} (mapcat #(cph/get-parent-ids objects %)) selected)
remove-xfm (mapcat #(cph/get-parent-ids objects %))
remove-id? (cond-> (into #{} remove-xfm selected)
(not mod?)
(into
(filter #(or (and (cph/root-frame? objects %) (d/not-empty? (get-in objects [% :shapes])))
(group-empty-space? % objects ids)))
ids)
root-frame-with-data? #(and (cph/root-frame? objects %) (d/not-empty? (get-in objects [% :shapes])))
mod?
(into (filter grouped?) ids))
;; Set with the elements to remove from the hover list
remove-id?
(cond-> selected-with-parents
(not mod?)
(into (filter #(or (root-frame-with-data? %)
(group-empty-space? % objects ids)))
ids)
hover-shape (->> ids
(remove remove-id?)
(filter #(or (empty? focus) (cp/is-in-focus? objects focus %)))
(first)
(get objects))]
mod?
(into (filter grouped?) ids))
hover-shape
(->> ids
(remove remove-id?)
(filter #(or (empty? focus) (cp/is-in-focus? objects focus %)))
(first)
(get objects))]
(reset! hover hover-shape)
(reset! hover-ids ids))))))
@ -214,13 +218,7 @@
(let [root-frame-ids
(mf/use-memo
(mf/deps objects)
(fn []
(let [frame? (into #{} (cph/get-frames-ids objects))
;; Removes from zero/shapes attribute all the frames so we can ask only for
;; the non-frame children
objects (-> objects
(update-in [uuid/zero :shapes] #(filterv (comp not frame?) %)))]
(cph/get-children-ids objects uuid/zero))))
#(cph/get-root-shapes-ids objects))
modifiers (select-keys modifiers root-frame-ids)]
(sfd/use-dynamic-modifiers objects globals/document modifiers)))
@ -238,14 +236,13 @@
selected-shapes-frames (mf/use-memo (mf/deps selected) #(into #{} xf-selected-frame selected))
active-selection (when (and (not= transform :move) (= (count selected-frames) 1)) (first selected-frames))
hover-frame (last @hover-ids)
last-hover-frame (mf/use-var nil)]
last-hover-ids (mf/use-var nil)]
(mf/use-effect
(mf/deps hover-frame)
(mf/deps @hover-ids)
(fn []
(when (some? hover-frame)
(reset! last-hover-frame hover-frame))))
(when (d/not-empty? @hover-ids)
(reset! last-hover-ids (set @hover-ids)))))
(mf/use-effect
(mf/deps objects @hover-ids selected zoom transform vbox)
@ -258,7 +255,9 @@
;; - If no hovering over any frames we keep the previous active one
;; - Check always that the active frames are inside the vbox
(let [is-active-frame?
(let [hover-ids? (set @hover-ids)
is-active-frame?
(fn [id]
(or
;; Zoom > 130% shows every frame
@ -267,7 +266,7 @@
;; Zoom >= 25% will show frames hovering
(and
(>= zoom 0.25)
(or (= id hover-frame) (= id @last-hover-frame)))
(or (contains? hover-ids? id) (contains? @last-hover-ids id)))
;; Otherwise, if it's a selected frame
(= id active-selection)