mirror of
https://github.com/penpot/penpot.git
synced 2025-05-28 20:16:10 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
2a6589ab01
95 changed files with 2490 additions and 2036 deletions
|
@ -2,7 +2,7 @@
|
|||
{org.clojure/clojure {:mvn/version "1.11.1"}
|
||||
org.clojure/data.json {:mvn/version "2.5.0"}
|
||||
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/data.fressian {:mvn/version "1.0.0"}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
criterium/criterium {:mvn/version "0.4.6"}
|
||||
|
||||
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"}
|
||||
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
||||
|
@ -63,7 +63,7 @@
|
|||
{:dev
|
||||
{:extra-deps
|
||||
{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.bhauman/rebel-readline {:mvn/version "RELEASE"}
|
||||
criterium/criterium {:mvn/version "RELEASE"}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"sax": "^1.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shadow-cljs": "2.26.2",
|
||||
"shadow-cljs": "2.27.4",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ws": "^8.13.0"
|
||||
},
|
||||
|
|
|
@ -150,6 +150,22 @@
|
|||
:else
|
||||
(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
|
||||
"Get the parent shape at the top of the component instance (main or copy)."
|
||||
[objects shape]
|
||||
|
@ -392,7 +408,7 @@
|
|||
(has-any-copy-parent? objects (:parent-id shape))))))
|
||||
|
||||
(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]
|
||||
(let [children (cfh/get-children-with-self objects (:id shape))
|
||||
parents (cfh/get-parents objects (:id shape))]
|
||||
|
@ -400,6 +416,12 @@
|
|||
(some ctk/main-instance? children)
|
||||
(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?
|
||||
"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
|
||||
|
@ -412,7 +434,7 @@
|
|||
(defn- invalid-structure-for-component?
|
||||
"Check if the structure generated nesting children in parent is invalid in terms of nested components"
|
||||
[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)
|
||||
comps-nesting-loop? (not (->> children
|
||||
(map #(cfh/components-nesting-loop? objects (:id %) (:id parent)))
|
||||
|
|
|
@ -117,6 +117,12 @@
|
|||
[libraries component-id & {:keys [include-deleted?] :or {include-deleted? false}}]
|
||||
(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
|
||||
"Retrieve a component from a library."
|
||||
[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
|
||||
referenced by the instance shape."
|
||||
[file page libraries shape & {:keys [include-deleted?] :or {include-deleted? false}}]
|
||||
(let [parent-heads (->> (cfh/get-parents-with-self (:objects page) (:id shape))
|
||||
(filter ctk/instance-head?)
|
||||
(reverse))
|
||||
|
||||
find-ref-shape-in-head
|
||||
(let [find-ref-shape-in-head
|
||||
(fn [head-shape]
|
||||
(let [head-file (if (and (some? file) (= (:component-file head-shape) (:id file)))
|
||||
file
|
||||
(get libraries (:component-file 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)
|
||||
(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
|
||||
"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
|
||||
(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
|
||||
"Retrieve all shapes of the component"
|
||||
[file-data component]
|
||||
|
|
|
@ -176,7 +176,7 @@
|
|||
(contains? event-types event-type))
|
||||
|
||||
(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)
|
||||
(cfh/frame-shape? shape)))
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ __metadata:
|
|||
dependencies:
|
||||
luxon: "npm:^3.4.2"
|
||||
sax: "npm:^1.2.4"
|
||||
shadow-cljs: "npm:2.26.2"
|
||||
shadow-cljs: "npm:2.27.4"
|
||||
source-map-support: "npm:^0.5.21"
|
||||
ws: "npm:^8.13.0"
|
||||
languageName: unknown
|
||||
|
@ -1437,9 +1437,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"shadow-cljs@npm:2.26.2":
|
||||
version: 2.26.2
|
||||
resolution: "shadow-cljs@npm:2.26.2"
|
||||
"shadow-cljs@npm:2.27.4":
|
||||
version: 2.27.4
|
||||
resolution: "shadow-cljs@npm:2.27.4"
|
||||
dependencies:
|
||||
node-libs-browser: "npm:^2.2.1"
|
||||
readline-sync: "npm:^1.4.7"
|
||||
|
@ -1449,7 +1449,7 @@ __metadata:
|
|||
ws: "npm:^7.4.6"
|
||||
bin:
|
||||
shadow-cljs: cli/runner.js
|
||||
checksum: d504969ea28bcf3d5fc879c8111cb630a8ae910ea692bbfb0d73097fb336e13e642116db9fcc91524686a6824e71d439ef0df31941eabb6331feb4aa4146e830
|
||||
checksum: bae23e71df9c2b2979259a0cde8747c923ee295f58ab4637c9d6b103d82542b40ef39172d4be2dbb94af2e6458a177d1ec96c1eb1e73b1d8f3a4ddb5eaaba7d4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
:dev
|
||||
{:extra-deps
|
||||
{thheller/shadow-cljs {:mvn/version "2.26.2"}}}
|
||||
{thheller/shadow-cljs {:mvn/version "2.27.4"}}}
|
||||
|
||||
:shadow-cljs
|
||||
{:main-opts ["-m" "shadow.cljs.devtools.cli"]}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"xregexp": "^5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shadow-cljs": "2.26.2",
|
||||
"shadow-cljs": "2.27.4",
|
||||
"source-map-support": "^0.5.21"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -735,7 +735,7 @@ __metadata:
|
|||
luxon: "npm:^3.4.4"
|
||||
playwright: "npm:^1.40.1"
|
||||
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"
|
||||
xml-js: "npm:^1.6.11"
|
||||
xregexp: "npm:^5.1.1"
|
||||
|
@ -1842,9 +1842,9 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"shadow-cljs@npm:2.26.2":
|
||||
version: 2.26.2
|
||||
resolution: "shadow-cljs@npm:2.26.2"
|
||||
"shadow-cljs@npm:2.27.4":
|
||||
version: 2.27.4
|
||||
resolution: "shadow-cljs@npm:2.27.4"
|
||||
dependencies:
|
||||
node-libs-browser: "npm:^2.2.1"
|
||||
readline-sync: "npm:^1.4.7"
|
||||
|
@ -1854,7 +1854,7 @@ __metadata:
|
|||
ws: "npm:^7.4.6"
|
||||
bin:
|
||||
shadow-cljs: cli/runner.js
|
||||
checksum: d504969ea28bcf3d5fc879c8111cb630a8ae910ea692bbfb0d73097fb336e13e642116db9fcc91524686a6824e71d439ef0df31941eabb6331feb4aa4146e830
|
||||
checksum: bae23e71df9c2b2979259a0cde8747c923ee295f58ab4637c9d6b103d82542b40ef39172d4be2dbb94af2e6458a177d1ec96c1eb1e73b1d8f3a4ddb5eaaba7d4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
:git/url "https://github.com/funcool/beicon.git"}
|
||||
|
||||
funcool/rumext
|
||||
{:git/tag "v2.10"
|
||||
:git/sha "d96ea18"
|
||||
{:git/tag "v2.11.1"
|
||||
:git/sha "c9197b0"
|
||||
:git/url "https://github.com/funcool/rumext.git"}
|
||||
|
||||
instaparse/instaparse {:mvn/version "1.4.12"}
|
||||
|
@ -41,7 +41,7 @@
|
|||
:dev
|
||||
{:extra-paths ["dev"]
|
||||
: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"}
|
||||
cider/cider-nrepl {:mvn/version "0.44.0"}}}
|
||||
|
||||
|
|
|
@ -39,53 +39,53 @@
|
|||
"storybook:build": "npm run storybook:compile && storybook build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-essentials": "^7.6.7",
|
||||
"@storybook/addon-interactions": "^7.6.7",
|
||||
"@storybook/addon-links": "^7.6.7",
|
||||
"@storybook/addon-onboarding": "^1.0.10",
|
||||
"@storybook/blocks": "^7.6.7",
|
||||
"@storybook/react": "^7.6.7",
|
||||
"@storybook/react-vite": "^7.6.7",
|
||||
"@storybook/addon-essentials": "^7.6.17",
|
||||
"@storybook/addon-interactions": "^7.6.17",
|
||||
"@storybook/addon-links": "^7.6.17",
|
||||
"@storybook/addon-onboarding": "^1.0.11",
|
||||
"@storybook/blocks": "^7.6.17",
|
||||
"@storybook/react": "^7.6.17",
|
||||
"@storybook/react-vite": "^7.6.17",
|
||||
"@storybook/testing-library": "^0.2.2",
|
||||
"@types/node": "^20.10.6",
|
||||
"@types/node": "^20.11.20",
|
||||
"animate.css": "^4.1.1",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"concurrently": "^8.2.2",
|
||||
"draft-js": "git+https://github.com/penpot/draft-js.git",
|
||||
"fancy-log": "^2.0.0",
|
||||
"gettext-parser": "^7.0.1",
|
||||
"gettext-parser": "^8.0.0",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-gzip": "^1.4.2",
|
||||
"gulp-mustache": "^5.0.0",
|
||||
"gulp-postcss": "^9.0.1",
|
||||
"gulp-postcss": "^10.0.0",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-sass": "^5.1.0",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"gulp-svg-sprite": "^2.0.3",
|
||||
"jsdom": "^23.1.0",
|
||||
"jsdom": "^24.0.0",
|
||||
"map-stream": "0.0.7",
|
||||
"marked": "^7.0.5",
|
||||
"marked": "^12.0.0",
|
||||
"mkdirp": "^3.0.1",
|
||||
"nodemon": "^3.0.2",
|
||||
"nodemon": "^3.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-clean": "^1.2.2",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier": "^3.2.5",
|
||||
"prop-types": "^15.8.1",
|
||||
"rimraf": "^5.0.5",
|
||||
"sass": "^1.69.7",
|
||||
"shadow-cljs": "2.26.2",
|
||||
"storybook": "^7.6.7",
|
||||
"sass": "^1.71.1",
|
||||
"shadow-cljs": "2.27.4",
|
||||
"storybook": "^7.6.17",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.11",
|
||||
"vitest": "^1.1.3"
|
||||
"vite": "^5.1.4",
|
||||
"vitest": "^1.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"date-fns": "^2.30.0",
|
||||
"draft-js": "^0.11.7",
|
||||
"eventsource-parser": "^1.1.1",
|
||||
"date-fns": "^3.3.1",
|
||||
"eventsource-parser": "^1.1.2",
|
||||
"highlight.js": "^11.9.0",
|
||||
"js-beautify": "^1.14.11",
|
||||
"js-beautify": "^1.15.1",
|
||||
"jszip": "^3.10.1",
|
||||
"luxon": "^3.4.4",
|
||||
"mousetrap": "^1.6.5",
|
||||
|
@ -95,7 +95,7 @@
|
|||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-virtualized": "^9.22.5",
|
||||
"rxjs": "8.0.0-alpha.13",
|
||||
"rxjs": "8.0.0-alpha.14",
|
||||
"sax": "^1.3.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tdigest": "^0.1.2",
|
||||
|
|
|
@ -57,16 +57,19 @@
|
|||
--la-quaternary: #ff6fe0;
|
||||
|
||||
// STATUS COLOR
|
||||
--status-color-success-50: #f0f8ff;
|
||||
--status-color-success-200: #a7e8d9;
|
||||
--status-color-success-500: #2d9f8f;
|
||||
--status-color-success-950: #0a2927;
|
||||
--status-color-warning-50: #fff4ed;
|
||||
|
||||
--status-color-warning-200: #ffc8a8;
|
||||
--status-color-warning-500: #fe4811;
|
||||
--status-color-warning-950: #440806;
|
||||
--status-color-error-50: #fff0f3;
|
||||
|
||||
--status-color-error-200: #ffcada;
|
||||
--status-color-error-500: #ff3277;
|
||||
--status-color-error-950: #500124;
|
||||
--status-color-info-50: #f0f8ff;
|
||||
|
||||
--status-color-info-200: #bae3fd;
|
||||
--status-color-info-500: #0e9be9;
|
||||
--status-color-info-950: #082c49;
|
||||
// Status color default will change with theme and will be defined on theme files
|
||||
|
|
|
@ -311,15 +311,30 @@
|
|||
--modal-separator-backogrund-color: var(--color-background-quaternary);
|
||||
|
||||
// ALERTS NOTIFICATION TOAST & STATUS WIDGET
|
||||
--alert-background-color-success: var(--status-color-success-500);
|
||||
--alert-foreground-color-success: var(--db-secondary); // We don't want this color to change with theme
|
||||
--alert-background-color-warning: var(--status-color-warning-500);
|
||||
--alert-foreground-color-warning: var(--app-white); // We don't want this color to change with theme
|
||||
--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-neutral: var(--color-background-quaternary);
|
||||
--alert-foreground-color-neutral: var(--color-foreground-secondary);
|
||||
--alert-foreground-color-neutral-active: var(--color-foreground-primary);
|
||||
--alert-background-color-success: var(--color-success-background);
|
||||
--alert-text-foreground-color-success: var(--color-foreground-primary);
|
||||
--alert-icon-foreground-color-success: var(--color-success-foreground);
|
||||
--alert-border-color-success: var(--color-success-foreground);
|
||||
|
||||
--alert-background-color-warning: var(--color-warning-background);
|
||||
--alert-text-foreground-color-warning: var(--color-foreground-primary);
|
||||
--alert-icon-foreground-color-warning: var(--color-warning-foreground);
|
||||
--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-foreground-color-success: var();
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
--color-accent-quaternary: var(--da-quaternary);
|
||||
--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);
|
||||
|
||||
--shadow-color: var(--db-secondary-30);
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
--color-accent-quaternary: var(--la-quaternary);
|
||||
--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);
|
||||
--shadow-color: var(--lf-secondary-40);
|
||||
--radio-button-box-shadow: 0 0 0 1px var(--lb-secondary) inset;
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
(rx/of (msg/dialog
|
||||
:content (tr "notifications.by-code.upgrade-version")
|
||||
:controls :inline-actions
|
||||
:notification-type :inline
|
||||
:type level
|
||||
:actions [{:label "Refresh" :callback force-reload!}]
|
||||
:tag :notification)))
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(:require
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.media :as cm]
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.store :as st]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[beicon.v2.core :as rx]
|
||||
|
@ -46,13 +46,13 @@
|
|||
|
||||
(defn notify-start-loading
|
||||
[]
|
||||
(st/emit! (dm/show {:content (tr "media.loading")
|
||||
:type :info
|
||||
:timeout nil})))
|
||||
(st/emit! (msg/show {:content (tr "media.loading")
|
||||
:type :info
|
||||
:timeout nil})))
|
||||
|
||||
(defn notify-finished-loading
|
||||
[]
|
||||
(st/emit! dm/hide))
|
||||
(st/emit! msg/hide))
|
||||
|
||||
(defn process-error
|
||||
[error]
|
||||
|
@ -68,4 +68,4 @@
|
|||
|
||||
:else
|
||||
(tr "errors.unexpected-error"))]
|
||||
(rx/of (dm/error msg))))
|
||||
(rx/of (msg/error msg))))
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
(declare show)
|
||||
|
||||
(def default-animation-timeout 600)
|
||||
(def default-timeout 5000)
|
||||
(def default-timeout 7000)
|
||||
|
||||
(def ^:private
|
||||
schema:message
|
||||
|
@ -27,6 +27,8 @@
|
|||
[::sm/one-of #{:visible :hide}]]
|
||||
[:position {:optional true}
|
||||
[::sm/one-of #{:fixed :floating :inline}]]
|
||||
[:notification-type {:optional true}
|
||||
[::sm/one-of #{:inline :context :toast}]]
|
||||
[:controls {:optional true}
|
||||
[::sm/one-of #{:none :close :inline-actions :bottom-actions}]]
|
||||
[:tag {:optional true}
|
||||
|
@ -93,18 +95,18 @@
|
|||
(rx/of hide))))))
|
||||
|
||||
(defn error
|
||||
([content] (error content {}))
|
||||
([content {:keys [timeout] :or {timeout default-timeout}}]
|
||||
([content]
|
||||
(show {:content content
|
||||
:type :error
|
||||
:position :fixed
|
||||
:timeout timeout})))
|
||||
:notification-type :toast
|
||||
:position :fixed})))
|
||||
|
||||
(defn info
|
||||
([content] (info content {}))
|
||||
([content {:keys [timeout] :or {timeout default-timeout}}]
|
||||
(show {:content content
|
||||
:type :info
|
||||
:notification-type :toast
|
||||
:position :fixed
|
||||
:timeout timeout})))
|
||||
|
||||
|
@ -113,6 +115,7 @@
|
|||
([content {:keys [timeout] :or {timeout default-timeout}}]
|
||||
(show {:content content
|
||||
:type :success
|
||||
:notification-type :toast
|
||||
:position :fixed
|
||||
:timeout timeout})))
|
||||
|
||||
|
@ -121,6 +124,7 @@
|
|||
([content {:keys [timeout] :or {timeout default-timeout}}]
|
||||
(show {:content content
|
||||
:type :warning
|
||||
:notification-type :toast
|
||||
:position :fixed
|
||||
:timeout timeout})))
|
||||
|
||||
|
@ -142,6 +146,7 @@
|
|||
{:content content
|
||||
:type :info
|
||||
:position :floating
|
||||
:notification-type :inline
|
||||
:controls controls
|
||||
:links links
|
||||
:actions actions
|
||||
|
|
|
@ -609,24 +609,29 @@
|
|||
(ptk/reify ::detach-selected-components
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
file (wsh/get-local-file state)
|
||||
container (cfh/get-container file :page page-id)
|
||||
libraries (wsh/get-libraries state)
|
||||
selected (->> state
|
||||
(wsh/lookup-selected)
|
||||
(cfh/clean-loops objects))
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
file (wsh/get-local-file state)
|
||||
container (cfh/get-container file :page page-id)
|
||||
libraries (wsh/get-libraries state)
|
||||
selected (->> state
|
||||
(wsh/lookup-selected)
|
||||
(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
|
||||
(fn [changes id]
|
||||
(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))))))
|
||||
(rx/of (when can-detach?
|
||||
(dch/commit-changes changes)))))))
|
||||
|
||||
(defn nav-to-component-file
|
||||
[file-id component]
|
||||
|
@ -1126,12 +1131,12 @@
|
|||
:controls :inline-actions
|
||||
:links [{:label (tr "workspace.updates.more-info")
|
||||
:callback do-more-info}]
|
||||
:actions [{:label (tr "workspace.updates.update")
|
||||
:type :primary
|
||||
:callback do-update}
|
||||
{:label (tr "workspace.updates.dismiss")
|
||||
:actions [{:label (tr "workspace.updates.dismiss")
|
||||
:type :secondary
|
||||
:callback do-dismiss}]
|
||||
:callback do-dismiss}
|
||||
{:label (tr "workspace.updates.update")
|
||||
:type :primary
|
||||
:callback do-update}]
|
||||
:tag :sync-dialog)))))))
|
||||
|
||||
(defn component-changed
|
||||
|
|
|
@ -599,15 +599,10 @@
|
|||
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))))
|
||||
component-shape (ctn/get-component-shape (:objects container) shape-inst)]
|
||||
(ctkl/get-deleted-component library (:component-id 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)
|
||||
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
|
||||
(if (and reset? components-v2)
|
||||
|
|
|
@ -82,13 +82,14 @@
|
|||
|
||||
(defn get-snap-points [page-id frame-id remove-snap? zoom 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
|
||||
:page-id page-id
|
||||
:frame-id frame-id
|
||||
:axis coord
|
||||
:bounds vbox
|
||||
:ranges [[(- value (/ 0.5 zoom)) (+ value (/ 0.5 zoom))]]})
|
||||
:ranges ranges})
|
||||
(rx/take 1)
|
||||
(rx/map (remove-from-snap-points remove-snap?)))))
|
||||
|
||||
|
|
|
@ -173,6 +173,6 @@
|
|||
(if edata
|
||||
[:& static/exception-page {:data edata}]
|
||||
[:*
|
||||
[:& msgs/notifications]
|
||||
[:& msgs/notifications-hub]
|
||||
(when route
|
||||
[:& main-page {:route route :profile profile}])])]]))
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
.auth-form {
|
||||
width: 100%;
|
||||
padding-bottom: $s-16;
|
||||
padding-block-end: $s-16;
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-12;
|
||||
margin-bottom: $s-24;
|
||||
margin-block-end: $s-24;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,10 @@
|
|||
margin: $s-24 0;
|
||||
}
|
||||
|
||||
.error-wrapper {
|
||||
padding-block-end: $s-8;
|
||||
}
|
||||
|
||||
.auth-title {
|
||||
@include bigTitleTipography;
|
||||
color: $df-primary;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[app.common.logging :as log]
|
||||
[app.common.spec :as us]
|
||||
[app.config :as cf]
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -19,7 +19,7 @@
|
|||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.components.link :as lk]
|
||||
[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.i18n :refer [tr]]
|
||||
[app.util.keyboard :as k]
|
||||
|
@ -48,10 +48,10 @@
|
|||
(cond
|
||||
(and (= type :restriction)
|
||||
(= 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
|
||||
(st/emit! (dm/error (tr "errors.generic"))))))))
|
||||
(st/emit! (msg/error (tr "errors.generic"))))))))
|
||||
|
||||
(defn- login-with-ldap
|
||||
[event params]
|
||||
|
@ -67,13 +67,13 @@
|
|||
(cond
|
||||
(and (= type :restriction)
|
||||
(= code :ldap-not-initialized))
|
||||
(st/emit! (dm/error (tr "errors.ldap-disabled")))
|
||||
(st/emit! (msg/error (tr "errors.ldap-disabled")))
|
||||
|
||||
(fn? on-error)
|
||||
(on-error error)
|
||||
|
||||
:else
|
||||
(st/emit! (dm/error (tr "errors.generic")))))))))
|
||||
(st/emit! (msg/error (tr "errors.generic")))))))))
|
||||
|
||||
(s/def ::email ::us/email)
|
||||
(s/def ::password ::us/not-empty-string)
|
||||
|
@ -157,12 +157,12 @@
|
|||
|
||||
[:*
|
||||
(when-let [message @error]
|
||||
[:& msgs/inline-banner
|
||||
{:type :warning
|
||||
:content message
|
||||
:on-close #(reset! error nil)
|
||||
:data-test "login-banner"
|
||||
:role "alert"}])
|
||||
[:div {:class (stl/css :error-wrapper)}
|
||||
[:& context-notification
|
||||
{:type :warning
|
||||
:content message
|
||||
:data-test "login-banner"
|
||||
:role "alert"}]])
|
||||
|
||||
[:& fm/form {:on-submit on-submit :form form}
|
||||
[:div {:class (stl/css :fields-row)}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[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.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
|
@ -39,11 +39,11 @@
|
|||
|
||||
(defn- on-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
|
||||
[_]
|
||||
(st/emit! (dm/info (tr "auth.notifications.password-changed-successfully"))
|
||||
(st/emit! (msg/info (tr "auth.notifications.password-changed-successfully"))
|
||||
(rt/nav :auth-login)))
|
||||
|
||||
(defn- on-submit
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[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.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
|
@ -37,7 +37,7 @@
|
|||
:initial {})
|
||||
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
|
||||
(mf/use-callback
|
||||
|
@ -53,13 +53,13 @@
|
|||
(reset! submitted false)
|
||||
(case code
|
||||
: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
|
||||
(rx/of (dm/error (tr "errors.profile-is-muted")))
|
||||
(rx/of (msg/error (tr "errors.profile-is-muted")))
|
||||
|
||||
: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))))
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.spec :as us]
|
||||
[app.config :as cf]
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -18,7 +18,7 @@
|
|||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.components.link :as lk]
|
||||
[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.router :as rt]
|
||||
[beicon.v2.core :as rx]
|
||||
|
@ -28,7 +28,7 @@
|
|||
(mf/defc demo-warning
|
||||
[_]
|
||||
[:div {:class (stl/css :banner)}
|
||||
[:& msgs/inline-banner
|
||||
[:& context-notification
|
||||
{:type :warning
|
||||
:content (tr "auth.demo-warning")}]])
|
||||
|
||||
|
@ -61,14 +61,14 @@
|
|||
[form {:keys [type code] :as cause}]
|
||||
(condp = [type code]
|
||||
[:restriction :registration-disabled]
|
||||
(st/emit! (dm/error (tr "errors.registration-disabled")))
|
||||
(st/emit! (msg/error (tr "errors.registration-disabled")))
|
||||
|
||||
[:restriction :profile-blocked]
|
||||
(st/emit! (dm/error (tr "errors.profile-blocked")))
|
||||
(st/emit! (msg/error (tr "errors.profile-blocked")))
|
||||
|
||||
[:validation :email-has-permanent-bounces]
|
||||
(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]
|
||||
(swap! form assoc-in [:errors :email]
|
||||
|
@ -78,7 +78,7 @@
|
|||
(swap! form assoc-in [:errors :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
|
||||
[params]
|
||||
|
@ -182,7 +182,7 @@
|
|||
|
||||
(do
|
||||
(println (:explain error))
|
||||
(st/emit! (dm/error (tr "errors.generic"))))))
|
||||
(st/emit! (msg/error (tr "errors.generic"))))))
|
||||
|
||||
(defn- handle-register-success
|
||||
[data]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
(ns app.main.ui.auth.verify-token
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -25,13 +25,13 @@
|
|||
(defmethod handle-token :verify-email
|
||||
[data]
|
||||
(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))))
|
||||
|
||||
(defmethod handle-token :change-email
|
||||
[_data]
|
||||
(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)
|
||||
(du/fetch-profile))))
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
|||
(case (:state tdata)
|
||||
:created
|
||||
(st/emit!
|
||||
(dm/success (tr "auth.notifications.team-invitation-accepted"))
|
||||
(msg/success (tr "auth.notifications.team-invitation-accepted"))
|
||||
(du/fetch-profile)
|
||||
(rt/nav :dashboard-projects {:team-id (:team-id tdata)}))
|
||||
|
||||
|
@ -57,7 +57,7 @@
|
|||
[_tdata]
|
||||
(st/emit!
|
||||
(rt/nav :auth-login)
|
||||
(dm/warn (tr "errors.unexpected-token"))))
|
||||
(msg/warn (tr "errors.unexpected-token"))))
|
||||
|
||||
(mf/defc verify-token
|
||||
[{:keys [route] :as props}]
|
||||
|
@ -79,17 +79,17 @@
|
|||
|
||||
(= :email-already-exists code)
|
||||
(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)))
|
||||
|
||||
(= :email-already-validated code)
|
||||
(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)))
|
||||
|
||||
:else
|
||||
(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))))))))
|
||||
|
||||
(if @bad-token
|
||||
|
|
|
@ -296,19 +296,13 @@
|
|||
|
||||
(mf/defc submit-button*
|
||||
{::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))
|
||||
|
||||
disabled? (or (and (some? form) (not (:valid @form)))
|
||||
(true? disabled))
|
||||
|
||||
large? (d/nilv large? true)
|
||||
|
||||
class (dm/str (d/nilv class "btn-primary")
|
||||
" "
|
||||
(if large? "btn-large" "")
|
||||
" "
|
||||
(if disabled? (stl/css :btn-disabled) ""))
|
||||
class (d/nilv class (stl/css :button-submit))
|
||||
|
||||
name (d/nilv name "submit")
|
||||
|
||||
|
|
|
@ -257,7 +257,11 @@
|
|||
}
|
||||
|
||||
// SUBMIT-BUTTON
|
||||
.btn-disabled {
|
||||
.button-submit {
|
||||
@extend .button-primary;
|
||||
}
|
||||
|
||||
:disabled {
|
||||
@extend .button-disabled;
|
||||
}
|
||||
|
||||
|
@ -329,10 +333,10 @@
|
|||
&.invalid {
|
||||
background-color: var(--status-widget-background-color-error);
|
||||
.text {
|
||||
color: var(--alert-foreground-color-error);
|
||||
color: var(--alert-text-foreground-color-error);
|
||||
}
|
||||
.icon svg {
|
||||
stroke: var(--alert-foreground-color-error);
|
||||
stroke: var(--alert-icon-foreground-color-error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,6 +426,7 @@
|
|||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
//TEXTAREA
|
||||
|
||||
.textarea-label {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
(mf/defc radio-button
|
||||
{::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)
|
||||
allow-empty (unchecked-get context "allow-empty")
|
||||
type (if ^boolean type
|
||||
|
@ -39,7 +39,6 @@
|
|||
|
||||
[:label {:html-for id
|
||||
:title title
|
||||
:key unique-key
|
||||
:class (stl/css-case
|
||||
:radio-icon true
|
||||
:checked checked?
|
||||
|
@ -88,9 +87,10 @@
|
|||
(dom/blur! input))))
|
||||
|
||||
context-value
|
||||
(mf/spread-obj props {:on-change on-change'
|
||||
:encode-fn encode-fn
|
||||
:decode-fn decode-fn})]
|
||||
(mf/spread props
|
||||
:on-change on-change'
|
||||
:encode-fn encode-fn
|
||||
:decode-fn decode-fn)]
|
||||
|
||||
[:& (mf/provider context) {:value context-value}
|
||||
[:div {:class (dm/str class " " (stl/css :radio-btn-wrapper))
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[app.main.data.common :as dcm]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[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.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -88,12 +88,12 @@
|
|||
on-duplicate
|
||||
(fn [_]
|
||||
(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
|
||||
(fn [_]
|
||||
(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)))
|
||||
|
||||
on-delete
|
||||
|
@ -126,21 +126,36 @@
|
|||
on-move-success
|
||||
(fn [team-id project-id]
|
||||
(if multi?
|
||||
(st/emit! (dm/success (tr "dashboard.success-move-files")))
|
||||
(st/emit! (dm/success (tr "dashboard.success-move-file"))))
|
||||
(st/emit! (msg/success (tr "dashboard.success-move-files")))
|
||||
(st/emit! (msg/success (tr "dashboard.success-move-file"))))
|
||||
(if (or navigate? (not= team-id current-team-id))
|
||||
(st/emit! (dd/go-to-files team-id project-id))
|
||||
(st/emit! (dd/fetch-recent-files team-id)
|
||||
(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
|
||||
(fn [team-id project-id]
|
||||
(let [params {:ids (into #{} (map :id) files)
|
||||
:project-id project-id}]
|
||||
(fn []
|
||||
(st/emit! (dd/move-files
|
||||
(with-meta params
|
||||
{:on-success #(on-move-success team-id project-id)}))))))
|
||||
|
||||
(let [num-shared (filter #(:is-shared %) files)]
|
||||
(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
|
||||
#(st/emit! (dd/set-file-shared (assoc file :is-shared true)))
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
[app.main.refs :as refs]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
||||
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
|
@ -131,18 +131,14 @@
|
|||
:ref input-ref
|
||||
:on-selected handle-selected}]]
|
||||
|
||||
[:div {:class (stl/css :banner)}
|
||||
[:div {:class (stl/css :icon)} i/msg-neutral-refactor]
|
||||
[:div {:class (stl/css :content)}
|
||||
[:& i18n/tr-html {:tag-name "span"
|
||||
:label "dashboard.fonts.hero-text2"}]]]
|
||||
[:& context-notification {:content (tr "dashboard.fonts.hero-text2")
|
||||
:type :default
|
||||
:is-html true}]
|
||||
|
||||
(when problematic-fonts?
|
||||
[:div {:class (stl/css :banner :warning)}
|
||||
[:div {:class (stl/css :icon)} i/msg-warning-refactor]
|
||||
[:div {:class (stl/css :content)}
|
||||
[:& i18n/tr-html {:tag-name "span"
|
||||
:label "dashboard.fonts.warning-text"}]]])]]
|
||||
[:& context-notification {:content (tr "dashboard.fonts.warning-text")
|
||||
:type :warning
|
||||
:is-html true}])]]
|
||||
|
||||
[:*
|
||||
(when (some? (vals fonts))
|
||||
|
@ -176,7 +172,7 @@
|
|||
|
||||
[:div {:class (stl/css :table-field :options)}
|
||||
(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)
|
||||
:class (stl/css-case :btn-primary true
|
||||
|
|
|
@ -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 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
[app.main.worker :as uw]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
|
@ -385,14 +386,12 @@
|
|||
|
||||
(when (and (= :importing (:status @state)) (not pending-import?))
|
||||
(if (> warning-files 0)
|
||||
[:div {:class (stl/css-case :feedback-banner true
|
||||
:warning true)}
|
||||
[:div {:class (stl/css :icon)} i/msg-warning-refactor]
|
||||
[:div {:class (stl/css :message)} (tr "dashboard.import.import-warning" warning-files success-files)]]
|
||||
|
||||
[:div {:class (stl/css :feedback-banner)}
|
||||
[: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)))]]))
|
||||
[:& context-notification
|
||||
{:type :warning
|
||||
:content (tr "dashboard.import.import-warning" warning-files success-files)}]
|
||||
[:& context-notification
|
||||
{:type :success
|
||||
:content (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))}]))
|
||||
|
||||
(for [file files]
|
||||
(let [editing? (and (some? (:file-id file))
|
||||
|
|
33
frontend/src/app/main/ui/dashboard/import.scss
vendored
33
frontend/src/app/main/ui/dashboard/import.scss
vendored
|
@ -29,39 +29,12 @@
|
|||
|
||||
.modal-content {
|
||||
@include bodyMedTipography;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: $s-16;
|
||||
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 {
|
||||
@extend .modal-action-btns;
|
||||
}
|
||||
|
|
|
@ -608,7 +608,7 @@
|
|||
height: $s-24;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--alert-foreground-color-error);
|
||||
stroke: var(--alert-icon-foreground-color-error);
|
||||
}
|
||||
}
|
||||
.message {
|
||||
|
@ -632,7 +632,7 @@
|
|||
height: $s-24;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--alert-foreground-color-warning);
|
||||
stroke: var(--alert-icon-foreground-color-warning);
|
||||
}
|
||||
}
|
||||
.message {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
(:require
|
||||
[app.common.spec :as us]
|
||||
[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.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
|
@ -29,22 +29,22 @@
|
|||
(defn- on-create-success
|
||||
[_form response]
|
||||
(let [msg "Team created successfully"]
|
||||
(st/emit! (dm/success msg)
|
||||
(st/emit! (msg/success msg)
|
||||
(modal/hide)
|
||||
(rt/nav :dashboard-projects {:team-id (:id response)}))))
|
||||
|
||||
(defn- on-update-success
|
||||
[_form _response]
|
||||
(let [msg "Team created successfully"]
|
||||
(st/emit! (dm/success msg)
|
||||
(st/emit! (msg/success msg)
|
||||
(modal/hide))))
|
||||
|
||||
(defn- on-error
|
||||
[form _response]
|
||||
(let [id (get-in @form [:clean-data :id])]
|
||||
(if id
|
||||
(rx/of (dm/error "Error on updating team."))
|
||||
(rx/of (dm/error "Error on creating team.")))))
|
||||
(rx/of (msg/error "Error on updating team."))
|
||||
(rx/of (msg/error "Error on creating team.")))))
|
||||
|
||||
(defn- on-create-submit
|
||||
[form]
|
||||
|
@ -117,6 +117,6 @@
|
|||
{:label (if team
|
||||
(tr "labels.update-team")
|
||||
(tr "labels.create-team"))
|
||||
:className (stl/css :accept-btn)}]]]]]]))
|
||||
:class (stl/css :accept-btn)}]]]]]]))
|
||||
|
||||
|
||||
|
|
|
@ -35,28 +35,26 @@
|
|||
cancel-label (tr "labels.cancel")
|
||||
accept-style (or accept-style :danger)
|
||||
|
||||
is-delete? (= origin :delete)
|
||||
count-files (count (keys references))
|
||||
|
||||
title (if ^boolean is-delete?
|
||||
(tr "modals.delete-shared-confirm.title" (i18n/c count-libraries))
|
||||
(tr "modals.unpublish-shared-confirm.title" (i18n/c count-libraries)))
|
||||
title (case origin
|
||||
:delete (tr "modals.delete-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?
|
||||
(tr "modals.delete-shared-confirm.message" (i18n/c count-libraries))
|
||||
(tr "modals.unpublish-shared-confirm.message" (i18n/c count-libraries)))
|
||||
subtitle (case origin
|
||||
:delete (tr "modals.delete-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?
|
||||
(tr "modals.delete-shared-confirm.accept" (i18n/c count-libraries))
|
||||
(tr "modals.unpublish-shared-confirm.accept" (i18n/c count-libraries)))
|
||||
accept-label (case origin
|
||||
:delete (tr "modals.delete-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?
|
||||
(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)))
|
||||
no-files-msg (tr "modals.delete-shared-confirm.activated.no-files-message" (i18n/c count-libraries))
|
||||
|
||||
scd-msg (if ^boolean is-delete?
|
||||
(tr "modals.delete-shared-confirm.activated.scd-message" (i18n/c count-libraries))
|
||||
(tr "modals.unpublish-shared-confirm.activated.scd-message" (i18n/c count-libraries)))
|
||||
scd-msg (tr "modals.delete-shared-confirm.activated.scd-message" (i18n/c count-libraries))
|
||||
|
||||
hint (tr "modals.delete-unpublish-shared-confirm.activated.hint" (i18n/c count-files))
|
||||
|
||||
|
|
|
@ -5,93 +5,43 @@
|
|||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.messages
|
||||
(: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.data.messages :as dmsg]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.link-button :as lb]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.notifications.context-notification :refer [context-notification]]
|
||||
[app.main.ui.notifications.inline-notification :refer [inline-notification]]
|
||||
[app.main.ui.notifications.toast-notification :refer [toast-notification]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc banner
|
||||
[{: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
|
||||
(mf/defc notifications-hub
|
||||
[]
|
||||
(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
|
||||
[:& banner (assoc message
|
||||
:position (or (:position message) :fixed)
|
||||
:controls (if (some? (:controls message))
|
||||
(:controls message)
|
||||
:close)
|
||||
:on-close on-close)])))
|
||||
|
||||
(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}])
|
||||
|
||||
(cond
|
||||
is-toast-msg
|
||||
[:& toast-notification toast-message]
|
||||
is-inline-msg
|
||||
[:& inline-notification inline-message]
|
||||
:else
|
||||
[:& context-notification context-message]))))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)}])])])
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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)])]])
|
|
@ -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;
|
||||
}
|
|
@ -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]])
|
103
frontend/src/app/main/ui/notifications/toast_notification.scss
Normal file
103
frontend/src/app/main/ui/notifications/toast_notification.scss
Normal 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);
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
(ns app.main.ui.onboarding.newsletter
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.store :as st]
|
||||
|
@ -33,7 +33,7 @@
|
|||
(mf/deps @newsletter-updates @newsletter-news)
|
||||
(fn []
|
||||
(st/emit! (when (or @newsletter-updates @newsletter-news)
|
||||
(dm/success message))
|
||||
(msg/success message))
|
||||
(modal/show {:type :onboarding-team})
|
||||
(du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))]
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
[app.common.spec :as us]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[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.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -169,7 +169,7 @@
|
|||
on-error
|
||||
(mf/use-fn
|
||||
(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
|
||||
on-invite-later
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[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.users :as du]
|
||||
[app.main.store :as st]
|
||||
|
@ -66,7 +66,7 @@
|
|||
(fn [_]
|
||||
(let [message (tr "dashboard.access-tokens.create.success")]
|
||||
(st/emit! (du/fetch-access-tokens)
|
||||
(dm/success message)
|
||||
(msg/success message)
|
||||
(reset! created? true)))))
|
||||
|
||||
on-close
|
||||
|
@ -79,7 +79,7 @@
|
|||
on-error
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(st/emit! (dm/error (tr "errors.generic"))
|
||||
(st/emit! (msg/error (tr "errors.generic"))
|
||||
(modal/hide))))
|
||||
|
||||
on-submit
|
||||
|
@ -101,9 +101,10 @@
|
|||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(wapi/write-to-clipboard (:token created))
|
||||
(st/emit! (dm/show {:type :info
|
||||
:content (tr "dashboard.access-tokens.copied-success")
|
||||
:timeout 1000}))))]
|
||||
(st/emit! (msg/show {:type :info
|
||||
:notification-type :toast
|
||||
:content (tr "dashboard.access-tokens.copied-success")
|
||||
:timeout 7000}))))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-container)}
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dma]
|
||||
[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.users :as du]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[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]]
|
||||
[beicon.v2.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
|
@ -47,11 +47,11 @@
|
|||
(assoc-in data [:errors :email-1] error))))
|
||||
|
||||
: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
|
||||
(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)))
|
||||
|
||||
|
@ -61,7 +61,7 @@
|
|||
(st/emit! (du/fetch-profile)
|
||||
(modal/hide))
|
||||
(let [message (tr "notifications.validation-email-sent" (:email profile))]
|
||||
(st/emit! (dm/info message)
|
||||
(st/emit! (msg/info message)
|
||||
(modal/hide)))))
|
||||
|
||||
(defn- on-submit
|
||||
|
@ -110,7 +110,7 @@
|
|||
:on-click on-close} i/close-refactor]]
|
||||
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
[:& msgs/inline-banner
|
||||
[:& context-notification
|
||||
{:type :info
|
||||
:content (tr "modals.change-email.info" (:email profile))}]
|
||||
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
(ns app.main.ui.settings.delete-account
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.store :as st]
|
||||
[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]]
|
||||
[beicon.v2.core :as rx]
|
||||
[rumext.v2 :as mf]))
|
||||
|
@ -21,7 +21,7 @@
|
|||
[{:keys [code] :as error}]
|
||||
(if (= :owner-teams-with-people code)
|
||||
(let [msg (tr "notifications.profile-deletion-not-allowed")]
|
||||
(rx/of (dm/error msg)))
|
||||
(rx/of (msg/error msg)))
|
||||
(rx/throw error)))
|
||||
|
||||
(mf/defc delete-account-modal
|
||||
|
@ -47,7 +47,7 @@
|
|||
:on-click on-close} i/close-refactor]]
|
||||
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
[:& msgs/inline-banner
|
||||
[:& context-notification
|
||||
{:type :warning
|
||||
:content (tr "modals.delete-account.info")}]]
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.spec :as us]
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -39,7 +39,7 @@
|
|||
(mf/deps profile)
|
||||
(fn [_]
|
||||
(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 {})))
|
||||
|
||||
on-error
|
||||
|
@ -48,8 +48,8 @@
|
|||
(fn [{:keys [code] :as error}]
|
||||
(reset! loading false)
|
||||
(if (= code :feedback-disabled)
|
||||
(st/emit! (dm/error (tr "labels.feedback-disabled")))
|
||||
(st/emit! (dm/error (tr "errors.generic"))))))
|
||||
(st/emit! (msg/error (tr "labels.feedback-disabled")))
|
||||
(st/emit! (msg/error (tr "errors.generic"))))))
|
||||
|
||||
on-submit
|
||||
(mf/use-callback
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[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.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
(defn- on-success
|
||||
[_]
|
||||
(st/emit! (dm/success (tr "notifications.profile-saved"))))
|
||||
(st/emit! (msg/success (tr "notifications.profile-saved"))))
|
||||
|
||||
(defn- on-submit
|
||||
[form _event]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[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.store :as st]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
|
@ -28,7 +28,7 @@
|
|||
{:message (tr "errors.email-as-password")})
|
||||
|
||||
(let [msg (tr "generic.error")]
|
||||
(st/emit! (dm/error msg)))))
|
||||
(st/emit! (msg/error msg)))))
|
||||
|
||||
(defn- on-success
|
||||
[form]
|
||||
|
@ -37,7 +37,7 @@
|
|||
msg (tr "dashboard.notifications.password-saved")]
|
||||
(dom/clean-value! password-old-node)
|
||||
(dom/focus! password-old-node)
|
||||
(st/emit! (dm/success msg))))
|
||||
(st/emit! (msg/success msg))))
|
||||
|
||||
(defn- on-submit
|
||||
[form event]
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
(:require
|
||||
[app.common.spec :as us]
|
||||
[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.users :as du]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -29,7 +29,7 @@
|
|||
|
||||
(defn- on-success
|
||||
[_]
|
||||
(st/emit! (dm/success (tr "notifications.profile-saved"))))
|
||||
(st/emit! (msg/success (tr "notifications.profile-saved"))))
|
||||
|
||||
(defn- on-submit
|
||||
[form _event]
|
||||
|
@ -80,7 +80,7 @@
|
|||
[:> fm/submit-button*
|
||||
{:label (tr "dashboard.save-settings")
|
||||
:disabled (empty? (:touched @form))
|
||||
:className (stl/css :btn-primary)}]
|
||||
:class (stl/css :btn-primary)}]
|
||||
|
||||
[:div {:class (stl/css :links)}
|
||||
[:div {:class (stl/css :link-item)}
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
}
|
||||
|
||||
.viewer-section {
|
||||
@extend .new-scrollbar;
|
||||
grid-row: 1 / span 2;
|
||||
grid-column: 1 / span 1;
|
||||
display: flex;
|
||||
|
@ -94,7 +95,7 @@
|
|||
}
|
||||
|
||||
.viewer-go-next.comment-sidebar {
|
||||
right: $s-264;
|
||||
right: $s-280;
|
||||
}
|
||||
|
||||
.viewer-go-prev {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
|
@ -26,16 +27,20 @@
|
|||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc comments-menu
|
||||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
{::mf/props :obj
|
||||
::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)
|
||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||
|
||||
update-mode
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [mode (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
|
@ -43,78 +48,76 @@
|
|||
(st/emit! (dcm/update-filters {:mode mode})))))
|
||||
|
||||
update-show
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [mode (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(d/read-string))]
|
||||
(keyword))
|
||||
mode (if (= :pending mode) :all :pending)]
|
||||
(st/emit! (dcm/update-filters {:show mode})))))
|
||||
|
||||
update-options
|
||||
(mf/use-callback
|
||||
(mf/deps show-sidebar?)
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [mode (-> (dom/get-target event)
|
||||
(let [mode (-> (dom/get-current-target event)
|
||||
(dom/get-data "value")
|
||||
(boolean))]
|
||||
(parse-boolean))]
|
||||
(st/emit! (dcm/update-options {:show-sidebar? (not mode)})))))]
|
||||
|
||||
[:div {:class (stl/css :view-options)
|
||||
:on-click toggle-dropdown}
|
||||
[:span {:class (stl/css :dropdown-title)}
|
||||
(tr "labels.comments")]
|
||||
[:span {:class (stl/css :icon-dropdown)}
|
||||
i/arrow-refactor]
|
||||
[:span {:class (stl/css :dropdown-title)} (tr "labels.comments")]
|
||||
[:span {:class (stl/css :icon-dropdown)} i/arrow-refactor]
|
||||
|
||||
[:& dropdown {:show @show-dropdown?
|
||||
:on-close hide-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"
|
||||
:on-click update-mode}
|
||||
|
||||
[:span {:class (stl/css :label)} (tr "labels.show-all-comments")]
|
||||
(when (or (= :all cmode) (nil? cmode))
|
||||
[:span {:class (stl/css :icon)} i/tick-refactor])]
|
||||
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= :yours cmode))
|
||||
[:li {:class (stl/css-case
|
||||
:dropdown-element true
|
||||
:selected (= :yours cmode))
|
||||
:data-value "yours"
|
||||
: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)
|
||||
[:span {:class (stl/css :icon)}
|
||||
i/tick-refactor])]
|
||||
|
||||
[:li {:class (stl/css :separator)}]
|
||||
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= :pending cshow))
|
||||
:data-value (if (= :pending cshow) "all" "pending")
|
||||
[:li {:class (stl/css-case
|
||||
:dropdown-element true
|
||||
:selected (= :pending cshow))
|
||||
:data-value (d/name cshow)
|
||||
: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)
|
||||
[:span {:class (stl/css :icon)}
|
||||
i/tick-refactor])]
|
||||
|
||||
[:li {:class (stl/css :separator)}]
|
||||
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected show-sidebar?)
|
||||
:data-value (str show-sidebar?)
|
||||
[:li {:class (stl/css-case
|
||||
:dropdown-element true
|
||||
:selected show-sidebar?)
|
||||
:data-value (dm/str show-sidebar?)
|
||||
:on-click update-options}
|
||||
|
||||
[:span {:class (stl/css :label)} (tr "labels.show-comments-list")]
|
||||
(when show-sidebar?
|
||||
[: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)]
|
||||
(-> thread
|
||||
(assoc :position (:position data))
|
||||
|
@ -122,7 +125,8 @@
|
|||
thread))
|
||||
|
||||
(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)
|
||||
local (mf/deref refs/comments-local)
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
position: absolute;
|
||||
right: 0;
|
||||
top: $s-44;
|
||||
width: $s-256;
|
||||
width: $s-276;
|
||||
height: calc(100vh - $s-48);
|
||||
z-index: $z-index-10;
|
||||
background-color: var(--panel-background-color);
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
(modal/show! :login-register {}))
|
||||
|
||||
(mf/defc zoom-widget
|
||||
{::mf/wrap [mf/memo]}
|
||||
{::mf/memo true
|
||||
::mf/props :obj}
|
||||
[{:keys [zoom
|
||||
on-increase
|
||||
on-decrease
|
||||
|
@ -102,38 +103,38 @@
|
|||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
|
||||
[: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)
|
||||
:on-click on-zoom-fill}
|
||||
(tr "workspace.header.zoom-fill")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-zoom-style))]
|
||||
[: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)
|
||||
:on-click on-fullscreen}
|
||||
(tr "workspace.header.zoom-full-screen")
|
||||
[:span {:class (stl/css :shortcuts)}
|
||||
(for [sc (scd/split-sc (sc/get-tooltip :toggle-fullscreen))]
|
||||
[:span {:class (stl/css :shortcut-key)
|
||||
:key (str "zoom-fullscreen-" sc)} sc])]]]]]))
|
||||
:key (dm/str "zoom-fullscreen-" sc)} sc])]]]]]))
|
||||
|
||||
(mf/defc header-options
|
||||
[{:keys [section zoom page file index permissions interactions-mode]}]
|
||||
(let [fullscreen? (mf/deref fullscreen-ref)
|
||||
|
||||
toggle-fullscreen
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [] (st/emit! dv/toggle-fullscreen)))
|
||||
|
||||
go-to-workspace
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps page)
|
||||
(fn []
|
||||
(st/emit! (dv/go-to-workspace (:id page)))))
|
||||
|
||||
open-share-dialog
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps page)
|
||||
(fn []
|
||||
(modal/show! :share-link {:page page :file file})
|
||||
|
@ -209,22 +210,22 @@
|
|||
show-dropdown? (mf/use-state false)
|
||||
|
||||
toggle-thumbnails
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! dv/toggle-thumbnails-panel)))
|
||||
|
||||
open-dropdown
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(reset! show-dropdown? true)))
|
||||
|
||||
close-dropdown
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(reset! show-dropdown? false)))
|
||||
|
||||
navigate-to
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [page-id]
|
||||
(st/emit! (dv/go-to-page page-id))
|
||||
(reset! show-dropdown? false)))]
|
||||
|
@ -245,8 +246,8 @@
|
|||
(for [id (get-in file [:data :pages])]
|
||||
[:li {:class (stl/css-case :dropdown-element true
|
||||
:selected (= page-id id))
|
||||
:id (str id)
|
||||
:key (str id)
|
||||
:id (dm/str id)
|
||||
:key (dm/str id)
|
||||
:on-click (partial navigate-to id)}
|
||||
[:span {:class (stl/css :label)}
|
||||
(get-in file [:data :pages-index id :name])]
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
:align-content
|
||||
:justify-items
|
||||
:justify-content
|
||||
:row-gap
|
||||
:column-gap
|
||||
:gap
|
||||
:padding])
|
||||
|
||||
|
|
|
@ -184,6 +184,7 @@
|
|||
|
||||
set-markup
|
||||
(mf/use-callback
|
||||
(mf/deps markup-type*)
|
||||
(fn [value]
|
||||
(reset! markup-type* value)))
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.viewer-code {
|
||||
padding: 0 $s-8;
|
||||
}
|
||||
|
||||
.tool-windows {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(mf/defc sidebar-options
|
||||
[]
|
||||
[{:keys [from-viewer]}]
|
||||
(let [{cmode :mode cshow :show} (mf/deref refs/comments-local)
|
||||
update-mode
|
||||
(mf/use-fn
|
||||
|
@ -44,7 +44,8 @@
|
|||
(let [mode (if (= :pending cshow) :all :pending)]
|
||||
(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
|
||||
:selected (or (= :all cmode) (nil? cmode)))
|
||||
:data-value "all"
|
||||
|
@ -115,8 +116,10 @@
|
|||
(dwcm/center-to-comment-thread thread)
|
||||
(-> (dcm/open-thread thread)
|
||||
(with-meta {::ev/origin "workspace"})))))))]
|
||||
[:div {:class (stl/css :comments-section)}
|
||||
[:div {:class (stl/css :comments-section-title)}
|
||||
[:div {:class (stl/css-case :comments-section true
|
||||
:from-viewer from-viewer)}
|
||||
[:div {:class (stl/css-case :comments-section-title true
|
||||
:viewer-title from-viewer)}
|
||||
[:span (tr "labels.comments")]
|
||||
[:button {:class (stl/css :close-button)
|
||||
:on-click close-section}
|
||||
|
@ -128,11 +131,11 @@
|
|||
[:span {:class (stl/css :mode-label)} (case (:mode local)
|
||||
(nil :all) (tr "labels.show-all-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?
|
||||
:on-close #(reset! state* false)}
|
||||
[:& sidebar-options {:local local}]]
|
||||
[:& sidebar-options {:local local :from-viewer from-viewer}]]
|
||||
|
||||
[:div {:class (stl/css :comments-section-content)}
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
grid-template-rows: $s-40 $s-48 1fr;
|
||||
}
|
||||
|
||||
.from-viewer {
|
||||
padding: 0 $s-8;
|
||||
}
|
||||
|
||||
.comments-section-title {
|
||||
@include flexCenter;
|
||||
@include uppercaseTitleTipography;
|
||||
|
@ -29,6 +33,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.viewer-title {
|
||||
margin: 0;
|
||||
margin-block-start: $s-8;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
@extend .button-tertiary;
|
||||
position: absolute;
|
||||
|
@ -48,7 +57,8 @@
|
|||
@extend .asset-element;
|
||||
background-color: var(--color-background-tertiary);
|
||||
display: flex;
|
||||
width: $s-256;
|
||||
width: 100%;
|
||||
max-width: $s-256;
|
||||
height: $s-32;
|
||||
padding: $s-8;
|
||||
border-radius: $br-8;
|
||||
|
@ -64,9 +74,8 @@
|
|||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.icon {
|
||||
.arrow-icon {
|
||||
@include flexCenter;
|
||||
padding-right: 8px;
|
||||
height: $s-24;
|
||||
width: $s-24;
|
||||
svg {
|
||||
|
@ -78,9 +87,14 @@
|
|||
|
||||
.comment-mode-dropdown {
|
||||
@extend .dropdown-wrapper;
|
||||
top: $s-80;
|
||||
top: $s-92;
|
||||
left: $s-12;
|
||||
width: $s-256;
|
||||
max-width: $s-256;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.viewer-dropdown {
|
||||
left: $s-8;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
|
|
|
@ -355,6 +355,9 @@
|
|||
(not (ctn/has-any-copy-parent? objects shape))
|
||||
(cfh/component-touched? objects (:id shape)))))
|
||||
|
||||
can-detach? (and (seq copies)
|
||||
(every? #(not (ctn/has-any-copy-parent? objects %)) copies))
|
||||
|
||||
|
||||
do-detach-component
|
||||
#(st/emit! (dwl/detach-components (map :id copies)))
|
||||
|
@ -420,7 +423,7 @@
|
|||
(when (and (not multi) main-instance? local-component? lacks-annotation? components-v2)
|
||||
{:msg "workspace.shape.menu.create-annotation"
|
||||
:action do-create-annotation})
|
||||
(when (seq copies)
|
||||
(when can-detach?
|
||||
{:msg (if (> (count copies) 1)
|
||||
"workspace.shape.menu.detach-instances-in-bulk"
|
||||
"workspace.shape.menu.detach-instance")
|
||||
|
|
|
@ -155,7 +155,8 @@
|
|||
children]))
|
||||
|
||||
(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]}]
|
||||
(let [id (:id item)
|
||||
blocked? (:blocked item)
|
||||
|
|
|
@ -21,19 +21,51 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.main.ui.workspace.sidebar.layer-item :refer [layer-item]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.object :as obj]
|
||||
[app.util.timers :as ts]
|
||||
[beicon.v2.core :as rx]
|
||||
[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
|
||||
;; level frames and try to avoid rerender frames that are does not
|
||||
;; affected by the selected set.
|
||||
(mf/defc frame-wrapper
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
|
||||
{::mf/wrap-props false}
|
||||
[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/wrap [mf/memo #(mf/throttle % 200)]
|
||||
|
@ -158,6 +190,21 @@
|
|||
(mf/use-fn
|
||||
#(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
|
||||
(mf/use-fn
|
||||
(fn [value _event]
|
||||
|
@ -190,6 +237,7 @@
|
|||
add-filter
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(let [key (-> (dom/get-current-target event)
|
||||
(dom/get-data "filter")
|
||||
(keyword))]
|
||||
|
@ -226,6 +274,11 @@
|
|||
(when (<= current-items filtered-objects-total)
|
||||
(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
|
||||
handle-show-more
|
||||
#(mf/html
|
||||
|
@ -236,7 +289,7 @@
|
|||
:value current-search
|
||||
:on-clear clear-search-text
|
||||
:placeholder (tr "workspace.sidebar.layers.search")}
|
||||
[:button {:on-click toggle-filters
|
||||
[:button {:on-click on-toggle-filters-click
|
||||
:class (stl/css-case
|
||||
:filter-button true
|
||||
:opened show-menu?
|
||||
|
@ -459,7 +512,7 @@
|
|||
(mf/use-fn
|
||||
#(st/emit! (dw/toggle-focus-mode)))]
|
||||
|
||||
[:div#layers
|
||||
[:div#layers {:class (stl/css :layers)}
|
||||
(if (d/not-empty? focus)
|
||||
[:div {:class (stl/css :tool-window-bar)}
|
||||
[:button {:class (stl/css :focus-title)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
justify-content: space-between;
|
||||
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;
|
||||
|
||||
&.search {
|
||||
|
@ -164,10 +164,14 @@
|
|||
color: var(--pill-foreground-color);
|
||||
}
|
||||
|
||||
.layers {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.filters-container {
|
||||
@extend .menu-dropdown;
|
||||
top: $s-44;
|
||||
left: $s-12;
|
||||
position: absolute;
|
||||
left: $s-20;
|
||||
width: $s-192;
|
||||
.filter-menu-item {
|
||||
@include bodyMedTipography;
|
||||
|
|
|
@ -522,7 +522,8 @@
|
|||
(when open?
|
||||
[:div {:class (stl/css :element-content)}
|
||||
[: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
|
||||
:with-main (and can-swap? (not multi))
|
||||
:swappeable (and can-swap? (not swap-opened?)))
|
||||
|
|
|
@ -51,6 +51,15 @@
|
|||
grid-template-columns: 1fr $s-28;
|
||||
gap: $s-2;
|
||||
}
|
||||
|
||||
&.without-actions {
|
||||
padding-right: 0.5rem;
|
||||
.component-name-wrapper {
|
||||
width: 100%;
|
||||
|
||||
border-radius: $br-8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.component-name-wrapper {
|
||||
|
|
|
@ -357,13 +357,14 @@
|
|||
(update-interaction index #(ctsi/set-offset-effect % value)))))
|
||||
|
||||
|
||||
event-type-options [{:value :click :label (tr "workspace.options.interaction-on-click")}
|
||||
;; TODO: need more UX research
|
||||
;; :mouse-over (tr "workspace.options.interaction-while-hovering")
|
||||
;; :mouse-press (tr "workspace.options.interaction-while-pressing")
|
||||
{:value :mouse-enter :label (tr "workspace.options.interaction-mouse-enter")}
|
||||
{:value :mouse-leave :label (tr "workspace.options.interaction-mouse-leave")}
|
||||
{:value :after-delay :label (tr "workspace.options.interaction-after-delay")}]
|
||||
event-type-options (-> [{:value :click :label (tr "workspace.options.interaction-on-click")}
|
||||
;; TODO: need more UX research
|
||||
;; :mouse-over (tr "workspace.options.interaction-while-hovering")
|
||||
;; :mouse-press (tr "workspace.options.interaction-while-pressing")
|
||||
{:value :mouse-enter :label (tr "workspace.options.interaction-mouse-enter")}
|
||||
{:value :mouse-leave :label (tr "workspace.options.interaction-mouse-leave")}]
|
||||
(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")}
|
||||
{:value :open-overlay :label (tr "workspace.options.interaction-open-overlay")}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,8 +20,7 @@
|
|||
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]
|
||||
[rumext.v2.props :as-alias mf.props]))
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def layout-item-attrs
|
||||
[:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0}
|
||||
|
@ -46,14 +45,14 @@
|
|||
|
||||
(mf/defc margin-simple
|
||||
{::mf/props :obj}
|
||||
[{:keys [margin on-change on-blur]}]
|
||||
(let [m1 (:m1 margin)
|
||||
m2 (:m2 margin)
|
||||
m3 (:m3 margin)
|
||||
m4 (:m4 margin)
|
||||
[{:keys [value on-change on-blur]}]
|
||||
(let [m1 (:m1 value)
|
||||
m2 (:m2 value)
|
||||
m3 (:m3 value)
|
||||
m4 (:m4 value)
|
||||
|
||||
m1 (when (and (not= margin :multiple) (= m1 m3)) m1)
|
||||
m2 (when (and (not= margin :multiple) (= m2 m4)) m2)
|
||||
m1 (when (and (not= value :multiple) (= m1 m3)) m1)
|
||||
m2 (when (and (not= value :multiple) (= m2 m4)) m2)
|
||||
|
||||
on-focus
|
||||
(mf/use-fn
|
||||
|
@ -106,11 +105,11 @@
|
|||
|
||||
(mf/defc margin-multiple
|
||||
{::mf/props :obj}
|
||||
[{:keys [margin on-change on-blur]}]
|
||||
(let [m1 (:m1 margin)
|
||||
m2 (:m2 margin)
|
||||
m3 (:m3 margin)
|
||||
m4 (:m4 margin)
|
||||
[{:keys [value on-change on-blur]}]
|
||||
(let [m1 (:m1 value)
|
||||
m2 (:m2 value)
|
||||
m3 (:m3 value)
|
||||
m4 (:m4 value)
|
||||
|
||||
on-focus
|
||||
(mf/use-fn
|
||||
|
@ -186,11 +185,11 @@
|
|||
(mf/defc margin-section
|
||||
{::mf/props :obj
|
||||
::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}]
|
||||
(let [type (d/nilv type :simple)
|
||||
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'
|
||||
(mf/use-fn
|
||||
|
@ -220,14 +219,17 @@
|
|||
i/margin-refactor]]))
|
||||
|
||||
(mf/defc element-behaviour-horizontal
|
||||
{::mf/props :obj}
|
||||
[{:keys [^boolean is-auto ^boolean has-fill sizing on-change]}]
|
||||
[:div {:class (stl/css-case :horizontal-behaviour true
|
||||
:one-element (and (not has-fill) (not is-auto))
|
||||
:two-element (or has-fill is-auto)
|
||||
:three-element (and has-fill is-auto))}
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [^boolean is-auto ^boolean has-fill value on-change]}]
|
||||
[:div {:class (stl/css-case
|
||||
:horizontal-behaviour true
|
||||
: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
|
||||
{:selected (d/name sizing)
|
||||
{:selected (d/name value)
|
||||
:decode-fn keyword
|
||||
:on-change on-change
|
||||
:wide true
|
||||
:name "flex-behaviour-h"}
|
||||
|
@ -252,14 +254,17 @@
|
|||
:id "behaviour-h-auto"}])]])
|
||||
|
||||
(mf/defc element-behaviour-vertical
|
||||
{::mf/props :obj}
|
||||
[{:keys [^boolean is-auto ^boolean has-fill sizing on-change]}]
|
||||
[:div {:class (stl/css-case :vertical-behaviour true
|
||||
:one-element (and (not has-fill) (not is-auto))
|
||||
:two-element (or has-fill is-auto)
|
||||
:three-element (and has-fill is-auto))}
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [^boolean is-auto ^boolean has-fill value on-change]}]
|
||||
[:div {:class (stl/css-case
|
||||
:vertical-behaviour true
|
||||
: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
|
||||
{:selected (d/name sizing)
|
||||
{:selected (d/name value)
|
||||
:decode-fn keyword
|
||||
:on-change on-change
|
||||
:wide true
|
||||
:name "flex-behaviour-v"}
|
||||
|
@ -286,34 +291,11 @@
|
|||
:title "Fit content"
|
||||
: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/props :obj}
|
||||
[{:keys [^boolean is-col align-self on-change]}]
|
||||
[:& radio-buttons {:selected (d/name align-self)
|
||||
[{:keys [^boolean is-col value on-change]}]
|
||||
[:& radio-buttons {:selected (d/name value)
|
||||
:decode-fn keyword
|
||||
:on-change on-change
|
||||
:name "flex-align-self"
|
||||
:allow-empty true}
|
||||
|
@ -392,16 +374,16 @@
|
|||
:else
|
||||
"Layout element")
|
||||
|
||||
set-align-self
|
||||
on-align-self-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids align-self)
|
||||
(fn [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 (keyword value)})))))
|
||||
(st/emit! (dwsl/update-layout-child ids {:layout-item-align-self value})))))
|
||||
|
||||
;; Margin
|
||||
on-change-margin-type
|
||||
on-margin-type-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [type]
|
||||
|
@ -422,19 +404,17 @@
|
|||
(st/emit! (dwsl/update-layout-child ids {:layout-item-margin {prop val}})))))
|
||||
|
||||
;; Behaviour
|
||||
on-change-behaviour-h
|
||||
on-behaviour-h-change
|
||||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(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/deps ids)
|
||||
(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
|
||||
on-size-change
|
||||
|
@ -450,10 +430,9 @@
|
|||
(mf/use-fn
|
||||
(mf/deps ids)
|
||||
(fn [value]
|
||||
(let [value (keyword value)]
|
||||
(when (= value :static)
|
||||
(st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil})))
|
||||
(st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)})))))
|
||||
(when (= value :static)
|
||||
(st/emit! (dwsl/update-layout-child ids {:layout-item-z-index nil})))
|
||||
(st/emit! (dwsl/update-layout-child ids {:layout-item-absolute (= value :absolute)}))))
|
||||
|
||||
;; Z Index
|
||||
on-change-z-index
|
||||
|
@ -476,6 +455,7 @@
|
|||
[:div {:class (stl/css :row)}
|
||||
[:div {:class (stl/css :position-options)}
|
||||
[:& radio-buttons {:selected (if is-absolute? "absolute" "static")
|
||||
:decode-fn keyword
|
||||
:on-change on-change-position
|
||||
:name "layout-style"
|
||||
:wide true}
|
||||
|
@ -497,24 +477,32 @@
|
|||
:value (:layout-item-z-index values)}]]])
|
||||
|
||||
[:div {:class (stl/css :row)}
|
||||
[:& element-behaviour {:has-fill is-layout-child?
|
||||
:is-auto is-layout-container?
|
||||
:v-sizing (:layout-item-v-sizing values)
|
||||
:h-sizing (:layout-item-h-sizing values)
|
||||
:on-h-change on-change-behaviour-h
|
||||
:on-v-change on-change-behaviour-v}]]
|
||||
[:div {:class (stl/css-case
|
||||
:behaviour-menu true
|
||||
:wrap (and ^boolean is-layout-child?
|
||||
^boolean is-layout-container?))}
|
||||
[:& element-behaviour-horizontal
|
||||
{: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?)
|
||||
[:div {:class (stl/css :row)}
|
||||
[:& align-self-row {:is-col is-col?
|
||||
:align-self align-self
|
||||
:on-change set-align-self}]])
|
||||
:value align-self
|
||||
:on-change on-align-self-change}]])
|
||||
|
||||
(when is-layout-child?
|
||||
[: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)
|
||||
:on-type-change on-change-margin-type
|
||||
:on-type-change on-margin-type-change
|
||||
:on-change on-margin-change}]])
|
||||
|
||||
(when (or (= h-sizing :fill)
|
||||
|
|
|
@ -632,6 +632,7 @@
|
|||
(not= @hover-top-frame-id (:id frame)))
|
||||
[:& grid-layout/editor
|
||||
{:zoom zoom
|
||||
:key (dm/str (:id frame))
|
||||
:objects base-objects
|
||||
:modifiers modifiers
|
||||
:shape frame
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
(+ (:y start-p) (/ 9 zoom))])
|
||||
|
||||
handle-click
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-click)
|
||||
#(when on-click (on-click)))]
|
||||
|
||||
|
@ -142,7 +142,7 @@
|
|||
current-pos-ref (mf/use-ref nil)
|
||||
|
||||
handle-pointer-down
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-drag-start)
|
||||
(fn [event]
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
|
@ -154,7 +154,7 @@
|
|||
(when on-drag-start (on-drag-start event position)))))
|
||||
|
||||
handle-lost-pointer-capture
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-drag-end)
|
||||
(fn [event]
|
||||
(let [raw-pt (mf/ref-val current-pos-ref)
|
||||
|
@ -165,7 +165,7 @@
|
|||
(when on-drag-end (on-drag-end event position)))))
|
||||
|
||||
handle-pointer-move
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-drag-delta on-drag-position)
|
||||
(fn [event]
|
||||
(when (mf/ref-val dragging-ref)
|
||||
|
@ -198,7 +198,7 @@
|
|||
layout-data (unchecked-get props "layout-data")
|
||||
|
||||
handle-drag-position
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps shape row column row-span column-span)
|
||||
(fn [_ 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))))))
|
||||
|
||||
handle-drag-end
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(st/emit! (dwm/apply-modifiers))))
|
||||
|
||||
|
@ -291,17 +291,10 @@
|
|||
text]]))
|
||||
|
||||
(mf/defc grid-cell
|
||||
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "cell" "layout-data" "zoom" "hover?" "selected?"]))]
|
||||
::mf/wrap-props false}
|
||||
[props]
|
||||
(let [shape (unchecked-get props "shape")
|
||||
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)
|
||||
{::mf/memo #{:shape :cell :layout-data :zoom :hover? :selected?}
|
||||
::mf/props :obj}
|
||||
[{:keys [shape cell layout-data zoom hover? selected?]}]
|
||||
(let [cell-bounds (gsg/cell-bounds layout-data cell)
|
||||
cell-origin (gpo/origin cell-bounds)
|
||||
cell-width (gpo/width-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)))
|
||||
|
||||
handle-pointer-enter
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape) (:id cell))
|
||||
(fn []
|
||||
(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) true))))
|
||||
|
||||
handle-pointer-leave
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape) (:id cell))
|
||||
(fn []
|
||||
(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) false))))
|
||||
|
||||
handle-pointer-down
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape) (:id cell) selected?)
|
||||
(fn [event]
|
||||
(when (dom/left-mouse? event)
|
||||
|
@ -339,7 +332,7 @@
|
|||
(st/emit! (dwge/set-selection (:id shape) (:id cell)))))))
|
||||
|
||||
handle-context-menu
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape) (:id cell) selected?)
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
|
@ -424,7 +417,7 @@
|
|||
start-size-after (mf/use-var nil)
|
||||
|
||||
handle-drag-start
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps shape track-before track-after)
|
||||
(fn []
|
||||
(reset! start-size-before (:size track-before))
|
||||
|
@ -444,7 +437,7 @@
|
|||
(st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers))))))
|
||||
|
||||
handle-drag-position
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps shape track-before track-after)
|
||||
(fn [_ position]
|
||||
(let [[tracks-prop axis]
|
||||
|
@ -469,7 +462,7 @@
|
|||
(st/emit! (dwm/set-modifiers (dwm/create-modif-tree [(:id shape)] modifiers))))))
|
||||
|
||||
handle-drag-end
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps track-before track-after)
|
||||
(fn []
|
||||
(reset! start-size-before nil)
|
||||
|
@ -732,7 +725,7 @@
|
|||
text-p (if (= type :column) hpt vpt)
|
||||
|
||||
handle-blur-track-input
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape))
|
||||
(fn [event]
|
||||
(let [target (-> event dom/get-target)
|
||||
|
@ -760,7 +753,7 @@
|
|||
(obj/set! target "value" (dom/get-attribute target "data-default-value"))))))
|
||||
|
||||
handle-keydown-track-input
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [enter? (kbd/enter? event)
|
||||
esc? (kbd/esc? event)]
|
||||
|
@ -770,13 +763,13 @@
|
|||
(dom/blur! (dom/get-target event))))))
|
||||
|
||||
handle-pointer-enter
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape) type index)
|
||||
(fn []
|
||||
(st/emit! (dwsl/hover-layout-track [(:id shape)] type index true))))
|
||||
|
||||
handle-pointer-leave
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape) type index)
|
||||
(fn []
|
||||
(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)])
|
||||
|
||||
handle-drag-start
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-start-reorder-track type index)
|
||||
(fn []
|
||||
(on-start-reorder-track type index)))
|
||||
|
||||
handle-drag-end
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-end-reorder-track type index)
|
||||
(fn [event position]
|
||||
(on-end-reorder-track type index position (not (kbd/mod? event)))))
|
||||
|
||||
handle-drag-position
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps on-move-reorder-track type index)
|
||||
(fn [_ position]
|
||||
(on-move-reorder-track type index position)))
|
||||
|
||||
handle-show-track-menu
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
|
@ -895,10 +888,9 @@
|
|||
:zoom zoom}]]))
|
||||
|
||||
(mf/defc editor
|
||||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
{::mf/memo true
|
||||
::mf/props :obj}
|
||||
[props]
|
||||
|
||||
(let [base-shape (unchecked-get props "shape")
|
||||
objects (unchecked-get props "objects")
|
||||
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)))
|
||||
|
||||
handle-pointer-down
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [event]
|
||||
(let [left-click? (= 1 (.-which (.-nativeEvent event)))]
|
||||
(when left-click?
|
||||
(dom/stop-propagation event)))))
|
||||
|
||||
handle-add-column
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape))
|
||||
(fn []
|
||||
(st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :column ctl/default-track-value)))))
|
||||
|
||||
handle-add-row
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps (:id shape))
|
||||
(fn []
|
||||
(st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :row ctl/default-track-value)))))
|
||||
|
||||
|
||||
target-tracks* (mf/use-ref nil)
|
||||
drop-track-type* (mf/use-state nil)
|
||||
drop-track-target* (mf/use-state nil)
|
||||
|
||||
handle-start-reorder-track
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps layout-data)
|
||||
(fn [type _from-idx]
|
||||
;; Initialize target-tracks
|
||||
|
@ -1014,7 +1005,7 @@
|
|||
(reset! drop-track-type* type))))
|
||||
|
||||
handle-move-reorder-track
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [_type _from-idx position]
|
||||
(let [index
|
||||
(->> (mf/ref-val target-tracks*)
|
||||
|
@ -1025,7 +1016,7 @@
|
|||
(reset! drop-track-target* index)))))
|
||||
|
||||
handle-end-reorder-track
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(mf/deps base-shape @drop-track-target*)
|
||||
(fn [type from-index _position move-content?]
|
||||
(when-let [to-index @drop-track-target*]
|
||||
|
@ -1041,9 +1032,8 @@
|
|||
(reset! drop-track-type* nil)
|
||||
(reset! drop-track-target* nil)))]
|
||||
|
||||
(mf/use-effect
|
||||
(fn []
|
||||
#(st/emit! (dwge/stop-grid-layout-editing (:id shape)))))
|
||||
(mf/with-effect []
|
||||
#(st/emit! (dwge/stop-grid-layout-editing (:id shape))))
|
||||
|
||||
(when (and (not (:hidden shape)) (not (:blocked shape)))
|
||||
[:g.grid-editor {:pointer-events (when view-only "none")
|
||||
|
@ -1057,7 +1047,8 @@
|
|||
:zoom zoom
|
||||
:hover? (contains? hover-cells (:id cell))
|
||||
:selected? (contains? selected-cells (:id cell))}])]
|
||||
(when-not view-only
|
||||
|
||||
(when-not ^boolean view-only
|
||||
[:*
|
||||
[:& grid-editor-frame {:zoom zoom
|
||||
:bounds bounds
|
||||
|
|
|
@ -291,7 +291,7 @@
|
|||
(not (ctk/main-instance? obj))))
|
||||
|
||||
;; Set with the elements to remove from the hover list
|
||||
remove-id-xf
|
||||
remove-hover-xf
|
||||
(cond
|
||||
mod?
|
||||
(filter grouped?)
|
||||
|
@ -306,8 +306,25 @@
|
|||
(and (contains? #{:group :bool} (dm/get-in objects [% :type]))
|
||||
(not (contains? child-parent? %)))))))
|
||||
|
||||
remove-id?
|
||||
(into selected-with-parents remove-id-xf ids)
|
||||
remove-measure-xf
|
||||
(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?
|
||||
(fn [id]
|
||||
|
@ -318,7 +335,7 @@
|
|||
|
||||
hover-shape
|
||||
(->> ids
|
||||
(remove remove-id?)
|
||||
(remove remove-hover?)
|
||||
(remove (partial cfh/hidden-parent? objects))
|
||||
(remove #(and mod? (no-fill-nested-frames? %)))
|
||||
(filter #(or (empty? focus) (cpf/is-in-focus? objects focus %)))
|
||||
|
@ -329,14 +346,12 @@
|
|||
measure-hover-shape
|
||||
(when show-measures?
|
||||
(->> ids
|
||||
(remove #(group-empty-space? % objects ids))
|
||||
(remove remove-measure?)
|
||||
(remove (partial cfh/hidden-parent? objects))
|
||||
(remove #(and mod? (no-fill-nested-frames? %)))
|
||||
(filter #(or (empty? focus) (cpf/is-in-focus? objects focus %)))
|
||||
(first)
|
||||
(get objects)))]
|
||||
|
||||
|
||||
(reset! hover hover-shape)
|
||||
(reset! measure-hover measure-hover-shape)
|
||||
(reset! hover-ids ids)))
|
||||
|
|
|
@ -6,22 +6,7 @@
|
|||
|
||||
(ns app.util.time
|
||||
(:require
|
||||
["date-fns/format" :default dateFnsFormat]
|
||||
["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]
|
||||
["./time_impl.js" :as impl]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.time :as common-time]
|
||||
[app.util.object :as obj]
|
||||
|
@ -207,22 +192,6 @@
|
|||
:json (.toJSON it)
|
||||
(.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
|
||||
([v] (timeago v nil))
|
||||
([v {:keys [locale] :or {locale "en"}}]
|
||||
|
@ -230,19 +199,18 @@
|
|||
(let [v (if (datetime? v) (format v :date) v)]
|
||||
(->> #js {:includeSeconds true
|
||||
:addSuffix true
|
||||
:locale (obj/get locales locale)}
|
||||
(dateFnsFormatDistanceToNowStrict v))))))
|
||||
:locale (obj/get impl/locales locale)}
|
||||
(impl/format-distance-to-now v))))))
|
||||
|
||||
(defn format-date-locale
|
||||
([v] (format-date-locale v nil))
|
||||
([v {:keys [locale] :or {locale "en"}}]
|
||||
(when 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)]
|
||||
(->> #js {:locale locale}
|
||||
(dateFnsFormat v f))))))
|
||||
|
||||
(impl/format v f))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Measurement Helpers
|
||||
|
|
71
frontend/src/app/util/time_impl.js
Normal file
71
frontend/src/app/util/time_impl.js
Normal 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;
|
|
@ -43,7 +43,7 @@
|
|||
(if (and (exists? js/window)
|
||||
(.-requestIdleCallback js/window))
|
||||
(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 %)))
|
||||
(do
|
||||
(def ^:private request-idle-callback #(js/setTimeout % 250))
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
[{:keys [page-id frame-id axis ranges bounds] :as message}]
|
||||
(let [match-bounds?
|
||||
(fn [[_ data]]
|
||||
(some #(grc/contains-point? bounds %) (map :pt data)))]
|
||||
(some #(or (= :guide (:type %))
|
||||
(grc/contains-point? bounds (:pt %))) data))]
|
||||
(->> (into []
|
||||
(comp (mapcat #(sd/query @state page-id frame-id axis %))
|
||||
(distinct))
|
||||
|
|
|
@ -4872,20 +4872,6 @@ msgstr[2] ""
|
|||
"Aktiva, která již byla v těchto souborech použita, tam zůstanou (nebude "
|
||||
"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
|
||||
msgid "auth.name.too-long"
|
||||
msgstr "Název musí obsahovat maximálně 250 znaků."
|
||||
|
|
|
@ -2122,18 +2122,6 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
|
|||
msgstr[0] "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/dashboard/file_menu.cljs
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -2103,17 +2103,10 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
|
|||
msgstr[0] "Unpublish"
|
||||
msgstr[1] "Unpublish"
|
||||
|
||||
#: 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] "It isn't activated in any file."
|
||||
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:"
|
||||
msgid "modals.move-shared-confirm.accept"
|
||||
msgid_plural "modals.move-shared-confirm.accept"
|
||||
msgstr[0] "Move"
|
||||
msgstr[1] "Move"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
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[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
|
||||
msgid "modals.unpublish-shared-confirm.title"
|
||||
msgid_plural "modals.unpublish-shared-confirm.title"
|
||||
msgstr[0] "Unpublish library"
|
||||
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
|
||||
msgid "modals.update-remote-component-in-bulk.hint"
|
||||
msgstr ""
|
||||
|
|
|
@ -2138,16 +2138,10 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
|
|||
msgstr[0] "Despublicar"
|
||||
msgstr[1] "Despublicar"
|
||||
|
||||
msgid "modals.unpublish-shared-confirm.activated.no-files-message"
|
||||
msgid_plural "modals.unpublish-shared-confirm.activated.no-files-message"
|
||||
msgstr[0] "No está activa en ningún fichero."
|
||||
msgstr[1] "No están activas en ningún fichero."
|
||||
|
||||
#: 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í:"
|
||||
msgid "modals.move-shared-confirm.accept"
|
||||
msgid_plural "modals.move-shared-confirm.accept"
|
||||
msgstr[0] "Mover"
|
||||
msgstr[1] "Mover"
|
||||
|
||||
#: src/app/main/ui/workspace/header.cljs, src/app/main/ui/dashboard/file_menu.cljs
|
||||
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[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
|
||||
msgid "modals.unpublish-shared-confirm.title"
|
||||
msgid_plural "modals.unpublish-shared-confirm.title"
|
||||
msgstr[0] "Despublicar biblioteca"
|
||||
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/context_menu.cljs
|
||||
msgid "modals.update-remote-component-in-bulk.hint"
|
||||
|
|
|
@ -2127,18 +2127,6 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
|
|||
msgstr[0] "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
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
msgid_plural "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -2157,12 +2157,6 @@ msgstr ""
|
|||
"wurin da za ka san yadda za ka hada-hannu da fassara, neman fasali, manyan "
|
||||
"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
|
||||
msgid "workspace.align.hright"
|
||||
msgstr "Daidaita dama (%s)"
|
||||
|
@ -3309,12 +3303,6 @@ msgstr "Yi da kanka"
|
|||
msgid "labels.save"
|
||||
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"
|
||||
msgstr "kammala aiki"
|
||||
|
||||
|
|
|
@ -4992,14 +4992,6 @@ msgstr "… תרשימי מתאר, סיפורי ותהליכי משתמשים,
|
|||
msgid "workspace.options.stroke-cap.diamond-marker-short"
|
||||
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,
|
||||
msgid "settings.detach"
|
||||
msgstr "ניתוק"
|
||||
|
@ -5008,14 +5000,6 @@ msgstr "ניתוק"
|
|||
msgid "workspace.options.stroke-cap.triangle-arrow-short"
|
||||
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"
|
||||
msgstr "יצירת הסבר"
|
||||
|
||||
|
|
|
@ -2098,16 +2098,6 @@ msgid "modals.unpublish-shared-confirm.accept"
|
|||
msgid_plural "modals.unpublish-shared-confirm.accept"
|
||||
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/dashboard/file_menu.cljs
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -2112,20 +2112,6 @@ msgstr[0] "Nav atlases"
|
|||
msgstr[1] "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/dashboard/file_menu.cljs
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -2143,20 +2143,6 @@ msgid_plural "modals.unpublish-shared-confirm.accept"
|
|||
msgstr[0] "Publicatie 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/dashboard/file_menu.cljs
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -2090,18 +2090,6 @@ msgstr "Remover \"%s\" como Biblioteca Partilhada"
|
|||
msgid "modals.small-nudge"
|
||||
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/dashboard/file_menu.cljs
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -2127,20 +2127,6 @@ msgstr[0] "Anulați publicarea"
|
|||
msgstr[1] "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/dashboard/file_menu.cljs
|
||||
msgid "modals.unpublish-shared-confirm.message"
|
||||
|
|
|
@ -4764,12 +4764,6 @@ msgstr "Ortala"
|
|||
msgid "workspace.options.stroke-cap.diamond-marker-short"
|
||||
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
|
||||
msgid "questions.questions-how-are-you-planning-to-use-penpot"
|
||||
msgstr "Penpot'u nasıl kullanmayı planlıyorsunuz?"
|
||||
|
@ -4859,12 +4853,6 @@ msgstr "Orantılı ölçeklendirmeyi etkinleştir"
|
|||
msgid "workspace.updates.more-info"
|
||||
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
|
||||
msgid "auth.name.not-all-space"
|
||||
msgstr "İsim boşluk dışında bir karakter içermelidir."
|
||||
|
|
1134
frontend/yarn.lock
1134
frontend/yarn.lock
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue