mirror of
https://github.com/penpot/penpot.git
synced 2026-10-28 21:40:34 +00:00
♻️ Use DS buttons and icons in the inspect code tab (#12521)
* ♻️ Use DS buttons and icons in the inspect code tab "Copy all code" becomes a DS secondary button, and the expand panel buttons ghost DS icon buttons labelled "Expand panel" (new key, en and es). The collapse toggles of the CSS and markup blocks stay raw buttons, since they sit in a 12px column; their arrow uses DS icons and they get a name and aria-expanded. The copy buttons belong to the shared copy button and move with it. A visual test covers the code tab buttons, expanded and collapsed. AI-assisted-by: claude-opus-5-5 * ♻️ Move inspect code tab styles off the deprecated styles Spacing, sizes, borders, typographies and color aliases move to DS tokens and logical properties. The 11px uppercase titles become the 12px DS headline-small, the only difference. The code typography keeps its values with a TODO: the DS code-font names "Roboto Mono", while the app loads "robotomono". The full-width "Copy all code" DS button centers its label explicitly. The refactor/ import stays only for the copy buttons, styled here until the shared copy button moves to the DS. AI-assisted-by: claude-opus-5-5
This commit is contained in:
parent
96b62f6475
commit
f07452e36b
@ -322,3 +322,43 @@ test.describe("Viewer header", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Inspect code tab", () => {
|
||||
test("Shows the code tab buttons, expanded and collapsed", async ({
|
||||
page,
|
||||
}) => {
|
||||
const viewerPage = new ViewerPage(page);
|
||||
await viewerPage.setupLoggedInUser();
|
||||
await viewerPage.setupFileWithComments();
|
||||
await viewerPage.goToViewer({
|
||||
fileId: singleBoardFileId,
|
||||
pageId: singleBoardPageId,
|
||||
});
|
||||
await viewerPage.showCode();
|
||||
await page.getByRole("combobox").filter({ hasText: "Styles" }).click();
|
||||
await page.getByRole("option", { name: "Code" }).click();
|
||||
|
||||
const copyAll = page.getByRole("button", { name: "Copy all code" });
|
||||
await expect(copyAll).toBeVisible();
|
||||
// The CSS block header, with its toggle, expand and copy buttons.
|
||||
const cssToggle = page.locator('button[data-type="css"]');
|
||||
const cssHeader = cssToggle.locator("..");
|
||||
await page.mouse.move(0, 0);
|
||||
await expect(copyAll).toHaveScreenshot({
|
||||
maxDiffPixelRatio: 0,
|
||||
threshold: 0,
|
||||
});
|
||||
await expect(cssHeader).toHaveScreenshot({
|
||||
maxDiffPixelRatio: 0,
|
||||
threshold: 0,
|
||||
});
|
||||
|
||||
await cssToggle.click();
|
||||
await page.mouse.move(0, 0);
|
||||
// Collapsed: the arrow turns.
|
||||
await expect(cssHeader).toHaveScreenshot({
|
||||
maxDiffPixelRatio: 0,
|
||||
threshold: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -20,14 +20,17 @@
|
||||
[app.main.ui.components.code-block :refer [code-block*]]
|
||||
[app.main.ui.components.copy-button :refer [copy-button*]]
|
||||
[app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]]
|
||||
[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.hooks.resize :refer [use-resize-hook]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.shapes.text.fontfaces :refer [shapes->fonts]]
|
||||
[app.util.clipboard :as clipboard]
|
||||
[app.util.code-beautify :as cb]
|
||||
[app.util.code-gen :as cg]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.http :as http]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
@ -278,8 +281,9 @@
|
||||
[:div {:class (stl/css-case :element-options true
|
||||
:viewer-code-block (= :viewer from))}
|
||||
[:div {:class (stl/css :attributes-block)}
|
||||
[:button {:class (stl/css :download-button)
|
||||
:on-click handle-copy-all-code}
|
||||
[:> button* {:variant "secondary"
|
||||
:class (stl/css :download-button)
|
||||
:on-click handle-copy-all-code}
|
||||
"Copy all code"]]
|
||||
|
||||
#_[:div.attributes-block
|
||||
@ -291,11 +295,12 @@
|
||||
[:div {:class (stl/css :code-row-lang)}
|
||||
[:button {:class (stl/css :toggle-btn)
|
||||
:data-type "css"
|
||||
:aria-label "CSS"
|
||||
:aria-expanded (not collapsed-css?)
|
||||
:on-click handle-collapse}
|
||||
[:span {:class (stl/css-case
|
||||
:collapsabled-icon true
|
||||
:rotated collapsed-css?)}
|
||||
deprecated-icon/arrow]]
|
||||
[:> icon* {:icon-id (if collapsed-css? i/arrow-right i/arrow-down)
|
||||
:size "s"
|
||||
:class (stl/css :collapsabled-icon)}]]
|
||||
|
||||
[:div {:class (stl/css :code-lang-option)}
|
||||
"CSS"]
|
||||
@ -306,9 +311,10 @@
|
||||
;; :options [{:label "CSS" :value "css"}]}]
|
||||
|
||||
[:div {:class (stl/css :action-btns)}
|
||||
[:button {:class (stl/css :expand-button)
|
||||
:on-click on-expand}
|
||||
deprecated-icon/code]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "inspect.code.expand-panel")
|
||||
:icon i/code
|
||||
:on-click on-expand}]
|
||||
|
||||
[:> copy-button* {:data copy-css-fn
|
||||
:class (stl/css :css-copy-btn)
|
||||
@ -330,11 +336,12 @@
|
||||
[:div {:class (stl/css :code-row-lang)}
|
||||
[:button {:class (stl/css :toggle-btn)
|
||||
:data-type "markup"
|
||||
:aria-label (str/upper markup-type)
|
||||
:aria-expanded (not collapsed-markup?)
|
||||
:on-click handle-collapse}
|
||||
[:span {:class (stl/css-case
|
||||
:collapsabled-icon true
|
||||
:rotated collapsed-markup?)}
|
||||
deprecated-icon/arrow]]
|
||||
[:> icon* {:icon-id (if collapsed-markup? i/arrow-right i/arrow-down)
|
||||
:size "s"
|
||||
:class (stl/css :collapsabled-icon)}]]
|
||||
|
||||
[:& radio-buttons {:selected markup-type
|
||||
:on-change set-markup
|
||||
@ -347,9 +354,10 @@
|
||||
:id :svg}]]
|
||||
|
||||
[:div {:class (stl/css :action-btns)}
|
||||
[:button {:class (stl/css :expand-button)
|
||||
:on-click on-expand}
|
||||
deprecated-icon/code]
|
||||
[:> icon-button* {:variant "ghost"
|
||||
:aria-label (tr "inspect.code.expand-panel")
|
||||
:icon i/code
|
||||
:on-click on-expand}]
|
||||
|
||||
[:> copy-button* {:data copy-html-fn
|
||||
:class (stl/css :html-copy-btn)
|
||||
|
||||
@ -4,45 +4,55 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
// Only for the copy buttons, styled here until the shared copy button
|
||||
// moves to the DS.
|
||||
@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 *;
|
||||
|
||||
.element-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100vh - #{deprecated.$s-160}); // TODO: Fix this hardcoded value
|
||||
block-size: calc(100vh - #{$sz-160}); // TODO: Fix this hardcoded value
|
||||
overflow: hidden;
|
||||
padding-bottom: deprecated.$s-16;
|
||||
padding-block-end: var(--sp-l);
|
||||
overflow-y: auto;
|
||||
padding-inline: var(--sp-m);
|
||||
}
|
||||
|
||||
.viewer-code-block {
|
||||
height: calc(100vh - #{deprecated.$s-108}); // TODO: Fix this hardcoded value
|
||||
block-size: calc(100vh - #{px2rem(108)}); // TODO: Fix this hardcoded value
|
||||
}
|
||||
|
||||
// A full-width DS button does not center its label on its own.
|
||||
.download-button {
|
||||
@extend %button-secondary;
|
||||
@include deprecated.uppercase-title-typography;
|
||||
|
||||
height: deprecated.$s-32;
|
||||
width: 100%;
|
||||
margin: deprecated.$s-8 0;
|
||||
justify-content: center;
|
||||
inline-size: 100%;
|
||||
margin: var(--sp-s) 0;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
@include deprecated.code-typography;
|
||||
|
||||
// TODO: No exact DS typography match found: the DS code-font names
|
||||
// "Roboto Mono", the app loads it as "robotomono".
|
||||
// Closest match: code-font.
|
||||
font-family: "robotomono", monospace;
|
||||
font-size: px2rem(12);
|
||||
font-weight: 400;
|
||||
line-height: 1.2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0 deprecated.$s-4 deprecated.$s-8 0;
|
||||
block-size: 100%;
|
||||
min-block-size: 0;
|
||||
padding: 0 var(--sp-xs) var(--sp-s) 0;
|
||||
|
||||
// The highlighted code markup has no class of its own.
|
||||
pre {
|
||||
border-radius: deprecated.$br-8;
|
||||
padding: deprecated.$s-16;
|
||||
border-radius: $br-8;
|
||||
padding: var(--sp-l);
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
// Overrides background setted in the theme
|
||||
@ -51,19 +61,19 @@
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
height: initial;
|
||||
block-size: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.code-row-lang {
|
||||
display: grid;
|
||||
grid-template-columns: deprecated.$s-12 1fr deprecated.$s-60;
|
||||
gap: deprecated.$s-4;
|
||||
width: 100%;
|
||||
grid-template-columns: $sz-12 1fr auto;
|
||||
gap: var(--sp-xs);
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.code-lang {
|
||||
@include deprecated.uppercase-title-typography;
|
||||
@include use-typography("headline-small");
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -71,92 +81,70 @@
|
||||
|
||||
.action-btns {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: deprecated.$s-4;
|
||||
grid-template-columns: auto auto;
|
||||
gap: var(--sp-xs);
|
||||
}
|
||||
|
||||
.expand-button,
|
||||
.css-copy-btn,
|
||||
.html-copy-btn {
|
||||
@extend %button-tertiary;
|
||||
|
||||
height: deprecated.$s-32;
|
||||
width: deprecated.$s-28;
|
||||
block-size: $sz-32;
|
||||
inline-size: $sz-28;
|
||||
|
||||
svg {
|
||||
@extend %button-icon;
|
||||
|
||||
stroke: var(--icon-foreground);
|
||||
stroke: var(--color-foreground-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.code-lang-options {
|
||||
max-width: deprecated.$s-108;
|
||||
max-inline-size: px2rem(108);
|
||||
}
|
||||
|
||||
.code-lang-select {
|
||||
@include deprecated.uppercase-title-typography;
|
||||
@include use-typography("headline-small");
|
||||
|
||||
width: deprecated.$s-72;
|
||||
border: deprecated.$s-1 solid transparent;
|
||||
inline-size: px2rem(72);
|
||||
border: $b-1 solid transparent;
|
||||
background-color: transparent;
|
||||
color: var(--menu-foreground-color-disabled);
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.code-lang-option {
|
||||
@include deprecated.uppercase-title-typography;
|
||||
@include use-typography("headline-small");
|
||||
|
||||
width: deprecated.$s-72;
|
||||
height: deprecated.$s-32;
|
||||
padding: deprecated.$s-8;
|
||||
color: var(--menu-foreground-color-disabled);
|
||||
inline-size: px2rem(72);
|
||||
block-size: $sz-32;
|
||||
padding: var(--sp-s);
|
||||
color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.code-row-display {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
min-block-size: 0;
|
||||
overflow: hidden;
|
||||
padding-bottom: deprecated.$s-8;
|
||||
padding-block-end: var(--sp-s);
|
||||
}
|
||||
|
||||
// A disclosure toggle in a 12px column, not a DS button.
|
||||
.toggle-btn {
|
||||
@include deprecated.button-style;
|
||||
--toggle-btn-foreground-color: var(--color-foreground-secondary);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
color: var(--title-foreground-color);
|
||||
stroke: var(--title-foreground-color);
|
||||
|
||||
.collapsabled-icon {
|
||||
@include deprecated.flex-center;
|
||||
|
||||
height: deprecated.$s-24;
|
||||
border-radius: deprecated.$br-8;
|
||||
|
||||
svg {
|
||||
@extend %button-icon-small;
|
||||
|
||||
transform: rotate(90deg);
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
|
||||
&.rotated svg {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: var(--toggle-btn-foreground-color);
|
||||
|
||||
&: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);
|
||||
}
|
||||
|
||||
.collapsabled-icon svg {
|
||||
stroke: var(--title-foreground-color-hover);
|
||||
}
|
||||
--toggle-btn-foreground-color: var(--color-foreground-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.collapsabled-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@ -2281,6 +2281,10 @@ msgstr "Variant properties"
|
||||
msgid "inspect.attributes.variants"
|
||||
msgstr "Variants properties"
|
||||
|
||||
#: src/app/main/ui/inspect/code.cljs:315, src/app/main/ui/inspect/code.cljs:358
|
||||
msgid "inspect.code.expand-panel"
|
||||
msgstr "Expand panel"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:169
|
||||
msgid "inspect.color-space-label"
|
||||
msgstr "Select color space"
|
||||
|
||||
@ -2317,6 +2317,10 @@ msgstr "Propiedades de la variante"
|
||||
msgid "inspect.attributes.variants"
|
||||
msgstr "Propiedades de las variantes"
|
||||
|
||||
#: src/app/main/ui/inspect/code.cljs:315, src/app/main/ui/inspect/code.cljs:358
|
||||
msgid "inspect.code.expand-panel"
|
||||
msgstr "Expandir panel"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:169
|
||||
msgid "inspect.color-space-label"
|
||||
msgstr "Seleccionar espacio de color"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user