12887 Commits

Author SHA1 Message Date
rockchris099
8cc05d9579
Show alpha percentage in asset library color names (#8975)
When several library colors share the same RGB value but differ only
in opacity, append the alpha percentage (e.g. "#ff0000 50%") next to
the displayed default name and in the color bullet tooltip so users
can tell them apart at a glance.

Closes #6328

Signed-off-by: rockchris99 <chrisleo0721@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-14 21:02:42 +02:00
Andrey Antukh
f07b954b7e
Add efficiency improvements to workspace components (refactor part 1) (#8887)
* ♻️ Convert snap-points components to modern rumext format

Migrate snap-point, snap-line, snap-feedback, and snap-points from
legacy mf/defc format to modern * suffix format. This enables
optimized props handling by the rumext macro, eliminating implicit
JS object wrapping overhead on each render. All internal and
external call sites updated to use [:> component* props] syntax.

* ♻️ Convert frame-title to modern rumext format

Migrate frame-title from legacy mf/defc format to modern * suffix
format. The component was using legacy implicit props wrapping without
::mf/wrap-props false or ::mf/props :obj, causing unnecessary JS
object conversion overhead on each render. The parent frame-titles*
call site updated to use [:> frame-title* props] syntax.

* ♻️ Convert interactions components to modern rumext format

Migrate interaction-marker, interaction-path, interaction-handle,
overlay-marker, and interactions from legacy mf/defc format to modern
* suffix format. These five components had zero props optimization
applied, causing implicit JS object wrapping on every render. All
internal and external call sites updated to use [:> component* props]
syntax.

* ♻️ Convert rulers components to modern rumext format

Migrate rulers-text, viewport-frame, and selection-area from legacy
mf/defc format to modern * suffix format. These three components in
the always-visible rulers layer had zero props optimization applied.
Internal call sites in the parent rulers component updated to use
[:> component* props] syntax.

* ♻️ Convert frame-grid components to modern rumext format

Migrate square-grid, layout-grid, grid-display-frame, and frame-grid
from legacy mf/defc format to modern * suffix format. These four
components render grid patterns per-frame with zero props optimization.
All internal and external call sites updated to use [:> component* props]
syntax.

* ♻️ Convert gradient handler components to modern rumext format

Migrate shadow, gradient-color-handler, and gradient-handler-transformed
from legacy mf/defc format to modern * suffix format. These components
are rendered during gradient editing with zero props optimization applied.
Internal call sites in gradient-handler-transformed and
gradient-handlers-impl updated to use [:> component* props] syntax.

* ♻️ Rename ?-ending props in modernized workspace viewport components

Apply prop naming rules to all * components migrated in the previous batch:
- remove-snap? -> remove-snap in snap-feedback* (and get-snap helper)
- selected? -> is-selected in interaction-path*
- hover-disabled? -> is-hover-disabled in overlay-marker* and interactions*
- show-rulers? -> show-rulers in viewport-frame*

Update all internal and external call sites consistently.

* 🐛 Fix get-snap call in snap-feedback* using JS props object

Modern rumext *-suffix components receive props as JS objects, not
Clojure maps. snap-feedback* was pushing the raw props object into the
rx/subject and get-snap was destructuring it as a Clojure map, causing
all keys to resolve to nil.

Fix by:
- Changing get-snap to take positional arguments (coord, shapes,
  page-id, remove-snap, zoom) instead of a map-destructured opts arg
- Building an explicit Clojure map from the bound locals before pushing
  to the subject
- Destructuring that map inside the rx/switch-map callback and calling
  get-snap with positional args

Also mark get-snap and add-point-to-snaps as private (defn-), consistent
with the other helpers in the namespace — none are referenced externally.
2026-04-14 19:48:59 +02:00
Andrey Antukh
6c90ba1582 🐛 Fix move-files allowing same project as target when multiple files selected
The 'Move to' menu in the dashboard file context menu only filtered
out the first selected file's project from the available target list.
When multiple files from different projects were selected, the other
files' projects still appeared as valid targets, causing a 400
'cant-move-to-same-project' backend error.

Now all selected files' project IDs are collected and excluded from
the available target projects.
2026-04-14 15:19:19 +02:00
Andrey Antukh
18f0ad246f 🐛 Fix parse-long crash when index query param is duplicated in URL
lambdaisland/uri's query-string->map uses :multikeys :duplicates by
default: a key that appears once yields a plain string, but the same
key repeated yields a vector. cljs.core/parse-long only accepts
strings and therefore threw "Expected string, got: object" whenever
a URL contained a duplicate 'index' parameter.

Add rt/get-query-param to app.main.router. The helper returns the
scalar value of a query param key, taking the last element when the
value is a sequential (i.e. the key was repeated). Use it at every
call site that feeds a query-param value into parse-long, in both
app.main.ui (page*) and app.main.data.viewer.
2026-04-14 15:16:04 +02:00
alonso.torres
dc5f222230 🐛 Improve change token set performance 2026-04-14 14:51:12 +02:00
rockchris099
207cb87d5e
Reorder prototype overlay options (position before relative to) (#8972)
Closes #2910

Signed-off-by: rockchris99 <chrisleo0721@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-14 13:56:26 +02:00
Clayton
39b0e011fc
Differentiate incoming and outgoing interaction link colors (#8923)
*  Color incoming and outgoing interaction links differently

* 🐛 Fix lint

---------

Signed-off-by: Clayton <claytonlin1110@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-14 13:30:22 +02:00
Dexterity
7c3a1a905e
Fix locked elements not selectable in viewer + add guide locking (#8949)
* 🐛 Allow viewers to select locked elements in canvas

*  Add ability to lock guides to prevent accidental movement

---------

Signed-off-by: Dexterity104 <hatanokanjiro@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-14 13:21:51 +02:00
Eva Marco
3469e867ff
🐛 Fix gap input throwing an error (#8984) 2026-04-14 13:02:03 +02:00
Andrey Antukh
62f3454607 🔧 Backport ci configuration changes from develop 2026-04-14 12:34:04 +02:00
Andrey Antukh
3264bc746f 🔧 Backport ci configuration changes from develop 2026-04-14 12:33:10 +02:00
Dream
68595e90eb
Persist asset search query when switching sidebar tabs (#8985)
When users switch between the Layers and Assets sidebar tabs, the
`assets-toolbox*` component unmounts and its local `use-state` is
discarded, so the search query and section filter are lost.

Lift the search term and section filter into a per-file, in-memory
session atom that survives tab switches but doesn't leak across files
or persist across reloads. Ordering and list-style continue to use
localStorage as before.

Closes #2913

Signed-off-by: eureka0928 <meobius123@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-14 12:31:25 +02:00
Andrey Antukh
6788df02ca 🔧 Add minor adjustments on ci workflow related to e2e tests 2026-04-14 11:49:16 +02:00
Dream
8b14de2610
Sort asset subfolders alphabetically (#8952)
Subgroups in asset libraries were rendered in hash-map order because
update-in descends into plain maps instead of sorted ones. Add a
recursive post-process that rebuilds every level as a sorted-map so
subfolders are alphabetical at every nesting depth.

Closes #2572

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-14 10:50:46 +02:00
Andrey Antukh
c39609b991
♻️ Use shared singleton containers for React portals (#8957)
Refactor use-portal-container to allocate one persistent <div> per
logical category (:modal, :popup, :tooltip, :default) instead of
creating a new div for every component instance. This keeps the DOM
clean with at most four fixed portal containers and eliminates the
arbitrary growth of empty <div> elements on document.body while
preserving the removeChild race condition fix.
2026-04-14 10:48:30 +02:00
Statxc
d90e7f8164
Add Find & Replace for text content and layer names (#8899)
*  Add Find & Replace for text content and layer names

* 💄 Fix cross-browser styling for Find & Replace radio buttons and action buttons

* 💄 Fix stylelint empty line before declaration in layers.scss

*  Improve match-filters and match-ids efficiency

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-14 10:41:31 +02:00
Dream
19b9c696fc
🐛 Reset account submenu state when profile menu closes (#8953)
Closes #8947

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-14 10:33:32 +02:00
Dream
4703fe6e3b
Add visibility toggle for strokes (#8913)
*  Add visibility toggle for strokes

* ♻️ Use single emit! call for stroke visibility toggle

* 💄 Disable stroke controls when hidden, matching shadow/blur pattern

When a stroke is hidden, the alignment/style selects, cap selects, and
cap switch button are now disabled. A .hidden CSS class dims the
options area with reduced opacity. This matches the existing behavior
in shadow_row and blur menu where controls are disabled when the
effect is hidden.

* 💄 Move stroke hide button before remove button

---------

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-14 10:08:13 +02:00
Andrey Antukh
9106a994f1 Merge remote-tracking branch 'origin/staging' into develop 2026-04-13 18:31:50 +02:00
Andrey Antukh
bc47b992eb Merge remote-tracking branch 'origin/main' into staging 2026-04-13 18:31:32 +02:00
Eva Marco
a3f7a1def6
🐛 Fix bugs with multiselection (#8932)
* 🐛 Fix app crash when selecting shapes with one hidden

* 🐛 Fix opacity input when mixed values
2026-04-13 18:29:15 +02:00
Alejandro Alonso
2ccaa3f0c5 Merge remote-tracking branch 'origin/staging' into develop 2026-04-13 16:51:51 +02:00
Alejandro Alonso
dfc5a256b4 Merge remote-tracking branch 'origin/staging' into develop 2026-04-13 16:47:18 +02:00
Elena Torro
6b3d5d930f 🔧 Improve zoom and pan performance 2026-04-13 16:35:36 +02:00
Marina López
a52831aa8c Show professional card when has nitrate subscription 2026-04-13 16:07:51 +02:00
rockchris099
bbd200f869
🐛 Fix dashboard Recent/Deleted titles overlapped by scrolling content (#8945)
Add z-index to the sticky .nav element in the dashboard so that
section titles (Recent, Deleted) stay above scrolling content
instead of being obscured by project cards and file thumbnails.

Fixes #8577
Signed-off-by: rockchris99 <chrisleo0721@gmail.com>
2026-04-13 15:55:13 +02:00
Juanfran
87179e806f
Add subscribe-nitrate route with post-registration nitrate modal (#8941) 2026-04-13 15:49:22 +02:00
Elena Torro
d85d63ef3c 🔧 Improve page loading 2026-04-13 14:42:03 +02:00
Aitor Moreno
83e9f85ccf
Merge pull request #8943 from penpot/ladybenko-13949-fix-resize-call
🐛 Fix initializing guards in viewport loading
2026-04-13 13:37:25 +02:00
Pablo Alba
d91ce0f9d1 🐛 Fix nitrate go to control center 2026-04-13 12:30:49 +02:00
Aitor Moreno
9c44f5bf65 🐛 Fix text editor v1 focus not being handled correctly (#8942) 2026-04-13 12:08:06 +02:00
Eva Marco
443fb60743 🐛 Fix highlight on frames after rename (#8938) 2026-04-13 12:04:04 +02:00
Luis de Dios
cbe9d31599 🐛 Fix dashboard navigation tabs overlap with content when scrolling (#8937)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-13 12:01:10 +02:00
Luis de Dios
599a66979a
🐛 Fix dashboard navigation tabs overlap with content when scrolling (#8937)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-13 11:59:19 +02:00
Pablo Alba
5c761125f3 Add invite-to-org to Nitrate API 2026-04-13 11:49:01 +02:00
Andrey Antukh
a403175d5c
🐛 Fix TypeError in sd-token-uuid when resolving tokens interactively (#8929)
The backtrace-tokens-tree function used a namespaced keyword :temp/id
which clj->js converted to the JS property "temp/id". The sd-token-uuid
function then tried to access .id on the sd-token top-level object,
which was undefined, causing "Cannot read properties of undefined
(reading uuid)".

Fix by using the existing token :id instead of generating a temporary
one, and read it from sd-token.original (matching sd-token-name pattern).
2026-04-13 11:34:15 +02:00
Aitor Moreno
bb85b312d6
🐛 Fix text editor v1 focus not being handled correctly (#8942) 2026-04-13 10:00:56 +02:00
Dream
78a16d99a9
Add clear artboard guides option to context menu (#8936)
*  Add clear artboard guides option to context menu

Adds a "Clear artboard guides" option to the right-click context menu
when one or more frames with guides are selected. Closes #6987

* ♻️ Address review feedback from niwinz

- Replace deprecated dm/assert! with assert
- Replace (map :id) with d/xf:map-id

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-13 09:58:23 +02:00
Dream
8dccb2a427
Make links in comments clickable (#8894)
*  Make links in comments clickable

Detect URLs in comment text and render them as clickable links that
open in a new tab. Extends the existing mention parsing to also split
text elements by URL patterns, handling trailing punctuation and
mixed mention+URL content.

Closes #1602

* 📚 Add changelog entry for clickable links in comments

* 🐛 Fix URL elements dropped in comment input initialization

* 🐛 Keep empty text elements in parse-urls to preserve cursor anchors

The remove filter in parse-urls was stripping empty text elements
produced by str/split at URL boundaries. These elements are needed
as cursor anchor spans in the contenteditable input, without them
ESC keydown and visual layout broke.

Signed-off-by: eureka928 <meobius123@gmail.com>
2026-04-13 09:55:53 +02:00
Eva Marco
6d1a2d449a
🐛 Fix highlight on frames after rename (#8938) 2026-04-13 09:09:03 +02:00
Belén Albeza
eb811621a9 🐛 Fix initializing guards in viewport loading 2026-04-10 13:54:06 +02:00
Andrés Moya
3312bfe62c Force current set as active when resolving tokens in sidebar 2026-04-10 13:33:29 +02:00
Dexterity
240e8ce50c
🐛 Use page name for multi-export downloads (#8874)
* 🐛 Use page name for multi-export downloads

* ♻️ Refactor parameter formatting in asset export function

*  Use page name for multi-export ZIP/PDF downloads [Github #8773]

---------

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-10 11:21:14 +02:00
Xaviju
9e4c8981be
🎉 Duplicate token group (#8886) 2026-04-10 10:42:35 +02:00
Alejandro Alonso
5eebc17ce2 🎉 Support for debugging cache texture 2026-04-09 19:02:14 +02:00
Alejandro Alonso
434e27bbe8 🎉 Improve panning performance 2026-04-09 19:02:14 +02:00
Dexterity
e49b7ce14c
🐛 Fix warnings for unsupported token $type (#8873)
* 🐛 Fix warnings for unsupported token $type

Signed-off-by: Dexterity104 <hatanokanjiro@gmail.com>

* 🐛 Add changelog entry for Github #8790

---------

Signed-off-by: Dexterity104 <hatanokanjiro@gmail.com>
Signed-off-by: Dexterity <173429049+Dexterity104@users.noreply.github.com>
2026-04-09 17:09:19 +02:00
Alejandro Alonso
5c67cd0a4b 🐛 Avoid unnecesary text editor pointer movements 2026-04-09 16:18:58 +02:00
Eva Marco
5b78de3594
🐛 Fix selected colors with tokens (#8889) 2026-04-09 14:10:23 +02:00
Xaviju
666313c2c3
🐛 Close expanded tree when switching or creating sets (#8920) 2026-04-09 12:37:29 +02:00