♻️ Use DS icons in the dashboard templates section (#12535)

The arrow and add icons of the dashboard libraries and templates
section use the DS icons and get their color from the color property.
The collapse button says whether the section is expanded, and the left
scroll button, which had no name, is now named "Previous".

The scroll buttons stay raw: they are round 36px buttons with no DS
equivalent. The template cards are anchors without href; they go to the
anchors backlog. A new fixture lists eight builtin templates, and a
visual test covers the cards, a card hover, the scroll buttons and the
collapsed title. No visual change.

AI-assisted-by: claude-opus-5-5
This commit is contained in:
Eva Marco 2026-10-28 09:21:00 +01:00 committed by GitHub
parent c05b2e2ead
commit 08228324db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 95 additions and 21 deletions

View File

@ -0,0 +1,34 @@
[
{
"~:id": "tokens-starter-kit",
"~:name": "Design tokens starter kit"
},
{
"~:id": "penpot-design-system",
"~:name": "Penpot Design System | Pencil"
},
{
"~:id": "wireframing-kit",
"~:name": "Wireframe library"
},
{
"~:id": "prototype-examples",
"~:name": "Prototype template"
},
{
"~:id": "plants-app",
"~:name": "UI mockup example"
},
{
"~:id": "tutorial-for-beginners",
"~:name": "Tutorial for beginners"
},
{
"~:id": "lucide-icons",
"~:name": "Lucide Icons"
},
{
"~:id": "font-awesome",
"~:name": "Font Awesome"
}
]

View File

@ -629,3 +629,46 @@ test.describe("Onboarding questions controls", () => {
await expect(actions).toHaveScreenshot(shot);
});
});
test.describe("Templates section controls", () => {
const shot = { maxDiffPixelRatio: 0, threshold: 0 };
test("Template cards, scroll buttons and collapse", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.mockRPC(
"get-builtin-templates",
"dashboard/get-builtin-templates.json",
);
await dashboardPage.goToDashboard();
const section = page.locator("[class*='dashboard-templates-section']");
const card = section.locator("[class*='template-card']").first();
await expect(card).toBeVisible();
await expect(section.locator("img").first()).toHaveJSProperty(
"complete",
true,
);
await page.mouse.move(640, 100);
await expect(section).toHaveScreenshot(shot);
// Hovering a card shows its add icon in the accent color.
await card.hover();
await expect(card).toHaveScreenshot(shot);
const moveButtons = section.locator("[class*='move-button']");
await moveButtons.last().hover();
await expect(moveButtons.last()).toHaveScreenshot(shot);
await moveButtons.last().click();
await expect(moveButtons).toHaveCount(2);
await page.mouse.move(640, 100);
await expect(moveButtons.first()).toHaveScreenshot(shot);
await section.locator("[class*='title-btn']").click();
await expect(section).toHaveClass(/collapsed/);
await page.waitForTimeout(500);
await expect(section.locator("[class*='title-btn']")).toHaveScreenshot(
shot,
);
});
});

View File

@ -16,7 +16,7 @@
[app.main.data.modal :as modal]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.icons :as deprecated-icon]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.util.dom :as dom]
[app.util.dom.normalize-wheel :as nw]
[app.util.i18n :refer [tr]]
@ -25,12 +25,6 @@
[okulary.core :as l]
[rumext.v2 :as mf]))
(def ^:private arrow-icon
(deprecated-icon/icon-xref :arrow (stl/css :arrow-icon)))
(def ^:private download-icon
(deprecated-icon/icon-xref :add (stl/css :download-icon)))
(def builtin-templates
(l/derived :builtin-templates st/state))
@ -77,6 +71,7 @@
[:div {:class (stl/css :title)}
[:button {:tab-index "0"
:class (stl/css :title-btn)
:aria-expanded (not is-collapsed)
:on-click on-click
:on-key-down on-key-down}
[:span {:class (stl/css :title-text)}
@ -85,11 +80,13 @@
[:span {:class (stl/css :title-icon-container)}
[:span {:class (stl/css :title-icon-text)} (tr "labels.show")]
[:span {:class (stl/css :title-icon :title-icon-collapsed)}
arrow-icon]]
[:> icon* {:icon-id i/arrow
:class (stl/css :arrow-icon)}]]]
[:span {:class (stl/css :title-icon-container)}
[:span {:class (stl/css :title-icon-text)} (tr "labels.hide")]
[:span {:class (stl/css :title-icon)}
arrow-icon]])]]))
[:> icon* {:icon-id i/arrow
:class (stl/css :arrow-icon)}]]])]]))
(mf/defc card-item*
[{:keys [item index is-visible collapsed on-import]}]
@ -131,7 +128,8 @@
(if @hover?
(tr "dashboard.template.add-to-project")
(:name item))]
download-icon]]]))
[:> icon* {:icon-id i/add
:class (stl/css :download-icon)}]]]]))
(mf/defc card-item-link*
[{:keys [total is-visible collapsed section]}]
@ -286,8 +284,10 @@
[:button {:class (stl/css :move-button :move-left)
:tab-index (if ^boolean collapsed "-1" "0")
:on-click on-move-left
:on-key-down on-move-left}
arrow-icon])
:on-key-down on-move-left
:aria-label (tr "labels.previous")}
[:> icon* {:icon-id i/arrow
:class (stl/css :arrow-icon)}]])
(when (:right @can-move)
[:button {:class (stl/css :move-button :move-right)
@ -295,4 +295,5 @@
:on-click on-move-right
:on-key-down on-move-right
:aria-label (tr "labels.next")}
arrow-icon])]))
[:> icon* {:icon-id i/arrow
:class (stl/css :arrow-icon)}]])]))

View File

@ -105,10 +105,8 @@
align-items: center;
height: $sz-16;
width: $sz-16;
color: transparent;
fill: none;
stroke-width: $b-1;
stroke: var(--color-foreground-secondary);
color: var(--color-foreground-secondary);
}
.move-button {
@ -131,7 +129,7 @@
background-color: var(--color-accent-primary);
.arrow-icon {
stroke: var(--color-background-tertiary);
color: var(--color-background-tertiary);
}
}
}
@ -196,7 +194,7 @@
border-color: var(--color-accent-primary);
.download-icon {
stroke: var(--color-accent-primary);
color: var(--color-accent-primary);
}
.card-text {
@ -243,10 +241,8 @@
align-items: center;
height: $sz-16;
width: $sz-16;
color: transparent;
fill: none;
stroke-width: $b-1;
stroke: var(--icon-foreground);
color: var(--color-foreground-secondary);
}
.template-link {