mirror of
https://github.com/penpot/penpot.git
synced 2025-06-07 20:21:38 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
4d7a572daa
44 changed files with 547 additions and 532 deletions
|
@ -110,6 +110,7 @@
|
||||||
"Get the parent top shape linked to a component for this shape, if any"
|
"Get the parent top shape linked to a component for this shape, if any"
|
||||||
([objects shape] (get-component-shape objects shape nil))
|
([objects shape] (get-component-shape objects shape nil))
|
||||||
([objects shape {:keys [allow-main?] :or {allow-main? false} :as options}]
|
([objects shape {:keys [allow-main?] :or {allow-main? false} :as options}]
|
||||||
|
(let [parent (get objects (:parent-id shape))]
|
||||||
(cond
|
(cond
|
||||||
(nil? shape)
|
(nil? shape)
|
||||||
nil
|
nil
|
||||||
|
@ -123,8 +124,11 @@
|
||||||
(and (not (ctk/in-component-copy? shape)) (not allow-main?))
|
(and (not (ctk/in-component-copy? shape)) (not allow-main?))
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
(and (ctk/instance-head? shape) (not (ctk/in-component-copy? parent)))
|
||||||
|
shape ; This case is a copy root inside a main component
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(get-component-shape objects (get objects (:parent-id shape)) options))))
|
(get-component-shape objects parent options)))))
|
||||||
|
|
||||||
(defn get-head-shape
|
(defn get-head-shape
|
||||||
"Get the parent top or nested shape linked to a component for this shape, if any"
|
"Get the parent top or nested shape linked to a component for this shape, if any"
|
||||||
|
|
|
@ -583,6 +583,7 @@
|
||||||
padding: $s-32;
|
padding: $s-32;
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
background-color: var(--modal-background-color);
|
background-color: var(--modal-background-color);
|
||||||
|
border: $s-2 solid var(--modal-border-color);
|
||||||
min-width: $s-364;
|
min-width: $s-364;
|
||||||
min-height: $s-192;
|
min-height: $s-192;
|
||||||
max-width: $s-512;
|
max-width: $s-512;
|
||||||
|
@ -843,6 +844,7 @@
|
||||||
z-index: $z-index-10;
|
z-index: $z-index-10;
|
||||||
color: var(--title-foreground-color-hover);
|
color: var(--title-foreground-color-hover);
|
||||||
background-color: var(--menu-background-color);
|
background-color: var(--menu-background-color);
|
||||||
|
border: $s-2 solid var(--panel-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item-base {
|
.menu-item-base {
|
||||||
|
@ -904,6 +906,7 @@
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background-color: var(--menu-background-color);
|
background-color: var(--menu-background-color);
|
||||||
color: var(--menu-foreground-color);
|
color: var(--menu-foreground-color);
|
||||||
|
border: $s-2 solid var(--panel-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-wrapper {
|
.select-wrapper {
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
|
|
||||||
--scrollbar-background-color: var(--color-foreground-secondary);
|
--scrollbar-background-color: var(--color-foreground-secondary);
|
||||||
--panel-background-color: var(--color-background-primary);
|
--panel-background-color: var(--color-background-primary);
|
||||||
|
--panel-border-color: var(--color-background-quaternary);
|
||||||
|
|
||||||
--app-background: var(--color-background-primary);
|
--app-background: var(--color-background-primary);
|
||||||
--loader-background: var(--color-background-primary);
|
--loader-background: var(--color-background-primary);
|
||||||
--panel-title-background-color: var(--color-background-secondary);
|
--panel-title-background-color: var(--color-background-secondary);
|
||||||
|
|
|
@ -70,6 +70,21 @@
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin headlineMediumTypography {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
font-size: $fs-16;
|
||||||
|
line-height: 1.4;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin bodyLargeTypography {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
font-size: $fs-16;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin textEllipsis {
|
@mixin textEllipsis {
|
||||||
max-width: 99%;
|
max-width: 99%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
:document-history
|
:document-history
|
||||||
:colorpalette
|
:colorpalette
|
||||||
:element-options
|
:element-options
|
||||||
:rules
|
:rulers
|
||||||
:display-grid
|
:display-grid
|
||||||
:snap-grid
|
:snap-grid
|
||||||
:scale-text
|
:scale-text
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
#{:sitemap
|
#{:sitemap
|
||||||
:layers
|
:layers
|
||||||
:element-options
|
:element-options
|
||||||
:rules
|
:rulers
|
||||||
:display-grid
|
:display-grid
|
||||||
:snap-grid
|
:snap-grid
|
||||||
:dynamic-alignment
|
:dynamic-alignment
|
||||||
|
|
|
@ -640,6 +640,21 @@
|
||||||
:path-params path-params
|
:path-params path-params
|
||||||
:query-params query-params}))))))
|
:query-params query-params}))))))
|
||||||
|
|
||||||
|
(defn library-thumbnails-fetched
|
||||||
|
[thumbnails]
|
||||||
|
(ptk/reify ::library-thumbnails-fetched
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update state :workspace-thumbnails merge thumbnails))))
|
||||||
|
|
||||||
|
(defn fetch-library-thumbnails
|
||||||
|
[library-id]
|
||||||
|
(ptk/reify ::fetch-library-thumbnails
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ _]
|
||||||
|
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
|
||||||
|
(rx/map library-thumbnails-fetched)))))
|
||||||
|
|
||||||
(defn ext-library-changed
|
(defn ext-library-changed
|
||||||
[library-id modified-at revn changes]
|
[library-id modified-at revn changes]
|
||||||
(dm/assert! (uuid? library-id))
|
(dm/assert! (uuid? library-id))
|
||||||
|
@ -654,11 +669,15 @@
|
||||||
ch/process-changes changes)))
|
ch/process-changes changes)))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ stream]
|
||||||
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
|
(let [stopper-s (rx/filter (ptk/type? ::ext-library-changed) stream)]
|
||||||
(rx/map (fn [thumbnails]
|
(->>
|
||||||
(fn [state]
|
(rx/merge
|
||||||
(assoc-in state [:workspace-libraries library-id :thumbnails] thumbnails))))))))
|
(->> (rx/of library-id)
|
||||||
|
(rx/delay 5000)
|
||||||
|
(rx/map fetch-library-thumbnails)))
|
||||||
|
|
||||||
|
(rx/take-until stopper-s))))))
|
||||||
|
|
||||||
(defn reset-component
|
(defn reset-component
|
||||||
"Cancels all modifications in the shape with the given id, and all its children, in
|
"Cancels all modifications in the shape with the given id, and all its children, in
|
||||||
|
@ -1261,7 +1280,7 @@
|
||||||
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
|
(->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id :tag "component"})
|
||||||
(rx/map (fn [thumbnails]
|
(rx/map (fn [thumbnails]
|
||||||
(fn [state]
|
(fn [state]
|
||||||
(assoc-in state [:workspace-libraries library-id :thumbnails] thumbnails))))))))))
|
(update state :workspace-thumbnails merge thumbnails))))))))))
|
||||||
|
|
||||||
(defn unlink-file-from-library
|
(defn unlink-file-from-library
|
||||||
[file-id library-id]
|
[file-id library-id]
|
||||||
|
|
|
@ -1081,7 +1081,10 @@
|
||||||
(:id component-parent-shape)
|
(:id component-parent-shape)
|
||||||
(get page :objects)
|
(get page :objects)
|
||||||
:update-new-shape update-new-shape
|
:update-new-shape update-new-shape
|
||||||
:update-original-shape update-original-shape)
|
:update-original-shape update-original-shape
|
||||||
|
:frame-id (if (cfh/frame-shape? component-parent-shape)
|
||||||
|
(:id component-parent-shape)
|
||||||
|
(:frame-id component-parent-shape)))
|
||||||
|
|
||||||
add-obj-change (fn [changes shape']
|
add-obj-change (fn [changes shape']
|
||||||
(update changes :redo-changes conj
|
(update changes :redo-changes conj
|
||||||
|
@ -1090,14 +1093,10 @@
|
||||||
{:type :add-obj
|
{:type :add-obj
|
||||||
:id (:id shape')
|
:id (:id shape')
|
||||||
:parent-id (:parent-id shape')
|
:parent-id (:parent-id shape')
|
||||||
|
:frame-id (:frame-id shape')
|
||||||
:index index
|
:index index
|
||||||
:ignore-touched true
|
:ignore-touched true
|
||||||
:obj shape'})
|
:obj shape'}))))
|
||||||
|
|
||||||
(ctn/page? component-container)
|
|
||||||
(assoc :frame-id (if (= (:type shape') :frame)
|
|
||||||
(:id shape')
|
|
||||||
(:frame-id shape'))))))
|
|
||||||
|
|
||||||
mod-obj-change (fn [changes shape']
|
mod-obj-change (fn [changes shape']
|
||||||
(update changes :redo-changes conj
|
(update changes :redo-changes conj
|
||||||
|
|
|
@ -351,10 +351,10 @@
|
||||||
|
|
||||||
;; MAIN MENU
|
;; MAIN MENU
|
||||||
|
|
||||||
:toggle-rules {:tooltip (ds/meta-shift "R")
|
:toggle-rulers {:tooltip (ds/meta-shift "R")
|
||||||
:command (ds/c-mod "shift+r")
|
:command (ds/c-mod "shift+r")
|
||||||
:subsections [:main-menu]
|
:subsections [:main-menu]
|
||||||
:fn #(st/emit! (toggle-layout-flag :rules))}
|
:fn #(st/emit! (toggle-layout-flag :rulers))}
|
||||||
|
|
||||||
:select-all {:tooltip (ds/meta "A")
|
:select-all {:tooltip (ds/meta "A")
|
||||||
:command (ds/c-mod "a")
|
:command (ds/c-mod "a")
|
||||||
|
|
|
@ -115,16 +115,10 @@
|
||||||
(ptk/reify ::assoc-thumbnail
|
(ptk/reify ::assoc-thumbnail
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [prev-uri (dm/get-in state [:workspace-thumbnails object-id])
|
(let [prev-uri (dm/get-in state [:workspace-thumbnails object-id])]
|
||||||
current-file-id (:current-file-id state)]
|
|
||||||
(some->> prev-uri (vreset! prev-uri*))
|
(some->> prev-uri (vreset! prev-uri*))
|
||||||
(l/trc :hint "assoc thumbnail" :object-id object-id :uri uri)
|
(l/trc :hint "assoc thumbnail" :object-id object-id :uri uri)
|
||||||
|
(update state :workspace-thumbnails assoc object-id uri)))
|
||||||
#_(update state :workspace-thumbnails assoc object-id uri)
|
|
||||||
(if (thc/file-id? object-id current-file-id)
|
|
||||||
(update state :workspace-thumbnails assoc object-id uri)
|
|
||||||
(let [file-id (thc/get-file-id object-id)]
|
|
||||||
(update-in state [:workspace-libraries file-id :thumbnails] assoc object-id uri)))))
|
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ _ _]
|
(effect [_ _ _]
|
||||||
|
|
|
@ -212,8 +212,8 @@
|
||||||
(def snap-pixel?
|
(def snap-pixel?
|
||||||
(l/derived #(contains? % :snap-pixel-grid) workspace-layout))
|
(l/derived #(contains? % :snap-pixel-grid) workspace-layout))
|
||||||
|
|
||||||
(def rules?
|
(def rulers?
|
||||||
(l/derived #(contains? % :rules) workspace-layout))
|
(l/derived #(contains? % :rulers) workspace-layout))
|
||||||
|
|
||||||
(def workspace-file
|
(def workspace-file
|
||||||
"A ref to a striped vision of file (without data)."
|
"A ref to a striped vision of file (without data)."
|
||||||
|
@ -490,6 +490,9 @@
|
||||||
(dm/get-in state [:viewer-local :zoom-type]))
|
(dm/get-in state [:viewer-local :zoom-type]))
|
||||||
st/state))
|
st/state))
|
||||||
|
|
||||||
|
(def workspace-thumbnails
|
||||||
|
(l/derived :workspace-thumbnails st/state))
|
||||||
|
|
||||||
(defn workspace-thumbnail-by-id
|
(defn workspace-thumbnail-by-id
|
||||||
[object-id]
|
[object-id]
|
||||||
(l/derived
|
(l/derived
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
(not (contains? focus id))))
|
(not (contains? focus id))))
|
||||||
|
|
||||||
(= type :guide)
|
(= type :guide)
|
||||||
(or (not (contains? layout :rules))
|
(or (not (contains? layout :rulers))
|
||||||
(not (contains? layout :snap-guides))
|
(not (contains? layout :snap-guides))
|
||||||
(and (d/not-empty? focus)
|
(and (d/not-empty? focus)
|
||||||
(not (contains? focus frame-id))))
|
(not (contains? focus frame-id))))
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,12 +30,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
margin-bottom: $s-24;
|
margin-bottom: $s-24;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-hint {
|
.modal-hint {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
.modal-scd-msg,
|
.modal-scd-msg,
|
||||||
.modal-subtitle,
|
.modal-subtitle,
|
||||||
.modal-msg {
|
.modal-msg {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
margin: $s-0;
|
margin: $s-0;
|
||||||
padding: $s-4;
|
padding: $s-4;
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
|
border: $s-2 solid var(--panel-border-color);
|
||||||
background-color: var(--menu-background-color);
|
background-color: var(--menu-background-color);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
& .separator {
|
& .separator {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
margin-bottom: $s-24;
|
margin-bottom: $s-24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal-component-name {
|
.modal-component-name {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-hint {
|
.modal-hint {
|
||||||
|
@ -74,7 +74,6 @@
|
||||||
.modal-scd-msg,
|
.modal-scd-msg,
|
||||||
.modal-subtitle,
|
.modal-subtitle,
|
||||||
.modal-msg {
|
.modal-msg {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
line-height: 1.5;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -178,6 +178,7 @@
|
||||||
|
|
||||||
[:div {:class (stl/css :invitation-row)}
|
[:div {:class (stl/css :invitation-row)}
|
||||||
[:& fm/multi-input {:type "email"
|
[:& fm/multi-input {:type "email"
|
||||||
|
:class (stl/css :email-input)
|
||||||
:name :emails
|
:name :emails
|
||||||
:auto-focus? true
|
:auto-focus? true
|
||||||
:trim true
|
:trim true
|
||||||
|
|
|
@ -588,13 +588,12 @@
|
||||||
width: $s-400;
|
width: $s-400;
|
||||||
padding: $s-32;
|
padding: $s-32;
|
||||||
background-color: var(--modal-background-color);
|
background-color: var(--modal-background-color);
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
&.hero {
|
&.hero {
|
||||||
top: $s-216;
|
top: $s-216;
|
||||||
right: $s-32;
|
right: $s-32;
|
||||||
}
|
}
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
@ -644,8 +643,9 @@
|
||||||
|
|
||||||
.role-select {
|
.role-select {
|
||||||
@include flexColumn;
|
@include flexColumn;
|
||||||
|
row-gap: $s-8;
|
||||||
.role-title {
|
.role-title {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
@ -676,7 +676,6 @@
|
||||||
|
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
@ -725,3 +724,7 @@
|
||||||
@extend .modal-cancel-btn;
|
@extend .modal-cancel-btn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.email-input {
|
||||||
|
@extend .input-base;
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,10 +40,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.element-list {
|
.element-list {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
.list-item {
|
color: var(--modal-text-foreground-color);
|
||||||
@include titleTipography;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
|
@ -64,7 +62,7 @@
|
||||||
.modal-scd-msg,
|
.modal-scd-msg,
|
||||||
.modal-subtitle,
|
.modal-subtitle,
|
||||||
.modal-msg {
|
.modal-msg {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,8 @@
|
||||||
(cond-> (:name shape) suffix (str suffix))]
|
(cond-> (:name shape) suffix (str suffix))]
|
||||||
(when (:scale export)
|
(when (:scale export)
|
||||||
[:div {:class (stl/css :selection-scale)}
|
[:div {:class (stl/css :selection-scale)}
|
||||||
(dm/str (ust/format-precision (* width (:scale export)) 2) "px"
|
(dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
||||||
(ust/format-precision (* height (:scale export)) 2) "px")])
|
(ust/format-precision (* height (:scale export)) 2))])
|
||||||
|
|
||||||
(when (:type export)
|
(when (:type export)
|
||||||
[:div {:class (stl/css :selection-extension)}
|
[:div {:class (stl/css :selection-extension)}
|
||||||
|
|
|
@ -41,14 +41,14 @@
|
||||||
|
|
||||||
.title-text {
|
.title-text {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
padding-left: $s-4;
|
padding-left: $s-4;
|
||||||
}
|
}
|
||||||
.progress {
|
.progress {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
padding-left: $s-8;
|
padding-left: $s-8;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.selection-title {
|
.selection-title {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,9 @@
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
.selection-btn {
|
.selection-btn {
|
||||||
@include buttonStyle;
|
@include buttonStyle;
|
||||||
@include flexRow;
|
display: grid;
|
||||||
|
grid-template-columns: min-content auto 1fr auto auto;
|
||||||
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 10%;
|
height: 10%;
|
||||||
gap: $s-8;
|
gap: $s-8;
|
||||||
|
@ -176,21 +178,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.selection-name {
|
.selection-name {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
@include textEllipsis;
|
@include textEllipsis;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
text-align: start;
|
text-align: start;
|
||||||
}
|
}
|
||||||
.selection-scale {
|
.selection-scale {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
@include textEllipsis;
|
@include textEllipsis;
|
||||||
min-width: $s-108;
|
min-width: $s-108;
|
||||||
padding: $s-12;
|
padding: $s-12;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
}
|
}
|
||||||
.selection-extension {
|
.selection-extension {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
@include textEllipsis;
|
@include textEllipsis;
|
||||||
min-width: $s-72;
|
min-width: $s-72;
|
||||||
padding: $s-12;
|
padding: $s-12;
|
||||||
|
@ -199,7 +201,6 @@
|
||||||
}
|
}
|
||||||
.image-wrapper {
|
.image-wrapper {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
height: 100%;
|
|
||||||
min-height: $s-32;
|
min-height: $s-32;
|
||||||
min-width: $s-32;
|
min-width: $s-32;
|
||||||
background-color: var(--app-white);
|
background-color: var(--app-white);
|
||||||
|
@ -231,9 +232,8 @@
|
||||||
.modal-scd-msg,
|
.modal-scd-msg,
|
||||||
.modal-subtitle,
|
.modal-subtitle,
|
||||||
.modal-msg {
|
.modal-msg {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
line-height: 1.5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.export-option {
|
.export-option {
|
||||||
|
@ -243,7 +243,8 @@
|
||||||
label {
|
label {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
.modal-subtitle {
|
.modal-subtitle {
|
||||||
@include tabTitleTipography;
|
// @include tabTitleTipography;
|
||||||
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,7 +255,7 @@
|
||||||
|
|
||||||
.option-content {
|
.option-content {
|
||||||
@include flexColumn;
|
@include flexColumn;
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-entry {
|
.file-entry {
|
||||||
|
@ -271,7 +272,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.file-name-label {
|
.file-name-label {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.loading {
|
&.loading {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-width: $s-712;
|
min-width: $s-712;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-left {
|
.modal-left {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: $s-712;
|
min-width: $s-712;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
min-width: $s-512;
|
min-width: $s-512;
|
||||||
position: relative;
|
position: relative;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP CONTAINER
|
// STEP CONTAINER
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: $s-712;
|
min-width: $s-712;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-left {
|
.modal-left {
|
||||||
|
|
|
@ -175,7 +175,6 @@
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
min-width: $s-408;
|
min-width: $s-408;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
min-width: $s-408;
|
min-width: $s-408;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
min-width: $s-408;
|
min-width: $s-408;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
width: $s-240;
|
width: $s-240;
|
||||||
padding: $s-4;
|
padding: $s-4;
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
|
border: $s-2 solid var(--panel-border-color);
|
||||||
background-color: var(--menu-background-color);
|
background-color: var(--menu-background-color);
|
||||||
z-index: $z-index-3;
|
z-index: $z-index-3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,36 +70,22 @@
|
||||||
|
|
||||||
(mf/defc describe-library-blocks
|
(mf/defc describe-library-blocks
|
||||||
[{:keys [components-count graphics-count colors-count typography-count] :as props}]
|
[{:keys [components-count graphics-count colors-count typography-count] :as props}]
|
||||||
|
|
||||||
(let [last-one (cond
|
|
||||||
(> colors-count 0) :color
|
|
||||||
(> graphics-count 0) :graphics
|
|
||||||
(> components-count 0) :components)]
|
|
||||||
[:*
|
[:*
|
||||||
(when (pos? components-count)
|
(when (pos? components-count)
|
||||||
[:*
|
[:li {:class (stl/css :element-count)}
|
||||||
[:span {:class (stl/css :element-count)}
|
(tr "workspace.libraries.components" components-count)])
|
||||||
(tr "workspace.libraries.components" components-count)]
|
|
||||||
(when (not= last-one :components)
|
|
||||||
[:span " · "])])
|
|
||||||
|
|
||||||
(when (pos? graphics-count)
|
(when (pos? graphics-count)
|
||||||
[:*
|
[:li {:class (stl/css :element-count)}
|
||||||
[:span {:class (stl/css :element-count)}
|
(tr "workspace.libraries.graphics" graphics-count)])
|
||||||
(tr "workspace.libraries.graphics" graphics-count)]
|
|
||||||
(when (not= last-one :graphics)
|
|
||||||
[:span " · "])])
|
|
||||||
|
|
||||||
(when (pos? colors-count)
|
(when (pos? colors-count)
|
||||||
[:*
|
[:li {:class (stl/css :element-count)}
|
||||||
[:span {:class (stl/css :element-count)}
|
(tr "workspace.libraries.colors" colors-count)])
|
||||||
(tr "workspace.libraries.colors" colors-count)]
|
|
||||||
(when (not= last-one :colors)
|
|
||||||
[:span " · "])])
|
|
||||||
|
|
||||||
(when (pos? typography-count)
|
(when (pos? typography-count)
|
||||||
[:span {:class (stl/css :element-count)}
|
[:li {:class (stl/css :element-count)}
|
||||||
(tr "workspace.libraries.typography" typography-count)])]))
|
(tr "workspace.libraries.typography" typography-count)])])
|
||||||
|
|
||||||
|
|
||||||
(mf/defc libraries-tab
|
(mf/defc libraries-tab
|
||||||
|
@ -208,7 +194,7 @@
|
||||||
[:div {:class (stl/css :section-list-item)}
|
[:div {:class (stl/css :section-list-item)}
|
||||||
[:div
|
[:div
|
||||||
[:div {:class (stl/css :item-name)} (tr "workspace.libraries.file-library")]
|
[:div {:class (stl/css :item-name)} (tr "workspace.libraries.file-library")]
|
||||||
[:div {:class (stl/css :item-contents)}
|
[:ul {:class (stl/css :item-contents)}
|
||||||
[:& describe-library-blocks {:components-count (count components)
|
[:& describe-library-blocks {:components-count (count components)
|
||||||
:graphics-count (count media)
|
:graphics-count (count media)
|
||||||
:colors-count (count colors)
|
:colors-count (count colors)
|
||||||
|
@ -229,7 +215,7 @@
|
||||||
:key (dm/str id)}
|
:key (dm/str id)}
|
||||||
[:div
|
[:div
|
||||||
[:div {:class (stl/css :item-name)} name]
|
[:div {:class (stl/css :item-name)} name]
|
||||||
[:div {:class (stl/css :item-contents)}
|
[:ul {:class (stl/css :item-contents)}
|
||||||
(let [components-count (count (or (ctkl/components-seq (:data library)) []))
|
(let [components-count (count (or (ctkl/components-seq (:data library)) []))
|
||||||
graphics-count (count (dm/get-in library [:data :media] []))
|
graphics-count (count (dm/get-in library [:data :media] []))
|
||||||
colors-count (count (dm/get-in library [:data :colors] []))
|
colors-count (count (dm/get-in library [:data :colors] []))
|
||||||
|
@ -262,7 +248,7 @@
|
||||||
:key (dm/str id)}
|
:key (dm/str id)}
|
||||||
[:div
|
[:div
|
||||||
[:div {:class (stl/css :item-name)} name]
|
[:div {:class (stl/css :item-name)} name]
|
||||||
[:div {:class (stl/css :item-contents)}
|
[:ul {:class (stl/css :item-contents)}
|
||||||
(let [components-count (dm/get-in library [:library-summary :components :count] 0)
|
(let [components-count (dm/get-in library [:library-summary :components :count] 0)
|
||||||
graphics-count (dm/get-in library [:library-summary :media :count] 0)
|
graphics-count (dm/get-in library [:library-summary :media :count] 0)
|
||||||
colors-count (dm/get-in library [:library-summary :colors :count] 0)
|
colors-count (dm/get-in library [:library-summary :colors :count] 0)
|
||||||
|
@ -376,7 +362,7 @@
|
||||||
:key (dm/str id)}
|
:key (dm/str id)}
|
||||||
[:div
|
[:div
|
||||||
[:div {:class (stl/css :item-name)} name]
|
[:div {:class (stl/css :item-name)} name]
|
||||||
[:div {:class (stl/css :item-contents)} (describe-library
|
[:ul {:class (stl/css :item-contents)} (describe-library
|
||||||
(count components)
|
(count components)
|
||||||
0
|
0
|
||||||
(count colors)
|
(count colors)
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
margin-bottom: $s-16;
|
margin-bottom: $s-16;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
|
@ -70,24 +70,18 @@
|
||||||
max-height: $s-320;
|
max-height: $s-320;
|
||||||
margin-top: $s-12;
|
margin-top: $s-12;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-right: $s-8;
|
|
||||||
.section-list-item {
|
.section-list-item {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
|
column-gap: $s-12;
|
||||||
margin-bottom: $s-24;
|
margin-bottom: $s-24;
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: $s-8;
|
margin-bottom: $s-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-name {
|
.item-name {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--library-name-foreground-color);
|
color: var(--library-name-foreground-color);
|
||||||
}
|
}
|
||||||
.item-contents {
|
|
||||||
@include titleTipography;
|
|
||||||
color: var(--library-content-foreground-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-publish,
|
.item-publish,
|
||||||
.item-unpublish {
|
.item-unpublish {
|
||||||
@extend .button-primary;
|
@extend .button-primary;
|
||||||
|
@ -99,7 +93,7 @@
|
||||||
}
|
}
|
||||||
.item-update {
|
.item-update {
|
||||||
@extend .button-warning;
|
@extend .button-warning;
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
min-width: $s-92;
|
min-width: $s-92;
|
||||||
padding: $s-8 $s-24;
|
padding: $s-8 $s-24;
|
||||||
|
@ -143,7 +137,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
margin-bottom: $s-12;
|
margin-bottom: $s-12;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +155,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.section-list-empty {
|
.section-list-empty {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
color: var(--empty-message-foreground-color);
|
color: var(--empty-message-foreground-color);
|
||||||
|
|
||||||
|
@ -236,6 +230,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-contents {
|
||||||
|
@include bodyLargeTypography;
|
||||||
|
color: var(--library-content-foreground-color);
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.element-count {
|
.element-count {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:not(:last-child)::after {
|
||||||
|
content: "·";
|
||||||
|
margin-inline: $s-4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,14 +305,14 @@
|
||||||
:on-key-down (fn [event]
|
:on-key-down (fn [event]
|
||||||
(when (kbd/enter? event)
|
(when (kbd/enter? event)
|
||||||
(toggle-flag event)))
|
(toggle-flag event)))
|
||||||
:data-test "rules"
|
:data-test "rulers"
|
||||||
:id "file-menu-rules"}
|
:id "file-menu-rulers"}
|
||||||
[:span {:class (stl/css :item-name)}
|
[:span {:class (stl/css :item-name)}
|
||||||
(if (contains? layout :rules)
|
(if (contains? layout :rulers)
|
||||||
(tr "workspace.header.menu.hide-rules")
|
(tr "workspace.header.menu.hide-rules")
|
||||||
(tr "workspace.header.menu.show-rules"))]
|
(tr "workspace.header.menu.show-rules"))]
|
||||||
[:span {:class (stl/css :shortcut)}
|
[:span {:class (stl/css :shortcut)}
|
||||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-rules))]
|
(for [sc (scd/split-sc (sc/get-tooltip :toggle-rulers))]
|
||||||
[:span {:class (stl/css :shortcut-key) :key sc} sc])]]
|
[:span {:class (stl/css :shortcut-key) :key sc} sc])]]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
.modal-container {
|
.modal-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
min-width: $s-408;
|
min-width: $s-408;
|
||||||
border: $s-1 solid var(--modal-border-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
|
@ -21,7 +20,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
@include tabTitleTipography;
|
@include headlineMediumTypography;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
.modal-close-btn {
|
.modal-close-btn {
|
||||||
|
@ -31,7 +30,7 @@
|
||||||
.modal-content {
|
.modal-content {
|
||||||
@include flexColumn;
|
@include flexColumn;
|
||||||
gap: $s-24;
|
gap: $s-24;
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
margin-bottom: $s-24;
|
margin-bottom: $s-24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-msg {
|
.modal-msg {
|
||||||
@include titleTipography;
|
@include bodyLargeTypography;
|
||||||
color: var(--modal-text-foreground-color);
|
color: var(--modal-text-foreground-color);
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
selected-text* (mf/use-state :file)
|
selected-text* (mf/use-state :file)
|
||||||
selected-text (deref selected-text*)
|
selected-text (deref selected-text*)
|
||||||
on-select (mf/use-fn #(reset! selected %))
|
on-select (mf/use-fn #(reset! selected %))
|
||||||
rulers? (mf/deref refs/rules?)
|
rulers? (mf/deref refs/rulers?)
|
||||||
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
|
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
|
||||||
(r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-palette-size)
|
(r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-palette-size)
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
padding: $s-0 $s-0 $s-8 $s-8;
|
padding: $s-0 $s-0 $s-8 $s-8;
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
background-color: var(--palette-background-color);
|
background-color: var(--palette-background-color);
|
||||||
|
border: $s-2 solid var(--panel-border-color);
|
||||||
transition:
|
transition:
|
||||||
right 0.3s,
|
right 0.3s,
|
||||||
opacity 0.2s,
|
opacity 0.2s,
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
(ns app.main.ui.workspace.sidebar.assets.common
|
(ns app.main.ui.workspace.sidebar.assets.common
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.thumbnails :as thc]
|
[app.common.thumbnails :as thc]
|
||||||
|
@ -263,39 +262,32 @@
|
||||||
(:id target-asset)
|
(:id target-asset)
|
||||||
(cfh/merge-path-item prefix (:name target-asset))))))))
|
(cfh/merge-path-item prefix (:name target-asset))))))))
|
||||||
|
|
||||||
|
|
||||||
(defn- get-component-thumbnail-uri
|
|
||||||
"Returns the component thumbnail uri"
|
|
||||||
[file-id component]
|
|
||||||
(let [page-id (:main-instance-page component)
|
|
||||||
root-id (:main-instance-id component)
|
|
||||||
object-id (thc/fmt-object-id file-id page-id root-id "component")
|
|
||||||
current-file? (= file-id (:id @refs/workspace-file))]
|
|
||||||
|
|
||||||
(if current-file?
|
|
||||||
(mf/deref (refs/workspace-thumbnail-by-id object-id))
|
|
||||||
(let [libraries @refs/workspace-libraries
|
|
||||||
thumbnail (dm/get-in libraries [file-id :thumbnails object-id])]
|
|
||||||
thumbnail))))
|
|
||||||
|
|
||||||
(mf/defc component-item-thumbnail
|
(mf/defc component-item-thumbnail
|
||||||
"Component that renders the thumbnail image or the original SVG."
|
"Component that renders the thumbnail image or the original SVG."
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [file-id root-shape component container class]}]
|
[{:keys [file-id root-shape component container class]}]
|
||||||
(let [retry (mf/use-state 0)
|
(let [page-id (:main-instance-page component)
|
||||||
thumbnail-uri (get-component-thumbnail-uri file-id component)
|
root-id (:main-instance-id component)
|
||||||
handle-error
|
|
||||||
|
retry (mf/use-state 0)
|
||||||
|
|
||||||
|
thumbnail-uri* (mf/with-memo [file-id page-id root-id]
|
||||||
|
(let [object-id (thc/fmt-object-id file-id page-id root-id "component")]
|
||||||
|
(refs/workspace-thumbnail-by-id object-id)))
|
||||||
|
thumbnail-uri (mf/deref thumbnail-uri*)
|
||||||
|
|
||||||
|
on-error
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps @retry)
|
(mf/deps @retry)
|
||||||
(fn []
|
(fn []
|
||||||
(when (@retry < 3)
|
(when (< @retry 3)
|
||||||
(inc retry))))]
|
(inc retry))))]
|
||||||
|
|
||||||
(if (some? thumbnail-uri)
|
(if (some? thumbnail-uri)
|
||||||
[:& component-svg-thumbnail
|
[:& component-svg-thumbnail
|
||||||
{:thumbnail-uri thumbnail-uri
|
{:thumbnail-uri thumbnail-uri
|
||||||
:class class
|
:class class
|
||||||
:on-error handle-error
|
:on-error on-error
|
||||||
:root-shape root-shape
|
:root-shape root-shape
|
||||||
:objects (:objects container)
|
:objects (:objects container)
|
||||||
:show-grids? true}]
|
:show-grids? true}]
|
||||||
|
|
|
@ -103,7 +103,7 @@
|
||||||
fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
|
fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
|
||||||
recent-fonts (mf/deref refs/workspace-recent-fonts)
|
recent-fonts (mf/deref refs/workspace-recent-fonts)
|
||||||
|
|
||||||
full-size? (boolean (and full-size recent-fonts show-recent))
|
full-size? (boolean (and full-size show-recent))
|
||||||
|
|
||||||
select-next
|
select-next
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
|
|
||||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||||
|
|
||||||
rulers? (mf/deref refs/rules?)
|
rulers? (mf/deref refs/rulers?)
|
||||||
hide-toolbar? (mf/deref refs/toolbar-visibility)
|
hide-toolbar? (mf/deref refs/toolbar-visibility)
|
||||||
|
|
||||||
interrupt
|
interrupt
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
height: $s-56;
|
height: $s-56;
|
||||||
padding: $s-8 $s-16;
|
padding: $s-8 $s-16;
|
||||||
border-radius: $s-8;
|
border-radius: $s-8;
|
||||||
|
border: $s-2 solid var(--panel-border-color);
|
||||||
z-index: $z-index-10;
|
z-index: $z-index-10;
|
||||||
background-color: var(--color-background-primary);
|
background-color: var(--color-background-primary);
|
||||||
transition:
|
transition:
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
[app.main.ui.workspace.viewport.outline :as outline]
|
[app.main.ui.workspace.viewport.outline :as outline]
|
||||||
[app.main.ui.workspace.viewport.pixel-overlay :as pixel-overlay]
|
[app.main.ui.workspace.viewport.pixel-overlay :as pixel-overlay]
|
||||||
[app.main.ui.workspace.viewport.presence :as presence]
|
[app.main.ui.workspace.viewport.presence :as presence]
|
||||||
[app.main.ui.workspace.viewport.rules :as rules]
|
[app.main.ui.workspace.viewport.rulers :as rulers]
|
||||||
[app.main.ui.workspace.viewport.scroll-bars :as scroll-bars]
|
[app.main.ui.workspace.viewport.scroll-bars :as scroll-bars]
|
||||||
[app.main.ui.workspace.viewport.selection :as selection]
|
[app.main.ui.workspace.viewport.selection :as selection]
|
||||||
[app.main.ui.workspace.viewport.snap-distances :as snap-distances]
|
[app.main.ui.workspace.viewport.snap-distances :as snap-distances]
|
||||||
|
@ -231,7 +231,7 @@
|
||||||
(or show-distances? mode-inspect?))
|
(or show-distances? mode-inspect?))
|
||||||
show-artboard-names? (contains? layout :display-artboard-names)
|
show-artboard-names? (contains? layout :display-artboard-names)
|
||||||
hide-ui? (contains? layout :hide-ui)
|
hide-ui? (contains? layout :hide-ui)
|
||||||
show-rules? (and (contains? layout :rules) (not hide-ui?))
|
show-rulers? (and (contains? layout :rulers) (not hide-ui?))
|
||||||
|
|
||||||
|
|
||||||
disabled-guides? (or drawing-tool transform drawing-path? node-editing?)
|
disabled-guides? (or drawing-tool transform drawing-path? node-editing?)
|
||||||
|
@ -264,7 +264,7 @@
|
||||||
(:y first-shape)
|
(:y first-shape)
|
||||||
(:y selected-frame))
|
(:y selected-frame))
|
||||||
|
|
||||||
rule-area-size (/ rules/rule-area-size zoom)]
|
rule-area-size (/ rulers/ruler-area-size zoom)]
|
||||||
|
|
||||||
(hooks/setup-dom-events zoom disable-paste in-viewport? workspace-read-only?)
|
(hooks/setup-dom-events zoom disable-paste in-viewport? workspace-read-only?)
|
||||||
(hooks/setup-viewport-size vport viewport-ref)
|
(hooks/setup-viewport-size vport viewport-ref)
|
||||||
|
@ -377,7 +377,7 @@
|
||||||
:on-pointer-up on-pointer-up}
|
:on-pointer-up on-pointer-up}
|
||||||
|
|
||||||
[:defs
|
[:defs
|
||||||
;; This clip is so the handlers are not over the rules
|
;; This clip is so the handlers are not over the rulers
|
||||||
[:clipPath {:id "clip-handlers"}
|
[:clipPath {:id "clip-handlers"}
|
||||||
[:rect {:x (+ (:x vbox) rule-area-size)
|
[:rect {:x (+ (:x vbox) rule-area-size)
|
||||||
:y (+ (:y vbox) rule-area-size)
|
:y (+ (:y vbox) rule-area-size)
|
||||||
|
@ -544,16 +544,16 @@
|
||||||
{:page-id page-id}])
|
{:page-id page-id}])
|
||||||
|
|
||||||
(when-not hide-ui?
|
(when-not hide-ui?
|
||||||
[:& rules/rules
|
[:& rulers/rulers
|
||||||
{:zoom zoom
|
{:zoom zoom
|
||||||
:zoom-inverse zoom-inverse
|
:zoom-inverse zoom-inverse
|
||||||
:vbox vbox
|
:vbox vbox
|
||||||
:selected-shapes selected-shapes
|
:selected-shapes selected-shapes
|
||||||
:offset-x offset-x
|
:offset-x offset-x
|
||||||
:offset-y offset-y
|
:offset-y offset-y
|
||||||
:show-rules? show-rules?}])
|
:show-rulers? show-rulers?}])
|
||||||
|
|
||||||
(when show-rules?
|
(when show-rulers?
|
||||||
[:& guides/viewport-guides
|
[:& guides/viewport-guides
|
||||||
{:zoom zoom
|
{:zoom zoom
|
||||||
:vbox vbox
|
:vbox vbox
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
[app.main.ui.css-cursors :as cur]
|
[app.main.ui.css-cursors :as cur]
|
||||||
[app.main.ui.formats :as fmt]
|
[app.main.ui.formats :as fmt]
|
||||||
[app.main.ui.workspace.viewport.rules :as rules]
|
[app.main.ui.workspace.viewport.rulers :as rulers]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@
|
||||||
|
|
||||||
(defn guide-area-axis
|
(defn guide-area-axis
|
||||||
[pos vbox zoom frame axis]
|
[pos vbox zoom frame axis]
|
||||||
(let [rules-pos (/ rules/rules-pos zoom)
|
(let [rulers-pos (/ rulers/rulers-pos zoom)
|
||||||
guide-active-area (/ guide-active-area zoom)]
|
guide-active-area (/ guide-active-area zoom)]
|
||||||
(cond
|
(cond
|
||||||
(and (some? frame) (= axis :x))
|
(and (some? frame) (= axis :x))
|
||||||
|
@ -146,12 +146,12 @@
|
||||||
|
|
||||||
(= axis :x)
|
(= axis :x)
|
||||||
{:x (- pos (/ guide-active-area 2))
|
{:x (- pos (/ guide-active-area 2))
|
||||||
:y (+ (:y vbox) rules-pos)
|
:y (+ (:y vbox) rulers-pos)
|
||||||
:width guide-active-area
|
:width guide-active-area
|
||||||
:height (:height vbox)}
|
:height (:height vbox)}
|
||||||
|
|
||||||
:else
|
:else
|
||||||
{:x (+ (:x vbox) rules-pos)
|
{:x (+ (:x vbox) rulers-pos)
|
||||||
:y (- pos (/ guide-active-area 2))
|
:y (- pos (/ guide-active-area 2))
|
||||||
:width (:width vbox)
|
:width (:width vbox)
|
||||||
:height guide-active-area})))
|
:height guide-active-area})))
|
||||||
|
@ -198,23 +198,23 @@
|
||||||
|
|
||||||
(defn guide-pill-axis
|
(defn guide-pill-axis
|
||||||
[pos vbox zoom axis]
|
[pos vbox zoom axis]
|
||||||
(let [rules-pos (/ rules/rules-pos zoom)
|
(let [rulers-pos (/ rulers/rulers-pos zoom)
|
||||||
guide-pill-width (/ guide-pill-width zoom)
|
guide-pill-width (/ guide-pill-width zoom)
|
||||||
guide-pill-height (/ guide-pill-height zoom)]
|
guide-pill-height (/ guide-pill-height zoom)]
|
||||||
|
|
||||||
(if (= axis :x)
|
(if (= axis :x)
|
||||||
{:rect-x (- pos (/ guide-pill-width 2))
|
{:rect-x (- pos (/ guide-pill-width 2))
|
||||||
:rect-y (+ (:y vbox) rules-pos (- (/ guide-pill-width 2)) (/ 3 zoom))
|
:rect-y (+ (:y vbox) rulers-pos (- (/ guide-pill-width 2)) (/ 3 zoom))
|
||||||
:rect-width guide-pill-width
|
:rect-width guide-pill-width
|
||||||
:rect-height guide-pill-height
|
:rect-height guide-pill-height
|
||||||
:text-x pos
|
:text-x pos
|
||||||
:text-y (+ (:y vbox) rules-pos (- (/ 3 zoom)))}
|
:text-y (+ (:y vbox) rulers-pos (- (/ 3 zoom)))}
|
||||||
|
|
||||||
{:rect-x (+ (:x vbox) rules-pos (- (/ guide-pill-height 2)) (- (/ 4 zoom)))
|
{:rect-x (+ (:x vbox) rulers-pos (- (/ guide-pill-height 2)) (- (/ 4 zoom)))
|
||||||
:rect-y (- pos (/ guide-pill-width 2))
|
:rect-y (- pos (/ guide-pill-width 2))
|
||||||
:rect-width guide-pill-height
|
:rect-width guide-pill-height
|
||||||
:rect-height guide-pill-width
|
:rect-height guide-pill-width
|
||||||
:text-x (+ (:x vbox) rules-pos (- (/ 3 zoom)))
|
:text-x (+ (:x vbox) rulers-pos (- (/ 3 zoom)))
|
||||||
:text-y pos})))
|
:text-y pos})))
|
||||||
|
|
||||||
(defn guide-inside-vbox?
|
(defn guide-inside-vbox?
|
||||||
|
@ -222,7 +222,7 @@
|
||||||
(partial guide-inside-vbox? zoom vbox))
|
(partial guide-inside-vbox? zoom vbox))
|
||||||
|
|
||||||
([zoom {:keys [x y width height]} {:keys [axis position]}]
|
([zoom {:keys [x y width height]} {:keys [axis position]}]
|
||||||
(let [rule-area-size (/ rules/rule-area-size zoom)
|
(let [rule-area-size (/ rulers/ruler-area-size zoom)
|
||||||
x1 x
|
x1 x
|
||||||
x2 (+ x width)
|
x2 (+ x width)
|
||||||
y1 y
|
y1 y
|
||||||
|
@ -376,8 +376,8 @@
|
||||||
:text-anchor "middle"
|
:text-anchor "middle"
|
||||||
:dominant-baseline "middle"
|
:dominant-baseline "middle"
|
||||||
:transform (when (= axis :y) (str "rotate(-90 " text-x "," text-y ")"))
|
:transform (when (= axis :y) (str "rotate(-90 " text-x "," text-y ")"))
|
||||||
:style {:font-size (/ rules/font-size zoom)
|
:style {:font-size (/ rulers/font-size zoom)
|
||||||
:font-family rules/font-family
|
:font-family rulers/font-family
|
||||||
:fill colors/black}}
|
:fill colors/black}}
|
||||||
;; If the guide is associated to a frame we show the position relative to the frame
|
;; If the guide is associated to a frame we show the position relative to the frame
|
||||||
(fmt/format-number (- pos (if (= axis :x) (:x frame) (:y frame))))]]))])))
|
(fmt/format-number (- pos (if (= axis :x) (:x frame) (:y frame))))]]))])))
|
||||||
|
|
347
frontend/src/app/main/ui/workspace/viewport/rulers.cljs
Normal file
347
frontend/src/app/main/ui/workspace/viewport/rulers.cljs
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.ui.workspace.viewport.rulers
|
||||||
|
(: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.ui.formats :as fmt]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
|
[app.util.object :as obj]
|
||||||
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(def rulers-pos 15)
|
||||||
|
(def rulers-size 4)
|
||||||
|
(def rulers-width 1)
|
||||||
|
(def ruler-area-size 22)
|
||||||
|
(def ruler-area-half-size (/ ruler-area-size 2))
|
||||||
|
(def rulers-background "var(--panel-background-color)")
|
||||||
|
(def selection-area-color "var(--color-accent-tertiary)")
|
||||||
|
(def selection-area-opacity 0.3)
|
||||||
|
(def over-number-size 100)
|
||||||
|
(def over-number-opacity 0.8)
|
||||||
|
(def over-number-percent 0.75)
|
||||||
|
|
||||||
|
(def font-size 12)
|
||||||
|
(def font-family "worksans")
|
||||||
|
(def font-color "var(--layer-row-foreground-color)")
|
||||||
|
(def canvas-border-radius 12)
|
||||||
|
|
||||||
|
;; ----------------
|
||||||
|
;; RULERS
|
||||||
|
;; ----------------
|
||||||
|
|
||||||
|
(defn- calculate-step-size
|
||||||
|
[zoom]
|
||||||
|
(cond
|
||||||
|
(< 0 zoom 0.008) 10000
|
||||||
|
(< 0.008 zoom 0.015) 5000
|
||||||
|
(< 0.015 zoom 0.04) 2500
|
||||||
|
(< 0.04 zoom 0.07) 1000
|
||||||
|
(< 0.07 zoom 0.2) 500
|
||||||
|
(< 0.2 zoom 0.5) 250
|
||||||
|
(< 0.5 zoom 1) 100
|
||||||
|
(<= 1 zoom 2) 50
|
||||||
|
(< 2 zoom 4) 25
|
||||||
|
(< 4 zoom 6) 10
|
||||||
|
(< 6 zoom 15) 5
|
||||||
|
(< 15 zoom 25) 2
|
||||||
|
(< 25 zoom) 1
|
||||||
|
:else 1))
|
||||||
|
|
||||||
|
(defn get-clip-area
|
||||||
|
[vbox zoom-inverse axis]
|
||||||
|
(if (= axis :x)
|
||||||
|
(let [x (+ (:x vbox) (* 25 zoom-inverse))
|
||||||
|
y (:y vbox)
|
||||||
|
width (- (:width vbox) (* 21 zoom-inverse))
|
||||||
|
height (* 25 zoom-inverse)]
|
||||||
|
{:x x :y y :width width :height height})
|
||||||
|
|
||||||
|
(let [x (:x vbox)
|
||||||
|
y (+ (:y vbox) (* 25 zoom-inverse))
|
||||||
|
width (* 25 zoom-inverse)
|
||||||
|
height (- (:height vbox) (* 21 zoom-inverse))]
|
||||||
|
{:x x :y y :width width :height height})))
|
||||||
|
|
||||||
|
(defn get-background-area
|
||||||
|
[vbox zoom-inverse axis]
|
||||||
|
(if (= axis :x)
|
||||||
|
(let [x (:x vbox)
|
||||||
|
y (:y vbox)
|
||||||
|
width (:width vbox)
|
||||||
|
height (* ruler-area-size zoom-inverse)]
|
||||||
|
{:x x :y y :width width :height height})
|
||||||
|
|
||||||
|
(let [x (:x vbox)
|
||||||
|
y (+ (:y vbox) (* ruler-area-size zoom-inverse))
|
||||||
|
width (* ruler-area-size zoom-inverse)
|
||||||
|
height (- (:height vbox) (* 21 zoom-inverse))]
|
||||||
|
{:x x :y y :width width :height height})))
|
||||||
|
|
||||||
|
(defn get-ruler-params
|
||||||
|
[vbox axis]
|
||||||
|
(if (= axis :x)
|
||||||
|
(let [start (:x vbox)
|
||||||
|
end (+ start (:width vbox))]
|
||||||
|
{:start start :end end})
|
||||||
|
|
||||||
|
(let [start (:y vbox)
|
||||||
|
end (+ start (:height vbox))]
|
||||||
|
{:start start :end end})))
|
||||||
|
|
||||||
|
(defn get-ruler-axis
|
||||||
|
[val vbox zoom-inverse axis]
|
||||||
|
(let [rulers-pos (* rulers-pos zoom-inverse)
|
||||||
|
rulers-size (* rulers-size zoom-inverse)]
|
||||||
|
(if (= axis :x)
|
||||||
|
{:text-x val
|
||||||
|
:text-y (+ (:y vbox) (- rulers-pos (* 4 zoom-inverse)))
|
||||||
|
:line-x1 val
|
||||||
|
:line-y1 (+ (:y vbox) rulers-pos (* 2 zoom-inverse))
|
||||||
|
:line-x2 val
|
||||||
|
:line-y2 (+ (:y vbox) rulers-pos (* 2 zoom-inverse) rulers-size)}
|
||||||
|
|
||||||
|
{:text-x (+ (:x vbox) (- rulers-pos (* 4 zoom-inverse)))
|
||||||
|
:text-y val
|
||||||
|
:line-x1 (+ (:x vbox) rulers-pos (* 2 zoom-inverse))
|
||||||
|
:line-y1 val
|
||||||
|
:line-x2 (+ (:x vbox) rulers-pos (* 2 zoom-inverse) rulers-size)
|
||||||
|
:line-y2 val})))
|
||||||
|
|
||||||
|
(defn rulers-outside-path
|
||||||
|
"Path data for the viewport outside"
|
||||||
|
[x1 y1 x2 y2]
|
||||||
|
(dm/str
|
||||||
|
"M" x1 "," y1
|
||||||
|
"L" x2 "," y1
|
||||||
|
"L" x2 "," y2
|
||||||
|
"L" x1 "," y2
|
||||||
|
"Z"))
|
||||||
|
|
||||||
|
(defn rulers-inside-path
|
||||||
|
"Calculates the path for the inside of the viewport frame"
|
||||||
|
[x1 y1 x2 y2 br bw]
|
||||||
|
(dm/str
|
||||||
|
"M" (+ x1 bw) "," (+ y1 bw br)
|
||||||
|
"Q" (+ x1 bw) "," (+ y1 bw) "," (+ x1 bw br) "," (+ y1 bw)
|
||||||
|
|
||||||
|
"L" (- x2 br) "," (+ y1 bw)
|
||||||
|
"Q" x2 "," (+ y1 bw) "," x2 "," (+ y1 bw br)
|
||||||
|
|
||||||
|
"L" x2 "," (- y2 br)
|
||||||
|
"Q" x2 "," y2 "," (- x2 br) "," y2
|
||||||
|
|
||||||
|
"L" (+ x1 bw br) "," y2
|
||||||
|
"Q" (+ x1 bw) "," y2 "," (+ x1 bw) "," (- y2 br)
|
||||||
|
|
||||||
|
"Z"))
|
||||||
|
|
||||||
|
(mf/defc rulers-text
|
||||||
|
"Draws the text for the rulers in a specific axis"
|
||||||
|
[{:keys [vbox step offset axis zoom-inverse]}]
|
||||||
|
(let [clip-id (str "clip-ruler-" (d/name axis))
|
||||||
|
{:keys [start end]} (get-ruler-params vbox axis)
|
||||||
|
minv (max start -100000)
|
||||||
|
minv (* (mth/ceil (/ minv step)) step)
|
||||||
|
maxv (min end 100000)
|
||||||
|
maxv (* (mth/floor (/ maxv step)) step)
|
||||||
|
|
||||||
|
;; These extra operations ensure that we are selecting a frame its initial location is rendered in the ruler
|
||||||
|
minv (+ minv (mod offset step))
|
||||||
|
maxv (+ maxv (mod offset step))]
|
||||||
|
|
||||||
|
[:g.rulers {:clipPath (str "url(#" clip-id ")")}
|
||||||
|
[:defs
|
||||||
|
[:clipPath {:id clip-id}
|
||||||
|
(let [{:keys [x y width height]} (get-clip-area vbox zoom-inverse axis)]
|
||||||
|
[:rect {:x x :y y :width width :height height}])]]
|
||||||
|
|
||||||
|
(for [step-val (range minv (inc maxv) step)]
|
||||||
|
(let [{:keys [text-x text-y line-x1 line-y1 line-x2 line-y2]}
|
||||||
|
(get-ruler-axis step-val vbox zoom-inverse axis)]
|
||||||
|
[:* {:key (dm/str "text-" (d/name axis) "-" step-val)}
|
||||||
|
[:text {:x text-x
|
||||||
|
:y text-y
|
||||||
|
:text-anchor "middle"
|
||||||
|
:dominant-baseline "middle"
|
||||||
|
:transform (when (= axis :y) (str "rotate(-90 " text-x "," text-y ")"))
|
||||||
|
:style {:font-size (* font-size zoom-inverse)
|
||||||
|
:font-family font-family
|
||||||
|
:fill font-color}}
|
||||||
|
;; If the guide is associated to a frame we show the position relative to the frame
|
||||||
|
(fmt/format-number (- step-val offset))]
|
||||||
|
|
||||||
|
[:line {:key (str "line-" (d/name axis) "-" step-val)
|
||||||
|
:x1 line-x1
|
||||||
|
:y1 line-y1
|
||||||
|
:x2 line-x2
|
||||||
|
:y2 line-y2
|
||||||
|
:style {:stroke font-color
|
||||||
|
:stroke-width rulers-width}}]]))]))
|
||||||
|
|
||||||
|
(mf/defc viewport-frame
|
||||||
|
[{:keys [show-rulers? zoom zoom-inverse vbox offset-x offset-y]}]
|
||||||
|
|
||||||
|
(let [{:keys [width height] x1 :x y1 :y} vbox
|
||||||
|
x2 (+ x1 width)
|
||||||
|
y2 (+ y1 height)
|
||||||
|
bw (if show-rulers? (* ruler-area-size zoom-inverse) 0)
|
||||||
|
br (/ canvas-border-radius zoom)
|
||||||
|
bs (* 4 zoom-inverse)]
|
||||||
|
[:*
|
||||||
|
[:g.viewport-frame-background
|
||||||
|
;; This goes behind because if it goes in front the background bleeds through
|
||||||
|
[:path {:d (rulers-inside-path x1 y1 x2 y2 br bw)
|
||||||
|
:fill "none"
|
||||||
|
:stroke-width bs
|
||||||
|
:stroke "var(--panel-border-color)"}]
|
||||||
|
|
||||||
|
[:path {:d (dm/str (rulers-outside-path x1 y1 x2 y2)
|
||||||
|
(rulers-inside-path x1 y1 x2 y2 br bw))
|
||||||
|
:fill-rule "evenodd"
|
||||||
|
:fill rulers-background}]]
|
||||||
|
|
||||||
|
(when show-rulers?
|
||||||
|
(let [step (calculate-step-size zoom)]
|
||||||
|
[:g.viewport-frame-rulers
|
||||||
|
[:& rulers-text {:vbox vbox :offset offset-x :step step :zoom-inverse zoom-inverse :axis :x}]
|
||||||
|
[:& rulers-text {:vbox vbox :offset offset-y :step step :zoom-inverse zoom-inverse :axis :y}]]))]))
|
||||||
|
|
||||||
|
(mf/defc selection-area
|
||||||
|
[{:keys [vbox zoom-inverse selection-rect offset-x offset-y]}]
|
||||||
|
;; When using the format-number callls we consider if the guide is associated to a frame and we show the position relative to it with the offset
|
||||||
|
[:g.selection-area
|
||||||
|
[:defs
|
||||||
|
[:linearGradient {:id "selection-gradient-start"}
|
||||||
|
[:stop {:offset "0%" :stop-color rulers-background :stop-opacity 0}]
|
||||||
|
[:stop {:offset "40%" :stop-color rulers-background :stop-opacity 1}]
|
||||||
|
[:stop {:offset "100%" :stop-color rulers-background :stop-opacity 1}]]
|
||||||
|
|
||||||
|
[:linearGradient {:id "selection-gradient-end"}
|
||||||
|
[:stop {:offset "0%" :stop-color rulers-background :stop-opacity 1}]
|
||||||
|
[:stop {:offset "60%" :stop-color rulers-background :stop-opacity 1}]
|
||||||
|
[:stop {:offset "100%" :stop-color rulers-background :stop-opacity 0}]]]
|
||||||
|
[:g
|
||||||
|
[:rect {:x (- (:x selection-rect) (* (* over-number-size over-number-percent) zoom-inverse))
|
||||||
|
:y (:y vbox)
|
||||||
|
:width (* over-number-size zoom-inverse)
|
||||||
|
:height (* ruler-area-size zoom-inverse)
|
||||||
|
:fill "url('#selection-gradient-start')"}]
|
||||||
|
|
||||||
|
[:rect {:x (- (:x2 selection-rect) (* over-number-size (- 1 over-number-percent)))
|
||||||
|
:y (:y vbox)
|
||||||
|
:width (* over-number-size zoom-inverse)
|
||||||
|
:height (* ruler-area-size zoom-inverse)
|
||||||
|
:fill "url('#selection-gradient-end')"}]
|
||||||
|
|
||||||
|
[:rect {:x (:x selection-rect)
|
||||||
|
:y (:y vbox)
|
||||||
|
:width (:width selection-rect)
|
||||||
|
:height (* ruler-area-size zoom-inverse)
|
||||||
|
:style {:fill selection-area-color
|
||||||
|
:fill-opacity selection-area-opacity}}]
|
||||||
|
|
||||||
|
[:text {:x (- (:x1 selection-rect) (* 4 zoom-inverse))
|
||||||
|
:y (+ (:y vbox) (* 10.6 zoom-inverse))
|
||||||
|
:text-anchor "end"
|
||||||
|
:dominant-baseline "middle"
|
||||||
|
:style {:font-size (* font-size zoom-inverse)
|
||||||
|
:font-family font-family
|
||||||
|
:fill selection-area-color}}
|
||||||
|
(fmt/format-number (- (:x1 selection-rect) offset-x))]
|
||||||
|
|
||||||
|
[:text {:x (+ (:x2 selection-rect) (* 4 zoom-inverse))
|
||||||
|
:y (+ (:y vbox) (* 10.6 zoom-inverse))
|
||||||
|
:text-anchor "start"
|
||||||
|
:dominant-baseline "middle"
|
||||||
|
:style {:font-size (* font-size zoom-inverse)
|
||||||
|
:font-family font-family
|
||||||
|
:fill selection-area-color}}
|
||||||
|
(fmt/format-number (- (:x2 selection-rect) offset-x))]]
|
||||||
|
|
||||||
|
(let [center-x (+ (:x vbox) (* ruler-area-half-size zoom-inverse))
|
||||||
|
center-y (- (+ (:y selection-rect) (/ (:height selection-rect) 2)) (* ruler-area-half-size zoom-inverse))]
|
||||||
|
|
||||||
|
[:g {:transform (str "rotate(-90 " center-x "," center-y ")")}
|
||||||
|
[:rect {:x (- center-x (/ (:height selection-rect) 2) (* ruler-area-half-size zoom-inverse))
|
||||||
|
:y (- center-y (* ruler-area-half-size zoom-inverse))
|
||||||
|
:width (:height selection-rect)
|
||||||
|
:height (* ruler-area-size zoom-inverse)
|
||||||
|
:style {:fill selection-area-color
|
||||||
|
:fill-opacity selection-area-opacity}}]
|
||||||
|
|
||||||
|
[:rect {:x (- center-x (/ (:height selection-rect) 2) (* ruler-area-half-size zoom-inverse) (* over-number-size zoom-inverse))
|
||||||
|
:y (- center-y (* ruler-area-half-size zoom-inverse))
|
||||||
|
:width (* over-number-size zoom-inverse)
|
||||||
|
:height (* ruler-area-size zoom-inverse)
|
||||||
|
:style {:fill rulers-background
|
||||||
|
:fill-opacity over-number-opacity}}]
|
||||||
|
|
||||||
|
[:rect {:x (+ (- center-x (/ (:height selection-rect) 2) (* ruler-area-half-size zoom-inverse)) (:height selection-rect))
|
||||||
|
:y (- center-y (* ruler-area-half-size zoom-inverse))
|
||||||
|
:width (* over-number-size zoom-inverse)
|
||||||
|
:height (* ruler-area-size zoom-inverse)
|
||||||
|
:style {:fill rulers-background
|
||||||
|
:fill-opacity over-number-opacity}}]
|
||||||
|
|
||||||
|
[:text {:x (- center-x (/ (:height selection-rect) 2) (* 15 zoom-inverse))
|
||||||
|
:y center-y
|
||||||
|
:text-anchor "end"
|
||||||
|
:dominant-baseline "middle"
|
||||||
|
:style {:font-size (* font-size zoom-inverse)
|
||||||
|
:font-family font-family
|
||||||
|
:fill selection-area-color}}
|
||||||
|
(fmt/format-number (- (:y2 selection-rect) offset-y))]
|
||||||
|
|
||||||
|
[:text {:x (+ center-x (/ (:height selection-rect) 2))
|
||||||
|
:y center-y
|
||||||
|
:text-anchor "start"
|
||||||
|
:dominant-baseline "middle"
|
||||||
|
:style {:font-size (* font-size zoom-inverse)
|
||||||
|
:font-family font-family
|
||||||
|
:fill selection-area-color}}
|
||||||
|
(fmt/format-number (- (:y1 selection-rect) offset-y))]])])
|
||||||
|
|
||||||
|
(mf/defc rulers
|
||||||
|
{::mf/wrap-props false
|
||||||
|
::mf/wrap [#(mf/memo' % (mf/check-props ["zoom" "vbox" "selected-shapes" "show-rulers?"]))]}
|
||||||
|
[props]
|
||||||
|
(let [zoom (obj/get props "zoom")
|
||||||
|
zoom-inverse (obj/get props "zoom-inverse")
|
||||||
|
vbox (obj/get props "vbox")
|
||||||
|
offset-x (obj/get props "offset-x")
|
||||||
|
offset-y (obj/get props "offset-y")
|
||||||
|
selected-shapes (-> (obj/get props "selected-shapes")
|
||||||
|
(hooks/use-equal-memo))
|
||||||
|
show-rulers? (obj/get props "show-rulers?")
|
||||||
|
|
||||||
|
selection-rect
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps selected-shapes)
|
||||||
|
#(when (d/not-empty? selected-shapes)
|
||||||
|
(gsh/shapes->rect selected-shapes)))]
|
||||||
|
|
||||||
|
(when (some? vbox)
|
||||||
|
[:g.viewport-frame {:pointer-events "none"}
|
||||||
|
[:& viewport-frame
|
||||||
|
{:show-rulers? show-rulers?
|
||||||
|
:zoom zoom
|
||||||
|
:zoom-inverse zoom-inverse
|
||||||
|
:vbox vbox
|
||||||
|
:offset-x offset-x
|
||||||
|
:offset-y offset-y}]
|
||||||
|
|
||||||
|
(when (and show-rulers? (some? selection-rect))
|
||||||
|
[:& selection-area
|
||||||
|
{:zoom zoom
|
||||||
|
:zoom-inverse zoom-inverse
|
||||||
|
:vbox vbox
|
||||||
|
:selection-rect selection-rect
|
||||||
|
:offset-x offset-x
|
||||||
|
:offset-y offset-y}])])))
|
|
@ -1,350 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) KALEIDOS INC
|
|
||||||
|
|
||||||
(ns app.main.ui.workspace.viewport.rules
|
|
||||||
(: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.ui.formats :as fmt]
|
|
||||||
[app.main.ui.hooks :as hooks]
|
|
||||||
[app.util.object :as obj]
|
|
||||||
[rumext.v2 :as mf]))
|
|
||||||
|
|
||||||
(def rules-pos 15)
|
|
||||||
(def rules-size 4)
|
|
||||||
(def rules-width 1)
|
|
||||||
(def rule-area-size 22)
|
|
||||||
(def rule-area-half-size (/ rule-area-size 2))
|
|
||||||
(def rules-background "var(--panel-background-color)")
|
|
||||||
(def selection-area-color "var(--color-accent-tertiary)")
|
|
||||||
(def selection-area-opacity 0.3)
|
|
||||||
(def over-number-size 100)
|
|
||||||
(def over-number-opacity 0.8)
|
|
||||||
(def over-number-percent 0.75)
|
|
||||||
|
|
||||||
(def font-size 12)
|
|
||||||
(def font-family "worksans")
|
|
||||||
(def font-color "var(--layer-row-foreground-color)")
|
|
||||||
(def canvas-border-radius 12)
|
|
||||||
|
|
||||||
;; ----------------
|
|
||||||
;; RULES
|
|
||||||
;; ----------------
|
|
||||||
|
|
||||||
(defn- calculate-step-size
|
|
||||||
[zoom]
|
|
||||||
(cond
|
|
||||||
(< 0 zoom 0.008) 10000
|
|
||||||
(< 0.008 zoom 0.015) 5000
|
|
||||||
(< 0.015 zoom 0.04) 2500
|
|
||||||
(< 0.04 zoom 0.07) 1000
|
|
||||||
(< 0.07 zoom 0.2) 500
|
|
||||||
(< 0.2 zoom 0.5) 250
|
|
||||||
(< 0.5 zoom 1) 100
|
|
||||||
(<= 1 zoom 2) 50
|
|
||||||
(< 2 zoom 4) 25
|
|
||||||
(< 4 zoom 6) 10
|
|
||||||
(< 6 zoom 15) 5
|
|
||||||
(< 15 zoom 25) 2
|
|
||||||
(< 25 zoom) 1
|
|
||||||
:else 1))
|
|
||||||
|
|
||||||
(defn get-clip-area
|
|
||||||
[vbox zoom-inverse axis]
|
|
||||||
(if (= axis :x)
|
|
||||||
(let [x (+ (:x vbox) (* 25 zoom-inverse))
|
|
||||||
y (:y vbox)
|
|
||||||
width (- (:width vbox) (* 21 zoom-inverse))
|
|
||||||
height (* 25 zoom-inverse)]
|
|
||||||
{:x x :y y :width width :height height})
|
|
||||||
|
|
||||||
(let [x (:x vbox)
|
|
||||||
y (+ (:y vbox) (* 25 zoom-inverse))
|
|
||||||
width (* 25 zoom-inverse)
|
|
||||||
height (- (:height vbox) (* 21 zoom-inverse))]
|
|
||||||
{:x x :y y :width width :height height})))
|
|
||||||
|
|
||||||
(defn get-background-area
|
|
||||||
[vbox zoom-inverse axis]
|
|
||||||
(if (= axis :x)
|
|
||||||
(let [x (:x vbox)
|
|
||||||
y (:y vbox)
|
|
||||||
width (:width vbox)
|
|
||||||
height (* rule-area-size zoom-inverse)]
|
|
||||||
{:x x :y y :width width :height height})
|
|
||||||
|
|
||||||
(let [x (:x vbox)
|
|
||||||
y (+ (:y vbox) (* rule-area-size zoom-inverse))
|
|
||||||
width (* rule-area-size zoom-inverse)
|
|
||||||
height (- (:height vbox) (* 21 zoom-inverse))]
|
|
||||||
{:x x :y y :width width :height height})))
|
|
||||||
|
|
||||||
(defn get-rule-params
|
|
||||||
[vbox axis]
|
|
||||||
(if (= axis :x)
|
|
||||||
(let [start (:x vbox)
|
|
||||||
end (+ start (:width vbox))]
|
|
||||||
{:start start :end end})
|
|
||||||
|
|
||||||
(let [start (:y vbox)
|
|
||||||
end (+ start (:height vbox))]
|
|
||||||
{:start start :end end})))
|
|
||||||
|
|
||||||
(defn get-rule-axis
|
|
||||||
[val vbox zoom-inverse axis]
|
|
||||||
(let [rules-pos (* rules-pos zoom-inverse)
|
|
||||||
rules-size (* rules-size zoom-inverse)]
|
|
||||||
(if (= axis :x)
|
|
||||||
{:text-x val
|
|
||||||
:text-y (+ (:y vbox) (- rules-pos (* 4 zoom-inverse)))
|
|
||||||
:line-x1 val
|
|
||||||
:line-y1 (+ (:y vbox) rules-pos (* 2 zoom-inverse))
|
|
||||||
:line-x2 val
|
|
||||||
:line-y2 (+ (:y vbox) rules-pos (* 2 zoom-inverse) rules-size)}
|
|
||||||
|
|
||||||
{:text-x (+ (:x vbox) (- rules-pos (* 4 zoom-inverse)))
|
|
||||||
:text-y val
|
|
||||||
:line-x1 (+ (:x vbox) rules-pos (* 2 zoom-inverse))
|
|
||||||
:line-y1 val
|
|
||||||
:line-x2 (+ (:x vbox) rules-pos (* 2 zoom-inverse) rules-size)
|
|
||||||
:line-y2 val})))
|
|
||||||
|
|
||||||
(defn- round-corner-path-tl
|
|
||||||
[cx cy radius]
|
|
||||||
(dm/str
|
|
||||||
"M" cx "," cy
|
|
||||||
"L" (+ cx radius) "," cy
|
|
||||||
"Q" cx "," cy "," cx "," (+ cy radius)
|
|
||||||
"Z"))
|
|
||||||
|
|
||||||
(defn- round-corner-path-tr
|
|
||||||
[cx cy radius]
|
|
||||||
(dm/str
|
|
||||||
"M" cx "," cy
|
|
||||||
"L" (+ cx radius) "," cy
|
|
||||||
"L" (+ cx radius) "," (+ cy radius)
|
|
||||||
"Q" (+ cx radius) "," cy "," cx "," cy
|
|
||||||
"Z"))
|
|
||||||
|
|
||||||
(defn- round-corner-path-bl
|
|
||||||
[cx cy radius]
|
|
||||||
(dm/str
|
|
||||||
"M" cx "," cy
|
|
||||||
"Q" cx "," (+ cy radius) "," (+ cx radius) "," (+ cy radius)
|
|
||||||
"L" cx "," (+ cy radius)
|
|
||||||
"Z"))
|
|
||||||
|
|
||||||
(defn- round-corner-path-br
|
|
||||||
[cx cy radius]
|
|
||||||
(dm/str
|
|
||||||
"M" (+ cx radius) "," cy
|
|
||||||
"L" (+ cx radius) "," (+ cy radius)
|
|
||||||
"L" cx "," (+ cy radius)
|
|
||||||
"Q" (+ cx radius) "," (+ cy radius) "," (+ cx radius) "," cy
|
|
||||||
"Z"))
|
|
||||||
|
|
||||||
(mf/defc rules-axis
|
|
||||||
[{:keys [zoom zoom-inverse vbox axis offset]}]
|
|
||||||
(let [rules-width (* rules-width zoom-inverse)
|
|
||||||
step (calculate-step-size zoom)
|
|
||||||
clip-id (str "clip-rule-" (d/name axis))
|
|
||||||
font-color font-color
|
|
||||||
rules-background rules-background]
|
|
||||||
|
|
||||||
[:*
|
|
||||||
(let [{:keys [x y width height]} (get-background-area vbox zoom-inverse axis)]
|
|
||||||
[:rect {:x x :y y :width width :height height :style {:fill rules-background}}])
|
|
||||||
|
|
||||||
[:g.rules {:clipPath (str "url(#" clip-id ")")}
|
|
||||||
|
|
||||||
[:defs
|
|
||||||
[:clipPath {:id clip-id}
|
|
||||||
(let [{:keys [x y width height]} (get-clip-area vbox zoom-inverse axis)]
|
|
||||||
[:rect {:x x :y y :width width :height height}])]]
|
|
||||||
|
|
||||||
(let [{:keys [start end]} (get-rule-params vbox axis)
|
|
||||||
minv (max start -100000)
|
|
||||||
minv (* (mth/ceil (/ minv step)) step)
|
|
||||||
maxv (min end 100000)
|
|
||||||
maxv (* (mth/floor (/ maxv step)) step)
|
|
||||||
|
|
||||||
;; These extra operations ensure that we are selecting a frame its initial location is rendered in the rule
|
|
||||||
minv (+ minv (mod offset step))
|
|
||||||
maxv (+ maxv (mod offset step))]
|
|
||||||
|
|
||||||
(for [step-val (range minv (inc maxv) step)]
|
|
||||||
(let [{:keys [text-x text-y line-x1 line-y1 line-x2 line-y2]}
|
|
||||||
(get-rule-axis step-val vbox zoom-inverse axis)]
|
|
||||||
[:* {:key (dm/str "text-" (d/name axis) "-" step-val)}
|
|
||||||
[:text {:x text-x
|
|
||||||
:y text-y
|
|
||||||
:text-anchor "middle"
|
|
||||||
:dominant-baseline "middle"
|
|
||||||
:transform (when (= axis :y) (str "rotate(-90 " text-x "," text-y ")"))
|
|
||||||
:style {:font-size (* font-size zoom-inverse)
|
|
||||||
:font-family font-family
|
|
||||||
:fill font-color}}
|
|
||||||
;; If the guide is associated to a frame we show the position relative to the frame
|
|
||||||
(fmt/format-number (- step-val offset))]
|
|
||||||
|
|
||||||
[:line {:key (str "line-" (d/name axis) "-" step-val)
|
|
||||||
:x1 line-x1
|
|
||||||
:y1 line-y1
|
|
||||||
:x2 line-x2
|
|
||||||
:y2 line-y2
|
|
||||||
:style {:stroke font-color
|
|
||||||
:stroke-width rules-width}}]])))]]))
|
|
||||||
|
|
||||||
(mf/defc selection-area
|
|
||||||
[{:keys [vbox zoom-inverse selection-rect offset-x offset-y]}]
|
|
||||||
;; When using the format-number callls we consider if the guide is associated to a frame and we show the position relative to it with the offset
|
|
||||||
(let [rules-background rules-background]
|
|
||||||
[:g.selection-area
|
|
||||||
[:defs
|
|
||||||
[:linearGradient {:id "selection-gradient-start"}
|
|
||||||
[:stop {:offset "0%" :stop-color rules-background :stop-opacity 0}]
|
|
||||||
[:stop {:offset "40%" :stop-color rules-background :stop-opacity 1}]
|
|
||||||
[:stop {:offset "100%" :stop-color rules-background :stop-opacity 1}]]
|
|
||||||
|
|
||||||
[:linearGradient {:id "selection-gradient-end"}
|
|
||||||
[:stop {:offset "0%" :stop-color rules-background :stop-opacity 1}]
|
|
||||||
[:stop {:offset "60%" :stop-color rules-background :stop-opacity 1}]
|
|
||||||
[:stop {:offset "100%" :stop-color rules-background :stop-opacity 0}]]]
|
|
||||||
[:g
|
|
||||||
[:rect {:x (- (:x selection-rect) (* (* over-number-size over-number-percent) zoom-inverse))
|
|
||||||
:y (:y vbox)
|
|
||||||
:width (* over-number-size zoom-inverse)
|
|
||||||
:height (* rule-area-size zoom-inverse)
|
|
||||||
:fill "url('#selection-gradient-start')"}]
|
|
||||||
|
|
||||||
[:rect {:x (- (:x2 selection-rect) (* over-number-size (- 1 over-number-percent)))
|
|
||||||
:y (:y vbox)
|
|
||||||
:width (* over-number-size zoom-inverse)
|
|
||||||
:height (* rule-area-size zoom-inverse)
|
|
||||||
:fill "url('#selection-gradient-end')"}]
|
|
||||||
|
|
||||||
[:rect {:x (:x selection-rect)
|
|
||||||
:y (:y vbox)
|
|
||||||
:width (:width selection-rect)
|
|
||||||
:height (* rule-area-size zoom-inverse)
|
|
||||||
:style {:fill selection-area-color
|
|
||||||
:fill-opacity selection-area-opacity}}]
|
|
||||||
|
|
||||||
[:text {:x (- (:x1 selection-rect) (* 4 zoom-inverse))
|
|
||||||
:y (+ (:y vbox) (* 10.6 zoom-inverse))
|
|
||||||
:text-anchor "end"
|
|
||||||
:dominant-baseline "middle"
|
|
||||||
:style {:font-size (* font-size zoom-inverse)
|
|
||||||
:font-family font-family
|
|
||||||
:fill selection-area-color}}
|
|
||||||
(fmt/format-number (- (:x1 selection-rect) offset-x))]
|
|
||||||
|
|
||||||
[:text {:x (+ (:x2 selection-rect) (* 4 zoom-inverse))
|
|
||||||
:y (+ (:y vbox) (* 10.6 zoom-inverse))
|
|
||||||
:text-anchor "start"
|
|
||||||
:dominant-baseline "middle"
|
|
||||||
:style {:font-size (* font-size zoom-inverse)
|
|
||||||
:font-family font-family
|
|
||||||
:fill selection-area-color}}
|
|
||||||
(fmt/format-number (- (:x2 selection-rect) offset-x))]]
|
|
||||||
|
|
||||||
(let [center-x (+ (:x vbox) (* rule-area-half-size zoom-inverse))
|
|
||||||
center-y (- (+ (:y selection-rect) (/ (:height selection-rect) 2)) (* rule-area-half-size zoom-inverse))]
|
|
||||||
|
|
||||||
[:g {:transform (str "rotate(-90 " center-x "," center-y ")")}
|
|
||||||
[:rect {:x (- center-x (/ (:height selection-rect) 2) (* rule-area-half-size zoom-inverse))
|
|
||||||
:y (- center-y (* rule-area-half-size zoom-inverse))
|
|
||||||
:width (:height selection-rect)
|
|
||||||
:height (* rule-area-size zoom-inverse)
|
|
||||||
:style {:fill selection-area-color
|
|
||||||
:fill-opacity selection-area-opacity}}]
|
|
||||||
|
|
||||||
[:rect {:x (- center-x (/ (:height selection-rect) 2) (* rule-area-half-size zoom-inverse) (* over-number-size zoom-inverse))
|
|
||||||
:y (- center-y (* rule-area-half-size zoom-inverse))
|
|
||||||
:width (* over-number-size zoom-inverse)
|
|
||||||
:height (* rule-area-size zoom-inverse)
|
|
||||||
:style {:fill rules-background
|
|
||||||
:fill-opacity over-number-opacity}}]
|
|
||||||
|
|
||||||
[:rect {:x (+ (- center-x (/ (:height selection-rect) 2) (* rule-area-half-size zoom-inverse)) (:height selection-rect))
|
|
||||||
:y (- center-y (* rule-area-half-size zoom-inverse))
|
|
||||||
:width (* over-number-size zoom-inverse)
|
|
||||||
:height (* rule-area-size zoom-inverse)
|
|
||||||
:style {:fill rules-background
|
|
||||||
:fill-opacity over-number-opacity}}]
|
|
||||||
|
|
||||||
[:text {:x (- center-x (/ (:height selection-rect) 2) (* 15 zoom-inverse))
|
|
||||||
:y center-y
|
|
||||||
:text-anchor "end"
|
|
||||||
:dominant-baseline "middle"
|
|
||||||
:style {:font-size (* font-size zoom-inverse)
|
|
||||||
:font-family font-family
|
|
||||||
:fill selection-area-color}}
|
|
||||||
(fmt/format-number (- (:y2 selection-rect) offset-y))]
|
|
||||||
|
|
||||||
[:text {:x (+ center-x (/ (:height selection-rect) 2))
|
|
||||||
:y center-y
|
|
||||||
:text-anchor "start"
|
|
||||||
:dominant-baseline "middle"
|
|
||||||
:style {:font-size (* font-size zoom-inverse)
|
|
||||||
:font-family font-family
|
|
||||||
:fill selection-area-color}}
|
|
||||||
(fmt/format-number (- (:y1 selection-rect) offset-y))]])]))
|
|
||||||
|
|
||||||
(mf/defc rules
|
|
||||||
{::mf/wrap-props false
|
|
||||||
::mf/wrap [#(mf/memo' % (mf/check-props ["zoom" "vbox" "selected-shapes" "show-rules?"]))]}
|
|
||||||
[props]
|
|
||||||
(let [zoom (obj/get props "zoom")
|
|
||||||
zoom-inverse (obj/get props "zoom-inverse")
|
|
||||||
vbox (obj/get props "vbox")
|
|
||||||
offset-x (obj/get props "offset-x")
|
|
||||||
offset-y (obj/get props "offset-y")
|
|
||||||
selected-shapes (-> (obj/get props "selected-shapes")
|
|
||||||
(hooks/use-equal-memo))
|
|
||||||
show-rules? (obj/get props "show-rules?")
|
|
||||||
|
|
||||||
rules-background rules-background
|
|
||||||
border-radius (/ canvas-border-radius zoom)
|
|
||||||
|
|
||||||
selection-rect
|
|
||||||
(mf/use-memo
|
|
||||||
(mf/deps selected-shapes)
|
|
||||||
#(when (d/not-empty? selected-shapes)
|
|
||||||
(gsh/shapes->rect selected-shapes)))]
|
|
||||||
|
|
||||||
(when (some? vbox)
|
|
||||||
[:g.rules {:pointer-events "none"}
|
|
||||||
(when show-rules?
|
|
||||||
[:*
|
|
||||||
[:& rules-axis {:zoom zoom :zoom-inverse zoom-inverse :vbox vbox :axis :x :offset offset-x}]
|
|
||||||
[:& rules-axis {:zoom zoom :zoom-inverse zoom-inverse :vbox vbox :axis :y :offset offset-y}]])
|
|
||||||
|
|
||||||
;; Draw the rules' rounded corners in the viewport corners
|
|
||||||
(let [{:keys [x y width height]} vbox
|
|
||||||
rule-area-size (if show-rules? (/ rule-area-size zoom) 0)]
|
|
||||||
[:*
|
|
||||||
[:path {:d (round-corner-path-tl (+ x rule-area-size) (+ y rule-area-size) border-radius)
|
|
||||||
:style {:fill rules-background}}]
|
|
||||||
|
|
||||||
[:path {:d (round-corner-path-tr (+ x width (- border-radius)) (+ y rule-area-size) border-radius)
|
|
||||||
:style {:fill rules-background}}]
|
|
||||||
|
|
||||||
[:path {:d (round-corner-path-bl (+ x rule-area-size) (+ y height (- border-radius)) border-radius)
|
|
||||||
:style {:fill rules-background}}]
|
|
||||||
|
|
||||||
[:path {:d (round-corner-path-br (+ x (:width vbox) (- border-radius)) (+ y height (- border-radius)) border-radius)
|
|
||||||
:style {:fill rules-background}}]])
|
|
||||||
|
|
||||||
(when (and show-rules? (some? selection-rect))
|
|
||||||
[:& selection-area {:zoom zoom
|
|
||||||
:zoom-inverse zoom-inverse
|
|
||||||
:vbox vbox
|
|
||||||
:selection-rect selection-rect
|
|
||||||
:offset-x offset-x
|
|
||||||
:offset-y offset-y}])])))
|
|
Loading…
Add table
Add a link
Reference in a new issue