mirror of
https://github.com/penpot/penpot.git
synced 2026-10-03 01:06:14 +00:00
🐛 Fix organization/team switcher issues from UI review (#11940)
* 🐛 Fix organization/team switcher issues from UI review * 📎 Code review
This commit is contained in:
parent
f38c7dd639
commit
be63107ed6
@ -20,10 +20,10 @@
|
||||
|
||||
.dashboard-content {
|
||||
display: grid;
|
||||
grid-template-rows: $sz-64 1fr;
|
||||
grid-template-rows: px2rem(72) 1fr;
|
||||
position: relative;
|
||||
grid-row: 1 / span 2;
|
||||
padding: var(--sp-l) var(--sp-l) 0 0;
|
||||
padding: var(--sp-s) var(--sp-l) 0 0;
|
||||
overflow: hidden;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
@ -158,9 +158,9 @@
|
||||
(defn resolve-admin-console-href
|
||||
"The admin-console link for the pinned action at the bottom of the
|
||||
organizations column: the organization-specific page when `profile`
|
||||
owns `organization`, the generic admin-console page otherwise —
|
||||
including when no organization is previewed at all (e.g. \"Other
|
||||
teams\"/personal projects is selected)."
|
||||
owns `organization` (the active team's one), the generic
|
||||
admin-console page otherwise — including when the active team has
|
||||
no organization at all (\"Other teams\"/personal projects)."
|
||||
[organization profile]
|
||||
(if (and (:id organization) (= (:id profile) (:owner-id organization)))
|
||||
(dnt/build-admin-console-href {:organization-id (:id organization)
|
||||
@ -171,119 +171,205 @@
|
||||
[event]
|
||||
(or (kbd/mod? event) (dom/middle-mouse? event)))
|
||||
|
||||
(mf/defc personal-projects-icon*
|
||||
"The \"Personal projects\" icon at the 20px size the design asks
|
||||
for, which `icon*` has no size for."
|
||||
{::mf/private true}
|
||||
[{:keys [class]}]
|
||||
[:svg {:class class :width "20px" :height "20px"}
|
||||
[:use {:href (dm/str "#icon-" i/files) :width "20px" :height "20px"}]])
|
||||
|
||||
(defn- use-scroll-fade
|
||||
"Whether a column's scroll area has more content below its visible
|
||||
part, so the fade over its bottom edge shows only then and never
|
||||
covers the last row. Rechecks on scroll and whenever `items`
|
||||
change."
|
||||
[items]
|
||||
(let [node-ref (mf/use-ref nil)
|
||||
fade* (mf/use-state false)
|
||||
|
||||
on-scroll
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(when-let [node (mf/ref-val node-ref)]
|
||||
(reset! fade* (> (- (.-scrollHeight ^js node)
|
||||
(.-scrollTop ^js node)
|
||||
(.-clientHeight ^js node))
|
||||
1)))))]
|
||||
|
||||
(mf/use-layout-effect (mf/deps items) #(do (on-scroll) nil))
|
||||
|
||||
{:ref node-ref
|
||||
:on-scroll on-scroll
|
||||
:fade? (deref fade*)}))
|
||||
|
||||
(mf/defc organization-item*
|
||||
"One row of `organizations-column*`; `organization` is nil for the
|
||||
\"Other teams\" bucket."
|
||||
{::mf/private true}
|
||||
[{:keys [organization selected-id current-id on-select on-context-menu]}]
|
||||
(let [bucket-id (organization-bucket-id organization)
|
||||
personal? (= bucket-id personal-bucket-id)]
|
||||
[:> dropdown-menu-item* {:data-value (str bucket-id)
|
||||
:class (stl/css-case :organization-item true
|
||||
:selected (= bucket-id selected-id))
|
||||
:on-click on-select
|
||||
:on-context-menu #(on-context-menu % organization)}
|
||||
(if personal?
|
||||
[:span {:class (stl/css :my-teams-icon)}
|
||||
[:> raw-svg* {:id penpot-logo-icon-subtle}]]
|
||||
[:> organization-avatar* {:organization organization :size "xxl"}])
|
||||
[:span {:class (stl/css :organization-text-group)}
|
||||
[:span {:class (stl/css :organization-text)
|
||||
:title (if personal? (tr "dashboard.other-teams") (:name organization))}
|
||||
(if personal? (tr "dashboard.other-teams") (:name organization))]
|
||||
(when (= bucket-id current-id)
|
||||
[:span {:class (stl/css :tick-icon)}
|
||||
[:> icon* {:icon-id i/tick :size "s"}]])]
|
||||
[:span {:class (stl/css :chevron-icon)}
|
||||
[:> icon* {:icon-id i/arrow-right :size "s"}]]]))
|
||||
|
||||
(mf/defc organizations-column*
|
||||
{::mf/private true}
|
||||
[{:keys [organizations selected-id current-id ^boolean has-organizations? on-select on-create-organization
|
||||
admin-console-href ^boolean valid-license on-context-menu on-dismiss-context-menu]}]
|
||||
[:li {:role "presentation" :class (stl/css :organizations-column)}
|
||||
[:div {:class (stl/css :column-label)}
|
||||
(tr "dashboard.section.organizations")]
|
||||
(let [;; "Other teams" is always last (see `sort-organizations`). It
|
||||
;; stays out of the scroll area so it sits right under a short
|
||||
;; list and sticks above the actions under a long one. Its
|
||||
;; entry is a bare `nil` (see `organization-bucket-id`), hence
|
||||
;; `some` rather than looking the value up.
|
||||
listed (remove (comp nil? :id) organizations)
|
||||
other? (some (comp nil? :id) organizations)
|
||||
|
||||
[:ul {:class (stl/css :column-list)}
|
||||
(when-not has-organizations?
|
||||
[:li {:class (stl/css :empty-state)}
|
||||
(tr "dashboard.no-organizations-yet")])
|
||||
{:keys [ref on-scroll fade?]} (use-scroll-fade organizations)]
|
||||
|
||||
(for [organization organizations]
|
||||
(let [bucket-id (organization-bucket-id organization)
|
||||
personal? (= bucket-id personal-bucket-id)]
|
||||
[:* {:key (str bucket-id)}
|
||||
;; "Other teams" is always last (see `sort-organizations`),
|
||||
;; set apart from the real organizations above it the same
|
||||
;; way `.column-separator` sets the pinned actions apart
|
||||
;; from the list.
|
||||
(when personal?
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}])
|
||||
[:> dropdown-menu-item* {:data-value (str bucket-id)
|
||||
:class (stl/css-case :organization-item true
|
||||
:selected (= bucket-id selected-id))
|
||||
:on-click on-select
|
||||
:on-context-menu #(on-context-menu % organization)}
|
||||
(if personal?
|
||||
[:span {:class (stl/css :my-teams-icon)}
|
||||
[:> raw-svg* {:id penpot-logo-icon-subtle}]]
|
||||
[:> organization-avatar* {:organization organization :size "xxl"}])
|
||||
[:span {:class (stl/css :organization-text-group)}
|
||||
[:span {:class (stl/css :organization-text)
|
||||
:title (if personal? (tr "dashboard.other-teams") (:name organization))}
|
||||
(if personal? (tr "dashboard.other-teams") (:name organization))]
|
||||
(when (= bucket-id current-id)
|
||||
[:span {:class (stl/css :tick-icon)}
|
||||
[:> icon* {:icon-id i/tick :size "s"}]])]
|
||||
[:span {:class (stl/css :chevron-icon)}
|
||||
[:> icon* {:icon-id i/arrow-right :size "s"}]]]]))]
|
||||
[:li {:role "presentation" :class (stl/css :organizations-column)}
|
||||
[:div {:class (stl/css-case :column-scroll true :fade fade?)
|
||||
:ref ref
|
||||
:on-scroll on-scroll}
|
||||
[:div {:class (stl/css :column-label)}
|
||||
(tr "dashboard.section.organizations")]
|
||||
|
||||
[:ul {:class (stl/css :column-actions)}
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}]
|
||||
[:ul {:class (stl/css :column-list)}
|
||||
(when-not has-organizations?
|
||||
[:li {:class (stl/css :empty-state)}
|
||||
(tr "dashboard.no-organizations-yet")])
|
||||
|
||||
[:> dropdown-menu-item* {:on-click on-create-organization
|
||||
:class (stl/css :organization-item :action)}
|
||||
[:span {:class (stl/css :icon-wrapper)}
|
||||
[:> icon* {:icon-id i/add :class (stl/css :action-icon)}]]
|
||||
[:span {:class (stl/css :organization-text)} (tr "dashboard.create-new-organization")]]
|
||||
(for [organization listed]
|
||||
[:> organization-item* {:key (str (:id organization))
|
||||
:organization organization
|
||||
:selected-id selected-id
|
||||
:current-id current-id
|
||||
:on-select on-select
|
||||
:on-context-menu on-context-menu}])]]
|
||||
|
||||
(when valid-license
|
||||
[:> dropdown-menu-item* {:class (stl/css :organization-item :action :with-link)
|
||||
:on-click (fn [event]
|
||||
(if (new-tab-click? event)
|
||||
(dom/stop-propagation event)
|
||||
(do
|
||||
(dom/prevent-default event)
|
||||
(when other?
|
||||
[:ul {:class (stl/css :column-bucket)}
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}]
|
||||
[:> organization-item* {:organization nil
|
||||
:selected-id selected-id
|
||||
:current-id current-id
|
||||
:on-select on-select
|
||||
:on-context-menu on-context-menu}]])
|
||||
|
||||
[:ul {:class (stl/css :column-actions)}
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}]
|
||||
|
||||
(when valid-license
|
||||
[:> dropdown-menu-item* {:class (stl/css :organization-item :action :with-link)
|
||||
:on-click (fn [event]
|
||||
(if (new-tab-click? event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (rt/nav-raw :href admin-console-href)))))
|
||||
:on-context-menu on-dismiss-context-menu}
|
||||
[:a {:class (stl/css :item-link)
|
||||
:href admin-console-href
|
||||
:tab-index "-1"}
|
||||
[:span {:class (stl/css :icon-wrapper)}
|
||||
[:> icon* {:icon-id i/arrow-up-right :class (stl/css :action-icon)}]]
|
||||
[:span {:class (stl/css :organization-text)} (tr "dashboard.go-to-admin-console")]]])]])
|
||||
(do
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (rt/nav-raw :href admin-console-href)))))
|
||||
:on-context-menu on-dismiss-context-menu}
|
||||
[:a {:class (stl/css :item-link)
|
||||
:href admin-console-href
|
||||
:tab-index "-1"}
|
||||
[:span {:class (stl/css :icon-wrapper)}
|
||||
[:> icon* {:icon-id i/arrow-up-right :class (stl/css :action-icon)}]]
|
||||
[:span {:class (stl/css :organization-text)} (tr "dashboard.go-to-admin-console")]]])
|
||||
|
||||
[:> dropdown-menu-item* {:on-click on-create-organization
|
||||
:class (stl/css :organization-item :action)}
|
||||
[:span {:class (stl/css :icon-wrapper)}
|
||||
[:> icon* {:icon-id i/add :class (stl/css :action-icon)}]]
|
||||
[:span {:class (stl/css :organization-text)} (tr "dashboard.create-new-organization")]]]]))
|
||||
|
||||
(mf/defc team-item*
|
||||
"One row of `teams-column*`."
|
||||
{::mf/private true}
|
||||
[{:keys [team href selected-team-id on-select on-context-menu]}]
|
||||
(let [subscription-type (get-subscription-type (:subscription team))
|
||||
show-badge? (show-subscription-badge? team)]
|
||||
[:> dropdown-menu-item* {:data-value (str (:id team))
|
||||
:class (stl/css-case :team-item true
|
||||
:with-link true)
|
||||
:on-click on-select
|
||||
:on-context-menu on-context-menu}
|
||||
[:a {:class (stl/css :item-link)
|
||||
:href href
|
||||
:tab-index "-1"}
|
||||
(if (:is-default team)
|
||||
[:span {:class (stl/css :team-item-personal-icon)}
|
||||
[:> personal-projects-icon* {:class (stl/css :personal-icon)}]]
|
||||
[:img {:src (cf/resolve-team-photo-url team)
|
||||
:class (stl/css :team-item-picture)
|
||||
:alt (:name team)}])
|
||||
[:span {:class (stl/css :team-text-group)}
|
||||
[:span {:class (stl/css :team-text)
|
||||
:title (team-display-name team)}
|
||||
(team-display-name team)]
|
||||
(when show-badge?
|
||||
[:> menu-team-icon* {:subscription-type subscription-type}])
|
||||
(when (= (:id team) selected-team-id)
|
||||
[:span {:class (stl/css :tick-icon)}
|
||||
[:> icon* {:icon-id i/tick :size "s"}]])]]]))
|
||||
|
||||
(mf/defc teams-column*
|
||||
{::mf/private true}
|
||||
[{:keys [teams selected-team-id on-select on-context-menu on-create-team
|
||||
on-create-organization]}]
|
||||
(let [router (mf/deref refs/router)]
|
||||
[:li {:role "presentation" :class (stl/css :teams-column)}
|
||||
[:div {:class (stl/css :column-label)}
|
||||
(tr "dashboard.section.teams")]
|
||||
(let [router (mf/deref refs/router)
|
||||
|
||||
[:ul {:class (stl/css :column-list)}
|
||||
(for [team teams]
|
||||
(let [subscription-type (get-subscription-type (:subscription team))
|
||||
show-badge? (show-subscription-badge? team)]
|
||||
[:* {:key (str (:id team))}
|
||||
;; "Personal projects" is always last (see
|
||||
;; `sort-organization-teams`/`sort-all-teams`), set apart
|
||||
;; from the real teams above it the same way
|
||||
;; `.column-separator` sets the pinned actions apart from
|
||||
;; the list. Skipped when it's the only team: there's
|
||||
;; nothing above it to separate from.
|
||||
(when (and (:is-default team) (> (count teams) 1))
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}])
|
||||
[:> dropdown-menu-item* {:data-value (str (:id team))
|
||||
:class (stl/css-case :team-item true
|
||||
:with-link true)
|
||||
:on-click on-select
|
||||
:on-context-menu on-context-menu}
|
||||
[:a {:class (stl/css :item-link)
|
||||
:href (team-href router team)
|
||||
:tab-index "-1"}
|
||||
(if (:is-default team)
|
||||
[:span {:class (stl/css :team-item-personal-icon)}
|
||||
[:> icon* {:icon-id i/files}]]
|
||||
[:img {:src (cf/resolve-team-photo-url team)
|
||||
:class (stl/css :team-item-picture)
|
||||
:alt (:name team)}])
|
||||
[:span {:class (stl/css :team-text-group)}
|
||||
[:span {:class (stl/css :team-text)
|
||||
:title (team-display-name team)}
|
||||
(team-display-name team)]
|
||||
(when show-badge?
|
||||
[:> menu-team-icon* {:subscription-type subscription-type}])
|
||||
(when (= (:id team) selected-team-id)
|
||||
[:span {:class (stl/css :tick-icon)}
|
||||
[:> icon* {:icon-id i/tick :size "s"}]])]]]]))]
|
||||
;; "Personal projects" is always last (see
|
||||
;; `sort-organization-teams`/`sort-all-teams`). It stays out of
|
||||
;; the scroll area so it sits right under a short list and
|
||||
;; sticks above the actions under a long one.
|
||||
listed (remove :is-default teams)
|
||||
personal (d/seek :is-default teams)
|
||||
|
||||
{:keys [ref on-scroll fade?]} (use-scroll-fade teams)]
|
||||
|
||||
[:li {:role "presentation" :class (stl/css :teams-column)}
|
||||
[:div {:class (stl/css-case :column-scroll true :fade fade?)
|
||||
:ref ref
|
||||
:on-scroll on-scroll}
|
||||
[:div {:class (stl/css :column-label)}
|
||||
(tr "dashboard.section.teams")]
|
||||
|
||||
[:ul {:class (stl/css :column-list)}
|
||||
(for [team listed]
|
||||
[:> team-item* {:key (str (:id team))
|
||||
:team team
|
||||
:href (team-href router team)
|
||||
:selected-team-id selected-team-id
|
||||
:on-select on-select
|
||||
:on-context-menu on-context-menu}])]]
|
||||
|
||||
(when personal
|
||||
[:ul {:class (stl/css :column-bucket)}
|
||||
;; Skipped when it's the only team: there's nothing above it
|
||||
;; to set it apart from.
|
||||
(when (seq listed)
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}])
|
||||
[:> team-item* {:team personal
|
||||
:href (team-href router personal)
|
||||
:selected-team-id selected-team-id
|
||||
:on-select on-select
|
||||
:on-context-menu on-context-menu}]])
|
||||
|
||||
[:ul {:class (stl/css :column-actions)}
|
||||
[:li {:role "separator" :class (stl/css :column-separator)}]
|
||||
@ -464,16 +550,13 @@
|
||||
(= subscription-type "unlimited")
|
||||
(assoc :show-contact-sales-option true)))))))
|
||||
|
||||
;; "Go to admin console" targets the organization currently
|
||||
;; previewed on the left column (not necessarily the active
|
||||
;; team's organization), and only owners of that organization
|
||||
;; get the option at all.
|
||||
selected-organization
|
||||
(get organizations selected-organization-id)
|
||||
|
||||
;; "Go to admin console" targets the active team's organization
|
||||
;; (the one with the tick), not the one previewed on the left
|
||||
;; column, and only its owner gets the organization-specific
|
||||
;; page.
|
||||
admin-console-href
|
||||
(mf/with-memo [selected-organization profile]
|
||||
(resolve-admin-console-href selected-organization profile))
|
||||
(mf/with-memo [current-organization profile]
|
||||
(resolve-admin-console-href current-organization profile))
|
||||
|
||||
;; "Create new team" targets the organization previewed on the
|
||||
;; left column (`selected-organization-id`), i.e. wherever the
|
||||
@ -537,7 +620,7 @@
|
||||
:aria-haspopup "menu"}
|
||||
(if (:is-default team)
|
||||
[:div {:class (stl/css :personal-projects-icon)}
|
||||
[:> icon* {:icon-id i/files}]]
|
||||
[:> personal-projects-icon* {:class (stl/css :personal-icon)}]]
|
||||
|
||||
[:img {:src (cf/resolve-team-photo-url team)
|
||||
:class (stl/css :team-picture)
|
||||
|
||||
@ -132,13 +132,15 @@
|
||||
}
|
||||
|
||||
.my-teams-icon {
|
||||
height: var(--sp-xxl);
|
||||
width: var(--sp-xxl);
|
||||
display: flex;
|
||||
height: $sz-24;
|
||||
width: $sz-24;
|
||||
|
||||
svg {
|
||||
fill: var(--icon-stroke-color);
|
||||
width: var(--sp-xxl);
|
||||
height: var(--sp-xxl);
|
||||
stroke: none;
|
||||
width: $sz-24;
|
||||
height: $sz-24;
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,10 +152,11 @@
|
||||
width: var(--sp-xxl);
|
||||
}
|
||||
|
||||
.team-item-personal-icon svg {
|
||||
.personal-icon {
|
||||
flex-shrink: 0;
|
||||
color: transparent;
|
||||
fill: none;
|
||||
stroke-width: 1px;
|
||||
stroke-width: 1.2px;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
|
||||
@ -174,13 +177,6 @@
|
||||
width: var(--sp-xxxl);
|
||||
}
|
||||
|
||||
.personal-projects-icon svg {
|
||||
color: transparent;
|
||||
fill: none;
|
||||
stroke-width: 1px;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
|
||||
.team-picture {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -191,23 +187,28 @@
|
||||
}
|
||||
|
||||
.organization-team-dropdown {
|
||||
--switcher-dropdown-background: var(--color-background-tertiary);
|
||||
|
||||
:global(.light) & {
|
||||
--switcher-dropdown-background: var(--color-background-primary);
|
||||
}
|
||||
|
||||
box-shadow: 0 0 var(--sp-m) 0 var(--menu-shadow-color);
|
||||
position: absolute;
|
||||
padding: var(--sp-xs);
|
||||
padding: var(--sp-s);
|
||||
border-radius: $br-8;
|
||||
z-index: var(--z-index-dropdown);
|
||||
color: var(--title-foreground-color-hover);
|
||||
background-color: var(--menu-background-color);
|
||||
background-color: var(--switcher-dropdown-background);
|
||||
border: $b-2 solid var(--panel-border-color);
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: px2rem(257) px2rem(257);
|
||||
grid-template-rows: minmax(0, 1fr);
|
||||
gap: var(--sp-m);
|
||||
gap: var(--sp-s);
|
||||
top: calc(var(--sp-s) + #{$sz-64} + var(--sp-xs));
|
||||
left: var(--sp-s);
|
||||
height: fit-content;
|
||||
max-height: px2rem(416);
|
||||
height: px2rem(416);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@ -224,9 +225,8 @@
|
||||
|
||||
.organizations-column,
|
||||
.teams-column {
|
||||
display: grid;
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
gap: var(--sp-xxs);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
@ -236,18 +236,39 @@
|
||||
|
||||
.teams-column {
|
||||
border-inline-start: $b-1 solid var(--color-background-quaternary);
|
||||
padding-inline-start: var(--sp-m);
|
||||
padding-inline-start: var(--sp-s);
|
||||
}
|
||||
|
||||
.column-scroll {
|
||||
@include custom-scrollbar;
|
||||
|
||||
flex: 0 1 auto;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
|
||||
&.fade::after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: sticky;
|
||||
inset-block-end: 0;
|
||||
height: px2rem(44);
|
||||
margin-block-start: calc(-1 * #{px2rem(44)});
|
||||
background: linear-gradient(transparent, var(--switcher-dropdown-background));
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.column-label {
|
||||
@include t.use-typography("headline-small");
|
||||
|
||||
color: var(--color-foreground-secondary);
|
||||
padding: $sz-6 $sz-6 $sz-6 var(--sp-m);
|
||||
padding: var(--sp-s) $sz-6 $sz-6 var(--sp-m);
|
||||
margin-block-end: var(--sp-xxs);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.column-list,
|
||||
.column-bucket,
|
||||
.column-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -257,16 +278,13 @@
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.column-list {
|
||||
@include custom-scrollbar;
|
||||
.column-bucket {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
background:
|
||||
linear-gradient(transparent, var(--menu-background-color) 70%) 0 100% / 100% #{$sz-40} local no-repeat,
|
||||
radial-gradient(farthest-side at 50% 100%, var(--menu-shadow-color), transparent) 0 100% / 100% #{$sz-14}
|
||||
scroll no-repeat;
|
||||
background-color: var(--menu-background-color);
|
||||
.column-actions {
|
||||
flex-shrink: 0;
|
||||
margin-block-start: auto;
|
||||
}
|
||||
|
||||
.column-separator {
|
||||
@ -275,6 +293,12 @@
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
// The fade ends right on these lines, with no gap above them.
|
||||
.column-bucket > .column-separator,
|
||||
.column-actions > .column-separator {
|
||||
margin-block-start: 0;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
@include t.use-typography("body-medium");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user