🐛 Fix component annotation in new UI

This commit is contained in:
Eva 2024-01-08 18:36:48 +01:00 committed by Andrey Antukh
parent 947cc0ce92
commit e866e99804
3 changed files with 472 additions and 267 deletions

View file

@ -88,6 +88,7 @@
--button-constraint-border-color-rest: var(--color-background-tertiary); --button-constraint-border-color-rest: var(--color-background-tertiary);
--button-constraint-border-color-hover: var(--color-accent-primary-muted); --button-constraint-border-color-hover: var(--color-accent-primary-muted);
--button-constraint-background-color-hover: var(--color-accent-primary); --button-constraint-background-color-hover: var(--color-accent-primary);
--constraint-widget-background-color: var(--color-background-tertiary); --constraint-widget-background-color: var(--color-background-tertiary);
--constraint-center-area-background-color: var(--color-background-primary); --constraint-center-area-background-color: var(--color-background-primary);
@ -138,6 +139,8 @@
// ICONS // ICONS
--icon-foreground: var(--color-foreground-secondary); --icon-foreground: var(--color-foreground-secondary);
--icon-foreground-hover: var(--color-foreground-primary); --icon-foreground-hover: var(--color-foreground-primary);
--icon-foreground-accept: var(--ok-color);
--icon-foreground-discard: var(--error-color);
// INPUTS, SELECTS, DROPDOWNS // INPUTS, SELECTS, DROPDOWNS
--input-background-color: var(--color-background-tertiary); --input-background-color: var(--color-background-tertiary);

View file

@ -106,35 +106,55 @@
(fn [] (st/emit! (dw/set-annotations-id-for-create nil))))) ;; cleanup set-annotationsid-for-create on unload (fn [] (st/emit! (dw/set-annotations-id-for-create nil))))) ;; cleanup set-annotationsid-for-create on unload
(when (or creating? annotation) (when (or creating? annotation)
[:div.component-annotation {:class (dom/classnames :editing @editing? :creating creating?)} [:div {:class (stl/css-case :component-annotation true
[:div.title {:class (dom/classnames :expandeable (not (or @editing? creating?))) :editing @editing?
:on-click #(expand (not annotations-expanded?))} :creating creating?)}
[:div (if (or @editing? creating?) [:div {:class (stl/css-case :annotation-title true
(if @editing? :expandeable (not (or @editing? creating?))
(tr "workspace.options.component.edit-annotation") :expanded annotations-expanded?)
(tr "workspace.options.component.create-annotation")) :on-click #(expand (not annotations-expanded?))}
[:* (if annotations-expanded?
[:div.expand i/arrow-down] (if (or @editing? creating?)
[:div.expand i/arrow-slide]) [:span {:class (stl/css :annotation-text)}
(tr "workspace.options.component.annotation")])] (if @editing?
[:div (tr "workspace.options.component.edit-annotation")
(tr "workspace.options.component.create-annotation"))]
[:*
[:span {:class (stl/css-case :icon-arrow true
:expanded annotations-expanded?)}
i/arrow-refactor]
[:span {:class (stl/css :annotation-text)}
(tr "workspace.options.component.annotation")]])
[:div {:class (stl/css :icons-wrapper)}
(when (and main-instance? annotations-expanded?) (when (and main-instance? annotations-expanded?)
(if (or @editing? creating?) (if (or @editing? creating?)
[:* [:*
[:div.icon {:title (if creating? (tr "labels.create") (tr "labels.save")) [:div {:title (if creating? (tr "labels.create") (tr "labels.save"))
:on-click save :on-click save
:class (dom/classnames :hidden @invalid-text?)} i/tick] :class (stl/css-case :icon true
[:div.icon {:title (tr "labels.discard") :icon-tick true
:on-click discard} i/cross]] :hidden @invalid-text?)}
[:* i/tick-refactor]
[:div.icon {:title (tr "labels.edit") [:div {:class (stl/css :icon :icon-cross)
:on-click edit} i/pencil] :title (tr "labels.discard")
[:div.icon {:title (tr "labels.delete") :on-click discard}
:on-click on-delete-annotation} i/trash]]))]] i/close-refactor]]
[:div {:class (dom/classnames :hidden (not annotations-expanded?))} [:*
[:div.grow-wrap [:div {:class (stl/css :icon :icon-edit)
[:div.texarea-copy] :title (tr "labels.edit")
:on-click edit}
i/curve-refactor]
[:div {:class (stl/css :icon :icon-trash)
:title (tr "labels.delete")
:on-click on-delete-annotation}
i/delete-refactor]]))]]
[:div {:class (stl/css-case :hidden (not annotations-expanded?))}
[:div {:class (stl/css :grow-wrap)}
[:div {:class (stl/css :texarea-copy)}]
[:textarea [:textarea
{:ref textarea-ref {:ref textarea-ref
:id "annotation-textarea" :id "annotation-textarea"
@ -145,7 +165,7 @@
:default-value annotation :default-value annotation
:read-only (not (or creating? @editing?))}]] :read-only (not (or creating? @editing?))}]]
(when (or @editing? creating?) (when (or @editing? creating?)
[:div.counter (str @size "/300")])]]))) [:div {:class (stl/css :counter)} (str @size "/300")])]])))
(mf/defc component-swap-item (mf/defc component-swap-item
{::mf/wrap-props false} {::mf/wrap-props false}
@ -157,22 +177,21 @@
(st/emit! (dwl/component-multi-swap shapes file-id (:id item))))) (st/emit! (dwl/component-multi-swap shapes file-id (:id item)))))
item-ref (mf/use-ref) item-ref (mf/use-ref)
visible? (h/use-visible item-ref :once? true)] visible? (h/use-visible item-ref :once? true)]
[:div [:div {:ref item-ref
{:ref item-ref :title (if is-search (:full-name item) (:name item))
:title (if is-search (:full-name item) (:name item)) :class (stl/css-case :component-item (not listing-thumbs)
:class (stl/css-case :component-item (not listing-thumbs) :grid-cell listing-thumbs
:grid-cell listing-thumbs :selected (= (:id item) component-id)
:selected (= (:id item) component-id) :disabled loop)
:disabled loop) :key (str "swap-item-" (:id item))
:key (str "swap-item-" (:id item)) :on-click on-select-component}
:on-click on-select-component}
(when visible? (when visible?
[:& cmm/component-item-thumbnail {:file-id (:file-id item) [:& cmm/component-item-thumbnail {:file-id (:file-id item)
:root-shape root-shape :root-shape root-shape
:component item :component item
:container container}]) :container container}])
[:span [:span {:class (stl/css-case :component-name true
{:class (stl/css-case :component-name true :selected (= (:id item) component-id))} :selected (= (:id item) component-id))}
(if is-search (:full-name item) (:name item))]])) (if is-search (:full-name item) (:name item))]]))
(mf/defc component-group-item (mf/defc component-group-item
@ -185,9 +204,11 @@
:title group-name} :title group-name}
[:div [:div
(when-not (str/blank? path) (when-not (str/blank? path)
[:span {:class (stl/css :component-group-path)} (str "\u00A0/\u00A0" path)]) [:span {:class (stl/css :component-group-path)}
[:span {:class (stl/css :component-group-name)} (cfh/last-path group-name)]] (str "\u00A0/\u00A0" path)])
[:span i/arrow-slide]])) [:span {:class (stl/css :component-group-name)}
(cfh/last-path group-name)]]
[:span i/arrow-refactor]]))
(mf/defc component-swap (mf/defc component-swap
[{:keys [shapes] :as props}] [{:keys [shapes] :as props}]
@ -328,11 +349,10 @@
:icon (mf/html [:span {:class (stl/css :search-icon)} i/search-refactor])}]] :icon (mf/html [:span {:class (stl/css :search-icon)} i/search-refactor])}]]
[:div {:class (stl/css :select-field)} [:div {:class (stl/css :select-field)}
[:& select [:& select {:class (stl/css :select-library)
{:class (stl/css :select-library) :default-value current-library-id
:default-value current-library-id :options libraries-options
:options libraries-options :on-change on-library-change}]]
:on-change on-library-change}]]
[:div {:class (stl/css :library-name)} current-library-name] [:div {:class (stl/css :library-name)} current-library-name]
@ -356,7 +376,7 @@
[:button {:class (stl/css :component-path) [:button {:class (stl/css :component-path)
:on-click on-go-back :on-click on-go-back
:title (:path filters)} :title (:path filters)}
[:span i/arrow-slide] [:span i/arrow-refactor]
[:span (:path filters)]]) [:span (:path filters)]])
(when (empty? items) (when (empty? items)
@ -462,7 +482,7 @@
(if swap-opened? (if swap-opened?
[:button {:class (stl/css :title-back) [:button {:class (stl/css :title-back)
:on-click on-component-back} :on-click on-component-back}
[:span i/arrow-slide] [:span i/arrow-refactor]
[:span (tr "workspace.options.component")]] [:span (tr "workspace.options.component")]]
[:& title-bar {:collapsable? true [:& title-bar {:collapsable? true
:collapsed? (not open?) :collapsed? (not open?)
@ -473,7 +493,9 @@
(when open? (when open?
[:div {:class (stl/css :element-content)} [:div {:class (stl/css :element-content)}
[:div {:class (stl/css :component-wrapper)} [:div {:class (stl/css :component-wrapper)}
[:div {:class (stl/css-case :component-name-wrapper true :with-main (and can-swap? (not multi)) :swappeable (and can-swap? (not swap-opened?))) [:div {:class (stl/css-case :component-name-wrapper true
:with-main (and can-swap? (not multi))
:swappeable (and can-swap? (not swap-opened?)))
:on-click open-component-panel} :on-click open-component-panel}
[:span {:class (stl/css :component-icon)} [:span {:class (stl/css :component-icon)}
(if main-instance? (if main-instance?

View file

@ -7,249 +7,260 @@
@import "refactor/common-refactor.scss"; @import "refactor/common-refactor.scss";
.element-set { .element-set {
margin: 0; margin: 0;
.element-content { }
@include flexColumn;
margin-bottom: $s-8;
.component-wrapper {
display: flex;
margin: 0 $s-4 0 $s-8;
.component-name-wrapper {
@extend .asset-element;
@include flexRow;
flex-grow: 1;
height: 100%;
width: 100%;
flex-wrap: wrap;
padding: 0 0 0 $s-12;
margin-top: $s-8;
&.with-main { .element-content {
padding-bottom: $s-12; @include flexColumn;
} margin-bottom: $s-8;
}
.component-icon { .component-wrapper {
@include flexCenter; display: flex;
height: $s-24; margin: 0 $s-4 0 $s-8;
width: $s-24; }
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
}
}
.component-name {
@include titleTipography;
@include textEllipsis;
width: 70%;
flex-grow: 2;
margin-left: $s-8;
}
.component-parent-name {
@include titleTipography;
@include textEllipsis;
padding-left: $s-36;
color: var(--title-foreground-color);
}
}
.swappeable {
cursor: pointer;
}
.component-actions {
position: relative;
.menu-btn { .component-name-wrapper {
@extend .button-tertiary; @extend .asset-element;
height: $s-32; @include flexRow;
width: $s-28; flex-grow: 1;
svg { height: 100%;
@extend .button-icon; width: 100%;
} flex-wrap: wrap;
} padding: 0 0 0 $s-12;
.custom-select-dropdown { margin-top: $s-8;
@extend .dropdown-wrapper;
right: 0; &.with-main {
left: unset; padding-bottom: $s-12;
width: $s-252;
.dropdown-element {
@extend .dropdown-element-base;
}
}
}
}
} }
}
.title-back { .component-icon {
@include tabTitleTipography; @include flexCenter;
cursor: pointer; height: $s-24;
width: 100%; width: $s-24;
background-color: var(--title-background-color); svg {
color: var(--title-foreground-color); @extend .button-icon;
text-align: left; stroke: var(--icon-foreground);
border: 0; }
margin-bottom: $s-16; }
.component-name {
@include titleTipography;
@include textEllipsis;
width: 70%;
flex-grow: 2;
margin-left: $s-8;
}
.component-parent-name {
@include titleTipography;
@include textEllipsis;
padding-left: $s-36;
color: var(--title-foreground-color);
}
.swappeable {
cursor: pointer;
}
.component-actions {
position: relative;
}
.menu-btn {
@extend .button-tertiary;
height: $s-32;
width: $s-28;
svg {
@extend .button-icon;
}
}
.custom-select-dropdown {
@extend .dropdown-wrapper;
right: 0;
left: unset;
width: $s-252;
}
.dropdown-element {
@extend .dropdown-element-base;
}
.title-back {
@include tabTitleTipography;
cursor: pointer;
width: 100%;
background-color: var(--title-background-color);
color: var(--title-foreground-color);
text-align: left;
border: 0;
margin-bottom: $s-16;
svg {
height: $s-8;
width: $s-8;
stroke: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
}
}
.search-field {
display: flex;
align-items: center;
height: $s-32;
margin: $s-16 $s-4 $s-4 $s-12;
border-radius: $br-8;
font-family: "worksans", sans-serif;
background-color: var(--input-background-color);
}
.search-box {
align-items: center;
display: flex;
width: 100%;
}
.icon-wrapper {
display: flex;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
.input-text {
@include removeInputStyle;
height: $s-32;
width: 100%;
margin: 0;
padding: $s-4;
border: 0;
font-size: $fs-12;
color: var(--input-foreground-color-active);
&::placeholder {
color: var(--input-foreground-color-disabled);
}
&:focus-visible {
border-color: var(--input-border-outline-color-active);
}
}
.clear-btn {
@include buttonStyle;
@include flexCenter;
height: $s-16;
width: $s-16;
.clear-icon {
@include flexCenter;
svg { svg {
height: $s-8; @extend .button-icon-small;
width: $s-8; stroke: var(--icon-foreground);
fill: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
} }
} }
}
.component-swap { .search-icon {
.search-field { @include flexCenter;
display: flex; width: $s-28;
align-items: center; svg {
height: $s-32; @extend .button-icon-small;
margin: $s-16 $s-4 $s-4 $s-12; stroke: var(--icon-foreground);
border-radius: $br-8; }
font-family: "worksans", sans-serif; }
background-color: var(--input-background-color);
.search-box {
align-items: center;
display: flex;
width: 100%;
.icon-wrapper { .select-field {
display: flex; margin: $s-8 $s-4 0 $s-12;
svg { }
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
.input-text { .select-library {
@include removeInputStyle; padding-left: $s-20;
height: $s-32; }
width: 100%;
margin: 0;
padding: $s-4;
border: 0;
font-size: $fs-12;
color: var(--input-foreground-color-active);
&::placeholder {
color: var(--input-foreground-color-disabled);
}
&:focus-visible {
border-color: var(--input-border-outline-color-active);
}
}
.clear-btn {
@include buttonStyle;
@include flexCenter;
height: $s-16;
width: $s-16;
.clear-icon {
@include flexCenter;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
}
}
.search-icon {
@include flexCenter;
width: $s-28;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}
}
.select-field { .listing-options-wrapper {
margin: $s-8 $s-4 0 $s-12; width: 100%;
} }
.select-library { .listing-options {
padding-left: $s-20; margin-left: auto;
} margin-right: $s-4;
}
.listing-options-wrapper { .component-path {
width: 100%; @include titleTipography;
} @include textEllipsis;
text-align: left;
cursor: pointer;
width: 100%;
background-color: var(--title-background-color);
color: var(--title-foreground-color);
border: 0;
margin: $s-16 0 $s-12 0;
padding: 0 $s-16 0 $s-24;
svg {
height: $s-8;
width: $s-8;
stroke: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
}
}
.listing-options { .component-path-empty {
margin-left: auto; height: $s-16;
margin-right: $s-4; }
}
.component-path { .component-list-empty {
@include titleTipography; @include titleTipography;
@include textEllipsis; margin: 0 $s-4 0 $s-8;
text-align: left; }
cursor: pointer;
width: 100%;
background-color: var(--title-background-color);
color: var(--title-foreground-color);
border: 0;
margin: $s-16 0 $s-12 0;
padding: 0 $s-16 0 $s-24;
svg {
height: $s-8;
width: $s-8;
fill: var(--icon-foreground);
margin-right: $s-16;
transform: rotate(180deg);
}
}
.component-path-empty { .component-list {
height: $s-16; margin: 0 $s-4 0 $s-8;
} }
.component-list-empty { .component-item {
@include titleTipography; display: flex;
margin: 0 $s-4 0 $s-8; align-items: center;
} margin-bottom: $s-4;
font-size: $s-12;
cursor: pointer;
width: 100%;
height: $s-36;
border-radius: $br-8;
background-color: var(--assets-item-background-color);
color: var(--assets-item-name-foreground-color);
.component-list { .component-name {
margin: 0 $s-4 0 $s-8; @include textEllipsis;
.component-item { width: 80%;
display: flex; }
align-items: center;
margin-bottom: $s-4;
font-size: $s-12;
cursor: pointer;
width: 100%;
height: $s-36;
border-radius: $br-8;
background-color: var(--assets-item-background-color);
color: var(--assets-item-name-foreground-color);
.component-name { svg,
@include textEllipsis; img {
width: 80%; background-color: var(--assets-component-background-color);
} border-radius: $br-8;
height: $s-32;
width: $s-32;
margin: $s-2 $s-8 $s-2 $s-2;
}
svg, .selected {
img { color: var(--assets-item-name-foreground-color-hover);
background-color: var(--assets-component-background-color); }
border-radius: $br-8;
height: $s-32;
width: $s-32;
margin: $s-2 $s-8 $s-2 $s-2;
}
.selected { &:hover {
color: var(--assets-item-name-foreground-color-hover); color: var(--assets-item-name-foreground-color-hover);
} background-color: var(--assets-item-background-color-hover);
}
&:hover { &.disabled {
color: var(--assets-item-name-foreground-color-hover); cursor: auto;
background-color: var(--assets-item-background-color-hover); color: var(--assets-item-name-foreground-color-disabled);
} background-color: var(--assets-item-background-color);
&.disabled { svg {
cursor: auto; cursor: auto;
color: var(--assets-item-name-foreground-color-disabled);
background-color: var(--assets-item-background-color);
svg {
cursor: auto;
}
}
}
} }
} }
} }
@ -390,3 +401,172 @@
cursor: pointer; cursor: pointer;
} }
} }
// Component annotation
.component-annotation {
@include titleTipography;
color: var(--entry-foreground-color);
border-radius: $br-8;
.annotation-title {
display: flex;
align-items: center;
height: $s-32;
&.expanded {
border-bottom: $s-1 solid var(--entry-border-color-disabled);
}
&.expandeable {
cursor: pointer;
}
div {
display: flex;
align-items: center;
line-height: 2.5;
}
.icon-arrow {
@include flexCenter;
width: $s-28;
height: $s-32;
display: flex;
margin: 0;
padding: 0;
cursor: pointer;
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
width: $s-16;
height: $s-16;
}
&.expanded svg {
transform: rotate(90deg);
}
}
.icon {
@include flexCenter;
width: $s-28;
height: $s-32;
border-radius: $br-8;
display: none;
margin: 0;
padding: 0;
cursor: pointer;
svg {
@extend .button-icon;
stroke: var(--icon-foreground);
width: $s-16;
height: $s-16;
}
&.icon-tick:hover,
&.icon-edit:hover {
svg {
stroke: var(--icon-foreground-accept);
}
}
&.icon-cross:hover,
&.icon-trash:hover {
svg {
stroke: var(--icon-foreground-discard);
}
}
}
.annotation-text {
flex-grow: 1;
margin-left: $s-12;
}
&:hover {
.icon {
display: flex;
}
}
}
&.editing {
border: $s-1 solid var(--input-border-color-success);
.annotation-title {
border-bottom: $s-1 solid var(--entry-border-color-disabled);
.icon {
display: flex;
}
}
textarea {
min-height: $s-252;
}
}
&.creating {
border: $s-1 solid var(--input-border-color-success);
.annotation-title .icon {
display: flex;
}
textarea {
min-height: $s-252;
}
}
.hidden {
display: none;
svg {
display: none;
}
}
.counter {
@include titleTipography;
text-align: right;
color: var(--entry-foreground-color);
margin: 0 $s-8 $s-8 0;
}
// Auto growing text
.grow-wrap {
// easy way to plop the elements on top of each other and have them both sized based on the tallest one's height
display: grid;
&:after {
// The space is needed to preventy jumpy behavior
content: attr(data-replicated-value) " ";
white-space: pre-wrap;
visibility: hidden;
}
textarea {
background-color: var(--input-background-color-active);
color: var(--input-foreground-color-active);
padding: $s-12;
border: none;
overflow: hidden;
outline: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
resize: none; /*remove the resize handle on the bottom right*/
}
textarea,
&:after {
/* Identical styling required!! */
font: inherit;
overflow-wrap: anywhere;
padding: 10px;
/* Place on top of each other */
grid-area: 1 / 1 / 2 / 2;
}
}
}