diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 784e52484..3d2098712 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -384,8 +384,10 @@ f.revn, f.vern, f.is_shared, - ft.media_id AS thumbnail_id + ft.media_id AS thumbnail_id, + p.team_id from file as f + inner join project as p on (p.id = f.project_id) left join file_thumbnail as ft on (ft.file_id = f.id and ft.revn = f.revn and ft.deleted_at is null) @@ -539,7 +541,8 @@ f.modified_at, f.name, f.is_shared, - ft.media_id + ft.media_id, + p.team_id from file as f inner join project as p on (p.id = f.project_id) left join file_thumbnail as ft on (ft.file_id = f.id and ft.revn = f.revn and ft.deleted_at is null) @@ -686,7 +689,8 @@ f.name, f.is_shared, ft.media_id AS thumbnail_id, - row_number() over w as row_num + row_number() over w as row_num, + p.team_id from file as f inner join project as p on (p.id = f.project_id) left join file_thumbnail as ft on (ft.file_id = f.id diff --git a/docs/img/styling/color-picker-gradient.webp b/docs/img/styling/color-picker-gradient.webp new file mode 100644 index 000000000..eec479e70 Binary files /dev/null and b/docs/img/styling/color-picker-gradient.webp differ diff --git a/docs/user-guide/styling/index.njk b/docs/user-guide/styling/index.njk index 928b4d351..47b3d9df8 100644 --- a/docs/user-guide/styling/index.njk +++ b/docs/user-guide/styling/index.njk @@ -51,13 +51,24 @@ title: 06· Styling
  1. Eyedropper - Allows you to pick any color of the objects at the viewport.
  2. Color profiles - Select between RGB, the Harmony Wheel or HSV.
  3. -
  4. Color type - Solid, linear gradient, radial gradient or image.
  5. +
  6. Color type - Solid, gradient, or image.
  7. Sliders - Easily manage settings like brightness, saturation or opacity.
  8. Values - Set precise color values of red(R), green(G), blue(B) and transparency(A).
  9. Libraries - Switch between recent colors and libraries.
  10. Color palette - A quick launcher of the palette with the selected library.
+

Gradients

+

You can apply gradient fills to layers. To do that select the Gradient type at the color picker.

+
+ Gradient +
+

You can choose between two types of gradients:

+ +

Color palette

The color palette allows you to have a selected color library in plain sight.

diff --git a/frontend/playwright/data/workspace/get-file-10113.json b/frontend/playwright/data/workspace/get-file-10113.json new file mode 100644 index 000000000..c85e21966 --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-10113.json @@ -0,0 +1,115 @@ +{ + "~:features": { + "~#set": [ + "layout/grid", + "fdata/pointer-map", + "fdata/objects-map", + "components/v2", + "fdata/shape-data-type" + ] + }, + "~:permissions": { + "~:type": "~:membership", + "~:is-owner": true, + "~:is-admin": true, + "~:can-edit": true, + "~:can-read": true, + "~:is-logged": true + }, + "~:has-media-trimmed": false, + "~:comment-thread-seqn": 0, + "~:name": "10113 - Emtpy lib", + "~:revn": 1, + "~:modified-at": "~m1739365936352", + "~:vern": 0, + "~:id": "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2e", + "~:is-shared": false, + "~:migrations": { + "~#ordered-set": [ + "legacy-2", + "legacy-3", + "legacy-5", + "legacy-6", + "legacy-7", + "legacy-8", + "legacy-9", + "legacy-10", + "legacy-11", + "legacy-12", + "legacy-13", + "legacy-14", + "legacy-16", + "legacy-17", + "legacy-18", + "legacy-19", + "legacy-25", + "legacy-26", + "legacy-27", + "legacy-28", + "legacy-29", + "legacy-31", + "legacy-32", + "legacy-33", + "legacy-34", + "legacy-36", + "legacy-37", + "legacy-38", + "legacy-39", + "legacy-40", + "legacy-41", + "legacy-42", + "legacy-43", + "legacy-44", + "legacy-45", + "legacy-46", + "legacy-47", + "legacy-48", + "legacy-49", + "legacy-50", + "legacy-51", + "legacy-52", + "legacy-53", + "legacy-54", + "legacy-55", + "legacy-56", + "legacy-57", + "legacy-59", + "legacy-62", + "legacy-65", + "legacy-66", + "legacy-67" + ] + }, + "~:version": 67, + "~:project-id": "~u1ad2931c-eb80-8098-8005-b86c1d9d26c2", + "~:created-at": "~m1739365911709", + "~:data": { + "~:pages": [ + "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2f" + ], + "~:pages-index": { + "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2f": { + "~#penpot/pointer": [ + "~u5b7ebd2b-2907-80db-8005-b9d67c21cbd3", + { + "~:created-at": "~m1739365911687" + } + ] + } + }, + "~:id": "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2e", + "~:options": { + "~:components-v2": true + }, + "~:colors": { + "~u84a1567d-3f0f-804e-8005-b9d6907e3c8a": { + "~:path": "", + "~:color": "#0087ff", + "~:name": "#0087ff", + "~:modified-at": "~m1739365936355", + "~:opacity": 1, + "~:id": "~u84a1567d-3f0f-804e-8005-b9d6907e3c8a" + } + } + } +} diff --git a/frontend/playwright/data/workspace/get-file-fragment-10113.json b/frontend/playwright/data/workspace/get-file-fragment-10113.json new file mode 100644 index 000000000..c37908a60 --- /dev/null +++ b/frontend/playwright/data/workspace/get-file-fragment-10113.json @@ -0,0 +1,101 @@ +{ + "~:id": "~u5b7ebd2b-2907-80db-8005-b9d67c21cbd3", + "~:file-id": "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2e", + "~:created-at": "~m1739365911680", + "~:data": { + "~:options": {}, + "~:objects": { + "~u00000000-0000-0000-0000-000000000000": { + "~#shape": { + "~:y": 0, + "~:hide-fill-on-export": false, + "~:transform": { + "~#matrix": { + "~:a": 1.0, + "~:b": 0.0, + "~:c": 0.0, + "~:d": 1.0, + "~:e": 0.0, + "~:f": 0.0 + } + }, + "~:rotation": 0, + "~:name": "Root Frame", + "~:width": 0.01, + "~:type": "~:frame", + "~:points": [ + { + "~#point": { + "~:x": 0.0, + "~:y": 0.0 + } + }, + { + "~#point": { + "~:x": 0.01, + "~:y": 0.0 + } + }, + { + "~#point": { + "~:x": 0.01, + "~:y": 0.01 + } + }, + { + "~#point": { + "~:x": 0.0, + "~:y": 0.01 + } + } + ], + "~:r2": 0, + "~:proportion-lock": false, + "~:transform-inverse": { + "~#matrix": { + "~:a": 1.0, + "~:b": 0.0, + "~:c": 0.0, + "~:d": 1.0, + "~:e": 0.0, + "~:f": 0.0 + } + }, + "~:r3": 0, + "~:r1": 0, + "~:id": "~u00000000-0000-0000-0000-000000000000", + "~:parent-id": "~u00000000-0000-0000-0000-000000000000", + "~:frame-id": "~u00000000-0000-0000-0000-000000000000", + "~:strokes": [], + "~:x": 0, + "~:proportion": 1.0, + "~:r4": 0, + "~:selrect": { + "~#rect": { + "~:x": 0, + "~:y": 0, + "~:width": 0.01, + "~:height": 0.01, + "~:x1": 0, + "~:y1": 0, + "~:x2": 0.01, + "~:y2": 0.01 + } + }, + "~:fills": [ + { + "~:fill-color": "#FFFFFF", + "~:fill-opacity": 1 + } + ], + "~:flip-x": null, + "~:height": 0.01, + "~:flip-y": null, + "~:shapes": [] + } + } + }, + "~:id": "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2f", + "~:name": "Page 1" + } +} \ No newline at end of file diff --git a/frontend/playwright/data/workspace/get-team-shared-files-empty.json b/frontend/playwright/data/workspace/get-team-shared-files-empty.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/frontend/playwright/data/workspace/get-team-shared-files-empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/frontend/playwright/data/workspace/set-file-shared-10113.json b/frontend/playwright/data/workspace/set-file-shared-10113.json new file mode 100644 index 000000000..9ff97cb34 --- /dev/null +++ b/frontend/playwright/data/workspace/set-file-shared-10113.json @@ -0,0 +1,5 @@ +{ + "~:id": "~u5b7ebd2b-2907-80db-8005-b9d67c20cf2e", + "~:name": "10113 - Emtpy lib", + "~:is-shared": true +} diff --git a/frontend/playwright/ui/pages/WorkspacePage.js b/frontend/playwright/ui/pages/WorkspacePage.js index 20b694f92..cdc6e2df8 100644 --- a/frontend/playwright/ui/pages/WorkspacePage.js +++ b/frontend/playwright/ui/pages/WorkspacePage.js @@ -227,7 +227,7 @@ export class WorkspacePage extends BaseWebSocketPage { } async openLibrariesModal(clickOptions = {}) { - await this.sidebar.getByText("Libraries").click(clickOptions); + await this.sidebar.getByTestId("libraries").click(clickOptions); await expect(this.librariesModal).toBeVisible(); } diff --git a/frontend/playwright/ui/specs/workspace-shared-library.spec.js b/frontend/playwright/ui/specs/workspace-shared-library.spec.js index 89c53cb7c..eaef180ae 100644 --- a/frontend/playwright/ui/specs/workspace-shared-library.spec.js +++ b/frontend/playwright/ui/specs/workspace-shared-library.spec.js @@ -72,3 +72,41 @@ test("Bug 9056 - 'More info' doesn't open the update tab", async ({ page }) => { /library updates/i, ); }); + +test("Bug 10113 - Empty library modal for non-empty library", async ({ + page, +}) => { + const workspace = new WorkspacePage(page); + + await workspace.setupEmptyFile(page); + await workspace.mockRPC(/get\-file\?/, "workspace/get-file-10113.json"); + await workspace.mockRPC( + "get-file-fragment?file-id=*&fragment-id=*", + "workspace/get-file-fragment-10113.json", + ); + await workspace.mockRPC(/get\-file\?/, "workspace/get-file-10113.json"); + await workspace.mockRPC( + "get-team-shared-files?team-id=*", + "workspace/get-team-shared-files-empty.json", + ); + await workspace.mockRPC( + "set-file-shared", + "workspace/set-file-shared-10113.json", + ); + + await workspace.goToWorkspace({ + fileId: "5b7ebd2b-2907-80db-8005-b9d67c20cf2e", + pageId: "5b7ebd2b-2907-80db-8005-b9d67c20cf2f", + }); + + await workspace.clickAssets(); + await workspace.openLibrariesModal(); + + await workspace.librariesModal + .getByRole("button", { name: "Publish" }) + .click(); + + await expect( + workspace.page.getByText("Publish empty library"), + ).not.toBeVisible(); +}); diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs index cd8e73186..064d1901d 100644 --- a/frontend/src/app/main/data/common.cljs +++ b/frontend/src/app/main/data/common.cljs @@ -84,7 +84,7 @@ :controls :inline-actions :type :inline :level level - :accept {:label (tr "Refresh") + :accept {:label (tr "labels.refresh") :callback force-reload!} :tag :notification)) diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index 5e637cc0f..acd082a20 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -16,6 +16,7 @@ [app.main.data.common :as dcm] [app.main.data.event :as ev] [app.main.data.fonts :as df] + [app.main.data.helpers :as dsh] [app.main.data.modal :as modal] [app.main.data.websocket :as dws] [app.main.features :as features] @@ -248,15 +249,18 @@ (ptk/reify ::create-project ptk/WatchEvent (watch [_ state _] - (let [unames (cfh/get-used-names (get state :projects)) + (let [team-id (:current-team-id state) + projects (dsh/lookup-team-projects state team-id) + unames (cfh/get-used-names projects) base-name (tr "dashboard.new-project-prefix") - name (cfh/generate-unique-name base-name unames :immediate-suffix? true) - team-id (:current-team-id state) - params {:name name - :team-id team-id} + name (cfh/generate-unique-name base-name unames :immediate-suffix? true) + team-id (:current-team-id state) + params {:name name + :team-id team-id} {:keys [on-success on-error] :or {on-success identity - on-error rx/throw}} (meta params)] + on-error rx/throw}} + (meta params)] (->> (rp/cmd! :create-project params) (rx/tap on-success) (rx/map project-created) @@ -465,10 +469,11 @@ ptk/UpdateEvent (update [_ state] - (-> state - (assoc-in [:files id] file) - (assoc-in [:recent-files id] file) - (update-in [:projects project-id :count] inc))))) + (let [file (dissoc file :data)] + (-> state + (assoc-in [:files id] file) + (assoc-in [:recent-files id] file) + (update-in [:projects project-id :count] inc)))))) (defn create-file [{:keys [project-id name] :as params}] @@ -482,8 +487,11 @@ (watch [it state _] (let [{:keys [on-success on-error] :or {on-success identity - on-error rx/throw}} (meta params) - unames (cfh/get-used-names (get state :files)) + on-error rx/throw}} + (meta params) + + files (dsh/lookup-team-files state) + unames (cfh/get-used-names files) base-name (tr "dashboard.new-file-prefix") name (or name (cfh/generate-unique-name base-name unames :immediate-suffix? true)) @@ -597,10 +605,10 @@ pparams (:path-params route) in-project? (contains? pparams :project-id) name (if in-project? - (let [files (get state :files) + (let [files (dsh/lookup-team-files state team-id) unames (cfh/get-used-names files)] (cfh/generate-unique-name (tr "dashboard.new-file-prefix") unames :immediate-suffix? true)) - (let [projects (get state :projects) + (let [projects (dsh/lookup-team-projects state team-id) unames (cfh/get-used-names projects)] (cfh/generate-unique-name (tr "dashboard.new-project-prefix") unames :immediate-suffix? true))) params (if in-project? diff --git a/frontend/src/app/main/data/helpers.cljs b/frontend/src/app/main/data/helpers.cljs index b104af0dc..279e3e0b2 100644 --- a/frontend/src/app/main/data/helpers.cljs +++ b/frontend/src/app/main/data/helpers.cljs @@ -168,3 +168,21 @@ [state] (when-let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])] (gpt/point (+ x (/ width 2)) (+ y (/ height 2))))) + +(defn lookup-team-files + ([state] + (lookup-team-files state (:current-team-id state))) + ([state team-id] + (->> state + :files + (filter #(= team-id (:team-id (val %)))) + (into {})))) + +(defn lookup-team-projects + ([state] + (lookup-team-projects (:current-team-id state))) + ([state team-id] + (->> state + :projects + (filter #(= team-id (:team-id (val %)))) + (into {})))) diff --git a/frontend/src/app/main/data/team.cljs b/frontend/src/app/main/data/team.cljs index 7ffb46463..5ff7cf097 100644 --- a/frontend/src/app/main/data/team.cljs +++ b/frontend/src/app/main/data/team.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.exceptions :as ex] [app.common.logging :as log] [app.common.schema :as sm] [app.common.types.team :as ctt] @@ -118,8 +119,10 @@ (let [team-id (:current-team-id state) teams (get state :teams) team (get teams team-id)] - (rx/of (set-current-team team) - (fetch-members)))))) + (if (not team) + (rx/throw (ex/error :type :authentication)) + (rx/of (set-current-team team) + (fetch-members))))))) (defn initialize-team [team-id] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 319c7f4ea..a23c08447 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -319,8 +319,6 @@ ptk/UpdateEvent (update [_ state] (-> state - (dissoc :files) - (dissoc :workspace-ready) (assoc :recent-colors (:recent-colors storage/user)) (assoc :recent-fonts (:recent-fonts storage/user)) (assoc :current-file-id file-id) @@ -395,12 +393,9 @@ (dissoc :current-file-id :workspace-editor-state - :files :workspace-media-objects :workspace-persistence :workspace-presence - :workspace-tokens - :workspace-ready :workspace-undo) (update :workspace-global dissoc :read-only?) (assoc-in [:workspace-global :options-mode] :design))) @@ -428,18 +423,18 @@ (defmethod ptk/resolve ::reload-current-file [_ _] (reload-current-file)) (defn initialize-page - [page-id] - (assert (uuid? page-id) "expected valid uuid for `page-id`") + [file-id page-id] + (assert (uuid? file-id) "expected valid uuid for `file-id`") (ptk/reify ::initialize-page ptk/UpdateEvent (update [_ state] - (if-let [{:keys [id] :as page} (dsh/lookup-page state page-id)] + (if-let [page (dsh/lookup-page state file-id page-id)] ;; we maintain a cache of page state for user convenience with the exception of the ;; selection; when user abandon the current page, the selection is lost - (let [local (dm/get-in state [:workspace-cache id] default-workspace-local)] + (let [local (dm/get-in state [:workspace-cache [file-id page-id]] default-workspace-local)] (-> state - (assoc :current-page-id id) + (assoc :current-page-id page-id) (assoc :workspace-local (assoc local :selected (d/ordered-set))) (assoc :workspace-trimmed-page (dm/select-keys page [:id :name])) @@ -451,24 +446,25 @@ ptk/WatchEvent (watch [_ state _] - (if (dsh/lookup-page state page-id) - (let [file-id (:current-file-id state)] - (rx/of (preload-data-uris page-id) - (dwth/watch-state-changes file-id page-id) - (dwl/watch-component-changes))) - (rx/of (dcm/go-to-workspace)))))) + (if (dsh/lookup-page state file-id page-id) + (rx/of (preload-data-uris page-id) + (dwth/watch-state-changes file-id page-id) + (dwl/watch-component-changes)) + (rx/of (dcm/go-to-workspace :file-id file-id ::rt/replace true)))))) (defn finalize-page - [page-id] + [file-id page-id] + (assert (uuid? file-id) "expected valid uuid for `file-id`") (assert (uuid? page-id) "expected valid uuid for `page-id`") + (ptk/reify ::finalize-page ptk/UpdateEvent (update [_ state] (let [local (-> (:workspace-local state) (dissoc :edition :edit-path :selected)) - exit? (not= :workspace (dm/get-in state [:route :data :name])) + exit? (not= :workspace (rt/lookup-name state)) state (-> state - (update :workspace-cache assoc page-id local) + (update :workspace-cache assoc [file-id page-id] local) (dissoc :current-page-id :workspace-local :workspace-trimmed-page diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 95d1df358..2cf8ad292 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -741,12 +741,12 @@ redirect-to-page (fn [page-id shape-id] (rx/merge - (rx/of (dcm/go-to-workspace :page-id page-id)) (->> stream - (rx/filter (ptk/type? ::initialize-page)) + (rx/filter (ptk/type? ::dw/initialize-page)) (rx/take 1) (rx/observe-on :async) - (rx/mapcat (fn [_] (select-and-zoom shape-id))))))] + (rx/mapcat (fn [_] (select-and-zoom shape-id)))) + (rx/of (dcm/go-to-workspace :page-id page-id))))] (when-let [component (dm/get-in data [:components id])] (let [page-id (:main-instance-page component) diff --git a/frontend/src/app/main/router.cljs b/frontend/src/app/main/router.cljs index 58e421983..e4c3b16a1 100644 --- a/frontend/src/app/main/router.cljs +++ b/frontend/src/app/main/router.cljs @@ -120,6 +120,11 @@ ([id params & {:as options}] (navigate id params options))) +(defn lookup-name + [state] + (dm/get-in state [:route :data :name])) + +;; FIXME: rename to lookup-params (defn get-params [state] (dm/get-in state [:route :params :query])) diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 328f2b3e4..f363ea878 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -127,7 +127,6 @@ {::mf/props :obj ::mf/private true} [{:keys [team-id children]}] - (mf/with-effect [team-id] (st/emit! (dtm/initialize-team team-id)) (fn [] diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index c41e4273f..6e0d1da30 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -237,9 +237,14 @@ (str/last-index-of (subs node-text 0 offset) "@") mention-text - (subs node-text current-at-symbol)] + (subs node-text current-at-symbol) - (if (re-matches #"@\w*" mention-text) + at-symbol-inside-word? + (and (> current-at-symbol 0) + (str/word? (str/slice node-text (- current-at-symbol 1) current-at-symbol)))] + + (if (and (not at-symbol-inside-word?) + (re-matches #"@\w*" mention-text)) (do (reset! cur-mention mention-text) (rx/push! mentions-s {:type :display-mentions}) @@ -305,6 +310,17 @@ (when (fn? on-change) (on-change (parse-nodes node)))))))) + handle-insert-at-symbol + (mf/use-fn + (fn [] + (let [node (mf/ref-val local-ref) [span-node] (current-text-node node)] + (when span-node + (let [node-text (dom/get-text span-node) + at-symbol (if (blank-content? node-text) "@" " @")] + + (dom/set-html! span-node (str/concat node-text at-symbol)) + (wapi/set-cursor-after! span-node)))))) + handle-key-down (mf/use-fn (mf/deps on-esc on-ctrl-enter handle-select handle-input) @@ -386,6 +402,8 @@ (case type :insert-mention (handle-insert-mention data) + :insert-at-symbol + (handle-insert-at-symbol) nil)))))) @@ -521,15 +539,25 @@ {::mf/props :obj ::mf/private true} [] - (let [mentions-s (mf/use-ctx mentions-context) + (let [mentions-s (mf/use-ctx mentions-context) display-mentions* (mf/use-state false) - handle-mouse-down + handle-pointer-down (mf/use-fn + (mf/deps @display-mentions*) (fn [event] (dom/prevent-default event) (dom/stop-propagation event) - (rx/push! mentions-s {:type :display-mentions})))] + (if @display-mentions* + (rx/push! mentions-s {:type :hide-mentions}) + (rx/push! mentions-s {:type :insert-at-symbol})))) + + handle-key-down + (mf/use-fn + (mf/deps @display-mentions*) + (fn [event] + (when (or (kbd/enter? event) (kbd/space? event)) + (handle-pointer-down event))))] (mf/use-effect (fn [] @@ -545,8 +573,9 @@ [:> icon-button* {:variant "ghost" - :aria-label (tr "labels.options") - :on-pointer-down handle-mouse-down + :aria-label (tr "labels.mention") + :on-pointer-down handle-pointer-down + :on-key-down handle-key-down :icon-class (stl/css-case :open-mentions-button true :is-toggled @display-mentions*) :icon "at"}])) diff --git a/frontend/src/app/main/ui/comments.scss b/frontend/src/app/main/ui/comments.scss index 70fd5b793..8dda4e806 100644 --- a/frontend/src/app/main/ui/comments.scss +++ b/frontend/src/app/main/ui/comments.scss @@ -255,7 +255,6 @@ } .open-mentions-button { - cursor: pointer; stroke: none; fill: var(--color-foreground-secondary); diff --git a/frontend/src/app/main/ui/settings/access_tokens.cljs b/frontend/src/app/main/ui/settings/access_tokens.cljs index b555e47e5..198165076 100644 --- a/frontend/src/app/main/ui/settings/access_tokens.cljs +++ b/frontend/src/app/main/ui/settings/access_tokens.cljs @@ -149,7 +149,6 @@ [:input {:type "text" :value (:token created "") :class (stl/css :custom-input-token) - :placeholder (tr "modals.create-access-token.token") :read-only true}] [:button {:title (tr "modals.create-access-token.copy-token") :class (stl/css :copy-btn) diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index a169ae616..24bf92e2e 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -9,7 +9,6 @@ (:require [app.common.data.macros :as dm] [app.main.data.common :as dcm] - [app.main.data.helpers :as dsh] [app.main.data.persistence :as dps] [app.main.data.plugins :as dpl] [app.main.data.workspace :as dw] @@ -43,13 +42,6 @@ [okulary.core :as l] [rumext.v2 :as mf])) -(defn- make-workspace-ready-ref - [file-id] - (l/derived (fn [state] - (and (= file-id (:workspace-ready state)) - (some? (dsh/lookup-file-data state file-id)))) - st/state)) - (mf/defc workspace-content* {::mf/private true} [{:keys [file layout page wglobal]}] @@ -138,22 +130,18 @@ key (events/listen globals/window "blur" focus-out)] (partial events/unlistenByKey key))) - (mf/with-effect [page-id] - (if (some? page-id) - (st/emit! (dw/initialize-page page-id)) - (st/emit! (dcm/go-to-workspace ::rt/replace true))) - + (mf/with-effect [file page-id] + (st/emit! (dw/initialize-page (:id file) page-id)) (fn [] - (when (some? page-id) - (st/emit! (dw/finalize-page page-id))))) + (when page-id + (st/emit! (dw/finalize-page (:id file) page-id))))) (if (some? page) [:> workspace-content* {:file file :page page :wglobal wglobal :layout layout}] - [:& workspace-loader*]))) - + [:> workspace-loader*]))) (def ^:private ref:file-without-data (l/derived (fn [file] @@ -181,10 +169,6 @@ read-only? (mf/deref refs/workspace-read-only?) read-only? (or read-only? (not (:can-edit permissions))) - ready* (mf/with-memo [file-id] - (make-workspace-ready-ref file-id)) - ready? (mf/deref ready*) - design-tokens? (features/use-feature "design-tokens/v1") background-color (:background-color wglobal)] @@ -207,6 +191,10 @@ (st/emit! ::dps/force-persist (dw/finalize-workspace file-id)))) + (mf/with-effect [file page-id] + (when-not page-id + (st/emit! (dcm/go-to-workspace :file-id file-id ::rt/replace true)))) + [:> (mf/provider ctx/current-project-id) {:value project-id} [:> (mf/provider ctx/current-file-id) {:value file-id} [:> (mf/provider ctx/current-page-id) {:value page-id} @@ -219,9 +207,10 @@ :touch-action "none"}} [:> context-menu*] - (if ^boolean ready? - [:> workspace-page* {:page-id page-id - :file file - :wglobal wglobal - :layout layout}] + (if (some? file) + [:> workspace-page* + {:page-id page-id + :file file + :wglobal wglobal + :layout layout}] [:> workspace-loader*])]]]]]]])) diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index ce1daca56..5a07a1a25 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -14,7 +14,6 @@ [app.common.types.file :as ctf] [app.common.types.typographies-list :as ctyl] [app.common.uuid :as uuid] - [app.config :as cf] [app.main.data.dashboard :as dd] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] @@ -176,15 +175,7 @@ (defn- empty-library? "Check if currentt library summary has elements or not" [summary] - (let [colors (or (-> summary :colors :count) 0) - components (or (-> summary :components :count) 0) - media (or (-> summary :media :count) 0) - typographies (or (-> summary :typographies :count) 0)] - - (and (zero? colors) - (zero? components) - (zero? media) - (zero? typographies)))) + (boolean (:is-empty summary))) (mf/defc libraries-tab* {::mf/props :obj @@ -362,7 +353,7 @@ (nil? shared-libraries) (tr "workspace.libraries.loading") - (and (str/empty? search-term) (cf/external-feature-flag "templates-03" "test")) + (str/empty? search-term) [:* [:div {:class (stl/css :sample-libraries-info)} (tr "workspace.libraries.empty.no-libraries") @@ -377,19 +368,6 @@ {:library library :importing importing*}])]] - (str/empty? search-term) - [:* - [:span {:class (stl/css :empty-state-icon)} - library-icon] - (tr "workspace.libraries.no-shared-libraries-available") - (when (cf/external-feature-flag "templates-01" "test") - [:div {:class (stl/css :templates-info)} - (tr "workspace.libraries.more-templates") - [:a {:target "_blank" - :class (stl/css :templates-info-link) - :href "https://penpot.app/libraries-templates"} - (tr "workspace.libraries.more-templates-link")]])] - :else (tr "workspace.libraries.no-matches-for" search-term))]))]])) diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss index a1df227fe..41a3747dd 100644 --- a/frontend/src/app/main/ui/workspace/libraries.scss +++ b/frontend/src/app/main/ui/workspace/libraries.scss @@ -326,16 +326,6 @@ padding: $s-0 $s-16; } -.templates-info { - color: var(--color-accent-primary); -} - -.templates-info-link { - color: var(--color-accent-primary); - text-decoration: underline; - font-weight: $fw400; -} - .sample-libraries-info { display: flex; flex-direction: column; diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 893ac6317..10973c9a5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -8,7 +8,6 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] - [app.config :as cf] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] [app.main.data.workspace.assets :as dwa] @@ -92,12 +91,6 @@ reverse-sort? (= :desc ordering) num-libs (count (mf/deref refs/libraries)) - show-templates-04-test1? - (and (cf/external-feature-flag "templates-04" "test1") (zero? num-libs)) - - show-templates-04-test2? - (and (cf/external-feature-flag "templates-04" "test2") (zero? num-libs)) - toggle-ordering (mf/use-fn (mf/deps ordering) @@ -166,18 +159,12 @@ [:article {:class (stl/css :assets-bar)} [:div {:class (stl/css :assets-header)} (when-not ^boolean read-only? - (cond - show-templates-04-test1? - [:button {:class (stl/css :libraries-button) - :on-click show-libraries-dialog - :data-testid "libraries"} - (tr "workspace.assets.add-library")] - show-templates-04-test2? + (if (= num-libs 1) [:button {:class (stl/css :add-library-button) :on-click show-libraries-dialog :data-testid "libraries"} (tr "workspace.assets.add-library")] - :else + [:button {:class (stl/css :libraries-button) :on-click show-libraries-dialog :data-testid "libraries"} diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index bef71e37e..15f81726c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -534,7 +534,7 @@ :on-ungroup on-ungroup :on-context-menu on-context-menu :selected-full selected-full - :local ^boolean is-local}]) + :is-local ^boolean is-local}]) [:& cmm/assets-context-menu {:on-close on-close-menu diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs index e223622b8..c3c2b68de 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs @@ -77,12 +77,12 @@ [:& radio-button {:icon i/boolean-intersection :value "intersection" :disabled disabled-bool-btns - :title (str (tr "intersection") " (" (sc/get-tooltip :bool-intersection) ")") + :title (str (tr "workspace.shape.menu.intersection") " (" (sc/get-tooltip :bool-intersection) ")") :id "bool-opt-intersection"}] [:& radio-button {:icon i/boolean-exclude :value "exclude" :disabled disabled-bool-btns - :title (str (tr "exclude") " (" (sc/get-tooltip :bool-exclude) ")") + :title (str (tr "workspace.shape.menu.exclude") " (" (sc/get-tooltip :bool-exclude) ")") :id "bool-opt-exclude"}]]] [:button diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs index c68c0287e..bfdd503fe 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs @@ -120,7 +120,7 @@ (dom/prevent-default e) (dom/stop-propagation e) (st/emit! (wdt/toggle-token-theme-active? group name)))} - [:& switch {:name (tr "workspace.token.theme" name) + [:& switch {:name (tr "workspace.token.theme-name" name) :on-change (constantly nil) :selected? selected?}]] [:> text* {:as "span" :typography "body-medium" :class (stl/css :theme-name)} name]] diff --git a/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs b/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs index 3d331c616..a6a59047a 100644 --- a/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs +++ b/frontend/test/frontend_tests/logic/copying_and_duplicating_test.cljs @@ -63,10 +63,10 @@ target-container-id (or target-container-id (:parent-id shape))] (filter some? - [(when target-page-id (dw/initialize-page target-page-id)) + [(when target-page-id (dw/initialize-page (:id file) target-page-id)) (dws/select-shape target-container-id) (dw/paste-shapes pdata) - (when target-page-id (dw/initialize-page (:id page)))]))) + (when target-page-id (dw/initialize-page (:id file) (:id page)))]))) (defn- sync-file [file] (map (fn [component-tag] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 025797e5d..46b567622 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -12,9 +12,8 @@ msgstr "" "X-Generator: Weblate 5.10-dev\n" #: src/app/main/data/common.cljs:87 -#, fuzzy -msgid "Refresh" -msgstr "" +msgid "labels.refresh" +msgstr "Refresh" #: src/app/main/ui/auth/register.cljs:133, src/app/main/ui/static.cljs:155, src/app/main/ui/viewer/login.cljs:98 msgid "auth.already-have-account" @@ -1386,11 +1385,6 @@ msgstr "Email or password is incorrect." msgid "errors.wrong-old-password" msgstr "Old password is incorrect" -#: src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:85 -#, fuzzy -msgid "exclude" -msgstr "" - #: src/app/main/ui/settings/feedback.cljs:74 msgid "feedback.description" msgstr "Description" @@ -1691,11 +1685,6 @@ msgstr "Text" msgid "inspect.tabs.info" msgstr "Info" -#: src/app/main/ui/workspace/sidebar/options/menus/bool.cljs:80 -#, fuzzy -msgid "intersection" -msgstr "" - #: src/app/main/ui/workspace/main_menu.cljs:162 msgid "label.shortcuts" msgstr "Shortcuts" @@ -2020,6 +2009,10 @@ msgstr "Member" msgid "labels.members" msgstr "Members" +#: src/app/main/ui/comments.cljs:558 +msgid "labels.mention" +msgstr "Mention" + #: src/app/main/ui/settings/password.cljs:84 msgid "labels.new-password" msgstr "New password" @@ -2458,11 +2451,6 @@ msgstr "Create token" msgid "modals.create-access-token.title" msgstr "Generate access token" -#: src/app/main/ui/settings/access_tokens.cljs:152 -#, fuzzy -msgid "modals.create-access-token.token" -msgstr "" - #: src/app/main/ui/dashboard/team.cljs:921 msgid "modals.create-webhook.submit-label" msgstr "Create webhook" @@ -4806,10 +4794,6 @@ msgstr "Loading…" msgid "workspace.libraries.more-templates" msgstr "You can look for " -#: src/app/main/ui/workspace/libraries.cljs:391 -msgid "workspace.libraries.more-templates-link" -msgstr "more templates in here" - #: src/app/main/ui/workspace/libraries.cljs:481 msgid "workspace.libraries.no-libraries-need-sync" msgstr "There are no Shared Libraries that need update" @@ -4818,10 +4802,6 @@ msgstr "There are no Shared Libraries that need update" msgid "workspace.libraries.no-matches-for" msgstr "No matches found for “%s“" -#: src/app/main/ui/workspace/libraries.cljs:384 -msgid "workspace.libraries.no-shared-libraries-available" -msgstr "There are no Shared Libraries available" - #: src/app/main/ui/workspace/libraries.cljs:337 msgid "workspace.libraries.search-shared-libraries" msgstr "Search shared libraries" @@ -6625,11 +6605,6 @@ msgstr "Select set." msgid "workspace.token.set-selection-theme" msgstr "Define what token sets should be used as part of this theme option:" -#: src/app/main/ui/workspace/tokens/modals/themes.cljs:123 -#, fuzzy -msgid "workspace.token.theme" -msgstr "" - #: src/app/main/ui/workspace/tokens/modals/themes.cljs #, unused msgid "workspace.token.theme-name" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index d7d6c1f0c..14e900594 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -2015,6 +2015,10 @@ msgstr "Integrante" msgid "labels.members" msgstr "Integrantes" +#: src/app/main/ui/comments.cljs:558 +msgid "labels.mention" +msgstr "Mencionar" + #: src/app/main/ui/settings/password.cljs:84 msgid "labels.new-password" msgstr "Nueva contraseña" @@ -4800,10 +4804,6 @@ msgstr "Cargando…" msgid "workspace.libraries.more-templates" msgstr "Puedes buscar " -#: src/app/main/ui/workspace/libraries.cljs:391 -msgid "workspace.libraries.more-templates-link" -msgstr "más plantillas aquí" - #: src/app/main/ui/workspace/libraries.cljs:481 msgid "workspace.libraries.no-libraries-need-sync" msgstr "No hay bibliotecas que necesiten ser actualizadas" @@ -4812,10 +4812,6 @@ msgstr "No hay bibliotecas que necesiten ser actualizadas" msgid "workspace.libraries.no-matches-for" msgstr "No se encuentra “%s“" -#: src/app/main/ui/workspace/libraries.cljs:384 -msgid "workspace.libraries.no-shared-libraries-available" -msgstr "No hay bibliotecas compartidas disponibles" - #: src/app/main/ui/workspace/libraries.cljs:337 msgid "workspace.libraries.search-shared-libraries" msgstr "Buscar bibliotecas compartidas"