From fb36b77bd18494dd9cb192bd5f38dbc6f6145794 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Wed, 27 Sep 2023 12:10:36 +0200 Subject: [PATCH] :lipstick: Update desing tab phase 2 (#3621) * :lipstick: Update constraint component * :lipstick: Update fill and selected color components * :lipstick: Update stroke component * :lipstick: Update text component * :lipstick: Update frame grid component * :lipstick: Update export component * :lipstick: Update shadow and blur components * :lipstick: Update colorpicker component UI * :lipstick: Update svg attrs and componets components UI * :lipstick: Small UI changes * :bug: Fix shadow functions --- .../resources/images/icons/hsva-refactor.svg | 3 + .../images/icons/picker-refactor.svg | 3 + .../icons/rgba-complementary-refactor.svg | 3 + .../resources/images/icons/rgba-refactor.svg | 3 + .../images/icons/switch-refactor.svg | 3 + .../styles/common/refactor/basic-rules.scss | 352 +++++++++---- .../styles/common/refactor/design-tokens.scss | 35 +- .../styles/common/refactor/spacing.scss | 5 + .../styles/main/partials/colorpicker.scss | 3 + .../main/ui/components/color_bullet_new.cljs | 6 +- .../main/ui/components/color_bullet_new.scss | 6 +- .../app/main/ui/components/color_input.cljs | 2 + .../main/ui/components/context_menu_a11y.scss | 6 +- .../main/ui/components/editable_select.cljs | 184 ++++--- .../main/ui/components/editable_select.scss | 69 +++ .../app/main/ui/components/radio_buttons.cljs | 5 + .../src/app/main/ui/components/select.cljs | 34 +- .../src/app/main/ui/components/select.scss | 57 ++- .../app/main/ui/components/tab_container.cljs | 32 +- .../app/main/ui/components/tab_container.scss | 10 + .../app/main/ui/debug/components_preview.cljs | 27 +- .../app/main/ui/debug/components_preview.scss | 6 +- frontend/src/app/main/ui/icons.cljs | 10 +- frontend/src/app/main/ui/measurements.cljs | 29 +- .../ui/workspace/color_palette_ctx_menu.scss | 2 +- .../app/main/ui/workspace/colorpicker.cljs | 319 ++++++++---- .../app/main/ui/workspace/colorpicker.scss | 124 +++++ .../workspace/colorpicker/color_inputs.cljs | 238 ++++++--- .../workspace/colorpicker/color_inputs.scss | 37 ++ .../ui/workspace/colorpicker/gradients.cljs | 49 +- .../ui/workspace/colorpicker/gradients.scss | 51 ++ .../ui/workspace/colorpicker/harmony.cljs | 127 +++-- .../ui/workspace/colorpicker/harmony.scss | 45 ++ .../main/ui/workspace/colorpicker/hsva.cljs | 124 +++-- .../main/ui/workspace/colorpicker/hsva.scss | 30 ++ .../ui/workspace/colorpicker/libraries.cljs | 115 +++-- .../ui/workspace/colorpicker/libraries.scss | 36 ++ .../main/ui/workspace/colorpicker/ramp.cljs | 123 +++-- .../main/ui/workspace/colorpicker/ramp.scss | 46 ++ .../colorpicker/slider_selector.cljs | 68 ++- .../colorpicker/slider_selector.scss | 117 +++++ .../app/main/ui/workspace/left_header.scss | 6 +- .../app/main/ui/workspace/right_header.scss | 1 - .../src/app/main/ui/workspace/sidebar.cljs | 2 +- .../src/app/main/ui/workspace/sidebar.scss | 4 +- .../workspace/sidebar/assets/components.cljs | 1 - .../app/main/ui/workspace/sidebar/layers.scss | 9 +- .../main/ui/workspace/sidebar/options.cljs | 2 +- .../main/ui/workspace/sidebar/options.scss | 1 + .../ui/workspace/sidebar/options/common.cljs | 21 +- .../ui/workspace/sidebar/options/common.scss | 13 + .../workspace/sidebar/options/menus/blur.cljs | 117 ++++- .../workspace/sidebar/options/menus/blur.scss | 85 +++ .../options/menus/color_selection.cljs | 150 ++++-- .../options/menus/color_selection.scss | 35 ++ .../sidebar/options/menus/component.cljs | 242 ++++++--- .../sidebar/options/menus/component.scss | 59 +++ .../sidebar/options/menus/constraints.cljs | 377 +++++++++----- .../sidebar/options/menus/constraints.scss | 151 ++++++ .../sidebar/options/menus/exports.cljs | 217 +++++--- .../sidebar/options/menus/exports.scss | 85 +++ .../workspace/sidebar/options/menus/fill.cljs | 88 +++- .../workspace/sidebar/options/menus/fill.scss | 72 +++ .../sidebar/options/menus/frame_grid.cljs | 436 +++++++++++----- .../sidebar/options/menus/frame_grid.scss | 240 +++++++++ .../sidebar/options/menus/layer.scss | 21 +- .../options/menus/layout_container.scss | 108 +--- .../sidebar/options/menus/layout_item.cljs | 202 ++++---- .../sidebar/options/menus/layout_item.scss | 63 +-- .../sidebar/options/menus/measures.cljs | 12 +- .../sidebar/options/menus/measures.scss | 108 +--- .../sidebar/options/menus/shadow.cljs | 430 +++++++++++----- .../sidebar/options/menus/shadow.scss | 130 +++++ .../sidebar/options/menus/stroke.cljs | 175 +++++-- .../sidebar/options/menus/stroke.scss | 42 ++ .../sidebar/options/menus/svg_attrs.cljs | 118 +++-- .../sidebar/options/menus/svg_attrs.scss | 52 ++ .../workspace/sidebar/options/menus/text.cljs | 483 +++++++++++++----- .../workspace/sidebar/options/menus/text.scss | 71 +++ .../sidebar/options/menus/typography.cljs | 111 ++-- .../sidebar/options/menus/typography.scss | 190 +++---- .../ui/workspace/sidebar/options/page.cljs | 47 +- .../ui/workspace/sidebar/options/page.scss | 7 + .../sidebar/options/rows/color_row.cljs | 211 +++++--- .../sidebar/options/rows/color_row.scss | 121 +++++ .../sidebar/options/rows/stroke_row.cljs | 365 +++++++++---- .../sidebar/options/rows/stroke_row.scss | 55 ++ .../main/ui/workspace/sidebar/sitemap.scss | 2 +- .../ui/workspace/text_palette_ctx_menu.scss | 4 +- .../ui/workspace/viewport/pixel_overlay.cljs | 12 +- frontend/translations/en.po | 24 + frontend/translations/es.po | 24 + 92 files changed, 6014 insertions(+), 2132 deletions(-) create mode 100644 frontend/resources/images/icons/hsva-refactor.svg create mode 100644 frontend/resources/images/icons/picker-refactor.svg create mode 100644 frontend/resources/images/icons/rgba-complementary-refactor.svg create mode 100644 frontend/resources/images/icons/rgba-refactor.svg create mode 100644 frontend/resources/images/icons/switch-refactor.svg create mode 100644 frontend/src/app/main/ui/components/editable_select.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/color_inputs.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/gradients.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/harmony.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/hsva.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/libraries.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/ramp.scss create mode 100644 frontend/src/app/main/ui/workspace/colorpicker/slider_selector.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/common.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/page.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss diff --git a/frontend/resources/images/icons/hsva-refactor.svg b/frontend/resources/images/icons/hsva-refactor.svg new file mode 100644 index 0000000000..eb7571bf58 --- /dev/null +++ b/frontend/resources/images/icons/hsva-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/picker-refactor.svg b/frontend/resources/images/icons/picker-refactor.svg new file mode 100644 index 0000000000..05f1ed1a70 --- /dev/null +++ b/frontend/resources/images/icons/picker-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/rgba-complementary-refactor.svg b/frontend/resources/images/icons/rgba-complementary-refactor.svg new file mode 100644 index 0000000000..35df1b9b53 --- /dev/null +++ b/frontend/resources/images/icons/rgba-complementary-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/rgba-refactor.svg b/frontend/resources/images/icons/rgba-refactor.svg new file mode 100644 index 0000000000..236e6b4d29 --- /dev/null +++ b/frontend/resources/images/icons/rgba-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/images/icons/switch-refactor.svg b/frontend/resources/images/icons/switch-refactor.svg new file mode 100644 index 0000000000..4e802c8183 --- /dev/null +++ b/frontend/resources/images/icons/switch-refactor.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index d174fa4dc6..0206395eaf 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -4,6 +4,36 @@ // // Copyright (c) KALEIDOS INC +// SCROLLBAR +.new-scrollbar { + ::-webkit-scrollbar { + background-color: transparent; + cursor: pointer; + height: $s-12; + width: $s-12; + } + ::-webkit-scrollbar-track, + ::-webkit-scrollbar-corner { + background-color: transparent; + } + + ::-webkit-scrollbar-thumb { + background-color: rgba(170, 181, 186, 0.3); + background-clip: content-box; + border: $s-2 solid transparent; + border-radius: $br-8; + &:hover { + background-color: rgba(170, 181, 186, 0.7); + outline: none; + } + } + + ::selection { + background-color: var(--color-accent-primary-muted); + } +} + +// BUTTONS .button-primary { @include buttonStyle; @include flexCenter; @@ -235,14 +265,130 @@ stroke-width: 1.33px; } -.link { - background: unset; - border: none; - color: var(--link-foreground-color); - cursor: pointer; - text-decoration: none; +.button-constraint { + @include buttonStyle; + width: $s-32; + height: $s-4; + border-radius: $br-8; + background-color: var(--button-constraint-background-color-rest); + padding: 0; + margin: 0; + &:hover, + &:focus { + outline: $s-4 solid var(--button-constraint-border-color-hover); + background-color: var(--button-constraint-background-color-hover); + } } +// INPUTS + +.input-base { + @include removeInputStyle; + @include titleTipography; + @include textEllipsis; + height: $s-28; + width: 100%; + margin: $s-2 0; + padding: 0 0 0 $s-4; + color: var(--input-foreground-color-active); + &:focus-within, + &:active { + color: var(--input-foreground-color-active); + background-color: var(--input-background-color-active); + } +} + +.input-icon { + @include flexCenter; + min-width: $s-12; + height: $s-32; + margin-right: $s-4; + svg { + @extend .button-icon; + } +} + +.input-label { + @include tabTitleTipography; + @include flexCenter; + min-width: $s-12; + height: $s-32; + margin-right: $s-4; + color: var(--input-foreground-color); +} + +.input-element { + @include titleTipography; + display: flex; + align-items: center; + height: $s-32; + padding: 0 $s-4; + border-radius: $br-8; + background-color: var(--input-background-color); + border: $s-1 solid var(--input-background-color); + color: var(--input-foreground-color); + span { + @extend .input-label; + svg { + @extend .button-icon; + stroke: var(--input-foreground-color); + } + } + + input { + @extend .input-base; + } + ::placeholder { + color: var(--input-placeholder-color); + } + &:hover { + span { + color: var(--input-foreground-color); + } + input { + color: var(--input-foreground-color-active); + } + background-color: var(--input-background-color-hover); + } + + &:focus-within, + &:active { + input { + color: var(--input-foreground-color-active); + } + background-color: var(--input-background-color-active); + border: $s-1 solid var(--input-border-color-active); + } +} + +.disabled-input { + background-color: var(--input-background-color-disabled); + border: 1px solid var(--input-border-color-disabled); + color: var(--input-foreground-color-disabled); + input { + pointer-events: none; + cursor: default; + color: var(--input-foreground-color-disabled); + } + span svg { + stroke: var(--input-foreground-color-disabled); + } +} + +//MODALS +.modal-background { + @include menuShadow; + position: absolute; + display: flex; + flex-direction: column; + padding: $s-12; + border-radius: $br-8; + z-index: $z-index-10; + color: var(--color-foreground-primary); + background-color: var(--modal-background-color); +} + +// UI ELEMENTS .asset-element { @include titleTipography; display: flex; @@ -259,89 +405,6 @@ } } -.input-element { - @include titleTipography; - display: flex; - align-items: center; - height: $s-32; - border-radius: $br-8; - background-color: var(--input-background-color); - color: var(--input-foreground-color); - span { - color: var(--input-foreground-color); - } - input { - @include removeInputStyle; - @include titleTipography; - color: var(--input-foreground-color); - height: $s-32; - } - ::placeholder { - color: var(--input-placeholder-color); - } - &:hover, - &:focus-within { - span { - color: var(--input-foreground-color); - } - input { - color: var(--input-foreground-color-active); - } - background-color: var(--input-background-color-hover); - } -} -.new-scrollbar { - ::-webkit-scrollbar { - background-color: transparent; - cursor: pointer; - height: $s-12; - width: $s-12; - } - ::-webkit-scrollbar-track, - ::-webkit-scrollbar-corner { - background-color: transparent; - } - - ::-webkit-scrollbar-thumb { - background-color: rgba(170, 181, 186, 0.3); - background-clip: content-box; - border: $s-2 solid transparent; - border-radius: $br-8; - &:hover { - background-color: rgba(170, 181, 186, 0.7); - outline: none; - } - } -} - -.menu-dropdown { - @include menuShadow; - color: var(--title-foreground-color-hover); - display: flex; - flex-direction: column; - gap: $s-4; - width: $s-192; - padding: $s-4; - border-radius: $br-8; - background-color: var(--menu-background-color); - z-index: $z-index-10; -} - -.menu-item { - @include titleTipography; - display: flex; - align-items: center; - justify-content: space-between; - height: $s-28; - width: 100%; - padding: $s-6; - border-radius: $br-8; - cursor: pointer; - &:hover { - background-color: var(--menu-background-color-hover); - } -} - .shortcut { @include flexCenter; gap: $s-2; @@ -368,3 +431,114 @@ border: $s-2 solid var(--user-count-foreground-color); } } + +.mixed-bar { + @include titleTipography; + display: flex; + align-items: center; + flex-grow: 1; + border-radius: $br-8; + height: $s-32; + padding: $s-8; + background-color: var(--input-background-color); + color: var(--input-foreground-color-active); +} + +.link { + background: unset; + border: none; + color: var(--link-foreground-color); + cursor: pointer; + text-decoration: none; +} + +.colorpicker-handler { + position: absolute; + left: 50%; + top: 50%; + width: $s-24; + height: $s-24; + border: $s-2 solid var(--colorpicker-details-color); + border-radius: $br-circle; + transform: translate(calc(-1 * $s-12), calc(-1 * $s-12)); + z-index: $z-index-1; + &:hover, + &:active { + border-color: var(--colorpicker-details-color-selected); + } +} +// SELECTS AND DROPDOWNS + +.menu-dropdown { + @include menuShadow; + position: absolute; + display: flex; + flex-direction: column; + gap: $s-4; + padding: $s-4; + border-radius: $br-8; + z-index: $z-index-10; + color: var(--title-foreground-color-hover); + background-color: var(--menu-background-color); +} + +.menu-item { + @include titleTipography; + display: flex; + align-items: center; + justify-content: space-between; + height: $s-28; + width: 100%; + padding: $s-6; + border-radius: $br-8; + cursor: pointer; + &:hover { + background-color: var(--menu-background-color-hover); + } +} + +.dropdown-element-base { + @include titleTipography; + display: flex; + align-items: center; + gap: $s-8; + height: $s-32; + padding: 0 $s-8; + border-radius: $br-6; + cursor: pointer; + color: var(--menu-foreground-color-rest); + + span { + @include flexCenter; + @include textEllipsis; + svg { + @extend .button-icon-small; + stroke: var(--icon-foreground); + } + } + &:hover { + background-color: var(--menu-background-color-hover); + color: var(--menu-foreground-color); + span svg { + stroke: var(--menu-foreground-color-hover); + } + } +} + +.dropdown-wrapper { + @include menuShadow; + position: absolute; + top: $s-32; + left: 0; + width: 100%; + max-height: $s-300; + padding: $s-2; + margin: 0; + margin-top: $s-4; + border-radius: $br-8; + z-index: $z-index-3; + overflow-y: auto; + overflow-x: hidden; + background-color: var(--menu-background-color); + color: var(--menu-foreground-color); +} diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss index 199fe20118..aec6339a37 100644 --- a/frontend/resources/styles/common/refactor/design-tokens.scss +++ b/frontend/resources/styles/common/refactor/design-tokens.scss @@ -77,6 +77,13 @@ --button-disabled-border-color-rest: var(--color-background-disabled); --button-disabled-foreground-color-rest: var(--color-foreground-disabled); + --button-constraint-background-color-rest: var(--color-foreground-secondary); + --button-constraint-border-color-rest: var(--color-background-tertiary); + --button-constraint-border-color-hover: var(--color-accent-primary-muted); + --button-constraint-background-color-hover: var(--color-accent-primary); + --constraint-widget-background-color: var(--color-background-tertiary); + --constraint-center-area-background-color: var(--color-background-primary); + --icon-foreground: var(--color-foreground-secondary); --icon-foreground-hover: var(--color-foreground-primary); @@ -111,18 +118,19 @@ --search-bar-input-border-color: var(--color-background-tertiary); --input-background-color: var(--color-background-tertiary); - --input-background-color-active: var(--color-background-primary); + --input-foreground-color: var(--color-foreground-secondary); + --input-placeholder-color: var(--color-foreground-secondary); --input-background-color-hover: var(--color-background-quaternary); --input-background-color-focus: var(--color-background-tertiary); - --input-background-color-disabled: var(--color-background-primary); - --input-placeholder-color: var(--color-foreground-secondary); - --input-foreground-color: var(--color-foreground-secondary); - --input-foreground-color-active: var(--color-foreground-primary); - --input-foreground-color-disabled: var(--color-foreground-secondary); - --input-border-color-active: var(--color-accent-primary); - --input-border-color-disabled: var(--color-background-quaternary); - --input-border-outline-color-active: var(--color-accent-primary-muted); --input-border-color-focus: var(--color-accent-primary); + --input-background-color-active: var(--color-background-primary); + --input-foreground-color-active: var(--color-foreground-primary); + --input-border-outline-color-active: var(--color-accent-primary-muted); + --input-border-color-active: var(--color-accent-primary); + --input-background-color-disabled: var(--color-background-primary); + --input-foreground-color-disabled: var(--color-foreground-secondary); + --input-border-color-disabled: var(--color-background-quaternary); + --input-details-color: var(--color-background-primary); --pill-background-color: var(--color-background-tertiary); --pill-foreground-color: var(--color-foreground-primary); @@ -130,17 +138,20 @@ --menu-background-color: var(--color-background-tertiary); --menu-foreground-color: var(--color-foreground-primary); --menu-background-color-selected: var(--color-background-tertiary); - --menu-foreground-color-selected: var(--color-foreground-primary); --menu-background-color-hover: var(--color-background-quaternary); --menu-foreground-color-hover: var(--color-foreground-primary); --menu-background-color-focus: var(--color-background-tertiary); --menu-foreground-color-focus: var(--color-foreground-primary); + --menu-foreground-color-rest: var(--color-foreground-secondary); --menu-border-color-focus: var(--color-accent-primary); --menu-shortcut-background-color: var(--color-background-primary); --menu-shortcut-foreground-color: var(--color-foreground-secondary); --menu-shortcut-foreground-color-selected: var(--color-foreground-primary); --menu-shortcut-foreground-color-hover: var(--color-foreground-primary); --menu-shadow-color: var(--color-background-subtle); + --menu-background-color-disabled: var(--color-background-primary); + --menu-foreground-color-disabled: var(--color-foreground-secondary); + --menu-border-color-disabled: var(--color-background-quaternary); --tag-background-color: var(--color-accent-primary); @@ -210,4 +221,8 @@ --modal-background-color: var(--color-background-primary); --modal-foreground-color: var(--color-foreground-primary); --modal-foreground-color-secondary: var(--color-foreground-secondary); + + --colorpicker-details-color: var(--color-background-quaternary); + --colorpicker-details-color-selected: var(--color-accent-primary); + --colorpicker-handlers-color: var(--color-foreground-primary); } diff --git a/frontend/resources/styles/common/refactor/spacing.scss b/frontend/resources/styles/common/refactor/spacing.scss index f2e18cd90d..e955e84789 100644 --- a/frontend/resources/styles/common/refactor/spacing.scss +++ b/frontend/resources/styles/common/refactor/spacing.scss @@ -33,11 +33,13 @@ $s-80: calc(var(--s-4) * 20); $s-84: calc(var(--s-4) * 21); $s-92: calc(var(--s-4) * 23); $s-96: calc(var(--s-4) * 24); +$s-100: calc(var(--s-4) * 25); $s-104: calc(var(--s-4) * 26); $s-108: calc(var(--s-4) * 27); $s-116: calc(var(--s-4) * 29); $s-120: calc(var(--s-4) * 30); $s-124: calc(var(--s-4) * 31); +$s-128: calc(var(--s-4) * 32); $s-136: calc(var(--s-4) * 34); $s-140: calc(var(--s-4) * 35); $s-148: calc(var(--s-4) * 37); @@ -45,6 +47,7 @@ $s-156: calc(var(--s-4) * 39); $s-152: calc(var(--s-4) * 38); $s-160: calc(var(--s-4) * 40); $s-168: calc(var(--s-4) * 42); +$s-172: calc(var(--s-4) * 43); $s-180: calc(var(--s-4) * 45); $s-184: calc(var(--s-4) * 46); $s-188: calc(var(--s-4) * 47); @@ -53,10 +56,12 @@ $s-196: calc(var(--s-4) * 49); $s-200: calc(var(--s-4) * 50); $s-216: calc(var(--s-4) * 54); $s-220: calc(var(--s-4) * 55); +$s-228: calc(var(--s-4) * 57); $s-240: calc(var(--s-4) * 60); $s-248: calc(var(--s-4) * 62); $s-252: calc(var(--s-4) * 63); $s-256: calc(var(--s-4) * 64); +$s-260: calc(var(--s-4) * 65); $s-272: calc(var(--s-4) * 68); $s-276: calc(var(--s-4) * 69); $s-280: calc(var(--s-4) * 70); diff --git a/frontend/resources/styles/main/partials/colorpicker.scss b/frontend/resources/styles/main/partials/colorpicker.scss index 71b049d8cf..e4559e9cb2 100644 --- a/frontend/resources/styles/main/partials/colorpicker.scss +++ b/frontend/resources/styles/main/partials/colorpicker.scss @@ -342,6 +342,9 @@ margin-right: -8px; max-height: 5.5rem; overflow: auto; + div { + grid-area: unset; + } } .selected-colors::after { diff --git a/frontend/src/app/main/ui/components/color_bullet_new.cljs b/frontend/src/app/main/ui/components/color_bullet_new.cljs index f396af1896..33cf9ba9f2 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.cljs +++ b/frontend/src/app/main/ui/components/color_bullet_new.cljs @@ -13,7 +13,7 @@ (mf/defc color-bullet {::mf/wrap [mf/memo] ::mf/wrap-props false} - [{:keys [color on-click mini?]}] + [{:keys [color on-click mini? area]}] (let [on-click (mf/use-fn (mf/deps color on-click) (fn [event] @@ -34,7 +34,9 @@ :is-library-color (some? id) :is-not-library-color (nil? id) :is-gradient (some? gradient) - :is-transparent (and opacity (> 1 opacity))) + :is-transparent (and opacity (> 1 opacity)) + :grid-area area) + :on-click on-click} (if (some? gradient) diff --git a/frontend/src/app/main/ui/components/color_bullet_new.scss b/frontend/src/app/main/ui/components/color_bullet_new.scss index ea0276cb0d..763c90b557 100644 --- a/frontend/src/app/main/ui/components/color_bullet_new.scss +++ b/frontend/src/app/main/ui/components/color_bullet_new.scss @@ -12,9 +12,13 @@ flex-direction: row; width: var(--bullet-size, $s-24); height: var(--bullet-size, $s-24); - margin-top: $s-4; + min-width: var(--bullet-size, $s-24); + min-height: var(--bullet-size, $s-24); border: $s-2 solid var(--color-bullet-border-color); border-radius: $br-circle; + &.grid-area { + grid-area: color; + } &.mini { width: var(--bullet-size, $s-16); height: var(--bullet-size, $s-16); diff --git a/frontend/src/app/main/ui/components/color_input.cljs b/frontend/src/app/main/ui/components/color_input.cljs index f8d193b5f6..45509a3410 100644 --- a/frontend/src/app/main/ui/components/color_input.cljs +++ b/frontend/src/app/main/ui/components/color_input.cljs @@ -32,6 +32,7 @@ on-blur (obj/get props "onBlur") on-focus (obj/get props "onFocus") select-on-focus? (d/nilv (unchecked-get props "selectOnFocus") true) + class (d/nilv (unchecked-get props "className") "color-input") ;; We need a ref pointing to the input dom element, but the user ;; of this component may provide one (that is forwarded here). @@ -132,6 +133,7 @@ (obj/unset! "selectOnFocus") (obj/set! "value" mf/undefined) (obj/set! "onChange" mf/undefined) + (obj/set! "className" class) (obj/set! "type" "text") (obj/set! "ref" ref) ;; (obj/set! "list" list-id) diff --git a/frontend/src/app/main/ui/components/context_menu_a11y.scss b/frontend/src/app/main/ui/components/context_menu_a11y.scss index 7dfe7c3f4c..f19a4d355b 100644 --- a/frontend/src/app/main/ui/components/context_menu_a11y.scss +++ b/frontend/src/app/main/ui/components/context_menu_a11y.scss @@ -82,12 +82,12 @@ &:hover .context-menu-action { background-color: var(--menu-background-color-hover); text-decoration: none; - color: var(--menu-foreground-color-hover); + color: var(--menu-foreground-color); &.submenu .submenu-icon svg { - stroke: var(--menu-foreground-color-hover); + stroke: var(--menu-foreground-color); } &.submenu-back .submenu-icon-back svg { - stroke: var(--menu-foreground-color-hover); + stroke: var(--menu-foreground-color); } } &:focus { diff --git a/frontend/src/app/main/ui/components/editable_select.cljs b/frontend/src/app/main/ui/components/editable_select.cljs index 1ae7ee75ba..bd9931d28f 100644 --- a/frontend/src/app/main/ui/components/editable_select.cljs +++ b/frontend/src/app/main/ui/components/editable_select.cljs @@ -5,12 +5,15 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.components.editable-select + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.math :as mth] [app.common.uuid :as uuid] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.keyboard :as kbd] @@ -18,13 +21,21 @@ [rumext.v2 :as mf])) (mf/defc editable-select - [{:keys [value type options class on-change placeholder on-blur] :as params}] - (let [state (mf/use-state {:id (uuid/next) - :is-open? false - :current-value value - :top nil - :left nil - :bottom nil}) + [{:keys [value type options class on-change placeholder on-blur input-class] :as params}] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + state* (mf/use-state {:id (uuid/next) + :is-open? false + :current-value value + :top nil + :left nil + :bottom nil}) + state (deref state*) + is-open? (:is-open? state) + current-value (:current-value state) + top-value (:top state) + left-value (:left state) + bottom-value (:bottom state) + element-id (:id state) min-val (get params :min) max-val (get params :max) @@ -35,16 +46,28 @@ open-dropdown (fn [event] (dom/stop-propagation event) - (swap! state assoc :is-open? true)) + (swap! state* assoc :is-open? true)) + + toggle-dropdown + (mf/use-fn + (mf/deps state) + #(swap! state* update :is-open? not)) + close-dropdown (fn [event] (dom/stop-propagation event) - (swap! state assoc :is-open? false)) - select-item (fn [value] - (fn [_] - (swap! state assoc :current-value value) - (when on-change (on-change value)) - (when on-blur (on-blur)))) + (swap! state* assoc :is-open? false)) + + select-item + (mf/use-fn + (mf/deps on-change on-blur) + (fn [event] + (let [value (-> (dom/get-current-target event) + (dom/get-data "value") + (d/read-string))] + (swap! state* assoc :current-value value) + (when on-change (on-change value)) + (when on-blur (on-blur))))) as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item])) labels-map (into {} (map as-key-value) options) @@ -52,7 +75,7 @@ set-value (fn [value] - (swap! state assoc :current-value value) + (swap! state* assoc :current-value value) (when on-change (on-change value))) ;; TODO: why this method supposes that all editable select @@ -75,14 +98,14 @@ {:keys [left top height]} bounds bottom (when (< (- window-height top) 300) (- window-height top)) top (when (>= (- window-height top) 300) (+ top height))] - (swap! state + (swap! state* assoc :left left :top top :bottom bottom)))))) handle-key-down - (mf/use-callback + (mf/use-fn (mf/deps set-value) (fn [event] (when (= type "number") @@ -113,12 +136,12 @@ (set-value new-value))))))) handle-focus - (mf/use-callback + (mf/use-fn (fn [] (mf/set-ref-val! emit-blur? false))) handle-blur - (mf/use-callback + (mf/use-fn (fn [] (mf/set-ref-val! emit-blur? true) (timers/schedule @@ -127,56 +150,101 @@ (when (and on-blur (mf/ref-val emit-blur?)) (on-blur))))))] (mf/use-effect - (mf/deps value (:current-value @state)) - #(when (not= (str value) (:current-value @state)) - (reset! state {:current-value value}))) + (mf/deps value current-value) + #(when (not= (str value) current-value) + (reset! state* {:current-value value}))) - (mf/with-effect [(:is-open? @state)] + (mf/with-effect [is-open?] (let [wrapper-node (mf/ref-val font-size-wrapper-ref) node (dom/get-element-by-class "checked-element is-selected" wrapper-node) nodes (dom/get-elements-by-class "checked-element-value" wrapper-node) closest (fn [a b] (first (sort-by #(mth/abs (- % b)) a))) closest-value (str (closest options value))] - (when (:is-open? @state) + (when is-open? (if (some? node) (dom/scroll-into-view-if-needed! node) (some->> nodes (d/seek #(= closest-value (dom/get-inner-text %))) (dom/scroll-into-view-if-needed!))))) - (mf/set-ref-val! emit-blur? (not (:is-open? @state)))) + (mf/set-ref-val! emit-blur? (not is-open?))) - [:div.editable-select {:class class - :ref on-node-load} - (if (= type "number") - [:> numeric-input* {:value (or (some-> @state :current-value value->label) "") - :on-change set-value - :on-focus handle-focus - :on-blur handle-blur - :placeholder placeholder}] - [:input.input-text {:value (or (some-> @state :current-value value->label) "") - :on-change handle-change-input - :on-key-down handle-key-down - :on-focus handle-focus - :on-blur handle-blur - :placeholder placeholder - :type type}]) - [:span.dropdown-button {:on-click open-dropdown} i/arrow-down] - [:& dropdown {:show (get @state :is-open? false) - :on-close close-dropdown} - [:ul.custom-select-dropdown {:style {:position "fixed" - :top (:top @state) - :left (:left @state) - :bottom (:bottom @state) - :ref font-size-wrapper-ref}} - (for [[index item] (map-indexed vector options)] - (if (= :separator item) - [:hr {:key (str (:id @state) "-" index)}] - (let [[value label] (as-key-value item)] - [:li.checked-element - {:key (str (:id @state) "-" index) - :class (when (= (str value) (-> @state :current-value)) "is-selected") - :on-click (select-item value)} - [:span.check-icon i/tick] - [:span.checked-element-value label]])))]]])) + (if new-css-system + [:div {:class (dm/str class " " (stl/css :editable-select)) + :ref on-node-load} + (if (= type "number") + [:> numeric-input* {:value (or (some-> current-value value->label) "") + :className input-class + :on-change set-value + :on-focus handle-focus + :on-blur handle-blur + :placeholder placeholder}] + [:input {:value (or (some-> current-value value->label) "") + :class input-class + :on-change handle-change-input + :on-key-down handle-key-down + :on-focus handle-focus + :on-blur handle-blur + :placeholder placeholder + :type type}]) + + [:span {:class (stl/css :dropdown-button) + :on-click toggle-dropdown} + i/arrow-refactor] + + [:& dropdown {:show (or is-open? false) + :on-close close-dropdown} + [:ul {:class (stl/css :custom-select-dropdown) + :ref font-size-wrapper-ref} + (for [[index item] (map-indexed vector options)] + (if (= :separator item) + [:li {:class (stl/css :separator) + :key (dm/str element-id "-" index)}] + (let [[value label] (as-key-value item)] + [:li + {:key (str element-id "-" index) + :class (stl/css-case :dropdown-element true + :is-selected (= value current-value)) + :data-value value + :on-click select-item} + [:span {:class (stl/css :label)} label] + [:span {:class (stl/css :check-icon)} + i/tick-refactor]])))]]] + + + [:div.editable-select {:class class + :ref on-node-load} + (if (= type "number") + [:> numeric-input* {:value (or (some-> current-value value->label) "") + :on-change set-value + :on-focus handle-focus + :on-blur handle-blur + :placeholder placeholder}] + [:input.input-text {:value (or (some-> current-value value->label) "") + :on-change handle-change-input + :on-key-down handle-key-down + :on-focus handle-focus + :on-blur handle-blur + :placeholder placeholder + :type type}]) + [:span.dropdown-button {:on-click open-dropdown} i/arrow-down] + + [:& dropdown {:show (or is-open? false) + :on-close close-dropdown} + [:ul.custom-select-dropdown {:style {:position "fixed" + :top top-value + :left left-value + :bottom bottom-value} + :ref font-size-wrapper-ref} + (for [[index item] (map-indexed vector options)] + (if (= :separator item) + [:hr {:key (str element-id "-" index)}] + (let [[value label] (as-key-value item)] + [:li.checked-element + {:key (str element-id "-" index) + :class (when (= (str value) current-value) "is-selected") + :data-value value + :on-click select-item} + [:span.check-icon i/tick] + [:span.checked-element-value label]])))]]]))) diff --git a/frontend/src/app/main/ui/components/editable_select.scss b/frontend/src/app/main/ui/components/editable_select.scss new file mode 100644 index 0000000000..06e3981e9f --- /dev/null +++ b/frontend/src/app/main/ui/components/editable_select.scss @@ -0,0 +1,69 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.editable-select { + @extend .asset-element; + margin: 0; + padding: 0; + border: $s-1 solid var(--input-background-color); + position: relative; + display: flex; + height: $s-32; + width: 100%; + padding: $s-8; + border-radius: $br-8; + cursor: pointer; + .dropdown-button { + @include flexCenter; + svg { + @extend .button-icon; + transform: rotate(90deg); + stroke: var(--icon-foreground); + } + } + + .custom-select-dropdown { + @extend .dropdown-wrapper; + max-height: $s-320; + .separator { + margin: 0; + height: $s-12; + } + .dropdown-element { + @extend .dropdown-element-base; + color: var(--menu-foreground-color); + .label { + flex-grow: 1; + width: 100%; + } + + .check-icon { + @include flexCenter; + svg { + @extend .button-icon-small; + visibility: hidden; + stroke: var(--icon-foreground); + } + } + + &.is-selected { + .check-icon svg { + stroke: var(--menu-foreground-color); + visibility: visible; + } + } + &:hover { + background-color: var(--menu-background-color-hover); + color: var(--menu-foreground-color-hover); + .check-icon svg { + stroke: var(--menu-foreground-color-hover); + } + } + } + } +} diff --git a/frontend/src/app/main/ui/components/radio_buttons.cljs b/frontend/src/app/main/ui/components/radio_buttons.cljs index 52c384d9d8..bbad622154 100644 --- a/frontend/src/app/main/ui/components/radio_buttons.cljs +++ b/frontend/src/app/main/ui/components/radio_buttons.cljs @@ -66,6 +66,7 @@ icon (unchecked-get props "icon") id (unchecked-get props "id") value (unchecked-get props "value") + title (unchecked-get props "title") disabled (unchecked-get props "disabled") unique-key (unchecked-get props "unique-key") icon-class (unchecked-get props "icon-class") @@ -79,6 +80,7 @@ [:label {:for id :key unique-key + :title title :class (stl/css-case :radio-icon true :disabled disabled @@ -142,3 +144,6 @@ [:div {:class (dm/str class " " (stl/css :radio-btn-wrapper)) :style {:width width}} children]])) + + + diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs index 7c7fb8ff08..04a963d3b1 100644 --- a/frontend/src/app/main/ui/components/select.cljs +++ b/frontend/src/app/main/ui/components/select.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.components.select - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -23,7 +23,7 @@ [item item])) (mf/defc select - [{:keys [default-value options class is-open? on-change on-pointer-enter-option on-pointer-leave-option]}] + [{:keys [default-value options class is-open? on-change on-pointer-enter-option on-pointer-leave-option disabled]}] (let [new-css-system (mf/use-ctx ctx/new-css-system) label-index (mf/with-memo [options] (into {} (map as-key-value) options)) @@ -39,7 +39,13 @@ current-label (get label-index current-value) is-open? (:is-open? state) - open-dropdown (mf/use-fn #(swap! state* assoc :is-open? true)) + open-dropdown + (mf/use-fn + (mf/deps disabled) + (fn[] + (when-not disabled + (swap! state* assoc :is-open? true)))) + close-dropdown (mf/use-fn #(swap! state* assoc :is-open? false)) select-item @@ -78,27 +84,29 @@ (swap! state* assoc :current-value default-value)) (if new-css-system [:div {:on-click open-dropdown - :class (dom/classnames (css class) true - (css :custom-select) true)} - [:span {:class (css :current-label)} current-label] - [:span {:class (css :dropdown-button)} i/arrow-refactor] + :class (dm/str class " " (stl/css-case :custom-select true + :disabled disabled))} + [:span {:class (stl/css :current-label)} current-label] + [:span {:class (stl/css :dropdown-button)} i/arrow-refactor] [:& dropdown {:show is-open? :on-close close-dropdown} - [:ul {:class (css :custom-select-dropdown)} + [:ul {:class (stl/css :custom-select-dropdown)} (for [[index item] (d/enumerate options)] (if (= :separator item) - [:hr {:key (dm/str current-id "-" index)}] + [:li {:class (dom/classnames (stl/css :separator) true) + :key (dm/str current-id "-" index)}] (let [[value label] (as-key-value item)] [:li {:key (dm/str current-id "-" index) :class (dom/classnames - (css :checked-element) true - (css :is-selected) (= value current-value)) + (stl/css :checked-element) true + (stl/css :is-selected) (= value current-value)) :data-value (pr-str value) :on-pointer-enter highlight-item :on-pointer-leave unhighlight-item :on-click select-item} - [:span {:class (css :label)} label] - [:span {:class (css :check-icon)} i/tick-refactor]])))]]] + [:span {:class (stl/css :label)} label] + [:span {:class (stl/css :check-icon)} i/tick-refactor]])))]]] + [:div.custom-select {:on-click open-dropdown :class class} [:span current-label] diff --git a/frontend/src/app/main/ui/components/select.scss b/frontend/src/app/main/ui/components/select.scss index 4950456275..7fb9fcd37b 100644 --- a/frontend/src/app/main/ui/components/select.scss +++ b/frontend/src/app/main/ui/components/select.scss @@ -7,11 +7,18 @@ @import "refactor/common-refactor.scss"; .custom-select { + @include titleTipography; position: relative; display: flex; + align-items: center; + height: $s-32; width: 100%; + margin: 0; padding: $s-8; border-radius: $br-8; + background-color: var(--menu-background-color); + border: $s-1 solid var(--menu-background-color); + color: var(--menu-foreground-color); cursor: pointer; .current-label { width: 100%; @@ -26,26 +33,15 @@ } } .custom-select-dropdown { - @include menuShadow; - position: absolute; - top: $s-32; - left: 0; - width: 100%; - padding: $s-2; - margin: 0; - margin-top: $s-4; - border-radius: $br-8; - z-index: $z-index-3; - overflow-y: auto; - background-color: var(--menu-background-color); + @extend .dropdown-wrapper; + .separator { + margin: 0; + height: $s-12; + } } .checked-element { - display: flex; - align-items: center; - height: $s-32; - padding: 0 $s-8; - border-radius: $br-6; - color: var(--menu-foreground-color); + @extend .dropdown-element-base; + .label { flex-grow: 1; width: 100%; @@ -61,26 +57,35 @@ } &.is-selected { + color: var(--menu-foreground-color); .check-icon svg { stroke: var(--menu-foreground-color); visibility: visible; } } - &:hover { - background-color: var(--menu-background-color-hover); - color: var(--menu-foreground-color-hover); - .check-icon svg { - stroke: var(--menu-foreground-color-hover); - } - } } &:hover { + background-color: var(--menu-background-color-hover); + border: $s-1 solid var(--menu-background-color-hover); .dropdown-button { - color: var(--menu-foreground-color-hover); svg { stroke: var(--menu-foreground-color-hover); } } } + &:focus { + background-color: var(--menu-background-color-focus); + border: $s-1 solid var(--menu-border-color-focus); + } + &.disabled { + background-color: var(--menu-background-color-disabled); + color: var(--menu-foreground-color-disabled); + border: $s-1 solid var(--menu-border-color-disabled); + pointer-events: none; + cursor: default; + .dropdown-button svg { + stroke: var(--menu-foreground-color-disabled); + } + } } diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container.cljs index 2b11ec5f15..9b52965a56 100644 --- a/frontend/src/app/main/ui/components/tab_container.cljs +++ b/frontend/src/app/main/ui/components/tab_container.cljs @@ -5,9 +5,10 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.components.tab-container - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -20,9 +21,7 @@ [props] (let [children (unchecked-get props "children") new-css-system (mf/use-ctx ctx/new-css-system)] - [:div {:class (if new-css-system - (dom/classnames (css :tab-element) true) - (dom/classnames :tab-element true))} + [:div {:class (stl/css new-css-system :tab-element)} children])) (mf/defc tab-container @@ -35,7 +34,7 @@ on-change (unchecked-get props "on-change-tab") collapsable? (unchecked-get props "collapsable?") handle-collapse (unchecked-get props "handle-collapse") - klass (unchecked-get props "klass") + class (unchecked-get props "class") content-class (unchecked-get props "content-class") state (mf/use-state #(or selected (-> children first .-props .-id))) @@ -45,31 +44,32 @@ (mf/use-fn (mf/deps on-change) (fn [event] - (let [id (d/read-string (.. event -target -dataset -id))] + (let [id (-> event + (dom/get-current-target) + (dom/get-data "id") + (keyword))] (reset! state id) (when (fn? on-change) (on-change id)))))] - [:div {:class (dom/classnames (css :tab-container) true)} - [:div {:class (dom/classnames (css :tab-container-tabs) true - klass true)} + [:div {:class (stl/css :tab-container)} + [:div {:class (dm/str class " "(stl/css :tab-container-tabs))} (when collapsable? [:button {:on-click handle-collapse - :class (dom/classnames (css :collapse-sidebar) true) + :class (stl/css :collapse-sidebar) :aria-label (tr "workspace.sidebar.collapse")} i/arrow-refactor]) - [:div {:class (dom/classnames (css :tab-container-tab-wrapper) true)} + [:div {:class (stl/css :tab-container-tab-wrapper)} (for [tab children] (let [props (.-props tab) id (.-id props) title (.-title props)] [:div {:key (str/concat "tab-" (d/name id)) - :data-id (pr-str id) + :data-id (d/name id) :on-click select-fn - :class (dom/classnames (css :tab-container-tab-title) true - (css :current) (= selected id))} + :class (stl/css-case :tab-container-tab-title true + :current (= selected id))} title]))]] - [:div {:class (dom/classnames (css :tab-container-content) true - content-class (some? content-class))} + [:div {:class (dm/str content-class " " (stl/css :tab-container-content ))} (d/seek #(= selected (-> % .-props .-id)) children)]])) diff --git a/frontend/src/app/main/ui/components/tab_container.scss b/frontend/src/app/main/ui/components/tab_container.scss index 56c7dac401..00be5342eb 100644 --- a/frontend/src/app/main/ui/components/tab_container.scss +++ b/frontend/src/app/main/ui/components/tab_container.scss @@ -48,14 +48,24 @@ background-color: transparent; color: var(--tab-foreground-color); white-space: nowrap; + svg { + @extend .button-icon; + stroke: var(--tab-foreground-color); + } &.current, &.current:hover { background: var(--tab-background-color-selected); color: var(--tab-foreground-color-selected); + svg { + stroke: var(--tab-foreground-color-selected); + } } &:hover { color: var(--tab-foreground-color-hover); + svg { + stroke: var(--tab-foreground-color-hover); + } } } } diff --git a/frontend/src/app/main/ui/debug/components_preview.cljs b/frontend/src/app/main/ui/debug/components_preview.cljs index 3ba458132f..98d6fee926 100644 --- a/frontend/src/app/main/ui/debug/components_preview.cljs +++ b/frontend/src/app/main/ui/debug/components_preview.cljs @@ -95,7 +95,7 @@ (d/name color)]))]] [:div {:class (stl/css :components-row)} - [:h2 {:class(stl/css :title)} "Components"] + [:h2 {:class (stl/css :title)} "Components"] [:div {:class (stl/css :components-wrapper)} [:div {:class (stl/css :components-group)} [:h3 "Titles"] @@ -167,7 +167,7 @@ [:& search-bar {:on-change update-search :value input-value :placeholder "Test value"} - [:button {:class (stl/css :test-button) + [:button {:class (stl/css :button-secondary) :on-click on-btn-click} "X"]]]] @@ -246,4 +246,25 @@ [:& component-wrapper {:title "Button tertiary with icon"} [:button {:class (stl/css :button-tertiary)} - i/add-refactor]]]]]])) + i/add-refactor]]] + + [:div {:class (stl/css :components-group)} + [:h3 "Inputs"] + [:& component-wrapper + {:title "Only input"} + [:div {:class (stl/css :input-wrapper)} + [:input {:class (stl/css :basic-input) + :placeholder "----"}]]] + [:& component-wrapper + {:title "Input with label"} + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "label"] + [:input {:class (stl/css :basic-input) + :placeholder "----"}]]] + [:& component-wrapper + {:title "Input with icon"} + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} + i/add-refactor] + [:input {:class (stl/css :basic-input) + :placeholder "----"}]]]]]]])) diff --git a/frontend/src/app/main/ui/debug/components_preview.scss b/frontend/src/app/main/ui/debug/components_preview.scss index d780a40901..a78e2e2dc8 100644 --- a/frontend/src/app/main/ui/debug/components_preview.scss +++ b/frontend/src/app/main/ui/debug/components_preview.scss @@ -84,11 +84,10 @@ display: flex; flex-wrap: wrap; gap: $s-20; - .component-group { + .components-group { @include flexCenter; justify-content: flex-start; flex-direction: column; - // width: $s-256; border-radius: $s-8; h3 { @include titleTipography; @@ -129,5 +128,8 @@ @extend .button-icon; } } + .input-wrapper { + @extend .input-element; + } } } diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 35a7dfca26..5d769b44eb 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -276,7 +276,6 @@ (def align-content-row-between-refactor (icon-xref :align-content-row-between-refactor)) (def align-content-row-evenly-refactor (icon-xref :align-content-row-evenly-refactor)) (def align-content-row-start-refactor (icon-xref :align-content-row-start-refactor)) - (def align-horizontal-center-refactor (icon-xref :align-horizontal-center-refactor)) (def align-vertical-center-refactor (icon-xref :align-vertical-center-refactor)) (def align-items-row-center-refactor (icon-xref :align-items-row-center-refactor)) @@ -345,6 +344,7 @@ (def gap-vertical-refactor (icon-xref :gap-vertical-refactor)) (def hide-refactor (icon-xref :hide-refactor)) (def history-refactor (icon-xref :history-refactor)) +(def hsva-refactor (icon-xref :hsva-refactor)) (def hug-content-refactor (icon-xref :hug-content-refactor)) (def img-refactor (icon-xref :img-refactor)) (def icon-refactor (icon-xref :icon-refactor)) @@ -384,9 +384,12 @@ (def padding-extended-refactor (icon-xref :padding-extended-refactor)) (def path-refactor (icon-xref :path-refactor)) (def pentool-refactor (icon-xref :pentool-refactor)) +(def picker-refactor (icon-xref :picker-refactor)) (def play-refactor (icon-xref :play-refactor)) (def rectangle-refactor (icon-xref :rectangle-refactor)) (def remove-refactor (icon-xref :remove-refactor)) +(def rgba-refactor (icon-xref :rgba-refactor)) +(def rgba-complementary-refactor (icon-xref :rgba-complementary-refactor)) (def rotation-refactor (icon-xref :rotation-refactor)) (def row-reverse-refactor (icon-xref :row-reverse-refactor)) (def search-refactor (icon-xref :search-refactor)) @@ -400,12 +403,13 @@ (def stroke-size-refactor (icon-xref :stroke-size-refactor)) (def svg-refactor (icon-xref :svg-refactor)) (def swatches-refactor (icon-xref :swatches-refactor)) +(def switch-refactor (icon-xref :switch-refactor)) (def text-align-center-refactor (icon-xref :text-align-center-refactor)) (def text-align-left-refactor (icon-xref :text-align-left-refactor)) (def text-align-right-refactor (icon-xref :text-align-right-refactor)) (def text-auto-height-refactor (icon-xref :text-auto-height-refactor)) (def text-auto-width-refactor (icon-xref :text-auto-width-refactor)) -(def text-fixed-refactor (icon-xref :textfixed--refactor)) +(def text-fixed-refactor (icon-xref :text-fixed-refactor)) (def text-justify-refactor (icon-xref :text-justify-refactor)) (def text-letterspacing-refactor (icon-xref :text-letterspacing-refactor)) (def text-lineheight-refactor (icon-xref :text-lineheight-refactor)) @@ -420,7 +424,7 @@ (def text-mixed-refactor (icon-xref :text-mixed-refactor)) (def text-stroked-refactor (icon-xref :text-stroked-refactor)) (def text-top-refactor (icon-xref :text-top-refactor)) -(def text-underlined-refactor (icon-xref :text-undelined-refactor)) +(def text-underlined-refactor (icon-xref :text-underlined-refactor)) (def text-uppercase-refactor (icon-xref :text-uppercase-refactor)) (def tick-refactor (icon-xref :tick-refactor)) (def unlock-refactor (icon-xref :unlock-refactor)) diff --git a/frontend/src/app/main/ui/measurements.cljs b/frontend/src/app/main/ui/measurements.cljs index a8f6b91c51..5a47afa4ba 100644 --- a/frontend/src/app/main/ui/measurements.cljs +++ b/frontend/src/app/main/ui/measurements.cljs @@ -825,21 +825,20 @@ (map create-cgdd)))] [:g.gaps {:pointer-events "visible"} - [:* - (for [[index display-item] (d/enumerate (concat display-blocks display-children))] - (let [gap-type (:gap-type display-item)] - [:& gap-display {:key (str frame-id index) - :frame-id frame-id - :zoom zoom - :gap-type gap-type - :gap gap - :on-pointer-enter (partial on-pointer-enter gap-type (get gap gap-type)) - :on-pointer-leave on-pointer-leave - :rect-data display-item - :hover? (= @hover gap-type) - :selected? (= gap-selected gap-type) - :mouse-pos mouse-pos - :hover-value hover-value}]))] + (for [[index display-item] (d/enumerate (concat display-blocks display-children))] + (let [gap-type (:gap-type display-item)] + [:& gap-display {:key (str frame-id index) + :frame-id frame-id + :zoom zoom + :gap-type gap-type + :gap gap + :on-pointer-enter (partial on-pointer-enter gap-type (get gap gap-type)) + :on-pointer-leave on-pointer-leave + :rect-data display-item + :hover? (= @hover gap-type) + :selected? (= gap-selected gap-type) + :mouse-pos mouse-pos + :hover-value hover-value}])) (when @hover [:& flex-display-pill {:height pill-height diff --git a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.scss b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.scss index 046b76b6cc..f43f09038b 100644 --- a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.scss +++ b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.scss @@ -9,8 +9,8 @@ .palette-menu { position: absolute; left: auto; - max-width: $s-480; bottom: $s-0; + max-width: $s-480; padding: $s-4; margin: 0 0 $s-4 0; z-index: $z-index-3; diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 9b912afd5a..28884c3634 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker + (:require-macros [app.main.style :as stl]) (:require [app.main.data.modal :as modal] [app.main.data.workspace.colors :as dc] @@ -12,6 +13,8 @@ [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.tab-container :refer [tab-container tab-element]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.colorpicker.color-inputs :refer [color-inputs]] [app.main.ui.workspace.colorpicker.gradients :refer [gradients]] @@ -44,7 +47,8 @@ (mf/defc colorpicker [{:keys [data disable-gradient disable-opacity on-change on-accept]}] - (let [state (mf/deref refs/colorpicker) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + state (mf/deref refs/colorpicker) node-ref (mf/use-ref) ;; TODO: I think we need to put all this picking state under @@ -58,15 +62,15 @@ active-tab (mf/use-state (dc/get-active-color-tab)) drag? (mf/use-state false) - + set-tab! (mf/use-fn - (fn [event] - (let [tab (-> (dom/get-current-target event) - (dom/get-data "tab") - (keyword))] - (reset! active-tab tab) - (dc/set-active-color-tab! tab)))) + (fn [event] + (let [tab (-> (dom/get-current-target event) + (dom/get-data "tab") + (keyword))] + (reset! active-tab tab) + (dc/set-active-color-tab! tab)))) handle-change-color (mf/use-fn @@ -86,14 +90,17 @@ (fn [] (if picking-color? (do (modal/disallow-click-outside!) - (st/emit! (dc/stop-picker))) + (st/emit! (dc/stop-picker))) (do (modal/allow-click-outside!) - (st/emit! (dc/start-picker)))))) + (st/emit! (dc/start-picker)))))) handle-change-stop (mf/use-fn - (fn [offset] - (st/emit! (dc/select-colorpicker-gradient-stop offset)))) + (fn [event] + (let [offset (-> (dom/get-current-target event) + (dom/get-data "value") + (int))] + (st/emit! (dc/select-colorpicker-gradient-stop offset))))) on-select-library-color (mf/use-fn @@ -128,7 +135,7 @@ ;; Click on a solid color -> This color is applied to the selected offset ;; Click on a color with transparency -> The same to solid color will happend ;; Click on any kind of gradient -> The color changes completly to new gradient - + ;; If we have a non gradient color the new color is applied without any change (if (or (= :radial-gradient type-origin) (= :linear-gradient type-origin)) (if is-gradient? @@ -150,15 +157,24 @@ on-start-drag (mf/use-fn + (mf/deps drag? node-ref) (fn [] (reset! drag? true) (st/emit! (dwu/start-undo-transaction (mf/ref-val node-ref))))) on-finish-drag (mf/use-fn + (mf/deps drag? node-ref) (fn [] (reset! drag? false) - (st/emit! (dwu/commit-undo-transaction (mf/ref-val node-ref)))))] + (st/emit! (dwu/commit-undo-transaction (mf/ref-val node-ref))))) + + on-color-accept + (mf/use-fn + (mf/deps state) + (fn [] + (on-accept (dc/get-color-from-colorpicker-state state)) + (modal/hide!)))] ;; Initialize colorpicker state (mf/with-effect [] @@ -199,110 +215,200 @@ :h h :s s :v v :alpha (/ alpha 255)})))) - [:div.colorpicker {:ref node-ref - :style {:touch-action "none"}} - [:div.colorpicker-content - [:div.top-actions - [:button.picker-btn - {:class (when picking-color? "active") - :on-click handle-click-picker} - i/picker] + (if new-css-system + [:div {:class (stl/css :colorpicker) + :ref node-ref + :style {:touch-action "none"}} + [:div {:class (stl/css :top-actions)} + [:button {:class (stl/css-case :picker-btn true + :selected picking-color?) + :on-click handle-click-picker} + i/picker-refactor] + (when (not disable-gradient) + [:div {:class (stl/css :gradient-buttons)} + [:button + {:on-click on-activate-linear-gradient + :class (stl/css-case :gradient-btn true + :linear-gradient-btn true + :selected (= :linear-gradient (:type state)))}] - (when (not disable-gradient) - [:div.gradients-buttons - [:button.gradient.linear-gradient - {:on-click on-activate-linear-gradient - :class (when (= :linear-gradient (:type state)) "active")}] + [:button + {:on-click on-activate-radial-gradient + :class (stl/css-case :gradient-btn true + :radial-gradient-btn true + :selected (= :radial-gradient (:type state)))}]])] - [:button.gradient.radial-gradient - {:on-click on-activate-radial-gradient - :class (when (= :radial-gradient (:type state)) "active")}]])] + (when (or (= (:type state) :linear-gradient) + (= (:type state) :radial-gradient)) + [:& gradients + {:stops (:stops state) + :editing-stop (:editing-stop state) + :on-select-stop handle-change-stop}]) + [:div {:class (stl/css :colorpicker-tabs)} + [:& tab-container + {:on-change-tab set-tab! + :selected @active-tab + :collapsable? false} - (when (or (= (:type state) :linear-gradient) - (= (:type state) :radial-gradient)) - [:& gradients - {:stops (:stops state) - :editing-stop (:editing-stop state) - :on-select-stop handle-change-stop}]) + [:& tab-element {:id :ramp :title i/rgba-refactor} + (if picking-color? + [:div {:class (stl/css :picker-detail-wrapper)} + [:div {:class (stl/css :center-circle)}] + [:canvas#picker-detail {:width 256 :height 140}]] + [:& ramp-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])] - [:div.colorpicker-tabs - [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand - {:class (when (= @active-tab :ramp) "active") - :alt (tr "workspace.libraries.colors.rgba") - :on-click set-tab! - :data-tab "ramp"} i/picker-ramp] - [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand - {:class (when (= @active-tab :harmony) "active") - :alt (tr "workspace.libraries.colors.rgb-complementary") - :on-click set-tab! - :data-tab "harmony"} i/picker-harmony] - [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand - {:class (when (= @active-tab :hsva) "active") - :alt (tr "workspace.libraries.colors.hsv") - :on-click set-tab! - :data-tab "hsva"} i/picker-hsv]] + [:& tab-element {:id :harmony :title i/rgba-complementary-refactor} + (if picking-color? + [:div {:class (stl/css :picker-detail-wrapper)} + [:div {:class (stl/css :center-circle)}] + [:canvas#picker-detail {:width 256 :height 140}]] + [:& harmony-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])] - (if picking-color? - [:div.picker-detail-wrapper - [:div.center-circle] - [:canvas#picker-detail {:width 200 :height 160}]] - (case @active-tab - :ramp - [:& ramp-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - :harmony - [:& harmony-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - :hsva - [:& hsva-selector - {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - nil)) + [:& tab-element {:id :hsva :title i/hsva-refactor} + (if picking-color? + [:div {:class (stl/css :picker-detail-wrapper)} + [:div {:class (stl/css :center-circle)}] + [:canvas#picker-detail {:width 256 :height 140}]] + [:& hsva-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])]]] - [:& color-inputs - {:type (if (= @active-tab :hsva) :hsv :rgb) - :disable-opacity disable-opacity - :color current-color - :on-change handle-change-color}] + [:& color-inputs + {:type (if (= @active-tab :hsva) :hsv :rgb) + :disable-opacity disable-opacity + :color current-color + :on-change handle-change-color}] - [:& libraries - {:state state - :current-color current-color - :disable-gradient disable-gradient - :disable-opacity disable-opacity - :on-select-color on-select-library-color - :on-add-library-color on-add-library-color}] + [:& libraries + {:state state + :current-color current-color + :on-select-color on-select-library-color + :on-add-library-color on-add-library-color}] - (when on-accept - [:div.actions - [:button.btn-primary.btn-large - {:on-click (fn [] - (on-accept (dc/get-color-from-colorpicker-state state)) - (modal/hide!))} - (tr "workspace.libraries.colors.save-color")]])]])) + (when on-accept + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :accept-color) + :on-click on-color-accept} + (tr "workspace.libraries.colors.save-color")]])] + + [:div.colorpicker {:ref node-ref + :style {:touch-action "none"}} + [:div.colorpicker-content + [:div.top-actions + [:button.picker-btn + {:class (when picking-color? "active") + :on-click handle-click-picker} + i/picker] + + (when (not disable-gradient) + [:div.gradients-buttons + [:button.gradient.linear-gradient + {:on-click on-activate-linear-gradient + :class (when (= :linear-gradient (:type state)) "active")}] + + [:button.gradient.radial-gradient + {:on-click on-activate-radial-gradient + :class (when (= :radial-gradient (:type state)) "active")}]])] + + (when (or (= (:type state) :linear-gradient) + (= (:type state) :radial-gradient)) + + [:& gradients + {:stops (:stops state) + :editing-stop (:editing-stop state) + :on-select-stop handle-change-stop}]) + + [:div.colorpicker-tabs + [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand + {:class (when (= @active-tab :ramp) "active") + :alt (tr "workspace.libraries.colors.rgba") + :on-click set-tab! + :data-tab "ramp"} i/picker-ramp] + [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand + {:class (when (= @active-tab :harmony) "active") + :alt (tr "workspace.libraries.colors.rgb-complementary") + :on-click set-tab! + :data-tab "harmony"} i/picker-harmony] + [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand + {:class (when (= @active-tab :hsva) "active") + :alt (tr "workspace.libraries.colors.hsv") + :on-click set-tab! + :data-tab "hsva"} i/picker-hsv]] + + (if picking-color? + [:div.picker-detail-wrapper + [:div.center-circle] + [:canvas#picker-detail {:width 200 :height 160}]] + (case @active-tab + :ramp + [:& ramp-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + :harmony + [:& harmony-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + :hsva + [:& hsva-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + nil)) + + [:& color-inputs + {:type (if (= @active-tab :hsva) :hsv :rgb) + :disable-opacity disable-opacity + :color current-color + :on-change handle-change-color}] + + [:& libraries + {:state state + :current-color current-color + :disable-gradient disable-gradient + :disable-opacity disable-opacity + :on-select-color on-select-library-color + :on-add-library-color on-add-library-color}] + + (when on-accept + [:div.actions + [:button.btn-primary.btn-large + {:on-click on-color-accept} + (tr "workspace.libraries.colors.save-color")]])]]))) (defn calculate-position "Calculates the style properties for the given coordinates and position" - [{vh :height} position x y] + [{vh :height} position x y new-css-system] (let [;; picker height in pixels - h 430 + h(if new-css-system 510 430) ;; Checks for overflow outside the viewport height - overflow-fix (max 0 (+ y (- 50) h (- vh)))] + overflow-fix (max 0 (+ y (- 50) h (- vh))) + + x-pos (if new-css-system 325 250)] (cond (or (nil? x) (nil? y)) {:left "auto" :right "16rem" :top "4rem"} - (= position :left) {:left (str (- x 250) "px") + (= position :left) {:left (str (- x x-pos) "px") :top (str (- y 50 overflow-fix) "px")} :else {:left (str (+ x 80) "px") :top (str (- y 70 overflow-fix) "px")}))) @@ -315,11 +421,12 @@ disable-gradient disable-opacity on-change on-close on-accept] :as props}] - (let [vport (mf/deref viewport) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + vport (mf/deref viewport) dirty? (mf/use-var false) last-change (mf/use-var nil) position (or position :left) - style (calculate-position vport position x y) + style (calculate-position vport position x y new-css-system) handle-change (fn [new-data] @@ -333,8 +440,8 @@ #(when (and @dirty? @last-change on-close) (on-close @last-change)))) - [:div.colorpicker-tooltip - {:style (clj->js style)} + [:div {:class (stl/css new-css-system :colorpicker-tooltip) + :style (clj->js style)} [:& colorpicker {:data data :disable-gradient disable-gradient :disable-opacity disable-opacity diff --git a/frontend/src/app/main/ui/workspace/colorpicker.scss b/frontend/src/app/main/ui/workspace/colorpicker.scss new file mode 100644 index 0000000000..f030e5a399 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker.scss @@ -0,0 +1,124 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.colorpicker-tooltip { + @extend .modal-background; + top: $s-100; + left: calc(10 * $s-140); + width: auto; + .colorpicker { + border-radius: $br-8; + width: $s-260; + & > * { + width: $s-260; + } + .top-actions { + display: flex; + align-items: flex-start; + justify-content: space-between; + height: $s-28; + .picker-btn { + @include buttonStyle; + @include flexCenter; + border-radius: $br-8; + background-color: transparent; + border: $s-1 solid transparent; + height: $s-20; + width: $s-20; + border-radius: $br-4; + padding: 0; + svg { + @extend .button-icon; + stroke: var(--button-tertiary-foreground-color-rest); + } + &:hover { + svg { + stroke: var(--button-tertiary-foreground-color-focus); + } + } + &:focus, + &:focus-visible { + outline: none; + svg { + stroke: var(--button-secondary-foreground-color-hover); + } + } + &:active { + outline: none; + border: $s-1 solid transparent; + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } + &.selected { + svg { + stroke: var(--button-tertiary-foreground-color-active); + } + } + } + .gradient-buttons { + display: flex; + align-items: center; + gap: $s-8; + .gradient-btn { + @extend .button-tertiary; + height: $s-20; + width: $s-20; + border-radius: $br-4; + border: $s-2 solid transparent; + &:hover { + border: $s-2 solid var(--colorpicker-details-color-selected); + } + } + .linear-gradient-btn { + background: linear-gradient(180deg, var(--color-foreground-secondary), transparent); + &.selected { + background: linear-gradient(to bottom, rgba(126, 255, 245, 1) 0%, rgba(126, 255, 245, 0.2) 100%); + border: $s-2 solid var(--colorpicker-details-color-selected); + } + } + + .radial-gradient-btn { + background: radial-gradient(transparent, var(--color-foreground-secondary)); + &.selected { + background: radial-gradient(rgba(126, 255, 245, 1) 0%, rgba(126, 255, 245, 0.2) 100%); + border: $s-2 solid var(--colorpicker-details-color-selected); + } + } + } + } + .actions { + display: flex; + gap: $s-4; + .accept-color { + @include titleTipography; + @extend .button-secondary; + width: 100%; + height: $s-32; + margin-top: $s-8; + } + } + } + .colorpicker-tabs { + .picker-detail-wrapper { + @include flexCenter; + position: relative; + margin: $s-12 0 $s-8 0; + .center-circle { + width: $s-24; + height: $s-24; + border: $s-2 solid var(--colorpicker-details-color); + border-radius: $br-circle; + position: absolute; + left: 50%; + top: 50%; + transform: translate(calc(-1 * $s-12), calc(-1 * $s-12)); + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs index dad0b71e73..b7bb1e5797 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs @@ -5,9 +5,11 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.color-inputs + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.math :as mth] + [app.main.ui.context :as ctx] [app.util.color :as uc] [app.util.dom :as dom] [rumext.v2 :as mf])) @@ -27,7 +29,8 @@ (* (/ val 255) 100)) (mf/defc color-inputs [{:keys [type color disable-opacity on-change]}] - (let [{red :r green :g blue :b + (let [new-css-system (mf/use-ctx ctx/new-css-system) + {red :r green :g blue :b hue :h saturation :s value :v hex :hex alpha :alpha} color @@ -108,84 +111,169 @@ property-val)] (dom/set-value! node new-val)))))))) - [:div.color-values - {:class (when disable-opacity "disable-opacity")} - [:input {:id "hex-value" - :ref (:hex refs) - :default-value hex - :on-change on-change-hex - :on-blur on-blur-hex}] + (if new-css-system + [:div {:class (stl/css-case :color-values true + :disable-opacity disable-opacity)} - (if (= type :rgb) - [:* - [:input {:id "red-value" - :ref (:r refs) - :type "number" - :min 0 - :max 255 - :default-value red - :on-change (on-change-property :r 255)}] + [:div {:class (stl/css :colors-row)} + (if (= type :rgb) + [:* + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "R"] + [:input {:id "red-value" + :ref (:r refs) + :type "number" + :min 0 + :max 255 + :default-value red + :on-change (on-change-property :r 255)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "G"] + [:input {:id "green-value" + :ref (:g refs) + :type "number" + :min 0 + :max 255 + :default-value green + :on-change (on-change-property :g 255)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "B"] + [:input {:id "blue-value" + :ref (:b refs) + :type "number" + :min 0 + :max 255 + :default-value blue + :on-change (on-change-property :b 255)}]]] - [:input {:id "green-value" - :ref (:g refs) - :type "number" - :min 0 - :max 255 - :default-value green - :on-change (on-change-property :g 255)}] + [:* + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "H"] + [:input {:id "hue-value" + :ref (:h refs) + :type "number" + :min 0 + :max 360 + :default-value hue + :on-change (on-change-property :h 360)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "S"] + [:input {:id "saturation-value" + :ref (:s refs) + :type "number" + :min 0 + :max 100 + :step 1 + :default-value saturation + :on-change (on-change-property :s 100)}]] + [:div {:class (stl/css :input-wrapper)} + [:span {:class (stl/css :input-label)} "V"] + [:input {:id "value-value" + :ref (:v refs) + :type "number" + :min 0 + :max 100 + :default-value value + :on-change (on-change-property :v 100)}]]])] + [:div {:class (stl/css :hex-alpha-wrapper)} + [:div {:class (stl/css-case :input-wrapper true + :hex true)} + [:span {:class (stl/css :input-label)} "HEX"] + [:input {:id "hex-value" + :ref (:hex refs) + :default-value hex + :on-change on-change-hex + :on-blur on-blur-hex}]] + (when (not disable-opacity) + [:div {:class (stl/css-case :input-wrapper true)} + [:span {:class (stl/css :input-label)} "A"] + [:input {:id "alpha-value" + :ref (:alpha refs) + :type "number" + :min 0 + :step 1 + :max 100 + :default-value (if (= alpha :multiple) "" alpha) + :on-change on-change-opacity}]])]] - [:input {:id "blue-value" - :ref (:b refs) - :type "number" - :min 0 - :max 255 - :default-value blue - :on-change (on-change-property :b 255)}]] - [:* - [:input {:id "hue-value" - :ref (:h refs) - :type "number" - :min 0 - :max 360 - :default-value hue - :on-change (on-change-property :h 360)}] + [:div.color-values + {:class (when disable-opacity "disable-opacity")} + [:input {:id "hex-value" + :ref (:hex refs) + :default-value hex + :on-change on-change-hex + :on-blur on-blur-hex}] - [:input {:id "saturation-value" - :ref (:s refs) - :type "number" - :min 0 - :max 100 - :step 1 - :default-value saturation - :on-change (on-change-property :s 100)}] + (if (= type :rgb) + [:* + [:input {:id "red-value" + :ref (:r refs) + :type "number" + :min 0 + :max 255 + :default-value red + :on-change (on-change-property :r 255)}] - [:input {:id "value-value" - :ref (:v refs) - :type "number" - :min 0 - :max 100 - :default-value value - :on-change (on-change-property :v 100)}]]) + [:input {:id "green-value" + :ref (:g refs) + :type "number" + :min 0 + :max 255 + :default-value green + :on-change (on-change-property :g 255)}] - (when (not disable-opacity) - [:input.alpha-value {:id "alpha-value" - :ref (:alpha refs) - :type "number" - :min 0 - :step 1 - :max 100 - :default-value (if (= alpha :multiple) "" alpha) - :on-change on-change-opacity}]) + [:input {:id "blue-value" + :ref (:b refs) + :type "number" + :min 0 + :max 255 + :default-value blue + :on-change (on-change-property :b 255)}]] + [:* + [:input {:id "hue-value" + :ref (:h refs) + :type "number" + :min 0 + :max 360 + :default-value hue + :on-change (on-change-property :h 360)}] - [:label.hex-label {:for "hex-value"} "HEX"] - (if (= type :rgb) - [:* - [:label.red-label {:for "red-value"} "R"] - [:label.green-label {:for "green-value"} "G"] - [:label.blue-label {:for "blue-value"} "B"]] - [:* - [:label.red-label {:for "hue-value"} "H"] - [:label.green-label {:for "saturation-value"} "S"] - [:label.blue-label {:for "value-value"} "V"]]) - (when (not disable-opacity) - [:label.alpha-label {:for "alpha-value"} "A"])])) + [:input {:id "saturation-value" + :ref (:s refs) + :type "number" + :min 0 + :max 100 + :step 1 + :default-value saturation + :on-change (on-change-property :s 100)}] + + [:input {:id "value-value" + :ref (:v refs) + :type "number" + :min 0 + :max 100 + :default-value value + :on-change (on-change-property :v 100)}]]) + + (when (not disable-opacity) + [:input.alpha-value {:id "alpha-value" + :ref (:alpha refs) + :type "number" + :min 0 + :step 1 + :max 100 + :default-value (if (= alpha :multiple) "" alpha) + :on-change on-change-opacity}]) + + [:label.hex-label {:for "hex-value"} "HEX"] + (if (= type :rgb) + [:* + [:label.red-label {:for "red-value"} "R"] + [:label.green-label {:for "green-value"} "G"] + [:label.blue-label {:for "blue-value"} "B"]] + [:* + [:label.red-label {:for "hue-value"} "H"] + [:label.green-label {:for "saturation-value"} "S"] + [:label.blue-label {:for "value-value"} "V"]]) + (when (not disable-opacity) + [:label.alpha-label {:for "alpha-value"} "A"])]))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.scss b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.scss new file mode 100644 index 0000000000..e66b883eeb --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.scss @@ -0,0 +1,37 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.color-values { + display: flex; + flex-direction: column; + gap: $s-4; + &.disable-opacity { + grid-template-columns: 3.5rem repeat(3, 1fr); + } + .colors-row { + display: flex; + align-items: center; + gap: $s-4; + .input-wrapper { + @extend .input-element; + width: $s-84; + } + } + .hex-alpha-wrapper { + display: flex; + align-items: center; + gap: $s-4; + .input-wrapper { + @extend .input-element; + width: $s-84; + &.hex { + width: $s-172; + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs index 43a4f768b6..4242861de6 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs @@ -5,8 +5,10 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.gradients + (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] + [app.main.ui.context :as ctx] [cuerdas.core :as str] [rumext.v2 :as mf])) @@ -20,17 +22,40 @@ (mf/defc gradients [{:keys [stops editing-stop on-select-stop]}] - [:div.gradient-stops - [:div.gradient-background-wrapper - [:div.gradient-background {:style {:background (gradient->string stops)}}]] + (let [new-css-system (mf/use-ctx ctx/new-css-system)] + (if new-css-system + [:div {:class (stl/css :gradient-stops)} + [:div {:class (stl/css :gradient-background-wrapper)} + [:div {:class (stl/css :gradient-background) + :style {:background (gradient->string stops)}}]] - [:div.gradient-stop-wrapper - (for [{:keys [offset hex r g b alpha] :as value} stops] - [:div.gradient-stop - {:class (when (= editing-stop offset) "active") - :on-click (partial on-select-stop offset) - :style {:left (dm/str (* offset 100) "%")} - :key (dm/str offset)} + [:div {:class (stl/css :gradient-stop-wrapper)} + (for [{:keys [offset hex r g b alpha] :as value} stops] + [:button {:class (stl/css-case :gradient-stop true + :selected (= editing-stop offset)) + :data-value offset + :on-click on-select-stop + :style {:left (dm/str (* offset 100) "%") + :backgroundColor hex} + :key (dm/str offset)} - [:div.gradient-stop-color {:style {:background-color hex}}] - [:div.gradient-stop-alpha {:style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]]) + [:div {:class (stl/css :gradient-stop-color) + :style {:background-color hex}}] + [:div {:class (stl/css :gradient-stop-alpha) + :style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]] + + [:div.gradient-stops + [:div.gradient-background-wrapper + [:div.gradient-background {:style {:background (gradient->string stops)}}]] + + [:div.gradient-stop-wrapper + (for [{:keys [offset hex r g b alpha] :as value} stops] + [:div.gradient-stop + {:class (when (= editing-stop offset) "active") + :data-value offset + :on-click on-select-stop + :style {:left (dm/str (* offset 100) "%")} + :key (dm/str offset)} + + [:div.gradient-stop-color {:style {:background-color hex}}] + [:div.gradient-stop-alpha {:style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]]))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss b/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss new file mode 100644 index 0000000000..78932650dd --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.scss @@ -0,0 +1,51 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.gradient-stops { + display: flex; + height: $s-20; + width: 100%; + margin: $s-12 0; + background-color: var(--colorpicker-handlers-color); + border-radius: $br-6; + + .gradient-background-wrapper { + height: 100%; + width: 100%; + border-radius: $br-6; + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") + left center; + + .gradient-background { + height: 100%; + width: 100%; + border-radius: $br-6; + border: $s-2 solid var(--colorpicker-details-color); + } + } + .gradient-stop-wrapper { + position: absolute; + width: calc(100% - 2rem); + .gradient-stop { + position: absolute; + display: grid; + grid-template-columns: 50% 50%; + width: $s-16; + height: $s-24; + border-radius: $br-4; + margin-top: calc(-1 * $s-2); + margin-left: calc(-1 * $s-8); + border: $s-2 solid var(--colorpicker-handlers-color); + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") + left center; + &.selected { + border: $s-2 solid var(--colorpicker-details-color-selected); + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs index 119faa933d..1c1d9b30a2 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs @@ -5,9 +5,11 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.harmony + (:require-macros [app.main.style :as stl]) (:require [app.common.geom.point :as gpt] [app.common.math :as mth] + [app.main.ui.context :as ctx] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.color :as uc] [app.util.dom :as dom] @@ -57,13 +59,16 @@ (gpt/point x y))) (mf/defc harmony-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [canvas-ref (mf/use-ref nil) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + canvas-ref (mf/use-ref nil) + canvas-side (if new-css-system + 192 + 152) {hue :h saturation :s value :v alpha :alpha} color - canvas-side 152 - pos-current (color->point canvas-side hue saturation) + pos-current (color->point canvas-side hue saturation) pos-complement (color->point canvas-side (mod (+ hue 180) 360) saturation) - dragging? (mf/use-state false) + dragging? (mf/use-state false) calculate-pos (fn [ev] (let [{:keys [left right top bottom]} (-> ev dom/get-target dom/get-bounding-rect) @@ -75,7 +80,7 @@ py (- (* 2 py) 1) angle (mth/degrees (mth/atan2 px py)) - new-hue (mod (- angle 90 ) 360) + new-hue (mod (- angle 90) 360) new-saturation (mth/clamp (mth/distance [px py] [0 0]) 0 1) hex (uc/hsv->hex [new-hue new-saturation value]) [r g b] (uc/hex->rgb hex)] @@ -123,41 +128,83 @@ (mf/deps canvas-ref) (fn [] (when canvas-ref (create-color-wheel (mf/ref-val canvas-ref))))) - - [:div.harmony-selector - [:div.hue-wheel-wrapper - [:canvas.hue-wheel - {:ref canvas-ref - :width canvas-side - :height canvas-side - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))}] - [:div.handler {:style {:pointer-events "none" - :left (:x pos-current) - :top (:y pos-current)}}] - [:div.handler.complement {:style {:left (:x pos-complement) - :top (:y pos-complement) - :cursor "pointer"} - :on-click on-complement-click}]] - [:div.handlers-wrapper - [:& slider-selector {:class "value" - :vertical? true - :reverse? true - :value value - :max-value 255 - :vertical true - :on-change on-change-value - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - (when (not disable-opacity) - [:& slider-selector {:class "opacity" + (if new-css-system + [:div {:class (stl/css :harmony-selector)} + [:div {:class (stl/css :handlers-wrapper)} + [:& slider-selector {:type :value :vertical? true - :value alpha - :max-value 1 + :reverse? true + :value value + :max-value 255 :vertical true - :on-change on-change-opacity + :on-change on-change-value :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])]])) + :on-finish-drag on-finish-drag}] + (when (not disable-opacity) + [[:& slider-selector {:type :opacity + :vertical? true + :value alpha + :max-value 1 + :vertical true + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]])] + + [:div {:class (stl/css :hue-wheel-wrapper)} + [:canvas {:class (stl/css :hue-wheel) + :ref canvas-ref + :width canvas-side + :height canvas-side + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))}] + [:div {:class (stl/css :handler) + :style {:pointer-events "none" + :left (:x pos-current) + :top (:y pos-current)}}] + [:div {:class (stl/css-case :handler true + :complement true) + :style {:left (:x pos-complement) + :top (:y pos-complement) + :cursor "pointer"} + :on-click on-complement-click}]]] + + [:div.harmony-selector + [:div.hue-wheel-wrapper + [:canvas.hue-wheel + {:ref canvas-ref + :width canvas-side + :height canvas-side + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))}] + [:div.handler {:style {:pointer-events "none" + :left (:x pos-current) + :top (:y pos-current)}}] + [:div.handler.complement {:style {:left (:x pos-complement) + :top (:y pos-complement) + :cursor "pointer"} + :on-click on-complement-click}]] + [:div.handlers-wrapper + [:& slider-selector {:class "value" + :vertical? true + :reverse? true + :value value + :max-value 255 + :vertical true + :on-change on-change-value + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + (when (not disable-opacity) + [:& slider-selector {:class "opacity" + :vertical? true + :value alpha + :max-value 1 + :vertical true + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])]]))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss b/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss new file mode 100644 index 0000000000..970c9ed5b5 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.scss @@ -0,0 +1,45 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.harmony-selector { + display: flex; + align-items: center; + gap: $s-8; + margin-top: $s-12; + margin-bottom: $s-8; + .hue-wheel-wrapper { + @include flexCenter; + position: relative; + + .hue-wheel { + width: $s-196; + height: $s-196; + } + + .handler { + @extend .colorpicker-handler; + height: $s-16; + width: $s-16; + border: $s-2 solid var(--colorpicker-handlers-color); + } + + .handler.complement { + background-color: var(--colorpicker-handlers-color); + border: $s-2 solid var(--colorpicker-handlers-color); + } + } + + .handlers-wrapper { + display: flex; + align-items: center; + gap: $s-4; + height: $s-200; + width: $s-52; + flex-grow: 1; + } +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs index 6933baeb3a..2b06676078 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs @@ -5,13 +5,16 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.hsva + (:require-macros [app.main.style :as stl]) (:require + [app.main.ui.context :as ctx] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.color :as uc] [rumext.v2 :as mf])) (mf/defc hsva-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [{hue :h saturation :s value :v alpha :alpha} color + (let [new-css-system (mf/use-ctx ctx/new-css-system) + {hue :h saturation :s value :v alpha :alpha} color handle-change-slider (fn [key] (fn [new-value] (let [change (hash-map key new-value) @@ -22,42 +25,87 @@ {:hex hex :r r :g g :b b}))))) on-change-opacity (fn [new-alpha] (on-change {:alpha new-alpha}))] - [:div.hsva-selector - [:span.hsva-selector-label "H"] - [:& slider-selector - {:class "hue" - :max-value 360 - :value hue - :on-change (handle-change-slider :h) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - [:span.hsva-selector-label "S"] - [:& slider-selector - {:class "saturation" - :max-value 1 - :value saturation - :on-change (handle-change-slider :s) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - [:span.hsva-selector-label "V"] - [:& slider-selector - {:class "value" - :reverse? false - :max-value 255 - :value value - :on-change (handle-change-slider :v) - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] - - (when (not disable-opacity) - [:* - [:span.hsva-selector-label "A"] + (if new-css-system + [:div {:class (stl/css :hsva-selector)} + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "H"] [:& slider-selector - {:class "opacity" - :max-value 1 - :value alpha - :on-change on-change-opacity + {:class (stl/css :hsva-bar) + :type :hue + :max-value 360 + :value hue + :on-change (handle-change-slider :h) :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}]])])) + :on-finish-drag on-finish-drag}]] + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "S"] + [:& slider-selector + {:class (stl/css :hsva-bar) + :type :saturation + :max-value 1 + :value saturation + :on-change (handle-change-slider :s) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]] + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "V"] + [:& slider-selector + {:class (stl/css :hsva-bar) + :type :value + :reverse? false + :max-value 255 + :value value + :on-change (handle-change-slider :v) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]] + (when (not disable-opacity) + [:div {:class (stl/css :hsva-row)} + [:span {:class (stl/css :hsva-selector-label)} "A"] + [:& slider-selector + {:class (stl/css :hsva-bar) + :type :opacity + :max-value 1 + :value alpha + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]])] + + [:div.hsva-selector + [:span.hsva-selector-label "H"] + [:& slider-selector + {:class "hue" + :max-value 360 + :value hue + :on-change (handle-change-slider :h) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + + [:span.hsva-selector-label "S"] + [:& slider-selector + {:class "saturation" + :max-value 1 + :value saturation + :on-change (handle-change-slider :s) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + [:span.hsva-selector-label "V"] + [:& slider-selector + {:class "value" + :reverse? false + :max-value 255 + :value value + :on-change (handle-change-slider :v) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + + (when (not disable-opacity) + [:* + [:span.hsva-selector-label "A"] + [:& slider-selector + {:class "opacity" + :max-value 1 + :value alpha + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}]])]) + )) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss b/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss new file mode 100644 index 0000000000..49e5f2e9e8 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.scss @@ -0,0 +1,30 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.hsva-selector { + display: flex; + flex-direction: column; + gap: $s-4; + padding: $s-4; + grid-row-gap: $s-8; + margin-bottom: $s-8; + .hsva-row { + display: flex; + align-items: center; + .hsva-selector-label { + @include tabTitleTipography; + display: flex; + align-items: center; + justify-content: flex-start; + width: $s-32; + } + .hsva-bar { + width: $s-228; + } + } +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index ba6a8b28e1..7a6690eba1 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -5,7 +5,9 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.libraries + (:require-macros [app.main.style :as stl]) (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.main.data.events :as ev] [app.main.data.workspace :as dw] @@ -13,6 +15,9 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.color-bullet :refer [color-bullet]] + [app.main.ui.components.color-bullet-new :as cb] + [app.main.ui.components.select :refer [select]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.hooks.resize :as r] [app.main.ui.icons :as i] @@ -23,7 +28,8 @@ (mf/defc libraries [{:keys [state on-select-color on-add-library-color disable-gradient disable-opacity]}] - (let [selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + selected (h/use-shared-state mdc/colorpicker-selected-broadcast-key :recent) current-colors (mf/use-state []) shared-libs (mf/deref refs/workspace-libraries) @@ -34,7 +40,9 @@ on-library-change (mf/use-fn (fn [event] - (let [val (dom/get-target-val event)] + (let [val (if new-css-system + event + (dom/get-target-val event))] (reset! selected (if (or (= val "recent") (= val "file")) @@ -44,7 +52,30 @@ check-valid-color? (fn [color] (and (or (not disable-gradient) (not (:gradient color))) - (or (not disable-opacity) (= 1 (:opacity color)))))] + (or (not disable-opacity) (= 1 (:opacity color))))) + + toggle-palette + (mf/use-fn + (fn [] + (r/set-resize-type! :bottom) + (dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down") + (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette) + (-> (dw/toggle-layout-flag :colorpalette) + (vary-meta assoc ::ev/origin "workspace-colorpicker")))))) + + shared-libs-options (mapv (fn[lib] {:value (d/name (:id lib)) :label (:name lib)} ) (vals shared-libs)) + + + library-options [{:value "recent" :label (tr "workspace.libraries.colors.recent-colors")} + {:value "file" :label (tr "workspace.libraries.colors.file-library")}] + + options (concat library-options shared-libs-options) + + on-color-click + (mf/use-fn + (mf/deps state) + (fn[event] + (on-select-color state event)))] ;; Load library colors when the select is changed (mf/with-effect [@selected recent-colors file-colors] @@ -71,33 +102,59 @@ (let [colors (vals file-colors)] (reset! current-colors (into [] (filter check-valid-color?) colors))))) - [:div.libraries - [:select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :on-change on-library-change - :value (name @selected)} - [:option {:value "recent"} (tr "workspace.libraries.colors.recent-colors")] - [:option {:value "file"} (tr "workspace.libraries.colors.file-library")] + (if new-css-system + [:div {:class (stl/css :libraries)} + [:div {:class (stl/css :select-wrapper)} + [:& select + {:class (stl/css :shadow-type-select) + :default-value (or (name @selected) "recent") + :options options + :on-change on-library-change}]] - (for [[_ {:keys [name id]}] shared-libs] - [:option {:key id :value id} name])] + [:div {:class (stl/css :selected-colors)} + (when (= @selected :file) + [:button {:class (stl/css :add-color-btn) + :on-click on-add-library-color} + i/add-refactor]) - [:div.selected-colors - (when (= @selected :file) - [:div.color-bullet.button.plus-button {:style {:background-color "var(--color-white)"} - :on-click on-add-library-color} - i/plus]) + [:button {:class (stl/css :palette-btn) + :on-click toggle-palette} + i/swatches-refactor] - [:div.color-bullet.button {:style {:background-color "var(--color-white)"} - :on-click(fn [] - (r/set-resize-type! :bottom) - (dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down") - (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette) - (-> (dw/toggle-layout-flag :colorpalette) - (vary-meta assoc ::ev/origin "workspace-colorpicker")))))} - i/palette] + (for [[idx color] (map-indexed vector @current-colors)] + [:& cb/color-bullet + {:key (dm/str "color-" idx) + :color color + :on-click on-color-click}])]] - (for [[idx color] (map-indexed vector @current-colors)] - [:& color-bullet - {:key (dm/str "color-" idx) - :color color - :on-click (partial on-select-color state)}])]])) + + [:div.libraries + [:select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :on-change on-library-change + :value (name @selected)} + [:option {:value "recent"} (tr "workspace.libraries.colors.recent-colors")] + [:option {:value "file"} (tr "workspace.libraries.colors.file-library")] + + (for [[_ {:keys [name id]}] shared-libs] + [:option {:key id :value id} name])] + + [:div.selected-colors + (when (= @selected :file) + [:div.color-bullet.button.plus-button {:style {:background-color "var(--color-white)"} + :on-click on-add-library-color} + i/plus]) + + [:div.color-bullet.button {:style {:background-color "var(--color-white)"} + :on-click (fn [] + (r/set-resize-type! :bottom) + (dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down") + (ts/schedule 300 #(st/emit! (dw/remove-layout-flag :textpalette) + (-> (dw/toggle-layout-flag :colorpalette) + (vary-meta assoc ::ev/origin "workspace-colorpicker")))))} + i/palette] + + (for [[idx color] (map-indexed vector @current-colors)] + [:& color-bullet + {:key (dm/str "color-" idx) + :color color + :on-click on-color-click}])]]))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss b/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss new file mode 100644 index 0000000000..2ae39c7f01 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.scss @@ -0,0 +1,36 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.libraries { + margin-top: $s-8; + width: 100%; + + .selected-colors { + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: $s-4; + justify-content: space-between; + overflow: auto; + margin-top: $s-8; + .add-color-btn, + .palette-btn { + @extend .button-secondary; + height: $s-24; + width: $s-24; + border-radius: $br-circle; + padding: 0; + svg { + @extend .button-icon; + } + } + } + .selected-colors::after { + content: ""; + flex: auto; + } +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index 0a839324a8..4adfb44638 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -5,16 +5,20 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.ramp + (:require-macros [app.main.style :as stl]) (:require [app.common.math :as mth] [app.main.ui.components.color-bullet :refer [color-bullet]] + [app.main.ui.components.color-bullet-new :as cb] + [app.main.ui.context :as ctx] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.color :as uc] [app.util.dom :as dom] [rumext.v2 :as mf])) (mf/defc value-saturation-selector [{:keys [saturation value on-change on-start-drag on-finish-drag]}] - (let [dragging? (mf/use-state false) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + dragging? (mf/use-state false) calculate-pos (fn [ev] (let [{:keys [left right top bottom]} (-> ev dom/get-target dom/get-bounding-rect) @@ -37,21 +41,33 @@ (fn [event] (dom/release-pointer event) (reset! dragging? false) - (on-finish-drag))) - ] - [:div.value-saturation-selector - {:on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))} - [:div.handler {:style {:pointer-events "none" - :left (str (* 100 saturation) "%") - :top (str (* 100 (- 1 (/ value 255))) "%")}}]])) + (on-finish-drag)))] + (if new-css-system + [:div {:class (stl/css :value-saturation-selector) + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))} + [:div {:class (stl/css :handler) + :style {:pointer-events "none" + :left (str (* 100 saturation) "%") + :top (str (* 100 (- 1 (/ value 255))) "%")}}]] + + [:div.value-saturation-selector + {:on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))} + [:div.handler {:style {:pointer-events "none" + :left (str (* 100 saturation) "%") + :top (str (* 100 (- 1 (/ value 255))) "%")}}]]))) (mf/defc ramp-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [{hex :hex + (let [new-css-system (mf/use-ctx ctx/new-css-system) + {hex :hex hue :h saturation :s value :v alpha :alpha} color on-change-value-saturation @@ -69,34 +85,65 @@ [r g b] (uc/hex->rgb hex)] (on-change {:hex hex :r r :g g :b b - :h new-hue} ))) + :h new-hue}))) on-change-opacity (fn [new-opacity] - (on-change {:alpha new-opacity} ))] - [:* - [:& value-saturation-selector - {:hue hue - :saturation saturation - :value value - :on-change on-change-value-saturation - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] + (on-change {:alpha new-opacity}))] + (if new-css-system + [:* + [:& value-saturation-selector + {:hue hue + :saturation saturation + :value value + :on-change on-change-value-saturation + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] - [:div.shade-selector - [:& color-bullet {:color {:color hex - :opacity alpha}}] - [:& slider-selector {:class "hue" - :max-value 360 - :value hue - :on-change on-change-hue - :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}] + [:div {:class (stl/css new-css-system :shade-selector) + :style #js {"--bullet-size" "52px"}} + [:& cb/color-bullet {:color {:color hex + :opacity alpha} + :area true}] + [:div {:class (stl/css :sliders-wrapper)} + [:& slider-selector {:type :hue + :max-value 360 + :value hue + :on-change on-change-hue + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] - (when (not disable-opacity) - [:& slider-selector {:class "opacity" - :max-value 1 - :value alpha - :on-change on-change-opacity + (when (not disable-opacity) + [:& slider-selector {:type :opacity + :max-value 1 + :value alpha + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])]]] + + [:* + [:& value-saturation-selector + {:hue hue + :saturation saturation + :value value + :on-change on-change-value-saturation + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}] + + [:div.shade-selector + [:& color-bullet {:color {:color hex + :opacity alpha}}] + [:& slider-selector {:class "hue" + :max-value 360 + :value hue + :on-change on-change-hue :on-start-drag on-start-drag - :on-finish-drag on-finish-drag}])]])) + :on-finish-drag on-finish-drag}] + + (when (not disable-opacity) + [:& slider-selector {:class "opacity" + :max-value 1 + :value alpha + :on-change on-change-opacity + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag}])]]))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss b/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss new file mode 100644 index 0000000000..dc788dbb86 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.scss @@ -0,0 +1,46 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.value-saturation-selector { + background-color: rgba(var(--hue-rgb)); + position: relative; + height: $s-140; + width: $s-256; + margin-top: $s-12; + margin-bottom: $s-6; + cursor: pointer; + + .handler { + @extend .colorpicker-handler; + height: $s-16; + width: $s-16; + border: $s-2 solid var(--colorpicker-handlers-color); + } + + &::before { + content: ""; + position: absolute; + width: 100%; + height: 100%; + background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0)); + } + + &::after { + content: ""; + position: absolute; + width: 100%; + height: 100%; + background: linear-gradient(to top, #000, rgba(0, 0, 0, 0)); + } +} +.shade-selector { + display: flex; + gap: $s-4; + height: $s-52; + cursor: pointer; +} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs index 7b5af5bae6..ddf475744d 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs @@ -5,15 +5,19 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.colorpicker.slider-selector + (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] [app.common.math :as mth] + [app.main.ui.context :as ctx] [app.util.dom :as dom] [app.util.object :as obj] [rumext.v2 :as mf])) (mf/defc slider-selector - [{:keys [value class min-value max-value vertical? reverse? on-change on-start-drag on-finish-drag]}] - (let [min-value (or min-value 0) + [{:keys [value class min-value max-value vertical? reverse? on-change on-start-drag on-finish-drag type]}] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + min-value (or min-value 0) max-value (or max-value 1) dragging? (mf/use-state false) @@ -49,23 +53,49 @@ value (+ min-value (* unit-value (- max-value min-value)))] (on-change value))))] - [:div.slider-selector - {:class (str (if vertical? "vertical " "") class) - :on-pointer-down handle-start-drag - :on-pointer-up handle-stop-drag - :on-lost-pointer-capture handle-stop-drag - :on-click calculate-pos - :on-pointer-move #(when @dragging? (calculate-pos %))} + (if new-css-system + [:div {:class (stl/css-case :opacity-wrapper (= type :opacity))} + [:div {:class (dm/str class (stl/css-case :vertical vertical? + :slider-selector true + :hue (= type :hue) + :opacity (= type :opacity) + :value (= type :value))) + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))} + (let [value-percent (* (/ (- value min-value) + (- max-value min-value)) 100) - (let [value-percent (* (/ (- value min-value) - (- max-value min-value)) 100) + value-percent (if reverse? + (mth/abs (- value-percent 100)) + value-percent) + value-percent-str (str value-percent "%") - value-percent (if reverse? - (mth/abs (- value-percent 100)) - value-percent) - value-percent-str (str value-percent "%") + style-common #js {:pointerEvents "none"} + style-horizontal (obj/merge! #js {:left value-percent-str} style-common) + style-vertical (obj/merge! #js {:bottom value-percent-str} style-common)] + [:div {:class (stl/css :handler) + :style (if vertical? style-vertical style-horizontal)}])]] - style-common #js {:pointerEvents "none"} - style-horizontal (obj/merge! #js {:left value-percent-str} style-common) - style-vertical (obj/merge! #js {:bottom value-percent-str} style-common)] - [:div.handler {:style (if vertical? style-vertical style-horizontal)}])])) + [:div.slider-selector + {:class (str (if vertical? "vertical " "") class) + :on-pointer-down handle-start-drag + :on-pointer-up handle-stop-drag + :on-lost-pointer-capture handle-stop-drag + :on-click calculate-pos + :on-pointer-move #(when @dragging? (calculate-pos %))} + + (let [value-percent (* (/ (- value min-value) + (- max-value min-value)) 100) + + value-percent (if reverse? + (mth/abs (- value-percent 100)) + value-percent) + value-percent-str (str value-percent "%") + + style-common #js {:pointerEvents "none"} + style-horizontal (obj/merge! #js {:left value-percent-str} style-common) + style-vertical (obj/merge! #js {:bottom value-percent-str} style-common)] + [:div.handler {:style (if vertical? style-vertical style-horizontal)}])]))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.scss b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.scss new file mode 100644 index 0000000000..65d2ae287b --- /dev/null +++ b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.scss @@ -0,0 +1,117 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.slider-selector { + --gradient-direction: 90deg; + --background-repeat: left; + + &.vertical { + --gradient-direction: 0deg; + --background-repeat: top; + } + position: relative; + align-self: center; + height: $s-24; + width: $s-200; + border: $s-2 solid var(--colorpicker-details-color); + border-radius: $br-6; + background: linear-gradient( + var(--gradient-direction), + rgba(var(--color), 0) 0%, + rgba(var(--color), 1) 100% + ); + cursor: pointer; + + &.vertical { + width: $s-24; + height: $s-200; + } + + &.hue { + background: linear-gradient( + var(--gradient-direction), + #f00 0%, + #ff0 17%, + #0f0 33%, + #0ff 50%, + #00f 67%, + #f0f 83%, + #f00 100% + ); + } + + &.saturation { + background: linear-gradient( + var(--gradient-direction), + var(--saturation-grad-from) 0%, + var(--saturation-grad-to) 100% + ); + } + + &.opacity { + background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=") + var(--background-repeat) center; + + &::after { + content: ""; + position: absolute; + width: 100%; + height: 100%; + background: linear-gradient( + var(--gradient-direction), + rgba(var(--color), 0) 0%, + rgba(var(--color), 1) 100% + ); + } + } + + &.value { + background: linear-gradient(var(--gradient-direction), #000 0%, #fff 100%); + } + + .handler { + position: absolute; + left: 50%; + width: calc($s-8 + $s-2); + height: calc($s-24 + $s-1); + border-radius: $br-4; + z-index: $z-index-1; + transform: translate(-4px, -3px); + background-color: var(--colorpicker-handlers-color); + } + + &.vertical .handler { + height: calc($s-8 + $s-2); + width: calc($s-24 + $s-1); + transform: translate(-12px, 5px); + } +} + +.opacity-wrapper { + background-color: var(--colorpicker-handlers-color); + border-radius: $br-8; +} + +.slider-selector.hue { + grid-area: hue; +} + +.slider-selector.opacity { + grid-area: opacity; +} + +.slider-selector.value { + background: linear-gradient(var(--gradient-direction), #000 0%, #fff 100%); +} +.slider-selector.saturation { + background: linear-gradient( + var(--gradient-direction), + var(--saturation-grad-from) 0%, + var(--saturation-grad-to) 100% + ); +} diff --git a/frontend/src/app/main/ui/workspace/left_header.scss b/frontend/src/app/main/ui/workspace/left_header.scss index cc1a5d275e..665b7c7795 100644 --- a/frontend/src/app/main/ui/workspace/left_header.scss +++ b/frontend/src/app/main/ui/workspace/left_header.scss @@ -83,9 +83,9 @@ } .menu { @extend .menu-dropdown; - position: absolute; top: $s-48; left: calc(var(--width, $s-256) - $s-16); + width: $s-192; margin: 0; .menu-item { @@ -125,9 +125,9 @@ } .sub-menu { @extend .menu-dropdown; - position: absolute; left: calc(var(--width, $s-256) + $s-180); - min-width: 270px; + width: $s-192; + min-width: calc($s-272 - $s-2); width: 110%; .shortcut { @extend .shortcut; diff --git a/frontend/src/app/main/ui/workspace/right_header.scss b/frontend/src/app/main/ui/workspace/right_header.scss index ccd1c804f8..b16d32f458 100644 --- a/frontend/src/app/main/ui/workspace/right_header.scss +++ b/frontend/src/app/main/ui/workspace/right_header.scss @@ -63,7 +63,6 @@ } .dropdown { @extend .menu-dropdown; - position: absolute; right: 0; top: $s-48; width: $s-280; diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index 653bb08e38..437993c685 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -94,7 +94,7 @@ :shortcuts? shortcuts? :collapsable? true :handle-collapse handle-collapse - :klass :tab-spacing} + :class :tab-spacing} [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")} [:div {:class (stl/css :layers-tab)} [:& sitemap {:layout layout}] diff --git a/frontend/src/app/main/ui/workspace/sidebar.scss b/frontend/src/app/main/ui/workspace/sidebar.scss index 5f18a54962..544083bf31 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.scss +++ b/frontend/src/app/main/ui/workspace/sidebar.scss @@ -20,10 +20,10 @@ $width-settings-bar-max: $s-500; .resize-area { position: absolute; - right: -8px; + right: calc(-1 * $s-8); z-index: $z-index-3; width: $s-8; - height: 100%; + height: calc(100vh - $s-52); cursor: ew-resize; } .settings-bar-inside { diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index d5133270f1..d3a8194257 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -652,7 +652,6 @@ :id "assets-group-component" :option-handler on-group}) - (when (and components-v2 (not multi-assets?)) {:option-name (tr "workspace.shape.menu.show-main") :id "assets-show-main-component" diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.scss b/frontend/src/app/main/ui/workspace/sidebar/layers.scss index 7bc6f141dc..8af16fd149 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.scss @@ -160,11 +160,12 @@ } } } + .filters-container { @extend .menu-dropdown; - position: absolute; top: $s-44; left: $s-12; + width: $s-192; .filter-menu-item { @include titleTipography; display: flex; @@ -201,16 +202,16 @@ .filter-menu-item-name-wrapper { .filter-menu-item-icon { svg { - stroke: var(--menu-foreground-color-selected); + stroke: var(--menu-foreground-color); } } .filter-menu-item-name { - color: var(--menu-foreground-color-selected); + color: var(--menu-foreground-color); } } .filter-menu-item-tick { svg { - stroke: var(--menu-foreground-color-selected); + stroke: var(--menu-foreground-color); } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 3dda831366..96668717d9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -98,7 +98,7 @@ :selected section :collapsable? false :content-class (stl/css :content-class) - :klass (stl/css :tab-spacing)} + :class (stl/css :tab-spacing)} [:& tab-element {:id :design :title (tr "workspace.options.design")} [:div {:class (stl/css :element-options)} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.scss b/frontend/src/app/main/ui/workspace/sidebar/options.scss index c2eebfa4e2..9bb5aa9902 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options.scss @@ -22,6 +22,7 @@ overflow-y: auto; overflow-x: hidden; height: calc(100vh - $s-96); + scrollbar-gutter: stable; } .element-options { diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs index 00f081aeed..dbe756c224 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs @@ -5,21 +5,30 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.common + (:require-macros [app.main.style :as stl]) (:require + [app.common.data.macros :as dm] + [app.main.ui.context :as ctx] [app.util.dom :as dom] [rumext.v2 :as mf])) -(mf/defc advanced-options [{:keys [visible? children]}] - (let [ref (mf/use-ref nil)] +(mf/defc advanced-options [{:keys [visible? class children]}] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + ref (mf/use-ref nil)] (mf/use-effect (mf/deps visible?) (fn [] (when-let [node (mf/ref-val ref)] (when visible? (dom/scroll-into-view-if-needed! node))))) + (if new-css-system + (when visible? + [:div {:class (dm/str class " " (stl/css :advanced-options-wrapper)) + :ref ref} + children]) - (when visible? - [:div.advanced-options-wrapper {:ref ref} - [:div.advanced-options {} - children]]))) + (when visible? + [:div.advanced-options-wrapper {:ref ref} + [:div.advanced-options {} + children]])))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.scss b/frontend/src/app/main/ui/workspace/sidebar/options/common.scss new file mode 100644 index 0000000000..6bd6984180 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.scss @@ -0,0 +1,13 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.advanced-options-wrapper { + display: flex; + flex-direction: column; + gap: $s-4; +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs index 8b6eb78952..0919d573a5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs @@ -5,10 +5,14 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.blur + (:require-macros [app.main.style :as stl]) (:require [app.common.uuid :as uuid] [app.main.data.workspace.changes :as dch] [app.main.store :as st] + [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.util.i18n :as i18n :refer [tr]] @@ -24,9 +28,26 @@ :hidden false})) (mf/defc blur-menu [{:keys [ids type values]}] - (let [blur (:blur values) - has-value? (not (nil? blur)) - multiple? (= blur :multiple) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + blur (:blur values) + has-value? (not (nil? blur)) + multiple? (= blur :multiple) + + state* (mf/use-state {:show-content true + :show-more-options false}) + + state (deref state*) + + open? (:show-content state) + more-options? (:show-more-options state) + + + toggle-content + (mf/use-fn #(swap! state* update :show-content not)) + + toggle-more-options + (mf/use-fn #(swap! state* update :show-more-options not)) + change! (mf/use-callback @@ -63,28 +84,74 @@ (fn [] (change! #(update-in % [:blur :hidden] not))))] - [:div.element-set - [:div.element-set-title - [:span - (case type - :multiple (tr "workspace.options.blur-options.title.multiple") - :group (tr "workspace.options.blur-options.title.group") - (tr "workspace.options.blur-options.title"))] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (case type + :multiple (tr "workspace.options.blur-options.title.multiple") + :group (tr "workspace.options.blur-options.title.group") + (tr "workspace.options.blur-options.title")) + :class (stl/css :title-spacing-blur)} - [:div.element-set-title-actions - (when (and has-value? (not multiple?)) - [:div.add-page {:on-click handle-toggle-visibility} (if (:hidden blur) i/eye-closed i/eye)]) + (when-not has-value? + [:button {:class (stl/css :add-blur) + :on-click handle-add} i/add-refactor])]] - (if has-value? - [:div.add-page {:on-click handle-delete} i/minus] - [:div.add-page {:on-click handle-add} i/close])]] + (when (and open? has-value?) + [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :first-row)} + [:div {:class (stl/css :blur-info)} + [:button {:class (stl/css-case :show-more true + :selected more-options?) + :on-click toggle-more-options} + i/menu-refactor] + [:span {:class (stl/css :label)} + (tr "workspace.options.blur-options.title")]] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click handle-toggle-visibility} + (if (:hidden blur) + i/hide-refactor + i/shown-refactor)] + [:button {:class (stl/css :action-btn) + :on-click handle-delete} i/remove-refactor]]] + (when more-options? + [:div {:class (stl/css :second-row)} + [:span {:class (stl/css :label)} + (tr "inspect.attributes.blur.value")] + [:> numeric-input* + {:className (stl/css :numeric-input) + :placeholder "--" + :min "0" + :on-change handle-change + :value (:value blur)}]])])] - (cond - has-value? - [:div.element-set-content - [:& input-row {:label "Value" - :class "pixels" - :min "0" - :value (:value blur) - :placeholder (tr "settings.multiple") - :on-change handle-change}]])])) + + [:div.element-set + [:div.element-set-title + [:span + (case type + :multiple (tr "workspace.options.blur-options.title.multiple") + :group (tr "workspace.options.blur-options.title.group") + (tr "workspace.options.blur-options.title"))] + + [:div.element-set-title-actions + (when (and has-value? (not multiple?)) + [:div.add-page {:on-click handle-toggle-visibility} (if (:hidden blur) i/eye-closed i/eye)]) + + (if has-value? + [:div.add-page {:on-click handle-delete} i/minus] + [:div.add-page {:on-click handle-add} i/close])]] + + (cond + has-value? + [:div.element-set-content + [:& input-row {:label "Value" + :class "pixels" + :min "0" + :value (:value blur) + :placeholder (tr "settings.multiple") + :on-change handle-change}]])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss new file mode 100644 index 0000000000..f9960fa801 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.scss @@ -0,0 +1,85 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-blur { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .element-set-content { + display: flex; + flex-direction: column; + gap: $s-4; + margin-bottom: $s-4; + .first-row { + display: flex; + align-items: center; + gap: $s-4; + width: 100%; + .blur-info { + display: flex; + align-items: center; + gap: $s-1; + flex-grow: 1; + border-radius: $br-8; + background-color: var(--input-details-color); + .show-more { + @extend .button-secondary; + height: $s-32; + width: $s-28; + border-radius: $br-8 0 0 $br-8; + svg { + @extend .button-icon; + } + &.selected { + background-color: var(--button-secondary-background-color-active); + color: var(--button-secondary-foreground-color-active); + svg { + stroke: var(--button-secondary-foreground-color-active); + } + } + } + .label { + @include tabTitleTipography; + flex-grow: 1; + display: flex; + align-items: center; + height: $s-32; + padding: 0 $s-8; + border-radius: 0 $br-8 $br-8 0; + background-color: var(--input-background-color); + } + } + .actions { + display: flex; + align-items: center; + gap: $s-4; + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + } + .second-row { + @extend .input-element; + gap: $s-4; + width: $s-92; + padding-left: $s-8; + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs index 87bc5af239..63a4d66237 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.color-selection + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -12,6 +13,8 @@ [app.main.data.workspace.colors :as dc] [app.main.data.workspace.selection :as dws] [app.main.store :as st] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] @@ -151,8 +154,15 @@ (mf/defc color-selection-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["shapes"]))]} [{:keys [shapes file-id shared-libs] :as props}] - (let [{:keys [ grouped-colors library-colors colors]} (mf/with-memo [shapes file-id shared-libs] - (prepare-colors shapes file-id shared-libs)) + (let [{:keys [grouped-colors library-colors colors]} (mf/with-memo [shapes file-id shared-libs] + (prepare-colors shapes file-id shared-libs)) + new-css-system (mf/use-ctx ctx/new-css-system) + + state* (mf/use-state true) + open? (deref state*) + + toggle-content (mf/use-fn #(swap! state* not)) + expand-lib-color (mf/use-state false) expand-color (mf/use-state false) @@ -202,26 +212,72 @@ (mf/with-effect [grouped-colors] (reset! grouped-colors* grouped-colors)) - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.selection-color")]] - [:div.element-set-content - [:div.selected-colors - (for [[index color] (d/enumerate (take 3 library-colors))] - [:& color-row {:key (dm/str "library-color-" (:color color)) - :color color - :index index - :on-detach on-detach - :select-only select-only - :on-change #(on-change %1 color %2) - :on-open on-open - :on-close on-close}]) - (when (and (false? @expand-lib-color) (< 3 (count library-colors))) - [:div.expand-colors {:on-click #(reset! expand-lib-color true)} - [:span i/actions] - [:span.text (tr "workspace.options.more-lib-colors")]]) - (when @expand-lib-color - (for [[index color] (d/enumerate (drop 3 library-colors))] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.options.selection-color") + :class (stl/css :title-spacing-selected-colors)}]] + + (when open? + [:div {:class (stl/css :element-content)} + [:div {:class (stl/css :selected-color-group)} + (for [[index color] (d/enumerate (take 3 library-colors))] + [:& color-row {:key (dm/str "library-color-" (:color color)) + :color color + :index index + :on-detach on-detach + :select-only select-only + :on-change #(on-change %1 color %2) + :on-open on-open + :on-close on-close}]) + (when (and (false? @expand-lib-color) (< 3 (count library-colors))) + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-lib-color true)} + (tr "workspace.options.more-lib-colors")]) + (when @expand-lib-color + (for [[index color] (d/enumerate (drop 3 library-colors))] + [:& color-row {:key (dm/str "library-color-" (:color color)) + :color color + :index index + :on-detach on-detach + :select-only select-only + :on-change #(on-change %1 color %2) + :on-open on-open + :on-close on-close}]))] + [:div {:class (stl/css :selected-color-group)} + (for [[index color] (d/enumerate (take 3 colors))] + [:& color-row {:key (dm/str "color-" index) + :color color + :index index + :select-only select-only + :on-change #(on-change %1 color %2) + :on-open on-open + :on-close on-close}]) + (when (and (false? @expand-color) (< 3 (count colors))) + [:button {:class (stl/css :more-colors-btn) + :on-click #(reset! expand-color true)} + (tr "workspace.options.more-colors")]) + + (when @expand-color + (for [[index color] (d/enumerate (drop 3 colors))] + [:& color-row {:key (dm/str "color-" (:color color)) + :color color + :index index + :select-only select-only + :on-change #(on-change %1 color %2) + :on-open on-open + :on-close on-close}]))]])] + + + [:div.element-set + [:div.element-set-title + [:span (tr "workspace.options.selection-color")]] + [:div.element-set-content + [:div.selected-colors + (for [[index color] (d/enumerate (take 3 library-colors))] [:& color-row {:key (dm/str "library-color-" (:color color)) :color color :index index @@ -229,27 +285,41 @@ :select-only select-only :on-change #(on-change %1 color %2) :on-open on-open - :on-close on-close}]))] + :on-close on-close}]) + (when (and (false? @expand-lib-color) (< 3 (count library-colors))) + [:div.expand-colors {:on-click #(reset! expand-lib-color true)} + [:span i/actions] + [:span.text (tr "workspace.options.more-lib-colors")]]) + (when @expand-lib-color + (for [[index color] (d/enumerate (drop 3 library-colors))] + [:& color-row {:key (dm/str "library-color-" (:color color)) + :color color + :index index + :on-detach on-detach + :select-only select-only + :on-change #(on-change %1 color %2) + :on-open on-open + :on-close on-close}]))] - [:div.selected-colors - (for [[index color] (d/enumerate (take 3 colors))] - [:& color-row {:key (dm/str "color-" index) - :color color - :index index - :select-only select-only - :on-change #(on-change %1 color %2) - :on-open on-open - :on-close on-close}]) - (when (and (false? @expand-color) (< 3 (count colors))) - [:div.expand-colors {:on-click #(reset! expand-color true)} - [:span i/actions] - [:span.text (tr "workspace.options.more-colors")]]) - (when @expand-color - (for [[index color] (d/enumerate (drop 3 colors))] - [:& color-row {:key (dm/str "color-" (:color color)) + [:div.selected-colors + (for [[index color] (d/enumerate (take 3 colors))] + [:& color-row {:key (dm/str "color-" index) :color color :index index :select-only select-only :on-change #(on-change %1 color %2) :on-open on-open - :on-close on-close}]))]]])) + :on-close on-close}]) + (when (and (false? @expand-color) (< 3 (count colors))) + [:div.expand-colors {:on-click #(reset! expand-color true)} + [:span i/actions] + [:span.text (tr "workspace.options.more-colors")]]) + (when @expand-color + (for [[index color] (d/enumerate (drop 3 colors))] + [:& color-row {:key (dm/str "color-" (:color color)) + :color color + :index index + :select-only select-only + :on-change #(on-change %1 color %2) + :on-open on-open + :on-close on-close}]))]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss new file mode 100644 index 0000000000..4301877b02 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.scss @@ -0,0 +1,35 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-fill { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .element-content { + display: flex; + flex-direction: column; + gap: $s-4; + .selected-color-group { + display: flex; + flex-direction: column; + gap: $s-4; + .more-colors-btn { + @extend .button-secondary; + @include tabTitleTipography; + height: $s-32; + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index 43bfa6b68e..bcb09fca49 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.component + (:require-macros [app.main.style :as stl]) (:require [app.common.pages.helpers :as cph] [app.common.types.component :as ctk] @@ -16,6 +17,8 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.context-menu :refer [context-menu]] + [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -143,7 +146,8 @@ (mf/defc component-menu [{:keys [ids values shape] :as props}] - (let [current-file-id (mf/use-ctx ctx/current-file-id) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + current-file-id (mf/use-ctx ctx/current-file-id) components-v2 (mf/use-ctx ctx/components-v2) objects (deref refs/workspace-page-objects) @@ -151,10 +155,16 @@ can-update-main? (or (not components-v2) touched?) id (first ids) - local (mf/use-state {:menu-open false}) + state* (mf/use-state {:show-content true + :menu-open false}) + state (deref state*) + open? (:show-content state) + menu-open? (:menu-open state) + + toggle-content + (mf/use-fn #(swap! state* update :show-content not)) shape-name (:name shape) - component-id (:component-id values) library-id (:component-file values) show? (some? component-id) @@ -165,6 +175,7 @@ lacks-annotation? (nil? (:annotation values)) local-component? (= library-id current-file-id) + workspace-data (deref refs/workspace-data) workspace-libraries (deref refs/workspace-libraries) component (if local-component? @@ -174,17 +185,16 @@ lib-exists? (and (not local-component?) (some? (get workspace-libraries library-id))) - on-menu-click - (mf/use-callback + (mf/use-fn (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (swap! local assoc :menu-open true))) + (swap! state* update :menu-open not))) on-menu-close (mf/use-callback - #(swap! local assoc :menu-open false)) + #(swap! state* assoc :menu-open false)) do-detach-component #(st/emit! (dwl/detach-component id)) @@ -217,59 +227,171 @@ do-create-annotation #(st/emit! (dw/set-annotations-id-for-create id)) do-navigate-component-file #(st/emit! (dwl/nav-to-component-file library-id))] (when show? - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.component")] - [:span (if main-instance? - (tr "workspace.options.component.main") - (tr "workspace.options.component.copy"))] - ] - [:div.element-set-content - [:div.row-flex.component-row - (if main-instance? - i/component - i/component-copy) - [:div.component-name shape-name] - [:div.row-actions - {:on-click on-menu-click} - i/actions - ;; WARNING: this menu is the same as the shape context menu. - ;; If you change it, you must change equally the file - ;; app/main/ui/workspace/context_menu.cljs - [:& context-menu {:on-close on-menu-close - :show (:menu-open @local) - :options - (if main-component? - [[(tr "workspace.shape.menu.show-in-assets") do-show-in-assets] - (when (and components-v2 local-component? lacks-annotation?) - [(tr "workspace.shape.menu.create-annotation") do-create-annotation])] - (if local-component? - (if is-dangling? - [[(tr "workspace.shape.menu.detach-instance") do-detach-component] - (when can-update-main? - [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) - (when components-v2 - [(tr "workspace.shape.menu.restore-main") do-restore-component])] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.options.component") + :class (stl/css :title-spacing-component)}]] - [[(tr "workspace.shape.menu.detach-instance") do-detach-component] - (when can-update-main? - [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) - (when can-update-main? - [(tr "workspace.shape.menu.update-main") do-update-component]) - [(tr "workspace.shape.menu.show-main") do-show-component]]) + (when open? + [:div {:class (stl/css :element-content)} + [:div {:class (stl/css :component-wrapper)} + [:div {:class (stl/css :component-name-wrapper)} + [:span {:class (stl/css :component-icon)} + (if main-instance? + i/component-refactor + i/copy-refactor)] - (if is-dangling? - [[(tr "workspace.shape.menu.detach-instance") do-detach-component] - (when can-update-main? - [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) - (when (and components-v2 lib-exists?) - [(tr "workspace.shape.menu.restore-main") do-restore-component])] - [[(tr "workspace.shape.menu.detach-instance") do-detach-component] - (when can-update-main? - [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) - (when can-update-main? - [(tr "workspace.shape.menu.update-main") do-update-remote-component]) - [(tr "workspace.shape.menu.go-main") do-navigate-component-file]])))}]]] + [:div {:class (stl/css :component-name)} shape-name]] - (when components-v2 - [:& component-annotation {:id id :values values :shape shape :component component}])]]))) + [:div {:class (stl/css :component-actions)} + [:button {:class (stl/css :menu-btn) + :on-click on-menu-click} + i/menu-refactor] + + [:& dropdown {:show menu-open? + :on-close on-menu-close} + [:ul {:class (stl/css :custom-select-dropdown)} + (if main-component? + [:* + [:li {:class (stl/css :dropdown-element) + :on-click do-show-in-assets} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.show-in-assets")]] + (when (and components-v2 local-component? lacks-annotation?) + [:li {:class (stl/css :dropdown-element) + :on-click do-create-annotation} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.create-annotation")]])] + + (if local-component? + (if is-dangling? + [:* + [:li {:class (stl/css :dropdown-element) + :on-click do-detach-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.detach-instance")]] + (when can-update-main? + [:li {:class (stl/css :dropdown-element) + :on-click do-reset-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.reset-overrides")]]) + (when components-v2 + [:li {:class (stl/css :dropdown-element) + :on-click do-restore-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.restore-main")]])] + + [:* + [:li {:class (stl/css :dropdown-element) + :on-click do-detach-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.detach-instance")]] + (when can-update-main? + [:li {:class (stl/css :dropdown-element) + :on-click do-reset-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.reset-overrides")]] + [:li {:class (stl/css :dropdown-element) + :on-click do-update-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.update-main")]]) + [:li {:class (stl/css :dropdown-element) + :on-click do-show-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.show-main")]]]) + (if is-dangling? + [:* + [:li {:class (stl/css :dropdown-element) + :on-click do-detach-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.detach-instance")]] + (when can-update-main? + [:li {:class (stl/css :dropdown-element) + :on-click do-reset-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.reset-overrides")]]) + + (when (and components-v2 lib-exists?) + [:li {:class (stl/css :dropdown-element) + :on-click do-restore-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.restore-main")]])] + [:* + [:li {:class (stl/css :dropdown-element) + :on-click do-detach-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.detach-instance")]] + (when can-update-main? + [:li {:class (stl/css :dropdown-element) + :on-click do-reset-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.reset-overrides")]] + [:li {:class (stl/css :dropdown-element) + :on-click do-update-remote-component} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.update-main")]]) + [:li {:class (stl/css :dropdown-element) + :on-click do-navigate-component-file} + [:span {:class (stl/css :dropdown-label)} + (tr "workspace.shape.menu.go-main")]]])))]]]] + (when components-v2 + [:& component-annotation {:id id :values values :shape shape :component component}])])] + + [:div.element-set + [:div.element-set-title + [:span (tr "workspace.options.component")] + [:span (if main-instance? + (tr "workspace.options.component.main") + (tr "workspace.options.component.copy"))]] + [:div.element-set-content + [:div.row-flex.component-row + (if main-instance? + i/component + i/component-copy) + [:div.component-name shape-name] + [:div.row-actions + {:on-click on-menu-click} + i/actions + ;; WARNING: this menu is the same as the shape context menu. + ;; If you change it, you must change equally the file + ;; app/main/ui/workspace/context_menu.cljs + [:& context-menu {:on-close on-menu-close + :show menu-open? + :options (if main-component? + [[(tr "workspace.shape.menu.show-in-assets") do-show-in-assets] + (when (and components-v2 local-component? lacks-annotation?) + [(tr "workspace.shape.menu.create-annotation") do-create-annotation])] + (if local-component? + (if is-dangling? + [[(tr "workspace.shape.menu.detach-instance") do-detach-component] + (when can-update-main? + [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) + (when components-v2 + [(tr "workspace.shape.menu.restore-main") do-restore-component])] + + [[(tr "workspace.shape.menu.detach-instance") do-detach-component] + (when can-update-main? + [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) + (when can-update-main? + [(tr "workspace.shape.menu.update-main") do-update-component]) + [(tr "workspace.shape.menu.show-main") do-show-component]]) + + (if is-dangling? + [[(tr "workspace.shape.menu.detach-instance") do-detach-component] + (when can-update-main? + [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) + (when (and components-v2 lib-exists?) + [(tr "workspace.shape.menu.restore-main") do-restore-component])] + [[(tr "workspace.shape.menu.detach-instance") do-detach-component] + (when can-update-main? + [(tr "workspace.shape.menu.reset-overrides") do-reset-component]) + (when can-update-main? + [(tr "workspace.shape.menu.update-main") do-update-remote-component]) + [(tr "workspace.shape.menu.go-main") do-navigate-component-file]])))}]]] + + (when components-v2 + [:& component-annotation {:id id :values values :shape shape :component component}])]])))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss new file mode 100644 index 0000000000..5d74ad3444 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss @@ -0,0 +1,59 @@ +// 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 + +@import "refactor/common-refactor.scss"; +.element-set { + .element-content { + display: flex; + flex-direction: column; + gap: $s-4; + .component-wrapper { + display: flex; + gap: $s-4; + .component-name-wrapper { + @extend .asset-element; + display: flex; + align-items: center; + gap: $s-4; + flex-grow: 1; + .component-icon { + @include flexCenter; + height: $s-24; + width: $s-24; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } + } + .component-name { + @include titleTipography; + flex-grow: 1; + } + } + .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; + } + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index 94ebe5c781..a61c6314a3 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.constraints + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.geom.rect :as grc] @@ -13,6 +14,9 @@ [app.main.data.workspace.changes :as dch] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.select :refer [select]] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -27,8 +31,15 @@ (mf/defc constraints-menu [{:keys [ids values] :as props}] - (let [old-shapes (deref (refs/objects-by-id ids)) - frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + + state* (mf/use-state true) + open? (deref state*) + + toggle-content (mf/use-fn #(swap! state* not)) + + old-shapes (deref (refs/objects-by-id ids)) + frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes) shapes (as-> old-shapes $ (map gsh/translate-to-frame $ frames)) @@ -53,127 +64,261 @@ constraints-h (or (get values :constraints-h) (gsh/default-constraints-h values)) constraints-v (or (get values :constraints-v) (gsh/default-constraints-v values)) - on-constraint-button-clicked - (mf/use-callback - (mf/deps [ids values]) - (fn [button] - (fn [_] - (let [constraints-h (get values :constraints-h :scale) - constraints-v (get values :constraints-v :scale) - [constraint new-value] - (case button - :top (case constraints-v - :top [:constraints-v :scale] - :topbottom [:constraints-v :bottom] - :bottom [:constraints-v :topbottom] - [:constraints-v :top]) - :bottom (case constraints-v - :bottom [:constraints-v :scale] - :topbottom [:constraints-v :top] - :top [:constraints-v :topbottom] - [:constraints-v :bottom]) - :left (case constraints-h - :left [:constraints-h :scale] - :leftright [:constraints-h :right] - :right [:constraints-h :leftright] - [:constraints-h :left]) - :right (case constraints-h - :right [:constraints-h :scale] - :leftright [:constraints-h :left] - :left [:constraints-h :leftright] - [:constraints-h :right]) - :centerv (case constraints-v - :center [:constraints-v :scale] - [:constraints-v :center]) - :centerh (case constraints-h - :center [:constraints-h :scale] - [:constraints-h :center]))] - (st/emit! (dch/update-shapes - ids - #(assoc % constraint new-value))))))) + on-constraint-button-clicked + (mf/use-fn + (mf/deps ids values) + (fn [event] + (let [button (-> (dom/get-current-target event) + (dom/get-data "value") + (keyword)) + constraints-h (get values :constraints-h :scale) + constraints-v (get values :constraints-v :scale) + + [constraint new-value] + (case button + :top (case constraints-v + :top [:constraints-v :scale] + :topbottom [:constraints-v :bottom] + :bottom [:constraints-v :topbottom] + [:constraints-v :top]) + :bottom (case constraints-v + :bottom [:constraints-v :scale] + :topbottom [:constraints-v :top] + :top [:constraints-v :topbottom] + [:constraints-v :bottom]) + :left (case constraints-h + :left [:constraints-h :scale] + :leftright [:constraints-h :right] + :right [:constraints-h :leftright] + [:constraints-h :left]) + :right (case constraints-h + :right [:constraints-h :scale] + :leftright [:constraints-h :left] + :left [:constraints-h :leftright] + [:constraints-h :right]) + :centerv (case constraints-v + :center [:constraints-v :scale] + [:constraints-v :center]) + :centerh (case constraints-h + :center [:constraints-h :scale] + [:constraints-h :center]) + nil ())] + + (st/emit! (dch/update-shapes + ids + #(assoc % constraint new-value)))))) on-constraint-select-changed - (mf/use-callback - (mf/deps [ids values]) - (fn [constraint] - (fn [event] - (let [value (-> (dom/get-target-val event) (keyword))] - (when-not (str/empty? value) - (st/emit! (dch/update-shapes - ids - #(assoc % constraint value)))))))) + (mf/use-fn + (mf/deps ids) + (fn [event] + (let [constraint (-> (dom/get-current-target event) + (dom/get-data "value") + (keyword)) + value (-> (dom/get-target-val event) (keyword))] + (when-not (str/empty? value) + (st/emit! (dch/update-shapes + ids + #(assoc % constraint value))))))) + + on-constraint-h-select-changed + (mf/use-fn + (mf/deps ids) + (fn [value] + (when-not (str/empty? value) + (st/emit! (dch/update-shapes + ids + #(assoc % :constraints-h (keyword value))))))) + + on-constraint-v-select-changed + (mf/use-fn + (mf/deps ids) + (fn [value] + (when-not (str/empty? value) + (st/emit! (dch/update-shapes + ids + #(assoc % :constraints-v (keyword value))))))) on-fixed-scroll-clicked - (mf/use-callback - (mf/deps [ids values]) + (mf/use-fn + (mf/deps ids) (fn [_] - (st/emit! (dch/update-shapes ids #(update % :fixed-scroll not)))))] + (st/emit! (dch/update-shapes ids #(update % :fixed-scroll not))))) - ;; CONSTRAINTS - (when in-frame? - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.constraints")]] + options-h + (mf/with-memo [constraints-h] + (d/concat-vec + (when (= constraints-h :multiple) + [{:value "" :label (tr "settings.multiple")}]) + [{:value "left" :label (tr "workspace.options.constraints.left")} + {:value "right" :label (tr "workspace.options.constraints.right")} + {:value "leftright" :label (tr "workspace.options.constraints.leftright")} + {:value "center" :label (tr "workspace.options.constraints.center")} + {:value "scale" :label (tr "workspace.options.constraints.scale")}])) - [:div.element-set-content - [:div.row-flex.align-top + options-v + (mf/with-memo [constraints-v] + (d/concat-vec + (when (= constraints-v :multiple) + [{:value "" :label (tr "settings.multiple")}]) + [{:value "top" :label (tr "workspace.options.constraints.top")} + {:value "bottom" :label (tr "workspace.options.constraints.bottom")} + {:value "topbottom" :label (tr "workspace.options.constraints.topbottom")} + {:value "center" :label (tr "workspace.options.constraints.center")} + {:value "scale" :label (tr "workspace.options.constraints.scale")}]))] - [:div.constraints-widget - [:div.constraints-box] - [:div.constraint-button.top - {:class (dom/classnames :active (or (= constraints-v :top) - (= constraints-v :topbottom))) - :on-click (on-constraint-button-clicked :top)}] - [:div.constraint-button.bottom - {:class (dom/classnames :active (or (= constraints-v :bottom) - (= constraints-v :topbottom))) - :on-click (on-constraint-button-clicked :bottom)}] - [:div.constraint-button.left - {:class (dom/classnames :active (or (= constraints-h :left) - (= constraints-h :leftright))) - :on-click (on-constraint-button-clicked :left)}] - [:div.constraint-button.right - {:class (dom/classnames :active (or (= constraints-h :right) - (= constraints-h :leftright))) - :on-click (on-constraint-button-clicked :right)}] - [:div.constraint-button.centerv - {:class (dom/classnames :active (= constraints-v :center)) - :on-click (on-constraint-button-clicked :centerv)}] - [:div.constraint-button.centerh - {:class (dom/classnames :active (= constraints-h :center)) - :on-click (on-constraint-button-clicked :centerh)}]] - [:div.constraints-form - [:div.row-flex - [:span.left-right i/full-screen] - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :on-change (on-constraint-select-changed :constraints-h) - :value (d/name constraints-h "scale")} - (when (= constraints-h :multiple) - [:option {:value ""} (tr "settings.multiple")]) - [:option {:value "left"} (tr "workspace.options.constraints.left")] - [:option {:value "right"} (tr "workspace.options.constraints.right")] - [:option {:value "leftright"} (tr "workspace.options.constraints.leftright")] - [:option {:value "center"} (tr "workspace.options.constraints.center")] - [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] - [:div.row-flex - [:span.top-bottom i/full-screen] - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :on-change (on-constraint-select-changed :constraints-v) - :value (d/name constraints-v "scale")} - (when (= constraints-v :multiple) - [:option {:value ""} (tr "settings.multiple")]) - [:option {:value "top"} (tr "workspace.options.constraints.top")] - [:option {:value "bottom"} (tr "workspace.options.constraints.bottom")] - [:option {:value "topbottom"} (tr "workspace.options.constraints.topbottom")] - [:option {:value "center"} (tr "workspace.options.constraints.center")] - [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] - (when first-level? - [:div.row-flex - [:div.fix-when {:class (dom/classnames :active (:fixed-scroll values)) - :on-click on-fixed-scroll-clicked} - (if (:fixed-scroll values) - i/pin-fill - i/pin) - [:span (tr "workspace.options.constraints.fix-when-scrolling")]]])]]]]))) + ;; CONSTRAINTS + (when in-frame? + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.options.constraints")}]] + (when open? + [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :constraints-widget)} + [:div {:class (stl/css :constraints-top)} + [:button {:class (stl/css-case :constraint-btn true + :active (or (= constraints-v :top) + (= constraints-v :topbottom))) + :data-value :top + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-left)} + [:button {:class (stl/css-case :constraint-btn true + :constraint-btn-rotated true + :active (or (= constraints-h :left) + (= constraints-h :leftright))) + :data-value :left + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-center)} + [:button {:class (stl/css-case :constraint-btn true + :active (= constraints-h :center)) + :data-value :centerh + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]] + [:button {:class (stl/css-case :constraint-btn-special true + :constraint-btn-rotated true + :active (= constraints-v :center)) + :data-value :centerv + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-right)} + [:button {:class (stl/css-case :constraint-btn true + :constraint-btn-rotated true + :active (or (= constraints-h :right) + (= constraints-h :leftright))) + :data-value :right + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]] + [:div {:class (stl/css :constraints-bottom)} + [:button {:class (stl/css-case :constraint-btn true + :active (or (= constraints-v :bottom) + (= constraints-v :topbottom))) + :data-value :bottom + :on-click on-constraint-button-clicked} + [:span {:class (stl/css :resalted-area)}]]]] + [:div {:class (stl/css :contraints-selects)} + [:div {:class (stl/css :horizontal-select)} + [:& select + {:default-value (d/name constraints-h "scale") + :options options-h + :on-change on-constraint-h-select-changed}]] + [:div {:class (stl/css :vertical-select)} + [:& select + {:default-value (d/name constraints-v "scale") + :options options-v + :on-change on-constraint-v-select-changed}]] + (when first-level? + [:div {:class (stl/css :checkbox)} + + [:label {:for "fixed-on-scroll" + :class (stl/css-case :checked (:fixed-scroll values))} + [:span {:class (stl/css-case :check-mark true + :checked (:fixed-scroll values))} + (when (:fixed-scroll values) + i/status-tick-refactor)] + (tr "workspace.options.constraints.fix-when-scrolling") + [:input {:type "checkbox" + :id "fixed-on-scroll" + :checked (:fixed-scroll values) + :on-change on-fixed-scroll-clicked}]]])]])] + + + [:div.element-set + [:div.element-set-title + [:span (tr "workspace.options.constraints")]] + + [:div.element-set-content + [:div.row-flex.align-top + [:div.constraints-widget + [:div.constraints-box] + [:div.constraint-button.top + {:class (dom/classnames :active (or (= constraints-v :top) + (= constraints-v :topbottom))) + :data-value :top + :on-click on-constraint-button-clicked}] + [:div.constraint-button.bottom + {:class (dom/classnames :active (or (= constraints-v :bottom) + (= constraints-v :topbottom))) + :data-value :bottom + :on-click on-constraint-button-clicked}] + [:div.constraint-button.left + {:class (dom/classnames :active (or (= constraints-h :left) + (= constraints-h :leftright))) + :data-value :left + :on-click on-constraint-button-clicked}] + [:div.constraint-button.right + {:class (dom/classnames :active (or (= constraints-h :right) + (= constraints-h :leftright))) + :data-value :right + :on-click on-constraint-button-clicked}] + [:div.constraint-button.centerv + {:class (dom/classnames :active (= constraints-v :center)) + :data-value :centerv + :on-click on-constraint-button-clicked}] + [:div.constraint-button.centerh + {:class (dom/classnames :active (= constraints-h :center)) + :data-value :centerh + :on-click on-constraint-button-clicked}]] + + [:div.constraints-form + [:div.row-flex + [:span.left-right i/full-screen] + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :data-value :constraints-h + :on-change on-constraint-select-changed + :value (d/name constraints-h "scale")} + (when (= constraints-h :multiple) + [:option {:value ""} (tr "settings.multiple")]) + [:option {:value "left"} (tr "workspace.options.constraints.left")] + [:option {:value "right"} (tr "workspace.options.constraints.right")] + [:option {:value "leftright"} (tr "workspace.options.constraints.leftright")] + [:option {:value "center"} (tr "workspace.options.constraints.center")] + [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] + [:div.row-flex + [:span.top-bottom i/full-screen] + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :data-value :constraints-v + :on-change on-constraint-select-changed + :value (d/name constraints-v "scale")} + (when (= constraints-v :multiple) + [:option {:value ""} (tr "settings.multiple")]) + [:option {:value "top"} (tr "workspace.options.constraints.top")] + [:option {:value "bottom"} (tr "workspace.options.constraints.bottom")] + [:option {:value "topbottom"} (tr "workspace.options.constraints.topbottom")] + [:option {:value "center"} (tr "workspace.options.constraints.center")] + [:option {:value "scale"} (tr "workspace.options.constraints.scale")]]] + (when first-level? + [:div.row-flex + [:div.fix-when {:class (dom/classnames :active (:fixed-scroll values)) + :on-click on-fixed-scroll-clicked} + (if (:fixed-scroll values) + i/pin-fill + i/pin) + [:span (tr "workspace.options.constraints.fix-when-scrolling")]]])]]]])))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss new file mode 100644 index 0000000000..c822e9129d --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.scss @@ -0,0 +1,151 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-set-content { + display: flex; + gap: $s-4; + .constraints-widget { + background-color: var(--constraint-widget-background-color); + display: grid; + grid-template-columns: $s-24 $s-72 $s-24; + grid-template-rows: $s-24 $s-72 $s-24; + grid-template-areas: + "top top top" + "left center right" + "bottom bottom bottom"; + height: $s-120; + width: $s-120; + border-radius: $br-8; + .constraints-top, + .constraints-left, + .constraints-center, + .constraints-right, + .constraints-bottom { + @include flexCenter; + grid-area: top; + .constraint-btn, + .constraint-btn-special, + .constraint-btn-rotated { + @include buttonStyle; + @include flexCenter; + width: 100%; + height: 100%; + .resalted-area { + width: $s-40; + height: $s-4; + border-radius: $br-8; + background-color: var(--button-constraint-background-color-rest); + padding: 0; + margin: 0; + } + &.active .resalted-area { + outline: $s-4 solid var(--button-constraint-border-color-hover); + background-color: var(--button-constraint-background-color-hover); + } + &:hover .resalted-area, + &:focus .resalted-area { + outline: $s-4 solid var(--button-constraint-border-color-hover); + background-color: var(--button-constraint-background-color-hover); + } + } + } + .constraints-left { + grid-area: left; + .constraint-btn-rotated { + height: $s-72; + width: $s-24; + .resalted-area { + height: $s-40; + width: $s-4; + } + } + } + .constraints-center { + grid-area: center; + position: relative; + background-color: var(--constraint-center-area-background-color); + border-radius: $br-8; + .constraint-btn { + width: $s-72; + height: $s-24; + .resalted-area { + width: $s-40; + height: $s-4; + } + } + .constraint-btn-special { + position: absolute; + height: $s-72; + width: $s-24; + .resalted-area { + height: $s-40; + width: $s-4; + } + } + } + .constraints-right { + grid-area: right; + .constraint-btn-rotated { + height: $s-72; + width: $s-24; + .resalted-area { + height: $s-40; + width: $s-4; + } + } + } + .constraints-bottom { + grid-area: bottom; + } + } + .contraints-selects { + display: flex; + flex-direction: column; + gap: $s-4; + + .horizontal-select, + .vertical-select { + width: $s-124; + padding: 0; + } + + .checkbox { + display: flex; + align-items: center; + margin-bottom: $s-8; + margin-top: $s-8; + padding-left: 0; + input { + margin: 0; + } + label { + @include titleTipography; + display: flex; + align-items: center; + gap: $s-2; + cursor: pointer; + .check-mark { + @include flexCenter; + width: $s-16; + height: $s-16; + border-radius: $br-6; + background-color: var(--input-background-color); + &.checked { + background-color: var(--input-border-color-active); + svg { + @extend .button-icon-small; + stroke: var(--input-details-color); + } + } + } + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index 9fe6cad425..66492c6e01 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.exports + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.main.data.exports :as de] @@ -12,6 +13,9 @@ [app.main.data.workspace.state-helpers :as wsh] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.select :refer [select]] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.export] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -26,7 +30,13 @@ (mf/defc exports-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "page-id" "file-id"]))]} [{:keys [ids type values page-id file-id] :as props}] - (let [exports (:exports values []) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + exports (:exports values []) + + comp-state* (mf/use-state true) + open? (deref comp-state*) + + toggle-content (mf/use-fn #(swap! comp-state* not)) state (mf/deref refs/export) in-progress? (:in-progress state) @@ -107,19 +117,23 @@ (mf/use-callback (mf/deps ids) (fn [index event] - (let [target (dom/get-target event) - value (dom/get-value target) - value (d/parse-double value)] + (let [scale (if new-css-system + (d/parse-double event) + (-> event + (dom/get-target-val) + (d/parse-double)))] (st/emit! (dch/update-shapes ids (fn [shape] - (assoc-in shape [:exports index :scale] value))))))) + (assoc-in shape [:exports index :scale] scale))))))) on-suffix-change (mf/use-callback (mf/deps ids) - (fn [index event] - (let [target (dom/get-target event) - value (dom/get-value target)] + (fn [event] + (let [value (dom/get-target-val event) + index (-> (dom/get-current-target event) + (dom/get-data "value") + (int))] (st/emit! (dch/update-shapes ids (fn [shape] (assoc-in shape [:exports index :suffix] value))))))) @@ -128,12 +142,14 @@ (mf/use-callback (mf/deps ids) (fn [index event] - (let [target (dom/get-target event) - value (dom/get-value target) - value (keyword value)] + (let [type (if new-css-system + (keyword event) + (-> event + (dom/get-target-val) + (keyword)))] (st/emit! (dch/update-shapes ids (fn [shape] - (assoc-in shape [:exports index :type] value))))))) + (assoc-in shape [:exports index :type] type))))))) on-remove-all (mf/use-callback @@ -147,58 +163,135 @@ (fn [event] (let [esc? (kbd/esc? event)] (when esc? - (dom/blur! (dom/get-target event))))))] + (dom/blur! (dom/get-target event)))))) - [:div.element-set.exports-options - [:div.element-set-title - [:span (tr (if (> (count ids) 1) "workspace.options.export-multiple" "workspace.options.export"))] - (when (not (= :multiple exports)) - [:div.add-page {:on-click add-export} i/close])] + size-options [{:value "0.5" :label "0.5x"} + {:value "0.75" :label "0.75x"} + {:value "1" :label "1x"} + {:value "1.5" :label "1.5x"} + {:value "2" :label "2x"} + {:value "4" :label "4x"} + {:value "6" :label "6"}] - (cond - (= :multiple exports) - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click on-remove-all} - i/minus]]] + format-options [{:value "png" :label "PNG"} + {:value "jpeg" :label "JPE"} + {:value "svg" :label "SVG"} + {:value "pdf" :label "PDF"}]] - (seq exports) - [:div.element-set-content - (for [[index export] (d/enumerate exports)] - [:div.element-set-options-group - {:key index} - (when (scale-enabled? export) + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr (if (> (count ids) 1) "workspace.options.export-multiple" "workspace.options.export")) + :class (stl/css :title-spacing-export)} + [:button {:class (stl/css :add-export) + :on-click add-export} i/add-refactor]]] + (when open? + [:div {:class (stl/css :element-set-content)} + + (cond + (= :multiple exports) + [:div {:class (stl/css :multiple-exports)} + [:div {:class (stl/css :label)} (tr "settings.multiple")] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click on-remove-all} + i/remove-refactor]]] + + (seq exports) + [:* + (for [[index export] (d/enumerate exports)] + [:div {:class (stl/css :element-group) + :key index} + [:div {:class (stl/css :input-wrapper)} + [:div {:class (stl/css :format-select)} + [:& select + {:default-value (d/name (:type export)) + :options format-options + :on-change (partial on-type-change index)}]] + (when (scale-enabled? export) + [:div {:class (stl/css :size-select)} + [:& select + {:default-value (str (:scale export)) + :options size-options + :on-change (partial on-scale-change index)}]]) + [:div {:class (stl/css :suffix-input)} + [:input {:class (stl/css :type-input) + :value (:suffix export) + :placeholder (tr "workspace.options.export.suffix") + :data-value index + :on-change on-suffix-change + :on-key-down manage-key-down}]]] + + [:button {:class (stl/css :action-btn) + :on-click (partial delete-export index)} + i/remove-refactor]])]) + + (when (or (= :multiple exports) (seq exports)) + [:button + {:on-click (when-not in-progress? on-download) + :class (stl/css-case + :export-btn true + :btn-disabled in-progress?) + :disabled in-progress?} + (if in-progress? + (tr "workspace.options.exporting-object") + (tr "workspace.options.export-object" (c (count shapes-with-exports))))])])] + + + [:div.element-set.exports-options + [:div.element-set-title + [:span (tr (if (> (count ids) 1) "workspace.options.export-multiple" "workspace.options.export"))] + (when (not (= :multiple exports)) + [:div.add-page {:on-click add-export} i/close])] + + (cond + (= :multiple exports) + [:div.element-set-options-group + [:div.element-set-label (tr "settings.multiple")] + [:div.element-set-actions + [:div.element-set-actions-button {:on-click on-remove-all} + i/minus]]] + + (seq exports) + [:div.element-set-content + (for [[index export] (d/enumerate exports)] + [:div.element-set-options-group + {:key index} + (when (scale-enabled? export) + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :on-change (partial on-scale-change index) + :value (:scale export)} + [:option {:value "0.5"} "0.5x"] + [:option {:value "0.75"} "0.75x"] + [:option {:value "1"} "1x"] + [:option {:value "1.5"} "1.5x"] + [:option {:value "2"} "2x"] + [:option {:value "4"} "4x"] + [:option {:value "6"} "6x"]]) + [:input.input-text {:value (:suffix export) + :placeholder (tr "workspace.options.export.suffix") + :data-value index + :on-change on-suffix-change + :on-key-down manage-key-down}] [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :on-change (partial on-scale-change index) - :value (:scale export)} - [:option {:value "0.5"} "0.5x"] - [:option {:value "0.75"} "0.75x"] - [:option {:value "1"} "1x"] - [:option {:value "1.5"} "1.5x"] - [:option {:value "2"} "2x"] - [:option {:value "4"} "4x"] - [:option {:value "6"} "6x"]]) - [:input.input-text {:value (:suffix export) - :placeholder (tr "workspace.options.export.suffix") - :on-change (partial on-suffix-change index) - :on-key-down manage-key-down}] - [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (d/name (:type export)) - :on-change (partial on-type-change index)} - [:option {:value "png"} "PNG"] - [:option {:value "jpeg"} "JPEG"] - [:option {:value "svg"} "SVG"] - [:option {:value "pdf"} "PDF"]] - [:div.delete-icon {:on-click (partial delete-export index)} - i/minus]])]) + :value (d/name (:type export)) + :on-change (partial on-type-change index)} + [:option {:value "png"} "PNG"] + [:option {:value "jpeg"} "JPEG"] + [:option {:value "svg"} "SVG"] + [:option {:value "pdf"} "PDF"]] + [:div.delete-icon {:on-click (partial delete-export index)} + i/minus]])]) - (when (or (= :multiple exports) (seq exports)) - [:div.btn-icon-dark.download-button - {:on-click (when-not in-progress? on-download) - :class (dom/classnames - :btn-disabled in-progress?) - :disabled in-progress?} - (if in-progress? - (tr "workspace.options.exporting-object") - (tr "workspace.options.export-object" (c (count shapes-with-exports))))])])) + (when (or (= :multiple exports) (seq exports)) + [:div.btn-icon-dark.download-button + {:on-click (when-not in-progress? on-download) + :class (dom/classnames + :btn-disabled in-progress?) + :disabled in-progress?} + (if in-progress? + (tr "workspace.options.exporting-object") + (tr "workspace.options.export-object" (c (count shapes-with-exports))))])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss new file mode 100644 index 0000000000..3c43629b87 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss @@ -0,0 +1,85 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-export { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .element-set-content { + display: flex; + flex-direction: column; + gap: $s-4; + margin-bottom: $s-4; + .multiple-exports { + display: flex; + align-items: center; + gap: $s-4; + .label { + @extend .mixed-bar; + } + .actions { + display: flex; + align-items: center; + gap: $s-4; + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + } + .element-group { + display: flex; + align-items: center; + gap: $s-4; + .input-wrapper { + display: flex; + align-items: center; + gap: $s-4; + .format-select { + width: $s-60; + padding: 0; + } + .size-select { + width: $s-60; + padding: 0; + } + .suffix-input { + @extend .input-element; + min-width: $s-92; + padding: 0 $s-8; + flex-grow: 1; + } + } + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .export-btn { + @extend .button-secondary; + @include tabTitleTipography; + height: $s-32; + width: $s-252; + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index 94631c9d4c..cedfbaa1bf 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -5,12 +5,15 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.fill + (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as clr] [app.common.data :as d] [app.common.types.shape.attrs :refer [default-color]] [app.main.data.workspace.colors :as dc] [app.main.store :as st] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] @@ -41,11 +44,17 @@ (mf/defc fill-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]} [{:keys [ids type values disable-remove?] :as props}] - (let [label (case type + (let [new-css-system (mf/use-ctx ctx/new-css-system) + label (case type :multiple (tr "workspace.options.selection-fill") :group (tr "workspace.options.group-fill") (tr "workspace.options.fill")) + state* (mf/use-state true) + open? (deref state*) + + toggle-content (mf/use-fn #(swap! state* not)) + ;; Excluding nil values values (d/without-nils values) @@ -103,20 +112,81 @@ disable-drag (mf/use-state false) on-focus (fn [_] - (reset! disable-drag true)) + (reset! disable-drag true)) on-blur (fn [_] (reset! disable-drag false))] (mf/use-layout-effect - (mf/deps hide-fill-on-export?) - #(let [checkbox (mf/ref-val checkbox-ref)] - (when checkbox + (mf/deps hide-fill-on-export?) + #(let [checkbox (mf/ref-val checkbox-ref)] + (when checkbox ;; Note that the "indeterminate" attribute only may be set by code, not as a static attribute. ;; See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#attr-indeterminate - (if (= hide-fill-on-export? :multiple) - (dom/set-attribute! checkbox "indeterminate" true) - (dom/remove-attribute! checkbox "indeterminate"))))) + (if (= hide-fill-on-export? :multiple) + (dom/set-attribute! checkbox "indeterminate" true) + (dom/remove-attribute! checkbox "indeterminate"))))) + + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title label + :class (stl/css :title-spacing-fill)} + + (when (and (not disable-remove?) (not (= :multiple (:fills values)))) + [:button {:class (stl/css :add-fill) + :on-click on-add} i/add-refactor])]] + + (when open? + [:div {:class (stl/css :element-content)} + (cond + (= :multiple (:fills values)) + [:div {:class (stl/css :element-set-options-group)} + [:div {:class (stl/css :group-label)} + (tr "settings.multiple")] + [:button {:on-click on-remove-all + :class (stl/css :remove-btn)} + i/remove-refactor]] + + (seq (:fills values)) + [:& h/sortable-container {} + (for [[index value] (d/enumerate (:fills values []))] + [:& color-row {:color {:color (:fill-color value) + :opacity (:fill-opacity value) + :id (:fill-color-ref-id value) + :file-id (:fill-color-ref-file value) + :gradient (:fill-color-gradient value)} + :key index + :index index + :title (tr "workspace.options.fill") + :on-change (on-change index) + :on-reorder (on-reorder index) + :on-detach (on-detach index) + :on-remove (on-remove index) + :disable-drag disable-drag + :on-focus on-focus + :select-on-focus (not @disable-drag) + :on-blur on-blur}])]) + + (when (or (= type :frame) + (and (= type :multiple) (some? (:hide-fill-on-export values)))) + [:div {:class (stl/css :checkbox)} + + [:label {:for "show-fill-on-export" + :class (stl/css-case :checked (not hide-fill-on-export?))} + [:span {:class (stl/css-case :check-mark true + :checked (not hide-fill-on-export?))} + (when(not hide-fill-on-export?) + i/status-tick-refactor)] + (tr "workspace.options.show-fill-on-export") + [:input {:type "checkbox" + :id "show-fill-on-export" + :ref checkbox-ref + :checked (not hide-fill-on-export?) + :on-change on-change-show-fill-on-export}]]])])] [:div.element-set [:div.element-set-title @@ -164,4 +234,4 @@ :on-change on-change-show-fill-on-export}] [:label {:for "show-fill-on-export"} - (tr "workspace.options.show-fill-on-export")]])]])) + (tr "workspace.options.show-fill-on-export")]])]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss new file mode 100644 index 0000000000..477343ed7c --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.scss @@ -0,0 +1,72 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-fill { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .element-content { + display: flex; + flex-direction: column; + gap: $s-12; + .element-set-options-group { + display: flex; + align-items: center; + gap: $s-4; + .group-label { + @extend .mixed-bar; + } + .remove-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .checkbox { + display: flex; + align-items: center; + margin-bottom: $s-8; + margin-top: calc(-1 * $s-4); + padding-left: $s-8; + input { + margin: 0; + } + label { + @include titleTipography; + display: flex; + align-items: center; + gap: $s-6; + cursor: pointer; + .check-mark { + @include flexCenter; + width: $s-16; + height: $s-16; + border-radius: $br-6; + background-color: var(--input-background-color); + &.checked { + background-color: var(--input-border-color-active); + svg { + @extend .button-icon-small; + stroke: var(--input-details-color); + } + } + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index 654244c60f..b1dc4cd9f8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.frame-grid + (:require-macros [app.main.style :as stl]) (:require [app.common.geom.grid :as gg] [app.main.data.workspace.grid :as dw] @@ -13,6 +14,8 @@ [app.main.ui.components.editable-select :refer [editable-select]] [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.components.select :refer [select]] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] @@ -32,17 +35,28 @@ (mf/defc grid-options {::mf/wrap [mf/memo]} [{:keys [shape-id index grid frame-width frame-height default-grid-params]}] - (let [on-change (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/set-frame-grid shape-id index %))) - on-remove (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/remove-frame-grid shape-id index))) - on-save-default (mf/use-fn #(st/emit! (dw/set-default-grid (:type %) (:params %)))) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + on-change (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/set-frame-grid shape-id index %))) + on-remove (mf/use-fn (mf/deps shape-id index) #(st/emit! (dw/remove-frame-grid shape-id index))) + on-save-default (mf/use-fn #(st/emit! (dw/set-default-grid (:type %) (:params %)))) - size-options (mf/use-memo get-size-options) - state (mf/use-state {:show-advanced-options false}) + size-options (mf/use-memo get-size-options) + state* (mf/use-state {:show-advanced-options false + :show-more-options false}) + state (deref state*) + + open? (:show-advanced-options state) + show-more-options? (:show-more-options state) + + is-hidden? (not (:display grid)) {:keys [type display params]} grid toggle-advanced-options - (mf/use-fn #(swap! state update :show-advanced-options not)) + (mf/use-fn #(swap! state* update :show-advanced-options not)) + + toggle-more-options + (mf/use-fn #(swap! state* update :show-more-options not)) handle-toggle-visibility (mf/use-fn @@ -119,146 +133,314 @@ (mf/use-fn (mf/deps grid) #(on-save-default grid)) is-default (= (->> grid :params) - (->> grid :type default-grid-params)) + (->> grid :type default-grid-params))] - open? (:show-advanced-options @state)] + (if new-css-system + [:div {:class (stl/css :grid-option)} + [:div {:class (stl/css :grid-title)} + [:div {:class (stl/css-case :option-row true + :hidden is-hidden?)} + [:button {:class (stl/css-case :show-options true + :selected open?) + :on-click toggle-advanced-options} + i/menu-refactor] + [:div {:class (stl/css :type-select-wrapper)} + [:& select + {:class (stl/css :grid-type-select) + :default-value type + :options [{:value :square :label (tr "workspace.options.grid.square")} + {:value :column :label (tr "workspace.options.grid.column")} + {:value :row :label (tr "workspace.options.grid.row")}] + :on-change handle-change-type}]] + (if (= type :square) + [:div {:class (stl/css :grid-size) + :title (tr "workspace.options.size")} + [:> numeric-input* {:min 0.01 + :value (or (:size params) "") + :no-validate true + :className (stl/css :numeric-input) + :on-change (handle-change :params :size)}]] - [:div.grid-option - [:div.grid-option-main {:style {:display (when open? "none")}} - [:button.custom-button {:class (when open? "is-active") - :on-click toggle-advanced-options} i/actions] + [:div {:class (stl/css :editable-select-wrapper)} + [:& editable-select {:value (:size params) + :type "number" + :class (stl/css :column-select) + :input-class (stl/css :numeric-input) + :min 1 + :options size-options + :placeholder "Auto" + :on-change handle-change-size}]])] - [:& select - {:class "flex-grow" - :default-value type - :options [{:value :square :label (tr "workspace.options.grid.square")} - {:value :column :label (tr "workspace.options.grid.column")} - {:value :row :label (tr "workspace.options.grid.row")}] - :on-change handle-change-type}] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click handle-toggle-visibility} + (if display i/shown-refactor i/hide-refactor)] + [:button {:class (stl/css :action-btn) + :on-click on-remove} + i/remove-refactor]]] - (if (= type :square) - [:div.input-element.pixels {:title (tr "workspace.options.size")} - [:> numeric-input* {:min 0.01 - :value (or (:size params) "") - :no-validate true - :on-change (handle-change :params :size)}]] + [:& advanced-options {:class (stl/css :grid-advanced-options) + :visible? open? + :on-close toggle-advanced-options} + ;; square + (when (= :square type) + [:div {:class (stl/css :square-row)} + [:div {:class (stl/css :advanced-row)} + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :on-change handle-change-color + :on-detach handle-detach-color}] + [:button {:class (stl/css :show-more-options) + :on-click toggle-more-options} + i/menu-refactor]] + (when show-more-options? + [:div {:class (stl/css :second-row)} + [:button {:class (stl/css-case :btn-options true + :disabled is-default) + :disabled is-default + :on-click handle-use-default} + [:span (tr "workspace.options.grid.params.use-default")]] + [:button {:class (stl/css-case :btn-options true + :disabled is-default) + :disabled is-default + :on-click handle-set-as-default} + [:span (tr "workspace.options.grid.params.set-default")]]])]) - [:& editable-select {:value (:size params) - :type "number" - :class "input-option" - :min 1 - :options size-options - :placeholder "Auto" - :on-change handle-change-size}]) + (when (or (= :column type) (= :row type)) + [:div {:class (stl/css :column-row)} + [:div {:class (stl/css :advanced-row)} + [:div {:class (stl/css :select-wrapper)} + [:& select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value (:type params) + :class (stl/css :orientation) + :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} + {:value :left :label (if (= type :row) + (tr "workspace.options.grid.params.type.top") + (tr "workspace.options.grid.params.type.left"))} + {:value :center :label (tr "workspace.options.grid.params.type.center")} + {:value :right :label (if (= type :row) + (tr "workspace.options.grid.params.type.bottom") + (tr "workspace.options.grid.params.type.right"))}] + :on-change (handle-change :params :type)}]] - [:div.grid-option-main-actions - [:button.custom-button {:on-click handle-toggle-visibility} (if display i/eye i/eye-closed)] - [:button.custom-button {:on-click on-remove} i/minus]]] + [:div {:class (stl/css :color-wrapper)} + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :on-change handle-change-color + :on-detach handle-detach-color}]]] - [:& advanced-options {:visible? open? :on-close toggle-advanced-options} - [:button.custom-button {:on-click toggle-advanced-options} i/actions] - (when (= :square type) - [:& input-row {:label (tr "workspace.options.grid.params.size") - :class "pixels" - :min 0.01 - :value (:size params) - :on-change (handle-change :params :size)}]) + [:div {:class (stl/css :advanced-row)} + [:div {:class (stl/css :height) + :title (if (= :row type) + (tr "workspace.options.grid.params.height") + (tr "workspace.options.grid.params.width"))} + [:span {:class (stl/css :icon-text)} + (if (= :row type) + "H" + "W")] + [:> numeric-input* {:placeholder "Auto" + :on-change handle-change-item-length + :nillable true + :className (stl/css :numeric-input) + :value (or (:item-length params) "")}]] - (when (= :row type) - [:& input-row {:label (tr "workspace.options.grid.params.rows") - :type :editable-select - :options size-options - :value (:size params) - :min 1 - :placeholder "Auto" - :on-change handle-change-size}]) + [:div {:class (stl/css :gutter) + :title (tr "workspace.options.grid.params.gutter")} + [:span {:class (stl/css-case :icon true + :rotated (= type :row))} i/gap-horizontal-refactor] + [:> numeric-input* {:placeholder "0" + :on-change (handle-change :params :gutter) + :nillable true + :className (stl/css :numeric-input) + :value (or (:gutter params) 0)}]] - (when (= :column type) - [:& input-row {:label (tr "workspace.options.grid.params.columns") - :type :editable-select - :options size-options - :value (:size params) - :min 1 - :placeholder "Auto" - :on-change handle-change-size}]) + [:div {:class (stl/css :margin) + :title (tr "workspace.options.grid.params.margin")} + [:span {:class (stl/css-case :icon true + :rotated (= type :column))} i/grid-margin-refactor] + [:> numeric-input* {:placeholder "0" + :on-change (handle-change :params :margin) + :nillable true + :className (stl/css :numeric-input) + :value (or (:margin params) 0)}]] - (when (#{:row :column} type) - [:& input-row {:label (tr "workspace.options.grid.params.type") - :type :select - :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} - {:value :left :label (if (= type :row) - (tr "workspace.options.grid.params.type.top") - (tr "workspace.options.grid.params.type.left"))} - {:value :center :label (tr "workspace.options.grid.params.type.center")} - {:value :right :label (if (= type :row) - (tr "workspace.options.grid.params.type.bottom") - (tr "workspace.options.grid.params.type.right"))}] - :value (:type params) - :on-change (handle-change :params :type)}]) + [:button {:class (stl/css :show-more-options) + :on-click toggle-more-options} + i/menu-refactor] + (when show-more-options? + [:div {:class (stl/css :more-options)} + [:button {:disabled is-default + :class (stl/css :option-btn) + :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] + [:button {:disabled is-default + :class (stl/css :option-btn) + :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]])]])]] - (when (#{:row :column} type) - [:& input-row-v2 - {:class "pixels" - :label (if (= :row type) - (tr "workspace.options.grid.params.height") - (tr "workspace.options.grid.params.width"))} - [:> numeric-input* - {:placeholder "Auto" - :value (or (:item-length params) "") - :nillable true - :on-change handle-change-item-length}]]) + [:div.grid-option + [:div.grid-option-main {:style {:display (when open? "none")}} + [:button.custom-button {:class (when open? "is-active") + :on-click toggle-advanced-options} i/actions] + [:& select + {:class "flex-grow" + :default-value type + :options [{:value :square :label (tr "workspace.options.grid.square")} + {:value :column :label (tr "workspace.options.grid.column")} + {:value :row :label (tr "workspace.options.grid.row")}] + :on-change handle-change-type}] - (when (#{:row :column} type) - [:* - [:& input-row {:label (tr "workspace.options.grid.params.gutter") - :class "pixels" - :value (:gutter params) - :min 0 - :nillable true - :default 0 - :placeholder "0" - :on-change (handle-change :params :gutter)}] - [:& input-row {:label (tr "workspace.options.grid.params.margin") - :class "pixels" - :min 0 - :nillable true - :default 0 - :placeholder "0" - :value (:margin params) - :on-change (handle-change :params :margin)}]]) + (if (= type :square) + [:div.input-element.pixels {:title (tr "workspace.options.size")} + [:> numeric-input* {:min 0.01 + :value (or (:size params) "") + :no-validate true + :on-change (handle-change :params :size)}]] - [:& color-row {:color (:color params) - :title (tr "workspace.options.grid.params.color") - :disable-gradient true - :on-change handle-change-color - :on-detach handle-detach-color}] - [:div.row-flex - [:button.btn-options {:disabled is-default - :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] - [:button.btn-options {:disabled is-default - :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]]]])) + [:& editable-select {:value (:size params) + :type "number" + :class "input-option" + :min 1 + :options size-options + :placeholder "Auto" + :on-change handle-change-size}]) + + [:div.grid-option-main-actions + [:button.custom-button {:on-click handle-toggle-visibility} (if display i/eye i/eye-closed)] + [:button.custom-button {:on-click on-remove} i/minus]]] + + [:& advanced-options {:visible? open? :on-close toggle-advanced-options} + [:button.custom-button {:on-click toggle-advanced-options} i/actions] + (when (= :square type) + [:& input-row {:label (tr "workspace.options.grid.params.size") + :class "pixels" + :min 0.01 + :value (:size params) + :on-change (handle-change :params :size)}]) + + (when (= :row type) + [:& input-row {:label (tr "workspace.options.grid.params.rows") + :type :editable-select + :options size-options + :value (:size params) + :min 1 + :placeholder "Auto" + :on-change handle-change-size}]) + + (when (= :column type) + [:& input-row {:label (tr "workspace.options.grid.params.columns") + :type :editable-select + :options size-options + :value (:size params) + :min 1 + :placeholder "Auto" + :on-change handle-change-size}]) + + (when (#{:row :column} type) + [:& input-row {:label (tr "workspace.options.grid.params.type") + :type :select + :options [{:value :stretch :label (tr "workspace.options.grid.params.type.stretch")} + {:value :left :label (if (= type :row) + (tr "workspace.options.grid.params.type.top") + (tr "workspace.options.grid.params.type.left"))} + {:value :center :label (tr "workspace.options.grid.params.type.center")} + {:value :right :label (if (= type :row) + (tr "workspace.options.grid.params.type.bottom") + (tr "workspace.options.grid.params.type.right"))}] + :value (:type params) + :on-change (handle-change :params :type)}]) + + (when (#{:row :column} type) + [:& input-row-v2 + {:class "pixels" + :label (if (= :row type) + (tr "workspace.options.grid.params.height") + (tr "workspace.options.grid.params.width"))} + [:> numeric-input* + {:placeholder "Auto" + :value (or (:item-length params) "") + :nillable true + :on-change handle-change-item-length}]]) + + (when (#{:row :column} type) + [:* + [:& input-row {:label (tr "workspace.options.grid.params.gutter") + :class "pixels" + :value (:gutter params) + :min 0 + :nillable true + :default 0 + :placeholder "0" + :on-change (handle-change :params :gutter)}] + [:& input-row {:label (tr "workspace.options.grid.params.margin") + :class "pixels" + :min 0 + :nillable true + :default 0 + :placeholder "0" + :value (:margin params) + :on-change (handle-change :params :margin)}]]) + + [:& color-row {:color (:color params) + :title (tr "workspace.options.grid.params.color") + :disable-gradient true + :on-change handle-change-color + :on-detach handle-detach-color}] + [:div.row-flex + [:button.btn-options {:disabled is-default + :on-click handle-use-default} (tr "workspace.options.grid.params.use-default")] + [:button.btn-options {:disabled is-default + :on-click handle-set-as-default} (tr "workspace.options.grid.params.set-default")]]]]))) (mf/defc frame-grid [{:keys [shape]}] - (let [id (:id shape) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + state* (mf/use-state true) + open? (deref state*) + + toggle-content (mf/use-fn #(swap! state* not)) + id (:id shape) saved-grids (mf/deref workspace-saved-grids) default-grid-params (mf/use-memo (mf/deps saved-grids) #(merge dw/default-grid-params saved-grids)) handle-create-grid (mf/use-fn (mf/deps id) #(st/emit! (dw/add-frame-grid id)))] - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.options.grid.grid-title")] - [:div.add-page {:on-click handle-create-grid} i/close]] - (when (seq (:grids shape)) - [:div.element-set-content - (for [[index grid] (map-indexed vector (:grids shape))] - [:& grid-options {:key (str id "-" index) - :shape-id id - :grid grid - :index index - :frame-width (:width shape) - :frame-height (:height shape) - :default-grid-params default-grid-params - }])])])) + (if new-css-system + [:div {:class (stl/css :element-set)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.options.grid.grid-title")} + + [:button {:on-click handle-create-grid + :class (stl/css :add-grid)} + i/add-refactor]] + + (when (and open? (seq (:grids shape))) + [:div {:class (stl/css :element-set-content)} + (for [[index grid] (map-indexed vector (:grids shape))] + [:& grid-options {:key (str id "-" index) + :shape-id id + :grid grid + :index index + :frame-width (:width shape) + :frame-height (:height shape) + :default-grid-params default-grid-params}])])] + + + [:div.element-set + [:div.element-set-title + [:span (tr "workspace.options.grid.grid-title")] + [:div.add-page {:on-click handle-create-grid} i/close]] + + (when (seq (:grids shape)) + [:div.element-set-content + (for [[index grid] (map-indexed vector (:grids shape))] + [:& grid-options {:key (str id "-" index) + :shape-id id + :grid grid + :index index + :frame-width (:width shape) + :frame-height (:height shape) + :default-grid-params default-grid-params}])])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss new file mode 100644 index 0000000000..3b46038922 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.scss @@ -0,0 +1,240 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .add-grid { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + .element-set-content { + display: flex; + flex-direction: column; + gap: $s-4; + .grid-option { + .grid-title { + display: flex; + align-items: center; + gap: $s-4; + .option-row { + display: flex; + align-items: center; + gap: $s-1; + border-radius: $br-8; + background-color: var(--input-details-color); + .show-options { + @extend .button-secondary; + height: $s-32; + width: $s-28; + border-radius: $br-8 0 0 $br-8; + svg { + @extend .button-icon; + } + &.selected { + background-color: var(--button-secondary-background-color-active); + color: var(--button-secondary-foreground-color-active); + svg { + stroke: var(--button-secondary-foreground-color-active); + } + } + } + .type-select-wrapper { + width: $s-96; + padding: 0; + border-radius: 0; + height: $s-32; + .grid-type-select { + border-radius: 0; + } + } + .grid-size { + @extend .asset-element; + width: $s-60; + margin: 0; + padding: 0; + padding-left: $s-8; + border-radius: 0 $br-8 $br-8 0; + .numeric-input { + @extend .input-base; + } + } + .editable-select-wrapper { + @extend .asset-element; + width: $s-60; + margin: 0; + padding: 0; + border: $s-1 solid var(--input-background-color); + position: relative; + border-radius: 0 $br-8 $br-8 0; + .column-select { + height: $s-32; + .numeric-input { + @extend .input-base; + margin: 0; + padding: 0; + } + span { + @include flexCenter; + svg { + @extend .button-icon; + } + } + } + } + + &.hidden { + .show-options, + .type-select-wrapper, + .editable-select-wrapper { + background-color: transparent; + border: $s-1 solid var(--input-border-color-disabled); + color: var(--input-foreground-color-disabled); + .column-select, + .grid-type-select { + background-color: transparent; + } + } + .grid-size { + background-color: transparent; + border: $s-1 solid var(--input-border-color-disabled); + color: var(--input-foreground-color-disabled); + + .icon { + stroke: var(--input-foreground-color-disabled); + } + .numeric-input { + color: var(--input-foreground-color-disabled); + } + } + .actions { + .hidden-btn, + .lock-btn { + background-color: transparent; + svg { + stroke: var(--input-foreground-color-disabled); + } + } + } + } + } + + .actions { + display: flex; + align-items: center; + gap: $s-4; + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + } + } + .grid-advanced-options { + display: flex; + flex-direction: column; + gap: $s-4; + margin-top: $s-4; + .column-row, + .square-row { + display: flex; + flex-direction: column; + gap: $s-4; + position: relative; + .advanced-row { + position: relative; + display: flex; + gap: $s-4; + .select-wrapper { + width: $s-92; + padding: 0; + } + .color-wrapper { + width: $s-156; + } + .show-more-options { + @extend .button-tertiary; + height: $s-32; + width: $s-32; + svg { + @extend .button-icon; + } + } + .height { + @extend .input-element; + width: $s-108; + padding-left: $s-8; + .icon-text { + padding-top: $s-1; + } + } + .gutter, + .margin { + @extend .input-element; + width: $s-108; + padding-left: $s-8; + .icon { + &.rotated svg { + transform: rotate(90deg); + } + } + } + .more-options { + @include menuShadow; + position: absolute; + top: $s-36; + right: 0; + display: flex; + flex-direction: column; + gap: $s-4; + width: $s-156; + max-height: $s-300; + padding: $s-2; + margin: 0 0 $s-40 0; + margin-top: $s-4; + border-radius: $br-8; + z-index: $z-index-3; + overflow-y: auto; + background-color: var(--menu-background-color); + .option-btn { + @include buttonStyle; + display: flex; + align-items: center; + height: $s-32; + padding: 0 $s-8; + border-radius: $br-6; + color: var(--menu-foreground-color); + + &:hover { + background-color: var(--menu-background-color-hover); + color: var(--menu-foreground-color-hover); + } + } + } + } + .second-row { + @extend .dropdown-wrapper; + left: unset; + right: 0; + width: $s-108; + .btn-options { + @include buttonStyle; + @extend .dropdown-element-base; + width: 100%; + } + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss index 62687e83ab..15229959b2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.scss @@ -12,28 +12,13 @@ height: $s-32; gap: $s-4; .select { - @extend .asset-element; width: $s-124; - margin: 0; padding: 0; - border: 1px solid var(--input-background-color); } .input { @extend .input-element; width: $s-60; padding-left: $s-8; - border: 1px solid var(--input-background-color); - .icon { - @include flexCenter; - margin-right: $s-4; - } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - } } .actions { display: flex; @@ -54,13 +39,13 @@ &.hidden { .select { background-color: transparent; - border: 1px solid var(--input-border-color-disabled); + border: $s-1 solid var(--input-border-color-disabled); color: var(--input-foreground-color-disabled); } .input { background-color: transparent; - border: 1px solid var(--input-border-color-disabled); - color: var(--input-foreground-color-disable); + border: $s-1 solid var(--input-border-color-disabled); + color: var(--input-foreground-color-disabled); .icon { stroke: var(--input-foreground-color-disabled); diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss index 428c85cc0b..a8408e936b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.scss @@ -8,7 +8,6 @@ .element-set { .element-title { - margin-right: $s-12; .title-spacing-layout { margin: 0; } @@ -74,74 +73,16 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } &.disabled { - background-color: var(--input-background-color-disabled); - border: 1px solid var(--input-border-color-disabled); - color: var(--input-foreground-color-disabled); - .numeric-input { - pointer-events: none; - cursor: default; - color: var(--input-foreground-color-disabled); - } - .icon { - svg { - stroke: var(--input-foreground-color-disabled); - } - } + @extend .disabled-input; } } .row-gap { @extend .input-element; width: $s-108; padding-left: $s-8; - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } &.disabled { - background-color: var(--input-background-color-disabled); - border: 1px solid var(--input-border-color-disabled); - color: var(--input-foreground-color-disabled); - .numeric-input { - pointer-events: none; - cursor: default; - color: var(--input-foreground-color-disabled); - } - .icon { - svg { - stroke: var(--input-foreground-color-disabled); - } - } + @extend .disabled-input; } } } @@ -158,23 +99,6 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } } } .paddings-multiple { @@ -185,23 +109,6 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } } } } @@ -224,15 +131,4 @@ } } } - .grid-layout-menu { - background-color: antiquewhite; - .first-row { - .direction-edit { - .direction { - } - .edit { - } - } - } - } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index 7a54130e98..1b2a2fc4ed 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -518,108 +518,109 @@ :id :static-position}] [:& radio-button {:value "absolute" :id :absolute-position}]]])]] - [:div {:class (stl/css :flex-element-menu)} - [:div {:class (stl/css :first-row)} - [:& element-behaviour {:fill? is-layout-child? - :auto? is-layout-container? - :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) - :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) - :on-change-behaviour-h-refactor on-change-behaviour-h - :on-change-behaviour-v-refactor on-change-behaviour-v - :on-change on-change-behaviour}] - (when is-absolute? - [:div {:class (stl/css-case :z-index-wrapper true) - :title "z-index"} - - [:span {:class (stl/css :icon-text)} - "Z"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change #(on-change-z-index %) - :nillable true - :value (:layout-item-z-index values)}]])] - - (when (and is-layout-child? is-flex-parent?) - [:div {:class (stl/css :second-row)} - [:& align-self-row {:is-col? is-col? - :align-self align-self - :on-changer set-align-self-refactor}]]) - - (when is-layout-child? - [:div {:class (stl/css :third-row)} - [:& margin-section {:values values - :change-margin-style change-margin-style - :on-margin-change on-margin-change}]]) - - [:div {:class (stl/css :forth-row)} - [:div {:class (stl/css :advanced-options)} - (when (= (:layout-item-h-sizing values) :fill) - [:div {:class (stl/css :horizontal-fill)} - [:div {:class (stl/css :layout-item-min-w) - :title (tr "workspace.options.layout-item.layout-item-min-w")} + (when open? + [:div {:class (stl/css :flex-element-menu)} + [:div {:class (stl/css :first-row)} + [:& element-behaviour {:fill? is-layout-child? + :auto? is-layout-container? + :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) + :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) + :on-change-behaviour-h-refactor on-change-behaviour-h + :on-change-behaviour-v-refactor on-change-behaviour-v + :on-change on-change-behaviour}] + (when is-absolute? + [:div {:class (stl/css :z-index-wrapper) + :title "z-index"} [:span {:class (stl/css :icon-text)} - "MIN W"] + "Z"] [:> numeric-input* {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true :placeholder "--" :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-min-w) - :value (get values :layout-item-min-w) - :nillable true}]] + :on-change #(on-change-z-index %) + :nillable true + :value (:layout-item-z-index values)}]])] - [:div {:class (stl/css :layout-item-max-w) - :title (tr "workspace.options.layout-item.layout-item-max-w")} - [:span {:class (stl/css :icon-text)} - "MAX W"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-max-w) - :value (get values :layout-item-max-w) - :nillable true}]]]) - (when (= (:layout-item-v-sizing values) :fill) - [:div {:class (stl/css :vertical-fill)} - [:div {:class (stl/css :layout-item-min-h) - :title (tr "workspace.options.layout-item.layout-item-min-h")} + (when (and is-layout-child? is-flex-parent?) + [:div {:class (stl/css :second-row)} + [:& align-self-row {:is-col? is-col? + :align-self align-self + :on-changer set-align-self-refactor}]]) - [:span {:class (stl/css :icon-text)} - "MIN H"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-min-h) - :value (get values :layout-item-min-h) - :nillable true}]] + (when is-layout-child? + [:div {:class (stl/css :third-row)} + [:& margin-section {:values values + :change-margin-style change-margin-style + :on-margin-change on-margin-change}]]) - [:div {:class (stl/css :layout-item-max-h) - :title (tr "workspace.options.layout-item.layout-item-max-h")} + [:div {:class (stl/css :forth-row)} + [:div {:class (stl/css :advanced-options)} + (when (= (:layout-item-h-sizing values) :fill) + [:div {:class (stl/css :horizontal-fill)} + [:div {:class (stl/css :layout-item-min-w) + :title (tr "workspace.options.layout-item.layout-item-min-w")} - [:span {:class (stl/css :icon-text)} - "MAX H"] - [:> numeric-input* - {:className (stl/css :numeric-input) - :no-validate true - :min 0 - :data-wrap true - :placeholder "--" - :on-focus #(dom/select-target %) - :on-change (partial on-size-change :layout-item-max-h) - :value (get values :layout-item-max-h) - :nillable true}]]])]]]] + [:span {:class (stl/css :icon-text)} + "MIN W"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-min-w) + :value (get values :layout-item-min-w) + :nillable true}]] + + [:div {:class (stl/css :layout-item-max-w) + :title (tr "workspace.options.layout-item.layout-item-max-w")} + [:span {:class (stl/css :icon-text)} + "MAX W"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-max-w) + :value (get values :layout-item-max-w) + :nillable true}]]]) + (when (= (:layout-item-v-sizing values) :fill) + [:div {:class (stl/css :vertical-fill)} + [:div {:class (stl/css :layout-item-min-h) + :title (tr "workspace.options.layout-item.layout-item-min-h")} + + [:span {:class (stl/css :icon-text)} + "MIN H"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-min-h) + :value (get values :layout-item-min-h) + :nillable true}]] + + [:div {:class (stl/css :layout-item-max-h) + :title (tr "workspace.options.layout-item.layout-item-max-h")} + + [:span {:class (stl/css :icon-text)} + "MAX H"] + [:> numeric-input* + {:className (stl/css :numeric-input) + :no-validate true + :min 0 + :data-wrap true + :placeholder "--" + :on-focus #(dom/select-target %) + :on-change (partial on-size-change :layout-item-max-h) + :value (get values :layout-item-max-h) + :nillable true}]]])]]])] [:div.element-set @@ -667,12 +668,12 @@ [:div.layout-row [:div.row-title.sizing "Sizing"] [:& element-behaviour {:fill? is-layout-child? - :auto? is-layout-container? - :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) - :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) - :on-change-behaviour-h-refactor on-change-behaviour-h - :on-change-behaviour-v-refactor on-change-behaviour-v - :on-change on-change-behaviour}]] + :auto? is-layout-container? + :layout-item-v-sizing (or (:layout-item-v-sizing values) :fix) + :layout-item-h-sizing (or (:layout-item-h-sizing values) :fix) + :on-change-behaviour-h-refactor on-change-behaviour-h + :on-change-behaviour-v-refactor on-change-behaviour-v + :on-change on-change-behaviour}]] (when (and is-layout-child? is-flex-parent?) [:div.layout-row @@ -713,7 +714,4 @@ :on-focus #(dom/select-target %) :on-change (partial on-size-change item) :value (get values item) - :nillable true}]]])]]]]] - ) - - )) + :nillable true}]]])]]]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss index 3c61bc7dfd..1c8dbf1805 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.scss @@ -50,27 +50,11 @@ width: $s-92; } } - &.wrap { - } } .z-index-wrapper { @extend .input-element; width: $s-124; padding-left: $s-8; - .icon-text { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - padding-top: $s-2; - } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } } } .second-row { @@ -107,23 +91,6 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } } } .margin-multiple { @@ -137,23 +104,6 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } } } } @@ -176,21 +126,10 @@ width: $s-108; padding-left: $s-8; .icon-text { - display: flex; - align-items: center; - height: $s-32; + justify-content: flex-start; width: $s-80; - margin-right: $s-4; padding-top: $s-2; } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index e0735e8e9e..6ca9156ba9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -392,7 +392,8 @@ :id :horiz}]]]) (when (options :size) [:div {:class (stl/css :size)} - [:div {:class (stl/css :height) + [:div {:class (stl/css-case :width true + :disabled disabled-width-sizing?) :title (tr "workspace.options.width")} [:span {:class (stl/css :icon-text)} "W"] [:> numeric-input* {:min 0.01 @@ -402,7 +403,8 @@ :disabled disabled-width-sizing? :className (stl/css :numeric-input) :value (:width values)}]] - [:div {:class (stl/css :height) + [:div {:class (stl/css-case :height true + :disabled disabled-height-sizing?) :title (tr "workspace.options.height")} [:span {:class (stl/css :icon-text)} "H"] [:> numeric-input* {:min 0.01 @@ -422,7 +424,8 @@ i/unlock-refactor)]]) (when (options :position) [:div {:class (stl/css :position)} - [:div {:class (stl/css :x-position) + [:div {:class (stl/css-case :x-position true + :disabled disabled-position-x?) :title (tr "workspace.options.x")} [:span {:class (stl/css :icon-text)} "X"] [:> numeric-input* {:no-validate true @@ -432,7 +435,8 @@ :className (stl/css :numeric-input) :value (:x values)}]] - [:div {:class (stl/css :y-position) + [:div {:class (stl/css-case :y-position true + :disabled disabled-position-y?) :title (tr "workspace.options.y")} [:span {:class (stl/css :icon-text)} "Y"] [:> numeric-input* {:no-validate true diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss index 955f16705c..ffda32b629 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss @@ -40,28 +40,11 @@ } } .custom-select-dropdown { - @include menuShadow; - position: absolute; - top: $s-32; - left: 0; - max-height: 300px; + @extend .dropdown-wrapper; width: $s-252; - padding: $s-2; - margin: 0; - margin-top: $s-4; - border-radius: $br-8; - z-index: $z-index-3; - overflow-y: auto; - background-color: var(--menu-background-color); .dropdown-element { - @include titleTipography; - display: flex; - align-items: center; - gap: $s-8; - height: $s-32; - padding: 0 $s-8; - border-radius: $br-6; - cursor: pointer; + @extend .dropdown-element-base; + &.disabled { pointer-events: none; cursor: default; @@ -119,25 +102,11 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .icon { - @include flexCenter; - width: $s-12; - height: $s-32; - margin-right: $s-4; - } - .icon-text { - @include flexCenter; - height: $s-32; - margin-right: $s-4; + y .icon-text { padding-top: $s-1; } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); + &.disabled { + @extend .disabled-input; } } .lock-size-btn { @@ -160,25 +129,11 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .icon { - @include flexCenter; - height: $s-32; - width: $s-12; - margin-right: $s-4; - } .icon-text { - @include flexCenter; - height: $s-32; - margin-right: $s-4; padding-top: $s-1; } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); + &.disabled { + @extend .disabled-input; } } } @@ -192,28 +147,8 @@ width: $s-108; padding-left: $s-8; .icon-text { - @include flexCenter; - height: $s-32; - margin-right: $s-4; padding-top: $s-1; } - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } } .radius { display: flex; @@ -226,25 +161,6 @@ @extend .input-element; width: $s-108; padding-left: $s-8; - .icon { - @include flexCenter; - height: $s-32; - margin-right: $s-4; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - padding: $s-1 $s-2; - color: var(--input-foreground-color-active); - } } .radius-4 { display: grid; @@ -254,14 +170,6 @@ @extend .input-element; width: $s-52; padding-left: $s-8; - .numeric-input { - @include removeInputStyle; - @include titleTipography; - height: $s-32; - width: 100%; - margin: 0; - color: var(--input-foreground-color-active); - } } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index f1f2ec21ee..93448e0ff4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.shadow + (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as clr] [app.common.data :as d] @@ -16,6 +17,9 @@ [app.main.data.workspace.undo :as dwu] [app.main.store :as st] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.select :refer [select]] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.common :refer [advanced-options]] @@ -47,7 +51,8 @@ (mf/defc shadow-entry [{:keys [ids index value on-reorder disable-drag? on-blur open-state-ref]}] - (let [basic-offset-x-ref (mf/use-ref nil) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + basic-offset-x-ref (mf/use-ref nil) basic-offset-y-ref (mf/use-ref nil) basic-blur-ref (mf/use-ref nil) @@ -56,7 +61,9 @@ adv-blur-ref (mf/use-ref nil) adv-spread-ref (mf/use-ref nil) - shadow-style (dm/str (:style value)) + shadow-style (if new-css-system + (:style value) + (dm/str (:style value))) shadow-id (:id value) open-status-ref (mf/with-memo [open-state-ref shadow-id] @@ -66,12 +73,9 @@ on-remove-shadow (mf/use-fn - (mf/deps ids) - (fn [event] - (let [index (-> (dom/get-current-target event) - (dom/get-data "index") - (parse-long))] - (st/emit! (dch/update-shapes ids #(update % :shadow remove-shadow-by-index index)))))) + (mf/deps ids index) + (fn [] + (st/emit! (dch/update-shapes ids #(update % :shadow remove-shadow-by-index index))))) on-drop (mf/use-fn @@ -105,66 +109,147 @@ (dom/set-value! update-node value)))))) update-color - (fn [index] - (fn [color] - (st/emit! (dch/update-shapes - ids - #(assoc-in % [:shadow index :color] color))))) + (mf/use-fn + (mf/deps ids index) + (fn [color] + (st/emit! (dch/update-shapes + ids + #(assoc-in % [:shadow index :color] color))))) detach-color - (fn [index] - (fn [_color _opacity] - (when-not (string? (:color value)) - (st/emit! (dch/update-shapes - ids - #(assoc-in % [:shadow index :color] - (dissoc (:color value) :id :file-id))))))) + (mf/use-fn + (mf/deps ids index) + (fn [_color _opacity] + (when-not (string? (:color value)) + (st/emit! (dch/update-shapes + ids + #(assoc-in % [:shadow index :color] + (dissoc (:color value) :id :file-id))))))) toggle-visibility - (fn [index] - (fn [] - (st/emit! (dch/update-shapes ids #(update-in % [:shadow index :hidden] not))))) + (mf/use-fn + (mf/deps ids index) + (fn [] + (st/emit! (dch/update-shapes ids #(update-in % [:shadow index :hidden] not))))) on-toggle-open-shadow (fn [] - (swap! open-state-ref update shadow-id not))] - [:* - [:div.shadow-option {:class (dom/classnames + (swap! open-state-ref update shadow-id not)) + + on-type-change + (mf/use-fn + (mf/deps ids index) + (fn [event] + (let [value (if new-css-system + (keyword event) + (-> event dom/get-target-val d/read-string))] + (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))) + + type-options [{:value "drop-shadow" :label (tr "workspace.options.shadow-options.drop-shadow")} + {:value "inner-shadow" :label (tr "workspace.options.shadow-options.inner-shadow")}]] + + (if new-css-system + [:div {:class (stl/css-case :shadow-element true :dnd-over-top (= (:over dprops) :top) :dnd-over-bot (= (:over dprops) :bot)) - :ref dref} - [:div.shadow-option-main {:style {:display (when open-shadow "none")}} - [:div.element-set-actions-button - {:on-click on-toggle-open-shadow} - i/actions] + :ref dref} + [:div {:class (stl/css :basic-options)} + [:div {:class (stl/css :shadow-info)} + [:button {:class (stl/css :more-options) + :on-click on-toggle-open-shadow} + i/menu-refactor] + [:div {:class (stl/css :type-select)} + [:& select + {:class (stl/css :shadow-type-select) + :default-value (d/name shadow-style) + :options type-options + :on-change on-type-change}]]] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click toggle-visibility} + (if (:hidden value) + i/hide-refactor + i/shown-refactor)] + [:button {:class (stl/css :action-btn) + :on-click on-remove-shadow} + i/remove-refactor]]] - [:select.input-select - {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :default-value shadow-style - :on-change (fn [event] - (let [value (-> event dom/get-target dom/get-value d/read-string)] - (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} - [:option {:value ":drop-shadow" - :selected (when (= shadow-style ":drop-shadow") "selected")} - (tr "workspace.options.shadow-options.drop-shadow")] - [:option {:value ":inner-shadow" - :selected (when (= shadow-style ":inner-shadow") "selected")} - (tr "workspace.options.shadow-options.inner-shadow")]] + (when open-shadow + [:& advanced-options {:class (stl/css :shadow-advanced-options) + :visible? open-shadow + :on-close on-toggle-open-shadow} - [:div.shadow-option-main-actions - [:div.element-set-actions-button {:on-click (toggle-visibility index)} - (if (:hidden value) i/eye-closed i/eye)] - [:div.element-set-actions-button - {:data-index index - :on-click on-remove-shadow} - i/minus]]] + [:div {:class (stl/css :first-row)} + [:div {:class (stl/css :offset-x-input) + :title (tr "workspace.options.shadow-options.offsetx")} + [:span {:class (stl/css :input-label)} + "X"] + [:> numeric-input* {:className (stl/css :numeric-input) + :ref adv-offset-x-ref + :no-validate true + :placeholder "--" + :on-change (update-attr index :offset-x basic-offset-x-ref) + :on-blur on-blur + :value (:offset-x value)}]] - [:& advanced-options {:visible? open-shadow - :on-close on-toggle-open-shadow} - [:div.color-data + [:div {:class (stl/css :blur-input) + :title (tr "workspace.options.shadow-options.blur")} + [:span {:class (stl/css :input-label)} + (tr "workspace.options.shadow-options.blur")] + [:> numeric-input* {:ref adv-blur-ref + :className (stl/css :numeric-input) + :no-validate true + :placeholder "--" + :on-change (update-attr index :blur basic-blur-ref) + :on-blur on-blur + :min 0 + :value (:blur value)}]] + + [:div {:class (stl/css :spread-input) + :title (tr "workspace.options.shadow-options.spread")} + [:span {:class (stl/css :input-label)} + (tr "workspace.options.shadow-options.spread")] + [:> numeric-input* {:ref adv-spread-ref + :className (stl/css :numeric-input) + :no-validate true + :placeholder "--" + :on-change (update-attr index :spread) + :on-blur on-blur + :value (:spread value)}]]] + + + [:div {:class (stl/css :second-row)} + [:div {:class (stl/css :offset-y-input) + :title (tr "workspace.options.shadow-options.offsety")} + [:span {:class (stl/css :input-label)} + "Y"] + [:> numeric-input* {:ref adv-offset-y-ref + :className (stl/css :numeric-input) + :no-validate true + :placeholder "--" + :on-change (update-attr index :offset-y basic-offset-y-ref) + :on-blur on-blur + :value (:offset-y value)}]] + [:& color-row {:color (if (string? (:color value)) + ;; Support for old format colors + {:color (:color value) :opacity (:opacity value)} + (:color value)) + :title (tr "workspace.options.shadow-options.color") + :disable-gradient true + :on-change update-color + :on-detach detach-color + :on-open #(st/emit! (dwu/start-undo-transaction :color-row)) + :on-close #(st/emit! (dwu/commit-undo-transaction :color-row))}]]])] + + [:div.shadow-option {:class (dom/classnames + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + [:div.shadow-option-main {:style {:display (when open-shadow "none")}} [:div.element-set-actions-button {:on-click on-toggle-open-shadow} i/actions] + [:select.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element :default-value shadow-style @@ -176,70 +261,106 @@ (tr "workspace.options.shadow-options.drop-shadow")] [:option {:value ":inner-shadow" :selected (when (= shadow-style ":inner-shadow") "selected")} - (tr "workspace.options.shadow-options.inner-shadow")]]] + (tr "workspace.options.shadow-options.inner-shadow")]] - [:div.row-grid-2 - [:div.input-element {:title (tr "workspace.options.shadow-options.offsetx")} - [:> numeric-input* {:ref adv-offset-x-ref - :no-validate true - :placeholder "--" - :on-change (update-attr index :offset-x basic-offset-x-ref) - :on-blur on-blur - :value (:offset-x value)}] - [:span.after (tr "workspace.options.shadow-options.offsetx")]] + [:div.shadow-option-main-actions + [:div.element-set-actions-button {:on-click (toggle-visibility index)} + (if (:hidden value) i/eye-closed i/eye)] + [:div.element-set-actions-button + {:data-index index + :on-click on-remove-shadow} + i/minus]]] - [:div.input-element {:title (tr "workspace.options.shadow-options.offsety")} - [:> numeric-input* {:ref adv-offset-y-ref - :no-validate true - :placeholder "--" - :on-change (update-attr index :offset-y basic-offset-y-ref) - :on-blur on-blur - :value (:offset-y value)}] - [:span.after (tr "workspace.options.shadow-options.offsety")]]] + [:& advanced-options {:visible? open-shadow + :on-close on-toggle-open-shadow} + [:div.color-data + [:div.element-set-actions-button + {:on-click on-toggle-open-shadow} + i/actions] + [:select.input-select + {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :default-value shadow-style + :on-change (fn [event] + (let [value (-> event dom/get-target dom/get-value d/read-string)] + (st/emit! (dch/update-shapes ids #(assoc-in % [:shadow index :style] value)))))} + [:option {:value ":drop-shadow" + :selected (when (= shadow-style ":drop-shadow") "selected")} + (tr "workspace.options.shadow-options.drop-shadow")] + [:option {:value ":inner-shadow" + :selected (when (= shadow-style ":inner-shadow") "selected")} + (tr "workspace.options.shadow-options.inner-shadow")]]] - [:div.row-grid-2 - [:div.input-element {:title (tr "workspace.options.shadow-options.blur")} - [:> numeric-input* {:ref adv-blur-ref - :no-validate true - :placeholder "--" - :on-change (update-attr index :blur basic-blur-ref) - :on-blur on-blur - :min 0 - :value (:blur value)}] - [:span.after (tr "workspace.options.shadow-options.blur")]] + [:div.row-grid-2 + [:div.input-element {:title (tr "workspace.options.shadow-options.offsetx")} + [:> numeric-input* {:ref adv-offset-x-ref + :no-validate true + :placeholder "--" + :on-change (update-attr index :offset-x basic-offset-x-ref) + :on-blur on-blur + :value (:offset-x value)}] + [:span.after (tr "workspace.options.shadow-options.offsetx")]] - [:div.input-element {:title (tr "workspace.options.shadow-options.spread")} - [:> numeric-input* {:ref adv-spread-ref - :no-validate true - :placeholder "--" - :on-change (update-attr index :spread) - :on-blur on-blur - :value (:spread value)}] - [:span.after (tr "workspace.options.shadow-options.spread")]]] + [:div.input-element {:title (tr "workspace.options.shadow-options.offsety")} + [:> numeric-input* {:ref adv-offset-y-ref + :no-validate true + :placeholder "--" + :on-change (update-attr index :offset-y basic-offset-y-ref) + :on-blur on-blur + :value (:offset-y value)}] + [:span.after (tr "workspace.options.shadow-options.offsety")]]] - [:div.color-row-wrap - [:& color-row {:color (if (string? (:color value)) - ;; Support for old format colors - {:color (:color value) :opacity (:opacity value)} - (:color value)) - :title (tr "workspace.options.shadow-options.color") - :disable-gradient true - :on-change (update-color index) - :on-detach (detach-color index) - :on-open #(st/emit! (dwu/start-undo-transaction :color-row)) - :on-close #(st/emit! (dwu/commit-undo-transaction :color-row))}]]]]])) + [:div.row-grid-2 + [:div.input-element {:title (tr "workspace.options.shadow-options.blur")} + [:> numeric-input* {:ref adv-blur-ref + :no-validate true + :placeholder "--" + :on-change (update-attr index :blur basic-blur-ref) + :on-blur on-blur + :min 0 + :value (:blur value)}] + [:span.after (tr "workspace.options.shadow-options.blur")]] + + [:div.input-element {:title (tr "workspace.options.shadow-options.spread")} + [:> numeric-input* {:ref adv-spread-ref + :no-validate true + :placeholder "--" + :on-change (update-attr index :spread) + :on-blur on-blur + :value (:spread value)}] + [:span.after (tr "workspace.options.shadow-options.spread")]]] + + [:div.color-row-wrap + [:& color-row {:color (if (string? (:color value)) + ;; Support for old format colors + {:color (:color value) :opacity (:opacity value)} + (:color value)) + :title (tr "workspace.options.shadow-options.color") + :disable-gradient true + :on-change update-color + :on-detach detach-color + :on-open #(st/emit! (dwu/start-undo-transaction :color-row)) + :on-close #(st/emit! (dwu/commit-undo-transaction :color-row))}]]]]))) (mf/defc shadow-menu {::mf/wrap-props false} [props] - (let [ids (unchecked-get props "ids") + (let [new-css-system (mf/use-ctx ctx/new-css-system) + ids (unchecked-get props "ids") type (unchecked-get props "type") values (unchecked-get props "values") shadows (:shadow values []) open-state-ref (mf/with-memo [] (l/atom {})) - disable-drag* (mf/use-state false) - disable-drag? (deref disable-drag*) + + state* (mf/use-state {:show-content true + :disable-drag false}) + + state (deref state*) + open? (:show-content state) + disable-drag? (:disable-drag state) + + toggle-content + (mf/use-fn #(swap! state* update :show-content not)) on-remove-all (mf/use-fn @@ -255,43 +376,84 @@ on-blur (mf/use-fn - #(reset! disable-drag* false)) + #(swap! state* assoc :disable-drag false)) on-add-shadow (mf/use-fn (mf/deps ids) #(st/emit! (dc/add-shadow ids (create-shadow))))] - [:div.element-set.shadow-options - [:div.element-set-title - [:span - (case type - :multiple (tr "workspace.options.shadow-options.title.multiple") - :group (tr "workspace.options.shadow-options.title.group") - (tr "workspace.options.shadow-options.title"))] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (case type + :multiple (tr "workspace.options.shadow-options.title.multiple") + :group (tr "workspace.options.shadow-options.title.group") + (tr "workspace.options.shadow-options.title")) + :class (stl/css :title-spacing-shadow)} - (when-not (= :multiple shadows) - [:div.add-page {:on-click on-add-shadow} i/close])] + (when-not (= :multiple shadows) + [:button {:class (stl/css :add-shadow) + :on-click on-add-shadow} i/add-refactor])]] - (cond - (= :multiple shadows) - [:div.element-set-content - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click on-remove-all} - i/minus]]]] + (when open? + (cond + (= :multiple shadows) + [:div {:class (stl/css :element-set-content)} + [:div {:class (stl/css :multiple-shadows)} + [:div {:class (stl/css :label)} (tr "settings.multiple")] + [:div {:class (stl/css :actions)} + [:button {:class (stl/css :action-btn) + :on-click on-remove-all} + i/remove-refactor]]]] - (seq shadows) - [:& h/sortable-container {} - [:div.element-set-content - (for [[index value] (d/enumerate shadows)] - [:& shadow-entry - {:key (dm/str "shadow-" index) - :ids ids - :value value - :on-reorder handle-reorder - :disable-drag? disable-drag? - :on-blur on-blur - :index index - :open-state-ref open-state-ref}])]])])) + (seq shadows) + [:& h/sortable-container {} + [:div {:class (stl/css :element-set-content)} + (for [[index value] (d/enumerate shadows)] + [:& shadow-entry + {:key (dm/str "shadow-" index) + :ids ids + :value value + :on-reorder handle-reorder + :disable-drag? disable-drag? + :on-blur on-blur + :index index + :open-state-ref open-state-ref}])]]))] + + [:div.element-set.shadow-options + [:div.element-set-title + [:span + (case type + :multiple (tr "workspace.options.shadow-options.title.multiple") + :group (tr "workspace.options.shadow-options.title.group") + (tr "workspace.options.shadow-options.title"))] + + (when-not (= :multiple shadows) + [:div.add-page {:on-click on-add-shadow} i/close])] + + (cond + (= :multiple shadows) + [:div.element-set-content + [:div.element-set-options-group + [:div.element-set-label (tr "settings.multiple")] + [:div.element-set-actions + [:div.element-set-actions-button {:on-click on-remove-all} + i/minus]]]] + + (seq shadows) + [:& h/sortable-container {} + [:div.element-set-content + (for [[index value] (d/enumerate shadows)] + [:& shadow-entry + {:key (dm/str "shadow-" index) + :ids ids + :value value + :on-reorder handle-reorder + :disable-drag? disable-drag? + :on-blur on-blur + :index index + :open-state-ref open-state-ref}])]])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss new file mode 100644 index 0000000000..2c7e02144c --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.scss @@ -0,0 +1,130 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-shadow { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .element-set-content { + display: flex; + flex-direction: column; + gap: $s-4; + .multiple-shadows { + display: flex; + align-items: center; + gap: $s-4; + .label { + @extend .mixed-bar; + } + .actions { + display: flex; + align-items: center; + gap: $s-4; + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + } + .shadow-element { + display: flex; + flex-direction: column; + gap: $s-4; + .basic-options { + display: flex; + align-items: center; + gap: $s-4; + .shadow-info { + display: flex; + align-items: center; + gap: $s-1; + width: $s-188; + .more-options { + @extend .button-secondary; + height: $s-32; + width: $s-28; + border-radius: $br-8 0 0 $br-8; + svg { + @extend .button-icon; + } + &.selected { + background-color: var(--button-secondary-background-color-active); + color: var(--button-secondary-foreground-color-active); + svg { + stroke: var(--button-secondary-foreground-color-active); + } + } + } + .type-select { + padding: 0; + border-radius: 0 $br-8 $br-8 0; + flex-grow: 1; + .shadow-type-select { + flex-grow: 1; + border-radius: 0 $br-8 $br-8 0; + } + } + } + .actions { + display: flex; + align-items: center; + gap: $s-4; + .action-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + } + .shadow-advanced-options { + display: flex; + flex-direction: column; + gap: $s-4; + .first-row, + .second-row { + display: flex; + align-items: center; + gap: $s-4; + .offset-x-input, + .blur-input, + .spread-input, + .offset-y-input { + @extend .input-element; + width: $s-60; + min-width: $s-60; + padding: 0 0 0 $s-8; + input { + width: $s-32; + } + } + .blur-input, + .spread-input { + width: $s-92; + .input-label { + width: $s-44; + } + } + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs index a00e21a3ed..4deded69dd 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs @@ -5,12 +5,15 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.stroke + (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as clr] [app.common.data :as d] [app.common.data.macros :as dm] [app.main.data.workspace.colors :as dc] [app.main.store :as st] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.stroke-row :refer [stroke-row]] @@ -35,11 +38,17 @@ (mf/defc stroke-menu {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "show-caps"]))]} [{:keys [ids type values show-caps disable-stroke-style] :as props}] - (let [label (case type + (let [new-css-system (mf/use-ctx ctx/new-css-system) + label (case type :multiple (tr "workspace.options.selection-stroke") :group (tr "workspace.options.group-stroke") (tr "workspace.options.stroke")) + state* (mf/use-state true) + open? (deref state*) + + toggle-content (mf/use-fn #(swap! state* not)) + handle-change-stroke-color (mf/use-callback (mf/deps ids) @@ -47,14 +56,25 @@ (fn [color] (st/emit! (dc/change-stroke ids color index))))) + on-color-change-refactor + (mf/use-callback + (mf/deps ids) + (fn [index color] + (st/emit! (dc/change-stroke ids color index)))) + handle-remove (mf/use-callback (mf/deps ids) (fn [index] (fn [] (st/emit! (dc/remove-stroke ids index))))) + on-remove-refactor + (mf/use-callback + (mf/deps ids) + (fn [index] + (st/emit! (dc/remove-stroke ids index)))) - handle-remove-remove-all + handle-remove-all (fn [_] (st/emit! (dc/remove-all-strokes ids))) @@ -67,6 +87,14 @@ (assoc :id nil :file-id nil))] (st/emit! (dc/change-stroke ids color index)))))) + on-color-detach-refactor + (mf/use-callback + (mf/deps ids) + (fn [index color] + (let [color (-> color + (assoc :id nil :file-id nil))] + (st/emit! (dc/change-stroke ids color index))))) + handle-reorder (mf/use-callback (mf/deps ids) @@ -82,6 +110,13 @@ (d/read-string))] (st/emit! (dc/change-stroke ids {:stroke-style value} index))))) + on-stroke-style-change-refactor + (mf/use-callback + (mf/deps ids) + (fn [index value] + (st/emit! (dc/change-stroke ids {:stroke-style value} index)))) + + on-stroke-alignment-change (fn [index] (fn [event] @@ -91,12 +126,24 @@ (when-not (str/empty? value) (st/emit! (dc/change-stroke ids {:stroke-alignment value} index)))))) + on-stroke-alignment-change-refactor + (fn [index value] + (when-not (str/empty? value) + (st/emit! (dc/change-stroke ids {:stroke-alignment value} index)))) + + on-stroke-width-change (fn [index] (fn [value] (when-not (str/empty? value) (st/emit! (dc/change-stroke ids {:stroke-width value} index))))) + on-stroke-width-change-refactor + (fn [index value] + (when-not (str/empty? value) + (st/emit! (dc/change-stroke ids {:stroke-width value} index)))) + + open-caps-select (fn [caps-state] (fn [event] @@ -147,48 +194,96 @@ disable-drag (mf/use-state false) on-focus (fn [_] - (reset! disable-drag true)) + (reset! disable-drag true)) on-blur (fn [_] (reset! disable-drag false))] - [:div.element-set - [:div.element-set-title - [:span label] - [:div.add-page {:on-click on-add-stroke} i/close]] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title label + :class (stl/css :title-spacing-fill)} - [:div.element-set-content - (cond - (= :multiple (:strokes values)) - [:div.element-set-options-group - [:div.element-set-label (tr "settings.multiple")] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click handle-remove-remove-all} - i/minus]]] + [:button {:class (stl/css :add-stroke) + :on-click on-add-stroke} i/add-refactor]]] + (when open? + [:div {:class (stl/css :element-content)} + (cond + (= :multiple (:strokes values)) + [:div {:class (stl/css :element-set-options-group)} + [:div {:class (stl/css :group-label)} + (tr "settings.multiple")] + [:button {:on-click handle-remove-all + :class (stl/css :remove-btn)} + i/remove-refactor]] + (seq (:strokes values)) + [:& h/sortable-container {} + (for [[index value] (d/enumerate (:strokes values []))] + [:& stroke-row {:key (dm/str "stroke-" index) + :stroke value + :title (tr "workspace.options.stroke-color") + :index index + :show-caps show-caps + :on-color-change on-color-change-refactor + :on-color-detach on-color-detach-refactor + :on-stroke-width-change on-stroke-width-change-refactor + :on-stroke-style-change on-stroke-style-change-refactor + :on-stroke-alignment-change on-stroke-alignment-change-refactor + :open-caps-select open-caps-select + :close-caps-select close-caps-select + :on-stroke-cap-start-change on-stroke-cap-start-change + :on-stroke-cap-end-change on-stroke-cap-end-change + :on-stroke-cap-switch on-stroke-cap-switch + :on-remove on-remove-refactor + :on-reorder (handle-reorder index) + :disable-drag disable-drag + :on-focus on-focus + :select-on-focus (not @disable-drag) + :on-blur on-blur + :disable-stroke-style disable-stroke-style}])])])] - (seq (:strokes values)) - [:& h/sortable-container {} - (for [[index value] (d/enumerate (:strokes values []))] - [:& stroke-row {:key (dm/str "stroke-" index) - :stroke value - :title (tr "workspace.options.stroke-color") - :index index - :show-caps show-caps - :on-color-change handle-change-stroke-color - :on-color-detach handle-detach - :on-stroke-width-change on-stroke-width-change - :on-stroke-style-change on-stroke-style-change - :on-stroke-alignment-change on-stroke-alignment-change - :open-caps-select open-caps-select - :close-caps-select close-caps-select - :on-stroke-cap-start-change on-stroke-cap-start-change - :on-stroke-cap-end-change on-stroke-cap-end-change - :on-stroke-cap-switch on-stroke-cap-switch - :on-remove handle-remove - :on-reorder (handle-reorder index) - :disable-drag disable-drag - :on-focus on-focus - :select-on-focus (not @disable-drag) - :on-blur on-blur - :disable-stroke-style disable-stroke-style}])])]])) + [:div.element-set + [:div.element-set-title + [:span label] + [:div.add-page {:on-click on-add-stroke} i/close]] + + [:div.element-set-content + (cond + (= :multiple (:strokes values)) + [:div.element-set-options-group + [:div.element-set-label (tr "settings.multiple")] + [:div.element-set-actions + [:div.element-set-actions-button {:on-click handle-remove-all} + i/minus]]] + + + (seq (:strokes values)) + [:& h/sortable-container {} + (for [[index value] (d/enumerate (:strokes values []))] + [:& stroke-row {:key (dm/str "stroke-" index) + :stroke value + :title (tr "workspace.options.stroke-color") + :index index + :show-caps show-caps + :on-color-change handle-change-stroke-color + :on-color-detach handle-detach + :on-stroke-width-change on-stroke-width-change + :on-stroke-style-change on-stroke-style-change + :on-stroke-alignment-change on-stroke-alignment-change + :open-caps-select open-caps-select + :close-caps-select close-caps-select + :on-stroke-cap-start-change on-stroke-cap-start-change + :on-stroke-cap-end-change on-stroke-cap-end-change + :on-stroke-cap-switch on-stroke-cap-switch + :on-remove handle-remove + :on-reorder (handle-reorder index) + :disable-drag disable-drag + :on-focus on-focus + :select-on-focus (not @disable-drag) + :on-blur on-blur + :disable-stroke-style disable-stroke-style}])])]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss new file mode 100644 index 0000000000..ce1d49eae4 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.scss @@ -0,0 +1,42 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-stroke { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + + .element-content { + display: flex; + flex-direction: column; + gap: $s-12; + .element-set-options-group { + display: flex; + align-items: center; + gap: $s-4; + .group-label { + @extend .mixed-bar; + } + .remove-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs index 4db6b521bf..8423f5b013 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs @@ -5,10 +5,13 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.svg-attrs + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.main.data.workspace.changes :as dch] [app.main.store :as st] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.util.dom :as dom] @@ -16,7 +19,8 @@ [rumext.v2 :as mf])) (mf/defc attribute-value [{:keys [attr value on-change on-delete] :as props}] - (let [handle-change + (let [new-css-system (mf/use-ctx ctx/new-css-system) + handle-change (mf/use-callback (mf/deps attr on-change) (fn [event] @@ -29,32 +33,62 @@ (on-delete attr))) label (->> attr last d/name)] - [:div.element-set-content - (if (string? value) - [:div.row-flex.row-flex-removable - [:& input-row {:label label - :type :text - :class "large" - :value (str value) - :on-change handle-change}] - [:div.element-set-actions - [:div.element-set-actions-button {:on-click handle-delete} - i/minus]]] + (if new-css-system + [:* + (if (string? value) + [:div {:class (stl/css :attr-content)} + [:span {:class (stl/css :attr-name)} label] + [:div {:class (stl/css :attr-input)} + [:input {:value value + :class "input-text" + :on-change handle-change}]] + [:div {:class (stl/css :attr-actions)} + [:button {:class (stl/css :attr-action-btn) + :on-click handle-delete} + i/remove-refactor]]] + [:div {:class (stl/css :attr-row)} + [:span {:class (stl/css :attr-title)} + (str (d/name (last attr)))] - [:* - [:div.element-set-title - {:style {:border-bottom "1px solid #444" :margin-bottom "0.5rem"}} - [:span (str (d/name (last attr)))]] + (for [[key value] value] + [:& attribute-value {:key key + :attr (conj attr key) + :value value + :on-change on-change + :on-delete on-delete}])])] - (for [[key value] value] - [:& attribute-value {:key key - :attr (conj attr key) - :value value - :on-change on-change - :on-delete on-delete}])])])) + + [:div.element-set-content + (if (string? value) + [:div.row-flex.row-flex-removable + [:& input-row {:label label + :type :text + :class "large" + :value (str value) + :on-change handle-change}] + [:div.element-set-actions + [:div.element-set-actions-button {:on-click handle-delete} + i/minus]]] + + [:* + [:div.element-set-title + {:style {:border-bottom "1px solid #444" :margin-bottom "0.5rem"}} + [:span (str (d/name (last attr)))]] + + (for [[key value] value] + [:& attribute-value {:key key + :attr (conj attr key) + :value value + :on-change on-change + :on-delete on-delete}])])]))) (mf/defc svg-attrs-menu [{:keys [ids values]}] - (let [handle-change + (let [new-css-system (mf/use-ctx ctx/new-css-system) + state* (mf/use-state true) + open? (deref state*) + + toggle-content (mf/use-fn #(swap! state* not)) + handle-change (mf/use-callback (mf/deps ids) (fn [attr value] @@ -75,18 +109,32 @@ (empty? (get-in shape [:svg-attrs :style])) (update :svg-attrs dissoc :style))] shape))] - (st/emit! (dch/update-shapes ids update-fn))))) - - ] + (st/emit! (dch/update-shapes ids update-fn)))))] (when-not (empty? (:svg-attrs values)) - [:div.element-set - [:div.element-set-title - [:span (tr "workspace.sidebar.options.svg-attrs.title")]] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-set-title)} + [:& title-bar {:collapsable? true + :collapsed? (not open?) + :on-collapsed toggle-content + :title (tr "workspace.sidebar.options.svg-attrs.title") + :class (stl/css :title-spacing-svg-attrs)}]] + [:div {:class (stl/css :element-set-content)} + (for [[attr-key attr-value] (:svg-attrs values)] + [:& attribute-value {:key attr-key + :attr [attr-key] + :value attr-value + :on-change handle-change + :on-delete handle-delete}])]] - (for [[attr-key attr-value] (:svg-attrs values)] - [:& attribute-value {:key attr-key - :attr [attr-key] - :value attr-value - :on-change handle-change - :on-delete handle-delete}])]))) + [:div.element-set + [:div.element-set-title + [:span (tr "workspace.sidebar.options.svg-attrs.title")]] + + (for [[attr-key attr-value] (:svg-attrs values)] + [:& attribute-value {:key attr-key + :attr [attr-key] + :value attr-value + :on-change handle-change + :on-delete handle-delete}])])))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss new file mode 100644 index 0000000000..5495e17be9 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.scss @@ -0,0 +1,52 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-set-content { + display: flex; + flex-direction: column; + gap: $s-4; + .attr-row { + display: flex; + gap: $s-4; + .attr-title { + @include tabTitleTipography; + border-bottom: $s-1 solid var(--color-foreground-secondary); + } + } + + .attr-content { + display: flex; + gap: $s-4; + .attr-name { + @include titleTipography; + @include twoLineTextEllipsis; + width: $s-92; + margin: auto $s-4; + margin-right: 0; + } + .attr-input { + @extend .input-element; + width: $s-124; + padding-left: $s-8; + } + .attr-actions { + display: flex; + gap: $s-4; + .attr-action-btn { + @extend .button-tertiary; + width: $s-28; + height: $s-32; + svg { + @extend .button-icon; + } + } + } + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index a7f85fe0ff..436eb28dc8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.text + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.text :as txt] @@ -16,6 +17,8 @@ [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons nilable-option]] + [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry typography-options]] @@ -27,147 +30,309 @@ (mf/defc text-align-options [{:keys [values on-change on-blur] :as props}] (let [{:keys [text-align]} values + new-css-system (mf/use-ctx ctx/new-css-system) + handle-change - (fn [_ new-align] - (on-change {:text-align new-align}) - (when (some? on-blur) (on-blur)))] + (mf/use-fn + (fn [value] + (let [new-align (if new-css-system + value + (-> (dom/get-current-target value) + (dom/get-data "value")))] + (on-change {:text-align new-align}) + (when (some? on-blur) (on-blur)))))] ;; --- Align - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-left" (sc/get-tooltip :text-align-left)) - :class (dom/classnames :current (= "left" text-align)) - :on-click #(handle-change % "left")} - i/text-align-left] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-center" (sc/get-tooltip :text-align-center)) - :class (dom/classnames :current (= "center" text-align)) - :on-click #(handle-change % "center")} - i/text-align-center] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-right" (sc/get-tooltip :text-align-right)) - :class (dom/classnames :current (= "right" text-align)) - :on-click #(handle-change % "right")} - i/text-align-right] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.text-align-justify" (sc/get-tooltip :text-align-justify)) - :class (dom/classnames :current (= "justify" text-align)) - :on-click #(handle-change % "justify")} - i/text-align-justify]])) + (if new-css-system + [:div {:class (stl/css :align-options)} + [:& radio-buttons {:selected text-align + :on-change handle-change + :name "align-text-options"} + [:& radio-button {:value "left" + :id "text-align-left" + :title (tr "workspace.options.text-options.text-align-left" (sc/get-tooltip :text-align-left)) + :icon i/text-align-left-refactor}] + [:& radio-button {:value "center" + :id "text-align-center" + :title (tr "workspace.options.text-options.text-align-center" (sc/get-tooltip :text-align-center)) + :icon i/text-align-center-refactor}] + [:& radio-button {:value "right" + :id "text-align-right" + :title (tr "workspace.options.text-options.text-align-right" (sc/get-tooltip :text-align-right)) + :icon i/text-align-right-refactor}] + [:& radio-button {:value "justify" + :id "text-align-justify" + :title (tr "workspace.options.text-options.text-align-justify" (sc/get-tooltip :text-align-justify)) + :icon i/text-justify-refactor}]]] + [:div.align-icons + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.text-align-left" (sc/get-tooltip :text-align-left)) + :class (dom/classnames :current (= "left" text-align)) + :data-value "left" + :on-click handle-change} + i/text-align-left] + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.text-align-center" (sc/get-tooltip :text-align-center)) + :class (dom/classnames :current (= "center" text-align)) + :data-value "center" + :on-click handle-change} + i/text-align-center] + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.text-align-right" (sc/get-tooltip :text-align-right)) + :class (dom/classnames :current (= "right" text-align)) + :data-value "right" + :on-click handle-change} + i/text-align-right] + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.text-align-justify" (sc/get-tooltip :text-align-justify)) + :class (dom/classnames :current (= "justify" text-align)) + :data-value "justify" + :on-click handle-change} + i/text-align-justify]]))) (mf/defc text-direction-options [{:keys [values on-change on-blur] :as props}] - (let [direction (:text-direction values) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + direction (:text-direction values) handle-change - (fn [_ val] - (on-change {:text-direction val}) - (when (some? on-blur) (on-blur)))] + (mf/use-fn + (mf/deps direction) + (fn [value] + (let [val (if new-css-system + value + (-> (dom/get-current-target value) + (dom/get-data "value"))) + dir (if (= val direction) + "none" + val)] + (on-change {:text-direction dir}) + (when (some? on-blur) (on-blur)))))] + + (if new-css-system + [:div {:class (stl/css :text-direction-options)} + [:& radio-buttons {:selected direction + :on-change handle-change + :name "text-direction-options"} + [:& nilable-option {:value "ltr" + :id "ltr-text-direction" + :title (tr "workspace.options.text-options.direction-ltr") + :icon i/text-ltr-refactor}] + [:& nilable-option {:value "rtl" + :id "rtl-text-direction" + :title (tr "workspace.options.text-options.direction-rtl") + :icon i/text-rtl-refactor}]]] ;; --- Align [:div.align-icons [:span.tooltip.tooltip-bottom-left {:alt (tr "workspace.options.text-options.direction-ltr") :class (dom/classnames :current (= "ltr" direction)) - :on-click #(handle-change % "ltr")} + :data-value "ltr" + :on-click handle-change} i/text-direction-ltr] [:span.tooltip.tooltip-bottom-left {:alt (tr "workspace.options.text-options.direction-rtl") :class (dom/classnames :current (= "rtl" direction)) - :on-click #(handle-change % "rtl")} - i/text-direction-rtl]])) + :data-value "rtl" + :on-click handle-change} + i/text-direction-rtl]]))) (mf/defc vertical-align [{:keys [values on-change on-blur] :as props}] (let [{:keys [vertical-align]} values + new-css-system (mf/use-ctx ctx/new-css-system) vertical-align (or vertical-align "top") handle-change - (fn [_ new-align] - (on-change {:vertical-align new-align}) - (when (some? on-blur) (on-blur)))] + (mf/use-fn + (fn [value] + (let [new-align (if new-css-system + value + (-> (dom/get-current-target value) + (dom/get-data "value")))] + (on-change {:vertical-align new-align}) + (when (some? on-blur) (on-blur)))))] - [:div.align-icons - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.align-top") - :class (dom/classnames :current (= "top" vertical-align)) - :on-click #(handle-change % "top")} - i/align-top] - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.align-middle") - :class (dom/classnames :current (= "center" vertical-align)) - :on-click #(handle-change % "center")} - i/align-middle] - [:span.tooltip.tooltip-bottom-left - {:alt (tr "workspace.options.text-options.align-bottom") - :class (dom/classnames :current (= "bottom" vertical-align)) - :on-click #(handle-change % "bottom")} - i/align-bottom]])) + (if new-css-system + [:div {:class (stl/css :vertical-align-options)} + [:& radio-buttons {:selected vertical-align + :on-change handle-change + :name "vertical-align-text-options"} + [:& radio-button {:value "top" + :id "vertical-text-align-top" + :title (tr "workspace.options.text-options.align-top") + :icon i/text-top-refactor}] + [:& radio-button {:value "center" + :id "vertical-text-align-center" + :title (tr "workspace.options.text-options.align-middle") + :icon i/text-middle-refactor}] + [:& radio-button {:value "bottom" + :id "vertical-text-align-bottom" + :title (tr "workspace.options.text-options.align-bottom") + :icon i/text-bottom-refactor}]]] + [:div.align-icons + [:span.tooltip.tooltip-bottom-left + {:alt (tr "workspace.options.text-options.align-top") + :class (dom/classnames :current (= "top" vertical-align)) + :data-value "top" + :on-click handle-change} + i/align-top] + [:span.tooltip.tooltip-bottom-left + {:alt (tr "workspace.options.text-options.align-middle") + :class (dom/classnames :current (= "center" vertical-align)) + :data-value "center" + :on-click handle-change} + i/align-middle] + [:span.tooltip.tooltip-bottom-left + {:alt (tr "workspace.options.text-options.align-bottom") + :class (dom/classnames :current (= "bottom" vertical-align)) + :data-value "bottom" + :on-click handle-change} + i/align-bottom]]))) (mf/defc grow-options [{:keys [ids values on-blur] :as props}] - (let [grow-type (:grow-type values) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + grow-type (:grow-type values) + handle-change-grow - (fn [_ grow-type] - (let [uid (js/Symbol)] + (mf/use-fn + (mf/deps ids) + (fn [value] + (let [uid (js/Symbol) + + grow-type (if new-css-system + (keyword value) + (-> (dom/get-current-target value) + (dom/get-data "value") + (keyword)))] (st/emit! (dwu/start-undo-transaction uid) (dch/update-shapes ids #(assoc % :grow-type grow-type))) ;; We asynchronously commit so every sychronous event is resolved first and inside the transaction (ts/schedule #(st/emit! (dwu/commit-undo-transaction uid)))) - (when (some? on-blur) (on-blur)))] + (when (some? on-blur) (on-blur))))] - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.grow-fixed") - :class (dom/classnames :current (= :fixed grow-type)) - :on-click #(handle-change-grow % :fixed)} - i/auto-fix] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.grow-auto-width") - :class (dom/classnames :current (= :auto-width grow-type)) - :on-click #(handle-change-grow % :auto-width)} - i/auto-width] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.grow-auto-height") - :class (dom/classnames :current (= :auto-height grow-type)) - :on-click #(handle-change-grow % :auto-height)} - i/auto-height]])) + (if new-css-system + [:div {:class (stl/css :grow-options)} + [:& radio-buttons {:selected (d/name grow-type) + :on-change handle-change-grow + :name "grow-text-options"} + [:& radio-button {:value "fixed" + :id "text-fixed-grow" + :title (tr "workspace.options.text-options.grow-fixed") + :icon i/text-fixed-refactor}] + [:& radio-button {:value "auto-width" + :id "text-auto-width-grow" + :title (tr "workspace.options.text-options.grow-auto-width") + :icon i/text-auto-width-refactor}] + [:& radio-button {:value "auto-height" + :id "text-auto-height-grow" + :title (tr "workspace.options.text-options.grow-auto-height") + :icon i/text-auto-height-refactor}]]] + + [:div.align-icons + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.grow-fixed") + :class (dom/classnames :current (= :fixed grow-type)) + :data-value "fixed" + :on-click handle-change-grow} + i/auto-fix] + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.grow-auto-width") + :data-value "auto-width" + :class (dom/classnames :current (= :auto-width grow-type)) + :on-click handle-change-grow} + i/auto-width] + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.grow-auto-height") + :class (dom/classnames :current (= :auto-height grow-type)) + :data-value "auto-height" + :on-click handle-change-grow} + i/auto-height]]))) (mf/defc text-decoration-options [{:keys [values on-change on-blur] :as props}] - (let [text-decoration (or (:text-decoration values) "none") + (let [new-css-system (mf/use-ctx ctx/new-css-system) + text-decoration (or (:text-decoration values) "none") handle-change - (fn [_ type] - (on-change {:text-decoration type}) - (when (some? on-blur) (on-blur)))] - [:div.align-icons - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.none") - :class (dom/classnames :current (= "none" text-decoration)) - :on-click #(handle-change % "none")} - i/minus] + (mf/use-fn + (mf/deps text-decoration) + (fn [value] + (let [val (if new-css-system + value + (-> (dom/get-current-target value) + (dom/get-data "value"))) + decoration (if (= val text-decoration) + "none" + val)] + (on-change {:text-decoration decoration}) + (when (some? on-blur) (on-blur)))))] + (if new-css-system + [:div {:class (stl/css :text-decoration-options)} + [:& radio-buttons {:selected text-decoration + :on-change handle-change + :name "text-decoration-options"} + [:& nilable-option {:value "underline" + :id "underline-text-decoration" + :title (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) + :icon i/text-underlined-refactor}] + [:& nilable-option {:value "line-through" + :id "line-through-text-decoration" + :title (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) + :icon i/text-stroked-refactor}]]] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) - :class (dom/classnames :current (= "underline" text-decoration)) - :on-click #(handle-change % "underline")} - i/underline] + [:div.align-icons + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.none") + :class (dom/classnames :current (= "none" text-decoration)) + :data-value "none" + :on-click handle-change} + i/minus] - [:span.tooltip.tooltip-bottom - {:alt (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) - :class (dom/classnames :current (= "line-through" text-decoration)) - :on-click #(handle-change % "line-through")} - i/strikethrough]])) + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.underline" (sc/get-tooltip :underline)) + :class (dom/classnames :current (= "underline" text-decoration)) + :data-value "underline" + :on-click handle-change} + i/underline] + + [:span.tooltip.tooltip-bottom + {:alt (tr "workspace.options.text-options.strikethrough" (sc/get-tooltip :line-through)) + :class (dom/classnames :current (= "line-through" text-decoration)) + :data-value "line-through" + :on-click handle-change} + i/strikethrough]]))) (mf/defc text-menu {::mf/wrap [mf/memo]} [{:keys [ids type values] :as props}] - (let [file-id (mf/use-ctx ctx/current-file-id) - typographies (mf/deref refs/workspace-file-typography) - shared-libs (mf/deref refs/workspace-libraries) - label (case type - :multiple (tr "workspace.options.text-options.title-selection") - :group (tr "workspace.options.text-options.title-group") - (tr "workspace.options.text-options.title")) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + file-id (mf/use-ctx ctx/current-file-id) + typographies (mf/deref refs/workspace-file-typography) + shared-libs (mf/deref refs/workspace-libraries) + label (case type + :multiple (tr "workspace.options.text-options.title-selection") + :group (tr "workspace.options.text-options.title-group") + (tr "workspace.options.text-options.title")) + + state* (mf/use-state {:main-menu true + :more-options false}) + state (deref state*) + main-menu-open? (:main-menu state) + more-options-open? (:more-options state) + + toggle-main-menu + (mf/use-fn + (mf/deps main-menu-open?) + #(swap! state* assoc-in [:main-menu] (not main-menu-open?))) + + toggle-more-options + (mf/use-fn + (mf/deps more-options-open?) + #(swap! state* assoc-in [:more-options] (not more-options-open?))) + + typography-id (:typography-ref-id values) + typography-file (:typography-ref-file values) emit-update! (mf/use-callback @@ -188,17 +353,17 @@ (mf/deps values file-id shared-libs) (fn [] (cond - (and (:typography-ref-id values) - (not= (:typography-ref-id values) :multiple) - (not= (:typography-ref-file values) file-id)) + (and typography-id + (not= typography-id :multiple) + (not= typography-file file-id)) (-> shared-libs - (get-in [(:typography-ref-file values) :data :typographies (:typography-ref-id values)]) - (assoc :file-id (:typography-ref-file values))) + (get-in [typography-file :data :typographies typography-id]) + (assoc :file-id typography-file)) - (and (:typography-ref-id values) - (not= (:typography-ref-id values) :multiple) - (= (:typography-ref-file values) file-id)) - (get typographies (:typography-ref-id values))))) + (and typography-id + (not= typography-id :multiple) + (= typography-file file-id)) + (get typographies typography-id)))) on-convert-to-typography (fn [_] @@ -243,39 +408,87 @@ (let [node (dom/get-element-by-class "public-DraftEditor-content")] (dom/focus! node))))))}] - [:div.element-set - [:div.element-set-title - [:span label] - (when (and (not typography) (not multiple?)) - [:div.add-page {:on-click on-convert-to-typography} i/close])] + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? true + :collapsed? (not main-menu-open?) + :on-collapsed toggle-main-menu + :title label + :class (stl/css :title-spacing-text)} + (when (and (not typography) (not multiple?)) + [:button {:class (stl/css :add-typography) + :on-click on-convert-to-typography} + i/add-refactor])]] - (cond - typography - [:& typography-entry {:typography typography - :local? (= (:typography-ref-file values) file-id) - :file (get shared-libs (:typography-ref-file values)) - :on-detach handle-detach-typography - :on-change handle-change-typography}] + (when main-menu-open? + [:div {:class (stl/css :element-content)} + (cond + typography + [:& typography-entry {:typography typography + :local? (= typography-file file-id) + :file (get shared-libs typography-file) + :on-detach handle-detach-typography + :on-change handle-change-typography}] - (= (:typography-ref-id values) :multiple) - [:div.multiple-typography - [:div.multiple-typography-text (tr "workspace.libraries.text.multiple-typography")] - [:div.multiple-typography-button {:on-click handle-detach-typography - :title (tr "workspace.libraries.text.multiple-typography-tooltip")} i/unchain]] + (= typography-id :multiple) + [:div {:class (stl/css :multiple-typography)} + [:span {:class (stl/css :multiple-text)} (tr "workspace.libraries.text.multiple-typography")] + [:div {:class (stl/css :multiple-typography-button) + :on-click handle-detach-typography + :title (tr "workspace.libraries.text.multiple-typography-tooltip")} + i/detach-refactor]] - :else - [:> typography-options opts]) + :else + [:> typography-options opts]) - [:div.element-set-content + [:div {:class (stl/css :text-align-options)} + [:> text-align-options opts] + [:> grow-options opts] + [:button {:class (stl/css :more-options) + :on-click toggle-more-options} + i/menu-refactor]] - [:div.row-flex - [:> text-align-options opts] - [:> vertical-align opts]] + (when more-options-open? + [:div {:class (stl/css :text-decoration-options)} + [:> vertical-align opts] + [:> text-decoration-options opts] + [:> text-direction-options opts]])])] - [:div.row-flex - [:> text-decoration-options opts] - [:> text-direction-options opts]] - [:div.row-flex - [:> grow-options opts] - [:div.align-icons]]]])) + [:div.element-set + [:div.element-set-title + [:span label] + (when (and (not typography) (not multiple?)) + [:div.add-page {:on-click on-convert-to-typography} i/close])] + + (cond + typography + [:& typography-entry {:typography typography + :local? (= typography-file file-id) + :file (get shared-libs typography-file) + :on-detach handle-detach-typography + :on-change handle-change-typography}] + + (= typography-id :multiple) + [:div.multiple-typography + [:div.multiple-typography-text (tr "workspace.libraries.text.multiple-typography")] + [:div.multiple-typography-button {:on-click handle-detach-typography + :title (tr "workspace.libraries.text.multiple-typography-tooltip")} i/unchain]] + + :else + [:> typography-options opts]) + + [:div.element-set-content + + [:div.row-flex + [:> text-align-options opts] + [:> vertical-align opts]] + + [:div.row-flex + [:> text-decoration-options opts] + [:> text-direction-options opts]] + + [:div.row-flex + [:> grow-options opts] + [:div.align-icons]]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss new file mode 100644 index 0000000000..e142d4d5ac --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.scss @@ -0,0 +1,71 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.element-set { + .element-title { + .add-typography { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .element-content { + display: flex; + flex-direction: column; + gap: $s-4; + .multiple-typography { + display: flex; + align-items: center; + padding: 0 $s-8; + gap: $s-4; + border-radius: $s-8; + background-color: var(--input-background-color); + height: $s-32; + flex-grow: 1; + .multiple-text { + @include titleTipography; + flex-grow: 1; + color: var(--input-foreground-color-active); + } + .multiple-typography-button { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .text-align-options { + display: flex; + gap: $s-4; + .align-options, + .text-direction-options, + .vertical-align-options, + .grow-options, + .text-decoration-options { + height: $s-32; + } + .more-options { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + .text-decoration-options { + display: flex; + gap: $s-4; + } + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index 5a90e4ab01..55d64f06c1 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.menus.typography - (:require-macros [app.main.style :refer [css]]) + (:require-macros [app.main.style :as stl]) (:require ["react-virtualized" :as rvt] [app.common.data :as d] @@ -73,15 +73,14 @@ (dom/scroll-into-view! element)))))) (if new-css-system - [:div {:class (css :font-wrapper) + [:div {:class (stl/css :font-wrapper) :style style :ref item-ref :on-click on-click} - [:div {:class (dom/classnames - (css :font-item) true - (css :selected) current?)} - [:span {:class (css :label)} (:name font)] - [:span {:class (css :icon)} (when current? i/tick-refactor)]]] + [:div {:class (stl/css-case :font-item true + :selected current?)} + [:span {:class (stl/css :label)} (:name font)] + [:span {:class (stl/css :icon)} (when current? i/tick-refactor)]]] [:div.font-item {:ref item-ref :style style @@ -186,9 +185,9 @@ (.scrollToPosition ^js inst offset))))) (if new-css-system - [:div {:class (css :font-selector)} - [:div {:class (css :font-selector-dropdown)} - [:div {:class (css :header)} + [:div {:class (stl/css :font-selector)} + [:div {:class (stl/css :font-selector-dropdown)} + [:div {:class (stl/css :header)} [:& search-bar {:on-change on-filter-change :value (:term @state) :placeholder (tr "workspace.options.search-font")}] @@ -202,7 +201,7 @@ :on-click on-select-and-close :current? (= (:id font) (:id @selected))}])])] - [:div {:class (css :fonts-list)} + [:div {:class (stl/css :fonts-list)} [:> rvt/AutoSizer {} (fn [props] (let [width (unchecked-get props "width") @@ -341,7 +340,7 @@ :show-recent show-recent}]) [:div - {:class (css :font-option) + {:class (stl/css :font-option) :on-click #(reset! open-selector? true)} (cond (= :multiple font-id) @@ -349,31 +348,30 @@ (some? font) [:* - [:span {:class (css :name)} + [:span {:class (stl/css :name)} (:name font)] - [:span {:class (css :icon)} + [:span {:class (stl/css :icon)} i/arrow-refactor]] :else (tr "dashboard.fonts.deleted-placeholder"))] - - [:div {:class (css :font-modifiers)} - [:div {:class (css :font-size-options)} - (let [sizes [8 9 10 11 12 14 16 18 24 36 48 72] - basic-size-options (map (fn [number] - {:value (dm/str number) :key (dm/str "size-" number) :label (dm/str number)}) sizes) - size-options (if (= font-size :multiple) - (conj {:value :key :mulitple-sizes :multiple :label "--"} basic-size-options) - basic-size-options)] - - [:& select - {:class (css :font-size-select) - :default-value (attr->string font-size) + [:div {:class (stl/css :font-modifiers)} + [:div {:class (stl/css :font-size-options)} + (let [size-options [8 9 10 11 12 14 16 18 24 36 48 72] + size-options (if (= font-size :multiple) (into [""] size-options) size-options)] + [:& editable-select + {:value (attr->string font-size) + :class (stl/css :font-size-select) + :input-class (stl/css :numeric-input) :options size-options + :type "number" + :placeholder "--" + :min 3 + :max 1000 :on-change on-font-size-change :on-blur on-blur}])] - [:div {:class (css :font-variant-options)} + [:div {:class (stl/css :font-variant-options)} (let [basic-variant-options (map (fn [variant] {:value (:id variant) :key (pr-str variant) :label (:name variant)}) (:variants font)) variant-options (if (= font-size :multiple) @@ -381,7 +379,7 @@ basic-variant-options)] ;; TODO Add disabled mode [:& select - {:class (css :font-variant-select) + {:class (stl/css :font-variant-select) :default-value (attr->string font-variant-id) :options variant-options :on-change on-font-variant-change @@ -451,34 +449,33 @@ (fn [value attr] (on-change {attr (str value)}))] (if new-css-system - [:div {:class (css :spacing-options)} - [:div {:class (css :line-height)} - [:span {:class (css :icon) + [:div {:class (stl/css :spacing-options)} + [:div {:class (stl/css :line-height)} + [:span {:class (stl/css :icon) :alt (tr "workspace.options.text-options.line-height")} i/text-lineheight-refactor] - [:> numeric-input* {:min -200 :max 200 :step 0.1 :default "1.2" - :class (css :line-height-input) + :class (stl/css :line-height-input) :value (attr->string line-height) :placeholder (tr "settings.multiple") :nillable line-height-nillable :on-change #(handle-change % :line-height) :on-blur on-blur}]] - [:div {:class (css :letter-spacing)} + [:div {:class (stl/css :letter-spacing)} [:span - {:class (css :icon) + {:class (stl/css :icon) :alt (tr "workspace.options.text-options.letter-spacing")} i/text-letterspacing-refactor] [:> numeric-input* {:min -200 :max 200 :step 0.1 - :class (css :letter-spacing-input) + :class (stl/css :letter-spacing-input) :value (attr->string letter-spacing) :placeholder (tr "settings.multiple") :on-change #(handle-change % :letter-spacing) @@ -525,7 +522,7 @@ (on-change {:text-transform type})) (when (some? on-blur) (on-blur)))] (if new-css-system - [:div {:class (css :text-transform)} + [:div {:class (stl/css :text-transform)} [:& radio-buttons {:selected text-transform :on-change handle-change :name "text-transform"} @@ -574,9 +571,9 @@ :show-recent show-recent}] (if new-css-system - [:div {:class (css :typography-options)} + [:div {:class (stl/css :typography-options)} [:> font-options opts] - [:div {:class (css :typography-variations)} + [:div {:class (stl/css :typography-variations)} [:> spacing-options opts] [:> text-transform-options opts]]] @@ -601,26 +598,26 @@ (when visible? [:div {:ref ref - :class (css :advanced-options-wrapper)} + :class (stl/css :advanced-options-wrapper)} (if ^boolean editable? [:* - [:div {:class (css :font-name-wrapper)} + [:div {:class (stl/css :font-name-wrapper)} [:div - {:class (dom/classnames (css :typography-sample-input) true) + {:class (stl/css :typography-sample-input) :style {:font-family (:font-family typography) :font-weight (:font-weight typography) :font-style (:font-style typography)}} (tr "workspace.assets.typography.sample")] [:input - {:class (css :adv-typography-name) + {:class (stl/css :adv-typography-name) :type "text" :ref name-input-ref :default-value (:name typography) :on-key-down on-key-down :on-blur on-name-blur}] - [:div {:class (css :action-btn) + [:div {:class (stl/css :action-btn) :on-click on-close} i/tick-refactor]] @@ -738,49 +735,49 @@ (dom/select-text! node))))) (if new-css-system [:* - [:div {:class (dom/classnames (css :typography-entry) true - (css :selected) ^boolean selected?) + [:div {:class (stl/css-case :typography-entry true + :selected ^boolean selected?) :style {:display (when ^boolean open? "none")}} (if renaming? - [:div {:class (css :font-name-wrapper)} + [:div {:class (stl/css :font-name-wrapper)} [:div - {:class (dom/classnames (css :typography-sample-input) true) + {:class (stl/css :typography-sample-input) :style {:font-family (:font-family typography) :font-weight (:font-weight typography) :font-style (:font-style typography)}} (tr "workspace.assets.typography.sample")] [:input - {:class (css :adv-typography-name) + {:class (stl/css :adv-typography-name) :type "text" :ref name-input-ref :default-value (:name typography) :on-key-down on-key-down :on-blur on-name-blur}]] [:div - {:class (dom/classnames (css :typography-selection-wrapper) true - (css :is-selectable) ^boolean on-click) + {:class (stl/css-case :typography-selection-wrapper true + :is-selectable ^boolean on-click) :on-click on-click :on-context-menu on-context-menu} [:div - {:class (dom/classnames (css :typography-sample) true) + {:class (stl/css :typography-sample) :style {:font-family (:font-family typography) :font-weight (:font-weight typography) :font-style (:font-style typography)}} (tr "workspace.assets.typography.sample")] - [:div {:class (dom/classnames (css :typography-name) true) + [:div {:class (stl/css :typography-name) :title (:name typography)} (:name typography)] (when-not name-only? - [:div {:class (dom/classnames (css :typography-font) true) + [:div {:class (stl/css :typography-font) :title (:name font-data)} (:name font-data)])]) (when ^boolean on-detach - [:div {:class (dom/classnames (css :element-set-actions) true)} + [:div {:class (stl/css :element-set-actions)} [:div - {:class (dom/classnames (css :element-set-actions-button) true) + {:class (stl/css :element-set-actions-button) :on-pointer-enter on-pointer-enter :on-pointer-leave on-pointer-leave :on-click on-detach} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss index 8ffe111de0..41bdb7e7ea 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss @@ -109,137 +109,109 @@ height: 100%; width: 100%; background-color: var(--assets-title-background-color); +} - .typography-options { - position: relative; - .font-option { - @include titleTipography; +.typography-options { + position: relative; + display: flex; + flex-direction: column; + gap: $s-4; + .font-option { + @include titleTipography; + @extend .asset-element; + padding-right: 0; + cursor: pointer; + .name { + flex-grow: 1; + } + .icon { + @include flexCenter; + height: $s-28; + width: $s-28; + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + transform: rotate(90deg); + } + } + } + .font-modifiers { + display: flex; + gap: $s-4; + .font-size-options { @extend .asset-element; - padding-right: 0; - margin-bottom: $s-4; - cursor: pointer; - .name { - flex-grow: 1; + @include titleTipography; + flex-grow: 1; + width: $s-60; + margin: 0; + padding: 0; + border: $s-1 solid var(--input-background-color); + position: relative; + .font-size-select { + height: $s-32; + .numeric-input { + @extend .input-base; + margin: 0; + padding: 0; + } + span { + @include flexCenter; + svg { + @extend .button-icon; + } + } } .icon { @include flexCenter; height: $s-28; - width: $s-28; + min-width: $s-28; svg { @extend .button-icon; stroke: var(--icon-foreground); transform: rotate(90deg); } } - } - .font-modifiers { - display: flex; - gap: $s-4; - .font-size-options { - @extend .asset-element; + .font-size-select { + @include removeInputStyle; @include titleTipography; + height: 100%; + width: 100%; + margin: 0; padding: 0; - margin-bottom: $s-4; - flex-grow: 1; - .icon { - @include flexCenter; - height: $s-28; - min-width: $s-28; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - transform: rotate(90deg); - } - } - .font-size-select { - @include removeInputStyle; - @include titleTipography; - height: 100%; - width: 100%; - margin: 0; - padding: 0; - } - } - .font-variant-options { - @extend .asset-element; - @include titleTipography; - padding: 0; - margin-bottom: $s-4; - flex-grow: 2; - .icon { - @include flexCenter; - height: $s-28; - min-width: $s-28; - svg { - @extend .button-icon; - stroke: var(--icon-foreground); - transform: rotate(90deg); - } - } - .font-variant-select { - @include removeInputStyle; - @include titleTipography; - height: 100%; - width: 100%; - margin: 0; - color: var(--assets-item-name-foreground-color); - option { - color: var(--assets-item-name-foreground-color); - } - &:hover { - color: var(--assets-item-name-foreground-color-hover); - option { - color: var(--assets-item-name-foreground-color-hover); - } - } - } } } - .typography-variations { + .font-variant-options { + padding: 0; + flex-grow: 2; + } + } + .typography-variations { + display: flex; + gap: $s-4; + align-items: center; + .spacing-options { display: flex; - gap: $s-4; align-items: center; - .spacing-options { - display: flex; - align-items: center; - gap: $s-4; - .line-height, - .letter-spacing { - @extend .asset-element; - margin-bottom: $s-4; - .icon { - @include flexCenter; - width: $s-28; - svg { - @extend .button-icon-small; - stroke: var(--icon-foreground); - } - } - .line-height-input, - .letter-spacing-input { - @include removeInputStyle; - @include titleTipography; - height: 100%; - width: 100%; - margin: 0; - color: var(--assets-item-name-foreground-color); - &:hover, - &:active, - &:focus { - color: var(--assets-item-name-foreground-color-hover); - } + gap: $s-4; + .line-height, + .letter-spacing { + @extend .input-element; + .icon { + @include flexCenter; + width: $s-28; + svg { + @extend .button-icon-small; } } } - .text-transform { - @extend .asset-element; - width: fit-content; - padding: 0; - margin-bottom: $s-4; + } + .text-transform { + @extend .asset-element; + width: fit-content; + padding: 0; + background-color: var(--radio-btns-background-color); + &:hover { background-color: var(--radio-btns-background-color); - &:hover { - background-color: var(--radio-btns-background-color); - } } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index e5a9a92ad6..fa0f3d23df 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -6,12 +6,15 @@ (ns app.main.ui.workspace.sidebar.options.page "Page options menu entries." + (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as clr] [app.main.data.workspace :as dw] [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.store :as st] + [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] [rumext.v2 :as mf])) @@ -20,20 +23,38 @@ {::mf/wrap [mf/memo] ::mf/wrap-props false} [] - (let [options (mf/deref refs/workspace-page-options) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + options (mf/deref refs/workspace-page-options) on-change (mf/use-fn #(st/emit! (dw/change-canvas-color %))) on-open (mf/use-fn #(st/emit! (dwu/start-undo-transaction :options))) on-close (mf/use-fn #(st/emit! (dwu/commit-undo-transaction :options)))] - [:div.element-set - [:div.element-set-title (tr "workspace.options.canvas-background")] - [:div.element-set-content - [:& color-row - {:disable-gradient true - :disable-opacity true - :title (tr "workspace.options.canvas-background") - :color {:color (get options :background clr/canvas) - :opacity 1} - :on-change on-change - :on-open on-open - :on-close on-close}]]])) + (if new-css-system + [:div {:class (stl/css :element-set)} + [:div {:class (stl/css :element-title)} + [:& title-bar {:collapsable? false + :title (tr "workspace.options.canvas-background") + :class (stl/css :title-spacing-page)}]] + [:div {:class (stl/css :element-content)} + [:& color-row + {:disable-gradient true + :disable-opacity true + :title (tr "workspace.options.canvas-background") + :color {:color (get options :background clr/canvas) + :opacity 1} + :on-change on-change + :on-open on-open + :on-close on-close}]]] + + [:div.element-set + [:div.element-set-title (tr "workspace.options.canvas-background")] + [:div.element-set-content + [:& color-row + {:disable-gradient true + :disable-opacity true + :title (tr "workspace.options.canvas-background") + :color {:color (get options :background clr/canvas) + :opacity 1} + :on-change on-change + :on-open on-open + :on-close on-close}]]]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.scss b/frontend/src/app/main/ui/workspace/sidebar/options/page.scss new file mode 100644 index 0000000000..da131647f1 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.scss @@ -0,0 +1,7 @@ +// 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 + +@import "refactor/common-refactor.scss"; diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index 4c47ab4850..c2ad44f5e0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.rows.color-row + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] @@ -13,7 +14,7 @@ [app.main.data.workspace.libraries :as dwl] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.color-bullet :as cb] + [app.main.ui.components.color-bullet-new :as cb] [app.main.ui.components.color-input :refer [color-input*]] [app.main.ui.components.numeric-input :refer [numeric-input*]] [app.main.ui.context :as ctx] @@ -42,7 +43,8 @@ [{:keys [index color disable-gradient disable-opacity on-change on-reorder on-detach on-open on-close title on-remove disable-drag on-focus on-blur select-only select-on-focus]}] - (let [current-file-id (mf/use-ctx ctx/current-file-id) + (let [new-css-system (mf/use-ctx ctx/new-css-system) + current-file-id (mf/use-ctx ctx/current-file-id) file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/workspace-libraries) hover-detach (mf/use-state false) @@ -53,6 +55,11 @@ color-name (dm/get-in src-colors [(:id color) :name]) + multiple-colors? (uc/multiple? color) + library-color? (and (:id color) color-name (not multiple-colors?)) + gradient-color? (and (not multiple-colors?) + (:gradient color) + (get-in color [:gradient :type])) parse-color (mf/use-fn (fn [color] @@ -79,7 +86,7 @@ (assoc :color new-value) (dissoc :gradient))] (st/emit! (dwl/add-recent-color color) - (on-change color))))) + (on-change color))))) handle-opacity-change (mf/use-fn @@ -90,14 +97,14 @@ :id nil :file-id nil)] (st/emit! (dwl/add-recent-color color) - (on-change color))))) + (on-change color))))) handle-click-color (mf/use-fn (mf/deps disable-gradient disable-opacity on-change on-close on-open) (fn [color event] (let [color (cond - (uc/multiple? color) + multiple-colors? {:color default-color :opacity 1} @@ -149,73 +156,153 @@ (when (not= prev-color color) (modal/update-props! :colorpicker {:data (parse-color color)}))) - [:div.row-flex.color-data {:title title - :class (dom/classnames - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot)) - :ref dref} - [:& cb/color-bullet {:color (cond-> color - (nil? color-name) (assoc - :id nil - :file-id nil)) - :on-click handle-click-color}] - (cond - ;; Rendering a color with ID - (and (:id color) color-name (not (uc/multiple? color))) - [:* - [:div.color-info - [:div.color-name (str color-name)]] - (when on-detach - [:div.element-set-actions-button - {:on-pointer-enter #(reset! hover-detach true) - :on-pointer-leave #(reset! hover-detach false) - :on-click detach-value} - (if @hover-detach i/unchain i/chain)]) + (if new-css-system + [:div {:class (stl/css-case + :color-data true + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + [:span {:class (stl/css :color-info)} + [:span {:class (stl/css-case :color-name-wrapper true + :gradient-name-wrapper gradient-color?)} + [:span {:class (stl/css :color-bullet-wrapper)} + [:& cb/color-bullet {:color (cond-> color + (nil? color-name) (assoc + :id nil + :file-id nil)) + :on-click handle-click-color}]] + (cond + ;; Rendering a color with ID + library-color? + [:* + [:div {:class (stl/css :color-name) + :title (str color-name)} - (when select-only - [:div.element-set-actions-button {:on-click handle-select} - i/pointer-inner])] + (str color-name)] + (when on-detach + [:button + {:class (stl/css :detach-btn) + :title (tr "settings.detach") + :on-pointer-enter #(reset! hover-detach true) + :on-pointer-leave #(reset! hover-detach false) + :on-click detach-value} + i/detach-refactor])] - ;; Rendering a gradient - (and (not (uc/multiple? color)) - (:gradient color) - (get-in color [:gradient :type])) - [:* - [:div.color-info - [:div.color-name (uc/gradient-type->string (get-in color [:gradient :type]))]] - (when select-only - [:div.element-set-actions-button {:on-click handle-select} - i/pointer-inner])] + ;; Rendering a gradient + gradient-color? + [:* + [:div {:class (stl/css :color-name)} + (uc/gradient-type->string (get-in color [:gradient :type]))]] + + ;; Rendering a plain color + :else + [:span {:class (stl/css :color-input-wrapper)} + [:> color-input* {:value (if multiple-colors? + "" + (-> color :color uc/remove-hash)) + :placeholder (tr "settings.multiple") + :className (stl/css :color-input) + :on-focus on-focus + :on-blur on-blur + :on-change handle-value-change}]])] + + (when (and (not gradient-color?) + (not multiple-colors?) + (not library-color?)) - ;; Rendering a plain color/opacity - :else - [:* - [:div.color-info - [:> color-input* {:value (if (uc/multiple? color) - "" - (-> color :color uc/remove-hash)) - :placeholder (tr "settings.multiple") - :on-focus on-focus - :on-blur on-blur - :on-change handle-value-change}]] - - (when (and (not disable-opacity) - (not (:gradient color))) - [:div.input-element - {:class (dom/classnames :percentail (not= (:opacity color) :multiple))} + [:div {:class (stl/css :opacity-element-wrapper)} + [:span {:class (stl/css :icon-text)} + "%"] [:> numeric-input* {:value (-> color :opacity opacity->string) + :className (stl/css :opacity-input) :placeholder (tr "settings.multiple") :select-on-focus select-on-focus :on-focus on-focus :on-blur on-blur :on-change handle-opacity-change :min 0 - :max 100}]]) - (when select-only - [:div.element-set-actions-button {:on-click handle-select} - i/pointer-inner])]) - (when (some? on-remove) - [:div.element-set-actions-button.remove {:on-click on-remove} i/minus])])) + :max 100}]])] + + (when (some? on-remove) + [:button {:class (stl/css :remove-btn) + :on-click on-remove} i/remove-refactor]) + (when select-only + [:button {:class (stl/css :select-btn) + :on-click handle-select} + i/move-refactor])] + + + + + + + + + + [:div.row-flex.color-data {:title title + :class (dom/classnames + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + [:& cb/color-bullet {:color (cond-> color + (nil? color-name) (assoc + :id nil + :file-id nil)) + :on-click handle-click-color}] + + (cond + ;; Rendering a color with ID + library-color? + [:* + [:div.color-info + [:div.color-name (str color-name)]] + (when on-detach + [:div.element-set-actions-button + {:on-pointer-enter #(reset! hover-detach true) + :on-pointer-leave #(reset! hover-detach false) + :on-click detach-value} + (if @hover-detach i/unchain i/chain)])] + + ;; Rendering a gradient + gradient-color? + [:* + [:div.color-info + [:div.color-name (uc/gradient-type->string (get-in color [:gradient :type]))]] + (when select-only + [:div.element-set-actions-button {:on-click handle-select} + i/pointer-inner])] + + ;; Rendering a plain color/opacity + :else + [:* + [:div.color-info + [:> color-input* {:value (if multiple-colors? + "" + (-> color :color uc/remove-hash)) + :placeholder (tr "settings.multiple") + :on-focus on-focus + :on-blur on-blur + :on-change handle-value-change}]] + + (when (and (not disable-opacity) + (not (:gradient color))) + [:div.input-element + {:class (dom/classnames :percentail (not= (:opacity color) :multiple))} + [:> numeric-input* {:value (-> color :opacity opacity->string) + :placeholder (tr "settings.multiple") + :select-on-focus select-on-focus + :on-focus on-focus + :on-blur on-blur + :on-change handle-opacity-change + :min 0 + :max 100}]]) + (when select-only + [:div.element-set-actions-button {:on-click handle-select} + i/pointer-inner])]) + (when (some? on-remove) + [:div.element-set-actions-button.remove {:on-click on-remove} i/minus])]) + + )) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss new file mode 100644 index 0000000000..fed6300cd8 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.scss @@ -0,0 +1,121 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.color-data { + display: flex; + align-items: center; + gap: $s-4; + .color-info { + display: flex; + align-items: center; + gap: $s-1; + border-radius: $s-8; + background-color: var(--input-details-color); + height: $s-32; + width: 100%; + flex-grow: 1; + .color-name-wrapper { + display: flex; + align-items: center; + border-radius: $br-8; + background-color: var(--input-background-color); + flex-grow: 1; + + .color-bullet-wrapper { + @extend .input-element; + background-color: transparent; + border-radius: $br-8 0 0 $br-8; + padding: 0 $s-4 0 $s-8; + &:hover { + background-color: transparent; + } + } + .color-name { + @include titleTipography; + display: flex; + align-items: center; + height: $s-32; + flex-grow: 1; + color: var(--input-foreground-color-active); + } + .detach-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + border-radius: 0 $br-8 $br-8 0; + svg { + @extend .button-icon; + } + } + .color-input-wrapper { + @extend .input-element; + border-radius: $br-0; + } + &:hover, + &:focus, + &:focus-within { + .color-bullet-wrapper, + .color-name, + .detach-btn, + .color-input-wrapper { + background-color: var(--input-background-color-hover); + } + .detach-btn svg { + stroke: var(--input-foreground-color-active); + } + } + } + .gradient-name-wrapper { + .color-name { + border-radius: 0 $br-8 $br-8 0; + } + } + .opacity-element-wrapper { + @extend .input-element; + width: $s-60; + border-radius: 0 $br-8 $br-8 0; + padding-left: $s-8; + .opacity-input { + border-radius: 0 $br-8 $br-8 0; + min-width: $s-28; + } + .icon-text { + @include flexCenter; + height: $s-32; + margin-right: $s-4; + padding-top: $s-2; + } + } + + &:hover { + .detach-btn, + .select-btn { + background-color: transparent; + svg { + stroke: var(--input-foreground-color-active); + } + } + } + } + .remove-btn, + .select-btn { + @extend .button-tertiary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + + &.dnd-over-top { + border-top: $s-1 solid var(--layer-row-foreground-color-drag); + } + &.dnd-over-bot { + border-bottom: $s-1 solid var(--layer-row-foreground-color-drag); + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index 60bf0afb6c..d938043c39 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -5,11 +5,14 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.workspace.sidebar.options.rows.stroke-row + (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] [app.common.data.macros :as dm] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.numeric-input :refer [numeric-input*]] + [app.main.ui.components.select :refer [select]] + [app.main.ui.context :as ctx] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] @@ -49,10 +52,34 @@ (mf/defc stroke-row {::mf/wrap-props false} - [{:keys [index stroke title show-caps on-color-change on-reorder on-color-detach on-remove on-stroke-width-change on-stroke-style-change on-stroke-alignment-change open-caps-select close-caps-select on-stroke-cap-start-change on-stroke-cap-end-change on-stroke-cap-switch disable-drag on-focus on-blur disable-stroke-style select-on-focus]}] - (let [start-caps-state (mf/use-state {:open? false - :top 0 - :left 0}) + [{:keys [index + stroke + title + show-caps + on-color-change + on-reorder + on-color-detach + on-remove + on-stroke-width-change + on-stroke-style-change + on-stroke-alignment-change + open-caps-select + close-caps-select + on-stroke-cap-start-change + on-stroke-cap-end-change + on-stroke-cap-switch + disable-drag + on-focus + on-blur + disable-stroke-style + select-on-focus]}] + (let [new-css-system (mf/use-ctx ctx/new-css-system) + start-caps-state* (mf/use-state {:open? false + :top 0 + :left 0}) + + start-caps-state (deref start-caps-state*) + end-caps-state (mf/use-state {:open? false :top 0 :left 0}) @@ -69,99 +96,255 @@ :data {:id (str "stroke-row-" index) :index index :name (str "Border row" index)}) - [nil nil])] + [nil nil]) - [:div.border-data {:class (dom/classnames - :dnd-over-top (= (:over dprops) :top) - :dnd-over-bot (= (:over dprops) :bot)) - :ref dref} - ;; Stroke Color - [:& color-row {:color {:color (:stroke-color stroke) - :opacity (:stroke-opacity stroke) - :id (:stroke-color-ref-id stroke) - :file-id (:stroke-color-ref-file stroke) - :gradient (:stroke-color-gradient stroke)} - :index index - :title title - :on-change (on-color-change index) - :on-detach (on-color-detach index) - :on-remove (on-remove index) - :disable-drag disable-drag - :on-focus on-focus - :select-on-focus select-on-focus - :on-blur on-blur}] + on-color-change-refactor + (mf/use-callback + (mf/deps index on-color-change) + (fn [color] + (on-color-change index color))) - ;; Stroke Width, Alignment & Style - [:div.row-flex - [:div.input-element - {:class (dom/classnames :pixels (not= (:stroke-width stroke) :multiple)) - :title (tr "workspace.options.stroke-width")} + on-color-detach-refactor + (mf/use-callback + (mf/deps index on-color-detach) + (fn [color] + (on-color-detach index color))) - [:> numeric-input* - {:min 0 - :value (-> (:stroke-width stroke) width->string) - :placeholder (tr "settings.multiple") - :on-change (on-stroke-width-change index) - :on-focus on-focus - :select-on-focus select-on-focus - :on-blur on-blur}]] + on-remove-refactor + (mf/use-callback + (mf/deps index on-remove) + #(on-remove index)) - [:select#style.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (enum->string (:stroke-alignment stroke)) - :on-change (on-stroke-alignment-change index)} - (when (= (:stroke-alignment stroke) :multiple) - [:option {:value ""} "--"]) - [:option {:value ":center"} (tr "workspace.options.stroke.center")] - [:option {:value ":inner"} (tr "workspace.options.stroke.inner")] - [:option {:value ":outer"} (tr "workspace.options.stroke.outer")]] + stroke-width (:stroke-width stroke) - (when-not disable-stroke-style - [:select#style.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element - :value (enum->string (:stroke-style stroke)) - :on-change (on-stroke-style-change index)} - (when (= (:stroke-style stroke) :multiple) - [:option {:value ""} "--"]) - [:option {:value ":solid"} (tr "workspace.options.stroke.solid")] - [:option {:value ":dotted"} (tr "workspace.options.stroke.dotted")] - [:option {:value ":dashed"} (tr "workspace.options.stroke.dashed")] - [:option {:value ":mixed"} (tr "workspace.options.stroke.mixed")]])] + on-width-change + (mf/use-callback + (mf/deps index on-stroke-width-change) + #(on-stroke-width-change index %)) - ;; Stroke Caps - (when show-caps + stroke-alignment (or (:stroke-alignment stroke) :center) + + stroke-alignment-options + (mf/with-memo [stroke-alignment] + (d/concat-vec + (when (= :multiple stroke-alignment) + [{:value :multiple :label "--"}]) + [{:value :center :label (tr "workspace.options.stroke.center")} + {:value :inner :label (tr "workspace.options.stroke.inner")} + {:value :outer :label (tr "workspace.options.stroke.outer")}])) + + on-alignment-change + (mf/use-callback + (mf/deps index on-stroke-alignment-change) + #(on-stroke-alignment-change index (keyword %))) + + stroke-style (or (:stroke-style stroke) :solid) + + stroke-style-options + (mf/with-memo [stroke-style] + (d/concat-vec + (when (= :multiple stroke-style) + [{:value :multiple :label "--"}]) + [{:value :solid :label (tr "workspace.options.stroke.solid")} + {:value :dotted :label (tr "workspace.options.stroke.dotted")} + {:value :dashed :label (tr "workspace.options.stroke.dashed")} + {:value :mixed :label (tr "workspace.options.stroke.mixed")}])) + + on-style-change + (mf/use-callback + (mf/deps index on-stroke-style-change) + #(on-stroke-style-change index (keyword %))) + + on-caps-start-change + (mf/use-callback + (mf/deps index on-stroke-cap-start-change) + #(on-stroke-cap-start-change index (keyword %))) + + on-caps-end-change + (mf/use-callback + (mf/deps index on-stroke-cap-end-change) + #(on-stroke-cap-end-change index (keyword %))) + + stroke-caps-options + [{:value nil :label (tr "workspace.options.stroke-cap.none")} + :separator + {:value :line-arrow :label (tr "workspace.options.stroke-cap.line-arrow-short")} + {:value :triangle-arrow :label (tr "workspace.options.stroke-cap.triangle-arrow-short")} + {:value :square-marker :label (tr "workspace.options.stroke-cap.square-marker-short")} + {:value :circle-marker :label (tr "workspace.options.stroke-cap.circle-marker-short")} + {:value :diamond-marker :label (tr "workspace.options.stroke-cap.diamond-marker-short")} + :separator + {:value :round :label (tr "workspace.options.stroke-cap.round")} + {:value :square :label (tr "workspace.options.stroke-cap.square")}] + + on-cap-switch + (mf/use-callback + (mf/deps index on-stroke-cap-switch) + #(on-stroke-cap-switch index))] + + (if new-css-system + [:div {:class (stl/css-case + :stroke-data true + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + ;; Stroke Color + [:& color-row {:color {:color (:stroke-color stroke) + :opacity (:stroke-opacity stroke) + :id (:stroke-color-ref-id stroke) + :file-id (:stroke-color-ref-file stroke) + :gradient (:stroke-color-gradient stroke)} + :index index + :title title + :on-change on-color-change-refactor + :on-detach on-color-detach-refactor + :on-remove on-remove-refactor + :disable-drag disable-drag + :on-focus on-focus + :select-on-focus select-on-focus + :on-blur on-blur}] + + ;; Stroke Width, Alignment & Style + [:div {:class (stl/css :stroke-options)} + [:div {:class (stl/css :stroke-width-input-element) + :title (tr "workspace.options.stroke-width")} + [:span {:class (stl/css :icon)} + i/stroke-size-refactor] + [:> numeric-input* + {:min 0 + :className (stl/css :stroke-width-input) + :value stroke-width + :placeholder (tr "settings.multiple") + :on-change on-width-change + :on-focus on-focus + :select-on-focus select-on-focus + :on-blur on-blur}]] + + [:div {:class (stl/css :select-wrapper)} + [:& select + {:default-value stroke-alignment + :options stroke-alignment-options + :on-change on-alignment-change}]] + + (when-not disable-stroke-style + [:div {:class (stl/css :select-wrapper)} + [:& select + {:default-value stroke-style + :options stroke-style-options + :on-change on-style-change}]])] + + ;; Stroke Caps + (when show-caps + [:div {:class (stl/css :stroke-caps-options)} + [:div {:class (stl/css :cap-select)} + [:& select + {:default-value (:stroke-cap-start stroke) + :options stroke-caps-options + :on-change on-caps-start-change}]] + + [:button {:class (stl/css :swap-caps-btn) + :on-click on-cap-switch} + i/switch-refactor] + + [:div {:class (stl/css :cap-select)} + [:& select + {:default-value (:stroke-cap-end stroke) + :options stroke-caps-options + :on-change on-caps-end-change}]]])] + + + + [:div.border-data {:class (dom/classnames + :dnd-over-top (= (:over dprops) :top) + :dnd-over-bot (= (:over dprops) :bot)) + :ref dref} + ;; Stroke Color + [:& color-row {:color {:color (:stroke-color stroke) + :opacity (:stroke-opacity stroke) + :id (:stroke-color-ref-id stroke) + :file-id (:stroke-color-ref-file stroke) + :gradient (:stroke-color-gradient stroke)} + :index index + :title title + :on-change (on-color-change index) + :on-detach (on-color-detach index) + :on-remove (on-remove index) + :disable-drag disable-drag + :on-focus on-focus + :select-on-focus select-on-focus + :on-blur on-blur}] + + ;; Stroke Width, Alignment & Style [:div.row-flex - [:div.cap-select {:tab-index 0 ;; tab-index to make the element focusable - :on-click (open-caps-select start-caps-state)} - (value->name (:stroke-cap-start stroke)) - [:span.cap-select-button - i/arrow-down]] - [:& dropdown {:show (:open? @start-caps-state) - :on-close (close-caps-select start-caps-state)} - [:ul.dropdown.cap-select-dropdown {:style {:top (:top @start-caps-state) - :left (:left @start-caps-state)}} - (for [[idx [value label separator]] (d/enumerate (stroke-cap-names))] - (let [img (value->img value)] - [:li {:key (dm/str "start-cap-" idx) - :class (dom/classnames :separator separator) - :on-click #(on-stroke-cap-start-change index value)} - (when img [:img {:src (value->img value)}]) - label]))]] + [:div.input-element + {:class (dom/classnames :pixels (not= (:stroke-width stroke) :multiple)) + :title (tr "workspace.options.stroke-width")} - [:div.element-set-actions-button {:on-click #(on-stroke-cap-switch index)} - i/switch] + [:> numeric-input* + {:min 0 + :value (-> (:stroke-width stroke) width->string) + :placeholder (tr "settings.multiple") + :on-change (on-stroke-width-change index) + :on-focus on-focus + :select-on-focus select-on-focus + :on-blur on-blur}]] - [:div.cap-select {:tab-index 0 - :on-click (open-caps-select end-caps-state)} - (value->name (:stroke-cap-end stroke)) - [:span.cap-select-button - i/arrow-down]] - [:& dropdown {:show (:open? @end-caps-state) - :on-close (close-caps-select end-caps-state)} - [:ul.dropdown.cap-select-dropdown {:style {:top (:top @end-caps-state) - :left (:left @end-caps-state)}} - (for [[idx [value label separator]] (d/enumerate (stroke-cap-names))] - (let [img (value->img value)] - [:li {:key (dm/str "end-cap-" idx) - :class (dom/classnames :separator separator) - :on-click #(on-stroke-cap-end-change index value)} - (when img [:img {:src (value->img value)}]) - label]))]]])])) + [:select#style.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :value (enum->string (:stroke-alignment stroke)) + :on-change (on-stroke-alignment-change index)} + (when (= (:stroke-alignment stroke) :multiple) + [:option {:value ""} "--"]) + [:option {:value ":center"} (tr "workspace.options.stroke.center")] + [:option {:value ":inner"} (tr "workspace.options.stroke.inner")] + [:option {:value ":outer"} (tr "workspace.options.stroke.outer")]] + + (when-not disable-stroke-style + [:select#style.input-select {:data-mousetrap-dont-stop true ;; makes mousetrap to not stop at this element + :value (enum->string (:stroke-style stroke)) + :on-change (on-stroke-style-change index)} + (when (= (:stroke-style stroke) :multiple) + [:option {:value ""} "--"]) + [:option {:value ":solid"} (tr "workspace.options.stroke.solid")] + [:option {:value ":dotted"} (tr "workspace.options.stroke.dotted")] + [:option {:value ":dashed"} (tr "workspace.options.stroke.dashed")] + [:option {:value ":mixed"} (tr "workspace.options.stroke.mixed")]])] + + ;; Stroke Caps + (when show-caps + [:div.row-flex + [:div.cap-select {:tab-index 0 ;; tab-index to make the element focusable + :on-click (open-caps-select start-caps-state*)} + (value->name (:stroke-cap-start stroke)) + [:span.cap-select-button + i/arrow-down]] + [:& dropdown {:show (:open? start-caps-state) + :on-close (close-caps-select start-caps-state*)} + [:ul.dropdown.cap-select-dropdown {:style {:top (:top start-caps-state) + :left (:left start-caps-state)}} + (for [[idx [value label separator]] (d/enumerate (stroke-cap-names))] + (let [img (value->img value)] + [:li {:key (dm/str "start-cap-" idx) + :class (dom/classnames :separator separator) + :on-click #(on-stroke-cap-start-change index value)} + (when img [:img {:src (value->img value)}]) + label]))]] + + [:div.element-set-actions-button {:on-click #(on-stroke-cap-switch index)} + i/switch] + + [:div.cap-select {:tab-index 0 + :on-click (open-caps-select end-caps-state)} + (value->name (:stroke-cap-end stroke)) + [:span.cap-select-button + i/arrow-down]] + [:& dropdown {:show (:open? @end-caps-state) + :on-close (close-caps-select end-caps-state)} + [:ul.dropdown.cap-select-dropdown {:style {:top (:top @end-caps-state) + :left (:left @end-caps-state)}} + (for [[idx [value label separator]] (d/enumerate (stroke-cap-names))] + (let [img (value->img value)] + [:li {:key (dm/str "end-cap-" idx) + :class (dom/classnames :separator separator) + :on-click #(on-stroke-cap-end-change index value)} + (when img [:img {:src (value->img value)}]) + label]))]]])]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss new file mode 100644 index 0000000000..0ed841ada6 --- /dev/null +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss @@ -0,0 +1,55 @@ +// 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 + +@import "refactor/common-refactor.scss"; + +.stroke-data { + display: flex; + flex-direction: column; + gap: $s-4; + .stroke-options { + display: flex; + align-items: center; + gap: $s-4; + .stroke-width-input-element { + @extend .input-element; + width: $s-60; + border-radius: $br-8; + padding: $s-8; + .icon { + @include flexCenter; + height: $s-32; + width: $s-12; + margin-right: $s-4; + } + } + .select-wrapper { + width: $s-124; + } + } + .stroke-caps-options { + display: flex; + align-items: center; + gap: $s-4; + .cap-select { + width: $s-124; + } + .swap-caps-btn { + @extend .button-secondary; + height: $s-32; + width: $s-28; + svg { + @extend .button-icon; + } + } + } + &.dnd-over-top { + border-top: $s-1 solid var(--layer-row-foreground-color-drag); + } + &.dnd-over-bot { + border-bottom: $s-1 solid var(--layer-row-foreground-color-drag); + } +} diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss b/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss index 8ba8c7d6d8..0cac04b5ba 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss @@ -44,7 +44,7 @@ } .resize-area { position: absolute; - bottom: -8px; + bottom: calc(-1 * $s-8); left: 0; width: 100%; height: $s-12; diff --git a/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.scss b/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.scss index 3b77f7f3d2..6c153cff1e 100644 --- a/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.scss +++ b/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.scss @@ -10,7 +10,7 @@ position: absolute; left: auto; bottom: $s-0; - max-width: $s-248; + max-width: $s-480; padding: $s-4; margin: 0 0 $s-4 0; z-index: $z-index-3; @@ -22,6 +22,7 @@ position: relative; display: flex; justify-content: space-between; + width: 100%; gap: $s-8; padding: $s-8; margin-bottom: $s-4; @@ -41,7 +42,6 @@ max-width: $s-380; } .lib-num { - background-color: green; margin-left: $s-4; } } diff --git a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs index e911ae42e1..2eab802c6c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -11,6 +11,7 @@ [app.main.data.workspace.undo :as dwu] [app.main.rasterizer :as thr] [app.main.store :as st] + [app.main.ui.context :as ctx] [app.main.ui.css-cursors :as cur] [app.util.dom :as dom] [app.util.keyboard :as kbd] @@ -23,7 +24,8 @@ (mf/defc pixel-overlay {::mf/wrap-props false} [props] - (let [vport (unchecked-get props "vport") + (let [new-css-system (mf/use-ctx ctx/new-css-system) + vport (unchecked-get props "vport") viewport-ref (unchecked-get props "viewport-ref") viewport-node (mf/ref-val viewport-ref) @@ -52,7 +54,9 @@ (when-let [zoom-view-node (dom/get-element "picker-detail")] (when-not (mf/ref-val zoom-view-context) (mf/set-ref-val! zoom-view-context (.getContext zoom-view-node "2d"))) - (let [{brx :left bry :top} (dom/get-bounding-rect viewport-node) + (let [canvas-width (if new-css-system 260 200) + canvas-height (if new-css-system 140 160) + {brx :left bry :top} (dom/get-bounding-rect viewport-node) x (- (.-clientX event) brx) y (- (.-clientY event) bry) @@ -75,8 +79,8 @@ sh 40 dx 0 dy 0 - dw 200 - dh 160] + dw canvas-width + dh canvas-height] (when (obj/get zoom-context "imageSmoothingEnabled") (obj/set! zoom-context "imageSmoothingEnabled" false)) (.drawImage zoom-context canvas sx sy sw sh dx dy dw dh) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 0e5a7bbf36..96473cca0f 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -2284,6 +2284,10 @@ msgstr "Go to login" msgid "settings.multiple" msgstr "Mixed" +#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs, +msgid "settings.detach" +msgstr "Detach" + # SECTIONS msgid "shortcut-section.basics" msgstr "Basics" @@ -4140,14 +4144,26 @@ msgstr "Stroke" msgid "workspace.options.stroke-cap.circle-marker" msgstr "Circle marker" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.circle-marker-short" +msgstr "Circle" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.diamond-marker" msgstr "Diamond marker" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.diamond-marker-short" +msgstr "Diamond" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.line-arrow" msgstr "Line arrow" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.line-arrow-short" +msgstr "Arrow" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.none" msgstr "None" @@ -4164,10 +4180,18 @@ msgstr "Square" msgid "workspace.options.stroke-cap.square-marker" msgstr "Square marker" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.square-marker-short" +msgstr "Rectangle" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.triangle-arrow" msgstr "Triangle arrow" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.triangle-arrow-short" +msgstr "Triangle" + msgid "workspace.options.stroke-color" msgstr "Stroke color" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index ee428ed1b8..0b38b32774 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2357,6 +2357,10 @@ msgstr "Ir al login" msgid "settings.multiple" msgstr "Varios" +#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs, +msgid "settings.detach" +msgstr "Desacoplar" + # SECTIONS msgid "shortcut-section.basics" msgstr "Básicos" @@ -4235,14 +4239,26 @@ msgstr "Borde" msgid "workspace.options.stroke-cap.circle-marker" msgstr "Marcador círculo" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.circle-marker-short" +msgstr "Círculo" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.diamond-marker" msgstr "Marcador diamante" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.diamond-marker-short" +msgstr "Diamante" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.line-arrow" msgstr "Flecha de línea" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.line-arrow-short" +msgstr "Flecha" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.none" msgstr "Ninguno" @@ -4259,10 +4275,18 @@ msgstr "Cuadrado" msgid "workspace.options.stroke-cap.square-marker" msgstr "Marcador cuadrado" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.square-marker-short" +msgstr "Rectángulo" + #: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs msgid "workspace.options.stroke-cap.triangle-arrow" msgstr "Flecha triángulo" +#: src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +msgid "workspace.options.stroke-cap.triangle-arrow-short" +msgstr "Triángulo" + msgid "workspace.options.stroke-color" msgstr "Color del trazo"