diff --git a/frontend/playwright/ui/pages/DashboardPage.js b/frontend/playwright/ui/pages/DashboardPage.js index 8532455c88..8d0f7df082 100644 --- a/frontend/playwright/ui/pages/DashboardPage.js +++ b/frontend/playwright/ui/pages/DashboardPage.js @@ -82,7 +82,10 @@ export class DashboardPage extends BaseWebSocketPage { this.fontsLink = this.sidebar.getByText("Fonts"); this.librariesLink = this.sidebar.getByText("Libraries"); - this.searchButton = page.getByRole("button", { name: "dashboard-search" }); + this.searchButton = page.getByRole("button", { + name: "Search", + exact: true, + }); this.searchInput = page.getByPlaceholder("Search…"); this.teamDropdown = this.sidebar.getByRole("button", { diff --git a/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js b/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js index 5b271306cb..320d855e64 100644 --- a/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js +++ b/frontend/playwright/ui/visual-specs/visual-dashboard.spec.js @@ -486,3 +486,31 @@ test.describe("Team modals controls", () => { await expect(modal).toHaveScreenshot(shot); }); }); + +test.describe("Dashboard sidebar controls", () => { + const shot = { maxDiffPixelRatio: 0, threshold: 0 }; + + test("Search box, pinned placeholder and profile menu", async ({ page }) => { + const dashboardPage = new DashboardPage(page); + await dashboardPage.goToDashboard(); + + const search = page.locator("[class*='sidebar-search']"); + await expect(search).toBeVisible(); + await expect(search).toHaveScreenshot(shot); + + await expect(page.getByTestId("pinned-projects")).toHaveScreenshot(shot); + + // A search term swaps the search icon for the clear button. + await page.locator("#search-input").fill("test"); + await expect(page).toHaveURL(/search/); + const clear = search.locator("button"); + await clear.hover(); + await expect(search).toHaveScreenshot(shot); + + await page.getByTestId("profile-btn").click(); + await expect(page.getByTestId("logout-profile-opt")).toBeVisible(); + await expect( + page.getByTestId("logout-profile-opt").locator("xpath=.."), + ).toHaveScreenshot(shot); + }); +}); diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index b528a5c788..d9514fb927 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -37,7 +37,6 @@ [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.ds.layout.menu :refer [context-menu*]] [app.main.ui.hooks :refer [use-focus-timer-ref]] - [app.main.ui.icons :as deprecated-icon] [app.main.ui.nitrate.nitrate-form] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] @@ -48,18 +47,6 @@ [goog.functions :as f] [rumext.v2 :as mf])) -(def ^:private clear-search-icon - (deprecated-icon/icon-xref :delete-text (stl/css :clear-search-icon))) - -(def ^:private search-icon - (deprecated-icon/icon-xref :search (stl/css :search-icon))) - -(def ^:private pin-icon - (deprecated-icon/icon-xref :pin (stl/css :pin-icon))) - -(def ^:private exit-icon - (deprecated-icon/icon-xref :exit (stl/css :exit-icon))) - (defn schedule-focus-by-id! [ref element-id] (when-let [h (mf/ref-val ref)] @@ -101,7 +88,6 @@ (schedule-focus-by-id! focus-timer-ref (str project-id)) (st/emit! (dcm/go-to-dashboard-files :project-id project-id))))) - on-edit-open (mf/use-fn #(swap! local* assoc :edition? true)) @@ -239,15 +225,19 @@ (if (or @focused? (seq search-term)) [:button {:class (stl/css :search-btn :clear-search-btn) :tab-index "0" - :aria-label "dashboard-clear-search" + :aria-label (tr "dashboard.clear-search") :on-click on-clear-click :on-key-down handle-clear-search} - clear-search-icon] + [:> icon* {:icon-id i/delete-text + :class (stl/css :search-icon) + :aria-hidden true}]] [:button {:class (stl/css :search-btn) - :aria-label "dashboard-search" + :aria-label (tr "labels.search") :on-click on-clear-click} - search-icon])])) + [:> icon* {:icon-id i/search + :class (stl/css :search-icon) + :aria-hidden true}]])])) (mf/defc sidebar-content* {::mf/private true} @@ -364,7 +354,6 @@ :keyboard-action go-drafts-with-key} [:span {:class (stl/css :element-title)} (tr "labels.drafts")]]]]] - [:div {:class (stl/css :sidebar-content-section)} [:div {:class (stl/css :sidebar-section-title)} (tr "labels.sources")] @@ -384,7 +373,6 @@ :keyboard-action go-libs-with-key} [:span {:class (stl/css :element-title)} (tr "labels.shared-libraries")]]]]] - [:div {:class (stl/css :sidebar-content-section) :data-testid "pinned-projects"} [:div {:class (stl/css :sidebar-section-title)} @@ -399,7 +387,9 @@ :team-id (:id team) :is-selected (= (:id item) (:id project))}])] [:div {:class (stl/css :sidebar-empty-placeholder)} - pin-icon + [:> icon* {:icon-id i/pin + :size "s" + :class (stl/css :pin-icon)}] [:span {:class (stl/css :empty-text)} (tr "dashboard.no-projects-placeholder")]])]] [:div {:class (stl/css-case :separator true :overflow-separator overflow?)}]]])) @@ -673,7 +663,6 @@ [:> dashboard-cta* {:profile profile}] [:> subscription-sidebar* {:profile profile}]))) - (when (and team profile) [:& comments-section {:profile profile @@ -704,7 +693,6 @@ [:li {:class (stl/css :profile-separator)}] - [:> dropdown-menu-item* {:class (stl/css-case :profile-dropdown-item true) :on-click on-menu-click :on-key-down (fn [event] @@ -749,7 +737,8 @@ [:> dropdown-menu-item* {:class (stl/css :profile-dropdown-item :item-with-icon) :on-click handle-logout-click :data-testid "logout-profile-opt"} - exit-icon + [:> icon* {:icon-id i/exit + :class (stl/css :exit-icon)}] (tr "labels.logout")]] (when (and team profile) diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss index 4bbd6d243b..424f56427b 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.scss +++ b/frontend/src/app/main/ui/dashboard/sidebar.scss @@ -4,14 +4,21 @@ // // Copyright (c) KALEIDOS SUBSIDIARY SL -@use "ds/typography.scss" as t; +@use "ds/typography.scss" as *; @use "ds/colors.scss" as *; @use "ds/spacing.scss" as *; @use "ds/_borders.scss" as *; @use "ds/_sizes.scss" as *; @use "ds/_utils.scss" as *; @use "ds/z-index.scss" as *; +@use "ds/mixins.scss" as *; + +// The shared dashboard header styles move in their own change: they are +// used by ten dashboard modules. @use "common/refactor/common-dashboard"; + +// refactor/ stays for the menu placeholders (%menu-dropdown, +// %menu-item-base) of the profile menu and its submenus. @use "common/refactor/common-refactor.scss" as deprecated; // SIDEBAR COMPONENT @@ -20,19 +27,19 @@ grid-row: 1 / span 2; grid-column: 1 / span 2; grid-template-rows: auto 1fr auto; - height: 100%; - width: 100%; + block-size: 100%; + inline-size: 100%; margin: 0 var(--sp-l) 0 0; - border-right: $b-1 solid var(--panel-border-color); - background-color: var(--panel-background-color); + border-inline-end: $b-1 solid var(--color-background-quaternary); + background-color: var(--color-background-primary); } // SIDEBAR CONTENT COMPONENT .sidebar-content-wrapper { display: flex; flex-direction: column; - min-height: 0; - height: 100%; + min-block-size: 0; + block-size: 100%; overflow: hidden; } @@ -41,7 +48,7 @@ grid-template-rows: auto auto auto auto 1fr; gap: var(--sp-xxl); flex: 1; - min-height: 0; + min-block-size: 0; padding: 0; overflow: hidden auto; } @@ -52,17 +59,17 @@ } .separator { - height: var(--sp-xxs); - width: 94%; - margin-left: 3%; + block-size: var(--sp-xxs); + inline-size: 94%; + margin-inline-start: 3%; } .overflow-separator { - border-bottom: $b-1 solid var(--color-background-quaternary); + border-block-end: $b-1 solid var(--color-background-quaternary); } .sidebar-section-title { - @include t.use-typography("headline-small"); + @include use-typography("headline-small"); padding: 0 var(--sp-s) var(--sp-s) var(--sp-xxl); color: var(--color-foreground-secondary); @@ -82,31 +89,33 @@ cursor: pointer; &:hover { - background-color: var(--sidebar-element-background-color-hover); + background-color: var(--color-background-secondary); + // The item labels have no class. span { - color: var(--sidebar-element-foreground-color-hover); + color: var(--color-accent-primary); } } &.current { - background-color: var(--sidebar-element-background-color-selected); + background-color: var(--color-background-quaternary); .element-title { - color: var(--sidebar-element-foreground-color-selected); + color: var(--color-accent-primary); } } } +// The icon has no class. .recent-projects svg { - stroke: var(--main-icon-foreground); + stroke: var(--color-foreground-primary); } .sidebar-link { display: block; padding: var(--sp-s) var(--sp-s) var(--sp-s) var(--sp-xxl); - font-weight: deprecated.$fw400; - width: 100%; + font-weight: 400; + inline-size: 100%; &:hover { text-decoration: none; @@ -118,31 +127,33 @@ } .element-title { - @include deprecated.text-ellipsis; + @include text-ellipsis; - width: deprecated.$s-256; + inline-size: px2rem(256); color: var(--color-foreground-primary); - font-size: deprecated.$fs-14; + font-size: px2rem(14); } // Pinned projects .sidebar-empty-placeholder { padding: var(--sp-m); - color: var(--empty-message-foreground-color); + color: var(--color-foreground-secondary); display: flex; align-items: center; } +// The DS small icon draws 12px inside a 16px box: 2px less margin on each +// side keeps the drawing and the text where they were. .pin-icon { - @extend %button-icon-small; - - stroke: var(--icon-foreground); - margin: 0 var(--sp-m); + flex-shrink: 0; + stroke-width: 1.33px; + color: var(--color-foreground-secondary); + margin: 0 px2rem(10); } .empty-text { - font-size: deprecated.$fs-12; + font-size: px2rem(12); } // Search @@ -155,55 +166,58 @@ border: $b-1 solid transparent; margin: 0 var(--sp-l); border-radius: $br-8; - background-color: var(--search-bar-input-background-color); + background-color: var(--color-background-tertiary); } .input-text { - @include t.use-typography("title-small"); + @include use-typography("title-small"); - height: $sz-40; - width: 100%; + block-size: $sz-40; + inline-size: 100%; padding: $sz-6 var(--sp-m); margin: 0; border: transparent; border-radius: $br-8; background: transparent; - color: var(--search-bar-foreground-color); + color: var(--color-foreground-primary); &:focus, &:focus-within, &:focus-visible { outline: none; - border: $b-1 solid var(--search-bar-input-border-color-focus); + border: $b-1 solid var(--color-accent-primary); } ::placeholder { - color: var(--search-bar-placeholder-foreground-color); + color: var(--color-foreground-secondary); } } .search-btn { - @include deprecated.button-style; - @include deprecated.flex-center; + border: none; + background: none; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + --sidebar-search-foreground-color: var(--color-foreground-secondary); + + color: var(--sidebar-search-foreground-color); position: absolute; - right: 0; - height: var(--sp-xxl); - width: var(--sp-xxxl); + inset-inline-end: 0; + block-size: var(--sp-xxl); + inline-size: var(--sp-xxxl); padding: 0 var(--sp-s); } -.search-icon, -.clear-search-btn { - @extend %button-icon; - - --sidebar-search-foreground-color: var(--search-bar-icon-foreground-color); - - stroke: var(--sidebar-search-foreground-color); +.search-icon { + flex-shrink: 0; + stroke-width: 1px; } .clear-search-btn:hover { - --sidebar-search-foreground-color: var(--search-bar-icon-foreground-color-hover); + --sidebar-search-foreground-color: var(--color-accent-primary); } // Profile @@ -212,33 +226,32 @@ display: grid; grid-template-columns: 1fr auto; padding: var(--sp-m) var(--sp-l); - border-top: $b-1 solid var(--panel-border-color); - background-color: var(--profile-section-background-color); + border-block-start: $b-1 solid var(--color-background-quaternary); + background-color: var(--color-background-tertiary); cursor: pointer; } .profile { - @include deprecated.button-style; - + border: none; + background: none; display: grid; grid-template-columns: auto 1fr; gap: var(--sp-s); cursor: pointer; - text-align: left; + text-align: start; } .profile-fullname { - @include t.use-typography("title-small"); - @include deprecated.text-ellipsis; + @include use-typography("title-small"); + @include text-ellipsis; align-self: center; - max-width: var(--sp-l) 0; - color: var(--profile-foreground-color); + color: var(--color-foreground-primary); } .profile-img { - height: $sz-40; - width: $sz-40; + block-size: $sz-40; + inline-size: $sz-40; border-radius: $br-circle; } @@ -247,14 +260,14 @@ inset-inline-start: var(--sp-s); inset-block-end: px2rem(72); // 72 is the height of the profile button - min-width: calc(100% - var(--sp-s)); + min-inline-size: calc(100% - var(--sp-s)); // TODO ADD animation fadeInUp } .profile-dropdown-item { @extend %menu-item-base; - @include t.use-typography("body-medium"); + @include use-typography("body-medium"); block-size: $sz-40; margin-block-end: var(--sp-xs); @@ -262,29 +275,25 @@ padding-inline-start: var(--sp-l); &:hover { - color: var(--menu-foreground-color-hover); + color: var(--color-foreground-primary); .open-arrow { - --icon-stroke-color: var(--menu-foreground-color-hover); + --icon-stroke-color: var(--color-foreground-primary); } } } .profile-dropdown-item .open-arrow { - @include deprecated.flex-center; -} - -.profile-dropdown-item .open-arrow svg { - @extend %button-icon; - - stroke: var(--icon-foreground); + display: flex; + justify-content: center; + align-items: center; } .sub-menu { @extend %menu-dropdown; - inset-inline-start: calc(deprecated.$s-292 + var(--sp-s)); - min-width: deprecated.$s-192; + inset-inline-start: calc(#{px2rem(292)} + var(--sp-s)); + min-inline-size: $sz-192; } // Each submenu is positioned via its bottom edge; the visual top lands @@ -293,11 +302,11 @@ // its top edge sits one row above Community — aligning with the // "Help & Learning" trigger row in the parent menu. .sub-menu.help-learning { - inset-block-end: deprecated.$s-120; + inset-block-end: $sz-120; } .sub-menu.community { - inset-block-end: deprecated.$s-120; + inset-block-end: $sz-120; } .sub-menu.about { @@ -306,7 +315,7 @@ .submenu-item { @extend %menu-item-base; - @include t.use-typography("body-medium"); + @include use-typography("body-medium"); block-size: $sz-40; margin-block-end: var(--sp-xs); @@ -314,7 +323,7 @@ padding-inline: var(--sp-l); &:hover { - color: var(--menu-foreground-color-hover); + color: var(--color-foreground-primary); } &.checking { @@ -334,7 +343,7 @@ } .submenu-separator { - border-top: $b-1 solid var(--color-background-quaternary); + border-block-start: $b-1 solid var(--color-background-quaternary); margin: 0; } @@ -345,8 +354,8 @@ } .menu-version { - @include t.use-typography("code-font"); - @include deprecated.text-ellipsis; + @include use-typography("code-font"); + @include text-ellipsis; color: var(--color-foreground-secondary); margin-inline-start: var(--sp-s); @@ -354,8 +363,8 @@ } .profile-separator { - height: $sz-6; - border-top: $b-1 solid var(--color-background-quaternary); + block-size: $sz-6; + border-block-start: $b-1 solid var(--color-background-quaternary); } .item-with-icon { @@ -365,38 +374,6 @@ } .exit-icon { - @extend %button-icon; - - stroke: var(--icon-foreground); -} - -.upgrade-plan-section { - @include deprecated.button-style; - - display: flex; - justify-content: space-between; - border: $b-1 solid var(--color-background-quaternary); - border-radius: var(--sp-s); - padding: var(--sp-m); - margin: var(--sp-m); + stroke-width: 1px; color: var(--color-foreground-secondary); - cursor: pointer; -} - -.penpot-free { - @include t.use-typography("body-medium"); - - display: flex; - flex-direction: column; - text-align: left; -} - -.no-limits { - @include t.use-typography("body-small"); -} - -.power-up { - @include t.use-typography("body-small"); - - color: var(--color-accent-tertiary); } diff --git a/frontend/translations/en.po b/frontend/translations/en.po index c747726caa..57b5569932 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -356,6 +356,10 @@ msgstr "View full changelog" msgid "dashboard.check-updates.view-release-notes" msgstr "View release notes" +#: src/app/main/ui/dashboard/sidebar.cljs:228 +msgid "dashboard.clear-search" +msgstr "Clear search" + #: src/app/main/ui/dashboard/deleted.cljs:322 msgid "dashboard.clear-trash-button" msgstr "Clear trash" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index c95dafcebd..6d20e94fe9 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -362,6 +362,10 @@ msgstr "Ver changelog completo" msgid "dashboard.check-updates.view-release-notes" msgstr "Ver notas de la versión" +#: src/app/main/ui/dashboard/sidebar.cljs:228 +msgid "dashboard.clear-search" +msgstr "Borrar búsqueda" + #: src/app/main/ui/dashboard/deleted.cljs:322 msgid "dashboard.clear-trash-button" msgstr "Vaciar papelera"