diff --git a/frontend/playwright/ui/visual-specs/workspace.spec.js b/frontend/playwright/ui/visual-specs/workspace.spec.js index 7ae69e0520..73c5e2a524 100644 --- a/frontend/playwright/ui/visual-specs/workspace.spec.js +++ b/frontend/playwright/ui/visual-specs/workspace.spec.js @@ -320,6 +320,39 @@ test.describe("Assets tab", () => { }); }); +test.describe("Left header", () => { + test("Shows the shared badge and the save status", async ({ page }) => { + const workspace = new WorkspacePage(page); + await workspace.setupEmptyFile(); + await workspace.mockRPC(/get\-file\?/, "workspace/get-file-library.json"); + await workspace.mockRPC( + "update-file?id=*", + "workspace/update-file-create-rect.json", + ); + await workspace.goToWorkspace({ + fileId: "c1249a66-fce0-8175-8004-7433fe4be8bc", + pageId: "c1249a66-fce0-8175-8004-7433fe4be8bd", + }); + + const header = page.locator("header", { hasText: "Testing library 1" }); + await expect(header).toBeVisible(); + // The badge and the status dot are tiny: compare every pixel. + await expect(header).toHaveScreenshot("left-header-shared.png", { + maxDiffPixelRatio: 0, + threshold: 0, + }); + + await workspace.rectShapeButton.click(); + await workspace.clickWithDragViewportAt(128, 128, 200, 100); + await expect(header.getByTitle("Saved")).toBeVisible(); + await page.mouse.move(640, 600); + await expect(header).toHaveScreenshot("left-header-saved.png", { + maxDiffPixelRatio: 0, + threshold: 0, + }); + }); +}); + test.describe("Palette", () => { test("Shows the bottom palette expanded and collapsed", async ({ page }) => { const workspace = new WorkspacePage(page); diff --git a/frontend/src/app/main/ui/workspace/left_header.cljs b/frontend/src/app/main/ui/workspace/left_header.cljs index 37e6247b87..3eec46c77d 100644 --- a/frontend/src/app/main/ui/workspace/left_header.cljs +++ b/frontend/src/app/main/ui/workspace/left_header.cljs @@ -15,6 +15,7 @@ [app.main.refs :as refs] [app.main.router :as rt] [app.main.store :as st] + [app.main.ui.ds.foundations.assets.icon :as i :refer [icon*]] [app.main.ui.icons :as deprecated-icon] [app.main.ui.workspace.main-menu :as main-menu] [app.util.dom :as dom] @@ -124,17 +125,11 @@ :saved (tr "workspace.header.saved") :retrying (tr "workspace.header.retrying") :error (tr "workspace.header.save-error") - nil)} - (case persistence-status - :pending deprecated-icon/status-alert - :saving deprecated-icon/status-alert - :saved deprecated-icon/status-tick - :retrying deprecated-icon/status-alert - :error deprecated-icon/status-wrong - nil)] + nil)}] [:div {:class (stl/css :file-name-label)} file-name]])] (when ^boolean shared? - [:span {:class (stl/css :shared-badge)} deprecated-icon/library]) + [:span {:class (stl/css :shared-badge)} + [:> icon* {:icon-id i/library :class (stl/css :shared-badge-icon)}]]) [:div {:class (stl/css :menu-section)} [:> main-menu/menu* {:layout layout :file file}]]])) diff --git a/frontend/src/app/main/ui/workspace/left_header.scss b/frontend/src/app/main/ui/workspace/left_header.scss index 663c7465b2..a1542d48a9 100644 --- a/frontend/src/app/main/ui/workspace/left_header.scss +++ b/frontend/src/app/main/ui/workspace/left_header.scss @@ -4,27 +4,32 @@ // // Copyright (c) KALEIDOS SUBSIDIARY SL -@use "refactor/common-refactor.scss" as deprecated; +@use "ds/_borders.scss" as *; +@use "ds/_sizes.scss" as *; +@use "ds/_utils.scss" as *; +@use "ds/typography.scss" as *; .workspace-header-left { display: flex; align-items: center; - padding: deprecated.$s-12 deprecated.$s-12 deprecated.$s-8 deprecated.$s-12; - min-height: deprecated.$s-52; + padding: var(--sp-m) var(--sp-m) var(--sp-s) var(--sp-m); + min-block-size: px2rem(52); } .main-icon { - @include deprecated.flex-center; - - width: deprecated.$s-32; - height: deprecated.$s-32; - min-height: deprecated.$s-32; - margin-right: deprecated.$s-4; + display: flex; + justify-content: center; + align-items: center; + inline-size: $sz-32; + block-size: $sz-32; + min-block-size: $sz-32; + margin-inline-end: var(--sp-xs); + // The Penpot logo is brand art from the legacy icon set and has no class. svg { - min-height: deprecated.$s-32; - width: deprecated.$s-32; - fill: var(--icon-foreground-hover); + min-block-size: $sz-32; + inline-size: $sz-32; + fill: var(--color-foreground-primary); } } @@ -32,49 +37,60 @@ position: relative; flex-grow: 1; flex-shrink: 1; - min-width: 0; - height: deprecated.$s-32; - min-height: deprecated.$s-32; + min-inline-size: 0; + block-size: $sz-32; + min-block-size: $sz-32; } .project-name, .file-name { - @include deprecated.uppercase-title-typography; - @include deprecated.text-ellipsis; - - height: deprecated.$s-16; - width: 100%; - padding-bottom: deprecated.$s-2; - color: var(--title-foreground-color); + display: block; + max-inline-size: 99%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + block-size: $sz-16; + inline-size: 100%; + padding-block-end: var(--sp-xxs); cursor: pointer; } -.file-name { - @include deprecated.small-title-typography; +.project-name { + @include use-typography("headline-small"); - text-transform: none; - color: var(--title-foreground-color-hover); + color: var(--color-foreground-secondary); +} + +.file-name { + @include use-typography("title-small"); + + color: var(--color-foreground-primary); align-items: center; display: flex; flex-direction: row; } .file-name-label { - @include deprecated.text-ellipsis; + display: block; + max-inline-size: 99%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .file-name-input { - @include deprecated.flex-center; + @include use-typography("title-small"); - width: 100%; + display: flex; + justify-content: center; + align-items: center; + inline-size: 100%; margin: 0; border: 0; padding: 0; - border-radius: deprecated.$br-4; - background-color: var(--input-background-color); - font-size: deprecated.$fs-14; - color: var(--input-foreground-color); - z-index: deprecated.$z-index-20; + border-radius: $br-4; + background-color: var(--color-background-tertiary); + color: var(--color-foreground-secondary); white-space: break-spaces; &:focus { @@ -83,46 +99,42 @@ } .shared-badge { - @include deprecated.flex-center; + display: flex; + justify-content: center; + align-items: center; + inline-size: $sz-16; + block-size: $sz-32; + margin-inline-end: var(--sp-xs); +} - width: deprecated.$s-16; - height: deprecated.$s-32; - margin-right: deprecated.$s-4; - - svg { - stroke: var(--button-secondary-foreground-color-rest); - fill: none; - height: deprecated.$s-16; - width: deprecated.$s-16; - } +.shared-badge-icon { + color: var(--color-foreground-secondary); } .status-notification { - width: deprecated.$s-6; - height: deprecated.$s-6; - border-radius: 50%; - margin-right: deprecated.$s-4; + --status-notification-background-color: transparent; + + inline-size: $sz-6; + block-size: $sz-6; + border-radius: $br-circle; + margin-inline-end: var(--sp-xs); flex-shrink: 0; + background-color: var(--status-notification-background-color); - &.pending-status { - background-color: var(--status-widget-background-color-warning); - } - - &.saving-status { - background-color: var(--status-widget-background-color-pending); + &.pending-status, + &.saving-status, + &.retrying-status { + --status-notification-background-color: var(--color-accent-warning); } &.saved-status { - background-color: var(--status-widget-background-color-success); + --status-notification-background-color: var(--color-accent-success); + animation: jump 0.3s ease-out; } - &.retrying-status { - background-color: var(--status-widget-background-color-warning); - } - &.error-status { - background-color: var(--status-widget-background-color-error); + --status-notification-background-color: var(--color-foreground-error); } }