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

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

View file

@ -13,7 +13,9 @@
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.components.shape-icon-refactor :as sic]
[app.main.ui.components.title-bar :refer [title-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.icons :as i]
@ -128,9 +130,14 @@
(swap! filter-state assoc :search-text "" :num-items 100)))
update-search-text
(mf/use-callback
(mf/use-fn
(mf/deps new-css-system)
(fn [event]
(let [value (-> event dom/get-target dom/get-value)]
;; NOTE: When old-css-system is removed this function will recibe value and event
;; Let won't be necessary any more
(let [value (if new-css-system
event
(dom/get-target-val event))]
(swap! filter-state assoc :search-text value :num-items 100))))
toggle-search
@ -226,12 +233,9 @@
(fn [event]
(let [enter? (kbd/enter? event)
esc? (kbd/esc? event)
input-node (dom/event->target event)]
(when enter?
(dom/blur! input-node))
(when esc?
(dom/blur! input-node)))))]
node (dom/event->target event)]
(when ^boolean enter? (dom/blur! node))
(when ^boolean esc? (dom/blur! node)))))]
[filtered-objects
handle-show-more
@ -243,33 +247,33 @@
(css :search) true)
(dom/classnames :tool-window-bar true
:search true))}
[:span {:class (if new-css-system
(dom/classnames (css :search-box) true)
(dom/classnames :search-box true))}
[:button
{:on-click toggle-filters
:class (if new-css-system
(dom/classnames :active active?
(css :filter-button) true)
(dom/classnames :active active?
:filter true))}
(if new-css-system
i/filter-refactor
i/icon-filter)]
[:div {:class (dom/classnames (css :search-input-wrapper) new-css-system)}
[:input {:on-change update-search-text
:value (:search-text @filter-state)
:auto-focus (:show-search-box @filter-state)
:placeholder (tr "workspace.sidebar.layers.search")
:on-key-down handle-key-down}]
(when (not (= "" (:search-text @filter-state)))
[:button {:class (if new-css-system
(dom/classnames (css :clear) true)
(dom/classnames :clear true))
:on-click clear-search-text}
(if new-css-system
i/delete-text-refactor
i/exclude)])]]
(if new-css-system
[:& search-bar
{:on-change update-search-text
:value (:search-text @filter-state)
:on-clear clear-search-text
:placeholder (tr "workspace.sidebar.layers.search")}
[:button
{:on-click toggle-filters
:class (dom/classnames :active active?
(css :filter-button) true)}
i/filter-refactor]]
[:span.search-box
[:button.filter
{:on-click toggle-filters
:class (dom/classnames :active active?)}
i/icon-filter]
[:div
[:input {:on-change update-search-text
:value (:search-text @filter-state)
:auto-focus (:show-search-box @filter-state)
:placeholder (tr "workspace.sidebar.layers.search")
:on-key-down handle-key-down}]
(when (not (= "" (:search-text @filter-state)))
[:button.clear {:on-click clear-search-text}
i/exclude])]])
[:button {:class (dom/classnames (css :close-search) new-css-system)
:on-click toggle-search}
(if new-css-system
@ -397,20 +401,18 @@
[:span {:on-click (add-filter :text)} i/text (tr "workspace.sidebar.layers.texts")]
[:span {:on-click (add-filter :image)} i/image (tr "workspace.sidebar.layers.images")]
[:span {:on-click (add-filter :shape)} i/curve (tr "workspace.sidebar.layers.shapes")]]))]
[:div {:class (if new-css-system
(dom/classnames (css :tool-window-bar) true)
(dom/classnames :tool-window-bar true))}
[:span {:class (if new-css-system
(dom/classnames (css :page-name) true)
(dom/classnames :page-name true))}
(:name page)]
[:button {:class (if new-css-system
(dom/classnames (css :icon-search) true)
(dom/classnames :icon-search true))
:on-click toggle-search}
(if new-css-system
i/search-refactor
i/search)]]))]))
(if new-css-system
[:div {:class (dom/classnames (css :tool-window-bar) true)}
[:& title-bar {:collapsable? false
:title (:name page)
:on-btn-click toggle-search
:btn-children i/search-refactor}]]
[:div.tool-window-bar
[:span.page-name
(:name page)]
[:button.icon-search {:on-click toggle-search}
i/search]])))]))
(mf/defc layers-toolbox
{:wrap [mf/memo]}

View file

@ -1 +1 @@
{"button-primary":"sidebar_layers_button-primary_q9e2I","layers":"sidebar_layers_layers_87ZOo","tool-window-bar":"sidebar_layers_tool-window-bar_lg54C","search":"sidebar_layers_search_zjs2x","close-search":"sidebar_layers_close-search_baIhK","icon-search":"sidebar_layers_icon-search_6kWUn","button-secondary":"sidebar_layers_button-secondary_H4lpi","active-filters":"sidebar_layers_active-filters_-JMMP","layer-filter":"sidebar_layers_layer-filter_rHZTz","search-box":"sidebar_layers_search-box_JtqOV","search-input-wrapper":"sidebar_layers_search-input-wrapper_oJa-7","clear":"sidebar_layers_clear_sLcl1","button-icon":"sidebar_layers_button-icon_SD8PP","button-icon-small":"sidebar_layers_button-icon-small_v5L-u","filters-container":"sidebar_layers_filters-container_c1Ux9","filter-menu-item":"sidebar_layers_filter-menu-item_aZd0D","filter-menu-item-tick":"sidebar_layers_filter-menu-item-tick_JNdIK","filter-menu-item-name-wrapper":"sidebar_layers_filter-menu-item-name-wrapper_DtGkH","filter-menu-item-icon":"sidebar_layers_filter-menu-item-icon_Oi3Ix","layer-filter-icon":"sidebar_layers_layer-filter-icon_0yKrb","layer-filter-close":"sidebar_layers_layer-filter-close_3mV4i","focus-title":"sidebar_layers_focus-title_35PvQ","back-button-icon":"sidebar_layers_back-button-icon_mHv6g","page-name":"sidebar_layers_page-name_8ZDRR","filter-button":"sidebar_layers_filter-button_KXxHh","focus-name":"sidebar_layers_focus-name_Fderf","focus-mode-tag-wrapper":"sidebar_layers_focus-mode-tag-wrapper_OHXCG","focus-mode-tag":"sidebar_layers_focus-mode-tag_J5ItD","layer-filter-name":"sidebar_layers_layer-filter-name_Y4PuB","filter-menu-item-name":"sidebar_layers_filter-menu-item-name_rxeut","selected":"sidebar_layers_selected_V5Vv3","tool-window-content":"sidebar_layers_tool-window-content_YnpDB","element-list":"sidebar_layers_element-list_nAntB"}
{"button-primary":"sidebar_layers_button-primary_q9e2I","button-secondary":"sidebar_layers_button-secondary_H4lpi","button-tertiary":"sidebar_layers_button-tertiary_5mq-9","layers":"sidebar_layers_layers_87ZOo","tool-window-bar":"sidebar_layers_tool-window-bar_lg54C","search":"sidebar_layers_search_zjs2x","close-search":"sidebar_layers_close-search_baIhK","icon-search":"sidebar_layers_icon-search_6kWUn","button-tag":"sidebar_layers_button-tag_FT7oa","active-filters":"sidebar_layers_active-filters_-JMMP","layer-filter":"sidebar_layers_layer-filter_rHZTz","button-icon":"sidebar_layers_button-icon_SD8PP","button-icon-small":"sidebar_layers_button-icon-small_v5L-u","filters-container":"sidebar_layers_filters-container_c1Ux9","filter-menu-item":"sidebar_layers_filter-menu-item_aZd0D","filter-menu-item-tick":"sidebar_layers_filter-menu-item-tick_JNdIK","filter-menu-item-name-wrapper":"sidebar_layers_filter-menu-item-name-wrapper_DtGkH","filter-menu-item-icon":"sidebar_layers_filter-menu-item-icon_Oi3Ix","layer-filter-icon":"sidebar_layers_layer-filter-icon_0yKrb","layer-filter-close":"sidebar_layers_layer-filter-close_3mV4i","focus-title":"sidebar_layers_focus-title_35PvQ","back-button-icon":"sidebar_layers_back-button-icon_mHv6g","asset-element":"sidebar_layers_asset-element_-dbA7","page-name":"sidebar_layers_page-name_8ZDRR","filter-button":"sidebar_layers_filter-button_KXxHh","focus-name":"sidebar_layers_focus-name_Fderf","focus-mode-tag-wrapper":"sidebar_layers_focus-mode-tag-wrapper_OHXCG","focus-mode-tag":"sidebar_layers_focus-mode-tag_J5ItD","layer-filter-name":"sidebar_layers_layer-filter-name_Y4PuB","filter-menu-item-name":"sidebar_layers_filter-menu-item-name_rxeut","selected":"sidebar_layers_selected_V5Vv3","tool-window-content":"sidebar_layers_tool-window-content_YnpDB","element-list":"sidebar_layers_element-list_nAntB"}

View file

@ -20,13 +20,14 @@
min-height: $s-32;
margin-top: $s-2;
margin-bottom: $s-4;
padding-right: $s-8;
.page-name {
@include tabTitleTipography;
padding: 0 $s-12;
color: var(--title-foreground-color);
}
.icon-search {
@extend .button-primary;
@extend .button-tertiary;
height: $s-32;
width: calc($s-24 + $s-4);
border-radius: $br-8;
@ -38,94 +39,41 @@
}
&.search {
padding: 0 $s-8 0 $s-12;
.search-box {
display: grid;
grid-template-columns: auto 1fr;
gap: $s-2;
gap: $s-4;
.filter-button {
@include flexCenter;
@include buttonStyle;
height: $s-32;
width: 100%;
margin-right: $s-4;
border-radius: $br-8;
background-color: var(--color-background-primary);
.filter-button {
@include flexCenter;
@include buttonStyle;
height: $s-32;
width: $s-32;
margin: 0;
border: 1px solid var(--color-background-tertiary);
border-radius: $br-8 $br-2 $br-2 $br-8;
background-color: var(--color-background-tertiary);
width: $s-32;
margin: 0;
border: 1px solid var(--color-background-tertiary);
border-radius: $br-8 $br-2 $br-2 $br-8;
background-color: var(--color-background-tertiary);
svg {
height: $s-16;
width: $s-16;
stroke: var(--icon-foreground);
}
&:focus {
border: 1px solid var(--input-border-color-focus);
outline: 0;
background-color: var(--input-background-color-active);
color: var(--input-foreground-color-active);
svg {
height: $s-16;
width: $s-16;
stroke: var(--icon-foreground);
}
&:focus {
border: 1px solid var(--input-border-color-focus);
outline: 0;
background-color: var(--input-background-color-active);
color: var(--input-foreground-color-active);
svg {
background-color: var(--input-background-color-active);
}
}
&:hover {
border: 1px solid var(--input-background-color-hover);
background-color: var(--input-background-color-hover);
svg {
background-color: var(--input-background-color-hover);
stroke: var(--button-foreground-hover);
}
}
}
.search-input-wrapper {
@include flexCenter;
height: $s-32;
width: 100%;
border: 1px solid var(--color-background-tertiary);
border-radius: $br-2 $br-8 $br-8 $br-2;
background-color: var(--color-background-tertiary);
input {
width: 100%;
margin: $s-8;
border: 0;
background-color: var(--input-background-color);
font-size: $fs-12;
color: var(--input-foreground-color);
&:focus {
outline: none;
}
}
&:hover {
border: 1px solid var(--input-background-color-hover);
&:hover {
border: 1px solid var(--input-background-color-hover);
background-color: var(--input-background-color-hover);
svg {
background-color: var(--input-background-color-hover);
input {
background-color: var(--input-background-color-hover);
}
}
&:focus-within {
background-color: var(--input-background-color-active);
color: var(--input-foreground-color-active);
border: 1px solid var(--input-border-color-focus);
input {
background-color: var(--input-background-color-active);
}
}
.clear {
@extend .button-secondary;
border-radius: $br-8;
height: 100%;
svg {
@extend .button-icon-small;
color: transparent;
}
stroke: var(--button-foreground-hover);
}
}
}
.close-search {
@extend .button-primary;
@extend .button-tertiary;
height: $s-32;
width: $s-28;
min-width: $s-28;
@ -184,7 +132,7 @@
gap: $s-4;
margin: 0 $s-12;
.layer-filter {
@extend .button-secondary;
@extend .button-tag;
@include buttonStyle;
gap: $s-6;
height: $s-24;
@ -296,7 +244,6 @@
flex-direction: column;
height: 100%;
width: 100%;
border-radius: $br-8;
overflow-y: auto;
overflow-x: hidden;
scrollbar-gutter: stable;

View file

@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.workspace.sidebar.options.menus.typography
(:require-macros [app.main.style :refer [css]])
(:require
["react-virtualized" :as rvt]
[app.common.data :as d]
@ -19,6 +20,9 @@
[app.main.store :as st]
[app.main.ui.components.editable-select :refer [editable-select]]
[app.main.ui.components.numeric-input :refer [numeric-input]]
[app.main.ui.components.radio-buttons :refer [nilable-option radio-buttons]]
[app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.components.select :refer [select]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
@ -57,7 +61,8 @@
{::mf/wrap [mf/memo]}
[{:keys [font current? on-click style]}]
(let [item-ref (mf/use-ref)
on-click (mf/use-callback (mf/deps font) #(on-click font))]
on-click (mf/use-callback (mf/deps font) #(on-click font))
new-css-system (mf/use-ctx ctx/new-css-system)]
(mf/use-effect
(mf/deps current?)
@ -67,12 +72,23 @@
(when-not (dom/is-in-viewport? element)
(dom/scroll-into-view! element))))))
[:div.font-item {:ref item-ref
:style style
:class (when current? "selected")
:on-click on-click}
[:span.icon (when current? i/tick)]
[:span.label (:name font)]]))
(if new-css-system
[:div {:class (css :font-wrapper)
:style style
:ref item-ref
:on-click on-click}
[:div {:class (dom/classnames
(css :font-item) true
(css :selected) current?)}
[:span {:class (css :label)} (:name font)]
[:span {:class (css :icon)} (when current? i/tick-refactor)]]]
[:div.font-item {:ref item-ref
:style style
:class (when current? "selected")
:on-click on-click}
[:span.icon (when current? i/tick)]
[:span.label (:name font)]])))
(declare row-renderer)
@ -87,25 +103,17 @@
(comp (filter #(contains? backends (:backend %)))))]
(into [] xform fonts)))
;; (defn- toggle-backend
;; [backends id]
;; (if (contains? backends id)
;; (disj backends id)
;; (conj backends id)))
(mf/defc font-selector
[{:keys [on-select on-close current-font show-recent] :as props}]
(let [selected (mf/use-state current-font)
state (mf/use-state {:term "" :backends #{}})
(let [new-css-system (mf/use-ctx ctx/new-css-system)
selected (mf/use-state current-font)
state (mf/use-state {:term "" :backends #{}})
flist (mf/use-ref)
input (mf/use-ref)
flist (mf/use-ref)
input (mf/use-ref)
fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
fontsdb (mf/deref fonts/fontsdb)
;; Filtering deleted fonts
recent-fonts (->> (mf/deref refs/workspace-recent-fonts)
(into [] (filter #(some? (get fontsdb (:id %))))))
fonts (mf/use-memo (mf/deps @state) #(filter-fonts @state @fonts/fonts))
recent-fonts (mf/deref refs/workspace-recent-fonts)
select-next
(mf/use-callback
@ -136,9 +144,11 @@
on-filter-change
(mf/use-callback
(mf/deps)
(mf/deps new-css-system)
(fn [event]
(let [value (dom/get-target-val event)]
(let [value (if new-css-system
event
(dom/get-target-val event))]
(swap! state assoc :term value))))
on-select-and-close
@ -184,60 +194,71 @@
#(let [offset (.getOffsetForRow ^js inst #js {:alignment "center" :index index})]
(.scrollToPosition ^js inst offset))))))
[:div.font-selector
[:div.font-selector-dropdown
[:header
[:input {:placeholder (tr "workspace.options.search-font")
:value (:term @state)
:ref input
:spell-check false
:on-change on-filter-change}]
(when (and recent-fonts show-recent)
[:hr]
[*
[:p.title (tr "workspace.options.recent-fonts")]
(for [[idx font] (d/enumerate recent-fonts)]
[:& font-item {:key (dm/str "font-" idx)
:font font
:style {}
:on-click on-select-and-close
:current? (= (:id font) (:id @selected))}])])
(if new-css-system
[:div {:class (css :font-selector)}
[:div {:class (css :font-selector-dropdown)}
[:div {:class (css :header)}
[:& search-bar {:on-change on-filter-change
:value (:term @state)
:placeholder (tr "workspace.options.search-font")}]
(when (and recent-fonts show-recent)
[*
[:p {:class :title} (tr "workspace.options.recent-fonts")]
(for [[idx font] (d/enumerate recent-fonts)]
[:& font-item {:key (dm/str "font-" idx)
:font font
:style {}
:on-click on-select-and-close
:current? (= (:id font) (:id @selected))}])])]
#_[:div.options
{:on-click #(swap! state assoc :show-options true)
:class (when (seq (:backends @state)) "active")}
i/picker-hsv]
[:div {:class (css :fonts-list)}
[:> rvt/AutoSizer {}
(fn [props]
(let [width (unchecked-get props "width")
height (unchecked-get props "height")
render #(row-renderer fonts @selected on-select-and-close %)]
(mf/html
[:> rvt/List #js {:height height
:ref flist
:width width
:rowCount (count fonts)
:rowHeight 36
:rowRenderer render}])))]]]]
#_[:& dropdown {:show (:show-options @state false)
:on-close #(swap! state dissoc :show-options)}
(let [backends (:backends @state)]
[:div.backend-filters.dropdown {:ref ddown}
[:div.backend-filter
{:class (when (backends :custom) "selected")
:on-click #(swap! state update :backends toggle-backend :custom)}
[:div.checkbox-icon i/tick]
[:div.backend-name (tr "labels.custom-fonts")]]
[:div.backend-filter
{:class (when (backends :google) "selected")
:on-click #(swap! state update :backends toggle-backend :google)}
[:div.checkbox-icon i/tick]
[:div.backend-name "Google Fonts"]]])]]
[:div.font-selector
[:div.font-selector-dropdown
[:header
[:input {:placeholder (tr "workspace.options.search-font")
:value (:term @state)
:ref input
:spell-check false
:on-change on-filter-change}]
(when (and recent-fonts show-recent)
[:hr]
[*
[:p.title (tr "workspace.options.recent-fonts")]
(for [[idx font] (d/enumerate recent-fonts)]
[:& font-item {:key (dm/str "font-" idx)
:font font
:style {}
:on-click on-select-and-close
:current? (= (:id font) (:id @selected))}])])]
[:hr]
[:hr]
[:div.fonts-list
[:> rvt/AutoSizer {}
(fn [props]
(let [width (unchecked-get props "width")
height (unchecked-get props "height")
render #(row-renderer fonts @selected on-select-and-close %)]
(mf/html
[:> rvt/List #js {:height height
:ref flist
:width width
:rowCount (count fonts)
:rowHeight 32
:rowRenderer render}])))]]]]))
[:div.fonts-list
[:> rvt/AutoSizer {}
(fn [props]
(let [width (unchecked-get props "width")
height (unchecked-get props "height")
render #(row-renderer fonts @selected on-select-and-close %)]
(mf/html
[:> rvt/List #js {:height height
:ref flist
:width width
:rowCount (count fonts)
:rowHeight 32
:rowRenderer render}])))]]]])))
(defn row-renderer
[fonts selected on-select props]
(let [index (unchecked-get props "index")
@ -259,12 +280,11 @@
font-id (or font-id (:font-id txt/default-text-attrs))
font-size (or font-size (:font-size txt/default-text-attrs))
font-variant-id (or font-variant-id (:font-variant-id txt/default-text-attrs))
new-css-system (mf/use-ctx ctx/new-css-system)
fonts (mf/deref fonts/fontsdb)
font (get fonts font-id)
;; Filtering deleted fonts
recent-fonts (->> (mf/deref refs/workspace-recent-fonts)
(into [] (filter #(some? (get fonts (:id %))))))
recent-fonts (mf/deref refs/workspace-recent-fonts)
last-font (mf/use-ref nil)
open-selector? (mf/use-state false)
@ -319,57 +339,110 @@
(when (some? on-blur)
(on-blur))
(when (mf/ref-val last-font)
(st/emit! (fts/add-recent-font (mf/ref-val last-font))))
))]
(st/emit! (fts/add-recent-font (mf/ref-val last-font))))))]
(if new-css-system
[:*
(when @open-selector?
[:& font-selector
{:current-font font
:on-close on-font-selector-close
:on-select on-font-select
:show-recent show-recent}])
[:*
(when @open-selector?
[:& font-selector
{:current-font font
:on-close on-font-selector-close
:on-select on-font-select
:show-recent show-recent}])
[:div
{:class (css :font-option)
:on-click #(reset! open-selector? true)}
(cond
(= :multiple font-id)
"--"
[:div.row-flex
[:div.input-select.font-option
{:on-click #(reset! open-selector? true)}
(cond
(= :multiple font-id)
"--"
(some? font)
[:*
[:span {:class (css :name)}
(:name font)]
[:span {:class (css :icon)}
i/arrow-refactor]]
(some? font)
(:name font)
:else
(tr "dashboard.fonts.deleted-placeholder"))]
:else
(tr "dashboard.fonts.deleted-placeholder"))]]
[:div {:class (css :font-modifiers)}
[:div {:class (css :font-size-options)}
(let [sizes [8 9 10 11 12 14 16 18 24 36 48 72]
basic-size-options (map (fn [number]
{:value (dm/str number) :key (dm/str "size-" number) :label (dm/str number)}) sizes)
size-options (if (= font-size :multiple)
(conj {:value :key :mulitple-sizes :multiple :label "--"} basic-size-options)
basic-size-options)]
[:& select
{:class (css :font-size-select)
:default-value (attr->string font-size)
:options size-options
:on-change on-font-size-change
:on-blur on-blur}])]
[:div {:class (css :font-variant-options)}
(let [basic-variant-options (map (fn [variant]
{:value (:id variant) :key (pr-str variant) :label (:name variant)}) (:variants font))
variant-options (if (= font-size :multiple)
(conj {:value :multiple :key :multiple-variants :label "--"} basic-variant-options)
basic-variant-options)]
;; TODO Add disabled mode
[:& select
{:class (css :font-variant-select)
:default-value (attr->string font-variant-id)
:options variant-options
:on-change on-font-variant-change
:on-blur on-blur}])]]]
[:*
(when @open-selector?
[:& font-selector
{:current-font font
:on-close on-font-selector-close
:on-select on-font-select
:show-recent show-recent}])
[:div.row-flex
[:div.input-select.font-option
{:on-click #(reset! open-selector? true)}
(cond
(= :multiple font-id)
"--"
(some? font)
(:name font)
:else
(tr "dashboard.fonts.deleted-placeholder"))]]
[:div.row-flex
(let [size-options [8 9 10 11 12 14 16 18 24 36 48 72]
size-options (if (= font-size :multiple) (into [""] size-options) size-options)]
[:& editable-select
{:value (attr->string font-size)
:class "input-option size-option"
:options size-options
:type "number"
:placeholder "--"
:min 3
:max 1000
:on-change on-font-size-change
:on-blur on-blur}])
[:select.input-select.variant-option
{:disabled (= font-id :multiple)
:value (attr->string font-variant-id)
:on-change on-font-variant-change
:on-blur on-blur}
(when (or (= font-id :multiple) (= font-variant-id :multiple))
[:option {:value ""} "--"])
(for [variant (:variants font)]
[:option {:value (:id variant)
:key (pr-str variant)}
(:name variant)])]]]))
[:div.row-flex
(let [size-options [8 9 10 11 12 14 16 18 24 36 48 72]
size-options (if (= font-size :multiple) (into [""] size-options) size-options)]
[:& editable-select
{:value (attr->string font-size)
:class "input-option size-option"
:options size-options
:type "number"
:placeholder "--"
:min 3
:max 1000
:on-change on-font-size-change
:on-blur on-blur}])
[:select.input-select.variant-option
{:disabled (= font-id :multiple)
:value (attr->string font-variant-id)
:on-change on-font-variant-change
:on-blur on-blur}
(when (or (= font-id :multiple) (= font-variant-id :multiple))
[:option {:value ""} "--"])
(for [variant (:variants font)]
[:option {:value (:id variant)
:key (pr-str variant)}
(:name variant)])]]])))
(mf/defc spacing-options
{::mf/wrap-props false}
@ -379,101 +452,243 @@
line-height (or line-height "1.2")
letter-spacing (or letter-spacing "0")
new-css-system (mf/use-ctx ctx/new-css-system)
line-height-nillable (if (= (str line-height) "1.2") false true)
handle-change
(fn [value attr]
(on-change {attr (str value)}))]
(if new-css-system
[:div {:class (css :spacing-options)}
[:div {:class (css :line-height)}
[:span {:class (css :icon)
:alt (tr "workspace.options.text-options.line-height")}
i/text-lineheight-refactor]
[:div.spacing-options
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.line-height")}
i/line-height]
[:> numeric-input
{:min -200
:max 200
:step 0.1
:default "1.2"
:value (attr->string line-height)
:placeholder (tr "settings.multiple")
:nillable line-height-nillable
:on-change #(handle-change % :line-height)
:on-blur on-blur}]]
[:> numeric-input
{:min -200
:max 200
:step 0.1
:default "1.2"
:klass (css :line-height-input)
:value (attr->string line-height)
:placeholder (tr "settings.multiple")
:nillable line-height-nillable
:on-change #(handle-change % :line-height)
:on-blur on-blur}]]
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.letter-spacing")}
i/letter-spacing]
[:> numeric-input
{:min -200
:max 200
:step 0.1
:value (attr->string letter-spacing)
:placeholder (tr "settings.multiple")
:on-change #(handle-change % :letter-spacing)
:on-blur on-blur}]]]))
[:div {:class (css :letter-spacing)}
[:span
{:class (css :icon)
:alt (tr "workspace.options.text-options.letter-spacing")}
i/text-letterspacing-refactor]
[:> numeric-input
{:min -200
:max 200
:step 0.1
:klass (css :letter-spacing-input)
:value (attr->string letter-spacing)
:placeholder (tr "settings.multiple")
:on-change #(handle-change % :letter-spacing)
:on-blur on-blur}]]]
[:div.spacing-options
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.line-height")}
i/line-height]
[:> numeric-input
{:min -200
:max 200
:step 0.1
:default "1.2"
:value (attr->string line-height)
:placeholder (tr "settings.multiple")
:nillable line-height-nillable
:on-change #(handle-change % :line-height)
:on-blur on-blur}]]
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.letter-spacing")}
i/letter-spacing]
[:> numeric-input
{:min -200
:max 200
:step 0.1
:value (attr->string letter-spacing)
:placeholder (tr "settings.multiple")
:on-change #(handle-change % :letter-spacing)
:on-blur on-blur}]]])))
(mf/defc text-transform-options
{::mf/wrap-props false}
[{:keys [values on-change on-blur]}]
(let [text-transform (or (:text-transform values) "none")
new-css-system (mf/use-ctx ctx/new-css-system)
handle-change
(fn [_ type]
(on-change {:text-transform type})
(fn [type]
(if (= text-transform type)
(on-change {:text-transform "unset"})
(on-change {:text-transform type}))
(when (some? on-blur) (on-blur)))]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-transform))
:on-focus #(dom/prevent-default %)
:on-click #(handle-change % "none")}
i/minus]
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.uppercase")
:class (dom/classnames :current (= "uppercase" text-transform))
:on-click #(handle-change % "uppercase")}
i/uppercase]
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.lowercase")
:class (dom/classnames :current (= "lowercase" text-transform))
:on-click #(handle-change % "lowercase")}
i/lowercase]
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.titlecase")
:class (dom/classnames :current (= "capitalize" text-transform))
:on-click #(handle-change % "capitalize")}
i/titlecase]]))
(if new-css-system
[:div {:class (css :text-transform)}
[:& radio-buttons {:selected text-transform
:on-change handle-change
:name "text-transform"}
[:& nilable-option {:icon (mf/html i/text-uppercase-refactor)
:value "uppercase"
:id :uppercase}]
[:& nilable-option {:icon (mf/html i/text-lowercase-refactor)
:value "lowercase"
:id :lowercase}]
[:& nilable-option {:icon "Aa"
:value "capitalize"
:id :capitalize}]]]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-transform))
:on-focus #(dom/prevent-default %)
:on-click #(handle-change "none")}
i/minus]
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.uppercase")
:class (dom/classnames :current (= "uppercase" text-transform))
:on-click #(handle-change "uppercase")}
i/uppercase]
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.lowercase")
:class (dom/classnames :current (= "lowercase" text-transform))
:on-click #(handle-change "lowercase")}
i/lowercase]
[:span.tooltip.tooltip-bottom
{:alt (tr "workspace.options.text-options.titlecase")
:class (dom/classnames :current (= "capitalize" text-transform))
:on-click #(handle-change "capitalize")}
i/titlecase]])))
(mf/defc typography-options
{::mf/wrap-props false}
[{:keys [ids editor values on-change on-blur show-recent]}]
(let [opts #js {:editor editor
(let [new-css-system (mf/use-ctx ctx/new-css-system)
opts #js {:editor editor
:ids ids
:values values
:on-change on-change
:on-blur on-blur
:show-recent show-recent}]
[:div.element-set-content
[:> font-options opts]
[:div.row-flex
[:> spacing-options opts]]
[:div.row-flex
[:> text-transform-options opts]]]))
(if new-css-system
[:div {:class (css :typography-options)}
[:> font-options opts]
[:div {:class (css :typography-variations)}
[:> spacing-options opts]
[:> text-transform-options opts]]]
[:div.element-set-content
[:> font-options opts]
[:div.row-flex
[:> spacing-options opts]]
[:div.row-flex
[:> text-transform-options opts]]])))
(mf/defc typography-advanced-options
{::mf/wrap [mf/memo]}
[{:keys [visible? typography editable? name-input-ref on-close on-change on-name-blur local? navigate-to-library]}]
(let [ref (mf/use-ref nil)]
(mf/use-effect
(mf/deps visible?)
(fn []
(when-let [node (mf/ref-val ref)]
(when visible?
(dom/scroll-into-view-if-needed! node)))))
(when visible?
[:div {:ref ref
:class (css :advanced-options-wrapper)}
(if ^boolean editable?
[:*
[:div {:class (css :font-name-wrapper)}
[:div
{:class (dom/classnames (css :typography-sample-input) true)
:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
(tr "workspace.assets.typography.sample")]
[:input
{:class (css :adv-typography-name)
:type "text"
:ref name-input-ref
:default-value (:name typography)
:on-blur on-name-blur}]
[:div {:class (css :action-btn)
:on-click on-close}
i/tick-refactor]]
[:& typography-options {:values typography
:on-change on-change
:show-recent false}]]
[:div.element-set-content.typography-read-only-data
[:div.row-flex.typography-name
[:span {:title (:name typography)} (:name typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-id")]
[:span (:font-id typography)]]
[:div.element-set-actions-button.actions-inside
{:on-click on-close}
i/actions]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-variant-id")]
[:span (:font-variant-id typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-size")]
[:span (:font-size typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.line-height")]
[:span (:line-height typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.letter-spacing")]
[:span (:letter-spacing typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.text-transform")]
[:span (:text-transform typography)]]
(when-not local?
[:div.row-flex
[:a.go-to-lib-button
{:on-click navigate-to-library}
(tr "workspace.assets.typography.go-to-edit")]])])])))
(mf/defc typography-entry
{::mf/wrap-props false}
[{:keys [file-id typography local? selected? on-click on-change on-detach on-context-menu editing? focus-name? external-open*]}]
[{:keys [file-id typography local? selected? on-click on-change on-detach on-context-menu editing? renaming? focus-name? external-open*]}]
(let [hover-detach* (mf/use-state false)
hover-detach? (deref hover-detach*)
name-input-ref (mf/use-ref)
read-only? (mf/use-ctx ctx/workspace-read-only?)
new-css-system (mf/use-ctx ctx/new-css-system)
editable? (and local? (not read-only?))
open* (mf/use-state editing?)
open? (deref open*)
font-data (fonts/get-font-data (:font-id typography))
name-only? (= (:name typography) (:name font-data))
on-name-blur
(mf/use-callback
@ -481,7 +696,8 @@
(fn [event]
(let [name (dom/get-target-val event)]
(when-not (str/blank? name)
(on-change {:name name})))))
(on-change {:name name})
(st/emit! #(update % :workspace-global dissoc :rename-typography))))))
on-pointer-enter
(mf/use-fn #(reset! hover-detach* true))
@ -500,9 +716,7 @@
(mf/deps file-id)
(fn []
(when file-id
(st/emit! (dw/navigate-to-library file-id)))))
]
(st/emit! (dw/navigate-to-library file-id)))))]
(mf/with-effect [editing?]
(when editing?
@ -518,88 +732,145 @@
#(when-let [node (mf/ref-val name-input-ref)]
(dom/focus! node)
(dom/select-text! node)))))
(if new-css-system
[:*
[:div {:class (dom/classnames (css :typography-entry) true
(css :selected) ^boolean selected?)
:style {:display (when ^boolean open? "none")}}
(if renaming?
[:div {:class (css :font-name-wrapper)}
[:div
{:class (dom/classnames (css :typography-sample-input) true)
:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
(tr "workspace.assets.typography.sample")]
[:*
[:div.element-set-options-group.typography-entry
{:class (when ^boolean selected? "selected")
:style {:display (when ^boolean open? "none")}}
[:div.typography-selection-wrapper
{:class (when ^boolean on-click "is-selectable")
:on-click on-click
:on-context-menu on-context-menu}
[:div.typography-sample
{:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
(tr "workspace.assets.typography.sample")]
[:div.typography-name {:title (:name typography)}(:name typography)]]
[:div.element-set-actions
(when ^boolean on-detach
[:div.element-set-actions-button
{:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave
:on-click on-detach}
(if ^boolean hover-detach? i/unchain i/chain)])
[:div.element-set-actions-button
{:on-click on-open}
i/actions]]]
[:& advanced-options {:visible? open? :on-close on-close}
(if ^boolean editable?
[:*
[:div.element-set-content
[:div.row-flex
[:input.element-name.adv-typography-name
{:type "text"
[:input
{:class (css :adv-typography-name)
:type "text"
:ref name-input-ref
:default-value (:name typography)
:on-blur on-name-blur}]
:on-blur on-name-blur}]]
[:div
{:class (dom/classnames (css :typography-selection-wrapper) true
(css :is-selectable) ^boolean on-click)
:on-click on-click
:on-context-menu on-context-menu}
[:div
{:class (dom/classnames (css :typography-sample) true)
:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
(tr "workspace.assets.typography.sample")]
[:div {:class (dom/classnames (css :typography-name) true)
:title (:name typography)} (:name typography)]
(when-not name-only?
[:div {:class (dom/classnames (css :typography-font) true)
:title (:name font-data)}
(:name font-data)])])
(when ^boolean on-detach
[:div {:class (dom/classnames (css :element-set-actions) true)}
[:div
{:class (dom/classnames (css :element-set-actions-button) true)
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave
:on-click on-detach}
(if ^boolean hover-detach? i/detach-refactor i/chain)]])]
[:& typography-advanced-options
{:visible? open? :on-close on-close
:typography typography
:editable? editable?
:name-input-ref name-input-ref
:on-change on-change
:on-name-blur on-name-blur
:local? local?
:navigate-to-library navigate-to-library}]]
[:*
[:div.element-set-options-group.typography-entry
{:class (when ^boolean selected? "selected")
:style {:display (when ^boolean open? "none")}}
[:div.typography-selection-wrapper
{:class (when ^boolean on-click "is-selectable")
:on-click on-click
:on-context-menu on-context-menu}
[:div.typography-sample
{:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
(tr "workspace.assets.typography.sample")]
[:div.typography-name {:title (:name typography)} (:name typography)]]
[:div.element-set-actions
(when ^boolean on-detach
[:div.element-set-actions-button
{:on-click on-close}
i/actions]]]
{:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave
:on-click on-detach}
(if ^boolean hover-detach? i/unchain i/chain)])
[:& typography-options {:values typography
:on-change on-change
:show-recent false}]]
[:div.element-set-actions-button
{:on-click on-open}
i/actions]]]
[:div.element-set-content.typography-read-only-data
[:div.row-flex.typography-name
[:span {:title (:name typography)} (:name typography)]]
[:& advanced-options {:visible? open? :on-close on-close}
(if ^boolean editable?
[:*
[:div.element-set-content
[:div.row-flex
[:input.element-name.adv-typography-name
{:type "text"
:ref name-input-ref
:default-value (:name typography)
:on-blur on-name-blur}]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-id")]
[:span (:font-id typography)]]
[:div.element-set-actions-button
{:on-click on-close}
i/actions]]]
[:div.element-set-actions-button.actions-inside
{:on-click on-close}
i/actions]
[:& typography-options {:values typography
:on-change on-change
:show-recent false}]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-variant-id")]
[:span (:font-variant-id typography)]]
[:div.element-set-content.typography-read-only-data
[:div.row-flex.typography-name
[:span {:title (:name typography)} (:name typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-size")]
[:span (:font-size typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.line-height")]
[:span (:line-height typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.letter-spacing")]
[:span (:letter-spacing typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.text-transform")]
[:span (:text-transform typography)]]
(when-not local?
[:div.row-flex
[:a.go-to-lib-button
{:on-click navigate-to-library}
(tr "workspace.assets.typography.go-to-edit")]])]
[:span.label (tr "workspace.assets.typography.font-id")]
[:span (:font-id typography)]]
)]]))
[:div.element-set-actions-button.actions-inside
{:on-click on-close}
i/actions]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-variant-id")]
[:span (:font-variant-id typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.font-size")]
[:span (:font-size typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.line-height")]
[:span (:line-height typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.letter-spacing")]
[:span (:letter-spacing typography)]]
[:div.row-flex
[:span.label (tr "workspace.assets.typography.text-transform")]
[:span (:text-transform typography)]]
(when-not local?
[:div.row-flex
[:a.go-to-lib-button
{:on-click navigate-to-library}
(tr "workspace.assets.typography.go-to-edit")]])])]])))

View file

@ -0,0 +1 @@
{"button-primary":"menus_typography_button-primary_s1c9M","button-secondary":"menus_typography_button-secondary_RjAsk","button-tertiary":"menus_typography_button-tertiary_Qt18f","font-name-wrapper":"menus_typography_font-name-wrapper_Njxb6","action-btn":"menus_typography_action-btn_hCakz","button-tag":"menus_typography_button-tag_32-df","button-icon":"menus_typography_button-icon_jucwh","advanced-options-wrapper":"menus_typography_advanced-options-wrapper_k3FD6","typography-options":"menus_typography_typography-options_j1u8l","font-modifiers":"menus_typography_font-modifiers_P8cSa","font-variant-options":"menus_typography_font-variant-options_qlgLr","icon":"menus_typography_icon_eDU2Z","font-size-options":"menus_typography_font-size-options_sKQdL","font-option":"menus_typography_font-option_7mgxF","button-icon-small":"menus_typography_button-icon-small_g3fsU","font-selector":"menus_typography_font-selector_TzuGa","font-selector-dropdown":"menus_typography_font-selector-dropdown_4s6s8","font-wrapper":"menus_typography_font-wrapper_GPkHS","font-item":"menus_typography_font-item_YQffA","typography-variations":"menus_typography_typography-variations_wbNM3","spacing-options":"menus_typography_spacing-options_RUpAK","line-height":"menus_typography_line-height_S7zsF","letter-spacing":"menus_typography_letter-spacing_8R6p2","asset-element":"menus_typography_asset-element_-LlIX","text-transform":"menus_typography_text-transform_U7Y3U","typography-entry":"menus_typography_typography-entry_Y6lvA","typography-selection-wrapper":"menus_typography_typography-selection-wrapper_W6ewx","is-selectable":"menus_typography_is-selectable_O6-D2","typography-sample":"menus_typography_typography-sample_6ruld","typography-name":"menus_typography_typography-name_b14xj","typography-font":"menus_typography_typography-font_hJIgO","selected":"menus_typography_selected_Ka-O9","typography-sample-input":"menus_typography_typography-sample-input_u2i8b","adv-typography-name":"menus_typography_adv-typography-name_PvB1X","name":"menus_typography_name_1SJal","font-size-select":"menus_typography_font-size-select_yexav","font-variant-select":"menus_typography_font-variant-select_-OQsO","line-height-input":"menus_typography_line-height-input_SG7be","letter-spacing-input":"menus_typography_letter-spacing-input_LShRc","header":"menus_typography_header_e-rUh","title":"menus_typography_title_uPejx","fonts-list":"menus_typography_fonts-list_ki8X-","label":"menus_typography_label_S-7jI"}

View file

@ -0,0 +1,304 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
@import "refactor/common-refactor.scss";
.typography-entry {
display: flex;
flex-direction: row;
align-items: center;
height: $s-32;
width: 100%;
border-radius: $br-8;
.typography-selection-wrapper {
display: grid;
grid-template-columns: $s-24 auto 1fr;
flex: 1;
height: 100%;
width: 100%;
padding: 0 $s-12;
&.is-selectable {
cursor: pointer;
}
.typography-sample {
@include flexCenter;
min-width: $s-24;
color: var(--assets-item-name-foreground-color-hover);
}
.typography-name,
.typography-font {
@include titleTipography;
@include textEllipsis;
display: flex;
align-items: center;
justify-content: flex-start;
margin-left: $s-6;
color: var(--assets-item-name-foreground-color-hover);
}
.typography-font {
display: flex;
align-items: center;
justify-content: flex-start;
min-width: 0;
color: var(--assets-item-name-foreground-color);
}
}
&.selected {
border: $s-1 solid var(--assets-item-border-color);
}
&:hover {
background-color: var(--assets-item-background-color-hover);
}
}
.font-name-wrapper {
@include titleTipography;
display: flex;
align-items: center;
height: $s-32;
width: 100%;
border-radius: $br-8;
border: $s-1 solid transparent;
box-sizing: border-box;
background-color: var(--assets-item-background-color);
margin-bottom: $s-4;
padding: $s-8 $s-0 $s-8 $s-12;
.typography-sample-input {
@include flexCenter;
width: $s-24;
height: 100%;
font-size: $fs-16;
}
.adv-typography-name {
@include removeInputStyle;
color: var(--input-foreground-color);
flex-grow: 1;
margin: 0;
}
.action-btn {
@extend .button-tertiary;
@include flexCenter;
width: $s-28;
height: $s-28;
svg {
@extend .button-icon-small;
}
}
&:focus-within {
border: $s-1 solid var(--input-border-color-active);
.adv-typography-name {
color: var(--input-foreground-color-active);
}
}
&:hover {
background-color: var(--assets-item-background-color-hover);
}
}
.advanced-options-wrapper {
height: 100%;
width: 100%;
background-color: var(--title-background-color);
.typography-options {
position: relative;
.font-option {
@include titleTipography;
@extend .asset-element;
padding-right: 0;
cursor: pointer;
.name {
flex-grow: 1;
}
.icon {
@include flexCenter;
height: $s-28;
width: $s-28;
svg {
@extend .button-icon;
transform: rotate(90deg);
}
}
}
.font-modifiers {
display: flex;
gap: $s-4;
.font-size-options {
@extend .asset-element;
@include titleTipography;
padding: 0;
flex-grow: 1;
.icon {
@include flexCenter;
height: $s-28;
min-width: $s-28;
svg {
@extend .button-icon;
transform: rotate(90deg);
}
}
.font-size-select {
@include removeInputStyle;
@include titleTipography;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
}
.font-variant-options {
@extend .asset-element;
@include titleTipography;
padding: 0;
flex-grow: 2;
.icon {
@include flexCenter;
height: $s-28;
min-width: $s-28;
svg {
@extend .button-icon;
transform: rotate(90deg);
}
}
.font-variant-select {
@include removeInputStyle;
@include titleTipography;
height: 100%;
width: 100%;
margin: 0;
color: var(--assets-item-name-foreground-color);
option {
color: var(--assets-item-name-foreground-color);
}
&:hover {
color: var(--assets-item-name-foreground-color-hover);
option {
color: var(--assets-item-name-foreground-color-hover);
}
}
}
}
}
.typography-variations {
display: flex;
gap: $s-4;
align-items: center;
.spacing-options {
display: flex;
align-items: center;
gap: $s-4;
.line-height,
.letter-spacing {
@extend .asset-element;
.icon {
@include flexCenter;
width: $s-28;
svg {
@extend .button-icon-small;
}
}
.line-height-input,
.letter-spacing-input {
@include removeInputStyle;
@include titleTipography;
height: 100%;
width: 100%;
margin: 0;
color: var(--assets-item-name-foreground-color);
&:hover,
&:active,
&:focus {
color: var(--assets-item-name-foreground-color-hover);
}
}
}
}
.text-transform {
@extend .asset-element;
width: fit-content;
padding: 0;
}
}
}
}
.font-selector {
@include flexCenter;
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: $z-index-10;
.font-selector-dropdown {
display: flex;
flex-direction: column;
flex-grow: 1;
height: 100%;
.header {
display: flex;
flex-direction: column;
position: relative;
margin-bottom: $s-2;
.title {
@include tabTitleTipography;
margin: 9px 17px;
}
}
.fonts-list {
position: absolute;
top: $s-36;
left: 0;
display: flex;
flex-direction: column;
flex: 1 1 auto;
min-height: 100%;
height: $s-216;
width: 100%;
padding: $s-2;
border-radius: $br-8;
background-color: var(--dropdown-background-color);
box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
}
.font-wrapper {
padding-bottom: $s-4;
cursor: pointer;
.font-item {
@extend .asset-element;
border-radius: $br-8;
display: flex;
.icon {
@include flexCenter;
height: $s-28;
width: $s-28;
svg {
@extend .button-icon-small;
}
}
&.selected {
color: var(--assets-item-name-foreground-color-hover);
.icon {
svg {
stroke: var(--assets-item-name-foreground-color-hover);
}
}
}
.label {
@include titleTipography;
flex-grow: 1;
}
}
}
}
}

View file

@ -18,6 +18,7 @@
[app.main.data.workspace.path.shortcuts]
[app.main.data.workspace.shortcuts]
[app.main.store :as st]
[app.main.ui.components.search-bar :refer [search-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
@ -280,7 +281,7 @@
(for [command-translate sorted-filtered]
(let [sc-by-translate (first (filter #(= (:translation (second %)) command-translate) elements))
[command comand-info] sc-by-translate
content (or (:show-command comand-info)(:command comand-info))]
content (or (:show-command comand-info) (:command comand-info))]
[:li {:class (css :shortcuts-name)
:key command-translate}
[:span {:class (css :command-name)}
@ -326,7 +327,7 @@
:filter-term filter-term
:match-section? match-section?
:match-subsection? true}])
[:ul {:class (dom/classnames (css :subsection-menu) new-css-system
:subsection-menu (not new-css-system))}
(for [sub-translated sorted-translations]
@ -365,7 +366,7 @@
translations (map #(translation-keyname :sc %) (keys subs-bodys))
match-shortcut? (some #(matches-search % @filter-term) translations)
visible? (some #(= % section-id) @open-sections)]
(when (or match-section? match-subsection? match-shortcut?)
[:div {:class (css :section)
:on-click (manage-sections section-id)}
@ -502,6 +503,11 @@
(manage-sections-on-search value)
(reset! filter-term value))))
on-search-term-change-2
(mf/use-callback
(fn [value]
(manage-sections-on-search value)
(reset! filter-term value)))
on-search-clear-click
(mf/use-callback
(fn [_]
@ -528,31 +534,17 @@
(if new-css-system
[:div {:class (css :shortcuts)}
[:div {:class (css :shortcuts-header)}
[:div {:class (css :shortcuts-title)} "Keyboard Shortcuts"]
[:div {:class (css :shortcuts-title)} (tr "shortcuts.title")]
[:div {:class (css :shortcuts-close-button)
:on-click close-fn}
i/close-refactor]]
;; TODO Change this for search bar component
[:div {:class (css :search-field)}
[:div {:class (css :search-box)}
[:span {:class (css :icon-wrapper)}
i/search-refactor]
[:input {:class (dom/classnames (css :input-text) true)
:id "shortcut-search"
:placeholder (tr "shortcuts.title")
:type "text"
:value @filter-term
:on-change on-search-term-change
:auto-complete "off"
:on-key-down manage-key-down}]
(when (not (str/empty? @filter-term))
[:button
{:class (css :clear-btn)
:on-click on-search-clear-click
:on-key-down on-key-down}
[:span {:class (css :clear-icon)}
i/delete-text-refactor]])]]
[:& search-bar {:on-change on-search-term-change-2
:clear-action on-search-clear-click
:value @filter-term
:placeholder (tr "shortcuts.title")
:icon (mf/html [:span {:class (css :search-icon)} i/search-refactor])}]]
(if match-any?
[:div {:class (dom/classnames (css :shortcuts-list) true)}

View file

@ -1 +1 @@
{"button-primary":"sidebar_shortcuts_button-primary_aIZ1F","shortcuts":"sidebar_shortcuts_shortcuts_cOJNo","shortcuts-header":"sidebar_shortcuts_shortcuts-header_0SZ19","shortcuts-close-button":"sidebar_shortcuts_shortcuts-close-button_gT7kn","button-secondary":"sidebar_shortcuts_button-secondary_dtWEN","button-icon":"sidebar_shortcuts_button-icon_rCHmV","button-icon-small":"sidebar_shortcuts_button-icon-small_9BnNh","shortcuts-list":"sidebar_shortcuts_shortcuts-list_z7osI","section-title":"sidebar_shortcuts_section-title_Dv7S-","collapsed-shortcuts":"sidebar_shortcuts_collapsed-shortcuts_XrOj5","subsection-title":"sidebar_shortcuts_subsection-title_--5j4","search-field":"sidebar_shortcuts_search-field_cDecA","search-box":"sidebar_shortcuts_search-box_vmYAl","clear-btn":"sidebar_shortcuts_clear-btn_vRbGu","clear-icon":"sidebar_shortcuts_clear-icon_ZL4ae","icon-wrapper":"sidebar_shortcuts_icon-wrapper_XaR8m","shortcuts-title":"sidebar_shortcuts_shortcuts-title_P38o9","input-text":"sidebar_shortcuts_input-text_e9n1x","section":"sidebar_shortcuts_section_Jxkqa","open":"sidebar_shortcuts_open_SxghD","subsection-name":"sidebar_shortcuts_subsection-name_rWvFY","section-name":"sidebar_shortcuts_section-name_SyF9-","subsection-menu":"sidebar_shortcuts_subsection-menu_FdH9L","sub-menu":"sidebar_shortcuts_sub-menu_95jTY","shortcuts-name":"sidebar_shortcuts_shortcuts-name_hPkq6","command-name":"sidebar_shortcuts_command-name_Cujed","keys":"sidebar_shortcuts_keys_-pUnF","key":"sidebar_shortcuts_key_QyU8q","space":"sidebar_shortcuts_space_aODdu","not-found":"sidebar_shortcuts_not-found_bKEb0"}
{"button-primary":"sidebar_shortcuts_button-primary_aIZ1F","button-secondary":"sidebar_shortcuts_button-secondary_dtWEN","button-tertiary":"sidebar_shortcuts_button-tertiary_3VDIw","shortcuts":"sidebar_shortcuts_shortcuts_cOJNo","shortcuts-header":"sidebar_shortcuts_shortcuts-header_0SZ19","shortcuts-close-button":"sidebar_shortcuts_shortcuts-close-button_gT7kn","button-tag":"sidebar_shortcuts_button-tag_3LImZ","button-icon":"sidebar_shortcuts_button-icon_rCHmV","button-icon-small":"sidebar_shortcuts_button-icon-small_9BnNh","shortcuts-list":"sidebar_shortcuts_shortcuts-list_z7osI","section-title":"sidebar_shortcuts_section-title_Dv7S-","collapsed-shortcuts":"sidebar_shortcuts_collapsed-shortcuts_XrOj5","subsection-title":"sidebar_shortcuts_subsection-title_--5j4","search-field":"sidebar_shortcuts_search-field_cDecA","search-icon":"sidebar_shortcuts_search-icon_NSAwd","search-box":"sidebar_shortcuts_search-box_vmYAl","clear-btn":"sidebar_shortcuts_clear-btn_vRbGu","clear-icon":"sidebar_shortcuts_clear-icon_ZL4ae","icon-wrapper":"sidebar_shortcuts_icon-wrapper_XaR8m","asset-element":"sidebar_shortcuts_asset-element_-zk6N","shortcuts-title":"sidebar_shortcuts_shortcuts-title_P38o9","input-text":"sidebar_shortcuts_input-text_e9n1x","section":"sidebar_shortcuts_section_Jxkqa","open":"sidebar_shortcuts_open_SxghD","subsection-name":"sidebar_shortcuts_subsection-name_rWvFY","section-name":"sidebar_shortcuts_section-name_SyF9-","subsection-menu":"sidebar_shortcuts_subsection-menu_FdH9L","sub-menu":"sidebar_shortcuts_sub-menu_95jTY","shortcuts-name":"sidebar_shortcuts_shortcuts-name_hPkq6","command-name":"sidebar_shortcuts_command-name_Cujed","keys":"sidebar_shortcuts_keys_-pUnF","key":"sidebar_shortcuts_key_QyU8q","space":"sidebar_shortcuts_space_aODdu","not-found":"sidebar_shortcuts_not-found_bKEb0"}

View file

@ -24,7 +24,7 @@
}
.shortcuts-close-button {
@extend .button-primary;
@extend .button-tertiary;
position: absolute;
right: $s-2;
top: $s-2;
@ -45,7 +45,6 @@
border-radius: $br-8;
font-family: "worksans", sans-serif;
background-color: var(--color-background-tertiary);
.search-box {
align-items: center;
display: flex;
@ -59,6 +58,7 @@
}
.input-text {
@include removeInputStyle;
height: $s-32;
width: 100%;
margin: 0;
@ -66,7 +66,6 @@
border: 0;
font-size: $fs-12;
color: var(--color-foreground-primary);
background-color: transparent;
&::placeholder {
color: var(--color-foreground-secondary);
}
@ -87,6 +86,13 @@
}
}
}
.search-icon {
@include flexCenter;
width: $s-28;
svg {
@extend .button-icon-small;
}
}
}
.section {

View file

@ -13,6 +13,7 @@
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.title-bar :refer [title-bar]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
@ -239,22 +240,20 @@
[:div {:class (dom/classnames (css :sitemap) true)
:ref parent-ref
:style #js {"--height" (str size "px")}}
[:div {:class (dom/classnames (css :pages-tool-bar) true)}
[:button {:class (dom/classnames (css :page-tool-bar-title) true)
:on-click toggle-pages}
[:span {:class (dom/classnames (css :collapsable-button) true)
:style {:transform (when (not @show-pages?) "rotate(-90deg)")}}
i/arrow-refactor]
(tr "workspace.sidebar.sitemap")]
[:& title-bar {:collapsable? true
:collapsed? (not @show-pages?)
:on-collapsed toggle-pages
:title (tr "workspace.sidebar.sitemap")
:klass :title-spacing-sitemap}
(if workspace-read-only?
[:div
{:class (dom/classnames (css :view-only-mode) true)}
(tr "labels.view-only")]
[:*
[:button {:class (dom/classnames (css :add-page) true)
:on-click create}
i/add-refactor]])]
[:button {:class (dom/classnames (css :add-page) true)
:on-click create}
i/add-refactor])]
[:div {:class (dom/classnames (css :tool-window-content) true)}
[:& pages-list {:file file :key (:id file)}]]

View file

@ -1 +1 @@
{"button-primary":"sidebar_sitemap_button-primary_Z-bKW","sitemap":"sidebar_sitemap_sitemap_kvKKx","pages-tool-bar":"sidebar_sitemap_pages-tool-bar_n1yfA","add-page":"sidebar_sitemap_add-page_r8Ibb","button-secondary":"sidebar_sitemap_button-secondary_a56LZ","button-icon":"sidebar_sitemap_button-icon_MkibT","page-tool-bar-title":"sidebar_sitemap_page-tool-bar-title_D7h-S","collapsable-button":"sidebar_sitemap_collapsable-button_Xt79y","button-icon-small":"sidebar_sitemap_button-icon-small_Mhipv","tool-window-content":"sidebar_sitemap_tool-window-content_G-Nut","pages-list":"sidebar_sitemap_pages-list_cb1Mx","page-element":"sidebar_sitemap_page-element_iR9wf","element-list-body":"sidebar_sitemap_element-list-body_OIVac","page-actions":"sidebar_sitemap_page-actions_QTuKw","page-icon":"sidebar_sitemap_page-icon_ujSjM","view-only-mode":"sidebar_sitemap_view-only-mode_JrsYg","resize-area":"sidebar_sitemap_resize-area_JgdjZ","dnd-over-top":"sidebar_sitemap_dnd-over-top_kGfcb","dnd-over-bot":"sidebar_sitemap_dnd-over-bot_352W2","dnd-over":"sidebar_sitemap_dnd-over_Sf5e2","page-name":"sidebar_sitemap_page-name_601Ii","element-name":"sidebar_sitemap_element-name_iMex0","on-drag":"sidebar_sitemap_on-drag_v3GM8","selected":"sidebar_sitemap_selected_mCOlT","hidden":"sidebar_sitemap_hidden_viFSn"}
{"button-primary":"sidebar_sitemap_button-primary_Z-bKW","button-secondary":"sidebar_sitemap_button-secondary_a56LZ","button-tertiary":"sidebar_sitemap_button-tertiary_E2hzd","sitemap":"sidebar_sitemap_sitemap_kvKKx","add-page":"sidebar_sitemap_add-page_r8Ibb","button-tag":"sidebar_sitemap_button-tag_u1NAz","button-icon":"sidebar_sitemap_button-icon_MkibT","button-icon-small":"sidebar_sitemap_button-icon-small_Mhipv","tool-window-content":"sidebar_sitemap_tool-window-content_G-Nut","pages-list":"sidebar_sitemap_pages-list_cb1Mx","page-element":"sidebar_sitemap_page-element_iR9wf","element-list-body":"sidebar_sitemap_element-list-body_OIVac","page-actions":"sidebar_sitemap_page-actions_QTuKw","page-icon":"sidebar_sitemap_page-icon_ujSjM","asset-element":"sidebar_sitemap_asset-element_I1-m4","view-only-mode":"sidebar_sitemap_view-only-mode_JrsYg","resize-area":"sidebar_sitemap_resize-area_JgdjZ","dnd-over-top":"sidebar_sitemap_dnd-over-top_kGfcb","dnd-over-bot":"sidebar_sitemap_dnd-over-bot_352W2","dnd-over":"sidebar_sitemap_dnd-over_Sf5e2","page-name":"sidebar_sitemap_page-name_601Ii","element-name":"sidebar_sitemap_element-name_iMex0","on-drag":"sidebar_sitemap_on-drag_v3GM8","selected":"sidebar_sitemap_selected_mCOlT","hidden":"sidebar_sitemap_hidden_viFSn"}

View file

@ -14,63 +14,26 @@
width: 100%;
height: var(--height, 200px);
.pages-tool-bar {
display: flex;
align-items: center;
min-height: $s-32;
padding: 0 $s-8 0 0;
margin: $s-2 0;
.page-tool-bar-title {
@include flexCenter;
@include tabTitleTipography;
@include buttonStyle;
flex-grow: 1;
gap: $s-4;
justify-content: flex-start;
padding: 0;
margin: 0;
color: var(--title-foreground-color);
.collapsable-button {
@include flexCenter;
height: $s-24;
width: $s-24;
padding: 0 $s-4 0 $s-8;
border-radius: $br-8;
svg {
@extend .button-icon;
height: $s-12;
width: $s-12;
transform: rotate(90deg);
}
}
&:hover {
color: var(--title-foreground-color-hover);
svg {
stroke: var(--icon-foreground-hover);
}
}
}
.add-page {
@extend .button-primary;
height: $s-32;
width: calc($s-24 + $s-4);
padding: 0;
border-radius: $br-8;
svg {
@extend .button-icon;
transform: rotate(90deg);
}
}
.view-only-mode {
@include flexCenter;
@include titleTipography;
height: $s-20;
padding: $s-4 $s-6;
border: 1px solid var(--tag-background-color);
border-radius: $br-6;
color: var(--tag-background-color);
.add-page {
@extend .button-tertiary;
height: $s-32;
width: calc($s-24 + $s-4);
padding: 0;
border-radius: $br-8;
svg {
@extend .button-icon;
transform: rotate(90deg);
}
}
.view-only-mode {
@include flexCenter;
@include titleTipography;
height: $s-20;
padding: $s-4 $s-6;
border: 1px solid var(--tag-background-color);
border-radius: $br-6;
color: var(--tag-background-color);
}
.resize-area {
position: absolute;
bottom: -8px;
@ -163,6 +126,7 @@
input.element-name {
@include textEllipsis;
@include titleTipography;
@include removeInputStyle;
flex-grow: 1;
height: $s-28;
max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
@ -170,8 +134,6 @@
padding-left: $s-6;
border-radius: $br-8;
border: 1px solid var(--input-border-color-focus);
outline: none;
background-color: transparent;
color: var(--layer-row-foreground-color);
}
}
@ -257,4 +219,7 @@
}
}
}
:global(.title-spacing-sitemap) {
padding-right: $s-8;
}
}

View file

@ -1 +1 @@
{"button-primary":"workspace_text_palette_button-primary_1umSD","button-secondary":"workspace_text_palette_button-secondary_VOIWz","button-icon":"workspace_text_palette_button-icon_bcydd","text-palette":"workspace_text_palette_text-palette_0yeGp","left-arrow":"workspace_text_palette_left-arrow_iSjPL","right-arrow":"workspace_text_palette_right-arrow_cWHr6","button-icon-small":"workspace_text_palette_button-icon-small_wGyH7","disabled":"workspace_text_palette_disabled_EF36J","text-palette-content":"workspace_text_palette_text-palette-content_anJb5","text-palette-inside":"workspace_text_palette_text-palette-inside_LgHnf","typography-item":"workspace_text_palette_typography-item_d0vFL","typography-name":"workspace_text_palette_typography-name_NVBRv","typography-font":"workspace_text_palette_typography-font_paqmC","typography-data":"workspace_text_palette_typography-data_eKyme","mid-item":"workspace_text_palette_mid-item_uTcD2","small-item":"workspace_text_palette_small-item_1Y6mx"}
{"button-primary":"workspace_text_palette_button-primary_1umSD","button-secondary":"workspace_text_palette_button-secondary_VOIWz","button-tertiary":"workspace_text_palette_button-tertiary_4AWFN","button-tag":"workspace_text_palette_button-tag_TMcKw","button-icon":"workspace_text_palette_button-icon_bcydd","text-palette":"workspace_text_palette_text-palette_0yeGp","left-arrow":"workspace_text_palette_left-arrow_iSjPL","right-arrow":"workspace_text_palette_right-arrow_cWHr6","button-icon-small":"workspace_text_palette_button-icon-small_wGyH7","asset-element":"workspace_text_palette_asset-element_edxQB","disabled":"workspace_text_palette_disabled_EF36J","text-palette-content":"workspace_text_palette_text-palette-content_anJb5","text-palette-inside":"workspace_text_palette_text-palette-inside_LgHnf","typography-item":"workspace_text_palette_typography-item_d0vFL","typography-name":"workspace_text_palette_typography-name_NVBRv","typography-font":"workspace_text_palette_typography-font_paqmC","typography-data":"workspace_text_palette_typography-data_eKyme","mid-item":"workspace_text_palette_mid-item_uTcD2","small-item":"workspace_text_palette_small-item_1Y6mx"}

View file

@ -1 +1 @@
{"button-primary":"workspace_text_palette_ctx_menu_button-primary_bkGXB","button-secondary":"workspace_text_palette_ctx_menu_button-secondary_mbPs7","button-icon":"workspace_text_palette_ctx_menu_button-icon_oklnh","button-icon-small":"workspace_text_palette_ctx_menu_button-icon-small_ebriD","workspace-context-menu":"workspace_text_palette_ctx_menu_workspace-context-menu_OShZn","palette-library":"workspace_text_palette_ctx_menu_palette-library_pDyi5","selected":"workspace_text_palette_ctx_menu_selected_k3kOd","icon-wrapper":"workspace_text_palette_ctx_menu_icon-wrapper_Xoj9o","file-library":"workspace_text_palette_ctx_menu_file-library_t-25M","library-name":"workspace_text_palette_ctx_menu_library-name_TGs9Z"}
{"button-primary":"workspace_text_palette_ctx_menu_button-primary_bkGXB","button-secondary":"workspace_text_palette_ctx_menu_button-secondary_mbPs7","button-tertiary":"workspace_text_palette_ctx_menu_button-tertiary_Z74wM","button-tag":"workspace_text_palette_ctx_menu_button-tag_OmlzA","button-icon":"workspace_text_palette_ctx_menu_button-icon_oklnh","button-icon-small":"workspace_text_palette_ctx_menu_button-icon-small_ebriD","workspace-context-menu":"workspace_text_palette_ctx_menu_workspace-context-menu_OShZn","palette-library":"workspace_text_palette_ctx_menu_palette-library_pDyi5","selected":"workspace_text_palette_ctx_menu_selected_k3kOd","icon-wrapper":"workspace_text_palette_ctx_menu_icon-wrapper_Xoj9o","file-library":"workspace_text_palette_ctx_menu_file-library_t-25M","asset-element":"workspace_text_palette_ctx_menu_asset-element_-ynNV","library-name":"workspace_text_palette_ctx_menu_library-name_TGs9Z"}