mirror of
https://github.com/penpot/penpot.git
synced 2026-10-28 21:40:34 +00:00
♻️ Move the dashboard header styles to the DS
The page header of the dashboard and settings pages took its styles from common/refactor/common-dashboard.scss. Move the rules still in use to dashboard/common/header.scss, written with DS tokens: - The page titles become heading* (title-large) with a class instead of a bare h1; the team section links get a class, and the active class moves from the li to the link. - Drop the rules that matched nothing: .element-name, .context-menu, .icon and .btn-secondary inside the header, and the global .btn-primary and .btn-secondary (only the fonts page uses them; it keeps the old import until its open change lands). - The sidebar and subscription styles imported the file without using it; drop the import. The header looks the same (0 px in the new visual test). The title line height goes from 1.15 to 1.4, which does not move the text. AI-assisted-by: claude-opus-5-5
This commit is contained in:
parent
8951c57ee6
commit
f52d8e74d7
@ -779,6 +779,50 @@ test.describe("Team pages controls", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Dashboard headers", () => {
|
||||
const shot = { maxDiffPixelRatio: 0, threshold: 0 };
|
||||
const header = (page) => page.getByTestId("dashboard-header");
|
||||
|
||||
test("Page headers", async ({ page }) => {
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
|
||||
await dashboardPage.goToDashboard();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
await dashboardPage.goToDrafts();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
await dashboardPage.goToLibraries();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
await dashboardPage.goToFonts();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
await dashboardPage.goToDeleted();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
await dashboardPage.goToSearch();
|
||||
await expect(dashboardPage.mainHeading).toBeVisible();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
});
|
||||
|
||||
test("Team header menu", async ({ page }) => {
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.setupDashboardFull();
|
||||
await dashboardPage.goToSecondTeamMembersSection();
|
||||
await expect(dashboardPage.mainHeading).toHaveText("Members");
|
||||
|
||||
await page.mouse.move(10, 700);
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
await header(page).getByText("Invitations").hover();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
});
|
||||
|
||||
test("Account header", async ({ page }) => {
|
||||
const dashboardPage = new DashboardPage(page);
|
||||
await dashboardPage.goToDashboard();
|
||||
await dashboardPage.goToAccount();
|
||||
await expect(page.getByTestId("account-title")).toBeVisible();
|
||||
await expect(header(page)).toHaveScreenshot(shot);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Settings controls", () => {
|
||||
const shot = { maxDiffPixelRatio: 0, threshold: 0 };
|
||||
|
||||
|
||||
91
frontend/src/app/main/ui/dashboard/common/header.scss
Normal file
91
frontend/src/app/main/ui/dashboard/common/header.scss
Normal file
@ -0,0 +1,91 @@
|
||||
// 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 SUBSIDIARY SL
|
||||
|
||||
// Page header shared by the dashboard and settings pages.
|
||||
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
@use "ds/typography.scss" as *;
|
||||
|
||||
.dashboard-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
block-size: $sz-64;
|
||||
max-block-size: $sz-64;
|
||||
padding: var(--sp-xs) var(--sp-l) var(--sp-xs) var(--sp-s);
|
||||
user-select: none;
|
||||
|
||||
&.team {
|
||||
display: grid;
|
||||
grid-template-columns: 20% 1fr 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-inline-start: var(--sp-m);
|
||||
}
|
||||
|
||||
.dashboard-title-text {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
inline-size: 100%;
|
||||
max-inline-size: $sz-712;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
user-select: all;
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.dashboard-header-actions {
|
||||
display: flex;
|
||||
column-gap: var(--sp-l);
|
||||
}
|
||||
|
||||
.dashboard-buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dashboard-header-menu {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dashboard-header-options {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.dashboard-header-link {
|
||||
@include use-typography("body-large");
|
||||
|
||||
--dashboard-header-link-color: var(--color-foreground-secondary);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
block-size: $sz-40;
|
||||
padding: var(--sp-xs) var(--sp-xxl);
|
||||
border-block-end: px2rem(3) solid transparent;
|
||||
color: var(--dashboard-header-link-color);
|
||||
|
||||
&:hover {
|
||||
--dashboard-header-link-color: var(--color-foreground-primary);
|
||||
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
--dashboard-header-link-color: var(--color-foreground-primary);
|
||||
}
|
||||
}
|
||||
@ -23,6 +23,8 @@
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.dom :as dom]
|
||||
@ -61,7 +63,10 @@
|
||||
[:header {:class (stl/css :dashboard-header)
|
||||
:data-testid "dashboard-header"}
|
||||
[:div#dashboard-deleted-title {:class (stl/css :dashboard-title)}
|
||||
[:h1 (tr "dashboard.projects-title")]]
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)}
|
||||
(tr "dashboard.projects-title")]]
|
||||
[:div {:class (stl/css :dashboard-header-actions)}
|
||||
[:> dashboard-mcp-menu*]
|
||||
[:> layout-toggle* {:layout layout :on-change on-change}]]])
|
||||
|
||||
@ -4,9 +4,7 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
// The shared dashboard header styles move in their own change: they are
|
||||
// used by ten dashboard modules.
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
@use "ds/typography.scss" as *;
|
||||
@use "ds/spacing.scss" as *;
|
||||
@use "ds/z-index.scss" as *;
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.dom :as dom]
|
||||
@ -84,7 +86,10 @@
|
||||
:data-testid "dashboard-header"}
|
||||
(if (:is-default project)
|
||||
[:div#dashboard-drafts-title {:class (stl/css :dashboard-title)}
|
||||
[:h1 (tr "labels.drafts")]]
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)}
|
||||
(tr "labels.drafts")]]
|
||||
|
||||
(if (and (:edition @local) can-edit)
|
||||
[:& inline-edition
|
||||
@ -97,9 +102,12 @@
|
||||
(swap! local assoc :edition false)))
|
||||
:max-length 250}]
|
||||
[:div {:class (stl/css :dashboard-title)}
|
||||
[:h1 {:on-double-click on-edit
|
||||
:data-testid "project-title"
|
||||
:id (:id project)}
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)
|
||||
:on-double-click on-edit
|
||||
:data-testid "project-title"
|
||||
:id (:id project)}
|
||||
(:name project)]]))
|
||||
|
||||
[:div {:class (stl/css :dashboard-header-actions)}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.grid :refer [grid*]]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
@ -68,7 +70,10 @@
|
||||
[:*
|
||||
[:header {:class (stl/css :dashboard-header) :data-testid "dashboard-header"}
|
||||
[:div#dashboard-libraries-title {:class (stl/css :dashboard-title)}
|
||||
[:h1 (tr "dashboard.libraries-title")]]]
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)}
|
||||
(tr "dashboard.libraries-title")]]]
|
||||
|
||||
[:section {:class (stl/css :dashboard-container :no-bg :dashboard-shared)
|
||||
:ref rowref}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
|
||||
.dashboard-container {
|
||||
flex: 1 0 0;
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.ds.layout.menu :refer [context-menu*]]
|
||||
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
@ -48,9 +50,12 @@
|
||||
[:header {:class (stl/css :dashboard-header)
|
||||
:data-testid "dashboard-header"}
|
||||
[:div#dashboard-projects-title {:class (stl/css :dashboard-title)}
|
||||
[:h1 (if default-team?
|
||||
(tr "dashboard.personal-projects")
|
||||
(tr "dashboard.projects-title"))]]
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)}
|
||||
(if default-team?
|
||||
(tr "dashboard.personal-projects")
|
||||
(tr "dashboard.projects-title"))]]
|
||||
[:div {:class (stl/css :dashboard-header-actions)}
|
||||
[:> dashboard-mcp-menu*]
|
||||
[:> layout-toggle* {:layout layout
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/spacing.scss" as *;
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.grid :refer [grid*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
@ -55,7 +57,10 @@
|
||||
[:*
|
||||
[:header {:class (stl/css :dashboard-header) :data-testid "dashboard-header"}
|
||||
[:div#dashboard-search-title {:class (stl/css :dashboard-title)}
|
||||
[:h1 (tr "dashboard.title-search")]]]
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)}
|
||||
(tr "dashboard.title-search")]]]
|
||||
|
||||
[:section {:class (stl/css :dashboard-container :search :no-bg)
|
||||
:ref rowref}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
@use "./placeholder";
|
||||
|
||||
.dashboard-container {
|
||||
|
||||
@ -13,9 +13,6 @@
|
||||
@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.
|
||||
|
||||
@ -8,9 +8,6 @@
|
||||
// power up submenu.
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
|
||||
// The shared dashboard header styles move in their own change: they are
|
||||
// used by ten dashboard modules.
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "ds/typography.scss" as *;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
@ -94,23 +94,34 @@
|
||||
|
||||
[:header {:class (stl/css :dashboard-header :team) :data-testid "dashboard-header"}
|
||||
[:div {:class (stl/css :dashboard-title)}
|
||||
[:h1 (cond
|
||||
members-section? (tr "labels.members")
|
||||
settings-section? (tr "labels.settings")
|
||||
invitations-section? (tr "labels.invitations")
|
||||
webhooks-section? (tr "labels.webhooks")
|
||||
:else nil)]]
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)}
|
||||
(cond
|
||||
members-section? (tr "labels.members")
|
||||
settings-section? (tr "labels.settings")
|
||||
invitations-section? (tr "labels.invitations")
|
||||
webhooks-section? (tr "labels.webhooks")
|
||||
:else nil)]]
|
||||
[:nav {:class (stl/css :dashboard-header-menu)}
|
||||
[:ul {:class (stl/css :dashboard-header-options)}
|
||||
[:li {:class (when members-section? (stl/css :active))}
|
||||
[:a {:on-click on-nav-members} (tr "labels.members")]]
|
||||
[:li {:class (when invitations-section? (stl/css :active))}
|
||||
[:a {:on-click on-nav-invitations} (tr "labels.invitations")]]
|
||||
[:li
|
||||
[:a {:class (stl/css-case :dashboard-header-link true
|
||||
:active members-section?)
|
||||
:on-click on-nav-members} (tr "labels.members")]]
|
||||
[:li
|
||||
[:a {:class (stl/css-case :dashboard-header-link true
|
||||
:active invitations-section?)
|
||||
:on-click on-nav-invitations} (tr "labels.invitations")]]
|
||||
(when (contains? cfg/flags :webhooks)
|
||||
[:li {:class (when webhooks-section? (stl/css :active))}
|
||||
[:a {:on-click on-nav-webhooks} (tr "labels.webhooks")]])
|
||||
[:li {:class (when settings-section? (stl/css :active))}
|
||||
[:a {:on-click on-nav-settings} (tr "labels.settings")]]]]
|
||||
[:li
|
||||
[:a {:class (stl/css-case :dashboard-header-link true
|
||||
:active webhooks-section?)
|
||||
:on-click on-nav-webhooks} (tr "labels.webhooks")]])
|
||||
[:li
|
||||
[:a {:class (stl/css-case :dashboard-header-link true
|
||||
:active settings-section?)
|
||||
:on-click on-nav-settings} (tr "labels.settings")]]]]
|
||||
[:div {:class (stl/css :dashboard-buttons)}
|
||||
(when (and (or invitations-section? members-section?) (not-empty invitations))
|
||||
(let [invite-button (mf/html
|
||||
|
||||
@ -5,10 +5,9 @@
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
// refactor/ stays for the component-family placeholders: %input-checkbox
|
||||
// and %checkbox-icon (checkboxes, #12380) and %modal-* (modals). The shared
|
||||
// dashboard header (common-dashboard) moves in its own change.
|
||||
// and %checkbox-icon (checkboxes, #12380) and %modal-* (modals).
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
@use "ds/_utils.scss" as *;
|
||||
@use "ds/typography.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
[app.main.refs :as refs]
|
||||
[app.main.router :as rt]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.hooks :as hooks]
|
||||
[app.main.ui.modal :refer [modal-container*]]
|
||||
[app.main.ui.settings.change-email]
|
||||
@ -33,7 +35,11 @@
|
||||
[:header {:class (stl/css :dashboard-header)
|
||||
:data-testid "dashboard-header"}
|
||||
[:div {:class (stl/css :dashboard-title)}
|
||||
[:h1 {:data-testid "account-title"} (tr "dashboard.your-account-title")]]])
|
||||
[:> heading* {:level 1
|
||||
:typography t/title-large
|
||||
:class (stl/css :dashboard-title-text)
|
||||
:data-testid "account-title"}
|
||||
(tr "dashboard.your-account-title")]]])
|
||||
|
||||
(mf/defc settings*
|
||||
[{:keys [route type error-report-id error-href]}]
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "common/refactor/common-dashboard";
|
||||
@use "dashboard/common/header";
|
||||
@use "ds/_utils.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_borders.scss" as *;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user