diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc
index f9bb170b90..529d3bf2f6 100644
--- a/common/src/app/common/pages/helpers.cljc
+++ b/common/src/app/common/pages/helpers.cljc
@@ -448,25 +448,37 @@
path)
name))
+(defn merge-path-item-with-dot
+ "Put the item at the end of the path."
+ [path name]
+ (if-not (empty? path)
+ (if-not (empty? name)
+ (str path "\u00A0\u2022\u00A0" name)
+ path)
+ name))
+
(defn compact-path
"Separate last item of the path, and truncate the others if too long:
'one' -> ['' 'one' false]
'one / two / three' -> ['one / two' 'three' false]
'one / two / three / four' -> ['one / two / ...' 'four' true]
'one-item-but-very-long / two' -> ['...' 'two' true] "
- [path max-length]
+ [path max-length dot?]
(let [path-split (split-path path)
- last-item (last path-split)]
+ last-item (last path-split)
+ merge-path (if dot?
+ merge-path-item-with-dot
+ merge-path-item)]
(loop [other-items (seq (butlast path-split))
other-path ""]
(if-let [item (first other-items)]
(let [full-path (-> other-path
- (merge-path-item item)
- (merge-path-item last-item))]
+ (merge-path item)
+ (merge-path last-item))]
(if (> (count full-path) max-length)
- [(merge-path-item other-path "...") last-item true]
+ [(merge-path other-path "...") last-item true]
(recur (next other-items)
- (merge-path-item other-path item))))
+ (merge-path other-path item))))
[other-path last-item false]))))
(defn compact-name
diff --git a/frontend/resources/images/icons/detach-refactor.svg b/frontend/resources/images/icons/detach-refactor.svg
new file mode 100644
index 0000000000..3f349eb189
--- /dev/null
+++ b/frontend/resources/images/icons/detach-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/library-refactor.svg b/frontend/resources/images/icons/library-refactor.svg
index a961bb3e32..ea1a7b8084 100644
--- a/frontend/resources/images/icons/library-refactor.svg
+++ b/frontend/resources/images/icons/library-refactor.svg
@@ -1,3 +1,3 @@
diff --git a/frontend/resources/images/icons/text-Autoheight-refactor.svg b/frontend/resources/images/icons/text-Autoheight-refactor.svg
new file mode 100644
index 0000000000..e7fe975604
--- /dev/null
+++ b/frontend/resources/images/icons/text-Autoheight-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-LTR-refactor.svg b/frontend/resources/images/icons/text-LTR-refactor.svg
new file mode 100644
index 0000000000..8acf7188bb
--- /dev/null
+++ b/frontend/resources/images/icons/text-LTR-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-RTL-refactor.svg b/frontend/resources/images/icons/text-RTL-refactor.svg
new file mode 100644
index 0000000000..217b18c121
--- /dev/null
+++ b/frontend/resources/images/icons/text-RTL-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-autowidth-refactor.svg b/frontend/resources/images/icons/text-autowidth-refactor.svg
new file mode 100644
index 0000000000..e7fe975604
--- /dev/null
+++ b/frontend/resources/images/icons/text-autowidth-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-bottom-refactor.svg b/frontend/resources/images/icons/text-bottom-refactor.svg
new file mode 100644
index 0000000000..89a0861e81
--- /dev/null
+++ b/frontend/resources/images/icons/text-bottom-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-fixed-refactor.svg b/frontend/resources/images/icons/text-fixed-refactor.svg
new file mode 100644
index 0000000000..3dc0d5fe22
--- /dev/null
+++ b/frontend/resources/images/icons/text-fixed-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-justify-refactor.svg b/frontend/resources/images/icons/text-justify-refactor.svg
new file mode 100644
index 0000000000..01b8392a82
--- /dev/null
+++ b/frontend/resources/images/icons/text-justify-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-letterspacing-refactor.svg b/frontend/resources/images/icons/text-letterspacing-refactor.svg
new file mode 100644
index 0000000000..ce8ff42bde
--- /dev/null
+++ b/frontend/resources/images/icons/text-letterspacing-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-lineheight-refactor.svg b/frontend/resources/images/icons/text-lineheight-refactor.svg
new file mode 100644
index 0000000000..eebb1c05b2
--- /dev/null
+++ b/frontend/resources/images/icons/text-lineheight-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-lowercase-refactor.svg b/frontend/resources/images/icons/text-lowercase-refactor.svg
new file mode 100644
index 0000000000..e003bafa78
--- /dev/null
+++ b/frontend/resources/images/icons/text-lowercase-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-middle-refactor.svg b/frontend/resources/images/icons/text-middle-refactor.svg
new file mode 100644
index 0000000000..50bf1347d5
--- /dev/null
+++ b/frontend/resources/images/icons/text-middle-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-mixed-refactor.svg b/frontend/resources/images/icons/text-mixed-refactor.svg
new file mode 100644
index 0000000000..c2856aea76
--- /dev/null
+++ b/frontend/resources/images/icons/text-mixed-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-stroked-refactor.svg b/frontend/resources/images/icons/text-stroked-refactor.svg
new file mode 100644
index 0000000000..e63a1ae955
--- /dev/null
+++ b/frontend/resources/images/icons/text-stroked-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-top-refactor.svg b/frontend/resources/images/icons/text-top-refactor.svg
new file mode 100644
index 0000000000..ada2e6129b
--- /dev/null
+++ b/frontend/resources/images/icons/text-top-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-underlined-refactor.svg b/frontend/resources/images/icons/text-underlined-refactor.svg
new file mode 100644
index 0000000000..ad91abf795
--- /dev/null
+++ b/frontend/resources/images/icons/text-underlined-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/text-uppercase-refactor.svg b/frontend/resources/images/icons/text-uppercase-refactor.svg
new file mode 100644
index 0000000000..01bf59429c
--- /dev/null
+++ b/frontend/resources/images/icons/text-uppercase-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/view-as-list-refactor.svg b/frontend/resources/images/icons/view-as-list-refactor.svg
new file mode 100644
index 0000000000..edc5e0b881
--- /dev/null
+++ b/frontend/resources/images/icons/view-as-list-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 e0d30f8cc6..cb4da27ec4 100644
--- a/frontend/resources/styles/common/refactor/basic-rules.scss
+++ b/frontend/resources/styles/common/refactor/basic-rules.scss
@@ -7,18 +7,24 @@
.button-primary {
@include buttonStyle;
@include flexCenter;
+ background-color: var(--button-primary-background-color-rest);
+ border: $s-1 solid var(--button-primary-border-color-rest);
+ color: var(--button-primary-foreground-color-rest);
&:hover {
- background-color: var(--button-background-hover);
+ background-color: var(--button-primary-background-color-hover);
+ border: $s-1 solid var(--button-primary-border-color-hover);
+ color: var(--button-primary-foreground-color-hover);
svg {
- stroke: var(--button-foreground-hover);
+ stroke: var(--button-primary-foreground-color-hover);
}
}
&:focus {
outline: none;
- border: 1px solid var(--button-border-focus);
- background-color: var(--button-background-focus);
+ background-color: var(--button-primary-background-color-focus);
+ border: $s-1 solid var(--button-primary-boder-color-focus);
+ color: var(--button-primary-foreground-color-focus);
svg {
- stroke: var(--button-foreground-focus);
+ stroke: var(--button-primary-foreground-color-focus);
}
}
&:active {
@@ -32,6 +38,73 @@
}
.button-secondary {
+ @include buttonStyle;
+ @include flexCenter;
+ background-color: var(--button-secondary-background-color-rest);
+ border: $s-1 solid var(--button-secondary-border-color-rest);
+ color: var(--button-secondary-foreground-color-rest);
+ &:hover {
+ background-color: var(--button-secondary-background-color-hover);
+ border: $s-1 solid var(--button-secondary-border-color-hover);
+ color: var(--button-secondary-foreground-color-hover);
+ svg,
+ span svg {
+ stroke: var(--button-secondary-foreground-color-hover);
+ }
+ }
+ &:focus {
+ outline: none;
+ background-color: var(--button-secondary-background-color-focus);
+ border: $s-1 solid var(--button-secondary-boder-color-focus);
+ color: var(--button-secondary-foreground-color-focus);
+ svg {
+ stroke: var(--button-secondary-foreground-color-focus);
+ }
+ }
+ &:active {
+ border: none;
+ background-color: transparent;
+ }
+ &:focus-visible {
+ border: none;
+ outline: none;
+ }
+}
+
+.button-tertiary {
+ @include buttonStyle;
+ @include flexCenter;
+ color: var(--button-tertiary-foreground-color-rest);
+ svg {
+ stroke: var(--button-tertiary-foreground-color-rest);
+ }
+ &:hover {
+ background-color: var(--button-tertiary-background-color-hover);
+ color: var(--button-tertiary-foreground-color-hover);
+ svg {
+ stroke: var(--button-tertiary-foreground-color-hover);
+ }
+ }
+ &:focus {
+ outline: none;
+ border: $s-1 solid var(--button-tertiary-border-color-focus);
+ background-color: var(--button-tertiary-background-color-focus);
+ color: var(--button-tertiary-foreground-color-focus);
+ svg {
+ stroke: var(--button-tertiary-foreground-color-focus);
+ }
+ }
+ &:active {
+ border: $s-1 solid var(--button-tertiary-border-color-focus);
+ outline: none;
+ }
+ &:focus-visible {
+ border: none;
+ outline: none;
+ }
+}
+
+.button-tag {
@include buttonStyle;
@include flexCenter;
&:hover {
@@ -73,3 +146,20 @@
width: $s-12;
stroke-width: 1.33px;
}
+
+.asset-element {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ border-radius: $br-8;
+ margin-bottom: $s-4;
+ padding: $s-8 $s-12;
+ background-color: var(--assets-item-background-color);
+ color: var(--assets-item-name-foreground-color);
+ &:hover,
+ &:focus-within {
+ background-color: var(--assets-item-background-color-hover);
+ color: var(--assets-item-name-foreground-color-hover);
+ }
+}
diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss
index 1f21439317..ccd8ea3281 100644
--- a/frontend/resources/styles/common/refactor/design-tokens.scss
+++ b/frontend/resources/styles/common/refactor/design-tokens.scss
@@ -8,15 +8,53 @@
.light,
.default {
--scrollbar-background-color: var(--color-foreground-secondary);
- --button-background-active: var(--color-background-primary);
+
--button-background-hover: var(--color-background-quaternary);
--button-foreground-hover: var(--color-accent-primary);
--button-foreground-active: var(--color-foreground-primary);
--button-background-focus: var(--color-background-secondary);
--button-foreground-focus: var(--color-foreground-primary);
--button-border-focus: var(--color-accent-primary);
+ --button-border: var(--color-background-tertiary);
--button-foreground-color-disabled: var(--color-background-quaternary);
+ --button-primary-background-color-rest: var(--color-accent-primary);
+ --button-primary-border-color-rest: var(--color-accent-primary);
+ --button-primary-foreground-color-rest: var(--color-background-secondary);
+ --button-primary-background-color-hover: var(--color-accent-tertiary);
+ --button-primary-border-color-hover: var(--color-accent-tertiary);
+ --button-primary-foreground-color-hover: var(--color-background-secondary);
+ --button-primary-background-color-selected: var(--color-background-secondary);
+ --button-primary-border-color-selected: var(--color-background-secondary);
+ --button-primary-foreground-color-selected: var(--color-accent-primary);
+ --button-primary-background-color-focus: var(--color-background-tertiary);
+ --button-primary-border-color-focus: var(--color-accent-primary);
+ --button-primary-foreground-color-focus: var(--color-foreground-secondary);
+
+ --button-secondary-background-color-rest: var(--color-background-tertiary);
+ --button-secondary-border-color-rest: var(--color-background-quaternary);
+ --button-secondary-foreground-color-rest: var(--color-foreground-secondary);
+ --button-secondary-background-color-hover: var(--color-background-quaternary);
+ --button-secondary-border-color-hover: var(--color-background-quaternary);
+ --button-secondary-foreground-color-hover: var(--color-accent-primary);
+ --button-secondary-background-color-selected: var(--color-background-secondary);
+ --button-secondary-border-color-selected: var(--color-background-quaternary);
+ --button-secondary-foreground-color-selected: var(--color-accent-primary);
+ --button-secondary-background-color-focus: var(--color-background-tertiary);
+ --button-secondary-border-color-focus: var(--color-accent-primary);
+ --button-secondary-foreground-color-focus: var(--color-foreground-secondary);
+
+ --button-tertiary-foreground-color-rest: var(--color-foreground-secondary);
+ --button-tertiary-background-color-hover: var(--color-background-quaternary);
+ --button-tertiary-border-color-hover: var(--color-background-quaternary);
+ --button-tertiary-foreground-color-hover: var(--color-accent-primary);
+ --button-tertiary-background-color-selected: var(--color-background-secondary);
+ --button-tertiary-border-color-selected: var(--color-background-quaternary);
+ --button-tertiary-foreground-color-selected: var(--color-accent-primary);
+ --button-tertiary-background-color-focus: var(--color-background-tertiary);
+ --button-tertiary-border-color-focus: var(--color-accent-primary);
+ --button-tertiary-foreground-color-focus: var(--color-foreground-primary);
+
--icon-foreground: var(--color-foreground-secondary);
--icon-foreground-hover: var(--color-foreground-primary);
@@ -29,6 +67,7 @@
--title-background-color: var(--color-background-secondary);
--title-foreground-color: var(--color-foreground-secondary);
--title-foreground-color-hover: var(--color-foreground-primary);
+ --title-background-color: var(--color-background-primary);
--layer-row-background-color: var(--color-background-primary);
--layer-row-background-color-hover: var(--color-background-secondary);
@@ -44,13 +83,17 @@
--layer-child-row-foreground-color: var(--color-foreground-secondary);
--layer-row-component-foreground-color: var(--color-accent-secondary);
+ --search-bar-background-color: var(--color-background-primary);
+ --search-bar-input-background-color: var(--color-background-tertiary);
+ --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-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-primary);
+ --input-foreground-color: var(--color-foreground-secondary);
--input-foreground-color-active: var(--color-foreground-primary);
--input-border-color-active: var(--color-accent-primary);
--input-border-outline-color-active: var(--color-accent-primary-muted);
@@ -95,4 +138,26 @@
--color-bullet-background-color: var(--white); // We don't want this color to change with palette
--color-bullet-border-color: var(--color-background-quaternary);
--palette-handler-background-color: var(--color-background-quaternary);
+
+ --assets-item-background-color: var(--color-background-tertiary);
+ --assets-item-background-color-hover: var(--color-background-quaternary);
+ --assets-item-name-foreground-color: var(--color-foreground-secondary);
+ --assets-item-name-foreground-color-hover: var(--color-foreground-primary);
+ --assets-item-border-color: var(--color-accent-primary);
+ --assets-item-background-color-drag: var(--color-accent-primary-muted);
+ --assets-item-border-color-drag: var(--color-accent-primary);
+ --assets-component-background-color: var(--white); // We don't want this color to change with palette
+
+ --radio-btns-background-color: var(--color-background-tertiary);
+ --radio-btn-background-color-selected: var(--color-background-primary);
+ --radio-btn-foreground-color: var(--color-foreground-secondary);
+ --radio-btn-foreground-color-selected: var(--color-accent-primary);
+ --radio-btn-border-color-selected: var(--color-background-quaternary);
+
+ --modal-background-color: var(--color-background-primary);
+
+ --library-name-foreground-color: var(--color-foreground-primary);
+ --library-content-foreground-color: var(--color-foreground-secondary);
+
+ --dropdown-background-color: var(--color-background-tertiary);
}
diff --git a/frontend/resources/styles/common/refactor/fonts.scss b/frontend/resources/styles/common/refactor/fonts.scss
index d60499e2d4..ebc5b5e150 100644
--- a/frontend/resources/styles/common/refactor/fonts.scss
+++ b/frontend/resources/styles/common/refactor/fonts.scss
@@ -20,6 +20,7 @@ $fs-9: math.div(9, $fs-base) + rem;
$fs-10: math.div(10, $fs-base) + rem;
$fs-12: math.div(12, $fs-base) + rem;
$fs-14: math.div(14, $fs-base) + rem;
+$fs-16: math.div(16, $fs-base) + rem;
$fs-19: math.div(19, $fs-base) + rem;
$fs-25: math.div(25, $fs-base) + rem;
$fs-33: math.div(33, $fs-base) + rem;
diff --git a/frontend/resources/styles/common/refactor/mixins.scss b/frontend/resources/styles/common/refactor/mixins.scss
index 9aa19c9bae..3c48959eab 100644
--- a/frontend/resources/styles/common/refactor/mixins.scss
+++ b/frontend/resources/styles/common/refactor/mixins.scss
@@ -15,6 +15,11 @@
background: none;
cursor: pointer;
}
+@mixin removeInputStyle {
+ border: none;
+ background: none;
+ outline: none;
+}
@mixin tabTitleTipography {
font-family: "worksans", sans-serif;
diff --git a/frontend/resources/styles/common/refactor/spacing.scss b/frontend/resources/styles/common/refactor/spacing.scss
index 81180d27df..bcf9ed6288 100644
--- a/frontend/resources/styles/common/refactor/spacing.scss
+++ b/frontend/resources/styles/common/refactor/spacing.scss
@@ -7,6 +7,7 @@
@use "sass:math";
$s-0: 0px;
+$s-1: 1px;
$s-2: math.div(0.25rem, 2);
$s-4: var(--s-4);
$s-6: calc($s-2 + $s-4);
@@ -29,13 +30,22 @@ $s-68: calc(var(--s-4) * 17);
$s-72: calc(var(--s-4) * 18);
$s-76: calc(var(--s-4) * 19);
$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-104: calc(var(--s-4) * 25);
$s-120: calc(var(--s-4) * 30);
$s-136: calc(var(--s-4) * 34);
$s-152: calc(var(--s-4) * 38);
$s-192: calc(var(--s-4) * 48);
+$s-196: calc(var(--s-4) * 49);
+$s-200: calc(var(--s-4) * 50);
+$s-216: calc(var(--s-4) * 54);
$s-240: calc(var(--s-4) * 60);
-$s-248: calc(var(--s-4) * 61);
+$s-248: calc(var(--s-4) * 62);
+$s-256: calc(var(--s-4) * 64);
+$s-348: calc(var(--s-4) * 87);
+$s-400: calc(var(--s-4) * 100);
$s-480: calc(var(--s-4) * 120);
+$s-664: calc(var(--s-4) * 166);
$s-736: calc(var(--s-4) * 184);
diff --git a/frontend/resources/styles/common/refactor/themes/default-theme.scss b/frontend/resources/styles/common/refactor/themes/default-theme.scss
index 2b6e09f98d..f116aa0933 100644
--- a/frontend/resources/styles/common/refactor/themes/default-theme.scss
+++ b/frontend/resources/styles/common/refactor/themes/default-theme.scss
@@ -16,4 +16,5 @@
--color-accent-primary-muted: var(--green-30);
--color-accent-secondary: var(--lilac);
--color-accent-tertiary: var(--strong-green);
+ --overlay-color: rgba(0, 0, 0, 0.4);
}
diff --git a/frontend/resources/styles/common/refactor/z-index.scss b/frontend/resources/styles/common/refactor/z-index.scss
index 876b035d62..c159be3e9d 100644
--- a/frontend/resources/styles/common/refactor/z-index.scss
+++ b/frontend/resources/styles/common/refactor/z-index.scss
@@ -9,3 +9,4 @@ $z-index-2: 2;
$z-index-4: 4;
$z-index-10: 10;
$z-index-20: 20;
+$z-index-modal: 30; // When refactor finish we can reduce this number,
diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs
index 7528fdcd3a..baf740baa6 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -7,6 +7,7 @@
(ns app.main.ui
(:require
[app.config :as cf]
+ [app.main.features :as features]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.auth :refer [auth]]
@@ -37,8 +38,10 @@
(mf/defc main-page
{::mf/wrap [#(mf/catch % {:fallback on-main-error})]}
[{:keys [route profile]}]
- (let [{:keys [data params]} route]
+ (let [{:keys [data params]} route
+ new-css-system (features/use-feature :new-css-system)]
[:& (mf/provider ctx/current-route) {:value route}
+ [:& (mf/provider ctx/new-css-system) {:value new-css-system}
(case (:name data)
(:auth-login
:auth-register
@@ -131,7 +134,7 @@
:page-id page-id
:layout-name layout
:key file-id}])
- nil)]))
+ nil)]]))
(mf/defc app
[]
diff --git a/frontend/src/app/main/ui/components/color_bullet_new.css.json b/frontend/src/app/main/ui/components/color_bullet_new.css.json
index 04e955d8e4..c8e23cac52 100644
--- a/frontend/src/app/main/ui/components/color_bullet_new.css.json
+++ b/frontend/src/app/main/ui/components/color_bullet_new.css.json
@@ -1 +1 @@
-{"button-primary":"components_color_bullet_new_button-primary_pDkQg","button-secondary":"components_color_bullet_new_button-secondary_y3A8V","button-icon":"components_color_bullet_new_button-icon_uAC1e","button-icon-small":"components_color_bullet_new_button-icon-small_rz5pc","color-bullet":"components_color_bullet_new_color-bullet_b1w8U","mini":"components_color_bullet_new_mini_B261Z","is-not-library-color":"components_color_bullet_new_is-not-library-color_PSveA","color-bullet-wrapper":"components_color_bullet_new_color-bullet-wrapper_clt4r","is-gradient":"components_color_bullet_new_is-gradient_6RdV2","is-transparent":"components_color_bullet_new_is-transparent_g0iwn","color-text":"components_color_bullet_new_color-text_HM6mp","small-text":"components_color_bullet_new_small-text_Y4OeK","no-text":"components_color_bullet_new_no-text_pbTQf"}
\ No newline at end of file
+{"button-primary":"components_color_bullet_new_button-primary_pDkQg","button-secondary":"components_color_bullet_new_button-secondary_y3A8V","button-tertiary":"components_color_bullet_new_button-tertiary_zPQ8t","button-tag":"components_color_bullet_new_button-tag_2Ur4i","button-icon":"components_color_bullet_new_button-icon_uAC1e","button-icon-small":"components_color_bullet_new_button-icon-small_rz5pc","asset-element":"components_color_bullet_new_asset-element_s3Yqx","color-bullet":"components_color_bullet_new_color-bullet_b1w8U","mini":"components_color_bullet_new_mini_B261Z","is-not-library-color":"components_color_bullet_new_is-not-library-color_PSveA","color-bullet-wrapper":"components_color_bullet_new_color-bullet-wrapper_clt4r","is-gradient":"components_color_bullet_new_is-gradient_6RdV2","is-transparent":"components_color_bullet_new_is-transparent_g0iwn","color-text":"components_color_bullet_new_color-text_HM6mp","small-text":"components_color_bullet_new_small-text_Y4OeK","no-text":"components_color_bullet_new_no-text_pbTQf"}
\ No newline at end of file
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 66e21258a5..ea0276cb0d 100644
--- a/frontend/src/app/main/ui/components/color_bullet_new.scss
+++ b/frontend/src/app/main/ui/components/color_bullet_new.scss
@@ -10,12 +10,15 @@
position: relative;
display: flex;
flex-direction: row;
- width: var(--bullet-size);
- height: var(--bullet-size);
+ width: var(--bullet-size, $s-24);
+ height: var(--bullet-size, $s-24);
margin-top: $s-4;
border: $s-2 solid var(--color-bullet-border-color);
border-radius: $br-circle;
&.mini {
+ width: var(--bullet-size, $s-16);
+ height: var(--bullet-size, $s-16);
+ margin-top: 0;
border: 1px solid var(--color-bullet-border-color);
}
diff --git a/frontend/src/app/main/ui/components/context_menu_a11y.cljs b/frontend/src/app/main/ui/components/context_menu_a11y.cljs
index 7bdd05ff57..8cd5536d2f 100644
--- a/frontend/src/app/main/ui/components/context_menu_a11y.cljs
+++ b/frontend/src/app/main/ui/components/context_menu_a11y.cljs
@@ -258,6 +258,7 @@
:key id
:class (if (and new-css-system workspace?)
(dom/classnames (css :is-selected) (and selected (= option-name selected))
+ (css :selected) (and selected (= data-test selected))
(css :context-menu-item) true)
(dom/classnames :is-selected (and selected (= option-name selected))))
:key-index (dm/str "context-item-" index)
@@ -274,7 +275,11 @@
:data-test data-test}
(if (and in-dashboard? (= option-name "Default"))
(tr "dashboard.default-team-name")
- option-name)]
+ option-name)
+
+ (when (and new-css-system selected (= data-test selected))
+ [:span {:class (dom/classnames (css :selected-icon) true)}
+ i/tick-refactor])]
[:a {:class (if (and new-css-system workspace?)
(dom/classnames (css :context-menu-action) true
(css :submenu) true)
@@ -289,7 +294,6 @@
i/arrow-refactor
i/arrow-slide)]])]))))])])])))
-
(mf/defc context-menu-a11y
{::mf/wrap-props false}
[props]
diff --git a/frontend/src/app/main/ui/components/context_menu_a11y.css.json b/frontend/src/app/main/ui/components/context_menu_a11y.css.json
index 480fdf318b..98dcbca412 100644
--- a/frontend/src/app/main/ui/components/context_menu_a11y.css.json
+++ b/frontend/src/app/main/ui/components/context_menu_a11y.css.json
@@ -1 +1 @@
-{"button-primary":"components_context_menu_a11y_button-primary_FTrG6","button-secondary":"components_context_menu_a11y_button-secondary_tIeiM","button-icon":"components_context_menu_a11y_button-icon_eOLGl","button-icon-small":"components_context_menu_a11y_button-icon-small_bQvvB","context-menu":"components_context_menu_a11y_context-menu_bS2vM","context-menu-items":"components_context_menu_a11y_context-menu-items_lQC7H","context-menu-item":"components_context_menu_a11y_context-menu-item_E2GpJ","context-menu-action":"components_context_menu_a11y_context-menu-action_E53yg","submenu-back":"components_context_menu_a11y_submenu-back_AboXg","submenu-icon-back":"components_context_menu_a11y_submenu-icon-back_gy-B6","submenu":"components_context_menu_a11y_submenu_MuyM8","submenu-icon":"components_context_menu_a11y_submenu-icon_tWTVU","is-open":"components_context_menu_a11y_is-open_FbqIp","fixed":"components_context_menu_a11y_fixed_iJxPr","separator":"components_context_menu_a11y_separator_DrZoB","min-width":"components_context_menu_a11y_min-width_w-ron","is-selected":"components_context_menu_a11y_is-selected_UPMXx","is-selectable":"components_context_menu_a11y_is-selectable_n7sdb"}
\ No newline at end of file
+{"button-primary":"components_context_menu_a11y_button-primary_FTrG6","button-secondary":"components_context_menu_a11y_button-secondary_tIeiM","button-tertiary":"components_context_menu_a11y_button-tertiary_0A2mW","button-tag":"components_context_menu_a11y_button-tag_iLpM-","context-menu":"components_context_menu_a11y_context-menu_bS2vM","context-menu-items":"components_context_menu_a11y_context-menu-items_lQC7H","context-menu-item":"components_context_menu_a11y_context-menu-item_E2GpJ","selected":"components_context_menu_a11y_selected_on-en","selected-icon":"components_context_menu_a11y_selected-icon_H2S7W","button-icon":"components_context_menu_a11y_button-icon_eOLGl","button-icon-small":"components_context_menu_a11y_button-icon-small_bQvvB","context-menu-action":"components_context_menu_a11y_context-menu-action_E53yg","submenu-back":"components_context_menu_a11y_submenu-back_AboXg","submenu-icon-back":"components_context_menu_a11y_submenu-icon-back_gy-B6","submenu":"components_context_menu_a11y_submenu_MuyM8","submenu-icon":"components_context_menu_a11y_submenu-icon_tWTVU","asset-element":"components_context_menu_a11y_asset-element_r3q1-","is-open":"components_context_menu_a11y_is-open_FbqIp","fixed":"components_context_menu_a11y_fixed_iJxPr","separator":"components_context_menu_a11y_separator_DrZoB","min-width":"components_context_menu_a11y_min-width_w-ron","is-selected":"components_context_menu_a11y_is-selected_UPMXx","is-selectable":"components_context_menu_a11y_is-selectable_n7sdb"}
\ No newline at end of file
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 f62c2f3dc5..6eb30fce94 100644
--- a/frontend/src/app/main/ui/components/context_menu_a11y.scss
+++ b/frontend/src/app/main/ui/components/context_menu_a11y.scss
@@ -109,6 +109,21 @@
}
}
}
+ &.selected {
+ .context-menu-action {
+ justify-content: space-between;
+ color: var(--menu-foreground-color-focus);
+ }
+ .selected-icon {
+ @extend .button-tag;
+ border-radius: $br-8;
+ height: 100%;
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color-focus);
+ }
+ }
+ }
}
.is-selected .context-menu-action {
padding-left: $s-28;
diff --git a/frontend/src/app/main/ui/components/editable_label.cljs b/frontend/src/app/main/ui/components/editable_label.cljs
index de24d8848c..5100482393 100644
--- a/frontend/src/app/main/ui/components/editable_label.cljs
+++ b/frontend/src/app/main/ui/components/editable_label.cljs
@@ -6,6 +6,7 @@
(ns app.main.ui.components.editable-label
(:require
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
@@ -18,6 +19,7 @@
tooltip (get props :tooltip)
input (mf/use-ref nil)
state (mf/use-state (:editing false))
+ new-css-system (mf/use-ctx ctx/new-css-system)
is-editing (:editing @state)
start-editing (fn []
(swap! state assoc :editing true)
@@ -52,7 +54,11 @@
:default-value value
:on-key-up on-key-up
:on-blur cancel-editing}]
- [:span.editable-label-close {:on-click cancel-editing} i/close]]
+
+ [:span.editable-label-close {:on-click cancel-editing}
+ (if new-css-system
+ i/delete-text-refactor
+ i/close)]]
[:span.editable-label {:class class-name
:title tooltip
:on-double-click on-dbl-click} display-value])))
diff --git a/frontend/src/app/main/ui/components/editable_label.css.json b/frontend/src/app/main/ui/components/editable_label.css.json
new file mode 100644
index 0000000000..fce3a08610
--- /dev/null
+++ b/frontend/src/app/main/ui/components/editable_label.css.json
@@ -0,0 +1 @@
+{"button-primary":"components_editable_label_button-primary_fp-ma","button-secondary":"components_editable_label_button-secondary_QPaT-","button-tertiary":"components_editable_label_button-tertiary_wOORv","button-tag":"components_editable_label_button-tag_pwEqY","button-icon":"components_editable_label_button-icon_acX7H","button-icon-small":"components_editable_label_button-icon-small_tSz5O","asset-element":"components_editable_label_asset-element_Bs5bh","editable-label-input":"components_editable_label_editable-label-input_q2Puk"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/editable_label.scss b/frontend/src/app/main/ui/components/editable_label.scss
new file mode 100644
index 0000000000..04b36e4825
--- /dev/null
+++ b/frontend/src/app/main/ui/components/editable_label.scss
@@ -0,0 +1,21 @@
+// 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-label-input {
+ @include textEllipsis;
+ @include titleTipography;
+ @include removeInputStyle;
+ flex-grow: 1;
+ height: $s-28;
+ max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
+ margin: 0;
+ padding-left: $s-6;
+ border-radius: $br-8;
+ border: $s-1 solid var(--input-border-color-focus);
+ color: var(--layer-row-foreground-color);
+}
diff --git a/frontend/src/app/main/ui/components/numeric_input.cljs b/frontend/src/app/main/ui/components/numeric_input.cljs
index cdc4ad970e..93125b5e12 100644
--- a/frontend/src/app/main/ui/components/numeric_input.cljs
+++ b/frontend/src/app/main/ui/components/numeric_input.cljs
@@ -35,6 +35,7 @@
default-val (obj/get props "default")
nillable (obj/get props "nillable")
select-on-focus? (obj/get props "data-select-on-focus" true)
+ class (obj/get props "klass")
;; We need a ref pointing to the input dom element, but the user
;; of this component may provide one (that is forwarded here).
@@ -218,7 +219,7 @@
props (-> props
(obj/without ["value" "onChange" "nillable" "onFocus"])
- (obj/set! "className" "input-text")
+ (obj/set! "className" (or class "input-text"))
(obj/set! "type" "text")
(obj/set! "ref" ref)
(obj/set! "defaultValue" (fmt/format-number value))
diff --git a/frontend/src/app/main/ui/components/radio_buttons.cljs b/frontend/src/app/main/ui/components/radio_buttons.cljs
new file mode 100644
index 0000000000..40784e6232
--- /dev/null
+++ b/frontend/src/app/main/ui/components/radio_buttons.cljs
@@ -0,0 +1,78 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.components.radio-buttons
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.math :as math]
+ [app.main.ui.formats :as fmt]
+ [app.util.dom :as dom]
+ [rumext.v2 :as mf]))
+
+(def ctx-radio-button (mf/create-context nil))
+
+(mf/defc radio-button
+ {::mf/wrap-props false}
+ [props]
+ (let [ctx (mf/use-ctx ctx-radio-button)
+ icon (unchecked-get props "icon")
+ id (unchecked-get props "id")
+ on-change (:on-change ctx)
+ selected (:selected ctx)
+ value (unchecked-get props "value")
+ checked? (= selected value)
+ name (:name ctx)]
+ [:label {:for id
+ :class (dom/classnames (css :radio-icon) true
+ (css :checked) checked?)}
+ icon
+ [:input {:id id
+ :on-change on-change
+ :type "radio"
+ :name name
+ :value value
+ :checked checked?}]]))
+
+(mf/defc nilable-option
+ {::mf/wrap-props false}
+ [props]
+ (let [ctx (mf/use-ctx ctx-radio-button)
+ icon (unchecked-get props "icon")
+ id (unchecked-get props "id")
+ on-change (:on-change ctx)
+ selected (:selected ctx)
+ value (unchecked-get props "value")
+ checked? (= selected value)
+ name (:name ctx)]
+ [:label {:for id
+ :class (dom/classnames (css :radio-icon) true
+ (css :checked) checked?)}
+ icon
+ [:input {:id id
+ :on-change on-change
+ :type "checkbox"
+ :name name
+ :value value
+ :checked checked?}]]))
+
+(mf/defc radio-buttons
+ {::mf/wrap-props false}
+ [props]
+ (let [children (unchecked-get props "children")
+ on-change (unchecked-get props "on-change")
+ selected (unchecked-get props "selected")
+ name (unchecked-get props "name")
+ calculate-width (fmt/format-pixels (+ (math/pow 2 (count children)) (* 28 (count children))))
+ handle-change
+ (mf/use-fn
+ (mf/deps on-change)
+ (fn [event]
+ (let [value (dom/get-target-val event)]
+ (on-change value event))))]
+ [:& (mf/provider ctx-radio-button) {:value {:selected selected :on-change handle-change :name name}}
+ [:div {:class (css :radio-btn-wrapper)
+ :style {:width calculate-width}}
+ children]]))
diff --git a/frontend/src/app/main/ui/components/radio_buttons.css.json b/frontend/src/app/main/ui/components/radio_buttons.css.json
new file mode 100644
index 0000000000..f806818d33
--- /dev/null
+++ b/frontend/src/app/main/ui/components/radio_buttons.css.json
@@ -0,0 +1 @@
+{"button-primary":"components_radio_buttons_button-primary_-XZNO","button-secondary":"components_radio_buttons_button-secondary_yj3Oe","button-tertiary":"components_radio_buttons_button-tertiary_s2RvI","radio-icon":"components_radio_buttons_radio-icon_1OnG1","button-tag":"components_radio_buttons_button-tag_4VTp-","button-icon":"components_radio_buttons_button-icon_jP0XC","button-icon-small":"components_radio_buttons_button-icon-small_3AO-R","asset-element":"components_radio_buttons_asset-element_l2wMX","radio-btn-wrapper":"components_radio_buttons_radio-btn-wrapper_mH6QX","checked":"components_radio_buttons_checked_sjVzy"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/radio_buttons.scss b/frontend/src/app/main/ui/components/radio_buttons.scss
new file mode 100644
index 0000000000..6d37280b1f
--- /dev/null
+++ b/frontend/src/app/main/ui/components/radio_buttons.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";
+
+.radio-btn-wrapper {
+ @include flexCenter;
+ border-radius: $br-8;
+ height: $s-32;
+ background-color: var(--radio-btns-background-color);
+}
+.radio-icon {
+ @extend .button-tertiary;
+ height: $s-28;
+ width: 100%;
+ border-radius: $s-6;
+ border: solid $s-2 transparent;
+ box-sizing: content-box;
+ input {
+ display: none;
+ }
+ svg {
+ @extend .button-icon;
+ stroke: var(--radio-btn-foreground-color);
+ }
+ &:hover {
+ border: solid $s-2 var(--radio-btns-background-color);
+ }
+ &.checked {
+ background-color: var(--radio-btn-background-color-selected);
+ border: $s-2 solid var(--radio-btn-border-color-selected);
+ svg {
+ stroke: var(--radio-btn-foreground-color-selected);
+ }
+ &:hover {
+ border: $s-2 solid var(--radio-btn-border-color-selected);
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/components/search_bar.cljs b/frontend/src/app/main/ui/components/search_bar.cljs
new file mode 100644
index 0000000000..607a2f4604
--- /dev/null
+++ b/frontend/src/app/main/ui/components/search_bar.cljs
@@ -0,0 +1,60 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.components.search-bar
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.main.ui.icons :as i]
+ [app.util.dom :as dom]
+ [app.util.keyboard :as kbd]
+ [rumext.v2 :as mf]))
+
+(mf/defc search-bar
+ {::mf/wrap-props false}
+ [props]
+ (let [children (unchecked-get props "children")
+ on-change (unchecked-get props "on-change")
+ value (unchecked-get props "value")
+ on-clear (unchecked-get props "clear-action")
+ placeholder (unchecked-get props "placeholder")
+ icon (unchecked-get props "icon")
+
+ handle-change
+ (mf/use-fn
+ (mf/deps on-change)
+ (fn [event]
+ (let [value (dom/get-target-val event)]
+ (on-change value event))))
+
+ handle-clear
+ (mf/use-fn
+ (mf/deps on-clear on-change)
+ (fn [event]
+ (if on-clear
+ (on-clear event)
+ (on-change "" event))))
+
+ handle-key-down
+ (mf/use-fn
+ (fn [event]
+ (let [enter? (kbd/enter? event)
+ esc? (kbd/esc? event)
+ node (dom/event->target event)]
+ (when ^boolean enter? (dom/blur! node))
+ (when ^boolean esc? (dom/blur! node)))))]
+ [:span {:class (dom/classnames (css :search-box) true
+ (css :has-children) (some? children))}
+ children
+ [:div {:class (dom/classnames (css :search-input-wrapper) true)}
+ icon
+ [:input {:on-change handle-change
+ :value value
+ :placeholder placeholder
+ :on-key-down handle-key-down}]
+ (when (not= "" value)
+ [:button {:class (dom/classnames (css :clear) true)
+ :on-click handle-clear}
+ i/delete-text-refactor])]]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/search_bar.css.json b/frontend/src/app/main/ui/components/search_bar.css.json
new file mode 100644
index 0000000000..e329b342a2
--- /dev/null
+++ b/frontend/src/app/main/ui/components/search_bar.css.json
@@ -0,0 +1 @@
+{"button-primary":"components_search_bar_button-primary_-9D1J","button-secondary":"components_search_bar_button-secondary_GbDgI","button-tertiary":"components_search_bar_button-tertiary_VTCfX","button-tag":"components_search_bar_button-tag_dKink","search-box":"components_search_bar_search-box_AFEzz","search-input-wrapper":"components_search_bar_search-input-wrapper_Djsml","clear":"components_search_bar_clear_B6lfz","button-icon":"components_search_bar_button-icon_CdwNa","button-icon-small":"components_search_bar_button-icon-small_gSOsT","asset-element":"components_search_bar_asset-element_rH-5k","has-children":"components_search_bar_has-children_u-VSq"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/search_bar.scss b/frontend/src/app/main/ui/components/search_bar.scss
new file mode 100644
index 0000000000..671ec54b91
--- /dev/null
+++ b/frontend/src/app/main/ui/components/search_bar.scss
@@ -0,0 +1,66 @@
+// 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";
+
+.search-box {
+ display: flex;
+ gap: $s-2;
+ height: $s-32;
+ width: 100%;
+ border-radius: $br-8;
+ background-color: var(--search-bar-background-color);
+
+ .search-input-wrapper {
+ @include flexCenter;
+ height: $s-32;
+ width: 100%;
+ border: $s-1 solid var(--search-bar-input-border-color);
+ border-radius: $br-8;
+ background-color: var(--search-bar-input-background-color);
+ input {
+ width: 100%;
+ height: 100%;
+ margin: 0 $s-8 0 $s-4;
+ border: 0;
+ background-color: var(--input-background-color);
+ font-size: $fs-12;
+ color: var(--input-foreground-color);
+ &:focus {
+ outline: none;
+ }
+ }
+ &:hover {
+ border: $s-1 solid var(--input-background-color-hover);
+ background-color: var(--input-background-color-hover);
+ input {
+ background-color: var(--input-background-color-hover);
+ }
+ }
+ &:focus-within {
+ background-color: var(--input-background-color-active);
+ color: var(--input-foreground-color-active);
+ border: $s-1 solid var(--input-border-color-focus);
+ input {
+ background-color: var(--input-background-color-active);
+ }
+ }
+
+ .clear {
+ @extend .button-tag;
+ border-radius: $br-8;
+ height: 100%;
+ svg {
+ @extend .button-icon-small;
+ color: transparent;
+ }
+ }
+ }
+ &.has-children .search-input-wrapper {
+ border-radius: $br-2 $br-8 $br-8 $br-2;
+ margin-left: 0;
+ }
+}
diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs
index cdb88fd037..e00aa2edb0 100644
--- a/frontend/src/app/main/ui/components/select.cljs
+++ b/frontend/src/app/main/ui/components/select.cljs
@@ -5,11 +5,13 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.components.select
+ (:require-macros [app.main.style :refer [css]])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.uuid :as uuid]
[app.main.ui.components.dropdown :refer [dropdown]]
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[rumext.v2 :as mf]))
@@ -22,7 +24,8 @@
(mf/defc select
[{:keys [default-value options class is-open? on-change on-pointer-enter-option on-pointer-leave-option]}]
- (let [label-index (mf/with-memo [options]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ label-index (mf/with-memo [options]
(into {} (map as-key-value) options))
state* (mf/use-state
@@ -73,22 +76,46 @@
(mf/with-effect [default-value]
(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]
+ [:& dropdown {:show is-open? :on-close close-dropdown}
+ [:ul {:class (css :custom-select-dropdown)}
+ (for [[index item] (d/enumerate options)]
+ (if (= :separator item)
+ [:hr {: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))
+ :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]])))]]]
+
+
- [:div.custom-select {:on-click open-dropdown :class class}
- [:span current-label]
- [:span.dropdown-button i/arrow-down]
- [:& dropdown {:show is-open? :on-close close-dropdown}
- [:ul.custom-select-dropdown
- (for [[index item] (d/enumerate options)]
- (if (= :separator item)
- [:hr {:key (dm/str current-id "-" index)}]
- (let [[value label] (as-key-value item)]
- [:li.checked-element
- {:key (dm/str current-id "-" index)
- :class (when (= value current-value) "is-selected")
- :data-value (pr-str value)
- :on-pointer-enter highlight-item
- :on-pointer-leave unhighlight-item
- :on-click select-item}
- [:span.check-icon i/tick]
- [:span label]])))]]]))
+ [:div.custom-select {:on-click open-dropdown :class class}
+ [:span current-label]
+ [:span.dropdown-button i/arrow-down]
+ [:& dropdown {:show is-open? :on-close close-dropdown}
+ [:ul.custom-select-dropdown
+ (for [[index item] (d/enumerate options)]
+ (if (= :separator item)
+ [:hr {:key (dm/str current-id "-" index)}]
+ (let [[value label] (as-key-value item)]
+ [:li.checked-element
+ {:key (dm/str current-id "-" index)
+ :class (when (= value current-value) "is-selected")
+ :data-value (pr-str value)
+ :on-pointer-enter highlight-item
+ :on-pointer-leave unhighlight-item
+ :on-click select-item}
+ [:span.check-icon i/tick]
+ [:span label]])))]]])))
diff --git a/frontend/src/app/main/ui/components/select.css.json b/frontend/src/app/main/ui/components/select.css.json
new file mode 100644
index 0000000000..f9a8982329
--- /dev/null
+++ b/frontend/src/app/main/ui/components/select.css.json
@@ -0,0 +1 @@
+{"button-primary":"components_select_button-primary_peYzv","button-secondary":"components_select_button-secondary_Kse6w","button-tertiary":"components_select_button-tertiary_srwoV","button-tag":"components_select_button-tag_AJXtX","button-icon":"components_select_button-icon_86LWm","custom-select":"components_select_custom-select_OM8-6","dropdown-button":"components_select_dropdown-button_IcpuR","button-icon-small":"components_select_button-icon-small_H0Bue","checked-element":"components_select_checked-element_c5-i4","check-icon":"components_select_check-icon_9x082","asset-element":"components_select_asset-element_5vxj7","current-label":"components_select_current-label_CUaQs","custom-select-dropdown":"components_select_custom-select-dropdown_2yZj9","label":"components_select_label_kTY8t","is-selected":"components_select_is-selected_nTUGr"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/select.scss b/frontend/src/app/main/ui/components/select.scss
new file mode 100644
index 0000000000..0bc68cfa0a
--- /dev/null
+++ b/frontend/src/app/main/ui/components/select.scss
@@ -0,0 +1,84 @@
+// 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";
+
+.custom-select {
+ position: relative;
+ display: flex;
+ width: 100%;
+ padding: $s-8;
+ border-radius: $br-8;
+ cursor: pointer;
+ .current-label {
+ width: 100%;
+ flex-grow: 1;
+ }
+ .dropdown-button {
+ @include flexCenter;
+ svg {
+ @extend .button-icon;
+ transform: rotate(90deg);
+ }
+ }
+ .custom-select-dropdown {
+ 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-10;
+ overflow-y: auto;
+ background-color: var(--menu-background-color);
+ box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
+ }
+ .checked-element {
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ padding: $s-8;
+ border-radius: $br-6;
+ color: var(--menu-foreground-color);
+ .label {
+ flex-grow: 1;
+ width: 100%;
+ }
+
+ .check-icon {
+ @include flexCenter;
+ svg {
+ @extend .button-icon-small;
+ visibility: hidden;
+ }
+ }
+
+ &.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);
+ }
+ }
+ }
+
+ &:hover {
+ .dropdown-button {
+ color: var(--menu-foreground-color-hover);
+ svg {
+ stroke: var(--menu-foreground-color-hover);
+ }
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container.cljs
index 5bd44abecd..ea37a89f8b 100644
--- a/frontend/src/app/main/ui/components/tab_container.cljs
+++ b/frontend/src/app/main/ui/components/tab_container.cljs
@@ -35,10 +35,10 @@
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")
state (mf/use-state #(or selected (-> children first .-props .-id)))
selected (or selected @state)
- new-css-system (mf/use-ctx ctx/new-css-system)
select-fn
(mf/use-fn
@@ -48,42 +48,26 @@
(reset! state id)
(when (fn? on-change) (on-change id)))))]
- [:div {:class (if new-css-system
- (dom/classnames (css :tab-container) true)
- (dom/classnames :tab-container true))}
- [:div {:class (if new-css-system
- (dom/classnames (css :tab-container-tabs) true)
- (dom/classnames :tab-container-tabs true))}
- (when (and new-css-system collapsable?)
+ [:div {:class (dom/classnames (css :tab-container) true)}
+ [:div {:class (dom/classnames (css :tab-container-tabs) true
+ klass true)}
+ (when collapsable?
[:button
{:on-click handle-collapse
:class (dom/classnames (css :collapse-sidebar) true)
:aria-label (tr "workspace.sidebar.collapse")}
i/arrow-refactor])
- (if new-css-system
- [:div {:class (dom/classnames (css :tab-container-tab-wrapper) new-css-system)}
- (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)
- :on-click select-fn
- :class (dom/classnames (css :tab-container-tab-title) true
- (css :current) (= selected id))}
- title]))]
- (for [tab children]
- (let [props (.-props tab)
- id (.-id props)
- title (.-title props)]
- [:div.tab-container-tab-title
- {:key (str/concat "tab-" (d/name id))
- :data-id (pr-str id)
- :on-click select-fn
- :class (when (= selected id) "current")}
- title])))]
- [:div {:class (if new-css-system
- (dom/classnames (css :tab-container-content) true)
- (dom/classnames :tab-container-content true))}
+ [:div {:class (dom/classnames (css :tab-container-tab-wrapper) true)}
+ (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)
+ :on-click select-fn
+ :class (dom/classnames (css :tab-container-tab-title) true
+ (css :current) (= selected id))}
+ title]))]]
+ [:div {:class (dom/classnames (css :tab-container-content) true)}
(d/seek #(= selected (-> % .-props .-id)) children)]]))
diff --git a/frontend/src/app/main/ui/components/tab_container.css.json b/frontend/src/app/main/ui/components/tab_container.css.json
index 6a5fd88cd8..9d8e6e6bfd 100644
--- a/frontend/src/app/main/ui/components/tab_container.css.json
+++ b/frontend/src/app/main/ui/components/tab_container.css.json
@@ -1 +1 @@
-{"button-primary":"components_tab_container_button-primary_ibiAz","button-secondary":"components_tab_container_button-secondary_wZR80","button-icon":"components_tab_container_button-icon_2NhVr","button-icon-small":"components_tab_container_button-icon-small_yU7na","tab-container":"components_tab_container_tab-container_P6HRr","tab-container-content":"components_tab_container_tab-container-content_yfM9F","tab-element":"components_tab_container_tab-element_gBIwV","tab-container-tabs":"components_tab_container_tab-container-tabs_6gXOY","tab-container-tab-wrapper":"components_tab_container_tab-container-tab-wrapper_-ngrN","tab-container-tab-title":"components_tab_container_tab-container-tab-title_IN1Dx","current":"components_tab_container_current_jrovp","collapse-sidebar":"components_tab_container_collapse-sidebar_e5hFv","collapsed":"components_tab_container_collapsed_lfkjK"}
\ No newline at end of file
+{"button-primary":"components_tab_container_button-primary_ibiAz","button-secondary":"components_tab_container_button-secondary_wZR80","button-tertiary":"components_tab_container_button-tertiary_JHJAx","button-tag":"components_tab_container_button-tag_NnL8y","button-icon":"components_tab_container_button-icon_2NhVr","button-icon-small":"components_tab_container_button-icon-small_yU7na","asset-element":"components_tab_container_asset-element_1-YWa","tab-container":"components_tab_container_tab-container_P6HRr","tab-container-content":"components_tab_container_tab-container-content_yfM9F","tab-element":"components_tab_container_tab-element_gBIwV","tab-container-tabs":"components_tab_container_tab-container-tabs_6gXOY","tab-container-tab-wrapper":"components_tab_container_tab-container-tab-wrapper_-ngrN","tab-container-tab-title":"components_tab_container_tab-container-tab-title_IN1Dx","current":"components_tab_container_current_jrovp","collapse-sidebar":"components_tab_container_collapse-sidebar_e5hFv","collapsed":"components_tab_container_collapsed_lfkjK"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/tab_container.scss b/frontend/src/app/main/ui/components/tab_container.scss
index 23e941e3a2..d5263e34f6 100644
--- a/frontend/src/app/main/ui/components/tab_container.scss
+++ b/frontend/src/app/main/ui/components/tab_container.scss
@@ -26,8 +26,7 @@
flex-direction: row;
gap: $s-2;
height: $s-32;
- margin: $s-4 $s-4 0 $s-4;
- padding: $s-2 $s-2 $s-2 0;
+ padding: $s-2 $s-2 $s-2 $s-2;
border-radius: $br-8;
background: var(--color-background-secondary);
cursor: pointer;
@@ -43,10 +42,12 @@
@include tabTitleTipography;
height: $s-28;
width: 100%;
+ padding: 0 $s-8;
margin: 0;
border-radius: $br-5;
background-color: transparent;
color: var(--tab-foreground-color);
+ white-space: nowrap;
&.current,
&.current:hover {
@@ -63,12 +64,13 @@
@include buttonStyle;
height: 100%;
width: $s-24;
- padding: 0;
+ min-width: $s-24;
+ padding: 0 $s-6 0 0;
border-radius: $br-5;
svg {
@include flexCenter;
- height: 12px;
- width: 16px;
+ height: $s-16;
+ width: $s-16;
stroke: var(--icon-foreground);
transform: rotate(180deg);
fill: none;
@@ -83,6 +85,7 @@
&.collapsed {
svg {
transform: rotate(0deg);
+ padding: 0 0 0 $s-6;
}
}
}
diff --git a/frontend/src/app/main/ui/components/title_bar.cljs b/frontend/src/app/main/ui/components/title_bar.cljs
new file mode 100644
index 0000000000..303b80e5a5
--- /dev/null
+++ b/frontend/src/app/main/ui/components/title_bar.cljs
@@ -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
+
+(ns app.main.ui.components.title-bar
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.main.ui.icons :as i]
+ [app.util.dom :as dom]
+ [rumext.v2 :as mf]))
+
+(mf/defc title-bar
+ {::mf/wrap-props false}
+ [props]
+ (let [collapsable? (unchecked-get props "collapsable?")
+ collapsed? (unchecked-get props "collapsed?")
+ on-collapsed (unchecked-get props "on-collapsed")
+ title (unchecked-get props "title")
+ children (unchecked-get props "children")
+ on-btn-click (unchecked-get props "on-btn-click")
+ btn-children (unchecked-get props "btn-children")
+ klass (unchecked-get props "klass")]
+
+ [:div {:class (dom/classnames (css :title-bar) true
+ klass true)}
+ (if collapsable?
+ [:button {:class (dom/classnames (css :toggle-btn) true)
+ :on-click on-collapsed}
+ [:span {:class (dom/classnames (css :collased-icon) true
+ (css :rotated) collapsed?)}
+ i/arrow-refactor]
+ [:div {:class (dom/classnames (css :title) true)}
+ title]]
+ [:div {:class (dom/classnames (css :title-only) true)}
+ title])
+ children
+ (when (some? on-btn-click)
+ [:button {:class (dom/classnames (css :title-button) true)
+ :on-click on-btn-click}
+ btn-children])]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/title_bar.css.json b/frontend/src/app/main/ui/components/title_bar.css.json
new file mode 100644
index 0000000000..57d0368568
--- /dev/null
+++ b/frontend/src/app/main/ui/components/title_bar.css.json
@@ -0,0 +1 @@
+{"button-primary":"components_title_bar_button-primary_svLtU","button-secondary":"components_title_bar_button-secondary_JA5NP","button-tertiary":"components_title_bar_button-tertiary_yqQfO","title-bar":"components_title_bar_title-bar_oUkS0","title-button":"components_title_bar_title-button_xTE-7","button-tag":"components_title_bar_button-tag_o9yFT","button-icon":"components_title_bar_button-icon_ROHrz","button-icon-small":"components_title_bar_button-icon-small_WibJp","toggle-btn":"components_title_bar_toggle-btn_9ekUv","collased-icon":"components_title_bar_collased-icon_SJ1ls","asset-element":"components_title_bar_asset-element_64u6f","title":"components_title_bar_title_qPuju","title-only":"components_title_bar_title-only_aSsdC","rotated":"components_title_bar_rotated_9z7Rn"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/title_bar.scss b/frontend/src/app/main/ui/components/title_bar.scss
new file mode 100644
index 0000000000..9f4a9549c4
--- /dev/null
+++ b/frontend/src/app/main/ui/components/title_bar.scss
@@ -0,0 +1,78 @@
+// 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";
+
+.title-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: $s-32;
+ width: 100%;
+ min-height: $s-32;
+ background-color: var(--title-background-color);
+ .title,
+ .title-only {
+ @include tabTitleTipography;
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+ height: 100%;
+ min-height: $s-32;
+ margin-right: $s-8;
+ color: var(--title-foreground-color);
+ }
+ .title-only {
+ margin-left: $s-8;
+ }
+
+ .toggle-btn {
+ @include buttonStyle;
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+ gap: $s-4;
+ padding: 0;
+ color: var(--title-foreground-color);
+ stroke: var(--title-foreground-color);
+ .collased-icon {
+ @include flexCenter;
+ height: $s-24;
+ width: $s-24;
+ border-radius: $br-8;
+ padding: 0 $s-4 0 $s-8;
+ svg {
+ @extend .button-icon-small;
+ transform: rotate(90deg);
+ }
+ &.rotated svg {
+ transform: rotate(0deg);
+ }
+ }
+ &:hover {
+ color: var(--title-foreground-color-hover);
+ stroke: var(--title-foreground-color-hover);
+ .title {
+ color: var(--title-foreground-color-hover);
+ stroke: var(--title-foreground-color-hover);
+ }
+ .collased-icon svg {
+ stroke: var(--title-foreground-color-hover);
+ }
+ }
+ }
+
+ .title-button {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: calc($s-24 + $s-4);
+ padding: 0;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/debug/components_preview.cljs b/frontend/src/app/main/ui/debug/components_preview.cljs
index 2b950df042..4282735569 100644
--- a/frontend/src/app/main/ui/debug/components_preview.cljs
+++ b/frontend/src/app/main/ui/debug/components_preview.cljs
@@ -10,9 +10,23 @@
[app.main.data.users :as du]
[app.main.refs :as refs]
[app.main.store :as st]
+ [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
+ [app.main.ui.components.search-bar :refer [search-bar]]
+ [app.main.ui.components.tab-container :refer [tab-container tab-element]]
+ [app.main.ui.components.title-bar :refer [title-bar]]
+ [app.main.ui.icons :as i]
[app.util.dom :as dom]
[rumext.v2 :as mf]))
+(mf/defc component-wrapper
+ {::mf/wrap-props false}
+ [props]
+ (let [children (unchecked-get props "children")
+ title (unchecked-get props "title")]
+ [:div {:class (dom/classnames (css :component) true)}
+ [:h4 {:class (dom/classnames (css :component-name) true)} title]
+ children]))
+
(mf/defc components-preview
{::mf/wrap-props false}
[]
@@ -24,7 +38,6 @@
(let [theme (dom/event->value event)
data (assoc initial :theme theme)]
(st/emit! (du/update-profile data))))
-
colors [:bg-primary
:bg-secondary
:bg-tertiary
@@ -34,10 +47,37 @@
:acc
:acc-muted
:acc-secondary
- :acc-tertiary]]
+ :acc-tertiary]
+
+ ;; COMPONENTS FNs
+ state* (mf/use-state {:collapsed? true
+ :tab-selected :first
+ :input-value ""
+ :radio-selected "first"})
+ state (deref state*)
+
+ collapsed? (:collapsed? state)
+ toggle-collapsed
+ (mf/use-fn #(swap! state* update :collapsed? not))
+
+ tab-selected (:tab-selected state)
+ set-tab (mf/use-fn #(swap! state* assoc :tab-selected %))
+
+ input-value (:input-value state)
+ radio-selected (:radio-selected state)
+
+ set-radio-selected (mf/use-fn #(swap! state* assoc :radio-selected %))
+
+ update-search
+ (mf/use-fn
+ (fn [value _event]
+ (swap! state* assoc :input-value value)))
+
+
+ on-btn-click (mf/use-fn #(prn "eyy"))]
[:section.debug-components-preview
- [:div {:class (css :themes-row)}
+ [:div {:class (dom/classnames (css :themes-row) true)}
[:h2 "Themes"]
[:select {:label "Select theme color"
:name :theme
@@ -46,12 +86,135 @@
:on-change on-change}
[:option {:label "Penpot Dark (default)" :value "default"}]
[:option {:label "Penpot Light" :value "light"}]]
- [:div {:class (css :wrapper)}
+ [:div {:class (dom/classnames (css :wrapper) true)}
(let [css (styles)]
(for [color colors]
- [:div {:class (dom/classnames (get css color) true
+ [:div {:key color
+ :class (dom/classnames (get css color) true
(get css :rect) true)}
(d/name color)]))]]
- [:div {:class (css :components-row)}
- [:h2 {:class (css :title)} "Components"]
- [:div {:class (css :component-wrapper)}]]]))
\ No newline at end of file
+ [:div {:class (dom/classnames (css :components-row) true)}
+ [:h2 {:class (dom/classnames (css :title) true)} "Components"]
+ [:div {:class (dom/classnames (css :components-wrapper) true)}
+ [:div {:class (dom/classnames (css :component-group) true)}
+ [:h3 "Titles"]
+ [:& component-wrapper
+ {:title "Title"}
+ [:& title-bar {:collapsable? false
+ :title "Title"}]]
+ [:& component-wrapper
+ {:title "Title and action button"}
+ [:& title-bar {:collapsable? false
+ :title "Title"
+ :on-btn-click on-btn-click
+ :btn-children i/add-refactor}]]
+ [:& component-wrapper
+ {:title "Collapsed title and action button"}
+ [:& title-bar {:collapsable? true
+ :collapsed? collapsed?
+ :on-collapsed toggle-collapsed
+ :title "Title"
+ :on-btn-click on-btn-click
+ :btn-children i/add-refactor}]]
+ [:& component-wrapper
+ {:title "Collapsed title and children"}
+ [:& title-bar {:collapsable? true
+ :collapsed? collapsed?
+ :on-collapsed toggle-collapsed
+ :title "Title"}
+ [:& tab-container {:on-change-tab set-tab
+ :selected tab-selected}
+ [:& tab-element {:id :first
+ :title "A tab"}]
+ [:& tab-element {:id :second
+ :title "B tab"}]]]]]
+
+ [:div {:class (dom/classnames (css :component-group) true)}
+ [:h3 "Tabs component"]
+ [:& component-wrapper
+ {:title "2 tab component"}
+ [:& tab-container {:on-change-tab set-tab
+ :selected tab-selected}
+ [:& tab-element {:id :first :title "First tab"}
+ [:div "This is first tab content"]]
+
+ [:& tab-element {:id :second :title "Second tab"}
+ [:div "This is second tab content"]]]]
+ [:& component-wrapper
+ {:title "3 tab component"}
+ [:& tab-container {:on-change-tab set-tab
+ :selected tab-selected}
+ [:& tab-element {:id :first :title "First tab"}
+ [:div "This is first tab content"]]
+
+ [:& tab-element {:id :second
+ :title "Second tab"}
+ [:div "This is second tab content"]]
+ [:& tab-element {:id :third
+ :title "Third tab"}
+ [:div "This is third tab content"]]]]]
+
+ [:div {:class (dom/classnames (css :component-group) true)}
+ [:h3 "Search bar"]
+ [:& component-wrapper
+ {:title "Search bar only"}
+ [:& search-bar {:on-change update-search
+ :value input-value
+ :placeholder "Test value"}]]
+ [:& component-wrapper
+ {:title "Search and button"}
+ [:& search-bar {:on-change update-search
+ :value input-value
+ :placeholder "Test value"}
+ [:button {:class (dom/classnames (css :test-button) true)
+ :on-click on-btn-click}
+ "X"]]]]
+
+ [:div {:class (dom/classnames (css :component-group) true)}
+ [:h3 "Radio buttons"]
+ [:& component-wrapper
+ {:title "Two radio buttons (toggle)"}
+ [:& radio-buttons {:selected radio-selected
+ :on-change set-radio-selected
+ :name "listing-style"}
+ [:& radio-button {:icon (mf/html i/view-as-list-refactor)
+ :value "first"
+ :id :list}]
+ [:& radio-button {:icon (mf/html i/flex-grid-refactor)
+ :value "second"
+ :id :grid}]]]
+ [:& component-wrapper
+ {:title "Three radio buttons"}
+ [:& radio-buttons {:selected radio-selected
+ :on-change set-radio-selected
+ :name "listing-style"}
+ [:& radio-button {:icon (mf/html i/view-as-list-refactor)
+ :value "first"
+ :id :first}]
+ [:& radio-button {:icon (mf/html i/flex-grid-refactor)
+ :value "second"
+ :id :second}]
+
+ [:& radio-button {:icon (mf/html i/add-refactor)
+ :value "third"
+ :id :third}]]]
+
+ [:& component-wrapper
+ {:title "Four radio buttons"}
+ [:& radio-buttons {:selected radio-selected
+ :on-change set-radio-selected
+ :name "listing-style"}
+ [:& radio-button {:icon (mf/html i/view-as-list-refactor)
+ :value "first"
+ :id :first}]
+ [:& radio-button {:icon (mf/html i/flex-grid-refactor)
+ :value "second"
+ :id :second}]
+
+ [:& radio-button {:icon (mf/html i/add-refactor)
+ :value "third"
+ :id :third}]
+
+ [:& radio-button {:icon (mf/html i/board-refactor)
+ :value "forth"
+ :id :forth}]]]]]]]))
diff --git a/frontend/src/app/main/ui/debug/components_preview.css.json b/frontend/src/app/main/ui/debug/components_preview.css.json
index 9b9b623867..ab7afd1ed4 100644
--- a/frontend/src/app/main/ui/debug/components_preview.css.json
+++ b/frontend/src/app/main/ui/debug/components_preview.css.json
@@ -1 +1 @@
-{"button-primary":"debug_components_preview_button-primary_Q2m40","button-secondary":"debug_components_preview_button-secondary_yPp3n","button-icon":"debug_components_preview_button-icon_J36A6","button-icon-small":"debug_components_preview_button-icon-small_Pf3jb","themes-row":"debug_components_preview_themes-row_wEU8d","wrapper":"debug_components_preview_wrapper_535-4","rect":"debug_components_preview_rect_jomnq","bg-primary":"debug_components_preview_bg-primary_Rt4oW","bg-secondary":"debug_components_preview_bg-secondary_rcmll","bg-tertiary":"debug_components_preview_bg-tertiary_7rITE","bg-cuaternary":"debug_components_preview_bg-cuaternary_UEBPN","fg-primary":"debug_components_preview_fg-primary_naliT","fg-secondary":"debug_components_preview_fg-secondary_zT9IX","acc":"debug_components_preview_acc_h3Bia","acc-muted":"debug_components_preview_acc-muted_uingh","acc-secondary":"debug_components_preview_acc-secondary_oHH6y","acc-tertiary":"debug_components_preview_acc-tertiary_SwBjy","components-row":"debug_components_preview_components-row_N3f-J","title":"debug_components_preview_title_TVtzz","component-wrapper":"debug_components_preview_component-wrapper_yC9G1"}
\ No newline at end of file
+{"button-primary":"debug_components_preview_button-primary_Q2m40","button-secondary":"debug_components_preview_button-secondary_yPp3n","button-tertiary":"debug_components_preview_button-tertiary_FIKgJ","button-tag":"debug_components_preview_button-tag_NNepE","button-icon":"debug_components_preview_button-icon_J36A6","button-icon-small":"debug_components_preview_button-icon-small_Pf3jb","asset-element":"debug_components_preview_asset-element_LhcNS","themes-row":"debug_components_preview_themes-row_wEU8d","wrapper":"debug_components_preview_wrapper_535-4","rect":"debug_components_preview_rect_jomnq","bg-primary":"debug_components_preview_bg-primary_Rt4oW","bg-secondary":"debug_components_preview_bg-secondary_rcmll","bg-tertiary":"debug_components_preview_bg-tertiary_7rITE","bg-cuaternary":"debug_components_preview_bg-cuaternary_UEBPN","fg-primary":"debug_components_preview_fg-primary_naliT","fg-secondary":"debug_components_preview_fg-secondary_zT9IX","acc":"debug_components_preview_acc_h3Bia","acc-muted":"debug_components_preview_acc-muted_uingh","acc-secondary":"debug_components_preview_acc-secondary_oHH6y","acc-tertiary":"debug_components_preview_acc-tertiary_SwBjy","components-row":"debug_components_preview_components-row_N3f-J","title":"debug_components_preview_title_TVtzz","components-wrapper":"debug_components_preview_components-wrapper_A8IgV","component-group":"debug_components_preview_component-group_dI55k","component":"debug_components_preview_component_xBMSU","component-name":"debug_components_preview_component-name_3ZJMW"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/debug/components_preview.scss b/frontend/src/app/main/ui/debug/components_preview.scss
index 4d1cf79e33..3e29500abb 100644
--- a/frontend/src/app/main/ui/debug/components_preview.scss
+++ b/frontend/src/app/main/ui/debug/components_preview.scss
@@ -79,7 +79,33 @@
.title {
padding: $s-20;
}
- .component-wrapper {
+ .components-wrapper {
padding: $s-20;
+ display: flex;
+ flex-wrap: wrap;
+ .component-group {
+ @include flexCenter;
+ justify-content: flex-start;
+ flex-direction: column;
+ // width: $s-256;
+ border-radius: $s-8;
+ h3 {
+ @include titleTipography;
+ font-size: $fs-25;
+ width: 100%;
+ }
+ .component {
+ display: flex;
+ flex-direction: column;
+ gap: $s-8;
+ width: $s-240;
+ max-height: $s-80;
+ margin-bottom: $s-16;
+ .component-name {
+ @include tabTitleTipography;
+ font-weight: bold;
+ }
+ }
+ }
}
}
diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs
index 7e338c7f5c..f62b8662e1 100644
--- a/frontend/src/app/main/ui/icons.cljs
+++ b/frontend/src/app/main/ui/icons.cljs
@@ -297,6 +297,7 @@
(def distribute-vertical-sapcing-refactor (icon-xref :distribute-vertical-spacing-refactor))
(def delete-refactor (icon-xref :delete-refactor))
(def delete-text-refactor (icon-xref :delete-text-refactor))
+(def detach-refactor (icon-xref :detach-refactor))
(def document-refactor (icon-xref :document-refactor))
(def drop-refactor (icon-xref :drop-refactor))
(def effects-refactor (icon-xref :effects-refactor))
@@ -365,9 +366,23 @@
(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-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))
+(def text-lowercase-refactor (icon-xref :text-lowercase-refactor))
+(def text-LTR-refactor (icon-xref :text-LTR-refactor))
+(def text-middle-refactor (icon-xref :text-middle-refactor))
+(def text-mixed-refactor (icon-xref :text-mixed-refactor))
+(def text-palette-refactor (icon-xref :text-palette-refactor))
(def text-paragraph-refactor (icon-xref :text-paragraph-refactor))
(def text-refactor (icon-xref :text-refactor))
-(def text-palette-refactor (icon-xref :text-palette-refactor))
+(def text-RTL-refactor (icon-xref :text-RTL-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-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))
(def vertical-align-items-center-refactor (icon-xref :vertical-align-items-center-refactor))
@@ -375,6 +390,7 @@
(def vertical-align-items-start-refactor (icon-xref :vertical-align-items-start-refactor))
(def view-as-icons-refactor (icon-xref :view-as-icons-refactor))
(def wrap-refactor (icon-xref :wrap-refactor))
+(def view-as-list-refactor (icon-xref :view-as-list-refactor))
(def loader-pencil
(mf/html
[:svg
diff --git a/frontend/src/app/main/ui/modal.cljs b/frontend/src/app/main/ui/modal.cljs
index 94831f9517..a27a8308c9 100644
--- a/frontend/src/app/main/ui/modal.cljs
+++ b/frontend/src/app/main/ui/modal.cljs
@@ -66,7 +66,7 @@
(events/listen js/document EventType.KEYDOWN handle-keydown)
;; Changing to js/document breaks the color picker
- (events/listen (dom/get-root) EventType.POINTERDOWN handle-click-outside)
+ (events/listen (dom/get-root) EventType.POINTERDOWN handle-click-outside)
(events/listen js/document EventType.CONTEXTMENU handle-click-outside)]]
#(doseq [key keys]
diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs
index 090fd7f75c..85c32b1bfc 100644
--- a/frontend/src/app/main/ui/workspace.cljs
+++ b/frontend/src/app/main/ui/workspace.cljs
@@ -169,7 +169,7 @@
file-ready? (mf/deref file-ready*)
components-v2? (features/use-feature :components-v2)
- new-css? (features/use-feature :new-css-system)
+ new-css-system (features/use-feature :new-css-system)
background-color (:background-color wglobal)]
@@ -192,9 +192,9 @@
[:& (mf/provider ctx/current-team-id) {:value team-id}
[:& (mf/provider ctx/current-page-id) {:value page-id}
[:& (mf/provider ctx/components-v2) {:value components-v2?}
- [:& (mf/provider ctx/new-css-system) {:value new-css?}
+ [:& (mf/provider ctx/new-css-system) {:value new-css-system}
[:& (mf/provider ctx/workspace-read-only?) {:value read-only?}
- [:section#workspace {:class (when new-css? (css :workspace))
+ [:section#workspace {:class (when new-css-system (css :workspace))
:style {:background-color background-color
:touch-action "none"}}
(when (not (:hide-ui layout))
diff --git a/frontend/src/app/main/ui/workspace.css.json b/frontend/src/app/main/ui/workspace.css.json
index f37e8f34fe..9b6145dbcb 100644
--- a/frontend/src/app/main/ui/workspace.css.json
+++ b/frontend/src/app/main/ui/workspace.css.json
@@ -1 +1 @@
-{"button-primary":"ui_workspace_button-primary_FZJ-T","button-secondary":"ui_workspace_button-secondary_oDzCJ","button-icon":"ui_workspace_button-icon_L5y8h","button-icon-small":"ui_workspace_button-icon-small_Ppp3W","workspace":"ui_workspace_workspace_xutJr"}
\ No newline at end of file
+{"button-primary":"ui_workspace_button-primary_FZJ-T","button-secondary":"ui_workspace_button-secondary_oDzCJ","button-tertiary":"ui_workspace_button-tertiary_LVpr3","button-tag":"ui_workspace_button-tag_cU1Th","button-icon":"ui_workspace_button-icon_L5y8h","button-icon-small":"ui_workspace_button-icon-small_Ppp3W","asset-element":"ui_workspace_asset-element_LTbhl","workspace":"ui_workspace_workspace_xutJr"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/color_palette.css.json b/frontend/src/app/main/ui/workspace/color_palette.css.json
index f8fedfc2bf..5e8a9eb6ff 100644
--- a/frontend/src/app/main/ui/workspace/color_palette.css.json
+++ b/frontend/src/app/main/ui/workspace/color_palette.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_color_palette_button-primary_0d2e2","button-secondary":"workspace_color_palette_button-secondary_C8qJL","button-icon":"workspace_color_palette_button-icon_-tBR6","color-palette":"workspace_color_palette_color-palette_hfJPA","left-arrow":"workspace_color_palette_left-arrow_PK7sj","right-arrow":"workspace_color_palette_right-arrow_swpS9","button-icon-small":"workspace_color_palette_button-icon-small_RrGTg","disabled":"workspace_color_palette_disabled_bz-he","color-palette-content":"workspace_color_palette_color-palette-content_okg18","color-palette-inside":"workspace_color_palette_color-palette-inside_dCIeR","color-cell":"workspace_color_palette_color-cell_ITDgl","is-not-library-color":"workspace_color_palette_is-not-library-color_EqCM6","no-text":"workspace_color_palette_no-text_QMPK0"}
\ No newline at end of file
+{"button-primary":"workspace_color_palette_button-primary_0d2e2","button-secondary":"workspace_color_palette_button-secondary_C8qJL","button-tertiary":"workspace_color_palette_button-tertiary_X6-9C","button-tag":"workspace_color_palette_button-tag_GtZK2","button-icon":"workspace_color_palette_button-icon_-tBR6","color-palette":"workspace_color_palette_color-palette_hfJPA","left-arrow":"workspace_color_palette_left-arrow_PK7sj","right-arrow":"workspace_color_palette_right-arrow_swpS9","button-icon-small":"workspace_color_palette_button-icon-small_RrGTg","asset-element":"workspace_color_palette_asset-element_3Q2Mp","disabled":"workspace_color_palette_disabled_bz-he","color-palette-content":"workspace_color_palette_color-palette-content_okg18","color-palette-inside":"workspace_color_palette_color-palette-inside_dCIeR","color-cell":"workspace_color_palette_color-cell_ITDgl","is-not-library-color":"workspace_color_palette_is-not-library-color_EqCM6","no-text":"workspace_color_palette_no-text_QMPK0"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.css.json b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.css.json
index a3d1913bbc..0821a3a8c5 100644
--- a/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.css.json
+++ b/frontend/src/app/main/ui/workspace/color_palette_ctx_menu.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_color_palette_ctx_menu_button-primary_2ka4z","button-secondary":"workspace_color_palette_ctx_menu_button-secondary_jfajf","button-icon":"workspace_color_palette_ctx_menu_button-icon_cCaY2","button-icon-small":"workspace_color_palette_ctx_menu_button-icon-small_-knT4","palette-menu":"workspace_color_palette_ctx_menu_palette-menu_Vrjfy","palette-library":"workspace_color_palette_ctx_menu_palette-library_0LFV5","selected":"workspace_color_palette_ctx_menu_selected_lfchf","icon-wrapper":"workspace_color_palette_ctx_menu_icon-wrapper_v8-ys","recent-colors":"workspace_color_palette_ctx_menu_recent-colors_Q4fss","file-library":"workspace_color_palette_ctx_menu_file-library_8qsbr","option-wrapper":"workspace_color_palette_ctx_menu_option-wrapper_st9Cq","library-name":"workspace_color_palette_ctx_menu_library-name_BL8b8","color-sample":"workspace_color_palette_ctx_menu_color-sample_jQUGL"}
\ No newline at end of file
+{"button-primary":"workspace_color_palette_ctx_menu_button-primary_2ka4z","button-secondary":"workspace_color_palette_ctx_menu_button-secondary_jfajf","button-tertiary":"workspace_color_palette_ctx_menu_button-tertiary_NLctS","button-tag":"workspace_color_palette_ctx_menu_button-tag_GN3ad","button-icon":"workspace_color_palette_ctx_menu_button-icon_cCaY2","button-icon-small":"workspace_color_palette_ctx_menu_button-icon-small_-knT4","palette-menu":"workspace_color_palette_ctx_menu_palette-menu_Vrjfy","palette-library":"workspace_color_palette_ctx_menu_palette-library_0LFV5","selected":"workspace_color_palette_ctx_menu_selected_lfchf","icon-wrapper":"workspace_color_palette_ctx_menu_icon-wrapper_v8-ys","recent-colors":"workspace_color_palette_ctx_menu_recent-colors_Q4fss","file-library":"workspace_color_palette_ctx_menu_file-library_8qsbr","asset-element":"workspace_color_palette_ctx_menu_asset-element_pV16m","option-wrapper":"workspace_color_palette_ctx_menu_option-wrapper_st9Cq","library-name":"workspace_color_palette_ctx_menu_library-name_BL8b8","color-sample":"workspace_color_palette_ctx_menu_color-sample_jQUGL"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/context_menu.css.json b/frontend/src/app/main/ui/workspace/context_menu.css.json
index a41facee1a..a3b579c750 100644
--- a/frontend/src/app/main/ui/workspace/context_menu.css.json
+++ b/frontend/src/app/main/ui/workspace/context_menu.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_context_menu_button-primary_d6q-P","button-secondary":"workspace_context_menu_button-secondary_bIdqe","button-icon":"workspace_context_menu_button-icon_tXvxe","button-icon-small":"workspace_context_menu_button-icon-small_c0rVU","workspace-context-menu":"workspace_context_menu_workspace-context-menu_2NyvR","icon-menu-item":"workspace_context_menu_icon-menu-item_P3-bA","shape-icon":"workspace_context_menu_shape-icon_xx1Ll","workspace-context-submenu":"workspace_context_menu_workspace-context-submenu_BUNLt","selected-icon":"workspace_context_menu_selected-icon_pZqBp","context-menu-item":"workspace_context_menu_context-menu-item_Tx-Ty","submenu-icon":"workspace_context_menu_submenu-icon_JwYm8","separator":"workspace_context_menu_separator_E9-aR","title":"workspace_context_menu_title_P8iFL","shortcut":"workspace_context_menu_shortcut_rypUe","shortcut-key":"workspace_context_menu_shortcut-key_3rF3t","icon-wrapper":"workspace_context_menu_icon-wrapper_n7VO2"}
\ No newline at end of file
+{"button-primary":"workspace_context_menu_button-primary_d6q-P","button-secondary":"workspace_context_menu_button-secondary_bIdqe","button-tertiary":"workspace_context_menu_button-tertiary_vGSns","button-tag":"workspace_context_menu_button-tag_rOUbd","button-icon":"workspace_context_menu_button-icon_tXvxe","button-icon-small":"workspace_context_menu_button-icon-small_c0rVU","workspace-context-menu":"workspace_context_menu_workspace-context-menu_2NyvR","icon-menu-item":"workspace_context_menu_icon-menu-item_P3-bA","shape-icon":"workspace_context_menu_shape-icon_xx1Ll","workspace-context-submenu":"workspace_context_menu_workspace-context-submenu_BUNLt","selected-icon":"workspace_context_menu_selected-icon_pZqBp","context-menu-item":"workspace_context_menu_context-menu-item_Tx-Ty","submenu-icon":"workspace_context_menu_submenu-icon_JwYm8","asset-element":"workspace_context_menu_asset-element_jkrbj","separator":"workspace_context_menu_separator_E9-aR","title":"workspace_context_menu_title_P8iFL","shortcut":"workspace_context_menu_shortcut_rypUe","shortcut-key":"workspace_context_menu_shortcut-key_3rF3t","icon-wrapper":"workspace_context_menu_icon-wrapper_n7VO2"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/left_toolbar.cljs b/frontend/src/app/main/ui/workspace/left_toolbar.cljs
index 6728f863ba..cd4deb9dc7 100644
--- a/frontend/src/app/main/ui/workspace/left_toolbar.cljs
+++ b/frontend/src/app/main/ui/workspace/left_toolbar.cljs
@@ -66,10 +66,10 @@
(let [selected-drawtool (mf/deref refs/selected-drawing-tool)
edition (mf/deref refs/selected-edition)
- new-css? (mf/use-ctx ctx/new-css-system)
+ new-css-system (mf/use-ctx ctx/new-css-system)
read-only? (mf/use-ctx ctx/workspace-read-only?)
- show-palette-btn? (and (not ^boolean read-only?) (not ^boolean new-css?))
+ show-palette-btn? (and (not ^boolean read-only?) (not ^boolean new-css-system))
interrupt
diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs
index e1b6660447..8b3adf122b 100644
--- a/frontend/src/app/main/ui/workspace/libraries.cljs
+++ b/frontend/src/app/main/ui/workspace/libraries.cljs
@@ -5,14 +5,20 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.libraries
+ (:require-macros [app.main.style :refer [css]])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.types.components-list :as ctkl]
[app.main.data.modal :as modal]
[app.main.data.workspace.libraries :as dwl]
+ [app.main.features :as features]
[app.main.refs :as refs]
[app.main.store :as st]
+ [app.main.ui.components.search-bar :refer [search-bar]]
+ [app.main.ui.components.tab-container :refer [tab-container tab-element]]
+ [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]]
@@ -56,6 +62,39 @@
(conj (tr "workspace.libraries.typography" typography-count))))
"\u00A0"))
+(mf/defc describe-library-blocks
+ [{:keys [components-count graphics-count colors-count typography-count] :as props}]
+
+ (let [last-one (cond
+ (> colors-count 0) :color
+ (> graphics-count 0) :graphics
+ (> components-count 0) :components)]
+ [:*
+ (when (pos? components-count)
+ [:*
+ [:span {:class (css :element-count)}
+ (tr "workspace.libraries.components" components-count)]
+ (when (not= last-one :components)
+ [:span " · "])])
+
+ (when (pos? graphics-count)
+ [:*
+ [:span {:class (css :element-count)}
+ (tr "workspace.libraries.graphics" graphics-count)]
+ (when (not= last-one :graphics)
+ [:span " · "])])
+
+ (when (pos? colors-count)
+ [:*
+ [:span {:class (css :element-count)}
+ (tr "workspace.libraries.colors" colors-count)]
+ (when (not= last-one :colors)
+ [:span " · "])])
+
+ (when (pos? typography-count)
+ [:span {:class (css :element-count)}
+ (tr "workspace.libraries.typography" typography-count)])]))
+
(defn- describe-linked-library
[library]
(let [components-count (count (or (ctkl/components-seq (:data library)) []))
@@ -75,16 +114,16 @@
(mf/defc libraries-tab
{::mf/wrap-props false}
[{:keys [file-id shared? linked-libraries shared-libraries]}]
- (let [search-term* (mf/use-state "")
- search-term (deref search-term*)
-
- library-ref (mf/with-memo [file-id]
- (create-file-library-ref file-id))
- library (deref library-ref)
- colors (:colors library)
- components (:components library)
- media (:media library)
- typographies (:typographies library)
+ (let [search-term* (mf/use-state "")
+ search-term (deref search-term*)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ library-ref (mf/with-memo [file-id]
+ (create-file-library-ref file-id))
+ library (deref library-ref)
+ colors (:colors library)
+ components (:components library)
+ media (:media library)
+ typographies (:typographies library)
shared-libraries
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
@@ -101,9 +140,12 @@
change-search-term
(mf/use-fn
+ (mf/deps new-css-system)
(fn [event]
- (let [value (-> (dom/get-target event)
- (dom/get-value))]
+ (let [value (if new-css-system
+ event
+ (-> (dom/get-target event)
+ (dom/get-value)))]
(reset! search-term* value))))
clear-search-term
@@ -111,20 +153,28 @@
link-library
(mf/use-fn
- (mf/deps file-id)
+ (mf/deps file-id new-css-system)
(fn [event]
- (let [library-id (some-> (dom/get-target event)
- (dom/get-data "library-id")
- (parse-uuid))]
+ (let [library-id (if new-css-system
+ (some-> (dom/get-current-target event)
+ (dom/get-data "library-id")
+ (parse-uuid))
+ (some-> (dom/get-target event)
+ (dom/get-data "library-id")
+ (parse-uuid)))]
(st/emit! (dwl/link-file-to-library file-id library-id)))))
unlink-library
(mf/use-fn
(mf/deps file-id)
(fn [event]
- (let [library-id (some-> (dom/get-target event)
- (dom/get-data "library-id")
- (parse-uuid))]
+ (let [library-id (if new-css-system
+ (some-> (dom/get-current-target event)
+ (dom/get-data "library-id")
+ (parse-uuid))
+ (some-> (dom/get-target event)
+ (dom/get-data "library-id")
+ (parse-uuid)))]
(st/emit! (dwl/unlink-file-from-library file-id library-id)
(dwl/sync-file file-id library-id)))))
@@ -140,7 +190,10 @@
publish
(mf/use-fn
(mf/deps file-id)
- #(st/emit! (dwl/set-file-shared file-id true)))
+ (fn [event]
+ (let [input-node (dom/event->target event)]
+ (st/emit! (dwl/set-file-shared file-id true))
+ (dom/blur! input-node))))
unpublish
(mf/use-fn
@@ -165,122 +218,230 @@
(when ^boolean esc?
(dom/blur! input-node)))))]
- [:*
- [:div.section
- [:div.section-title (tr "workspace.libraries.in-this-file")]
- [:div.section-list
+ (if new-css-system
+ [:*
+ [:div {:class (css :section)}
+ [:& title-bar {:collapsable? false
+ :title (tr "workspace.libraries.in-this-file")
+ :klass :title-spacing-lib}]
+ [:div {:class (css :section-list)}
- [:div.section-list-item
- [:div
- [:div.item-name (tr "workspace.libraries.file-library")]
- [:div.item-contents (describe-library
- (count components)
- (count media)
- (count colors)
- (count typographies))]]
- [:div
- (if ^boolean shared?
- [:input.item-button {:type "button"
- :value (tr "common.unpublish")
- :on-click unpublish}]
- [:input.item-button {:type "button"
- :value (tr "common.publish")
- :on-click publish}])]]
+ [:div {:class (css :section-list-item)}
+ [:div
+ [:div {:class (css :item-name)} (tr "workspace.libraries.file-library")]
+ [:div {:class (css :item-contents)}
+ [:& describe-library-blocks {:components-count (count components)
+ :graphics-count (count media)
+ :colors-count (count colors)
+ :typography-count (count typographies)}]]]
+ [:div
+ (if ^boolean shared?
+ [:input {:class (css :item-unpublish)
+ :type "button"
+ :value (tr "common.unpublish")
+ :on-click unpublish}]
+ [:input {:class (css :item-publish)
+ :type "button"
+ :value (tr "common.publish")
+ :on-click publish}])]]
- (for [{:keys [id name] :as library} linked-libraries]
- [:div.section-list-item {:key (dm/str id)}
- [:div.item-name name]
- [:div.item-contents (describe-linked-library library)]
- [:input.item-button {:type "button"
- :value (tr "labels.remove")
- :data-library-id (dm/str id)
- :on-click unlink-library}]])]]
+ (for [{:keys [id name] :as library} linked-libraries]
+ [:div {:class (css :section-list-item)
+ :key (dm/str id)}
+ [:div
+ [:div {:class (css :item-name)} name]
+ [:div {:class (css :item-contents)}
+ (let [components-count (count (or (ctkl/components-seq (:data library)) []))
+ graphics-count (count (dm/get-in library [:data :media] []))
+ colors-count (count (dm/get-in library [:data :colors] []))
+ typography-count (count (dm/get-in library [:data :typographies] []))]
+ [:& describe-library-blocks {:components-count components-count
+ :graphics-count graphics-count
+ :colors-count colors-count
+ :typography-count typography-count}])]]
- [:div.section
- [:div.section-title (tr "workspace.libraries.shared-libraries")]
- [:div.libraries-search
- [:input.search-input
- {:placeholder (tr "workspace.libraries.search-shared-libraries")
- :type "text"
- :value search-term
- :on-change change-search-term
- :on-key-down handle-key-down}]
- (if (str/empty? search-term)
- [:div.search-icon
- i/search]
- [:div.search-icon.search-close
- {:on-click clear-search-term}
- i/close])]
+ [:button {:class (css :item-button)
+ :type "button"
+ :data-library-id (dm/str id)
+ :on-click unlink-library}
+ i/delete-refactor]])]]
- (if (seq shared-libraries)
+ [:div {:class (css :section)}
+ [:& title-bar {:collapsable? false
+ :title (tr "workspace.libraries.shared-libraries")
+ :klass :title-spacing-lib}]
+ [:div {:class (css :libraries-search)}
+ [:& search-bar {:on-change change-search-term
+ :value search-term
+ :placeholder (tr "workspace.libraries.search-shared-libraries")
+ :icon (mf/html [:span {:class (css :search-icon)} i/search-refactor])}]]
+
+ (if (seq shared-libraries)
+ [:div {:class (css :section-list)}
+ (for [{:keys [id name] :as library} shared-libraries]
+ [:div {:class (css :section-list-item)
+ :key (dm/str id)}
+ [:div
+ [:div {:class (css :item-name)} name]
+ [:div {:class (css :item-contents)}
+ (let [components-count (dm/get-in library [:library-summary :components :count] 0)
+ graphics-count (dm/get-in library [:library-summary :media :count] 0)
+ colors-count (dm/get-in library [:library-summary :colors :count] 0)
+ typography-count (dm/get-in library [:library-summary :typographies :count] 0)]
+ [:& describe-library-blocks {:components-count components-count
+ :graphics-count graphics-count
+ :colors-count colors-count
+ :typography-count typography-count}])]]
+ [:button {:class (css :item-button)
+ :data-library-id (dm/str id)
+ :on-click link-library}
+ i/add-refactor]])]
+
+ [:div {:class (css :section-list-empty)}
+ (if (nil? shared-libraries)
+ i/loader-pencil
+ (if (str/empty? search-term)
+ (tr "workspace.libraries.no-shared-libraries-available")
+ (tr "workspace.libraries.no-matches-for" search-term)))])]]
+
+ [:*
+ [:div.section
+ [:div.section-title (tr "workspace.libraries.in-this-file")]
[:div.section-list
- (for [{:keys [id name] :as library} shared-libraries]
+
+ [:div.section-list-item
+ [:div
+ [:div.item-name (tr "workspace.libraries.file-library")]
+ [:div.item-contents (describe-library
+ (count components)
+ (count media)
+ (count colors)
+ (count typographies))]]
+ [:div
+ (if ^boolean shared?
+ [:input.item-button {:type "button"
+ :value (tr "common.unpublish")
+ :on-click unpublish}]
+ [:input.item-button {:type "button"
+ :value (tr "common.publish")
+ :on-click publish}])]]
+
+ (for [{:keys [id name] :as library} linked-libraries]
[:div.section-list-item {:key (dm/str id)}
[:div.item-name name]
- [:div.item-contents (describe-external-library library)]
+ [:div.item-contents (describe-linked-library library)]
[:input.item-button {:type "button"
- :value (tr "workspace.libraries.add")
+ :value (tr "labels.remove")
:data-library-id (dm/str id)
- :on-click link-library}]])]
+ :on-click unlink-library}]])]]
- [:div.section-list-empty
- (if (nil? shared-libraries)
- i/loader-pencil
- [:* i/library
- (if (str/empty? search-term)
- (tr "workspace.libraries.no-shared-libraries-available")
- (tr "workspace.libraries.no-matches-for" search-term))])])]]))
+ [:div.section
+ [:div.section-title (tr "workspace.libraries.shared-libraries")]
+ [:div.libraries-search
+ [:input.search-input
+ {:placeholder (tr "workspace.libraries.search-shared-libraries")
+ :type "text"
+ :value search-term
+ :on-change change-search-term
+ :on-key-down handle-key-down}]
+ (if (str/empty? search-term)
+ [:div.search-icon
+ i/search]
+ [:div.search-icon.search-close
+ {:on-click clear-search-term}
+ i/close])]
+ (if (seq shared-libraries)
+ [:div.section-list
+ (for [{:keys [id name] :as library} shared-libraries]
+ [:div.section-list-item {:key (dm/str id)}
+ [:div.item-name name]
+ [:div.item-contents (describe-external-library library)]
+ [:input.item-button {:type "button"
+ :value (tr "workspace.libraries.add")
+ :data-library-id (dm/str id)
+ :on-click link-library}]])]
+
+ [:div.section-list-empty
+ (if (nil? shared-libraries)
+ i/loader-pencil
+ [:* i/library
+ (if (str/empty? search-term)
+ (tr "workspace.libraries.no-shared-libraries-available")
+ (tr "workspace.libraries.no-matches-for" search-term))])])]])))
(mf/defc updates-tab
{::mf/wrap-props false}
[{:keys [file-id file-data libraries]}]
- (let [libraries (mf/with-memo [file-data libraries]
- (filter #(seq (dwl/assets-need-sync % file-data))
- (vals libraries)))
+ (let [libraries (mf/with-memo [file-data libraries]
+ (filter #(seq (dwl/assets-need-sync % file-data)) (vals libraries)))
+ new-css-system (mf/use-ctx ctx/new-css-system)
- update (mf/use-fn
- (mf/deps file-id)
- (fn [event]
- (let [library-id (some-> (dom/get-target event)
- (dom/get-data "library-id")
- (parse-uuid))]
- (st/emit! (dwl/sync-file file-id library-id)))))]
- [:div.section
- (if (empty? libraries)
- [:div.section-list-empty
- i/library
- (tr "workspace.libraries.no-libraries-need-sync")]
- [:*
- [:div.section-title (tr "workspace.libraries.library")]
- [:div.section-list
- (for [{:keys [id name] :as library} libraries]
- [:div.section-list-item {:key (dm/str id)}
- [:div.item-name name]
- [:div.item-contents (describe-external-library library)]
- [:input.item-button {:type "button"
- :value (tr "workspace.libraries.update")
- :data-library-id (dm/str id)
- :on-click update}]])]])]))
+ update (mf/use-fn
+ (mf/deps file-id)
+ (fn [event]
+ (let [library-id (some-> (dom/get-target event)
+ (dom/get-data "library-id")
+ (parse-uuid))]
+ (st/emit! (dwl/sync-file file-id library-id)))))]
+ (if new-css-system
+ [:div {:class (css :section)}
+ (if (empty? libraries)
+ [:div {:class (css :section-list-empty)}
+ (tr "workspace.libraries.no-libraries-need-sync")]
+ [:*
+ [:div {:class (css :section-title)} (tr "workspace.libraries.library")]
+
+ [:div {:class (css :section-list)}
+ (for [{:keys [id name] :as library} libraries]
+ [:div {:class (css :section-list-item)
+ :key (dm/str id)}
+ [:div
+ [:div {:class (css :item-name)} name]
+ [:div {:class (css :item-contents)} (describe-external-library library)]]
+ [:input {:class (css :item-update)
+ :type "button"
+ :value (tr "workspace.libraries.update")
+ :data-library-id (dm/str id)
+ :on-click update}]])]])]
+
+ [:div.section
+ (if (empty? libraries)
+ [:div.section-list-empty
+ i/library
+ (tr "workspace.libraries.no-libraries-need-sync")]
+ [:*
+ [:div.section-title (tr "workspace.libraries.library")]
+
+ [:div.section-list
+ (for [{:keys [id name] :as library} libraries]
+ [:div.section-list-item {:key (dm/str id)}
+ [:div.item-name name]
+ [:div.item-contents (describe-external-library library)]
+ [:input.item-button {:type "button"
+ :value (tr "workspace.libraries.update")
+ :data-library-id (dm/str id)
+ :on-click update}]])]])])))
(mf/defc libraries-dialog
{::mf/register modal/components
::mf/register-as :libraries-dialog}
[]
- (let [project (mf/deref refs/workspace-project)
- file-data (mf/deref refs/workspace-data)
- file (mf/deref ref:workspace-file)
+ (let [new-css-system (features/use-feature :new-css-system)
+ project (mf/deref refs/workspace-project)
+ file-data (mf/deref refs/workspace-data)
+ file (mf/deref ref:workspace-file)
- team-id (:team-id project)
- file-id (:id file)
- shared? (:is-shared file)
+ team-id (:team-id project)
+ file-id (:id file)
+ shared? (:is-shared file)
- selected-tab* (mf/use-state :libraries)
- selected-tab (deref selected-tab*)
+ selected-tab* (mf/use-state :libraries)
+ selected-tab (deref selected-tab*)
- libraries (mf/deref refs/workspace-libraries)
- libraries (mf/with-memo [libraries]
- (d/removem (fn [[_ val]] (:is-indirect val)) libraries))
+ libraries (mf/deref refs/workspace-libraries)
+ libraries (mf/with-memo [libraries]
+ (d/removem (fn [[_ val]] (:is-indirect val)) libraries))
;; NOTE: we really don't need react on shared files
shared-libraries
@@ -292,35 +453,61 @@
select-updates-tab
(mf/use-fn #(reset! selected-tab* :updates))
+ on-tab-change
+ (mf/use-fn #(reset! selected-tab* %))
+
close-dialog
- (mf/use-fn #(modal/hide!))]
+ (mf/use-fn (fn [_] (modal/hide!)
+ (modal/disallow-click-outside!)))]
(mf/with-effect [team-id]
(when team-id
(st/emit! (dwl/fetch-shared-files {:team-id team-id}))))
+ [:& (mf/provider ctx/new-css-system) {:value new-css-system}
+ (if new-css-system
+ [:div {:class (css :modal-overlay)}
+ [:div {:class (css :modal-dialog)}
+ [:div {:class (css :modal-content)}
+ [:div {:class (css :libraries-header)}
- [:div.modal-overlay
- [:div.modal.libraries-dialog
- [:a.close {:on-click close-dialog} i/close]
- [:div.modal-content
- [:div.libraries-header
- [:div.header-item
- {:class (dom/classnames :active (= selected-tab :libraries))
- :on-click select-libraries-tab}
- (tr "workspace.libraries.libraries")]
- [:div.header-item
- {:class (dom/classnames :active (= selected-tab :updates))
- :on-click select-updates-tab}
- (tr "workspace.libraries.updates")]]
- [:div.libraries-content
- (case selected-tab
- :libraries
- [:& libraries-tab {:file-id file-id
- :shared? shared?
- :linked-libraries libraries
- :shared-libraries shared-libraries}]
- :updates
- [:& updates-tab {:file-id file-id
- :file-data file-data
- :libraries libraries}])]]]]))
+ [:& tab-container
+ {:on-change-tab on-tab-change
+ :selected selected-tab
+ :collapsable? false}
+ [:& tab-element {:id :libraries :title (tr "workspace.libraries.libraries")}
+ [:div {:class (dom/classnames (css :libraries-content) true)}
+ [:& libraries-tab {:file-id file-id
+ :shared? shared?
+ :linked-libraries libraries
+ :shared-libraries shared-libraries}]]]
+ [:& tab-element {:id :updates :title (tr "workspace.libraries.updates")}
+ [:div {:class (dom/classnames (css :updates-content) true)}
+ [:& updates-tab {:file-id file-id
+ :file-data file-data
+ :libraries libraries}]]]]]]]]
+
+ [:div.modal-overlay
+ [:div.modal.libraries-dialog
+ [:a.close {:on-click close-dialog} i/close]
+ [:div.modal-content
+ [:div.libraries-header
+ [:div.header-item
+ {:class (dom/classnames :active (= selected-tab :libraries))
+ :on-click select-libraries-tab}
+ (tr "workspace.libraries.libraries")]
+ [:div.header-item
+ {:class (dom/classnames :active (= selected-tab :updates))
+ :on-click select-updates-tab}
+ (tr "workspace.libraries.updates")]]
+ [:div.libraries-content
+ (case selected-tab
+ :libraries
+ [:& libraries-tab {:file-id file-id
+ :shared? shared?
+ :linked-libraries libraries
+ :shared-libraries shared-libraries}]
+ :updates
+ [:& updates-tab {:file-id file-id
+ :file-data file-data
+ :libraries libraries}])]]]])]))
diff --git a/frontend/src/app/main/ui/workspace/libraries.css.json b/frontend/src/app/main/ui/workspace/libraries.css.json
new file mode 100644
index 0000000000..0ffda66893
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/libraries.css.json
@@ -0,0 +1 @@
+{"button-primary":"workspace_libraries_button-primary_Hsioh","modal-overlay":"workspace_libraries_modal-overlay_qC-df","modal-dialog":"workspace_libraries_modal-dialog_Kj293","modal-content":"workspace_libraries_modal-content_4EVEQ","libraries-content":"workspace_libraries_libraries-content_ycQdm","section":"workspace_libraries_section_SUsgi","section-list":"workspace_libraries_section-list_lGSrM","section-list-item":"workspace_libraries_section-list-item_hwASN","item-publish":"workspace_libraries_item-publish_ZMopF","item-unpublish":"workspace_libraries_item-unpublish_1seca","item-update":"workspace_libraries_item-update_GklIE","updates-content":"workspace_libraries_updates-content_lqMoE","button-secondary":"workspace_libraries_button-secondary_l5M0x","button-tertiary":"workspace_libraries_button-tertiary_C54rH","item-button":"workspace_libraries_item-button_dKUeX","close":"workspace_libraries_close_bED7B","button-tag":"workspace_libraries_button-tag_wAh-s","button-icon":"workspace_libraries_button-icon_kxS7q","item-button-icon":"workspace_libraries_item-button-icon_CeJWg","button-icon-small":"workspace_libraries_button-icon-small_Q9eo3","section-list-empty":"workspace_libraries_section-list-empty_mOKkJ","libraries-search":"workspace_libraries_libraries-search_JS70w","search-icon":"workspace_libraries_search-icon_y7N9S","asset-element":"workspace_libraries_asset-element_-FuJl","libraries-header":"workspace_libraries_libraries-header_-W6bJ","item-name":"workspace_libraries_item-name_Zjbsw","item-contents":"workspace_libraries_item-contents_EPTF6","section-title":"workspace_libraries_section-title_7rsm7","element-count":"workspace_libraries_element-count_07SV2"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss
new file mode 100644
index 0000000000..8ab144ad6e
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/libraries.scss
@@ -0,0 +1,139 @@
+// 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";
+.modal-overlay {
+ @include flexCenter;
+ position: fixed;
+ left: 0;
+ top: 0;
+ height: 100%;
+ width: 100%;
+ z-index: $z-index-modal;
+ background-color: var(--overlay-color);
+ pointer-events: none; // This is to allow outside click that closes modal.
+ .modal-dialog {
+ height: $s-400;
+ max-height: 100%;
+ width: $s-664;
+ border-radius: $br-8;
+ background-color: var(--modal-background-color);
+ pointer-events: all;
+ .close {
+ @extend .button-tertiary;
+ width: $s-32;
+ height: $s-32;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+ }
+ .modal-content {
+ .libraries-header {
+ padding: $s-12;
+ }
+
+ .libraries-content,
+ .updates-content {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: $s-24;
+ padding-top: $s-16;
+ height: 100%;
+
+ .section {
+ height: 100%;
+ :global(.title-spacing-lib) {
+ margin: 0 0 $s-8 calc(-1 * $s-8);
+ }
+ .section-list {
+ height: 100%;
+ max-height: 250px;
+ overflow: auto;
+ .section-list-item {
+ display: grid;
+ grid-template-columns: 1fr auto;
+ margin-bottom: $s-12;
+
+ .item-name {
+ @include titleTipography;
+ color: var(--library-name-foreground-color);
+ }
+ .item-contents {
+ @include titleTipography;
+ color: var(--library-content-foreground-color);
+ }
+
+ .item-publish,
+ .item-unpublish,
+ .item-update {
+ @extend .button-primary;
+ @include tabTitleTipography;
+ height: $s-32;
+ min-width: $s-92;
+ padding: $s-8 $s-12;
+ border-radius: $br-8;
+ }
+ .item-unpublish {
+ @extend .button-secondary;
+ }
+ .item-button {
+ @extend .button-tertiary;
+ width: $s-32;
+ height: $s-32;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+ }
+ .item-button-icon {
+ width: $s-28;
+ height: $s-28;
+ svg {
+ @extend .button-icon;
+ }
+ }
+ }
+ }
+
+ .section-title {
+ @include titleTipography;
+ margin-bottom: $s-12;
+ }
+ .libraries-search {
+ margin-bottom: $s-12;
+ .search-icon {
+ @include flexCenter;
+ padding: 0 0 0 $s-8;
+ width: $s-20;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
+ }
+ .section-list-empty {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+
+ svg {
+ @extend .button-icon-small;
+ width: $s-16;
+ height: $s-16;
+ }
+ }
+ }
+ }
+ .updates-content {
+ grid-template-columns: 1fr;
+ }
+ }
+ }
+}
+
+.element-count {
+ white-space: nowrap;
+}
diff --git a/frontend/src/app/main/ui/workspace/palette.css.json b/frontend/src/app/main/ui/workspace/palette.css.json
index ec0718e284..decd0e4101 100644
--- a/frontend/src/app/main/ui/workspace/palette.css.json
+++ b/frontend/src/app/main/ui/workspace/palette.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_palette_button-primary_zEUyD","palettes":"workspace_palette_palettes_JHGUw","palette-actions":"workspace_palette_palette-actions_2GwR6","palette-btn-list":"workspace_palette_palette-btn-list_x7gPS","palette-item":"workspace_palette_palette-item_50uj6","palette-btn":"workspace_palette_palette-btn_kP66y","button-secondary":"workspace_palette_button-secondary_ksr24","button-icon":"workspace_palette_button-icon_pmEDv","button-icon-small":"workspace_palette_button-icon-small_vbLDq","wide":"workspace_palette_wide_3G4e1","mid-palette":"workspace_palette_mid-palette_rGR5I","small-palette":"workspace_palette_small-palette_18Otk","resize-area":"workspace_palette_resize-area_0LwVu","selected":"workspace_palette_selected_Z6BFo","palette":"workspace_palette_palette_eqp3q","handler":"workspace_palette_handler_4JV0J","handler-btn":"workspace_palette_handler-btn_7lnlF","hidden-bts":"workspace_palette_hidden-bts_mhbc0"}
\ No newline at end of file
+{"button-primary":"workspace_palette_button-primary_zEUyD","button-secondary":"workspace_palette_button-secondary_ksr24","button-tertiary":"workspace_palette_button-tertiary_91YQK","palettes":"workspace_palette_palettes_JHGUw","palette-actions":"workspace_palette_palette-actions_2GwR6","palette-btn-list":"workspace_palette_palette-btn-list_x7gPS","palette-item":"workspace_palette_palette-item_50uj6","palette-btn":"workspace_palette_palette-btn_kP66y","button-tag":"workspace_palette_button-tag_S9v-Z","button-icon":"workspace_palette_button-icon_pmEDv","button-icon-small":"workspace_palette_button-icon-small_vbLDq","asset-element":"workspace_palette_asset-element_4bXi3","wide":"workspace_palette_wide_3G4e1","mid-palette":"workspace_palette_mid-palette_rGR5I","small-palette":"workspace_palette_small-palette_18Otk","resize-area":"workspace_palette_resize-area_0LwVu","selected":"workspace_palette_selected_Z6BFo","palette":"workspace_palette_palette_eqp3q","handler":"workspace_palette_handler_4JV0J","handler-btn":"workspace_palette_handler-btn_7lnlF","hidden-bts":"workspace_palette_hidden-bts_mhbc0"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/palette.scss b/frontend/src/app/main/ui/workspace/palette.scss
index 209593e2fe..e2d1d2ea41 100644
--- a/frontend/src/app/main/ui/workspace/palette.scss
+++ b/frontend/src/app/main/ui/workspace/palette.scss
@@ -57,7 +57,7 @@
opacity: $op-10;
transition: opacity 1s ease;
.palette-btn {
- @extend .button-primary;
+ @extend .button-tertiary;
height: $s-32;
width: $s-32;
border-radius: $br-8;
@@ -82,7 +82,7 @@
}
}
.palette-actions {
- @extend .button-primary;
+ @extend .button-tertiary;
grid-area: actions;
height: calc(var(--height) - $s-16);
width: $s-32;
diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
index 2f6de0e75b..870487b719 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -12,6 +12,7 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.tab-container :refer [tab-container tab-element]]
+ [app.main.ui.components.tabs-container :refer [tabs-container tabs-element]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.icons :as i]
@@ -40,7 +41,7 @@
(contains? layout :assets) :assets)
shortcuts? (contains? layout :shortcuts)
show-debug? (contains? layout :debug-panel)
- new-css? (mf/use-ctx ctx/new-css-system)
+ new-css-system (mf/use-ctx ctx/new-css-system)
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
(use-resize-hook :left-sidebar 255 255 500 :x false :left)
@@ -49,12 +50,14 @@
(mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))
on-tab-change
- (mf/use-fn #(st/emit! (dw/go-to-layout %)))
- ]
+ (mf/use-fn #(st/emit! (dw/go-to-layout %)))]
[:aside {:ref parent-ref
- :class (if ^boolean new-css?
- (dom/classnames (css :left-settings-bar) true)
+ :class (if ^boolean new-css-system
+ (dom/classnames (css :left-settings-bar) true
+ :two-row (<= size 300)
+ :three-row (and (> size 300) (<= size 400))
+ :four-row (> size 400))
(dom/classnames :settings-bar true
:settings-bar-left true
:two-row (<= size 300)
@@ -65,10 +68,10 @@
[:div {:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move
- :class (if ^boolean new-css?
+ :class (if ^boolean new-css-system
(dom/classnames (css :resize-area) true)
(dom/classnames :resize-area true))}]
- [:div {:class (if ^boolean new-css?
+ [:div {:class (if ^boolean new-css-system
(dom/classnames (css :settings-bar-inside) true)
(dom/classnames :settings-bar-inside true))}
(cond
@@ -79,22 +82,23 @@
[:& debug-panel]
:else
- (if ^boolean new-css?
- [:& tab-container
- {:on-change-tab on-tab-change
- :selected section
- :shortcuts? shortcuts?
- :collapsable? true
- :handle-collapse handle-collapse}
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :tabs-wrapper) true)}
+ [:& tab-container
+ {:on-change-tab on-tab-change
+ :selected section
+ :shortcuts? shortcuts?
+ :collapsable? true
+ :handle-collapse handle-collapse
+ :klass :tab-spacing}
+ [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")}
+ [:div {:class (dom/classnames (css :layers-tab) true)}
+ [:& sitemap {:layout layout}]
+ [:& layers-toolbox {:size-parent size}]]]
- [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")}
- [:div {:class (dom/classnames (css :layers-tab) true)}
- [:& sitemap {:layout layout}]
- [:& layers-toolbox {:size-parent size}]]]
-
- (when-not ^boolean mode-inspect?
- [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
- [:& assets-toolbox]])]
+ (when-not ^boolean mode-inspect?
+ [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
+ [:& assets-toolbox]])]]
[:*
[:button.collapse-sidebar
@@ -102,20 +106,20 @@
:aria-label (tr "workspace.sidebar.collapse")}
i/arrow-slide]
- [:& tab-container
+ [:& tabs-container
{:on-change-tab on-tab-change
:selected section
:shortcuts? shortcuts?
:collapsable? true
:handle-collapse handle-collapse}
- [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")}
+ [:& tabs-element {:id :layers :title (tr "workspace.sidebar.layers")}
[:div {:class (dom/classnames :layers-tab true)}
[:& sitemap {:layout layout}]
[:& layers-toolbox {:size-parent size}]]]
(when-not ^boolean mode-inspect?
- [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
+ [:& tabs-element {:id :assets :title (tr "workspace.toolbar.assets")}
[:& assets-toolbox]])]]))]]))
;; --- Right Sidebar (Component)
@@ -150,4 +154,3 @@
:else
[:> options-toolbox props])]]))
-
diff --git a/frontend/src/app/main/ui/workspace/sidebar.css.json b/frontend/src/app/main/ui/workspace/sidebar.css.json
index c27ff9be21..ac76a824b5 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_sidebar_button-primary_K7xW6","button-secondary":"workspace_sidebar_button-secondary_e2eQE","button-icon":"workspace_sidebar_button-icon_OXdmL","button-icon-small":"workspace_sidebar_button-icon-small_EYb9x","left-settings-bar":"workspace_sidebar_left-settings-bar_7co5t","resize-area":"workspace_sidebar_resize-area_ny1v0","settings-bar-inside":"workspace_sidebar_settings-bar-inside_YnFv8","layers-tab":"workspace_sidebar_layers-tab_soxRL"}
\ No newline at end of file
+{"button-primary":"workspace_sidebar_button-primary_K7xW6","button-secondary":"workspace_sidebar_button-secondary_e2eQE","button-tertiary":"workspace_sidebar_button-tertiary_QKqHT","button-tag":"workspace_sidebar_button-tag_Xc0Sm","button-icon":"workspace_sidebar_button-icon_OXdmL","button-icon-small":"workspace_sidebar_button-icon-small_EYb9x","asset-element":"workspace_sidebar_asset-element_vzrfV","left-settings-bar":"workspace_sidebar_left-settings-bar_7co5t","resize-area":"workspace_sidebar_resize-area_ny1v0","settings-bar-inside":"workspace_sidebar_settings-bar-inside_YnFv8","tabs-wrapper":"workspace_sidebar_tabs-wrapper_YDo4o","layers-tab":"workspace_sidebar_layers-tab_soxRL"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar.scss b/frontend/src/app/main/ui/workspace/sidebar.scss
index 6f2d76f8da..c7a1aedee7 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar.scss
@@ -33,12 +33,17 @@ $width-settings-bar-max: 500px;
grid-template-columns: 100%;
grid-template-rows: 100%;
height: calc(100% - 2px);
- .layers-tab {
- display: grid;
- grid-template-rows: auto 1fr;
- grid-template-columns: 100%;
- height: 100%;
- overflow: hidden;
+ .tabs-wrapper {
+ .layers-tab {
+ display: grid;
+ grid-template-rows: auto 1fr;
+ grid-template-columns: 100%;
+ height: 100%;
+ overflow: hidden;
+ }
}
}
}
+:global(.tab-spacing) {
+ margin: $s-4 $s-4 0 $s-4;
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
index 339aa0bf6e..cd6b7a4066 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs
@@ -5,2374 +5,23 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.sidebar.assets
+ (:require-macros [app.main.style :refer [css]])
(:require
- [app.common.data :as d]
[app.common.data.macros :as dm]
- [app.common.media :as cm]
- [app.common.pages.helpers :as cph]
- [app.common.spec :as us]
- [app.common.types.file :as ctf]
- [app.config :as cf]
- [app.main.data.events :as ev]
[app.main.data.modal :as modal]
- [app.main.data.workspace :as dw]
- [app.main.data.workspace.colors :as dc]
- [app.main.data.workspace.libraries :as dwl]
- [app.main.data.workspace.media :as dwm]
- [app.main.data.workspace.texts :as dwt]
- [app.main.data.workspace.undo :as dwu]
[app.main.refs :as refs]
- [app.main.render :refer [component-svg]]
- [app.main.store :as st]
- [app.main.ui.components.color-bullet :as bc]
- [app.main.ui.components.context-menu :refer [context-menu]]
- [app.main.ui.components.editable-label :refer [editable-label]]
- [app.main.ui.components.file-uploader :refer [file-uploader]]
- [app.main.ui.components.forms :as fm]
+ [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
+ [app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.context :as ctx]
- [app.main.ui.hooks :as h]
[app.main.ui.icons :as i]
- [app.main.ui.workspace.libraries :refer [create-file-library-ref]]
- [app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry]]
- [app.util.color :as uc]
+ [app.main.ui.workspace.sidebar.assets.common :as cmm]
+ [app.main.ui.workspace.sidebar.assets.file-library :refer [file-library]]
[app.util.dom :as dom]
- [app.util.dom.dnd :as dnd]
[app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
- [app.util.router :as rt]
- [app.util.strings :refer [matches-search]]
- [app.util.timers :as ts]
- [cljs.spec.alpha :as s]
[cuerdas.core :as str]
- [okulary.core :as l]
- [potok.core :as ptk]
[rumext.v2 :as mf]))
-(def ctx:filters (mf/create-context nil))
-(def ctx:toggle-ordering (mf/create-context nil))
-(def ctx:toggle-list-style (mf/create-context nil))
-
-(def lens:selected
- (-> (l/in [:workspace-assets :selected])
- (l/derived st/state)))
-
-(def lens:open-status
- (l/derived (l/in [:workspace-assets :open-status]) st/state))
-
-(def lens:typography-section-state
- (l/derived (fn [gstate]
- {:rename-typography (:rename-typography gstate)
- :edit-typography (:edit-typography gstate)})
- refs/workspace-global
- =))
-
-;; ---- Group assets management ----
-
-(defn group-assets
- "Convert a list of assets in a nested structure like this:
-
- {'': [{assetA} {assetB}]
- 'group1': {'': [{asset1A} {asset1B}]
- 'subgroup11': {'': [{asset11A} {asset11B} {asset11C}]}
- 'subgroup12': {'': [{asset12A}]}}
- 'group2': {'subgroup21': {'': [{asset21A}}}}
- "
- [assets reverse-sort?]
- (when-not (empty? assets)
- (reduce (fn [groups {:keys [path] :as asset}]
- (let [path (cph/split-path (or path ""))]
- (update-in groups
- (conj path "")
- (fn [group]
- (if group
- (conj group asset)
- [asset])))))
- (sorted-map-by (fn [key1 key2]
- (if reverse-sort?
- (compare key2 key1)
- (compare key1 key2))))
- assets)))
-
-(defn add-group
- [asset group-name]
- (-> (:path asset)
- (cph/merge-path-item group-name)
- (cph/merge-path-item (:name asset))))
-
-(defn rename-group
- [asset path last-path]
- (-> (:path asset)
- (str/slice 0 (count path))
- (cph/split-path)
- butlast
- (vec)
- (conj last-path)
- (cph/join-path)
- (str (str/slice (:path asset) (count path)))
- (cph/merge-path-item (:name asset))))
-
-(defn ungroup
- [asset path]
- (-> (:path asset)
- (str/slice 0 (count path))
- (cph/split-path)
- butlast
- (cph/join-path)
- (str (str/slice (:path asset) (count path)))
- (cph/merge-path-item (:name asset))))
-
-(s/def ::asset-name ::us/not-empty-string)
-(s/def ::name-group-form
- (s/keys :req-un [::asset-name]))
-
-(mf/defc name-group-dialog
- {::mf/register modal/components
- ::mf/register-as :name-group-dialog}
- [{:keys [path last-path accept] :as ctx
- :or {path "" last-path ""}}]
- (let [initial (mf/use-memo
- (mf/deps last-path)
- (constantly {:asset-name last-path}))
- form (fm/use-form :spec ::name-group-form
- :initial initial)
-
- create? (empty? path)
-
- on-close (mf/use-fn #(modal/hide!))
-
- on-accept
- (mf/use-fn
- (mf/deps form)
- (fn [_]
- (let [asset-name (get-in @form [:clean-data :asset-name])]
- (if create?
- (accept asset-name)
- (accept path asset-name))
- (modal/hide!))))]
-
- [:div.modal-overlay
- [:div.modal-container.confirm-dialog
- [:div.modal-header
- [:div.modal-header-title
- [:h2 (if create?
- (tr "workspace.assets.create-group")
- (tr "workspace.assets.rename-group"))]]
- [:div.modal-close-button
- {:on-click on-close} i/close]]
-
- [:div.modal-content.generic-form
- [:& fm/form {:form form :on-submit on-accept}
- [:& fm/input {:name :asset-name
- :auto-focus? true
- :label (tr "workspace.assets.group-name")
- :hint (tr "workspace.assets.create-group-hint")}]]]
-
- [:div.modal-footer
- [:div.action-buttons
- [:input.cancel-button
- {:type "button"
- :value (tr "labels.cancel")
- :on-click on-close}]
-
- [:input.accept-button.primary
- {:type "button"
- :class (when-not (:valid @form) "btn-disabled")
- :disabled (not (:valid @form))
- :value (if create? (tr "labels.create") (tr "labels.rename"))
- :on-click on-accept}]]]]]))
-
-
-;; ---- Group assets by drag and drop ----
-
-(defn- create-assets-group
- [rename components-to-group group-name]
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (apply st/emit!
- (->> components-to-group
- (map #(rename
- (:id %)
- (add-group % group-name)))))
- (st/emit! (dwu/commit-undo-transaction undo-id))))
-
-(defn- on-drop-asset
- [event asset dragging* selected selected-full selected-paths rename]
- (let [create-typed-assets-group (partial create-assets-group rename)]
- (when (not (dnd/from-child? event))
- (reset! dragging* false)
- (when
- (and (not (contains? selected (:id asset)))
- (every? #(= % (:path asset)) selected-paths))
- (let [components-to-group (conj selected-full asset)
- create-typed-assets-group (partial create-typed-assets-group components-to-group)]
- (modal/show! :name-group-dialog {:accept create-typed-assets-group}))))))
-
-(defn- on-drag-enter-asset
- [event asset dragging* selected selected-paths]
- (when (and
- (not (dnd/from-child? event))
- (every? #(= % (:path asset)) selected-paths)
- (not (contains? selected (:id asset))))
- (reset! dragging* true)))
-
-(defn- on-drag-leave-asset
- [event dragging*]
- (when (not (dnd/from-child? event))
- (reset! dragging* false)))
-
-(defn- create-counter-element
- [asset-count]
- (let [counter-el (dom/create-element "div")]
- (dom/set-property! counter-el "class" "drag-counter")
- (dom/set-text! counter-el (str asset-count))
- counter-el))
-
-(defn- set-drag-image
- [event item-ref num-selected]
- (let [offset (dom/get-offset-position (.-nativeEvent event))
- item-el (mf/ref-val item-ref)
- counter-el (create-counter-element num-selected)]
-
- ;; set-drag-image requires that the element is rendered and
- ;; visible to the user at the moment of creating the ghost
- ;; image (to make a snapshot), but you may remove it right
- ;; afterwards, in the next render cycle.
- (dom/append-child! item-el counter-el)
- (dnd/set-drag-image! event item-el (:x offset) (:y offset))
- (ts/raf #(.removeChild ^js item-el counter-el))))
-
-(defn- on-asset-drag-start
- [event file-id asset selected item-ref asset-type on-drag-start]
- (let [id-asset (:id asset)
- num-selected (if (contains? selected id-asset)
- (count selected)
- 1)]
- (when (not (contains? selected id-asset))
- (st/emit! (dw/unselect-all-assets file-id)
- (dw/toggle-selected-assets file-id id-asset asset-type)))
- (on-drag-start asset event)
- (when (> num-selected 1)
- (set-drag-image event item-ref num-selected))))
-
-(defn- on-drag-enter-asset-group
- [event dragging* prefix selected-paths]
- (dom/stop-propagation event)
- (when (and (not (dnd/from-child? event))
- (not (every? #(= % prefix) selected-paths)))
- (reset! dragging* true)))
-
-(defn- on-drop-asset-group
- [event dragging* prefix selected-paths selected-full rename]
- (dom/stop-propagation event)
- (when (not (dnd/from-child? event))
- (reset! dragging* false)
- (when (not (every? #(= % prefix) selected-paths))
- (doseq [target-asset selected-full]
- (st/emit!
- (rename
- (:id target-asset)
- (cph/merge-path-item prefix (:name target-asset))))))))
-
-;; ---- Common blocks ----
-
-(def ^:private initial-context-menu-state
- {:open? false :top nil :left nil})
-
-(defn- open-context-menu
- [state pos]
- (let [top (:y pos)
- left (+ (:x pos) 10)]
- (assoc state
- :open? true
- :top top
- :left left)))
-
-(defn- close-context-menu
- [state]
- (assoc state :open? false))
-
-(mf/defc assets-context-menu
- {::mf/wrap-props false}
- [{:keys [options state on-close]}]
- [:& context-menu
- {:selectable false
- :show (:open? state)
- :on-close on-close
- :top (:top state)
- :left (:left state)
- :options options}])
-
-(mf/defc asset-section
- {::mf/wrap-props false}
- [{:keys [children file-id title section assets-count open?]}]
- (let [children (->> (if (array? children) children [children])
- (filter some?))
- get-role #(.. % -props -role)
- title-buttons (filter #(= (get-role %) :title-button) children)
- content (filter #(= (get-role %) :content) children)]
- [:div.asset-section
- [:div.asset-title {:class (when (not ^boolean open?) "closed")}
- [:span {:on-click #(st/emit! (dw/set-assets-section-open file-id section (not open?)))}
- i/arrow-slide title]
- [:span.num-assets (str "\u00A0(") assets-count ")"] ;; Unicode 00A0 is non-breaking space
- title-buttons]
- (when ^boolean open?
- content)]))
-
-(mf/defc asset-section-block
- [{:keys [children]}]
- [:* children])
-
-(mf/defc asset-group-title
- [{:keys [file-id section path group-open? on-rename on-ungroup]}]
- (when-not (empty? path)
- (let [[other-path last-path truncated] (cph/compact-path path 35)
- menu-state (mf/use-state initial-context-menu-state)
-
- on-fold-group
- (mf/use-fn
- (mf/deps file-id section path group-open?)
- (fn [event]
- (dom/stop-propagation event)
- (st/emit! (dw/set-assets-group-open file-id
- section
- path
- (not group-open?)))))
- on-context-menu
- (mf/use-fn
- (fn [event]
- (dom/prevent-default event)
- (let [pos (dom/get-client-position event)]
- (swap! menu-state open-context-menu pos))))
-
- on-close-menu
- (mf/use-fn #(swap! menu-state close-context-menu))]
-
- [:div.group-title {:class (when-not group-open? "closed")
- :on-click on-fold-group
- :on-context-menu on-context-menu}
- [:span i/arrow-slide]
- (when-not (empty? other-path)
- [:span.dim {:title (when truncated path)}
- other-path "\u00A0/\u00A0"])
- [:span {:title (when truncated path)}
- last-path]
- [:& assets-context-menu
- {:on-close on-close-menu
- :state @menu-state
- :options [[(tr "workspace.assets.rename") #(on-rename % path last-path)]
- [(tr "workspace.assets.ungroup") #(on-ungroup path)]]}]])))
-
-
-;;---- Components section ----
-
-
-(defn- get-component-root-and-container
- [file-id component components-v2]
- (if (= file-id (:id @refs/workspace-file))
- (let [data @refs/workspace-data]
- [(ctf/get-component-root data component)
- (if components-v2
- (ctf/get-component-page data component)
- component)])
- (let [data (dm/get-in @refs/workspace-libraries [file-id :data])]
- [(ctf/get-component-root data component)
- (if components-v2
- (ctf/get-component-page data component)
- component)])))
-
-(mf/defc components-item
- {::mf/wrap-props false}
- [{:keys [component renaming listing-thumbs? selected
- file-id on-asset-click on-context-menu on-drag-start do-rename
- cancel-rename selected-full selected-paths]}]
- (let [item-ref (mf/use-ref)
-
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- read-only? (mf/use-ctx ctx/workspace-read-only?)
- components-v2 (mf/use-ctx ctx/components-v2)
- component-id (:id component)
-
- ;; NOTE: we don't use reactive deref for it because we don't
- ;; really need rerender on any change on the file change. If
- ;; the component changes, it will trigger rerender anyway.
- [root-shape container]
- (get-component-root-and-container file-id component components-v2)
-
- unselect-all
- (mf/use-fn
- (fn []
- (st/emit! (dw/unselect-all-assets))))
-
- on-component-click
- (mf/use-fn
- (mf/deps component selected)
- (fn [event]
- (dom/stop-propagation event)
- (on-asset-click component-id unselect-all event)))
-
- on-component-double-click
- (mf/use-fn
- (mf/deps file-id component-id)
- (fn [event]
- (dom/stop-propagation event)
- (st/emit! (dw/go-to-main-instance file-id component-id))))
-
- on-drop
- (mf/use-fn
- (mf/deps component dragging* selected selected-full selected-paths)
- (fn [event]
- (on-drop-asset event component dragging* selected selected-full
- selected-paths dwl/rename-component)))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps component dragging* selected selected-paths)
- (fn [event]
- (on-drag-enter-asset event component dragging* selected selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-component-drag-start
- (mf/use-fn
- (mf/deps file-id component selected item-ref on-drag-start read-only?)
- (fn [event]
- (if read-only?
- (dom/prevent-default event)
- (on-asset-drag-start event file-id component selected item-ref :components on-drag-start))))
-
- on-context-menu
- (mf/use-fn
- (mf/deps component-id)
- (partial on-context-menu component-id))]
-
- [:div {:ref item-ref
- :class (dom/classnames
- :selected (contains? selected (:id component))
- :grid-cell listing-thumbs?
- :enum-item (not listing-thumbs?))
- :id (dm/str "component-shape-id-" (:id component))
- :draggable (not read-only?)
- :on-click on-component-click
- :on-double-click on-component-double-click
- :on-context-menu on-context-menu
- :on-drag-start on-component-drag-start
- :on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- (when (and (some? root-shape)
- (some? container))
- [:*
- [:& component-svg {:root-shape root-shape
- :objects (:objects container)}]
- (let [renaming? (= renaming (:id component))]
- [:*
- [:& editable-label
- {:class-name (dom/classnames
- :cell-name listing-thumbs?
- :item-name (not listing-thumbs?)
- :editing renaming?)
- :value (cph/merge-path-item (:path component) (:name component))
- :tooltip (cph/merge-path-item (:path component) (:name component))
- :display-value (:name component)
- :editing? renaming?
- :disable-dbl-click? true
- :on-change do-rename
- :on-cancel cancel-rename}]
-
- (when ^boolean dragging?
- [:div.dragging])])])]))
-
-(mf/defc components-group
- {::mf/wrap-props false}
- [{:keys [file-id prefix groups open-groups renaming listing-thumbs? selected on-asset-click
- on-drag-start do-rename cancel-rename on-rename-group on-group on-ungroup on-context-menu
- selected-full]}]
-
- (let [group-open? (get open-groups prefix true)
-
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- selected-paths (mf/with-memo [selected-full]
- (into #{}
- (comp (map :path) (d/nilv ""))
- selected-full))
- on-drag-enter
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths)
- (fn [event]
- (on-drag-enter-asset-group event dragging* prefix selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-drop
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths selected-full)
- (fn [event]
- (on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-component)))]
-
- [:div {:on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- [:& asset-group-title
- {:file-id file-id
- :section :components
- :path prefix
- :group-open? group-open?
- :on-rename on-rename-group
- :on-ungroup on-ungroup}]
-
- (when group-open?
- [:*
- (let [components (get groups "" [])]
- [:div {:class-name (dom/classnames
- :asset-grid listing-thumbs?
- :big listing-thumbs?
- :asset-enum (not listing-thumbs?)
- :drop-space (and
- (empty? components)
- (some? groups)
- (not dragging?)))
- :on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- (when ^boolean dragging?
- [:div.grid-placeholder "\u00A0"])
-
- (when (and (empty? components)
- (some? groups))
- [:div.drop-space])
-
- (for [component components]
- [:& components-item
- {:component component
- :key (dm/str "component-" (:id component))
- :renaming renaming
- :listing-thumbs? listing-thumbs?
- :file-id file-id
- :selected selected
- :selected-full selected-full
- :selected-paths selected-paths
- :on-asset-click on-asset-click
- :on-context-menu on-context-menu
- :on-drag-start on-drag-start
- :on-group on-group
- :do-rename do-rename
- :cancel-rename cancel-rename}])])
-
- (for [[path-item content] groups]
- (when-not (empty? path-item)
- [:& components-group {:file-id file-id
- :key path-item
- :prefix (cph/merge-path-item prefix path-item)
- :groups content
- :open-groups open-groups
- :renaming renaming
- :listing-thumbs? listing-thumbs?
- :selected selected
- :on-asset-click on-asset-click
- :on-drag-start on-drag-start
- :do-rename do-rename
- :cancel-rename cancel-rename
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :on-context-menu on-context-menu
- :selected-full selected-full}]))])]))
-
-(mf/defc components-section
- {::mf/wrap-props false}
- [{:keys [file-id local? components listing-thumbs? open? reverse-sort? selected
- on-asset-click on-assets-delete on-clear-selection open-status-ref]}]
-
- (let [input-ref (mf/use-ref nil)
-
- state* (mf/use-state {})
- state (deref state*)
-
- current-component-id (:component-id state)
- renaming? (:renaming state)
-
- open-groups-ref (mf/with-memo [open-status-ref]
- (-> (l/in [:groups :components])
- (l/derived open-status-ref)))
-
- open-groups (mf/deref open-groups-ref)
-
- menu-state (mf/use-state initial-context-menu-state)
- read-only? (mf/use-ctx ctx/workspace-read-only?)
-
- selected (:components selected)
- selected-full (into #{} (filter #(contains? selected (:id %))) components)
- multi-components? (> (count selected) 1)
- multi-assets? (or (seq (:graphics selected))
- (seq (:colors selected))
- (seq (:typographies selected)))
-
- groups (mf/with-memo [components reverse-sort?]
- (group-assets components reverse-sort?))
-
- components-v2 (mf/use-ctx ctx/components-v2)
-
- add-component
- (mf/use-fn
- (fn []
- (st/emit! (dw/set-assets-section-open file-id :components true))
- (dom/click (mf/ref-val input-ref))))
-
- on-file-selected
- (mf/use-fn
- (mf/deps file-id)
- (fn [blobs]
- (let [params {:file-id file-id
- :blobs (seq blobs)}]
- (st/emit! (dwm/upload-media-components params)
- (ptk/event ::ev/event {::ev/name "add-asset-to-library"
- :asset-type "components"})))))
-
- on-duplicate
- (mf/use-fn
- (mf/deps current-component-id selected)
- (fn []
- (if (empty? selected)
- (st/emit! (dwl/duplicate-component file-id current-component-id))
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit! (map (partial dwl/duplicate-component file-id) selected))
- (st/emit! (dwu/commit-undo-transaction undo-id))))))
-
- on-delete
- (mf/use-fn
- (mf/deps current-component-id file-id multi-components? multi-assets? on-assets-delete)
- (fn []
- (let [undo-id (js/Symbol)]
- (if (or multi-components? multi-assets?)
- (on-assets-delete)
- (st/emit! (dwu/start-undo-transaction undo-id)
- (dwl/delete-component {:id current-component-id})
- (dwl/sync-file file-id file-id :components current-component-id)
- (dwu/commit-undo-transaction undo-id))))))
-
- on-close-menu
- (mf/use-fn #(swap! menu-state close-context-menu))
-
- on-rename
- (mf/use-fn #(swap! state* assoc :renaming true))
-
- cancel-rename
- (mf/use-fn #(swap! state* dissoc :renaming))
-
- do-rename
- (mf/use-fn
- (mf/deps current-component-id)
- (fn [new-name]
- (swap! state* dissoc :renaming)
- (st/emit!
- (dwl/rename-component-and-main-instance current-component-id new-name))))
-
- on-context-menu
- (mf/use-fn
- (mf/deps selected on-clear-selection read-only?)
- (fn [component-id event]
- (dom/prevent-default event)
- (let [pos (dom/get-client-position event)]
- (when (and local? (not read-only?))
- (when-not (contains? selected component-id)
- (on-clear-selection))
-
- (swap! state* assoc :component-id component-id)
- (swap! menu-state open-context-menu pos)))))
-
- create-group
- (mf/use-fn
- (mf/deps current-component-id components selected on-clear-selection)
- (fn [group-name]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> components
- (filter #(if multi-components?
- (contains? selected (:id %))
- (= current-component-id (:id %))))
- (map #(dwl/rename-component
- (:id %)
- (add-group % group-name)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- rename-group
- (mf/use-fn
- (mf/deps components)
- (fn [path last-path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> components
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/rename-component
- (:id %)
- (rename-group % path last-path)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-group
- (mf/use-fn
- (mf/deps components selected create-group)
- (fn [event]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:accept create-group})))
-
- on-rename-group
- (mf/use-fn
- (mf/deps components)
- (fn [event path last-path]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:path path
- :last-path last-path
- :accept rename-group})))
-
- on-ungroup
- (mf/use-fn
- (mf/deps components)
- (fn [path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> components
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/rename-component (:id %) (ungroup % path)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-drag-start
- (mf/use-fn
- (mf/deps file-id)
- (fn [component event]
- (dnd/set-data! event "penpot/component" {:file-id file-id
- :component component})
- (dnd/set-allowed-effect! event "move")))
-
- on-show-main
- (mf/use-fn
- (mf/deps current-component-id file-id)
- (fn [event]
- (dom/stop-propagation event)
- (st/emit! (dw/go-to-main-instance file-id current-component-id))))
-
- on-asset-click
- (mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
-
- [:& asset-section {:file-id file-id
- :title (tr "workspace.assets.components")
- :section :components
- :assets-count (count components)
- :open? open?}
- (when local?
- [:& asset-section-block {:role :title-button}
- (when (and components-v2 (not read-only?))
- [:div.assets-button {:on-click add-component}
- i/plus
- [:& file-uploader {:accept cm/str-image-types
- :multi true
- :ref input-ref
- :on-selected on-file-selected}]])])
-
- [:& asset-section-block {:role :content}
- [:& components-group {:file-id file-id
- :prefix ""
- :groups groups
- :open-groups open-groups
- :renaming (when ^boolean renaming? current-component-id)
- :listing-thumbs? listing-thumbs?
- :selected selected
- :on-asset-click on-asset-click
- :on-drag-start on-drag-start
- :do-rename do-rename
- :cancel-rename cancel-rename
- :on-rename-group on-rename-group
- :on-group on-group
- :on-ungroup on-ungroup
- :on-context-menu on-context-menu
- :selected-full selected-full}]
- (when local?
- [:& assets-context-menu
- {:on-close on-close-menu
- :state @menu-state
- :options [(when-not (or multi-components? multi-assets?)
- [(tr "workspace.assets.rename") on-rename])
- (when-not multi-assets?
- [(if components-v2
- (tr "workspace.assets.duplicate-main")
- (tr "workspace.assets.duplicate")) on-duplicate])
- [(tr "workspace.assets.delete") on-delete]
- (when-not multi-assets?
- [(tr "workspace.assets.group") on-group])
- (when (and components-v2 (not multi-assets?))
- [(tr "workspace.shape.menu.show-main") on-show-main])]}])]]))
-
-
-;; ---- Graphics section ----
-
-(mf/defc graphics-item
- [{:keys [object renaming listing-thumbs? selected-objects file-id
- on-asset-click on-context-menu on-drag-start do-rename cancel-rename
- selected-full selected-graphics-paths]}]
- (let [item-ref (mf/use-ref)
- visible? (h/use-visible item-ref :once? true)
- object-id (:id object)
-
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- read-only? (mf/use-ctx ctx/workspace-read-only?)
-
- on-drop
- (mf/use-fn
- (mf/deps object dragging* selected-objects selected-full selected-graphics-paths)
- (fn [event]
- (on-drop-asset event object dragging* selected-objects selected-full
- selected-graphics-paths dwl/rename-media)))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps object dragging* selected-objects selected-graphics-paths)
- (fn [event]
- (on-drag-enter-asset event object dragging* selected-objects selected-graphics-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-grahic-drag-start
- (mf/use-fn
- (mf/deps object file-id selected-objects item-ref on-drag-start read-only?)
- (fn [event]
- (if read-only?
- (dom/prevent-default event)
- (on-asset-drag-start event file-id object selected-objects item-ref :graphics on-drag-start))))
-
- on-context-menu
- (mf/use-fn
- (mf/deps object-id)
- (partial on-context-menu object-id))
-
- on-asset-click
- (mf/use-fn
- (mf/deps object-id on-asset-click)
- (partial on-asset-click object-id nil))
-
- ]
-
- [:div {:ref item-ref
- :class-name (dom/classnames
- :selected (contains? selected-objects object-id)
- :grid-cell listing-thumbs?
- :enum-item (not listing-thumbs?))
- :draggable (not read-only?)
- :on-click on-asset-click
- :on-context-menu on-context-menu
- :on-drag-start on-grahic-drag-start
- :on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- (when visible?
- [:*
- [:img {:src (when visible? (cf/resolve-file-media object true))
- :draggable false}] ;; Also need to add css pointer-events: none
-
- (let [renaming? (= renaming (:id object))]
- [:*
- [:& editable-label
- {:class-name (dom/classnames
- :cell-name listing-thumbs?
- :item-name (not listing-thumbs?)
- :editing renaming?)
- :value (cph/merge-path-item (:path object) (:name object))
- :tooltip (cph/merge-path-item (:path object) (:name object))
- :display-value (:name object)
- :editing? renaming?
- :disable-dbl-click? true
- :on-change do-rename
- :on-cancel cancel-rename}]
-
- (when ^boolean dragging?
- [:div.dragging])])])]))
-
-(mf/defc graphics-group
- [{:keys [file-id prefix groups open-groups renaming listing-thumbs? selected-objects on-asset-click
- on-drag-start do-rename cancel-rename on-rename-group on-ungroup
- on-context-menu selected-full]}]
- (let [group-open? (get open-groups prefix true)
-
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- selected-paths
- (mf/with-memo [selected-full]
- (into #{}
- (comp (map :path) (d/nilv ""))
- selected-full))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths)
- (fn [event]
- (on-drag-enter-asset-group event dragging* prefix selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-drop
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths selected-full)
- (fn [event]
- (on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-media)))]
-
- [:div {:on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
- [:& asset-group-title {:file-id file-id
- :section :graphics
- :path prefix
- :group-open? group-open?
- :on-rename on-rename-group
- :on-ungroup on-ungroup}]
- (when group-open?
- [:*
- (let [objects (get groups "" [])]
- [:div {:class-name (dom/classnames
- :asset-grid listing-thumbs?
- :asset-enum (not listing-thumbs?)
- :drop-space (and
- (empty? objects)
- (some? groups)
- (not dragging?)))
- :on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- (when ^boolean dragging?
- [:div.grid-placeholder "\u00A0"])
-
- (when (and (empty? objects)
- (some? groups))
- [:div.drop-space])
-
- (for [object objects]
- [:& graphics-item {:key (dm/str "object-" (:id object))
- :file-id file-id
- :object object
- :renaming renaming
- :listing-thumbs? listing-thumbs?
- :selected-objects selected-objects
- :on-asset-click on-asset-click
- :on-context-menu on-context-menu
- :on-drag-start on-drag-start
- :do-rename do-rename
- :cancel-rename cancel-rename
- :selected-full selected-full
- :selected-paths selected-paths}])])
- (for [[path-item content] groups]
- (when-not (empty? path-item)
- [:& graphics-group {:file-id file-id
- :key path-item
- :prefix (cph/merge-path-item prefix path-item)
- :groups content
- :open-groups open-groups
- :renaming renaming
- :listing-thumbs? listing-thumbs?
- :selected-objects selected-objects
- :on-asset-click on-asset-click
- :on-drag-start on-drag-start
- :do-rename do-rename
- :cancel-rename cancel-rename
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :on-context-menu on-context-menu
- :selected-full selected-full
- :selected-paths selected-paths}]))])]))
-
-(mf/defc graphics-section
- {::mf/wrap-props false}
- [{:keys [file-id project-id local? objects listing-thumbs? open? open-status-ref selected reverse-sort?
- on-asset-click on-assets-delete on-clear-selection]}]
- (let [input-ref (mf/use-ref nil)
- state (mf/use-state {:renaming nil :object-id nil})
-
- menu-state (mf/use-state initial-context-menu-state)
- read-only? (mf/use-ctx ctx/workspace-read-only?)
-
- open-groups-ref (mf/with-memo [open-status-ref]
- (-> (l/in [:groups :graphics])
- (l/derived open-status-ref)))
- open-groups (mf/deref open-groups-ref)
-
- selected (:graphics selected)
- selected-full (into #{} (filter #(contains? selected (:id %))) objects)
- multi-objects? (> (count selected) 1)
- multi-assets? (or (seq (:components selected))
- (seq (:colors selected))
- (seq (:typographies selected)))
-
- objects (mf/with-memo [objects]
- (mapv dwl/extract-path-if-missing objects))
-
- groups (mf/with-memo [objects reverse-sort?]
- (group-assets objects reverse-sort?))
-
- components-v2 (mf/use-ctx ctx/components-v2)
- team-id (mf/use-ctx ctx/current-team-id)
-
- add-graphic
- (mf/use-fn
- (fn []
- (st/emit! (dw/set-assets-section-open file-id :graphics true))
- (dom/click (mf/ref-val input-ref))))
-
- on-file-selected
- (mf/use-fn
- (mf/deps file-id project-id team-id)
- (fn [blobs]
- (let [params {:file-id file-id
- :blobs (seq blobs)}]
- (st/emit! (dwm/upload-media-asset params)
- (ptk/event ::ev/event {::ev/name "add-asset-to-library"
- :asset-type "graphics"
- :file-id file-id
- :project-id project-id
- :team-id team-id})))))
- on-delete
- (mf/use-fn
- (mf/deps @state multi-objects? multi-assets?)
- (fn []
- (if (or multi-objects? multi-assets?)
- (on-assets-delete)
- (st/emit! (dwl/delete-media {:id (:object-id @state)})))))
-
- on-rename
- (mf/use-fn
- (fn []
- (swap! state (fn [state]
- (assoc state :renaming (:component-id state))))))
- cancel-rename
- (mf/use-fn
- (fn []
- (swap! state assoc :renaming nil)))
-
- do-rename
- (mf/use-fn
- (mf/deps @state)
- (fn [new-name]
- (st/emit! (dwl/rename-media (:renaming @state) new-name))
- (swap! state assoc :renaming nil)))
-
- on-context-menu
- (mf/use-fn
- (mf/deps selected on-clear-selection read-only?)
- (fn [object-id event]
- (dom/prevent-default event)
- (let [pos (dom/get-client-position event)]
- (when (and local? (not read-only?))
- (when-not (contains? selected object-id)
- (on-clear-selection))
- (swap! state assoc :object-id object-id)
- (swap! menu-state open-context-menu pos)))))
-
- on-close-menu
- (mf/use-fn
- (fn []
- (swap! menu-state close-context-menu)))
-
- create-group
- (mf/use-fn
- (mf/deps objects selected on-clear-selection (:object-id @state))
- (fn [group-name]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> objects
- (filter #(if multi-objects?
- (contains? selected (:id %))
- (= (:object-id @state) (:id %))))
- (map #(dwl/rename-media (:id %) (add-group % group-name)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- rename-group
- (mf/use-fn
- (mf/deps objects)
- (fn [path last-path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> objects
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/rename-media (:id %) (rename-group % path last-path)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-group
- (mf/use-fn
- (mf/deps objects selected create-group)
- (fn [event]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:accept create-group})))
-
- on-rename-group
- (mf/use-fn
- (mf/deps objects)
- (fn [event path last-path]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:path path
- :last-path last-path
- :accept rename-group})))
- on-ungroup
- (mf/use-fn
- (mf/deps objects)
- (fn [path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> objects
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/rename-media (:id %) (ungroup % path)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-drag-start
- (mf/use-fn
- (fn [{:keys [name id mtype]} event]
- (dnd/set-data! event "text/asset-id" (str id))
- (dnd/set-data! event "text/asset-name" name)
- (dnd/set-data! event "text/asset-type" mtype)
- (dnd/set-allowed-effect! event "move")))
-
- on-asset-click
- (mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
-
- [:& asset-section {:file-id file-id
- :title (tr "workspace.assets.graphics")
- :section :graphics
- :assets-count (count objects)
- :open? open?}
- (when local?
- [:& asset-section-block {:role :title-button}
- (when (and (not components-v2) (not read-only?))
- [:div.assets-button {:on-click add-graphic}
- i/plus
- [:& file-uploader {:accept cm/str-image-types
- :multi true
- :ref input-ref
- :on-selected on-file-selected}]])])
-
- [:& asset-section-block {:role :content}
- [:& graphics-group {:file-id file-id
- :prefix ""
- :groups groups
- :open-groups open-groups
- :renaming (:renaming @state)
- :listing-thumbs? listing-thumbs?
- :selected selected
- :on-asset-click on-asset-click
- :on-drag-start on-drag-start
- :do-rename do-rename
- :cancel-rename cancel-rename
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :on-context-menu on-context-menu
- :selected-full selected-full}]
- (when local?
- [:& assets-context-menu
- {:on-close on-close-menu
- :state @menu-state
- :options [(when-not (or multi-objects? multi-assets?)
- [(tr "workspace.assets.rename") on-rename])
- [(tr "workspace.assets.delete") on-delete]
- (when-not multi-assets?
- [(tr "workspace.assets.group") on-group])]}])]]))
-
-
-;; ---- Colors section ----
-
-(mf/defc color-item
- {::mf/wrap-props false}
- [{:keys [color local? file-id selected multi-colors? multi-assets?
- on-asset-click on-assets-delete on-clear-selection on-group
- selected-full selected-paths move-color]}]
-
- (let [color (mf/with-memo [color file-id]
- (cond-> color
- (:value color) (assoc :color (:value color) :opacity 1)
- (:value color) (dissoc :value)
- true (assoc :file-id file-id)))
-
-
- color-id (:id color)
-
- item-ref (mf/use-ref)
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- rename? (= (:color-for-rename @refs/workspace-local) color-id)
- input-ref (mf/use-ref)
-
- editing* (mf/use-state rename?)
- editing? (deref editing*)
-
- menu-state (mf/use-state initial-context-menu-state)
- read-only? (mf/use-ctx ctx/workspace-read-only?)
-
- default-name (cond
- (:gradient color) (uc/gradient-type->string (dm/get-in color [:gradient :type]))
- (:color color) (:color color)
- :else (:value color))
-
- apply-color
- (mf/use-fn
- (mf/deps color)
- (fn [event]
- (st/emit! (dc/apply-color-from-palette (merge uc/empty-color color) (kbd/alt? event)))))
-
- rename-color
- (mf/use-fn
- (mf/deps file-id color-id)
- (fn [name]
- (st/emit! (dwl/rename-color file-id color-id name))))
-
- edit-color
- (mf/use-fn
- (mf/deps color file-id)
- (fn [attrs]
- (let [name (cph/merge-path-item (:path color) (:name color))
- color (-> attrs
- (assoc :id (:id color))
- (assoc :file-id file-id)
- (assoc :name name))]
- (st/emit! (dwl/update-color color file-id)))))
-
- delete-color
- (mf/use-fn
- (mf/deps multi-colors? multi-assets? file-id color-id)
- (fn []
- (if (or multi-colors? multi-assets?)
- (on-assets-delete)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id)
- (dwl/delete-color color)
- (dwl/sync-file file-id file-id :colors color-id)
- (dwu/commit-undo-transaction undo-id))))))
-
- rename-color-clicked
- (mf/use-fn
- (mf/deps read-only? local?)
- (fn [event]
- (when (and local? (not read-only?))
- (dom/prevent-default event)
- (reset! editing* true))))
-
- input-blur
- (mf/use-fn
- (mf/deps rename-color)
- (fn [event]
- (let [target (dom/event->target event)
- name (dom/get-value target)]
- (rename-color name)
- (st/emit! dwl/clear-color-for-rename)
- (reset! editing* false))))
-
- input-key-down
- (mf/use-fn
- (mf/deps input-blur)
- (fn [event]
- (when (kbd/esc? event)
- (st/emit! dwl/clear-color-for-rename)
- (reset! editing* false))
- (when (kbd/enter? event)
- (input-blur event))))
-
- edit-color-clicked
- (mf/use-fn
- (mf/deps edit-color color)
- (fn [event]
- (modal/show! :colorpicker
- {:x (.-clientX ^js event)
- :y (.-clientY ^js event)
- :on-accept edit-color
- :data color
- :position :right})))
-
- on-context-menu
- (mf/use-fn
- (mf/deps color-id selected on-clear-selection read-only?)
- (fn [event]
- (dom/prevent-default event)
- (let [pos (dom/get-client-position event)]
- (when (and local? (not read-only?))
- (when-not (contains? selected color-id)
- (on-clear-selection))
- (swap! menu-state open-context-menu pos)))))
-
- on-close-menu
- (mf/use-fn
- (fn []
- (swap! menu-state close-context-menu)))
-
- on-drop
- (mf/use-fn
- (mf/deps color dragging* selected selected-full selected-paths move-color)
- (fn [event]
- (on-drop-asset event color dragging* selected selected-full
- selected-paths move-color)))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps color dragging* selected selected-paths)
- (fn [event]
- (on-drag-enter-asset event color dragging* selected selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-color-drag-start
- (mf/use-fn
- (mf/deps color file-id selected item-ref read-only?)
- (fn [event]
- (if read-only?
- (dom/prevent-default event)
- (on-asset-drag-start event file-id color selected item-ref :colors identity))))
-
- on-click
- (mf/use-fn
- (mf/deps color-id apply-color on-asset-click)
- (partial on-asset-click color-id apply-color))]
-
- (mf/with-effect [editing?]
- (when editing?
- (let [input (mf/ref-val input-ref)]
- (dom/select-text! input)
- nil)))
-
- [:div.asset-list-item
- {:class-name (dom/classnames
- :selected (contains? selected (:id color)))
- :on-context-menu on-context-menu
- :on-click (when-not editing? on-click)
- :ref item-ref
- :draggable (and (not read-only?) (not editing?))
- :on-drag-start on-color-drag-start
- :on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- [:& bc/color-bullet {:color color}]
-
- (if ^boolean editing?
- [:input.element-name
- {:type "text"
- :ref input-ref
- :on-blur input-blur
- :on-key-down input-key-down
- :auto-focus true
- :default-value (cph/merge-path-item (:path color) (:name color))}]
-
- [:div.name-block {:title (:name color)
- :on-double-click rename-color-clicked}
- (:name color)
- (when-not (= (:name color) default-name)
- [:span default-name])])
-
- (when local?
- [:& assets-context-menu
- {:on-close on-close-menu
- :state @menu-state
- :options [(when-not (or multi-colors? multi-assets?)
- [(tr "workspace.assets.rename") rename-color-clicked])
- (when-not (or multi-colors? multi-assets?)
- [(tr "workspace.assets.edit") edit-color-clicked])
- [(tr "workspace.assets.delete") delete-color]
- (when-not multi-assets?
- [(tr "workspace.assets.group") (on-group (:id color))])]}])
-
- (when ^boolean dragging?
- [:div.dragging])]))
-
-(mf/defc colors-group
- [{:keys [file-id prefix groups open-groups local? selected
- multi-colors? multi-assets? on-asset-click on-assets-delete
- on-clear-selection on-group on-rename-group on-ungroup colors
- selected-full]}]
- (let [group-open? (get open-groups prefix true)
-
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- selected-paths (mf/with-memo [selected-full]
- (into #{}
- (comp (map :path) (d/nilv ""))
- selected-full))
-
- move-color
- (mf/use-fn (mf/deps file-id) (partial dwl/rename-color file-id))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths)
- (fn [event]
- (on-drag-enter-asset-group event dragging* prefix selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-drop
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths selected-full move-color)
- (fn [event]
- (on-drop-asset-group event dragging* prefix selected-paths selected-full move-color)))]
-
- [:div {:on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
- [:& asset-group-title {:file-id file-id
- :section :colors
- :path prefix
- :group-open? group-open?
- :on-rename on-rename-group
- :on-ungroup on-ungroup}]
- (when group-open?
- [:*
- (let [colors (get groups "" [])]
- [:div.asset-list {:on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- (when ^boolean dragging?
- [:div.grid-placeholder "\u00A0"])
-
- (when (and (empty? colors)
- (some? groups))
- [:div.drop-space])
-
- (for [color colors]
- [:& color-item {:key (dm/str (:id color))
- :color color
- :file-id file-id
- :local? local?
- :selected selected
- :multi-colors? multi-colors?
- :multi-assets? multi-assets?
- :on-asset-click on-asset-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection
- :on-group on-group
- :colors colors
- :selected-full selected-full
- :selected-paths selected-paths
- :move-color move-color}])])
-
- (for [[path-item content] groups]
- (when-not (empty? path-item)
- [:& colors-group {:file-id file-id
- :prefix (cph/merge-path-item prefix path-item)
- :key (dm/str "group-" path-item)
- :groups content
- :open-groups open-groups
- :local? local?
- :selected selected
- :multi-colors? multi-colors?
- :multi-assets? multi-assets?
- :on-asset-click on-asset-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection
- :on-group on-group
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :colors colors
- :selected-full selected-full}]))])]))
-
-(mf/defc colors-section
- [{:keys [file-id local? colors open? open-status-ref selected reverse-sort?
- on-asset-click on-assets-delete on-clear-selection] :as props}]
-
- (let [selected (:colors selected)
- selected-full (mf/with-memo [selected colors]
- (into #{} (filter #(contains? selected (:id %))) colors))
-
- open-groups-ref (mf/with-memo [open-status-ref]
- (-> (l/in [:groups :colors])
- (l/derived open-status-ref)))
- open-groups (mf/deref open-groups-ref)
-
- multi-colors? (> (count selected) 1)
- multi-assets? (or (seq (:components selected))
- (seq (:graphics selected))
- (seq (:typographies selected)))
-
- groups (mf/with-memo [colors reverse-sort?]
- (group-assets colors reverse-sort?))
-
- read-only? (mf/use-ctx ctx/workspace-read-only?)
-
- add-color
- (mf/use-fn
- (fn [value _]
- (st/emit! (dwl/add-color value))))
-
- add-color-clicked
- (mf/use-fn
- (fn [event]
- (let [position (dom/get-client-position event)]
- (st/emit! (dc/select-color position add-color)))))
-
- create-group
- (mf/use-fn
- (mf/deps colors selected on-clear-selection file-id)
- (fn [color-id]
- (fn [group-name]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> colors
- (filter #(if multi-colors?
- (contains? selected (:id %))
- (= color-id (:id %))))
- (map #(dwl/update-color
- (assoc % :name
- (add-group % group-name))
- file-id))))
- (st/emit! (dwu/commit-undo-transaction undo-id))))))
-
- rename-group
- (mf/use-fn
- (mf/deps colors)
- (fn [path last-path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> colors
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/update-color
- (assoc % :name
- (rename-group % path last-path))
- file-id))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-group
- (mf/use-fn
- (mf/deps colors selected)
- (fn [color-id]
- (fn [event]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:accept (create-group color-id)}))))
-
- on-rename-group
- (mf/use-fn
- (mf/deps colors)
- (fn [event path last-path]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:path path
- :last-path last-path
- :accept rename-group})))
- on-ungroup
- (mf/use-fn
- (mf/deps colors)
- (fn [path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (apply st/emit!
- (->> colors
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/update-color
- (assoc % :name
- (ungroup % path))
- file-id))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-asset-click
- (mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
-
- [:& asset-section {:file-id file-id
- :title (tr "workspace.assets.colors")
- :section :colors
- :assets-count (count colors)
- :open? open?}
- (when local?
- [:& asset-section-block {:role :title-button}
- (when-not read-only?
- [:div.assets-button {:on-click add-color-clicked}
- i/plus])])
-
- [:& asset-section-block {:role :content}
- [:& colors-group {:file-id file-id
- :prefix ""
- :groups groups
- :open-groups open-groups
- :local? local?
- :selected selected
- :multi-colors? multi-colors?
- :multi-assets? multi-assets?
- :on-asset-click on-asset-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection
- :on-group on-group
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :colors colors
- :selected-full selected-full}]]]))
-
-;; ---- Typography section ----
-
-(mf/defc typography-item
- {::mf/wrap-props false}
- [{:keys [typography file-id local? handle-change selected apply-typography editing-id on-asset-click
- on-context-menu selected-full selected-paths move-typography rename?]}]
- (let [item-ref (mf/use-ref)
- typography-id (:id typography)
-
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- read-only? (mf/use-ctx ctx/workspace-read-only?)
- editing? (= editing-id (:id typography))
-
- open* (mf/use-state editing?)
- open? (deref open*)
-
- on-drop
- (mf/use-fn
- (mf/deps typography dragging* selected selected-full selected-paths move-typography)
- (fn [event]
- (on-drop-asset event typography dragging* selected selected-full
- selected-paths move-typography)))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps typography dragging* selected selected-paths)
- (fn [event]
- (on-drag-enter-asset event typography dragging* selected selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-typography-drag-start
- (mf/use-fn
- (mf/deps typography file-id selected item-ref read-only?)
- (fn [event]
- (if read-only?
- (dom/prevent-default event)
- (on-asset-drag-start event file-id typography selected item-ref :typographies identity))))
-
- on-context-menu
- (mf/use-fn
- (mf/deps on-context-menu typography-id)
- (partial on-context-menu typography-id))
-
- handle-change
- (mf/use-fn
- (mf/deps typography)
- (partial handle-change typography))
-
- apply-typography
- (mf/use-fn
- (mf/deps typography)
- (partial apply-typography typography))
-
- on-asset-click
- (mf/use-fn
- (mf/deps typography apply-typography on-asset-click)
- (partial on-asset-click typography-id apply-typography))
-
- ]
-
- [:div.typography-container {:ref item-ref
- :draggable (and (not read-only?) (not open?))
- :on-drag-start on-typography-drag-start
- :on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
- [:& typography-entry
- {:typography typography
- :local? local?
- :on-context-menu on-context-menu
- :on-change handle-change
- :selected? (contains? selected typography-id)
- :on-click on-asset-click
- :editing? editing?
- :focus-name? rename?
- :external-open* open*
- :file-id file-id
- }]
-
- (when ^boolean dragging?
- [:div.dragging])]))
-
-(mf/defc typographies-group
- {::mf/wrap-props false}
- [{:keys [file-id prefix groups open-groups file local? selected local-data
- editing-id on-asset-click handle-change apply-typography on-rename-group
- on-ungroup on-context-menu selected-full]}]
- (let [group-open? (get open-groups prefix true)
- dragging* (mf/use-state false)
- dragging? (deref dragging*)
-
- selected-paths (mf/with-memo [selected-full]
- (into #{}
- (comp (map :path) (d/nilv ""))
- selected-full))
- move-typography
- (mf/use-fn
- (mf/deps file-id)
- (partial dwl/rename-typography file-id))
-
- on-drag-enter
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths)
- (fn [event]
- (on-drag-enter-asset-group event dragging* prefix selected-paths)))
-
- on-drag-leave
- (mf/use-fn
- (mf/deps dragging*)
- (fn [event]
- (on-drag-leave-asset event dragging*)))
-
- on-drop
- (mf/use-fn
- (mf/deps dragging* prefix selected-paths selected-full move-typography)
- (fn [event]
- (on-drop-asset-group event dragging* prefix selected-paths selected-full move-typography)))]
-
- [:div {:on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
- [:& asset-group-title {:file-id file-id
- :section :typographies
- :path prefix
- :group-open? group-open?
- :on-rename on-rename-group
- :on-ungroup on-ungroup}]
- (when group-open?
- [:*
- (let [typographies (get groups "" [])]
- [:div.asset-list {:on-drag-enter on-drag-enter
- :on-drag-leave on-drag-leave
- :on-drag-over dom/prevent-default
- :on-drop on-drop}
-
- (when ^boolean dragging?
- [:div.grid-placeholder "\u00A0"])
-
- (when (and
- (empty? typographies)
- (some? groups))
- [:div.drop-space])
- (for [{:keys [id] :as typography} typographies]
- [:& typography-item {:typography typography
- :key (dm/str "typography-" id)
- :file-id file-id
- :local? local?
- :handle-change handle-change
- :selected selected
- :apply-typography apply-typography
- :editing-id editing-id
- :rename? (= (:rename-typography local-data) id)
- :on-asset-click on-asset-click
- :on-context-menu on-context-menu
- :selected-full selected-full
- :selected-paths selected-paths
- :move-typography move-typography}])])
-
- (for [[path-item content] groups]
- (when-not (empty? path-item)
- [:& typographies-group {:file-id file-id
- :prefix (cph/merge-path-item prefix path-item)
- :key (dm/str "group-" path-item)
- :groups content
- :open-groups open-groups
- :file file
- :local? local?
- :selected selected
- :editing-id editing-id
- :local-data local-data
- :on-asset-click on-asset-click
- :handle-change handle-change
- :apply-typography apply-typography
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :on-context-menu on-context-menu
- :selected-full selected-full}]))])]))
-
-(mf/defc typographies-section
- {::mf/wrap-props false}
- [{:keys [file file-id local? typographies open? open-status-ref selected reverse-sort?
- on-asset-click on-assets-delete on-clear-selection]}]
- (let [state (mf/use-state {:detail-open? false :id nil})
- local-data (mf/deref lens:typography-section-state)
-
- read-only? (mf/use-ctx ctx/workspace-read-only?)
- menu-state (mf/use-state initial-context-menu-state)
- typographies (mf/with-memo [typographies]
- (mapv dwl/extract-path-if-missing typographies))
-
- groups (mf/with-memo [typographies reverse-sort?]
- (group-assets typographies reverse-sort?))
-
- selected (:typographies selected)
- selected-full (mf/with-memo [selected typographies]
- (into #{} (filter #(contains? selected (:id %))) typographies))
-
- multi-typographies? (> (count selected) 1)
- multi-assets? (or (seq (:components selected))
- (seq (:graphics selected))
- (seq (:colors selected)))
-
- open-groups-ref (mf/with-memo [open-status-ref]
- (-> (l/in [:groups :typographies])
- (l/derived open-status-ref)))
-
- open-groups (mf/deref open-groups-ref)
-
- add-typography
- (mf/use-fn
- (mf/deps file-id)
- (fn [_]
- (st/emit! (dwt/add-typography file-id))))
-
- handle-change
- (mf/use-fn
- (mf/deps file-id)
- (fn [typography changes]
- (st/emit! (dwl/update-typography (merge typography changes) file-id))))
-
- apply-typography
- (mf/use-fn
- (mf/deps file-id)
- (fn [typography _event]
- (st/emit! (dwt/apply-typography typography file-id))))
-
- create-group
- (mf/use-fn
- (mf/deps typographies selected on-clear-selection file-id (:id @state))
- (fn [group-name]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> typographies
- (filter #(if multi-typographies?
- (contains? selected (:id %))
- (= (:id @state) (:id %))))
- (map #(dwl/update-typography
- (assoc % :name
- (add-group % group-name))
- file-id))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- rename-group
- (mf/use-fn
- (mf/deps typographies)
- (fn [path last-path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit!
- (->> typographies
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/update-typography
- (assoc % :name
- (rename-group % path last-path))
- file-id))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-group
- (mf/use-fn
- (mf/deps typographies selected create-group)
- (fn [event]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:accept create-group})))
-
- on-rename-group
- (mf/use-fn
- (mf/deps typographies)
- (fn [event path last-path]
- (dom/stop-propagation event)
- (modal/show! :name-group-dialog {:path path
- :last-path last-path
- :accept rename-group})))
- on-ungroup
- (mf/use-fn
- (mf/deps typographies)
- (fn [path]
- (on-clear-selection)
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (apply st/emit!
- (->> typographies
- (filter #(str/starts-with? (:path %) path))
- (map #(dwl/rename-typography
- file-id
- (:id %)
- (ungroup % path)))))
- (st/emit! (dwu/commit-undo-transaction undo-id)))))
-
- on-context-menu
- (mf/use-fn
- (mf/deps selected on-clear-selection read-only?)
- (fn [id event]
- (dom/prevent-default event)
- (let [pos (dom/get-client-position event)]
- (when (and local? (not read-only?))
- (when-not (contains? selected id)
- (on-clear-selection))
- (swap! state assoc :id id)
- (swap! menu-state open-context-menu pos)))))
-
- on-close-menu
- (mf/use-fn
- (fn []
- (swap! menu-state close-context-menu)))
-
- handle-rename-typography-clicked
- (fn []
- (st/emit! #(assoc-in % [:workspace-global :rename-typography] (:id @state))))
-
- handle-edit-typography-clicked
- (fn []
- (st/emit! #(assoc-in % [:workspace-global :edit-typography] (:id @state))))
-
- handle-delete-typography
- (mf/use-fn
- (mf/deps @state multi-typographies? multi-assets?)
- (fn []
- (let [undo-id (js/Symbol)]
- (if (or multi-typographies? multi-assets?)
- (on-assets-delete)
- (st/emit! (dwu/start-undo-transaction undo-id)
- (dwl/delete-typography (:id @state))
- (dwl/sync-file file-id file-id :typographies (:id @state))
- (dwu/commit-undo-transaction undo-id))))))
-
- editing-id (or (:rename-typography local-data)
- (:edit-typography local-data))
-
- on-asset-click
- (mf/use-fn
- (mf/deps groups on-asset-click)
- (partial on-asset-click groups))]
-
- (mf/use-effect
- (mf/deps local-data)
- (fn []
- (when (:rename-typography local-data)
- (st/emit! #(update % :workspace-global dissoc :rename-typography)))
- (when (:edit-typography local-data)
- (st/emit! #(update % :workspace-global dissoc :edit-typography)))))
-
- [:& asset-section {:file-id file-id
- :title (tr "workspace.assets.typography")
- :section :typographies
- :assets-count (count typographies)
- :open? open?}
- (when local?
- [:& asset-section-block {:role :title-button}
- (when-not read-only?
- [:div.assets-button {:on-click add-typography}
- i/plus])])
-
- [:& asset-section-block {:role :content}
- [:& typographies-group {:file-id file-id
- :prefix ""
- :groups groups
- :open-groups open-groups
- :state state
- :file file
- :local? local?
- :selected selected
- :editing-id editing-id
- :local-data local-data
- :on-asset-click on-asset-click
- :handle-change handle-change
- :apply-typography apply-typography
- :on-rename-group on-rename-group
- :on-ungroup on-ungroup
- :on-context-menu on-context-menu
- :selected-full selected-full}]
-
- (when local?
- [:& assets-context-menu
- {:on-close on-close-menu
- :state @menu-state
- :options [(when-not (or multi-typographies? multi-assets?)
- [(tr "workspace.assets.rename") handle-rename-typography-clicked])
- (when-not (or multi-typographies? multi-assets?)
- [(tr "workspace.assets.edit") handle-edit-typography-clicked])
- [(tr "workspace.assets.delete") handle-delete-typography]
- (when-not multi-assets?
- [(tr "workspace.assets.group") on-group])]}])]]))
-
-
-;; --- Assets toolsection ----
-
-(defn- apply-filters
- [coll {:keys [ordering term] :as filters}]
- (let [reverse? (= :desc ordering)
- comp-fn (if ^boolean reverse? > <)]
- (->> coll
- (filter (fn [item]
- (or (matches-search (:name item "!$!") term)
- (matches-search (:value item "!$!") term))))
- ; Sort by folder order, but
- ; putting all "root" items
- ; always first, independently
- ; of sort order.
- (sort-by #(str/lower (cph/merge-path-item (if (empty? (:path %))
- (if reverse? "z" "a")
- (:path %))
- (:name %)))
- comp-fn))))
-
-
-(mf/defc file-library-title
- {::mf/wrap-props false}
- [{:keys [open? local? shared? project-id file-id page-id file-name]}]
- (let [router (mf/deref refs/router)
- url (rt/resolve router :workspace
- {:project-id project-id
- :file-id file-id}
- {:page-id page-id})
-
- toggle-open
- (mf/use-fn
- (mf/deps file-id open?)
- (fn []
- (st/emit! (dw/set-assets-section-open file-id :library (not open?)))))
- ]
-
- [:div.tool-window-bar.library-bar
- {:on-click toggle-open}
- [:div.collapse-library
- {:class (dom/classnames :open open?)}
- i/arrow-slide]
-
- (if local?
- [:*
- [:span file-name " (" (tr "workspace.assets.local-library") ")"]
- (when shared?
- [:span.tool-badge (tr "workspace.assets.shared")])]
- [:*
- [:span file-name]
- [:span.tool-link.tooltip.tooltip-left {:alt "Open library file"}
- [:a {:href (str "#" url)
- :target "_blank"
- :on-click dom/stop-propagation}
- i/chain]]])]))
-
-(mf/defc file-library-content
- {::mf/wrap-props false}
- [{:keys [file local? open-status-ref on-clear-selection]}]
- (let [components-v2 (mf/use-ctx ctx/components-v2)
- open-status (mf/deref open-status-ref)
-
- file-id (:id file)
- project-id (:project-id file)
-
- filters (mf/use-ctx ctx:filters)
- filters-section (:section filters)
- filters-term (:term filters)
- filters-ordering (:ordering filters)
- filters-list-style (:list-style filters)
-
- reverse-sort? (= :desc filters-ordering)
- listing-thumbs? (= :thumbs filters-list-style)
-
- toggle-ordering (mf/use-ctx ctx:toggle-ordering)
- toggle-list-style (mf/use-ctx ctx:toggle-list-style)
-
- library-ref (mf/with-memo [file-id]
- (create-file-library-ref file-id))
-
- library (mf/deref library-ref)
- colors (:colors library)
- components (:components library)
- media (:media library)
- typographies (:typographies library)
-
- colors (mf/with-memo [filters colors]
- (apply-filters colors filters))
- components (mf/with-memo [filters components]
- (apply-filters components filters))
- media (mf/with-memo [filters media]
- (apply-filters media filters))
- typographies (mf/with-memo [filters typographies]
- (apply-filters typographies filters))
-
- show-components? (and (or (= filters-section :all)
- (= filters-section :components))
- (or (pos? (count components))
- (str/empty? filters-term)))
- show-graphics? (and (or (= filters-section :all)
- (= filters-section :graphics))
- (or (pos? (count media))
- (and (str/empty? filters-term)
- (not components-v2))))
- show-colors? (and (or (= filters-section :all)
- (= filters-section :colors))
- (or (> (count colors) 0)
- (str/empty? filters-term)))
- show-typography? (and (or (= filters-section :all)
- (= filters-section :typographies))
- (or (pos? (count typographies))
- (str/empty? filters-term)))
-
-
- selected-lens (mf/with-memo [file-id]
- (-> (l/key file-id)
- (l/derived lens:selected)))
- selected (mf/deref selected-lens)
- selected-count (+ (count (get selected :components))
- (count (get selected :graphics))
- (count (get selected :colors))
- (count (get selected :typographies)))
-
- extend-selected
- (fn [type asset-groups asset-id]
- (letfn [(flatten-groups [groups]
- (reduce concat [(get groups "" [])
- (into []
- (->> (filter #(seq (first %)) groups)
- (map second)
- (mapcat flatten-groups)))]))]
-
- (let [selected' (get selected type)]
- (if (zero? (count selected'))
- (st/emit! (dw/select-single-asset file-id asset-id type))
- (let [all-assets (flatten-groups asset-groups)
- click-index (d/index-of-pred all-assets #(= (:id %) asset-id))
- first-index (->> (get selected type)
- (map (fn [asset] (d/index-of-pred all-assets #(= (:id %) asset))))
- (sort)
- (first))
-
- min-index (min first-index click-index)
- max-index (max first-index click-index)
- ids (->> (d/enumerate all-assets)
- (into #{} (comp (filter #(<= min-index (first %) max-index))
- (map (comp :id second)))))]
-
- (st/emit! (dw/select-assets file-id ids type)))))))
-
- on-asset-click
- (mf/use-fn
- (mf/deps file-id extend-selected)
- (fn [asset-type asset-groups asset-id default-click event]
- (cond
- (kbd/mod? event)
- (do
- (dom/stop-propagation event)
- (st/emit! (dw/toggle-selected-assets file-id asset-id asset-type)))
-
- (kbd/shift? event)
- (do
- (dom/stop-propagation event)
- (extend-selected asset-type asset-groups asset-id))
-
- :else
- (when default-click
- (default-click event)))))
-
- on-component-click
- (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :components))
-
- on-graphics-click
- (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :graphics))
-
- on-colors-click
- (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :colors))
-
- on-typography-click
- (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :typographies))
-
- on-assets-delete
- (mf/use-fn
- (mf/deps selected file-id)
- (fn []
- (let [undo-id (js/Symbol)]
- (st/emit! (dwu/start-undo-transaction undo-id))
- (run! st/emit! (map #(dwl/delete-component {:id %})
- (:components selected)))
- (run! st/emit! (map #(dwl/delete-media {:id %})
- (:graphics selected)))
- (run! st/emit! (map #(dwl/delete-color {:id %})
- (:colors selected)))
- (run! st/emit! (map #(dwl/delete-typography %)
- (:typographies selected)))
-
- (when (or (seq (:components selected))
- (seq (:colors selected))
- (seq (:typographies selected)))
- (st/emit! (dwl/sync-file file-id file-id)))
-
- (st/emit! (dwu/commit-undo-transaction undo-id)))))]
-
- [:div.tool-window-content
- [:div.listing-options
- (when (> selected-count 0)
- [:span.selected-count
- (tr "workspace.assets.selected-count" (i18n/c selected-count))])
- [:div.listing-option-btn.first {:on-click toggle-ordering}
- (if reverse-sort?
- i/sort-ascending
- i/sort-descending)]
- [:div.listing-option-btn {:on-click toggle-list-style}
- (if listing-thumbs?
- i/listing-enum
- i/listing-thumbs)]]
-
- (when ^boolean show-components?
- [:& components-section
- {:file-id file-id
- :local? local?
- :components components
- :listing-thumbs? listing-thumbs?
- :open? (get open-status :components true)
- :open-status-ref open-status-ref
- :reverse-sort? reverse-sort?
- :selected selected
- :on-asset-click on-component-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection}])
-
- (when ^boolean show-graphics?
- [:& graphics-section
- {:file-id file-id
- :project-id project-id
- :local? local?
- :objects media
- :listing-thumbs? listing-thumbs?
- :open? (get open-status :graphics true)
- :open-status-ref open-status-ref
- :reverse-sort? reverse-sort?
- :selected selected
- :on-asset-click on-graphics-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection}])
-
- (when ^boolean show-colors?
- [:& colors-section
- {:file-id file-id
- :local? local?
- :colors colors
- :open? (get open-status :colors true)
- :open-status-ref open-status-ref
- :reverse-sort? reverse-sort?
- :selected selected
- :on-asset-click on-colors-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection}])
-
- (when ^boolean show-typography?
- [:& typographies-section
- {:file file
- :file-id (:id file)
- :local? local?
- :typographies typographies
- :open? (get open-status :typographies true)
- :open-status-ref open-status-ref
- :reverse-sort? reverse-sort?
- :selected selected
- :on-asset-click on-typography-click
- :on-assets-delete on-assets-delete
- :on-clear-selection on-clear-selection}])
-
- (when (and (not ^boolean show-components?)
- (not ^boolean show-graphics?)
- (not ^boolean show-colors?)
- (not ^boolean show-typography?))
- [:div.asset-section
- [:div.asset-title (tr "workspace.assets.not-found")]])]))
-
-(mf/defc file-library
- {::mf/wrap-props false}
- [{:keys [file local? default-open? filters]}]
- (let [file-id (:id file)
- file-name (:name file)
- shared? (:is-shared file)
- project-id (:project-id file)
- page-id (dm/get-in file [:data :pages 0])
-
- open-status-ref (mf/with-memo [file-id]
- (-> (l/key file-id)
- (l/derived lens:open-status)))
- open-status (mf/deref open-status-ref)
- open? (d/nilv (:library open-status) default-open?)
-
- unselect-all
- (mf/use-fn
- (mf/deps file-id)
- (fn []
- (st/emit! (dw/unselect-all-assets file-id))))
-
- ]
-
- [:div.tool-window {:on-context-menu dom/prevent-default
- :on-click unselect-all}
- [:& file-library-title
- {:project-id project-id
- :file-id file-id
- :page-id page-id
- :file-name file-name
- :open? open?
- :local? local?
- :shared? shared?}]
- (when ^boolean open?
- [:& file-library-content
- {:file file
- :local? local?
- :filters filters
- :on-clear-selection unselect-all
- :open-status-ref open-status-ref}])]))
-
(mf/defc assets-libraries
{::mf/wrap [mf/memo]
::mf/wrap-props false}
@@ -2420,14 +69,18 @@
::mf/wrap-props false}
[]
(let [components-v2 (mf/use-ctx ctx/components-v2)
- read-only? (mf/use-ctx ctx/workspace-read-only?)
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
filters* (mf/use-state
{:term ""
- :section :all
+ :section "all"
:ordering :asc
- :list-style :thumbs})
+ :list-style :thumbs
+ :open-menu false})
filters (deref filters*)
term (:term filters)
+ menu-open? (:open-menu filters)
+ section (:section filters)
toggle-ordering
(mf/use-fn #(swap! filters* update :ordering toggle-values [:asc :desc]))
@@ -2437,8 +90,13 @@
on-search-term-change
(mf/use-fn
+ (mf/deps new-css-system)
(fn [event]
- (let [value (dom/get-target-val event)]
+ ;; NOTE: When old-css-system is removed this function will recibe value and event
+ ;; Let won't be necessary any more
+ (let [value (if ^boolean new-css-system
+ event
+ (dom/get-target-val event))]
(swap! filters* assoc :term value))))
on-search-clear-click
@@ -2447,10 +105,11 @@
on-section-filter-change
(mf/use-fn
(fn [event]
- (let [value (-> (dom/get-target event)
- (dom/get-value)
- (d/read-string))]
- (swap! filters* assoc :section value))))
+ (let [value (or (-> (dom/get-target event)
+ (dom/get-value))
+ (as-> (dom/get-current-target event) $
+ (dom/get-attribute $ "data-test")))]
+ (swap! filters* assoc :section value :open-menu false))))
handle-key-down
(mf/use-fn
@@ -2463,46 +122,116 @@
(when ^boolean esc? (dom/blur! node)))))
show-libraries-dialog
- (mf/use-fn #(modal/show! :libraries-dialog {}))]
+ (mf/use-fn
+ (fn []
+ (modal/show! :libraries-dialog {})
+ (modal/allow-click-outside!)))
- [:div.assets-bar
- [:div.tool-window
- [:div.tool-window-content
- [:div.assets-bar-title
- (tr "workspace.assets.assets")
- (when-not ^boolean read-only?
- [:div.libraries-button {:on-click show-libraries-dialog}
- i/text-align-justify
- (tr "workspace.assets.libraries")])]
+ on-open-menu
+ (mf/use-fn #(swap! filters* update :open-menu not))
- [:div.search-block
- [:input.search-input
- {:placeholder (tr "workspace.assets.search")
- :type "text"
- :value term
- :on-change on-search-term-change
- :on-key-down handle-key-down}]
+ on-menu-close
+ (mf/use-fn #(swap! filters* assoc :open-menu false))
- (if ^boolean (str/empty? term)
- [:div.search-icon
- i/search]
- [:div.search-icon.close
- {:on-click on-search-clear-click}
- i/close])]
+ options [{:option-name (tr "workspace.assets.box-filter-all")
+ :id "section-all"
+ :option-handler on-section-filter-change
+ :data-test "all"}
- [:select.input-select {:value (:section filters)
- :on-change on-section-filter-change}
- [:option {:value ":all"} (tr "workspace.assets.box-filter-all")]
- [:option {:value ":components"} (tr "workspace.assets.components")]
- (when-not components-v2
- [:option {:value ":graphics"} (tr "workspace.assets.graphics")])
- [:option {:value ":colors"} (tr "workspace.assets.colors")]
- [:option {:value ":typographies"} (tr "workspace.assets.typography")]]]]
+ {:option-name (tr "workspace.assets.components")
+ :id "section-components"
+ :option-handler on-section-filter-change
+ :data-test "components"}
- [:& (mf/provider ctx:filters) {:value filters}
- [:& (mf/provider ctx:toggle-ordering) {:value toggle-ordering}
- [:& (mf/provider ctx:toggle-list-style) {:value toggle-list-style}
- [:div.libraries-wrapper
- [:& assets-local-library {:filters filters}]
- [:& assets-libraries {:filters filters}]]]]]]))
+ {:option-name (tr "workspace.assets.graphics")
+ :id "section-graphics"
+ :option-handler on-section-filter-change
+ :data-test "graphics"}
+
+ {:option-name (tr "workspace.assets.colors")
+ :id "section-color"
+ :option-handler on-section-filter-change
+ :data-test "colors"}
+
+ {:option-name (tr "workspace.assets.typography")
+ :id "section-typography"
+ :option-handler on-section-filter-change
+ :data-test "typographies"}]]
+
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :assets-bar) true)}
+ [:div {:class (dom/classnames (css :assets-header) true)}
+ (when-not read-only?
+ [:button {:class (dom/classnames (css :libraries-button) true)
+ :on-click #(modal/show! :libraries-dialog {})}
+ [:span {:class (dom/classnames (css :libraries-icon) true)}
+ i/library-refactor]
+ (tr "workspace.assets.libraries")])
+
+ [:& search-bar {:on-change on-search-term-change
+ :value term
+ :placeholder (tr "workspace.assets.search")}
+ [:button
+ {:on-click on-open-menu
+ :class (dom/classnames (css :section-button) true)}
+ i/filter-refactor]]
+ [:& context-menu-a11y
+ {:on-close on-menu-close
+ :selectable true
+ :selected section
+ :show menu-open?
+ :fixed? true
+ :min-width? true
+ :top 152
+ :left 64
+ :options options
+ :workspace? true}]]
+
+ [:& (mf/provider cmm/assets-filters) {:value filters}
+ [:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
+ [:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
+ [:div {:class (dom/classnames (css :libraries-wrapper) true)}
+ [:& assets-local-library {:filters filters}]
+ [:& assets-libraries {:filters filters}]]]]]]
+
+ [:div.assets-bar
+ [:div.tool-window
+ [:div.tool-window-content
+ [:div.assets-bar-title
+ (tr "workspace.assets.assets")
+
+ (when-not ^boolean read-only?
+ [:div.libraries-button {:on-click show-libraries-dialog}
+ i/text-align-justify
+ (tr "workspace.assets.libraries")])]
+ [:div.search-block
+ [:input.search-input
+ {:placeholder (tr "workspace.assets.search")
+ :type "text"
+ :value term
+ :on-change on-search-term-change
+ :on-key-down handle-key-down}]
+
+ (if ^boolean (str/empty? term)
+ [:div.search-icon
+ i/search]
+ [:div.search-icon.close
+ {:on-click on-search-clear-click}
+ i/close])]
+
+ [:select.input-select {:value (:section filters)
+ :on-change on-section-filter-change}
+ [:option {:value "all"} (tr "workspace.assets.box-filter-all")]
+ [:option {:value "components"} (tr "workspace.assets.components")]
+ (when-not components-v2
+ [:option {:value "graphics"} (tr "workspace.assets.graphics")])
+ [:option {:value "colors"} (tr "workspace.assets.colors")]
+ [:option {:value "typographies"} (tr "workspace.assets.typography")]]]]
+
+ [:& (mf/provider cmm/assets-filters) {:value filters}
+ [:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
+ [:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
+ [:div.libraries-wrapper
+ [:& assets-local-library {:filters filters}]
+ [:& assets-libraries {:filters filters}]]]]]])))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets.css.json
new file mode 100644
index 0000000000..33be480970
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.css.json
@@ -0,0 +1 @@
+{"button-primary":"sidebar_assets_button-primary_a9p4J","button-secondary":"sidebar_assets_button-secondary_hbgBA","assets-bar":"sidebar_assets_assets-bar_gzAPj","libraries-button":"sidebar_assets_libraries-button_cKUY7","button-tertiary":"sidebar_assets_button-tertiary_KoPen","button-tag":"sidebar_assets_button-tag_yzpPm","button-icon":"sidebar_assets_button-icon_M5Yy6","libraries-icon":"sidebar_assets_libraries-icon_ikusB","button-icon-small":"sidebar_assets_button-icon-small_xZWe1","asset-element":"sidebar_assets_asset-element_xHJzG","section-button":"sidebar_assets_section-button_RSjn8","sections-container":"sidebar_assets_sections-container_r2YTM","section-item":"sidebar_assets_section-item_u6EYM","section-btn":"sidebar_assets_section-btn_s4h2P","libraries-wrapper":"sidebar_assets_libraries-wrapper_agaHg","assets-header":"sidebar_assets_assets-header_aFHCj"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.scss b/frontend/src/app/main/ui/workspace/sidebar/assets.scss
new file mode 100644
index 0000000000..eb3603f54f
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets.scss
@@ -0,0 +1,119 @@
+// 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";
+
+.assets-bar {
+ position: relative;
+ height: 100%;
+ overflow: hidden;
+
+ .libraries-button {
+ @include tabTitleTipography;
+ @extend .button-secondary;
+ gap: $s-2;
+ height: $s-32;
+ width: 100%;
+ border-radius: $s-8;
+ margin-bottom: $s-4;
+ .libraries-icon {
+ @include flexCenter;
+ width: $s-24;
+ height: 100%;
+ svg {
+ @include flexCenter;
+ @extend .button-icon;
+ }
+ }
+ &:hover {
+ background-color: var(--button-secondary-background-color-hover);
+ color: var(--button-secondary-foreground-color-hover);
+ border: $s-1 solid var(--button-secondary-border-color-hover);
+ svg {
+ stroke: var(--button-secondary-foreground-color-hover);
+ }
+ }
+ &:focus {
+ background-color: var(--button-secondary-background-color-focus);
+ color: var(--button-secondary-foreground-color-focus);
+ border: $s-1 solid var(--button-secondary-border-color-focus);
+ svg {
+ stroke: var(--button-secondary-foreground-color-focus);
+ }
+ }
+ }
+ .section-button {
+ @include flexCenter;
+ @include buttonStyle;
+ height: $s-32;
+ width: $s-32;
+ margin: 0;
+ border: 1px solid var(--color-background-tertiary);
+ border-radius: $br-8 $br-2 $br-2 $br-8;
+ background-color: var(--color-background-tertiary);
+ svg {
+ height: $s-16;
+ width: $s-16;
+ stroke: var(--icon-foreground);
+ }
+ &:focus {
+ border: 1px solid var(--input-border-color-focus);
+ outline: 0;
+ background-color: var(--input-background-color-active);
+ color: var(--input-foreground-color-active);
+ svg {
+ background-color: var(--input-background-color-active);
+ }
+ }
+ &:hover {
+ border: 1px solid var(--input-background-color-hover);
+ background-color: var(--input-background-color-hover);
+ svg {
+ background-color: var(--input-background-color-hover);
+ stroke: var(--button-foreground-hover);
+ }
+ }
+ }
+ .sections-container {
+ position: absolute;
+ top: $s-84;
+ left: $s-12;
+ 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-4;
+ box-shadow: 0px 0px 10px 0px var(--menu-shadow-color);
+ .section-item {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: $s-6;
+ border-radius: $br-8;
+ .section-btn {
+ @include buttonStyle;
+ }
+ }
+ }
+ .libraries-wrapper {
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
+ height: calc(100% - $s-72);
+ overflow-y: auto;
+ overflow-x: hidden;
+ scrollbar-gutter: stable;
+ overflow-y: overlay;
+ }
+ .assets-header {
+ padding: $s-8 $s-12 $s-4 $s-12;
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs
new file mode 100644
index 0000000000..216ece7849
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs
@@ -0,0 +1,621 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.workspace.sidebar.assets.colors
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.common.pages.helpers :as cph]
+ [app.main.data.events :as ev]
+ [app.main.data.modal :as modal]
+ [app.main.data.workspace :as dw]
+ [app.main.data.workspace.colors :as dc]
+ [app.main.data.workspace.libraries :as dwl]
+ [app.main.data.workspace.undo :as dwu]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.components.color-bullet :as bc]
+ [app.main.ui.components.color-bullet-new :as cb]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.sidebar.assets.common :as cmm]
+ [app.main.ui.workspace.sidebar.assets.groups :as grp]
+ [app.util.color :as uc]
+ [app.util.dom :as dom]
+ [app.util.i18n :as i18n :refer [tr]]
+ [app.util.keyboard :as kbd]
+ [cuerdas.core :as str]
+ [okulary.core :as l]
+ [potok.core :as ptk]
+ [rumext.v2 :as mf]))
+
+(mf/defc color-item
+ {::mf/wrap-props false}
+ [{:keys [color local? file-id selected multi-colors? multi-assets?
+ on-asset-click on-assets-delete on-clear-selection on-group
+ selected-full selected-paths move-color]}]
+
+ (let [color (mf/with-memo [color file-id]
+ (cond-> color
+ (:value color) (assoc :color (:value color) :opacity 1)
+ (:value color) (dissoc :value)
+ true (assoc :file-id file-id)))
+
+
+ color-id (:id color)
+
+ item-ref (mf/use-ref)
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ rename? (= (:color-for-rename @refs/workspace-local) color-id)
+ input-ref (mf/use-ref)
+
+ editing* (mf/use-state rename?)
+ editing? (deref editing*)
+
+ menu-state (mf/use-state cmm/initial-context-menu-state)
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+
+ default-name (cond
+ (:gradient color) (uc/gradient-type->string (dm/get-in color [:gradient :type]))
+ (:color color) (:color color)
+ :else (:value color))
+
+ apply-color
+ (mf/use-fn
+ (mf/deps color)
+ (fn [event]
+ (st/emit! (dc/apply-color-from-palette (merge uc/empty-color color) (kbd/alt? event)))))
+
+ rename-color
+ (mf/use-fn
+ (mf/deps file-id color-id)
+ (fn [name]
+ (st/emit! (dwl/rename-color file-id color-id name))))
+
+ edit-color
+ (mf/use-fn
+ (mf/deps color file-id)
+ (fn [attrs]
+ (let [name (cph/merge-path-item (:path color) (:name color))
+ color (-> attrs
+ (assoc :id (:id color))
+ (assoc :file-id file-id)
+ (assoc :name name))]
+ (st/emit! (dwl/update-color color file-id)))))
+
+ delete-color
+ (mf/use-fn
+ (mf/deps multi-colors? multi-assets? file-id color-id)
+ (fn []
+ (if (or multi-colors? multi-assets?)
+ (on-assets-delete)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id)
+ (dwl/delete-color color)
+ (dwl/sync-file file-id file-id :colors color-id)
+ (dwu/commit-undo-transaction undo-id))))))
+
+ rename-color-clicked
+ (mf/use-fn
+ (mf/deps read-only? local?)
+ (fn [event]
+ (when (and local? (not read-only?))
+ (dom/prevent-default event)
+ (reset! editing* true))))
+
+ input-blur
+ (mf/use-fn
+ (mf/deps rename-color)
+ (fn [event]
+ (let [target (dom/event->target event)
+ name (dom/get-value target)]
+ (rename-color name)
+ (st/emit! dwl/clear-color-for-rename)
+ (reset! editing* false))))
+
+ input-key-down
+ (mf/use-fn
+ (mf/deps input-blur)
+ (fn [event]
+ (when (kbd/esc? event)
+ (st/emit! dwl/clear-color-for-rename)
+ (reset! editing* false))
+ (when (kbd/enter? event)
+ (input-blur event))))
+
+ edit-color-clicked
+ (mf/use-fn
+ (mf/deps edit-color color)
+ (fn [event]
+ (modal/show! :colorpicker
+ {:x (.-clientX ^js event)
+ :y (.-clientY ^js event)
+ :on-accept edit-color
+ :data color
+ :position :right})))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps color-id selected on-clear-selection read-only?)
+ (fn [event]
+ (dom/prevent-default event)
+ (let [pos (dom/get-client-position event)]
+ (when (and local? (not read-only?))
+ (when-not (contains? selected color-id)
+ (on-clear-selection))
+ (swap! menu-state cmm/open-context-menu pos)))))
+
+ on-close-menu
+ (mf/use-fn
+ (fn []
+ (swap! menu-state cmm/close-context-menu)))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps color dragging* selected selected-full selected-paths move-color)
+ (fn [event]
+ (cmm/on-drop-asset event color dragging* selected selected-full
+ selected-paths move-color)))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps color dragging* selected selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset event color dragging* selected selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-color-drag-start
+ (mf/use-fn
+ (mf/deps color file-id selected item-ref read-only?)
+ (fn [event]
+ (if read-only?
+ (dom/prevent-default event)
+ (cmm/on-asset-drag-start event file-id color selected item-ref :colors identity))))
+
+ on-click
+ (mf/use-fn
+ (mf/deps color-id apply-color on-asset-click)
+ (partial on-asset-click color-id apply-color))]
+
+ (mf/with-effect [editing?]
+ (when editing?
+ (let [input (mf/ref-val input-ref)]
+ (dom/select-text! input)
+ nil)))
+
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :asset-list-item) true
+ (css :selected) (contains? selected (:id color))
+ (css :editing) editing?)
+ :style #js {"--bullet-size" "16px"}
+ :on-context-menu on-context-menu
+ :on-click (when-not editing? on-click)
+ :ref item-ref
+ :draggable (and (not read-only?) (not editing?))
+ :on-drag-start on-color-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ [:div {:class (dom/classnames (css :bullet-block) true)}
+ [:& cb/color-bullet {:color color
+ :mini? true}]]
+
+ (if ^boolean editing?
+ [:input
+ {:type "text"
+ :class (dom/classnames (css :element-name) true)
+ :ref input-ref
+ :on-blur input-blur
+ :on-key-down input-key-down
+ :auto-focus true
+ :default-value (cph/merge-path-item (:path color) (:name color))}]
+
+ [:div {:title (:name color)
+ :class (dom/classnames (css :name-block) true)
+ :on-double-click rename-color-clicked}
+
+ (if (= (:name color) default-name)
+ [:span {:class (dom/classnames (css :default-name-only) true)} default-name]
+ [:*
+ [:span {:class (dom/classnames (css :name) true)} (:name color)]
+ [:span {:class (dom/classnames (css :default-name) true)} default-name]])])
+
+ (when local?
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options [(when-not (or multi-colors? multi-assets?)
+ {:option-name (tr "workspace.assets.rename")
+ :id "assets-rename-color"
+ :option-handler rename-color-clicked})
+ (when-not (or multi-colors? multi-assets?)
+ {:option-name (tr "workspace.assets.edit")
+ :id "assets-edit-color"
+ :option-handler edit-color-clicked})
+
+ {:option-name (tr "workspace.assets.delete")
+ :id "assets-delete-color"
+ :option-handler delete-color}
+ (when-not multi-assets?
+ {:option-name (tr "workspace.assets.group")
+ :id "assets-group-color"
+ :option-handler (on-group (:id color))})]}])
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :dragging) true)}])]
+
+ [:div.asset-list-item
+ {:class-name (dom/classnames
+ :selected (contains? selected (:id color)))
+ :on-context-menu on-context-menu
+ :on-click (when-not editing? on-click)
+ :ref item-ref
+ :draggable (and (not read-only?) (not editing?))
+ :on-drag-start on-color-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ [:& bc/color-bullet {:color color}]
+
+ (if ^boolean editing?
+ [:input.element-name
+ {:type "text"
+ :ref input-ref
+ :on-blur input-blur
+ :on-key-down input-key-down
+ :auto-focus true
+ :default-value (cph/merge-path-item (:path color) (:name color))}]
+
+ [:div.name-block {:title (:name color)
+ :on-double-click rename-color-clicked}
+ (:name color)
+ (when-not (= (:name color) default-name)
+ [:span default-name])])
+
+ (when local?
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options [(when-not (or multi-colors? multi-assets?)
+ [(tr "workspace.assets.rename") rename-color-clicked])
+ (when-not (or multi-colors? multi-assets?)
+ [(tr "workspace.assets.edit") edit-color-clicked])
+ [(tr "workspace.assets.delete") delete-color]
+ (when-not multi-assets?
+ [(tr "workspace.assets.group") (on-group (:id color))])]}])
+
+ (when ^boolean dragging?
+ [:div.dragging])])))
+
+(mf/defc colors-group
+ [{:keys [file-id prefix groups open-groups local? selected
+ multi-colors? multi-assets? on-asset-click on-assets-delete
+ on-clear-selection on-group on-rename-group on-ungroup colors
+ selected-full]}]
+ (let [group-open? (get open-groups prefix true)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ selected-paths (mf/with-memo [selected-full]
+ (into #{}
+ (comp (map :path) (d/nilv ""))
+ selected-full))
+
+ move-color
+ (mf/use-fn (mf/deps file-id) (partial dwl/rename-color file-id))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset-group event dragging* prefix selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths selected-full move-color)
+ (fn [event]
+ (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full move-color)))]
+
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :colors-group) true)
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title {:file-id file-id
+ :section :colors
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+ (when group-open?
+ [:*
+ (let [colors (get groups "" [])]
+ [:div {:class (dom/classnames (css :asset-list) true)
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :grid-placeholder) true)}
+ "\u00A0"])
+
+ (when (and (empty? colors)
+ (some? groups))
+ [:div {:class (dom/classnames (css :drop-space) true)}])
+
+ (for [color colors]
+ [:& color-item {:key (dm/str (:id color))
+ :color color
+ :file-id file-id
+ :local? local?
+ :selected selected
+ :multi-colors? multi-colors?
+ :multi-assets? multi-assets?
+ :on-asset-click on-asset-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection
+ :on-group on-group
+ :colors colors
+ :selected-full selected-full
+ :selected-paths selected-paths
+ :move-color move-color}])])
+
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& colors-group {:file-id file-id
+ :prefix (cph/merge-path-item prefix path-item)
+ :key (dm/str "group-" path-item)
+ :groups content
+ :open-groups open-groups
+ :local? local?
+ :selected selected
+ :multi-colors? multi-colors?
+ :multi-assets? multi-assets?
+ :on-asset-click on-asset-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection
+ :on-group on-group
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :colors colors
+ :selected-full selected-full}]))])]
+
+
+ [:div {:on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title {:file-id file-id
+ :section :colors
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+ (when group-open?
+ [:*
+ (let [colors (get groups "" [])]
+ [:div.asset-list {:on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div.grid-placeholder "\u00A0"])
+
+ (when (and (empty? colors)
+ (some? groups))
+ [:div.drop-space])
+
+ (for [color colors]
+ [:& color-item {:key (dm/str (:id color))
+ :color color
+ :file-id file-id
+ :local? local?
+ :selected selected
+ :multi-colors? multi-colors?
+ :multi-assets? multi-assets?
+ :on-asset-click on-asset-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection
+ :on-group on-group
+ :colors colors
+ :selected-full selected-full
+ :selected-paths selected-paths
+ :move-color move-color}])])
+
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& colors-group {:file-id file-id
+ :prefix (cph/merge-path-item prefix path-item)
+ :key (dm/str "group-" path-item)
+ :groups content
+ :open-groups open-groups
+ :local? local?
+ :selected selected
+ :multi-colors? multi-colors?
+ :multi-assets? multi-assets?
+ :on-asset-click on-asset-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection
+ :on-group on-group
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :colors colors
+ :selected-full selected-full}]))])])))
+
+(mf/defc colors-section
+ [{:keys [file-id local? colors open? open-status-ref selected reverse-sort?
+ on-asset-click on-assets-delete on-clear-selection] :as props}]
+
+ (let [selected (:colors selected)
+ selected-full (mf/with-memo [selected colors]
+ (into #{} (filter #(contains? selected (:id %))) colors))
+
+ open-groups-ref (mf/with-memo [open-status-ref]
+ (-> (l/in [:groups :colors])
+ (l/derived open-status-ref)))
+ open-groups (mf/deref open-groups-ref)
+
+ multi-colors? (> (count selected) 1)
+ multi-assets? (or (seq (:components selected))
+ (seq (:graphics selected))
+ (seq (:typographies selected)))
+
+ groups (mf/with-memo [colors reverse-sort?]
+ (grp/group-assets colors reverse-sort?))
+
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ add-color
+ (mf/use-fn
+ (fn [value _]
+ (st/emit! (dwl/add-color value))))
+
+ add-color-clicked
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn [event]
+ (st/emit! (dw/set-assets-section-open file-id :colors true)
+ (ptk/event ::ev/event {::ev/name "add-asset-to-library"
+ :asset-type "color"}))
+ (modal/show! :colorpicker
+ {:x (.-clientX event)
+ :y (.-clientY event)
+ :on-accept add-color
+ :data {:color "#406280"
+ :opacity 1}
+ :position :right})))
+
+ create-group
+ (mf/use-fn
+ (mf/deps colors selected on-clear-selection file-id)
+ (fn [color-id]
+ (fn [group-name]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> colors
+ (filter #(if multi-colors?
+ (contains? selected (:id %))
+ (= color-id (:id %))))
+ (map #(dwl/update-color
+ (assoc % :name
+ (cmm/add-group % group-name))
+ file-id))))
+ (st/emit! (dwu/commit-undo-transaction undo-id))))))
+
+ rename-group
+ (mf/use-fn
+ (mf/deps colors)
+ (fn [path last-path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> colors
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/update-color
+ (assoc % :name
+ (cmm/rename-group % path last-path))
+ file-id))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-group
+ (mf/use-fn
+ (mf/deps colors selected)
+ (fn [color-id]
+ (fn [event]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:accept (create-group color-id)}))))
+
+ on-rename-group
+ (mf/use-fn
+ (mf/deps colors)
+ (fn [event path last-path]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:path path
+ :last-path last-path
+ :accept rename-group})))
+ on-ungroup
+ (mf/use-fn
+ (mf/deps colors)
+ (fn [path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (apply st/emit!
+ (->> colors
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/update-color
+ (assoc % :name
+ (cmm/ungroup % path))
+ file-id))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-asset-click
+ (mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
+
+
+ [:& cmm/asset-section {:file-id file-id
+ :title (tr "workspace.assets.colors")
+ :section :colors
+ :assets-count (count colors)
+ :open? open?}
+ (if ^boolean new-css-system
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when-not read-only?
+ [:button {:class (dom/classnames (css :assets-btn) true)
+ :on-click add-color-clicked}
+ i/add-refactor])])
+
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when-not read-only?
+ [:div.assets-button {:on-click add-color-clicked}
+ i/plus])]))
+
+
+ [:& cmm/asset-section-block {:role :content}
+ [:& colors-group {:file-id file-id
+ :prefix ""
+ :groups groups
+ :open-groups open-groups
+ :local? local?
+ :selected selected
+ :multi-colors? multi-colors?
+ :multi-assets? multi-assets?
+ :on-asset-click on-asset-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection
+ :on-group on-group
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :colors colors
+ :selected-full selected-full}]]]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.css.json
new file mode 100644
index 0000000000..3de5347cd7
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_colors_button-primary_6ZMmx","button-secondary":"assets_colors_button-secondary_dNSLH","button-tertiary":"assets_colors_button-tertiary_h20-o","assets-btn":"assets_colors_assets-btn_t8DHG","button-tag":"assets_colors_button-tag_ux-NH","button-icon":"assets_colors_button-icon_f-EVH","button-icon-small":"assets_colors_button-icon-small_zq8dv","asset-element":"assets_colors_asset-element_XSxD1","colors-group":"assets_colors_colors-group_fUsuo","asset-list":"assets_colors_asset-list_wMm1l","asset-list-item":"assets_colors_asset-list-item_ZFtXC","bullet-block":"assets_colors_bullet-block_ZRR2Y","name-block":"assets_colors_name-block_Zvmy3","default-name-only":"assets_colors_default-name-only_JFCGo","name":"assets_colors_name_AjZzr","default-name":"assets_colors_default-name_8gEAb","element-name":"assets_colors_element-name_ADGM8","selected":"assets_colors_selected_ElMu0","editing":"assets_colors_editing_FWnHU","grid-placeholder":"assets_colors_grid-placeholder_7wTFd","drop-space":"assets_colors_drop-space_lbzeC","dragging":"assets_colors_dragging_EmBOk"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss
new file mode 100644
index 0000000000..e8d9b6bed0
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.scss
@@ -0,0 +1,102 @@
+// 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";
+
+.assets-btn {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: calc($s-24 + $s-4);
+ padding: 0;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+}
+
+.colors-group {
+ margin-top: $s-4;
+ .asset-list {
+ padding: 0 0 0 $s-12;
+ .asset-list-item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ padding: $s-8 $s-12 $s-8 $s-8;
+ margin-bottom: $s-4;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ cursor: pointer;
+ .bullet-block {
+ @include flexCenter;
+ height: 100%;
+ width: $s-32;
+ }
+ .name-block {
+ @include titleTipography;
+ display: grid;
+ grid-template-columns: auto 1fr;
+ margin: 0;
+ overflow: hidden;
+ .default-name-only,
+ .name {
+ color: var(--assets-item-name-foreground-color-hover);
+ margin-right: $s-6;
+ @include textEllipsis;
+ }
+ .default-name {
+ min-width: 0;
+ color: var(--assets-item-name-foreground-color);
+ }
+ }
+ .element-name {
+ @include textEllipsis;
+ color: var(--color-foreground-primary);
+ }
+ &.selected {
+ border: $s-1 solid var(--assets-item-border-color);
+ }
+
+ &.editing {
+ border: $s-1 solid var(--input-border-color-focus);
+ input.element-name {
+ @include textEllipsis;
+ @include titleTipography;
+ @include removeInputStyle;
+ flex-grow: 1;
+ height: $s-28;
+ max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
+ margin: 0;
+ color: var(--layer-row-foreground-color);
+ }
+ }
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ }
+ }
+ }
+ .grid-placeholder {
+ height: $s-2;
+ margin-bottom: $s-2;
+ background-color: var(--color-accent-primary);
+ }
+ .drop-space {
+ height: $s-12;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ }
+ .dragging {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: $s-8;
+ background-color: var(--assets-item-background-color-drag);
+ border: $s-2 solid var(--assets-item-border-color-drag);
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs
new file mode 100644
index 0000000000..c75c199c9b
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.cljs
@@ -0,0 +1,257 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+
+(ns app.main.ui.workspace.sidebar.assets.common
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data.macros :as dm]
+ [app.common.pages.helpers :as cph]
+ [app.common.spec :as us]
+ [app.main.data.modal :as modal]
+ [app.main.data.workspace :as dw]
+ [app.main.data.workspace.undo :as dwu]
+ [app.main.store :as st]
+ [app.main.ui.components.context-menu :refer [context-menu]]
+ [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
+ [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.dom.dnd :as dnd]
+ [app.util.strings :refer [matches-search]]
+ [app.util.timers :as ts]
+ [cljs.spec.alpha :as s]
+ [cuerdas.core :as str]
+ [rumext.v2 :as mf]))
+
+(def assets-filters (mf/create-context nil))
+(def assets-toggle-ordering (mf/create-context nil))
+(def assets-toggle-list-style (mf/create-context nil))
+
+(defn apply-filters
+ [coll {:keys [ordering term] :as filters}]
+ (let [reverse? (= :desc ordering)
+ comp-fn (if ^boolean reverse? > <)]
+ (->> coll
+ (filter (fn [item]
+ (or (matches-search (:name item "!$!") term)
+ (matches-search (:value item "!$!") term))))
+ ; Sort by folder order, but
+ ; putting all "root" items
+ ; always first, independently
+ ; of sort order.
+ (sort-by #(str/lower (cph/merge-path-item (if (empty? (:path %))
+ (if reverse? "z" "a")
+ (:path %))
+ (:name %)))
+ comp-fn))))
+
+(defn add-group
+ [asset group-name]
+ (-> (:path asset)
+ (cph/merge-path-item group-name)
+ (cph/merge-path-item (:name asset))))
+
+(defn rename-group
+ [asset path last-path]
+ (-> (:path asset)
+ (str/slice 0 (count path))
+ (cph/split-path)
+ butlast
+ (vec)
+ (conj last-path)
+ (cph/join-path)
+ (str (str/slice (:path asset) (count path)))
+ (cph/merge-path-item (:name asset))))
+
+(defn ungroup
+ [asset path]
+ (-> (:path asset)
+ (str/slice 0 (count path))
+ (cph/split-path)
+ butlast
+ (cph/join-path)
+ (str (str/slice (:path asset) (count path)))
+ (cph/merge-path-item (:name asset))))
+
+(s/def ::asset-name ::us/not-empty-string)
+(s/def ::name-group-form
+ (s/keys :req-un [::asset-name]))
+
+(def initial-context-menu-state
+ {:open? false :top nil :left nil})
+
+(defn open-context-menu
+ [state pos]
+ (let [top (:y pos)
+ left (+ (:x pos) 10)]
+ (assoc state
+ :open? true
+ :top top
+ :left left)))
+
+(defn close-context-menu
+ [state]
+ (assoc state :open? false))
+
+(mf/defc assets-context-menu
+ {::mf/wrap-props false}
+ [{:keys [options state on-close]}]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:& context-menu-a11y
+ {:show (:open? state)
+ :fixed? (or (not= (:top state) 0) (not= (:left state) 0))
+ :on-close on-close
+ :top (:top state)
+ :left (:left state)
+ :options options
+ :workspace? true}]
+
+ [:& context-menu
+ {:selectable false
+ :show (:open? state)
+ :on-close on-close
+ :top (:top state)
+ :left (:left state)
+ :options options}])))
+
+(mf/defc section-icon
+ [{:keys [section] :as props}]
+ (case section
+ :colors i/drop-refactor
+ :components i/component-refactor
+ :typographies i/text-palette-refactor
+ i/add-refactor))
+
+(mf/defc asset-section
+ {::mf/wrap-props false}
+ [{:keys [children file-id title section assets-count open?]}]
+ (let [children (->> (if (array? children) children [children])
+ (filter some?))
+ get-role #(.. % -props -role)
+ title-buttons (filter #(= (get-role %) :title-button) children)
+ content (filter #(= (get-role %) :content) children)
+ new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :asset-section) true)}
+ [:& title-bar {:collapsable? true
+ :collapsed? (not open?)
+ :on-collapsed #(st/emit! (dw/set-assets-section-open file-id section (not open?)))
+ :klass :title-spacing
+ :title (mf/html [:span {:class (dom/classnames (css :title-name) true)}
+ [:span {:class (dom/classnames (css :section-icon) true)}
+ [:& section-icon {:section section}]]
+ [:span {:class (dom/classnames (css :section-name) true)}
+ title]
+
+ [:span {:class (dom/classnames (css :num-assets) true)}
+ assets-count]])}
+ title-buttons]
+ (when ^boolean open?
+ content)]
+ [:div.asset-section
+ [:div.asset-title {:class (when (not ^boolean open?) "closed")}
+ [:span {:on-click #(st/emit! (dw/set-assets-section-open file-id section (not open?)))}
+ i/arrow-slide title]
+ [:span.num-assets (dm/str "\u00A0(") assets-count ")"] ;; Unicode 00A0 is non-breaking space
+ title-buttons]
+ (when ^boolean open?
+ content)])))
+
+(mf/defc asset-section-block
+ [{:keys [children]}]
+ [:* children])
+
+(defn create-assets-group
+ [rename components-to-group group-name]
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (apply st/emit!
+ (->> components-to-group
+ (map #(rename
+ (:id %)
+ (add-group % group-name)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id))))
+
+(defn on-drop-asset
+ [event asset dragging* selected selected-full selected-paths rename]
+ (let [create-typed-assets-group (partial create-assets-group rename)]
+ (when (not (dnd/from-child? event))
+ (reset! dragging* false)
+ (when
+ (and (not (contains? selected (:id asset)))
+ (every? #(= % (:path asset)) selected-paths))
+ (let [components-to-group (conj selected-full asset)
+ create-typed-assets-group (partial create-typed-assets-group components-to-group)]
+ (modal/show! :name-group-dialog {:accept create-typed-assets-group}))))))
+
+(defn on-drag-enter-asset
+ [event asset dragging* selected selected-paths]
+ (when (and
+ (not (dnd/from-child? event))
+ (every? #(= % (:path asset)) selected-paths)
+ (not (contains? selected (:id asset))))
+ (reset! dragging* true)))
+
+(defn on-drag-leave-asset
+ [event dragging*]
+ (when (not (dnd/from-child? event))
+ (reset! dragging* false)))
+
+(defn create-counter-element
+ [asset-count]
+ (let [counter-el (dom/create-element "div")]
+ (dom/set-property! counter-el "class" "drag-counter")
+ (dom/set-text! counter-el (str asset-count))
+ counter-el))
+
+(defn set-drag-image
+ [event item-ref num-selected]
+ (let [offset (dom/get-offset-position (.-nativeEvent event))
+ item-el (mf/ref-val item-ref)
+ counter-el (create-counter-element num-selected)]
+
+ ;; set-drag-image requires that the element is rendered and
+ ;; visible to the user at the moment of creating the ghost
+ ;; image (to make a snapshot), but you may remove it right
+ ;; afterwards, in the next render cycle.
+ (dom/append-child! item-el counter-el)
+ (dnd/set-drag-image! event item-el (:x offset) (:y offset))
+ (ts/raf #(.removeChild ^js item-el counter-el))))
+
+(defn on-asset-drag-start
+ [event file-id asset selected item-ref asset-type on-drag-start]
+ (let [id-asset (:id asset)
+ num-selected (if (contains? selected id-asset)
+ (count selected)
+ 1)]
+ (when (not (contains? selected id-asset))
+ (st/emit! (dw/unselect-all-assets file-id)
+ (dw/toggle-selected-assets file-id id-asset asset-type)))
+ (on-drag-start asset event)
+ (when (> num-selected 1)
+ (set-drag-image event item-ref num-selected))))
+
+(defn on-drag-enter-asset-group
+ [event dragging* prefix selected-paths]
+ (dom/stop-propagation event)
+ (when (and (not (dnd/from-child? event))
+ (not (every? #(= % prefix) selected-paths)))
+ (reset! dragging* true)))
+
+(defn on-drop-asset-group
+ [event dragging* prefix selected-paths selected-full rename]
+ (dom/stop-propagation event)
+ (when (not (dnd/from-child? event))
+ (reset! dragging* false)
+ (when (not (every? #(= % prefix) selected-paths))
+ (doseq [target-asset selected-full]
+ (st/emit!
+ (rename
+ (:id target-asset)
+ (cph/merge-path-item prefix (:name target-asset))))))))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/common.css.json
new file mode 100644
index 0000000000..e4b336d85c
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_common_button-primary_-eBqD","button-secondary":"assets_common_button-secondary_qo2kg","button-tertiary":"assets_common_button-tertiary_ApdBb","button-tag":"assets_common_button-tag_MHJlj","button-icon":"assets_common_button-icon_0R1zt","button-icon-small":"assets_common_button-icon-small_5kQfO","asset-element":"assets_common_asset-element_frsFR","asset-section":"assets_common_asset-section_uKhc8","title-name":"assets_common_title-name_ZOz9E","section-icon":"assets_common_section-icon_Kitcf","section-name":"assets_common_section-name_RVo-u","num-assets":"assets_common_num-assets_Dguaz"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss
new file mode 100644
index 0000000000..16a95d2388
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/common.scss
@@ -0,0 +1,40 @@
+// 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";
+
+.asset-section {
+ .title-name {
+ @include tabTitleTipography;
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+ width: 100%;
+ .section-icon {
+ @include flexCenter;
+ padding-right: $s-8;
+ svg {
+ @include flexCenter;
+ height: $s-16;
+ width: $s-16;
+ color: transparent;
+ fill: none;
+ }
+ }
+ .section-name {
+ display: flex;
+ align-items: center;
+ }
+ .num-assets {
+ @include flexCenter;
+ height: 100%;
+ padding-left: $s-8;
+ }
+ }
+}
+:global(.title-spacing) {
+ margin-bottom: $s-4;
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs
new file mode 100644
index 0000000000..fcfbf06db1
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs
@@ -0,0 +1,662 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.workspace.sidebar.assets.components
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.common.media :as cm]
+ [app.common.pages.helpers :as cph]
+ [app.common.types.file :as ctf]
+ [app.main.data.events :as ev]
+ [app.main.data.modal :as modal]
+ [app.main.data.workspace :as dw]
+ [app.main.data.workspace.libraries :as dwl]
+ [app.main.data.workspace.media :as dwm]
+ [app.main.data.workspace.undo :as dwu]
+ [app.main.refs :as refs]
+ [app.main.render :refer [component-svg]]
+ [app.main.store :as st]
+ [app.main.ui.components.editable-label :refer [editable-label]]
+ [app.main.ui.components.file-uploader :refer [file-uploader]]
+ [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.sidebar.assets.common :as cmm]
+ [app.main.ui.workspace.sidebar.assets.groups :as grp]
+ [app.util.dom :as dom]
+ [app.util.dom.dnd :as dnd]
+ [app.util.i18n :as i18n :refer [tr]]
+ [cuerdas.core :as str]
+ [okulary.core :as l]
+ [potok.core :as ptk]
+ [rumext.v2 :as mf]))
+
+(defn- get-component-root-and-container
+ [file-id component components-v2]
+ (if (= file-id (:id @refs/workspace-file))
+ (let [data @refs/workspace-data]
+ [(ctf/get-component-root data component)
+ (if components-v2
+ (ctf/get-component-page data component)
+ component)])
+ (let [data (dm/get-in @refs/workspace-libraries [file-id :data])]
+ [(ctf/get-component-root data component)
+ (if components-v2
+ (ctf/get-component-page data component)
+ component)])))
+
+(mf/defc components-item
+ {::mf/wrap-props false}
+ [{:keys [component renaming listing-thumbs? selected
+ file-id on-asset-click on-context-menu on-drag-start do-rename
+ cancel-rename selected-full selected-paths]}]
+ (let [item-ref (mf/use-ref)
+
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ components-v2 (mf/use-ctx ctx/components-v2)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ component-id (:id component)
+
+ ;; NOTE: we don't use reactive deref for it because we don't
+ ;; really need rerender on any change on the file change. If
+ ;; the component changes, it will trigger rerender anyway.
+ [root-shape container]
+ (get-component-root-and-container file-id component components-v2)
+
+ unselect-all
+ (mf/use-fn
+ (fn []
+ (st/emit! (dw/unselect-all-assets))))
+
+ on-component-click
+ (mf/use-fn
+ (mf/deps component selected)
+ (fn [event]
+ (dom/stop-propagation event)
+ (on-asset-click component-id unselect-all event)))
+
+ on-component-double-click
+ (mf/use-fn
+ (mf/deps file-id component-id)
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dw/go-to-main-instance file-id component-id))))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps component dragging* selected selected-full selected-paths)
+ (fn [event]
+ (cmm/on-drop-asset event component dragging* selected selected-full
+ selected-paths dwl/rename-component)))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps component dragging* selected selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset event component dragging* selected selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-component-drag-start
+ (mf/use-fn
+ (mf/deps file-id component selected item-ref on-drag-start read-only?)
+ (fn [event]
+ (if read-only?
+ (dom/prevent-default event)
+ (cmm/on-asset-drag-start event file-id component selected item-ref :components on-drag-start))))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps component-id)
+ (partial on-context-menu component-id))]
+
+ (if ^boolean new-css-system
+ [:div {:ref item-ref
+ :class (dom/classnames
+ (css :selected) (contains? selected (:id component))
+ (css :grid-cell) listing-thumbs?
+ (css :enum-item) (not listing-thumbs?))
+ :id (dm/str "component-shape-id-" (:id component))
+ :draggable (not read-only?)
+ :on-click on-component-click
+ :on-double-click on-component-double-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-component-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ (when (and (some? root-shape)
+ (some? container))
+ [:*
+ [:& component-svg {:root-shape root-shape
+ :objects (:objects container)}]
+ (let [renaming? (= renaming (:id component))]
+ [:*
+ [:& editable-label
+ {:class-name (dom/classnames
+ (css :cell-name) listing-thumbs?
+ (css :item-name) (not listing-thumbs?)
+ (css :editing) renaming?)
+ :value (cph/merge-path-item (:path component) (:name component))
+ :tooltip (cph/merge-path-item (:path component) (:name component))
+ :display-value (:name component)
+ :editing? renaming?
+ :disable-dbl-click? true
+ :on-change do-rename
+ :on-cancel cancel-rename}]
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :dragging) true)}])])])]
+
+ [:div {:ref item-ref
+ :class (dom/classnames
+ :selected (contains? selected (:id component))
+ :grid-cell listing-thumbs?
+ :enum-item (not listing-thumbs?))
+ :id (dm/str "component-shape-id-" (:id component))
+ :draggable (not read-only?)
+ :on-click on-component-click
+ :on-double-click on-component-double-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-component-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when (and (some? root-shape)
+ (some? container))
+ [:*
+ [:& component-svg {:root-shape root-shape
+ :objects (:objects container)}]
+ (let [renaming? (= renaming (:id component))]
+ [:*
+ [:& editable-label
+ {:class-name (dom/classnames
+ :cell-name listing-thumbs?
+ :item-name (not listing-thumbs?)
+ :editing renaming?)
+ :value (cph/merge-path-item (:path component) (:name component))
+ :tooltip (cph/merge-path-item (:path component) (:name component))
+ :display-value (:name component)
+ :editing? renaming?
+ :disable-dbl-click? true
+ :on-change do-rename
+ :on-cancel cancel-rename}]
+
+ (when ^boolean dragging?
+ [:div.dragging])])])])))
+
+(mf/defc components-group
+ {::mf/wrap-props false}
+ [{:keys [file-id prefix groups open-groups renaming listing-thumbs? selected on-asset-click
+ on-drag-start do-rename cancel-rename on-rename-group on-group on-ungroup on-context-menu
+ selected-full]}]
+
+ (let [group-open? (get open-groups prefix true)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ selected-paths (mf/with-memo [selected-full]
+ (into #{}
+ (comp (map :path) (d/nilv ""))
+ selected-full))
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset-group event dragging* prefix selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths selected-full)
+ (fn [event]
+ (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-component)))]
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :component-group) true)
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title
+ {:file-id file-id
+ :section :components
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+
+
+ (when group-open?
+ [:*
+ (let [components (get groups "" [])]
+ [:div {:class-name (dom/classnames
+ (css :asset-grid) listing-thumbs?
+ (css :asset-enum) (not listing-thumbs?)
+ (css :drop-space) (and
+ (empty? components)
+ (some? groups)
+ (not dragging?)))
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :grid-placeholder) true)} "\u00A0"])
+
+
+ (when (and (empty? components)
+ (some? groups))
+ [:div {:class (dom/classnames (css :drop-space) true)}])
+
+ (for [component components]
+ [:& components-item
+ {:component component
+ :key (dm/str "component-" (:id component))
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :file-id file-id
+ :selected selected
+ :selected-full selected-full
+ :selected-paths selected-paths
+ :on-asset-click on-asset-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-drag-start
+ :on-group on-group
+ :do-rename do-rename
+ :cancel-rename cancel-rename}])])
+
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& components-group {:file-id file-id
+ :key path-item
+ :prefix (cph/merge-path-item prefix path-item)
+ :groups content
+ :open-groups open-groups
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :selected selected
+ :on-asset-click on-asset-click
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]))])]
+
+
+ [:div {:on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ [:& grp/asset-group-title
+ {:file-id file-id
+ :section :components
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+
+ (when group-open?
+ [:*
+ (let [components (get groups "" [])]
+ [:div {:class-name (dom/classnames
+ :asset-grid listing-thumbs?
+ :big listing-thumbs?
+ :asset-enum (not listing-thumbs?)
+ :drop-space (and
+ (empty? components)
+ (some? groups)
+ (not dragging?)))
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div.grid-placeholder "\u00A0"])
+
+ (when (and (empty? components)
+ (some? groups))
+ [:div.drop-space])
+
+ (for [component components]
+ [:& components-item
+ {:component component
+ :key (dm/str "component-" (:id component))
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :file-id file-id
+ :selected selected
+ :selected-full selected-full
+ :selected-paths selected-paths
+ :on-asset-click on-asset-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-drag-start
+ :on-group on-group
+ :do-rename do-rename
+ :cancel-rename cancel-rename}])])
+
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& components-group {:file-id file-id
+ :key path-item
+ :prefix (cph/merge-path-item prefix path-item)
+ :groups content
+ :open-groups open-groups
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :selected selected
+ :on-asset-click on-asset-click
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]))])])))
+
+(mf/defc components-section
+ {::mf/wrap-props false}
+ [{:keys [file-id local? components listing-thumbs? open? reverse-sort? selected
+ on-asset-click on-assets-delete on-clear-selection open-status-ref]}]
+
+ (let [input-ref (mf/use-ref nil)
+
+ state* (mf/use-state {})
+ state (deref state*)
+
+ current-component-id (:component-id state)
+ renaming? (:renaming state)
+
+ open-groups-ref (mf/with-memo [open-status-ref]
+ (-> (l/in [:groups :components])
+ (l/derived open-status-ref)))
+
+ open-groups (mf/deref open-groups-ref)
+
+ menu-state (mf/use-state cmm/initial-context-menu-state)
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ components-v2 (mf/use-ctx ctx/components-v2)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ toggle-list-style (mf/use-ctx cmm/assets-toggle-list-style)
+
+ selected (:components selected)
+ selected-full (into #{} (filter #(contains? selected (:id %))) components)
+ multi-components? (> (count selected) 1)
+ multi-assets? (or (seq (:graphics selected))
+ (seq (:colors selected))
+ (seq (:typographies selected)))
+
+ groups (mf/with-memo [components reverse-sort?]
+ (grp/group-assets components reverse-sort?))
+
+ add-component
+ (mf/use-fn
+ (fn []
+ (st/emit! (dw/set-assets-section-open file-id :components true))
+ (dom/click (mf/ref-val input-ref))))
+
+ on-file-selected
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn [blobs]
+ (let [params {:file-id file-id
+ :blobs (seq blobs)}]
+ (st/emit! (dwm/upload-media-components params)
+ (ptk/event ::ev/event {::ev/name "add-asset-to-library"
+ :asset-type "components"})))))
+
+ on-duplicate
+ (mf/use-fn
+ (mf/deps current-component-id selected)
+ (fn []
+ (if (empty? selected)
+ (st/emit! (dwl/duplicate-component file-id current-component-id))
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit! (map (partial dwl/duplicate-component file-id) selected))
+ (st/emit! (dwu/commit-undo-transaction undo-id))))))
+
+ on-delete
+ (mf/use-fn
+ (mf/deps current-component-id file-id multi-components? multi-assets? on-assets-delete)
+ (fn []
+ (let [undo-id (js/Symbol)]
+ (if (or multi-components? multi-assets?)
+ (on-assets-delete)
+ (st/emit! (dwu/start-undo-transaction undo-id)
+ (dwl/delete-component {:id current-component-id})
+ (dwl/sync-file file-id file-id :components current-component-id)
+ (dwu/commit-undo-transaction undo-id))))))
+
+ on-close-menu
+ (mf/use-fn #(swap! menu-state cmm/close-context-menu))
+
+ on-rename
+ (mf/use-fn #(swap! state* assoc :renaming true))
+
+ cancel-rename
+ (mf/use-fn #(swap! state* dissoc :renaming))
+
+ do-rename
+ (mf/use-fn
+ (mf/deps current-component-id)
+ (fn [new-name]
+ (swap! state* dissoc :renaming)
+ (st/emit!
+ (dwl/rename-component-and-main-instance current-component-id new-name))))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps selected on-clear-selection read-only?)
+ (fn [component-id event]
+ (dom/prevent-default event)
+ (let [pos (dom/get-client-position event)]
+ (when (and local? (not read-only?))
+ (when-not (contains? selected component-id)
+ (on-clear-selection))
+
+ (swap! state* assoc :component-id component-id)
+ (swap! menu-state cmm/open-context-menu pos)))))
+
+ create-group
+ (mf/use-fn
+ (mf/deps current-component-id components selected on-clear-selection)
+ (fn [group-name]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> components
+ (filter #(if multi-components?
+ (contains? selected (:id %))
+ (= current-component-id (:id %))))
+ (map #(dwl/rename-component
+ (:id %)
+ (cmm/add-group % group-name)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ rename-group
+ (mf/use-fn
+ (mf/deps components)
+ (fn [path last-path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> components
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/rename-component
+ (:id %)
+ (cmm/rename-group % path last-path)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-group
+ (mf/use-fn
+ (mf/deps components selected create-group)
+ (fn [event]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:accept create-group})))
+
+ on-rename-group
+ (mf/use-fn
+ (mf/deps components)
+ (fn [event path last-path]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:path path
+ :last-path last-path
+ :accept rename-group})))
+
+ on-ungroup
+ (mf/use-fn
+ (mf/deps components)
+ (fn [path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> components
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/rename-component (:id %) (cmm/ungroup % path)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-drag-start
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn [component event]
+ (dnd/set-data! event "penpot/component" {:file-id file-id
+ :component component})
+ (dnd/set-allowed-effect! event "move")))
+
+ on-show-main
+ (mf/use-fn
+ (mf/deps current-component-id file-id)
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dw/go-to-main-instance file-id current-component-id))))
+
+ on-asset-click
+ (mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
+
+ [:& cmm/asset-section {:file-id file-id
+ :title (tr "workspace.assets.components")
+ :section :components
+ :assets-count (count components)
+ :open? open?}
+ (if ^boolean new-css-system
+ [:& cmm/asset-section-block {:role :title-button}
+
+ (when open?
+ [:div {:class (dom/classnames (css :listing-options) true)}
+ (let [option-selected (if listing-thumbs?
+ "grid"
+ "list")]
+ [:& radio-buttons {:selected option-selected
+ :on-change toggle-list-style
+ :name "listing-style"}
+ [:& radio-button {:icon (mf/html i/view-as-list-refactor)
+ :value "list"
+ :id :list}]
+ [:& radio-button {:icon (mf/html i/flex-grid-refactor)
+ :value "grid"
+ :id :grid}]])])
+ (when (and components-v2 (not read-only?) local?)
+ [:div {:on-click add-component
+ :class (dom/classnames (css :add-component) true)}
+ i/add-refactor
+ [:& file-uploader {:accept cm/str-image-types
+ :multi true
+ :ref input-ref
+ :on-selected on-file-selected}]])]
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when (and components-v2 (not read-only?))
+ [:div.assets-button {:on-click add-component}
+ i/plus
+ [:& file-uploader {:accept cm/str-image-types
+ :multi true
+ :ref input-ref
+ :on-selected on-file-selected}]])]))
+ [:& cmm/asset-section-block {:role :content}
+ [:& components-group {:file-id file-id
+ :prefix ""
+ :groups groups
+ :open-groups open-groups
+ :renaming (when ^boolean renaming? current-component-id)
+ :listing-thumbs? listing-thumbs?
+ :selected selected
+ :on-asset-click on-asset-click
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :on-rename-group on-rename-group
+ :on-group on-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]
+ (when local?
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options (if new-css-system
+ [(when-not (or multi-components? multi-assets?)
+ {:option-name (tr "workspace.assets.rename")
+ :id "assets-rename-component"
+ :option-handler on-rename})
+ (when-not multi-assets?
+ {:option-name (if components-v2
+ (tr "workspace.assets.duplicate-main")
+ (tr "workspace.assets.duplicate"))
+ :id "assets-duplicate-component"
+ :option-handler on-duplicate})
+
+ {:option-name (tr "workspace.assets.delete")
+ :id "assets-delete-component"
+ :option-handler on-delete}
+ (when-not multi-assets?
+ {:option-name (tr "workspace.assets.group")
+ :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"
+ :option-handler on-show-main})]
+
+ [(when-not (or multi-components? multi-assets?)
+ [(tr "workspace.assets.rename") on-rename])
+ (when-not multi-assets?
+ [(if components-v2
+ (tr "workspace.assets.duplicate-main")
+ (tr "workspace.assets.duplicate")) on-duplicate])
+ [(tr "workspace.assets.delete") on-delete]
+ (when-not multi-assets?
+ [(tr "workspace.assets.group") on-group])
+ (when (and components-v2 (not multi-assets?))
+ [(tr "workspace.shape.menu.show-main") on-show-main])])}])]]))
+
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/components.css.json
new file mode 100644
index 0000000000..64e72325f1
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_components_button-primary_lsoWq","button-secondary":"assets_components_button-secondary_P8v5X","button-tertiary":"assets_components_button-tertiary_7wMqf","add-component":"assets_components_add-component_X9o2C","button-tag":"assets_components_button-tag_ibmtY","button-icon":"assets_components_button-icon_4Lapr","button-icon-small":"assets_components_button-icon-small_7WrRR","component-group":"assets_components_component-group_AYXVI","asset-enum":"assets_components_asset-enum_iLlfH","enum-item":"assets_components_enum-item_l4zuE","item-name":"assets_components_item-name_Hwadc","editing":"assets_components_editing_3RdZy","asset-grid":"assets_components_asset-grid_mK75F","grid-cell":"assets_components_grid-cell_ctU6T","cell-name":"assets_components_cell-name_DUUMt","asset-element":"assets_components_asset-element_UsbdX","drop-space":"assets_components_drop-space_QhD1-","selected":"assets_components_selected_QLPO7","grid-placeholder":"assets_components_grid-placeholder_a3PoY","listing-options":"assets_components_listing-options_-vPIQ","listing-option-btn":"assets_components_listing-option-btn_-d9cg","first":"assets_components_first_sri1T","dragging":"assets_components_dragging_bWqQC"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss
new file mode 100644
index 0000000000..66ff32efac
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.scss
@@ -0,0 +1,249 @@
+// 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";
+
+.component-group {
+ .drop-space {
+ height: $s-12;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ }
+ .asset-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-auto-rows: calc(10vh + $s-16);
+ gap: $s-4;
+ margin-left: $s-8;
+ margin-right: $s-12;
+ .grid-cell {
+ @include flexCenter;
+ position: relative;
+ padding: $s-8;
+ border: $s-2 solid transparent;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ overflow: hidden;
+ cursor: pointer;
+ img {
+ height: auto;
+ width: auto;
+ max-height: 100%;
+ max-width: 100%;
+ pointer-events: none;
+ }
+ svg {
+ height: 10vh;
+ }
+ .cell-name {
+ @include titleTipography;
+ @include textEllipsis;
+ display: none;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ padding: $s-2;
+
+ &.editing {
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ border: $s-1 solid var(--input-border-color-focus);
+ border-radius: $br-8;
+ background-color: var(--input-background-color);
+ input {
+ @include textEllipsis;
+ @include titleTipography;
+ @include removeInputStyle;
+ flex-grow: 1;
+ height: $s-28;
+ max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
+ padding-left: $s-6;
+ margin: 0;
+ border-radius: $br-8;
+ color: var(--input-foreground-color);
+ }
+ span {
+ @include flexCenter;
+ height: $s-28;
+ background-color: transparent;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--input-foreground-color);
+ transform: rotate(90deg);
+ }
+ }
+ }
+ }
+
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ .cell-name {
+ display: block;
+ color: var(--assets-item-name-foreground-color-hover);
+ background: linear-gradient(to top, rgba(52, 57, 59, 1) 0%, rgba(52, 57, 59, 0) 100%);
+ &.editing {
+ display: flex;
+ background: var(--input-background-color);
+ input {
+ color: var(--input-foreground-color-active);
+ }
+ span svg {
+ stroke: var(--input-foreground-color-active);
+ }
+ }
+ }
+ }
+
+ &.selected {
+ border: $s-1 solid var(--assets-item-border-color);
+ }
+ }
+ .grid-placeholder {
+ width: 100%;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ }
+ }
+ .asset-enum {
+ margin: 0 $s-12;
+ .enum-item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ height: $s-36;
+ margin-bottom: $s-4;
+ padding: $s-2;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ cursor: pointer;
+
+ svg,
+ img {
+ @include flexCenter;
+ padding: $s-2;
+ height: $s-32;
+ width: $s-32;
+ border-radius: $br-6;
+ background-color: var(--assets-item-background-color);
+ }
+
+ .item-name {
+ @include titleTipography;
+ @include textEllipsis;
+ padding-left: $s-8;
+ color: var(--assets-item-name-foreground-color);
+ &.editing {
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ border: $s-1 solid var(--input-border-color-focus);
+ border-radius: $br-8;
+ background-color: var(--input-background-color);
+ input {
+ @include textEllipsis;
+ @include titleTipography;
+ @include removeInputStyle;
+ flex-grow: 1;
+ height: $s-28;
+ max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
+ padding-left: $s-6;
+ margin: 0;
+ border-radius: $br-8;
+ color: var(--input-foreground-color);
+ }
+ span {
+ @include flexCenter;
+ height: $s-28;
+ background-color: transparent;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--input-foreground-color);
+ transform: rotate(90deg);
+ }
+ }
+ }
+ }
+
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ .item-name {
+ color: var(--assets-item-name-foreground-color-hover);
+ &.editing {
+ background: var(--input-background-color);
+ input {
+ color: var(--input-foreground-color-active);
+ }
+ span svg {
+ stroke: var(--input-foreground-color-active);
+ }
+ }
+ }
+ }
+ &.selected {
+ border: $s-1 solid var(--assets-item-border-color);
+ }
+ }
+ .grid-placeholder {
+ height: $s-2;
+ width: 100%;
+ background-color: var(--color-accent-primary);
+ }
+ }
+}
+.listing-options {
+ display: flex;
+ align-items: center;
+
+ .listing-option-btn {
+ @include flexCenter;
+ cursor: pointer;
+
+ &.first {
+ margin-left: auto;
+ }
+
+ svg {
+ height: 16px;
+ width: 16px;
+ }
+ }
+}
+.add-component {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: $s-28;
+ margin-left: $s-2;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+}
+:global(.three-row) {
+ .asset-grid {
+ grid-template-columns: repeat(3, 1fr);
+ }
+}
+
+:global(.four-row) {
+ .asset-grid {
+ grid-template-columns: repeat(4, 1fr);
+ }
+}
+
+.dragging {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: $s-8;
+ background-color: var(--assets-item-background-color-drag);
+ border: $s-2 solid var(--assets-item-border-color-drag);
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs
new file mode 100644
index 0000000000..a0252788e9
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs
@@ -0,0 +1,420 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.workspace.sidebar.assets.file-library
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.main.data.workspace :as dw]
+ [app.main.data.workspace.libraries :as dwl]
+ [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.icons :as i]
+ [app.main.ui.workspace.libraries :refer [create-file-library-ref]]
+ [app.main.ui.workspace.sidebar.assets.colors :refer [colors-section]]
+ [app.main.ui.workspace.sidebar.assets.common :as cmm]
+ [app.main.ui.workspace.sidebar.assets.components :refer [components-section]]
+ [app.main.ui.workspace.sidebar.assets.graphics :refer [graphics-section]]
+ [app.main.ui.workspace.sidebar.assets.typographies :refer [typographies-section]]
+ [app.util.dom :as dom]
+ [app.util.i18n :as i18n :refer [tr]]
+ [app.util.keyboard :as kbd]
+ [app.util.router :as rt]
+ [cuerdas.core :as str]
+ [okulary.core :as l]
+ [rumext.v2 :as mf]))
+
+(def lens:open-status
+ (l/derived (l/in [:workspace-assets :open-status]) st/state))
+
+(def lens:selected
+ (-> (l/in [:workspace-assets :selected])
+ (l/derived st/state)))
+
+(mf/defc file-library-title
+ {::mf/wrap-props false}
+ [{:keys [open? local? shared? project-id file-id page-id file-name]}]
+ (let [router (mf/deref refs/router)
+ url (rt/resolve router :workspace
+ {:project-id project-id
+ :file-id file-id}
+ {:page-id page-id})
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ toggle-open
+ (mf/use-fn
+ (mf/deps file-id open?)
+ (fn []
+ (st/emit! (dw/set-assets-section-open file-id :library (not open?)))))]
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :library-title) true)}
+ [:& title-bar {:collapsable? true
+ :collapsed? (not open?)
+ :on-collapsed toggle-open
+ :title (if local?
+ (mf/html [:div {:class (dom/classnames (css :special-title) true)} (tr "workspace.assets.local-library")
+ [:span {:class (dom/classnames (css :special-subtitle) true)} file-name]])
+
+ (mf/html [:div {:class (dom/classnames (css :special-title) true)} file-name]))}
+ (when-not local?
+ [:span.tool-link.tooltip.tooltip-left {:alt "Open library file"}
+ [:a {:class (dom/classnames (css :file-link) true)
+ :href (str "#" url)
+ :target "_blank"
+ :on-click dom/stop-propagation}
+ i/open-link-refactor]])]]
+
+ [:div.tool-window-bar.library-bar
+ {:on-click toggle-open}
+ [:div.collapse-library
+ {:class (dom/classnames :open open?)}
+ i/arrow-slide]
+
+ (if local?
+ [:*
+ [:span file-name " (" (tr "workspace.assets.local-library") ")"]
+ (when shared?
+ [:span.tool-badge (tr "workspace.assets.shared")])]
+ [:*
+ [:span file-name]
+ [:span.tool-link.tooltip.tooltip-left {:alt "Open library file"}
+ [:a {:href (str "#" url)
+ :target "_blank"
+ :on-click dom/stop-propagation}
+ i/chain]]])])))
+
+(mf/defc file-library-content
+ {::mf/wrap-props false}
+ [{:keys [file local? open-status-ref on-clear-selection]}]
+ (let [components-v2 (mf/use-ctx ctx/components-v2)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ open-status (mf/deref open-status-ref)
+
+ file-id (:id file)
+ project-id (:project-id file)
+
+ filters (mf/use-ctx cmm/assets-filters)
+ filters-section (:section filters)
+
+ filters-term (:term filters)
+ filters-ordering (:ordering filters)
+ filters-list-style (:list-style filters)
+
+ reverse-sort? (= :desc filters-ordering)
+ listing-thumbs? (= :thumbs filters-list-style)
+
+ toggle-ordering (mf/use-ctx cmm/assets-toggle-ordering)
+ toggle-list-style (mf/use-ctx cmm/assets-toggle-list-style)
+
+ library-ref (mf/with-memo [file-id]
+ (create-file-library-ref file-id))
+
+ library (mf/deref library-ref)
+ colors (:colors library)
+ components (:components library)
+ media (:media library)
+ typographies (:typographies library)
+
+ colors (mf/with-memo [filters colors]
+ (cmm/apply-filters colors filters))
+ components (mf/with-memo [filters components]
+ (cmm/apply-filters components filters))
+ media (mf/with-memo [filters media]
+ (cmm/apply-filters media filters))
+ typographies (mf/with-memo [filters typographies]
+ (cmm/apply-filters typographies filters))
+
+ show-components? (and (or (= filters-section "all")
+ (= filters-section "components"))
+ (or (pos? (count components))
+ (str/empty? filters-term)))
+ show-graphics? (and (or (= filters-section "all")
+ (= filters-section "graphics"))
+ (or (pos? (count media))
+ (and (str/empty? filters-term)
+ (not components-v2))))
+ show-colors? (and (or (= filters-section "all")
+ (= filters-section "colors"))
+ (or (> (count colors) 0)
+ (str/empty? filters-term)))
+ show-typography? (and (or (= filters-section "all")
+ (= filters-section "typographies"))
+ (or (pos? (count typographies))
+ (str/empty? filters-term)))
+
+
+ selected-lens (mf/with-memo [file-id]
+ (-> (l/key file-id)
+ (l/derived lens:selected)))
+
+ selected (mf/deref selected-lens)
+ selected-count (+ (count (get selected :components))
+ (count (get selected :graphics))
+ (count (get selected :colors))
+ (count (get selected :typographies)))
+
+ extend-selected
+ (fn [type asset-groups asset-id]
+ (letfn [(flatten-groups [groups]
+ (reduce concat [(get groups "" [])
+ (into []
+ (->> (filter #(seq (first %)) groups)
+ (map second)
+ (mapcat flatten-groups)))]))]
+
+ (let [selected' (get selected type)]
+ (if (zero? (count selected'))
+ (st/emit! (dw/select-single-asset file-id asset-id type))
+ (let [all-assets (flatten-groups asset-groups)
+ click-index (d/index-of-pred all-assets #(= (:id %) asset-id))
+ first-index (->> (get selected type)
+ (map (fn [asset] (d/index-of-pred all-assets #(= (:id %) asset))))
+ (sort)
+ (first))
+
+ min-index (min first-index click-index)
+ max-index (max first-index click-index)
+ ids (->> (d/enumerate all-assets)
+ (into #{} (comp (filter #(<= min-index (first %) max-index))
+ (map (comp :id second)))))]
+
+ (st/emit! (dw/select-assets file-id ids type)))))))
+
+ on-asset-click
+ (mf/use-fn
+ (mf/deps file-id extend-selected)
+ (fn [asset-type asset-groups asset-id default-click event]
+ (cond
+ (kbd/mod? event)
+ (do
+ (dom/stop-propagation event)
+ (st/emit! (dw/toggle-selected-assets file-id asset-id asset-type)))
+
+ (kbd/shift? event)
+ (do
+ (dom/stop-propagation event)
+ (extend-selected asset-type asset-groups asset-id))
+
+ :else
+ (when default-click
+ (default-click event)))))
+
+ on-component-click
+ (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :components))
+
+ on-graphics-click
+ (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :graphics))
+
+ on-colors-click
+ (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :colors))
+
+ on-typography-click
+ (mf/use-fn (mf/deps on-asset-click) (partial on-asset-click :typographies))
+
+ on-assets-delete
+ (mf/use-fn
+ (mf/deps selected file-id)
+ (fn []
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit! (map #(dwl/delete-component {:id %})
+ (:components selected)))
+ (run! st/emit! (map #(dwl/delete-media {:id %})
+ (:graphics selected)))
+ (run! st/emit! (map #(dwl/delete-color {:id %})
+ (:colors selected)))
+ (run! st/emit! (map #(dwl/delete-typography %)
+ (:typographies selected)))
+
+ (when (or (seq (:components selected))
+ (seq (:colors selected))
+ (seq (:typographies selected)))
+ (st/emit! (dwl/sync-file file-id file-id)))
+
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))]
+
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :library-content) true)}
+ (when ^boolean show-components?
+ [:& components-section
+ {:file-id file-id
+ :local? local?
+ :components components
+ :listing-thumbs? listing-thumbs?
+ :open? (get open-status :components true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-component-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when ^boolean show-graphics?
+ [:& graphics-section
+ {:file-id file-id
+ :project-id project-id
+ :local? local?
+ :objects media
+ :listing-thumbs? listing-thumbs?
+ :open? (get open-status :graphics true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-graphics-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when ^boolean show-colors?
+ [:& colors-section
+ {:file-id file-id
+ :local? local?
+ :colors colors
+ :open? (get open-status :colors true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-colors-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when ^boolean show-typography?
+ [:& typographies-section
+ {:file file
+ :file-id (:id file)
+ :local? local?
+ :typographies typographies
+ :open? (get open-status :typographies true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-typography-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when (and (not ^boolean show-components?)
+ (not ^boolean show-graphics?)
+ (not ^boolean show-colors?)
+ (not ^boolean show-typography?))
+ [:div {:class (css :asset-title)} (tr "workspace.assets.not-found")])]
+
+ [:div.tool-window-content
+ [:div.listing-options
+ (when (> selected-count 0)
+ [:span.selected-count
+ (tr "workspace.assets.selected-count" (i18n/c selected-count))])
+ [:div.listing-option-btn.first {:on-click toggle-ordering}
+ (if reverse-sort?
+ i/sort-ascending
+ i/sort-descending)]
+ [:div.listing-option-btn {:on-click toggle-list-style}
+ (if listing-thumbs?
+ i/listing-enum
+ i/listing-thumbs)]]
+
+ (when ^boolean show-components?
+ [:& components-section
+ {:file-id file-id
+ :local? local?
+ :components components
+ :listing-thumbs? listing-thumbs?
+ :open? (get open-status :components true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-component-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when ^boolean show-graphics?
+ [:& graphics-section
+ {:file-id file-id
+ :project-id project-id
+ :local? local?
+ :objects media
+ :listing-thumbs? listing-thumbs?
+ :open? (get open-status :graphics true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-graphics-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when ^boolean show-colors?
+ [:& colors-section
+ {:file-id file-id
+ :local? local?
+ :colors colors
+ :open? (get open-status :colors true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-colors-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when ^boolean show-typography?
+ [:& typographies-section
+ {:file file
+ :file-id (:id file)
+ :local? local?
+ :typographies typographies
+ :open? (get open-status :typographies true)
+ :open-status-ref open-status-ref
+ :reverse-sort? reverse-sort?
+ :selected selected
+ :on-asset-click on-typography-click
+ :on-assets-delete on-assets-delete
+ :on-clear-selection on-clear-selection}])
+
+ (when (and (not ^boolean show-components?)
+ (not ^boolean show-graphics?)
+ (not ^boolean show-colors?)
+ (not ^boolean show-typography?))
+ [:div.asset-section
+ [:div.asset-title (tr "workspace.assets.not-found")]])])))
+
+(mf/defc file-library
+ {::mf/wrap-props false}
+ [{:keys [file local? default-open? filters]}]
+ (let [file-id (:id file)
+ file-name (:name file)
+ shared? (:is-shared file)
+ project-id (:project-id file)
+ page-id (dm/get-in file [:data :pages 0])
+
+ open-status-ref (mf/with-memo [file-id]
+ (-> (l/key file-id)
+ (l/derived lens:open-status)))
+ open-status (mf/deref open-status-ref)
+ open? (d/nilv (:library open-status) default-open?)
+
+ unselect-all
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn []
+ (st/emit! (dw/unselect-all-assets file-id))))]
+
+ [:div.tool-window {:on-context-menu dom/prevent-default
+ :on-click unselect-all}
+ [:& file-library-title
+ {:project-id project-id
+ :file-id file-id
+ :page-id page-id
+ :file-name file-name
+ :open? open?
+ :local? local?
+ :shared? shared?}]
+ (when ^boolean open?
+ [:& file-library-content
+ {:file file
+ :local? local?
+ :filters filters
+ :on-clear-selection unselect-all
+ :open-status-ref open-status-ref}])]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.css.json
new file mode 100644
index 0000000000..6cbfca0e4d
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_file_library_button-primary_o8czr","button-secondary":"assets_file_library_button-secondary_BCBmw","button-tertiary":"assets_file_library_button-tertiary_JiCQn","library-title":"assets_file_library_library-title_FvGs6","file-link":"assets_file_library_file-link_CtN0K","button-tag":"assets_file_library_button-tag_cyg7Q","button-icon":"assets_file_library_button-icon_R-4R0","button-icon-small":"assets_file_library_button-icon-small_9UOdy","asset-element":"assets_file_library_asset-element_6ian7","file-name":"assets_file_library_file-name_Pc8ng","special-title":"assets_file_library_special-title_-Pqzq","special-subtitle":"assets_file_library_special-subtitle_9xOl9","library-content":"assets_file_library_library-content_Yto-8","asset-title":"assets_file_library_asset-title_ozD8M"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.scss
new file mode 100644
index 0000000000..deb65469d0
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.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";
+
+.library-title {
+ .file-name {
+ @include titleTipography;
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ flex-grow: 100;
+ height: 100%;
+ }
+
+ .special-title {
+ color: var(--title-foreground-color-hover);
+ }
+ .special-subtitle {
+ padding-left: $s-4;
+ color: var(--title-foreground-color);
+ text-transform: initial;
+ }
+ .file-link {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: $s-28;
+ margin-right: $s-12;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon-small;
+ fill: var(--title-foreground-color-hover);
+ }
+ }
+}
+.library-content {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.asset-title {
+ @include titleTipography;
+ margin-left: $s-28;
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs
new file mode 100644
index 0000000000..a1ba98b2c5
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.cljs
@@ -0,0 +1,553 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.workspace.sidebar.assets.graphics
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.common.media :as cm]
+ [app.common.pages.helpers :as cph]
+ [app.config :as cf]
+ [app.main.data.events :as ev]
+ [app.main.data.modal :as modal]
+ [app.main.data.workspace :as dw]
+ [app.main.data.workspace.libraries :as dwl]
+ [app.main.data.workspace.media :as dwm]
+ [app.main.data.workspace.undo :as dwu]
+ [app.main.store :as st]
+ [app.main.ui.components.editable-label :refer [editable-label]]
+ [app.main.ui.components.file-uploader :refer [file-uploader]]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.hooks :as h]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.sidebar.assets.common :as cmm]
+ [app.main.ui.workspace.sidebar.assets.groups :as grp]
+ [app.util.dom :as dom]
+ [app.util.dom.dnd :as dnd]
+ [app.util.i18n :as i18n :refer [tr]]
+ [cuerdas.core :as str]
+ [okulary.core :as l]
+ [potok.core :as ptk]
+ [rumext.v2 :as mf]))
+
+(mf/defc graphics-item
+ [{:keys [object renaming listing-thumbs? selected-objects file-id
+ on-asset-click on-context-menu on-drag-start do-rename cancel-rename
+ selected-full selected-graphics-paths]}]
+ (let [item-ref (mf/use-ref)
+ visible? (h/use-visible item-ref :once? true)
+ object-id (:id object)
+
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+
+ on-drop
+ (mf/use-fn
+ (mf/deps object dragging* selected-objects selected-full selected-graphics-paths)
+ (fn [event]
+ (cmm/on-drop-asset event object dragging* selected-objects selected-full
+ selected-graphics-paths dwl/rename-media)))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps object dragging* selected-objects selected-graphics-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset event object dragging* selected-objects selected-graphics-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-grahic-drag-start
+ (mf/use-fn
+ (mf/deps object file-id selected-objects item-ref on-drag-start read-only?)
+ (fn [event]
+ (if read-only?
+ (dom/prevent-default event)
+ (cmm/on-asset-drag-start event file-id object selected-objects item-ref :graphics on-drag-start))))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps object-id)
+ (partial on-context-menu object-id))
+
+ on-asset-click
+ (mf/use-fn
+ (mf/deps object-id on-asset-click)
+ (partial on-asset-click object-id nil))]
+ (if ^boolean new-css-system
+ [:div {:ref item-ref
+ :class-name (dom/classnames
+ (css :selected) (contains? selected-objects object-id)
+ (css :grid-cell) listing-thumbs?
+ (css :enum-item) (not listing-thumbs?))
+ :draggable (not read-only?)
+ :on-click on-asset-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-grahic-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when visible?
+ [:*
+ [:img {:src (when visible? (cf/resolve-file-media object true))
+ :class (css :graphic-image)
+ :draggable false}] ;; Also need to add css pointer-events: none
+
+ (let [renaming? (= renaming (:id object))]
+ [:*
+ [:& editable-label
+ {:class-name (dom/classnames
+ (css :cell-name) listing-thumbs?
+ (css :item-name) (not listing-thumbs?)
+ (css :editing) renaming?)
+ :value (cph/merge-path-item (:path object) (:name object))
+ :tooltip (cph/merge-path-item (:path object) (:name object))
+ :display-value (:name object)
+ :editing? renaming?
+ :disable-dbl-click? true
+ :on-change do-rename
+ :on-cancel cancel-rename}]
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :dragging) true)}])])])]
+
+ [:div {:ref item-ref
+ :class-name (dom/classnames
+ :selected (contains? selected-objects object-id)
+ :grid-cell listing-thumbs?
+ :enum-item (not listing-thumbs?))
+ :draggable (not read-only?)
+ :on-click on-asset-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-grahic-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when visible?
+ [:*
+ [:img {:src (when visible? (cf/resolve-file-media object true))
+ :draggable false}] ;; Also need to add css pointer-events: none
+
+ (let [renaming? (= renaming (:id object))]
+ [:*
+ [:& editable-label
+ {:class-name (dom/classnames
+ :cell-name listing-thumbs?
+ :item-name (not listing-thumbs?)
+ :editing renaming?)
+ :value (cph/merge-path-item (:path object) (:name object))
+ :tooltip (cph/merge-path-item (:path object) (:name object))
+ :display-value (:name object)
+ :editing? renaming?
+ :disable-dbl-click? true
+ :on-change do-rename
+ :on-cancel cancel-rename}]
+
+ (when ^boolean dragging?
+ [:div.dragging])])])])))
+
+(mf/defc graphics-group
+ [{:keys [file-id prefix groups open-groups renaming listing-thumbs? selected-objects on-asset-click
+ on-drag-start do-rename cancel-rename on-rename-group on-ungroup
+ on-context-menu selected-full]}]
+ (let [group-open? (get open-groups prefix true)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ selected-paths
+ (mf/with-memo [selected-full]
+ (into #{}
+ (comp (map :path) (d/nilv ""))
+ selected-full))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset-group event dragging* prefix selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths selected-full)
+ (fn [event]
+ (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full dwl/rename-media)))]
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :graphics-group) true)
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title
+ {:file-id file-id
+ :section :graphics
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+ (when group-open?
+ [:*
+ (let [objects (get groups "" [])]
+ [:div {:class-name (dom/classnames
+ (css :asset-grid) listing-thumbs?
+ (css :asset-enum) (not listing-thumbs?)
+ (css :drop-space) (and
+ (empty? objects)
+ (some? groups)
+ (not dragging?)))
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :grid-placeholder) true)} "\u00A0"])
+
+ (when (and (empty? objects)
+ (some? groups))
+ [:div {:class (dom/classnames (css :drop-space) true)}])
+
+ (for [object objects]
+ [:& graphics-item
+ {:key (dm/str "object-" (:id object))
+ :file-id file-id
+ :object object
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :selected-objects selected-objects
+ :on-asset-click on-asset-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :selected-full selected-full
+ :selected-paths selected-paths}])])
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& graphics-group {:file-id file-id
+ :key path-item
+ :prefix (cph/merge-path-item prefix path-item)
+ :groups content
+ :open-groups open-groups
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :selected-objects selected-objects
+ :on-asset-click on-asset-click
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full
+ :selected-paths selected-paths}]))])]
+
+ [:div {:on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title {:file-id file-id
+ :section :graphics
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+ (when group-open?
+ [:*
+ (let [objects (get groups "" [])]
+ [:div {:class-name (dom/classnames
+ :asset-grid listing-thumbs?
+ :asset-enum (not listing-thumbs?)
+ :drop-space (and
+ (empty? objects)
+ (some? groups)
+ (not dragging?)))
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div.grid-placeholder "\u00A0"])
+
+ (when (and (empty? objects)
+ (some? groups))
+ [:div.drop-space])
+
+ (for [object objects]
+ [:& graphics-item {:key (dm/str "object-" (:id object))
+ :file-id file-id
+ :object object
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :selected-objects selected-objects
+ :on-asset-click on-asset-click
+ :on-context-menu on-context-menu
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :selected-full selected-full
+ :selected-paths selected-paths}])])
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& graphics-group {:file-id file-id
+ :key path-item
+ :prefix (cph/merge-path-item prefix path-item)
+ :groups content
+ :open-groups open-groups
+ :renaming renaming
+ :listing-thumbs? listing-thumbs?
+ :selected-objects selected-objects
+ :on-asset-click on-asset-click
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full
+ :selected-paths selected-paths}]))])])))
+
+(mf/defc graphics-section
+ {::mf/wrap-props false}
+ [{:keys [file-id project-id local? objects listing-thumbs? open? open-status-ref selected reverse-sort?
+ on-asset-click on-assets-delete on-clear-selection]}]
+ (let [input-ref (mf/use-ref nil)
+ state (mf/use-state {:renaming nil :object-id nil})
+
+ menu-state (mf/use-state cmm/initial-context-menu-state)
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+
+ open-groups-ref (mf/with-memo [open-status-ref]
+ (-> (l/in [:groups :graphics])
+ (l/derived open-status-ref)))
+ open-groups (mf/deref open-groups-ref)
+
+ selected (:graphics selected)
+ selected-full (into #{} (filter #(contains? selected (:id %))) objects)
+ multi-objects? (> (count selected) 1)
+ multi-assets? (or (seq (:components selected))
+ (seq (:colors selected))
+ (seq (:typographies selected)))
+
+ objects (mf/with-memo [objects]
+ (mapv dwl/extract-path-if-missing objects))
+
+ groups (mf/with-memo [objects reverse-sort?]
+ (grp/group-assets objects reverse-sort?))
+
+ components-v2 (mf/use-ctx ctx/components-v2)
+ team-id (mf/use-ctx ctx/current-team-id)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+
+ add-graphic
+ (mf/use-fn
+ (fn []
+ (st/emit! (dw/set-assets-section-open file-id :graphics true))
+ (dom/click (mf/ref-val input-ref))))
+
+ on-file-selected
+ (mf/use-fn
+ (mf/deps file-id project-id team-id)
+ (fn [blobs]
+ (let [params {:file-id file-id
+ :blobs (seq blobs)}]
+ (st/emit! (dwm/upload-media-asset params)
+ (ptk/event ::ev/event {::ev/name "add-asset-to-library"
+ :asset-type "graphics"
+ :file-id file-id
+ :project-id project-id
+ :team-id team-id})))))
+ on-delete
+ (mf/use-fn
+ (mf/deps @state multi-objects? multi-assets?)
+ (fn []
+ (if (or multi-objects? multi-assets?)
+ (on-assets-delete)
+ (st/emit! (dwl/delete-media {:id (:object-id @state)})))))
+
+ on-rename
+ (mf/use-fn
+ (fn []
+ (swap! state (fn [state]
+ (assoc state :renaming (:component-id state))))))
+ cancel-rename
+ (mf/use-fn
+ (fn []
+ (swap! state assoc :renaming nil)))
+
+ do-rename
+ (mf/use-fn
+ (mf/deps @state)
+ (fn [new-name]
+ (st/emit! (dwl/rename-media (:renaming @state) new-name))
+ (swap! state assoc :renaming nil)))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps selected on-clear-selection read-only?)
+ (fn [object-id event]
+ (dom/prevent-default event)
+ (let [pos (dom/get-client-position event)]
+ (when (and local? (not read-only?))
+ (when-not (contains? selected object-id)
+ (on-clear-selection))
+ (swap! state assoc :object-id object-id)
+ (swap! menu-state cmm/open-context-menu pos)))))
+
+ on-close-menu
+ (mf/use-fn
+ (fn []
+ (swap! menu-state cmm/close-context-menu)))
+
+ create-group
+ (mf/use-fn
+ (mf/deps objects selected on-clear-selection (:object-id @state))
+ (fn [group-name]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> objects
+ (filter #(if multi-objects?
+ (contains? selected (:id %))
+ (= (:object-id @state) (:id %))))
+ (map #(dwl/rename-media (:id %) (cmm/add-group % group-name)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ rename-group
+ (mf/use-fn
+ (mf/deps objects)
+ (fn [path last-path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> objects
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/rename-media (:id %) (cmm/rename-group % path last-path)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-group
+ (mf/use-fn
+ (mf/deps objects selected create-group)
+ (fn [event]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:accept create-group})))
+
+ on-rename-group
+ (mf/use-fn
+ (mf/deps objects)
+ (fn [event path last-path]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:path path
+ :last-path last-path
+ :accept rename-group})))
+ on-ungroup
+ (mf/use-fn
+ (mf/deps objects)
+ (fn [path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> objects
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/rename-media (:id %) (cmm/ungroup % path)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-drag-start
+ (mf/use-fn
+ (fn [{:keys [name id mtype]} event]
+ (dnd/set-data! event "text/asset-id" (str id))
+ (dnd/set-data! event "text/asset-name" name)
+ (dnd/set-data! event "text/asset-type" mtype)
+ (dnd/set-allowed-effect! event "move")))
+
+ on-asset-click
+ (mf/use-fn (mf/deps groups on-asset-click) (partial on-asset-click groups))]
+
+ [:& cmm/asset-section {:file-id file-id
+ :title (tr "workspace.assets.graphics")
+ :section :graphics
+ :assets-count (count objects)
+ :open? open?}
+ (if new-css-system
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when (and (not components-v2) (not read-only?))
+ [:button {:class (dom/classnames (css :assets-btn) true)
+ :on-click add-graphic}
+ i/add-refactor
+ [:& file-uploader {:accept cm/str-image-types
+ :multi true
+ :ref input-ref
+ :on-selected on-file-selected}]])])
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when (and (not components-v2) (not read-only?))
+ [:div.assets-button {:on-click add-graphic}
+ i/plus
+ [:& file-uploader {:accept cm/str-image-types
+ :multi true
+ :ref input-ref
+ :on-selected on-file-selected}]])]))
+
+ [:& cmm/asset-section-block {:role :content}
+ [:& graphics-group {:file-id file-id
+ :prefix ""
+ :groups groups
+ :open-groups open-groups
+ :renaming (:renaming @state)
+ :listing-thumbs? listing-thumbs?
+ :selected selected
+ :on-asset-click on-asset-click
+ :on-drag-start on-drag-start
+ :do-rename do-rename
+ :cancel-rename cancel-rename
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]
+ (when local?
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options (if new-css-system
+ [(when-not (or multi-objects? multi-assets?)
+ {:option-name (tr "workspace.assets.rename")
+ :id "assets-rename-graphics"
+ :option-handler on-rename})
+ {:option-name (tr "workspace.assets.delete")
+ :id "assets-delete-graphics"
+ :option-handler on-delete}
+ (when-not multi-assets?
+ {:option-name (tr "workspace.assets.group")
+ :id "assets-group-graphics"
+ :option-handler on-group})]
+
+ [(when-not (or multi-objects? multi-assets?)
+ [(tr "workspace.assets.rename") on-rename])
+ [(tr "workspace.assets.delete") on-delete]
+ (when-not multi-assets?
+ [(tr "workspace.assets.group") on-group])])}])]]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.css.json
new file mode 100644
index 0000000000..0917c975f5
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_graphics_button-primary_6qIO6","button-secondary":"assets_graphics_button-secondary_0qkG4","button-tertiary":"assets_graphics_button-tertiary_bWZ1s","assets-btn":"assets_graphics_assets-btn_BIoeo","add-component":"assets_graphics_add-component_bgwrr","button-tag":"assets_graphics_button-tag_K3ckf","button-icon":"assets_graphics_button-icon_En5qq","button-icon-small":"assets_graphics_button-icon-small_xNHzC","asset-element":"assets_graphics_asset-element_-VwmF","graphics-group":"assets_graphics_graphics-group_kibPf","drop-space":"assets_graphics_drop-space_2UAKf","asset-grid":"assets_graphics_asset-grid_6ET0K","grid-cell":"assets_graphics_grid-cell_EHW4x","cell-name":"assets_graphics_cell-name_JgbUS","editing":"assets_graphics_editing_O-Ozt","editable-label-input":"assets_graphics_editable-label-input_Yc2zA","editable-label-close":"assets_graphics_editable-label-close_16VT8","selected":"assets_graphics_selected_Q9YJC","dragging":"assets_graphics_dragging_oVA41","asset-enum":"assets_graphics_asset-enum_TS6Je","enum-item":"assets_graphics_enum-item_UFh4c","item-name":"assets_graphics_item-name_HGIQs","grid-placeholder":"assets_graphics_grid-placeholder_9brkO","listing-options":"assets_graphics_listing-options_Jw51P","listing-option-btn":"assets_graphics_listing-option-btn_3IkTO","first":"assets_graphics_first_kU3zf"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss
new file mode 100644
index 0000000000..2ac0a04d8d
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/graphics.scss
@@ -0,0 +1,190 @@
+// 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";
+
+.graphics-group {
+ .drop-space {
+ height: $s-12;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ }
+ .asset-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: $s-4;
+ margin-left: $s-8;
+ margin-right: $s-12;
+ .grid-cell {
+ @include flexCenter;
+ position: relative;
+ padding: $s-8;
+ border: $s-2 solid transparent;
+ border-radius: $br-8;
+ aspect-ratio: 1/1;
+ background-color: var(--assets-item-background-color);
+ overflow: hidden;
+ cursor: pointer;
+ img {
+ height: auto;
+ width: auto;
+ max-height: 100%;
+ max-width: 100%;
+ pointer-events: none;
+ }
+ svg {
+ height: 10vh;
+ }
+ .cell-name {
+ @include titleTipography;
+ @include textEllipsis;
+ display: none;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ padding: $s-2;
+
+ &.editing {
+ display: block;
+ }
+
+ .editable-label-input {
+ height: unset;
+ width: 100%;
+ padding: $s-2;
+ margin: 0;
+ }
+
+ .editable-label-close {
+ display: none;
+ }
+ }
+
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ .cell-name {
+ display: block;
+ color: var(--assets-item-name-foreground-color-hover);
+ background: linear-gradient(to top, rgba(52, 57, 59, 1) 0%, rgba(52, 57, 59, 0) 100%);
+ }
+ }
+
+ &.selected {
+ border: $s-1 solid var(--assets-item-border-color);
+ }
+
+ .dragging {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: $s-8;
+ background-color: var(--assets-item-background-color-drag);
+ border: $s-2 solid var(--assets-item-border-color-drag);
+ }
+ }
+ }
+ .asset-enum {
+ margin: 0 $s-12;
+
+ .enum-item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ height: $s-36;
+ margin-bottom: $s-4;
+ padding: $s-2;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ cursor: pointer;
+
+ svg,
+ img {
+ @include flexCenter;
+ padding: $s-2;
+ height: $s-32;
+ width: $s-32;
+ border-radius: $br-6;
+ background-color: var(--assets-component-background-color);
+ }
+
+ .item-name {
+ @include titleTipography;
+ @include textEllipsis;
+ padding-left: $s-8;
+ color: var(--assets-item-name-foreground-color);
+
+ &.editing {
+ display: flex;
+ align-items: center;
+
+ .editable-label-input {
+ height: $s-24;
+ }
+
+ .editable-label-close {
+ display: none;
+ }
+ }
+ }
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ .item-name {
+ color: var(--assets-item-name-foreground-color-hover);
+ }
+ }
+ &.selected {
+ border: $s-1 solid var(--assets-item-border-color);
+ }
+ }
+ }
+ .grid-placeholder {
+ height: $s-2;
+ background-color: var(--color-accent-primary);
+ margin-bottom: $s-2;
+ }
+}
+.listing-options {
+ display: flex;
+ align-items: center;
+
+ .listing-option-btn {
+ @include flexCenter;
+ cursor: pointer;
+
+ &.first {
+ margin-left: auto;
+ }
+
+ svg {
+ height: $s-16;
+ width: $s-16;
+ }
+ }
+}
+.add-component {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: $s-28;
+ margin-left: $s-2;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+}
+
+.assets-btn {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: calc($s-24 + $s-4);
+ padding: 0;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs
new file mode 100644
index 0000000000..6f41143ac5
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.cljs
@@ -0,0 +1,171 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.workspace.sidebar.assets.groups
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.pages.helpers :as cph]
+ [app.common.spec :as us]
+ [app.main.data.modal :as modal]
+ [app.main.data.workspace :as dw]
+ [app.main.store :as st]
+ [app.main.ui.components.forms :as fm]
+ [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.assets.common :as cmm]
+ [app.util.dom :as dom]
+ [app.util.i18n :as i18n :refer [tr]]
+ [cljs.spec.alpha :as s]
+ [rumext.v2 :as mf]))
+
+(mf/defc asset-group-title
+ [{:keys [file-id section path group-open? on-rename on-ungroup]}]
+ (when-not (empty? path)
+ (let [[other-path last-path truncated] (cph/compact-path path 35 true)
+ menu-state (mf/use-state cmm/initial-context-menu-state)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ on-fold-group
+ (mf/use-fn
+ (mf/deps file-id section path group-open?)
+ (fn [event]
+ (dom/stop-propagation event)
+ (st/emit! (dw/set-assets-group-open file-id
+ section
+ path
+ (not group-open?)))))
+ on-context-menu
+ (mf/use-fn
+ (fn [event]
+ (dom/prevent-default event)
+ (let [pos (dom/get-client-position event)]
+ (swap! menu-state cmm/open-context-menu pos))))
+
+ on-close-menu
+ (mf/use-fn #(swap! menu-state cmm/close-context-menu))]
+ (if new-css-system
+ [:div {:class (dom/classnames (css :group-title) true)
+ :on-context-menu on-context-menu}
+ [:& title-bar {:collapsable? true
+ :collapsed? (not group-open?)
+ :on-collapsed on-fold-group
+ :title (mf/html [:* (when-not (empty? other-path)
+ [:span {:class (dom/classnames (css :pre-path) true)
+ :title (when truncated path)}
+ other-path "\u00A0\u2022\u00A0"])
+ [:span {:class (dom/classnames (css :path) true)
+ :title (when truncated path)}
+ last-path]])}]
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options [{:option-name (tr "workspace.assets.rename")
+ :id "assets-rename-group"
+ :option-handler #(on-rename % path last-path)}
+ {:option-name (tr "workspace.assets.ungroup")
+ :id "assets-ungroup-group"
+ :option-handler #(on-ungroup path)}]}]]
+
+
+ [:div.group-title {:class (when-not group-open? "closed")
+ :on-click on-fold-group
+ :on-context-menu on-context-menu}
+ [:span i/arrow-slide]
+ (when-not (empty? other-path)
+ [:span.dim {:title (when truncated path)}
+ other-path "\u00A0/\u00A0"])
+ [:span {:title (when truncated path)}
+ last-path]
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options [[(tr "workspace.assets.rename") #(on-rename % path last-path)]
+ [(tr "workspace.assets.ungroup") #(on-ungroup path)]]}]]))))
+
+(defn group-assets
+ "Convert a list of assets in a nested structure like this:
+
+ {'': [{assetA} {assetB}]
+ 'group1': {'': [{asset1A} {asset1B}]
+ 'subgroup11': {'': [{asset11A} {asset11B} {asset11C}]}
+ 'subgroup12': {'': [{asset12A}]}}
+ 'group2': {'subgroup21': {'': [{asset21A}}}}
+ "
+ [assets reverse-sort?]
+ (when-not (empty? assets)
+ (reduce (fn [groups {:keys [path] :as asset}]
+ (let [path (cph/split-path (or path ""))]
+ (update-in groups
+ (conj path "")
+ (fn [group]
+ (if group
+ (conj group asset)
+ [asset])))))
+ (sorted-map-by (fn [key1 key2]
+ (if reverse-sort?
+ (compare key2 key1)
+ (compare key1 key2))))
+ assets)))
+
+(s/def ::asset-name ::us/not-empty-string)
+(s/def ::name-group-form
+ (s/keys :req-un [::asset-name]))
+
+(mf/defc name-group-dialog
+ {::mf/register modal/components
+ ::mf/register-as :name-group-dialog}
+ [{:keys [path last-path accept] :as ctx
+ :or {path "" last-path ""}}]
+ (let [initial (mf/use-memo
+ (mf/deps last-path)
+ (constantly {:asset-name last-path}))
+ form (fm/use-form :spec ::name-group-form
+ :initial initial)
+
+ create? (empty? path)
+
+ on-close (mf/use-fn #(modal/hide!))
+
+ on-accept
+ (mf/use-fn
+ (mf/deps form)
+ (fn [_]
+ (let [asset-name (get-in @form [:clean-data :asset-name])]
+ (if create?
+ (accept asset-name)
+ (accept path asset-name))
+ (modal/hide!))))]
+
+ [:div.modal-overlay
+ [:div.modal-container.confirm-dialog
+ [:div.modal-header
+ [:div.modal-header-title
+ [:h2 (if create?
+ (tr "workspace.assets.create-group")
+ (tr "workspace.assets.rename-group"))]]
+ [:div.modal-close-button
+ {:on-click on-close} i/close]]
+
+ [:div.modal-content.generic-form
+ [:& fm/form {:form form :on-submit on-accept}
+ [:& fm/input {:name :asset-name
+ :auto-focus? true
+ :label (tr "workspace.assets.group-name")
+ :hint (tr "workspace.assets.create-group-hint")}]]]
+
+ [:div.modal-footer
+ [:div.action-buttons
+ [:input.cancel-button
+ {:type "button"
+ :value (tr "labels.cancel")
+ :on-click on-close}]
+
+ [:input.accept-button.primary
+ {:type "button"
+ :class (when-not (:valid @form) "btn-disabled")
+ :disabled (not (:valid @form))
+ :value (if create? (tr "labels.create") (tr "labels.rename"))
+ :on-click on-accept}]]]]]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.css.json
new file mode 100644
index 0000000000..c6166fbe30
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_groups_button-primary_2o3Db","button-secondary":"assets_groups_button-secondary_-qdxB","button-tertiary":"assets_groups_button-tertiary_1f4Jy","button-tag":"assets_groups_button-tag_yIgd9","button-icon":"assets_groups_button-icon_MSptS","button-icon-small":"assets_groups_button-icon-small_73Ir0","asset-element":"assets_groups_asset-element_RgKXH","group-title":"assets_groups_group-title_cV4AQ","pre-path":"assets_groups_pre-path_1rE71","path":"assets_groups_path_m0esc"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss
new file mode 100644
index 0000000000..5ba5138060
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/groups.scss
@@ -0,0 +1,19 @@
+// 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";
+
+.group-title {
+ padding-left: $s-16;
+ .pre-path {
+ text-transform: initial;
+ color: var(--title-foreground-color);
+ }
+ .path {
+ text-transform: initial;
+ color: var(--title-foreground-color-hover);
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs
new file mode 100644
index 0000000000..ab8da5c9aa
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs
@@ -0,0 +1,553 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) KALEIDOS INC
+
+(ns app.main.ui.workspace.sidebar.assets.typographies
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.common.pages.helpers :as cph]
+ [app.main.data.modal :as modal]
+ [app.main.data.workspace.libraries :as dwl]
+ [app.main.data.workspace.texts :as dwt]
+ [app.main.data.workspace.undo :as dwu]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.sidebar.assets.common :as cmm]
+ [app.main.ui.workspace.sidebar.assets.groups :as grp]
+ [app.main.ui.workspace.sidebar.options.menus.typography :refer [typography-entry]]
+ [app.util.dom :as dom]
+ [app.util.i18n :as i18n :refer [tr]]
+ [cuerdas.core :as str]
+ [okulary.core :as l]
+ [rumext.v2 :as mf]))
+
+(def lens:typography-section-state
+ (l/derived (fn [gstate]
+ {:rename-typography (:rename-typography gstate)
+ :edit-typography (:edit-typography gstate)})
+ refs/workspace-global
+ =))
+
+(mf/defc typography-item
+ {::mf/wrap-props false}
+ [{:keys [typography file-id local? handle-change selected apply-typography editing-id renaming-id on-asset-click
+ on-context-menu selected-full selected-paths move-typography rename?]}]
+ (let [item-ref (mf/use-ref)
+ typography-id (:id typography)
+
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ editing? (= editing-id (:id typography))
+ renaming? (= renaming-id (:id typography))
+
+ open* (mf/use-state editing?)
+ open? (deref open*)
+
+ on-drop
+ (mf/use-fn
+ (mf/deps typography dragging* selected selected-full selected-paths move-typography)
+ (fn [event]
+ (cmm/on-drop-asset event typography dragging* selected selected-full
+ selected-paths move-typography)))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps typography dragging* selected selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset event typography dragging* selected selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-typography-drag-start
+ (mf/use-fn
+ (mf/deps typography file-id selected item-ref read-only?)
+ (fn [event]
+ (if read-only?
+ (dom/prevent-default event)
+ (cmm/on-asset-drag-start event file-id typography selected item-ref :typographies identity))))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps on-context-menu typography-id)
+ (partial on-context-menu typography-id))
+
+ handle-change
+ (mf/use-fn
+ (mf/deps typography)
+ (partial handle-change typography))
+
+ apply-typography
+ (mf/use-fn
+ (mf/deps typography)
+ (partial apply-typography typography))
+
+ on-asset-click
+ (mf/use-fn
+ (mf/deps typography apply-typography on-asset-click)
+ (partial on-asset-click typography-id apply-typography))]
+
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :typography-item) true)
+ :ref item-ref
+ :draggable (and (not read-only?) (not open?))
+ :on-drag-start on-typography-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& typography-entry
+ {:typography typography
+ :local? local?
+ :on-context-menu on-context-menu
+ :on-change handle-change
+ :selected? (contains? selected typography-id)
+ :on-click on-asset-click
+ :editing? editing?
+ :renaming? renaming?
+ :focus-name? rename?
+ :external-open* open*
+ :file-id file-id}]
+
+ (when ^boolean dragging?
+ [:div {:class (dom/classnames (css :dragging) true)}])]
+
+ [:div.typography-container {:ref item-ref
+ :draggable (and (not read-only?) (not open?))
+ :on-drag-start on-typography-drag-start
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& typography-entry
+ {:typography typography
+ :local? local?
+ :on-context-menu on-context-menu
+ :on-change handle-change
+ :selected? (contains? selected typography-id)
+ :on-click on-asset-click
+ :editing? editing?
+ :focus-name? rename?
+ :external-open* open*
+ :file-id file-id}]
+
+ (when ^boolean dragging?
+ [:div.dragging])])))
+
+(mf/defc typographies-group
+ {::mf/wrap-props false}
+ [{:keys [file-id prefix groups open-groups file local? selected local-data
+ editing-id renaming-id on-asset-click handle-change apply-typography on-rename-group
+ on-ungroup on-context-menu selected-full]}]
+ (let [group-open? (get open-groups prefix true)
+ dragging* (mf/use-state false)
+ dragging? (deref dragging*)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ selected-paths (mf/with-memo [selected-full]
+ (into #{}
+ (comp (map :path) (d/nilv ""))
+ selected-full))
+ move-typography
+ (mf/use-fn
+ (mf/deps file-id)
+ (partial dwl/rename-typography file-id))
+
+ on-drag-enter
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths)
+ (fn [event]
+ (cmm/on-drag-enter-asset-group event dragging* prefix selected-paths)))
+
+ on-drag-leave
+ (mf/use-fn
+ (mf/deps dragging*)
+ (fn [event]
+ (cmm/on-drag-leave-asset event dragging*)))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps dragging* prefix selected-paths selected-full move-typography)
+ (fn [event]
+ (cmm/on-drop-asset-group event dragging* prefix selected-paths selected-full move-typography)))]
+
+ (if ^boolean new-css-system
+ [:div {:class (dom/classnames (css :typographies-group) true)
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title {:file-id file-id
+ :section :typographies
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+
+ (when group-open?
+ [:*
+ (let [typographies (get groups "" [])]
+ [:div {:class (dom/classnames (css :assets-list) true)
+ :on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div {:class (css :grid-placeholder)} "\u00A0"])
+
+ (when (and
+ (empty? typographies)
+ (some? groups))
+ [:div {:class (css :drop-space)}])
+ (for [{:keys [id] :as typography} typographies]
+ [:& typography-item {:typography typography
+ :key (dm/str "typography-" id)
+ :file-id file-id
+ :local? local?
+ :handle-change handle-change
+ :selected selected
+ :apply-typography apply-typography
+ :editing-id editing-id
+ :renaming-id renaming-id
+ :rename? (= (:rename-typography local-data) id)
+ :on-asset-click on-asset-click
+ :on-context-menu on-context-menu
+ :selected-full selected-full
+ :selected-paths selected-paths
+ :move-typography move-typography}])])
+
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& typographies-group {:file-id file-id
+ :prefix (cph/merge-path-item prefix path-item)
+ :key (dm/str "group-" path-item)
+ :groups content
+ :open-groups open-groups
+ :file file
+ :local? local?
+ :selected selected
+ :editing-id editing-id
+ :renaming-id renaming-id
+ :local-data local-data
+ :on-asset-click on-asset-click
+ :handle-change handle-change
+ :apply-typography apply-typography
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]))])]
+ [:div {:on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+ [:& grp/asset-group-title {:file-id file-id
+ :section :typographies
+ :path prefix
+ :group-open? group-open?
+ :on-rename on-rename-group
+ :on-ungroup on-ungroup}]
+ (when group-open?
+ [:*
+ (let [typographies (get groups "" [])]
+ [:div.asset-list {:on-drag-enter on-drag-enter
+ :on-drag-leave on-drag-leave
+ :on-drag-over dom/prevent-default
+ :on-drop on-drop}
+
+ (when ^boolean dragging?
+ [:div.grid-placeholder "\u00A0"])
+
+ (when (and
+ (empty? typographies)
+ (some? groups))
+ [:div.drop-space])
+ (for [{:keys [id] :as typography} typographies]
+ [:& typography-item {:typography typography
+ :key (dm/str "typography-" id)
+ :file-id file-id
+ :local? local?
+ :handle-change handle-change
+ :selected selected
+ :apply-typography apply-typography
+ :editing-id editing-id
+ :rename? (= (:rename-typography local-data) id)
+ :on-asset-click on-asset-click
+ :on-context-menu on-context-menu
+ :selected-full selected-full
+ :selected-paths selected-paths
+ :move-typography move-typography}])])
+
+ (for [[path-item content] groups]
+ (when-not (empty? path-item)
+ [:& typographies-group {:file-id file-id
+ :prefix (cph/merge-path-item prefix path-item)
+ :key (dm/str "group-" path-item)
+ :groups content
+ :open-groups open-groups
+ :file file
+ :local? local?
+ :selected selected
+ :editing-id editing-id
+ :local-data local-data
+ :on-asset-click on-asset-click
+ :handle-change handle-change
+ :apply-typography apply-typography
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]))])])))
+
+(mf/defc typographies-section
+ {::mf/wrap-props false}
+ [{:keys [file file-id local? typographies open? open-status-ref selected reverse-sort?
+ on-asset-click on-assets-delete on-clear-selection]}]
+ (let [state (mf/use-state {:detail-open? false :id nil})
+ local-data (mf/deref lens:typography-section-state)
+
+ read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ menu-state (mf/use-state cmm/initial-context-menu-state)
+ typographies (mf/with-memo [typographies]
+ (mapv dwl/extract-path-if-missing typographies))
+
+ groups (mf/with-memo [typographies reverse-sort?]
+ (grp/group-assets typographies reverse-sort?))
+
+ selected (:typographies selected)
+ selected-full (mf/with-memo [selected typographies]
+ (into #{} (filter #(contains? selected (:id %))) typographies))
+
+ multi-typographies? (> (count selected) 1)
+ multi-assets? (or (seq (:components selected))
+ (seq (:graphics selected))
+ (seq (:colors selected)))
+
+ open-groups-ref (mf/with-memo [open-status-ref]
+ (-> (l/in [:groups :typographies])
+ (l/derived open-status-ref)))
+
+ open-groups (mf/deref open-groups-ref)
+
+ add-typography
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn [_]
+ (st/emit! (dwt/add-typography file-id))))
+
+ handle-change
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn [typography changes]
+ (st/emit! (dwl/update-typography (merge typography changes) file-id))))
+
+ apply-typography
+ (mf/use-fn
+ (mf/deps file-id)
+ (fn [typography _event]
+ (st/emit! (dwt/apply-typography typography file-id))))
+
+ create-group
+ (mf/use-fn
+ (mf/deps typographies selected on-clear-selection file-id (:id @state))
+ (fn [group-name]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> typographies
+ (filter #(if multi-typographies?
+ (contains? selected (:id %))
+ (= (:id @state) (:id %))))
+ (map #(dwl/update-typography
+ (assoc % :name
+ (cmm/add-group % group-name))
+ file-id))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ rename-group
+ (mf/use-fn
+ (mf/deps typographies)
+ (fn [path last-path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (run! st/emit!
+ (->> typographies
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/update-typography
+ (assoc % :name
+ (cmm/rename-group % path last-path))
+ file-id))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-group
+ (mf/use-fn
+ (mf/deps typographies selected create-group)
+ (fn [event]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:accept create-group})))
+
+ on-rename-group
+ (mf/use-fn
+ (mf/deps typographies)
+ (fn [event path last-path]
+ (dom/stop-propagation event)
+ (modal/show! :name-group-dialog {:path path
+ :last-path last-path
+ :accept rename-group})))
+ on-ungroup
+ (mf/use-fn
+ (mf/deps typographies)
+ (fn [path]
+ (on-clear-selection)
+ (let [undo-id (js/Symbol)]
+ (st/emit! (dwu/start-undo-transaction undo-id))
+ (apply st/emit!
+ (->> typographies
+ (filter #(str/starts-with? (:path %) path))
+ (map #(dwl/rename-typography
+ file-id
+ (:id %)
+ (cmm/ungroup % path)))))
+ (st/emit! (dwu/commit-undo-transaction undo-id)))))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps selected on-clear-selection read-only?)
+ (fn [id event]
+ (dom/prevent-default event)
+ (let [pos (dom/get-client-position event)]
+ (when (and local? (not read-only?))
+ (when-not (contains? selected id)
+ (on-clear-selection))
+ (swap! state assoc :id id)
+ (swap! menu-state cmm/open-context-menu pos)))))
+
+ on-close-menu
+ (mf/use-fn
+ (fn []
+ (swap! menu-state cmm/close-context-menu)))
+
+ handle-rename-typography-clicked
+ (fn []
+ (st/emit! #(assoc-in % [:workspace-global :rename-typography] (:id @state))))
+
+ handle-edit-typography-clicked
+ (fn []
+ (st/emit! #(assoc-in % [:workspace-global :edit-typography] (:id @state))))
+
+ handle-delete-typography
+ (mf/use-fn
+ (mf/deps @state multi-typographies? multi-assets?)
+ (fn []
+ (let [undo-id (js/Symbol)]
+ (if (or multi-typographies? multi-assets?)
+ (on-assets-delete)
+ (st/emit! (dwu/start-undo-transaction undo-id)
+ (dwl/delete-typography (:id @state))
+ (dwl/sync-file file-id file-id :typographies (:id @state))
+ (dwu/commit-undo-transaction undo-id))))))
+
+ editing-id (if new-css-system
+ (:edit-typography local-data)
+ (or (:rename-typography local-data)
+ (:edit-typography local-data)))
+
+ renaming-id (:rename-typography local-data)
+
+ on-asset-click
+ (mf/use-fn
+ (mf/deps groups on-asset-click)
+ (partial on-asset-click groups))]
+
+ (mf/use-effect
+ (mf/deps local-data new-css-system)
+ (fn []
+ (when (and (not new-css-system)(:rename-typography local-data))
+ (st/emit! #(update % :workspace-global dissoc :rename-typography)))
+ (when (:edit-typography local-data)
+ (st/emit! #(update % :workspace-global dissoc :edit-typography)))))
+
+ [:& cmm/asset-section {:file-id file-id
+ :title (tr "workspace.assets.typography")
+ :section :typographies
+ :assets-count (count typographies)
+ :open? open?}
+ (if ^boolean new-css-system
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when-not read-only?
+ [:button {:class (dom/classnames (css :assets-btn) true)
+ :on-click add-typography}
+ i/add-refactor])])
+
+ (when local?
+ [:& cmm/asset-section-block {:role :title-button}
+ (when-not read-only?
+ [:div.assets-button {:on-click add-typography}
+ i/plus])]))
+
+ [:& cmm/asset-section-block {:role :content}
+ [:& typographies-group {:file-id file-id
+ :prefix ""
+ :groups groups
+ :open-groups open-groups
+ :state state
+ :file file
+ :local? local?
+ :selected selected
+ :editing-id editing-id
+ :renaming-id renaming-id
+ :local-data local-data
+ :on-asset-click on-asset-click
+ :handle-change handle-change
+ :apply-typography apply-typography
+ :on-rename-group on-rename-group
+ :on-ungroup on-ungroup
+ :on-context-menu on-context-menu
+ :selected-full selected-full}]
+
+ (when local?
+ [:& cmm/assets-context-menu
+ {:on-close on-close-menu
+ :state @menu-state
+ :options (if new-css-system
+ [(when-not (or multi-typographies? multi-assets?)
+ {:option-name (tr "workspace.assets.rename")
+ :id "assets-rename-typography"
+ :option-handler handle-rename-typography-clicked})
+
+ (when-not (or multi-typographies? multi-assets?)
+ {:option-name (tr "workspace.assets.edit")
+ :id "assets-edit-typography"
+ :option-handler handle-edit-typography-clicked})
+
+ {:option-name (tr "workspace.assets.delete")
+ :id "assets-delete-typography"
+ :option-handler handle-delete-typography}
+
+ (when-not multi-assets?
+ {:option-name (tr "workspace.assets.group")
+ :id "assets-group-typography"
+ :option-handler on-group})]
+
+
+ [(when-not (or multi-typographies? multi-assets?)
+ [(tr "workspace.assets.rename") handle-rename-typography-clicked])
+ (when-not (or multi-typographies? multi-assets?)
+ [(tr "workspace.assets.edit") handle-edit-typography-clicked])
+ [(tr "workspace.assets.delete") handle-delete-typography]
+ (when-not multi-assets?
+ [(tr "workspace.assets.group") on-group])])}])]]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.css.json b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.css.json
new file mode 100644
index 0000000000..569ecc8249
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.css.json
@@ -0,0 +1 @@
+{"button-primary":"assets_typographies_button-primary_njVYq","button-secondary":"assets_typographies_button-secondary_Wzmmw","button-tertiary":"assets_typographies_button-tertiary_k3V5a","assets-btn":"assets_typographies_assets-btn_wCF-m","button-tag":"assets_typographies_button-tag_grTbB","button-icon":"assets_typographies_button-icon_7peoi","button-icon-small":"assets_typographies_button-icon-small_oHD9w","asset-element":"assets_typographies_asset-element_hvNzY","typographies-group":"assets_typographies_typographies-group_iCR4V","assets-list":"assets_typographies_assets-list_wS3At","drop-space":"assets_typographies_drop-space_kGrjB","grid-placeholder":"assets_typographies_grid-placeholder_FvcCI","typography-item":"assets_typographies_typography-item_qkADe","dragging":"assets_typographies_dragging_Ns4o7"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.scss
new file mode 100644
index 0000000000..6feea36ab2
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.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";
+
+.assets-btn {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: calc($s-24 + $s-4);
+ padding: 0;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ }
+}
+.typographies-group {
+ .assets-list {
+ padding: 0 0 0 $s-12;
+ .drop-space {
+ height: $s-12;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ }
+ .grid-placeholder {
+ height: $s-2;
+ width: 100%;
+ background-color: var(--color-accent-primary);
+ }
+ .typography-item {
+ position: relative;
+ display: flex;
+ align-items: center;
+ margin-bottom: $s-4;
+ border-radius: $br-8;
+ background-color: var(--assets-item-background-color);
+ }
+ .dragging {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ border: $s-2 solid var(--assets-item-border-color-drag);
+ border-radius: $s-8;
+ background-color: var(--assets-item-background-color-drag);
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs
index 86ef4cf188..e266382237 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.cljs
@@ -18,9 +18,9 @@
(mf/defc collapsed-button
{::mf/wrap-props false}
[]
- (let [new-css? (mf/use-ctx ctx/new-css-system)
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))]
- (if ^boolean new-css?
+ (if ^boolean new-css-system
[:div {:class (dom/classnames (css :collapsed-sidebar) true)}
[:div {:class (dom/classnames (css :collapsed-title) true)}
[:button {:class (dom/classnames (css :collapsed-button) true)
diff --git a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.css.json b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.css.json
index e4c9e7e0a4..a3399ec491 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button.css.json
@@ -1 +1 @@
-{"button-primary":"sidebar_collapsable_button_button-primary_qaRce","button-secondary":"sidebar_collapsable_button_button-secondary_OqDpe","button-icon":"sidebar_collapsable_button_button-icon_P4-xy","button-icon-small":"sidebar_collapsable_button_button-icon-small_lQUE3","collapsed-sidebar":"sidebar_collapsable_button_collapsed-sidebar_uQnGJ","collapsed-title":"sidebar_collapsable_button_collapsed-title_Jb62g","collapsed-button":"sidebar_collapsable_button_collapsed-button_LT5ME"}
\ No newline at end of file
+{"button-primary":"sidebar_collapsable_button_button-primary_qaRce","button-secondary":"sidebar_collapsable_button_button-secondary_OqDpe","button-tertiary":"sidebar_collapsable_button_button-tertiary_NuJrA","button-tag":"sidebar_collapsable_button_button-tag_unQKq","button-icon":"sidebar_collapsable_button_button-icon_P4-xy","button-icon-small":"sidebar_collapsable_button_button-icon-small_lQUE3","asset-element":"sidebar_collapsable_button_asset-element_BboJ7","collapsed-sidebar":"sidebar_collapsable_button_collapsed-sidebar_uQnGJ","collapsed-title":"sidebar_collapsable_button_collapsed-title_Jb62g","collapsed-button":"sidebar_collapsable_button_collapsed-button_LT5ME"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_item.css.json b/frontend/src/app/main/ui/workspace/sidebar/layer_item.css.json
index 96e75da537..3b0b58bf05 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layer_item.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar/layer_item.css.json
@@ -1 +1 @@
-{"button-primary":"sidebar_layer_item_button-primary_74ST4","button-secondary":"sidebar_layer_item_button-secondary_e4u9V","button-icon":"sidebar_layer_item_button-icon_-D7KH","button-icon-small":"sidebar_layer_item_button-icon-small_1RfDl","layer-row":"sidebar_layer_item_layer-row_KibLX","element-list-body":"sidebar_layer_item_element-list-body_832JO","element-actions":"sidebar_layer_item_element-actions_ACGJI","toggle-element":"sidebar_layer_item_toggle-element_4bhRW","block-element":"sidebar_layer_item_block-element_RhKz-","button-content":"sidebar_layer_item_button-content_bPwop","icon-shape":"sidebar_layer_item_icon-shape_g9Wxn","toggle-content":"sidebar_layer_item_toggle-content_MKhsv","filtered":"sidebar_layer_item_filtered_V5CHf","inverse":"sidebar_layer_item_inverse_zzZ54","absolute":"sidebar_layer_item_absolute_mYIKg","selected":"sidebar_layer_item_selected_O7P-j","element-children":"sidebar_layer_item_element-children_3iA4Q","parent-selected":"sidebar_layer_item_parent-selected_uIIyQ","hidden":"sidebar_layer_item_hidden_JRbJO","type-comp":"sidebar_layer_item_type-comp_FBSRt","tab-indentation":"sidebar_layer_item_tab-indentation_e-2dQ"}
\ No newline at end of file
+{"button-primary":"sidebar_layer_item_button-primary_74ST4","button-secondary":"sidebar_layer_item_button-secondary_e4u9V","button-tertiary":"sidebar_layer_item_button-tertiary_Mo--6","button-tag":"sidebar_layer_item_button-tag_lFKoD","button-icon":"sidebar_layer_item_button-icon_-D7KH","button-icon-small":"sidebar_layer_item_button-icon-small_1RfDl","layer-row":"sidebar_layer_item_layer-row_KibLX","element-list-body":"sidebar_layer_item_element-list-body_832JO","element-actions":"sidebar_layer_item_element-actions_ACGJI","toggle-element":"sidebar_layer_item_toggle-element_4bhRW","block-element":"sidebar_layer_item_block-element_RhKz-","button-content":"sidebar_layer_item_button-content_bPwop","icon-shape":"sidebar_layer_item_icon-shape_g9Wxn","toggle-content":"sidebar_layer_item_toggle-content_MKhsv","asset-element":"sidebar_layer_item_asset-element_AXTD0","filtered":"sidebar_layer_item_filtered_V5CHf","inverse":"sidebar_layer_item_inverse_zzZ54","absolute":"sidebar_layer_item_absolute_mYIKg","selected":"sidebar_layer_item_selected_O7P-j","element-children":"sidebar_layer_item_element-children_3iA4Q","parent-selected":"sidebar_layer_item_parent-selected_uIIyQ","hidden":"sidebar_layer_item_hidden_JRbJO","type-comp":"sidebar_layer_item_type-comp_FBSRt","tab-indentation":"sidebar_layer_item_tab-indentation_e-2dQ"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_name.css.json b/frontend/src/app/main/ui/workspace/sidebar/layer_name.css.json
index 40f1367aaf..4e8c50d740 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layer_name.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar/layer_name.css.json
@@ -1 +1 @@
-{"button-primary":"sidebar_layer_name_button-primary_V-6Cp","button-secondary":"sidebar_layer_name_button-secondary_Q14Qj","button-icon":"sidebar_layer_name_button-icon_UQXjw","button-icon-small":"sidebar_layer_name_button-icon-small_At5P8","element-name":"sidebar_layer_name_element-name_hZ-lA","selected":"sidebar_layer_name_selected_MKxdm","type-comp":"sidebar_layer_name_type-comp_TNGM-","hidden":"sidebar_layer_name_hidden_e-K3G","element-name-input":"sidebar_layer_name_element-name-input_Wpnkf"}
\ No newline at end of file
+{"button-primary":"sidebar_layer_name_button-primary_V-6Cp","button-secondary":"sidebar_layer_name_button-secondary_Q14Qj","button-tertiary":"sidebar_layer_name_button-tertiary_dA-v0","button-tag":"sidebar_layer_name_button-tag_fr2K0","button-icon":"sidebar_layer_name_button-icon_UQXjw","button-icon-small":"sidebar_layer_name_button-icon-small_At5P8","asset-element":"sidebar_layer_name_asset-element_WVekz","element-name":"sidebar_layer_name_element-name_hZ-lA","selected":"sidebar_layer_name_selected_MKxdm","type-comp":"sidebar_layer_name_type-comp_TNGM-","hidden":"sidebar_layer_name_hidden_e-K3G","element-name-input":"sidebar_layer_name_element-name-input_Wpnkf"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss b/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss
index 8e6ede5708..c7f95086e7 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/layer_name.scss
@@ -28,6 +28,7 @@
.element-name-input {
@include textEllipsis;
@include titleTipography;
+ @include removeInputStyle;
flex-grow: 1;
height: $s-28;
max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
@@ -35,7 +36,5 @@
padding-left: $s-6;
border-radius: $br-8;
border: 1px solid var(--input-border-color-focus);
- outline: none;
- background-color: transparent;
color: var(--layer-row-foreground-color);
}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
index d5682b96da..99f24fe23b 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
@@ -13,7 +13,9 @@
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
+ [app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.components.shape-icon-refactor :as sic]
+ [app.main.ui.components.title-bar :refer [title-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
@@ -128,9 +130,14 @@
(swap! filter-state assoc :search-text "" :num-items 100)))
update-search-text
- (mf/use-callback
+ (mf/use-fn
+ (mf/deps new-css-system)
(fn [event]
- (let [value (-> event dom/get-target dom/get-value)]
+ ;; NOTE: When old-css-system is removed this function will recibe value and event
+ ;; Let won't be necessary any more
+ (let [value (if new-css-system
+ event
+ (dom/get-target-val event))]
(swap! filter-state assoc :search-text value :num-items 100))))
toggle-search
@@ -226,12 +233,9 @@
(fn [event]
(let [enter? (kbd/enter? event)
esc? (kbd/esc? event)
- input-node (dom/event->target event)]
-
- (when enter?
- (dom/blur! input-node))
- (when esc?
- (dom/blur! input-node)))))]
+ node (dom/event->target event)]
+ (when ^boolean enter? (dom/blur! node))
+ (when ^boolean esc? (dom/blur! node)))))]
[filtered-objects
handle-show-more
@@ -243,33 +247,33 @@
(css :search) true)
(dom/classnames :tool-window-bar true
:search true))}
- [:span {:class (if new-css-system
- (dom/classnames (css :search-box) true)
- (dom/classnames :search-box true))}
- [:button
- {:on-click toggle-filters
- :class (if new-css-system
- (dom/classnames :active active?
- (css :filter-button) true)
- (dom/classnames :active active?
- :filter true))}
- (if new-css-system
- i/filter-refactor
- i/icon-filter)]
- [:div {:class (dom/classnames (css :search-input-wrapper) new-css-system)}
- [:input {:on-change update-search-text
- :value (:search-text @filter-state)
- :auto-focus (:show-search-box @filter-state)
- :placeholder (tr "workspace.sidebar.layers.search")
- :on-key-down handle-key-down}]
- (when (not (= "" (:search-text @filter-state)))
- [:button {:class (if new-css-system
- (dom/classnames (css :clear) true)
- (dom/classnames :clear true))
- :on-click clear-search-text}
- (if new-css-system
- i/delete-text-refactor
- i/exclude)])]]
+ (if new-css-system
+ [:& search-bar
+ {:on-change update-search-text
+ :value (:search-text @filter-state)
+ :on-clear clear-search-text
+ :placeholder (tr "workspace.sidebar.layers.search")}
+ [:button
+ {:on-click toggle-filters
+ :class (dom/classnames :active active?
+ (css :filter-button) true)}
+ i/filter-refactor]]
+
+ [:span.search-box
+ [:button.filter
+ {:on-click toggle-filters
+ :class (dom/classnames :active active?)}
+ i/icon-filter]
+ [:div
+ [:input {:on-change update-search-text
+ :value (:search-text @filter-state)
+ :auto-focus (:show-search-box @filter-state)
+ :placeholder (tr "workspace.sidebar.layers.search")
+ :on-key-down handle-key-down}]
+ (when (not (= "" (:search-text @filter-state)))
+ [:button.clear {:on-click clear-search-text}
+ i/exclude])]])
+
[:button {:class (dom/classnames (css :close-search) new-css-system)
:on-click toggle-search}
(if new-css-system
@@ -397,20 +401,18 @@
[:span {:on-click (add-filter :text)} i/text (tr "workspace.sidebar.layers.texts")]
[:span {:on-click (add-filter :image)} i/image (tr "workspace.sidebar.layers.images")]
[:span {:on-click (add-filter :shape)} i/curve (tr "workspace.sidebar.layers.shapes")]]))]
- [:div {:class (if new-css-system
- (dom/classnames (css :tool-window-bar) true)
- (dom/classnames :tool-window-bar true))}
- [:span {:class (if new-css-system
- (dom/classnames (css :page-name) true)
- (dom/classnames :page-name true))}
- (:name page)]
- [:button {:class (if new-css-system
- (dom/classnames (css :icon-search) true)
- (dom/classnames :icon-search true))
- :on-click toggle-search}
- (if new-css-system
- i/search-refactor
- i/search)]]))]))
+
+ (if new-css-system
+ [:div {:class (dom/classnames (css :tool-window-bar) true)}
+ [:& title-bar {:collapsable? false
+ :title (:name page)
+ :on-btn-click toggle-search
+ :btn-children i/search-refactor}]]
+ [:div.tool-window-bar
+ [:span.page-name
+ (:name page)]
+ [:button.icon-search {:on-click toggle-search}
+ i/search]])))]))
(mf/defc layers-toolbox
{:wrap [mf/memo]}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.css.json b/frontend/src/app/main/ui/workspace/sidebar/layers.css.json
index f9c4de1291..ac87f734c4 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layers.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers.css.json
@@ -1 +1 @@
-{"button-primary":"sidebar_layers_button-primary_q9e2I","layers":"sidebar_layers_layers_87ZOo","tool-window-bar":"sidebar_layers_tool-window-bar_lg54C","search":"sidebar_layers_search_zjs2x","close-search":"sidebar_layers_close-search_baIhK","icon-search":"sidebar_layers_icon-search_6kWUn","button-secondary":"sidebar_layers_button-secondary_H4lpi","active-filters":"sidebar_layers_active-filters_-JMMP","layer-filter":"sidebar_layers_layer-filter_rHZTz","search-box":"sidebar_layers_search-box_JtqOV","search-input-wrapper":"sidebar_layers_search-input-wrapper_oJa-7","clear":"sidebar_layers_clear_sLcl1","button-icon":"sidebar_layers_button-icon_SD8PP","button-icon-small":"sidebar_layers_button-icon-small_v5L-u","filters-container":"sidebar_layers_filters-container_c1Ux9","filter-menu-item":"sidebar_layers_filter-menu-item_aZd0D","filter-menu-item-tick":"sidebar_layers_filter-menu-item-tick_JNdIK","filter-menu-item-name-wrapper":"sidebar_layers_filter-menu-item-name-wrapper_DtGkH","filter-menu-item-icon":"sidebar_layers_filter-menu-item-icon_Oi3Ix","layer-filter-icon":"sidebar_layers_layer-filter-icon_0yKrb","layer-filter-close":"sidebar_layers_layer-filter-close_3mV4i","focus-title":"sidebar_layers_focus-title_35PvQ","back-button-icon":"sidebar_layers_back-button-icon_mHv6g","page-name":"sidebar_layers_page-name_8ZDRR","filter-button":"sidebar_layers_filter-button_KXxHh","focus-name":"sidebar_layers_focus-name_Fderf","focus-mode-tag-wrapper":"sidebar_layers_focus-mode-tag-wrapper_OHXCG","focus-mode-tag":"sidebar_layers_focus-mode-tag_J5ItD","layer-filter-name":"sidebar_layers_layer-filter-name_Y4PuB","filter-menu-item-name":"sidebar_layers_filter-menu-item-name_rxeut","selected":"sidebar_layers_selected_V5Vv3","tool-window-content":"sidebar_layers_tool-window-content_YnpDB","element-list":"sidebar_layers_element-list_nAntB"}
\ No newline at end of file
+{"button-primary":"sidebar_layers_button-primary_q9e2I","button-secondary":"sidebar_layers_button-secondary_H4lpi","button-tertiary":"sidebar_layers_button-tertiary_5mq-9","layers":"sidebar_layers_layers_87ZOo","tool-window-bar":"sidebar_layers_tool-window-bar_lg54C","search":"sidebar_layers_search_zjs2x","close-search":"sidebar_layers_close-search_baIhK","icon-search":"sidebar_layers_icon-search_6kWUn","button-tag":"sidebar_layers_button-tag_FT7oa","active-filters":"sidebar_layers_active-filters_-JMMP","layer-filter":"sidebar_layers_layer-filter_rHZTz","button-icon":"sidebar_layers_button-icon_SD8PP","button-icon-small":"sidebar_layers_button-icon-small_v5L-u","filters-container":"sidebar_layers_filters-container_c1Ux9","filter-menu-item":"sidebar_layers_filter-menu-item_aZd0D","filter-menu-item-tick":"sidebar_layers_filter-menu-item-tick_JNdIK","filter-menu-item-name-wrapper":"sidebar_layers_filter-menu-item-name-wrapper_DtGkH","filter-menu-item-icon":"sidebar_layers_filter-menu-item-icon_Oi3Ix","layer-filter-icon":"sidebar_layers_layer-filter-icon_0yKrb","layer-filter-close":"sidebar_layers_layer-filter-close_3mV4i","focus-title":"sidebar_layers_focus-title_35PvQ","back-button-icon":"sidebar_layers_back-button-icon_mHv6g","asset-element":"sidebar_layers_asset-element_-dbA7","page-name":"sidebar_layers_page-name_8ZDRR","filter-button":"sidebar_layers_filter-button_KXxHh","focus-name":"sidebar_layers_focus-name_Fderf","focus-mode-tag-wrapper":"sidebar_layers_focus-mode-tag-wrapper_OHXCG","focus-mode-tag":"sidebar_layers_focus-mode-tag_J5ItD","layer-filter-name":"sidebar_layers_layer-filter-name_Y4PuB","filter-menu-item-name":"sidebar_layers_filter-menu-item-name_rxeut","selected":"sidebar_layers_selected_V5Vv3","tool-window-content":"sidebar_layers_tool-window-content_YnpDB","element-list":"sidebar_layers_element-list_nAntB"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.scss b/frontend/src/app/main/ui/workspace/sidebar/layers.scss
index 34f76f5740..8d00a150b9 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/layers.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers.scss
@@ -20,13 +20,14 @@
min-height: $s-32;
margin-top: $s-2;
margin-bottom: $s-4;
+ padding-right: $s-8;
.page-name {
@include tabTitleTipography;
padding: 0 $s-12;
color: var(--title-foreground-color);
}
.icon-search {
- @extend .button-primary;
+ @extend .button-tertiary;
height: $s-32;
width: calc($s-24 + $s-4);
border-radius: $br-8;
@@ -38,94 +39,41 @@
}
&.search {
padding: 0 $s-8 0 $s-12;
- .search-box {
- display: grid;
- grid-template-columns: auto 1fr;
- gap: $s-2;
+ gap: $s-4;
+ .filter-button {
+ @include flexCenter;
+ @include buttonStyle;
height: $s-32;
- width: 100%;
- margin-right: $s-4;
- border-radius: $br-8;
- background-color: var(--color-background-primary);
- .filter-button {
- @include flexCenter;
- @include buttonStyle;
- height: $s-32;
- width: $s-32;
- margin: 0;
- border: 1px solid var(--color-background-tertiary);
- border-radius: $br-8 $br-2 $br-2 $br-8;
- background-color: var(--color-background-tertiary);
+ width: $s-32;
+ margin: 0;
+ border: 1px solid var(--color-background-tertiary);
+ border-radius: $br-8 $br-2 $br-2 $br-8;
+ background-color: var(--color-background-tertiary);
+ svg {
+ height: $s-16;
+ width: $s-16;
+ stroke: var(--icon-foreground);
+ }
+ &:focus {
+ border: 1px solid var(--input-border-color-focus);
+ outline: 0;
+ background-color: var(--input-background-color-active);
+ color: var(--input-foreground-color-active);
svg {
- height: $s-16;
- width: $s-16;
- stroke: var(--icon-foreground);
- }
- &:focus {
- border: 1px solid var(--input-border-color-focus);
- outline: 0;
background-color: var(--input-background-color-active);
- color: var(--input-foreground-color-active);
- svg {
- background-color: var(--input-background-color-active);
- }
- }
- &:hover {
- border: 1px solid var(--input-background-color-hover);
- background-color: var(--input-background-color-hover);
- svg {
- background-color: var(--input-background-color-hover);
- stroke: var(--button-foreground-hover);
- }
}
}
- .search-input-wrapper {
- @include flexCenter;
- height: $s-32;
- width: 100%;
- border: 1px solid var(--color-background-tertiary);
- border-radius: $br-2 $br-8 $br-8 $br-2;
- background-color: var(--color-background-tertiary);
- input {
- width: 100%;
- margin: $s-8;
- border: 0;
- background-color: var(--input-background-color);
- font-size: $fs-12;
- color: var(--input-foreground-color);
- &:focus {
- outline: none;
- }
- }
- &:hover {
- border: 1px solid var(--input-background-color-hover);
+ &:hover {
+ border: 1px solid var(--input-background-color-hover);
+ background-color: var(--input-background-color-hover);
+ svg {
background-color: var(--input-background-color-hover);
- input {
- background-color: var(--input-background-color-hover);
- }
- }
- &:focus-within {
- background-color: var(--input-background-color-active);
- color: var(--input-foreground-color-active);
- border: 1px solid var(--input-border-color-focus);
- input {
- background-color: var(--input-background-color-active);
- }
- }
-
- .clear {
- @extend .button-secondary;
- border-radius: $br-8;
- height: 100%;
- svg {
- @extend .button-icon-small;
- color: transparent;
- }
+ stroke: var(--button-foreground-hover);
}
}
}
.close-search {
- @extend .button-primary;
+ @extend .button-tertiary;
height: $s-32;
width: $s-28;
min-width: $s-28;
@@ -184,7 +132,7 @@
gap: $s-4;
margin: 0 $s-12;
.layer-filter {
- @extend .button-secondary;
+ @extend .button-tag;
@include buttonStyle;
gap: $s-6;
height: $s-24;
@@ -296,7 +244,6 @@
flex-direction: column;
height: 100%;
width: 100%;
- border-radius: $br-8;
overflow-y: auto;
overflow-x: hidden;
scrollbar-gutter: stable;
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 7b88a06d08..728652f818 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,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.sidebar.options.menus.typography
+ (:require-macros [app.main.style :refer [css]])
(:require
["react-virtualized" :as rvt]
[app.common.data :as d]
@@ -19,6 +20,9 @@
[app.main.store :as st]
[app.main.ui.components.editable-select :refer [editable-select]]
[app.main.ui.components.numeric-input :refer [numeric-input]]
+ [app.main.ui.components.radio-buttons :refer [nilable-option radio-buttons]]
+ [app.main.ui.components.search-bar :refer [search-bar]]
+ [app.main.ui.components.select :refer [select]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
@@ -57,7 +61,8 @@
{::mf/wrap [mf/memo]}
[{:keys [font current? on-click style]}]
(let [item-ref (mf/use-ref)
- on-click (mf/use-callback (mf/deps font) #(on-click font))]
+ on-click (mf/use-callback (mf/deps font) #(on-click font))
+ new-css-system (mf/use-ctx ctx/new-css-system)]
(mf/use-effect
(mf/deps current?)
@@ -67,12 +72,23 @@
(when-not (dom/is-in-viewport? element)
(dom/scroll-into-view! element))))))
- [:div.font-item {:ref item-ref
- :style style
- :class (when current? "selected")
- :on-click on-click}
- [:span.icon (when current? i/tick)]
- [:span.label (:name font)]]))
+ (if new-css-system
+ [:div {:class (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.font-item {:ref item-ref
+ :style style
+ :class (when current? "selected")
+ :on-click on-click}
+ [:span.icon (when current? i/tick)]
+ [:span.label (:name font)]])))
(declare row-renderer)
@@ -87,25 +103,17 @@
(comp (filter #(contains? backends (:backend %)))))]
(into [] xform fonts)))
-;; (defn- toggle-backend
-;; [backends id]
-;; (if (contains? backends id)
-;; (disj backends id)
-;; (conj backends id)))
-
(mf/defc font-selector
[{:keys [on-select on-close current-font show-recent] :as props}]
- (let [selected (mf/use-state current-font)
- state (mf/use-state {:term "" :backends #{}})
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ selected (mf/use-state current-font)
+ state (mf/use-state {:term "" :backends #{}})
- flist (mf/use-ref)
- input (mf/use-ref)
+ flist (mf/use-ref)
+ input (mf/use-ref)
- fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
- fontsdb (mf/deref fonts/fontsdb)
- ;; Filtering deleted fonts
- recent-fonts (->> (mf/deref refs/workspace-recent-fonts)
- (into [] (filter #(some? (get fontsdb (:id %))))))
+ fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
+ recent-fonts (mf/deref refs/workspace-recent-fonts)
select-next
(mf/use-callback
@@ -136,9 +144,11 @@
on-filter-change
(mf/use-callback
- (mf/deps)
+ (mf/deps new-css-system)
(fn [event]
- (let [value (dom/get-target-val event)]
+ (let [value (if new-css-system
+ event
+ (dom/get-target-val event))]
(swap! state assoc :term value))))
on-select-and-close
@@ -184,60 +194,71 @@
#(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})]
(.scrollToPosition ^js inst offset))))))
- [:div.font-selector
- [:div.font-selector-dropdown
- [:header
- [:input {:placeholder (tr "workspace.options.search-font")
- :value (:term @state)
- :ref input
- :spell-check false
- :on-change on-filter-change}]
- (when (and recent-fonts show-recent)
- [:hr]
- [*
- [:p.title (tr "workspace.options.recent-fonts")]
- (for [[idx font] (d/enumerate recent-fonts)]
- [:& font-item {:key (dm/str "font-" idx)
- :font font
- :style {}
- :on-click on-select-and-close
- :current? (= (:id font) (:id @selected))}])])
+ (if new-css-system
+ [:div {:class (css :font-selector)}
+ [:div {:class (css :font-selector-dropdown)}
+ [:div {:class (css :header)}
+ [:& search-bar {:on-change on-filter-change
+ :value (:term @state)
+ :placeholder (tr "workspace.options.search-font")}]
+ (when (and recent-fonts show-recent)
+ [*
+ [:p {:class :title} (tr "workspace.options.recent-fonts")]
+ (for [[idx font] (d/enumerate recent-fonts)]
+ [:& font-item {:key (dm/str "font-" idx)
+ :font font
+ :style {}
+ :on-click on-select-and-close
+ :current? (= (:id font) (:id @selected))}])])]
- #_[:div.options
- {:on-click #(swap! state assoc :show-options true)
- :class (when (seq (:backends @state)) "active")}
- i/picker-hsv]
+ [:div {:class (css :fonts-list)}
+ [:> rvt/AutoSizer {}
+ (fn [props]
+ (let [width (unchecked-get props "width")
+ height (unchecked-get props "height")
+ render #(row-renderer fonts @selected on-select-and-close %)]
+ (mf/html
+ [:> rvt/List #js {:height height
+ :ref flist
+ :width width
+ :rowCount (count fonts)
+ :rowHeight 36
+ :rowRenderer render}])))]]]]
- #_[:& dropdown {:show (:show-options @state false)
- :on-close #(swap! state dissoc :show-options)}
- (let [backends (:backends @state)]
- [:div.backend-filters.dropdown {:ref ddown}
- [:div.backend-filter
- {:class (when (backends :custom) "selected")
- :on-click #(swap! state update :backends toggle-backend :custom)}
- [:div.checkbox-icon i/tick]
- [:div.backend-name (tr "labels.custom-fonts")]]
- [:div.backend-filter
- {:class (when (backends :google) "selected")
- :on-click #(swap! state update :backends toggle-backend :google)}
- [:div.checkbox-icon i/tick]
- [:div.backend-name "Google Fonts"]]])]]
+ [:div.font-selector
+ [:div.font-selector-dropdown
+ [:header
+ [:input {:placeholder (tr "workspace.options.search-font")
+ :value (:term @state)
+ :ref input
+ :spell-check false
+ :on-change on-filter-change}]
+ (when (and recent-fonts show-recent)
+ [:hr]
+ [*
+ [:p.title (tr "workspace.options.recent-fonts")]
+ (for [[idx font] (d/enumerate recent-fonts)]
+ [:& font-item {:key (dm/str "font-" idx)
+ :font font
+ :style {}
+ :on-click on-select-and-close
+ :current? (= (:id font) (:id @selected))}])])]
- [:hr]
+ [:hr]
- [:div.fonts-list
- [:> rvt/AutoSizer {}
- (fn [props]
- (let [width (unchecked-get props "width")
- height (unchecked-get props "height")
- render #(row-renderer fonts @selected on-select-and-close %)]
- (mf/html
- [:> rvt/List #js {:height height
- :ref flist
- :width width
- :rowCount (count fonts)
- :rowHeight 32
- :rowRenderer render}])))]]]]))
+ [:div.fonts-list
+ [:> rvt/AutoSizer {}
+ (fn [props]
+ (let [width (unchecked-get props "width")
+ height (unchecked-get props "height")
+ render #(row-renderer fonts @selected on-select-and-close %)]
+ (mf/html
+ [:> rvt/List #js {:height height
+ :ref flist
+ :width width
+ :rowCount (count fonts)
+ :rowHeight 32
+ :rowRenderer render}])))]]]])))
(defn row-renderer
[fonts selected on-select props]
(let [index (unchecked-get props "index")
@@ -259,12 +280,11 @@
font-id (or font-id (:font-id txt/default-text-attrs))
font-size (or font-size (:font-size txt/default-text-attrs))
font-variant-id (or font-variant-id (:font-variant-id txt/default-text-attrs))
+ new-css-system (mf/use-ctx ctx/new-css-system)
fonts (mf/deref fonts/fontsdb)
font (get fonts font-id)
- ;; Filtering deleted fonts
- recent-fonts (->> (mf/deref refs/workspace-recent-fonts)
- (into [] (filter #(some? (get fonts (:id %))))))
+ recent-fonts (mf/deref refs/workspace-recent-fonts)
last-font (mf/use-ref nil)
open-selector? (mf/use-state false)
@@ -319,57 +339,110 @@
(when (some? on-blur)
(on-blur))
(when (mf/ref-val last-font)
- (st/emit! (fts/add-recent-font (mf/ref-val last-font))))
- ))]
+ (st/emit! (fts/add-recent-font (mf/ref-val last-font))))))]
+ (if new-css-system
+ [:*
+ (when @open-selector?
+ [:& font-selector
+ {:current-font font
+ :on-close on-font-selector-close
+ :on-select on-font-select
+ :show-recent show-recent}])
- [:*
- (when @open-selector?
- [:& font-selector
- {:current-font font
- :on-close on-font-selector-close
- :on-select on-font-select
- :show-recent show-recent}])
+ [:div
+ {:class (css :font-option)
+ :on-click #(reset! open-selector? true)}
+ (cond
+ (= :multiple font-id)
+ "--"
- [:div.row-flex
- [:div.input-select.font-option
- {:on-click #(reset! open-selector? true)}
- (cond
- (= :multiple font-id)
- "--"
+ (some? font)
+ [:*
+ [:span {:class (css :name)}
+ (:name font)]
+ [:span {:class (css :icon)}
+ i/arrow-refactor]]
- (some? font)
- (:name font)
+ :else
+ (tr "dashboard.fonts.deleted-placeholder"))]
- :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)
+ :options size-options
+ :on-change on-font-size-change
+ :on-blur on-blur}])]
+
+ [:div {:class (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)
+ (conj {:value :multiple :key :multiple-variants :label "--"} basic-variant-options)
+ basic-variant-options)]
+ ;; TODO Add disabled mode
+ [:& select
+ {:class (css :font-variant-select)
+ :default-value (attr->string font-variant-id)
+ :options variant-options
+ :on-change on-font-variant-change
+ :on-blur on-blur}])]]]
+
+ [:*
+ (when @open-selector?
+ [:& font-selector
+ {:current-font font
+ :on-close on-font-selector-close
+ :on-select on-font-select
+ :show-recent show-recent}])
+
+ [:div.row-flex
+ [:div.input-select.font-option
+ {:on-click #(reset! open-selector? true)}
+ (cond
+ (= :multiple font-id)
+ "--"
+
+ (some? font)
+ (:name font)
+
+ :else
+ (tr "dashboard.fonts.deleted-placeholder"))]]
- [:div.row-flex
- (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 "input-option size-option"
- :options size-options
- :type "number"
- :placeholder "--"
- :min 3
- :max 1000
- :on-change on-font-size-change
- :on-blur on-blur}])
-
- [:select.input-select.variant-option
- {:disabled (= font-id :multiple)
- :value (attr->string font-variant-id)
- :on-change on-font-variant-change
- :on-blur on-blur}
- (when (or (= font-id :multiple) (= font-variant-id :multiple))
- [:option {:value ""} "--"])
- (for [variant (:variants font)]
- [:option {:value (:id variant)
- :key (pr-str variant)}
- (:name variant)])]]]))
+ [:div.row-flex
+ (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 "input-option size-option"
+ :options size-options
+ :type "number"
+ :placeholder "--"
+ :min 3
+ :max 1000
+ :on-change on-font-size-change
+ :on-blur on-blur}])
+ [:select.input-select.variant-option
+ {:disabled (= font-id :multiple)
+ :value (attr->string font-variant-id)
+ :on-change on-font-variant-change
+ :on-blur on-blur}
+ (when (or (= font-id :multiple) (= font-variant-id :multiple))
+ [:option {:value ""} "--"])
+ (for [variant (:variants font)]
+ [:option {:value (:id variant)
+ :key (pr-str variant)}
+ (:name variant)])]]])))
(mf/defc spacing-options
{::mf/wrap-props false}
@@ -379,101 +452,243 @@
line-height (or line-height "1.2")
letter-spacing (or letter-spacing "0")
-
+ new-css-system (mf/use-ctx ctx/new-css-system)
line-height-nillable (if (= (str line-height) "1.2") false true)
handle-change
(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)
+ :alt (tr "workspace.options.text-options.line-height")}
+ i/text-lineheight-refactor]
- [:div.spacing-options
- [:div.input-icon
- [:span.icon-before.tooltip.tooltip-bottom
- {:alt (tr "workspace.options.text-options.line-height")}
- i/line-height]
- [:> numeric-input
- {:min -200
- :max 200
- :step 0.1
- :default "1.2"
- :value (attr->string line-height)
- :placeholder (tr "settings.multiple")
- :nillable line-height-nillable
- :on-change #(handle-change % :line-height)
- :on-blur on-blur}]]
+ [:> numeric-input
+ {:min -200
+ :max 200
+ :step 0.1
+ :default "1.2"
+ :klass (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.input-icon
- [:span.icon-before.tooltip.tooltip-bottom
- {:alt (tr "workspace.options.text-options.letter-spacing")}
- i/letter-spacing]
- [:> numeric-input
- {:min -200
- :max 200
- :step 0.1
- :value (attr->string letter-spacing)
- :placeholder (tr "settings.multiple")
- :on-change #(handle-change % :letter-spacing)
- :on-blur on-blur}]]]))
+ [:div {:class (css :letter-spacing)}
+ [:span
+ {:class (css :icon)
+ :alt (tr "workspace.options.text-options.letter-spacing")}
+ i/text-letterspacing-refactor]
+ [:> numeric-input
+ {:min -200
+ :max 200
+ :step 0.1
+ :klass (css :letter-spacing-input)
+ :value (attr->string letter-spacing)
+ :placeholder (tr "settings.multiple")
+ :on-change #(handle-change % :letter-spacing)
+ :on-blur on-blur}]]]
+
+ [:div.spacing-options
+ [:div.input-icon
+ [:span.icon-before.tooltip.tooltip-bottom
+ {:alt (tr "workspace.options.text-options.line-height")}
+ i/line-height]
+ [:> numeric-input
+ {:min -200
+ :max 200
+ :step 0.1
+ :default "1.2"
+ :value (attr->string line-height)
+ :placeholder (tr "settings.multiple")
+ :nillable line-height-nillable
+ :on-change #(handle-change % :line-height)
+ :on-blur on-blur}]]
+
+ [:div.input-icon
+ [:span.icon-before.tooltip.tooltip-bottom
+ {:alt (tr "workspace.options.text-options.letter-spacing")}
+ i/letter-spacing]
+ [:> numeric-input
+ {:min -200
+ :max 200
+ :step 0.1
+ :value (attr->string letter-spacing)
+ :placeholder (tr "settings.multiple")
+ :on-change #(handle-change % :letter-spacing)
+ :on-blur on-blur}]]])))
(mf/defc text-transform-options
{::mf/wrap-props false}
[{:keys [values on-change on-blur]}]
(let [text-transform (or (:text-transform values) "none")
+ new-css-system (mf/use-ctx ctx/new-css-system)
handle-change
- (fn [_ type]
- (on-change {:text-transform type})
+ (fn [type]
+ (if (= text-transform type)
+ (on-change {:text-transform "unset"})
+ (on-change {:text-transform 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-transform))
- :on-focus #(dom/prevent-default %)
- :on-click #(handle-change % "none")}
- i/minus]
- [:span.tooltip.tooltip-bottom
- {:alt (tr "workspace.options.text-options.uppercase")
- :class (dom/classnames :current (= "uppercase" text-transform))
- :on-click #(handle-change % "uppercase")}
- i/uppercase]
- [:span.tooltip.tooltip-bottom
- {:alt (tr "workspace.options.text-options.lowercase")
- :class (dom/classnames :current (= "lowercase" text-transform))
- :on-click #(handle-change % "lowercase")}
- i/lowercase]
- [:span.tooltip.tooltip-bottom
- {:alt (tr "workspace.options.text-options.titlecase")
- :class (dom/classnames :current (= "capitalize" text-transform))
- :on-click #(handle-change % "capitalize")}
- i/titlecase]]))
+ (if new-css-system
+ [:div {:class (css :text-transform)}
+ [:& radio-buttons {:selected text-transform
+ :on-change handle-change
+ :name "text-transform"}
+ [:& nilable-option {:icon (mf/html i/text-uppercase-refactor)
+ :value "uppercase"
+ :id :uppercase}]
+ [:& nilable-option {:icon (mf/html i/text-lowercase-refactor)
+ :value "lowercase"
+ :id :lowercase}]
+ [:& nilable-option {:icon "Aa"
+ :value "capitalize"
+ :id :capitalize}]]]
+
+ [:div.align-icons
+ [:span.tooltip.tooltip-bottom
+ {:alt (tr "workspace.options.text-options.none")
+ :class (dom/classnames :current (= "none" text-transform))
+ :on-focus #(dom/prevent-default %)
+ :on-click #(handle-change "none")}
+ i/minus]
+ [:span.tooltip.tooltip-bottom
+ {:alt (tr "workspace.options.text-options.uppercase")
+ :class (dom/classnames :current (= "uppercase" text-transform))
+ :on-click #(handle-change "uppercase")}
+ i/uppercase]
+ [:span.tooltip.tooltip-bottom
+ {:alt (tr "workspace.options.text-options.lowercase")
+ :class (dom/classnames :current (= "lowercase" text-transform))
+ :on-click #(handle-change "lowercase")}
+ i/lowercase]
+ [:span.tooltip.tooltip-bottom
+ {:alt (tr "workspace.options.text-options.titlecase")
+ :class (dom/classnames :current (= "capitalize" text-transform))
+ :on-click #(handle-change "capitalize")}
+ i/titlecase]])))
(mf/defc typography-options
{::mf/wrap-props false}
[{:keys [ids editor values on-change on-blur show-recent]}]
- (let [opts #js {:editor editor
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ opts #js {:editor editor
:ids ids
:values values
:on-change on-change
:on-blur on-blur
:show-recent show-recent}]
- [:div.element-set-content
- [:> font-options opts]
- [:div.row-flex
- [:> spacing-options opts]]
- [:div.row-flex
- [:> text-transform-options opts]]]))
+
+ (if new-css-system
+ [:div {:class (css :typography-options)}
+ [:> font-options opts]
+ [:div {:class (css :typography-variations)}
+ [:> spacing-options opts]
+ [:> text-transform-options opts]]]
+
+ [:div.element-set-content
+ [:> font-options opts]
+ [:div.row-flex
+ [:> spacing-options opts]]
+ [:div.row-flex
+ [:> text-transform-options opts]]])))
+
+
+(mf/defc typography-advanced-options
+ {::mf/wrap [mf/memo]}
+ [{:keys [visible? typography editable? name-input-ref on-close on-change on-name-blur local? navigate-to-library]}]
+ (let [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)))))
+
+ (when visible?
+ [:div {:ref ref
+ :class (css :advanced-options-wrapper)}
+ (if ^boolean editable?
+ [:*
+ [:div {:class (css :font-name-wrapper)}
+ [:div
+ {:class (dom/classnames (css :typography-sample-input) true)
+ :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)
+ :type "text"
+ :ref name-input-ref
+ :default-value (:name typography)
+ :on-blur on-name-blur}]
+
+ [:div {:class (css :action-btn)
+ :on-click on-close}
+ i/tick-refactor]]
+
+ [:& typography-options {:values typography
+ :on-change on-change
+ :show-recent false}]]
+
+ [:div.element-set-content.typography-read-only-data
+ [:div.row-flex.typography-name
+ [:span {:title (:name typography)} (:name typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.font-id")]
+ [:span (:font-id typography)]]
+
+ [:div.element-set-actions-button.actions-inside
+ {:on-click on-close}
+ i/actions]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.font-variant-id")]
+ [:span (:font-variant-id typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.font-size")]
+ [:span (:font-size typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.line-height")]
+ [:span (:line-height typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.letter-spacing")]
+ [:span (:letter-spacing typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.text-transform")]
+ [:span (:text-transform typography)]]
+
+ (when-not local?
+ [:div.row-flex
+ [:a.go-to-lib-button
+ {:on-click navigate-to-library}
+ (tr "workspace.assets.typography.go-to-edit")]])])])))
+
(mf/defc typography-entry
{::mf/wrap-props false}
- [{:keys [file-id typography local? selected? on-click on-change on-detach on-context-menu editing? focus-name? external-open*]}]
+ [{:keys [file-id typography local? selected? on-click on-change on-detach on-context-menu editing? renaming? focus-name? external-open*]}]
(let [hover-detach* (mf/use-state false)
hover-detach? (deref hover-detach*)
name-input-ref (mf/use-ref)
read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
editable? (and local? (not read-only?))
open* (mf/use-state editing?)
open? (deref open*)
+ font-data (fonts/get-font-data (:font-id typography))
+ name-only? (= (:name typography) (:name font-data))
on-name-blur
(mf/use-callback
@@ -481,7 +696,8 @@
(fn [event]
(let [name (dom/get-target-val event)]
(when-not (str/blank? name)
- (on-change {:name name})))))
+ (on-change {:name name})
+ (st/emit! #(update % :workspace-global dissoc :rename-typography))))))
on-pointer-enter
(mf/use-fn #(reset! hover-detach* true))
@@ -500,9 +716,7 @@
(mf/deps file-id)
(fn []
(when file-id
- (st/emit! (dw/navigate-to-library file-id)))))
-
- ]
+ (st/emit! (dw/navigate-to-library file-id)))))]
(mf/with-effect [editing?]
(when editing?
@@ -518,88 +732,145 @@
#(when-let [node (mf/ref-val name-input-ref)]
(dom/focus! node)
(dom/select-text! node)))))
+ (if new-css-system
+ [:*
+ [:div {:class (dom/classnames (css :typography-entry) true
+ (css :selected) ^boolean selected?)
+ :style {:display (when ^boolean open? "none")}}
+ (if renaming?
+ [:div {:class (css :font-name-wrapper)}
+ [:div
+ {:class (dom/classnames (css :typography-sample-input) true)
+ :style {:font-family (:font-family typography)
+ :font-weight (:font-weight typography)
+ :font-style (:font-style typography)}}
+ (tr "workspace.assets.typography.sample")]
- [:*
- [:div.element-set-options-group.typography-entry
- {:class (when ^boolean selected? "selected")
- :style {:display (when ^boolean open? "none")}}
- [:div.typography-selection-wrapper
- {:class (when ^boolean on-click "is-selectable")
- :on-click on-click
- :on-context-menu on-context-menu}
- [:div.typography-sample
- {:style {:font-family (:font-family typography)
- :font-weight (:font-weight typography)
- :font-style (:font-style typography)}}
- (tr "workspace.assets.typography.sample")]
- [:div.typography-name {:title (:name typography)}(:name typography)]]
- [:div.element-set-actions
- (when ^boolean on-detach
- [:div.element-set-actions-button
- {:on-pointer-enter on-pointer-enter
- :on-pointer-leave on-pointer-leave
- :on-click on-detach}
- (if ^boolean hover-detach? i/unchain i/chain)])
-
- [:div.element-set-actions-button
- {:on-click on-open}
- i/actions]]]
-
- [:& advanced-options {:visible? open? :on-close on-close}
- (if ^boolean editable?
- [:*
- [:div.element-set-content
- [:div.row-flex
- [:input.element-name.adv-typography-name
- {:type "text"
+ [:input
+ {:class (css :adv-typography-name)
+ :type "text"
:ref name-input-ref
:default-value (:name typography)
- :on-blur on-name-blur}]
+ :on-blur on-name-blur}]]
+ [:div
+ {:class (dom/classnames (css :typography-selection-wrapper) true
+ (css :is-selectable) ^boolean on-click)
+ :on-click on-click
+ :on-context-menu on-context-menu}
+ [:div
+ {:class (dom/classnames (css :typography-sample) true)
+ :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)
+ :title (:name typography)} (:name typography)]
+
+ (when-not name-only?
+ [:div {:class (dom/classnames (css :typography-font) true)
+ :title (:name font-data)}
+ (:name font-data)])])
+
+ (when ^boolean on-detach
+ [:div {:class (dom/classnames (css :element-set-actions) true)}
+ [:div
+ {:class (dom/classnames (css :element-set-actions-button) true)
+ :on-pointer-enter on-pointer-enter
+ :on-pointer-leave on-pointer-leave
+ :on-click on-detach}
+ (if ^boolean hover-detach? i/detach-refactor i/chain)]])]
+
+ [:& typography-advanced-options
+ {:visible? open? :on-close on-close
+ :typography typography
+ :editable? editable?
+ :name-input-ref name-input-ref
+ :on-change on-change
+ :on-name-blur on-name-blur
+ :local? local?
+ :navigate-to-library navigate-to-library}]]
+
+
+ [:*
+ [:div.element-set-options-group.typography-entry
+ {:class (when ^boolean selected? "selected")
+ :style {:display (when ^boolean open? "none")}}
+ [:div.typography-selection-wrapper
+ {:class (when ^boolean on-click "is-selectable")
+ :on-click on-click
+ :on-context-menu on-context-menu}
+ [:div.typography-sample
+ {:style {:font-family (:font-family typography)
+ :font-weight (:font-weight typography)
+ :font-style (:font-style typography)}}
+ (tr "workspace.assets.typography.sample")]
+ [:div.typography-name {:title (:name typography)} (:name typography)]]
+ [:div.element-set-actions
+ (when ^boolean on-detach
[:div.element-set-actions-button
- {:on-click on-close}
- i/actions]]]
+ {:on-pointer-enter on-pointer-enter
+ :on-pointer-leave on-pointer-leave
+ :on-click on-detach}
+ (if ^boolean hover-detach? i/unchain i/chain)])
- [:& typography-options {:values typography
- :on-change on-change
- :show-recent false}]]
+ [:div.element-set-actions-button
+ {:on-click on-open}
+ i/actions]]]
- [:div.element-set-content.typography-read-only-data
- [:div.row-flex.typography-name
- [:span {:title (:name typography)} (:name typography)]]
+ [:& advanced-options {:visible? open? :on-close on-close}
+ (if ^boolean editable?
+ [:*
+ [:div.element-set-content
+ [:div.row-flex
+ [:input.element-name.adv-typography-name
+ {:type "text"
+ :ref name-input-ref
+ :default-value (:name typography)
+ :on-blur on-name-blur}]
- [:div.row-flex
- [:span.label (tr "workspace.assets.typography.font-id")]
- [:span (:font-id typography)]]
+ [:div.element-set-actions-button
+ {:on-click on-close}
+ i/actions]]]
- [:div.element-set-actions-button.actions-inside
- {:on-click on-close}
- i/actions]
+ [:& typography-options {:values typography
+ :on-change on-change
+ :show-recent false}]]
- [:div.row-flex
- [:span.label (tr "workspace.assets.typography.font-variant-id")]
- [:span (:font-variant-id typography)]]
+ [:div.element-set-content.typography-read-only-data
+ [:div.row-flex.typography-name
+ [:span {:title (:name typography)} (:name typography)]]
- [:div.row-flex
- [:span.label (tr "workspace.assets.typography.font-size")]
- [:span (:font-size typography)]]
-
- [:div.row-flex
- [:span.label (tr "workspace.assets.typography.line-height")]
- [:span (:line-height typography)]]
-
- [:div.row-flex
- [:span.label (tr "workspace.assets.typography.letter-spacing")]
- [:span (:letter-spacing typography)]]
-
- [:div.row-flex
- [:span.label (tr "workspace.assets.typography.text-transform")]
- [:span (:text-transform typography)]]
-
- (when-not local?
[:div.row-flex
- [:a.go-to-lib-button
- {:on-click navigate-to-library}
- (tr "workspace.assets.typography.go-to-edit")]])]
+ [:span.label (tr "workspace.assets.typography.font-id")]
+ [:span (:font-id typography)]]
- )]]))
+ [:div.element-set-actions-button.actions-inside
+ {:on-click on-close}
+ i/actions]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.font-variant-id")]
+ [:span (:font-variant-id typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.font-size")]
+ [:span (:font-size typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.line-height")]
+ [:span (:line-height typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.letter-spacing")]
+ [:span (:letter-spacing typography)]]
+
+ [:div.row-flex
+ [:span.label (tr "workspace.assets.typography.text-transform")]
+ [:span (:text-transform typography)]]
+
+ (when-not local?
+ [:div.row-flex
+ [:a.go-to-lib-button
+ {:on-click navigate-to-library}
+ (tr "workspace.assets.typography.go-to-edit")]])])]])))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.css.json b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.css.json
new file mode 100644
index 0000000000..007aeef5a8
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.css.json
@@ -0,0 +1 @@
+{"button-primary":"menus_typography_button-primary_s1c9M","button-secondary":"menus_typography_button-secondary_RjAsk","button-tertiary":"menus_typography_button-tertiary_Qt18f","font-name-wrapper":"menus_typography_font-name-wrapper_Njxb6","action-btn":"menus_typography_action-btn_hCakz","button-tag":"menus_typography_button-tag_32-df","button-icon":"menus_typography_button-icon_jucwh","advanced-options-wrapper":"menus_typography_advanced-options-wrapper_k3FD6","typography-options":"menus_typography_typography-options_j1u8l","font-modifiers":"menus_typography_font-modifiers_P8cSa","font-variant-options":"menus_typography_font-variant-options_qlgLr","icon":"menus_typography_icon_eDU2Z","font-size-options":"menus_typography_font-size-options_sKQdL","font-option":"menus_typography_font-option_7mgxF","button-icon-small":"menus_typography_button-icon-small_g3fsU","font-selector":"menus_typography_font-selector_TzuGa","font-selector-dropdown":"menus_typography_font-selector-dropdown_4s6s8","font-wrapper":"menus_typography_font-wrapper_GPkHS","font-item":"menus_typography_font-item_YQffA","typography-variations":"menus_typography_typography-variations_wbNM3","spacing-options":"menus_typography_spacing-options_RUpAK","line-height":"menus_typography_line-height_S7zsF","letter-spacing":"menus_typography_letter-spacing_8R6p2","asset-element":"menus_typography_asset-element_-LlIX","text-transform":"menus_typography_text-transform_U7Y3U","typography-entry":"menus_typography_typography-entry_Y6lvA","typography-selection-wrapper":"menus_typography_typography-selection-wrapper_W6ewx","is-selectable":"menus_typography_is-selectable_O6-D2","typography-sample":"menus_typography_typography-sample_6ruld","typography-name":"menus_typography_typography-name_b14xj","typography-font":"menus_typography_typography-font_hJIgO","selected":"menus_typography_selected_Ka-O9","typography-sample-input":"menus_typography_typography-sample-input_u2i8b","adv-typography-name":"menus_typography_adv-typography-name_PvB1X","name":"menus_typography_name_1SJal","font-size-select":"menus_typography_font-size-select_yexav","font-variant-select":"menus_typography_font-variant-select_-OQsO","line-height-input":"menus_typography_line-height-input_SG7be","letter-spacing-input":"menus_typography_letter-spacing-input_LShRc","header":"menus_typography_header_e-rUh","title":"menus_typography_title_uPejx","fonts-list":"menus_typography_fonts-list_ki8X-","label":"menus_typography_label_S-7jI"}
\ No newline at end of file
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
new file mode 100644
index 0000000000..0763cbf918
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.scss
@@ -0,0 +1,304 @@
+// 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";
+
+.typography-entry {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ height: $s-32;
+ width: 100%;
+ border-radius: $br-8;
+
+ .typography-selection-wrapper {
+ display: grid;
+ grid-template-columns: $s-24 auto 1fr;
+ flex: 1;
+ height: 100%;
+ width: 100%;
+ padding: 0 $s-12;
+
+ &.is-selectable {
+ cursor: pointer;
+ }
+
+ .typography-sample {
+ @include flexCenter;
+ min-width: $s-24;
+ color: var(--assets-item-name-foreground-color-hover);
+ }
+ .typography-name,
+ .typography-font {
+ @include titleTipography;
+ @include textEllipsis;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ margin-left: $s-6;
+ color: var(--assets-item-name-foreground-color-hover);
+ }
+ .typography-font {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ min-width: 0;
+ color: var(--assets-item-name-foreground-color);
+ }
+ }
+
+ &.selected {
+ border: $s-1 solid var(--assets-item-border-color);
+ }
+
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ }
+}
+
+.font-name-wrapper {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ width: 100%;
+ border-radius: $br-8;
+ border: $s-1 solid transparent;
+ box-sizing: border-box;
+ background-color: var(--assets-item-background-color);
+ margin-bottom: $s-4;
+ padding: $s-8 $s-0 $s-8 $s-12;
+
+ .typography-sample-input {
+ @include flexCenter;
+ width: $s-24;
+ height: 100%;
+ font-size: $fs-16;
+ }
+ .adv-typography-name {
+ @include removeInputStyle;
+ color: var(--input-foreground-color);
+ flex-grow: 1;
+ margin: 0;
+ }
+ .action-btn {
+ @extend .button-tertiary;
+ @include flexCenter;
+ width: $s-28;
+ height: $s-28;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
+ &:focus-within {
+ border: $s-1 solid var(--input-border-color-active);
+ .adv-typography-name {
+ color: var(--input-foreground-color-active);
+ }
+ }
+ &:hover {
+ background-color: var(--assets-item-background-color-hover);
+ }
+}
+
+.advanced-options-wrapper {
+ height: 100%;
+ width: 100%;
+ background-color: var(--title-background-color);
+
+ .typography-options {
+ position: relative;
+ .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;
+ transform: rotate(90deg);
+ }
+ }
+ }
+ .font-modifiers {
+ display: flex;
+ gap: $s-4;
+ .font-size-options {
+ @extend .asset-element;
+ @include titleTipography;
+ padding: 0;
+ flex-grow: 1;
+ .icon {
+ @include flexCenter;
+ height: $s-28;
+ min-width: $s-28;
+ svg {
+ @extend .button-icon;
+ 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;
+ flex-grow: 2;
+ .icon {
+ @include flexCenter;
+ height: $s-28;
+ min-width: $s-28;
+ svg {
+ @extend .button-icon;
+ 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 {
+ 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;
+ .icon {
+ @include flexCenter;
+ width: $s-28;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
+ .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);
+ }
+ }
+ }
+ }
+ .text-transform {
+ @extend .asset-element;
+ width: fit-content;
+ padding: 0;
+ }
+ }
+ }
+}
+
+.font-selector {
+ @include flexCenter;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ z-index: $z-index-10;
+
+ .font-selector-dropdown {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ height: 100%;
+ .header {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ margin-bottom: $s-2;
+ .title {
+ @include tabTitleTipography;
+ margin: 9px 17px;
+ }
+ }
+ .fonts-list {
+ position: absolute;
+ top: $s-36;
+ left: 0;
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 auto;
+ min-height: 100%;
+ height: $s-216;
+ width: 100%;
+ padding: $s-2;
+ border-radius: $br-8;
+ background-color: var(--dropdown-background-color);
+ box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
+ }
+ .font-wrapper {
+ padding-bottom: $s-4;
+ cursor: pointer;
+ .font-item {
+ @extend .asset-element;
+ border-radius: $br-8;
+ display: flex;
+ .icon {
+ @include flexCenter;
+ height: $s-28;
+ width: $s-28;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
+ &.selected {
+ color: var(--assets-item-name-foreground-color-hover);
+ .icon {
+ svg {
+ stroke: var(--assets-item-name-foreground-color-hover);
+ }
+ }
+ }
+
+ .label {
+ @include titleTipography;
+ flex-grow: 1;
+ }
+ }
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
index 26d554ffe2..65b37b1e10 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
@@ -18,6 +18,7 @@
[app.main.data.workspace.path.shortcuts]
[app.main.data.workspace.shortcuts]
[app.main.store :as st]
+ [app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
@@ -280,7 +281,7 @@
(for [command-translate sorted-filtered]
(let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements))
[command comand-info] sc-by-translate
- content (or (:show-command comand-info)(:command comand-info))]
+ content (or (:show-command comand-info) (:command comand-info))]
[:li {:class (css :shortcuts-name)
:key command-translate}
[:span {:class (css :command-name)}
@@ -326,7 +327,7 @@
:filter-term filter-term
:match-section? match-section?
:match-subsection? true}])
-
+
[:ul {:class (dom/classnames (css :subsection-menu) new-css-system
:subsection-menu (not new-css-system))}
(for [sub-translated sorted-translations]
@@ -365,7 +366,7 @@
translations (map #(translation-keyname :sc %) (keys subs-bodys))
match-shortcut? (some #(matches-search % @filter-term) translations)
visible? (some #(= % section-id) @open-sections)]
-
+
(when (or match-section? match-subsection? match-shortcut?)
[:div {:class (css :section)
:on-click (manage-sections section-id)}
@@ -502,6 +503,11 @@
(manage-sections-on-search value)
(reset! filter-term value))))
+ on-search-term-change-2
+ (mf/use-callback
+ (fn [value]
+ (manage-sections-on-search value)
+ (reset! filter-term value)))
on-search-clear-click
(mf/use-callback
(fn [_]
@@ -528,31 +534,17 @@
(if new-css-system
[:div {:class (css :shortcuts)}
[:div {:class (css :shortcuts-header)}
- [:div {:class (css :shortcuts-title)} "Keyboard Shortcuts"]
+ [:div {:class (css :shortcuts-title)} (tr "shortcuts.title")]
[:div {:class (css :shortcuts-close-button)
:on-click close-fn}
i/close-refactor]]
- ;; TODO Change this for search bar component
[:div {:class (css :search-field)}
- [:div {:class (css :search-box)}
- [:span {:class (css :icon-wrapper)}
- i/search-refactor]
- [:input {:class (dom/classnames (css :input-text) true)
- :id "shortcut-search"
- :placeholder (tr "shortcuts.title")
- :type "text"
- :value @filter-term
- :on-change on-search-term-change
- :auto-complete "off"
- :on-key-down manage-key-down}]
- (when (not (str/empty? @filter-term))
- [:button
- {:class (css :clear-btn)
- :on-click on-search-clear-click
- :on-key-down on-key-down}
- [:span {:class (css :clear-icon)}
- i/delete-text-refactor]])]]
+ [:& search-bar {:on-change on-search-term-change-2
+ :clear-action on-search-clear-click
+ :value @filter-term
+ :placeholder (tr "shortcuts.title")
+ :icon (mf/html [:span {:class (css :search-icon)} i/search-refactor])}]]
(if match-any?
[:div {:class (dom/classnames (css :shortcuts-list) true)}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.css.json b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.css.json
index c2e9635b92..cba898593b 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.css.json
@@ -1 +1 @@
-{"button-primary":"sidebar_shortcuts_button-primary_aIZ1F","shortcuts":"sidebar_shortcuts_shortcuts_cOJNo","shortcuts-header":"sidebar_shortcuts_shortcuts-header_0SZ19","shortcuts-close-button":"sidebar_shortcuts_shortcuts-close-button_gT7kn","button-secondary":"sidebar_shortcuts_button-secondary_dtWEN","button-icon":"sidebar_shortcuts_button-icon_rCHmV","button-icon-small":"sidebar_shortcuts_button-icon-small_9BnNh","shortcuts-list":"sidebar_shortcuts_shortcuts-list_z7osI","section-title":"sidebar_shortcuts_section-title_Dv7S-","collapsed-shortcuts":"sidebar_shortcuts_collapsed-shortcuts_XrOj5","subsection-title":"sidebar_shortcuts_subsection-title_--5j4","search-field":"sidebar_shortcuts_search-field_cDecA","search-box":"sidebar_shortcuts_search-box_vmYAl","clear-btn":"sidebar_shortcuts_clear-btn_vRbGu","clear-icon":"sidebar_shortcuts_clear-icon_ZL4ae","icon-wrapper":"sidebar_shortcuts_icon-wrapper_XaR8m","shortcuts-title":"sidebar_shortcuts_shortcuts-title_P38o9","input-text":"sidebar_shortcuts_input-text_e9n1x","section":"sidebar_shortcuts_section_Jxkqa","open":"sidebar_shortcuts_open_SxghD","subsection-name":"sidebar_shortcuts_subsection-name_rWvFY","section-name":"sidebar_shortcuts_section-name_SyF9-","subsection-menu":"sidebar_shortcuts_subsection-menu_FdH9L","sub-menu":"sidebar_shortcuts_sub-menu_95jTY","shortcuts-name":"sidebar_shortcuts_shortcuts-name_hPkq6","command-name":"sidebar_shortcuts_command-name_Cujed","keys":"sidebar_shortcuts_keys_-pUnF","key":"sidebar_shortcuts_key_QyU8q","space":"sidebar_shortcuts_space_aODdu","not-found":"sidebar_shortcuts_not-found_bKEb0"}
\ No newline at end of file
+{"button-primary":"sidebar_shortcuts_button-primary_aIZ1F","button-secondary":"sidebar_shortcuts_button-secondary_dtWEN","button-tertiary":"sidebar_shortcuts_button-tertiary_3VDIw","shortcuts":"sidebar_shortcuts_shortcuts_cOJNo","shortcuts-header":"sidebar_shortcuts_shortcuts-header_0SZ19","shortcuts-close-button":"sidebar_shortcuts_shortcuts-close-button_gT7kn","button-tag":"sidebar_shortcuts_button-tag_3LImZ","button-icon":"sidebar_shortcuts_button-icon_rCHmV","button-icon-small":"sidebar_shortcuts_button-icon-small_9BnNh","shortcuts-list":"sidebar_shortcuts_shortcuts-list_z7osI","section-title":"sidebar_shortcuts_section-title_Dv7S-","collapsed-shortcuts":"sidebar_shortcuts_collapsed-shortcuts_XrOj5","subsection-title":"sidebar_shortcuts_subsection-title_--5j4","search-field":"sidebar_shortcuts_search-field_cDecA","search-icon":"sidebar_shortcuts_search-icon_NSAwd","search-box":"sidebar_shortcuts_search-box_vmYAl","clear-btn":"sidebar_shortcuts_clear-btn_vRbGu","clear-icon":"sidebar_shortcuts_clear-icon_ZL4ae","icon-wrapper":"sidebar_shortcuts_icon-wrapper_XaR8m","asset-element":"sidebar_shortcuts_asset-element_-zk6N","shortcuts-title":"sidebar_shortcuts_shortcuts-title_P38o9","input-text":"sidebar_shortcuts_input-text_e9n1x","section":"sidebar_shortcuts_section_Jxkqa","open":"sidebar_shortcuts_open_SxghD","subsection-name":"sidebar_shortcuts_subsection-name_rWvFY","section-name":"sidebar_shortcuts_section-name_SyF9-","subsection-menu":"sidebar_shortcuts_subsection-menu_FdH9L","sub-menu":"sidebar_shortcuts_sub-menu_95jTY","shortcuts-name":"sidebar_shortcuts_shortcuts-name_hPkq6","command-name":"sidebar_shortcuts_command-name_Cujed","keys":"sidebar_shortcuts_keys_-pUnF","key":"sidebar_shortcuts_key_QyU8q","space":"sidebar_shortcuts_space_aODdu","not-found":"sidebar_shortcuts_not-found_bKEb0"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss
index 42c3b385d3..e8527b9c66 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.scss
@@ -24,7 +24,7 @@
}
.shortcuts-close-button {
- @extend .button-primary;
+ @extend .button-tertiary;
position: absolute;
right: $s-2;
top: $s-2;
@@ -45,7 +45,6 @@
border-radius: $br-8;
font-family: "worksans", sans-serif;
background-color: var(--color-background-tertiary);
-
.search-box {
align-items: center;
display: flex;
@@ -59,6 +58,7 @@
}
.input-text {
+ @include removeInputStyle;
height: $s-32;
width: 100%;
margin: 0;
@@ -66,7 +66,6 @@
border: 0;
font-size: $fs-12;
color: var(--color-foreground-primary);
- background-color: transparent;
&::placeholder {
color: var(--color-foreground-secondary);
}
@@ -87,6 +86,13 @@
}
}
}
+ .search-icon {
+ @include flexCenter;
+ width: $s-28;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
}
.section {
diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs
index 0872288152..c016b0cc17 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs
@@ -13,6 +13,7 @@
[app.main.data.workspace :as dw]
[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.hooks :as hooks]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
@@ -239,22 +240,20 @@
[:div {:class (dom/classnames (css :sitemap) true)
:ref parent-ref
:style #js {"--height" (str size "px")}}
- [:div {:class (dom/classnames (css :pages-tool-bar) true)}
- [:button {:class (dom/classnames (css :page-tool-bar-title) true)
- :on-click toggle-pages}
- [:span {:class (dom/classnames (css :collapsable-button) true)
- :style {:transform (when (not @show-pages?) "rotate(-90deg)")}}
- i/arrow-refactor]
- (tr "workspace.sidebar.sitemap")]
+ [:& title-bar {:collapsable? true
+ :collapsed? (not @show-pages?)
+ :on-collapsed toggle-pages
+ :title (tr "workspace.sidebar.sitemap")
+ :klass :title-spacing-sitemap}
+
(if workspace-read-only?
[:div
{:class (dom/classnames (css :view-only-mode) true)}
(tr "labels.view-only")]
- [:*
- [:button {:class (dom/classnames (css :add-page) true)
- :on-click create}
- i/add-refactor]])]
+ [:button {:class (dom/classnames (css :add-page) true)
+ :on-click create}
+ i/add-refactor])]
[:div {:class (dom/classnames (css :tool-window-content) true)}
[:& pages-list {:file file :key (:id file)}]]
diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.css.json b/frontend/src/app/main/ui/workspace/sidebar/sitemap.css.json
index 46ae1745fb..0aec9ae5c2 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.css.json
+++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.css.json
@@ -1 +1 @@
-{"button-primary":"sidebar_sitemap_button-primary_Z-bKW","sitemap":"sidebar_sitemap_sitemap_kvKKx","pages-tool-bar":"sidebar_sitemap_pages-tool-bar_n1yfA","add-page":"sidebar_sitemap_add-page_r8Ibb","button-secondary":"sidebar_sitemap_button-secondary_a56LZ","button-icon":"sidebar_sitemap_button-icon_MkibT","page-tool-bar-title":"sidebar_sitemap_page-tool-bar-title_D7h-S","collapsable-button":"sidebar_sitemap_collapsable-button_Xt79y","button-icon-small":"sidebar_sitemap_button-icon-small_Mhipv","tool-window-content":"sidebar_sitemap_tool-window-content_G-Nut","pages-list":"sidebar_sitemap_pages-list_cb1Mx","page-element":"sidebar_sitemap_page-element_iR9wf","element-list-body":"sidebar_sitemap_element-list-body_OIVac","page-actions":"sidebar_sitemap_page-actions_QTuKw","page-icon":"sidebar_sitemap_page-icon_ujSjM","view-only-mode":"sidebar_sitemap_view-only-mode_JrsYg","resize-area":"sidebar_sitemap_resize-area_JgdjZ","dnd-over-top":"sidebar_sitemap_dnd-over-top_kGfcb","dnd-over-bot":"sidebar_sitemap_dnd-over-bot_352W2","dnd-over":"sidebar_sitemap_dnd-over_Sf5e2","page-name":"sidebar_sitemap_page-name_601Ii","element-name":"sidebar_sitemap_element-name_iMex0","on-drag":"sidebar_sitemap_on-drag_v3GM8","selected":"sidebar_sitemap_selected_mCOlT","hidden":"sidebar_sitemap_hidden_viFSn"}
\ No newline at end of file
+{"button-primary":"sidebar_sitemap_button-primary_Z-bKW","button-secondary":"sidebar_sitemap_button-secondary_a56LZ","button-tertiary":"sidebar_sitemap_button-tertiary_E2hzd","sitemap":"sidebar_sitemap_sitemap_kvKKx","add-page":"sidebar_sitemap_add-page_r8Ibb","button-tag":"sidebar_sitemap_button-tag_u1NAz","button-icon":"sidebar_sitemap_button-icon_MkibT","button-icon-small":"sidebar_sitemap_button-icon-small_Mhipv","tool-window-content":"sidebar_sitemap_tool-window-content_G-Nut","pages-list":"sidebar_sitemap_pages-list_cb1Mx","page-element":"sidebar_sitemap_page-element_iR9wf","element-list-body":"sidebar_sitemap_element-list-body_OIVac","page-actions":"sidebar_sitemap_page-actions_QTuKw","page-icon":"sidebar_sitemap_page-icon_ujSjM","asset-element":"sidebar_sitemap_asset-element_I1-m4","view-only-mode":"sidebar_sitemap_view-only-mode_JrsYg","resize-area":"sidebar_sitemap_resize-area_JgdjZ","dnd-over-top":"sidebar_sitemap_dnd-over-top_kGfcb","dnd-over-bot":"sidebar_sitemap_dnd-over-bot_352W2","dnd-over":"sidebar_sitemap_dnd-over_Sf5e2","page-name":"sidebar_sitemap_page-name_601Ii","element-name":"sidebar_sitemap_element-name_iMex0","on-drag":"sidebar_sitemap_on-drag_v3GM8","selected":"sidebar_sitemap_selected_mCOlT","hidden":"sidebar_sitemap_hidden_viFSn"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss b/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss
index 037a925f39..51c8984dd9 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss
+++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.scss
@@ -14,63 +14,26 @@
width: 100%;
height: var(--height, 200px);
- .pages-tool-bar {
- display: flex;
- align-items: center;
- min-height: $s-32;
- padding: 0 $s-8 0 0;
- margin: $s-2 0;
- .page-tool-bar-title {
- @include flexCenter;
- @include tabTitleTipography;
- @include buttonStyle;
- flex-grow: 1;
- gap: $s-4;
- justify-content: flex-start;
- padding: 0;
- margin: 0;
- color: var(--title-foreground-color);
- .collapsable-button {
- @include flexCenter;
- height: $s-24;
- width: $s-24;
- padding: 0 $s-4 0 $s-8;
- border-radius: $br-8;
- svg {
- @extend .button-icon;
- height: $s-12;
- width: $s-12;
- transform: rotate(90deg);
- }
- }
- &:hover {
- color: var(--title-foreground-color-hover);
- svg {
- stroke: var(--icon-foreground-hover);
- }
- }
- }
- .add-page {
- @extend .button-primary;
- height: $s-32;
- width: calc($s-24 + $s-4);
- padding: 0;
- border-radius: $br-8;
- svg {
- @extend .button-icon;
- transform: rotate(90deg);
- }
- }
- .view-only-mode {
- @include flexCenter;
- @include titleTipography;
- height: $s-20;
- padding: $s-4 $s-6;
- border: 1px solid var(--tag-background-color);
- border-radius: $br-6;
- color: var(--tag-background-color);
+ .add-page {
+ @extend .button-tertiary;
+ height: $s-32;
+ width: calc($s-24 + $s-4);
+ padding: 0;
+ border-radius: $br-8;
+ svg {
+ @extend .button-icon;
+ transform: rotate(90deg);
}
}
+ .view-only-mode {
+ @include flexCenter;
+ @include titleTipography;
+ height: $s-20;
+ padding: $s-4 $s-6;
+ border: 1px solid var(--tag-background-color);
+ border-radius: $br-6;
+ color: var(--tag-background-color);
+ }
.resize-area {
position: absolute;
bottom: -8px;
@@ -163,6 +126,7 @@
input.element-name {
@include textEllipsis;
@include titleTipography;
+ @include removeInputStyle;
flex-grow: 1;
height: $s-28;
max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
@@ -170,8 +134,6 @@
padding-left: $s-6;
border-radius: $br-8;
border: 1px solid var(--input-border-color-focus);
- outline: none;
- background-color: transparent;
color: var(--layer-row-foreground-color);
}
}
@@ -257,4 +219,7 @@
}
}
}
+ :global(.title-spacing-sitemap) {
+ padding-right: $s-8;
+ }
}
diff --git a/frontend/src/app/main/ui/workspace/text_palette.css.json b/frontend/src/app/main/ui/workspace/text_palette.css.json
index 236e19b66e..bf4e65ccca 100644
--- a/frontend/src/app/main/ui/workspace/text_palette.css.json
+++ b/frontend/src/app/main/ui/workspace/text_palette.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_text_palette_button-primary_1umSD","button-secondary":"workspace_text_palette_button-secondary_VOIWz","button-icon":"workspace_text_palette_button-icon_bcydd","text-palette":"workspace_text_palette_text-palette_0yeGp","left-arrow":"workspace_text_palette_left-arrow_iSjPL","right-arrow":"workspace_text_palette_right-arrow_cWHr6","button-icon-small":"workspace_text_palette_button-icon-small_wGyH7","disabled":"workspace_text_palette_disabled_EF36J","text-palette-content":"workspace_text_palette_text-palette-content_anJb5","text-palette-inside":"workspace_text_palette_text-palette-inside_LgHnf","typography-item":"workspace_text_palette_typography-item_d0vFL","typography-name":"workspace_text_palette_typography-name_NVBRv","typography-font":"workspace_text_palette_typography-font_paqmC","typography-data":"workspace_text_palette_typography-data_eKyme","mid-item":"workspace_text_palette_mid-item_uTcD2","small-item":"workspace_text_palette_small-item_1Y6mx"}
\ No newline at end of file
+{"button-primary":"workspace_text_palette_button-primary_1umSD","button-secondary":"workspace_text_palette_button-secondary_VOIWz","button-tertiary":"workspace_text_palette_button-tertiary_4AWFN","button-tag":"workspace_text_palette_button-tag_TMcKw","button-icon":"workspace_text_palette_button-icon_bcydd","text-palette":"workspace_text_palette_text-palette_0yeGp","left-arrow":"workspace_text_palette_left-arrow_iSjPL","right-arrow":"workspace_text_palette_right-arrow_cWHr6","button-icon-small":"workspace_text_palette_button-icon-small_wGyH7","asset-element":"workspace_text_palette_asset-element_edxQB","disabled":"workspace_text_palette_disabled_EF36J","text-palette-content":"workspace_text_palette_text-palette-content_anJb5","text-palette-inside":"workspace_text_palette_text-palette-inside_LgHnf","typography-item":"workspace_text_palette_typography-item_d0vFL","typography-name":"workspace_text_palette_typography-name_NVBRv","typography-font":"workspace_text_palette_typography-font_paqmC","typography-data":"workspace_text_palette_typography-data_eKyme","mid-item":"workspace_text_palette_mid-item_uTcD2","small-item":"workspace_text_palette_small-item_1Y6mx"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.css.json b/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.css.json
index 3629792d0a..d3f82dd944 100644
--- a/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.css.json
+++ b/frontend/src/app/main/ui/workspace/text_palette_ctx_menu.css.json
@@ -1 +1 @@
-{"button-primary":"workspace_text_palette_ctx_menu_button-primary_bkGXB","button-secondary":"workspace_text_palette_ctx_menu_button-secondary_mbPs7","button-icon":"workspace_text_palette_ctx_menu_button-icon_oklnh","button-icon-small":"workspace_text_palette_ctx_menu_button-icon-small_ebriD","workspace-context-menu":"workspace_text_palette_ctx_menu_workspace-context-menu_OShZn","palette-library":"workspace_text_palette_ctx_menu_palette-library_pDyi5","selected":"workspace_text_palette_ctx_menu_selected_k3kOd","icon-wrapper":"workspace_text_palette_ctx_menu_icon-wrapper_Xoj9o","file-library":"workspace_text_palette_ctx_menu_file-library_t-25M","library-name":"workspace_text_palette_ctx_menu_library-name_TGs9Z"}
\ No newline at end of file
+{"button-primary":"workspace_text_palette_ctx_menu_button-primary_bkGXB","button-secondary":"workspace_text_palette_ctx_menu_button-secondary_mbPs7","button-tertiary":"workspace_text_palette_ctx_menu_button-tertiary_Z74wM","button-tag":"workspace_text_palette_ctx_menu_button-tag_OmlzA","button-icon":"workspace_text_palette_ctx_menu_button-icon_oklnh","button-icon-small":"workspace_text_palette_ctx_menu_button-icon-small_ebriD","workspace-context-menu":"workspace_text_palette_ctx_menu_workspace-context-menu_OShZn","palette-library":"workspace_text_palette_ctx_menu_palette-library_pDyi5","selected":"workspace_text_palette_ctx_menu_selected_k3kOd","icon-wrapper":"workspace_text_palette_ctx_menu_icon-wrapper_Xoj9o","file-library":"workspace_text_palette_ctx_menu_file-library_t-25M","asset-element":"workspace_text_palette_ctx_menu_asset-element_-ynNV","library-name":"workspace_text_palette_ctx_menu_library-name_TGs9Z"}
\ No newline at end of file