0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-04 19:11:20 -05:00

Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2024-03-22 08:40:09 +01:00
commit a79e4d7af3
80 changed files with 563 additions and 2702 deletions

View file

@ -4,7 +4,7 @@ export PENPOT_HOST=devenv
export PENPOT_TENANT=dev
export PENPOT_FLAGS="\
$PENPOT_FLAGS \
enable-registration
enable-login-with-ldap \
enable-login-with-password
enable-login-with-oidc \
enable-login-with-google \
@ -28,9 +28,7 @@ export PENPOT_FLAGS="\
enable-access-tokens \
disable-feature-components-v2 \
enable-file-validation \
enable-file-schema-validation \
disable-soft-file-schema-validation \
disable-soft-file-validation";
enable-file-schema-validation";
# Setup default upload media file size to 100MiB

View file

@ -15,13 +15,12 @@ export PENPOT_FLAGS="\
enable-feature-fdata-pointer-map \
enable-feature-fdata-objects-map \
disable-secure-session-cookies \
enable-rpc-climit \
enable-smtp \
enable-access-tokens \
disable-feature-components-v2 \
enable-file-validation \
enable-file-schema-validation \
disable-soft-file-schema-validation \
disable-soft-file-validation";
enable-file-schema-validation";
export OPTIONS="
-A:jmx-remote -A:dev \

View file

@ -215,10 +215,15 @@
(update :pages-index update-vals fix-container)
(d/update-when :components update-vals fix-container))))
fix-page-invalid-options
fix-invalid-page
(fn [file-data]
(letfn [(update-page [page]
(update page :options fix-options))
(-> page
(update :name (fn [name]
(if (nil? name)
"Page"
name)))
(update :options fix-options)))
(fix-background [options]
(if (and (contains? options :background)
@ -433,7 +438,8 @@
(letfn [(fix-component [components id component]
(let [root-shape (ctst/get-shape component (:id component))]
(if (or (empty? (:objects component))
(nil? root-shape))
(nil? root-shape)
(nil? (:type root-shape)))
(dissoc components id)
components)))]
@ -731,43 +737,61 @@
(fn [file-data]
;; Remap shape-refs so that they point to the near main.
;; At the same time, if there are any dangling ref, detach the shape and its children.
(letfn [(fix-container [container]
(reduce fix-shape container (ctn/shapes-seq container)))
(let [count (volatile! 0)
(fix-shape [container shape]
(if (ctk/in-component-copy? shape)
;; First look for the direct shape.
(let [root (ctn/get-component-shape (:objects container) shape)
libraries (assoc-in libraries [(:id file-data) :data] file-data)
library (get libraries (:component-file root))
component (ctkl/get-component (:data library) (:component-id root) true)
direct-shape (ctf/get-component-shape (:data library) component (:shape-ref shape))]
(if (some? direct-shape)
;; If it exists, there is nothing else to do.
container
;; If not found, find the near shape.
(let [near-shape (d/seek #(= (:shape-ref %) (:shape-ref shape))
(ctf/get-component-shapes (:data library) component))]
(if (some? near-shape)
;; If found, update the ref to point to the near shape.
(ctn/update-shape container (:id shape) #(assoc % :shape-ref (:id near-shape)))
;; If not found, it may be a fostered component. Try to locate a direct shape
;; in the head component.
(let [head (ctn/get-head-shape (:objects container) shape)
library-2 (get libraries (:component-file head))
component-2 (ctkl/get-component (:data library-2) (:component-id head) true)
direct-shape-2 (ctf/get-component-shape (:data library-2) component-2 (:shape-ref shape))]
(if (some? direct-shape-2)
;; If it exists, there is nothing else to do.
container
;; If not found, detach shape and all children.
;; container
(detach-shape container shape)))))))
container))]
fix-shape
(fn [container shape]
(if (ctk/in-component-copy? shape)
;; First look for the direct shape.
(let [root (ctn/get-component-shape (:objects container) shape)
libraries (assoc-in libraries [(:id file-data) :data] file-data)
library (get libraries (:component-file root))
component (ctkl/get-component (:data library) (:component-id root) true)
direct-shape (ctf/get-component-shape (:data library) component (:shape-ref shape))]
(if (some? direct-shape)
;; If it exists, there is nothing else to do.
container
;; If not found, find the near shape.
(let [near-shape (d/seek #(= (:shape-ref %) (:shape-ref shape))
(ctf/get-component-shapes (:data library) component))]
(if (some? near-shape)
;; If found, update the ref to point to the near shape.
(do
(vswap! count inc)
(ctn/update-shape container (:id shape) #(assoc % :shape-ref (:id near-shape))))
;; If not found, it may be a fostered component. Try to locate a direct shape
;; in the head component.
(let [head (ctn/get-head-shape (:objects container) shape)
library-2 (get libraries (:component-file head))
component-2 (ctkl/get-component (:data library-2) (:component-id head) true)
direct-shape-2 (ctf/get-component-shape (:data library-2) component-2 (:shape-ref shape))]
(if (some? direct-shape-2)
;; If it exists, there is nothing else to do.
container
;; If not found, detach shape and all children.
;; container
(do
(vswap! count inc)
(detach-shape container shape))))))))
container))
(-> file-data
(update :pages-index update-vals fix-container)
(d/update-when :components update-vals fix-container))))
fix-container
(fn [container]
(reduce fix-shape container (ctn/shapes-seq container)))]
[(-> file-data
(update :pages-index update-vals fix-container)
(d/update-when :components update-vals fix-container))
@count]))
remap-refs-recur
;; remapping refs can generate cascade changes so we call it until no changes are done
(fn [file-data]
(loop [f-data file-data]
(let [[f-data count] (remap-refs f-data)]
(if (= count 0)
f-data
(recur f-data)))))
fix-converted-copies
(fn [file-data]
@ -974,7 +998,7 @@
(-> file-data
(fix-file-data)
(fix-page-invalid-options)
(fix-invalid-page)
(fix-misc-shape-issues)
(fix-recent-colors)
(fix-missing-image-metadata)
@ -993,8 +1017,8 @@
(remove-nested-roots)
(add-not-nested-roots)
(fix-components-without-id)
(remap-refs)
(fix-converted-copies)
(remap-refs-recur)
(wrap-non-group-component-roots)
(detach-non-group-instance-roots)
(transform-to-frames)

View file

@ -21,7 +21,6 @@
[app.worker :as-alias wrk]
[clojure.edn :as edn]
[clojure.spec.alpha :as s]
[cuerdas.core :as str]
[datoteka.fs :as fs]
[integrant.core :as ig]
[promesa.exec :as px]
@ -241,16 +240,15 @@
[{:keys [::label ::profile-id ::rpc/climit ::mtx/metrics] :as cfg} f]
(let [config (get climit ::config)
cache (get climit ::cache)]
(reduce (fn [handler [limit-id limit-key :as ckey]]
(let [config (get config limit-id)]
(when-not config
(throw (IllegalArgumentException.
(str/ffmt "config not found for: %" limit-id))))
(if-let [config (get config limit-id)]
(fn [& params]
(let [limiter (cache/get cache ckey (partial create-limiter config))]
(invoke limiter metrics limit-id limit-key label profile-id handler params)))))
(invoke limiter metrics limit-id limit-key label profile-id handler params)))
(do
(l/wrn :hint "config not found" :label label :id limit-id)
f)))
f
(get-limits cfg))))

View file

@ -190,8 +190,8 @@
{:project-id (:id project)
:profile-id profile-id
:team-id team-id
:is-pinned true})
(assoc project :is-pinned true))))
:is-pinned false})
(assoc project :is-pinned false))))
;; --- MUTATION: Toggle Project Pin

View file

@ -179,7 +179,7 @@
component-child (first component-children)]
(if (or (nil? child) (nil? component-child))
container
(let [container (if (and (not (ctk/is-main-of? component-child child))
(let [container (if (and (not (ctk/is-main-of? component-child child true))
(nil? (ctk/get-swap-slot child))
(ctk/instance-head? child))
(let [slot (guess-swap-slot component-child component-container)]

View file

@ -56,7 +56,9 @@
;; migrations process, so all features referenced in migrations should
;; be here.
(def default-enabled-features
#{"fdata/shape-data-type"})
#{"fdata/shape-data-type"
"styles/v2"
"layout/grid"})
;; A set of features which only affects on frontend and can be enabled
;; and disabled freely by the user any time. This features does not

View file

@ -732,7 +732,8 @@
:main-instance-id (:main-instance-id new-component)
:main-instance-page (:main-instance-page new-component)
:annotation (:annotation new-component)
:objects (:objects new-component)}) ;; this won't exist in components-v2 (except for deleted components)
:objects (:objects new-component) ;; this won't exist in components-v2 (except for deleted components)
:modified-at (:modified-at new-component)})
(update :undo-changes conj {:type :mod-component
:id id
:name (:name prev-component)

View file

@ -73,7 +73,7 @@
[{:keys [version] :as file}]
(if (int? version)
file
(let [version (or version (-> file :data :version))]
(let [version (or (-> file :data :version) 0)]
(-> file
(assoc :version version)
(update :data dissoc :version)))))
@ -853,11 +853,11 @@
(defn migrate-up-44
[data]
(letfn [(fix-shadow [shadow]
(if (string? (:color shadow))
(let [color {:color (:color shadow)
:opacity 1}]
(assoc shadow :color color))
shadow))
(let [color (if (string? (:color shadow))
{:color (:color shadow)
:opacity 1}
(d/without-nils (:color shadow)))]
(assoc shadow :color color)))
(update-object [object]
(d/update-when object :shadow

View file

@ -12,9 +12,7 @@
(def default
"A common flags that affects both: backend and frontend."
[:enable-registration
:enable-login-with-password
:enable-login-illustration
:enable-feature-styles-v2])
:enable-login-with-password])
(defn parse
[& flags]
@ -35,5 +33,3 @@
:else
(recur (rest flags) result)))))))

View file

@ -190,3 +190,8 @@
(get-rect-filter-bounds children-bounds filters blur-value))))
(defn get-frame-bounds
([shape]
(get-frame-bounds shape nil))
([shape {:keys [ignore-margin?] :or {ignore-margin? false}}]
(get-object-bounds [] shape {:ignore-margin? ignore-margin?})))

View file

@ -995,6 +995,9 @@
(= key :style)
attrs
(= key :unicode)
attrs
(str/starts-with? (d/name key) "data-")
attrs

View file

@ -383,13 +383,16 @@
(update :svg-attrs dissoc :fill)
(assoc-in [:fills 0 :fill-color] (clr/parse color-style)))
(dm/get-in shape [:svg-attrs :fillOpacity])
;; Only create an opacity if the color is setted. Othewise can create problems down the line
(and (or (clr/color-string? color-attr) (clr/color-string? color-style))
(dm/get-in shape [:svg-attrs :fillOpacity]))
(-> (update :svg-attrs dissoc :fillOpacity)
(update-in [:svg-attrs :style] dissoc :fillOpacity)
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :fillOpacity])
(d/parse-double 1))))
(dm/get-in shape [:svg-attrs :style :fillOpacity])
(and (or (clr/color-string? color-attr) (clr/color-string? color-style))
(dm/get-in shape [:svg-attrs :style :fillOpacity]))
(-> (update-in [:svg-attrs :style] dissoc :fillOpacity)
(update :svg-attrs dissoc :fillOpacity)
(assoc-in [:fills 0 :fill-opacity] (-> (dm/get-in shape [:svg-attrs :style :fillOpacity])

View file

@ -138,10 +138,10 @@
(= (:component-file shape) file-id)))
(defn is-main-of?
[shape-main shape-inst]
(and (:shape-ref shape-inst)
(or (= (:shape-ref shape-inst) (:id shape-main))
(= (:shape-ref shape-inst) (:shape-ref shape-main)))))
[shape-main shape-inst components-v2]
(or (= (:shape-ref shape-inst) (:id shape-main))
(and (= (:shape-ref shape-inst) (:shape-ref shape-main))
(not components-v2))))
(defn main-instance?
"Check if this shape is the root of the main instance of some

View file

@ -48,7 +48,7 @@
(wrap-object-fn)))))))
(defn mod-component
[file-data {:keys [id name path main-instance-id main-instance-page objects annotation]}]
[file-data {:keys [id name path main-instance-id main-instance-page objects annotation modified-at]}]
(let [wrap-objects-fn cfeat/*wrap-with-objects-map-fn*]
(d/update-in-when file-data [:components id]
(fn [component]
@ -69,6 +69,9 @@
(some? objects)
(assoc :objects objects)
(some? modified-at)
(assoc :modified-at modified-at)
(some? annotation)
(assoc :annotation annotation)
@ -76,7 +79,7 @@
(dissoc :annotation))
diff (set/difference
(ctk/diff-components component new-comp)
#{:annotation})] ;; The set of properties that doesn't mark a component as touched
#{:annotation :modified-at})] ;; The set of properties that doesn't mark a component as touched
(if (empty? diff)
new-comp

View file

@ -154,6 +154,17 @@
:else
(get-head-shape objects (get objects (:parent-id shape)) options))))
(defn get-child-heads
"Get all recursive childs that are heads (when a head is found, do not
continue down looking for subsequent nested heads)."
[objects shape-id]
(let [shape (get objects shape-id)]
(if (nil? shape)
[]
(if (ctk/instance-head? shape)
[shape]
(mapcat #(get-child-heads objects %) (:shapes shape))))))
(defn get-parent-heads
"Get all component heads that are ancestors of the shape, in top-down order
(include self if it's also a head)."
@ -170,6 +181,20 @@
(filter #(and (ctk/instance-head? %) (ctk/in-component-copy? %)))
(reverse)))
(defn get-nesting-level-delta
"Get how many levels a shape will 'go up' if moved under the new parent."
[objects shape new-parent]
(let [orig-heads (->> (get-parent-copy-heads objects shape)
(remove #(= (:id %) (:id shape))))
dest-heads (get-parent-copy-heads objects new-parent)
;; Calculate how many parent heads share in common the original
;; shape and the new parent.
pairs (map vector orig-heads dest-heads)
common-count (count (take-while (fn [a b] (= a b)) pairs))]
(- (count orig-heads) common-count)))
(defn get-instance-root
"Get the parent shape at the top of the component instance (main or copy)."
[objects shape]

View file

@ -216,14 +216,14 @@
(some find-ref-shape-in-head (ctn/get-parent-heads (:objects container) shape))))
(defn find-original-ref-shape
"Recursively call to find-ref-shape until find the original shape of the original component"
[file container libraries shape & options]
(defn advance-shape-ref
"Get the shape-ref of the near main of the shape, recursively repeated as many times
as the given levels."
[file container libraries shape levels & options]
(let [ref-shape (find-ref-shape file container libraries shape options)]
(if (nil? (:shape-ref ref-shape))
ref-shape
(find-original-ref-shape file container libraries ref-shape options))))
(if (or (nil? (:shape-ref ref-shape)) (not (pos? levels)))
(:id ref-shape)
(advance-shape-ref file container libraries ref-shape (dec levels) options))))
(defn find-ref-component
"Locate the nearest component in the local file or libraries that is referenced by the

View file

@ -237,7 +237,7 @@
--assets-item-border-color: var(--color-accent-primary);
--assets-item-background-color-drag: transparent;
--assets-item-border-color-drag: var(--color-accent-primary-muted);
--assets-component-background-color: var(--color-foreground-secondary);
--assets-component-background-color: var(--color-canvas);
--assets-component-background-color-disabled: var(--df-secondary;);
--assets-component-border-color: var(--color-background-tertiary);
--assets-component-border-selected: var(--color-accent-tertiary);
@ -419,8 +419,6 @@
}
.light {
--assets-component-background-color: var(--color-background-secondary);
--tabs-background-color: var(--color-background-tertiary);
--tab-background-color-selected: var(--color-background-primary);
--tab-border-color: var(--color-background-tertiary);

View file

@ -4,6 +4,18 @@
//
// Copyright (c) KALEIDOS INC
@mixin font-face($style-name, $file, $weight: unquote("normal"), $style: unquote("normal")) {
$filepath: "/fonts/" + $file;
@font-face {
font-family: "#{$style-name}";
src:
url($filepath + ".woff2") format("woff2"),
url($filepath + ".ttf") format("truetype");
font-weight: unquote($weight);
font-style: unquote($style);
}
}
@mixin flexCenter {
display: flex;
justify-content: center;

View file

@ -33,34 +33,20 @@
//#################################################
@import "common/base";
@import "main/layouts/login";
@import "main/layouts/main-layout";
@import "main/layouts/not-found";
@import "main/layouts/viewer";
@import "main/layouts/inspect";
//#################################################
// Commons
//#################################################
@import "common/framework";
@import "main/partials/forms";
@import "main/partials/texts";
@import "main/partials/context-menu";
@import "main/partials/dropdown";
//#################################################
// Partials
//#################################################
@import "main/partials/activity-bar";
@import "main/partials/debug-icons-preview";
@import "main/partials/editable-label";
@import "main/partials/loader";
@import "main/partials/project-bar";
@import "main/partials/sidebar";
@import "main/partials/tab-container";
@import "main/partials/user-settings";
@import "main/partials/workspace";
@import "main/partials/exception-page";
@import "main/partials/signup-questions";

View file

@ -1,161 +0,0 @@
$width-left-toolbar: 48px;
$width-settings-bar: 256px;
.inspect-layout {
height: 100vh;
display: grid;
grid-template-rows: 48px auto;
grid-template-columns: 1fr;
user-select: none;
.viewer-header {
grid-column: 1 / span 1;
grid-row: 1 / span 1;
}
.viewer-content {
grid-column: 1 / span 1;
grid-row: 2 / span 1;
}
}
.fullscreen.inspect-layout.force-visible {
display: grid;
grid-template-rows: 1fr;
& .viewer-header {
position: fixed;
top: 0;
transition: top 400ms ease 300ms;
margin-bottom: 0;
z-index: 10;
}
& .viewer-bottom {
position: fixed;
bottom: 0;
transition: bottom 400ms ease 300ms;
z-index: 2;
}
}
.fullscreen.inspect-layout:not(.force-visible) {
& .viewer-header {
width: 100%;
position: fixed;
top: -48px;
left: 0;
transition: top 400ms ease 300ms;
z-index: 10;
margin-bottom: 48px;
&::after {
content: " ";
position: absolute;
width: 100%;
height: 1rem;
left: 0;
top: 48px;
}
}
& .viewer-header:hover {
top: 0;
transition: top 200ms;
}
& .viewer-bottom {
width: 100%;
position: fixed;
bottom: -48px;
left: 0;
transition: bottom 400ms ease 300ms;
z-index: 2;
&::after {
content: " ";
position: absolute;
width: 100%;
height: 1rem;
left: 0;
bottom: 0px;
}
}
& .viewer-bottom:hover {
bottom: 0px;
transition: bottom 200ms;
}
& .viewer-content {
grid-row: 1 / span 2;
}
}
.inspect-layout {
.viewer-section {
flex-wrap: nowrap;
margin-top: 0;
&.fullscreen {
.settings-bar,
.settings-bar {
padding-top: 48px;
}
}
}
.settings-bar {
width: $width-settings-bar;
&.settings-bar-right,
&.settings-bar-left {
height: 100%;
position: relative;
left: unset;
right: unset;
.settings-bar-inside {
padding-top: 0.5rem;
overflow-y: auto;
}
}
&.settings-bar-right {
width: 100%;
grid-area: right-sidebar;
}
}
.inspect-svg-wrapper {
flex: 1;
overflow: hidden;
flex-direction: column;
justify-content: flex-start;
position: relative;
}
.inspect-svg-container {
display: grid;
width: 100%;
height: 100%;
overflow: auto;
align-items: center;
justify-content: safe center;
margin: 0 auto;
}
}
.sidebar-container {
display: flex;
flex-direction: column;
width: var(--width, $width-settings-bar);
height: 100%;
overflow: hidden;
& > .resize-area {
position: absolute;
width: 8px;
height: 100%;
z-index: 10;
cursor: ew-resize;
}
}

View file

@ -1,250 +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
// TODO: rename to auth.scss
.auth {
display: grid;
grid-template-rows: auto;
grid-template-columns: 33% auto;
height: 100vh;
overflow-y: scroll;
}
.auth-sidebar {
grid-column: 1 / span 1;
height: 100vh;
display: flex;
padding-top: 7vh;
flex-direction: column;
align-items: center;
justify-content: flex-start;
background-color: #151035;
background-image: url("/images/login-penpot.svg");
background-position: center 30vh;
background-size: 96%;
background-repeat: no-repeat;
.tagline {
text-align: center;
width: 280px;
font-size: $fs18;
margin-top: 2vh;
color: white;
}
.logo {
svg {
fill: white;
max-width: 11vw;
height: 80px;
}
.hidden-name {
visibility: hidden;
width: 0;
height: 0;
float: left;
}
}
}
.auth-content {
grid-column: 2 / span 1;
background-color: $color-white;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.form-container {
width: 412px;
flex-direction: column;
margin-bottom: 30px;
.auth-buttons {
margin: $size-6 0 $size-4 0;
display: flex;
justify-content: center;
column-gap: 17px;
}
form {
margin: 2rem 0 0.5rem 0;
.accept-terms-and-privacy-wrapper {
position: relative;
.input-checkbox {
margin-bottom: 0;
}
.input-checkbox input[type="checkbox"] {
position: absolute;
display: block;
width: 20px;
height: 20px;
opacity: 0;
top: 22px;
}
label {
margin-left: 40px;
}
label:before {
position: absolute;
top: 15px;
left: -36px;
}
label:after {
position: absolute;
top: 15px;
left: -33px;
}
.input-checkbox input[type="checkbox"]:focus {
opacity: 100%;
}
.auth-links {
margin-left: 40px;
font-size: 0.75rem;
}
}
}
}
input {
margin-bottom: 0px;
}
.buttons-stack {
display: flex;
flex-direction: column;
width: 100%;
*:not(:last-child) {
margin-bottom: $size-4;
}
}
.btn-large {
flex-grow: 1;
font-size: $fs14;
font-style: normal;
font-weight: $fw400;
}
.btn-google-auth {
background-color: #4285f4;
color: $color-white;
margin-bottom: $size-4;
text-decoration: none;
.logo {
width: 20px;
height: 20px;
margin-right: 1rem;
}
&:hover,
&:focus {
background-color: #2065d7;
color: $color-white;
}
}
.btn-gitlab-auth {
background-color: #fc6d26;
color: $color-white;
margin-bottom: $size-4;
text-decoration: none;
.logo {
width: 20px;
height: 20px;
margin-right: 1rem;
}
&:hover,
&:focus {
background-color: #ee5f18;
color: $color-white;
}
}
.btn-github-auth {
background-color: #4c4c4c;
color: $color-white;
margin-bottom: $size-4;
text-decoration: none;
.logo {
width: 20px;
height: 20px;
margin-right: 1rem;
}
&:hover,
&:focus {
background-color: #2f2f2f;
color: $color-white;
}
}
.link-oidc {
text-align: center;
}
.separator {
display: flex;
justify-content: center;
width: 100%;
text-transform: uppercase;
text-align: center;
.text {
margin: 0 10px;
color: $color-gray-40;
}
.line {
border: 1px solid $color-gray-10;
flex-grow: 10;
margin: auto;
}
}
.links {
display: flex;
font-size: $fs14;
flex-direction: column;
justify-content: space-between;
margin-top: $size-4;
margin-bottom: $size-4;
&.demo {
justify-content: center;
margin-top: $size-5;
}
.link-entry {
font-size: $fs14;
color: $color-gray-40;
margin-bottom: 10px;
a {
font-size: $fs14;
font-weight: $fw500;
color: $color-gray-50;
&:hover,
&:focus {
text-decoration: underline;
}
}
}
}
.terms-login {
bottom: $size-5;
font-size: $fs14;
position: absolute;
span {
margin: 0 $size-2;
color: $color-gray-40;
}
}
}

View file

@ -1,101 +0,0 @@
.viewer-layout {
height: 100vh;
display: grid;
grid-template-rows: 48px auto;
grid-template-columns: 1fr;
user-select: none;
.viewer-header {
grid-column: 1 / span 1;
grid-row: 1 / span 1;
}
.viewer-content {
grid-column: 1 / span 1;
grid-row: 2 / span 1;
}
}
.fullscreen.viewer-layout.force-visible {
grid-template-rows: 1fr;
& .viewer-header {
position: fixed;
top: 0;
transition: top 400ms ease 300ms;
margin-bottom: 0;
z-index: 2;
}
& .viewer-bottom {
position: fixed;
bottom: 0;
transition: bottom 400ms ease 300ms;
z-index: 2;
}
}
.fullscreen.viewer-layout:not(.force-visible) {
grid-template-rows: 1fr;
& .viewer-header {
width: 100%;
position: fixed;
top: -48px;
left: 0;
transition: top 400ms ease 300ms;
z-index: 2;
margin-bottom: 48px;
&::after {
content: " ";
position: absolute;
width: 100%;
height: 1rem;
left: 0;
top: 48px;
}
}
& .viewer-header:hover {
top: 0;
transition: top 200ms;
}
& .viewer-bottom {
width: 100%;
position: fixed;
bottom: -48px;
left: 0;
transition: bottom 400ms ease 300ms;
z-index: 2;
&::after {
content: " ";
position: absolute;
width: 100%;
height: 1rem;
left: 0;
bottom: 0px;
}
}
& .viewer-bottom:hover {
bottom: 0px;
transition: bottom 200ms;
}
& .viewer-content {
grid-row: 1 / span 2;
}
}
.viewer-overlay {
position: absolute;
}
.viewer-overlay-background {
position: absolute;
top: 0;
left: 0;
&.visible {
background-color: rgb(0, 0, 0, 0.2);
}
}

View file

@ -1,77 +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
.activity-bar {
background-color: $color-gray-50;
bottom: 0;
height: 100%;
position: fixed;
right: 0;
width: 250px;
.activity-bar-inside {
align-items: center;
display: flex;
flex-direction: column;
overflow-y: auto;
padding-top: 70px;
}
h4 {
color: $color-gray-40;
font-size: $fs16;
font-weight: $fw700;
margin-bottom: $size-1;
}
.date-ribbon {
background-color: lighten($color-gray-20, 12%);
color: $color-white;
font-size: $fs12;
font-weight: $fw700;
padding: 2px;
text-align: center;
width: 100%;
}
.activity-input {
border-bottom: 1px solid $color-gray-10;
display: flex;
font-size: $fs12;
padding: $size-2;
width: 100%;
img.activity-author {
border-radius: 50%;
flex-shrink: 0;
height: 30px;
margin-right: $size-4;
width: 30px;
}
.activity-content {
display: flex;
flex-direction: column;
.activity-project {
align-items: center;
display: flex;
flex-wrap: wrap;
a {
font-weight: $fw700;
margin: 0 3px;
}
}
.activity-time {
color: $color-gray-20;
font-size: $fs12;
font-style: italic;
}
}
}
}

View file

@ -1,104 +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
.context-menu {
position: relative;
visibility: hidden;
opacity: 0;
z-index: 3;
}
.context-menu.is-open {
position: relative;
display: block;
opacity: 1;
visibility: visible;
}
.context-menu.fixed {
position: fixed;
}
.context-menu-items {
background: $color-white;
border-radius: $br3;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
left: -$size-4;
max-height: 30rem;
min-width: 7rem;
overflow: auto;
position: absolute;
top: $size-3;
& .separator {
border-top: 1px solid $color-gray-10;
padding: 0px;
margin: 2px;
}
&.min-width {
min-width: 13rem;
}
}
.context-menu-action {
color: $color-black;
display: block;
font-size: $fs14;
font-weight: $fw400;
padding: $size-2 $size-4;
text-align: left;
white-space: nowrap;
&:hover {
color: $color-black;
background-color: $color-primary-lighter;
text-decoration: none;
}
&.submenu {
display: flex;
align-items: center;
justify-content: space-between;
& span {
margin-left: 0.5rem;
}
& svg {
height: 10px;
width: 10px;
}
}
&.submenu-back {
color: $color-black;
display: flex;
font-weight: $fw700;
align-items: center;
& svg {
height: 10px;
width: 10px;
transform: rotate(180deg);
margin-right: $size-2;
}
}
}
.context-menu.is-selectable {
& .context-menu-action {
padding-left: 1.5rem;
}
& .context-menu-item.is-selected .context-menu-action {
background-image: url(/images/icons/tick.svg);
background-repeat: no-repeat;
background-position: 5% 48%;
background-size: 10px;
font-weight: $fw700;
}
}

View file

@ -1,70 +0,0 @@
.dropdown {
position: absolute;
max-height: 30rem;
background-color: $color-white;
border-radius: $br2;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
z-index: 3;
hr {
margin: 0 !important;
border-color: $color-gray-10;
}
> li {
display: flex;
align-items: center;
color: $color-gray-60;
cursor: pointer;
font-size: $fs14;
height: 40px;
padding: 5px 16px;
&.warning {
color: $color-danger;
}
svg {
fill: $color-gray-20;
height: 12px;
width: 12px;
}
&.title {
font-weight: $fw600;
cursor: default;
}
&:hover {
background-color: $color-primary-lighter;
}
&:focus {
border: 1px black solid;
}
}
&.with-check {
> li {
padding: 5px 10px;
}
> li:not(.selected) {
svg {
display: none;
}
}
svg {
fill: $color-gray-50;
}
.icon {
display: flex;
align-items: center;
width: 20px;
height: 20px;
margin-right: 7px;
}
}
}

View file

@ -1,30 +0,0 @@
.editable-label {
display: flex;
&.is-hidden {
display: none;
}
}
.editable-label-input {
border: 0;
height: 30px;
padding: 5px;
margin: 0;
width: 100%;
background-color: $color-white;
}
.editable-label-close {
background-color: $color-white;
cursor: pointer;
padding: 3px 5px;
& svg {
fill: $color-gray-30;
height: 15px;
transform: rotate(45deg) translateY(7px);
width: 15px;
margin: 0;
}
}

View file

@ -1,83 +0,0 @@
.exception-layout {
display: grid;
grid-template-rows: 120px auto;
grid-template-columns: 1fr;
}
.exception-header {
grid-column: 1 / span 1;
grid-row: 1 / span 1;
display: flex;
align-items: center;
padding: 32px;
z-index: 40;
cursor: pointer;
svg {
height: 55px;
width: 170px;
}
}
.exception-content {
grid-column: 1 / span 1;
grid-row: 1 / span 2;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
.container {
max-width: 600px;
}
.image {
align-items: center;
display: flex;
justify-content: center;
margin-bottom: 2rem;
svg {
height: 220px;
width: 220px;
}
}
.main-message {
color: $color-black;
font-size: $fs80;
line-height: $lh-188; // Original value was 150px; 150px/80px = 187.5 % => $lh-188 (rounded)
text-align: center;
}
.desc-message {
color: $color-black;
font-size: $fs26;
font-weight: $fw300;
text-align: center;
}
.sign-info {
margin-top: 20px;
color: $color-black;
font-size: $fs16;
font-weight: $fw200;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
b {
font-weight: $fw400;
}
.btn-primary {
margin-top: 15px;
}
}
}

View file

@ -1,390 +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
input,
select,
textarea {
&.invalid {
border-color: $color-danger;
color: $color-danger;
}
}
.form-container,
.generic-form {
display: flex;
justify-content: center;
flex-direction: column;
.forms-container {
display: flex;
margin-top: 40px;
width: 536px;
justify-content: center;
}
form {
display: flex;
flex-direction: column;
// flex-basis: 368px;
}
.fields-row {
margin-bottom: 20px;
flex-direction: column;
.options {
display: flex;
justify-content: flex-end;
font-size: $fs14;
margin-top: 13px;
}
}
.field {
margin-bottom: 20px;
}
h1 {
font-size: $fs36;
color: #2c233e;
margin-bottom: 20px;
}
.subtitle {
font-size: $fs24;
color: #2c233e;
margin-bottom: 20px;
}
.notification-icon {
justify-content: center;
display: flex;
margin-bottom: 3rem;
svg {
fill: $color-gray-60;
height: 40%;
width: 40%;
}
}
.notification-text {
font-size: $fs18;
color: $color-gray-60;
margin-bottom: 20px;
}
.notification-text-email {
background: $color-gray-10;
border-radius: $br3;
color: $color-gray-60;
font-size: $fs18;
font-weight: $fw500;
margin: 1.5rem 0 2.5rem 0;
padding: 1rem;
text-align: center;
}
h2 {
font-size: $fs24;
color: $color-gray-60;
// height: 40px;
display: flex;
align-items: center;
}
a {
&:hover {
text-decoration: underline;
}
}
p {
color: $color-gray-60;
}
hr {
border-color: $color-gray-20;
}
}
.custom-input {
display: flex;
flex-direction: column;
position: relative;
input,
textarea {
background-color: $color-white;
border-radius: $br2;
border: 1px solid $color-gray-20;
color: $color-gray-60;
font-size: $fs14;
height: 40px;
margin: 0;
padding: 15px 15px 0 15px;
width: 100%;
}
textarea {
height: auto;
font-size: $fs14;
font-family: "worksans", sans-serif;
padding-top: 20px;
}
// Makes the background for autocomplete white
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0 30px $color-white inset !important;
}
label {
font-size: $fs12;
color: $color-gray-50;
position: absolute;
left: 15px;
top: 6px;
}
&.invalid {
input {
border-color: $color-danger;
}
label {
color: $color-danger;
}
}
&.valid {
input {
border-color: $color-success;
}
}
&.focus {
input {
border-color: $color-gray-60;
}
}
&.disabled {
input {
background-color: lighten($color-gray-10, 5%);
user-select: none;
}
}
&.empty {
input {
padding-top: 0;
}
label {
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
width: 1px;
}
}
&.with-icon {
input {
padding-right: 50px;
}
}
.help-icon {
position: absolute;
right: 15px;
top: 12px;
display: flex;
justify-content: center;
align-items: center;
svg {
fill: $color-gray-30;
width: 15px;
height: 15px;
}
}
.hint {
color: $color-gray-40;
padding: 4px;
font-size: $fs12;
}
.error {
color: $color-danger;
padding: 4px;
font-size: $fs12;
}
}
.custom-multi-input {
border-radius: $br2;
border: 1px solid $color-gray-20;
max-height: 300px;
overflow-y: auto;
&.invalid {
label {
color: unset;
}
}
input {
border: 0px;
&.no-padding {
padding-top: 0px;
}
}
.selected-items {
padding-top: 25px;
padding-left: 15px;
display: flex;
flex-wrap: wrap;
}
.selected-item {
width: 100%;
&:not(:last-child) {
margin-right: 3px;
}
.around {
border: 1px solid $color-gray-20;
padding-left: 5px;
border-radius: $br4;
&.invalid {
border: 1px solid $color-danger;
}
&.caution {
border: 1px solid $color-warning;
}
.text {
display: inline-block;
max-width: 85%;
overflow: hidden;
text-overflow: ellipsis;
line-height: $lh-115; // Original value was 16px; 16px/14px = 114.285714286% => $lh-115 (rounded)
font-size: $fs14;
color: $color-black;
}
.icon {
cursor: pointer;
margin-left: 10px;
margin-right: 5px;
}
}
}
}
.custom-select {
display: flex;
flex-direction: column;
position: relative;
justify-content: center;
label {
font-size: $fs12;
color: $color-gray-30;
}
select {
cursor: pointer;
font-size: $fs14;
border: 0px;
opacity: 0;
z-index: 10;
padding: 0px;
margin: 0px;
background-color: transparent;
position: absolute;
width: calc(100% - 1px);
height: 100%;
padding: 15px;
}
.main-content {
flex-grow: 1;
display: flex;
flex-direction: column;
font-family: "worksans", sans-serif;
justify-content: center;
padding-top: 6px;
padding-bottom: 6px;
padding-left: 15px;
}
.input-container {
display: flex;
flex-direction: row;
background-color: $color-white;
border-radius: $br2;
border: 1px solid $color-gray-20;
height: 40px;
&.focus {
border-color: $color-gray-60;
}
&.invalid {
border-color: $color-danger;
label {
color: $color-danger;
}
}
&.valid {
border-color: $color-success;
}
&.focus {
border-color: $color-gray-60;
}
&.disabled {
background-color: $color-gray-10;
user-select: none;
}
}
.value {
color: $color-gray-60;
font-size: $fs14;
width: 100%;
border: 0px;
padding: 0px;
margin: 0px;
}
.icon {
display: flex;
justify-content: center;
align-items: center;
padding-left: 10px;
padding-right: 10px;
pointer-events: none;
svg {
fill: $color-gray-30;
transform: rotate(90deg);
width: 15px;
height: 15px;
}
}
}

View file

@ -1,94 +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
.project-bar {
background-color: $color-gray-50;
border-right: 1px solid $color-gray-10;
bottom: 0;
height: 100%;
left: 50px;
position: fixed;
width: 200px;
z-index: 9;
&.toggle {
left: -201px;
}
.project-bar-inside {
align-items: center;
display: flex;
flex-direction: column;
overflow-y: auto;
padding-top: 60px;
.project-name {
border-bottom: 1px solid $color-gray-10;
font-size: $fs14;
font-weight: $fw700;
padding: 0 $size-2;
width: 100%;
}
.btn-primary,
.btn-warning,
.btn-danger {
font-size: $fs12;
margin-bottom: 0.5rem;
padding: 8px $size-2;
width: 90%;
}
}
}
.tree-view {
width: 100%;
li {
align-items: center;
cursor: pointer;
display: flex;
padding: $size-1 $size-2;
position: relative;
svg {
fill: $color-gray-20;
height: 12px;
margin-right: $size-1;
width: 12px;
}
span {
font-size: $fs12;
}
&:hover,
&.current {
span {
color: $color-primary;
}
}
.options {
align-items: center;
position: absolute;
display: flex;
right: 0;
top: 40%;
svg {
fill: $color-gray-20;
height: 12px;
margin-right: $size-2;
width: 12px;
&:hover {
fill: $color-gray-40;
}
}
}
}
}

View file

@ -1,575 +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
.settings-bar {
background-color: $color-gray-50;
border-left: 1px solid $color-gray-60;
position: relative;
&.settings-bar-left {
border-left: none;
border-right: 1px solid $color-gray-60;
& .tab-container-tabs {
padding-left: 1.5rem;
}
}
.settings-bar-inside {
display: grid;
grid-template-columns: 100%;
grid-template-rows: 100%;
height: calc(100% - 2px);
.tool-window {
position: relative;
border-bottom: 1px solid $color-gray-60;
display: flex;
flex-direction: column;
flex: 1;
width: 100%;
height: 100%;
.tool-window-bar {
align-items: center;
display: flex;
flex-shrink: 0;
padding: $size-2;
overflow: hidden;
margin: 0;
svg {
fill: $color-gray-20;
height: 12px;
width: 12px;
}
button,
div {
border: none;
background-color: transparent;
color: $color-gray-10;
font-size: $fs14;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
span.pages-title {
color: #e3e3e3;
font-size: 0.875rem;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
span.tool-badge {
border: 1px solid $color-primary;
border-radius: $br2;
font-size: $fs10;
color: $color-primary;
padding: 2px 4px;
margin-left: auto;
}
span.tool-link,
span.shared-library {
margin-left: auto;
padding-left: 17px;
display: flex;
svg {
fill: $color-gray-30;
height: 20px;
width: 20px;
}
}
span.tool-link:hover svg {
fill: $color-primary;
}
span.library-title {
color: $color-gray-10;
font-size: $fs14;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&:first-letter {
text-transform: uppercase;
}
}
.tool-window-bar-icon {
height: 21px;
display: flex;
align-items: center;
justify-content: center;
svg {
width: 15px;
height: 15px;
}
}
&.big {
height: 3rem;
padding-bottom: 1rem;
}
.tool-window-bar-title {
font-size: $fs14;
margin-left: 0.5rem;
}
.tool-window-icon {
margin-right: $size-2;
display: none;
}
.tool-window-close {
cursor: pointer;
margin-left: auto;
transform: rotate(45deg);
&:hover {
svg {
fill: $color-danger;
}
}
}
& .view-only-mode {
color: $color-primary;
border: 1px solid $color-primary;
border-radius: $br3;
font-size: $fs10;
text-transform: uppercase;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
padding: 0.25rem;
}
}
}
}
.empty {
color: $color-gray-20;
font-size: $fs12;
line-height: $lh-150;
text-align: center;
padding: 0 15px;
display: flex;
flex-direction: column;
gap: 20px;
margin-top: 12px;
.tool-window-bar-icon {
height: 32px;
display: flex;
align-items: center;
justify-content: center;
margin-top: 16px;
}
svg {
width: 32px;
height: 32px;
fill: $color-gray-30;
}
.btn-primary {
margin-top: 10px;
background-color: $color-gray-60;
color: $color-gray-10;
&:hover {
background-color: $color-primary;
color: $color-black;
}
}
}
& > .resize-area {
position: absolute;
width: 8px;
height: 100%;
z-index: 10;
cursor: ew-resize;
}
&.settings-bar-left > .resize-area {
right: -8px;
}
&.settings-bar-right > .resize-area {
left: -4px;
}
}
.tool-window-content {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
overflow-y: auto;
overflow-x: hidden;
&.inspect {
.tab-container-tabs {
padding-bottom: 0.5rem;
background-color: $color-gray-50;
border-bottom: 1px solid $color-gray-60;
height: 3rem;
}
.tab-container-tab-title {
border-radius: $br4;
&.current {
background-color: $color-primary;
color: black;
}
}
}
}
.element-list {
margin: 0;
width: 100%;
ul {
border-left: 9px solid $color-gray-50;
margin: 0 0 0 0.4rem;
li {
border-left: 1px solid $color-gray-40;
}
}
li {
cursor: pointer;
display: flex;
flex-direction: column;
width: 100%;
padding-top: 1px;
padding-bottom: 1px;
&.open {
ul {
li {
.element-list-body {
border-style: dashed;
}
}
}
}
}
}
.element-list.pages-list {
max-height: 10rem;
.context-menu {
position: fixed;
}
.context-menu-items {
border: none;
margin: none;
}
.context-menu-action {
width: 100%;
}
}
button.collapse-sidebar {
background: none;
border: none;
cursor: pointer;
height: 2.5rem;
padding-top: 0.75rem;
position: absolute;
width: 1rem;
& svg {
width: 12px;
height: 12px;
fill: $color-gray-20;
transform: rotate(180deg);
}
&.collapsed {
background: $color-gray-60;
left: 48px;
top: 48px;
width: 28px;
height: 48px;
padding: 0;
border-radius: 0 $br4 $br4 0;
border-left: 1px solid $color-gray-50;
& svg {
transform: rotate(0deg);
}
}
}
.layers-tab {
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 100%;
height: 100%;
overflow: hidden;
position: relative;
.resize-area-horiz {
position: absolute;
top: var(--height, 200px);
left: 0;
height: 8px;
width: 100%;
z-index: 10;
cursor: ns-resize;
}
}
.shortcuts,
.debug-panel {
.shortcuts-header,
.debug-panel-header {
display: flex;
height: 40px;
background-color: $color-gray-60;
.shortcuts-title,
.debug-panel-title {
color: $color-white;
font-size: $fs12;
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
svg {
height: 18px;
width: 18px;
transform: rotate(45deg);
fill: $color-gray-20;
}
}
.shortcuts-close-button,
.debug-panel-close-button {
display: flex;
justify-content: center;
background-color: transparent;
border: none;
cursor: pointer;
padding: 2px 0 2px 15px;
position: absolute;
top: 8px;
svg {
height: 18px;
width: 18px;
transform: rotate(45deg);
fill: $color-gray-20;
}
}
}
.search-field {
height: 60px;
display: flex;
justify-content: center;
align-items: center;
padding: 12px 10px;
.search-box {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid $color-gray-30;
border-radius: $br2;
width: 100%;
&:focus-within {
border: 1px solid $color-primary;
}
.input-text {
margin: 0;
background: $color-gray-50;
width: 100%;
color: $color-white;
&:focus {
border-bottom: none;
}
}
.icon-wrapper {
display: flex;
justify-content: center;
align-items: center;
border: none;
background-color: transparent;
padding: 0;
.icon {
display: flex;
justify-content: center;
align-items: center;
&.close {
transform: rotate(45deg);
}
}
}
svg {
width: 16px;
height: 16px;
margin: 0 7px;
cursor: pointer;
fill: $color-gray-20;
}
}
}
.shortcut-list {
border-top: 1px solid $color-gray-60;
padding: 10px;
overflow-y: auto;
height: 90%;
margin-bottom: 15px;
.section-title {
background-color: $color-gray-60;
padding: 4px 0;
}
.section-title,
.subsection-title {
display: flex;
cursor: pointer;
margin-top: 4px;
font-size: $fs12;
.section-name {
color: $color-white;
}
.collapesed-shortcuts {
padding: 0 10px;
svg {
height: 8px;
width: 8px;
fill: $color-gray-20;
}
&.open {
svg {
transform: rotate(90deg);
}
}
}
.shortcut-count {
padding-left: 5px;
color: $color-white;
}
}
.subsection-title {
padding: 4px 0px;
.subsection-name {
color: $color-white;
}
}
.section-title,
.subsection-title {
&:hover {
background-color: $color-primary;
.subsection-name,
.section-name {
color: $color-gray-60;
}
svg {
fill: $color-gray-60;
}
}
}
.shortcut-name {
border: 1px solid $color-gray-60;
border-radius: $br4;
padding: 7px;
display: flex;
justify-content: space-between;
margin-top: 4px;
color: $color-white;
font-size: $fs12;
.command-name {
display: flex;
align-items: center;
}
.keys {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: flex-end;
}
.char-box {
min-width: 15px;
background-color: $color-white;
color: $color-black;
border-radius: $br3;
padding: 2px 5px;
font-size: $fs11;
font-weight: $fw600;
margin: 0 2px;
text-transform: capitalize;
display: inline-block;
text-align: center;
}
.space {
margin: 0 3px;
}
}
}
.not-found {
background-color: $color-gray-60;
padding: 4px 0;
color: $color-white;
display: flex;
justify-content: center;
margin-top: 4px;
font-size: $fs12;
}
}
.debug-panel {
.debug-panel-inner {
padding: 8px;
}
.debug-option {
display: flex;
gap: 8px;
margin: 4px 0;
cursor: pointer;
label {
font-size: 80%;
cursor: pointer;
}
svg {
width: 15px;
height: 15px;
background: white;
}
&:hover {
svg {
stroke: $color-primary;
}
label {
color: $color-primary;
}
}
}
}

View file

@ -1,190 +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
.signup-questions {
background-color: $color-white;
color: $color-gray-60;
max-width: 646px;
overflow-y: auto;
padding: 1.5rem 1rem;
position: relative;
width: 100%;
form {
display: flex;
flex-direction: column;
height: 100%;
}
h1,
h3 {
font-family: "worksans", sans-serif;
font-weight: $fw500;
}
h1 {
font-size: $fs36;
padding-top: 2.5rem;
}
h3 {
font-size: $fs23;
}
.step-header {
height: 2.5rem;
width: 100%;
}
.custom-select {
margin-bottom: 10px;
}
.step-number {
background-color: $color-gray-10;
border: none;
border-radius: 1rem; // Need to be investigated, before we can use variable
color: $color-gray-40;
float: right;
font-family: "worksans", sans-serif;
font-size: $fs12;
height: 1.5rem;
line-height: $lh-200; // Original value was 1.5rem = 24px; 24px/12px = 200% => lh-200
text-align: center;
width: 2.5rem;
}
.header-image {
width: 240px;
}
.intro {
font-size: $fs16;
padding: 0.5rem 0 1rem 0;
color: $color-gray-40;
}
.section {
display: block;
font-weight: $fw500;
font-size: $fs18;
margin: 0 0 0.3em 0;
padding: 0.8rem 0 0 0;
font-family: "worksans", sans-serif !important;
}
.other {
.custom-input {
margin: 0.75rem 0 2rem 0;
}
}
.buttons {
flex-grow: 1;
display: grid;
grid-template-columns: 50% 50%;
grid-template-areas: "previous next";
.step-prev {
display: flex;
align-items: flex-end;
justify-content: flex-start;
grid-area: previous;
button {
background-color: transparent;
border: none;
cursor: pointer;
height: 40px;
font-size: $fs15;
}
}
.step-next {
display: flex;
align-items: flex-end;
justify-content: flex-end;
grid-area: next;
input {
font-size: $fs15;
color: $color-black;
background-color: $color-primary;
width: 11rem;
margin-left: auto;
margin: 0;
}
}
}
.custom-radio {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.input-radio {
margin: 0;
max-width: 12rem;
width: 100%;
&.with-image {
display: block;
padding: 0;
}
label {
font-family: "worksans", sans-serif !important;
color: $color-gray-60;
font-size: $fs15;
padding-left: 0;
position: relative;
text-align: center;
height: 4rem;
margin: 0;
&.with-image {
min-height: 120px;
display: flex;
padding-top: 4rem;
justify-content: center;
background-size: 50px;
background-repeat: no-repeat;
background-position: center 0.75rem;
}
}
input[type="radio"] {
/*We need it to be accesible so we can't use display none*/
display: inline;
opacity: 0;
}
input[type="radio"] + label:before {
background-color: $color-white;
border: 1px solid $color-gray-10;
}
input[type="radio"] + label.with-image:before {
background-color: transparent;
border-radius: 4px;
min-width: 100%;
min-height: 100%;
position: absolute;
top: 0;
left: 0;
margin: 0;
}
input[type="radio"]:focus + label:before {
border: 1px solid $color-gray-60;
}
input[type="radio"]:checked + label:before {
box-shadow: inset 0 0 0 4px $color-white;
background-color: $color-primary;
border: 1px solid $color-gray-30;
}
input[type="radio"]:checked + label.with-image:before {
border: 1px solid $color-primary;
background-color: transparent;
}
}
}
}

View file

@ -1,45 +0,0 @@
.tab-container {
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 100%;
height: 100%;
}
.tab-container-tabs {
background: $color-gray-60;
cursor: pointer;
display: flex;
flex-direction: row;
font-size: $fs12;
height: 2.5rem;
padding: 0 0.25rem;
}
.tab-container-tab-title {
align-items: center;
background: $color-gray-60;
border-radius: $br2 $br2 0 0;
color: $color-white;
display: flex;
justify-content: center;
margin: 0.5rem 0.25rem 0 0.25rem;
width: 100%;
&.current {
background: $color-gray-50;
}
}
.tab-container-content {
overflow-y: auto;
overflow-x: hidden;
}
.inspect .tab-container-content {
overflow: hidden;
}
.tab-element,
.tab-element-content {
height: 100%;
}

View file

@ -1,188 +0,0 @@
.settings-content {
header {
display: flex;
flex-direction: column;
height: 160px;
background-color: $color-white;
.secondary-menu {
display: flex;
justify-content: space-between;
height: 40px;
font-size: $fs14;
color: $color-gray-60;
.icon {
display: flex;
align-items: center;
}
.left {
margin-left: 30px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
.label {
margin-left: 15px;
}
svg {
fill: $color-gray-60;
width: 14px;
height: 14px;
transform: rotate(180deg);
}
}
.right {
align-items: center;
cursor: pointer;
display: flex;
justify-content: center;
margin-right: 30px;
.label {
color: $color-primary-dark;
margin-right: 15px;
}
svg {
fill: $color-primary-dark;
width: 14px;
height: 14px;
}
&:hover {
.label {
color: $color-danger;
}
svg {
fill: $color-danger;
}
}
}
}
h1 {
align-items: top;
color: $color-gray-60;
display: flex;
flex-grow: 1;
font-size: $fs24;
font-weight: $fw400;
justify-content: center;
}
nav {
display: flex;
justify-content: center;
height: 40px;
.nav-item {
align-items: center;
color: $color-gray-40;
display: flex;
flex-basis: 140px;
justify-content: center;
&.current {
border-bottom: 3px solid $color-primary;
}
}
}
}
.settings-profile {
.forms-container {
margin-top: 80px;
}
}
.avatar-form {
flex-basis: 168px;
height: 100vh;
display: flex;
position: relative;
.image-change-field {
position: relative;
width: 120px;
height: 120px;
.update-overlay {
opacity: 0;
cursor: pointer;
position: absolute;
width: 121px;
height: 121px;
border-radius: 50%;
font-size: $fs24;
color: $color-white;
line-height: $lh-500; // Original value was 120px; 120px/24px =500% => $lh-500
text-align: center;
background: $color-primary-dark;
z-index: 14;
}
input[type="file"] {
width: 120px;
height: 120px;
position: absolute;
opacity: 0;
cursor: pointer;
top: 0;
z-index: 15;
}
&:hover {
img {
display: none;
}
.update-overlay {
opacity: 1;
}
}
}
}
.profile-form {
flex-grow: 1;
flex-basis: 390px;
display: flex;
flex-direction: column;
.change-email {
display: flex;
flex-direction: row;
font-size: $fs14;
color: $color-primary-dark;
justify-content: flex-end;
margin-bottom: 20px;
}
}
.avatar-form {
img {
border-radius: 50%;
flex-shrink: 0;
height: 120px;
margin-right: $size-4;
width: 120px;
}
}
.options-form,
.password-form {
display: flex;
flex-direction: column;
flex-basis: 368px;
h2 {
font-size: $fs14;
font-weight: $fw400;
margin-bottom: $size-4;
}
}
}

View file

@ -25,6 +25,7 @@
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctkl]
[app.common.types.container :as ctn]
[app.common.types.file :as ctf]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.layout :as ctl]
@ -1598,6 +1599,34 @@
(let [frame (get objects parent-frame-id)]
(gsh/translate-to-frame shape frame))))
;; When copying an instance that is nested inside another one, we need to
;; advance the shape refs to one or more levels of remote mains.
(advance-copies [state selected data]
(let [file (wsh/get-local-file-full state)
libraries (wsh/get-libraries state)
page (wsh/lookup-page state)
heads (mapcat #(ctn/get-child-heads (:objects data) %) selected)]
(update data :objects
#(reduce (partial advance-copy file libraries page)
%
heads))))
(advance-copy [file libraries page objects shape]
(if (and (ctk/instance-head? shape) (not (ctk/main-instance? shape)))
(let [level-delta (ctn/get-nesting-level-delta (:objects page) shape uuid/zero)]
(if (pos? level-delta)
(reduce (partial advance-shape file libraries page level-delta)
objects
(cfh/get-children-with-self objects (:id shape)))
objects))
objects))
(advance-shape [file libraries page level-delta objects shape]
(let [new-shape-ref (ctf/advance-shape-ref file page libraries shape level-delta {:include-deleted? true})]
(cond-> objects
(and (some? new-shape-ref) (not= new-shape-ref (:shape-ref shape)))
(assoc-in [(:id shape) :shape-ref] new-shape-ref))))
(on-copy-error [error]
(js/console.error "clipboard blocked:" error)
(rx/empty))]
@ -1636,6 +1665,7 @@
(rx/merge-map (partial prepare-object objects frame-id))
(rx/reduce collect-data initial)
(rx/map (partial sort-selected state))
(rx/map (partial advance-copies state selected))
(rx/map #(t/encode-str % {:type :json-verbose}))
(rx/map wapi/write-to-clipboard)
(rx/catch on-copy-error)

View file

@ -168,13 +168,6 @@
;; Toolbar
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn toggle-toolbar-visibility
[]
(ptk/reify ::toggle-toolbar-visibility
ptk/UpdateEvent
(update [_ state]
(update-in state [:workspace-local :hide-toolbar] not))))
(defn hide-toolbar
[]
(ptk/reify ::hide-toolbar
@ -188,3 +181,10 @@
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-local :hide-toolbar] false))))
(defn toggle-toolbar-visibility
[]
(ptk/reify ::toggle-toolbar-visibility
ptk/UpdateEvent
(update [_ state]
(update-in state [:workspace-local :hide-toolbar] not))))

View file

@ -89,7 +89,6 @@
(update [_ state]
(update state :workspace-layout
(fn [flags]
(prn flags)
(if force?
(conj flags flag)
(if (contains? flags flag)

View file

@ -706,6 +706,38 @@
(rx/take-until stopper-s))))))
(defn sync-head
[id]
(ptk/reify ::sync-head
ptk/WatchEvent
(watch [it state _]
(log/info :msg "SYNC-head of shape" :id (str id))
(let [file (wsh/get-local-file state)
file-full (wsh/get-local-file-full state)
libraries (wsh/get-libraries state)
page-id (:current-page-id state)
container (cfh/get-container file :page page-id)
objects (:objects container)
shape-inst (ctn/get-shape container id)
parent (get objects (:parent-id shape-inst))
head (ctn/get-component-shape container parent)
components-v2
(features/active-feature? state "components/v2")
changes
(-> (pcb/empty-changes it)
(pcb/with-container container)
(pcb/with-objects (:objects container))
(dwlh/generate-sync-shape-direct file-full libraries container (:id head) false components-v2))]
(log/debug :msg "SYNC-head finished" :js/rchanges (log-changes
(:redo-changes changes)
file))
(rx/of (dch/commit-changes changes))))))
(defn reset-component
"Cancels all modifications in the shape with the given id, and all its children, in
the current page. Set all attributes equal to the ones in the linked component,
@ -726,23 +758,26 @@
components-v2
(features/active-feature? state "components/v2")
shape-inst (ctn/get-shape container id)
swap-slot (-> (ctn/get-shape container id)
(ctk/get-swap-slot))
undo-id (js/Symbol)
changes
(-> (pcb/empty-changes it)
(pcb/with-container container)
(pcb/with-objects (:objects container))
(dwlh/generate-sync-shape-direct file-full libraries container id true components-v2)
(cond->
(some? swap-slot)
;; We need to propagate parent changes
(dwlh/generate-sync-shape-direct file-full libraries container (:parent-id shape-inst) true components-v2)))]
(dwlh/generate-sync-shape-direct file-full libraries container id true components-v2))]
(log/debug :msg "RESET-COMPONENT finished" :js/rchanges (log-changes
(:redo-changes changes)
file))
(rx/of (dch/commit-changes changes))))))
(rx/of
(dwu/start-undo-transaction undo-id)
(dch/commit-changes changes)
(when (some? swap-slot)
(sync-head id))
(dwu/commit-undo-transaction undo-id))))))
(defn reset-components
"Cancels all modifications in the shapes with the given ids"
@ -1186,6 +1221,26 @@
:callback do-update}]
:tag :sync-dialog)))))))
(defn touch-component
"Update the modified-at attribute of the component to now"
[id]
(dm/verify! (uuid? id))
(ptk/reify ::touch-component
cljs.core/IDeref
(-deref [_] [id])
ptk/WatchEvent
(watch [it state _]
(let [data (get state :workspace-data)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/update-component id #(assoc % :modified-at (dt/now))))]
(rx/of (dch/commit-changes {:origin it
:redo-changes (:redo-changes changes)
:undo-changes []
:save-undo? false}))))))
(defn component-changed
"Notify that the component with the given id has changed, so it needs to be updated
in the current file and in the copies. And also update its thumbnails."
@ -1197,6 +1252,7 @@
ptk/WatchEvent
(watch [_ _ _]
(rx/of
(touch-component component-id)
(launch-component-sync component-id file-id undo-group)))))
(defn watch-component-changes
@ -1244,13 +1300,18 @@
(map (partial ch/components-changed old-data))
(reduce into #{})))]
(if (and (d/not-empty? changed-components) save-undo?)
(do (log/info :msg "DETECTED COMPONENTS CHANGED"
:ids (map str changed-components)
:undo-group undo-group)
(if (d/not-empty? changed-components)
(if save-undo?
(do (log/info :msg "DETECTED COMPONENTS CHANGED"
:ids (map str changed-components)
:undo-group undo-group)
(->> (rx/from changed-components)
(rx/map #(component-changed % (:id old-data) undo-group))))
(->> (rx/from changed-components)
(rx/map #(component-changed % (:id old-data) undo-group))))
;; even if save-undo? is false, we need to update the :modified-date of the component
;; (for example, for undos)
(->> (rx/from changed-components)
(rx/map #(touch-component %))))
(rx/empty)))))
changes-s

View file

@ -759,7 +759,8 @@
root-inst
root-main
omit-touched?
set-remote-synced?)
set-remote-synced?
components-v2)
changes))
both (fn [changes child-inst child-main]
@ -813,7 +814,8 @@
swapped
moved
false
reset?))))
reset?
components-v2))))
(defn- generate-rename-component
@ -948,7 +950,8 @@
component-container
container
root-inst
root-main))
root-main
components-v2))
only-main (fn [changes child-main]
(remove-shape changes
@ -1001,7 +1004,8 @@
swapped
moved
true
true)
true
components-v2)
;; The inverse sync may be made on a component that is inside a
;; remote library. We need to separate changes that are from
@ -1019,7 +1023,7 @@
;; ---- Operation generation helpers ----
(defn- compare-children
[changes children-inst children-main container-inst container-main file libraries only-inst-cb only-main-cb both-cb swapped-cb moved-cb inverse? reset?]
[changes children-inst children-main container-inst container-main file libraries only-inst-cb only-main-cb both-cb swapped-cb moved-cb inverse? reset? components-v2]
(log/trace :msg "Compare children")
(loop [children-inst (seq (or children-inst []))
children-main (seq (or children-main []))
@ -1039,18 +1043,18 @@
(reduce only-inst-cb changes children-inst)
:else
(if (or (ctk/is-main-of? child-main child-inst)
(if (or (ctk/is-main-of? child-main child-inst components-v2)
(and (ctf/match-swap-slot? child-main child-inst container-inst container-main file libraries) (not reset?)))
(recur (next children-inst)
(next children-main)
(if (ctk/is-main-of? child-main child-inst)
(if (ctk/is-main-of? child-main child-inst components-v2)
(both-cb changes child-inst child-main)
(swapped-cb changes child-inst child-main)))
(let [child-inst' (d/seek #(or (ctk/is-main-of? child-main %)
(let [child-inst' (d/seek #(or (ctk/is-main-of? child-main % components-v2)
(and (ctf/match-swap-slot? child-main % container-inst container-main file libraries) (not reset?)))
children-inst)
child-main' (d/seek #(or (ctk/is-main-of? % child-inst)
child-main' (d/seek #(or (ctk/is-main-of? % child-inst components-v2)
(and (ctf/match-swap-slot? % child-inst container-inst container-main file libraries) (not reset?)))
children-main)]
(cond
@ -1066,7 +1070,7 @@
:else
(if inverse?
(let [is-main? (ctk/is-main-of? child-inst child-main')]
(let [is-main? (ctk/is-main-of? child-inst child-main' components-v2)]
(recur (next children-inst)
(remove #(= (:id %) (:id child-main')) children-main)
(cond-> changes
@ -1076,7 +1080,7 @@
(swapped-cb child-inst child-main')
:always
(moved-cb child-inst child-main'))))
(let [is-main? (ctk/is-main-of? child-inst' child-main)]
(let [is-main? (ctk/is-main-of? child-inst' child-main components-v2)]
(recur (remove #(= (:id %) (:id child-inst')) children-inst)
(next children-main)
(cond-> changes
@ -1088,13 +1092,13 @@
(moved-cb child-inst' child-main))))))))))))
(defn- add-shape-to-instance
[changes component-shape index component-page container root-instance root-main omit-touched? set-remote-synced?]
[changes component-shape index component-page container root-instance root-main omit-touched? set-remote-synced? components-v2]
(log/info :msg (str "ADD [P " (pretty-uuid (:id container)) "] "
(:name component-shape)
" "
(pretty-uuid (:id component-shape))))
(let [component-parent-shape (ctn/get-shape component-page (:parent-id component-shape))
parent-shape (d/seek #(ctk/is-main-of? component-parent-shape %)
parent-shape (d/seek #(ctk/is-main-of? component-parent-shape % components-v2)
(cfh/get-children-with-self (:objects container)
(:id root-instance)))
all-parents (into [(:id parent-shape)]
@ -1163,13 +1167,13 @@
changes')))
(defn- add-shape-to-main
[changes shape index component component-container page root-instance root-main]
[changes shape index component component-container page root-instance root-main components-v2]
(log/info :msg (str "ADD [C " (pretty-uuid (:id component-container)) "] "
(:name shape)
" "
(pretty-uuid (:id shape))))
(let [parent-shape (ctn/get-shape page (:parent-id shape))
component-parent-shape (d/seek #(ctk/is-main-of? % parent-shape)
component-parent-shape (d/seek #(ctk/is-main-of? % parent-shape components-v2)
(cfh/get-children-with-self (:objects component-container)
(:id root-main)))
all-parents (into [(:id component-parent-shape)]

View file

@ -546,10 +546,7 @@
:layout-padding-type
:layout-gap
:layout-item-margin
:layout-item-margin-type
:layout-grid-cells
:layout-grid-columns
:layout-grid-rows]})
:layout-item-margin-type]})
;; We've applied the text-modifier so we can dissoc the temporary data
(fn [state]
(update state :workspace-text-modifier #(apply dissoc % ids)))

View file

@ -22,13 +22,9 @@
(defn esc-pressed []
(ptk/reify ::esc-pressed
ptk/WatchEvent
(watch [_ state _]
(watch [_ _ _]
;; Not interrupt when we're editing a path
(let [edition-id (or (get-in state [:workspace-drawing :object :id])
(get-in state [:workspace-local :edition]))
path-edit-mode (get-in state [:workspace-local :edit-path edition-id :edit-mode])]
(when-not (= :draw path-edit-mode)
(rx/of :interrupt))))))
(rx/of :interrupt))))
(def shortcuts
{:move-nodes {:tooltip "M"

View file

@ -404,6 +404,7 @@
ids-map
%2
delta
nil
libraries
library-data
it
@ -459,10 +460,10 @@
;; TODO: move to common.files.shape-helpers
(defn- prepare-duplicate-shape-change
([changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id]
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id (:frame-id obj) (:parent-id obj) false false))
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id]
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id (:frame-id obj) (:parent-id obj) false false))
([changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id frame-id parent-id duplicating-component? child?]
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id frame-id parent-id duplicating-component? child?]
(cond
(nil? obj)
changes
@ -486,11 +487,14 @@
duplicating-component? (or duplicating-component? (ctk/instance-head? obj))
is-component-main? (ctk/main-instance? obj)
original-ref-shape (-> (ctf/find-original-ref-shape nil page libraries obj {:include-deleted? true})
:id)
into-component? (and duplicating-component?
(ctn/in-any-component? objects parent))
level-delta (if (some? level-delta)
level-delta
(ctn/get-nesting-level-delta objects obj parent))
new-shape-ref (ctf/advance-shape-ref nil page libraries obj level-delta {:include-deleted? true})
regenerate-component
(fn [changes shape]
(let [components-v2 (dm/get-in library-data [:options :components-v2])
@ -518,9 +522,9 @@
(cond-> (or frame? group? bool?)
(assoc :shapes []))
(cond-> (and (some? original-ref-shape)
(not= original-ref-shape (:shape-ref obj)))
(assoc :shape-ref original-ref-shape))
(cond-> (and (some? new-shape-ref)
(not= new-shape-ref (:shape-ref obj)))
(assoc :shape-ref new-shape-ref))
(gsh/move delta)
(d/update-when :interactions #(ctsi/remap-interactions % ids-map objects))
@ -561,6 +565,7 @@
ids-map
child
delta
level-delta
libraries
library-data
it

View file

@ -353,13 +353,14 @@
(ptk/reify ::create-artboard-from-selection
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (wsh/lookup-selected state)
selected (cfh/clean-loops objects selected)
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
selected (->> (wsh/lookup-selected state)
(cfh/clean-loops objects)
(remove #(ctn/has-any-copy-parent? objects (get objects %))))
changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects))
changes (-> (pcb/empty-changes it page-id)
(pcb/with-objects objects))
[frame-shape changes]
(cfsh/prepare-create-artboard-from-selection changes

View file

@ -606,11 +606,11 @@
(->> move-stream
(rx/last)
(rx/mapcat
(fn [[_ target-frame drop-index]]
(fn [[_ target-frame drop-index cell-data]]
(let [undo-id (js/Symbol)]
(rx/of (dwu/start-undo-transaction undo-id)
(move-shapes-to-frame ids target-frame drop-index)
(dwm/apply-modifiers {:undo-transation? false})
(move-shapes-to-frame ids target-frame drop-index cell-data)
(finish-transform)
(dwu/commit-undo-transaction undo-id))))))))))))))
@ -832,7 +832,7 @@
:ignore-snap-pixel true}))))))
(defn- move-shapes-to-frame
[ids frame-id drop-index]
[ids frame-id drop-index [row column :as cell]]
(ptk/reify ::move-shapes-to-frame
ptk/WatchEvent
(watch [it state _]
@ -905,6 +905,11 @@
moving-shapes-ids
(map :id moving-shapes)
moving-shapes-children-ids
(->> moving-shapes
(mapcat #(cfh/get-children-with-self objects (:id %)))
(map :id))
changes
(-> (pcb/empty-changes it page-id)
(pcb/with-objects objects)
@ -913,7 +918,7 @@
(pcb/update-shapes moving-shapes-ids ctl/remove-layout-item-data))
;; Remove component-root property when moving a shape inside a component
(cond-> (ctn/get-instance-root objects frame)
(pcb/update-shapes moving-shapes-ids #(dissoc % :component-root)))
(pcb/update-shapes moving-shapes-children-ids #(dissoc % :component-root)))
;; Add component-root property when moving a component outside a component
(cond-> (not (ctn/get-instance-root objects frame))
(pcb/update-shapes moving-shapes-ids (fn [shape]
@ -924,7 +929,16 @@
(pcb/update-shapes shape-ids-to-detach ctk/detach-shape)
(pcb/change-parent frame-id moving-shapes drop-index)
(cond-> (ctl/grid-layout? objects frame-id)
(-> (pcb/update-shapes [frame-id] ctl/assign-cell-positions {:with-objects? true})
(-> (pcb/update-shapes
[frame-id]
(fn [frame objects]
(-> frame
;; Assign the cell when pushing into a specific grid cell
(cond-> (some? cell)
(-> (ctl/push-into-cell moving-shapes-ids row column)
(ctl/assign-cells objects)))
(ctl/assign-cell-positions objects)))
{:with-objects? true})
(pcb/reorder-grid-children [frame-id])))
(pcb/remove-objects empty-parents))]

View file

@ -625,7 +625,7 @@
(if (some? shape)
(let [fonts (ff/shape->fonts shape objects)
bounds (gsb/get-object-bounds objects shape)
bounds (gsb/get-object-bounds objects shape {:ignore-margin? false})
background (when (str/ends-with? object-id "component")
(or (:background options) (dom/get-css-variable "--assets-component-background-color") "#fff"))

View file

@ -7,6 +7,7 @@
(ns app.main.ui.auth
(:require-macros [app.main.style :as stl])
(:require
[app.common.data.macros :as dm]
[app.config :as cf]
[app.main.ui.auth.login :refer [login-page]]
[app.main.ui.auth.recovery :refer [recovery-page]]
@ -35,41 +36,39 @@
[:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])])))
(mf/defc auth
[{:keys [route] :as props}]
(let [section (get-in route [:data :name])
params (:query-params route)
show-illustration? (contains? cf/flags :login-illustration)]
{::mf/props :obj}
[{:keys [route]}]
(let [section (dm/get-in route [:data :name])
params (:query-params route)]
(mf/use-effect
#(dom/set-html-title (tr "title.default")))
(mf/with-effect []
(dom/set-html-title (tr "title.default")))
[:main {:class (stl/css-case :auth-section true
:no-illustration (not show-illustration?))}
(when show-illustration?
[:div {:class (stl/css :login-illustration)}
i/login-illustration])
[:main {:class (stl/css :auth-section)}
[:div {:class (stl/css :login-illustration)}
i/login-illustration]
[:section {:class (stl/css :auth-content)}
[:*
[:a {:href "#/" :class (stl/css :logo-btn)} i/logo]
(case section
:auth-register
[:& register-page {:params params}]
[:a {:href "#/" :class (stl/css :logo-btn)} i/logo]
(case section
:auth-register
[:& register-page {:params params}]
:auth-register-validate
[:& register-validate-page {:params params}]
:auth-register-validate
[:& register-validate-page {:params params}]
:auth-register-success
[:& register-success-page {:params params}]
:auth-register-success
[:& register-success-page {:params params}]
:auth-login
[:& login-page {:params params}]
:auth-login
[:& login-page {:params params}]
:auth-recovery-request
[:& recovery-request-page]
:auth-recovery-request
[:& recovery-request-page]
:auth-recovery
[:& recovery-page {:params params}])]
:auth-recovery
[:& recovery-page {:params params}])
(when (contains? #{:auth-login :auth-register} section)
(when (or (= section :auth-login)
(= section :auth-register))
[:& terms-login])]]))

View file

@ -17,11 +17,6 @@
width: 100%;
overflow: auto;
&.no-illustration {
display: flex;
justify-content: center;
}
@media (max-width: 992px) {
display: flex;
justify-content: center;

View file

@ -35,6 +35,14 @@
:login-with-gitlab
:login-with-oidc]))
(mf/defc demo-warning
{::mf/props :obj}
[]
[:div {:class (stl/css :banner)}
[:& context-notification
{:type :warning
:content (tr "auth.demo-warning")}]])
(defn- login-with-oidc
[event provider params]
(dom/prevent-default event)
@ -284,6 +292,9 @@
[:h1 {:class (stl/css :auth-title)
:data-test "login-title"} (tr "auth.login-title")]
(when (contains? cf/flags :demo-warning)
[:& demo-warning])
[:hr {:class (stl/css :separator)}]
[:& login-methods {:params params}]

View file

@ -18,20 +18,12 @@
[app.main.ui.components.forms :as fm]
[app.main.ui.components.link :as lk]
[app.main.ui.icons :as i]
[app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.i18n :refer [tr tr-html]]
[app.util.router :as rt]
[beicon.v2.core :as rx]
[cljs.spec.alpha :as s]
[rumext.v2 :as mf]))
(mf/defc demo-warning
[_]
[:div {:class (stl/css :banner)}
[:& context-notification
{:type :warning
:content (tr "auth.demo-warning")}]])
;; --- PAGE: Register
(defn- validate
@ -86,7 +78,7 @@
(st/emit! (rt/nav :auth-register-validate {} params)))
(mf/defc register-form
[{:keys [params on-success-callback] :as props}]
[{:keys [params on-success-callback]}]
(let [initial (mf/use-memo (mf/deps params) (constantly params))
form (fm/use-form :spec ::register-form
:validators [validate
@ -136,7 +128,8 @@
(mf/defc register-methods
[{:keys [params on-success-callback] :as props}]
{::mf/props :obj}
[{:keys [params on-success-callback]}]
[:*
(when login/show-alt-login-buttons?
[:*
@ -146,14 +139,15 @@
[:& register-form {:params params :on-success-callback on-success-callback}]])
(mf/defc register-page
[{:keys [params] :as props}]
{::mf/props :obj}
[{:keys [params]}]
[:div {:class (stl/css :auth-form)}
[:h1 {:class (stl/css :auth-title)
:data-test "registration-title"} (tr "auth.register-title")]
[:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")]
(when (contains? cf/flags :demo-warning)
[:& demo-warning])
[:& login/demo-warning])
[:& register-methods {:params params}]
@ -212,7 +206,7 @@
::accept-newsletter-subscription])))
(mf/defc register-validate-form
[{:keys [params on-success-callback] :as props}]
[{:keys [params on-success-callback]}]
(let [form (fm/use-form :spec ::register-validate-form
:validators [(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))
(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))]
@ -263,7 +257,7 @@
(mf/defc register-validate-page
[{:keys [params] :as props}]
[{:keys [params]}]
[:div {:class (stl/css :auth-form)}
[:h1 {:class (stl/css :auth-title)
:data-test "register-title"} (tr "auth.register-title")]
@ -279,7 +273,7 @@
(tr "labels.go-back")]]]])
(mf/defc register-success-page
[{:keys [params] :as props}]
[{:keys [params]}]
[:div {:class (stl/css :auth-form :register-success)}
[:div {:class (stl/css :notification-icon)} i/icon-verify]
[:div {:class (stl/css :notification-text)} (tr "auth.verification-email-sent")]

View file

@ -17,7 +17,7 @@
[app.main.fonts :as fonts]
[app.main.rasterizer :as thr]
[app.main.refs :as refs]
[app.main.render :refer [component-svg]]
[app.main.render :as render]
[app.main.repo :as rp]
[app.main.store :as st]
[app.main.ui.components.color-bullet :as bc]
@ -49,8 +49,7 @@
(->> (rp/cmd! :create-file-thumbnail params)
(rx/map :uri))))
(defn- ask-for-thumbnail
"Creates some hooks to handle the files thumbnails cache"
(defn render-thumbnail
[file-id revn]
(->> (wrk/ask! {:cmd :thumbnails/generate-for-file
:revn revn
@ -61,7 +60,12 @@
(rx/map (fn [styles]
(assoc result
:styles styles
:width 252))))))
:width 252))))))))
(defn- ask-for-thumbnail
"Creates some hooks to handle the files thumbnails cache"
[file-id revn]
(->> (render-thumbnail file-id revn)
(rx/mapcat thr/render)
(rx/mapcat (partial persist-thumbnail file-id revn))))
@ -141,8 +145,8 @@
(let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library
[:div {:class (stl/css :asset-list-item)
:key (str "assets-component-" (:id component))}
[:& component-svg {:root-shape (get-in component [:objects root-id])
:objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2
[:& render/component-svg {:root-shape (get-in component [:objects root-id])
:objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2
[:div {:class (stl/css :name-block)}
[:span {:class (stl/css :item-name)
:title (:name component)}

View file

@ -12,6 +12,8 @@
.modal-container {
@extend .modal-container-base;
display: flex;
flex-direction: column;
}
.modal-header {
@ -29,6 +31,9 @@
.modal-content {
@include bodySmallTypography;
flex: 1;
overflow-y: auto;
overflow-x: hidden;
display: grid;
grid-template-columns: 1fr;
gap: $s-16;

View file

@ -378,6 +378,7 @@
tutorial-viewed? (:viewed-tutorial? props true)
walkthrough-viewed? (:viewed-walkthrough? props true)
is-my-penpot (= (:default-team-id profile) (:id team))
team-id (:id team)
@ -387,6 +388,7 @@
(st/emit! (du/update-profile-props {:team-hero? false})
(ptk/data-event ::ev/event {::ev/name "dont-show-team-up-hero"
::ev/origin "dashboard"}))))
close-tutorial
(mf/use-fn
(fn []
@ -395,6 +397,7 @@
::ev/origin "get-started-hero"
:type "tutorial"
:section "dashboard"}))))
close-walkthrough
(mf/use-fn
(fn []
@ -402,7 +405,13 @@
(ptk/data-event ::ev/event {::ev/name "dont-show-walkthrough"
::ev/origin "get-started-hero"
:type "walkthrough"
:section "dashboard"}))))]
:section "dashboard"}))))
show-hero? (and is-my-penpot
(or (not tutorial-viewed?)
(not walkthrough-viewed?)))
show-team-hero? (and (not is-my-penpot) team-hero?)]
(mf/with-effect [team]
(let [tname (if (:is-default team)
@ -423,8 +432,7 @@
[:& team-hero {:team team :close-fn close-banner}])
(when (and (contains? cf/flags :dashboard-templates-section)
(or (not tutorial-viewed?)
(not walkthrough-viewed?)))
show-hero?)
[:div {:class (stl/css :hero-projects)}
(when (and (not tutorial-viewed?) (:is-default team))
[:& tutorial-project
@ -435,7 +443,11 @@
[:& interface-walkthrough
{:close-walkthrough close-walkthrough}])])
[:div {:class (stl/css :dashboard-container :no-bg :dashboard-projects)}
[:div {:class (stl/css-case :dashboard-container true
:no-bg true
:dashboard-projects true
:with-hero show-hero?
:with-team-hero show-team-hero?)}
(for [{:keys [id] :as project} projects]
(let [files (when recent-map
(->> (vals recent-map)

View file

@ -17,6 +17,12 @@
.dashboard-projects {
user-select: none;
height: calc(100vh - $s-64);
}
.with-hero,
.with-team-hero {
height: calc(100vh - $s-280);
}
.dashboard-shared {

View file

@ -339,7 +339,7 @@
.profile-fullname {
@include smallTitleTipography;
@include text-ellipsis;
@include textEllipsis;
align-self: center;
max-width: $s-160;
color: var(--profile-foreground-color);

View file

@ -118,6 +118,7 @@
:id id
:data-index index
:on-click on-click
:on-mouse-down dom/prevent-default
:on-key-down on-key-down}
[:div {:class (stl/css :template-card)}
[:div {:class (stl/css :img-container)}

View file

@ -91,4 +91,4 @@
(defmethod rc/render-release-notes "0.0"
[params]
(rc/render-release-notes (assoc params :version "1.21")))
(rc/render-release-notes (assoc params :version "2.0")))

View file

@ -11,10 +11,6 @@
[app.main.ui.releases.common :as c]
[rumext.v2 :as mf]))
(defmethod c/render-release-notes "1.21"
[data]
(c/render-release-notes (assoc data :version "2.0")))
;; TODO: Review all copies and alt text
(defmethod c/render-release-notes "2.0"
[{:keys [slide klass next finish navigate version]}]

View file

@ -39,8 +39,8 @@
(s/keys :req-un [::email-1 ::email-2]))
(defn- on-error
[form {:keys [code] :as error}]
(case code
[form error]
(case (:code (ex-data error))
:email-already-exists
(swap! form (fn [data]
(let [error {:message (tr "errors.email-already-exists")}]
@ -93,7 +93,6 @@
(let [different-emails-error? (= (dma/get-in @form [:errors :email-2 :code]) :different-emails)
email-1 (dma/get-in @form [:clean-data :email-1])
email-2 (dma/get-in @form [:clean-data :email-2])]
(println "different-emails-error?" (and different-emails-error? (= email-1 email-2)))
(when (and different-emails-error? (= email-1 email-2))
(swap! form d/dissoc-in [:errors :email-2])))))]

View file

@ -62,32 +62,34 @@
(obj/merge! props (get-border-props shape)))
(defn add-fill!
[attrs fill-data render-id index type]
(let [index (if (some? index) (dm/str "-" index) "")]
(cond
(contains? fill-data :fill-image)
(let [id (dm/str "fill-image-" render-id)]
(obj/set! attrs "fill" (dm/str "url(#" id ")")))
([attrs fill-data render-id index type]
(add-fill! attrs fill-data render-id index type "none"))
([attrs fill-data render-id index type fill-default]
(let [index (if (some? index) (dm/str "-" index) "")]
(cond
(contains? fill-data :fill-image)
(let [id (dm/str "fill-image-" render-id)]
(obj/set! attrs "fill" (dm/str "url(#" id ")")))
(some? (:fill-color-gradient fill-data))
(let [id (dm/str "fill-color-gradient-" render-id index)]
(obj/set! attrs "fill" (dm/str "url(#" id ")")))
(some? (:fill-color-gradient fill-data))
(let [id (dm/str "fill-color-gradient-" render-id index)]
(obj/set! attrs "fill" (dm/str "url(#" id ")")))
(contains? fill-data :fill-color)
(obj/set! attrs "fill" (:fill-color fill-data))
(contains? fill-data :fill-color)
(obj/set! attrs "fill" (:fill-color fill-data))
:else
(obj/set! attrs "fill" "none"))
:else
(obj/set! attrs "fill" fill-default))
(when (contains? fill-data :fill-opacity)
(obj/set! attrs "fillOpacity" (:fill-opacity fill-data)))
(when (contains? fill-data :fill-opacity)
(obj/set! attrs "fillOpacity" (:fill-opacity fill-data)))
(when (and (= :text type)
(nil? (:fill-color-gradient fill-data))
(nil? (:fill-color fill-data)))
(obj/set! attrs "fill" "black"))
(when (and (= :text type)
(nil? (:fill-color-gradient fill-data))
(nil? (:fill-color fill-data)))
(obj/set! attrs "fill" "black"))
attrs))
attrs)))
(defn add-stroke!
[attrs data render-id index open-path?]
@ -165,8 +167,10 @@
(obj/map->obj)))))
(defn get-fill-style
[fill-data index render-id type]
(add-fill! #js {} fill-data render-id index type))
([fill-data index render-id type]
(add-fill! #js {} fill-data render-id index type))
([fill-data index render-id type fill-default]
(add-fill! #js {} fill-data render-id index type fill-default)))
(defn add-fill-props!
([props shape render-id]
@ -242,8 +246,10 @@
(obj/set! style "fillOpacity" opacity)))
^boolean (d/not-empty? shape-fills)
(let [fill (nth shape-fills 0)]
(obj/merge! style (get-fill-style fill render-id 0 shape-type)))
(let [fill (nth shape-fills 0)
svg-fill (obj/get svg-attrs "fill")
fill-default (d/nilv svg-fill "none")]
(obj/merge! style (get-fill-style fill render-id 0 shape-type fill-default)))
(and ^boolean (cfh/path-shape? shape)
^boolean (empty? shape-fills))

View file

@ -476,7 +476,8 @@
svg-attrs (attrs/get-svg-props shape render-id)
style (-> (obj/get props "style")
(obj/clone))
(obj/clone)
(obj/merge! (obj/get svg-attrs "style")))
props (mf/spread-props svg-attrs
{:id stroke-id

View file

@ -8,8 +8,8 @@
(:require
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.bounds :as gsb]
[app.common.types.shape.layout :as ctl]
[app.config :as cf]
[app.main.ui.context :as muc]
@ -119,7 +119,7 @@
points (dm/get-prop shape :points)
bounds (mf/with-memo [bounds points]
(or bounds (grc/points->rect points)))
(or bounds (gsb/get-frame-bounds shape)))
thumb (:thumbnail shape)

View file

@ -51,7 +51,7 @@
.layer-title {
@include bodySmallTypography;
@include text-ellipsis;
@include textEllipsis;
height: $s-32;
padding: $s-8 0;
color: var(--assets-item-name-foreground-color-rest);

View file

@ -36,7 +36,7 @@
width: $s-272;
padding: $s-6;
max-height: calc(100vh - 3 * ($s-2 + $s-48));
overflow: scroll;
overflow: auto;
}
.dropdown-element {

View file

@ -228,48 +228,54 @@
(mf/defc context-menu-group
[{:keys [shapes]}]
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
do-create-artboard-from-selection #(st/emit! (dwsh/create-artboard-from-selection))
(let [multiple? (> (count shapes) 1)
single? (= (count shapes) 1)
objects (deref refs/workspace-page-objects)
any-in-copy? (some true? (map #(ctn/has-any-copy-parent? objects %) shapes))
;; components can't be ungrouped
has-frame? (->> shapes (d/seek #(and (cfh/frame-shape? %) (not (ctk/instance-head? %)))))
has-group? (->> shapes (d/seek #(and (cfh/group-shape? %) (not (ctk/instance-head? %)))))
has-bool? (->> shapes (d/seek cfh/bool-shape?))
has-mask? (->> shapes (d/seek :masked-group))
has-bool? (->> shapes (d/seek cfh/bool-shape?))
has-mask? (->> shapes (d/seek :masked-group))
is-group? (and single? has-group?)
is-bool? (and single? has-bool?)
is-group? (and single? has-group?)
is-bool? (and single? has-bool?)
do-create-group #(st/emit! dw/group-selected)
do-mask-group #(st/emit! dw/mask-group)
do-remove-group #(st/emit! dw/ungroup-selected)
do-unmask-group #(st/emit! dw/unmask-group)]
do-unmask-group #(st/emit! dw/unmask-group)
do-create-artboard-from-selection
#(st/emit! (dwsh/create-artboard-from-selection))]
[:*
(when (or has-bool? has-group? has-mask? has-frame?)
[:& menu-entry {:title (tr "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}])
(when (not any-in-copy?)
[:*
(when (or has-bool? has-group? has-mask? has-frame?)
[:& menu-entry {:title (tr "workspace.shape.menu.ungroup")
:shortcut (sc/get-tooltip :ungroup)
:on-click do-remove-group}])
[:& menu-entry {:title (tr "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}]
[:& menu-entry {:title (tr "workspace.shape.menu.group")
:shortcut (sc/get-tooltip :group)
:on-click do-create-group}]
(when (or multiple? (and is-group? (not has-mask?)) is-bool?)
[:& menu-entry {:title (tr "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}])
(when (or multiple? (and is-group? (not has-mask?)) is-bool?)
[:& menu-entry {:title (tr "workspace.shape.menu.mask")
:shortcut (sc/get-tooltip :mask)
:on-click do-mask-group}])
(when has-mask?
[:& menu-entry {:title (tr "workspace.shape.menu.unmask")
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}])
(when has-mask?
[:& menu-entry {:title (tr "workspace.shape.menu.unmask")
:shortcut (sc/get-tooltip :unmask)
:on-click do-unmask-group}])
[:& menu-entry {:title (tr "workspace.shape.menu.create-artboard-from-selection")
:shortcut (sc/get-tooltip :artboard-selection)
:on-click do-create-artboard-from-selection}]
[:& menu-separator]]))
[:& menu-entry {:title (tr "workspace.shape.menu.create-artboard-from-selection")
:shortcut (sc/get-tooltip :artboard-selection)
:on-click do-create-artboard-from-selection}]
[:& menu-separator]])]))
(mf/defc context-focus-mode-menu
[{:keys []}]
@ -391,7 +397,9 @@
(mf/defc context-menu-layout
{::mf/props :obj}
[{:keys [shapes]}]
(let [single? (= (count shapes) 1)
(let [single? (= (count shapes) 1)
objects (deref refs/workspace-page-objects)
any-in-copy? (some true? (map #(ctn/has-any-copy-parent? objects %) shapes))
has-flex?
(and single? (every? ctl/flex-layout? shapes))
@ -414,29 +422,30 @@
(fn [_event]
(let [ids (map :id shapes)]
(st/emit! (dwsl/remove-layout ids)))))]
[:*
(when (not any-in-copy?)
(if (or ^boolean has-flex?
^boolean has-grid?)
[:div
[:& menu-separator]
(if has-flex?
[:& menu-entry {:title (tr "workspace.shape.menu.remove-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:on-click on-remove-layout}]
[:& menu-entry {:title (tr "workspace.shape.menu.remove-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:on-click on-remove-layout}])]
(if (or ^boolean has-flex?
^boolean has-grid?)
[:div
[:& menu-separator]
(if has-flex?
[:& menu-entry {:title (tr "workspace.shape.menu.remove-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:on-click on-remove-layout}]
[:& menu-entry {:title (tr "workspace.shape.menu.remove-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:on-click on-remove-layout}])]
[:div
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.add-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:value "flex"
:on-click on-add-layout}]
[:& menu-entry {:title (tr "workspace.shape.menu.add-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:value "grid"
:on-click on-add-layout}]])))
[:div
[:& menu-separator]
[:& menu-entry {:title (tr "workspace.shape.menu.add-flex")
:shortcut (sc/get-tooltip :toggle-layout-flex)
:value "flex"
:on-click on-add-layout}]
[:& menu-entry {:title (tr "workspace.shape.menu.add-grid")
:shortcut (sc/get-tooltip :toggle-layout-grid)
:value "grid"
:on-click on-add-layout}]]))]))
(mf/defc context-menu-component
[{:keys [shapes]}]

View file

@ -62,14 +62,11 @@
}
}
.submenu-icon {
position: absolute;
right: $s-16;
svg {
@extend .button-icon-small;
stroke: var(--menu-foreground-color);
}
.submenu-icon svg {
@extend .button-icon-small;
stroke: var(--menu-foreground-color);
}
&:hover {
background-color: var(--menu-background-color-hover);
.title {

View file

@ -81,11 +81,6 @@
height: fit-content;
}
.item-name {
@include bodyLargeTypography;
color: var(--library-name-foreground-color);
}
.item-publish,
.item-unpublish {
@extend .button-primary;
@ -216,8 +211,11 @@
}
.item-name {
@include bodyLargeTypography;
@include textEllipsis;
margin: 0;
max-width: $s-244;
color: var(--library-name-foreground-color);
}
.item-update {
@ -254,6 +252,7 @@
.modal-v2-info {
width: $s-664;
height: fit-content;
max-height: fit-content;
}
.modal-v2-title {

View file

@ -179,6 +179,10 @@
(mf/use-fn
(mf/deps selected-drawtool)
(fn [_]
(when (contains? layout :document-history)
(st/emit! (-> (dw/remove-layout-flag :document-history)
(vary-meta assoc ::ev/origin "workspace-header"))))
(if (= :comments selected-drawtool)
(st/emit! :interrupt)
(active-comments))))
@ -187,8 +191,11 @@
(mf/use-fn
(mf/deps selected-drawtool)
(fn []
(when (= :comments selected-drawtool)
(st/emit! :interrupt))
(st/emit! :interrupt
(-> (dw/toggle-layout-flag :comments)
(vary-meta assoc ::ev/origin "workspace-header"))))
(st/emit! (-> (dw/toggle-layout-flag :document-history)
(vary-meta assoc ::ev/origin "workspace-header")))))]

View file

@ -130,7 +130,7 @@
container-ref (mf/use-ref nil)
content-ref (mf/use-ref nil)
bounds (gsb/get-object-bounds objects shape)
bounds (gsb/get-object-bounds objects shape {:ignore-margin? false})
x (dm/get-prop bounds :x)
y (dm/get-prop bounds :y)

View file

@ -219,7 +219,9 @@
:auto-focus true
:default-value (cfh/merge-path-item (:path color) (:name color))}]
[:div {:title (:name color)
[:div {:title (if (= (:name color) default-name)
default-name
(dm/str (:name color) " (" default-name ")"))
:class (stl/css :name-block)
:on-double-click rename-color-clicked}

View file

@ -109,6 +109,8 @@
:style {"--depth" depth "--parent-size" parent-size}
:ref ref
:on-double-click start-edit}
(d/nilv shape-name "")]
(if (dbg/enabled? :show-ids)
(str (d/nilv shape-name "") " | " (str/slice (str shape-id) 24))
(d/nilv shape-name ""))]
(when (and (dbg/enabled? :show-touched) ^boolean shape-touched?)
[:span {:class (stl/css :element-name-touched)} "*"])])))

View file

@ -13,10 +13,10 @@
height: $s-32;
min-height: $s-32;
margin: $s-8 0 $s-4 $s-8;
padding-right: $s-8;
padding-right: $s-12;
&.search {
padding: 0 $s-8 0 $s-12;
padding: 0 $s-12 0 $s-8;
gap: $s-4;
.filter-button {
@include flexCenter;

View file

@ -26,6 +26,7 @@
[app.main.ui.hooks :as h]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.assets.common :as cmm]
[app.util.debug :as dbg]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.timers :as tm]
@ -639,4 +640,6 @@
[:& component-swap {:shapes copies}])
(when (and (not swap-opened?) (not multi) components-v2)
[:& component-annotation {:id id :shape shape :component component}])])])))
[:& component-annotation {:id id :shape shape :component component}])
(when (dbg/enabled? :display-touched)
[:div ":touched " (str (:touched shape))])])])))

View file

@ -187,15 +187,15 @@
(def ^:private corner-bottom-icon
(i/icon-xref :corner-bottom (stl/css :corner-icon)))
(def ^:private corner-bottomleft-icon
(i/icon-xref :corner-bottomleft (stl/css :corner-icon)))
(i/icon-xref :corner-bottom-left (stl/css :corner-icon)))
(def ^:private corner-bottomright-icon
(i/icon-xref :corner-bottomright (stl/css :corner-icon)))
(i/icon-xref :corner-bottom-right (stl/css :corner-icon)))
(def ^:private corner-top-icon
(i/icon-xref :corner-top (stl/css :corner-icon)))
(def ^:private corner-topleft-icon
(i/icon-xref :corner-topleft (stl/css :corner-icon)))
(i/icon-xref :corner-top-left (stl/css :corner-icon)))
(def ^:private corner-topright-icon
(i/icon-xref :corner-topright (stl/css :corner-icon)))
(i/icon-xref :corner-top-right (stl/css :corner-icon)))
(mf/defc interaction-entry
[{:keys [index shape interaction update-interaction remove-interaction]}]

View file

@ -227,5 +227,5 @@
.title-spacing-sitemap {
padding-inline-start: $s-8;
margin-block-start: $s-8;
padding-inline-end: $s-20;
margin-block-end: $s-4;
}

View file

@ -11,7 +11,10 @@
[app.common.geom.point :as gpt]
[app.main.store :as st]
[app.util.dom :as dom]
[rumext.v2 :as mf]))
[app.util.mouse :as mse]
[goog.events :as events]
[rumext.v2 :as mf])
(:import goog.events.EventType))
(defonce viewport-ref (atom nil))
(defonce current-observer (atom nil))
@ -45,6 +48,8 @@
#(fn [node]
(mf/set-ref-val! ref node)
(reset! viewport-ref node)
(when (some? node)
(events/listen node EventType.MOUSELEAVE (fn [] (st/emit! (mse/->BlurEvent)))))
(init-observer node on-change-bounds)))]))
(defn point->viewport

View file

@ -73,6 +73,9 @@
;; Show an asterisk for touched copies
:show-touched
;; Show the id with the name
:show-ids
;;
:grid-layout
@ -80,7 +83,10 @@
:grid-cells
;; Show info about shapes
:shape-panel})
:shape-panel
;; Show what is touched in copies
:display-touched})
(defn enable!
[option]

View file

@ -588,7 +588,7 @@
(t/is (= (:fill-color shape1) clr/black))
(t/is (= (:fill-opacity shape1) 0))
(t/is (= (:name shape2) "Rect 1"))
(t/is (= (:touched shape2) nil))
(t/is (= (:touched shape2) #{:fill-group}))
(t/is (= (:fill-color shape2) clr/test))
(t/is (= (:fill-opacity shape2) 0.5))
(t/is (= (:name c-instance2) "Board"))

View file

@ -5064,7 +5064,7 @@ msgstr "Click to close the path"
#, markdown
msgid "workspace.top-bar.view-only"
msgstr "**Inspecting mode** (View Only)"
msgstr "**Inspecting code** (View Only)"
msgid "workspace.top-bar.read-only.done"
msgstr "Done"

View file

@ -5149,7 +5149,7 @@ msgstr "Pulsar para cerrar la ruta"
#, markdown
msgid "workspace.top-bar.view-only"
msgstr "**Modo inspección** (View only)"
msgstr "**Inspeccionando código** (View only)"
msgid "workspace.top-bar.read-only.done"
msgstr "Hecho"

View file

@ -1 +1 @@
1.21.0
2.0.0