diff --git a/frontend/src/app/main/data/preview.cljs b/frontend/src/app/main/data/preview.cljs
index d00daefb9..d50e0a5e9 100644
--- a/frontend/src/app/main/data/preview.cljs
+++ b/frontend/src/app/main/data/preview.cljs
@@ -48,11 +48,11 @@
(beautify/html #js {"indent_size" 2})))
(defn update-preview-window
- [preview code]
+ [preview code width height]
(when preview
(if (aget preview "load")
- (.load preview code)
- (ts/schedule #(update-preview-window preview code)))))
+ (.load preview code width height)
+ (ts/schedule #(update-preview-window preview code width height)))))
(defn shapes->fonts
[shapes]
@@ -92,7 +92,11 @@
(-> (cg/generate-markup-code objects markup-type [shape])
(format-code markup-type))]
- (update-preview-window preview (str/format page-template style-code markup-code))))))))))
+ (update-preview-window
+ preview
+ (str/format page-template style-code markup-code)
+ (-> shape :selrect :width)
+ (-> shape :selrect :height))))))))))
(defn open-preview-selected
[]
diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs
index 77106939e..dbacccfdd 100644
--- a/frontend/src/app/main/data/workspace/shortcuts.cljs
+++ b/frontend/src/app/main/data/workspace/shortcuts.cljs
@@ -8,6 +8,7 @@
(:require
[app.main.data.events :as ev]
[app.main.data.exports :as de]
+ [app.main.data.preview :as dp]
[app.main.data.shortcuts :as ds]
[app.main.data.workspace :as dw]
[app.main.data.workspace.colors :as mdc]
@@ -539,8 +540,12 @@
:bool-exclude {:tooltip (ds/meta (ds/alt "E"))
:command (ds/c-mod "alt+e")
:subsections [:shape]
- :fn #(emit-when-no-readonly (dw/create-bool :exclude))}}
- )
+ :fn #(emit-when-no-readonly (dw/create-bool :exclude))}
+
+ ;; PREVIEW
+ :preview-frame {:tooltip (ds/meta (ds/alt ds/enter))
+ :command (ds/c-mod "alt+enter")
+ :fn #(emit-when-no-readonly (dp/open-preview-selected))}})
(def opacity-shortcuts
(into {} (->>
diff --git a/frontend/src/app/main/ui/frame_preview.cljs b/frontend/src/app/main/ui/frame_preview.cljs
index 9188edb51..805b73a1e 100644
--- a/frontend/src/app/main/ui/frame_preview.cljs
+++ b/frontend/src/app/main/ui/frame_preview.cljs
@@ -24,11 +24,13 @@
handle-load
(mf/use-callback
- (fn [data]
+ (fn [data width height]
(prn "handle-load" data)
(reset! last-data* data)
(let [iframe-dom (mf/ref-val iframe-ref)]
(when iframe-dom
+ (-> iframe-dom (aset "width" width))
+ (-> iframe-dom (aset "height" height))
(-> iframe-dom .-contentWindow .-document .open)
(-> iframe-dom .-contentWindow .-document (.write data))
(-> iframe-dom .-contentWindow .-document .close)))))
@@ -65,11 +67,5 @@
[:iframe {:ref load-ref
:frameborder "0"
:scrolling "no"
- :style {:width (str (* 100 (if (> zoom 1)
- (* 1 zoom)
- (/ 1 zoom))) "%")
- :height (str (* 100 (if (> zoom 1)
- (* 1 zoom)
- (/ 1 zoom))) "%")
- :transform-origin "left top"
+ :style {:transform-origin "top center"
:transform (str "scale(" zoom ")")}}]]]))
diff --git a/frontend/src/app/util/code_gen/common.cljs b/frontend/src/app/util/code_gen/common.cljs
index aa4719c62..5abbe40fb 100644
--- a/frontend/src/app/util/code_gen/common.cljs
+++ b/frontend/src/app/util/code_gen/common.cljs
@@ -6,7 +6,11 @@
(ns app.util.code-gen.common
(:require
+ [app.common.data :as d]
[app.common.data.macros :as dm]
+ [app.common.geom.matrix :as gmt]
+ [app.common.pages.helpers :as cph]
+ [app.common.types.shape.layout :as ctl]
[cuerdas.core :as str]))
(defn shape->selector
@@ -23,3 +27,36 @@
selector (if (str/starts-with? selector "-") (subs selector 1) selector)]
selector)
""))
+
+(defn svg-markup?
+ "Function to determine whether a shape is rendered in HTML+CSS or is rendered
+ through a SVG"
+ [shape]
+ (or
+ ;; path and path-like shapes
+ (cph/path-shape? shape)
+ (cph/bool-shape? shape)
+
+ ;; imported SVG images
+ (cph/svg-raw-shape? shape)
+ (some? (:svg-attrs shape))
+
+ ;; CSS masks are not enough we need to delegate to SVG
+ (cph/mask-shape? shape)
+
+ ;; Texts with shadows or strokes we render in SVG
+ (and (cph/text-shape? shape)
+ (or (d/not-empty? (:shadow shape))
+ (d/not-empty? (:strokes shape))))
+
+ ;; When a shape has several strokes or the stroke is not a "border"
+ (or (> (count (:strokes shape)) 1)
+ (and (= (count (:strokes shape)) 1)
+ (not= (-> shape :strokes first :stroke-alignment) :inner)))))
+
+(defn has-wrapper?
+ [objects shape]
+ ;; Layout children with a transform should be wrapped
+ (and (ctl/any-layout-immediate-child? objects shape)
+ (not (gmt/unit? (:transform shape)))))
+
diff --git a/frontend/src/app/util/code_gen/markup_html.cljs b/frontend/src/app/util/code_gen/markup_html.cljs
index 4c5fdf0c5..3229bf70a 100644
--- a/frontend/src/app/util/code_gen/markup_html.cljs
+++ b/frontend/src/app/util/code_gen/markup_html.cljs
@@ -18,32 +18,6 @@
[cuerdas.core :as str]
[rumext.v2 :as mf]))
-(defn svg-markup?
- "Function to determine whether a shape is rendered in HTML+CSS or is rendered
- through a SVG"
- [shape]
- (or
- ;; path and path-like shapes
- (cph/path-shape? shape)
- (cph/bool-shape? shape)
-
- ;; imported SVG images
- (cph/svg-raw-shape? shape)
- (some? (:svg-attrs shape))
-
- ;; CSS masks are not enough we need to delegate to SVG
- (cph/mask-shape? shape)
-
- ;; Texts with shadows or strokes we render in SVG
- (and (cph/text-shape? shape)
- (or (d/not-empty? (:shadow shape))
- (d/not-empty? (:strokes shape))))
-
- ;; When a shape has several strokes or the stroke is not a "border"
- (or (> (count (:strokes shape)) 1)
- (and (= (count (:strokes shape)) 1)
- (not= (-> shape :strokes first :stroke-alignment) :inner)))))
-
(defn generate-html
([objects shape]
(generate-html objects shape 0))
@@ -54,7 +28,7 @@
shape-html
(cond
- (svg-markup? shape)
+ (cgc/svg-markup? shape)
(let [svg-markup (generate-svg objects shape)]
(dm/fmt "%
\n%\n%
"
indent
@@ -98,7 +72,15 @@
(maybe-reverse)
(map #(generate-html objects (get objects %) (inc level)))
(str/join "\n"))
- indent))]
+ indent))
+
+ shape-html
+ (if (cgc/has-wrapper? objects shape)
+ (dm/fmt "%
"
+ (dm/str (cgc/shape->selector shape) "-wrapper")
+ shape-html)
+
+ shape-html)]
(dm/fmt "%\n%" indent (dm/str (d/name (:type shape)) ": " (:name shape)) shape-html))))
(defn generate-markup
diff --git a/frontend/src/app/util/code_gen/style_css.cljs b/frontend/src/app/util/code_gen/style_css.cljs
index cabbda805..ed70144d1 100644
--- a/frontend/src/app/util/code_gen/style_css.cljs
+++ b/frontend/src/app/util/code_gen/style_css.cljs
@@ -8,8 +8,11 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
+ [app.common.geom.matrix :as gmt]
+ [app.common.geom.shapes :as gsh]
[app.common.pages.helpers :as cph]
[app.common.text :as txt]
+ [app.common.types.shape.layout :as ctl]
[app.main.ui.shapes.text.styles :as sts]
[app.util.code-gen.common :as cgc]
[app.util.code-gen.style-css-formats :refer [format-value]]
@@ -50,6 +53,19 @@ svg {
")
+(def shape-wrapper-css-properties
+ #{:flex-shrink
+ :margin
+ :max-height
+ :min-height
+ :max-width
+ :min-width
+ :align-self
+ :justify-self
+ :grid-column
+ :grid-row
+ :z-index})
+
(def shape-css-properties
[:position
:left
@@ -82,6 +98,7 @@ svg {
;; Flex related properties
:flex-direction
:flex-wrap
+ :flex
;; Grid related properties
:grid-template-rows
@@ -118,6 +135,24 @@ svg {
(when-let [value (get-value property shape objects)]
[property value]))
+(defn shape->wrapper-css-properties
+ [shape objects]
+ (when (and (ctl/any-layout-immediate-child? objects shape)
+ (not (gmt/unit? (:transform shape))))
+ (let [{:keys [width height]} (gsh/shapes->rect [shape])]
+ (cond-> [[:position "relative"]
+ [:width width]
+ [:height height]]
+ (ctl/flex-layout-immediate-child? objects shape)
+ (conj [:flex-shrink 0])))))
+
+(defn shape->wrapper-child-css-properties
+ [shape objects]
+ (when (and (ctl/any-layout-immediate-child? objects shape) (not (gmt/unit? (:transform shape))))
+ [[:position "absolute"]
+ [:left "50%"]
+ [:top "50%"]]))
+
(defn shape->css-properties
"Given a shape extract the CSS properties in the format of list [property value]"
[shape objects properties]
@@ -143,9 +178,10 @@ svg {
(defn format-css-properties
"Format a list of [property value] into a list of css properties in the format 'property: value;'"
[properties options]
- (->> properties
- (map #(dm/str " " (format-css-property % options)))
- (str/join "\n")))
+ (when properties
+ (->> properties
+ (map #(dm/str " " (format-css-property % options)))
+ (str/join "\n"))))
(defn get-shape-properties-css
([objects shape properties]
@@ -199,13 +235,40 @@ svg {
(get-shape-css-selector shape objects nil))
([shape objects options]
- (let [properties (-> shape
- (shape->css-properties objects shape-css-properties)
- (format-css-properties options))
- selector (cgc/shape->selector shape)]
- (str/join "\n" [(str/fmt "/* %s */" (:name shape))
+ (let [selector (cgc/shape->selector shape)
+
+ wrapper? (cgc/has-wrapper? objects shape)
+
+ css-properties
+ (if wrapper?
+ (filter (complement shape-wrapper-css-properties) shape-css-properties)
+ shape-css-properties)
+
+ properties
+ (-> shape
+ (shape->css-properties objects css-properties)
+ (format-css-properties options))
+
+ wrapper-properties
+ (when wrapper?
+ (-> (d/concat-vec
+ (shape->css-properties shape objects shape-wrapper-css-properties)
+ (shape->wrapper-css-properties shape objects))
+ (format-css-properties options)))
+
+ wrapper-child-properties
+ (when wrapper?
+ (-> shape
+ (shape->wrapper-child-css-properties objects)
+ (format-css-properties options)))]
+
+ (str/join
+ "\n"
+ (filter some? [(str/fmt "/* %s */" (:name shape))
+ (when wrapper? (str/fmt ".%s-wrapper {\n%s\n}" selector wrapper-properties))
+ (when wrapper? (str/fmt ".%s-wrapper > * {\n%s\n}" selector wrapper-child-properties))
(str/fmt ".%s {\n%s\n}" selector properties)
- (when (cph/text-shape? shape) (generate-text-css shape))]))))
+ (when (cph/text-shape? shape) (generate-text-css shape))])))))
(defn get-css-property
([objects shape property]
diff --git a/frontend/src/app/util/code_gen/style_css_formats.cljs b/frontend/src/app/util/code_gen/style_css_formats.cljs
index 83ce8580c..7717d9e51 100644
--- a/frontend/src/app/util/code_gen/style_css_formats.cljs
+++ b/frontend/src/app/util/code_gen/style_css_formats.cljs
@@ -33,7 +33,6 @@
:margin :size-array
:grid-template-rows :tracks
:grid-template-columns :tracks
- :transform :matrix
})
(defmulti format-value
diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs
index 148adcb50..dbbb18b03 100644
--- a/frontend/src/app/util/code_gen/style_css_values.cljs
+++ b/frontend/src/app/util/code_gen/style_css_values.cljs
@@ -7,12 +7,14 @@
(ns app.util.code-gen.style-css-values
(:require
+ [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt]
[app.common.geom.shapes :as gsh]
[app.common.pages.helpers :as cph]
[app.common.types.shape.layout :as ctl]
- [app.util.code-gen.markup-html :refer [svg-markup?]]))
+ [app.main.ui.formats :as fmt]
+ [app.util.code-gen.common :as cgc]))
(defn fill->color
[{:keys [fill-color fill-opacity fill-color-gradient]}]
@@ -30,7 +32,7 @@
(not (ctl/layout-absolute? shape))
(or (cph/group-like-shape? shape)
(cph/frame-shape? shape)
- (svg-markup? shape)))
+ (cgc/svg-markup? shape)))
(cph/root-frame? shape))
:relative
@@ -66,14 +68,37 @@
[_ shape objects]
(get-shape-position shape objects :y))
+(defmethod get-value :flex
+ [_ shape objects]
+ (let [parent (cph/get-parent objects (:id shape))]
+ (when (and (ctl/flex-layout-immediate-child? objects shape)
+ (or (and (contains? #{:row :reverse-row} (:layout-flex-dir parent))
+ (= :fill (:layout-item-h-sizing shape)))
+ (and (contains? #{:column :column-row} (:layout-flex-dir parent))
+ (= :fill (:layout-item-v-sizing shape)))))
+ 1)))
+
(defn get-shape-size
[shape objects type]
- (let [sizing (if (= type :width)
+ (let [parent (cph/get-parent objects (:id shape))
+ sizing (if (= type :width)
(:layout-item-h-sizing shape)
(:layout-item-v-sizing shape))]
(cond
- (or (and (ctl/any-layout? shape) (= sizing :auto) (not (svg-markup? shape)))
- (and (ctl/any-layout-immediate-child? objects shape) (= sizing :fill)))
+ (and (ctl/flex-layout-immediate-child? objects shape)
+ (or (and (= type :height)
+ (contains? #{:row :reverse-row} (:layout-flex-dir parent))
+ (= :fill (:layout-item-v-sizing shape)))
+ (and (= type :width)
+ (contains? #{:column :column-row} (:layout-flex-dir parent))
+ (= :fill (:layout-item-h-sizing shape)))))
+ :fill
+
+ (and (ctl/flex-layout-immediate-child? objects shape) (= sizing :fill))
+ nil
+
+ (or (and (ctl/any-layout? shape) (= sizing :auto) (not (cgc/svg-markup? shape)))
+ (and (ctl/grid-layout-immediate-child? objects shape) (= sizing :fill)))
sizing
(some? (:selrect shape))
@@ -92,21 +117,25 @@
(defmethod get-value :transform
[_ shape objects]
- (when-not (svg-markup? shape)
+ (when-not (cgc/svg-markup? shape)
(let [parent (get objects (:parent-id shape))
transform
(gmt/multiply (:transform shape (gmt/matrix))
- (:transform-inverse parent (gmt/matrix)))]
- (when-not (gmt/unit? transform)
- transform))))
+ (:transform-inverse parent (gmt/matrix)))
+
+ transform-str (when-not (gmt/unit? transform) (fmt/format-matrix transform))]
+
+ (if (cgc/has-wrapper? objects shape)
+ (dm/str "translate(-50%, -50%) " (d/nilv transform-str ""))
+ transform-str))))
(defmethod get-value :background
[_ {:keys [fills] :as shape} _]
(let [single-fill? (= (count fills) 1)
ffill (first fills)
gradient? (some? (:fill-color-gradient ffill))]
- (when (and (not (svg-markup? shape)) (not (cph/group-shape? shape)) single-fill? gradient?)
+ (when (and (not (cgc/svg-markup? shape)) (not (cph/group-shape? shape)) single-fill? gradient?)
(fill->color ffill))))
(defmethod get-value :background-color
@@ -114,12 +143,12 @@
(let [single-fill? (= (count fills) 1)
ffill (first fills)
gradient? (some? (:fill-color-gradient ffill))]
- (when (and (not (svg-markup? shape)) (not (cph/group-shape? shape)) single-fill? (not gradient?))
+ (when (and (not (cgc/svg-markup? shape)) (not (cph/group-shape? shape)) single-fill? (not gradient?))
(fill->color ffill))))
(defmethod get-value :background-image
[_ {:keys [fills] :as shape} _]
- (when (and (not (svg-markup? shape)) (not (cph/group-shape? shape)) (> (count fills) 1))
+ (when (and (not (cgc/svg-markup? shape)) (not (cph/group-shape? shape)) (> (count fills) 1))
(->> fills
(map fill->color))))
@@ -138,7 +167,7 @@
(defmethod get-value :border
[_ shape _]
- (when-not (svg-markup? shape)
+ (when-not (cgc/svg-markup? shape)
(get-stroke-data (first (:strokes shape)))))
(defmethod get-value :border-radius
@@ -155,12 +184,12 @@
(defmethod get-value :box-shadow
[_ shape _]
- (when-not (svg-markup? shape)
+ (when-not (cgc/svg-markup? shape)
(:shadow shape)))
(defmethod get-value :filter
[_ shape _]
- (when-not (svg-markup? shape)
+ (when-not (cgc/svg-markup? shape)
(get-in shape [:blur :value])))
(defmethod get-value :display
@@ -258,8 +287,15 @@
(defmethod get-value :flex-shrink
[_ shape objects]
(when (and (ctl/flex-layout-immediate-child? objects shape)
- (not= :fill (:layout-item-h-sizing shape))
- (not= :fill (:layout-item-v-sizing shape))
+
+ (not (and (contains? #{:row :reverse-row} (:layout-flex-dir shape))
+ (= :fill (:layout-item-h-sizing shape))))
+
+ (not (and (contains? #{:column :column-row} (:layout-flex-dir shape))
+ (= :fill (:layout-item-v-sizing shape))))
+
+ ;;(not= :fill (:layout-item-h-sizing shape))
+ ;;(not= :fill (:layout-item-v-sizing shape))
(not= :auto (:layout-item-h-sizing shape))
(not= :auto (:layout-item-v-sizing shape)))
0))
@@ -336,5 +372,3 @@
(defmethod get-value :default
[property shape _]
(get shape property))
-
-