mirror of
https://github.com/penpot/penpot.git
synced 2026-05-11 11:03:52 +00:00
Merge remote-tracking branch 'origin/main-staging'
This commit is contained in:
commit
1a212a2769
90
.opencode/skills/backport-commit/SKILL.md
Normal file
90
.opencode/skills/backport-commit/SKILL.md
Normal file
@ -0,0 +1,90 @@
|
||||
---
|
||||
name: backport-commit
|
||||
description: Port changes from a specific Git commit to the current branch by manually applying the diff, avoiding cherry-pick when it would introduce complex conflicts.
|
||||
---
|
||||
|
||||
# Backport Commit
|
||||
|
||||
Port changes from a specific Git commit to the current branch by manually
|
||||
applying the diff, avoiding `git cherry-pick` when it would introduce
|
||||
complex conflicts.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use this skill whenever the user asks to backport a commit, especially when:
|
||||
|
||||
- The commit touches multiple modules or files with significant divergence
|
||||
- `git cherry-pick` is explicitly ruled out ("do not use cherry-pick")
|
||||
- The target commit is old enough that conflicts are likely
|
||||
- The commit introduces both source changes AND new files (tests, etc.)
|
||||
- You need full control over how each hunk is applied
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Identify the target commit
|
||||
|
||||
```bash
|
||||
# Verify the commit exists and understand what it does
|
||||
git log --oneline -1 <commit-sha>
|
||||
|
||||
# Get the full diff (including new/deleted files)
|
||||
git show <commit-sha>
|
||||
|
||||
# Capture the original commit message for later reuse
|
||||
git log --format='%B' -1 <commit-sha>
|
||||
```
|
||||
|
||||
### 2. Identify affected modules
|
||||
|
||||
From the file paths in the diff, determine which Penpot modules are affected
|
||||
(frontend, backend, common, render-wasm, etc.) and read their `AGENTS.md`
|
||||
files **before** making any changes. If a module has no `AGENTS.md`, skip
|
||||
that step — verify with `ls <module>/AGENTS.md` first.
|
||||
|
||||
### 3. Read the current state of each affected file
|
||||
|
||||
For every file the diff touches, read the current version on disk to understand
|
||||
context and ensure correct placement before editing.
|
||||
|
||||
### 4. Apply changes manually (the core of this approach)
|
||||
|
||||
Process every hunk in the diff using the appropriate tool:
|
||||
|
||||
| Diff action | Tool to use |
|
||||
|-------------|-------------|
|
||||
| Modify existing file | `edit` — use enough surrounding context in `oldString` to uniquely match the location |
|
||||
| Add new file | `write` — include proper license header and namespace conventions matching project style |
|
||||
| Delete file | `bash rm <path>` |
|
||||
| Rename/move file | `bash mv <old> <new>`, then apply any content changes with `edit` |
|
||||
|
||||
> **Tip:** Group nearby hunks from the same file into a single `edit` call.
|
||||
> Use separate calls when hunks are far apart to keep `oldString` short and
|
||||
> unambiguous.
|
||||
|
||||
Repeat until **all** hunks in the diff are ported.
|
||||
|
||||
### 5. Validate
|
||||
|
||||
Run **lint**, **check-fmt**, and **tests** for every affected module (see each
|
||||
module's `AGENTS.md` for the exact commands). If the formatter auto-fixes
|
||||
indentation, verify the logic is still semantically correct. All checks must
|
||||
pass before moving on.
|
||||
|
||||
### 6. Port the changelog entry (if any)
|
||||
|
||||
If the original commit added or modified a `CHANGES.md` entry, port that entry
|
||||
too — adapting wording and version references for the target branch.
|
||||
|
||||
### 7. Commit
|
||||
|
||||
Ask the `commiter` sub-agent to create a commit. Stage all relevant files
|
||||
(exclude unrelated untracked files) and provide the original commit message as
|
||||
a reference, adapting it as needed for the target branch context.
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **Context matters** — always read files before editing; never guess
|
||||
indentation or surrounding code
|
||||
- **Lint + format + test** — never skip validation before committing
|
||||
- **Preserve intent** — keep the original commit message meaning; the
|
||||
`commiter` agent handles formatting
|
||||
@ -25,6 +25,7 @@
|
||||
- Fix layer hierarchy to match old and new SCSS [Github #9126](https://github.com/penpot/penpot/pull/9126)
|
||||
- Fix multiple selection on shapes with token applied to stroke color [Github #9110](https://github.com/penpot/penpot/pull/9110)
|
||||
- Fix onboarding modals appearing behind libraries and templates panel [Github #9178](https://github.com/penpot/penpot/pull/9178)
|
||||
- Fix release notes modal appearing behind the dashboard sidebar (by @RenzoMXD) [Github #8296](https://github.com/penpot/penpot/issues/8296)
|
||||
|
||||
## 2.14.5
|
||||
|
||||
@ -32,7 +33,6 @@
|
||||
|
||||
- Fix incorrect invitation token handling on register process [Github #9380](https://github.com/penpot/penpot/pull/9380)
|
||||
|
||||
|
||||
## 2.14.4
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
@ -287,7 +287,7 @@ RUN set -ex; \
|
||||
curl -LfsSo /tmp/gh.tar.gz ${BINARY_URL}; \
|
||||
mkdir /opt/gh; \
|
||||
cd /opt/gh; \
|
||||
tar -xf /tmp/gh.tar.gz; \
|
||||
tar -xv --strip-components=1 -f /tmp/gh.tar.gz; \
|
||||
rm -rf /tmp/gh.tar.gz;
|
||||
|
||||
# Install minio client
|
||||
|
||||
@ -96,12 +96,13 @@
|
||||
(update-in [:comments id] assoc (:id comment) comment))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (ptk/data-event ::ev/event
|
||||
{::ev/name "create-comment-thread"
|
||||
::ev/origin "workspace"
|
||||
:id id
|
||||
:content-size (count (:content comment))}))))))
|
||||
(watch [it _ _]
|
||||
(rx/of (ev/event
|
||||
(merge {::ev/name "create-comment-thread"
|
||||
::ev/origin "workspace"
|
||||
:id id
|
||||
:content-size (count (:content comment))}
|
||||
(meta it))))))))
|
||||
|
||||
(def ^:private
|
||||
schema:create-thread-on-workspace
|
||||
@ -119,7 +120,7 @@
|
||||
|
||||
(ptk/reify ::create-thread-on-workspace
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
frame-id (ctst/get-frame-id-by-position objects (:position params))
|
||||
@ -129,7 +130,10 @@
|
||||
(->> (rp/cmd! :create-comment-thread params)
|
||||
(rx/mapcat #(rp/cmd! :get-comment-thread {:file-id (:file-id %) :id (:id %)}))
|
||||
(rx/tap on-thread-created)
|
||||
(rx/map #(created-thread-on-workspace % open?))
|
||||
(rx/map
|
||||
(fn [data]
|
||||
(-> (created-thread-on-workspace data open?)
|
||||
(with-meta (meta it)))))
|
||||
(rx/catch (fn [{:keys [type code] :as cause}]
|
||||
(if (and (= type :restriction)
|
||||
(= code :max-quote-reached))
|
||||
@ -152,11 +156,11 @@
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (ptk/data-event ::ev/event
|
||||
{::ev/name "create-comment-thread"
|
||||
::ev/origin "viewer"
|
||||
:id id
|
||||
:content-size (count (:content comment))})))))
|
||||
(rx/of (ev/event
|
||||
{::ev/name "create-comment-thread"
|
||||
::ev/origin "viewer"
|
||||
:id id
|
||||
:content-size (count (:content comment))})))))
|
||||
|
||||
(def ^:private
|
||||
schema:create-thread-on-viewer
|
||||
@ -216,11 +220,13 @@
|
||||
(d/update-in-when state [:comment-threads id] assoc :is-resolved is-resolved))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(let [share-id (-> state :viewer-local :share-id)]
|
||||
(rx/concat
|
||||
(when is-resolved (rx/of
|
||||
(ptk/event ::ev/event {::ev/name "resolve-comment-thread" :thread-id id})))
|
||||
(when is-resolved
|
||||
(rx/of (ev/event
|
||||
(-> {::ev/name "resolve-comment-thread" :thread-id id}
|
||||
(merge (meta it))))))
|
||||
(->> (rp/cmd! :update-comment-thread {:id id :is-resolved is-resolved :share-id share-id})
|
||||
(rx/catch (fn [{:keys [type code] :as cause}]
|
||||
(if (and (= type :restriction)
|
||||
@ -309,16 +315,18 @@
|
||||
(update :comment-threads dissoc id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(watch [it _ _]
|
||||
(rx/concat
|
||||
(->> (rp/cmd! :delete-comment-thread {:id id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/tap on-delete)
|
||||
(rx/ignore))
|
||||
(rx/of (ptk/data-event ::ev/event
|
||||
{::ev/name "delete-comment-thread"
|
||||
::ev/origin "workspace"
|
||||
:id id})))))))
|
||||
(rx/of (ev/event
|
||||
(merge
|
||||
{::ev/name "delete-comment-thread"
|
||||
::ev/origin "workspace"
|
||||
:id id}
|
||||
(meta it)))))))))
|
||||
|
||||
(defn delete-comment-thread-on-viewer
|
||||
[{:keys [id] :as thread}]
|
||||
@ -341,10 +349,10 @@
|
||||
(->> (rp/cmd! :delete-comment-thread {:id id :share-id share-id})
|
||||
(rx/catch #(rx/throw {:type :comment-error}))
|
||||
(rx/ignore))
|
||||
(rx/of (ptk/data-event ::ev/event
|
||||
{::ev/name "delete-comment-thread"
|
||||
::ev/origin "viewer"
|
||||
:id id})))))))
|
||||
(rx/of (ev/event
|
||||
{::ev/name "delete-comment-thread"
|
||||
::ev/origin "viewer"
|
||||
:id id})))))))
|
||||
(defn delete-comment
|
||||
[{:keys [id thread-id] :as comment}]
|
||||
(dm/assert!
|
||||
|
||||
@ -479,7 +479,7 @@
|
||||
(->> (rp/cmd! :get-file-summary {:id id})
|
||||
(rx/map (fn [summary]
|
||||
(when (-> summary :variants :count pos?)
|
||||
(ptk/event ::ev/event {::ev/name "set-file-variants-shared" ::ev/origin "dashboard"})))))))))))
|
||||
(ev/event {::ev/name "set-file-variants-shared" ::ev/origin "dashboard"})))))))))))
|
||||
|
||||
(defn set-file-thumbnail
|
||||
[file-id thumbnail-id]
|
||||
|
||||
@ -267,8 +267,7 @@
|
||||
counts))
|
||||
{:png 0, :jpeg 0, :webp 0, :pdf 0, :svg 0}
|
||||
exports)]
|
||||
(ptk/event
|
||||
::ev/event (merge types
|
||||
{::ev/name "export-shapes"
|
||||
::ev/origin origin
|
||||
:num-shapes (count exports)}))))
|
||||
(ev/event (merge types
|
||||
{::ev/name "export-shapes"
|
||||
::ev/origin origin
|
||||
:num-shapes (count exports)}))))
|
||||
|
||||
@ -261,12 +261,12 @@
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/of (ptk/data-event ::ev/event {::ev/name "add-font"
|
||||
:team-id team-id
|
||||
:font-id (:id font)
|
||||
:font-family (:font-family font)
|
||||
:font-style (:font-style font)
|
||||
:font-weight (:font-weight font)}))))))
|
||||
(rx/of (ev/event {::ev/name "add-font"
|
||||
:team-id team-id
|
||||
:font-id (:id font)
|
||||
:font-family (:font-family font)
|
||||
:font-style (:font-style font)
|
||||
:font-weight (:font-weight font)}))))))
|
||||
|
||||
(defn update-font
|
||||
[{:keys [id name] :as params}]
|
||||
@ -310,9 +310,9 @@
|
||||
(rx/concat
|
||||
(->> (rp/cmd! :delete-font {:id font-id :team-id team-id})
|
||||
(rx/ignore))
|
||||
(rx/of (ptk/data-event ::ev/event {::ev/name "delete-font"
|
||||
:team-id team-id
|
||||
:font-id font-id})))))))
|
||||
(rx/of (ev/event {::ev/name "delete-font"
|
||||
:team-id team-id
|
||||
:font-id font-id})))))))
|
||||
|
||||
(defn delete-font-variant
|
||||
[id]
|
||||
@ -331,9 +331,9 @@
|
||||
(rx/concat
|
||||
(->> (rp/cmd! :delete-font-variant {:id id :team-id team-id})
|
||||
(rx/ignore))
|
||||
(rx/of (ptk/data-event ::ev/event {::ev/name "delete-font-variant"
|
||||
:id id
|
||||
:team-id team-id})))))))
|
||||
(rx/of (ev/event {::ev/name "delete-font-variant"
|
||||
:id id
|
||||
:team-id team-id})))))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@ -152,10 +152,10 @@
|
||||
|
||||
(when (not= (:theme profile)
|
||||
(:theme profile'))
|
||||
(rx/of (ptk/data-event ::ev/event
|
||||
{::ev/name "activate-theme"
|
||||
::ev/origin "settings"
|
||||
:theme (:theme profile)})))))))))
|
||||
(rx/of (ev/event
|
||||
{::ev/name "activate-theme"
|
||||
::ev/origin "settings"
|
||||
:theme (:theme profile)})))))))))
|
||||
|
||||
;; --- Toggle Theme
|
||||
|
||||
@ -186,9 +186,9 @@
|
||||
(watch [it state _]
|
||||
(let [profile (get state :profile)
|
||||
origin (::ev/origin (meta it))]
|
||||
(rx/of (ptk/data-event ::ev/event {:theme (:theme profile)
|
||||
::ev/name "activate-theme"
|
||||
::ev/origin origin})
|
||||
(rx/of (ev/event {:theme (:theme profile)
|
||||
::ev/name "activate-theme"
|
||||
::ev/origin origin})
|
||||
(persist-profile))))))
|
||||
|
||||
;; --- Request Email Change
|
||||
|
||||
@ -176,10 +176,10 @@
|
||||
(rx/of (dp/refresh-profile)
|
||||
(fetch-members team-id)
|
||||
(fetch-teams)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "delete-team-member"
|
||||
:team-id team-id
|
||||
:member-id member-id})))))))))
|
||||
(ev/event
|
||||
{::ev/name "delete-team-member"
|
||||
:team-id team-id
|
||||
:member-id member-id})))))))))
|
||||
|
||||
|
||||
(defn- stats-fetched
|
||||
@ -240,9 +240,9 @@
|
||||
(rx/tap on-success)
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (fetch-teams)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "update-team-photo"
|
||||
:team-id team-id}))))
|
||||
(ev/event
|
||||
{::ev/name "update-team-photo"
|
||||
:team-id team-id}))))
|
||||
(rx/catch on-error))))))
|
||||
|
||||
|
||||
@ -345,10 +345,10 @@
|
||||
(rx/merge
|
||||
(rx/of (team-leaved params)
|
||||
(fetch-teams)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "leave-team"
|
||||
:reassign-to reassign-to
|
||||
:team-id team-id}))
|
||||
(ev/event
|
||||
{::ev/name "leave-team"
|
||||
:reassign-to reassign-to
|
||||
:team-id team-id}))
|
||||
(on-success))))
|
||||
(rx/catch on-error))))))
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
(when (some? (:profile state))
|
||||
(fetch-comment-threads params))
|
||||
(when (:share-id params)
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "shared-prototipe-visited"})))))
|
||||
(rx/of (ev/event {::ev/name "shared-prototipe-visited"})))))
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
;; Set the window name, the window name is used on inter-tab
|
||||
|
||||
@ -1343,7 +1343,7 @@
|
||||
(rx/concat
|
||||
(rx/of (dch/commit-changes changes))
|
||||
(when (nil? annotation)
|
||||
(rx/of (ptk/data-event ::ev/event {::ev/name "delete-component-annotation"}))))))))
|
||||
(rx/of (ev/event {::ev/name "delete-component-annotation"}))))))))
|
||||
|
||||
(defn set-annotations-expanded
|
||||
[expanded]
|
||||
@ -1365,7 +1365,7 @@
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(when (some? id)
|
||||
(rx/of (ptk/data-event ::ev/event {::ev/name "create-component-annotation"}))))))
|
||||
(rx/of (ev/event {::ev/name "create-component-annotation"}))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Preview blend modes
|
||||
|
||||
@ -960,7 +960,7 @@
|
||||
(ptk/data-event :layout/update {:ids [frame-id]})
|
||||
(dwu/commit-undo-transaction undo-id)
|
||||
(when add-component-to-variant?
|
||||
(ptk/event ::ev/event {::ev/name "add-component-to-variant"})))))))))
|
||||
(ev/event {::ev/name "add-component-to-variant"})))))))))
|
||||
|
||||
(defn- as-content [text]
|
||||
(let [paragraphs (->> (str/lines text)
|
||||
|
||||
@ -390,7 +390,7 @@
|
||||
([id-ref ids]
|
||||
(ptk/reify ::add-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
selected (->> (d/nilv ids (dsh/lookup-selected state))
|
||||
(cfh/clean-loops objects))
|
||||
@ -399,7 +399,8 @@
|
||||
can-make-component (every? true? (map #(ctn/valid-shape-for-component? objects %) selected-objects))]
|
||||
|
||||
(when can-make-component
|
||||
(rx/of (add-component2 id-ref selected))))))))
|
||||
(rx/of (-> (add-component2 id-ref selected)
|
||||
(with-meta (meta it))))))))))
|
||||
|
||||
(defn add-multiple-components
|
||||
"Add several new components to current file library, from the currently selected shapes."
|
||||
@ -601,11 +602,12 @@
|
||||
(when id-ref
|
||||
(reset! id-ref (:id new-shape)))
|
||||
|
||||
(rx/of (ptk/event ::ev/event
|
||||
{::ev/name "use-library-component"
|
||||
::ev/origin origin
|
||||
:external-library (not= file-id current-file-id)
|
||||
:is-variant (ctk/is-variant? component)})
|
||||
(rx/of (ev/event
|
||||
(-> {::ev/name "use-library-component"
|
||||
::ev/origin origin
|
||||
:external-library (not= file-id current-file-id)
|
||||
:is-variant (ctk/is-variant? component)}
|
||||
(merge (meta it))))
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dch/commit-changes changes)
|
||||
(ptk/data-event :layout/update {:ids [(:id new-shape)]})
|
||||
@ -1399,7 +1401,7 @@
|
||||
vals
|
||||
(some ctk/is-variant?))]
|
||||
(if has-variants?
|
||||
(rx/of (ptk/event ::ev/event {::ev/name "set-file-variants-shared" ::ev/origin "workspace"}))
|
||||
(rx/of (ev/event {::ev/name "set-file-variants-shared" ::ev/origin "workspace"}))
|
||||
(rx/empty)))))))))
|
||||
|
||||
;; --- Link and unlink Files
|
||||
@ -1463,11 +1465,11 @@
|
||||
(when (pos? variants-count)
|
||||
(->> (rp/cmd! :get-library-usage {:file-id library-id})
|
||||
(rx/map (fn [library-usage]
|
||||
(ptk/event ::ev/event {::ev/name "attach-library-variants"
|
||||
:file-id file-id
|
||||
:library-id library-id
|
||||
:variants-count variants-count
|
||||
:library-used-in (:used-in library-usage)}))))))))))
|
||||
(ev/event {::ev/name "attach-library-variants"
|
||||
:file-id file-id
|
||||
:library-id library-id
|
||||
:variants-count variants-count
|
||||
:library-used-in (:used-in library-usage)}))))))))))
|
||||
|
||||
(defn unlink-file-from-library
|
||||
[file-id library-id]
|
||||
|
||||
@ -305,11 +305,11 @@
|
||||
(ptk/data-event :layout/update {:ids ids})
|
||||
(dwu/commit-undo-transaction undo-id)
|
||||
(when (or (:layout-align-content changes) (:layout-justify-content changes))
|
||||
(ptk/event ::ev/event
|
||||
{::ev/name "layout-change-alignment"}))
|
||||
(ev/event
|
||||
{::ev/name "layout-change-alignment"}))
|
||||
(when (or (:layout-padding changes) (:layout-gap changes))
|
||||
(ptk/event ::ev/event
|
||||
{::ev/name "layout-change-margin"}))))))))
|
||||
(ev/event
|
||||
{::ev/name "layout-change-margin"}))))))))
|
||||
|
||||
(defn add-layout-track
|
||||
([ids type value]
|
||||
|
||||
@ -602,7 +602,7 @@
|
||||
:subsections [:basics]
|
||||
:fn #(when (features/active-feature? @st/state "plugins/runtime")
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:shortcuts"})
|
||||
(ev/event {::ev/name "open-plugins-manager" ::ev/origin "workspace:shortcuts"})
|
||||
(modal/show :plugin-management {})))}})
|
||||
|
||||
(def debug-shortcuts
|
||||
|
||||
@ -897,8 +897,8 @@
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dwl/add-typography typ)
|
||||
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "typography"}))
|
||||
(ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "typography"}))
|
||||
|
||||
(when (not multiple?)
|
||||
(rx/of (update-attrs (:id shape)
|
||||
|
||||
@ -658,7 +658,7 @@
|
||||
[{:keys [attributes attributes-to-remove token shape-ids on-update-shape]}]
|
||||
(ptk/reify ::apply-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
;; We do not allow to apply tokens while text editor is open.
|
||||
(let [edition (get-in state [:workspace-local :edition])
|
||||
objects (dsh/lookup-page-objects state)
|
||||
@ -702,10 +702,12 @@
|
||||
type (:type token)]
|
||||
(rx/concat
|
||||
(rx/of
|
||||
(st/emit! (ev/event {::ev/name "apply-tokens"
|
||||
:type type
|
||||
:applied-to attributes
|
||||
:applied-to-variant any-variant?}))
|
||||
(st/emit! (ev/event
|
||||
(-> {::ev/name "apply-tokens"
|
||||
:type type
|
||||
:applied-to attributes
|
||||
:applied-to-variant any-variant?}
|
||||
(merge (meta it)))))
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwsh/update-shapes shape-ids (fn [shape]
|
||||
(cond-> shape
|
||||
@ -734,7 +736,7 @@
|
||||
[{:keys [token shapes attr]}]
|
||||
(ptk/reify ::apply-spacing-token-separated
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
|
||||
{:keys [attributes on-update-shape]}
|
||||
@ -744,14 +746,17 @@
|
||||
(group-by #(if (ctsl/any-layout-immediate-child? objects %) :frame-children :other) shapes)]
|
||||
|
||||
(rx/of
|
||||
(apply-token {:attributes (or attr attributes)
|
||||
:token token
|
||||
:shape-ids (map :id other)
|
||||
:on-update-shape on-update-shape})
|
||||
(apply-token {:attributes ctt/spacing-margin-keys
|
||||
:token token
|
||||
:shape-ids (map :id frame-children)
|
||||
:on-update-shape update-layout-item-margin}))))))
|
||||
(-> (apply-token {:attributes (or attr attributes)
|
||||
:token token
|
||||
:shape-ids (map :id other)
|
||||
:on-update-shape on-update-shape})
|
||||
(with-meta (meta it)))
|
||||
|
||||
(-> (apply-token {:attributes ctt/spacing-margin-keys
|
||||
:token token
|
||||
:shape-ids (map :id frame-children)
|
||||
:on-update-shape update-layout-item-margin})
|
||||
(with-meta (meta it))))))))
|
||||
|
||||
(defn unapply-token
|
||||
"Removes `attributes` that match `token` for `shape-ids`.
|
||||
@ -773,7 +778,7 @@
|
||||
[{:keys [token attrs shape-ids expand-with-children]}]
|
||||
(ptk/reify ::on-toggle-token
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shapes (into [] (keep (d/getf objects)) shape-ids)
|
||||
|
||||
@ -810,15 +815,17 @@
|
||||
(cond
|
||||
(and (= (:type token) :spacing)
|
||||
(nil? attrs))
|
||||
(apply-spacing-token-separated {:token token
|
||||
:attr attrs
|
||||
:shapes shapes})
|
||||
(-> (apply-spacing-token-separated {:token token
|
||||
:attr attrs
|
||||
:shapes shapes})
|
||||
(with-meta (meta it)))
|
||||
|
||||
:else
|
||||
(apply-token {:attributes (if (empty? attrs) attributes attrs)
|
||||
:token token
|
||||
:shape-ids shape-ids
|
||||
:on-update-shape on-update-shape}))))))))
|
||||
(-> (apply-token {:attributes (if (empty? attrs) attributes attrs)
|
||||
:token token
|
||||
:shape-ids shape-ids
|
||||
:on-update-shape on-update-shape})
|
||||
(with-meta (meta it))))))))))
|
||||
|
||||
(defn apply-token-on-selected
|
||||
[color-operations token]
|
||||
|
||||
@ -426,7 +426,8 @@
|
||||
token))]
|
||||
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ptk/data-event ::ev/event {::ev/name "create-token" :type token-type})))
|
||||
(ev/event (-> {::ev/name "create-token" :type token-type}
|
||||
(merge (meta it))))))
|
||||
|
||||
(rx/of (create-token-with-set token)))))))
|
||||
|
||||
@ -454,7 +455,8 @@
|
||||
id
|
||||
token'))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ptk/data-event ::ev/event {::ev/name "edit-token" :type token-type})))))))
|
||||
(ev/event (-> {::ev/name "edit-token" :type token-type}
|
||||
(merge (meta it))))))))))
|
||||
|
||||
(defn delete-token
|
||||
[set-id token-id]
|
||||
@ -475,7 +477,8 @@
|
||||
(pcb/with-library-data data)
|
||||
(pcb/set-token set-id token-id nil))]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ptk/data-event ::ev/event {::ev/name "delete-token" :type token-type}))))))
|
||||
(ev/event (-> {::ev/name "delete-token" :type token-type}
|
||||
(merge (meta it)))))))))
|
||||
|
||||
(defn bulk-delete-tokens
|
||||
[set-id token-ids]
|
||||
@ -491,7 +494,7 @@
|
||||
(pcb/with-library-data data))
|
||||
token-ids)]
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(ptk/data-event ::ev/event {::ev/name "delete-token-node"}))))))
|
||||
(ev/event {::ev/name "delete-token-node"}))))))
|
||||
|
||||
(defn duplicate-token
|
||||
[token-id]
|
||||
|
||||
@ -616,7 +616,7 @@
|
||||
[ids {:keys [page-id trigger variant-id]}]
|
||||
(ptk/reify ::combine-as-variants
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(watch [it state stream]
|
||||
(let [current-page (:current-page-id state)
|
||||
|
||||
combine
|
||||
@ -665,7 +665,8 @@
|
||||
(dwsh/relocate-shapes #{variant-id} common-parent index)
|
||||
(dwt/update-dimensions [variant-id] :width (+ (:width rect) 60))
|
||||
(dwt/update-dimensions [variant-id] :height (+ (:height rect) 60))
|
||||
(ev/event {::ev/name "combine-as-variants" ::ev/origin trigger :number-of-combined (count ids)}))
|
||||
(ev/event (-> {::ev/name "combine-as-variants" ::ev/origin trigger :number-of-combined (count ids)}
|
||||
(merge (meta it)))))
|
||||
|
||||
;; NOTE: we need to schedule a commit into a
|
||||
;; microtask for ensure that all the scheduled
|
||||
@ -701,7 +702,7 @@
|
||||
[shape {:keys [pos val] :as params}]
|
||||
(ptk/reify ::variant-switch
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
(let [libraries (dsh/lookup-libraries state)
|
||||
component-id (:component-id shape)
|
||||
component (ctf/get-component libraries (:component-file shape) component-id :include-deleted? false)]
|
||||
@ -735,20 +736,23 @@
|
||||
(rx/empty))
|
||||
(rx/of
|
||||
(dwl/component-swap shape (:component-file shape) (:id nearest-comp) true)
|
||||
(ev/event {::ev/name "variant-switch" ::ev/origin "workspace:design-tab"}))))))))))
|
||||
(ev/event (-> {::ev/name "variant-switch" ::ev/origin "workspace:design-tab"}
|
||||
(merge (meta it)))))))))))))
|
||||
|
||||
(defn variants-switch
|
||||
"Switch each shape (that must be a variant copy head) for the closest one with the property value passed as parameter"
|
||||
[{:keys [shapes] :as params}]
|
||||
(ptk/reify ::variants-switch
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(watch [it _ _]
|
||||
(let [ids (into (d/ordered-set) d/xf:map-id shapes)
|
||||
undo-id (js/Symbol)]
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id))
|
||||
(->> (rx/from shapes)
|
||||
(rx/map #(variant-switch % params)))
|
||||
(rx/map (fn [data]
|
||||
(-> (variant-switch data params)
|
||||
(with-meta (meta it))))))
|
||||
(rx/of (dwu/commit-undo-transaction undo-id)
|
||||
(dws/select-shapes ids)))))))
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
;; Force persist before creating snapshot, otherwise we could loss changes
|
||||
(rx/concat
|
||||
(rx/of ::dwp/force-persist
|
||||
(ptk/event ::ev/event {::ev/name "create-version"}))
|
||||
(ev/event {::ev/name "create-version"}))
|
||||
|
||||
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
|
||||
(rx/filter #(or (nil? %) (= :saved %)))
|
||||
@ -88,8 +88,8 @@
|
||||
(let [file-id (:current-file-id state)]
|
||||
(rx/merge
|
||||
(rx/of (update-versions-state {:editing nil})
|
||||
(ptk/event ::ev/event {::ev/name "rename-version"
|
||||
:file-id file-id}))
|
||||
(ev/event {::ev/name "rename-version"
|
||||
:file-id file-id}))
|
||||
(->> (rp/cmd! :update-file-snapshot {:id id :label label})
|
||||
(rx/map fetch-versions)))))))
|
||||
|
||||
@ -173,7 +173,7 @@
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (update-versions-state {:editing id})
|
||||
(fetch-versions)
|
||||
(ptk/event ::ev/event {::ev/name "pin-version"}))))))))))
|
||||
(ev/event {::ev/name "pin-version"}))))))))))
|
||||
|
||||
(defn lock-version
|
||||
[id]
|
||||
@ -215,9 +215,6 @@
|
||||
(let [current-file-id (:current-file-id state)]
|
||||
;; Force persist before creating snapshot, otherwise we could loss changes
|
||||
(->> (rx/concat
|
||||
(rx/of (ptk/event ::ev/event {::ev/origin "plugins"
|
||||
::ev/name "create-version"}))
|
||||
|
||||
(when (= file-id current-file-id)
|
||||
(rx/of ::dwp/force-persist))
|
||||
|
||||
@ -246,20 +243,15 @@
|
||||
|
||||
(ptk/reify ::restore-version-from-plugins
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(rx/concat
|
||||
(rx/of (ev/event {::ev/name "restore-version-plugin"
|
||||
:file-id file-id
|
||||
:team-id team-id})
|
||||
::dwp/force-persist)
|
||||
(watch [_ _ _]
|
||||
(rx/concat
|
||||
(rx/of ::dwp/force-persist)
|
||||
(->> (wait-for-persistence file-id id)
|
||||
(rx/map #(initialize-version)))
|
||||
|
||||
(->> (wait-for-persistence file-id id)
|
||||
(rx/map #(initialize-version)))
|
||||
|
||||
(->> (rx/of 1)
|
||||
(rx/tap resolve)
|
||||
(rx/ignore)))))))
|
||||
(->> (rx/of 1)
|
||||
(rx/tap resolve)
|
||||
(rx/ignore))))))
|
||||
|
||||
|
||||
|
||||
|
||||
@ -76,8 +76,7 @@
|
||||
(when send-event-info?
|
||||
(let [route (dm/get-in match [:data :name])
|
||||
params (get match :query-params)]
|
||||
(rx/of (ptk/event
|
||||
::ev/event
|
||||
(rx/of (ev/event
|
||||
(assoc params
|
||||
::ev/name "navigate"
|
||||
:route (name route)))))))
|
||||
|
||||
@ -44,7 +44,6 @@
|
||||
[cuerdas.core :as str]
|
||||
[goog.events :as events]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc dashboard-content*
|
||||
@ -216,7 +215,7 @@
|
||||
(fn [plugin]
|
||||
(if plugin
|
||||
(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url}))
|
||||
(st/emit! (ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url}))
|
||||
(open-permissions-dialog plugin))
|
||||
(st/emit! (notif/error (tr "dashboard.plugins.parse-error")))))
|
||||
(fn [_]
|
||||
@ -245,12 +244,12 @@
|
||||
(dd/fetch-recent-files team-id)
|
||||
(dd/fetch-projects team-id)
|
||||
(dd/clear-selected-files)
|
||||
(ptk/event ::ev/event {::ev/name "install-template-from-link-finished"
|
||||
:name template-name
|
||||
:url template-url}))]
|
||||
(ev/event {::ev/name "install-template-from-link-finished"
|
||||
:name template-name
|
||||
:url template-url}))]
|
||||
(if valid-url?
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url})
|
||||
(ev/event {::ev/name "install-template-from-link" :name template-name :url template-url})
|
||||
(modal/show
|
||||
{:type :import
|
||||
:project-id project-id
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private comments-icon-svg
|
||||
@ -81,8 +80,8 @@
|
||||
(mf/deps show?)
|
||||
(fn []
|
||||
(when show?
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "open-comment-notifications"
|
||||
::ev/origin "dashboard"})))))
|
||||
(st/emit! (ev/event {::ev/name "open-comment-notifications"
|
||||
::ev/origin "dashboard"})))))
|
||||
|
||||
[:div {:class (stl/css :dashboard-comments-section)}
|
||||
[:& dropdown {:show show? :on-close on-hide-comments :dropdown-id "dashboard-comments"}
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(log/set-level! :debug)
|
||||
@ -171,14 +170,14 @@
|
||||
(rx/subs!
|
||||
(fn [message]
|
||||
(when (some? (:error message))
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-files-error"
|
||||
:error (:error message)})))
|
||||
(st/emit! (ev/event {::ev/name "import-files-error"
|
||||
:error (:error message)})))
|
||||
(swap! state update-with-analyze-result message))))))
|
||||
|
||||
(defn- import-files
|
||||
[state project-id entries]
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-files"
|
||||
:num-files (count entries)}))
|
||||
(st/emit! (ev/event {::ev/name "import-files"
|
||||
:num-files (count entries)}))
|
||||
|
||||
(let [features (get @st/state :features)]
|
||||
(->> (mw/ask-many!
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc empty-project-placeholder*
|
||||
@ -27,9 +26,9 @@
|
||||
on-add-library
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "dashboard"
|
||||
:section "empty-placeholder-projects"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "dashboard"
|
||||
:section "empty-placeholder-projects"}))
|
||||
(dom/open-new-window "https://penpot.app/penpothub/libraries-templates")))
|
||||
|
||||
on-import
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
[app.util.storage :as storage]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private show-more-icon
|
||||
@ -344,8 +343,8 @@
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(reset! show-team-hero* false)
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "dont-show-team-up-hero"
|
||||
::ev/origin "dashboard"}))))]
|
||||
(st/emit! (ev/event {::ev/name "dont-show-team-up-hero"
|
||||
::ev/origin "dashboard"}))))]
|
||||
|
||||
(mf/with-effect [show-team-hero?]
|
||||
(swap! storage/global assoc ::show-team-hero show-team-hero?))
|
||||
|
||||
@ -44,7 +44,6 @@
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[goog.functions :as f]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private clear-search-icon
|
||||
@ -869,8 +868,8 @@
|
||||
(dom/get-data "url"))
|
||||
eventname (-> (dom/get-current-target event)
|
||||
(dom/get-data "eventname"))]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name eventname
|
||||
::ev/origin "menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name eventname
|
||||
::ev/origin "menu:in-app"}))
|
||||
(dom/open-new-window url))))
|
||||
|
||||
handle-feedback-click
|
||||
@ -914,8 +913,8 @@
|
||||
(dom/get-data "url"))
|
||||
eventname (-> (dom/get-current-target event)
|
||||
(dom/get-data "eventname"))]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name eventname
|
||||
::ev/origin "menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name eventname
|
||||
::ev/origin "menu:in-app"}))
|
||||
(dom/open-new-window url))))]
|
||||
|
||||
[:> dropdown-menu* {:show true
|
||||
@ -942,7 +941,7 @@
|
||||
show-release-notes
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version (:main version)}))
|
||||
(st/emit! (ev/event {::ev/name "show-release-notes" :version (:main version)}))
|
||||
(if (and (kbd/alt? event) (kbd/mod? event))
|
||||
(st/emit! (modal/show {:type :onboarding}))
|
||||
(st/emit! (modal/show {:type :release-notes :version (:main version)})))))
|
||||
@ -954,8 +953,8 @@
|
||||
(dom/get-data "url"))
|
||||
eventname (-> (dom/get-current-target event)
|
||||
(dom/get-data "eventname"))]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name eventname
|
||||
::ev/origin "menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name eventname
|
||||
::ev/origin "menu:in-app"}))
|
||||
(dom/open-new-window url))))]
|
||||
|
||||
[:> dropdown-menu* {:show true
|
||||
@ -1052,7 +1051,7 @@
|
||||
on-power-up-click
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-pricing-click" ::ev/origin "dashboard" :section "sidebar"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-pricing-click" ::ev/origin "dashboard" :section "sidebar"}))
|
||||
(dom/open-new-window "https://penpot.app/pricing")))]
|
||||
|
||||
[:*
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
margin: 0 var(--sp-l) 0 0;
|
||||
border-right: $b-1 solid var(--panel-border-color);
|
||||
background-color: var(--panel-background-color);
|
||||
z-index: var(--z-index-dropdown);
|
||||
}
|
||||
|
||||
//SIDEBAR CONTENT COMPONENT
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[lambdaisland.uri :as u]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn get-subscription-type
|
||||
@ -124,9 +123,9 @@
|
||||
go-to-manage-subscription
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "open-subscription-management"
|
||||
::ev/origin "dashboard"
|
||||
:section "team-settings"}))
|
||||
(st/emit! (ev/event {::ev/name "open-subscription-management"
|
||||
::ev/origin "dashboard"
|
||||
:section "team-settings"}))
|
||||
(let [href (-> (rt/get-current-href)
|
||||
(rt/encode-url))
|
||||
href (str "payments/subscriptions/show?returnUrl=" href)]
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.storage :as storage]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private arrow-icon
|
||||
@ -40,10 +39,10 @@
|
||||
(letfn [(on-finish []
|
||||
(st/emit!
|
||||
(dd/fetch-recent-files team-id)
|
||||
(ptk/event ::ev/event {::ev/name "import-template-finish"
|
||||
::ev/origin "dashboard"
|
||||
:template (:name template)
|
||||
:section section})
|
||||
(ev/event {::ev/name "import-template-finish"
|
||||
::ev/origin "dashboard"
|
||||
:template (:name template)
|
||||
:section section})
|
||||
|
||||
(when-not (some? project-id)
|
||||
(dcm/go-to-dashboard-recent
|
||||
@ -51,10 +50,10 @@
|
||||
:project-id default-project-id))))]
|
||||
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "import-template-launch"
|
||||
::ev/origin "dashboard"
|
||||
:template (:name template)
|
||||
:section section})
|
||||
(ev/event {::ev/name "import-template-launch"
|
||||
::ev/origin "dashboard"
|
||||
:template (:name template)
|
||||
:section section})
|
||||
|
||||
(modal/show
|
||||
{:type :import
|
||||
@ -145,9 +144,9 @@
|
||||
(mf/use-fn
|
||||
(mf/deps section)
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "dashboard"
|
||||
:section section}))))
|
||||
(st/emit! (ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "dashboard"
|
||||
:section section}))))
|
||||
|
||||
on-key-down
|
||||
(mf/use-fn
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def embed-images? true)
|
||||
@ -158,10 +157,10 @@
|
||||
(let [origin (if (= :workspace from)
|
||||
"workspace"
|
||||
"viewer")]
|
||||
(st/emit! (ptk/event ::ev/event
|
||||
{::ev/name "copy-inspect-code"
|
||||
::ev/origin origin
|
||||
:type markup-type})))))
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "copy-inspect-code"
|
||||
::ev/origin origin
|
||||
:type markup-type})))))
|
||||
|
||||
on-style-copied
|
||||
(mf/use-fn
|
||||
@ -170,10 +169,10 @@
|
||||
(let [origin (if (= :workspace from)
|
||||
"workspace"
|
||||
"viewer")]
|
||||
(st/emit! (ptk/event ::ev/event
|
||||
{::ev/name "copy-inspect-style"
|
||||
::ev/origin origin
|
||||
:type style-type})))))
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "copy-inspect-style"
|
||||
::ev/origin origin
|
||||
:type style-type})))))
|
||||
|
||||
{on-markup-pointer-down :on-pointer-down
|
||||
on-markup-lost-pointer-capture :on-lost-pointer-capture
|
||||
@ -206,10 +205,10 @@
|
||||
(let [origin (if (= :workspace from)
|
||||
"workspace"
|
||||
"viewer")]
|
||||
(st/emit! (ptk/event ::ev/event
|
||||
{::ev/name "copy-inspect-code"
|
||||
::ev/origin origin
|
||||
:type "all"})))))
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "copy-inspect-code"
|
||||
::ev/origin origin
|
||||
:type "all"})))))
|
||||
|
||||
;;handle-open-review
|
||||
;;(mf/use-fn
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.shape-icon :as usi]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- get-libraries
|
||||
@ -75,7 +74,7 @@
|
||||
(when on-change-section
|
||||
(on-change-section (keyword new-section))
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "change-inspect-tab" :tab new-section})))))
|
||||
(ev/event {::ev/name "change-inspect-tab" :tab new-section})))))
|
||||
|
||||
handle-expand
|
||||
(mf/use-fn
|
||||
@ -122,7 +121,7 @@
|
||||
(mf/deps shapes handle-change-tab)
|
||||
(fn []
|
||||
(if (seq shapes)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"}))
|
||||
(st/emit! (ev/event {::ev/name "inspect-mode-click-element"}))
|
||||
(handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info)))))
|
||||
|
||||
[:aside {:class (stl/css-case :settings-bar-right true
|
||||
|
||||
@ -11,14 +11,13 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.main.data.event :as-alias ev]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.profile :as du]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc step-container
|
||||
@ -33,7 +32,7 @@
|
||||
(assoc :label label)
|
||||
(assoc :step step)
|
||||
(assoc ::ev/name "onboarding-step"))]
|
||||
(st/emit! (ptk/data-event ::ev/event params))
|
||||
(st/emit! (ev/event params))
|
||||
(on-next form event))))]
|
||||
|
||||
[:& fm/form {:form form
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc left-sidebar
|
||||
@ -121,13 +120,13 @@
|
||||
params {:name name}]
|
||||
(st/emit! (-> (dtm/create-team (with-meta params mdata))
|
||||
(with-meta {::ev/origin :onboarding-without-invitations}))
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:create-team-and-invite-later"
|
||||
:team-name name
|
||||
:step 8})
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-finish"})))))
|
||||
(ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:create-team-and-invite-later"
|
||||
:team-name name
|
||||
:step 8})
|
||||
(ev/event
|
||||
{::ev/name "onboarding-finish"})))))
|
||||
|
||||
on-invite-now
|
||||
(mf/use-fn
|
||||
@ -137,15 +136,15 @@
|
||||
|
||||
(st/emit! (-> (dtm/create-team-with-invitations (with-meta params mdata))
|
||||
(with-meta {::ev/origin :onboarding-with-invitations}))
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:create-team-and-invite"
|
||||
:invites (count emails)
|
||||
:team-name name
|
||||
:role (:role params)
|
||||
:step 8})
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-finish"})))))
|
||||
(ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:create-team-and-invite"
|
||||
:invites (count emails)
|
||||
:team-name name
|
||||
:role (:role params)
|
||||
:step 8})
|
||||
(ev/event
|
||||
{::ev/name "onboarding-finish"})))))
|
||||
|
||||
on-submit*
|
||||
(mf/use-fn
|
||||
@ -160,12 +159,12 @@
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (du/update-profile-props {:onboarding-viewed true})
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:skip-team-creation"
|
||||
:step 7})
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-finish"}))))]
|
||||
(ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:skip-team-creation"
|
||||
:step 7})
|
||||
(ev/event
|
||||
{::ev/name "onboarding-finish"}))))]
|
||||
[:*
|
||||
[:div {:class (stl/css :modal-right)}
|
||||
[:div {:class (stl/css :first-block)}
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private arrow-icon
|
||||
@ -52,7 +51,7 @@
|
||||
(defn- show-release-notes
|
||||
[event]
|
||||
(let [version (:main cf/version)]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version version}))
|
||||
(st/emit! (ev/event {::ev/name "show-release-notes" :version version}))
|
||||
|
||||
(if (and (kbd/alt? event) (kbd/mod? event))
|
||||
(st/emit! (modal/show {:type :onboarding}))
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
[app.main.ui.notifications.badge :refer [badge-notification]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr c]]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc plan-card*
|
||||
@ -132,16 +131,16 @@
|
||||
add-payment-details? "&quantity="
|
||||
min-members "&returnUrl=" return-url)]
|
||||
(reset! form nil)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "create-trial-subscription"
|
||||
:type "unlimited"
|
||||
:quantity min-members})
|
||||
(st/emit! (ev/event {::ev/name "create-trial-subscription"
|
||||
:type "unlimited"
|
||||
:quantity min-members})
|
||||
(rt/nav-raw :href href))))))
|
||||
|
||||
subscribe-to-enterprise
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "create-trial-subscription"
|
||||
:type "enterprise"}))
|
||||
(st/emit! (ev/event {::ev/name "create-trial-subscription"
|
||||
:type "enterprise"}))
|
||||
(let [return-url (-> (rt/get-current-href) (rt/encode-url))
|
||||
href (dm/str "payments/subscriptions/create?type=enterprise&returnUrl=" return-url)]
|
||||
(st/emit! (rt/nav-raw :href href)))))
|
||||
@ -161,7 +160,7 @@
|
||||
handle-close-dialog
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "close-subscription-modal"}))
|
||||
(st/emit! (ev/event {::ev/name "close-subscription-modal"}))
|
||||
(modal/hide!)))
|
||||
|
||||
show-editors-list*
|
||||
@ -323,7 +322,7 @@
|
||||
(let [profile (mf/deref refs/profile)
|
||||
handle-close-dialog (mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "subscription-success"}))
|
||||
(st/emit! (ev/event {::ev/name "subscription-success"}))
|
||||
(modal/hide!)))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
@ -434,8 +433,8 @@
|
||||
^boolean show-trial-subscription-modal?
|
||||
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "open-subscription-modal"
|
||||
::ev/origin "settings:from-pricing-page"})
|
||||
(ev/event {::ev/name "open-subscription-modal"
|
||||
::ev/origin "settings:from-pricing-page"})
|
||||
(modal/show :management-dialog
|
||||
{:subscription-type (if (= params-subscription "subscription-to-penpot-unlimited")
|
||||
"unlimited"
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
[app.util.clipboard :as clipboard]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(log/set-level! :warn)
|
||||
@ -126,10 +125,10 @@
|
||||
(let [params (prepare-params options)
|
||||
params (assoc params :file-id (:id file))]
|
||||
(st/emit! (dc/create-share-link params)
|
||||
(ptk/event ::ev/event {::ev/name "create-share-link"
|
||||
::ev/origin "viewer"
|
||||
:can-comment (:who-comment params)
|
||||
:can-inspect-code (:who-inspect params)}))))
|
||||
(ev/event {::ev/name "create-share-link"
|
||||
::ev/origin "viewer"
|
||||
:can-comment (:who-comment params)
|
||||
:can-inspect-code (:who-inspect params)}))))
|
||||
|
||||
copy-link
|
||||
(fn [_]
|
||||
@ -138,8 +137,8 @@
|
||||
:type :toast
|
||||
:content (tr "common.share-link.link-copied-success")
|
||||
:timeout 1000})
|
||||
(ptk/event ::ev/event {::ev/name "copy-share-link"
|
||||
::ev/origin "viewer"})))
|
||||
(ev/event {::ev/name "copy-share-link"
|
||||
::ev/origin "viewer"})))
|
||||
|
||||
try-delete-link
|
||||
(fn [_]
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc palette-item*
|
||||
@ -37,10 +36,10 @@
|
||||
(st/emit! (mdc/add-recent-color color)
|
||||
(mdc/apply-color-from-palette color (kbd/alt? event))
|
||||
(when (not= selected :recent)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "use-library-color"
|
||||
::ev/origin "color-palette"
|
||||
:external-library (not= selected :file)})))))
|
||||
(ev/event
|
||||
{::ev/name "use-library-color"
|
||||
::ev/origin "color-palette"
|
||||
:external-library (not= selected :file)})))))
|
||||
title
|
||||
(uc/get-color-name color)]
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
[app.common.types.fills :as types.fills]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.event :as-alias ev]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.shortcuts :as dsc]
|
||||
[app.main.data.workspace.colors :as dc]
|
||||
@ -46,7 +46,6 @@
|
||||
[app.util.timers :as ts]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]
|
||||
[rumext.v2.util :as mfu]))
|
||||
|
||||
@ -174,9 +173,9 @@
|
||||
|
||||
(st/emit!
|
||||
(dc/update-colorpicker-color {:image image} true)
|
||||
(ptk/data-event ::ev/event {::ev/name "toggle-image-aspect-ratio"
|
||||
::ev/origin "workspace:colorpicker"
|
||||
:checked keep-aspect-ratio?})))))
|
||||
(ev/event {::ev/name "toggle-image-aspect-ratio"
|
||||
::ev/origin "workspace:colorpicker"
|
||||
:checked keep-aspect-ratio?})))))
|
||||
|
||||
on-change-tab
|
||||
(mf/use-fn #(reset! active-color-tab* %))
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc libraries
|
||||
@ -87,8 +86,7 @@
|
||||
(mf/deps state selected on-select-color)
|
||||
(fn [event]
|
||||
(when-not (= :recent selected)
|
||||
(st/emit! (ptk/event
|
||||
::ev/event
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "use-library-color"
|
||||
::ev/origin "colorpicker"
|
||||
:external-library (not= :file selected)})))
|
||||
|
||||
@ -41,7 +41,6 @@
|
||||
[app.util.timers :as timers]
|
||||
[beicon.v2.core :as rx]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def menu-ref
|
||||
@ -676,7 +675,7 @@
|
||||
:on-accept delete-fn}))
|
||||
do-duplicate #(st/emit!
|
||||
(dw/duplicate-page id)
|
||||
(ptk/event ::ev/event {::ev/name "duplicate-page"}))
|
||||
(ev/event {::ev/name "duplicate-page"}))
|
||||
do-rename #(st/emit! (dw/start-rename-page-item id))]
|
||||
|
||||
[:*
|
||||
|
||||
@ -43,7 +43,6 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc shortcuts*
|
||||
@ -62,43 +61,43 @@
|
||||
(let [nav-to-helpc-center
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-help-center-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-help-center-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(dom/open-new-window "https://help.penpot.app")))
|
||||
|
||||
nav-to-community
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-community-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-community-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(dom/open-new-window "https://community.penpot.app")))
|
||||
|
||||
nav-to-youtube
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-tutorials-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-tutorials-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(dom/open-new-window "https://www.youtube.com/c/Penpot")))
|
||||
|
||||
nav-to-templates
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "workspace"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "workspace"}))
|
||||
(dom/open-new-window "https://penpot.app/libraries-templates")))
|
||||
|
||||
nav-to-github
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-github-repository-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-github-repository-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(dom/open-new-window "https://github.com/penpot/penpot")))
|
||||
|
||||
nav-to-terms
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-terms-service-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-terms-service-click"
|
||||
::ev/origin "workspace-menu:in-app"}))
|
||||
(dom/open-new-window "https://penpot.app/terms")))
|
||||
|
||||
nav-to-feedback
|
||||
@ -125,8 +124,8 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [version (:main cf/version)]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes"
|
||||
:version version}))
|
||||
(st/emit! (ev/event {::ev/name "show-release-notes"
|
||||
:version version}))
|
||||
(println version)
|
||||
(if (and (kbd/alt? event) (kbd/mod? event))
|
||||
(st/emit! (modal/show {:type :onboarding}))
|
||||
@ -712,10 +711,10 @@
|
||||
(fn [event]
|
||||
(if can-open?
|
||||
(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(st/emit! (ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(dp/open-plugin! manifest user-can-edit?))
|
||||
(dom/stop-propagation event))))
|
||||
on-key-down
|
||||
@ -724,10 +723,10 @@
|
||||
(fn [event]
|
||||
(when can-open?
|
||||
(when (kbd/enter? event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(st/emit! (ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:menu"
|
||||
:name name
|
||||
:host host}))
|
||||
(dp/open-plugin! manifest user-can-edit?)))))]
|
||||
|
||||
[:> dropdown-menu-item* {:key (dm/str "plugins-menu-" idx)
|
||||
@ -765,8 +764,8 @@
|
||||
on-nav-to-integrations
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "manage-mpc-option"
|
||||
::ev/origin "workspace-menu"}))
|
||||
(st/emit! (ev/event {::ev/name "manage-mpc-option"
|
||||
::ev/origin "workspace-menu"}))
|
||||
(dom/open-new-window "/#/settings/integrations")))
|
||||
|
||||
on-nav-to-integrations-key-down
|
||||
@ -780,11 +779,11 @@
|
||||
(fn []
|
||||
(if mcp-connected?
|
||||
(st/emit! (mcp/user-disconnect-mcp)
|
||||
(ptk/event ::ev/event {::ev/name "disconnect-mcp-plugin"
|
||||
::ev/origin "workspace-menu"}))
|
||||
(ev/event {::ev/name "disconnect-mcp-plugin"
|
||||
::ev/origin "workspace-menu"}))
|
||||
(st/emit! (mcp/connect-mcp)
|
||||
(ptk/event ::ev/event {::ev/name "connect-mcp-plugin"
|
||||
::ev/origin "workspace-menu"})))))
|
||||
(ev/event {::ev/name "connect-mcp-plugin"
|
||||
::ev/origin "workspace-menu"})))))
|
||||
|
||||
on-toggle-mcp-plugin-key-down
|
||||
(mf/use-fn
|
||||
@ -866,8 +865,8 @@
|
||||
on-power-up-click
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-pricing-click"
|
||||
::ev/origin "workspace-menu"}))
|
||||
(st/emit! (ev/event {::ev/name "explore-pricing-click"
|
||||
::ev/origin "workspace-menu"}))
|
||||
(dom/open-new-window "https://penpot.app/pricing")))
|
||||
|
||||
toggle-flag
|
||||
@ -896,8 +895,8 @@
|
||||
(reset! show-menu* false)
|
||||
(reset! selected-sub-menu* nil)
|
||||
(st/emit!
|
||||
(ptk/event ::ev/event {::ev/name "open-plugins-manager"
|
||||
::ev/origin "workspace:menu"})
|
||||
(ev/event {::ev/name "open-plugins-manager"
|
||||
::ev/origin "workspace:menu"})
|
||||
(modal/show :plugin-management {}))))
|
||||
|
||||
subscription (:subscription (:props profile))
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private close-icon
|
||||
@ -128,7 +127,7 @@
|
||||
(reset! fetching-manifest? false)
|
||||
(if plugin
|
||||
(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url}))
|
||||
(st/emit! (ev/event {::ev/name "install-plugin" :name (:name plugin) :url plugin-url}))
|
||||
(modal/show!
|
||||
:plugin-permissions
|
||||
{:plugin plugin
|
||||
@ -148,10 +147,10 @@
|
||||
handle-open-plugin
|
||||
(mf/use-fn
|
||||
(fn [manifest]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:plugins"
|
||||
:name (:name manifest)
|
||||
:host (:host manifest)}))
|
||||
(st/emit! (ev/event {::ev/name "start-plugin"
|
||||
::ev/origin "workspace:plugins"
|
||||
:name (:name manifest)
|
||||
:host (:host manifest)}))
|
||||
(dp/open-plugin! manifest user-can-edit?)
|
||||
(modal/hide!)))
|
||||
|
||||
@ -161,9 +160,9 @@
|
||||
(fn [plugin-index]
|
||||
(let [plugins-list (preg/plugins-list)
|
||||
plugin (nth plugins-list plugin-index)]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "remove-plugin"
|
||||
:name (:name plugin)
|
||||
:host (:host plugin)}))
|
||||
(st/emit! (ev/event {::ev/name "remove-plugin"
|
||||
:name (:name plugin)
|
||||
:host (:host plugin)}))
|
||||
(dp/close-plugin! plugin)
|
||||
(preg/remove-plugin! plugin)
|
||||
(reset! plugins-state* (preg/plugins-list)))))]
|
||||
@ -195,7 +194,7 @@
|
||||
(when-not (empty? plugins-state)
|
||||
[:> i18n/tr-html*
|
||||
{:class (stl/css :discover)
|
||||
:on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))
|
||||
:on-click #(st/emit! (ev/event {::ev/name "open-plugins-list"}))
|
||||
:content (tr "workspace.plugins.discover" cfg/plugins-list-uri)}])
|
||||
|
||||
[:hr]
|
||||
@ -207,7 +206,7 @@
|
||||
[:a {:class (stl/css :plugins-link)
|
||||
:href cfg/plugins-list-uri
|
||||
:target "_blank"
|
||||
:on-click #(st/emit! (ptk/event ::ev/event {::ev/name "open-plugins-list"}))}
|
||||
:on-click #(st/emit! (ev/event {::ev/name "open-plugins-list"}))}
|
||||
(tr "workspace.plugins.plugin-list-link") deprecated-icon/external-link]]
|
||||
|
||||
[:*
|
||||
@ -298,9 +297,9 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "allow-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(st/emit! (ev/event {::ev/name "allow-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(modal/hide))
|
||||
(when on-accept (on-accept))))
|
||||
|
||||
@ -308,9 +307,9 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "reject-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(st/emit! (ev/event {::ev/name "reject-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(modal/hide))
|
||||
(when on-close (on-close))))]
|
||||
|
||||
@ -353,9 +352,9 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "allow-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(st/emit! (ev/event {::ev/name "allow-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(modal/hide))
|
||||
(when on-accept (on-accept))))
|
||||
|
||||
@ -363,9 +362,9 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "reject-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(st/emit! (ev/event {::ev/name "reject-plugin-permissions"
|
||||
:host host
|
||||
:permissions (->> permissions (str/join ", "))})
|
||||
(modal/hide))
|
||||
(when on-close (on-close))))]
|
||||
|
||||
@ -406,7 +405,7 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "try-out-accept"})
|
||||
(st/emit! (ev/event {::ev/name "try-out-accept"})
|
||||
(modal/hide))
|
||||
(when on-accept (on-accept))))
|
||||
|
||||
@ -414,7 +413,7 @@
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "try-out-cancel"})
|
||||
(st/emit! (ev/event {::ev/name "try-out-cancel"})
|
||||
(modal/hide))
|
||||
(when on-close (on-close))))]
|
||||
|
||||
|
||||
@ -43,7 +43,6 @@
|
||||
[app.main.ui.workspace.tokens.sidebar :refer [tokens-sidebar-tab*]]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
;; --- Left Sidebar (Component)
|
||||
@ -146,7 +145,7 @@
|
||||
(fn [id]
|
||||
(st/emit! (dcm/go-to-workspace :layout (keyword id)))
|
||||
(when (= id "tokens")
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "open-tokens-tab"})))))
|
||||
(st/emit! (ev/event {::ev/name "open-tokens-tab"})))))
|
||||
|
||||
tabs
|
||||
(mf/with-memo [mode-inspect? design-tokens?]
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
[app.util.keyboard :as kbd]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc color-item
|
||||
@ -180,10 +179,10 @@
|
||||
(mf/deps color on-asset-click read-only? file-id)
|
||||
(fn [event]
|
||||
(when-not read-only?
|
||||
(st/emit! (ptk/data-event ::ev/event
|
||||
{::ev/name "use-library-color"
|
||||
::ev/origin "sidebar"
|
||||
:external-library (not local?)}))
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "use-library-color"
|
||||
::ev/origin "sidebar"
|
||||
:external-library (not local?)}))
|
||||
|
||||
(when-not (on-asset-click event (:id color))
|
||||
(st/emit! (dc/apply-color-from-assets file-id color (kbd/alt? event)))))))]
|
||||
@ -403,8 +402,8 @@
|
||||
y-position (:top bounds)]
|
||||
|
||||
(st/emit! (dw/set-assets-section-open file-id :colors true)
|
||||
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "color"})
|
||||
(ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "color"})
|
||||
(modal/show :colorpicker
|
||||
{:x x-position
|
||||
:y y-position
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def drag-data* (atom {:is-local false}))
|
||||
@ -373,8 +372,8 @@
|
||||
(let [params {:file-id file-id
|
||||
:blobs (seq blobs)}]
|
||||
(st/emit! (dwm/upload-media-components params)
|
||||
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "components"})))))
|
||||
(ev/event {::ev/name "add-asset-to-library"
|
||||
:asset-type "components"})))))
|
||||
|
||||
on-duplicate
|
||||
(mf/use-fn
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
[app.util.keyboard :as kbd]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@ -94,7 +93,7 @@
|
||||
(mf/use-fn
|
||||
(fn [ev]
|
||||
(dom/stop-propagation ev)
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "navigate-to-library-file"}))))]
|
||||
(st/emit! (ev/event {::ev/name "navigate-to-library-file"}))))]
|
||||
|
||||
[:div {:class (stl/css-case
|
||||
:library-title true
|
||||
|
||||
@ -28,7 +28,6 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def lens:typography-section-state
|
||||
@ -97,10 +96,10 @@
|
||||
(mf/deps typography on-asset-click read-only? local?)
|
||||
(fn [event]
|
||||
(when-not read-only?
|
||||
(st/emit! (ptk/data-event ::ev/event
|
||||
{::ev/name "use-library-typography"
|
||||
::ev/origin "sidebar"
|
||||
:external-library (not local?)}))
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "use-library-typography"
|
||||
::ev/origin "sidebar"
|
||||
:external-library (not local?)}))
|
||||
(when-not (on-asset-click event (:id typography))
|
||||
(st/emit! (dwt/apply-typography typography file-id))))))]
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc typography-item
|
||||
@ -38,8 +37,7 @@
|
||||
:typography-ref-id (:id typography)}
|
||||
(dissoc typography :id :name))]
|
||||
|
||||
(st/emit! (ptk/event
|
||||
::ev/event
|
||||
(st/emit! (ev/event
|
||||
{::ev/name "use-library-typography"
|
||||
::ev/origin "text-palette"
|
||||
:external-library (not= file-id current-file-id)}))
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.webapi :as wapi]
|
||||
[app.util.zip :as zip]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc export-tab*
|
||||
@ -61,7 +60,7 @@
|
||||
(mf/deps tokens-json)
|
||||
(fn []
|
||||
(when tokens-json
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "export-tokens" :type "single"}))
|
||||
(st/emit! (ev/event {::ev/name "export-tokens" :type "single"}))
|
||||
(->> (wapi/create-blob (or tokens-json "{}") "application/json")
|
||||
(dom/trigger-download "tokens.json")))))]
|
||||
[:> export-tab* {:is-disabled is-disabled
|
||||
@ -88,7 +87,7 @@
|
||||
(mf/use-fn
|
||||
(mf/deps files)
|
||||
(fn []
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "export-tokens" :type "multiple"}))
|
||||
(st/emit! (ev/event {::ev/name "export-tokens" :type "multiple"}))
|
||||
(download-tokens-zip! files)))]
|
||||
[:> export-tab* {:on-export on-export
|
||||
:is-disabled is-disabled}
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
[app.util.zip :as uz]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn- on-stream-imported
|
||||
@ -35,7 +34,7 @@
|
||||
(rx/sub!
|
||||
tokens-lib-stream
|
||||
(fn [lib]
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "import-tokens" :type type})
|
||||
(st/emit! (ev/event {::ev/name "import-tokens" :type type})
|
||||
(dwtl/import-tokens-lib lib))
|
||||
(modal/hide!))
|
||||
(fn [err]
|
||||
|
||||
@ -7,8 +7,7 @@
|
||||
[app.main.data.notifications :as ntf]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.store :as st]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[potok.v2.core :as ptk]))
|
||||
[app.util.i18n :refer [tr]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; HELPERS - Shared functions for token sets management
|
||||
@ -37,7 +36,7 @@
|
||||
[tokens-lib parent-set name]
|
||||
(let [name (ctob/make-child-name parent-set name)
|
||||
errors (sm/validation-errors name (cfo/make-token-set-name-schema tokens-lib nil))]
|
||||
(st/emit! (ptk/data-event ::ev/event {::ev/name "create-token-set" :name name})
|
||||
(st/emit! (ev/event {::ev/name "create-token-set" :name name})
|
||||
(dwtl/clear-token-set-creation))
|
||||
(if (empty? errors)
|
||||
(let [token-set (ctob/make-token-set :name name)]
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.keyboard :as k]
|
||||
[cuerdas.core :as str]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
;; Form Component --------------------------------------------------------------
|
||||
@ -412,7 +411,7 @@
|
||||
on-save
|
||||
(mf/use-fn
|
||||
(fn [theme]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "create-tokens-theme"})
|
||||
(st/emit! (ev/event {::ev/name "create-tokens-theme"})
|
||||
(dwtl/create-token-theme theme))))
|
||||
has-prev-view (has-prev-view (:prev-type state))]
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.timers :as ts]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc image-upload
|
||||
@ -209,8 +208,8 @@
|
||||
:aria-label (tr "workspace.toolbar.plugins" (sc/get-tooltip :plugins))
|
||||
:class (stl/css :main-toolbar-options-button)
|
||||
:on-click #(st/emit!
|
||||
(ptk/data-event ::ev/event {::ev/name "open-plugins-manager"
|
||||
::ev/origin "workspace:toolbar"})
|
||||
(ev/event {::ev/name "open-plugins-manager"
|
||||
::ev/origin "workspace:toolbar"})
|
||||
(modal/show :plugin-management {}))
|
||||
:data-tool "plugins"
|
||||
:data-testid "plugins-btn"}
|
||||
|
||||
@ -273,6 +273,7 @@
|
||||
(->> (dwm/upload-media-url name file-id url)
|
||||
(rx/take 1)
|
||||
(rx/map format/format-image)
|
||||
(rx/tap #(st/emit! (se/event plugin-id "add-media")))
|
||||
(rx/subs! resolve reject)))))))
|
||||
|
||||
:uploadMediaData
|
||||
@ -289,6 +290,7 @@
|
||||
:on-svg identity})
|
||||
(rx/take 1)
|
||||
(rx/map format/format-image)
|
||||
(rx/tap #(st/emit! (se/event plugin-id "add-media")))
|
||||
(rx/subs! resolve reject))))))
|
||||
|
||||
:group
|
||||
@ -462,6 +464,7 @@
|
||||
(conj acc (cg/generate-formatted-markup-code objects type resolved-shapes))))
|
||||
[]))]
|
||||
|
||||
(st/emit! (se/event plugin-id "copy-inspect-code"))
|
||||
(->> resolved-code (str/join "\n"))))))
|
||||
|
||||
:generateStyle
|
||||
@ -508,6 +511,7 @@
|
||||
(cg/generate-style-code
|
||||
objects type shapes resolved-shapes {:with-prelude? prelude?}))))
|
||||
[]))]
|
||||
(st/emit! (se/event plugin-id "copy-inspect-style"))
|
||||
(dm/str
|
||||
(if prelude? (cg/prelude type) "")
|
||||
(->> resolved-styles
|
||||
@ -542,7 +546,8 @@
|
||||
(fn []
|
||||
(let [file-id (:current-file-id @st/state)
|
||||
id (uuid/next)]
|
||||
(st/emit! (dw/create-page {:page-id id :file-id file-id}))
|
||||
(st/emit! (-> (dw/create-page {:page-id id :file-id file-id})
|
||||
(se/add-event plugin-id)))
|
||||
(page/page-proxy plugin-id file-id id)))
|
||||
|
||||
:openPage
|
||||
@ -648,9 +653,10 @@
|
||||
ids)]
|
||||
(if valid?
|
||||
(let [variant-id (uuid/next)]
|
||||
(st/emit! (dwv/combine-as-variants
|
||||
ids
|
||||
{:trigger "plugin:combine-as-variants" :variant-id variant-id}))
|
||||
(st/emit! (-> (dwv/combine-as-variants
|
||||
ids
|
||||
{:trigger "plugin:combine-as-variants" :variant-id variant-id})
|
||||
(se/add-event plugin-id)))
|
||||
(shape/shape-proxy plugin-id variant-id))
|
||||
|
||||
(u/not-valid plugin-id :shapes "One of the components is not on the same page or is already a variant")))))))
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.user :as user]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
@ -71,7 +72,13 @@
|
||||
:else
|
||||
(->> (rp/cmd! :update-comment {:id (:id data) :content content})
|
||||
(rx/tap #(st/emit! (dc/retrieve-comment-threads file-id)))
|
||||
(rx/subs! #(swap! data* assoc :content content))))))}
|
||||
(rx/subs!
|
||||
(fn []
|
||||
(st/emit! (se/event plugin-id "update-comment"
|
||||
:thread-id thread-id
|
||||
:id (:id data)
|
||||
:content-size (count content)))
|
||||
(swap! data* assoc :content content)))))))}
|
||||
|
||||
;; Public methods
|
||||
:remove
|
||||
@ -87,7 +94,11 @@
|
||||
:else
|
||||
(->> (rp/cmd! :delete-comment {:id (:id data)})
|
||||
(rx/tap #(st/emit! (dc/retrieve-comment-threads file-id)))
|
||||
(rx/subs! #(resolve) reject)))))))))
|
||||
(rx/subs!
|
||||
(fn []
|
||||
(st/emit! (se/event plugin-id "update-comment" :thread-id thread-id))
|
||||
(resolve))
|
||||
reject)))))))))
|
||||
|
||||
(defn comment-thread-proxy? [p]
|
||||
(obj/type-of? p "CommentThreadProxy"))
|
||||
@ -143,7 +154,8 @@
|
||||
(u/not-valid plugin-id :resolved "Plugin doesn't have 'comment:write' permission")
|
||||
|
||||
:else
|
||||
(do (st/emit! (dc/update-comment-thread (assoc @data* :is-resolved is-resolved)))
|
||||
(do (st/emit! (-> (dc/update-comment-thread (assoc @data* :is-resolved is-resolved))
|
||||
(se/add-event plugin-id)))
|
||||
(swap! data* assoc :is-resolved is-resolved))))}
|
||||
|
||||
:findComments
|
||||
@ -178,7 +190,13 @@
|
||||
(js/Promise.
|
||||
(fn [resolve reject]
|
||||
(->> (rp/cmd! :create-comment {:thread-id (:id data) :content content})
|
||||
(rx/subs! #(resolve (comment-proxy plugin-id file-id page-id (:id data) %)) reject))))))
|
||||
(rx/subs!
|
||||
(fn [result]
|
||||
(st/emit! (se/event plugin-id "create-comment"
|
||||
:thread-id (:id data)
|
||||
:file-id file-id
|
||||
:content-size (count content)))
|
||||
(resolve (comment-proxy plugin-id file-id page-id (:id data) result))) reject))))))
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
@ -194,4 +212,5 @@
|
||||
:else
|
||||
(js/Promise.
|
||||
(fn [resolve]
|
||||
(st/emit! (dc/delete-comment-thread-on-workspace {:id (:id data)} #(resolve)))))))))))
|
||||
(st/emit! (-> (dc/delete-comment-thread-on-workspace {:id (:id data)} #(resolve))
|
||||
(se/add-event plugin-id)))))))))))
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
[app.plugins.page :as page]
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.user :as user]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.http :as http]
|
||||
@ -54,7 +55,7 @@
|
||||
(do (swap! data assoc :label value :created-by "user")
|
||||
(->> (rp/cmd! :update-file-snapshot {:id (:id @data) :label value})
|
||||
(rx/take 1)
|
||||
(rx/subs! identity)))))}
|
||||
(rx/subs! #(st/emit! (se/event "rename-version" :file-id file-id)))))))}
|
||||
|
||||
:createdBy
|
||||
{:get
|
||||
@ -78,7 +79,9 @@
|
||||
|
||||
:else
|
||||
(let [version-id (get @data :id)]
|
||||
(st/emit! (dwv/restore-version-from-plugin file-id version-id resolve reject)))))))
|
||||
(st/emit!
|
||||
(dwv/restore-version-from-plugin file-id version-id resolve reject)
|
||||
(se/event plugin-id "restore-version" :file-id file-id)))))))
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
@ -110,10 +113,12 @@
|
||||
:label (ct/format-inst (:created-at @data) :localized-date)}]
|
||||
(->> (rx/zip (rp/cmd! :get-team-users {:file-id file-id})
|
||||
(rp/cmd! :update-file-snapshot params))
|
||||
(rx/subs! (fn [[users data]]
|
||||
(let [users (d/index-by :id users)]
|
||||
(resolve (file-version-proxy plugin-id file-id users @data))))
|
||||
reject))))))))))
|
||||
(rx/subs!
|
||||
(fn [[users data]]
|
||||
(let [users (d/index-by :id users)]
|
||||
(st/emit! (se/event plugin-id "pin-version" :file-id file-id))
|
||||
(resolve (file-version-proxy plugin-id file-id users @data))))
|
||||
reject))))))))))
|
||||
|
||||
(defn file-proxy? [p]
|
||||
(obj/type-of? p "FileProxy"))
|
||||
@ -220,7 +225,8 @@
|
||||
|
||||
:else
|
||||
(let [page-id (uuid/next)]
|
||||
(st/emit! (dw/create-page {:page-id page-id :file-id id}))
|
||||
(st/emit! (-> (dw/create-page {:page-id page-id :file-id id})
|
||||
(se/add-event plugin-id)))
|
||||
(page/page-proxy plugin-id id page-id))))
|
||||
|
||||
:export
|
||||
@ -269,6 +275,7 @@
|
||||
:response-type :buffer}))))
|
||||
(rx/take 1)
|
||||
(rx/map #(js/Uint8Array. (:body %)))
|
||||
(rx/tap #(st/emit! (se/event plugin-id "export-binary-files" :format format :type type)))
|
||||
(rx/subs! resolve reject))))))))
|
||||
:findVersions
|
||||
(fn [criteria]
|
||||
@ -315,7 +322,9 @@
|
||||
(u/reject-not-valid reject :findVersions "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwv/create-version-from-plugins id label resolve reject)))))]
|
||||
(st/emit!
|
||||
(dwv/create-version-from-plugins id label resolve reject)
|
||||
(se/event plugin-id "create-version" :file-id id)))))]
|
||||
(-> (js/Promise.all #js [users-promise create-version-promise])
|
||||
(.then
|
||||
(fn [[users data]]
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
@ -186,7 +187,6 @@
|
||||
:else
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}}))))}
|
||||
|
||||
|
||||
:topPadding
|
||||
{:this true
|
||||
:get #(-> % u/proxy->shape :layout-padding :p1 (d/nilv 0))
|
||||
@ -260,11 +260,16 @@
|
||||
:else
|
||||
(let [child-id (obj/get child "$id")
|
||||
shape (u/locate-shape file-id page-id id)
|
||||
child-shape (u/locate-shape file-id page-id child-id)
|
||||
index
|
||||
(if (and (u/natural-child-ordering? plugin-id) (not (ctl/reverse? shape)))
|
||||
0
|
||||
(count (:shapes shape)))]
|
||||
(st/emit! (dwsh/relocate-shapes #{child-id} id index)))))
|
||||
(st/emit!
|
||||
(dwsh/relocate-shapes #{child-id} id index)
|
||||
(se/event plugin-id "add-layout-element"
|
||||
:type (:type child-shape)
|
||||
:parent-type (:type shape))))))
|
||||
|
||||
:horizontalSizing
|
||||
{:this true
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.typography :as ctt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.plugins :as dp]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
@ -27,6 +26,7 @@
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.text :as text]
|
||||
[app.plugins.tokens :as tokens]
|
||||
[app.plugins.utils :as u]
|
||||
@ -164,7 +164,8 @@
|
||||
(u/not-valid plugin-id :remove "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwl/delete-color {:id id}))))
|
||||
(st/emit! (-> (dwl/delete-color {:id id})
|
||||
(se/add-event plugin-id)))))
|
||||
|
||||
:clone
|
||||
(fn []
|
||||
@ -176,7 +177,8 @@
|
||||
(let [color-id (uuid/next)
|
||||
color (-> (u/locate-library-color file-id id)
|
||||
(assoc :id color-id))]
|
||||
(st/emit! (dwl/add-color color {:rename? false}))
|
||||
(st/emit! (-> (dwl/add-color color {:rename? false})
|
||||
(se/add-event plugin-id)))
|
||||
(lib-color-proxy plugin-id id color-id))))
|
||||
|
||||
:asFill
|
||||
@ -309,7 +311,8 @@
|
||||
:else
|
||||
(let [typo (u/proxy->library-typography self)
|
||||
value (dm/str (d/nilv (:path typo) "") " / " value)]
|
||||
(st/emit! (dwl/rename-typography file-id id value)))))}
|
||||
(st/emit! (-> (dwl/rename-typography file-id id value)
|
||||
(se/add-event plugin-id))))))}
|
||||
|
||||
:path
|
||||
{:this true
|
||||
@ -488,7 +491,8 @@
|
||||
(u/not-valid plugin-id :remove "Plugin doesn't have 'library:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwl/delete-typography {:id id}))))
|
||||
(st/emit! (-> (dwl/delete-typography {:id id})
|
||||
(se/add-event plugin-id)))))
|
||||
|
||||
:clone
|
||||
(fn []
|
||||
@ -500,7 +504,8 @@
|
||||
(let [typo-id (uuid/next)
|
||||
typo (-> (u/locate-library-typography file-id id)
|
||||
(assoc :id typo-id))]
|
||||
(st/emit! (dwl/add-typography typo false))
|
||||
(st/emit! (-> (dwl/add-typography typo false)
|
||||
(se/add-event plugin-id)))
|
||||
(lib-typography-proxy plugin-id id typo-id))))
|
||||
|
||||
:applyToText
|
||||
@ -662,13 +667,13 @@
|
||||
:addVariant
|
||||
(fn []
|
||||
(st/emit!
|
||||
(ev/event {::ev/name "add-new-variant" ::ev/origin "plugin:add-variant"})
|
||||
(se/event plugin-id "add-new-variant")
|
||||
(dwv/add-new-variant id)))
|
||||
|
||||
:addProperty
|
||||
(fn []
|
||||
(st/emit!
|
||||
(ev/event {::ev/name "add-new-property" ::ev/origin "plugin:add-property"})
|
||||
(se/event plugin-id "add-new-property")
|
||||
(dwv/add-new-property id {:property-value "Value 1"})))
|
||||
|
||||
:removeProperty
|
||||
@ -676,7 +681,7 @@
|
||||
(if (not (nat-int? pos))
|
||||
(u/not-valid plugin-id :pos pos)
|
||||
(st/emit!
|
||||
(ev/event {::ev/name "remove-property" ::ev/origin "plugin:remove-property"})
|
||||
(se/event plugin-id "remove-property")
|
||||
(dwv/remove-property id pos))))
|
||||
|
||||
:renameProperty
|
||||
@ -759,7 +764,8 @@
|
||||
|
||||
:else
|
||||
(let [id-ref (atom nil)]
|
||||
(st/emit! (dwl/instantiate-component file-id id (gpt/point 0 0) {:id-ref id-ref :origin "plugin"}))
|
||||
(st/emit! (-> (dwl/instantiate-component file-id id (gpt/point 0 0) {:id-ref id-ref :origin "plugin"})
|
||||
(se/add-event plugin-id)))
|
||||
(shape/shape-proxy plugin-id @id-ref))))
|
||||
|
||||
:getPluginData
|
||||
@ -885,7 +891,7 @@
|
||||
(when (and component
|
||||
(not (ctk/is-variant? component)))
|
||||
(st/emit!
|
||||
(ev/event {::ev/name "transform-in-variant" ::ev/origin "plugin:transform-in-variant"})
|
||||
(se/event plugin-id "transform-in-variant")
|
||||
(dwv/transform-in-variant (:main-instance-id component))))))
|
||||
|
||||
:addVariant
|
||||
@ -894,7 +900,7 @@
|
||||
(when (and component
|
||||
(ctk/is-variant? component))
|
||||
(st/emit!
|
||||
(ev/event {::ev/name "add-new-variant" ::ev/origin "plugin:add-variant-from-component"})
|
||||
(se/event plugin-id "add-new-variant")
|
||||
(dwv/add-new-variant (:main-instance-id component))))))
|
||||
|
||||
:setVariantProperty
|
||||
@ -908,7 +914,7 @@
|
||||
|
||||
:else
|
||||
(st/emit!
|
||||
(ev/event {::ev/name "variant-edit-property-value" ::ev/origin "plugin:edit-property-value"})
|
||||
(se/event plugin-id "variant-edit-property-value")
|
||||
(dwv/update-property-value id pos value))))))
|
||||
|
||||
(defn library-proxy? [p]
|
||||
@ -974,7 +980,8 @@
|
||||
|
||||
:else
|
||||
(let [color-id (uuid/next)]
|
||||
(st/emit! (dwl/add-color {:id color-id :name "Color" :color "#000000" :opacity 1} {:rename? false}))
|
||||
(st/emit! (-> (dwl/add-color {:id color-id :name "Color" :color "#000000" :opacity 1} {:rename? false})
|
||||
(se/add-event plugin-id)))
|
||||
(lib-color-proxy plugin-id file-id color-id))))
|
||||
|
||||
:createTypography
|
||||
@ -985,7 +992,8 @@
|
||||
|
||||
:else
|
||||
(let [typography-id (uuid/next)]
|
||||
(st/emit! (dwl/add-typography (ctt/make-typography {:id typography-id :name "Typography"}) false))
|
||||
(st/emit! (-> (dwl/add-typography (ctt/make-typography {:id typography-id :name "Typography"}) false)
|
||||
(se/add-event plugin-id)))
|
||||
(lib-typography-proxy plugin-id file-id typography-id))))
|
||||
|
||||
:createComponent
|
||||
@ -997,7 +1005,8 @@
|
||||
:else
|
||||
(let [id-ref (atom nil)
|
||||
ids (into #{} (map #(obj/get % "$id")) shapes)]
|
||||
(st/emit! (dwl/add-component id-ref ids))
|
||||
(st/emit! (-> (dwl/add-component id-ref ids)
|
||||
(se/add-event plugin-id)))
|
||||
(lib-component-proxy plugin-id file-id @id-ref))))
|
||||
|
||||
;; Plugin data
|
||||
@ -1127,4 +1136,5 @@
|
||||
(rx/filter (ptk/type? ::dwl/attach-library-finished))
|
||||
(rx/take 1)
|
||||
(rx/subs! #(resolve (library-proxy plugin-id library-id)) reject))
|
||||
(st/emit! (dwl/link-file-to-library file-id library-id))))))))))
|
||||
(st/emit! (-> (dwl/link-file-to-library file-id library-id)
|
||||
(se/add-event plugin-id)))))))))))
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.ruler-guides :as rg]
|
||||
[app.plugins.shape :as shape]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
@ -283,7 +284,9 @@
|
||||
|
||||
:else
|
||||
(let [flow-id (uuid/next)]
|
||||
(st/emit! (dwi/add-flow flow-id id name (obj/get frame "$id")))
|
||||
(st/emit!
|
||||
(dwi/add-flow flow-id id name (obj/get frame "$id"))
|
||||
(se/event plugin-id "add-flow"))
|
||||
(flow-proxy plugin-id file-id id flow-id))))
|
||||
|
||||
:removeFlow
|
||||
@ -293,7 +296,9 @@
|
||||
(u/not-valid plugin-id :removeFlow-flow flow)
|
||||
|
||||
:else
|
||||
(st/emit! (dwi/remove-flow id (obj/get flow "$id")))))
|
||||
(st/emit!
|
||||
(dwi/remove-flow id (obj/get flow "$id"))
|
||||
(se/event plugin-id "remove-flow"))))
|
||||
|
||||
:addRulerGuide
|
||||
(fn [orientation value board]
|
||||
@ -316,12 +321,13 @@
|
||||
:else
|
||||
(let [ruler-id (uuid/next)]
|
||||
(st/emit!
|
||||
(dwgu/update-guides
|
||||
(d/without-nils
|
||||
{:id ruler-id
|
||||
:axis (parser/orientation->axis orientation)
|
||||
:position value
|
||||
:frame-id (when board (obj/get board "$id"))})))
|
||||
(-> (dwgu/update-guides
|
||||
(d/without-nils
|
||||
{:id ruler-id
|
||||
:axis (parser/orientation->axis orientation)
|
||||
:position value
|
||||
:frame-id (when board (obj/get board "$id"))}))
|
||||
(se/add-event plugin-id)))
|
||||
(rg/ruler-guide-proxy plugin-id file-id id ruler-id)))))
|
||||
|
||||
:removeRulerGuide
|
||||
@ -335,7 +341,8 @@
|
||||
|
||||
:else
|
||||
(let [guide (u/proxy->ruler-guide value)]
|
||||
(st/emit! (dwgu/remove-guide guide)))))
|
||||
(st/emit! (-> (dwgu/remove-guide guide)
|
||||
(se/add-event plugin-id))))))
|
||||
|
||||
:addCommentThread
|
||||
(fn [content position board]
|
||||
@ -364,15 +371,15 @@
|
||||
(js/Promise.
|
||||
(fn [resolve]
|
||||
(st/emit!
|
||||
(dc/create-thread-on-workspace
|
||||
{:file-id file-id
|
||||
:page-id id
|
||||
:position (gpt/point position)
|
||||
:content content}
|
||||
|
||||
(fn [data]
|
||||
(resolve (pc/comment-thread-proxy plugin-id file-id id data)))
|
||||
false))))))))
|
||||
(-> (dc/create-thread-on-workspace
|
||||
{:file-id file-id
|
||||
:page-id id
|
||||
:position (gpt/point position)
|
||||
:content content}
|
||||
(fn [data]
|
||||
(resolve (pc/comment-thread-proxy plugin-id file-id id data)))
|
||||
false)
|
||||
(se/add-event plugin-id)))))))))
|
||||
|
||||
:removeCommentThread
|
||||
(fn [thread]
|
||||
|
||||
@ -135,3 +135,7 @@
|
||||
(= plugin-id mcp-plugin-id)
|
||||
(let [{:keys [permissions]} (dm/get-in @registry [:data plugin-id])]
|
||||
(contains? permissions permission))))
|
||||
|
||||
(defn get-plugin-data
|
||||
[state plugin-id]
|
||||
(get-in state [:profile :props :plugins :data plugin-id]))
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
[app.main.store :as st]
|
||||
[app.plugins.format :as format]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
@ -55,7 +56,8 @@
|
||||
:else
|
||||
(let [board-id (when value (obj/get value "$id"))
|
||||
guide (-> self u/proxy->ruler-guide)]
|
||||
(st/emit! (dwgu/update-guides (assoc guide :frame-id board-id)))))))}
|
||||
(st/emit! (-> (dwgu/update-guides (assoc guide :frame-id board-id))
|
||||
(se/add-event plugin-id)))))))}
|
||||
|
||||
:orientation
|
||||
{:this true
|
||||
@ -92,9 +94,11 @@
|
||||
(+ board-pos value))
|
||||
|
||||
value)]
|
||||
(st/emit! (dwgu/update-guides (assoc guide :position position))))))}
|
||||
(st/emit! (-> (dwgu/update-guides (assoc guide :position position))
|
||||
(se/add-event plugin-id))))))}
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
(let [guide (u/locate-ruler-guide file-id page-id id)]
|
||||
(st/emit! (dwgu/remove-guide guide))))))
|
||||
(st/emit! (-> (dwgu/remove-guide guide)
|
||||
(se/add-event plugin-id)))))))
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
[app.plugins.parser :as parser]
|
||||
[app.plugins.register :as r]
|
||||
[app.plugins.ruler-guides :as rg]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.text :as text]
|
||||
[app.plugins.tokens :refer [applied-tokens-plugin->applied-tokens token-attr-plugin->token-attr token-attr?]]
|
||||
[app.plugins.utils :as u]
|
||||
@ -785,10 +786,8 @@
|
||||
(when (ctl/grid-layout-immediate-child-id? objects id)
|
||||
(grid/layout-cell-proxy plugin-id file-id page-id id))))}
|
||||
|
||||
|
||||
;; Interactions
|
||||
|
||||
|
||||
:interactions
|
||||
{:this true
|
||||
:get
|
||||
@ -962,12 +961,17 @@
|
||||
|
||||
:else
|
||||
(let [child-id (obj/get child "$id")
|
||||
child-shape (u/locate-shape file-id page-id child-id)
|
||||
is-reversed? (ctl/flex-layout? shape)
|
||||
index
|
||||
(if (or (not (u/natural-child-ordering? plugin-id)) is-reversed?)
|
||||
0
|
||||
(count (:shapes shape)))]
|
||||
(st/emit! (dwsh/relocate-shapes #{child-id} id index))))))
|
||||
(st/emit!
|
||||
(dwsh/relocate-shapes #{child-id} id index)
|
||||
(se/event plugin-id (if (ctl/any-layout? shape) "add-layout-element" "add-element")
|
||||
:type (:type child-shape)
|
||||
:parent-type (:type shape)))))))
|
||||
|
||||
:insertChild
|
||||
(fn [index child]
|
||||
@ -987,12 +991,17 @@
|
||||
|
||||
:else
|
||||
(let [child-id (obj/get child "$id")
|
||||
child-shape (u/locate-shape file-id page-id child-id)
|
||||
is-reversed? (ctl/flex-layout? shape)
|
||||
index
|
||||
(if (or (not (u/natural-child-ordering? plugin-id)) is-reversed?)
|
||||
(- (count (:shapes shape)) index)
|
||||
index)]
|
||||
(st/emit! (dwsh/relocate-shapes #{child-id} id index))))))
|
||||
(st/emit!
|
||||
(dwsh/relocate-shapes #{child-id} id index)
|
||||
(se/event plugin-id (if (ctl/any-layout? shape) "add-layout-element" "add-element")
|
||||
:type (:type child-shape)
|
||||
:parent-type (:type shape)))))))
|
||||
|
||||
;; Only for frames
|
||||
:addFlexLayout
|
||||
@ -1006,7 +1015,9 @@
|
||||
(u/not-valid plugin-id :addFlexLayout "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(do (st/emit! (dwsl/create-layout-from-id id :flex :from-frame? true :calculate-params? false))
|
||||
(do (st/emit!
|
||||
(dwsl/create-layout-from-id id :flex :from-frame? true :calculate-params? false)
|
||||
(se/event plugin-id "create-layout" :layout "flex"))
|
||||
(flex/flex-layout-proxy plugin-id file-id page-id id)))))
|
||||
|
||||
:addGridLayout
|
||||
@ -1021,6 +1032,7 @@
|
||||
|
||||
:else
|
||||
(do (st/emit! (dwsl/create-layout-from-id id :grid :from-frame? true :calculate-params? false))
|
||||
(se/event plugin-id "create-layout" :layout "grid")
|
||||
(grid/grid-layout-proxy plugin-id file-id page-id id)))))
|
||||
|
||||
;; Make masks for groups
|
||||
@ -1035,7 +1047,9 @@
|
||||
(u/not-valid plugin-id :makeMask "Plugin doesn't have 'content:write' permission")
|
||||
|
||||
:else
|
||||
(st/emit! (dwg/mask-group #{id})))))
|
||||
(st/emit!
|
||||
(dwg/mask-group #{id})
|
||||
(se/event plugin-id "create-shape" :type "mask")))))
|
||||
|
||||
:removeMask
|
||||
(fn []
|
||||
@ -1224,8 +1238,10 @@
|
||||
(rx/map :body))))
|
||||
(rx/mapcat #(.arrayBuffer %))
|
||||
(rx/map #(js/Uint8Array. %))
|
||||
(rx/tap #(st/emit! (se/event plugin-id "export-shapes")))
|
||||
(rx/subs! resolve reject))))))))
|
||||
|
||||
|
||||
;; Interactions
|
||||
:addInteraction
|
||||
(fn [trigger action delay]
|
||||
@ -1238,7 +1254,9 @@
|
||||
|
||||
:else
|
||||
(let [index (-> (u/locate-shape file-id page-id id) (:interactions []) count)]
|
||||
(st/emit! (dwi/add-interaction page-id id interaction))
|
||||
(st/emit!
|
||||
(dwi/add-interaction page-id id interaction)
|
||||
(se/event plugin-id "add-interaction"))
|
||||
(interaction-proxy plugin-id file-id page-id id index)))))
|
||||
|
||||
:removeInteraction
|
||||
@ -1248,7 +1266,9 @@
|
||||
(u/not-valid plugin-id :removeInteraction interaction)
|
||||
|
||||
:else
|
||||
(st/emit! (dwi/remove-interaction {:id id} (obj/get interaction "$index")))))
|
||||
(st/emit!
|
||||
(dwi/remove-interaction {:id id} (obj/get interaction "$index"))
|
||||
(se/event plugin-id "remove-interaction"))))
|
||||
|
||||
;; Ruler guides
|
||||
:addRulerGuide
|
||||
@ -1275,11 +1295,12 @@
|
||||
board-pos (get frame axis)
|
||||
position (+ board-pos value)]
|
||||
(st/emit!
|
||||
(dwgu/update-guides
|
||||
{:id id
|
||||
:axis axis
|
||||
:position position
|
||||
:frame-id id}))
|
||||
(-> (dwgu/update-guides
|
||||
{:id id
|
||||
:axis axis
|
||||
:position position
|
||||
:frame-id id})
|
||||
(se/add-event plugin-id)))
|
||||
(rg/ruler-guide-proxy plugin-id file-id page-id id)))))
|
||||
|
||||
:removeRulerGuide
|
||||
@ -1293,7 +1314,8 @@
|
||||
|
||||
:else
|
||||
(let [guide (u/proxy->ruler-guide value)]
|
||||
(st/emit! (dwgu/remove-guide guide)))))
|
||||
(st/emit! (-> (dwgu/remove-guide guide)
|
||||
(se/add-event plugin-id))))))
|
||||
|
||||
:tokens
|
||||
{:this true
|
||||
@ -1313,17 +1335,18 @@
|
||||
{:enumerable false
|
||||
:schema [:tuple
|
||||
[:fn token-proxy?]
|
||||
[:maybe [:set [:and ::sm/keyword [:fn token-attr?]]]]]
|
||||
[:maybe [::sm/set [:and ::sm/keyword [:fn token-attr?]]]]]
|
||||
:fn (fn [token attrs]
|
||||
(let [token (u/locate-token file-id (obj/get token "$set-id") (obj/get token "$id"))
|
||||
kw-attrs (into #{} (map token-attr-plugin->token-attr attrs))]
|
||||
(if (some #(not (token-attr? %)) kw-attrs)
|
||||
(u/not-valid plugin-id :applyToken attrs)
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token token
|
||||
:attrs kw-attrs
|
||||
:shape-ids [id]
|
||||
:expand-with-children false})))))}
|
||||
(-> (dwta/toggle-token {:token token
|
||||
:attrs kw-attrs
|
||||
:shape-ids [id]
|
||||
:expand-with-children false})
|
||||
(se/add-event plugin-id))))))}
|
||||
|
||||
:isVariantHead
|
||||
(fn []
|
||||
@ -1349,7 +1372,8 @@
|
||||
(let [shape (u/locate-shape file-id page-id id)
|
||||
component (u/locate-library-component file-id (:component-id shape))]
|
||||
(when (and component (ctk/is-variant? component))
|
||||
(st/emit! (dwv/variants-switch {:shapes [shape] :pos pos :val value}))))))
|
||||
(st/emit! (-> (dwv/variants-switch {:shapes [shape] :pos pos :val value})
|
||||
(se/add-event plugin-id)))))))
|
||||
|
||||
:combineAsVariants
|
||||
(fn [ids]
|
||||
@ -1371,9 +1395,10 @@
|
||||
|
||||
(if valid?
|
||||
(let [variant-id (uuid/next)]
|
||||
(st/emit! (dwv/combine-as-variants
|
||||
ids
|
||||
{:trigger "plugin:combine-as-variants" :variant-id variant-id}))
|
||||
(st/emit! (-> (dwv/combine-as-variants
|
||||
ids
|
||||
{:trigger "plugin:combine-as-variants" :variant-id variant-id})
|
||||
(se/add-event plugin-id)))
|
||||
(shape-proxy plugin-id variant-id))
|
||||
|
||||
(u/not-valid plugin-id :ids "One of the components is not on the same page or is already a variant"))))))
|
||||
|
||||
@ -7,17 +7,34 @@
|
||||
(ns app.plugins.system-events
|
||||
(:require
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.store :as st]))
|
||||
[app.main.store :as st]
|
||||
[app.plugins.register :as r]))
|
||||
|
||||
;; Formats an event from the plugin system
|
||||
(defn event
|
||||
[plugin-id name & {:as props}]
|
||||
(let [plugin-data (get-in @st/state [:profile :props :plugins :data plugin-id])]
|
||||
(if (= plugin-id r/mcp-plugin-id)
|
||||
(-> props
|
||||
(assoc ::ev/name name)
|
||||
(assoc ::ev/origin "plugin")
|
||||
(assoc ::ev/context
|
||||
{:plugin-name (:name plugin-data)
|
||||
:plugin-url (:url plugin-data)})
|
||||
(ev/event))))
|
||||
(assoc ::ev/origin "mcp")
|
||||
(ev/event))
|
||||
|
||||
(let [plugin-data (r/get-plugin-data @st/state plugin-id)]
|
||||
(-> props
|
||||
(assoc ::ev/name name)
|
||||
(assoc ::ev/origin "plugin")
|
||||
(assoc ::ev/context
|
||||
{:plugin-name (:name plugin-data)
|
||||
:plugin-url (:url plugin-data)})
|
||||
(ev/event)))))
|
||||
|
||||
(defn add-event
|
||||
[event plugin-id]
|
||||
(let [plugin-data (r/get-plugin-data @st/state plugin-id)]
|
||||
(with-meta
|
||||
event
|
||||
(if (= plugin-id r/mcp-plugin-id)
|
||||
{::ev/origin "mcp"}
|
||||
{::ev/origin "plugin"
|
||||
::ev/context {:plugin-name (:name plugin-data)
|
||||
:plugin-url (:url plugin-data)}}))))
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.system-events :as se]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.object :as obj]
|
||||
[clojure.datafy :refer [datafy]]
|
||||
@ -49,8 +50,19 @@
|
||||
(get map:token-attr->token-attr-plugin k k))
|
||||
|
||||
(defn token-attr-plugin->token-attr
|
||||
"Resolve a plugin-side token attribute reference to its canonical
|
||||
internal keyword.
|
||||
|
||||
Accepts either a Clojure keyword (the canonical form, e.g. `:r1`,
|
||||
`:fill`) or a string (the natural shape that arrives from a JS plugin
|
||||
call such as `shape.applyToken(token, [\"fill\"])`). Converts strings
|
||||
to keywords first, then maps verbose plugin-side aliases (e.g.
|
||||
`:border-radius-top-left`) to their internal short form (e.g. `:r1`).
|
||||
Inputs that are already in canonical form (`:r1`, `:fill`, `\"fill\"`,
|
||||
…) pass through unchanged."
|
||||
[k]
|
||||
(get map:token-attr-plugin->token-attr k k))
|
||||
(let [k (cond-> k (string? k) keyword)]
|
||||
(get map:token-attr-plugin->token-attr k k)))
|
||||
|
||||
(defn applied-tokens-plugin->applied-tokens
|
||||
[value]
|
||||
@ -69,10 +81,11 @@
|
||||
(if (some #(not (token-attr? %)) attrs)
|
||||
(u/not-valid plugin-id :applyToSelected attrs)
|
||||
(st/emit!
|
||||
(dwta/toggle-token {:token token
|
||||
:attrs (into #{} (map token-attr-plugin->token-attr) attrs)
|
||||
:shape-ids shape-ids
|
||||
:expand-with-children false})))))
|
||||
(-> (dwta/toggle-token {:token token
|
||||
:attrs (into #{} (map token-attr-plugin->token-attr) attrs)
|
||||
:shape-ids shape-ids
|
||||
:expand-with-children false})
|
||||
(se/add-event plugin-id))))))
|
||||
|
||||
(defn- get-resolved-value
|
||||
[token tokens-tree]
|
||||
@ -112,7 +125,8 @@
|
||||
(ctob/get-tokens set-id)))
|
||||
:set
|
||||
(fn [_ value]
|
||||
(st/emit! (dwtl/update-token set-id id {:name value})))}
|
||||
(st/emit! (-> (dwtl/update-token set-id id {:name value})
|
||||
(se/add-event plugin-id))))}
|
||||
|
||||
:type
|
||||
{:this true
|
||||
@ -162,7 +176,8 @@
|
||||
:schema cfo/schema:token-description
|
||||
:set
|
||||
(fn [_ value]
|
||||
(st/emit! (dwtl/update-token set-id id {:description value})))}
|
||||
(st/emit! (-> (dwtl/update-token set-id id {:description value})
|
||||
(se/add-event :plugin-id))))}
|
||||
|
||||
:duplicate
|
||||
(fn []
|
||||
@ -175,24 +190,26 @@
|
||||
token' (ctob/make-token (-> (datafy token)
|
||||
(dissoc :id
|
||||
:modified-at)))]
|
||||
(st/emit! (dwtl/create-token set-id token'))
|
||||
(st/emit! (-> (dwtl/create-token set-id token')
|
||||
(se/add-event plugin-id)))
|
||||
(token-proxy plugin-id file-id set-id (:id token'))))
|
||||
|
||||
:remove
|
||||
(fn []
|
||||
(st/emit! (dwtl/delete-token set-id id)))
|
||||
(st/emit! (-> (dwtl/delete-token set-id id)
|
||||
(se/add-event plugin-id))))
|
||||
|
||||
:applyToShapes
|
||||
{:enumerable false
|
||||
:schema [:tuple
|
||||
[:vector [:fn shape-proxy?]]
|
||||
[:maybe [:set [:and ::sm/keyword [:fn token-attr?]]]]]
|
||||
[:maybe [::sm/set [:and ::sm/keyword [:fn token-attr?]]]]]
|
||||
:fn (fn [shapes attrs]
|
||||
(apply-token-to-shapes plugin-id file-id set-id id (map #(obj/get % "$id") shapes) attrs))}
|
||||
|
||||
:applyToSelected
|
||||
{:enumerable false
|
||||
:schema [:tuple [:maybe [:set [:and ::sm/keyword [:fn token-attr?]]]]]
|
||||
:schema [:tuple [:maybe [::sm/set [:and ::sm/keyword [:fn token-attr?]]]]]
|
||||
:fn (fn [attrs]
|
||||
(let [selected (get-in @st/state [:workspace-local :selected])]
|
||||
(apply-token-to-shapes plugin-id file-id set-id id selected attrs)))}))
|
||||
@ -312,7 +329,8 @@
|
||||
(get resolved-tokens (:name token))]
|
||||
|
||||
(if resolved-value
|
||||
(do (st/emit! (dwtl/create-token id token))
|
||||
(do (st/emit! (-> (dwtl/create-token id token)
|
||||
(se/add-event plugin-id)))
|
||||
(token-proxy plugin-id file-id id (:id token)))
|
||||
(do (u/not-valid plugin-id :addToken (str errors))
|
||||
nil))))}
|
||||
|
||||
82
frontend/test/frontend_tests/plugins/tokens_test.cljs
Normal file
82
frontend/test/frontend_tests/plugins/tokens_test.cljs
Normal file
@ -0,0 +1,82 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns frontend-tests.plugins.tokens-test
|
||||
(:require
|
||||
[app.plugins.tokens :as ptok]
|
||||
[cljs.test :as t :include-macros true]))
|
||||
|
||||
;; Regression coverage for issue #9162.
|
||||
;;
|
||||
;; Plugin code calling `shape.applyToken(token, ["fill"])` or
|
||||
;; `token.applyToShapes([rect], ["fill"])` from JavaScript supplies a JS
|
||||
;; array of strings. Penpot's plugin proxies expect a Clojure set of
|
||||
;; keywords. Two coupled defects made these calls silently no-op (or, with
|
||||
;; `throwValidationErrors` enabled, throw a "check error"):
|
||||
;;
|
||||
;; 1. `token-attr-plugin->token-attr` only consulted its alias map when
|
||||
;; the input was already a keyword — string inputs like "fill" or
|
||||
;; "border-radius-top-left" fell through to the identity branch
|
||||
;; unchanged, so the downstream `cto/token-attr?` predicate (which
|
||||
;; checks against a set of keywords) returned false.
|
||||
;; 2. The `applyToken` / `applyToShapes` / `applyToSelected` schemas used
|
||||
;; plain `[:set ...]`, which does not have a `:decode/json`
|
||||
;; transformer for the JS array → Clojure set coercion. Penpot's
|
||||
;; custom `[::sm/set ...]` does. Switching to the registered set type
|
||||
;; lets the standard JSON decoder pipeline turn the JS argument into
|
||||
;; a set of strings, after which the `[:and ::sm/keyword [:fn
|
||||
;; token-attr?]]` element schema coerces each string to a keyword and
|
||||
;; validates it.
|
||||
;;
|
||||
;; These helper-level tests pin the string-friendly conversion contract;
|
||||
;; the schema-level fix is covered by the existing plugin integration
|
||||
;; suite that exercises `applyToken` end-to-end.
|
||||
|
||||
(t/deftest token-attr-plugin->token-attr-passes-canonical-form-through
|
||||
;; Both already-canonical short names and unaliased names pass through
|
||||
;; unchanged.
|
||||
(t/is (= :fill (ptok/token-attr-plugin->token-attr :fill)))
|
||||
(t/is (= :stroke-color (ptok/token-attr-plugin->token-attr :stroke-color)))
|
||||
(t/is (= :r1 (ptok/token-attr-plugin->token-attr :r1)))
|
||||
(t/is (= :p2 (ptok/token-attr-plugin->token-attr :p2))))
|
||||
|
||||
(t/deftest token-attr-plugin->token-attr-resolves-verbose-plugin-aliases
|
||||
;; Plugin-side verbose names (e.g. `:border-radius-top-left`) map to
|
||||
;; their canonical short internal form (`:r1`) so plugin authors can
|
||||
;; spell the corner explicitly without the engine having to know both.
|
||||
(t/is (= :r1 (ptok/token-attr-plugin->token-attr :border-radius-top-left)))
|
||||
(t/is (= :r2 (ptok/token-attr-plugin->token-attr :border-radius-top-right)))
|
||||
(t/is (= :r3 (ptok/token-attr-plugin->token-attr :border-radius-bottom-right)))
|
||||
(t/is (= :r4 (ptok/token-attr-plugin->token-attr :border-radius-bottom-left)))
|
||||
(t/is (= :p1 (ptok/token-attr-plugin->token-attr :padding-top-left)))
|
||||
(t/is (= :m3 (ptok/token-attr-plugin->token-attr :margin-bottom-right))))
|
||||
|
||||
(t/deftest token-attr-plugin->token-attr-coerces-string-input
|
||||
;; This is the actual regression — JS plugin calls supply strings.
|
||||
(t/is (= :fill (ptok/token-attr-plugin->token-attr "fill")))
|
||||
(t/is (= :stroke-color (ptok/token-attr-plugin->token-attr "stroke-color")))
|
||||
;; Verbose plugin aliases work via the string path too.
|
||||
(t/is (= :r1 (ptok/token-attr-plugin->token-attr "border-radius-top-left")))
|
||||
(t/is (= :m3 (ptok/token-attr-plugin->token-attr "margin-bottom-right"))))
|
||||
|
||||
(t/deftest token-attr?-accepts-keyword-input
|
||||
(t/is (true? (boolean (ptok/token-attr? :fill))))
|
||||
(t/is (true? (boolean (ptok/token-attr? :stroke-color))))
|
||||
(t/is (true? (boolean (ptok/token-attr? :r1))))
|
||||
(t/is (true? (boolean (ptok/token-attr? :p2)))))
|
||||
|
||||
(t/deftest token-attr?-accepts-string-input
|
||||
;; Same JS-array-of-strings reproducer as the issue, exercised at the
|
||||
;; predicate layer the plugin schemas call into.
|
||||
(t/is (true? (boolean (ptok/token-attr? "fill"))))
|
||||
(t/is (true? (boolean (ptok/token-attr? "stroke-color"))))
|
||||
(t/is (true? (boolean (ptok/token-attr? "r1"))))
|
||||
(t/is (true? (boolean (ptok/token-attr? "m3")))))
|
||||
|
||||
(t/deftest token-attr?-rejects-unknown-input
|
||||
(t/is (false? (boolean (ptok/token-attr? :not-a-real-attr))))
|
||||
(t/is (false? (boolean (ptok/token-attr? "not-a-real-attr"))))
|
||||
(t/is (false? (boolean (ptok/token-attr? nil)))))
|
||||
@ -19,6 +19,7 @@
|
||||
[frontend-tests.logic.pasting-in-containers-test]
|
||||
[frontend-tests.main-errors-test]
|
||||
[frontend-tests.plugins.context-shapes-test]
|
||||
[frontend-tests.plugins.tokens-test]
|
||||
[frontend-tests.svg-fills-test]
|
||||
[frontend-tests.tokens.import-export-test]
|
||||
[frontend-tests.tokens.logic.token-actions-test]
|
||||
@ -61,6 +62,7 @@
|
||||
'frontend-tests.logic.groups-test
|
||||
'frontend-tests.logic.pasting-in-containers-test
|
||||
'frontend-tests.plugins.context-shapes-test
|
||||
'frontend-tests.plugins.tokens-test
|
||||
'frontend-tests.svg-fills-test
|
||||
'frontend-tests.tokens.import-export-test
|
||||
'frontend-tests.tokens.logic.token-actions-test
|
||||
|
||||
@ -386,6 +386,9 @@ For many tasks, it can be critical to visually inspect the design. Remember to u
|
||||
* When transferring styles from a Penpot design to code, make sure that you strictly adhere to the design.
|
||||
NEVER make assumptions about missing values and don't get overly creative (e.g. don't pick your own colours and stick to
|
||||
non-creative defaults such as white/black if you are lacking information).
|
||||
* When creating new designs,
|
||||
- ensure a clean internal structure by applying flex and grid layouts when appropriate
|
||||
- ensure proper semantic naming of elements.
|
||||
|
||||
# Revising Designs
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user