Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2024-02-27 12:45:59 +01:00
commit 2a6589ab01
95 changed files with 2490 additions and 2036 deletions

View file

@ -2,7 +2,7 @@
{org.clojure/clojure {:mvn/version "1.11.1"} {org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/data.json {:mvn/version "2.5.0"} org.clojure/data.json {:mvn/version "2.5.0"}
org.clojure/tools.cli {:mvn/version "1.0.219"} org.clojure/tools.cli {:mvn/version "1.0.219"}
org.clojure/clojurescript {:mvn/version "1.11.60"} org.clojure/clojurescript {:mvn/version "1.11.132"}
org.clojure/test.check {:mvn/version "1.1.1"} org.clojure/test.check {:mvn/version "1.1.1"}
org.clojure/data.fressian {:mvn/version "1.0.0"} org.clojure/data.fressian {:mvn/version "1.0.0"}
@ -19,7 +19,7 @@
criterium/criterium {:mvn/version "0.4.6"} criterium/criterium {:mvn/version "0.4.6"}
metosin/jsonista {:mvn/version "0.3.8"} metosin/jsonista {:mvn/version "0.3.8"}
metosin/malli {:mvn/version "0.13.0"} metosin/malli {:mvn/version "0.14.0"}
expound/expound {:mvn/version "0.9.0"} expound/expound {:mvn/version "0.9.0"}
com.cognitect/transit-clj {:mvn/version "1.0.333"} com.cognitect/transit-clj {:mvn/version "1.0.333"}
@ -63,7 +63,7 @@
{:dev {:dev
{:extra-deps {:extra-deps
{org.clojure/tools.namespace {:mvn/version "RELEASE"} {org.clojure/tools.namespace {:mvn/version "RELEASE"}
thheller/shadow-cljs {:mvn/version "2.26.2"} thheller/shadow-cljs {:mvn/version "2.27.4"}
com.clojure-goes-fast/clj-async-profiler {:mvn/version "RELEASE"} com.clojure-goes-fast/clj-async-profiler {:mvn/version "RELEASE"}
com.bhauman/rebel-readline {:mvn/version "RELEASE"} com.bhauman/rebel-readline {:mvn/version "RELEASE"}
criterium/criterium {:mvn/version "RELEASE"} criterium/criterium {:mvn/version "RELEASE"}

View file

@ -15,7 +15,7 @@
"sax": "^1.2.4" "sax": "^1.2.4"
}, },
"devDependencies": { "devDependencies": {
"shadow-cljs": "2.26.2", "shadow-cljs": "2.27.4",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"ws": "^8.13.0" "ws": "^8.13.0"
}, },

View file

@ -150,6 +150,22 @@
:else :else
(get-head-shape objects (get objects (:parent-id shape)) options)))) (get-head-shape objects (get objects (:parent-id shape)) options))))
(defn get-parent-heads
"Get all component heads that are ancestors of the shape, in top-down order
(include self if it's also a head)."
[objects shape]
(->> (cfh/get-parents-with-self objects (:id shape))
(filter ctk/instance-head?)
(reverse)))
(defn get-parent-copy-heads
"Get all component heads that are ancestors of the shape, in top-down order,
excluding mains (include self if it's also a head)."
[objects shape]
(->> (cfh/get-parents-with-self objects (:id shape))
(filter #(and (ctk/instance-head? %) (ctk/in-component-copy? %)))
(reverse)))
(defn get-instance-root (defn get-instance-root
"Get the parent shape at the top of the component instance (main or copy)." "Get the parent shape at the top of the component instance (main or copy)."
[objects shape] [objects shape]
@ -392,7 +408,7 @@
(has-any-copy-parent? objects (:parent-id shape)))))) (has-any-copy-parent? objects (:parent-id shape))))))
(defn has-any-main? (defn has-any-main?
"Check if the shape has any children or parent that is a main component." "Check if the shape is a main component or has any children or parent that is a main component."
[objects shape] [objects shape]
(let [children (cfh/get-children-with-self objects (:id shape)) (let [children (cfh/get-children-with-self objects (:id shape))
parents (cfh/get-parents objects (:id shape))] parents (cfh/get-parents objects (:id shape))]
@ -400,6 +416,12 @@
(some ctk/main-instance? children) (some ctk/main-instance? children)
(some ctk/main-instance? parents)))) (some ctk/main-instance? parents))))
(defn has-any-main-children?
"Check if the shape is a main component or has any children that is a main component."
[objects shape]
(let [children (cfh/get-children-with-self objects (:id shape))]
(some ctk/main-instance? children)))
(defn valid-shape-for-component? (defn valid-shape-for-component?
"Check if a main component can be generated from this shape in terms of nested components: "Check if a main component can be generated from this shape in terms of nested components:
- A main can't be the ancestor of another main - A main can't be the ancestor of another main
@ -412,7 +434,7 @@
(defn- invalid-structure-for-component? (defn- invalid-structure-for-component?
"Check if the structure generated nesting children in parent is invalid in terms of nested components" "Check if the structure generated nesting children in parent is invalid in terms of nested components"
[objects parent children] [objects parent children]
(let [selected-main-instance? (some true? (map #(has-any-main? objects %) children)) (let [selected-main-instance? (some true? (map #(has-any-main-children? objects %) children))
parent-in-component? (in-any-component? objects parent) parent-in-component? (in-any-component? objects parent)
comps-nesting-loop? (not (->> children comps-nesting-loop? (not (->> children
(map #(cfh/components-nesting-loop? objects (:id %) (:id parent))) (map #(cfh/components-nesting-loop? objects (:id %) (:id parent)))

View file

@ -117,6 +117,12 @@
[libraries component-id & {:keys [include-deleted?] :or {include-deleted? false}}] [libraries component-id & {:keys [include-deleted?] :or {include-deleted? false}}]
(some #(ctkl/get-component (:data %) component-id include-deleted?) (vals libraries))) (some #(ctkl/get-component (:data %) component-id include-deleted?) (vals libraries)))
(defn find-component-file
[file libraries component-file]
(if (and (some? file) (= component-file (:id file)))
file
(get libraries component-file)))
(defn get-component (defn get-component
"Retrieve a component from a library." "Retrieve a component from a library."
[libraries library-id component-id & {:keys [include-deleted?] :or {include-deleted? false}}] [libraries library-id component-id & {:keys [include-deleted?] :or {include-deleted? false}}]
@ -188,21 +194,30 @@
"Locate the nearest component in the local file or libraries, and retrieve the shape "Locate the nearest component in the local file or libraries, and retrieve the shape
referenced by the instance shape." referenced by the instance shape."
[file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}] [file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}]
(let [parent-heads (->> (cfh/get-parents-with-self (:objects page) (:id shape)) (let [find-ref-shape-in-head
(filter ctk/instance-head?)
(reverse))
find-ref-shape-in-head
(fn [head-shape] (fn [head-shape]
(let [head-file (if (and (some? file) (= (:component-file head-shape) (:id file))) (let [head-file (find-component-file file libraries (:component-file head-shape))
file
(get libraries (:component-file head-shape)))
head-component (when (some? head-file) head-component (when (some? head-file)
(ctkl/get-component (:data head-file) (:component-id head-shape) include-deleted?))] (ctkl/get-component (:data head-file) (:component-id head-shape) include-deleted?))]
(when (some? head-component) (when (some? head-component)
(get-ref-shape (:data head-file) head-component shape))))] (get-ref-shape (:data head-file) head-component shape))))]
(d/seek find-ref-shape-in-head parent-heads))) (some find-ref-shape-in-head (ctn/get-parent-heads (:objects page) shape))))
(defn find-ref-component
"Locate the nearest component in the local file or libraries that is referenced by the
instance shape."
[file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}]
(let [find-ref-component-in-head
(fn [head-shape]
(let [head-file (find-component-file file libraries (:component-file head-shape))
head-component (when (some? head-file)
(ctkl/get-component (:data head-file) (:component-id head-shape) include-deleted?))]
(when (some? head-component)
(when (get-ref-shape (:data head-file) head-component shape)
head-component))))]
(some find-ref-component-in-head (ctn/get-parent-copy-heads (:objects page) shape))))
(defn find-remote-shape (defn find-remote-shape
"Recursively go back by the :shape-ref of the shape until find the correct shape of the original component" "Recursively go back by the :shape-ref of the shape until find the correct shape of the original component"
@ -229,6 +244,13 @@
remote-shape remote-shape
(find-remote-shape component-container libraries remote-shape))))) (find-remote-shape component-container libraries remote-shape)))))
(defn direct-copy?
"Check if the shape is in a direct copy of the component (i.e. the shape-ref points to shapes inside
the component)."
[shape component page file libraries]
(let [ref-component (find-ref-component file page libraries shape :include-deleted? true)]
(true? (= (:id component) (:id ref-component)))))
(defn get-component-shapes (defn get-component-shapes
"Retrieve all shapes of the component" "Retrieve all shapes of the component"
[file-data component] [file-data component]

View file

@ -176,7 +176,7 @@
(contains? event-types event-type)) (contains? event-types event-type))
(dm/assert! (dm/assert!
"The `:after-delay` event type incompatible with frame shapes" "The `:after-delay` event type incompatible with not frame shapes"
(or (not= event-type :after-delay) (or (not= event-type :after-delay)
(cfh/frame-shape? shape))) (cfh/frame-shape? shape)))

View file

@ -352,7 +352,7 @@ __metadata:
dependencies: dependencies:
luxon: "npm:^3.4.2" luxon: "npm:^3.4.2"
sax: "npm:^1.2.4" sax: "npm:^1.2.4"
shadow-cljs: "npm:2.26.2" shadow-cljs: "npm:2.27.4"
source-map-support: "npm:^0.5.21" source-map-support: "npm:^0.5.21"
ws: "npm:^8.13.0" ws: "npm:^8.13.0"
languageName: unknown languageName: unknown
@ -1437,9 +1437,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"shadow-cljs@npm:2.26.2": "shadow-cljs@npm:2.27.4":
version: 2.26.2 version: 2.27.4
resolution: "shadow-cljs@npm:2.26.2" resolution: "shadow-cljs@npm:2.27.4"
dependencies: dependencies:
node-libs-browser: "npm:^2.2.1" node-libs-browser: "npm:^2.2.1"
readline-sync: "npm:^1.4.7" readline-sync: "npm:^1.4.7"
@ -1449,7 +1449,7 @@ __metadata:
ws: "npm:^7.4.6" ws: "npm:^7.4.6"
bin: bin:
shadow-cljs: cli/runner.js shadow-cljs: cli/runner.js
checksum: d504969ea28bcf3d5fc879c8111cb630a8ae910ea692bbfb0d73097fb336e13e642116db9fcc91524686a6824e71d439ef0df31941eabb6331feb4aa4146e830 checksum: bae23e71df9c2b2979259a0cde8747c923ee295f58ab4637c9d6b103d82542b40ef39172d4be2dbb94af2e6458a177d1ec96c1eb1e73b1d8f3a4ddb5eaaba7d4
languageName: node languageName: node
linkType: hard linkType: hard

View file

@ -15,7 +15,7 @@
:dev :dev
{:extra-deps {:extra-deps
{thheller/shadow-cljs {:mvn/version "2.26.2"}}} {thheller/shadow-cljs {:mvn/version "2.27.4"}}}
:shadow-cljs :shadow-cljs
{:main-opts ["-m" "shadow.cljs.devtools.cli"]} {:main-opts ["-m" "shadow.cljs.devtools.cli"]}

View file

@ -22,7 +22,7 @@
"xregexp": "^5.1.1" "xregexp": "^5.1.1"
}, },
"devDependencies": { "devDependencies": {
"shadow-cljs": "2.26.2", "shadow-cljs": "2.27.4",
"source-map-support": "^0.5.21" "source-map-support": "^0.5.21"
}, },
"scripts": { "scripts": {

View file

@ -735,7 +735,7 @@ __metadata:
luxon: "npm:^3.4.4" luxon: "npm:^3.4.4"
playwright: "npm:^1.40.1" playwright: "npm:^1.40.1"
raw-body: "npm:^2.5.2" raw-body: "npm:^2.5.2"
shadow-cljs: "npm:2.26.2" shadow-cljs: "npm:2.27.4"
source-map-support: "npm:^0.5.21" source-map-support: "npm:^0.5.21"
xml-js: "npm:^1.6.11" xml-js: "npm:^1.6.11"
xregexp: "npm:^5.1.1" xregexp: "npm:^5.1.1"
@ -1842,9 +1842,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"shadow-cljs@npm:2.26.2": "shadow-cljs@npm:2.27.4":
version: 2.26.2 version: 2.27.4
resolution: "shadow-cljs@npm:2.26.2" resolution: "shadow-cljs@npm:2.27.4"
dependencies: dependencies:
node-libs-browser: "npm:^2.2.1" node-libs-browser: "npm:^2.2.1"
readline-sync: "npm:^1.4.7" readline-sync: "npm:^1.4.7"
@ -1854,7 +1854,7 @@ __metadata:
ws: "npm:^7.4.6" ws: "npm:^7.4.6"
bin: bin:
shadow-cljs: cli/runner.js shadow-cljs: cli/runner.js
checksum: d504969ea28bcf3d5fc879c8111cb630a8ae910ea692bbfb0d73097fb336e13e642116db9fcc91524686a6824e71d439ef0df31941eabb6331feb4aa4146e830 checksum: bae23e71df9c2b2979259a0cde8747c923ee295f58ab4637c9d6b103d82542b40ef39172d4be2dbb94af2e6458a177d1ec96c1eb1e73b1d8f3a4ddb5eaaba7d4
languageName: node languageName: node
linkType: hard linkType: hard

View file

@ -19,8 +19,8 @@
:git/url "https://github.com/funcool/beicon.git"} :git/url "https://github.com/funcool/beicon.git"}
funcool/rumext funcool/rumext
{:git/tag "v2.10" {:git/tag "v2.11.1"
:git/sha "d96ea18" :git/sha "c9197b0"
:git/url "https://github.com/funcool/rumext.git"} :git/url "https://github.com/funcool/rumext.git"}
instaparse/instaparse {:mvn/version "1.4.12"} instaparse/instaparse {:mvn/version "1.4.12"}
@ -41,7 +41,7 @@
:dev :dev
{:extra-paths ["dev"] {:extra-paths ["dev"]
:extra-deps :extra-deps
{thheller/shadow-cljs {:mvn/version "2.26.2"} {thheller/shadow-cljs {:mvn/version "2.27.4"}
org.clojure/tools.namespace {:mvn/version "RELEASE"} org.clojure/tools.namespace {:mvn/version "RELEASE"}
cider/cider-nrepl {:mvn/version "0.44.0"}}} cider/cider-nrepl {:mvn/version "0.44.0"}}}

View file

@ -39,53 +39,53 @@
"storybook:build": "npm run storybook:compile && storybook build" "storybook:build": "npm run storybook:compile && storybook build"
}, },
"devDependencies": { "devDependencies": {
"@storybook/addon-essentials": "^7.6.7", "@storybook/addon-essentials": "^7.6.17",
"@storybook/addon-interactions": "^7.6.7", "@storybook/addon-interactions": "^7.6.17",
"@storybook/addon-links": "^7.6.7", "@storybook/addon-links": "^7.6.17",
"@storybook/addon-onboarding": "^1.0.10", "@storybook/addon-onboarding": "^1.0.11",
"@storybook/blocks": "^7.6.7", "@storybook/blocks": "^7.6.17",
"@storybook/react": "^7.6.7", "@storybook/react": "^7.6.17",
"@storybook/react-vite": "^7.6.7", "@storybook/react-vite": "^7.6.17",
"@storybook/testing-library": "^0.2.2", "@storybook/testing-library": "^0.2.2",
"@types/node": "^20.10.6", "@types/node": "^20.11.20",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.17",
"concurrently": "^8.2.2", "concurrently": "^8.2.2",
"draft-js": "git+https://github.com/penpot/draft-js.git",
"fancy-log": "^2.0.0", "fancy-log": "^2.0.0",
"gettext-parser": "^7.0.1", "gettext-parser": "^8.0.0",
"gulp": "4.0.2", "gulp": "4.0.2",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-gzip": "^1.4.2", "gulp-gzip": "^1.4.2",
"gulp-mustache": "^5.0.0", "gulp-mustache": "^5.0.0",
"gulp-postcss": "^9.0.1", "gulp-postcss": "^10.0.0",
"gulp-rename": "^2.0.0", "gulp-rename": "^2.0.0",
"gulp-sass": "^5.1.0", "gulp-sass": "^5.1.0",
"gulp-sourcemaps": "^3.0.0", "gulp-sourcemaps": "^3.0.0",
"gulp-svg-sprite": "^2.0.3", "gulp-svg-sprite": "^2.0.3",
"jsdom": "^23.1.0", "jsdom": "^24.0.0",
"map-stream": "0.0.7", "map-stream": "0.0.7",
"marked": "^7.0.5", "marked": "^12.0.0",
"mkdirp": "^3.0.1", "mkdirp": "^3.0.1",
"nodemon": "^3.0.2", "nodemon": "^3.1.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"postcss": "^8.4.33", "postcss": "^8.4.35",
"postcss-clean": "^1.2.2", "postcss-clean": "^1.2.2",
"prettier": "^3.1.1", "prettier": "^3.2.5",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"sass": "^1.69.7", "sass": "^1.71.1",
"shadow-cljs": "2.26.2", "shadow-cljs": "2.27.4",
"storybook": "^7.6.7", "storybook": "^7.6.17",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.0.11", "vite": "^5.1.4",
"vitest": "^1.1.3" "vitest": "^1.3.1"
}, },
"dependencies": { "dependencies": {
"date-fns": "^2.30.0", "date-fns": "^3.3.1",
"draft-js": "^0.11.7", "eventsource-parser": "^1.1.2",
"eventsource-parser": "^1.1.1",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"js-beautify": "^1.14.11", "js-beautify": "^1.15.1",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"luxon": "^3.4.4", "luxon": "^3.4.4",
"mousetrap": "^1.6.5", "mousetrap": "^1.6.5",
@ -95,7 +95,7 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-virtualized": "^9.22.5", "react-virtualized": "^9.22.5",
"rxjs": "8.0.0-alpha.13", "rxjs": "8.0.0-alpha.14",
"sax": "^1.3.0", "sax": "^1.3.0",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"tdigest": "^0.1.2", "tdigest": "^0.1.2",

View file

@ -57,16 +57,19 @@
--la-quaternary: #ff6fe0; --la-quaternary: #ff6fe0;
// STATUS COLOR // STATUS COLOR
--status-color-success-50: #f0f8ff; --status-color-success-200: #a7e8d9;
--status-color-success-500: #2d9f8f; --status-color-success-500: #2d9f8f;
--status-color-success-950: #0a2927; --status-color-success-950: #0a2927;
--status-color-warning-50: #fff4ed;
--status-color-warning-200: #ffc8a8;
--status-color-warning-500: #fe4811; --status-color-warning-500: #fe4811;
--status-color-warning-950: #440806; --status-color-warning-950: #440806;
--status-color-error-50: #fff0f3;
--status-color-error-200: #ffcada;
--status-color-error-500: #ff3277; --status-color-error-500: #ff3277;
--status-color-error-950: #500124; --status-color-error-950: #500124;
--status-color-info-50: #f0f8ff;
--status-color-info-200: #bae3fd;
--status-color-info-500: #0e9be9; --status-color-info-500: #0e9be9;
--status-color-info-950: #082c49; --status-color-info-950: #082c49;
// Status color default will change with theme and will be defined on theme files // Status color default will change with theme and will be defined on theme files

View file

@ -311,15 +311,30 @@
--modal-separator-backogrund-color: var(--color-background-quaternary); --modal-separator-backogrund-color: var(--color-background-quaternary);
// ALERTS NOTIFICATION TOAST & STATUS WIDGET // ALERTS NOTIFICATION TOAST & STATUS WIDGET
--alert-background-color-success: var(--status-color-success-500); --alert-background-color-success: var(--color-success-background);
--alert-foreground-color-success: var(--db-secondary); // We don't want this color to change with theme --alert-text-foreground-color-success: var(--color-foreground-primary);
--alert-background-color-warning: var(--status-color-warning-500); --alert-icon-foreground-color-success: var(--color-success-foreground);
--alert-foreground-color-warning: var(--app-white); // We don't want this color to change with theme --alert-border-color-success: var(--color-success-foreground);
--alert-background-color-error: var(--status-color-error-500);
--alert-foreground-color-error: var(--app-white); // We don't want this color to change with theme --alert-background-color-warning: var(--color-warning-background);
--alert-background-color-neutral: var(--color-background-quaternary); --alert-text-foreground-color-warning: var(--color-foreground-primary);
--alert-foreground-color-neutral: var(--color-foreground-secondary); --alert-icon-foreground-color-warning: var(--color-warning-foreground);
--alert-foreground-color-neutral-active: var(--color-foreground-primary); --alert-border-color-warning: var(--color-warning-foreground);
--alert-background-color-error: var(--color-error-background);
--alert-text-foreground-color-error: var(--color-foreground-primary);
--alert-icon-foreground-color-error: var(--color-error-foreground);
--alert-border-color-error: var(--color-error-foreground);
--alert-background-color-info: var(--color-info-background);
--alert-text-foreground-color-info: var(--color-foreground-primary);
--alert-icon-foreground-color-info: var(--color-info-foreground);
--alert-border-color-info: var(--color-info-foreground);
--alert-background-color-default: var(--color-background-primary);
--alert-text-foreground-color-default: var(--color-foreground-primary);
--alert-icon-foreground-color-default: var(--color-foreground-primary);
--alert-border-color-default: var(--color-background-quaternary);
--notification-background-color-success: var(); --notification-background-color-success: var();
--notification-foreground-color-success: var(); --notification-foreground-color-success: var();

View file

@ -24,6 +24,18 @@
--color-accent-quaternary: var(--da-quaternary); --color-accent-quaternary: var(--da-quaternary);
--color-component-highlight: var(--da-secondary); --color-component-highlight: var(--da-secondary);
--color-success-background: var(--status-color-success-950);
--color-success-foreground: var(--status-color-success-500);
--color-warning-background: var(--status-color-warning-950);
--color-warning-foreground: var(--status-color-warning-500);
--color-error-background: var(--status-color-error-950);
--color-error-foreground: var(--status-color-error-500);
--color-info-background: var(--status-color-info-950);
--color-info-foreground: var(--status-color-info-500);
--overlay-color: var(--db-primary-60); --overlay-color: var(--db-primary-60);
--shadow-color: var(--db-secondary-30); --shadow-color: var(--db-secondary-30);

View file

@ -24,6 +24,18 @@
--color-accent-quaternary: var(--la-quaternary); --color-accent-quaternary: var(--la-quaternary);
--color-component-highlight: var(--la-secondary); --color-component-highlight: var(--la-secondary);
--color-success-background: var(--status-color-success-200);
--color-success-foreground: var(--status-color-success-500);
--color-warning-background: var(--status-color-warning-200);
--color-warning-foreground: var(--status-color-warning-500);
--color-error-background: var(--status-color-error-200);
--color-error-foreground: var(--status-color-error-500);
--color-info-background: var(--status-color-info-200);
--color-info-foreground: var(--status-color-info-500);
--overlay-color: var(--lb-primary-60); --overlay-color: var(--lb-primary-60);
--shadow-color: var(--lf-secondary-40); --shadow-color: var(--lf-secondary-40);
--radio-button-box-shadow: 0 0 0 1px var(--lb-secondary) inset; --radio-button-box-shadow: 0 0 0 1px var(--lb-secondary) inset;

View file

@ -70,6 +70,7 @@
(rx/of (msg/dialog (rx/of (msg/dialog
:content (tr "notifications.by-code.upgrade-version") :content (tr "notifications.by-code.upgrade-version")
:controls :inline-actions :controls :inline-actions
:notification-type :inline
:type level :type level
:actions [{:label "Refresh" :callback force-reload!}] :actions [{:label "Refresh" :callback force-reload!}]
:tag :notification))) :tag :notification)))

View file

@ -8,7 +8,7 @@
(:require (:require
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.media :as cm] [app.common.media :as cm]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.store :as st] [app.main.store :as st]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -46,13 +46,13 @@
(defn notify-start-loading (defn notify-start-loading
[] []
(st/emit! (dm/show {:content (tr "media.loading") (st/emit! (msg/show {:content (tr "media.loading")
:type :info :type :info
:timeout nil}))) :timeout nil})))
(defn notify-finished-loading (defn notify-finished-loading
[] []
(st/emit! dm/hide)) (st/emit! msg/hide))
(defn process-error (defn process-error
[error] [error]
@ -68,4 +68,4 @@
:else :else
(tr "errors.unexpected-error"))] (tr "errors.unexpected-error"))]
(rx/of (dm/error msg)))) (rx/of (msg/error msg))))

View file

@ -16,7 +16,7 @@
(declare show) (declare show)
(def default-animation-timeout 600) (def default-animation-timeout 600)
(def default-timeout 5000) (def default-timeout 7000)
(def ^:private (def ^:private
schema:message schema:message
@ -27,6 +27,8 @@
[::sm/one-of #{:visible :hide}]] [::sm/one-of #{:visible :hide}]]
[:position {:optional true} [:position {:optional true}
[::sm/one-of #{:fixed :floating :inline}]] [::sm/one-of #{:fixed :floating :inline}]]
[:notification-type {:optional true}
[::sm/one-of #{:inline :context :toast}]]
[:controls {:optional true} [:controls {:optional true}
[::sm/one-of #{:none :close :inline-actions :bottom-actions}]] [::sm/one-of #{:none :close :inline-actions :bottom-actions}]]
[:tag {:optional true} [:tag {:optional true}
@ -93,18 +95,18 @@
(rx/of hide)))))) (rx/of hide))))))
(defn error (defn error
([content] (error content {})) ([content]
([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content (show {:content content
:type :error :type :error
:position :fixed :notification-type :toast
:timeout timeout}))) :position :fixed})))
(defn info (defn info
([content] (info content {})) ([content] (info content {}))
([content {:keys [timeout] :or {timeout default-timeout}}] ([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content (show {:content content
:type :info :type :info
:notification-type :toast
:position :fixed :position :fixed
:timeout timeout}))) :timeout timeout})))
@ -113,6 +115,7 @@
([content {:keys [timeout] :or {timeout default-timeout}}] ([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content (show {:content content
:type :success :type :success
:notification-type :toast
:position :fixed :position :fixed
:timeout timeout}))) :timeout timeout})))
@ -121,6 +124,7 @@
([content {:keys [timeout] :or {timeout default-timeout}}] ([content {:keys [timeout] :or {timeout default-timeout}}]
(show {:content content (show {:content content
:type :warning :type :warning
:notification-type :toast
:position :fixed :position :fixed
:timeout timeout}))) :timeout timeout})))
@ -142,6 +146,7 @@
{:content content {:content content
:type :info :type :info
:position :floating :position :floating
:notification-type :inline
:controls controls :controls controls
:links links :links links
:actions actions :actions actions

View file

@ -609,24 +609,29 @@
(ptk/reify ::detach-selected-components (ptk/reify ::detach-selected-components
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (:current-page-id state) (let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id) objects (wsh/lookup-page-objects state page-id)
file (wsh/get-local-file state) file (wsh/get-local-file state)
container (cfh/get-container file :page page-id) container (cfh/get-container file :page page-id)
libraries (wsh/get-libraries state) libraries (wsh/get-libraries state)
selected (->> state selected (->> state
(wsh/lookup-selected) (wsh/lookup-selected)
(cfh/clean-loops objects)) (cfh/clean-loops objects))
selected-objects (map #(get objects %) selected)
copies (filter ctk/in-component-copy? selected-objects)
can-detach? (and (seq copies)
(every? #(not (ctn/has-any-copy-parent? objects %)) selected-objects))
changes (when can-detach?
(reduce
(fn [changes id]
(dwlh/generate-detach-instance changes container libraries id))
(-> (pcb/empty-changes it)
(pcb/with-container container)
(pcb/with-objects objects))
selected))]
changes (reduce (rx/of (when can-detach?
(fn [changes id] (dch/commit-changes changes)))))))
(dwlh/generate-detach-instance changes libraries container id))
(-> (pcb/empty-changes it)
(pcb/with-container container)
(pcb/with-objects objects))
selected)]
(rx/of (dch/commit-changes changes))))))
(defn nav-to-component-file (defn nav-to-component-file
[file-id component] [file-id component]
@ -1126,12 +1131,12 @@
:controls :inline-actions :controls :inline-actions
:links [{:label (tr "workspace.updates.more-info") :links [{:label (tr "workspace.updates.more-info")
:callback do-more-info}] :callback do-more-info}]
:actions [{:label (tr "workspace.updates.update") :actions [{:label (tr "workspace.updates.dismiss")
:type :primary
:callback do-update}
{:label (tr "workspace.updates.dismiss")
:type :secondary :type :secondary
:callback do-dismiss}] :callback do-dismiss}
{:label (tr "workspace.updates.update")
:type :primary
:callback do-update}]
:tag :sync-dialog))))))) :tag :sync-dialog)))))))
(defn component-changed (defn component-changed

View file

@ -599,15 +599,10 @@
library (dm/get-in libraries [(:component-file shape-inst) :data]) library (dm/get-in libraries [(:component-file shape-inst) :data])
component (or (ctkl/get-component library (:component-id shape-inst)) component (or (ctkl/get-component library (:component-id shape-inst))
(and reset? (and reset?
(ctkl/get-deleted-component library (:component-id shape-inst)))) (ctkl/get-deleted-component library (:component-id shape-inst))))]
component-shape (ctn/get-component-shape (:objects container) shape-inst)]
(if (and (ctk/in-component-copy? shape-inst) (if (and (ctk/in-component-copy? shape-inst)
(or (= (:id component) (:component-id component-shape)) reset?)) ; In a normal sync, we don't want to sync remote mains, only near (or (ctf/direct-copy? shape-inst component container nil libraries) reset?)) ; In a normal sync, we don't want to sync remote mains, only direct/near
(let [redirect-shaperef (partial redirect-shaperef container libraries) (let [redirect-shaperef (partial redirect-shaperef container libraries)
library (dm/get-in libraries [(:component-file shape-inst) :data])
component (or (ctkl/get-component library (:component-id shape-inst))
(and reset?
(ctkl/get-deleted-component library (:component-id shape-inst))))
shape-main (when component shape-main (when component
(if (and reset? components-v2) (if (and reset? components-v2)

View file

@ -82,13 +82,14 @@
(defn get-snap-points [page-id frame-id remove-snap? zoom point coord] (defn get-snap-points [page-id frame-id remove-snap? zoom point coord]
(let [value (get point coord) (let [value (get point coord)
vbox @refs/vbox] vbox @refs/vbox
ranges [[(- value (/ 0.5 zoom)) (+ value (/ 0.5 zoom))]]]
(->> (uw/ask! {:cmd :snaps/range-query (->> (uw/ask! {:cmd :snaps/range-query
:page-id page-id :page-id page-id
:frame-id frame-id :frame-id frame-id
:axis coord :axis coord
:bounds vbox :bounds vbox
:ranges [[(- value (/ 0.5 zoom)) (+ value (/ 0.5 zoom))]]}) :ranges ranges})
(rx/take 1) (rx/take 1)
(rx/map (remove-from-snap-points remove-snap?))))) (rx/map (remove-from-snap-points remove-snap?)))))

View file

@ -173,6 +173,6 @@
(if edata (if edata
[:& static/exception-page {:data edata}] [:& static/exception-page {:data edata}]
[:* [:*
[:& msgs/notifications] [:& msgs/notifications-hub]
(when route (when route
[:& main-page {:route route :profile profile}])])]])) [:& main-page {:route route :profile profile}])])]]))

View file

@ -8,13 +8,13 @@
.auth-form { .auth-form {
width: 100%; width: 100%;
padding-bottom: $s-16; padding-block-end: $s-16;
form { form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: $s-12; gap: $s-12;
margin-bottom: $s-24; margin-block-end: $s-24;
} }
} }
@ -23,6 +23,10 @@
margin: $s-24 0; margin: $s-24 0;
} }
.error-wrapper {
padding-block-end: $s-8;
}
.auth-title { .auth-title {
@include bigTitleTipography; @include bigTitleTipography;
color: $df-primary; color: $df-primary;

View file

@ -11,7 +11,7 @@
[app.common.logging :as log] [app.common.logging :as log]
[app.common.spec :as us] [app.common.spec :as us]
[app.config :as cf] [app.config :as cf]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
@ -19,7 +19,7 @@
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
[app.main.ui.components.link :as lk] [app.main.ui.components.link :as lk]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.messages :as msgs] [app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[app.util.keyboard :as k] [app.util.keyboard :as k]
@ -48,10 +48,10 @@
(cond (cond
(and (= type :restriction) (and (= type :restriction)
(= code :provider-not-configured)) (= code :provider-not-configured))
(st/emit! (dm/error (tr "errors.auth-provider-not-configured"))) (st/emit! (msg/error (tr "errors.auth-provider-not-configured")))
:else :else
(st/emit! (dm/error (tr "errors.generic")))))))) (st/emit! (msg/error (tr "errors.generic"))))))))
(defn- login-with-ldap (defn- login-with-ldap
[event params] [event params]
@ -67,13 +67,13 @@
(cond (cond
(and (= type :restriction) (and (= type :restriction)
(= code :ldap-not-initialized)) (= code :ldap-not-initialized))
(st/emit! (dm/error (tr "errors.ldap-disabled"))) (st/emit! (msg/error (tr "errors.ldap-disabled")))
(fn? on-error) (fn? on-error)
(on-error error) (on-error error)
:else :else
(st/emit! (dm/error (tr "errors.generic"))))))))) (st/emit! (msg/error (tr "errors.generic")))))))))
(s/def ::email ::us/email) (s/def ::email ::us/email)
(s/def ::password ::us/not-empty-string) (s/def ::password ::us/not-empty-string)
@ -157,12 +157,12 @@
[:* [:*
(when-let [message @error] (when-let [message @error]
[:& msgs/inline-banner [:div {:class (stl/css :error-wrapper)}
{:type :warning [:& context-notification
:content message {:type :warning
:on-close #(reset! error nil) :content message
:data-test "login-banner" :data-test "login-banner"
:role "alert"}]) :role "alert"}]])
[:& fm/form {:on-submit on-submit :form form} [:& fm/form {:on-submit on-submit :form form}
[:div {:class (stl/css :fields-row)} [:div {:class (stl/css :fields-row)}

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
@ -39,11 +39,11 @@
(defn- on-error (defn- on-error
[_form _error] [_form _error]
(st/emit! (dm/error (tr "auth.notifications.invalid-token-error")))) (st/emit! (msg/error (tr "auth.notifications.invalid-token-error"))))
(defn- on-success (defn- on-success
[_] [_]
(st/emit! (dm/info (tr "auth.notifications.password-changed-successfully")) (st/emit! (msg/info (tr "auth.notifications.password-changed-successfully"))
(rt/nav :auth-login))) (rt/nav :auth-login)))
(defn- on-submit (defn- on-submit

View file

@ -9,7 +9,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
@ -37,7 +37,7 @@
:initial {}) :initial {})
submitted (mf/use-state false) submitted (mf/use-state false)
default-success-finish #(st/emit! (dm/info (tr "auth.notifications.recovery-token-sent"))) default-success-finish #(st/emit! (msg/info (tr "auth.notifications.recovery-token-sent")))
on-success on-success
(mf/use-callback (mf/use-callback
@ -53,13 +53,13 @@
(reset! submitted false) (reset! submitted false)
(case code (case code
:profile-not-verified :profile-not-verified
(rx/of (dm/error (tr "auth.notifications.profile-not-verified") {:timeout nil})) (rx/of (msg/error (tr "auth.notifications.profile-not-verified")))
:profile-is-muted :profile-is-muted
(rx/of (dm/error (tr "errors.profile-is-muted"))) (rx/of (msg/error (tr "errors.profile-is-muted")))
:email-has-permanent-bounces :email-has-permanent-bounces
(rx/of (dm/error (tr "errors.email-has-permanent-bounces" (:email data)))) (rx/of (msg/error (tr "errors.email-has-permanent-bounces" (:email data))))
(rx/throw error)))) (rx/throw error))))

View file

@ -10,7 +10,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.spec :as us] [app.common.spec :as us]
[app.config :as cf] [app.config :as cf]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
@ -18,7 +18,7 @@
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
[app.main.ui.components.link :as lk] [app.main.ui.components.link :as lk]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.messages :as msgs] [app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.i18n :refer [tr tr-html]] [app.util.i18n :refer [tr tr-html]]
[app.util.router :as rt] [app.util.router :as rt]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
@ -28,7 +28,7 @@
(mf/defc demo-warning (mf/defc demo-warning
[_] [_]
[:div {:class (stl/css :banner)} [:div {:class (stl/css :banner)}
[:& msgs/inline-banner [:& context-notification
{:type :warning {:type :warning
:content (tr "auth.demo-warning")}]]) :content (tr "auth.demo-warning")}]])
@ -61,14 +61,14 @@
[form {:keys [type code] :as cause}] [form {:keys [type code] :as cause}]
(condp = [type code] (condp = [type code]
[:restriction :registration-disabled] [:restriction :registration-disabled]
(st/emit! (dm/error (tr "errors.registration-disabled"))) (st/emit! (msg/error (tr "errors.registration-disabled")))
[:restriction :profile-blocked] [:restriction :profile-blocked]
(st/emit! (dm/error (tr "errors.profile-blocked"))) (st/emit! (msg/error (tr "errors.profile-blocked")))
[:validation :email-has-permanent-bounces] [:validation :email-has-permanent-bounces]
(let [email (get @form [:data :email])] (let [email (get @form [:data :email])]
(st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email)))) (st/emit! (msg/error (tr "errors.email-has-permanent-bounces" email))))
[:validation :email-already-exists] [:validation :email-already-exists]
(swap! form assoc-in [:errors :email] (swap! form assoc-in [:errors :email]
@ -78,7 +78,7 @@
(swap! form assoc-in [:errors :password] (swap! form assoc-in [:errors :password]
{:message "errors.email-as-password"}) {:message "errors.email-as-password"})
(st/emit! (dm/error (tr "errors.generic"))))) (st/emit! (msg/error (tr "errors.generic")))))
(defn- handle-prepare-register-success (defn- handle-prepare-register-success
[params] [params]
@ -182,7 +182,7 @@
(do (do
(println (:explain error)) (println (:explain error))
(st/emit! (dm/error (tr "errors.generic")))))) (st/emit! (msg/error (tr "errors.generic"))))))
(defn- handle-register-success (defn- handle-register-success
[data] [data]

View file

@ -7,7 +7,7 @@
(ns app.main.ui.auth.verify-token (ns app.main.ui.auth.verify-token
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
@ -25,13 +25,13 @@
(defmethod handle-token :verify-email (defmethod handle-token :verify-email
[data] [data]
(let [msg (tr "dashboard.notifications.email-verified-successfully")] (let [msg (tr "dashboard.notifications.email-verified-successfully")]
(ts/schedule 1000 #(st/emit! (dm/success msg))) (ts/schedule 1000 #(st/emit! (msg/success msg)))
(st/emit! (du/login-from-token data)))) (st/emit! (du/login-from-token data))))
(defmethod handle-token :change-email (defmethod handle-token :change-email
[_data] [_data]
(let [msg (tr "dashboard.notifications.email-changed-successfully")] (let [msg (tr "dashboard.notifications.email-changed-successfully")]
(ts/schedule 100 #(st/emit! (dm/success msg))) (ts/schedule 100 #(st/emit! (msg/success msg)))
(st/emit! (rt/nav :settings-profile) (st/emit! (rt/nav :settings-profile)
(du/fetch-profile)))) (du/fetch-profile))))
@ -44,7 +44,7 @@
(case (:state tdata) (case (:state tdata)
:created :created
(st/emit! (st/emit!
(dm/success (tr "auth.notifications.team-invitation-accepted")) (msg/success (tr "auth.notifications.team-invitation-accepted"))
(du/fetch-profile) (du/fetch-profile)
(rt/nav :dashboard-projects {:team-id (:team-id tdata)})) (rt/nav :dashboard-projects {:team-id (:team-id tdata)}))
@ -57,7 +57,7 @@
[_tdata] [_tdata]
(st/emit! (st/emit!
(rt/nav :auth-login) (rt/nav :auth-login)
(dm/warn (tr "errors.unexpected-token")))) (msg/warn (tr "errors.unexpected-token"))))
(mf/defc verify-token (mf/defc verify-token
[{:keys [route] :as props}] [{:keys [route] :as props}]
@ -79,17 +79,17 @@
(= :email-already-exists code) (= :email-already-exists code)
(let [msg (tr "errors.email-already-exists")] (let [msg (tr "errors.email-already-exists")]
(ts/schedule 100 #(st/emit! (dm/error msg))) (ts/schedule 100 #(st/emit! (msg/error msg)))
(st/emit! (rt/nav :auth-login))) (st/emit! (rt/nav :auth-login)))
(= :email-already-validated code) (= :email-already-validated code)
(let [msg (tr "errors.email-already-validated")] (let [msg (tr "errors.email-already-validated")]
(ts/schedule 100 #(st/emit! (dm/warn msg))) (ts/schedule 100 #(st/emit! (msg/warn msg)))
(st/emit! (rt/nav :auth-login))) (st/emit! (rt/nav :auth-login)))
:else :else
(let [msg (tr "errors.generic")] (let [msg (tr "errors.generic")]
(ts/schedule 100 #(st/emit! (dm/error msg))) (ts/schedule 100 #(st/emit! (msg/error msg)))
(st/emit! (rt/nav :auth-login)))))))) (st/emit! (rt/nav :auth-login))))))))
(if @bad-token (if @bad-token

View file

@ -296,19 +296,13 @@
(mf/defc submit-button* (mf/defc submit-button*
{::mf/wrap-props false} {::mf/wrap-props false}
[{:keys [on-click children label form class name disabled large?] :as props}] [{:keys [on-click children label form class name disabled] :as props}]
(let [form (or form (mf/use-ctx form-ctx)) (let [form (or form (mf/use-ctx form-ctx))
disabled? (or (and (some? form) (not (:valid @form))) disabled? (or (and (some? form) (not (:valid @form)))
(true? disabled)) (true? disabled))
large? (d/nilv large? true) class (d/nilv class (stl/css :button-submit))
class (dm/str (d/nilv class "btn-primary")
" "
(if large? "btn-large" "")
" "
(if disabled? (stl/css :btn-disabled) ""))
name (d/nilv name "submit") name (d/nilv name "submit")

View file

@ -257,7 +257,11 @@
} }
// SUBMIT-BUTTON // SUBMIT-BUTTON
.btn-disabled { .button-submit {
@extend .button-primary;
}
:disabled {
@extend .button-disabled; @extend .button-disabled;
} }
@ -329,10 +333,10 @@
&.invalid { &.invalid {
background-color: var(--status-widget-background-color-error); background-color: var(--status-widget-background-color-error);
.text { .text {
color: var(--alert-foreground-color-error); color: var(--alert-text-foreground-color-error);
} }
.icon svg { .icon svg {
stroke: var(--alert-foreground-color-error); stroke: var(--alert-icon-foreground-color-error);
} }
} }
} }
@ -422,6 +426,7 @@
fill: none; fill: none;
} }
} }
//TEXTAREA //TEXTAREA
.textarea-label { .textarea-label {

View file

@ -18,7 +18,7 @@
(mf/defc radio-button (mf/defc radio-button
{::mf/props :obj} {::mf/props :obj}
[{:keys [icon id value disabled title unique-key icon-class type]}] [{:keys [icon id value disabled title icon-class type]}]
(let [context (mf/use-ctx context) (let [context (mf/use-ctx context)
allow-empty (unchecked-get context "allow-empty") allow-empty (unchecked-get context "allow-empty")
type (if ^boolean type type (if ^boolean type
@ -39,7 +39,6 @@
[:label {:html-for id [:label {:html-for id
:title title :title title
:key unique-key
:class (stl/css-case :class (stl/css-case
:radio-icon true :radio-icon true
:checked checked? :checked checked?
@ -88,9 +87,10 @@
(dom/blur! input)))) (dom/blur! input))))
context-value context-value
(mf/spread-obj props {:on-change on-change' (mf/spread props
:encode-fn encode-fn :on-change on-change'
:decode-fn decode-fn})] :encode-fn encode-fn
:decode-fn decode-fn)]
[:& (mf/provider context) {:value context-value} [:& (mf/provider context) {:value context-value}
[:div {:class (dm/str class " " (stl/css :radio-btn-wrapper)) [:div {:class (dm/str class " " (stl/css :radio-btn-wrapper))

View file

@ -9,7 +9,7 @@
[app.main.data.common :as dcm] [app.main.data.common :as dcm]
[app.main.data.dashboard :as dd] [app.main.data.dashboard :as dd]
[app.main.data.events :as ev] [app.main.data.events :as ev]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
@ -88,12 +88,12 @@
on-duplicate on-duplicate
(fn [_] (fn [_]
(apply st/emit! (map dd/duplicate-file files)) (apply st/emit! (map dd/duplicate-file files))
(st/emit! (dm/success (tr "dashboard.success-duplicate-file" (i18n/c (count files)))))) (st/emit! (msg/success (tr "dashboard.success-duplicate-file" (i18n/c (count files))))))
on-delete-accept on-delete-accept
(fn [_] (fn [_]
(apply st/emit! (map dd/delete-file files)) (apply st/emit! (map dd/delete-file files))
(st/emit! (dm/success (tr "dashboard.success-delete-file" (i18n/c (count files)))) (st/emit! (msg/success (tr "dashboard.success-delete-file" (i18n/c (count files))))
(dd/clear-selected-files))) (dd/clear-selected-files)))
on-delete on-delete
@ -126,21 +126,36 @@
on-move-success on-move-success
(fn [team-id project-id] (fn [team-id project-id]
(if multi? (if multi?
(st/emit! (dm/success (tr "dashboard.success-move-files"))) (st/emit! (msg/success (tr "dashboard.success-move-files")))
(st/emit! (dm/success (tr "dashboard.success-move-file")))) (st/emit! (msg/success (tr "dashboard.success-move-file"))))
(if (or navigate? (not= team-id current-team-id)) (if (or navigate? (not= team-id current-team-id))
(st/emit! (dd/go-to-files team-id project-id)) (st/emit! (dd/go-to-files team-id project-id))
(st/emit! (dd/fetch-recent-files team-id) (st/emit! (dd/fetch-recent-files team-id)
(dd/clear-selected-files)))) (dd/clear-selected-files))))
on-move-accept
(fn [params team-id project-id]
(st/emit! (dd/move-files
(with-meta params
{:on-success #(on-move-success team-id project-id)}))))
on-move on-move
(fn [team-id project-id] (fn [team-id project-id]
(let [params {:ids (into #{} (map :id) files) (let [params {:ids (into #{} (map :id) files)
:project-id project-id}] :project-id project-id}]
(fn [] (fn []
(st/emit! (dd/move-files
(with-meta params (let [num-shared (filter #(:is-shared %) files)]
{:on-success #(on-move-success team-id project-id)})))))) (if (and (< 0 (count num-shared))
(not= team-id current-team-id))
(st/emit! (modal/show
{:type :delete-shared-libraries
:origin :move
:ids (into #{} (map :id) files)
:on-accept #(on-move-accept params team-id project-id)
:count-libraries (count num-shared)}))
(on-move-accept params team-id project-id))))))
add-shared add-shared
#(st/emit! (dd/set-file-shared (assoc file :is-shared true))) #(st/emit! (dd/set-file-shared (assoc file :is-shared true)))

View file

@ -14,10 +14,10 @@
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]] [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
[app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.file-uploader :refer [file-uploader]]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
@ -131,18 +131,14 @@
:ref input-ref :ref input-ref
:on-selected handle-selected}]] :on-selected handle-selected}]]
[:div {:class (stl/css :banner)} [:& context-notification {:content (tr "dashboard.fonts.hero-text2")
[:div {:class (stl/css :icon)} i/msg-neutral-refactor] :type :default
[:div {:class (stl/css :content)} :is-html true}]
[:& i18n/tr-html {:tag-name "span"
:label "dashboard.fonts.hero-text2"}]]]
(when problematic-fonts? (when problematic-fonts?
[:div {:class (stl/css :banner :warning)} [:& context-notification {:content (tr "dashboard.fonts.warning-text")
[:div {:class (stl/css :icon)} i/msg-warning-refactor] :type :warning
[:div {:class (stl/css :content)} :is-html true}])]]
[:& i18n/tr-html {:tag-name "span"
:label "dashboard.fonts.warning-text"}]]])]]
[:* [:*
(when (some? (vals fonts)) (when (some? (vals fonts))
@ -176,7 +172,7 @@
[:div {:class (stl/css :table-field :options)} [:div {:class (stl/css :table-field :options)}
(when (:height-warning? item) (when (:height-warning? item)
[:span {:class (stl/css :icon :failure)} i/msg-warning-refactor]) [:span {:class (stl/css :icon :failure)} i/msg-neutral-refactor])
[:button {:on-click #(on-upload item) [:button {:on-click #(on-upload item)
:class (stl/css-case :btn-primary true :class (stl/css-case :btn-primary true

View file

@ -255,47 +255,6 @@
} }
} }
.banner {
overflow: hidden;
display: grid;
grid-template-columns: $s-40 1fr;
background-color: $db-primary;
border-radius: $br-12;
border: $s-1 solid $db-quaternary;
color: $df-primary;
font-size: $fs-12;
&:not(:last-child) {
margin-bottom: $s-12;
}
.icon {
display: flex;
align-items: flex-start;
justify-content: center;
padding-top: $s-12;
svg {
stroke: $df-secondary;
fill: none;
height: $s-20;
width: $s-20;
}
}
.content {
margin: $s-12;
a {
color: $da-primary;
}
}
&.warning {
background-color: $db-quaternary;
.icon svg {
stroke: var(--element-foreground-warning);
}
}
}
.btn-primary { .btn-primary {
flex-shrink: 0; flex-shrink: 0;
} }

View file

@ -19,6 +19,7 @@
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.file-uploader :refer [file-uploader]]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.notifications.context-notification :refer [context-notification]]
[app.main.worker :as uw] [app.main.worker :as uw]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
@ -385,14 +386,12 @@
(when (and (= :importing (:status @state)) (not pending-import?)) (when (and (= :importing (:status @state)) (not pending-import?))
(if (> warning-files 0) (if (> warning-files 0)
[:div {:class (stl/css-case :feedback-banner true [:& context-notification
:warning true)} {:type :warning
[:div {:class (stl/css :icon)} i/msg-warning-refactor] :content (tr "dashboard.import.import-warning" warning-files success-files)}]
[:div {:class (stl/css :message)} (tr "dashboard.import.import-warning" warning-files success-files)]] [:& context-notification
{:type :success
[:div {:class (stl/css :feedback-banner)} :content (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))}]))
[:div {:class (stl/css :icon)} i/msg-success-refactor]
[:div {:class (stl/css :message)} (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]]))
(for [file files] (for [file files]
(let [editing? (and (some? (:file-id file)) (let [editing? (and (some? (:file-id file))

View file

@ -29,39 +29,12 @@
.modal-content { .modal-content {
@include bodyMedTipography; @include bodyMedTipography;
display: grid;
grid-template-columns: 1fr;
gap: $s-16;
margin-bottom: $s-24; margin-bottom: $s-24;
} }
.feedback-banner {
@include flexRow;
height: $s-32;
width: 100%;
margin-bottom: $s-24;
border-radius: $br-8;
background-color: var(--alert-background-color-success);
color: var(--alert-foreground-color-success);
.icon {
@include flexCenter;
height: $s-24;
width: $s-24;
svg {
@extend .button-icon;
stroke: var(--alert-foreground-color-success);
}
}
.message {
@include bodyMedTipography;
}
&.warning {
background-color: var(--alert-background-color-warning);
color: var(--alert-foreground-color-warning);
.icon svg {
stroke: var(--alert-foreground-color-warning);
}
}
}
.action-buttons { .action-buttons {
@extend .modal-action-btns; @extend .modal-action-btns;
} }

View file

@ -608,7 +608,7 @@
height: $s-24; height: $s-24;
svg { svg {
@extend .button-icon; @extend .button-icon;
stroke: var(--alert-foreground-color-error); stroke: var(--alert-icon-foreground-color-error);
} }
} }
.message { .message {
@ -632,7 +632,7 @@
height: $s-24; height: $s-24;
svg { svg {
@extend .button-icon; @extend .button-icon;
stroke: var(--alert-foreground-color-warning); stroke: var(--alert-icon-foreground-color-warning);
} }
} }
.message { .message {

View file

@ -9,7 +9,7 @@
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.dashboard :as dd] [app.main.data.dashboard :as dd]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
@ -29,22 +29,22 @@
(defn- on-create-success (defn- on-create-success
[_form response] [_form response]
(let [msg "Team created successfully"] (let [msg "Team created successfully"]
(st/emit! (dm/success msg) (st/emit! (msg/success msg)
(modal/hide) (modal/hide)
(rt/nav :dashboard-projects {:team-id (:id response)})))) (rt/nav :dashboard-projects {:team-id (:id response)}))))
(defn- on-update-success (defn- on-update-success
[_form _response] [_form _response]
(let [msg "Team created successfully"] (let [msg "Team created successfully"]
(st/emit! (dm/success msg) (st/emit! (msg/success msg)
(modal/hide)))) (modal/hide))))
(defn- on-error (defn- on-error
[form _response] [form _response]
(let [id (get-in @form [:clean-data :id])] (let [id (get-in @form [:clean-data :id])]
(if id (if id
(rx/of (dm/error "Error on updating team.")) (rx/of (msg/error "Error on updating team."))
(rx/of (dm/error "Error on creating team."))))) (rx/of (msg/error "Error on creating team.")))))
(defn- on-create-submit (defn- on-create-submit
[form] [form]
@ -117,6 +117,6 @@
{:label (if team {:label (if team
(tr "labels.update-team") (tr "labels.update-team")
(tr "labels.create-team")) (tr "labels.create-team"))
:className (stl/css :accept-btn)}]]]]]])) :class (stl/css :accept-btn)}]]]]]]))

View file

@ -35,28 +35,26 @@
cancel-label (tr "labels.cancel") cancel-label (tr "labels.cancel")
accept-style (or accept-style :danger) accept-style (or accept-style :danger)
is-delete? (= origin :delete)
count-files (count (keys references)) count-files (count (keys references))
title (if ^boolean is-delete? title (case origin
(tr "modals.delete-shared-confirm.title" (i18n/c count-libraries)) :delete (tr "modals.delete-shared-confirm.title" (i18n/c count-libraries))
(tr "modals.unpublish-shared-confirm.title" (i18n/c count-libraries))) :unpublish (tr "modals.unpublish-shared-confirm.title" (i18n/c count-libraries))
:move (tr "modals.move-shared-confirm.title" (i18n/c count-libraries)))
subtitle (if ^boolean is-delete? subtitle (case origin
(tr "modals.delete-shared-confirm.message" (i18n/c count-libraries)) :delete (tr "modals.delete-shared-confirm.message" (i18n/c count-libraries))
(tr "modals.unpublish-shared-confirm.message" (i18n/c count-libraries))) :unpublish (tr "modals.unpublish-shared-confirm.message" (i18n/c count-libraries))
:move (tr "modals.move-shared-confirm.message" (i18n/c count-libraries)))
accept-label (if ^boolean is-delete? accept-label (case origin
(tr "modals.delete-shared-confirm.accept" (i18n/c count-libraries)) :delete (tr "modals.delete-shared-confirm.accept" (i18n/c count-libraries))
(tr "modals.unpublish-shared-confirm.accept" (i18n/c count-libraries))) :unpublish (tr "modals.unpublish-shared-confirm.accept" (i18n/c count-libraries))
:move (tr "modals.move-shared-confirm.accept" (i18n/c count-libraries)))
no-files-msg (if ^boolean is-delete? no-files-msg (tr "modals.delete-shared-confirm.activated.no-files-message" (i18n/c count-libraries))
(tr "modals.delete-shared-confirm.activated.no-files-message" (i18n/c count-libraries))
(tr "modals.unpublish-shared-confirm.activated.no-files-message" (i18n/c count-libraries)))
scd-msg (if ^boolean is-delete? scd-msg (tr "modals.delete-shared-confirm.activated.scd-message" (i18n/c count-libraries))
(tr "modals.delete-shared-confirm.activated.scd-message" (i18n/c count-libraries))
(tr "modals.unpublish-shared-confirm.activated.scd-message" (i18n/c count-libraries)))
hint (tr "modals.delete-unpublish-shared-confirm.activated.hint" (i18n/c count-files)) hint (tr "modals.delete-unpublish-shared-confirm.activated.hint" (i18n/c count-files))

View file

@ -5,93 +5,43 @@
;; Copyright (c) KALEIDOS INC ;; Copyright (c) KALEIDOS INC
(ns app.main.ui.messages (ns app.main.ui.messages
(:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.uuid :as uuid]
[app.main.data.messages :as dmsg] [app.main.data.messages :as dmsg]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.link-button :as lb] [app.main.ui.notifications.context-notification :refer [context-notification]]
[app.main.ui.icons :as i] [app.main.ui.notifications.inline-notification :refer [inline-notification]]
[app.main.ui.notifications.toast-notification :refer [toast-notification]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc banner (mf/defc notifications-hub
[{:keys [type position status controls content links actions on-close data-test role] :as props}]
[:div {:class (stl/css-case :banner true
:warning (= type :warning)
:error (= type :error)
:success (= type :success)
:info (= type :info)
:fixed (= position :fixed)
:floating (= position :floating)
:inline (= position :inline)
:hide (= status :hide))}
[:div {:class (stl/css :wrapper)}
[:div {:class (stl/css :icon)}
(case type
:warning i/msg-warning-refactor
:error i/msg-error-refactor
:success i/msg-success-refactor
:info i/msg-neutral-refactor
i/msg-error-refactor)]
[:div {:class (stl/css-case :content true
:inline-actions (= controls :inline-actions)
:bottom-actions (= controls :bottom-actions))
:data-test data-test
:role role}
[:span {:class (stl/css :text)}
content
(for [[index link] (d/enumerate links)]
[:* {:key (dm/str "link-" index)}
" " [:& lb/link-button {:class (stl/css :link)
:on-click (:callback link)
:value (:label link)}]])]
(when (or (= controls :bottom-actions) (= controls :inline-actions))
[:div {:class (stl/css :actions)}
(for [action actions]
[:button {:key (uuid/next)
:class (stl/css-case :action-btn true
:primary (= :primary (:type action))
:secondary (= :secondary (:type action))
:danger (= :danger (:type action)))
:on-click (:callback action)}
(:label action)])])]
(when (= controls :close)
[:button {:class (stl/css :btn-close)
:on-click on-close} i/close-refactor])]])
(mf/defc notifications
[] []
(let [message (mf/deref refs/message) (let [message (mf/deref refs/message)
on-close #(st/emit! dmsg/hide)]
on-close #(st/emit! dmsg/hide)
toast-message {:type (or (:type message) :info)
:links (:links message)
:on-close on-close
:content (:content message)}
inline-message {:actions (:actions message)
:links (:links message)
:content (:content message)}
context-message {:actions (:actions message)
:links (:links message)
:content (:content message)}
;; TODO review this options
is-toast-msg (or (= :toast (:notification-type message)) (some? (:timeout message)))
is-inline-msg (or (= :inline (:notification-type message)) (and (some? (:position message)) (= :floating (:position message))))]
(when message (when message
[:& banner (assoc message (cond
:position (or (:position message) :fixed) is-toast-msg
:controls (if (some? (:controls message)) [:& toast-notification toast-message]
(:controls message) is-inline-msg
:close) [:& inline-notification inline-message]
:on-close on-close)]))) :else
[:& context-notification context-message]))))
(mf/defc inline-banner
{::mf/wrap [mf/memo]}
[{:keys [type content on-close actions data-test role] :as props}]
[:& banner {:type type
:position :inline
:status :visible
:controls (if (some? on-close)
:close
(if (some? actions)
:bottom-actions
:none))
:content content
:on-close on-close
:actions actions
:data-test data-test
:role role}])

View file

@ -1,150 +0,0 @@
// 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
@import "refactor/common-refactor.scss";
.banner {
--bg-color: var(--alert-background-color-error);
--fg-color: var(--alert-foreground-color-error);
position: relative;
display: flex;
align-items: center;
border-radius: $br-8;
background-color: var(--bg-color);
color: var(--fg-color);
}
.warning {
--bg-color: var(--alert-background-color-warning);
--fg-color: var(--alert-foreground-color-warning);
}
.success {
--bg-color: var(--alert-background-color-success);
--fg-color: var(--alert-foreground-color-success);
}
.info {
--bg-color: var(--alert-background-color-neutral);
--fg-color: var(--alert-foreground-color-neutral-active);
}
.banner.info .icon {
--fg-color: var(--alert-foreground-color-neutral);
}
.banner.info:hover .icon {
--fg-color: var(--alert-foreground-color-neutral);
}
.wrapper {
display: flex;
align-items: center;
padding: $s-8 $s-8 $s-8 $s-16;
gap: $s-8;
height: 100%;
width: 100%;
}
.icon {
@include flexCenter;
height: 100%;
width: $s-16;
svg {
@extend .button-icon;
stroke: var(--fg-color);
}
}
.fixed {
@include alertShadow;
position: fixed;
top: $s-16;
right: $s-16;
display: flex;
align-items: center;
height: $s-48;
min-width: $s-500;
max-width: calc(10 * $s-100);
padding-left: $s-16;
z-index: $z-index-alert;
}
.floating {
@include alertShadow;
position: absolute;
min-height: $s-32;
top: $s-72;
left: 0;
right: 0;
width: $s-640;
margin-left: auto;
margin-right: auto;
z-index: $z-index-modal;
}
.inline {
min-height: $s-40;
width: 100%;
}
.hide {
display: none;
}
.content {
@include flexRow;
gap: $s-8;
flex-grow: 1;
}
.text {
@include bodyMedTipography;
flex-grow: 1;
}
.link {
@include bodyMedTipography;
color: var(--modal-link-foreground-color);
margin: 0;
}
.actions {
@include flexRow;
gap: $s-8;
}
.action-btn {
@extend .button-tertiary;
@include uppercaseTitleTipography;
min-height: $s-32;
min-width: $s-32;
svg {
@extend .button-icon-small;
}
&.primary {
@extend .button-primary;
padding: $s-8 $s-24;
}
&.secondary {
@extend .button-secondary;
padding: $s-8 $s-24;
}
&.danger {
@extend .modal-danger-btn;
padding: $s-8 $s-24;
}
}
.btn-close {
@extend .button-tertiary;
height: $s-32;
width: $s-32;
svg {
@extend .button-icon-small;
stroke: var(--icon-foreground);
}
}

View file

@ -0,0 +1,69 @@
;; 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 app.main.ui.notifications.context-notification
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.ui.components.link-button :as lb]
[app.main.ui.icons :as i]
[rumext.v2 :as mf]))
(def ^:private neutral-icon
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
(def ^:private error-icon
(i/icon-xref :delete-text-refactor (stl/css :icon)))
(def ^:private success-icon
(i/icon-xref :status-tick-refactor (stl/css :icon)))
(def ^:private info-icon
(i/icon-xref :help-refactor (stl/css :icon)))
(defn get-icon-by-type
[type]
(case type
:warning neutral-icon
:error error-icon
:success success-icon
:info info-icon
neutral-icon))
(mf/defc context-notification
"They are persistent, informative and non-actionable.
They are contextual messages in specific areas off the app"
{::mf/props :obj}
[{:keys [type content links is-html] :as props}]
[:aside {:class (stl/css-case :context-notification true
:contain-html is-html
:warning (= type :warning)
:error (= type :error)
:success (= type :success)
:info (= type :info))}
(get-icon-by-type type)
;; The content can arrive in markdown format, in these cases
;; we will use the prop is-html to true to indicate it and
;; that the html injection is performed and the necessary css classes are applied.
[:div {:class (stl/css :context-text)
:dangerouslySetInnerHTML (when is-html #js {:__html content})}
(when-not is-html
content)]
(when (some? links)
[:nav {:class (stl/css :link-nav)}
(for [[index link] (d/enumerate links)]
;; TODO Review this component
[:& lb/link-button {:class (stl/css :link)
:on-click (:callback link)
:value (:label link)
:key (dm/str "link-" index)}])])])

View file

@ -0,0 +1,90 @@
// 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
@import "refactor/common-refactor.scss";
.context-notification {
---context-notification-bg-color: var(--alert-background-color-default);
--context-notification-fg-color: var(--alert-text-foreground-color-default);
--context-notification-icon-color: var(--alert-icon-foreground-color-default);
--context-notification-border-color: var(--alert-border-color-default);
display: grid;
grid-template-columns: $s-16 auto 1fr;
gap: $s-8;
min-height: $s-32;
width: 100%;
padding: $s-8 $s-8 $s-8 $s-16;
border: $s-1 solid var(--context-notification-border-color);
border-radius: $br-8;
background-color: var(--context-notification-bg-color);
}
.warning {
--context-notification-bg-color: var(--alert-background-color-warning);
--context-notification-fg-color: var(--alert-text-foreground-color-warning);
--context-notification-icon-color: var(--alert-icon-foreground-color-warning);
--context-notification-border-color: var(--alert-border-color-warning);
}
.success {
--context-notification-bg-color: var(--alert-background-color-success);
--context-notification-fg-color: var(--alert-text-foreground-color-success);
--context-notification-icon-color: var(--alert-icon-foreground-color-success);
--context-notification-border-color: var(--alert-border-color-success);
}
.info {
--context-notification-bg-color: var(--alert-background-color-info);
--context-notification-fg-color: var(--alert-text-foreground-color-info);
--context-notification-icon-color: var(--alert-icon-foreground-color-info);
--context-notification-border-color: var(--alert-border-color-info);
}
.default {
--context-notification-bg-color: var(--alert-background-color-default);
--context-notification-fg-color: var(--alert-text-foreground-color-default);
--context-notification-icon-color: var(--alert-icon-foreground-color-default);
--context-notification-border-color: var(--alert-border-color-default);
}
.error {
--context-notification-bg-color: var(--alert-background-color-error);
--context-notification-fg-color: var(--alert-text-foreground-color-error);
--context-notification-icon-color: var(--alert-icon-foreground-color-error);
--context-notification-border-color: var(--alert-border-color-error);
}
.icon {
@extend .button-icon;
align-self: self-start;
stroke: var(--context-notification-icon-color);
}
.link-nav {
align-self: center;
height: $s-24;
margin: 0;
}
.context-text {
@include bodyMedTipography;
align-self: center;
color: var(--context-notification-fg-color);
margin: auto 0;
}
// The second rule only applies when the element receives embedded
// links within the content by means of the dangerouslySetInnerHTML.
// Only in this case the contain-html class will be used.
.link,
.contain-html .context-text a {
@include bodyMedTipography;
align-self: center;
height: $s-16;
margin: 0;
color: var(--modal-link-foreground-color);
}

View file

@ -0,0 +1,49 @@
;; 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 app.main.ui.notifications.inline-notification
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.uuid :as uuid]
[app.main.ui.components.link-button :as lb]
[app.main.ui.icons :as i]
[rumext.v2 :as mf]))
(def ^:private neutral-icon
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
(mf/defc inline-notification
"They are persistent messages and report a special situation
of the application and require user interaction to disappear."
{::mf/props :obj}
[{:keys [content actions links] :as props}]
[:aside {:class (stl/css :inline-notification)}
neutral-icon
[:div {:class (stl/css :inline-text)}
content]
(when (some? links)
[:nav {:class (stl/css :link-nav)}
(for [[index link] (d/enumerate links)]
[:& lb/link-button {:key (dm/str "link-" index)
:class (stl/css :link)
:on-click (:callback link)
:value (:label link)}])])
[:div {:class (stl/css :actions)}
(for [action actions]
[:button {:key (uuid/next)
:class (stl/css-case :action-btn true
:primary (= :primary (:type action))
:secondary (= :secondary (:type action))
:danger (= :danger (:type action)))
:on-click (:callback action)}
(:label action)])]])

View file

@ -0,0 +1,79 @@
// 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
@import "refactor/common-refactor.scss";
.inline-notification {
--inline-notification-bg-color: var(--alert-background-color-default);
--inline-notification-fg-color: var(--alert-text-foreground-color-default);
--inline-notification-icon-color: var(--alert-icon-foreground-color-default);
--inline-notification-border-color: var(--alert-border-color-default);
@include alertShadow;
position: absolute;
top: $s-72;
left: 0;
right: 0;
display: grid;
grid-template-columns: $s-16 auto 1fr auto;
gap: $s-8;
min-height: $s-48;
min-width: $s-640;
max-width: $s-712;
padding: $s-8 $s-8 $s-8 $s-16;
margin-inline: auto;
border: $s-1 solid var(--inline-notification-border-color);
border-radius: $br-8;
z-index: $z-index-modal;
background-color: var(--inline-notification-bg-color);
color: var(--inline-notification-fg-color);
}
.icon {
@extend .button-icon;
height: 100%;
stroke: var(--inline-notification-icon-color);
}
.inline-text {
@include bodyMedTipography;
align-self: center;
}
.link {
@include bodyMedTipography;
margin: 0;
height: 100%;
color: var(--modal-link-foreground-color);
}
.actions {
display: grid;
grid-template-columns: none;
grid-auto-flow: column;
gap: $s-8;
align-self: center;
}
.action-btn {
@extend .button-tertiary;
@include uppercaseTitleTipography;
min-height: $s-32;
min-width: $s-32;
padding: $s-8 $s-24;
border: $s-1 solid transparent;
}
.action-btn.primary {
@extend .button-primary;
}
.action-btn.secondary {
@extend .button-secondary;
}
.action-btn.danger {
@extend .modal-danger-btn;
}

View file

@ -0,0 +1,73 @@
;; 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 app.main.ui.notifications.toast-notification
(:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.ui.components.link-button :as lb]
[app.main.ui.icons :as i]
[rumext.v2 :as mf]))
(def ^:private neutral-icon
(i/icon-xref :msg-neutral-refactor (stl/css :icon)))
(def ^:private error-icon
(i/icon-xref :delete-text-refactor (stl/css :icon)))
(def ^:private success-icon
(i/icon-xref :status-tick-refactor (stl/css :icon)))
(def ^:private info-icon
(i/icon-xref :help-refactor (stl/css :icon)))
(def ^:private close-icon
(i/icon-xref :close-refactor (stl/css :close-icon)))
(defn get-icon-by-type
[type]
(case type
:warning neutral-icon
:error error-icon
:success success-icon
:info info-icon
neutral-icon))
(mf/defc toast-notification
"These are ephemeral elements that disappear when
the close button is pressed,
the page is refreshed,
the page is navigated to another page or
after 7 seconds, which is enough time to be read,
except for error messages that require user interaction."
{::mf/props :obj}
[{:keys [type content on-close links] :as props}]
[:aside {:class (stl/css-case :toast-notification true
:with-links (some? links)
:warning (= type :warning)
:error (= type :error)
:success (= type :success)
:info (= type :info))}
(get-icon-by-type type)
[:div {:class (stl/css :text)}
content]
(when (some? links)
[:nav {:class (stl/css :link-nav)}
(for [[index link] (d/enumerate links)]
[:& lb/link-button {:key (dm/str "link-" index)
:class (stl/css :link)
:on-click (:callback link)
:value (:label link)}])])
[:button {:class (stl/css :btn-close)
:on-click on-close}
close-icon]])

View file

@ -0,0 +1,103 @@
// 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
@import "refactor/common-refactor.scss";
.toast-notification {
--toast-notification-bg-color: var(--alert-background-color-default);
--toast-notification-fg-color: var(--alert-text-foreground-color-default);
--toast-notification-icon-color: var(--alert-icon-foreground-color-default);
--toast-notification-border-color: var(--alert-border-color-default);
@include alertShadow;
position: fixed;
top: $s-16;
right: $s-16;
display: grid;
grid-template-columns: $s-16 1fr auto;
gap: $s-8;
min-height: $s-32;
min-width: $s-500;
max-width: calc(10 * $s-100);
padding: $s-8 $s-8 $s-8 $s-16;
border: $s-1 solid var(--toast-notification-border-color);
background-color: var(--toast-notification-bg-color);
border-radius: $br-8;
color: var(--toast-notification-fg-color);
z-index: $z-index-alert;
}
.with-links {
grid-template-columns: $s-16 auto 1fr auto;
}
.warning {
--toast-notification-bg-color: var(--alert-background-color-warning);
--toast-notification-fg-color: var(--alert-text-foreground-color-warning);
--toast-notification-icon-color: var(--alert-icon-foreground-color-warning);
--toast-notification-border-color: var(--alert-border-color-warning);
}
.success {
--toast-notification-bg-color: var(--alert-background-color-success);
--toast-notification-fg-color: var(--alert-text-foreground-color-success);
--toast-notification-icon-color: var(--alert-icon-foreground-color-success);
--toast-notification-border-color: var(--alert-border-color-success);
}
.info {
--bg-color: var(--alert-background-color-info);
--fg-color: var(--alert-text-foreground-color-info);
--icon-color: var(--alert-icon-foreground-color-info);
--border-color: var(--alert-border-color-info);
}
.default {
--toast-notification-bg-color: var(--alert-background-color-default);
--toast-notification-fg-color: var(--alert-text-foreground-color-default);
--toast-notification-icon-color: var(--alert-icon-foreground-color-default);
--toast-notification-border-color: var(--alert-border-color-default);
}
.error {
--toast-notification-bg-color: var(--alert-background-color-error);
--toast-notification-fg-color: var(--alert-text-foreground-color-error);
--toast-notification-icon-color: var(--alert-icon-foreground-color-error);
--toast-notification-border-color: var(--alert-border-color-error);
}
.link-nav {
height: $s-24;
}
.link {
@include bodyMedTipography;
color: var(--modal-link-foreground-color);
margin: 0;
}
.icon {
@extend .button-icon;
height: 100%;
stroke: var(--toast-notification-icon-color);
}
.text {
@include bodyMedTipography;
align-self: center;
}
.btn-close {
@include buttonStyle;
@include flexCenter;
height: 100%;
min-width: $s-32;
background-color: transparent;
}
.close-icon {
@extend .button-icon;
stroke: var(--toast-notification-icon-color);
}

View file

@ -7,7 +7,7 @@
(ns app.main.ui.onboarding.newsletter (ns app.main.ui.onboarding.newsletter
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.store :as st] [app.main.store :as st]
@ -33,7 +33,7 @@
(mf/deps @newsletter-updates @newsletter-news) (mf/deps @newsletter-updates @newsletter-news)
(fn [] (fn []
(st/emit! (when (or @newsletter-updates @newsletter-news) (st/emit! (when (or @newsletter-updates @newsletter-news)
(dm/success message)) (msg/success message))
(modal/show {:type :onboarding-team}) (modal/show {:type :onboarding-team})
(du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))] (du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))]

View file

@ -11,7 +11,7 @@
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.dashboard :as dd] [app.main.data.dashboard :as dd]
[app.main.data.events :as ev] [app.main.data.events :as ev]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
@ -169,7 +169,7 @@
on-error on-error
(mf/use-fn (mf/use-fn
(fn [_form _response] (fn [_form _response]
(st/emit! (dm/error "Error on creating team.")))) (st/emit! (msg/error "Error on creating team."))))
;; The SKIP branch only creates the team, without invitations ;; The SKIP branch only creates the team, without invitations
on-invite-later on-invite-later

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.store :as st] [app.main.store :as st]
@ -66,7 +66,7 @@
(fn [_] (fn [_]
(let [message (tr "dashboard.access-tokens.create.success")] (let [message (tr "dashboard.access-tokens.create.success")]
(st/emit! (du/fetch-access-tokens) (st/emit! (du/fetch-access-tokens)
(dm/success message) (msg/success message)
(reset! created? true))))) (reset! created? true)))))
on-close on-close
@ -79,7 +79,7 @@
on-error on-error
(mf/use-fn (mf/use-fn
(fn [_] (fn [_]
(st/emit! (dm/error (tr "errors.generic")) (st/emit! (msg/error (tr "errors.generic"))
(modal/hide)))) (modal/hide))))
on-submit on-submit
@ -101,9 +101,10 @@
(fn [event] (fn [event]
(dom/prevent-default event) (dom/prevent-default event)
(wapi/write-to-clipboard (:token created)) (wapi/write-to-clipboard (:token created))
(st/emit! (dm/show {:type :info (st/emit! (msg/show {:type :info
:content (tr "dashboard.access-tokens.copied-success") :notification-type :toast
:timeout 1000}))))] :content (tr "dashboard.access-tokens.copied-success")
:timeout 7000}))))]
[:div {:class (stl/css :modal-overlay)} [:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-container)} [:div {:class (stl/css :modal-container)}

View file

@ -10,14 +10,14 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dma] [app.common.data.macros :as dma]
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.messages :as msgs] [app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[cljs.spec.alpha :as s] [cljs.spec.alpha :as s]
@ -47,11 +47,11 @@
(assoc-in data [:errors :email-1] error)))) (assoc-in data [:errors :email-1] error))))
:profile-is-muted :profile-is-muted
(rx/of (dm/error (tr "errors.profile-is-muted"))) (rx/of (msg/error (tr "errors.profile-is-muted")))
:email-has-permanent-bounces :email-has-permanent-bounces
(let [email (get @form [:data :email-1])] (let [email (get @form [:data :email-1])]
(rx/of (dm/error (tr "errors.email-has-permanent-bounces" email)))) (rx/of (msg/error (tr "errors.email-has-permanent-bounces" email))))
(rx/throw error))) (rx/throw error)))
@ -61,7 +61,7 @@
(st/emit! (du/fetch-profile) (st/emit! (du/fetch-profile)
(modal/hide)) (modal/hide))
(let [message (tr "notifications.validation-email-sent" (:email profile))] (let [message (tr "notifications.validation-email-sent" (:email profile))]
(st/emit! (dm/info message) (st/emit! (msg/info message)
(modal/hide))))) (modal/hide)))))
(defn- on-submit (defn- on-submit
@ -110,7 +110,7 @@
:on-click on-close} i/close-refactor]] :on-click on-close} i/close-refactor]]
[:div {:class (stl/css :modal-content)} [:div {:class (stl/css :modal-content)}
[:& msgs/inline-banner [:& context-notification
{:type :info {:type :info
:content (tr "modals.change-email.info" (:email profile))}] :content (tr "modals.change-email.info" (:email profile))}]

View file

@ -7,12 +7,12 @@
(ns app.main.ui.settings.delete-account (ns app.main.ui.settings.delete-account
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.messages :as msgs] [app.main.ui.notifications.context-notification :refer [context-notification]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@ -21,7 +21,7 @@
[{:keys [code] :as error}] [{:keys [code] :as error}]
(if (= :owner-teams-with-people code) (if (= :owner-teams-with-people code)
(let [msg (tr "notifications.profile-deletion-not-allowed")] (let [msg (tr "notifications.profile-deletion-not-allowed")]
(rx/of (dm/error msg))) (rx/of (msg/error msg)))
(rx/throw error))) (rx/throw error)))
(mf/defc delete-account-modal (mf/defc delete-account-modal
@ -47,7 +47,7 @@
:on-click on-close} i/close-refactor]] :on-click on-close} i/close-refactor]]
[:div {:class (stl/css :modal-content)} [:div {:class (stl/css :modal-content)}
[:& msgs/inline-banner [:& context-notification
{:type :warning {:type :warning
:content (tr "modals.delete-account.info")}]] :content (tr "modals.delete-account.info")}]]

View file

@ -9,7 +9,7 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
@ -39,7 +39,7 @@
(mf/deps profile) (mf/deps profile)
(fn [_] (fn [_]
(reset! loading false) (reset! loading false)
(st/emit! (dm/success (tr "labels.feedback-sent"))) (st/emit! (msg/success (tr "labels.feedback-sent")))
(swap! form assoc :data {} :touched {} :errors {}))) (swap! form assoc :data {} :touched {} :errors {})))
on-error on-error
@ -48,8 +48,8 @@
(fn [{:keys [code] :as error}] (fn [{:keys [code] :as error}]
(reset! loading false) (reset! loading false)
(if (= code :feedback-disabled) (if (= code :feedback-disabled)
(st/emit! (dm/error (tr "labels.feedback-disabled"))) (st/emit! (msg/error (tr "labels.feedback-disabled")))
(st/emit! (dm/error (tr "errors.generic")))))) (st/emit! (msg/error (tr "errors.generic"))))))
on-submit on-submit
(mf/use-callback (mf/use-callback

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
@ -26,7 +26,7 @@
(defn- on-success (defn- on-success
[_] [_]
(st/emit! (dm/success (tr "notifications.profile-saved")))) (st/emit! (msg/success (tr "notifications.profile-saved"))))
(defn- on-submit (defn- on-submit
[form _event] [form _event]

View file

@ -8,7 +8,7 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.users :as udu] [app.main.data.users :as udu]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
@ -28,7 +28,7 @@
{:message (tr "errors.email-as-password")}) {:message (tr "errors.email-as-password")})
(let [msg (tr "generic.error")] (let [msg (tr "generic.error")]
(st/emit! (dm/error msg))))) (st/emit! (msg/error msg)))))
(defn- on-success (defn- on-success
[form] [form]
@ -37,7 +37,7 @@
msg (tr "dashboard.notifications.password-saved")] msg (tr "dashboard.notifications.password-saved")]
(dom/clean-value! password-old-node) (dom/clean-value! password-old-node)
(dom/focus! password-old-node) (dom/focus! password-old-node)
(st/emit! (dm/success msg)))) (st/emit! (msg/success msg))))
(defn- on-submit (defn- on-submit
[form event] [form event]

View file

@ -9,7 +9,7 @@
(:require (:require
[app.common.spec :as us] [app.common.spec :as us]
[app.config :as cf] [app.config :as cf]
[app.main.data.messages :as dm] [app.main.data.messages :as msg]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.users :as du] [app.main.data.users :as du]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -29,7 +29,7 @@
(defn- on-success (defn- on-success
[_] [_]
(st/emit! (dm/success (tr "notifications.profile-saved")))) (st/emit! (msg/success (tr "notifications.profile-saved"))))
(defn- on-submit (defn- on-submit
[form _event] [form _event]
@ -80,7 +80,7 @@
[:> fm/submit-button* [:> fm/submit-button*
{:label (tr "dashboard.save-settings") {:label (tr "dashboard.save-settings")
:disabled (empty? (:touched @form)) :disabled (empty? (:touched @form))
:className (stl/css :btn-primary)}] :class (stl/css :btn-primary)}]
[:div {:class (stl/css :links)} [:div {:class (stl/css :links)}
[:div {:class (stl/css :link-item)} [:div {:class (stl/css :link-item)}

View file

@ -58,6 +58,7 @@
} }
.viewer-section { .viewer-section {
@extend .new-scrollbar;
grid-row: 1 / span 2; grid-row: 1 / span 2;
grid-column: 1 / span 1; grid-column: 1 / span 1;
display: flex; display: flex;
@ -94,7 +95,7 @@
} }
.viewer-go-next.comment-sidebar { .viewer-go-next.comment-sidebar {
right: $s-264; right: $s-280;
} }
.viewer-go-prev { .viewer-go-prev {

View file

@ -8,6 +8,7 @@
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.rect :as grc] [app.common.geom.rect :as grc]
@ -26,16 +27,20 @@
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc comments-menu (mf/defc comments-menu
{::mf/wrap [mf/memo] {::mf/props :obj
::mf/wrap-props false} ::mf/memo true}
[] []
(let [{cmode :mode cshow :show show-sidebar? :show-sidebar?} (mf/deref refs/comments-local) (let [state (mf/deref refs/comments-local)
cmode (:mode state)
cshow (:show state)
show-sidebar? (:show-sidebar? state false)
show-dropdown? (mf/use-state false) show-dropdown? (mf/use-state false)
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not)) toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
hide-dropdown (mf/use-fn #(reset! show-dropdown? false)) hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
update-mode update-mode
(mf/use-callback (mf/use-fn
(fn [event] (fn [event]
(let [mode (-> (dom/get-current-target event) (let [mode (-> (dom/get-current-target event)
(dom/get-data "value") (dom/get-data "value")
@ -43,78 +48,76 @@
(st/emit! (dcm/update-filters {:mode mode}))))) (st/emit! (dcm/update-filters {:mode mode})))))
update-show update-show
(mf/use-callback (mf/use-fn
(fn [event] (fn [event]
(let [mode (-> (dom/get-current-target event) (let [mode (-> (dom/get-current-target event)
(dom/get-data "value") (dom/get-data "value")
(d/read-string))] (keyword))
mode (if (= :pending mode) :all :pending)]
(st/emit! (dcm/update-filters {:show mode}))))) (st/emit! (dcm/update-filters {:show mode})))))
update-options update-options
(mf/use-callback (mf/use-fn
(mf/deps show-sidebar?)
(fn [event] (fn [event]
(let [mode (-> (dom/get-target event) (let [mode (-> (dom/get-current-target event)
(dom/get-data "value") (dom/get-data "value")
(boolean))] (parse-boolean))]
(st/emit! (dcm/update-options {:show-sidebar? (not mode)})))))] (st/emit! (dcm/update-options {:show-sidebar? (not mode)})))))]
[:div {:class (stl/css :view-options) [:div {:class (stl/css :view-options)
:on-click toggle-dropdown} :on-click toggle-dropdown}
[:span {:class (stl/css :dropdown-title)} [:span {:class (stl/css :dropdown-title)} (tr "labels.comments")]
(tr "labels.comments")] [:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
[:span {:class (stl/css :icon-dropdown)}
i/arrow-refactor]
[:& dropdown {:show @show-dropdown? [:& dropdown {:show @show-dropdown?
:on-close hide-dropdown} :on-close hide-dropdown}
[:ul {:class (stl/css :dropdown)} [:ul {:class (stl/css :dropdown)}
[:li {:class (stl/css-case :dropdown-element true
:selected (or (= :all cmode) (nil? cmode))) [:li {:class (stl/css-case
:dropdown-element true
:selected (or (= :all cmode) (nil? cmode)))
:data-value "all" :data-value "all"
:on-click update-mode} :on-click update-mode}
[:span {:class (stl/css :label)} (tr "labels.show-all-comments")] [:span {:class (stl/css :label)} (tr "labels.show-all-comments")]
(when (or (= :all cmode) (nil? cmode)) (when (or (= :all cmode) (nil? cmode))
[:span {:class (stl/css :icon)} i/tick-refactor])] [:span {:class (stl/css :icon)} i/tick-refactor])]
[:li {:class (stl/css-case :dropdown-element true [:li {:class (stl/css-case
:selected (= :yours cmode)) :dropdown-element true
:selected (= :yours cmode))
:data-value "yours" :data-value "yours"
:on-click update-mode} :on-click update-mode}
[:span {:class (stl/css :label)} (tr "labels.show-your-comments")]
[:span {:class (stl/css :label)}
(tr "labels.show-your-comments")]
(when (= :yours cmode) (when (= :yours cmode)
[:span {:class (stl/css :icon)} [:span {:class (stl/css :icon)}
i/tick-refactor])] i/tick-refactor])]
[:li {:class (stl/css :separator)}] [:li {:class (stl/css :separator)}]
[:li {:class (stl/css-case :dropdown-element true [:li {:class (stl/css-case
:selected (= :pending cshow)) :dropdown-element true
:data-value (if (= :pending cshow) "all" "pending") :selected (= :pending cshow))
:data-value (d/name cshow)
:on-click update-show} :on-click update-show}
[:span {:class (stl/css :label)} (tr "labels.hide-resolved-comments")]
[:span {:class (stl/css :label)}
(tr "labels.hide-resolved-comments")]
(when (= :pending cshow) (when (= :pending cshow)
[:span {:class (stl/css :icon)} [:span {:class (stl/css :icon)}
i/tick-refactor])] i/tick-refactor])]
[:li {:class (stl/css :separator)}] [:li {:class (stl/css :separator)}]
[:li {:class (stl/css-case :dropdown-element true [:li {:class (stl/css-case
:selected show-sidebar?) :dropdown-element true
:data-value (str show-sidebar?) :selected show-sidebar?)
:data-value (dm/str show-sidebar?)
:on-click update-options} :on-click update-options}
[:span {:class (stl/css :label)} (tr "labels.show-comments-list")] [:span {:class (stl/css :label)} (tr "labels.show-comments-list")]
(when show-sidebar? (when show-sidebar?
[:span {:class (stl/css :icon)} i/tick-refactor])]]]])) [:span {:class (stl/css :icon)} i/tick-refactor])]]]]))
(defn- update-thread-position [positions {:keys [id] :as thread}] (defn- update-thread-position
[positions {:keys [id] :as thread}]
(if-let [data (get positions id)] (if-let [data (get positions id)]
(-> thread (-> thread
(assoc :position (:position data)) (assoc :position (:position data))
@ -122,7 +125,8 @@
thread)) thread))
(mf/defc comments-layer (mf/defc comments-layer
[{:keys [zoom file users frame page] :as props}] {::mf/props :obj}
[{:keys [zoom file users frame page]}]
(let [profile (mf/deref refs/profile) (let [profile (mf/deref refs/profile)
local (mf/deref refs/comments-local) local (mf/deref refs/comments-local)

View file

@ -104,7 +104,7 @@
position: absolute; position: absolute;
right: 0; right: 0;
top: $s-44; top: $s-44;
width: $s-256; width: $s-276;
height: calc(100vh - $s-48); height: calc(100vh - $s-48);
z-index: $z-index-10; z-index: $z-index-10;
background-color: var(--panel-background-color); background-color: var(--panel-background-color);

View file

@ -34,7 +34,8 @@
(modal/show! :login-register {})) (modal/show! :login-register {}))
(mf/defc zoom-widget (mf/defc zoom-widget
{::mf/wrap [mf/memo]} {::mf/memo true
::mf/props :obj}
[{:keys [zoom [{:keys [zoom
on-increase on-increase
on-decrease on-decrease
@ -102,38 +103,38 @@
[:span {:class (stl/css :shortcuts)} [:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))] (for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
[:span {:class (stl/css :shortcut-key) [:span {:class (stl/css :shortcut-key)
:key (str "zoom-fit-" sc)} sc])]] :key (dm/str "zoom-fit-" sc)} sc])]]
[:li {:class (stl/css :zoom-option) [:li {:class (stl/css :zoom-option)
:on-click on-zoom-fill} :on-click on-zoom-fill}
(tr "workspace.header.zoom-fill") (tr "workspace.header.zoom-fill")
[:span {:class (stl/css :shortcuts)} [:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))] (for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
[:span {:class (stl/css :shortcut-key) [:span {:class (stl/css :shortcut-key)
:key (str "zoom-fill-" sc)} sc])]] :key (dm/str "zoom-fill-" sc)} sc])]]
[:li {:class (stl/css :zoom-option) [:li {:class (stl/css :zoom-option)
:on-click on-fullscreen} :on-click on-fullscreen}
(tr "workspace.header.zoom-full-screen") (tr "workspace.header.zoom-full-screen")
[:span {:class (stl/css :shortcuts)} [:span {:class (stl/css :shortcuts)}
(for [sc (scd/split-sc (sc/get-tooltip :toggle-fullscreen))] (for [sc (scd/split-sc (sc/get-tooltip :toggle-fullscreen))]
[:span {:class (stl/css :shortcut-key) [:span {:class (stl/css :shortcut-key)
:key (str "zoom-fullscreen-" sc)} sc])]]]]])) :key (dm/str "zoom-fullscreen-" sc)} sc])]]]]]))
(mf/defc header-options (mf/defc header-options
[{:keys [section zoom page file index permissions interactions-mode]}] [{:keys [section zoom page file index permissions interactions-mode]}]
(let [fullscreen? (mf/deref fullscreen-ref) (let [fullscreen? (mf/deref fullscreen-ref)
toggle-fullscreen toggle-fullscreen
(mf/use-callback (mf/use-fn
(fn [] (st/emit! dv/toggle-fullscreen))) (fn [] (st/emit! dv/toggle-fullscreen)))
go-to-workspace go-to-workspace
(mf/use-callback (mf/use-fn
(mf/deps page) (mf/deps page)
(fn [] (fn []
(st/emit! (dv/go-to-workspace (:id page))))) (st/emit! (dv/go-to-workspace (:id page)))))
open-share-dialog open-share-dialog
(mf/use-callback (mf/use-fn
(mf/deps page) (mf/deps page)
(fn [] (fn []
(modal/show! :share-link {:page page :file file}) (modal/show! :share-link {:page page :file file})
@ -209,22 +210,22 @@
show-dropdown? (mf/use-state false) show-dropdown? (mf/use-state false)
toggle-thumbnails toggle-thumbnails
(mf/use-callback (mf/use-fn
(fn [] (fn []
(st/emit! dv/toggle-thumbnails-panel))) (st/emit! dv/toggle-thumbnails-panel)))
open-dropdown open-dropdown
(mf/use-callback (mf/use-fn
(fn [] (fn []
(reset! show-dropdown? true))) (reset! show-dropdown? true)))
close-dropdown close-dropdown
(mf/use-callback (mf/use-fn
(fn [] (fn []
(reset! show-dropdown? false))) (reset! show-dropdown? false)))
navigate-to navigate-to
(mf/use-callback (mf/use-fn
(fn [page-id] (fn [page-id]
(st/emit! (dv/go-to-page page-id)) (st/emit! (dv/go-to-page page-id))
(reset! show-dropdown? false)))] (reset! show-dropdown? false)))]
@ -245,8 +246,8 @@
(for [id (get-in file [:data :pages])] (for [id (get-in file [:data :pages])]
[:li {:class (stl/css-case :dropdown-element true [:li {:class (stl/css-case :dropdown-element true
:selected (= page-id id)) :selected (= page-id id))
:id (str id) :id (dm/str id)
:key (str id) :key (dm/str id)
:on-click (partial navigate-to id)} :on-click (partial navigate-to id)}
[:span {:class (stl/css :label)} [:span {:class (stl/css :label)}
(get-in file [:data :pages-index id :name])] (get-in file [:data :pages-index id :name])]

View file

@ -26,6 +26,8 @@
:align-content :align-content
:justify-items :justify-items
:justify-content :justify-content
:row-gap
:column-gap
:gap :gap
:padding]) :padding])

View file

@ -184,6 +184,7 @@
set-markup set-markup
(mf/use-callback (mf/use-callback
(mf/deps markup-type*)
(fn [value] (fn [value]
(reset! markup-type* value))) (reset! markup-type* value)))

View file

@ -20,6 +20,10 @@
} }
} }
.viewer-code {
padding: 0 $s-8;
}
.tool-windows { .tool-windows {
height: 100%; height: 100%;
display: flex; display: flex;

View file

@ -27,7 +27,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(mf/defc sidebar-options (mf/defc sidebar-options
[] [{:keys [from-viewer]}]
(let [{cmode :mode cshow :show} (mf/deref refs/comments-local) (let [{cmode :mode cshow :show} (mf/deref refs/comments-local)
update-mode update-mode
(mf/use-fn (mf/use-fn
@ -44,7 +44,8 @@
(let [mode (if (= :pending cshow) :all :pending)] (let [mode (if (= :pending cshow) :all :pending)]
(st/emit! (dcm/update-filters {:show mode})))))] (st/emit! (dcm/update-filters {:show mode})))))]
[:ul {:class (stl/css :comment-mode-dropdown)} [:ul {:class (stl/css-case :comment-mode-dropdown true
:viewer-dropdown from-viewer)}
[:li {:class (stl/css-case :dropdown-item true [:li {:class (stl/css-case :dropdown-item true
:selected (or (= :all cmode) (nil? cmode))) :selected (or (= :all cmode) (nil? cmode)))
:data-value "all" :data-value "all"
@ -115,8 +116,10 @@
(dwcm/center-to-comment-thread thread) (dwcm/center-to-comment-thread thread)
(-> (dcm/open-thread thread) (-> (dcm/open-thread thread)
(with-meta {::ev/origin "workspace"})))))))] (with-meta {::ev/origin "workspace"})))))))]
[:div {:class (stl/css :comments-section)} [:div {:class (stl/css-case :comments-section true
[:div {:class (stl/css :comments-section-title)} :from-viewer from-viewer)}
[:div {:class (stl/css-case :comments-section-title true
:viewer-title from-viewer)}
[:span (tr "labels.comments")] [:span (tr "labels.comments")]
[:button {:class (stl/css :close-button) [:button {:class (stl/css :close-button)
:on-click close-section} :on-click close-section}
@ -128,11 +131,11 @@
[:span {:class (stl/css :mode-label)} (case (:mode local) [:span {:class (stl/css :mode-label)} (case (:mode local)
(nil :all) (tr "labels.show-all-comments") (nil :all) (tr "labels.show-all-comments")
:yours (tr "labels.show-your-comments"))] :yours (tr "labels.show-your-comments"))]
[:div {:class (stl/css :icon)} i/arrow-refactor]] [:div {:class (stl/css :arrow-icon)} i/arrow-refactor]]
[:& dropdown {:show options? [:& dropdown {:show options?
:on-close #(reset! state* false)} :on-close #(reset! state* false)}
[:& sidebar-options {:local local}]] [:& sidebar-options {:local local :from-viewer from-viewer}]]
[:div {:class (stl/css :comments-section-content)} [:div {:class (stl/css :comments-section-content)}

View file

@ -13,6 +13,10 @@
grid-template-rows: $s-40 $s-48 1fr; grid-template-rows: $s-40 $s-48 1fr;
} }
.from-viewer {
padding: 0 $s-8;
}
.comments-section-title { .comments-section-title {
@include flexCenter; @include flexCenter;
@include uppercaseTitleTipography; @include uppercaseTitleTipography;
@ -29,6 +33,11 @@
} }
} }
.viewer-title {
margin: 0;
margin-block-start: $s-8;
}
.close-button { .close-button {
@extend .button-tertiary; @extend .button-tertiary;
position: absolute; position: absolute;
@ -48,7 +57,8 @@
@extend .asset-element; @extend .asset-element;
background-color: var(--color-background-tertiary); background-color: var(--color-background-tertiary);
display: flex; display: flex;
width: $s-256; width: 100%;
max-width: $s-256;
height: $s-32; height: $s-32;
padding: $s-8; padding: $s-8;
border-radius: $br-8; border-radius: $br-8;
@ -64,9 +74,8 @@
justify-content: flex-start; justify-content: flex-start;
} }
.icon { .arrow-icon {
@include flexCenter; @include flexCenter;
padding-right: 8px;
height: $s-24; height: $s-24;
width: $s-24; width: $s-24;
svg { svg {
@ -78,9 +87,14 @@
.comment-mode-dropdown { .comment-mode-dropdown {
@extend .dropdown-wrapper; @extend .dropdown-wrapper;
top: $s-80; top: $s-92;
left: $s-12; left: $s-12;
width: $s-256; max-width: $s-256;
width: 100%;
}
.viewer-dropdown {
left: $s-8;
} }
.dropdown-item { .dropdown-item {

View file

@ -355,6 +355,9 @@
(not (ctn/has-any-copy-parent? objects shape)) (not (ctn/has-any-copy-parent? objects shape))
(cfh/component-touched? objects (:id shape))))) (cfh/component-touched? objects (:id shape)))))
can-detach? (and (seq copies)
(every? #(not (ctn/has-any-copy-parent? objects %)) copies))
do-detach-component do-detach-component
#(st/emit! (dwl/detach-components (map :id copies))) #(st/emit! (dwl/detach-components (map :id copies)))
@ -420,7 +423,7 @@
(when (and (not multi) main-instance? local-component? lacks-annotation? components-v2) (when (and (not multi) main-instance? local-component? lacks-annotation? components-v2)
{:msg "workspace.shape.menu.create-annotation" {:msg "workspace.shape.menu.create-annotation"
:action do-create-annotation}) :action do-create-annotation})
(when (seq copies) (when can-detach?
{:msg (if (> (count copies) 1) {:msg (if (> (count copies) 1)
"workspace.shape.menu.detach-instances-in-bulk" "workspace.shape.menu.detach-instances-in-bulk"
"workspace.shape.menu.detach-instance") "workspace.shape.menu.detach-instance")

View file

@ -155,7 +155,8 @@
children])) children]))
(mf/defc layer-item (mf/defc layer-item
{::mf/wrap-props false} {::mf/wrap-props false
::mf/wrap [mf/memo]}
[{:keys [index item selected objects sortable? filtered? depth parent-size component-child? highlighted]}] [{:keys [index item selected objects sortable? filtered? depth parent-size component-child? highlighted]}]
(let [id (:id item) (let [id (:id item)
blocked? (:blocked item) blocked? (:blocked item)

View file

@ -21,19 +21,51 @@
[app.main.ui.icons :as i] [app.main.ui.icons :as i]
[app.main.ui.workspace.sidebar.layer-item :refer [layer-item]] [app.main.ui.workspace.sidebar.layer-item :refer [layer-item]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.globals :as globals]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
[app.util.timers :as ts] [app.util.timers :as ts]
[beicon.v2.core :as rx]
[cuerdas.core :as str] [cuerdas.core :as str]
[rumext.v2 :as mf])) [goog.events :as events]
[rumext.v2 :as mf])
(:import goog.events.EventType))
;; This components is a piece for sharding equality check between top ;; This components is a piece for sharding equality check between top
;; level frames and try to avoid rerender frames that are does not ;; level frames and try to avoid rerender frames that are does not
;; affected by the selected set. ;; affected by the selected set.
(mf/defc frame-wrapper (mf/defc frame-wrapper
{::mf/wrap-props false {::mf/wrap-props false}
::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
[props] [props]
[:> layer-item props]) (let [selected (obj/get props "selected")
callback (mf/use-var false)
pending-selected (mf/use-var selected)
current-selected (mf/use-state selected)
props
(-> props
(obj/clone)
(obj/set! "selected" @current-selected))]
(mf/use-effect
(mf/deps selected)
(fn []
;; Change in selected we schedule a idle-then-raf
;; following changes will update the pending but not create
;; a new callbacks
(reset! pending-selected selected)
(when (not @callback)
(reset!
callback
(ts/idle-then-raf
(fn []
(reset! current-selected @pending-selected)
(reset! callback nil)))))
(fn []
(when @callback
(rx/dispose! @callback)))))
[:> layer-item props]))
(mf/defc layers-tree (mf/defc layers-tree
{::mf/wrap [mf/memo #(mf/throttle % 200)] {::mf/wrap [mf/memo #(mf/throttle % 200)]
@ -158,6 +190,21 @@
(mf/use-fn (mf/use-fn
#(swap! state* update :show-menu not)) #(swap! state* update :show-menu not))
on-toggle-filters-click
(mf/use-fn
(fn [event]
(dom/stop-propagation event)
(toggle-filters)))
hide-menu
(mf/use-fn
#(swap! state* assoc :show-menu false))
on-key-down
(mf/use-fn
(fn [event]
(when (kbd/esc? event) (hide-menu))))
update-search-text update-search-text
(mf/use-fn (mf/use-fn
(fn [value _event] (fn [value _event]
@ -190,6 +237,7 @@
add-filter add-filter
(mf/use-fn (mf/use-fn
(fn [event] (fn [event]
(dom/stop-propagation event)
(let [key (-> (dom/get-current-target event) (let [key (-> (dom/get-current-target event)
(dom/get-data "filter") (dom/get-data "filter")
(keyword))] (keyword))]
@ -226,6 +274,11 @@
(when (<= current-items filtered-objects-total) (when (<= current-items filtered-objects-total)
(swap! state* update :num-items + 100))))] (swap! state* update :num-items + 100))))]
(mf/with-effect []
(let [keys [(events/listen globals/document EventType.KEYDOWN on-key-down)
(events/listen globals/document EventType.CLICK hide-menu)]]
(fn [] (doseq [key keys] (events/unlistenByKey key)))))
[filtered-objects [filtered-objects
handle-show-more handle-show-more
#(mf/html #(mf/html
@ -236,7 +289,7 @@
:value current-search :value current-search
:on-clear clear-search-text :on-clear clear-search-text
:placeholder (tr "workspace.sidebar.layers.search")} :placeholder (tr "workspace.sidebar.layers.search")}
[:button {:on-click toggle-filters [:button {:on-click on-toggle-filters-click
:class (stl/css-case :class (stl/css-case
:filter-button true :filter-button true
:opened show-menu? :opened show-menu?
@ -459,7 +512,7 @@
(mf/use-fn (mf/use-fn
#(st/emit! (dw/toggle-focus-mode)))] #(st/emit! (dw/toggle-focus-mode)))]
[:div#layers [:div#layers {:class (stl/css :layers)}
(if (d/not-empty? focus) (if (d/not-empty? focus)
[:div {:class (stl/css :tool-window-bar)} [:div {:class (stl/css :tool-window-bar)}
[:button {:class (stl/css :focus-title) [:button {:class (stl/css :focus-title)

View file

@ -12,7 +12,7 @@
justify-content: space-between; justify-content: space-between;
height: $s-32; height: $s-32;
min-height: $s-32; min-height: $s-32;
margin: $s-4 0 $s-4 $s-8; margin: $s-8 0 $s-4 $s-8;
padding-right: $s-8; padding-right: $s-8;
&.search { &.search {
@ -164,10 +164,14 @@
color: var(--pill-foreground-color); color: var(--pill-foreground-color);
} }
.layers {
position: relative;
}
.filters-container { .filters-container {
@extend .menu-dropdown; @extend .menu-dropdown;
top: $s-44; position: absolute;
left: $s-12; left: $s-20;
width: $s-192; width: $s-192;
.filter-menu-item { .filter-menu-item {
@include bodyMedTipography; @include bodyMedTipography;

View file

@ -522,7 +522,8 @@
(when open? (when open?
[:div {:class (stl/css :element-content)} [:div {:class (stl/css :element-content)}
[:div {:class (stl/css-case :component-wrapper true [:div {:class (stl/css-case :component-wrapper true
:with-actions show-menu?)} :with-actions show-menu?
:without-actions (not show-menu?))}
[:button {:class (stl/css-case :component-name-wrapper true [:button {:class (stl/css-case :component-name-wrapper true
:with-main (and can-swap? (not multi)) :with-main (and can-swap? (not multi))
:swappeable (and can-swap? (not swap-opened?))) :swappeable (and can-swap? (not swap-opened?)))

View file

@ -51,6 +51,15 @@
grid-template-columns: 1fr $s-28; grid-template-columns: 1fr $s-28;
gap: $s-2; gap: $s-2;
} }
&.without-actions {
padding-right: 0.5rem;
.component-name-wrapper {
width: 100%;
border-radius: $br-8;
}
}
} }
.component-name-wrapper { .component-name-wrapper {

View file

@ -357,13 +357,14 @@
(update-interaction index #(ctsi/set-offset-effect % value))))) (update-interaction index #(ctsi/set-offset-effect % value)))))
event-type-options [{:value :click :label (tr "workspace.options.interaction-on-click")} event-type-options (-> [{:value :click :label (tr "workspace.options.interaction-on-click")}
;; TODO: need more UX research ;; TODO: need more UX research
;; :mouse-over (tr "workspace.options.interaction-while-hovering") ;; :mouse-over (tr "workspace.options.interaction-while-hovering")
;; :mouse-press (tr "workspace.options.interaction-while-pressing") ;; :mouse-press (tr "workspace.options.interaction-while-pressing")
{:value :mouse-enter :label (tr "workspace.options.interaction-mouse-enter")} {:value :mouse-enter :label (tr "workspace.options.interaction-mouse-enter")}
{:value :mouse-leave :label (tr "workspace.options.interaction-mouse-leave")} {:value :mouse-leave :label (tr "workspace.options.interaction-mouse-leave")}]
{:value :after-delay :label (tr "workspace.options.interaction-after-delay")}] (cond-> (cfh/frame-shape? shape)
(conj {:value :after-delay :label (tr "workspace.options.interaction-after-delay")})))
action-type-options [{:value :navigate :label (tr "workspace.options.interaction-navigate-to")} action-type-options [{:value :navigate :label (tr "workspace.options.interaction-navigate-to")}
{:value :open-overlay :label (tr "workspace.options.interaction-open-overlay")} {:value :open-overlay :label (tr "workspace.options.interaction-open-overlay")}

View file

@ -20,8 +20,7 @@
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]] [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf] [rumext.v2 :as mf]))
[rumext.v2.props :as-alias mf.props]))
(def layout-item-attrs (def layout-item-attrs
[:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} [:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0}
@ -46,14 +45,14 @@
(mf/defc margin-simple (mf/defc margin-simple
{::mf/props :obj} {::mf/props :obj}
[{:keys [margin on-change on-blur]}] [{:keys [value on-change on-blur]}]
(let [m1 (:m1 margin) (let [m1 (:m1 value)
m2 (:m2 margin) m2 (:m2 value)
m3 (:m3 margin) m3 (:m3 value)
m4 (:m4 margin) m4 (:m4 value)
m1 (when (and (not= margin :multiple) (= m1 m3)) m1) m1 (when (and (not= value :multiple) (= m1 m3)) m1)
m2 (when (and (not= margin :multiple) (= m2 m4)) m2) m2 (when (and (not= value :multiple) (= m2 m4)) m2)
on-focus on-focus
(mf/use-fn (mf/use-fn
@ -106,11 +105,11 @@
(mf/defc margin-multiple (mf/defc margin-multiple
{::mf/props :obj} {::mf/props :obj}
[{:keys [margin on-change on-blur]}] [{:keys [value on-change on-blur]}]
(let [m1 (:m1 margin) (let [m1 (:m1 value)
m2 (:m2 margin) m2 (:m2 value)
m3 (:m3 margin) m3 (:m3 value)
m4 (:m4 margin) m4 (:m4 value)
on-focus on-focus
(mf/use-fn (mf/use-fn
@ -186,11 +185,11 @@
(mf/defc margin-section (mf/defc margin-section
{::mf/props :obj {::mf/props :obj
::mf/private true ::mf/private true
::mf.props/expect #{:margin :type :on-type-change :on-change}} ::mf/expect-props #{:value :type :on-type-change :on-change}}
[{:keys [type on-type-change] :as props}] [{:keys [type on-type-change] :as props}]
(let [type (d/nilv type :simple) (let [type (d/nilv type :simple)
on-blur (mf/use-fn #(select-margins false false false false)) on-blur (mf/use-fn #(select-margins false false false false))
props (mf/spread-obj props {:on-blur on-blur}) props (mf/spread props :on-blur on-blur)
on-type-change' on-type-change'
(mf/use-fn (mf/use-fn
@ -220,14 +219,17 @@
i/margin-refactor]])) i/margin-refactor]]))
(mf/defc element-behaviour-horizontal (mf/defc element-behaviour-horizontal
{::mf/props :obj} {::mf/props :obj
[{:keys [^boolean is-auto ^boolean has-fill sizing on-change]}] ::mf/private true}
[:div {:class (stl/css-case :horizontal-behaviour true [{:keys [^boolean is-auto ^boolean has-fill value on-change]}]
:one-element (and (not has-fill) (not is-auto)) [:div {:class (stl/css-case
:two-element (or has-fill is-auto) :horizontal-behaviour true
:three-element (and has-fill is-auto))} :one-element (and (not has-fill) (not is-auto))
:two-element (or has-fill is-auto)
:three-element (and has-fill is-auto))}
[:& radio-buttons [:& radio-buttons
{:selected (d/name sizing) {:selected (d/name value)
:decode-fn keyword
:on-change on-change :on-change on-change
:wide true :wide true
:name "flex-behaviour-h"} :name "flex-behaviour-h"}
@ -252,14 +254,17 @@
:id "behaviour-h-auto"}])]]) :id "behaviour-h-auto"}])]])
(mf/defc element-behaviour-vertical (mf/defc element-behaviour-vertical
{::mf/props :obj} {::mf/props :obj
[{:keys [^boolean is-auto ^boolean has-fill sizing on-change]}] ::mf/private true}
[:div {:class (stl/css-case :vertical-behaviour true [{:keys [^boolean is-auto ^boolean has-fill value on-change]}]
:one-element (and (not has-fill) (not is-auto)) [:div {:class (stl/css-case
:two-element (or has-fill is-auto) :vertical-behaviour true
:three-element (and has-fill is-auto))} :one-element (and (not has-fill) (not is-auto))
:two-element (or has-fill is-auto)
:three-element (and has-fill is-auto))}
[:& radio-buttons [:& radio-buttons
{:selected (d/name sizing) {:selected (d/name value)
:decode-fn keyword
:on-change on-change :on-change on-change
:wide true :wide true
:name "flex-behaviour-v"} :name "flex-behaviour-v"}
@ -286,34 +291,11 @@
:title "Fit content" :title "Fit content"
:id "behaviour-v-auto"}])]]) :id "behaviour-v-auto"}])]])
(mf/defc element-behaviour
{::mf/props :obj
::mf/private true}
[{:keys [^boolean is-auto
^boolean has-fill
h-sizing
v-sizing
on-h-change
on-v-change]}]
[:div {:class (stl/css-case
:behaviour-menu true
:wrap (and has-fill is-auto))}
[:& element-behaviour-horizontal
{:is-auto is-auto
:has-fill has-fill
:sizing h-sizing
:on-change on-h-change}]
[:& element-behaviour-vertical
{:is-auto is-auto
:has-fill has-fill
:sizing v-sizing
:on-change on-v-change}]])
(mf/defc align-self-row (mf/defc align-self-row
{::mf/props :obj} {::mf/props :obj}
[{:keys [^boolean is-col align-self on-change]}] [{:keys [^boolean is-col value on-change]}]
[:& radio-buttons {:selected (d/name align-self) [:& radio-buttons {:selected (d/name value)
:decode-fn keyword
:on-change on-change :on-change on-change
:name "flex-align-self" :name "flex-align-self"
:allow-empty true} :allow-empty true}
@ -392,16 +374,16 @@
:else :else
"Layout element") "Layout element")
set-align-self on-align-self-change
(mf/use-fn (mf/use-fn
(mf/deps ids align-self) (mf/deps ids align-self)
(fn [value] (fn [value]
(if (= align-self value) (if (= align-self value)
(st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil})) (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self nil}))
(st/emit! (dwsl/update-layout-child ids {:layout-item-align-self (keyword value)}))))) (st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))))
;; Margin ;; Margin
on-change-margin-type on-margin-type-change
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
(fn [type] (fn [type]
@ -422,19 +404,17 @@
(st/emit! (dwsl/update-layout-child ids {:layout-item-margin {prop val}}))))) (st/emit! (dwsl/update-layout-child ids {:layout-item-margin {prop val}})))))
;; Behaviour ;; Behaviour
on-change-behaviour-h on-behaviour-h-change
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
(fn [value] (fn [value]
(let [value (keyword value)] (st/emit! (dwsl/update-layout-child ids {:layout-item-h-sizing value}))))
(st/emit! (dwsl/update-layout-child ids {:layout-item-h-sizing value})))))
on-change-behaviour-v on-behaviour-v-change
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
(fn [value] (fn [value]
(let [value (keyword value)] (st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing value}))))
(st/emit! (dwsl/update-layout-child ids {:layout-item-v-sizing value})))))
;; Size and position ;; Size and position
on-size-change on-size-change
@ -450,10 +430,9 @@
(mf/use-fn (mf/use-fn
(mf/deps ids) (mf/deps ids)
(fn [value] (fn [value]
(let [value (keyword value)] (when (= value :static)
(when (= value :static) (st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil})))
(st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil}))) (st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)}))))
(st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)})))))
;; Z Index ;; Z Index
on-change-z-index on-change-z-index
@ -476,6 +455,7 @@
[:div {:class (stl/css :row)} [:div {:class (stl/css :row)}
[:div {:class (stl/css :position-options)} [:div {:class (stl/css :position-options)}
[:& radio-buttons {:selected (if is-absolute? "absolute" "static") [:& radio-buttons {:selected (if is-absolute? "absolute" "static")
:decode-fn keyword
:on-change on-change-position :on-change on-change-position
:name "layout-style" :name "layout-style"
:wide true} :wide true}
@ -497,24 +477,32 @@
:value (:layout-item-z-index values)}]]]) :value (:layout-item-z-index values)}]]])
[:div {:class (stl/css :row)} [:div {:class (stl/css :row)}
[:& element-behaviour {:has-fill is-layout-child? [:div {:class (stl/css-case
:is-auto is-layout-container? :behaviour-menu true
:v-sizing (:layout-item-v-sizing values) :wrap (and ^boolean is-layout-child?
:h-sizing (:layout-item-h-sizing values) ^boolean is-layout-container?))}
:on-h-change on-change-behaviour-h [:& element-behaviour-horizontal
:on-v-change on-change-behaviour-v}]] {:is-auto is-layout-container?
:has-fill is-layout-child?
:value (:layout-item-h-sizing values)
:on-change on-behaviour-h-change}]
[:& element-behaviour-vertical
{:is-auto is-layout-container?
:has-fill is-layout-child?
:value (:layout-item-v-sizing values)
:on-change on-behaviour-v-change}]]]
(when (and is-layout-child? is-flex-parent?) (when (and is-layout-child? is-flex-parent?)
[:div {:class (stl/css :row)} [:div {:class (stl/css :row)}
[:& align-self-row {:is-col is-col? [:& align-self-row {:is-col is-col?
:align-self align-self :value align-self
:on-change set-align-self}]]) :on-change on-align-self-change}]])
(when is-layout-child? (when is-layout-child?
[:div {:class (stl/css :row)} [:div {:class (stl/css :row)}
[:& margin-section {:margin (:layout-item-margin values) [:& margin-section {:value (:layout-item-margin values)
:type (:layout-item-margin-type values) :type (:layout-item-margin-type values)
:on-type-change on-change-margin-type :on-type-change on-margin-type-change
:on-change on-margin-change}]]) :on-change on-margin-change}]])
(when (or (= h-sizing :fill) (when (or (= h-sizing :fill)

View file

@ -632,6 +632,7 @@
(not= @hover-top-frame-id (:id frame))) (not= @hover-top-frame-id (:id frame)))
[:& grid-layout/editor [:& grid-layout/editor
{:zoom zoom {:zoom zoom
:key (dm/str (:id frame))
:objects base-objects :objects base-objects
:modifiers modifiers :modifiers modifiers
:shape frame :shape frame

View file

@ -113,7 +113,7 @@
(+ (:y start-p) (/ 9 zoom))]) (+ (:y start-p) (/ 9 zoom))])
handle-click handle-click
(mf/use-callback (mf/use-fn
(mf/deps on-click) (mf/deps on-click)
#(when on-click (on-click)))] #(when on-click (on-click)))]
@ -142,7 +142,7 @@
current-pos-ref (mf/use-ref nil) current-pos-ref (mf/use-ref nil)
handle-pointer-down handle-pointer-down
(mf/use-callback (mf/use-fn
(mf/deps on-drag-start) (mf/deps on-drag-start)
(fn [event] (fn [event]
(let [raw-pt (dom/get-client-position event) (let [raw-pt (dom/get-client-position event)
@ -154,7 +154,7 @@
(when on-drag-start (on-drag-start event position))))) (when on-drag-start (on-drag-start event position)))))
handle-lost-pointer-capture handle-lost-pointer-capture
(mf/use-callback (mf/use-fn
(mf/deps on-drag-end) (mf/deps on-drag-end)
(fn [event] (fn [event]
(let [raw-pt (mf/ref-val current-pos-ref) (let [raw-pt (mf/ref-val current-pos-ref)
@ -165,7 +165,7 @@
(when on-drag-end (on-drag-end event position))))) (when on-drag-end (on-drag-end event position)))))
handle-pointer-move handle-pointer-move
(mf/use-callback (mf/use-fn
(mf/deps on-drag-delta on-drag-position) (mf/deps on-drag-delta on-drag-position)
(fn [event] (fn [event]
(when (mf/ref-val dragging-ref) (when (mf/ref-val dragging-ref)
@ -198,7 +198,7 @@
layout-data (unchecked-get props "layout-data") layout-data (unchecked-get props "layout-data")
handle-drag-position handle-drag-position
(mf/use-callback (mf/use-fn
(mf/deps shape row column row-span column-span) (mf/deps shape row column row-span column-span)
(fn [_ position] (fn [_ position]
(let [[drag-row drag-column] (gsg/get-position-grid-coord layout-data position) (let [[drag-row drag-column] (gsg/get-position-grid-coord layout-data position)
@ -235,7 +235,7 @@
(st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers)))))) (st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers))))))
handle-drag-end handle-drag-end
(mf/use-callback (mf/use-fn
(fn [] (fn []
(st/emit! (dwm/apply-modifiers)))) (st/emit! (dwm/apply-modifiers))))
@ -291,17 +291,10 @@
text]])) text]]))
(mf/defc grid-cell (mf/defc grid-cell
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "cell" "layout-data" "zoom" "hover?" "selected?"]))] {::mf/memo #{:shape :cell :layout-data :zoom :hover? :selected?}
::mf/wrap-props false} ::mf/props :obj}
[props] [{:keys [shape cell layout-data zoom hover? selected?]}]
(let [shape (unchecked-get props "shape") (let [cell-bounds (gsg/cell-bounds layout-data cell)
cell (unchecked-get props "cell")
layout-data (unchecked-get props "layout-data")
zoom (unchecked-get props "zoom")
hover? (unchecked-get props "hover?")
selected? (unchecked-get props "selected?")
cell-bounds (gsg/cell-bounds layout-data cell)
cell-origin (gpo/origin cell-bounds) cell-origin (gpo/origin cell-bounds)
cell-width (gpo/width-points cell-bounds) cell-width (gpo/width-points cell-bounds)
cell-height (gpo/height-points cell-bounds) cell-height (gpo/height-points cell-bounds)
@ -309,19 +302,19 @@
cell-origin (gpt/transform cell-origin (gmt/transform-in cell-center (:transform-inverse shape))) cell-origin (gpt/transform cell-origin (gmt/transform-in cell-center (:transform-inverse shape)))
handle-pointer-enter handle-pointer-enter
(mf/use-callback (mf/use-fn
(mf/deps (:id shape) (:id cell)) (mf/deps (:id shape) (:id cell))
(fn [] (fn []
(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) true)))) (st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) true))))
handle-pointer-leave handle-pointer-leave
(mf/use-callback (mf/use-fn
(mf/deps (:id shape) (:id cell)) (mf/deps (:id shape) (:id cell))
(fn [] (fn []
(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) false)))) (st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) false))))
handle-pointer-down handle-pointer-down
(mf/use-callback (mf/use-fn
(mf/deps (:id shape) (:id cell) selected?) (mf/deps (:id shape) (:id cell) selected?)
(fn [event] (fn [event]
(when (dom/left-mouse? event) (when (dom/left-mouse? event)
@ -339,7 +332,7 @@
(st/emit! (dwge/set-selection (:id shape) (:id cell))))))) (st/emit! (dwge/set-selection (:id shape) (:id cell)))))))
handle-context-menu handle-context-menu
(mf/use-callback (mf/use-fn
(mf/deps (:id shape) (:id cell) selected?) (mf/deps (:id shape) (:id cell) selected?)
(fn [event] (fn [event]
(dom/prevent-default event) (dom/prevent-default event)
@ -424,7 +417,7 @@
start-size-after (mf/use-var nil) start-size-after (mf/use-var nil)
handle-drag-start handle-drag-start
(mf/use-callback (mf/use-fn
(mf/deps shape track-before track-after) (mf/deps shape track-before track-after)
(fn [] (fn []
(reset! start-size-before (:size track-before)) (reset! start-size-before (:size track-before))
@ -444,7 +437,7 @@
(st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers)))))) (st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers))))))
handle-drag-position handle-drag-position
(mf/use-callback (mf/use-fn
(mf/deps shape track-before track-after) (mf/deps shape track-before track-after)
(fn [_ position] (fn [_ position]
(let [[tracks-prop axis] (let [[tracks-prop axis]
@ -469,7 +462,7 @@
(st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers)))))) (st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers))))))
handle-drag-end handle-drag-end
(mf/use-callback (mf/use-fn
(mf/deps track-before track-after) (mf/deps track-before track-after)
(fn [] (fn []
(reset! start-size-before nil) (reset! start-size-before nil)
@ -732,7 +725,7 @@
text-p (if (= type :column) hpt vpt) text-p (if (= type :column) hpt vpt)
handle-blur-track-input handle-blur-track-input
(mf/use-callback (mf/use-fn
(mf/deps (:id shape)) (mf/deps (:id shape))
(fn [event] (fn [event]
(let [target (-> event dom/get-target) (let [target (-> event dom/get-target)
@ -760,7 +753,7 @@
(obj/set! target "value" (dom/get-attribute target "data-default-value")))))) (obj/set! target "value" (dom/get-attribute target "data-default-value"))))))
handle-keydown-track-input handle-keydown-track-input
(mf/use-callback (mf/use-fn
(fn [event] (fn [event]
(let [enter? (kbd/enter? event) (let [enter? (kbd/enter? event)
esc? (kbd/esc? event)] esc? (kbd/esc? event)]
@ -770,13 +763,13 @@
(dom/blur! (dom/get-target event)))))) (dom/blur! (dom/get-target event))))))
handle-pointer-enter handle-pointer-enter
(mf/use-callback (mf/use-fn
(mf/deps (:id shape) type index) (mf/deps (:id shape) type index)
(fn [] (fn []
(st/emit! (dwsl/hover-layout-track [(:id shape)] type index true)))) (st/emit! (dwsl/hover-layout-track [(:id shape)] type index true))))
handle-pointer-leave handle-pointer-leave
(mf/use-callback (mf/use-fn
(mf/deps (:id shape) type index) (mf/deps (:id shape) type index)
(fn [] (fn []
(st/emit! (dwsl/hover-layout-track [(:id shape)] type index false)))) (st/emit! (dwsl/hover-layout-track [(:id shape)] type index false))))
@ -788,25 +781,25 @@
[(- (:x text-p) (max 0 (:size track-data))) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)]) [(- (:x text-p) (max 0 (:size track-data))) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)])
handle-drag-start handle-drag-start
(mf/use-callback (mf/use-fn
(mf/deps on-start-reorder-track type index) (mf/deps on-start-reorder-track type index)
(fn [] (fn []
(on-start-reorder-track type index))) (on-start-reorder-track type index)))
handle-drag-end handle-drag-end
(mf/use-callback (mf/use-fn
(mf/deps on-end-reorder-track type index) (mf/deps on-end-reorder-track type index)
(fn [event position] (fn [event position]
(on-end-reorder-track type index position (not (kbd/mod? event))))) (on-end-reorder-track type index position (not (kbd/mod? event)))))
handle-drag-position handle-drag-position
(mf/use-callback (mf/use-fn
(mf/deps on-move-reorder-track type index) (mf/deps on-move-reorder-track type index)
(fn [_ position] (fn [_ position]
(on-move-reorder-track type index position))) (on-move-reorder-track type index position)))
handle-show-track-menu handle-show-track-menu
(mf/use-callback (mf/use-fn
(fn [event] (fn [event]
(dom/stop-propagation event) (dom/stop-propagation event)
(dom/prevent-default event) (dom/prevent-default event)
@ -895,10 +888,9 @@
:zoom zoom}]])) :zoom zoom}]]))
(mf/defc editor (mf/defc editor
{::mf/wrap [mf/memo] {::mf/memo true
::mf/wrap-props false} ::mf/props :obj}
[props] [props]
(let [base-shape (unchecked-get props "shape") (let [base-shape (unchecked-get props "shape")
objects (unchecked-get props "objects") objects (unchecked-get props "objects")
modifiers (unchecked-get props "modifiers") modifiers (unchecked-get props "modifiers")
@ -962,31 +954,30 @@
height (max (gpo/height-points bounds) (+ row-total-size row-total-gap (ctl/v-padding shape))) height (max (gpo/height-points bounds) (+ row-total-size row-total-gap (ctl/v-padding shape)))
handle-pointer-down handle-pointer-down
(mf/use-callback (mf/use-fn
(fn [event] (fn [event]
(let [left-click? (= 1 (.-which (.-nativeEvent event)))] (let [left-click? (= 1 (.-which (.-nativeEvent event)))]
(when left-click? (when left-click?
(dom/stop-propagation event))))) (dom/stop-propagation event)))))
handle-add-column handle-add-column
(mf/use-callback (mf/use-fn
(mf/deps (:id shape)) (mf/deps (:id shape))
(fn [] (fn []
(st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :column ctl/default-track-value))))) (st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :column ctl/default-track-value)))))
handle-add-row handle-add-row
(mf/use-callback (mf/use-fn
(mf/deps (:id shape)) (mf/deps (:id shape))
(fn [] (fn []
(st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :row ctl/default-track-value))))) (st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :row ctl/default-track-value)))))
target-tracks* (mf/use-ref nil) target-tracks* (mf/use-ref nil)
drop-track-type* (mf/use-state nil) drop-track-type* (mf/use-state nil)
drop-track-target* (mf/use-state nil) drop-track-target* (mf/use-state nil)
handle-start-reorder-track handle-start-reorder-track
(mf/use-callback (mf/use-fn
(mf/deps layout-data) (mf/deps layout-data)
(fn [type _from-idx] (fn [type _from-idx]
;; Initialize target-tracks ;; Initialize target-tracks
@ -1014,7 +1005,7 @@
(reset! drop-track-type* type)))) (reset! drop-track-type* type))))
handle-move-reorder-track handle-move-reorder-track
(mf/use-callback (mf/use-fn
(fn [_type _from-idx position] (fn [_type _from-idx position]
(let [index (let [index
(->> (mf/ref-val target-tracks*) (->> (mf/ref-val target-tracks*)
@ -1025,7 +1016,7 @@
(reset! drop-track-target* index))))) (reset! drop-track-target* index)))))
handle-end-reorder-track handle-end-reorder-track
(mf/use-callback (mf/use-fn
(mf/deps base-shape @drop-track-target*) (mf/deps base-shape @drop-track-target*)
(fn [type from-index _position move-content?] (fn [type from-index _position move-content?]
(when-let [to-index @drop-track-target*] (when-let [to-index @drop-track-target*]
@ -1041,9 +1032,8 @@
(reset! drop-track-type* nil) (reset! drop-track-type* nil)
(reset! drop-track-target* nil)))] (reset! drop-track-target* nil)))]
(mf/use-effect (mf/with-effect []
(fn [] #(st/emit! (dwge/stop-grid-layout-editing (:id shape))))
#(st/emit! (dwge/stop-grid-layout-editing (:id shape)))))
(when (and (not (:hidden shape)) (not (:blocked shape))) (when (and (not (:hidden shape)) (not (:blocked shape)))
[:g.grid-editor {:pointer-events (when view-only "none") [:g.grid-editor {:pointer-events (when view-only "none")
@ -1057,7 +1047,8 @@
:zoom zoom :zoom zoom
:hover? (contains? hover-cells (:id cell)) :hover? (contains? hover-cells (:id cell))
:selected? (contains? selected-cells (:id cell))}])] :selected? (contains? selected-cells (:id cell))}])]
(when-not view-only
(when-not ^boolean view-only
[:* [:*
[:& grid-editor-frame {:zoom zoom [:& grid-editor-frame {:zoom zoom
:bounds bounds :bounds bounds

View file

@ -291,7 +291,7 @@
(not (ctk/main-instance? obj)))) (not (ctk/main-instance? obj))))
;; Set with the elements to remove from the hover list ;; Set with the elements to remove from the hover list
remove-id-xf remove-hover-xf
(cond (cond
mod? mod?
(filter grouped?) (filter grouped?)
@ -306,8 +306,25 @@
(and (contains? #{:group :bool} (dm/get-in objects [% :type])) (and (contains? #{:group :bool} (dm/get-in objects [% :type]))
(not (contains? child-parent? %))))))) (not (contains? child-parent? %)))))))
remove-id? remove-measure-xf
(into selected-with-parents remove-id-xf ids) (cond
mod?
(filter grouped?)
(not mod?)
(let [child-parent?
(into #{}
(comp (remove #(cfh/group-like-shape? objects %))
(mapcat #(cfh/get-parent-ids objects %)))
ids)]
(filter #(and (contains? #{:group :bool} (dm/get-in objects [% :type]))
(not (contains? child-parent? %))))))
remove-hover?
(into selected-with-parents remove-hover-xf ids)
remove-measure?
(into selected-with-parents remove-measure-xf ids)
no-fill-nested-frames? no-fill-nested-frames?
(fn [id] (fn [id]
@ -318,7 +335,7 @@
hover-shape hover-shape
(->> ids (->> ids
(remove remove-id?) (remove remove-hover?)
(remove (partial cfh/hidden-parent? objects)) (remove (partial cfh/hidden-parent? objects))
(remove #(and mod? (no-fill-nested-frames? %))) (remove #(and mod? (no-fill-nested-frames? %)))
(filter #(or (empty? focus) (cpf/is-in-focus? objects focus %))) (filter #(or (empty? focus) (cpf/is-in-focus? objects focus %)))
@ -329,14 +346,12 @@
measure-hover-shape measure-hover-shape
(when show-measures? (when show-measures?
(->> ids (->> ids
(remove #(group-empty-space? % objects ids)) (remove remove-measure?)
(remove (partial cfh/hidden-parent? objects)) (remove (partial cfh/hidden-parent? objects))
(remove #(and mod? (no-fill-nested-frames? %))) (remove #(and mod? (no-fill-nested-frames? %)))
(filter #(or (empty? focus) (cpf/is-in-focus? objects focus %))) (filter #(or (empty? focus) (cpf/is-in-focus? objects focus %)))
(first) (first)
(get objects)))] (get objects)))]
(reset! hover hover-shape) (reset! hover hover-shape)
(reset! measure-hover measure-hover-shape) (reset! measure-hover measure-hover-shape)
(reset! hover-ids ids))) (reset! hover-ids ids)))

View file

@ -6,22 +6,7 @@
(ns app.util.time (ns app.util.time
(:require (:require
["date-fns/format" :default dateFnsFormat] ["./time_impl.js" :as impl]
["date-fns/formatDistanceToNowStrict" :default dateFnsFormatDistanceToNowStrict]
["date-fns/locale/ar-SA" :default dateFnsLocalesAr]
["date-fns/locale/ca" :default dateFnsLocalesCa]
["date-fns/locale/de" :default dateFnsLocalesDe]
["date-fns/locale/el" :default dateFnsLocalesEl]
["date-fns/locale/en-US" :default dateFnsLocalesEnUs]
["date-fns/locale/es" :default dateFnsLocalesEs]
["date-fns/locale/fa-IR" :default dateFnsLocalesFa]
["date-fns/locale/fr" :default dateFnsLocalesFr]
["date-fns/locale/he" :default dateFnsLocalesHe]
["date-fns/locale/pt-BR" :default dateFnsLocalesPtBr]
["date-fns/locale/ro" :default dateFnsLocalesRo]
["date-fns/locale/ru" :default dateFnsLocalesRu]
["date-fns/locale/tr" :default dateFnsLocalesTr]
["date-fns/locale/zh-CN" :default dateFnsLocalesZhCn]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.time :as common-time] [app.common.time :as common-time]
[app.util.object :as obj] [app.util.object :as obj]
@ -207,22 +192,6 @@
:json (.toJSON it) :json (.toJSON it)
(.toFormat ^js it fmt)))) (.toFormat ^js it fmt))))
(def ^:private locales
#js {:en dateFnsLocalesEnUs
:ar dateFnsLocalesAr
:he dateFnsLocalesHe
:fr dateFnsLocalesFr
:tr dateFnsLocalesTr
:es dateFnsLocalesEs
:ca dateFnsLocalesCa
:el dateFnsLocalesEl
:ru dateFnsLocalesRu
:ro dateFnsLocalesRo
:de dateFnsLocalesDe
:fa dateFnsLocalesFa
:pt_br dateFnsLocalesPtBr
:zh_cn dateFnsLocalesZhCn})
(defn timeago (defn timeago
([v] (timeago v nil)) ([v] (timeago v nil))
([v {:keys [locale] :or {locale "en"}}] ([v {:keys [locale] :or {locale "en"}}]
@ -230,19 +199,18 @@
(let [v (if (datetime? v) (format v :date) v)] (let [v (if (datetime? v) (format v :date) v)]
(->> #js {:includeSeconds true (->> #js {:includeSeconds true
:addSuffix true :addSuffix true
:locale (obj/get locales locale)} :locale (obj/get impl/locales locale)}
(dateFnsFormatDistanceToNowStrict v)))))) (impl/format-distance-to-now v))))))
(defn format-date-locale (defn format-date-locale
([v] (format-date-locale v nil)) ([v] (format-date-locale v nil))
([v {:keys [locale] :or {locale "en"}}] ([v {:keys [locale] :or {locale "en"}}]
(when v (when v
(let [v (if (datetime? v) (format v :date) v) (let [v (if (datetime? v) (format v :date) v)
locale (obj/get locales locale) locale (obj/get impl/locales locale)
f (.date (.-formatLong ^js locale) v)] f (.date (.-formatLong ^js locale) v)]
(->> #js {:locale locale} (->> #js {:locale locale}
(dateFnsFormat v f)))))) (impl/format v f))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Measurement Helpers ;; Measurement Helpers

View file

@ -0,0 +1,71 @@
import fmt1 from "date-fns/format";
import fmt2 from "date-fns/formatDistanceToNowStrict";
import {arSA} from "date-fns/locale/ar-SA";
import {ca} from "date-fns/locale/ca";
import {de} from "date-fns/locale/de";
import {el} from "date-fns/locale/el";
import {enUS} from "date-fns/locale/en-US";
import {es} from "date-fns/locale/es";
import {faIR} from "date-fns/locale/fa-IR";
import {fr} from "date-fns/locale/fr";
import {he} from "date-fns/locale/he";
import {pt} from "date-fns/locale/pt";
import {ptBR} from "date-fns/locale/pt-BR";
import {ro} from "date-fns/locale/ro";
import {ru} from "date-fns/locale/ru";
import {tr} from "date-fns/locale/tr";
import {zhCN} from "date-fns/locale/zh-CN";
import {nl} from "date-fns/locale/nl";
import {eu} from "date-fns/locale/eu";
import {gl} from "date-fns/locale/gl";
import {hr} from "date-fns/locale/hr";
import {it} from "date-fns/locale/it";
import {nb} from "date-fns/locale/nb";
import {pl} from "date-fns/locale/pl";
import {id} from "date-fns/locale/id";
import {uk} from "date-fns/locale/uk";
import {cs} from "date-fns/locale/cs";
import {lv} from "date-fns/locale/lv";
import {ko} from "date-fns/locale/ko";
import {ja} from "date-fns/locale/ja";
export const locales = {
"ar": arSA,
"ca": ca,
"de": de,
"el": el,
"en": enUS,
"en_us": enUS,
"es": es,
"es_es": es,
"fa": faIR,
"fa_ir": faIR,
"fr": fr,
"he": he,
"pt": pt,
"pt_pt": pt,
"pt_br": ptBR,
"ro": ro,
"ru": ru,
"tr": tr,
"zh_cn": zhCN,
"nl": nl,
"eu": eu,
"gl": gl,
"hr": hr,
"it": it,
"nb": nb,
"nb_no": nb,
"pl": pl,
"id": id,
"uk": uk,
"cs": cs,
"lv": lv,
"ko": ko,
"ja": ja,
"ja_jp": ja,
};
export const format = fmt1.format;
export const format_distance_to_now = fmt2.formatDistanceToNowStrict;

View file

@ -43,7 +43,7 @@
(if (and (exists? js/window) (if (and (exists? js/window)
(.-requestIdleCallback js/window)) (.-requestIdleCallback js/window))
(do (do
(def ^:private request-idle-callback #(js/requestIdleCallback %)) (def ^:private request-idle-callback #(js/requestIdleCallback % #js {:timeout 30000})) ;; 30s timeout
(def ^:private cancel-idle-callback #(js/cancelIdleCallback %))) (def ^:private cancel-idle-callback #(js/cancelIdleCallback %)))
(do (do
(def ^:private request-idle-callback #(js/setTimeout % 250)) (def ^:private request-idle-callback #(js/setTimeout % 250))

View file

@ -28,7 +28,8 @@
[{:keys [page-id frame-id axis ranges bounds] :as message}] [{:keys [page-id frame-id axis ranges bounds] :as message}]
(let [match-bounds? (let [match-bounds?
(fn [[_ data]] (fn [[_ data]]
(some #(grc/contains-point? bounds %) (map :pt data)))] (some #(or (= :guide (:type %))
(grc/contains-point? bounds (:pt %))) data))]
(->> (into [] (->> (into []
(comp (mapcat #(sd/query @state page-id frame-id axis %)) (comp (mapcat #(sd/query @state page-id frame-id axis %))
(distinct)) (distinct))

View file

@ -4872,20 +4872,6 @@ msgstr[2] ""
"Aktiva, která již byla v těchto souborech použita, tam zůstanou (nebude " "Aktiva, která již byla v těchto souborech použita, tam zůstanou (nebude "
"porušen žádný návrh)." "porušen žádný návrh)."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Není aktivován v žádném souboru."
msgstr[1] "Nejsou aktivovány v žádném souboru."
msgstr[2] "Nejsou aktivovány v žádném souboru."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Tato knihovna je aktivována zde:"
msgstr[1] "Tyto knihovny jsou aktivovány zde:"
msgstr[2] "Tyto knihovny jsou aktivovány zde:"
#: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs #: src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.too-long" msgid "auth.name.too-long"
msgstr "Název musí obsahovat maximálně 250 znaků." msgstr "Název musí obsahovat maximálně 250 znaků."

View file

@ -2122,18 +2122,6 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
msgstr[0] "Veröffentlichung aufheben" msgstr[0] "Veröffentlichung aufheben"
msgstr[1] "Veröffentlichung aufheben" msgstr[1] "Veröffentlichung aufheben"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Es ist in keiner Datei aktiviert."
msgstr[1] "Sie sind in keiner Datei aktiviert."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Diese Bibliothek ist hier aktiviert:"
msgstr[1] "Diese Bibliotheken sind hier aktiviert:"
#: src/app/main/ui/workspace/header.cljs, #: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"

View file

@ -2103,17 +2103,10 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
msgstr[0] "Unpublish" msgstr[0] "Unpublish"
msgstr[1] "Unpublish" msgstr[1] "Unpublish"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs msgid "modals.move-shared-confirm.accept"
msgid "modals.unpublish-shared-confirm.activated.no-files-message" msgid_plural "modals.move-shared-confirm.accept"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message" msgstr[0] "Move"
msgstr[0] "It isn't activated in any file." msgstr[1] "Move"
msgstr[1] "They aren't activated in any file."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "This library is activated here:"
msgstr[1] "This libraries are activated here:"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"
@ -2121,12 +2114,22 @@ msgid_plural "modals.unpublish-shared-confirm.message"
msgstr[0] "Are you sure you want to unpublish this library?" msgstr[0] "Are you sure you want to unpublish this library?"
msgstr[1] "Are you sure you want to unpublish these libraries?" msgstr[1] "Are you sure you want to unpublish these libraries?"
msgid "modals.move-shared-confirm.message"
msgid_plural "modals.move-shared-confirm.message"
msgstr[0] "Are you sure you want to move this library?"
msgstr[1] "Are you sure you want to move these libraries?"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.title" msgid "modals.unpublish-shared-confirm.title"
msgid_plural "modals.unpublish-shared-confirm.title" msgid_plural "modals.unpublish-shared-confirm.title"
msgstr[0] "Unpublish library" msgstr[0] "Unpublish library"
msgstr[1] "Unpublish libraries" msgstr[1] "Unpublish libraries"
msgid "modals.move-shared-confirm.title"
msgid_plural "modals.move-shared-confirm.title"
msgstr[0] "Move library"
msgstr[1] "Move libraries"
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs, src/app/main/ui/workspace/context_menu.cljs #: src/app/main/ui/workspace/sidebar/options/menus/component.cljs, src/app/main/ui/workspace/context_menu.cljs
msgid "modals.update-remote-component-in-bulk.hint" msgid "modals.update-remote-component-in-bulk.hint"
msgstr "" msgstr ""

View file

@ -2138,16 +2138,10 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
msgstr[0] "Despublicar" msgstr[0] "Despublicar"
msgstr[1] "Despublicar" msgstr[1] "Despublicar"
msgid "modals.unpublish-shared-confirm.activated.no-files-message" msgid "modals.move-shared-confirm.accept"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message" msgid_plural "modals.move-shared-confirm.accept"
msgstr[0] "No está activa en ningún fichero." msgstr[0] "Mover"
msgstr[1] "No están activas en ningún fichero." msgstr[1] "Mover"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Está activa aquí:"
msgstr[1] "Están activas aquí:"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"
@ -2155,12 +2149,22 @@ msgid_plural "modals.unpublish-shared-confirm.message"
msgstr[0] "¿Seguro que quieres despublicar esta biblioteca?" msgstr[0] "¿Seguro que quieres despublicar esta biblioteca?"
msgstr[1] "¿Seguro que quieres despublicar estas bibliotecas?" msgstr[1] "¿Seguro que quieres despublicar estas bibliotecas?"
msgid "modals.move-shared-confirm.message"
msgid_plural "modals.move-shared-confirm.message"
msgstr[0] "¿Seguro que quieres mover esta biblioteca?"
msgstr[1] "¿Seguro que quieres mover estas bibliotecas?"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.title" msgid "modals.unpublish-shared-confirm.title"
msgid_plural "modals.unpublish-shared-confirm.title" msgid_plural "modals.unpublish-shared-confirm.title"
msgstr[0] "Despublicar biblioteca" msgstr[0] "Despublicar biblioteca"
msgstr[1] "Despublicar bibliotecas" msgstr[1] "Despublicar bibliotecas"
msgid "modals.move-shared-confirm.title"
msgid_plural "modals.move-shared-confirm.title"
msgstr[0] "Mover biblioteca"
msgstr[1] "Mover bibliotecas"
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs, #: src/app/main/ui/workspace/sidebar/options/menus/component.cljs,
#: src/app/main/ui/workspace/context_menu.cljs #: src/app/main/ui/workspace/context_menu.cljs
msgid "modals.update-remote-component-in-bulk.hint" msgid "modals.update-remote-component-in-bulk.hint"

View file

@ -2127,18 +2127,6 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
msgstr[0] "Dépublier" msgstr[0] "Dépublier"
msgstr[1] "Dépublier" msgstr[1] "Dépublier"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Activée dans aucun fichier."
msgstr[1] "Activées dans aucun fichier."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Est activée ici:"
msgstr[1] "Sont activées ici:"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"
msgid_plural "modals.unpublish-shared-confirm.message" msgid_plural "modals.unpublish-shared-confirm.message"

View file

@ -2157,12 +2157,6 @@ msgstr ""
"wurin da za ka san yadda za ka hada-hannu da fassara, neman fasali, manyan " "wurin da za ka san yadda za ka hada-hannu da fassara, neman fasali, manyan "
"gudunmawa, magance matsala…" "gudunmawa, magance matsala…"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "an buxe wannan taskar a nan:"
msgstr[1] "an buxe taskokin nan a nan:"
#: src/app/main/ui/workspace/sidebar/align.cljs #: src/app/main/ui/workspace/sidebar/align.cljs
msgid "workspace.align.hright" msgid "workspace.align.hright"
msgstr "Daidaita dama (%s)" msgstr "Daidaita dama (%s)"
@ -3309,12 +3303,6 @@ msgstr "Yi da kanka"
msgid "labels.save" msgid "labels.save"
msgstr "ajiye" msgstr "ajiye"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "ba zai yi aiki a kowane kundi ba."
msgstr[1] "ba zai yi aiki a kowane kundi ba."
msgid "dashboard.import.progress.process-media" msgid "dashboard.import.progress.process-media"
msgstr "kammala aiki" msgstr "kammala aiki"

View file

@ -4992,14 +4992,6 @@ msgstr "… תרשימי מתאר, סיפורי ותהליכי משתמשים,
msgid "workspace.options.stroke-cap.diamond-marker-short" msgid "workspace.options.stroke-cap.diamond-marker-short"
msgstr "יהלום" msgstr "יהלום"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "הספרייה הזאת מופעלת כאן:"
msgstr[1] "הספריות האלו מופעלות כאן:"
msgstr[2] "הספריות האלו מופעלות כאן:"
msgstr[3] "הספריות האלו מופעלות כאן:"
#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs, #: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs,
msgid "settings.detach" msgid "settings.detach"
msgstr "ניתוק" msgstr "ניתוק"
@ -5008,14 +5000,6 @@ msgstr "ניתוק"
msgid "workspace.options.stroke-cap.triangle-arrow-short" msgid "workspace.options.stroke-cap.triangle-arrow-short"
msgstr "משולש" msgstr "משולש"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "אינו מופעל באף קובץ."
msgstr[1] "אינם מופעלים באף קובץ."
msgstr[2] "אינם מופעלים באף קובץ."
msgstr[3] "אינם מופעלים באף קובץ."
msgid "workspace.shape.menu.create-annotation" msgid "workspace.shape.menu.create-annotation"
msgstr "יצירת הסבר" msgstr "יצירת הסבר"

View file

@ -2098,16 +2098,6 @@ msgid "modals.unpublish-shared-confirm.accept"
msgid_plural "modals.unpublish-shared-confirm.accept" msgid_plural "modals.unpublish-shared-confirm.accept"
msgstr[0] "Batalkan penerbitan" msgstr[0] "Batalkan penerbitan"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Tidak diaktifkan dalam berkas mana pun."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Pustaka ini diaktifkan di sini:"
#: src/app/main/ui/workspace/header.cljs, #: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"

View file

@ -2112,20 +2112,6 @@ msgstr[0] "Nav atlases"
msgstr[1] "Atcelt publicēšanu" msgstr[1] "Atcelt publicēšanu"
msgstr[2] "Atcelt publicēšanu" msgstr[2] "Atcelt publicēšanu"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Nav aktivēti nevienā datnē."
msgstr[1] "Tas nav aktivēts nevienā datnē."
msgstr[2] "Tie nav aktivēti nevienā datnē."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Bibliotēkas ir aktivētas šeit:"
msgstr[1] "Šī bibliotēka ir aktivēta šeit:"
msgstr[2] "Šīs bibliotēkas ir aktivētas šeit:"
#: src/app/main/ui/workspace/header.cljs, #: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"

View file

@ -2143,20 +2143,6 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
msgstr[0] "Publicatie ongedaan maken" msgstr[0] "Publicatie ongedaan maken"
msgstr[1] "Publicaties ongedaan maken" msgstr[1] "Publicaties ongedaan maken"
#: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Het is in geen enkel bestand geactiveerd."
msgstr[1] "Ze zijn in geen enkel bestand geactiveerd."
#: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Deze bibliotheek wordt hier geactiveerd:"
msgstr[1] "Deze bibliotheken worden hier geactiveerd:"
#: src/app/main/ui/workspace/header.cljs, #: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"

View file

@ -2090,18 +2090,6 @@ msgstr "Remover \"%s\" como Biblioteca Partilhada"
msgid "modals.small-nudge" msgid "modals.small-nudge"
msgstr "Pequeno deslocamento" msgstr "Pequeno deslocamento"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Não está ativa em nenhum ficheiro."
msgstr[1] "Não estão ativas em nenhum ficheiro."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Esta biblioteca está ativa aqui:"
msgstr[1] "Estas bibliotecas estão ativas aqui:"
#: src/app/main/ui/workspace/header.cljs, #: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"

View file

@ -2127,20 +2127,6 @@ msgstr[0] "Anulați publicarea"
msgstr[1] "Anulați publicarea" msgstr[1] "Anulați publicarea"
msgstr[2] "Anulați publicarea" msgstr[2] "Anulați publicarea"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Nu este activat în niciun fișier."
msgstr[1] "Nu sunt activate în niciun fișier."
msgstr[2] "Nu sunt activate în niciun fișier."
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Aceasta librărie este activată aici:"
msgstr[1] "Aceste librării sunt activate aici:"
msgstr[2] "Aceste librării sunt activate aici:"
#: src/app/main/ui/workspace/header.cljs, #: src/app/main/ui/workspace/header.cljs,
#: src/app/main/ui/dashboard/file_menu.cljs #: src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.message" msgid "modals.unpublish-shared-confirm.message"

View file

@ -4764,12 +4764,6 @@ msgstr "Ortala"
msgid "workspace.options.stroke-cap.diamond-marker-short" msgid "workspace.options.stroke-cap.diamond-marker-short"
msgstr "Elmas" msgstr "Elmas"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.scd-message"
msgid_plural "modals.unpublish-shared-confirm.activated.scd-message"
msgstr[0] "Bu kütüphane burada etkinleştirildi:"
msgstr[1] "Bu kütüphaneler burada etkinleştirildi:"
#: src/app/main/ui/onboarding/questions.cljs #: src/app/main/ui/onboarding/questions.cljs
msgid "questions.questions-how-are-you-planning-to-use-penpot" msgid "questions.questions-how-are-you-planning-to-use-penpot"
msgstr "Penpot'u nasıl kullanmayı planlıyorsunuz?" msgstr "Penpot'u nasıl kullanmayı planlıyorsunuz?"
@ -4859,12 +4853,6 @@ msgstr "Orantılı ölçeklendirmeyi etkinleştir"
msgid "workspace.updates.more-info" msgid "workspace.updates.more-info"
msgstr "Daha fazla bilgi" msgstr "Daha fazla bilgi"
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
msgstr[0] "Hiçbir dosyada etkinleştirilmemiş."
msgstr[1] "Hiçbir dosyada etkinleştirilmemişler."
#: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs #: src/app/main/ui/settings/team-form.cljs, src/app/main/ui/auth/register.cljs, src/app/main/ui/dashboard/team_form.cljs, src/app/main/ui/onboarding/team_choice.cljs, src/app/main/ui/settings/access_tokens.cljs, src/app/main/ui/settings/feedback.cljs, src/app/main/ui/settings/profile.cljs, src/app/main/ui/workspace/sidebar/assets.cljs
msgid "auth.name.not-all-space" msgid "auth.name.not-all-space"
msgstr "İsim boşluk dışında bir karakter içermelidir." msgstr "İsim boşluk dışında bir karakter içermelidir."

File diff suppressed because it is too large Load diff