* ✨ Add read-only preview mode for saved versions (#7622)
* 🔧 Address review feedback on version preview (#7622)
* 🐛 Fix version preview for WASM renderer (#7622)
* 🐛 Fix stylelint color-named and color-function-notation in preview banner (#7622)
* 🐛 Fix invalid-arity call to initialize-workspace in exit-preview (#7622)
* 🐛 Fix unclosed defn paren in exit-preview (#7622)
* ♻️ Refactor version preview/restore flow
Separate enter-preview and enter-restore flows with dedicated dialogs
instead of a persistent banner. Removes preview-banner component in favor
of inline actions dialog. Uses backup/restore pattern for exit-preview
instead of full workspace reinitialization. Adds analytics events for
preview/restore actions.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ⚡ Extract on-name-input-focus as namespace-level private function
The callback had no dependencies on component-local state or props,
making it a pure function that can be hoisted to a defn-. This avoids
recreating the same callback identity on every render of version-entry*.
* ⚡ Extract extract-id-from-event helper to deduplicate snapshot callbacks
Three callbacks in snapshot-entry* shared the same DOM extraction logic
(get current target, read data-id, parse UUID). Extracted into a private
defn- to remove the duplication and simplify each callback.
* ⚡ Extract pure state-update callbacks from versions-toolbox* to namespace level
Eight callbacks that only emit fixed Potok events with no meaningful
deps were hoisted out of the component as defn- functions:
- on-create-version
- on-edit-version
- on-cancel-version-edition
- on-rename-version
- on-delete-version
- on-pin-version
- on-lock-version
- on-unlock-version
These no longer need mf/use-fn wrappers since namespace-level functions
have stable identity across renders, avoiding unnecessary callback
recreation on each render cycle.
* ✨ Rename filter parameter to filter-value in on-change-filter to avoid core shadowing
The parameter name 'filter' shadowed clojure.core/filter within the
function scope. Renamed to 'filter-value' for clarity and to prevent
potential bugs if core/filter were needed in future changes.
* 🔧 Fix linter warnings and errors across version-related namespaces
frontend/src/app/main/ui/workspace.cljs:
- Remove unused requires: app.common.data, app.main.data.notifications,
app.main.data.workspace.versions
frontend/src/app/main/data/workspace/versions.cljs:
- Remove unused require: app.common.uuid
- Fix duplicate reify type: enter-restore used ::restore-version
(same as the private restore-version fn), renamed to ::enter-restore
- Remove unused bindings: state in enter-restore, team-id in
exit-preview and restore-version-from-plugin
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Signed-off-by: wdeveloper16 <wdeveloer16@protonmail.com>
Co-authored-by: wdeveloper16 <wdeveloer16@protonmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add loader feedback while importing and exporting files
Show a loader icon with a status label ("Importing files…" /
"Exporting files…") in the import and export dialog footers while the
operation is running, so users get clear in-progress feedback and
cannot retrigger the action by mistake.
Closes#9020
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
* ✨ Address import/export loader feedback PR review
- Show the loader beside file names in the import dialog while files
are being imported (previously queued entries kept showing the
Penpot logo until each one moved into :import-progress).
- Drop the loader from the "Importing files…" / "Exporting files…"
footer status, leaving just the text styled with the modal title
color, per the design proposal.
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
* ✨ Match design proposal for import/export progress feedback
- Move the in-progress label from the modal footer into the modal
body, under the file rows, styled italic with the modal title
color.
- Rename the labels to match the design wording: "Uploading file…"
for import and "Downloading file…" for export.
- Restore the disabled "Accept" button in the import footer during
the import-progress phase, mirroring the disabled "Close" button
used by export.
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
* 🐛 Rename deprecated bodySmallTypography mixin to body-small-typography
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
---------
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
Fixes#9067. Adds a delete button that appears on hover over an
uploaded profile photo; clicking it opens a confirm modal and, on
accept, clears the stored photo so the generated fallback avatar is
shown again. A new :delete-profile-photo RPC schedules the old
storage object for garbage collection and sets photo-id to null.
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* 🐛 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>
* ✨ 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>
* ✨ 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>
* 🔧 Create flag
* ✨ Add typography type on tokens by input
* 🎉 Add typography token row
* ♻️ Update sub-components to use new style
* 🎉 Add disabled option on radio-buttons* component
* 🎉 Add combobox search in a new component
* 🎉 Divide components
* 🐛 Fix placeholder
When the browser denies clipboard read permission (NotAllowedError),
the unhandled exception handler was showing a generic 'Something wrong
has happened' toast. This change adds proper error handling for
clipboard permission errors in paste operations and shows a
user-friendly warning message instead.
Changes:
- Add error handling in paste-from-clipboard for NotAllowedError
- Improve error handling in paste-selected-props to detect permission errors
- Mark clipboard NotAllowedError as ignorable in the uncaught error handler
to prevent duplicate generic error toasts
- Add translation key for clipboard permission denied message
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add copy and paste for grid layout rows and columns via context menu
* 🔧 Use grid-id instead of grid in context menu deps
---------
Co-authored-by: bittoby <bittoby@users.noreply.github.com>
* ✨ Make the MCP plugin switching between tabs work correctly
* 🎉 Show notification when the plugin is loaded in another tab
* 📎 PR changes
* ✨ Add events