0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-16 17:51:18 -05:00

Add new palette UI

This commit is contained in:
Eva 2023-04-27 12:44:11 +02:00 committed by Alonso Torres
parent 56bee7dd7c
commit fe8f13ed57
114 changed files with 6754 additions and 3172 deletions
common/src/app/common/pages
frontend
resources
src/app/main

View file

@ -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

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 4.667h2c.438 0 .871.086 1.276.253a3.342 3.342 0 011.804 1.804 3.345 3.345 0 010 2.552 3.343 3.343 0 01-1.804 1.804 3.345 3.345 0 01-1.276.253h-2m-4 0H4c-.438 0-.871-.086-1.276-.253A3.333 3.333 0 014 4.667h2m-.667 3.326h5.334z"/>
</svg>

After

(image error) Size: 357 B

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M2 9.75C2 9.06 2.56 8.5 3.25 8.5H10M2 9.75C2 10.44 2.56 11 3.25 11H10V1H3.25C2.56 1 2 1.56 2 2.25V9.75Z"/>
<path d="M2.667 13c0 .92.746 1.667 1.666 1.667h9V1.333h-9c-.92 0-1.666.747-1.666 1.667v10zm0 0c0-.92.746-1.667 1.666-1.667h9"/>
</svg>

Before

(image error) Size: 235 B

After

(image error) Size: 247 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M11.333 12H2m12-8H2m6.667 4H2"/>
</svg>

After

(image error) Size: 161 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.72 2.333H9.28c-1.788 0-3.333 1.493-3.333 3.334S7.492 9 9.28 9h2m0-6.667v11.334m2-11.334v11.334m-12-7.334l2 2-2 2"/>
</svg>

After

(image error) Size: 248 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.72 2.333H9.28c-1.788 0-3.333 1.493-3.333 3.334S7.492 9 9.28 9h2m0-6.667v11.334m2-11.334v11.334m-10-7.334l-2 2 2 2"/>
</svg>

After

(image error) Size: 249 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M11.333 12H2m12-8H2m6.667 4H2"/>
</svg>

After

(image error) Size: 161 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M10 3L8 5 6 3m6.667 10H3.333m9.334-2.667H3.333"/>
</svg>

After

(image error) Size: 178 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M5.667 10.667l.863-1.918m0 0l1.537-3.416 1.536 3.416m-3.073 0h3.073m0 0l.864 1.918M1.333 3.333c0-1.103.897-2 2-2h9.334c1.103 0 2 .897 2 2v9.334c0 1.103-.897 2-2 2H3.333c-1.103 0-2-.897-2-2V3.333z"/>
</svg>

After

(image error) Size: 327 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 8H2m12-4H2m12 8H2"/>
</svg>

After

(image error) Size: 153 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M2.667 14l-1.334-1.333m0 0l1.334-1.333m-1.334 1.333h13.334M13.333 14l1.334-1.333m0 0l-1.334-1.333M2.5 8l.959-2.157m0 0L5.167 2l1.708 3.843m-3.416 0h3.416m0 0L7.833 8m.834-6.5l2.666 6L14 1.5"/>
</svg>

After

(image error) Size: 321 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M8.333 3.333H15M8.333 8H15m-6.667 4.667H15M1 4l2-2 2 2m-4 8l2 2 2-2M3 2.667v10.666"/>
</svg>

After

(image error) Size: 214 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 7.333c0-1.031.689-2 2.167-2 1.478 0 2.166.969 2.166 2v.655m0 .178v2.167c0 1.334 1.334 1.334 1.334 1.334m-13-4.334c0-1.031.688-2 2.166-2S6 6.302 6 7.333v.655m0 .178v2.167c0 1.334 1.333 1.334 1.333 1.334m3.334.333c1.021 0 2.616-.352 2.665-3.832L13.333 8c0 .727-1.889.667-2.666.667-1.334 0-2 .666-2 1.666 0 1 .963 1.667 2 1.667zm-7.334 0c1.021 0 2.616-.352 2.666-3.832L6 8c0 .727-1.889.667-2.667.667-1.333 0-2 .666-2 1.666 0 1 .963 1.667 2 1.667z"/>
</svg>

After

(image error) Size: 578 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 14l2-2 2 2M3.333 6.667h9.334M3.333 9.333h9.334M10 2L8 4 6 2"/>
</svg>

After

(image error) Size: 194 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M.667 12l1.318-2.877m0 0L4.333 4l2.348 5.123m-4.696 0h4.696m0 0L8 12m1.667-4.667c0-1.031.688-2 2.166-2s2.167.969 2.167 2v.655m0 .178v2.167c0 1.334 1.333 1.334 1.333 1.334m-4 .333c1.021 0 2.616-.352 2.666-3.832L14 8c0 .727-1.889.667-2.667.667-1.333 0-2 .666-2 1.666 0 1 .963 1.667 2 1.667z"/>
</svg>

After

(image error) Size: 420 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M11.444 3.533C9.96.878 5 1.48 5 4.667c0 1.333 1 2 1 2m-1.482 4.3c.99 3.185 6.926 2.826 6.926-.531 0-1.317-1.249-2.61-2.503-2.621m0 0h4.392m-4.392 0H2"/>
</svg>

After

(image error) Size: 281 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M6 13l2-2 2 2M3.333 3h9.334M3.333 5.667h9.334"/>
</svg>

After

(image error) Size: 177 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M11.333 2.667v4.666a3.334 3.334 0 11-6.666 0V2.667M12 14H4"/>
</svg>

After

(image error) Size: 190 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M.667 12l1.318-2.877m0 0L4.333 4l2.348 5.123m-4.696 0h4.696m0 0L8 12l1.319-2.877m0 0L11.667 4l2.348 5.123m-4.696 0h4.696m0 0L15.333 12"/>
</svg>

After

(image error) Size: 266 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
<path d="M5.333 4H14M5.333 8H14m-8.667 4H14M1.333 4h1.334M1.333 8h1.334m-1.334 4h1.334"/>
</svg>

After

(image error) Size: 209 B

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -15,6 +15,11 @@
background: none;
cursor: pointer;
}
@mixin removeInputStyle {
border: none;
background: none;
outline: none;
}
@mixin tabTitleTipography {
font-family: "worksans", sans-serif;

View file

@ -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);

View file

@ -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);
}

View file

@ -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,

View file

@ -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
[]

View file

@ -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"}
{"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"}

View file

@ -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);
}

View file

@ -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]

View file

@ -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"}
{"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"}

View file

@ -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;

View file

@ -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])))

View file

@ -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"}

View file

@ -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);
}

View file

@ -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))

View file

@ -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]]))

View file

@ -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"}

View file

@ -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);
}
}
}

View file

@ -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])]]))

View file

@ -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"}

View file

@ -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;
}
}

View file

@ -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]])))]]])))

View file

@ -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"}

View file

@ -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);
}
}
}
}

View file

@ -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)]]))

View file

@ -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"}
{"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"}

View file

@ -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;
}
}
}

View file

@ -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])]))

View file

@ -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"}

View file

@ -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;
}
}
}

View file

@ -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)}]]]))
[: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}]]]]]]]))

View file

@ -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"}
{"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"}

View file

@ -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;
}
}
}
}
}

View file

@ -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

View file

@ -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]

View file

@ -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))

View file

@ -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"}
{"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"}

View file

@ -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"}
{"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"}

View file

@ -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"}
{"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"}

View file

@ -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"}
{"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"}

View file

@ -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

View file

@ -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}])]]]])]))

View file

@ -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"}

View file

@ -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;
}

View file

@ -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"}
{"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"}

View file

@ -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;

View file

@ -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])]]))

View file

@ -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"}
{"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"}

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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"}

View file

@ -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;
}
}

View file

@ -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}]]]))

View file

@ -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"}

View file

@ -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);
}
}

View file

@ -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))))))))

View file

@ -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"}

View file

@ -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;
}

View file

@ -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])])}])]]))

View file

@ -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"}

View file

@ -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);
}

View file

@ -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}])]))

View file

@ -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"}

View file

@ -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;
}

View file

@ -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])])}])]]))

View file

@ -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"}

View file

@ -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;
}
}

View file

@ -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}]]]]]))

View file

@ -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"}

View file

@ -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);
}
}

View file

@ -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])])}])]]))

View file

@ -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"}

View file

@ -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);
}
}
}

View file

@ -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)

View file

@ -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"}
{"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"}

View file

@ -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"}
{"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"}

View file

@ -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"}
{"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"}

View file

@ -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);
}

Some files were not shown because too many files have changed in this diff Show more