* ♻️ Use DS buttons and icons in the dashboard fonts page
The fonts page moves off the deprecated icons and raw buttons:
- "Add custom font", "Upload all", "Upload" and "Save" become DS primary
buttons and "Dismiss all" a secondary one.
- The remove, cancel and menu controls of the font rows become ghost DS
icon buttons named "Remove", "Cancel" and "Options"; the menu one
says whether its menu is open. Two of them were spans.
- The delete control of a font style was a span; it is now a button
named "Delete font style" with the DS close icon, still shown only
on hover.
- The warning and empty list icons use the DS icons. The loading
placeholder keeps the legacy loader: there is no DS one.
The font menu offset grows by the 6px the taller menu button added, so
the menu opens where it did. New key: dashboard.fonts.delete-variant
(en, es). A visual test covers a font ready to upload, the style hover,
the font menu and the edition row.
AI-assisted-by: claude-opus-5-5
* ♻️ Move dashboard fonts styles to logical properties
Physical sizes, offsets, margins and paddings become logical properties
and the DS typography module is used without a namespace. The element
selectors (section title, inputs, hero text) stay, with a comment: they
have no class.
The shared dashboard header styles (common-dashboard) still come from
refactor/: ten dashboard modules use them, so they move in their own
change. No visual change.
AI-assisted-by: claude-opus-5-5
* ♻️ Use the DS loader and heading in the dashboard fonts page
The fonts loading placeholder used the legacy loader icon, drawn as an
outline in a 32px box. It now uses the DS loader*, the same animated
pencil as the other dashboard loading screens. Its box is 9px tall,
so the label moves 6px up.
The section title h3 is now a heading* with the title-small typography
and its own class, so the SCSS no longer styles the bare element.
The legacy loader icon has no other use, so its SVG and def are gone.
AI-assisted-by: claude-opus-5-5
* ♻️ Give the dashboard fonts inputs and hero text classes
The font name and search inputs and the hero text get their own
classes instead of bare input and p selectors, and the hero title uses
the DS heading with title-large instead of the global h2 rule. The
title keeps its 24px size and weight; the DS line height (1.4 instead
of 1.15) moves the hero content about 6px down.
AI-assisted-by: claude-opus-5-5
* 🐛 Give the fonts placeholder icon its color back
Removing the legacy loader also removed the .icon svg rule, which gave
the empty placeholder text icon its color, so the icon had none. The
icon now has its own class with the secondary foreground color, and the
wrapper div without styles goes.
AI-assisted-by: claude-opus-5-5
* ✨ Add the share, handlers and snap icons to the DS
The share button and the path editing bar could not move to the DS
buttons because their icons were missing from the DS icon set. As agreed
with design:
- handlers-equal, handlers-independent, handlers-mirror and snap join the
DS as they are (their SVGs already follow the DS format).
- share keeps its drawing, moved onto the 16x16 grid as a single path
with no fixed color.
- snap-nodes is deleted: nothing used it, and snap is the icon of the
snap nodes button.
The legacy share button in the workspace header uses the same SVG: its
icon is about 6% smaller and now takes the hover color, which the fixed
stroke color blocked before.
AI-assisted-by: claude-opus-5-5
* 🐛 Show the share icon lines outside the app
The share SVG had no fill or stroke, so plain SVG viewers used the
defaults (black fill, no stroke) and drew only three dots. Set
fill="none" and stroke="currentColor", like settings.svg. The app
already sets both in CSS, so nothing changes there.
AI-assisted-by: claude-opus-5-5
* 🐛 Show the handlers and snap icons right outside the app
Like share, these SVGs had no fill or stroke, so plain SVG viewers
filled the shapes black and drew no lines. Set fill="none" and
stroke="currentColor". The app sets both in CSS, so nothing changes
there.
AI-assisted-by: claude-opus-5-5
* ✨ Add new slides content for 2.19 release
* 🎉 Update user settings instructions in v2_19.cljs
Signed-off-by: Juan de la Cruz <delacruzgarciajuan@gmail.com>
---------
Signed-off-by: Juan de la Cruz <delacruzgarciajuan@gmail.com>
* ✨ Add new slides content for 2.18 release
* ♻️ Use buttons from DS
* ♻️ Use new SCSS guidelines
* ♻️ Use a base stylesheet for all version files
* ♻️ Use new SCSS guidelines
* ✨ Add new images and wording
---------
Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
* ✨ Improve path operations and edition
* 🐛 Fix floating-point equality issues in path editing
Replace exact equality checks with tolerance-based comparisons
in path editing functions to handle floating-point rounding
differences after transforms, rotations, or curve fitting.
Changes:
- distribute-content: Round coordinates to 0.1 precision before
grouping to ensure coincident nodes move together
- separate-node: Use gpt/close? instead of exact equality to
find nodes with floating-point imprecision
- collision-step: Use mth/close? for tolerance-based comparison
to detect paste collisions correctly
- resolve-edit-fills: Add cycle detection to prevent infinite
loops with corrupted parent chains
Made collision-step, available-offset-step, and resolve-edit-fills
public for better testability.
Added comprehensive tests for all fixes covering both exact and
floating-point coordinate scenarios.
AI-assisted-by: qwen3.7-plus
* 🐛 Fix path editor code review findings
Fix issues identified during code review of path editor enhancements:
- Fix unused binding lint warning in distribute-content that blocked CI
- Fix collision-step floor comparison to use round instead of floor,
correctly detecting collisions when coordinates drift slightly below
integer boundaries
- Fix resolve-edit-fills to recurse through empty parent groups when
searching for inherited fills in nested group hierarchies
- Fix expand-coincident-node-indices to use fuzzy comparison (gpt/close?)
instead of exact equality, handling floating-point divergence after
transforms or rotations
- Remove unreachable dead code in path-point* on-pointer-down handler
- Add tests for collision-step boundary cases, nested group fill
inheritance, and coincident node alignment/flipping
AI-assisted-by: mimo-v2.5-pro
---------
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add headless wasm render backend to the exporter
* ♻️ Move render-wasm bridge to common and split wasm builds
* 🔧 Upload builtin font variants in the wasm exporter
* ♻️ Move shared font and resources utils out of render_wasm
* ⚡ Fetch only the exported roots in the wasm exporter
* ⚡ Bound save_layer rects in the vector export path
* 🐛 Fix main menu is covered by the toolbar
* ♻️ Refactor SCSS
* 🐛 Fix adjust z-index of workspace context menu
* ♻️ Refactor SCSS
* 🐛 Fix adjust z-index of tokens context menu
* ♻️ Refactor SCSS
* 🐛 Fix adjust z-index of old context menu
* 📎 PR improvements
* 🎉 Install react-aria-components
* 🎉 Create modal component in TS using react-aria-component
* 🎉 Create modal ds component
* 🎉 Separate header content and footer components
* 🐛 Remove mf/html macros when not needed
* 🎉 Solve little problems
* ♻️ Format files
* ♻️ Remove ModalCloseBtn
* 🐛 Fix CI
* ♻️ Remove unused files
* 🎉 Make close button not dependant on the modal header
* 🎉 Add footer with two slots
* 🎉 Improvements on modal
* 🐛 Fix package imports and remove login example code
---------
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ♻️ Modify social media icons in verification email
* ♻️ Update verify email
* ♻️ Update copies in 'check your email'
* ♻️ Update onboarding images
* ♻️ Refurbish create team slide
* ♻️ Refactor SCSS for in-app onboarding
* 🐛 Fix replace old uxbox with penpot image for all email HTMLs
* 🐛 Fix use of link component
Rename the icon file and fix the icon ID from "elipse" (single "l")
to "ellipse" (double "l") across the codebase.
The root cause was a mismatch: the icon file/ID was named "elipse"
but get-shape-icon returns "ellipse" for circle shapes. Since the
icon* component validates icon-id against the auto-generated
icon-list set, the string "ellipse" failed validation.
Changes:
- Rename frontend/resources/images/icons/elipse.svg to ellipse.svg
- Fix icon def in icon.cljs: ^:icon-id elipse -> ^:icon-id ellipse
- Fix deprecated icon in icons.cljs: ^:icon elipse -> ^:icon ellipse
- Fix usage in top_toolbar.cljs: deprecated-icon/elipse -> ellipse
- Fix usage in history.cljs: deprecated-icon/elipse -> ellipse
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Fixes#9135.
The <link href="css/ui.css"> tag in
frontend/resources/templates/index.mustache references a CSS file that
the build pipeline never produces:
- compileStyles() in frontend/scripts/_helpers.js only writes main.css
(always) and debug.css (dev-only) — there is no write to ui.css
- compileStorybookStyles() writes ds.css (design system), not ui.css
- No ui.scss source exists anywhere in frontend/resources/styles/
The reference was added in 45d04942c ("✨ Add example ui
storybook") but no corresponding build step was added to emit the file.
Result: every page load issues a request for /css/ui.css that nginx
returns as 404. In self-hosted Penpot deployments behind a reverse
proxy, the SPA's CSS init promise rejects on the 404, the React root
never mounts, and the user sees a black screen.
This patch removes the dead reference. If a future change actually
emits ui.css (or another distinct UI bundle), the <link> can be
re-added at that time.
Co-authored-by: Admin <admin@Admins-MacBook-Pro.local>
* 🐛 Remove cursor CSS for all inputs
- Restore the default cursor for the dashboard inputs.
- Make the numeric-input component from DS to work as expected.
* 🐛 Fix remove drag-to-change behaviour from old numeric-input
- Remove penpotWorkerURI from index.mustache and rasterizer.mustache templates
- Remove worker_main entry from the build manifest
- Construct worker URI in config.cljs by joining public-uri with worker path
- Fix global variable casing for plugins-list-uri and templates-uri
- Fix alignment in worker.cljs let bindings