diff --git a/frontend/gulpfile.js b/frontend/gulpfile.js
index d91859673..f07eba915 100644
--- a/frontend/gulpfile.js
+++ b/frontend/gulpfile.js
@@ -186,7 +186,8 @@ gulpSass.compiler = sass;
gulp.task("scss:modules", function() {
return gulp.src(["src/**/**.scss"])
- .pipe(gulpSass.sync().on('error', gulpSass.logError))
+ .pipe(gulpSass.sync({includePaths: ["./resources/styles/common/",
+ "./resources/styles/"]}).on('error', gulpSass.logError))
.pipe(gulpPostcss([
modules({
generateScopedName: "[folder]_[name]_[local]_[hash:base64:5]",
@@ -198,7 +199,8 @@ gulp.task("scss:modules", function() {
gulp.task("scss:main", function() {
return gulp.src(paths.resources + "styles/main-default.scss")
- .pipe(gulpSass.sync().on('error', gulpSass.logError))
+ .pipe(gulpSass.sync(
+ ).on('error', gulpSass.logError))
.pipe(gulpPostcss([
autoprefixer,
]))
@@ -208,7 +210,7 @@ gulp.task("scss:main", function() {
gulp.task("scss:concat", function() {
return gulp.src([paths.output + "css/main-default.css",
paths.output + "css/app/**/*.css"])
- .pipe(gulpConcat("main.css"))
+ .pipe(gulpConcat("main.css"), {rebaseUrls: false})
.pipe(gulp.dest(paths.output + "css/"));
});
diff --git a/frontend/package.json b/frontend/package.json
index 4a3d1353e..46c917463 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -14,7 +14,7 @@
"scripts": {
"compile-test": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
"lint": "clj-kondo --parallel --lint src/",
- "lint-scss": "yarn run prettier -c resources/styles",
+ "lint-scss": "yarn run prettier -c resources/styles -c src/**/*.scss",
"run-test": "node target/tests.js",
"test": "yarn run compile-test && yarn run run-test",
"watch-gulp": "gulp watch",
diff --git a/frontend/resources/images/icons/add-refactor.svg b/frontend/resources/images/icons/add-refactor.svg
new file mode 100644
index 000000000..93f863748
--- /dev/null
+++ b/frontend/resources/images/icons/add-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-bottom-refactor.svg b/frontend/resources/images/icons/align-bottom-refactor.svg
new file mode 100644
index 000000000..add9efe67
--- /dev/null
+++ b/frontend/resources/images/icons/align-bottom-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-content-center-refactor.svg b/frontend/resources/images/icons/align-content-center-refactor.svg
new file mode 100644
index 000000000..87775ca90
--- /dev/null
+++ b/frontend/resources/images/icons/align-content-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-content-end-refactor.svg b/frontend/resources/images/icons/align-content-end-refactor.svg
new file mode 100644
index 000000000..b31b629eb
--- /dev/null
+++ b/frontend/resources/images/icons/align-content-end-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-content-space-around-refactor.svg b/frontend/resources/images/icons/align-content-space-around-refactor.svg
new file mode 100644
index 000000000..41537d8a9
--- /dev/null
+++ b/frontend/resources/images/icons/align-content-space-around-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-content-space-between-refactor.svg b/frontend/resources/images/icons/align-content-space-between-refactor.svg
new file mode 100644
index 000000000..b8e1ad1f5
--- /dev/null
+++ b/frontend/resources/images/icons/align-content-space-between-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-content-space-evenly-refactor.svg b/frontend/resources/images/icons/align-content-space-evenly-refactor.svg
new file mode 100644
index 000000000..2607631c6
--- /dev/null
+++ b/frontend/resources/images/icons/align-content-space-evenly-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-content-start-refactor.svg b/frontend/resources/images/icons/align-content-start-refactor.svg
new file mode 100644
index 000000000..e20658500
--- /dev/null
+++ b/frontend/resources/images/icons/align-content-start-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-horizontal-center-refactor.svg b/frontend/resources/images/icons/align-horizontal-center-refactor.svg
new file mode 100644
index 000000000..24937634b
--- /dev/null
+++ b/frontend/resources/images/icons/align-horizontal-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-items-center-refactor.svg b/frontend/resources/images/icons/align-items-center-refactor.svg
new file mode 100644
index 000000000..b7e4541b8
--- /dev/null
+++ b/frontend/resources/images/icons/align-items-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-items-end-refactor.svg b/frontend/resources/images/icons/align-items-end-refactor.svg
new file mode 100644
index 000000000..2080b816a
--- /dev/null
+++ b/frontend/resources/images/icons/align-items-end-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-items-start-refactor.svg b/frontend/resources/images/icons/align-items-start-refactor.svg
new file mode 100644
index 000000000..a05190ed7
--- /dev/null
+++ b/frontend/resources/images/icons/align-items-start-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-items-start.svg b/frontend/resources/images/icons/align-items-start.svg
new file mode 100644
index 000000000..f7c71a69e
--- /dev/null
+++ b/frontend/resources/images/icons/align-items-start.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/align-left-refactor.svg b/frontend/resources/images/icons/align-left-refactor.svg
new file mode 100644
index 000000000..70a911395
--- /dev/null
+++ b/frontend/resources/images/icons/align-left-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-right-refactor.svg b/frontend/resources/images/icons/align-right-refactor.svg
new file mode 100644
index 000000000..018955887
--- /dev/null
+++ b/frontend/resources/images/icons/align-right-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-top-refactor.svg b/frontend/resources/images/icons/align-top-refactor.svg
new file mode 100644
index 000000000..acb7268d8
--- /dev/null
+++ b/frontend/resources/images/icons/align-top-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/align-vertical-center-refactor.svg b/frontend/resources/images/icons/align-vertical-center-refactor.svg
new file mode 100644
index 000000000..94cc178bb
--- /dev/null
+++ b/frontend/resources/images/icons/align-vertical-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/arrow-refactor.svg b/frontend/resources/images/icons/arrow-refactor.svg
new file mode 100644
index 000000000..261a2db41
--- /dev/null
+++ b/frontend/resources/images/icons/arrow-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/board-refactor.svg b/frontend/resources/images/icons/board-refactor.svg
new file mode 100644
index 000000000..d4e8525c2
--- /dev/null
+++ b/frontend/resources/images/icons/board-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/boards-thumbnail-refactor.svg b/frontend/resources/images/icons/boards-thumbnail-refactor.svg
new file mode 100644
index 000000000..a8af8bdce
--- /dev/null
+++ b/frontend/resources/images/icons/boards-thumbnail-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/boolean-difference-refactor.svg b/frontend/resources/images/icons/boolean-difference-refactor.svg
new file mode 100644
index 000000000..7d184da97
--- /dev/null
+++ b/frontend/resources/images/icons/boolean-difference-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/boolean-exclude-refactor.svg b/frontend/resources/images/icons/boolean-exclude-refactor.svg
new file mode 100644
index 000000000..23956eea9
--- /dev/null
+++ b/frontend/resources/images/icons/boolean-exclude-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/boolean-flatten-refactor.svg b/frontend/resources/images/icons/boolean-flatten-refactor.svg
new file mode 100644
index 000000000..269d05530
--- /dev/null
+++ b/frontend/resources/images/icons/boolean-flatten-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/boolean-intersection-refactor.svg b/frontend/resources/images/icons/boolean-intersection-refactor.svg
new file mode 100644
index 000000000..42bf660ba
--- /dev/null
+++ b/frontend/resources/images/icons/boolean-intersection-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/boolean-union-refactor.svg b/frontend/resources/images/icons/boolean-union-refactor.svg
new file mode 100644
index 000000000..132a1fc29
--- /dev/null
+++ b/frontend/resources/images/icons/boolean-union-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/close-refactor.svg b/frontend/resources/images/icons/close-refactor.svg
new file mode 100644
index 000000000..3c4885be7
--- /dev/null
+++ b/frontend/resources/images/icons/close-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/close-small-refactor.svg b/frontend/resources/images/icons/close-small-refactor.svg
new file mode 100644
index 000000000..5be0d961a
--- /dev/null
+++ b/frontend/resources/images/icons/close-small-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/column-refactor.svg b/frontend/resources/images/icons/column-refactor.svg
new file mode 100644
index 000000000..ca681dd0d
--- /dev/null
+++ b/frontend/resources/images/icons/column-refactor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/column-reverse-refactor.svg b/frontend/resources/images/icons/column-reverse-refactor.svg
new file mode 100644
index 000000000..78e1849bf
--- /dev/null
+++ b/frontend/resources/images/icons/column-reverse-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/component-refactor.svg b/frontend/resources/images/icons/component-refactor.svg
new file mode 100644
index 000000000..0cb789e57
--- /dev/null
+++ b/frontend/resources/images/icons/component-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/constraint-horizontal-refactor.svg b/frontend/resources/images/icons/constraint-horizontal-refactor.svg
new file mode 100644
index 000000000..c0f31ceea
--- /dev/null
+++ b/frontend/resources/images/icons/constraint-horizontal-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/constraint-vertical-refactor.svg b/frontend/resources/images/icons/constraint-vertical-refactor.svg
new file mode 100644
index 000000000..769703b9a
--- /dev/null
+++ b/frontend/resources/images/icons/constraint-vertical-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/copy-refactor.svg b/frontend/resources/images/icons/copy-refactor.svg
new file mode 100644
index 000000000..d6b3b53f5
--- /dev/null
+++ b/frontend/resources/images/icons/copy-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/corner-radius-refactor.svg b/frontend/resources/images/icons/corner-radius-refactor.svg
new file mode 100644
index 000000000..a8c6bfb4a
--- /dev/null
+++ b/frontend/resources/images/icons/corner-radius-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/curve-refactor.svg b/frontend/resources/images/icons/curve-refactor.svg
new file mode 100644
index 000000000..cdc84c29c
--- /dev/null
+++ b/frontend/resources/images/icons/curve-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/delete-refactor.svg b/frontend/resources/images/icons/delete-refactor.svg
new file mode 100644
index 000000000..b12f9702e
--- /dev/null
+++ b/frontend/resources/images/icons/delete-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/delete-text-refactor.svg b/frontend/resources/images/icons/delete-text-refactor.svg
new file mode 100644
index 000000000..fe1453cad
--- /dev/null
+++ b/frontend/resources/images/icons/delete-text-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/distribute-vertical-spacing-refactor.svg b/frontend/resources/images/icons/distribute-vertical-spacing-refactor.svg
new file mode 100644
index 000000000..8dcce544e
--- /dev/null
+++ b/frontend/resources/images/icons/distribute-vertical-spacing-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/document-refactor.svg b/frontend/resources/images/icons/document-refactor.svg
new file mode 100644
index 000000000..465d90265
--- /dev/null
+++ b/frontend/resources/images/icons/document-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/effects-refactor.svg b/frontend/resources/images/icons/effects-refactor.svg
new file mode 100644
index 000000000..f6ab6d930
--- /dev/null
+++ b/frontend/resources/images/icons/effects-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/elipse-refactor.svg b/frontend/resources/images/icons/elipse-refactor.svg
new file mode 100644
index 000000000..15b22df3a
--- /dev/null
+++ b/frontend/resources/images/icons/elipse-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/filter-refactor.svg b/frontend/resources/images/icons/filter-refactor.svg
new file mode 100644
index 000000000..323863f0a
--- /dev/null
+++ b/frontend/resources/images/icons/filter-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/flex-grid-refactor.svg b/frontend/resources/images/icons/flex-grid-refactor.svg
new file mode 100644
index 000000000..99be07bab
--- /dev/null
+++ b/frontend/resources/images/icons/flex-grid-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/flex-horizontal-refactor.svg b/frontend/resources/images/icons/flex-horizontal-refactor.svg
new file mode 100644
index 000000000..7447ef087
--- /dev/null
+++ b/frontend/resources/images/icons/flex-horizontal-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/flex-refactor.svg b/frontend/resources/images/icons/flex-refactor.svg
new file mode 100644
index 000000000..1ca1b5cb7
--- /dev/null
+++ b/frontend/resources/images/icons/flex-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/flex-vertical-refactor.svg b/frontend/resources/images/icons/flex-vertical-refactor.svg
new file mode 100644
index 000000000..d6d4d2b6e
--- /dev/null
+++ b/frontend/resources/images/icons/flex-vertical-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/flip-horizontal-refactor.svg b/frontend/resources/images/icons/flip-horizontal-refactor.svg
new file mode 100644
index 000000000..f8f59fb1b
--- /dev/null
+++ b/frontend/resources/images/icons/flip-horizontal-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/flip-vertical-refactor.svg b/frontend/resources/images/icons/flip-vertical-refactor.svg
new file mode 100644
index 000000000..99b8f8a1c
--- /dev/null
+++ b/frontend/resources/images/icons/flip-vertical-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/grid-column-refactor.svg b/frontend/resources/images/icons/grid-column-refactor.svg
new file mode 100644
index 000000000..f7b1a386a
--- /dev/null
+++ b/frontend/resources/images/icons/grid-column-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/grid-columns-refactor.svg b/frontend/resources/images/icons/grid-columns-refactor.svg
new file mode 100644
index 000000000..2f7fdef1f
--- /dev/null
+++ b/frontend/resources/images/icons/grid-columns-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/grid-gutter-refactor.svg b/frontend/resources/images/icons/grid-gutter-refactor.svg
new file mode 100644
index 000000000..c692ffd21
--- /dev/null
+++ b/frontend/resources/images/icons/grid-gutter-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/grid-margin-refactor.svg b/frontend/resources/images/icons/grid-margin-refactor.svg
new file mode 100644
index 000000000..578897c0a
--- /dev/null
+++ b/frontend/resources/images/icons/grid-margin-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/grid-refactor.svg b/frontend/resources/images/icons/grid-refactor.svg
new file mode 100644
index 000000000..d15e06b9a
--- /dev/null
+++ b/frontend/resources/images/icons/grid-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/grid-row-refactor.svg b/frontend/resources/images/icons/grid-row-refactor.svg
new file mode 100644
index 000000000..c54bd170e
--- /dev/null
+++ b/frontend/resources/images/icons/grid-row-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/grid-rows-refactor.svg b/frontend/resources/images/icons/grid-rows-refactor.svg
new file mode 100644
index 000000000..70b72636a
--- /dev/null
+++ b/frontend/resources/images/icons/grid-rows-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/grid-square-refactor.svg b/frontend/resources/images/icons/grid-square-refactor.svg
new file mode 100644
index 000000000..10d56a4fa
--- /dev/null
+++ b/frontend/resources/images/icons/grid-square-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/group-refactor.svg b/frontend/resources/images/icons/group-refactor.svg
new file mode 100644
index 000000000..93d8b6f7c
--- /dev/null
+++ b/frontend/resources/images/icons/group-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/gutter-horizontal-refactor.svg b/frontend/resources/images/icons/gutter-horizontal-refactor.svg
new file mode 100644
index 000000000..10cd32404
--- /dev/null
+++ b/frontend/resources/images/icons/gutter-horizontal-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/gutter-vertical-refactor.svg b/frontend/resources/images/icons/gutter-vertical-refactor.svg
new file mode 100644
index 000000000..b4e14a345
--- /dev/null
+++ b/frontend/resources/images/icons/gutter-vertical-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/hide-refactor.svg b/frontend/resources/images/icons/hide-refactor.svg
new file mode 100644
index 000000000..2348140d0
--- /dev/null
+++ b/frontend/resources/images/icons/hide-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/icon-refactor.svg b/frontend/resources/images/icons/icon-refactor.svg
new file mode 100644
index 000000000..ccfc77942
--- /dev/null
+++ b/frontend/resources/images/icons/icon-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/img-refactor.svg b/frontend/resources/images/icons/img-refactor.svg
new file mode 100644
index 000000000..77fc3a76d
--- /dev/null
+++ b/frontend/resources/images/icons/img-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/justify-content-center-refactor.svg b/frontend/resources/images/icons/justify-content-center-refactor.svg
new file mode 100644
index 000000000..6b185e939
--- /dev/null
+++ b/frontend/resources/images/icons/justify-content-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/justify-content-end-refactor.svg b/frontend/resources/images/icons/justify-content-end-refactor.svg
new file mode 100644
index 000000000..0c6955c3e
--- /dev/null
+++ b/frontend/resources/images/icons/justify-content-end-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/justify-content-space-around-refactor.svg b/frontend/resources/images/icons/justify-content-space-around-refactor.svg
new file mode 100644
index 000000000..9fd7cdd75
--- /dev/null
+++ b/frontend/resources/images/icons/justify-content-space-around-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/justify-content-space-between-refactor.svg b/frontend/resources/images/icons/justify-content-space-between-refactor.svg
new file mode 100644
index 000000000..b4878ab1c
--- /dev/null
+++ b/frontend/resources/images/icons/justify-content-space-between-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/justify-content-space-evenly-refactor.svg b/frontend/resources/images/icons/justify-content-space-evenly-refactor.svg
new file mode 100644
index 000000000..f60cee27d
--- /dev/null
+++ b/frontend/resources/images/icons/justify-content-space-evenly-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/justify-content-start-refactor.svg b/frontend/resources/images/icons/justify-content-start-refactor.svg
new file mode 100644
index 000000000..15c38fd14
--- /dev/null
+++ b/frontend/resources/images/icons/justify-content-start-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/lock-refactor.svg b/frontend/resources/images/icons/lock-refactor.svg
new file mode 100644
index 000000000..c1a51ce03
--- /dev/null
+++ b/frontend/resources/images/icons/lock-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/margin-bottom-refactor.svg b/frontend/resources/images/icons/margin-bottom-refactor.svg
new file mode 100644
index 000000000..2da34d0ce
--- /dev/null
+++ b/frontend/resources/images/icons/margin-bottom-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/margin-left-refactor.svg b/frontend/resources/images/icons/margin-left-refactor.svg
new file mode 100644
index 000000000..0f7207c5c
--- /dev/null
+++ b/frontend/resources/images/icons/margin-left-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/margin-left-right-refactor.svg b/frontend/resources/images/icons/margin-left-right-refactor.svg
new file mode 100644
index 000000000..fb3ce6b7d
--- /dev/null
+++ b/frontend/resources/images/icons/margin-left-right-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/margin-right-refactor.svg b/frontend/resources/images/icons/margin-right-refactor.svg
new file mode 100644
index 000000000..24e91cf0f
--- /dev/null
+++ b/frontend/resources/images/icons/margin-right-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/margin-top-bottom-refactor.svg b/frontend/resources/images/icons/margin-top-bottom-refactor.svg
new file mode 100644
index 000000000..cc600fb4c
--- /dev/null
+++ b/frontend/resources/images/icons/margin-top-bottom-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/margin-top-refactor.svg b/frontend/resources/images/icons/margin-top-refactor.svg
new file mode 100644
index 000000000..6cb1046b7
--- /dev/null
+++ b/frontend/resources/images/icons/margin-top-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/mask-refactor.svg b/frontend/resources/images/icons/mask-refactor.svg
new file mode 100644
index 000000000..466697abf
--- /dev/null
+++ b/frontend/resources/images/icons/mask-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/masked-refactor.svg b/frontend/resources/images/icons/masked-refactor.svg
new file mode 100644
index 000000000..a9436fe4d
--- /dev/null
+++ b/frontend/resources/images/icons/masked-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/menu-refactor.svg b/frontend/resources/images/icons/menu-refactor.svg
new file mode 100644
index 000000000..6832a6471
--- /dev/null
+++ b/frontend/resources/images/icons/menu-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/move-refactor.svg b/frontend/resources/images/icons/move-refactor.svg
new file mode 100644
index 000000000..7985ad38a
--- /dev/null
+++ b/frontend/resources/images/icons/move-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-bottom-refactor.svg b/frontend/resources/images/icons/padding-bottom-refactor.svg
new file mode 100644
index 000000000..c5716d5cb
--- /dev/null
+++ b/frontend/resources/images/icons/padding-bottom-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-extended-refactor.svg b/frontend/resources/images/icons/padding-extended-refactor.svg
new file mode 100644
index 000000000..ef2df4436
--- /dev/null
+++ b/frontend/resources/images/icons/padding-extended-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-left-refactor.svg b/frontend/resources/images/icons/padding-left-refactor.svg
new file mode 100644
index 000000000..28cae123d
--- /dev/null
+++ b/frontend/resources/images/icons/padding-left-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-left-right-refactor.svg b/frontend/resources/images/icons/padding-left-right-refactor.svg
new file mode 100644
index 000000000..46fe52211
--- /dev/null
+++ b/frontend/resources/images/icons/padding-left-right-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-right-refactor.svg b/frontend/resources/images/icons/padding-right-refactor.svg
new file mode 100644
index 000000000..0caec32e1
--- /dev/null
+++ b/frontend/resources/images/icons/padding-right-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-top-bottom-refactor.svg b/frontend/resources/images/icons/padding-top-bottom-refactor.svg
new file mode 100644
index 000000000..0bf9a83a3
--- /dev/null
+++ b/frontend/resources/images/icons/padding-top-bottom-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/padding-top-refactor.svg b/frontend/resources/images/icons/padding-top-refactor.svg
new file mode 100644
index 000000000..a0374b83c
--- /dev/null
+++ b/frontend/resources/images/icons/padding-top-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/path-refactor.svg b/frontend/resources/images/icons/path-refactor.svg
new file mode 100644
index 000000000..bb3125a63
--- /dev/null
+++ b/frontend/resources/images/icons/path-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/pentool-refactor.svg b/frontend/resources/images/icons/pentool-refactor.svg
new file mode 100644
index 000000000..2b4179bac
--- /dev/null
+++ b/frontend/resources/images/icons/pentool-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/rectangle-refactor.svg b/frontend/resources/images/icons/rectangle-refactor.svg
new file mode 100644
index 000000000..650267027
--- /dev/null
+++ b/frontend/resources/images/icons/rectangle-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/remove-refactor.svg b/frontend/resources/images/icons/remove-refactor.svg
new file mode 100644
index 000000000..3fc18c170
--- /dev/null
+++ b/frontend/resources/images/icons/remove-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/rotation-refactor.svg b/frontend/resources/images/icons/rotation-refactor.svg
new file mode 100644
index 000000000..1d6cd6d36
--- /dev/null
+++ b/frontend/resources/images/icons/rotation-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/row-refactor.svg b/frontend/resources/images/icons/row-refactor.svg
new file mode 100644
index 000000000..8475819d4
--- /dev/null
+++ b/frontend/resources/images/icons/row-refactor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/row-reverse-refactor.svg b/frontend/resources/images/icons/row-reverse-refactor.svg
new file mode 100644
index 000000000..07ceaa2a5
--- /dev/null
+++ b/frontend/resources/images/icons/row-reverse-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/search-refactor.svg b/frontend/resources/images/icons/search-refactor.svg
new file mode 100644
index 000000000..aacd59883
--- /dev/null
+++ b/frontend/resources/images/icons/search-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/shown-refactor.svg b/frontend/resources/images/icons/shown-refactor.svg
new file mode 100644
index 000000000..16bdea787
--- /dev/null
+++ b/frontend/resources/images/icons/shown-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/size-horizontal-refactor.svg b/frontend/resources/images/icons/size-horizontal-refactor.svg
new file mode 100644
index 000000000..ccfc77942
--- /dev/null
+++ b/frontend/resources/images/icons/size-horizontal-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/size-vertical-refactor.svg b/frontend/resources/images/icons/size-vertical-refactor.svg
new file mode 100644
index 000000000..b32ee77c2
--- /dev/null
+++ b/frontend/resources/images/icons/size-vertical-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/stroke-size-refactor.svg b/frontend/resources/images/icons/stroke-size-refactor.svg
new file mode 100644
index 000000000..0d9241d47
--- /dev/null
+++ b/frontend/resources/images/icons/stroke-size-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/swatches-refactor.svg b/frontend/resources/images/icons/swatches-refactor.svg
new file mode 100644
index 000000000..bd69f5de0
--- /dev/null
+++ b/frontend/resources/images/icons/swatches-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-Paragraph-refactor.svg b/frontend/resources/images/icons/text-Paragraph-refactor.svg
new file mode 100644
index 000000000..2ed5e0d78
--- /dev/null
+++ b/frontend/resources/images/icons/text-Paragraph-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-align-center-refactor.svg b/frontend/resources/images/icons/text-align-center-refactor.svg
new file mode 100644
index 000000000..279428533
--- /dev/null
+++ b/frontend/resources/images/icons/text-align-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-align-left-refactor.svg b/frontend/resources/images/icons/text-align-left-refactor.svg
new file mode 100644
index 000000000..8f117047b
--- /dev/null
+++ b/frontend/resources/images/icons/text-align-left-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-align-right-refactor.svg b/frontend/resources/images/icons/text-align-right-refactor.svg
new file mode 100644
index 000000000..503291102
--- /dev/null
+++ b/frontend/resources/images/icons/text-align-right-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-auto-height-refactor.svg b/frontend/resources/images/icons/text-auto-height-refactor.svg
new file mode 100644
index 000000000..90016a8e0
--- /dev/null
+++ b/frontend/resources/images/icons/text-auto-height-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-auto-width-refactor.svg b/frontend/resources/images/icons/text-auto-width-refactor.svg
new file mode 100644
index 000000000..07b07ed76
--- /dev/null
+++ b/frontend/resources/images/icons/text-auto-width-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/text-refactor.svg b/frontend/resources/images/icons/text-refactor.svg
new file mode 100644
index 000000000..36169c1fd
--- /dev/null
+++ b/frontend/resources/images/icons/text-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/thumbnail-refactor.svg b/frontend/resources/images/icons/thumbnail-refactor.svg
new file mode 100644
index 000000000..ab55c9367
--- /dev/null
+++ b/frontend/resources/images/icons/thumbnail-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/tick-refactor.svg b/frontend/resources/images/icons/tick-refactor.svg
new file mode 100644
index 000000000..4e616b7d7
--- /dev/null
+++ b/frontend/resources/images/icons/tick-refactor.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/images/icons/unlock-refactor.svg b/frontend/resources/images/icons/unlock-refactor.svg
new file mode 100644
index 000000000..6382db15d
--- /dev/null
+++ b/frontend/resources/images/icons/unlock-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/vertical-align-items-center-refactor.svg b/frontend/resources/images/icons/vertical-align-items-center-refactor.svg
new file mode 100644
index 000000000..2ef2437bb
--- /dev/null
+++ b/frontend/resources/images/icons/vertical-align-items-center-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/vertical-align-items-end-refactor.svg b/frontend/resources/images/icons/vertical-align-items-end-refactor.svg
new file mode 100644
index 000000000..c75ad0918
--- /dev/null
+++ b/frontend/resources/images/icons/vertical-align-items-end-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/vertical-align-items-start-refactor.svg b/frontend/resources/images/icons/vertical-align-items-start-refactor.svg
new file mode 100644
index 000000000..7050242cb
--- /dev/null
+++ b/frontend/resources/images/icons/vertical-align-items-start-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/view-as-icons-refactor.svg b/frontend/resources/images/icons/view-as-icons-refactor.svg
new file mode 100644
index 000000000..7a7633fc3
--- /dev/null
+++ b/frontend/resources/images/icons/view-as-icons-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/wrap-refactor.svg b/frontend/resources/images/icons/wrap-refactor.svg
new file mode 100644
index 000000000..9a0619f03
--- /dev/null
+++ b/frontend/resources/images/icons/wrap-refactor.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss
new file mode 100644
index 000000000..ece2050f2
--- /dev/null
+++ b/frontend/resources/styles/common/refactor/basic-rules.scss
@@ -0,0 +1,64 @@
+// 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
+
+.button-primary {
+ @include buttonStyle;
+ @include flexCenter;
+ &:hover {
+ background-color: var(--button-background-hover);
+ svg {
+ stroke: var(--button-foreground-hover);
+ }
+ }
+ &:focus {
+ outline: none;
+ border: 1px solid var(--button-border-focus);
+ background-color: var(--button-background-focus);
+ svg {
+ stroke: var(--button-foreground-focus);
+ }
+ }
+ &:active {
+ border: none;
+ }
+}
+
+.button-secondary {
+ @include buttonStyle;
+ @include flexCenter;
+ &:hover {
+ svg {
+ stroke: var(--title-foreground-color-hover);
+ }
+ }
+ &:focus {
+ outline: none;
+ border: 1px solid var(--button-border-focus);
+ background-color: var(--button-background-focus);
+ svg {
+ stroke: var(--button-foreground-focus);
+ }
+ }
+ &:active {
+ border: none;
+ background-color: transparent;
+ }
+}
+
+.button-icon {
+ @include flexCenter;
+ height: $s-16;
+ width: $s-16;
+ color: transparent;
+ fill: none;
+ stroke: var(--icon-foreground);
+}
+
+.button-icon-small {
+ @extend .button-icon;
+ height: $s-12;
+ width: $s-12;
+}
diff --git a/frontend/resources/styles/common/refactor/borders.scss b/frontend/resources/styles/common/refactor/borders.scss
index 851f894d7..0fe6762a8 100644
--- a/frontend/resources/styles/common/refactor/borders.scss
+++ b/frontend/resources/styles/common/refactor/borders.scss
@@ -6,15 +6,15 @@
// Border radius
$br0: 0px;
-$br2: 2px;
+$br2: $s-2;
$br3: 3px;
$br4: 4px;
$br5: 5px;
-$br6: 6px;
+$br6: $s-6;
$br7: 7px;
-$br8: 8px;
+$br8: $s-8;
$br10: 10px;
-$br12: 12px;
+$br12: $s-12;
$br25: 25px;
$br50: 50px;
$br99: 99px;
diff --git a/frontend/resources/styles/common/refactor/color-defs.scss b/frontend/resources/styles/common/refactor/color-defs.scss
index 0cfc7cf52..7896a7986 100644
--- a/frontend/resources/styles/common/refactor/color-defs.scss
+++ b/frontend/resources/styles/common/refactor/color-defs.scss
@@ -6,9 +6,10 @@
:root {
// DARK
- --dark-gray-1: #171a1c;
- --dark-gray-2: #000;
- --dark-gray-3: #252a2d;
+ --dark-gray-1: #1d1f20;
+ --dark-gray-2: #000000;
+ --dark-gray-2-30: rgba(0, 0, 0, 0.3);
+ --dark-gray-3: #292c2d;
--dark-gray-4: #34393b;
--white: #fff;
--off-white: #aab5ba;
@@ -20,6 +21,7 @@
// LIGHT
--light-gray-1: #fff;
--light-gray-2: #e8eaee;
+ --light-gray-2-30: rgba(232, 234, 238, 0.3);
--light-gray-3: #f3f4f6;
--light-gray-4: #eef0f2;
--black: #000;
diff --git a/frontend/resources/styles/common/refactor/common-refactor.scss b/frontend/resources/styles/common/refactor/common-refactor.scss
new file mode 100644
index 000000000..d5d508479
--- /dev/null
+++ b/frontend/resources/styles/common/refactor/common-refactor.scss
@@ -0,0 +1,37 @@
+// 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
+
+//#################################################
+// MAIN STYLES
+//#################################################
+
+@import "common/refactor/fonts.scss";
+@import "common/refactor/spacing.scss";
+@import "common/refactor/borders.scss";
+@import "common/refactor/shadows.scss";
+@import "common/refactor/z-index.scss";
+@import "common/refactor/mixins.scss";
+@import "common/refactor/basic-rules.scss";
+
+::-webkit-scrollbar {
+ background-color: transparent;
+ cursor: pointer;
+ height: $s-8;
+ width: $s-12;
+}
+::-webkit-scrollbar-track {
+ background-color: transparent;
+}
+::-webkit-scrollbar-thumb {
+ background-color: rgba(170, 181, 186, 0.3);
+ background-clip: content-box;
+ border: $s-2 solid transparent;
+ border-radius: $br8;
+ &:hover {
+ background-color: rgba(170, 181, 186, 0.7);
+ outline: none;
+ }
+}
diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss
index 4ba3ffa62..2dc2a53ed 100644
--- a/frontend/resources/styles/common/refactor/design-tokens.scss
+++ b/frontend/resources/styles/common/refactor/design-tokens.scss
@@ -3,9 +3,78 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) KALEIDOS INC
+@use "sass:color";
.light,
.default {
- --button-bg-active: var(--color-background-primary);
+ --scrollbar-background-color: var(--color-foreground-secondary);
+ --button-background-active: var(--color-background-primary);
+ --button-background-hover: var(--color-background-quaternary);
+ --button-foreground-hover: var(--color-accent-primary);
--button-foreground-active: var(--color-foreground-primary);
+ --button-background-focus: var(--color-background-secondary);
+ --button-foreground-focus: var(--color-foreground-primary);
+ --button-border-focus: var(--color-accent-primary);
+
+ --icon-foreground: var(--color-foreground-secondary);
+ --icon-foreground-hover: var(--color-foreground-primary);
+
+ --tab-background-color-hover: var(--color-background-primary);
+ --tab-background-color-selected: var(--color-background-quaternary);
+ --tab-foreground-color: var(--color-foreground-secondary);
+ --tab-foreground-color-hover: var(--color-foreground-primary);
+ --tab-foreground-color-selected: var(--color-accent-primary);
+
+ --title-foreground-color: var(--color-foreground-secondary);
+ --title-foreground-color-hover: var(--color-foreground-primary);
+
+ --layer-row-background-color: var(--color-background-primary);
+ --layer-row-background-color-hover: var(--color-background-secondary);
+ --layer-row-background-color-selected: var(--color-background-quaternary);
+ --layer-row-background-color-drag: var(--color-background-quaternary);
+ --layer-row-foreground-color: var(--color-foreground-secondary);
+ --layer-row-foreground-color-hover: var(--color-accent-primary);
+ --layer-row-foreground-color-selected: var(--color-accent-primary);
+ --layer-row-foreground-color-drag: var(--color-accent-primary);
+ --layer-row-foreground-color-hidden: rgba(var(--color-foreground-secondary-rgb), 0.7);
+ --layer-row-foreground-color-focus: var(--color-foreground-primary);
+ --layer-row-border-color-focus: var(--color-accent-primary);
+ --layer-child-row-background-color: var(--color-background-tertiary);
+ --layer-child-row-foreground-color: var(--color-foreground-secondary);
+ --layer-row-component-foreground-color: var(--color-accent-secondary);
+
+ --input-background-color: var(--color-background-tertiary);
+ --input-background-color-active: var(--color-background-primary);
+ --input-background-color-hover: var(--color-background-quaternary);
+ --input-background-color-focus: var(--color-background-tertiary);
+ --input-background-color-disabled: var(--color-background-primary);
+ --input-placeholder-color: var(--color-foreground-secondary);
+ --input-foreground-color: var(--color-foreground-primary);
+ --input-foreground-color-active: var(--color-foreground-primary);
+ --input-foreground-color-hover: var();
+ --input-foreground-color-focus: var();
+ --input-border-color-active: var(--color-accent-primary);
+ --input-border-outline-color-active: var(--color-accent-primary-muted);
+ --input-border-color-focus: var(--color-accent-primary);
+ --input-border-color-disabled: var();
+
+ --pill-background-color: var(--color-background-tertiary);
+ --pill-foreground-color: var(--color-foreground-primary);
+
+ --menu-background-color: var(--color-background-tertiary);
+ --menu-foreground-color: var(--color-foreground-secondary);
+ --menu-background-color-selected: var(--color-background-tertiary);
+ --menu-foreground-color-selected: var(--color-foreground-primary);
+ --menu-background-color-hover: var(--color-background-quaternary);
+ --menu-foreground-color-hover: var(--color-foreground-primary);
+ --menu-background-color-focus: var(--color-background-tertiary);
+ --menu-foreground-color-focus: var(--color-foreground-primary);
+ --menu-border-color-focus: var(--color-accent-primary);
+ --menu-shortcut-background-color: var(--color-background-primary);
+ --menu-shortcut-foreground-color: var(--color-foreground-secondary);
+ --menu-shortcut-foreground-color-selected: var(--color-foreground-primary);
+ --menu-shortcut-foreground-color-hover: var(--color-foreground-primary);
+ --menu-shadow-color: var(--color-background-subtle);
+
+ --tag-background-color: var(--color-accent-primary);
}
diff --git a/frontend/resources/styles/common/refactor/fonts.scss b/frontend/resources/styles/common/refactor/fonts.scss
index 94262bc16..6bd7533c1 100644
--- a/frontend/resources/styles/common/refactor/fonts.scss
+++ b/frontend/resources/styles/common/refactor/fonts.scss
@@ -5,9 +5,11 @@
// Copyright (c) KALEIDOS INC
@use "sass:math";
+@import "common/dependencies/mixin";
// Font sizes
$fs10: 0.625rem;
+$fs-11: 0.688rem;
$fs12: 0.75rem;
$fs14: 0.875rem;
@@ -15,6 +17,7 @@ $fs14: 0.875rem;
$fs-base: 16;
$fs-9: math.div(9, $fs-base) + rem;
+$fs-10: math.div(10, $fs-base) + rem;
$fs-12: math.div(12, $fs-base) + rem;
$fs-14: math.div(14, $fs-base) + rem;
$fs-19: math.div(19, $fs-base) + rem;
diff --git a/frontend/resources/styles/common/refactor/mixins.scss b/frontend/resources/styles/common/refactor/mixins.scss
new file mode 100644
index 000000000..57805d5cd
--- /dev/null
+++ b/frontend/resources/styles/common/refactor/mixins.scss
@@ -0,0 +1,46 @@
+// 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
+
+@mixin flexCenter {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+@mixin buttonStyle {
+ border: none;
+ background: none;
+ cursor: pointer;
+}
+
+@mixin tabTitleTipography {
+ font-family: "worksans", sans-serif;
+ font-size: $fs-11;
+ font-weight: $fw500;
+ line-height: 1.2;
+ text-transform: uppercase;
+}
+
+@mixin titleTipography {
+ font-family: "worksans", sans-serif;
+ font-size: $fs-12;
+ font-weight: $fw400;
+ line-height: 1.2;
+}
+
+@mixin buttonSmallTipography {
+ font-family: "worksans", sans-serif;
+ font-size: $fs-10;
+ font-weight: $fw400;
+ line-height: 1.2;
+}
+
+@mixin textEllipsis {
+ max-width: 99%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
diff --git a/frontend/resources/styles/common/refactor/spacing.scss b/frontend/resources/styles/common/refactor/spacing.scss
index 09ff33996..2c4f06ad2 100644
--- a/frontend/resources/styles/common/refactor/spacing.scss
+++ b/frontend/resources/styles/common/refactor/spacing.scss
@@ -4,23 +4,38 @@
//
// Copyright (c) KALEIDOS INC
-$spacing-4: 0.25rem;
-$spacing-8: calc(var(--spacing-4) * 2);
-$spacing-12: calc(var(--spacing-4) * 3);
-$spacing-16: calc(var(--spacing-4) * 4);
-$spacing-20: calc(var(--spacing-4) * 5);
-$spacing-24: calc(var(--spacing-4) * 6);
-$spacing-28: calc(var(--spacing-4) * 7);
-$spacing-32: calc(var(--spacing-4) * 8);
-$spacing-36: calc(var(--spacing-4) * 9);
-$spacing-40: calc(var(--spacing-4) * 10);
-$spacing-44: calc(var(--spacing-4) * 11);
-$spacing-48: calc(var(--spacing-4) * 12);
-$spacing-52: calc(var(--spacing-4) * 13);
-$spacing-56: calc(var(--spacing-4) * 14);
-$spacing-60: calc(var(--spacing-4) * 15);
-$spacing-64: calc(var(--spacing-4) * 16);
-$spacing-68: calc(var(--spacing-4) * 17);
-$spacing-72: calc(var(--spacing-4) * 18);
-$spacing-76: calc(var(--spacing-4) * 19);
-$spacing-80: calc(var(--spacing-4) * 20);
+@use "sass:math";
+
+:root {
+ --s-4: 0.25rem;
+ --layer-indentation-size: calc(var(--s-4) * 5);
+}
+
+$s-2: math.div(0.25rem, 2);
+$s-4: var(--s-4);
+$s-6: calc($s-2 + $s-4);
+$s-8: calc(var(--s-4) * 2);
+$s-12: calc(var(--s-4) * 3);
+$s-16: calc(var(--s-4) * 4);
+$s-20: calc(var(--s-4) * 5);
+$s-24: calc(var(--s-4) * 6);
+$s-28: calc(var(--s-4) * 7);
+$s-32: calc(var(--s-4) * 8);
+$s-36: calc(var(--s-4) * 9);
+$s-40: calc(var(--s-4) * 10);
+$s-44: calc(var(--s-4) * 11);
+$s-48: calc(var(--s-4) * 12);
+$s-52: calc(var(--s-4) * 13);
+$s-56: calc(var(--s-4) * 14);
+$s-60: calc(var(--s-4) * 15);
+$s-64: calc(var(--s-4) * 16);
+$s-68: calc(var(--s-4) * 17);
+$s-72: calc(var(--s-4) * 18);
+$s-76: calc(var(--s-4) * 19);
+$s-80: calc(var(--s-4) * 20);
+$s-96: calc(var(--s-4) * 24);
+$s-152: calc(var(--s-4) * 38);
+$s-192: calc(var(--s-4) * 48);
+$s-240: calc(var(--s-4) * 60);
+$s-480: calc(var(--s-4) * 120);
+$s-736: calc(var(--s-4) * 184);
diff --git a/frontend/resources/styles/common/refactor/themes/default-theme.scss b/frontend/resources/styles/common/refactor/themes/default-theme.scss
index 78a0194ba..2b6e09f98 100644
--- a/frontend/resources/styles/common/refactor/themes/default-theme.scss
+++ b/frontend/resources/styles/common/refactor/themes/default-theme.scss
@@ -9,10 +9,11 @@
--color-background-secondary: var(--dark-gray-2);
--color-background-tertiary: var(--dark-gray-3);
--color-background-quaternary: var(--dark-gray-4);
+ --color-background-subtle: var(--dark-gray-2-30);
--color-foreground-primary: var(--white);
--color-foreground-secondary: var(--off-white);
- --accent-primary: var(--green);
- --accent-primary-muted: var(--green-30);
- --accent-secondary: var(--lilac);
- --accent-tertiary: var(--strong-green);
+ --color-accent-primary: var(--green);
+ --color-accent-primary-muted: var(--green-30);
+ --color-accent-secondary: var(--lilac);
+ --color-accent-tertiary: var(--strong-green);
}
diff --git a/frontend/resources/styles/common/refactor/themes/light-theme.scss b/frontend/resources/styles/common/refactor/themes/light-theme.scss
index b7b28f04a..fbc4c83cb 100644
--- a/frontend/resources/styles/common/refactor/themes/light-theme.scss
+++ b/frontend/resources/styles/common/refactor/themes/light-theme.scss
@@ -9,10 +9,11 @@
--color-background-secondary: var(--light-gray-2);
--color-background-tertiary: var(--light-gray-3);
--color-background-quaternary: var(--light-gray-4);
+ --color-background-subtle: var(--light-gray-2-30); //Whatch this¡¡
--color-foreground-primary: var(--black);
--color-foreground-secondary: var(--off-black);
- --accent-primary: var(--purple);
- --accent-primary-muted: var(--purple-30);
- --accent-secondary: var(--blue);
- --accent-tertiary: var(--strong-purple);
+ --color-accent-primary: var(--purple);
+ --color-accent-primary-muted: var(--purple-30);
+ --color-accent-secondary: var(--blue);
+ --color-accent-tertiary: var(--strong-purple);
}
diff --git a/frontend/resources/styles/common/refactor/z-index.scss b/frontend/resources/styles/common/refactor/z-index.scss
new file mode 100644
index 000000000..876b035d6
--- /dev/null
+++ b/frontend/resources/styles/common/refactor/z-index.scss
@@ -0,0 +1,11 @@
+// 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
+
+$z-index-1: 1;
+$z-index-2: 2;
+$z-index-4: 4;
+$z-index-10: 10;
+$z-index-20: 20;
diff --git a/frontend/resources/styles/main-default.scss b/frontend/resources/styles/main-default.scss
index 3205cbf41..b1db2c1b3 100644
--- a/frontend/resources/styles/main-default.scss
+++ b/frontend/resources/styles/main-default.scss
@@ -23,6 +23,10 @@
@import "common/dependencies/z-index";
@import "common/dependencies/highlightjs-theme";
+@import "common/refactor/color-defs.scss";
+@import "common/refactor/themes.scss";
+@import "common/refactor/design-tokens.scss";
+
//#################################################
// Layouts
//#################################################
@@ -70,13 +74,13 @@
@import "main/partials/loader";
@import "main/partials/project-bar";
@import "main/partials/sidebar";
+@import "main/partials/sidebar-layers";
@import "main/partials/sidebar-align-options";
@import "main/partials/sidebar-assets";
@import "main/partials/sidebar-document-history";
@import "main/partials/sidebar-element-options";
@import "main/partials/sidebar-icons";
@import "main/partials/sidebar-interactions";
-@import "main/partials/sidebar-layers";
@import "main/partials/sidebar-sitemap";
@import "main/partials/sidebar-tools";
@import "main/partials/tab-container";
@@ -90,19 +94,3 @@
@import "main/partials/exception-page";
@import "main/partials/share-link";
@import "main/partials/af-signup-questions";
-
-//#################################################
-// Refactor
-//#################################################
-
-//#################################################
-// MAIN STYLES
-//#################################################
-
-@import "common/refactor/color-defs.scss";
-@import "common/refactor/themes.scss";
-@import "common/refactor/design-tokens.scss";
-@import "common/refactor/fonts.scss";
-@import "common/refactor/spacing.scss";
-@import "common/refactor/borders.scss";
-@import "common/refactor/shadows.scss";
diff --git a/frontend/resources/styles/main/partials/dashboard-fonts.scss b/frontend/resources/styles/main/partials/dashboard-fonts.scss
index cdb1327e7..bd93dca5f 100644
--- a/frontend/resources/styles/main/partials/dashboard-fonts.scss
+++ b/frontend/resources/styles/main/partials/dashboard-fonts.scss
@@ -193,7 +193,7 @@
}
.icon {
display: flex;
- align-items: start;
+ align-items: flex-start;
justify-content: center;
padding-top: 10px;
background-color: $color-info;
diff --git a/frontend/resources/styles/main/partials/dashboard-grid.scss b/frontend/resources/styles/main/partials/dashboard-grid.scss
index 0765863d4..13b861ebc 100644
--- a/frontend/resources/styles/main/partials/dashboard-grid.scss
+++ b/frontend/resources/styles/main/partials/dashboard-grid.scss
@@ -367,7 +367,7 @@
background-color: $color-gray-50;
flex-direction: column;
height: 90%;
- justify-content: start;
+ justify-content: flex-start;
max-height: 550px;
padding: $size-6;
diff --git a/frontend/resources/styles/main/partials/debug-icons-preview.scss b/frontend/resources/styles/main/partials/debug-icons-preview.scss
index afca85123..e08f1d274 100644
--- a/frontend/resources/styles/main/partials/debug-icons-preview.scss
+++ b/frontend/resources/styles/main/partials/debug-icons-preview.scss
@@ -22,6 +22,12 @@
svg {
width: 100%;
height: 100%;
+ min-width: 16px;
+ min-height: 16px;
+ fill: black;
+ fill: none;
+ color: transparent;
+ stroke: black;
}
}
.cursor-item {
diff --git a/frontend/resources/styles/main/partials/sidebar-element-options.scss b/frontend/resources/styles/main/partials/sidebar-element-options.scss
index c0a2de9e8..41ad89785 100644
--- a/frontend/resources/styles/main/partials/sidebar-element-options.scss
+++ b/frontend/resources/styles/main/partials/sidebar-element-options.scss
@@ -353,13 +353,13 @@
font-size: $fs14;
display: flex;
gap: 0 10px;
- justify-content: start;
+ justify-content: flex-start;
padding: $size-2;
span {
color: $color-gray-20;
display: flex;
- justify-content: start;
+ justify-content: flex-start;
align-items: center;
}
@@ -1643,7 +1643,7 @@
.row-title {
font-size: $fs12;
display: flex;
- justify-content: start;
+ justify-content: flex-start;
align-items: center;
margin-right: 5px;
font-family: "worksans", sans-serif;
@@ -1651,13 +1651,13 @@
&.justify-content,
&.align-content,
&.sizing {
- align-items: start;
+ align-items: flex-start;
margin-top: 4px;
}
&.align-items-grid,
&.jusfiy-content-grid {
- align-items: start;
+ align-items: flex-start;
margin-top: 11px;
}
}
@@ -2300,7 +2300,7 @@
padding: 0;
.icon {
display: flex;
- justify-content: start;
+ justify-content: flex-start;
align-items: center;
margin-right: 10px;
svg {
diff --git a/frontend/resources/styles/main/partials/sidebar-layers.scss b/frontend/resources/styles/main/partials/sidebar-layers.scss
index 33e7b435b..79ad3b4af 100644
--- a/frontend/resources/styles/main/partials/sidebar-layers.scss
+++ b/frontend/resources/styles/main/partials/sidebar-layers.scss
@@ -293,6 +293,8 @@ span.element-name {
.toggle-element,
.block-element {
+ border: none;
+ background-color: transparent;
left: 0;
position: absolute;
top: 0;
@@ -349,7 +351,8 @@ span.element-name {
}
#layers {
- .tool-window-bar {
+ .tool-window-bar,
+ .pages-tool-bar {
display: flex;
justify-content: space-between;
height: 32px;
@@ -378,7 +381,7 @@ span.element-name {
outline: none;
}
}
- span {
+ div {
height: 16px;
overflow: hidden;
}
@@ -412,6 +415,7 @@ span.element-name {
color: $color-black;
padding: 3px 5px;
margin: 0 2px;
+ border: none;
border-radius: $br4;
cursor: pointer;
svg {
diff --git a/frontend/resources/styles/main/partials/sidebar-sitemap.scss b/frontend/resources/styles/main/partials/sidebar-sitemap.scss
index f7ed9e3fc..ea4381262 100644
--- a/frontend/resources/styles/main/partials/sidebar-sitemap.scss
+++ b/frontend/resources/styles/main/partials/sidebar-sitemap.scss
@@ -4,10 +4,12 @@
//
// Copyright (c) KALEIDOS INC
-#sitemap {
+#sitemap,
+.sitemap {
height: var(--height, 200px);
- .element-list {
+ .element-list,
+ .pages-list {
li {
align-items: center;
display: flex;
@@ -37,7 +39,9 @@
display: none;
margin-left: auto;
- a {
+ button {
+ border: none;
+ background-color: transparent;
svg {
fill: $color-gray-60;
height: 15px;
@@ -163,7 +167,7 @@
.layout-btns {
display: flex;
align-items: center;
- justify-content: end;
+ justify-content: flex-end;
}
.remove-layout {
display: flex;
diff --git a/frontend/resources/styles/main/partials/sidebar.scss b/frontend/resources/styles/main/partials/sidebar.scss
index 4d71965e7..09ac24e24 100644
--- a/frontend/resources/styles/main/partials/sidebar.scss
+++ b/frontend/resources/styles/main/partials/sidebar.scss
@@ -24,7 +24,8 @@
grid-template-rows: 100%;
height: calc(100% - 2px);
- .tool-window {
+ .tool-window,
+ .sitemap {
position: relative;
border-bottom: 1px solid $color-gray-60;
display: flex;
@@ -46,7 +47,10 @@
width: 12px;
}
- span {
+ button,
+ div {
+ border: none;
+ background-color: transparent;
color: $color-gray-10;
font-size: $fs14;
max-width: 100%;
@@ -246,7 +250,6 @@
width: 100%;
overflow-y: auto;
overflow-x: hidden;
-
&.inspect {
.tab-container-tabs {
padding-bottom: 0.5rem;
diff --git a/frontend/src/app/main/data/shortcuts.cljs b/frontend/src/app/main/data/shortcuts.cljs
index ff4577f9b..2b99bbeb8 100644
--- a/frontend/src/app/main/data/shortcuts.cljs
+++ b/frontend/src/app/main/data/shortcuts.cljs
@@ -12,6 +12,7 @@
[app.common.spec :as us]
[app.config :as cf]
[cljs.spec.alpha :as s]
+ [cuerdas.core :as str]
[potok.core :as ptk]))
(log/set-level! :warn)
@@ -112,6 +113,14 @@
mac-enter
"Enter"))
+(defn split-sc
+ [sc]
+ (let [sc (cond-> sc (str/includes? sc "++")
+ (str/replace "++" "+plus"))]
+ (if (= (count sc) 1)
+ [sc]
+ (str/split sc #"\+| "))))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Events
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -148,13 +157,13 @@
(if type
(mousetrap/bind command callback type)
(mousetrap/bind command callback)))]
- (->> shortcuts
- (remove #(:disabled (second %)))
- (run! (fn [[key {:keys [command fn type]}]]
- (let [callback (wrap-cb key fn)]
- (if (vector? command)
- (run! #(msbind % callback type) command)
- (msbind command callback type))))))))
+ (->> shortcuts
+ (remove #(:disabled (second %)))
+ (run! (fn [[key {:keys [command fn type]}]]
+ (let [callback (wrap-cb key fn)]
+ (if (vector? command)
+ (run! #(msbind % callback type) command)
+ (msbind command callback type))))))))
(defn- reset!
([]
diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs
index d33cfbdad..cc2ba101d 100644
--- a/frontend/src/app/main/data/workspace.cljs
+++ b/frontend/src/app/main/data/workspace.cljs
@@ -1265,6 +1265,7 @@
not-group-like? (and (= (count selected) 1)
(not (contains? #{:group :bool} (:type head))))
+
no-bool-shapes? (->> all-selected (some (comp #{:frame :text} :type)))]
(rx/concat
diff --git a/frontend/src/app/main/features.cljs b/frontend/src/app/main/features.cljs
index 337f8c32a..cc3332e19 100644
--- a/frontend/src/app/main/features.cljs
+++ b/frontend/src/app/main/features.cljs
@@ -20,7 +20,7 @@
(log/set-level! :warn)
(def available-features
- #{:auto-layout :components-v2})
+ #{:auto-layout :components-v2 :new-css-system})
(defn- toggle-feature
[feature]
@@ -103,4 +103,5 @@
;; environment, that are enabled except components-v2
(->> (rx/from available-features)
(rx/filter #(not= % :components-v2))
+ (rx/filter #(not= % :new-css-system))
(rx/map enable-feature)))))))
diff --git a/frontend/src/app/main/style.clj b/frontend/src/app/main/style.clj
index 82dd96a47..80cb4f7c2 100644
--- a/frontend/src/app/main/style.clj
+++ b/frontend/src/app/main/style.clj
@@ -19,3 +19,13 @@
(json/read-str))
result (get data (d/name selector))]
`~result))
+
+(defmacro styles
+ []
+ (let [;; Get the associated styles will be module.cljs => module.css.json
+ filename (:file (meta *ns*))
+ styles-file (str "./src/" (subs filename 0 (- (count filename) 4)) "css.json")
+ data (-> (slurp styles-file)
+ (json/read-str))
+ data (into {} (map (fn [[k v]] [(keyword k) v])) data)]
+ `~data))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs
index 266113c86..5808325fd 100644
--- a/frontend/src/app/main/ui.cljs
+++ b/frontend/src/app/main/ui.cljs
@@ -14,6 +14,7 @@
[app.main.ui.context :as ctx]
[app.main.ui.cursors :as c]
[app.main.ui.dashboard :refer [dashboard]]
+ [app.main.ui.debug.components-preview :as cm]
[app.main.ui.icons :as i]
[app.main.ui.messages :as msgs]
[app.main.ui.onboarding]
@@ -65,6 +66,11 @@
[:h1 "Icons"]
[:& i/debug-icons-preview]])
+ :debug-components-preview
+ [:div.debug-preview
+ [:h1 "Components preview"]
+ [:& cm/components-preview]]
+
(:dashboard-search
:dashboard-projects
:dashboard-files
diff --git a/frontend/src/app/main/ui/components/context_menu_a11y.cljs b/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.cljs
similarity index 51%
rename from frontend/src/app/main/ui/components/context_menu_a11y.cljs
rename to frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.cljs
index fadaacc3d..44acb2733 100644
--- a/frontend/src/app/main/ui/components/context_menu_a11y.cljs
+++ b/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.cljs
@@ -4,12 +4,14 @@
;;
;; Copyright (c) KALEIDOS INC
-(ns app.main.ui.components.context-menu-a11y
+(ns app.main.ui.components.context-menu-a11y.context-menu-a11y
+ (:require-macros [app.main.style :refer [css]])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.main.refs :as refs]
[app.main.ui.components.dropdown :refer [dropdown']]
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@@ -36,15 +38,15 @@
on-click (gobj/get props "on-click")
on-key-down (gobj/get props "on-key-down")
id (gobj/get props "id")
- klass (gobj/get props "klass")
- key (gobj/get props "key")
+ klass (gobj/get props "class")
+ key-index (gobj/get props "key-index")
data-test (gobj/get props "data-test")]
[:li {:id id
:class klass
:tab-index "0"
:on-key-down on-key-down
:on-click on-click
- :key key
+ :key key-index
:role "menuitem"
:data-test data-test}
children]))
@@ -54,22 +56,24 @@
[props]
(assert (fn? (gobj/get props "on-close")) "missing `on-close` prop")
(assert (boolean? (gobj/get props "show")) "missing `show` prop")
- (assert (vector? (gobj/get props "options")) "missing `options` prop")
- (let [open? (gobj/get props "show")
- on-close (gobj/get props "on-close")
- options (gobj/get props "options")
- is-selectable (gobj/get props "selectable")
- selected (gobj/get props "selected")
- top (gobj/get props "top" 0)
- left (gobj/get props "left" 0)
- fixed? (gobj/get props "fixed?" false)
- min-width? (gobj/get props "min-width?" false)
- origin (gobj/get props "origin")
- route (mf/deref refs/route)
- in-dashboard? (= :dashboard-projects (:name (:data route)))
- local (mf/use-state {:offset-y 0
- :offset-x 0
- :levels nil})
+ (assert (vector? (gobj/get props "options")) "missing `options` prop")
+ (let [open? (gobj/get props "show")
+ on-close (gobj/get props "on-close")
+ options (gobj/get props "options")
+ is-selectable (gobj/get props "selectable")
+ selected (gobj/get props "selected")
+ top (gobj/get props "top" 0)
+ left (gobj/get props "left" 0)
+ fixed? (gobj/get props "fixed?" false)
+ min-width? (gobj/get props "min-width?" false)
+ workspace? (gobj/get props "workspace?" false)
+ origin (gobj/get props "origin")
+ route (mf/deref refs/route)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ in-dashboard? (= :dashboard-projects (:name (:data route)))
+ local (mf/use-state {:offset-y 0
+ :offset-x 0
+ :levels nil})
on-local-close
(mf/use-callback
@@ -79,7 +83,7 @@
(on-close)))
props (obj/merge props #js {:on-close on-local-close})
-
+
ids (generate-ids-group (:options (last (:levels @local))) (:parent-option (last (:levels @local))))
check-menu-offscreen
(mf/use-callback
@@ -190,64 +194,100 @@
(when (and open? (some? (:levels @local)))
[:> dropdown' props
-
+
(let [level (-> @local :levels peek)
original-options (:options level)
parent-original (:parent-option level)]
- [:div.context-menu {:class (dom/classnames :is-open open?
- :fixed fixed?
- :is-selectable is-selectable)
- :style {:top (+ top (:offset-y @local))
- :left (+ left (:offset-x @local))}
- :on-key-down (on-key-down original-options parent-original)}
- (let [level (-> @local :levels peek)]
- [:ul.context-menu-items {:class (dom/classnames :min-width min-width?)
- :role "menu"
- :ref check-menu-offscreen}
- (when-let [parent-option (:parent-option level)]
- [:*
- [:& context-menu-a11y-item
- {:id "go-back-sub-option"
- :tab-index "0"
- :on-key-down (fn [event]
- (dom/prevent-default event))}
- [:div.context-menu-action.submenu-back
- {:data-no-close true
- :on-click exit-submenu}
- [:span i/arrow-slide]
- parent-option]]
- [:li.separator]])
- (for [[index option] (d/enumerate (:options level))]
+ [:div {:class (if (and new-css-system workspace?)
+ (dom/classnames (css :is-selectable) is-selectable
+ (css :context-menu) true
+ (css :is-open) open?
+ (css :fixed) fixed?)
+ (dom/classnames :is-selectable is-selectable
+ :context-menu true
+ :is-open open?
+ :fixed fixed?))
+ :style {:top (+ top (:offset-y @local))
+ :left (+ left (:offset-x @local))}
+ :on-key-down (on-key-down original-options parent-original)}
+ (let [level (-> @local :levels peek)]
+ [:ul {:class (if (and new-css-system workspace?)
+ (dom/classnames (css :min-width) min-width?
+ (css :context-menu-items) true)
+ (dom/classnames :min-width min-width?
+ :context-menu-items true))
+ :role "menu"
+ :ref check-menu-offscreen}
+ (when-let [parent-option (:parent-option level)]
+ [:*
+ [:& context-menu-a11y-item
+ {:id "go-back-sub-option"
+ :class (dom/classnames (css :context-menu-item) (and new-css-system workspace?))
+ :tab-index "0"
+ :on-key-down (fn [event]
+ (dom/prevent-default event))}
+ [:div {:class (if (and new-css-system workspace?)
+ (dom/classnames (css :context-menu-action) true
+ (css :submenu-back) true)
+ (dom/classnames :context-menu-action true
+ :submenu-back true))
+ :data-no-close true
+ :on-click exit-submenu}
+ [:span {:class (dom/classnames (css :submenu-icon-back) (and new-css-system workspace?))}
+ (if (and new-css-system workspace?)
+ i/arrow-refactor
+ i/arrow-slide)]
+ parent-option]]
+ [:li {:class (if (and new-css-system workspace?)
+ (dom/classnames (css :separator) true)
+ (dom/classnames :separator true))}]])
+ (for [[index option] (d/enumerate (:options level))]
+ (let [option-name (:option-name option)
+ id (:id option)
+ sub-options (:sub-options option)
+ option-handler (:option-handler option)
+ data-test (:data-test option)]
+ (when option-name
+ (if (= option-name :separator)
+ [:li {:key (dm/str "context-item-" index)
+ :class (if (and new-css-system workspace?)
+ (dom/classnames (css :separator) true)
+ (dom/classnames :separator true))}]
+ [:& context-menu-a11y-item
+ {:id id
+ :class (if (and new-css-system workspace?)
+ (dom/classnames (css :is-selected) (and selected (= option-name selected))
+ (css :context-menu-item) true)
+ (dom/classnames :is-selected (and selected (= option-name selected))))
+ :key-index (dm/str "context-item-" index)
+ :tab-index "0"
+ :on-key-down (fn [event]
+ (dom/prevent-default event))}
+ (if-not sub-options
+ [:a {:class (if (and new-css-system workspace?)
+ (dom/classnames (css :context-menu-action) true)
+ (dom/classnames :context-menu-action true))
+ :on-click #(do (dom/stop-propagation %)
+ (on-close)
+ (option-handler %))
+ :data-test data-test}
+ (if (and in-dashboard? (= option-name "Default"))
+ (tr "dashboard.default-team-name")
+ option-name)]
+ [:a {:class (if (and new-css-system workspace?)
+ (dom/classnames (css :context-menu-action) true
+ (css :submenu) true)
+ (dom/classnames :context-menu-action true
+ :submenu true))
+ :data-no-close true
+ :on-click (enter-submenu option-name sub-options)
+ :data-test data-test}
+ option-name
+ [:span {:class (dom/classnames (css :submenu-icon) (and new-css-system workspace?))}
+ (if (and new-css-system workspace?)
+ i/arrow-refactor
+ i/arrow-slide)]])]))))])])])))
- (let [option-name (:option-name option)
- id (:id option)
- sub-options (:sub-options option)
- option-handler (:option-handler option)
- data-test (:data-test option)]
- (when option-name
- (if (= option-name :separator)
- [:li.separator {:key (dm/str "context-item-" index)}]
- [:& context-menu-a11y-item
- {:id id
- :class (dom/classnames :is-selected (and selected (= option-name selected)))
- :key (dm/str "context-item-" index)
- :tab-index "0"
- :on-key-down (fn [event]
- (dom/prevent-default event))}
- (if-not sub-options
- [:a.context-menu-action {:on-click #(do (dom/stop-propagation %)
- (on-close)
- (option-handler %))
- :data-test data-test}
- (if (and in-dashboard? (= option-name "Default"))
- (tr "dashboard.default-team-name")
- option-name)]
- [:a.context-menu-action.submenu
- {:data-no-close true
- :on-click (enter-submenu option-name sub-options)
- :data-test data-test}
- option-name
- [:span i/arrow-slide]])]))))])])])))
(mf/defc context-menu-a11y
{::mf/wrap-props false}
@@ -255,6 +295,6 @@
(assert (fn? (gobj/get props "on-close")) "missing `on-close` prop")
(assert (boolean? (gobj/get props "show")) "missing `show` prop")
(assert (vector? (gobj/get props "options")) "missing `options` prop")
-
+
(when (gobj/get props "show")
(mf/element context-menu-a11y' props)))
diff --git a/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.css.json b/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.css.json
new file mode 100644
index 000000000..5626dab9d
--- /dev/null
+++ b/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.css.json
@@ -0,0 +1 @@
+{"button-primary":"context_menu_a11y_context_menu_a11y_button-primary_-nqKB","button-secondary":"context_menu_a11y_context_menu_a11y_button-secondary_3sivR","button-icon":"context_menu_a11y_context_menu_a11y_button-icon_45j80","button-icon-small":"context_menu_a11y_context_menu_a11y_button-icon-small_TNORx","context-menu":"context_menu_a11y_context_menu_a11y_context-menu_HLzPl","context-menu-items":"context_menu_a11y_context_menu_a11y_context-menu-items_r2JIA","context-menu-item":"context_menu_a11y_context_menu_a11y_context-menu-item_KB64Q","context-menu-action":"context_menu_a11y_context_menu_a11y_context-menu-action_x7nPU","submenu-back":"context_menu_a11y_context_menu_a11y_submenu-back_8iOw0","submenu-icon-back":"context_menu_a11y_context_menu_a11y_submenu-icon-back_vlCP7","submenu":"context_menu_a11y_context_menu_a11y_submenu_pUX19","submenu-icon":"context_menu_a11y_context_menu_a11y_submenu-icon_mlof4","is-open":"context_menu_a11y_context_menu_a11y_is-open_ASqQk","fixed":"context_menu_a11y_context_menu_a11y_fixed_5h8sL","separator":"context_menu_a11y_context_menu_a11y_separator_b1CzA","min-width":"context_menu_a11y_context_menu_a11y_min-width_jirG8","is-selected":"context_menu_a11y_context_menu_a11y_is-selected_jihDn","is-selectable":"context_menu_a11y_context_menu_a11y_is-selectable_wqvJa"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.scss b/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.scss
new file mode 100644
index 000000000..556bc1acf
--- /dev/null
+++ b/frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.scss
@@ -0,0 +1,127 @@
+// 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-menu {
+ position: relative;
+ visibility: hidden;
+ opacity: 0;
+ z-index: $z-index-2;
+
+ &.is-open {
+ position: relative;
+ display: block;
+ opacity: 1;
+ visibility: visible;
+ }
+ &.fixed {
+ position: fixed;
+ }
+
+ .context-menu-items {
+ position: absolute;
+ top: $s-12;
+ left: calc(-1 * $s-6);
+ max-height: $s-480;
+ min-width: $s-96;
+ margin: 0;
+ padding: $s-4;
+ border-radius: $br8;
+ background-color: var(--menu-background-color);
+ box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
+ overflow: auto;
+ & .separator {
+ height: $s-12;
+ }
+
+ &.min-width {
+ min-width: $s-192;
+ }
+
+ .context-menu-item {
+ display: flex;
+ .context-menu-action {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ height: $s-28;
+ width: 100%;
+ padding: $s-6;
+ border-radius: $br8;
+ white-space: nowrap;
+ color: var(--menu-foreground-color);
+ &.submenu {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ .submenu-icon {
+ margin-left: 0.5rem;
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ }
+ }
+ }
+
+ &.submenu-back {
+ display: flex;
+ align-items: center;
+ font-weight: $fw700;
+ .submenu-icon-back svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ transform: rotate(180deg);
+ }
+ }
+ }
+ &:hover .context-menu-action {
+ background-color: var(--menu-background-color-hover);
+ text-decoration: none;
+ color: var(--menu-foreground-color-hover);
+ &.submenu .submenu-icon svg {
+ stroke: var(--menu-foreground-color-hover);
+ }
+ &.submenu-back .submenu-icon-back svg {
+ stroke: var(--menu-foreground-color-hover);
+ }
+ }
+ &:focus {
+ outline: none;
+ }
+ &:focus-visible {
+ outline: none;
+ .context-menu-action {
+ border: 1px solid var(--menu-border-color-focus);
+ background-color: var(--menu-background-color-focus);
+ text-decoration: none;
+ color: var(--menu-foreground-color-focus);
+ &.submenu .submenu-icon svg {
+ stroke: var(--menu-foreground-color-focus);
+ }
+
+ &.submenu-back .submenu-icon-back svg {
+ stroke: var(--menu-foreground-color-focus);
+ }
+ }
+ }
+ }
+ .is-selected .context-menu-action {
+ padding-left: $s-28;
+ background-image: url(/images/icons/tick.svg);
+ background-repeat: no-repeat;
+ background-position: 5% 48%;
+ background-size: $s-12;
+ font-weight: $fw700;
+ }
+ }
+ &.is-selectable {
+ .context-menu-action {
+ padding-left: 1.5rem;
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/components/shape_icon_refactor.cljs b/frontend/src/app/main/ui/components/shape_icon_refactor.cljs
new file mode 100644
index 000000000..bbb4b4686
--- /dev/null
+++ b/frontend/src/app/main/ui/components/shape_icon_refactor.cljs
@@ -0,0 +1,63 @@
+;; 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.components.shape-icon-refactor
+ (:require
+ [app.common.types.component :as ctk]
+ [app.common.types.shape.layout :as ctl]
+ [app.main.ui.icons :as i]
+ [rumext.v2 :as mf]))
+
+
+(mf/defc element-icon-refactor
+ [{:keys [shape main-instance?] :as props}]
+ (if (ctk/instance-root? shape)
+ (if main-instance?
+ i/component-refactor
+ i/copy-refactor)
+ (case (:type shape)
+ :frame (cond
+ (and (ctl/flex-layout? shape) (ctl/col? shape))
+ i/flex-vertical-refactor
+
+ (and (ctl/flex-layout? shape) (ctl/row? shape))
+ i/flex-horizontal-refactor
+
+ ;; TODO: GRID ICON
+
+ :else
+ i/board-refactor)
+ ;; TODO -> THUMBNAIL ICON
+ :image i/img-refactor
+ :line i/path-refactor
+ :circle i/elipse-refactor
+ :path i/path-refactor
+ :rect i/rectangle-refactor
+ :text i/text-refactor
+ :group (if (:masked-group? shape)
+ i/mask-refactor
+ i/group-refactor)
+ :bool (case (:bool-type shape)
+ :difference i/boolean-difference-refactor
+ :exclude i/boolean-exclude-refactor
+ :intersection i/boolean-intersection-refactor
+ #_:default i/boolean-union-refactor)
+ :svg-raw i/file-svg
+ nil)))
+
+
+(mf/defc element-icon-refactor-by-type
+ [{:keys [type main-instance?] :as props}]
+ (if main-instance?
+ i/component-refactor
+ (case type
+ :frame i/board-refactor
+ :image i/img-refactor
+ :shape i/path-refactor
+ :text i/text-refactor
+ :mask i/mask-refactor
+ :group i/group-refactor
+ nil)))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/tab_container/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container/tab_container.cljs
new file mode 100644
index 000000000..a21d26d34
--- /dev/null
+++ b/frontend/src/app/main/ui/components/tab_container/tab_container.cljs
@@ -0,0 +1,89 @@
+;; 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.components.tab-container.tab-container
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.icons :as i]
+ [app.util.dom :as dom]
+ [app.util.i18n :refer [tr]]
+ [cuerdas.core :as str]
+ [rumext.v2 :as mf]))
+
+(mf/defc tab-element
+ {::mf/wrap-props false}
+ [props]
+ (let [children (unchecked-get props "children")
+ new-css-system (mf/use-ctx ctx/new-css-system)]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tab-element) true)
+ (dom/classnames :tab-element true))}
+ children]))
+
+(mf/defc tab-container
+ {::mf/wrap-props false}
+ [props]
+ (let [children (->>
+ (unchecked-get props "children")
+ (filter some?))
+ selected (unchecked-get props "selected")
+ on-change (unchecked-get props "on-change-tab")
+ collapsable? (unchecked-get props "collapsable?")
+ handle-collapse (unchecked-get props "handle-collapse")
+
+ state (mf/use-state #(or selected (-> children first .-props .-id)))
+ selected (or selected @state)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+
+ select-fn
+ (mf/use-fn
+ (mf/deps on-change)
+ (fn [event]
+ (let [id (d/read-string (.. event -target -dataset -id))]
+ (reset! state id)
+ (when (fn? on-change) (on-change id)))))]
+
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tab-container) true)
+ (dom/classnames :tab-container true))}
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tab-container-tabs) true)
+ (dom/classnames :tab-container-tabs true))}
+ (when (and new-css-system collapsable?)
+ [:button
+ {:on-click handle-collapse
+ :class (dom/classnames (css :collapse-sidebar) true)
+ :aria-label (tr "workspace.sidebar.collapse")}
+ i/arrow-refactor])
+ (if new-css-system
+ [:div {:class (dom/classnames (css :tab-container-tab-wrapper) new-css-system)}
+ (for [tab children]
+ (let [props (.-props tab)
+ id (.-id props)
+ title (.-title props)]
+ [:div
+ {:key (str/concat "tab-" (d/name id))
+ :data-id (pr-str id)
+ :on-click select-fn
+ :class (dom/classnames (css :tab-container-tab-title) true
+ (css :current) (= selected id))}
+ title]))]
+ (for [tab children]
+ (let [props (.-props tab)
+ id (.-id props)
+ title (.-title props)]
+ [:div.tab-container-tab-title
+ {:key (str/concat "tab-" (d/name id))
+ :data-id (pr-str id)
+ :on-click select-fn
+ :class (when (= selected id) "current")}
+ title])))]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tab-container-content) true)
+ (dom/classnames :tab-container-content true))}
+ (d/seek #(= selected (-> % .-props .-id)) children)]]))
diff --git a/frontend/src/app/main/ui/components/tab_container/tab_container.css.json b/frontend/src/app/main/ui/components/tab_container/tab_container.css.json
new file mode 100644
index 000000000..4b608310f
--- /dev/null
+++ b/frontend/src/app/main/ui/components/tab_container/tab_container.css.json
@@ -0,0 +1 @@
+{"button-primary":"tab_container_tab_container_button-primary_83Zqm","button-secondary":"tab_container_tab_container_button-secondary_lnkfT","button-icon":"tab_container_tab_container_button-icon_9pt7Y","button-icon-small":"tab_container_tab_container_button-icon-small_A8MNz","tab-container":"tab_container_tab_container_tab-container_UElWL","tab-container-content":"tab_container_tab_container_tab-container-content_5dioy","tab-element":"tab_container_tab_container_tab-element_ehGDK","tab-container-tabs":"tab_container_tab_container_tab-container-tabs_Vrl6C","tab-container-tab-wrapper":"tab_container_tab_container_tab-container-tab-wrapper_-g0lU","tab-container-tab-title":"tab_container_tab_container_tab-container-tab-title_lR2I4","current":"tab_container_tab_container_current_jHyvE","collapse-sidebar":"tab_container_tab_container_collapse-sidebar_cuRC2","collapsed":"tab_container_tab_container_collapsed_KWhAl"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/tab_container/tab_container.scss b/frontend/src/app/main/ui/components/tab_container/tab_container.scss
new file mode 100644
index 000000000..e957bd3ba
--- /dev/null
+++ b/frontend/src/app/main/ui/components/tab_container/tab_container.scss
@@ -0,0 +1,89 @@
+// 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";
+
+.tab-container {
+ display: grid;
+ grid-template-rows: auto 1fr;
+ grid-template-columns: 100%;
+ height: 100%;
+
+ .tab-container-content {
+ overflow-y: auto;
+ overflow-x: hidden;
+ }
+
+ .tab-element {
+ height: 100%;
+ }
+}
+.tab-container-tabs {
+ display: flex;
+ align-items: center;
+ flex-direction: row;
+ gap: $s-2;
+ height: $s-32;
+ margin: $s-2 $s-2 0 $s-2;
+ padding: $s-2;
+ border-radius: $br8;
+ background: var(--color-background-secondary);
+ cursor: pointer;
+ font-size: $fs12;
+ .tab-container-tab-wrapper {
+ @include flexCenter;
+ flex-direction: row;
+ height: 100%;
+ width: 100%;
+ gap: $s-2;
+ .tab-container-tab-title {
+ @include flexCenter;
+ @include tabTitleTipography;
+ height: $s-28;
+ width: 100%;
+ margin: 0;
+ border-radius: $br5;
+ background-color: transparent;
+ color: var(--tab-foreground-color);
+
+ &.current,
+ &.current:hover {
+ background: var(--tab-background-color-selected);
+ color: var(--tab-foreground-color-selected);
+ }
+ &:hover {
+ color: var(--tab-foreground-color-hover);
+ }
+ }
+ }
+ .collapse-sidebar {
+ @include flexCenter;
+ @include buttonStyle;
+ height: 100%;
+ width: $s-24;
+ padding: 0;
+ border-radius: $br5;
+ svg {
+ @include flexCenter;
+ height: 12px;
+ width: 16px;
+ stroke: var(--icon-foreground);
+ transform: rotate(180deg);
+ fill: none;
+ color: transparent;
+ }
+ &:hover {
+ svg {
+ stroke: var(--icon-foreground-hover);
+ }
+ }
+
+ &.collapsed {
+ svg {
+ transform: rotate(0deg);
+ }
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tabs_container.cljs
similarity index 94%
rename from frontend/src/app/main/ui/components/tab_container.cljs
rename to frontend/src/app/main/ui/components/tabs_container.cljs
index 1052cbe12..2275d06fe 100644
--- a/frontend/src/app/main/ui/components/tab_container.cljs
+++ b/frontend/src/app/main/ui/components/tabs_container.cljs
@@ -4,20 +4,20 @@
;;
;; Copyright (c) KALEIDOS INC
-(ns app.main.ui.components.tab-container
+(ns app.main.ui.components.tabs-container
(:require
[app.common.data :as d]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
-(mf/defc tab-element
+(mf/defc tabs-element
{::mf/wrap-props false}
[props]
(let [children (unchecked-get props "children")]
[:div.tab-element
[:div.tab-element-content children]]))
-(mf/defc tab-container
+(mf/defc tabs-container
{::mf/wrap-props false}
[props]
(let [children (->>
diff --git a/frontend/src/app/main/ui/components/tests/test_component.cljs b/frontend/src/app/main/ui/components/tests/test_component.cljs
new file mode 100644
index 000000000..df154fdc5
--- /dev/null
+++ b/frontend/src/app/main/ui/components/tests/test_component.cljs
@@ -0,0 +1,23 @@
+;; 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.components.tests.test-component
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.util.keyboard :as kbd]
+ [rumext.v2 :as mf]))
+
+(mf/defc test-component [{:keys [action icon name ]}]
+ [:button.test-component
+ {:class (css :button)
+ :tab-index "0"
+ :on-click action
+ :on-key-down (fn [event]
+ (when (kbd/enter? event)
+ (action event)))}
+
+ (when icon [:span.logo icon])
+ name])
diff --git a/frontend/src/app/main/ui/components/tests/test_component.css.json b/frontend/src/app/main/ui/components/tests/test_component.css.json
new file mode 100644
index 000000000..e7a2316d8
--- /dev/null
+++ b/frontend/src/app/main/ui/components/tests/test_component.css.json
@@ -0,0 +1 @@
+{"button":"tests_test_component_button_8MQZj"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/components/tests/test_component.scss b/frontend/src/app/main/ui/components/tests/test_component.scss
new file mode 100644
index 000000000..2579a0c1a
--- /dev/null
+++ b/frontend/src/app/main/ui/components/tests/test_component.scss
@@ -0,0 +1,4 @@
+.button {
+ color: var(--button-foreground-active);
+ background-color: var(--button-background-active);
+}
diff --git a/frontend/src/app/main/ui/context.cljs b/frontend/src/app/main/ui/context.cljs
index 244dbe9c2..c0d1aa00e 100644
--- a/frontend/src/app/main/ui/context.cljs
+++ b/frontend/src/app/main/ui/context.cljs
@@ -22,6 +22,7 @@
(def libraries (mf/create-context nil))
(def components-v2 (mf/create-context nil))
+(def new-css-system (mf/create-context nil))
(def current-scroll (mf/create-context nil))
(def current-zoom (mf/create-context nil))
diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs
index 178635c98..36fadaa36 100644
--- a/frontend/src/app/main/ui/dashboard/file_menu.cljs
+++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs
@@ -12,7 +12,7 @@
[app.main.data.modal :as modal]
[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.context-menu-a11y.context-menu-a11y :refer [context-menu-a11y]]
[app.main.ui.context :as ctx]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@@ -313,4 +313,5 @@
:top top
:left left
:options options
- :origin parent-id}]))))
+ :origin parent-id
+ :workspace? false}]))))
diff --git a/frontend/src/app/main/ui/dashboard/project_menu.cljs b/frontend/src/app/main/ui/dashboard/project_menu.cljs
index 5c749d52d..e1def815a 100644
--- a/frontend/src/app/main/ui/dashboard/project_menu.cljs
+++ b/frontend/src/app/main/ui/dashboard/project_menu.cljs
@@ -12,7 +12,7 @@
[app.main.data.modal :as modal]
[app.main.refs :as refs]
[app.main.store :as st]
- [app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
+ [app.main.ui.components.context-menu-a11y.context-menu-a11y :refer [context-menu-a11y]]
[app.main.ui.context :as ctx]
[app.main.ui.dashboard.import :as udi]
[app.util.dom :as dom]
@@ -143,5 +143,6 @@
:min-width? true
:top top
:left left
- :options options}]]))
+ :options options
+ :workspace false}]]))
diff --git a/frontend/src/app/main/ui/debug/components_preview.cljs b/frontend/src/app/main/ui/debug/components_preview.cljs
new file mode 100644
index 000000000..e8a741444
--- /dev/null
+++ b/frontend/src/app/main/ui/debug/components_preview.cljs
@@ -0,0 +1,60 @@
+;; 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.debug.components-preview
+ (:require-macros [app.main.style :refer [css styles]])
+ (:require [app.common.data :as d]
+ [app.main.data.users :as du]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.components.tests.test-component :as tc]
+ [app.util.dom :as dom]
+ [rumext.v2 :as mf]))
+
+(mf/defc components-preview
+ {::mf/wrap-props false}
+ []
+ (let [profile (mf/deref refs/profile)
+ initial (mf/with-memo [profile]
+ (update profile :lang #(or % "")))
+ initial-theme (:theme initial)
+ on-change (fn [event]
+ (let [theme (dom/event->value event)
+ data (assoc initial :theme theme)]
+ (st/emit! (du/update-profile data))))
+
+ colors [:bg-primary
+ :bg-secondary
+ :bg-tertiary
+ :bg-cuaternary
+ :fg-primary
+ :fg-secondary
+ :acc
+ :acc-muted
+ :acc-secondary
+ :acc-tertiary]]
+
+ [:section.debug-components-preview
+ [:div {:class (css :themes-row)}
+ [:h2 "Themes"]
+ [:select {:label "Select theme color"
+ :name :theme
+ :default "default"
+ :value initial-theme
+ :on-change on-change}
+ [:option {:label "Penpot Dark (default)" :value "default"}]
+ [:option {:label "Penpot Light" :value "light"}]]
+ [:div {:class (css :wrapper)}
+ (let [css (styles)]
+ (for [color colors]
+ [:div {:class (dom/classnames (get css color) true
+ (get css :rect) true)}
+ (d/name color)]))]]
+ [:div {:class (css :components-row)}
+ [:h2 {:class (css :title)} "Components"]
+ [:div {:class (css :component-wrapper)}
+ [:& tc/test-component
+ {:action #(prn "ey soy un botĂłn") :name "Click me"}]]]]))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/debug/components_preview.css.json b/frontend/src/app/main/ui/debug/components_preview.css.json
new file mode 100644
index 000000000..9b9b62386
--- /dev/null
+++ b/frontend/src/app/main/ui/debug/components_preview.css.json
@@ -0,0 +1 @@
+{"button-primary":"debug_components_preview_button-primary_Q2m40","button-secondary":"debug_components_preview_button-secondary_yPp3n","button-icon":"debug_components_preview_button-icon_J36A6","button-icon-small":"debug_components_preview_button-icon-small_Pf3jb","themes-row":"debug_components_preview_themes-row_wEU8d","wrapper":"debug_components_preview_wrapper_535-4","rect":"debug_components_preview_rect_jomnq","bg-primary":"debug_components_preview_bg-primary_Rt4oW","bg-secondary":"debug_components_preview_bg-secondary_rcmll","bg-tertiary":"debug_components_preview_bg-tertiary_7rITE","bg-cuaternary":"debug_components_preview_bg-cuaternary_UEBPN","fg-primary":"debug_components_preview_fg-primary_naliT","fg-secondary":"debug_components_preview_fg-secondary_zT9IX","acc":"debug_components_preview_acc_h3Bia","acc-muted":"debug_components_preview_acc-muted_uingh","acc-secondary":"debug_components_preview_acc-secondary_oHH6y","acc-tertiary":"debug_components_preview_acc-tertiary_SwBjy","components-row":"debug_components_preview_components-row_N3f-J","title":"debug_components_preview_title_TVtzz","component-wrapper":"debug_components_preview_component-wrapper_yC9G1"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/debug/components_preview.scss b/frontend/src/app/main/ui/debug/components_preview.scss
new file mode 100644
index 000000000..4d1cf79e3
--- /dev/null
+++ b/frontend/src/app/main/ui/debug/components_preview.scss
@@ -0,0 +1,85 @@
+// 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";
+
+.themes-row {
+ width: 100%;
+ padding: $s-20;
+ color: var(--color-foreground-primary);
+ background: var(--color-background-secondary);
+ .wrapper {
+ background-color: var(--color-background-primary);
+ width: 100%;
+ padding: $s-20;
+ display: flex;
+ justify-content: center;
+ gap: $s-20;
+ flex-wrap: wrap;
+ .rect {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 1px solid var(--color-foreground-primary);
+ padding: $s-20;
+ height: $s-96;
+ min-width: $s-152;
+ }
+ .bg-primary {
+ background: var(--color-background-primary);
+ color: var(--color-foreground-primary);
+ }
+ .bg-secondary {
+ background: var(--color-background-secondary);
+ color: var(--color-foreground-primary);
+ }
+ .bg-tertiary {
+ background: var(--color-background-tertiary);
+ color: var(--color-foreground-primary);
+ }
+ .bg-cuaternary {
+ background: var(--color-background-quaternary);
+ color: var(--color-foreground-primary);
+ }
+ .fg-primary {
+ background: var(--color-foreground-primary);
+ color: var(--color-background-primary);
+ }
+ .fg-secondary {
+ background: var(--color-foreground-secondary);
+ color: var(--color-background-primary);
+ }
+ .acc {
+ background: var(--color-accent-primary);
+ color: var(--color-background-primary);
+ }
+ .acc-muted {
+ background: var(--color-accent-primary-muted);
+ color: var(--color-foreground-primary);
+ }
+ .acc-secondary {
+ background: var(--color-accent-secondary);
+ color: var(--color-background-primary);
+ }
+ .acc-tertiary {
+ background: var(--color-accent-tertiary);
+ color: var(--color-background-primary);
+ }
+ }
+}
+
+.components-row {
+ color: var(--color-foreground-primary);
+ background: var(--color-background-secondary);
+ height: 100%;
+ padding: 0 $s-20;
+ .title {
+ padding: $s-20;
+ }
+ .component-wrapper {
+ padding: $s-20;
+ }
+}
diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs
index edc033bfc..3a228cf64 100644
--- a/frontend/src/app/main/ui/icons.cljs
+++ b/frontend/src/app/main/ui/icons.cljs
@@ -258,6 +258,42 @@
(def brand-gitlab (icon-xref :brand-gitlab))
(def brand-google (icon-xref :brand-google))
+(def add-refactor (icon-xref :add-refactor))
+(def arrow-refactor (icon-xref :arrow-refactor))
+(def board-refactor (icon-xref :board-refactor))
+(def boards-thumbnail-refactor (icon-xref :boards-thumbnail-refactor))
+(def close-refactor (icon-xref :close-refactor))
+(def close-small-refactor (icon-xref :close-small-refactor))
+(def component-refactor (icon-xref :component-refactor))
+(def copy-refactor (icon-xref :copy-refactor))
+(def curve-refactor (icon-xref :curve-refactor))
+(def delete-refactor (icon-xref :delete-refactor))
+(def delete-text-refactor (icon-xref :delete-text-refactor))
+(def boolean-difference-refactor (icon-xref :boolean-difference-refactor))
+(def document-refactor (icon-xref :document-refactor))
+(def elipse-refactor (icon-xref :elipse-refactor))
+(def boolean-exclude-refactor (icon-xref :boolean-exclude-refactor))
+(def filter-refactor (icon-xref :filter-refactor))
+(def boolean-flatten-refactor (icon-xref :boolean-flatten-refactor))
+(def flex-refactor (icon-xref :flex-refactor))
+(def flex-horizontal-refactor (icon-xref :flex-horizontal-refactor))
+(def flex-grid-refactor (icon-xref :flex-grid-refactor))
+(def flex-vertical-refactor (icon-xref :flex-vertical-refactor))
+(def flip-horizontal-refactor (icon-xref :flip-horizontal-refactor))
+(def group-refactor (icon-xref :group-refactor))
+(def hide-refactor (icon-xref :hide-refactor))
+(def img-refactor (icon-xref :img-refactor))
+(def boolean-intersection-refactor (icon-xref :boolean-intersection-refactor))
+(def lock-refactor (icon-xref :lock-refactor))
+(def mask-refactor (icon-xref :mask-refactor))
+(def path-refactor (icon-xref :path-refactor))
+(def rectangle-refactor (icon-xref :rectangle-refactor))
+(def search-refactor (icon-xref :search-refactor))
+(def shown-refactor (icon-xref :shown-refactor))
+(def text-refactor (icon-xref :text-refactor))
+(def tick-refactor (icon-xref :tick-refactor))
+(def unlock-refactor (icon-xref :unlock-refactor))
+(def boolean-union-refactor (icon-xref :boolean-union-refactor))
(def loader-pencil
(mf/html
[:svg
diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs
index 222ae33e2..0c18d47ba 100644
--- a/frontend/src/app/main/ui/routes.cljs
+++ b/frontend/src/app/main/ui/routes.cljs
@@ -55,6 +55,8 @@
(when *assert*
["/debug/icons-preview" :debug-icons-preview])
+
+ ["/debug/components-preview" :debug-components-preview]
;; Used for export
["/render-sprite/:file-id" :render-sprite]
diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs
index 08f53d59b..5399ad70a 100644
--- a/frontend/src/app/main/ui/settings/options.cljs
+++ b/frontend/src/app/main/ui/settings/options.cljs
@@ -55,8 +55,8 @@
:name :lang
:data-test "setting-lang"}]]
- #_[:h2 (tr "dashboard.theme-change")]
- #_[:div.fields-row
+ [:h2 (tr "dashboard.theme-change")]
+ [:div.fields-row
[:& fm/select {:label (tr "dashboard.select-ui-theme")
:name :theme
:default "default"
diff --git a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs
index 4de4d9fd8..0e81b153e 100644
--- a/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs
+++ b/frontend/src/app/main/ui/viewer/inspect/left_sidebar.cljs
@@ -12,7 +12,7 @@
[app.main.store :as st]
[app.main.ui.components.shape-icon :as si]
[app.main.ui.icons :as i]
- [app.main.ui.workspace.sidebar.layers :refer [layer-name]]
+ [app.main.ui.workspace.sidebar.layers.layer-name.layer-name :refer [layer-name]]
[app.util.dom :as dom]
[app.util.keyboard :as kbd]
[okulary.core :as l]
@@ -53,9 +53,7 @@
(st/emit! (dv/shift-select-to id))
:else
- (st/emit! (dv/select-shape id)))
- ))
- ]
+ (st/emit! (dv/select-shape id)))))]
(mf/use-effect
(mf/deps selected)
@@ -65,9 +63,9 @@
[:li {:ref item-ref
:class (dom/classnames
- :component (not (nil? (:component-id item)))
- :masked (:masked-group? item)
- :selected selected?)}
+ :component (not (nil? (:component-id item)))
+ :masked (:masked-group? item)
+ :selected selected?)}
[:div.element-list-body {:class (dom/classnames :selected selected?
:icon-layer (= (:type item) :icon))
diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs
index c8a496409..2d6ede247 100644
--- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs
+++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs
@@ -9,7 +9,7 @@
[app.main.data.workspace :as dw]
[app.main.store :as st]
[app.main.ui.components.shape-icon :as si]
- [app.main.ui.components.tab-container :refer [tab-container tab-element]]
+ [app.main.ui.components.tabs-container :refer [tabs-container tabs-element]]
[app.main.ui.icons :as i]
[app.main.ui.viewer.inspect.attributes :refer [attributes]]
[app.main.ui.viewer.inspect.code :refer [code]]
@@ -56,20 +56,20 @@
;; inspect.tabs.code.selected.text
[:span.tool-window-bar-title (:name first-shape)]])]
[:div.tool-window-content.inspect
- [:& tab-container {:on-change-tab #(do
+ [:& tabs-container {:on-change-tab #(do
(reset! expanded false)
(reset! section %)
(when (= from :workspace)
(st/emit! (dw/set-inspect-expanded false))))
:selected @section}
- [:& tab-element {:id :info :title (tr "inspect.tabs.info")}
+ [:& tabs-element {:id :info :title (tr "inspect.tabs.info")}
[:& attributes {:page-id page-id
:file-id file-id
:frame frame
:shapes shapes
:from from}]]
- [:& tab-element {:id :code :title (tr "inspect.tabs.code")}
+ [:& tabs-element {:id :code :title (tr "inspect.tabs.code")}
[:& code {:frame frame
:shapes shapes
:on-expand (fn []
diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs
index 60fdc07b3..a09bb2aef 100644
--- a/frontend/src/app/main/ui/workspace.cljs
+++ b/frontend/src/app/main/ui/workspace.cljs
@@ -21,13 +21,14 @@
[app.main.ui.icons :as i]
[app.main.ui.workspace.colorpalette :refer [colorpalette]]
[app.main.ui.workspace.colorpicker]
- [app.main.ui.workspace.context-menu :refer [context-menu]]
+ [app.main.ui.workspace.context-menu.context-menu :refer [context-menu]]
[app.main.ui.workspace.coordinates :as coordinates]
[app.main.ui.workspace.header :refer [header]]
[app.main.ui.workspace.left-toolbar :refer [left-toolbar]]
[app.main.ui.workspace.libraries]
[app.main.ui.workspace.nudge]
- [app.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
+ [app.main.ui.workspace.sidebar.collapsable-button.collapsable-button :refer [collapsed-button]]
+ [app.main.ui.workspace.sidebar.component.sidebar :refer [left-sidebar right-sidebar]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
[app.main.ui.workspace.textpalette :refer [textpalette]]
[app.main.ui.workspace.viewport :refer [viewport]]
@@ -93,9 +94,7 @@
[:*
[:& left-toolbar {:layout layout}]
(if (:collapse-left-sidebar layout)
- [:button.collapse-sidebar.collapsed {:on-click #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar))
- :aria-label (tr "workspace.sidebar.expand")}
- i/arrow-slide]
+ [:& collapsed-button]
[:& left-sidebar {:layout layout}])
[:& right-sidebar {:section options-mode
:selected selected
@@ -137,9 +136,10 @@
ready? (mf/deref refs/workspace-ready?)
workspace-read-only? (mf/deref refs/workspace-read-only?)
- components-v2 (features/use-feature :components-v2)
+ components-v2 (features/use-feature :components-v2)
+ new-css-system (features/use-feature :new-css-system)
- background-color (:background-color wglobal)
+ background-color (:background-color wglobal)
focus-out
(mf/use-callback
@@ -177,7 +177,8 @@
[:& (mf/provider ctx/current-project-id) {:value (:id project)}
[:& (mf/provider ctx/current-page-id) {:value page-id}
[:& (mf/provider ctx/components-v2) {:value components-v2}
- [:& (mf/provider ctx/workspace-read-only?) {:value workspace-read-only?}
+ [:& (mf/provider ctx/new-css-system) {:value new-css-system}
+ [:& (mf/provider ctx/workspace-read-only?) {:value workspace-read-only?}
[:section#workspace {:style {:background-color background-color
:touch-action "none"}}
(when (not (:hide-ui layout))
@@ -193,7 +194,7 @@
:file file
:wglobal wglobal
:layout layout}]
- [:& workspace-loader])]]]]]]]))
+ [:& workspace-loader])]]]]]]]]))
(mf/defc remove-graphics-dialog
{::mf/register modal/components
diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu/context_menu.cljs
similarity index 86%
rename from frontend/src/app/main/ui/workspace/context_menu.cljs
rename to frontend/src/app/main/ui/workspace/context_menu/context_menu.cljs
index bcd897060..2bfa1b712 100644
--- a/frontend/src/app/main/ui/workspace/context_menu.cljs
+++ b/frontend/src/app/main/ui/workspace/context_menu/context_menu.cljs
@@ -4,8 +4,9 @@
;;
;; Copyright (c) KALEIDOS INC
-(ns app.main.ui.workspace.context-menu
+(ns app.main.ui.workspace.context-menu.context-menu
"A workspace specific context menu (mouse right click)."
+ (:require-macros [app.main.style :refer [css]])
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
@@ -16,6 +17,7 @@
[app.common.types.page :as ctp]
[app.main.data.events :as ev]
[app.main.data.modal :as modal]
+ [app.main.data.shortcuts :as scd]
[app.main.data.workspace :as dw]
[app.main.data.workspace.interactions :as dwi]
[app.main.data.workspace.libraries :as dwl]
@@ -27,7 +29,7 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
- [app.main.ui.components.shape-icon :as si]
+ [app.main.ui.components.shape-icon-refactor :as sic]
[app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
@@ -48,7 +50,7 @@
[{:keys [title shortcut on-click on-pointer-enter on-pointer-leave on-unmount children selected? icon] :as props}]
(let [submenu-ref (mf/use-ref nil)
hovering? (mf/use-ref false)
-
+ new-css-system (mf/use-ctx ctx/new-css-system)
on-pointer-enter
(mf/use-callback
(fn []
@@ -77,41 +79,74 @@
(when (and (some? dom) (some? submenu-node))
(dom/set-css-property! submenu-node "top" (str (.-offsetTop dom) "px"))))))]
-
(mf/use-effect
(mf/deps on-unmount)
(constantly on-unmount))
(if icon
- [:li.icon-menu-item {:ref set-dom-node
- :on-click on-click
- :on-pointer-enter on-pointer-enter
- :on-pointer-leave on-pointer-leave}
- [:span.icon-wrapper
- (if selected? [:span.selected-icon i/tick]
- [:span.selected-icon])
- [:span.shape-icon icon]]
- [:span.title title]]
- [:li {:ref set-dom-node
+ [:li {:class (if new-css-system
+ (dom/classnames (css :icon-menu-item) true)
+ (dom/classnames :icon-menu-item true))
+ :ref set-dom-node
:on-click on-click
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave}
- [:span.title title]
- [:span.shortcut (or shortcut "")]
+ [:span
+ {:class (if new-css-system
+ (dom/classnames (css :icon-wrapper) true)
+ (dom/classnames :icon-wrapper true))}
+ (if selected? [:span {:class (if new-css-system
+ (dom/classnames (css :selected-icon) true)
+ (dom/classnames :selected-icon true))}
+ (if new-css-system
+ i/tick-refactor
+ i/tick)]
+ [:span {:class (if new-css-system
+ (dom/classnames (css :selected-icon) true)
+ (dom/classnames :selected-icon true))}])
+ [:span {:class (if new-css-system
+ (dom/classnames (css :shape-icon) true)
+ (dom/classnames :shape-icon true))} icon]]
+ [:span {:class (if new-css-system
+ (dom/classnames (css :title) true)
+ (dom/classnames :title true))} title]]
+ [:li {:class (dom/classnames (css :context-menu-item) new-css-system)
+ :ref set-dom-node
+ :on-click on-click
+ :on-pointer-enter on-pointer-enter
+ :on-pointer-leave on-pointer-leave}
+ [:span {:class (if new-css-system
+ (dom/classnames (css :title) true)
+ (dom/classnames :title true))} title]
+ (when shortcut
+ [:span {:class (if new-css-system
+ (dom/classnames (css :shortcut) true)
+ (dom/classnames :shortcut true))}
+ (if new-css-system
+ (for [sc (scd/split-sc shortcut)]
+ [:span {:class (dom/classnames (css :shortcut-key) true)} sc])
+ (or shortcut ""))])
(when (> (count children) 1)
- [:span.submenu-icon i/arrow-slide])
+ (if new-css-system
+ [:span {:class (dom/classnames (css :submenu-icon) true)} i/arrow-refactor]
+ [:span.submenu-icon i/arrow-slide]))
(when (> (count children) 1)
- [:ul.workspace-context-menu
- {:ref submenu-ref
+ [:ul
+ {:class (if new-css-system
+ (dom/classnames (css :workspace-context-submenu) true)
+ (dom/classnames :workspace-context-menu true))
+ :ref submenu-ref
:style {:display "none" :left 250}
:on-context-menu prevent-default}
children])])))
-
(mf/defc menu-separator
[]
- [:li.separator])
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ [:li {:class (if new-css-system
+ (dom/classnames (css :separator) true)
+ (dom/classnames :separator true))}]))
(mf/defc context-menu-edit
[]
@@ -165,7 +200,7 @@
:on-pointer-enter (on-pointer-enter (:id object))
:on-pointer-leave (on-pointer-leave (:id object))
:on-unmount (on-unmount (:id object))
- :icon (si/element-icon {:shape object})}])])
+ :icon (sic/element-icon-refactor {:shape object})}])])
[:& menu-entry {:title (tr "workspace.shape.menu.forward")
:shortcut (sc/get-tooltip :bring-forward)
:on-click do-bring-forward}]
@@ -336,14 +371,18 @@
[:*
(if (every? :hidden shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.show")
+ :shortcut (sc/get-tooltip :toggle-visibility)
:on-click do-show-shape}]
[:& menu-entry {:title (tr "workspace.shape.menu.hide")
+ :shortcut (sc/get-tooltip :toggle-visibility)
:on-click do-hide-shape}])
(if (every? :blocked shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.unlock")
+ :shortcut (sc/get-tooltip :toggle-lock)
:on-click do-unlock-shape}]
[:& menu-entry {:title (tr "workspace.shape.menu.lock")
+ :shortcut (sc/get-tooltip :toggle-lock)
:on-click do-lock-shape}])]))
(mf/defc context-menu-prototype
@@ -555,6 +594,30 @@
[:> context-menu-component props]
[:> context-menu-delete props]])))
+(mf/defc page-item-context-menu
+ [{:keys [mdata] :as props}]
+ (let [page (:page mdata)
+ deletable? (:deletable? mdata)
+ id (:id page)
+ delete-fn #(st/emit! (dw/delete-page id))
+ do-delete #(st/emit! (modal/show
+ {:type :confirm
+ :title (tr "modals.delete-page.title")
+ :message (tr "modals.delete-page.body")
+ :on-accept delete-fn}))
+ do-duplicate #(st/emit! (dw/duplicate-page id))
+ do-rename #(st/emit! (dw/start-rename-page-item id))]
+
+ [:*
+ (when deletable?
+ [:& menu-entry {:title (tr "workspace.assets.delete")
+ :on-click do-delete}])
+
+ [:& menu-entry {:title (tr "workspace.assets.rename")
+ :on-click do-rename}]
+ [:& menu-entry {:title (tr "workspace.assets.duplicate")
+ :on-click do-duplicate}]]))
+
(mf/defc viewport-context-menu
[]
(let [focus (mf/deref refs/workspace-focus-selected)
@@ -575,36 +638,13 @@
:shortcut (sc/get-tooltip :toggle-focus-mode)
:on-click do-toggle-focus-mode}])]))
-(mf/defc page-item-context-menu
- [{:keys [mdata] :as props}]
- (let [page (:page mdata)
- deletable? (:deletable? mdata)
- id (:id page)
- delete-fn #(st/emit! (dw/delete-page id))
- do-delete #(st/emit! (modal/show
- {:type :confirm
- :title (tr "modals.delete-page.title")
- :message (tr "modals.delete-page.body")
- :on-accept delete-fn}))
- do-duplicate #(st/emit! (dw/duplicate-page id))
- do-rename #(st/emit! (dw/start-rename-page-item id))]
-
- [:*
- (when deletable?
- [:& menu-entry {:title (tr "workspace.assets.delete")
- :on-click do-delete}])
-
- [:& menu-entry {:title (tr "workspace.assets.rename")
- :on-click do-rename}]
- [:& menu-entry {:title (tr "workspace.assets.duplicate")
- :on-click do-duplicate}]]))
-
(mf/defc context-menu
[]
- (let [mdata (mf/deref menu-ref)
- top (- (get-in mdata [:position :y]) 20)
- left (get-in mdata [:position :x])
- dropdown-ref (mf/use-ref)]
+ (let [mdata (mf/deref menu-ref)
+ top (- (get-in mdata [:position :y]) 20)
+ left (get-in mdata [:position :x])
+ dropdown-ref (mf/use-ref)
+ new-css-system (mf/use-ctx ctx/new-css-system)]
(mf/use-effect
(mf/deps mdata)
@@ -621,8 +661,11 @@
[:& dropdown {:show (boolean mdata)
:on-close #(st/emit! dw/hide-context-menu)}
- [:ul.workspace-context-menu
- {:ref dropdown-ref
+ [:ul
+ {:class (if new-css-system
+ (dom/classnames (css :workspace-context-menu) true)
+ (dom/classnames :workspace-context-menu true))
+ :ref dropdown-ref
:style {:top top :left left}
:on-context-menu prevent-default}
@@ -632,4 +675,3 @@
[:& viewport-context-menu {:mdata mdata}])]]))
-
diff --git a/frontend/src/app/main/ui/workspace/context_menu/context_menu.css.json b/frontend/src/app/main/ui/workspace/context_menu/context_menu.css.json
new file mode 100644
index 000000000..53d0935c2
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/context_menu/context_menu.css.json
@@ -0,0 +1 @@
+{"button-primary":"context_menu_context_menu_button-primary_RH3ML","button-secondary":"context_menu_context_menu_button-secondary_b46I0","button-icon":"context_menu_context_menu_button-icon_3liUK","button-icon-small":"context_menu_context_menu_button-icon-small_TEk7r","workspace-context-menu":"context_menu_context_menu_workspace-context-menu_1ttcO","icon-menu-item":"context_menu_context_menu_icon-menu-item_aII2v","shape-icon":"context_menu_context_menu_shape-icon_Jje3F","workspace-context-submenu":"context_menu_context_menu_workspace-context-submenu_CJdTO","selected-icon":"context_menu_context_menu_selected-icon_LPfha","context-menu-item":"context_menu_context_menu_context-menu-item_wMn3O","submenu-icon":"context_menu_context_menu_submenu-icon_BbOET","separator":"context_menu_context_menu_separator_adR3k","title":"context_menu_context_menu_title_LFn2G","shortcut":"context_menu_context_menu_shortcut_C0492","shortcut-key":"context_menu_context_menu_shortcut-key_EElQO","icon-wrapper":"context_menu_context_menu_icon-wrapper_zC0vW"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/context_menu/context_menu.scss b/frontend/src/app/main/ui/workspace/context_menu/context_menu.scss
new file mode 100644
index 000000000..c439740ed
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/context_menu/context_menu.scss
@@ -0,0 +1,112 @@
+// 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";
+
+.workspace-context-menu,
+.workspace-context-submenu {
+ position: absolute;
+ top: $s-40;
+ left: $s-736;
+ display: flex;
+ flex-direction: column;
+ width: $s-240;
+ padding: $s-4;
+ border-radius: $br8;
+ background-color: var(--menu-background-color);
+ z-index: $z-index-20;
+ box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
+ .separator {
+ height: $s-12;
+ }
+ .context-menu-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: $s-28;
+ width: 100%;
+ padding: $s-6;
+ border-radius: $br8;
+ cursor: pointer;
+
+ .title {
+ @include titleTipography;
+ color: var(--menu-foreground-color);
+ }
+ .shortcut {
+ @include flexCenter;
+ gap: $s-2;
+ color: var(--menu-shortcut-foreground-color);
+ .shortcut-key {
+ @include titleTipography;
+ @include flexCenter;
+ height: $s-20;
+ padding: $s-2 $s-6;
+ border-radius: $br6;
+ background-color: var(--menu-shortcut-background-color);
+ }
+ }
+
+ .submenu-icon {
+ position: absolute;
+ right: $s-16;
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ }
+ }
+ &:hover {
+ background-color: var(--menu-background-color-hover);
+ .title {
+ color: var(--menu-foreground-color-hover);
+ }
+ .shortcut {
+ color: var(--menu-shortcut-foreground-color-hover);
+ }
+ }
+ &:focus {
+ border: 1px solid var(--menu-border-color-focus);
+ background-color: var(--menu-background-color-focus);
+ }
+ }
+
+ .icon-menu-item {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ height: $s-28;
+ padding: $s-6;
+ border-radius: $br8;
+ &:hover {
+ background-color: var(--menu-background-color-hover);
+ }
+
+ span.title {
+ margin-left: $s-6;
+ }
+
+ .selected-icon {
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ }
+ }
+
+ .shape-icon {
+ margin-left: $s-2;
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ }
+ }
+
+ .icon-wrapper {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ margin: 0;
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
deleted file mode 100644
index bc311baf9..000000000
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ /dev/null
@@ -1,121 +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
-
-(ns app.main.ui.workspace.sidebar
- (:require
- [app.main.data.workspace :as dw]
- [app.main.refs :as refs]
- [app.main.store :as st]
- [app.main.ui.components.tab-container :refer [tab-container tab-element]]
- [app.main.ui.hooks.resize :refer [use-resize-hook]]
- [app.main.ui.icons :as i]
- [app.main.ui.workspace.comments :refer [comments-sidebar]]
- [app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]]
- [app.main.ui.workspace.sidebar.debug :refer [debug-panel]]
- [app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
- [app.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
- [app.main.ui.workspace.sidebar.options :refer [options-toolbox]]
- [app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container]]
- [app.main.ui.workspace.sidebar.sitemap :refer [sitemap]]
- [app.util.dom :as dom]
- [app.util.i18n :refer [tr]]
- [app.util.object :as obj]
- [rumext.v2 :as mf]))
-
-;; --- Left Sidebar (Component)
-
-(mf/defc left-sidebar
- {:wrap [mf/memo]}
- [{:keys [layout] :as props}]
- (let [options-mode (mf/deref refs/options-mode-global)
- mode-inspect? (= options-mode :inspect)
- section (cond (or mode-inspect? (contains? layout :layers)) :layers
- (contains? layout :assets) :assets)
- shortcuts? (contains? layout :shortcuts)
- show-debug? (contains? layout :debug-panel)
-
- {:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
- (use-resize-hook :left-sidebar 255 255 500 :x false :left)
-
- handle-collapse
- (fn []
- (st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))]
-
- [:aside.settings-bar.settings-bar-left {:ref parent-ref
- :class (dom/classnames
- :two-row (<= size 300)
- :three-row (and (> size 300) (<= size 400))
- :four-row (> size 400))
- :style #js {"--width" (str size "px")}}
- [:div.resize-area {:on-pointer-down on-pointer-down
- :on-lost-pointer-capture on-lost-pointer-capture
- :on-pointer-move on-pointer-move}]
-
- [:div.settings-bar-inside
- (cond
- shortcuts?
- [:& shortcuts-container]
-
- show-debug?
- [:& debug-panel]
-
- :else
- [:*
- [:button.collapse-sidebar
- {:on-click handle-collapse
- :aria-label (tr "workspace.sidebar.collapse")}
- i/arrow-slide]
- [:& tab-container {:on-change-tab #(st/emit! (dw/go-to-layout %))
- :selected section
- :shortcuts? shortcuts?}
-
- [:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")}
- [:div.layers-tab
- [:& sitemap {:layout layout}]
- [:& layers-toolbox]]]
-
- (when-not mode-inspect?
- [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
- [:& assets-toolbox]])]])]]))
-
-;; --- Right Sidebar (Component)
-
-(mf/defc right-sidebar
- {::mf/wrap-props false
- ::mf/wrap [mf/memo]}
- [props]
- (let [layout (obj/get props "layout")
- section (obj/get props "section")
- drawing-tool (:tool (mf/deref refs/workspace-drawing))
-
- is-comments? (= drawing-tool :comments)
- is-history? (contains? layout :document-history)
- is-inspect? (= section :inspect)
-
- expanded? (mf/deref refs/inspect-expanded)
- can-be-expanded? (and
- (not is-comments?)
- (not is-history?)
- is-inspect?)]
-
- (mf/use-effect
- (mf/deps can-be-expanded?)
- (fn []
- (when (not can-be-expanded?)
- (st/emit! (dw/set-inspect-expanded false)))))
-
- [:aside.settings-bar.settings-bar-right {:class (when (and can-be-expanded? expanded?) "expanded")}
- [:div.settings-bar-inside
- (cond
- is-comments?
- [:& comments-sidebar]
-
- is-history?
- [:& history-toolbox]
-
- :else
- [:> options-toolbox props])]]))
-
diff --git a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.cljs b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.cljs
new file mode 100644
index 000000000..48eb3e0aa
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.cljs
@@ -0,0 +1,33 @@
+;; 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.workspace.sidebar.collapsable-button.collapsable-button
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.main.data.workspace :as dw]
+ [app.main.store :as st]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.icons :as i]
+ [app.util.dom :as dom]
+ [app.util.i18n :refer [tr]]
+ [rumext.v2 :as mf]))
+
+(mf/defc collapsed-button
+ {::mf/wrap-props false}
+ []
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:div {:class (dom/classnames (css :collapsed-sidebar) true)}
+ [:div {:class (dom/classnames (css :collapsed-title) true)}
+ [:button {:class (dom/classnames (css :collapsed-button) true)
+ :on-click #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar))
+ :aria-label (tr "workspace.sidebar.expand")}
+ i/arrow-refactor]]]
+ [:button.collapse-sidebar.collapsed
+ {:on-click #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar))
+ :aria-label (tr "workspace.sidebar.expand")}
+ i/arrow-slide]
+ )))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.css.json b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.css.json
new file mode 100644
index 000000000..244c3f094
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.css.json
@@ -0,0 +1 @@
+{"button-primary":"collapsable_button_collapsable_button_button-primary_sHqxQ","button-secondary":"collapsable_button_collapsable_button_button-secondary_f66GY","button-icon":"collapsable_button_collapsable_button_button-icon_bKnW3","button-icon-small":"collapsable_button_collapsable_button_button-icon-small_xnfYB","collapsed-sidebar":"collapsable_button_collapsable_button_collapsed-sidebar_JUHji","collapsed-title":"collapsable_button_collapsable_button_collapsed-title_v8MhF","collapsed-button":"collapsable_button_collapsable_button_collapsed-button_MGz3x"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.scss b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.scss
new file mode 100644
index 000000000..608abed96
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.scss
@@ -0,0 +1,44 @@
+// 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";
+
+.collapsed-sidebar {
+ @include flexCenter;
+ position: absolute;
+ top: $s-48;
+ left: $s-48;
+ padding: $s-8;
+ border-radius: $br8;
+ background: var(--color-background-primary);
+}
+.collapsed-title {
+ @include flexCenter;
+ height: $s-32;
+ width: $s-24;
+ border-radius: $br8;
+ background: var(--color-background-secondary);
+}
+.collapsed-button {
+ @include buttonStyle;
+ height: $s-24;
+ width: $s-16;
+ padding: 0;
+ border-radius: $br5;
+ svg {
+ @include flexCenter;
+ height: $s-12;
+ width: $s-16;
+ color: transparent;
+ fill: none;
+ stroke: var(--icon-foreground);
+ }
+ &:hover {
+ svg {
+ stroke: var(--icon-foreground-hover);
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.cljs
new file mode 100644
index 000000000..0659a8250
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.cljs
@@ -0,0 +1,151 @@
+;; 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.workspace.sidebar.component.sidebar
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.main.data.workspace :as dw]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.components.tab-container.tab-container :refer [tab-container tab-element]]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.hooks.resize :refer [use-resize-hook]]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.comments :refer [comments-sidebar]]
+ [app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]]
+ [app.main.ui.workspace.sidebar.debug :refer [debug-panel]]
+ [app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
+ [app.main.ui.workspace.sidebar.layers.layers :refer [layers-toolbox]]
+ [app.main.ui.workspace.sidebar.options :refer [options-toolbox]]
+ [app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container]]
+ [app.main.ui.workspace.sidebar.sitemap.sitemap :refer [sitemap]]
+ [app.util.dom :as dom]
+ [app.util.i18n :refer [tr]]
+ [app.util.object :as obj]
+ [rumext.v2 :as mf]))
+
+;; --- Left Sidebar (Component)
+
+(mf/defc left-sidebar
+ {:wrap [mf/memo]}
+ [{:keys [layout] :as props}]
+ (let [options-mode (mf/deref refs/options-mode-global)
+ mode-inspect? (= options-mode :inspect)
+ section (cond (or mode-inspect? (contains? layout :layers)) :layers
+ (contains? layout :assets) :assets)
+ shortcuts? (contains? layout :shortcuts)
+ show-debug? (contains? layout :debug-panel)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ {:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
+ (use-resize-hook :left-sidebar 255 255 500 :x false :left)
+
+ handle-collapse
+ (fn []
+ (st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))]
+
+ [:aside {:ref parent-ref
+ :class (if new-css-system
+ (dom/classnames (css :left-settings-bar) true)
+ (dom/classnames :settings-bar true
+ :settings-bar-left true
+ :two-row (<= size 300)
+ :three-row (and (> size 300) (<= size 400))
+ :four-row (> size 400)))
+ :style #js {"--width" (str size "px")}}
+
+ [:div {:on-pointer-down on-pointer-down
+ :on-lost-pointer-capture on-lost-pointer-capture
+ :on-pointer-move on-pointer-move
+ :class (if new-css-system
+ (dom/classnames (css :resize-area) true)
+ (dom/classnames :resize-area true))}]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :settings-bar-inside) true)
+ (dom/classnames :settings-bar-inside true))}
+ (cond
+ shortcuts?
+ [:& shortcuts-container]
+
+ show-debug?
+ [:& debug-panel]
+
+ :else
+ [:*
+
+ (if new-css-system
+ [:& tab-container {:on-change-tab #(st/emit! (dw/go-to-layout %))
+ :selected section
+ :shortcuts? shortcuts?
+ :collapsable? true
+ :handle-collapse handle-collapse}
+ [:& tab-element {:id :layers
+ :title (tr "workspace.sidebar.layers")}
+ [:div {:class (dom/classnames (css :layers-tab) true)}
+ [:& sitemap {:layout layout}]
+ [:& layers-toolbox {:size-parent size}]]]
+
+ (when-not mode-inspect?
+ [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
+ [:& assets-toolbox]])]
+
+ [:*
+ [:button.collapse-sidebar
+ {:on-click handle-collapse
+ :aria-label (tr "workspace.sidebar.collapse")}
+ i/arrow-slide]
+ [:& tab-container {:on-change-tab #(st/emit! (dw/go-to-layout %))
+ :selected section
+ :shortcuts? shortcuts?
+ :collapsable? true
+ :handle-collapse handle-collapse}
+ [:& tab-element {:id :layers
+ :title (tr "workspace.sidebar.layers")}
+ [:div {:class (dom/classnames :layers-tab true)}
+ [:& sitemap {:layout layout}]
+ [:& layers-toolbox {:size-parent size}]]]
+
+ (when-not mode-inspect?
+ [:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
+ [:& assets-toolbox]])]])])]]))
+
+;; --- Right Sidebar (Component)
+
+(mf/defc right-sidebar
+ {::mf/wrap-props false
+ ::mf/wrap [mf/memo]}
+ [props]
+ (let [layout (obj/get props "layout")
+ section (obj/get props "section")
+ drawing-tool (:tool (mf/deref refs/workspace-drawing))
+
+ is-comments? (= drawing-tool :comments)
+ is-history? (contains? layout :document-history)
+ is-inspect? (= section :inspect)
+
+ expanded? (mf/deref refs/inspect-expanded)
+ can-be-expanded? (and
+ (not is-comments?)
+ (not is-history?)
+ is-inspect?)]
+
+ (mf/use-effect
+ (mf/deps can-be-expanded?)
+ (fn []
+ (when (not can-be-expanded?)
+ (st/emit! (dw/set-inspect-expanded false)))))
+
+ [:aside.settings-bar.settings-bar-right {:class (when (and can-be-expanded? expanded?) "expanded")}
+ [:div.settings-bar-inside
+ (cond
+ is-comments?
+ [:& comments-sidebar]
+
+ is-history?
+ [:& history-toolbox]
+
+ :else
+ [:> options-toolbox props])]]))
+
diff --git a/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.css.json b/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.css.json
new file mode 100644
index 000000000..e356bcc16
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.css.json
@@ -0,0 +1 @@
+{"button-primary":"component_sidebar_button-primary_hM5wy","button-secondary":"component_sidebar_button-secondary_XalRe","button-icon":"component_sidebar_button-icon_3XEKH","button-icon-small":"component_sidebar_button-icon-small_iWwQF","left-settings-bar":"component_sidebar_left-settings-bar_eKx6q","resize-area":"component_sidebar_resize-area_1IyNp","settings-bar-inside":"component_sidebar_settings-bar-inside_AaJEH","layers-tab":"component_sidebar_layers-tab_wQLFe"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.scss b/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.scss
new file mode 100644
index 000000000..825fa66b2
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/component/sidebar.scss
@@ -0,0 +1,44 @@
+// 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";
+
+$width-settings-bar: 256px;
+$width-settings-bar-min: 255px;
+$width-settings-bar-max: 500px;
+
+.left-settings-bar {
+ position: relative;
+ grid-area: left-sidebar;
+ min-width: $width-settings-bar;
+ max-width: 500px;
+ width: var(--width, $width-settings-bar);
+ height: 100%;
+ border-radius: $br8;
+ background-color: var(--color-background-primary);
+
+ .resize-area {
+ position: absolute;
+ right: -8px;
+ z-index: $z-index-10;
+ width: $s-8;
+ height: 100%;
+ cursor: ew-resize;
+ }
+ .settings-bar-inside {
+ display: grid;
+ grid-template-columns: 100%;
+ grid-template-rows: 100%;
+ height: calc(100% - 2px);
+ .layers-tab {
+ display: grid;
+ grid-template-rows: auto 1fr;
+ grid-template-columns: 100%;
+ height: 100%;
+ overflow: hidden;
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
deleted file mode 100644
index 39cfc501b..000000000
--- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs
+++ /dev/null
@@ -1,610 +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
-
-(ns app.main.ui.workspace.sidebar.layers
- (:require
- [app.common.data :as d]
- [app.common.data.macros :as dm]
- [app.common.pages.helpers :as cph]
- [app.common.types.shape.layout :as ctl]
- [app.common.uuid :as uuid]
- [app.main.data.workspace :as dw]
- [app.main.data.workspace.collapse :as dwc]
- [app.main.refs :as refs]
- [app.main.store :as st]
- [app.main.ui.components.shape-icon :as si]
- [app.main.ui.context :as ctx]
- [app.main.ui.hooks :as hooks]
- [app.main.ui.icons :as i]
- [app.util.dom :as dom]
- [app.util.i18n :as i18n :refer [tr]]
- [app.util.keyboard :as kbd]
- [app.util.timers :as ts]
- [beicon.core :as rx]
- [cuerdas.core :as str]
- [okulary.core :as l]
- [rumext.v2 :as mf]))
-
-;; --- Layer Name
-
-(def shape-for-rename-ref
- (l/derived (l/in [:workspace-local :shape-for-rename]) st/state))
-
-(mf/defc layer-name
- [{:keys [shape on-start-edit disabled-double-click on-stop-edit name-ref] :as props}]
- (let [local (mf/use-state {})
- shape-for-rename (mf/deref shape-for-rename-ref)
-
- start-edit (fn []
- (when (not disabled-double-click)
- (on-start-edit)
- (swap! local assoc :edition true)))
-
- accept-edit (fn []
- (let [name-input (mf/ref-val name-ref)
- name (dom/get-value name-input)]
- (on-stop-edit)
- (swap! local assoc :edition false)
- (st/emit! (dw/end-rename-shape)
- (when-not (str/empty? (str/trim name))
- (dw/update-shape (:id shape) {:name (str/trim name)})))))
-
- cancel-edit (fn []
- (on-stop-edit)
- (swap! local assoc :edition false)
- (st/emit! (dw/end-rename-shape)))
-
- on-key-down (fn [event]
- (when (kbd/enter? event) (accept-edit))
- (when (kbd/esc? event) (cancel-edit)))]
-
- (mf/with-effect [shape-for-rename]
- (when (and (= shape-for-rename (:id shape))
- (not (:edition @local)))
- (start-edit)))
-
- (mf/with-effect [(:edition @local)]
- (when (:edition @local)
- (let [name-input (mf/ref-val name-ref)]
- (dom/select-text! name-input)
- nil)))
-
- (if (:edition @local)
- [:input.element-name
- {:type "text"
- :ref name-ref
- :on-blur accept-edit
- :on-key-down on-key-down
- :auto-focus true
- :default-value (:name shape "")}]
- [:span.element-name
- {:ref name-ref
- :on-double-click start-edit}
- (:name shape "")
- (when (seq (:touched shape)) " *")])))
-
-(mf/defc layer-item
- [{:keys [index item selected objects sortable? filtered?] :as props}]
- (let [id (:id item)
- blocked? (:blocked item)
- hidden? (:hidden item)
-
- disable-drag (mf/use-state false)
- scroll-to-middle? (mf/use-var true)
- expanded-iref (mf/with-memo [id]
- (-> (l/in [:expanded id])
- (l/derived refs/workspace-local)))
-
- expanded? (mf/deref expanded-iref)
- selected? (contains? selected id)
- container? (or (cph/frame-shape? item)
- (cph/group-shape? item))
- absolute? (ctl/layout-absolute? item)
-
- components-v2 (mf/use-ctx ctx/components-v2)
- workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
- main-instance? (if components-v2
- (:main-instance? item)
- true)
-
- toggle-collapse
- (mf/use-fn
- (mf/deps expanded?)
- (fn [event]
- (dom/stop-propagation event)
- (if (and expanded? (kbd/shift? event))
- (st/emit! (dwc/collapse-all))
- (st/emit! (dwc/toggle-collapse id)))))
-
- toggle-blocking
- (mf/use-fn
- (mf/deps id blocked?)
- (fn [event]
- (dom/stop-propagation event)
- (if blocked?
- (st/emit! (dw/update-shape-flags [id] {:blocked false}))
- (st/emit! (dw/update-shape-flags [id] {:blocked true})
- (dw/deselect-shape id)))))
-
- toggle-visibility
- (mf/use-fn
- (mf/deps hidden?)
- (fn [event]
- (dom/stop-propagation event)
- (if hidden?
- (st/emit! (dw/update-shape-flags [id] {:hidden false}))
- (st/emit! (dw/update-shape-flags [id] {:hidden true})))))
-
- select-shape
- (mf/use-fn
- (mf/deps id filtered? objects)
- (fn [event]
- (dom/prevent-default event)
- (reset! scroll-to-middle? false)
- (cond
- (kbd/shift? event)
- (if filtered?
- (st/emit! (dw/shift-select-shapes id objects))
- (st/emit! (dw/shift-select-shapes id)))
-
- (kbd/mod? event)
- (st/emit! (dw/select-shape id true))
-
- (> (count selected) 1)
- (st/emit! (dw/select-shape id))
-
- :else
- (st/emit! (dw/select-shape id)))))
-
- on-pointer-enter
- (mf/use-fn
- (mf/deps id)
- (fn [_event]
- (st/emit! (dw/highlight-shape id))))
-
- on-pointer-leave
- (mf/use-fn
- (mf/deps id)
- (fn [_event]
- (st/emit! (dw/dehighlight-shape id))))
-
- on-context-menu
- (mf/use-fn
- (mf/deps item workspace-read-only?)
- (fn [event]
- (dom/prevent-default event)
- (dom/stop-propagation event)
- (when-not workspace-read-only?
- (let [pos (dom/get-client-position event)]
- (st/emit! (dw/show-shape-context-menu {:position pos :shape item}))))))
-
- on-drag
- (mf/use-fn
- (mf/deps id selected)
- (fn [{:keys [id]}]
- (when (not (contains? selected id))
- (st/emit! (dw/select-shape id)))))
-
- on-drop
- (mf/use-fn
- (mf/deps id index objects)
- (fn [side _data]
- (if (= side :center)
- (st/emit! (dw/relocate-selected-shapes id 0))
- (let [to-index (if (= side :top) (inc index) index)
- parent-id (cph/get-parent-id objects id)]
- (st/emit! (dw/relocate-selected-shapes parent-id to-index))))))
-
- on-hold
- (mf/use-fn
- (mf/deps id expanded?)
- (fn []
- (when-not expanded?
- (st/emit! (dwc/toggle-collapse id)))))
-
- [dprops dref]
- (hooks/use-sortable
- :data-type "penpot/layer"
- :on-drop on-drop
- :on-drag on-drag
- :on-hold on-hold
- :disabled @disable-drag
- :detect-center? container?
- :data {:id (:id item)
- :index index
- :name (:name item)}
- :draggable? (and sortable? (not workspace-read-only?)))
-
- ref (mf/use-ref)]
-
- (mf/with-effect [selected? selected]
- (let [single? (= (count selected) 1)
- node (mf/ref-val ref)
-
- subid
- (when (and single? selected?)
- (let [scroll-to @scroll-to-middle?]
- (ts/schedule
- 100
- #(if scroll-to
- (dom/scroll-into-view! node #js {:block "center", :behavior "smooth"})
- (do
- (dom/scroll-into-view-if-needed! node #js {:block "center", :behavior "smooth"})
- (reset! scroll-to-middle? true))))))]
-
- #(when (some? subid)
- (rx/dispose! subid))))
-
- [:li {:on-context-menu on-context-menu
- :ref dref
- :class (dom/classnames
- :component (not (nil? (:component-id item)))
- :masked (:masked-group? item)
- :dnd-over (= (:over dprops) :center)
- :dnd-over-top (= (:over dprops) :top)
- :dnd-over-bot (= (:over dprops) :bot)
- :selected selected?
- :type-frame (= :frame (:type item)))}
-
- [:div.element-list-body {:class (dom/classnames :selected selected?
- :icon-layer (= (:type item) :icon))
- :on-click select-shape
- :on-pointer-enter on-pointer-enter
- :on-pointer-leave on-pointer-leave
- :on-double-click #(dom/stop-propagation %)}
- [:div.icon {:on-double-click #(do (dom/stop-propagation %)
- (dom/prevent-default %)
- (st/emit! dw/zoom-to-selected-shape))}
- (when absolute?
- [:div.absolute i/position-absolute])
- [:& si/element-icon {:shape item
- :main-instance? main-instance?}]]
- [:& layer-name {:shape item
- :name-ref ref
- :disabled-double-click workspace-read-only?
- :on-start-edit #(reset! disable-drag true)
- :on-stop-edit #(reset! disable-drag false)}]
-
- [:div.element-actions {:class (when (:shapes item) "is-parent")}
- [:div.toggle-element {:class (when (:hidden item) "selected")
- :on-click toggle-visibility}
- (if (:hidden item) i/eye-closed i/eye)]
- [:div.block-element {:class (when (:blocked item) "selected")
- :on-click toggle-blocking}
- (if (:blocked item) i/lock i/unlock)]]
-
- (when (:shapes item)
- [:span.toggle-content
- {:on-click toggle-collapse
- :class (when expanded? "inverse")}
- i/arrow-slide])]
- (when (and (:shapes item) expanded?)
- [:ul.element-children
- (for [[index id] (reverse (d/enumerate (:shapes item)))]
- (when-let [item (get objects id)]
- [:& layer-item
- {:item item
- :selected selected
- :index index
- :objects objects
- :key (:id item)
- :sortable? sortable?}]))])]))
-
-;; 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)]}
- [props]
- [:> layer-item props])
-
-(mf/defc layers-tree
- {::mf/wrap [#(mf/memo % =)
- #(mf/throttle % 200)]}
- [{:keys [objects filtered?] :as props}]
- (let [selected (mf/deref refs/selected-shapes)
- selected (hooks/use-equal-memo selected)
- root (get objects uuid/zero)]
- [:ul.element-list
- [:& hooks/sortable-container {}
- (for [[index id] (reverse (d/enumerate (:shapes root)))]
- (when-let [obj (get objects id)]
- (if (= (:type obj) :frame)
- [:& frame-wrapper
- {:item obj
- :selected selected
- :index index
- :objects objects
- :key id
- :sortable? true
- :filtered? filtered?}]
- [:& layer-item
- {:item obj
- :selected selected
- :index index
- :objects objects
- :key id
- :sortable? true
- :filtered? filtered?}])))]]))
-
-(mf/defc filters-tree
- {::mf/wrap [#(mf/memo % =)
- #(mf/throttle % 200)]}
- [{:keys [objects] :as props}]
- (let [selected (mf/deref refs/selected-shapes)
- selected (hooks/use-equal-memo selected)
- root (get objects uuid/zero)]
- [:ul.element-list
- (for [[index id] (d/enumerate (:shapes root))]
- (when-let [obj (get objects id)]
- [:& layer-item
- {:item obj
- :selected selected
- :index index
- :objects objects
- :key id
- :sortable? false
- :filtered? true}]))]))
-
-
-(defn calc-reparented-objects
- [objects]
-
- (let [reparented-objects
- (d/mapm (fn [_ val]
- (assoc val :parent-id uuid/zero :shapes nil))
- objects)
-
- reparented-shapes
- (->> reparented-objects
- keys
- (filter #(not= uuid/zero %))
- vec)]
- (update reparented-objects uuid/zero assoc :shapes reparented-shapes)))
-
-;; --- Layers Toolbox
-
-(defn use-search
- [page objects]
- (let [filter-state (mf/use-state {:show-search-box false
- :show-filters-menu false
- :search-text ""
- :active-filters #{}
- :num-items 100})
-
- clear-search-text
- (mf/use-callback
- (fn []
- (swap! filter-state assoc :search-text "" :num-items 100)))
-
- update-search-text
- (mf/use-callback
- (fn [event]
- (let [value (-> event dom/get-target dom/get-value)]
- (swap! filter-state assoc :search-text value :num-items 100))))
-
- toggle-search
- (mf/use-callback
- (fn []
- (swap! filter-state assoc :search-text "")
- (swap! filter-state assoc :active-filters #{})
- (swap! filter-state assoc :show-filters-menu false)
- (swap! filter-state assoc :num-items 100)
- (swap! filter-state update :show-search-box not)))
-
- toggle-filters
- (mf/use-callback
- (fn []
- (swap! filter-state update :show-filters-menu not)))
-
- remove-filter
- (mf/use-callback
- (mf/deps @filter-state)
- (fn [key]
- (fn [_]
- (swap! filter-state update :active-filters disj key)
- (swap! filter-state assoc :num-items 100))))
-
- add-filter
- (mf/use-callback
- (mf/deps @filter-state (:show-filters-menu @filter-state))
- (fn [key]
- (fn [_]
- (swap! filter-state update :active-filters conj key)
- (swap! filter-state assoc :num-items 100)
- (toggle-filters))))
-
- active?
- (and
- (:show-search-box @filter-state)
- (or (d/not-empty? (:search-text @filter-state))
- (d/not-empty? (:active-filters @filter-state))))
-
- search-and-filters
- (fn [[id shape]]
- (let [search (:search-text @filter-state)
- filters (:active-filters @filter-state)
- filters (cond-> filters
- (some #{:shape} filters)
- (conj :rect :circle :path :bool))]
- (or
- (= uuid/zero id)
- (and
- (or (str/includes? (str/lower (:name shape)) (str/lower search))
- (str/includes? (dm/str (:id shape)) (str/lower search)))
- (or
- (empty? filters)
- (and
- (some #{:component} filters)
- (contains? shape :component-id))
- (let [direct_filters (filter #{:frame :rect :circle :path :bool :image :text} filters)]
- (some #{(:type shape)} direct_filters))
- (and
- (some #{:group} filters)
- (and (= :group (:type shape))
- (not (contains? shape :component-id))
- (or (not (contains? shape :masked-group?)) (false? (:masked-group? shape)))))
- (and
- (some #{:mask} filters)
- (true? (:masked-group? shape))))))))
-
- filtered-objects-total
- (mf/use-memo
- (mf/deps objects active? @filter-state)
- #(when active?
- ;; filterv so count is constant time
- (filterv search-and-filters objects)))
-
- filtered-objects
- (mf/use-memo
- (mf/deps filtered-objects-total)
- #(when active?
- (calc-reparented-objects
- (into {}
- (take (:num-items @filter-state))
- filtered-objects-total))))
-
- handle-show-more
- (fn []
- (when (<= (:num-items @filter-state) (count filtered-objects-total))
- (swap! filter-state update :num-items + 100)))
-
- handle-key-down
- (mf/use-callback
- (fn [event]
- (let [enter? (kbd/enter? event)
- esc? (kbd/esc? event)
- input-node (dom/event->target event)]
-
- (when enter?
- (dom/blur! input-node))
- (when esc?
- (dom/blur! input-node)))))]
-
- [filtered-objects
- handle-show-more
-
- (mf/html
- (if (:show-search-box @filter-state)
- [:*
- [:div.tool-window-bar.search
- [:span.search-box
- [:span.filter {:on-click toggle-filters :class (dom/classnames :active active?)} i/icon-filter]
- [:span
- [:input {:on-change update-search-text
- :value (:search-text @filter-state)
- :auto-focus (:show-search-box @filter-state)
- :placeholder (tr "workspace.sidebar.layers.search")
- :on-key-down handle-key-down}]]
- (when (not (= "" (:search-text @filter-state)))
- [:span.clear {:on-click clear-search-text} i/exclude])]
- [:span {:on-click toggle-search} i/cross]]
-
- [:div.active-filters
- (for [f (:active-filters @filter-state)]
- (let [name (case f
- :frame (tr "workspace.sidebar.layers.frames")
- :group (tr "workspace.sidebar.layers.groups")
- :mask (tr "workspace.sidebar.layers.masks")
- :component (tr "workspace.sidebar.layers.components")
- :text (tr "workspace.sidebar.layers.texts")
- :image (tr "workspace.sidebar.layers.images")
- :shape (tr "workspace.sidebar.layers.shapes")
- (tr f))]
- [:span {:on-click (remove-filter f)}
- name i/cross]))]
-
- (when (:show-filters-menu @filter-state)
- [:div.filters-container
- [:span{:on-click (add-filter :frame)} i/artboard (tr "workspace.sidebar.layers.frames")]
- [:span{:on-click (add-filter :group)} i/folder (tr "workspace.sidebar.layers.groups")]
- [:span{:on-click (add-filter :mask)} i/mask (tr "workspace.sidebar.layers.masks")]
- [:span{:on-click (add-filter :component)} i/component (tr "workspace.sidebar.layers.components")]
- [:span{:on-click (add-filter :text)} i/text (tr "workspace.sidebar.layers.texts")]
- [:span{:on-click (add-filter :image)} i/image (tr "workspace.sidebar.layers.images")]
- [:span{:on-click (add-filter :shape)} i/curve (tr "workspace.sidebar.layers.shapes")]])]
-
- [:div.tool-window-bar
- [:span (:name page)]
- [:span {:on-click toggle-search} i/search]]))]))
-
-(mf/defc layers-toolbox
- {:wrap [mf/memo]}
- []
- (let [page (mf/deref refs/workspace-page)
- focus (mf/deref refs/workspace-focus-selected)
- objects (hooks/with-focus-objects (:objects page) focus)
- title (when (= 1 (count focus)) (get-in objects [(first focus) :name]))
-
- observer-var (mf/use-var nil)
- lazy-load-ref (mf/use-ref nil)
-
- [filtered-objects show-more filter-component] (use-search page objects)
-
- intersection-callback
- (fn [entries]
- (when (and (.-isIntersecting (first entries)) (some? show-more))
- (show-more)))
-
- on-render-container
- (fn [element]
- (let [options #js {:root element}
- lazy-el (mf/ref-val lazy-load-ref)]
- (cond
- (and (some? element) (not (some? @observer-var)))
- (let [observer (js/IntersectionObserver. intersection-callback options)]
- (.observe observer lazy-el)
- (reset! observer-var observer))
-
- (and (nil? element) (some? @observer-var))
- (do (.disconnect @observer-var)
- (reset! observer-var nil)))))
-
- on-scroll
- (fn [event]
- (let [target (dom/get-target event)
- target-top (:top (dom/get-bounding-rect target))
- frames (dom/get-elements-by-class "type-frame")
- last-hidden-frame (->> frames
- (filter #(< (- (:top (dom/get-bounding-rect %)) target-top) 0))
- last)]
- (doseq [frame frames]
- (dom/remove-class! frame "sticky"))
-
- (when last-hidden-frame
- (dom/add-class! last-hidden-frame "sticky"))))]
-
- [:div#layers.tool-window
- (if (d/not-empty? focus)
- [:div.tool-window-bar
- [:div.focus-title {:on-click #(st/emit! (dw/toggle-focus-mode))}
- [:button.back-button i/arrow-slide]
- [:div.focus-name (or title (tr "workspace.focus.selection"))]
- [:div.focus-mode (tr "workspace.focus.focus-mode")]]]
- filter-component)
-
- (if (some? filtered-objects)
- [:*
- [:div.tool-window-content {:ref on-render-container :key "filters"}
- [:& filters-tree {:objects filtered-objects
- :key (dm/str (:id page))}]
- [:div.lazy {:ref lazy-load-ref
- :key "lazy-load"
- :style {:min-height 16}}]]
- [:div.tool-window-content {:on-scroll on-scroll
- :style {:display (when (some? filtered-objects) "none")}}
- [:& layers-tree {:objects filtered-objects
- :key (dm/str (:id page))
- :filtered? true}]]]
-
- [:div.tool-window-content {:on-scroll on-scroll
- :style {:display (when (some? filtered-objects) "none")}}
- [:& layers-tree {:objects objects
- :key (dm/str (:id page))
- :filtered? false}]])]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.cljs
new file mode 100644
index 000000000..ac88e5c35
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.cljs
@@ -0,0 +1,346 @@
+;; 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.workspace.sidebar.layers.layer-item.layer-item
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.pages.helpers :as cph]
+ [app.common.types.shape.layout :as ctl]
+ [app.common.uuid :as uuid]
+ [app.main.data.workspace :as dw]
+ [app.main.data.workspace.collapse :as dwc]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.components.shape-icon :as si]
+ [app.main.ui.components.shape-icon-refactor :as sic]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.hooks :as hooks]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.sidebar.layers.layer-name.layer-name :refer [layer-name]]
+ [app.util.dom :as dom]
+ [app.util.keyboard :as kbd]
+ [app.util.timers :as ts]
+ [beicon.core :as rx]
+ [okulary.core :as l]
+ [rumext.v2 :as mf]))
+
+
+(mf/defc layer-item
+ [{:keys [index item selected objects sortable? filtered? recieved-depth parent-size component-child?] :as props}]
+ (let [id (:id item)
+ blocked? (:blocked item)
+ hidden? (:hidden item)
+
+ disable-drag (mf/use-state false)
+ scroll-to-middle? (mf/use-var true)
+ expanded-iref (mf/with-memo [id]
+ (-> (l/in [:expanded id])
+ (l/derived refs/workspace-local)))
+
+ expanded? (mf/deref expanded-iref)
+ selected? (contains? selected id)
+ container? (or (cph/frame-shape? item)
+ (cph/group-shape? item))
+ absolute? (ctl/layout-absolute? item)
+
+ components-v2 (mf/use-ctx ctx/components-v2)
+ workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ main-instance? (if components-v2
+ (:main-instance? item)
+ true)
+ parent-board? (and (= :frame (:type item))
+ (= uuid/zero (:parent-id item)))
+ toggle-collapse
+ (mf/use-fn
+ (mf/deps expanded?)
+ (fn [event]
+ (dom/stop-propagation event)
+ (if (and expanded? (kbd/shift? event))
+ (st/emit! (dwc/collapse-all))
+ (st/emit! (dwc/toggle-collapse id)))))
+
+ toggle-blocking
+ (mf/use-fn
+ (mf/deps id blocked?)
+ (fn [event]
+ (dom/stop-propagation event)
+ (if blocked?
+ (st/emit! (dw/update-shape-flags [id] {:blocked false}))
+ (st/emit! (dw/update-shape-flags [id] {:blocked true})
+ (dw/deselect-shape id)))))
+
+ toggle-visibility
+ (mf/use-fn
+ (mf/deps hidden?)
+ (fn [event]
+ (dom/stop-propagation event)
+ (if hidden?
+ (st/emit! (dw/update-shape-flags [id] {:hidden false}))
+ (st/emit! (dw/update-shape-flags [id] {:hidden true})))))
+
+ select-shape
+ (mf/use-fn
+ (mf/deps id filtered? objects)
+ (fn [event]
+ (dom/prevent-default event)
+ (reset! scroll-to-middle? false)
+ (cond
+ (kbd/shift? event)
+ (if filtered?
+ (st/emit! (dw/shift-select-shapes id objects))
+ (st/emit! (dw/shift-select-shapes id)))
+
+ (kbd/mod? event)
+ (st/emit! (dw/select-shape id true))
+
+ (> (count selected) 1)
+ (st/emit! (dw/select-shape id))
+
+ :else
+ (st/emit! (dw/select-shape id)))))
+
+ on-pointer-enter
+ (mf/use-fn
+ (mf/deps id)
+ (fn [_event]
+ (st/emit! (dw/highlight-shape id))))
+
+ on-pointer-leave
+ (mf/use-fn
+ (mf/deps id)
+ (fn [_event]
+ (st/emit! (dw/dehighlight-shape id))))
+
+ on-context-menu
+ (mf/use-fn
+ (mf/deps item workspace-read-only?)
+ (fn [event]
+ (dom/prevent-default event)
+ (dom/stop-propagation event)
+ (when-not workspace-read-only?
+ (let [pos (dom/get-client-position event)]
+ (st/emit! (dw/show-shape-context-menu {:position pos :shape item}))))))
+
+ on-drag
+ (mf/use-fn
+ (mf/deps id selected)
+ (fn [{:keys [id]}]
+ (when (not (contains? selected id))
+ (st/emit! (dw/select-shape id)))))
+
+ on-drop
+ (mf/use-fn
+ (mf/deps id index objects)
+ (fn [side _data]
+ (if (= side :center)
+ (st/emit! (dw/relocate-selected-shapes id 0))
+ (let [to-index (if (= side :top) (inc index) index)
+ parent-id (cph/get-parent-id objects id)]
+ (st/emit! (dw/relocate-selected-shapes parent-id to-index))))))
+
+ on-hold
+ (mf/use-fn
+ (mf/deps id expanded?)
+ (fn []
+ (when-not expanded?
+ (st/emit! (dwc/toggle-collapse id)))))
+
+ [dprops dref]
+ (hooks/use-sortable
+ :data-type "penpot/layer"
+ :on-drop on-drop
+ :on-drag on-drag
+ :on-hold on-hold
+ :disabled @disable-drag
+ :detect-center? container?
+ :data {:id (:id item)
+ :index index
+ :name (:name item)}
+ :draggable? (and sortable? (not workspace-read-only?)))
+
+ ref (mf/use-ref)
+ depth (+ recieved-depth 1)
+ component-tree? (or component-child? (:component-root? item))]
+
+ (mf/with-effect [selected? selected]
+ (let [single? (= (count selected) 1)
+ node (mf/ref-val ref)
+ parent-node (dom/get-parent (dom/get-parent node))
+
+ subid
+ (when (and single? selected?)
+ (let [scroll-to @scroll-to-middle?]
+ (ts/schedule
+ 100
+ #(if scroll-to
+ (dom/scroll-into-view! parent-node #js {:block "center" :behavior "smooth" :inline "start"})
+ (do
+ (dom/scroll-into-view-if-needed! parent-node #js {:block "center" :behavior "smooth" :inline "start"})
+ (reset! scroll-to-middle? true))))))]
+
+ #(when (some? subid)
+ (rx/dispose! subid))))
+
+ (if new-css-system
+ [:*
+ [:div {:on-context-menu on-context-menu
+ :ref dref
+ :on-click select-shape
+ :id id
+ :class (dom/classnames
+ (css :layer-row) true
+ (css :component) (not (nil? (:component-id item)))
+ (css :masked) (:masked-group? item)
+ (css :selected) selected?
+ (css :type-frame) (= :frame (:type item))
+ (css :type-bool) (= :bool (:type item))
+ (css :type-comp) component-tree?
+ (css :hidden) (:hidden item)
+ :dnd-over (= (:over dprops) :center)
+ :dnd-over-top (= (:over dprops) :top)
+ :dnd-over-bot (= (:over dprops) :bot)
+ :root-board parent-board?)}
+ [:span {:class (dom/classnames (css :tab-indentation) true
+ (css :filtered) filtered?)
+ :style #js {"--depth" depth}}]
+ [:div {:class (dom/classnames (css :element-list-body) true
+ (css :filtered) filtered?
+ (css :selected) selected?
+ (css :icon-layer) (= (:type item) :icon))
+ :style #js {"--depth" depth}
+ :on-pointer-enter on-pointer-enter
+ :on-pointer-leave on-pointer-leave
+ :on-double-click #(dom/stop-propagation %)}
+
+ (if (:shapes item)
+ [:div {:class (dom/classnames (css :button-content) true)}
+ (when (not filtered?)
+ [:button {:class (dom/classnames (css :toggle-content) true
+ (css :inverse) expanded?)
+ :on-click toggle-collapse}
+ i/arrow-refactor])
+
+ [:div {:class (dom/classnames (css :icon-shape) true)
+ :on-double-click #(do (dom/stop-propagation %)
+ (dom/prevent-default %)
+ (st/emit! dw/zoom-to-selected-shape))}
+ (when absolute?
+ [:div {:class (dom/classnames (css :absolute) true)} ])
+ [:& sic/element-icon-refactor {:shape item
+ :main-instance? main-instance?}]]]
+ [:div {:class (dom/classnames (css :button-content) true)}
+ (when (not filtered?)
+ [:span {:class (dom/classnames (css :toggle-content) true)}])
+ [:div {:class (dom/classnames (css :icon-shape) true)
+ :on-double-click #(do (dom/stop-propagation %)
+ (dom/prevent-default %)
+ (st/emit! dw/zoom-to-selected-shape))}
+ (when absolute?
+ [:div {:class (dom/classnames (css :absolute) true)} ])
+ [:& sic/element-icon-refactor {:shape item
+ :main-instance? main-instance?}]]])
+
+ [:& layer-name {:shape item
+ :name-ref ref
+ :disabled-double-click workspace-read-only?
+ :on-start-edit #(reset! disable-drag true)
+ :on-stop-edit #(reset! disable-drag false)
+ :depth depth
+ :parent-size parent-size
+ :selected? selected?
+ :type-comp component-tree?
+ :type-frame (= :frame (:type item))
+ :hidden (:hidden item)}]
+ [:div {:class (dom/classnames (css :element-actions) true
+ (css :is-parent) (:shapes item)
+ (css :selected) (:hidden item)
+ (css :selected) (:blocked item))}
+ [:button {:class (dom/classnames (css :toggle-element) true
+ (css :selected) (:hidden item))
+ :on-click toggle-visibility}
+ (if (:hidden item) i/hide-refactor i/shown-refactor)]
+ [:button {:class (dom/classnames (css :block-element) true
+ (css :selected) (:blocked item))
+ :on-click toggle-blocking}
+ (if (:blocked item) i/lock-refactor i/unlock-refactor)]]]]
+ (when (and (:shapes item) expanded?)
+ [:div {:class (dom/classnames (css :element-children) true
+ (css :parent-selected) selected?
+ :sticky-children parent-board?)
+ :data-id (when parent-board? (:id item))}
+ (for [[index id] (reverse (d/enumerate (:shapes item)))]
+ (when-let [item (get objects id)]
+ [:& layer-item
+ {:item item
+ :selected selected
+ :index index
+ :objects objects
+ :key (:id item)
+ :sortable? sortable?
+ :recieved-depth depth
+ :parent-size parent-size
+ :component-child? component-tree?}]))])]
+ [:li {:on-context-menu on-context-menu
+ :ref dref
+ :class (dom/classnames
+ :component (not (nil? (:component-id item)))
+ :masked (:masked-group? item)
+ :dnd-over (= (:over dprops) :center)
+ :dnd-over-top (= (:over dprops) :top)
+ :dnd-over-bot (= (:over dprops) :bot)
+ :selected selected?
+ :type-frame (= :frame (:type item)))}
+
+ [:div.element-list-body {:class (dom/classnames :selected selected?
+ :icon-layer (= (:type item) :icon))
+ :on-click select-shape
+ :on-pointer-enter on-pointer-enter
+ :on-pointer-leave on-pointer-leave
+ :on-double-click #(dom/stop-propagation %)}
+
+ [:div.icon {:on-double-click #(do (dom/stop-propagation %)
+ (dom/prevent-default %)
+ (st/emit! dw/zoom-to-selected-shape))}
+ (when absolute?
+ [:div.absolute i/position-absolute])
+ [:& si/element-icon {:shape item
+ :main-instance? main-instance?}]]
+ [:& layer-name {:shape item
+ :name-ref ref
+ :disabled-double-click workspace-read-only?
+ :on-start-edit #(reset! disable-drag true)
+ :on-stop-edit #(reset! disable-drag false)
+ :selected? selected?
+ :type-comp component-tree?
+ :type-frame (= :frame (:type item))
+ :hidden (:hidden item)}]
+
+ [:div.element-actions {:class (when (:shapes item) "is-parent")}
+ [:div.toggle-element {:class (when (:hidden item) "selected")
+ :on-click toggle-visibility}
+ (if (:hidden item) i/eye-closed i/eye)]
+ [:div.block-element {:class (when (:blocked item) "selected")
+ :on-click toggle-blocking}
+ (if (:blocked item) i/lock i/unlock)]]
+
+ (when (:shapes item)
+ (when (not filtered?) [:span.toggle-content
+ {:on-click toggle-collapse
+ :class (when expanded? "inverse")}
+ i/arrow-slide]))]
+ (when (and (:shapes item) expanded?)
+ [:ul.element-children
+ (for [[index id] (reverse (d/enumerate (:shapes item)))]
+ (when-let [item (get objects id)]
+ [:& layer-item
+ {:item item
+ :selected selected
+ :index index
+ :objects objects
+ :key (:id item)
+ :sortable? sortable?}]))])])))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.css.json b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.css.json
new file mode 100644
index 000000000..00a701dbe
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.css.json
@@ -0,0 +1 @@
+{"button-primary":"layer_item_layer_item_button-primary_kAdM3","button-secondary":"layer_item_layer_item_button-secondary_8h38L","button-icon":"layer_item_layer_item_button-icon_VcZvz","button-icon-small":"layer_item_layer_item_button-icon-small_T3K6R","layer-row":"layer_item_layer_item_layer-row_w-zf5","element-list-body":"layer_item_layer_item_element-list-body_Re3av","element-actions":"layer_item_layer_item_element-actions_DdAbM","toggle-element":"layer_item_layer_item_toggle-element_r9y4-","block-element":"layer_item_layer_item_block-element_FlRIg","button-content":"layer_item_layer_item_button-content_Yp5xy","icon-shape":"layer_item_layer_item_icon-shape_nfE87","toggle-content":"layer_item_layer_item_toggle-content_6eVXm","filtered":"layer_item_layer_item_filtered_X5Nuq","inverse":"layer_item_layer_item_inverse_7rUY7","absolute":"layer_item_layer_item_absolute_xq8KU","selected":"layer_item_layer_item_selected_AMvUN","element-children":"layer_item_layer_item_element-children_oFioa","parent-selected":"layer_item_layer_item_parent-selected_ANFtr","hidden":"layer_item_layer_item_hidden_wk3Yo","type-comp":"layer_item_layer_item_type-comp_n71sd","tab-indentation":"layer_item_layer_item_tab-indentation_gm6TA"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.scss b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.scss
new file mode 100644
index 000000000..16fc90ca6
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.scss
@@ -0,0 +1,380 @@
+// 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";
+
+.layer-row {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ width: 100%;
+ background-color: var(--layer-row-background-color);
+
+ .element-list-body {
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ width: calc(100% - (var(--depth) * var(--layer-indentation-size)));
+ padding-right: $s-12;
+
+ &.filtered {
+ width: calc(100% - $s-12);
+ }
+ .button-content {
+ display: flex;
+ height: 100%;
+ .toggle-content {
+ @include buttonStyle;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ align-items: center;
+ height: 100%;
+ width: $s-24;
+ padding: 0 4px 0 8px;
+ svg {
+ @extend .button-icon-small;
+ }
+ &.inverse {
+ svg {
+ transform: rotate(90deg);
+ }
+ .icon-shape {
+ transform: rotate(-90deg);
+ }
+ }
+ }
+ .icon-shape {
+ @include flexCenter;
+ @include buttonStyle;
+ position: relative;
+ justify-self: flex-end;
+ width: $s-16;
+ height: 100%;
+ width: $s-24;
+ padding: 0 $s-8 0 $s-4;
+ svg {
+ @extend .button-icon-small;
+ }
+
+ .absolute {
+ position: absolute;
+ background-color: var(--layer-row-foreground-color);
+ opacity: 0.4;
+ width: $s-12;
+ height: $s-12;
+ border-radius: $br2;
+ }
+ }
+ }
+ .element-actions {
+ display: none;
+ height: 100%;
+ .toggle-element,
+ .block-element {
+ @include buttonStyle;
+ @include flexCenter;
+ height: 100%;
+ width: $s-24;
+ margin: 0;
+ display: none;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
+ &.selected {
+ display: flex;
+ .toggle-element,
+ .block-element {
+ display: flex;
+ opacity: 0;
+ &.selected {
+ opacity: 100%;
+ }
+ }
+ }
+ }
+ }
+ .element-children {
+ width: 100%;
+ ul {
+ margin-bottom: 0;
+ }
+ &.parent-selected {
+ .layer-row {
+ background-color: var(--layer-child-row-background-color);
+ }
+ }
+ }
+ &.hidden {
+ .element-list-body {
+ .button-content {
+ .toggle-content {
+ svg {
+ opacity: 0.7;
+ }
+ }
+ .icon-shape {
+ svg {
+ opacity: 0.7;
+ }
+ .absolute {
+ opacity: 0.1;
+ }
+ }
+ }
+ .element-actions {
+ .toggle-element,
+ .block-element {
+ svg {
+ opacity: 0.7;
+ }
+ }
+ }
+ }
+ }
+ &:hover {
+ --context-hover-color: var(--layer-row-foreground-color-hover);
+ --context-hover-opacity: 1;
+ background-color: var(--layer-row-background-color-hover);
+ &.hidden {
+ opacity: 1;
+ }
+ .element-list-body {
+ .button-content {
+ .toggle-content {
+ background-color: var(--layer-row-background-color-hover);
+ svg {
+ opacity: 1;
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ }
+ .icon-shape {
+ opacity: 1;
+ svg {
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ & .absolute {
+ opacity: 0.4;
+ background-color: var(--layer-row-foreground-color-hover);
+ }
+ }
+ }
+ .element-actions {
+ display: flex;
+ .toggle-element,
+ .block-element {
+ display: flex;
+ svg {
+ opacity: 1;
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ }
+ &.selected {
+ .toggle-element,
+ .block-element {
+ opacity: 1;
+ }
+ }
+ }
+ }
+ .element-children {
+ .layer-row {
+ background-color: transparent;
+ color: var(--layer-row-foreground-color-hover);
+ &:hover {
+ background-color: var(--layer-row-background-color-hover);
+ }
+ }
+ }
+ }
+ &.selected {
+ background-color: var(--layer-row-background-color-selected);
+ .element-list-body {
+ .button-content {
+ .toggle-content {
+ background-color: var(--layer-row-background-color-selected);
+ svg {
+ stroke: var(--layer-row-foreground-color-selected);
+ }
+ }
+ .icon-shape {
+ svg {
+ stroke: var(--layer-row-foreground-color-selected);
+ }
+ .absolute {
+ background-color: var(--layer-row-foreground-color-selected);
+ }
+ }
+ }
+ .element-actions {
+ .toggle-element,
+ .block-element {
+ display: flex;
+ svg {
+ stroke: var(--layer-row-foreground-color-selected);
+ }
+ }
+ &.selected {
+ .toggle-element,
+ .block-element {
+ display: flex;
+ opacity: 1;
+ &.selected {
+ opacity: 1;
+ }
+ }
+ }
+ }
+ }
+ .element-children {
+ background-color: transparent;
+ color: var(--layer-row-foreground-color-selected);
+ &:hover {
+ background-color: var(--layer-row-background-color-selected);
+ }
+ }
+ &:hover {
+ background-color: var(--layer-row-background-color-selected);
+ }
+ }
+
+ &.type-comp {
+ .button-content {
+ .toggle-content {
+ svg {
+ stroke: var(--layer-row-component-foreground-color);
+ }
+ }
+ .icon-shape {
+ svg {
+ stroke: var(--layer-row-component-foreground-color);
+ }
+ .absolute {
+ background-color: var(--layer-row-component-foreground-color);
+ }
+ }
+ }
+ .element-actions {
+ .toggle-element,
+ .block-element {
+ svg {
+ stroke: var(--layer-row-component-foreground-color);
+ }
+ }
+ }
+ .element-children {
+ color: var(--layer-row-component-foreground-color);
+ }
+ &.hidden {
+ .element-list-body {
+ .button-content {
+ .toggle-content {
+ opacity: 0.7;
+ }
+ .icon-shape {
+ opacity: 0.7;
+ .absolute {
+ opacity: 0.1;
+ }
+ }
+ }
+ .element-actions {
+ .toggle-element,
+ .block-element {
+ svg {
+ opacity: 0.7;
+ }
+ }
+ }
+ }
+ &:hover {
+ .element-list-body {
+ .button-content {
+ .toggle-content {
+ opacity: 1;
+ }
+ .icon-shape {
+ opacity: 1;
+ & .absolute {
+ opacity: 0.4;
+ }
+ }
+ }
+ .element-actions {
+ .toggle-element,
+ .block-element {
+ svg {
+ opacity: 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ &:global(.sticky) {
+ position: sticky;
+ top: 0px;
+ z-index: 3;
+ }
+}
+.parent-selected .layer-row {
+ background-color: var(--layer-child-row-background-color);
+ &:hover {
+ background-color: var(--layer-row-background-color-hover);
+ &.hidden {
+ opacity: 1;
+ }
+ .element-list-body {
+ .button-content {
+ .toggle-content {
+ background-color: var(--layer-row-background-color-hover);
+ svg {
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ }
+ .icon-shape {
+ svg {
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ .absolute {
+ background-color: var(--layer-row-foreground-color-hover);
+ }
+ }
+ }
+ .element-actions {
+ .toggle-element,
+ .block-element {
+ display: flex;
+ svg {
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ }
+ &.selected {
+ .toggle-element,
+ .block-element {
+ opacity: 100%;
+ }
+ }
+ }
+ }
+ .element-children :global(.layer-row) {
+ background-color: transparent;
+ color: var(--layer-row-foreground-color-hover);
+ &:hover {
+ background-color: var(--layer-row-background-color-hover);
+ }
+ }
+ }
+}
+.tab-indentation {
+ display: block;
+ height: $s-16;
+ min-width: calc(var(--depth) * var(--layer-indentation-size));
+}
+.filtered {
+ min-width: $s-12;
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.cljs
new file mode 100644
index 000000000..67b7ad550
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.cljs
@@ -0,0 +1,86 @@
+;; 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.workspace.sidebar.layers.layer-name.layer-name
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.main.data.workspace :as dw]
+ [app.main.store :as st]
+ [app.main.ui.context :as ctx]
+ [app.util.dom :as dom]
+ [app.util.keyboard :as kbd]
+ [cuerdas.core :as str]
+ [okulary.core :as l]
+ [rumext.v2 :as mf]))
+
+(def shape-for-rename-ref
+ (l/derived (l/in [:workspace-local :shape-for-rename]) st/state))
+(mf/defc layer-name
+ [{:keys [shape on-start-edit disabled-double-click on-stop-edit name-ref depth parent-size selected? type-comp type-frame hidden] :as props}]
+ (let [local (mf/use-state {})
+ shape-for-rename (mf/deref shape-for-rename-ref)
+ new-css-system (mf/use-ctx ctx/new-css-system)
+
+ start-edit (fn []
+ (when (not disabled-double-click)
+ (on-start-edit)
+ (swap! local assoc :edition true)))
+
+ accept-edit (fn []
+ (let [name-input (mf/ref-val name-ref)
+ name (dom/get-value name-input)]
+ (on-stop-edit)
+ (swap! local assoc :edition false)
+ (st/emit! (dw/end-rename-shape)
+ (when-not (str/empty? (str/trim name))
+ (dw/update-shape (:id shape) {:name (str/trim name)})))))
+ cancel-edit (fn []
+ (on-stop-edit)
+ (swap! local assoc :edition false)
+ (st/emit! (dw/end-rename-shape)))
+
+ on-key-down (fn [event]
+ (when (kbd/enter? event) (accept-edit))
+ (when (kbd/esc? event) (cancel-edit)))
+ space-for-icons 110
+ parent-size (str (- parent-size space-for-icons) "px")]
+
+ (mf/with-effect [shape-for-rename]
+ (when (and (= shape-for-rename (:id shape))
+ (not (:edition @local)))
+ (start-edit)))
+
+ (mf/with-effect [(:edition @local)]
+ (when (:edition @local)
+ (let [name-input (mf/ref-val name-ref)]
+ (dom/select-text! name-input)
+ nil)))
+
+ (if (:edition @local)
+ [:input
+ {:class (if new-css-system
+ (dom/classnames (css :element-name-input) true)
+ (dom/classnames :element-name true))
+ :style #js {"--depth" depth "--parent-size" parent-size}
+ :type "text"
+ :ref name-ref
+ :on-blur accept-edit
+ :on-key-down on-key-down
+ :auto-focus true
+ :default-value (:name shape "")}]
+ [:span
+ {:class (if new-css-system
+ (dom/classnames (css :element-name) true
+ (css :selected) selected?
+ (css :hidden) hidden
+ (css :type-comp) type-comp
+ (css :type-frame) type-frame)
+ (dom/classnames :element-name true))
+ :style #js {"--depth" depth "--parent-size" parent-size}
+ :ref name-ref
+ :on-double-click start-edit}
+ (:name shape "")
+ (when (seq (:touched shape)) " *")])))
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.css.json b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.css.json
new file mode 100644
index 000000000..6273495cf
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.css.json
@@ -0,0 +1 @@
+{"button-primary":"layer_name_layer_name_button-primary_44JkR","button-secondary":"layer_name_layer_name_button-secondary_-2vFA","button-icon":"layer_name_layer_name_button-icon_88NHi","button-icon-small":"layer_name_layer_name_button-icon-small_XTt-A","element-name":"layer_name_layer_name_element-name_zNpYC","selected":"layer_name_layer_name_selected_RPmXO","type-comp":"layer_name_layer_name_type-comp_KGgxt","hidden":"layer_name_layer_name_hidden_Ka-JZ","element-name-input":"layer_name_layer_name_element-name-input_59MCD"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.scss b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.scss
new file mode 100644
index 000000000..c07dd9e52
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.scss
@@ -0,0 +1,41 @@
+// 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";
+
+.element-name {
+ @include textEllipsis;
+ @include titleTipography;
+ flex-grow: 1;
+ color: var(--context-hover-color, var(--layer-row-foreground-color));
+ &.selected {
+ color: var(--layer-row-foreground-color-selected);
+ }
+
+ &.type-comp {
+ color: var(--context-hover-color, var(--layer-row-component-foreground-color));
+ &.hidden {
+ opacity: var(--context-hover-opacity, 0.7);
+ }
+ }
+ &.hidden {
+ opacity: var(--context-hover-opacity, 0.7);
+ }
+}
+.element-name-input {
+ @include textEllipsis;
+ @include titleTipography;
+ flex-grow: 1;
+ height: $s-28;
+ max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
+ margin: 0;
+ padding-left: $s-6;
+ border-radius: $br8;
+ border: 1px solid var(--input-border-color-focus);
+ outline: none;
+ background-color: transparent;
+ color: var(--layer-row-foreground-color);
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers/layers.cljs
new file mode 100644
index 000000000..deff4a14e
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layers.cljs
@@ -0,0 +1,531 @@
+;; 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.workspace.sidebar.layers.layers
+ (:require-macros [app.main.style :refer [css]])
+ (:require
+ [app.common.data :as d]
+ [app.common.data.macros :as dm]
+ [app.common.uuid :as uuid]
+ [app.main.data.workspace :as dw]
+ [app.main.refs :as refs]
+ [app.main.store :as st]
+ [app.main.ui.components.shape-icon-refactor :as sic]
+ [app.main.ui.context :as ctx]
+ [app.main.ui.hooks :as hooks]
+ [app.main.ui.icons :as i]
+ [app.main.ui.workspace.sidebar.layers.layer-item.layer-item :refer [layer-item]]
+ [app.util.dom :as dom]
+ [app.util.i18n :as i18n :refer [tr]]
+ [app.util.keyboard :as kbd]
+ [app.util.timers :as ts]
+ [cuerdas.core :as str]
+ [rumext.v2 :as mf]))
+
+
+;; 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)]}
+ [props]
+ [:> layer-item props])
+
+(mf/defc layers-tree
+ {::mf/wrap [#(mf/memo % =)
+ #(mf/throttle % 200)]}
+ [{:keys [objects filtered? parent-size] :as props}]
+ (let [selected (mf/deref refs/selected-shapes)
+ selected (hooks/use-equal-memo selected)
+ root (get objects uuid/zero)
+ new-css-system (mf/use-ctx ctx/new-css-system)]
+ [:ul
+ {:class (if new-css-system
+ (dom/classnames (css :element-list) true)
+ (dom/classnames :element-list true))}
+ [:& hooks/sortable-container {}
+ (for [[index id] (reverse (d/enumerate (:shapes root)))]
+ (when-let [obj (get objects id)]
+ (if (= (:type obj) :frame)
+ [:& frame-wrapper
+ {:item obj
+ :selected selected
+ :index index
+ :objects objects
+ :key id
+ :sortable? true
+ :filtered? filtered?
+ :parent-size parent-size
+ :recieved-depth -1}]
+ [:& layer-item
+ {:item obj
+ :selected selected
+ :index index
+ :objects objects
+ :key id
+ :sortable? true
+ :filtered? filtered?
+ :recieved-depth -1
+ :parent-size parent-size}])))]]))
+
+(mf/defc filters-tree
+ {::mf/wrap [#(mf/memo % =)
+ #(mf/throttle % 200)]}
+ [{:keys [objects parent-size] :as props}]
+ (let [selected (mf/deref refs/selected-shapes)
+ selected (hooks/use-equal-memo selected)
+ root (get objects uuid/zero)
+ new-css-system (mf/use-ctx ctx/new-css-system)]
+ [:ul {:class (if new-css-system
+ (dom/classnames (css :element-list) true)
+ (dom/classnames :element-list true))}
+ (for [[index id] (d/enumerate (:shapes root))]
+ (when-let [obj (get objects id)]
+ [:& layer-item
+ {:item obj
+ :selected selected
+ :index index
+ :objects objects
+ :key id
+ :sortable? false
+ :filtered? true
+ :recieved-depth -1
+ :parent-size parent-size}]))]))
+
+(defn calc-reparented-objects
+ [objects]
+
+ (let [reparented-objects
+ (d/mapm (fn [_ val]
+ (assoc val :parent-id uuid/zero :shapes nil))
+ objects)
+
+ reparented-shapes
+ (->> reparented-objects
+ keys
+ (filter #(not= uuid/zero %))
+ vec)]
+ (update reparented-objects uuid/zero assoc :shapes reparented-shapes)))
+
+;; --- Layers Toolbox
+
+(defn use-search
+ [page objects]
+ (let [filter-state (mf/use-state {:show-search-box false
+ :show-filters-menu false
+ :search-text ""
+ :active-filters #{}
+ :num-items 100})
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ clear-search-text
+ (mf/use-callback
+ (fn []
+ (swap! filter-state assoc :search-text "" :num-items 100)))
+
+ update-search-text
+ (mf/use-callback
+ (fn [event]
+ (let [value (-> event dom/get-target dom/get-value)]
+ (swap! filter-state assoc :search-text value :num-items 100))))
+
+ toggle-search
+ (mf/use-callback
+ (fn []
+ (swap! filter-state assoc :search-text "")
+ (swap! filter-state assoc :active-filters #{})
+ (swap! filter-state assoc :show-filters-menu false)
+ (swap! filter-state assoc :num-items 100)
+ (swap! filter-state update :show-search-box not)))
+
+ toggle-filters
+ (mf/use-callback
+ (fn []
+ (swap! filter-state update :show-filters-menu not)))
+
+ remove-filter
+ (mf/use-callback
+ (mf/deps @filter-state)
+ (fn [key]
+ (fn [_]
+ (swap! filter-state update :active-filters disj key)
+ (swap! filter-state assoc :num-items 100))))
+
+ add-filter
+ (mf/use-callback
+ (mf/deps @filter-state (:show-filters-menu @filter-state))
+ (fn [key]
+ (fn [_]
+ (swap! filter-state update :active-filters conj key)
+ (swap! filter-state assoc :num-items 100)
+ (toggle-filters))))
+
+ active?
+ (and
+ (:show-search-box @filter-state)
+ (or (d/not-empty? (:search-text @filter-state))
+ (d/not-empty? (:active-filters @filter-state))))
+
+ search-and-filters
+ (fn [[id shape]]
+ (let [search (:search-text @filter-state)
+ filters (:active-filters @filter-state)
+ filters (cond-> filters
+ (some #{:shape} filters)
+ (conj :rect :circle :path :bool))]
+ (or
+ (= uuid/zero id)
+ (and
+ (or (str/includes? (str/lower (:name shape)) (str/lower search))
+ (str/includes? (dm/str (:id shape)) (str/lower search)))
+ (or
+ (empty? filters)
+ (and
+ (some #{:component} filters)
+ (contains? shape :component-id))
+ (let [direct_filters (filter #{:frame :rect :circle :path :bool :image :text} filters)]
+ (some #{(:type shape)} direct_filters))
+ (and
+ (some #{:group} filters)
+ (and (= :group (:type shape))
+ (not (contains? shape :component-id))
+ (or (not (contains? shape :masked-group?)) (false? (:masked-group? shape)))))
+ (and
+ (some #{:mask} filters)
+ (true? (:masked-group? shape))))))))
+
+ filtered-objects-total
+ (mf/use-memo
+ (mf/deps objects active? @filter-state)
+ #(when active?
+ ;; filterv so count is constant time
+ (filterv search-and-filters objects)))
+
+ filtered-objects
+ (mf/use-memo
+ (mf/deps filtered-objects-total)
+ #(when active?
+ (calc-reparented-objects
+ (into {}
+ (take (:num-items @filter-state))
+ filtered-objects-total))))
+
+ handle-show-more
+ (fn []
+ (when (<= (:num-items @filter-state) (count filtered-objects-total))
+ (swap! filter-state update :num-items + 100)))
+
+ handle-key-down
+ (mf/use-callback
+ (fn [event]
+ (let [enter? (kbd/enter? event)
+ esc? (kbd/esc? event)
+ input-node (dom/event->target event)]
+
+ (when enter?
+ (dom/blur! input-node))
+ (when esc?
+ (dom/blur! input-node)))))]
+
+ [filtered-objects
+ handle-show-more
+ (mf/html
+ (if (:show-search-box @filter-state)
+ [:*
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tool-window-bar) true
+ (css :search) true)
+ (dom/classnames :tool-window-bar true
+ :search true))}
+ [:span {:class (if new-css-system
+ (dom/classnames (css :search-box) true)
+ (dom/classnames :search-box true))}
+ [:button
+ {:on-click toggle-filters
+ :class (if new-css-system
+ (dom/classnames :active active?
+ (css :filter-button) true)
+ (dom/classnames :active active?
+ :filter true))}
+ (if new-css-system
+ i/filter-refactor
+ i/icon-filter)]
+ [:div {:class (dom/classnames (css :search-input-wrapper) new-css-system)}
+ [:input {:on-change update-search-text
+ :value (:search-text @filter-state)
+ :auto-focus (:show-search-box @filter-state)
+ :placeholder (tr "workspace.sidebar.layers.search")
+ :on-key-down handle-key-down}]
+ (when (not (= "" (:search-text @filter-state)))
+ [:button {:class (if new-css-system
+ (dom/classnames (css :clear) true)
+ (dom/classnames :clear true))
+ :on-click clear-search-text}
+ (if new-css-system
+ i/delete-text-refactor
+ i/exclude)])]]
+ [:button {:class (dom/classnames (css :close-search) new-css-system)
+ :on-click toggle-search}
+ (if new-css-system
+ i/close-refactor
+ i/cross)]]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :active-filters) true)
+ (dom/classnames :active-filters true))}
+ (for [f (:active-filters @filter-state)]
+ (let [name (case f
+ :frame (tr "workspace.sidebar.layers.frames")
+ :group (tr "workspace.sidebar.layers.groups")
+ :mask (tr "workspace.sidebar.layers.masks")
+ :component (tr "workspace.sidebar.layers.components")
+ :text (tr "workspace.sidebar.layers.texts")
+ :image (tr "workspace.sidebar.layers.images")
+ :shape (tr "workspace.sidebar.layers.shapes")
+ (tr f))]
+ (if new-css-system
+ [:button {:class (dom/classnames (css :layer-filter) true)
+ :on-click (remove-filter f)}
+ [:span {:class (dom/classnames (css :layer-filter-icon) true)}
+ [:& sic/element-icon-refactor-by-type {:type f
+ :main-instance? (= f :component)}]]
+ [:span {:class (dom/classnames (css :layer-filter-name) true)}
+ name]
+ [:span {:class (dom/classnames (css :layer-filter-close) true)}
+ i/close-small-refactor]]
+ [:span {:on-click (remove-filter f)}
+ name i/cross]
+ )
+ ))]
+
+ (when (:show-filters-menu @filter-state)
+ (if new-css-system
+ [:ul {:class (dom/classnames (css :filters-container) true)}
+ [:li {:key "frames-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :frame))
+ :on-click (add-filter :frame)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/board-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.frames")]]
+ (when (contains? (:active-filters @filter-state) :frame)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]
+ [:li {:key "groups-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :group))
+ :on-click (add-filter :group)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/group-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.groups")]]
+ (when (contains? (:active-filters @filter-state) :group)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]
+ [:li {:key "masks-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :mask))
+ :on-click (add-filter :mask)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/mask-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.masks")]]
+ (when (contains? (:active-filters @filter-state) :mask)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]
+ [:li {:key "components-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :component))
+ :on-click (add-filter :component)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/component-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.components")]]
+ (when (contains? (:active-filters @filter-state) :component)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]
+ [:li {:key "texts-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :text))
+ :on-click (add-filter :text)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/text-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.texts")]]
+ (when (contains? (:active-filters @filter-state) :text)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]
+ [:li {:key "images-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :image))
+ :on-click (add-filter :image)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/img-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.images")]]
+ (when (contains? (:active-filters @filter-state) :image)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]
+ [:li {:key "shapes-filter-item"
+ :class (dom/classnames (css :filter-menu-item) true
+ (css :selected) (contains? (:active-filters @filter-state) :shape))
+ :on-click (add-filter :shape)}
+ [:div {:class (dom/classnames (css :filter-menu-item-name-wrapper) true)}
+ [:span {:class (dom/classnames (css :filter-menu-item-icon) true)}
+ i/path-refactor]
+ [:span {:class (dom/classnames (css :filter-menu-item-name) true)}
+ (tr "workspace.sidebar.layers.shapes")]]
+ (when (contains? (:active-filters @filter-state) :shape)
+ [:span {:class (dom/classnames (css :filter-menu-item-tick) true)}
+ i/tick-refactor])]]
+
+ [:div.filters-container
+ [:span {:on-click (add-filter :frame)} i/artboard (tr "workspace.sidebar.layers.frames")]
+ [:span {:on-click (add-filter :group)} i/folder (tr "workspace.sidebar.layers.groups")]
+ [:span {:on-click (add-filter :mask)} i/mask (tr "workspace.sidebar.layers.masks")]
+ [:span {:on-click (add-filter :component)} i/component (tr "workspace.sidebar.layers.components")]
+ [:span {:on-click (add-filter :text)} i/text (tr "workspace.sidebar.layers.texts")]
+ [:span {:on-click (add-filter :image)} i/image (tr "workspace.sidebar.layers.images")]
+ [:span {:on-click (add-filter :shape)} i/curve (tr "workspace.sidebar.layers.shapes")]]))]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tool-window-bar) true)
+ (dom/classnames :tool-window-bar true))}
+ [:span {:class (if new-css-system
+ (dom/classnames (css :page-name) true)
+ (dom/classnames :page-name true))}
+ (:name page)]
+ [:button {:class (if new-css-system
+ (dom/classnames (css :icon-search) true)
+ (dom/classnames :icon-search true))
+ :on-click toggle-search}
+ (if new-css-system
+ i/search-refactor
+ i/search)]]))]))
+
+(mf/defc layers-toolbox
+ {:wrap [mf/memo]}
+ [{:keys [size-parent] :as props}]
+ (let [page (mf/deref refs/workspace-page)
+ focus (mf/deref refs/workspace-focus-selected)
+ objects (hooks/with-focus-objects (:objects page) focus)
+ title (when (= 1 (count focus)) (get-in objects [(first focus) :name]))
+ new-css-system (mf/use-ctx ctx/new-css-system)
+ observer-var (mf/use-var nil)
+ lazy-load-ref (mf/use-ref nil)
+
+ [filtered-objects show-more filter-component] (use-search page objects)
+
+ intersection-callback
+ (fn [entries]
+ (when (and (.-isIntersecting (first entries)) (some? show-more))
+ (show-more)))
+
+ on-render-container
+ (fn [element]
+ (let [options #js {:root element}
+ lazy-el (mf/ref-val lazy-load-ref)]
+ (cond
+ (and (some? element) (not (some? @observer-var)))
+ (let [observer (js/IntersectionObserver. intersection-callback options)]
+ (.observe observer lazy-el)
+ (reset! observer-var observer))
+
+ (and (nil? element) (some? @observer-var))
+ (do (.disconnect @observer-var)
+ (reset! observer-var nil)))))
+
+ on-scroll
+ (fn [event]
+ (let [target (dom/get-target event)
+ target-top (:top (dom/get-bounding-rect target))
+ frames (dom/get-elements-by-class "root-board")
+
+ last-hidden-frame (->> frames
+ (filter #(<= (- (:top (dom/get-bounding-rect %)) target-top) 0))
+ last)
+ frame-id (dom/get-attribute last-hidden-frame "id")
+ children (dom/get-elements-by-class "sticky-children")
+ last-hidden-children (->> children
+ (filter #(< (- (:top (dom/get-bounding-rect %)) target-top) 0))
+ last)
+ is-children-shown? (> (- (:bottom (dom/get-bounding-rect last-hidden-children)) target-top) 0)
+
+ children-frame-id (dom/get-attribute last-hidden-children "data-id")
+ ;; We want to check that root-board is out of view but its children are not.
+ ;; only in that case we make root board sticky.
+ sticky? (and last-hidden-frame
+ is-children-shown?
+ (= frame-id children-frame-id))]
+ (doseq [frame frames]
+ (dom/remove-class! frame "sticky"))
+
+ (when sticky?
+ (dom/add-class! last-hidden-frame "sticky"))))]
+ [:div#layers
+ {:class (if new-css-system
+ (dom/classnames (css :layers) true)
+ (dom/classnames :tool-window true))}
+ (if (d/not-empty? focus)
+ [:div
+ {:class (if new-css-system
+ (dom/classnames (css :tool-window-bar) true)
+ (dom/classnames :tool-window-bar true))}
+ [:button {:class (if new-css-system
+ (dom/classnames (css :focus-title) true)
+ (dom/classnames :focus-title true))
+ :on-click #(st/emit! (dw/toggle-focus-mode))}
+ [:span {:class (if new-css-system
+ (dom/classnames (css :back-button) true)
+ (dom/classnames :back-button true))}
+ (if new-css-system
+ i/arrow-refactor
+ i/arrow-slide)]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :focus-name) true)
+ (dom/classnames :focus-name true))}
+ (or title (tr "workspace.sidebar.layers"))]
+ (if new-css-system
+ [:div {:class (dom/classnames (css :focus-mode-tag-wrapper) true)}
+ [:div {:class (dom/classnames (css :focus-mode-tag) true)} (tr "workspace.focus.focus-mode")]]
+ [:div.focus-mode (tr "workspace.focus.focus-mode")])]]
+ filter-component)
+ (if (some? filtered-objects)
+ [:*
+ [:div {:class (if new-css-system
+ (dom/classnames (css :tool-window-content) true)
+ (dom/classnames :tool-window-content true))
+ :ref on-render-container :key "filters"}
+ [:& filters-tree {:objects filtered-objects
+ :key (dm/str (:id page))
+ :parent-size size-parent}]
+ [:div.lazy {:ref lazy-load-ref
+ :key "lazy-load"
+ :style {:min-height 16}}]]
+ [:div {:on-scroll on-scroll
+ :class (if new-css-system
+ (dom/classnames (css :tool-window-content) true)
+ (dom/classnames :tool-window-content true))
+ :style {:display (when (some? filtered-objects) "none")}}
+ [:& layers-tree {:objects filtered-objects
+ :key (dm/str (:id page))
+ :filtered? true
+ :parent-size size-parent}]]]
+ [:div {:on-scroll on-scroll
+ :class (if new-css-system
+ (dom/classnames (css :tool-window-content) true)
+ (dom/classnames :tool-window-content true))
+ :style {:display (when (some? filtered-objects) "none")}}
+ [:& layers-tree {:objects objects
+ :key (dm/str (:id page))
+ :filtered? false
+ :parent-size size-parent}]])]))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layers.css.json b/frontend/src/app/main/ui/workspace/sidebar/layers/layers.css.json
new file mode 100644
index 000000000..4fd8cbda2
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layers.css.json
@@ -0,0 +1 @@
+{"button-primary":"layers_layers_button-primary_kTW1N","layers":"layers_layers_layers_UoyQo","tool-window-bar":"layers_layers_tool-window-bar_wNnsi","search":"layers_layers_search_HR-CX","close-search":"layers_layers_close-search_f0s6R","icon-search":"layers_layers_icon-search_s-Pu5","button-secondary":"layers_layers_button-secondary_Fwe4E","active-filters":"layers_layers_active-filters_zYWOS","layer-filter":"layers_layers_layer-filter_D9YhT","search-box":"layers_layers_search-box_Z1aaC","search-input-wrapper":"layers_layers_search-input-wrapper_e3k9C","clear":"layers_layers_clear_I3ZI3","button-icon":"layers_layers_button-icon_6BwkV","button-icon-small":"layers_layers_button-icon-small_B6dfY","filters-container":"layers_layers_filters-container_Mq4fc","filter-menu-item":"layers_layers_filter-menu-item_NKqSw","filter-menu-item-tick":"layers_layers_filter-menu-item-tick_CpoIk","filter-menu-item-name-wrapper":"layers_layers_filter-menu-item-name-wrapper_e6K3Q","filter-menu-item-icon":"layers_layers_filter-menu-item-icon_K-qNz","layer-filter-icon":"layers_layers_layer-filter-icon_9BZaV","layer-filter-close":"layers_layers_layer-filter-close_TB6GH","focus-title":"layers_layers_focus-title_FpLeI","back-button-icon":"layers_layers_back-button-icon_5LJV1","page-name":"layers_layers_page-name_ojguA","filter-button":"layers_layers_filter-button_036bM","focus-name":"layers_layers_focus-name_v53pl","focus-mode-tag-wrapper":"layers_layers_focus-mode-tag-wrapper_0QsfU","focus-mode-tag":"layers_layers_focus-mode-tag_ZVK1e","layer-filter-name":"layers_layers_layer-filter-name_BboGy","filter-menu-item-name":"layers_layers_filter-menu-item-name_88Gj4","selected":"layers_layers_selected_FQSrA","tool-window-content":"layers_layers_tool-window-content_g-XI4","element-list":"layers_layers_element-list_XKN8R"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers/layers.scss b/frontend/src/app/main/ui/workspace/sidebar/layers/layers.scss
new file mode 100644
index 000000000..dc4f0c0a2
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/layers/layers.scss
@@ -0,0 +1,306 @@
+// 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";
+
+.layers {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+ box-sizing: border-box;
+ .tool-window-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: $s-32;
+ min-height: $s-32;
+ margin-top: $s-8;
+ margin-bottom: $s-4;
+ .page-name {
+ @include tabTitleTipography;
+ padding: 0 $s-12;
+ color: var(--title-foreground-color);
+ }
+ .icon-search {
+ @extend .button-primary;
+ height: $s-24;
+ width: $s-24;
+ border-radius: $br8;
+ margin-right: $s-12;
+ svg {
+ @extend .button-icon-small;
+ margin: 0;
+ }
+ }
+ &.search {
+ padding: 0 $s-12;
+ .search-box {
+ display: grid;
+ grid-template-columns: auto 1fr;
+ gap: $s-2;
+ height: $s-32;
+ width: 100%;
+ margin-right: $s-4;
+ margin-bottom: $s-4;
+ border-radius: $br8;
+ background-color: var(--color-background-primary);
+ .filter-button {
+ @include flexCenter;
+ @include buttonStyle;
+ height: $s-32;
+ width: $s-32;
+ margin: 0;
+ border: 1px solid var(--color-background-tertiary);
+ border-radius: $br8 $br2 $br2 $br8;
+ background-color: var(--color-background-tertiary);
+ svg {
+ height: $s-16;
+ width: $s-16;
+ stroke: var(--icon-foreground);
+ }
+ &:focus {
+ border: 1px solid var(--input-border-color-focus);
+ outline: 0;
+ background-color: var(--input-background-color-active);
+ color: var(--input-foreground-color-active);
+ svg {
+ background-color: var(--input-background-color-active);
+ }
+ }
+ &:hover {
+ border: 1px solid var(--input-background-color-hover);
+ background-color: var(--input-background-color-hover);
+ svg {
+ background-color: var(--input-background-color-hover);
+ stroke: var(--button-foreground-hover);
+ }
+ }
+ }
+ .search-input-wrapper {
+ @include flexCenter;
+ height: $s-32;
+ width: 100%;
+ border: 1px solid var(--color-background-tertiary);
+ border-radius: $br2 $br8 $br8 $br2;
+ background-color: var(--color-background-tertiary);
+ input {
+ width: 100%;
+ margin: $s-8;
+ border: 0;
+ background-color: var(--input-background-color);
+ font-size: $fs-12;
+ color: var(--input-foreground-color);
+ &:focus {
+ outline: none;
+ }
+ }
+ &:hover {
+ border: 1px solid var(--input-background-color-hover);
+ background-color: var(--input-background-color-hover);
+ input {
+ background-color: var(--input-background-color-hover);
+ }
+ }
+ &:focus-within {
+ background-color: var(--input-background-color-active);
+ color: var(--input-foreground-color-active);
+ border: 1px solid var(--input-border-color-focus);
+ input {
+ background-color: var(--input-background-color-active);
+ }
+ }
+
+ .clear {
+ @extend .button-secondary;
+ border-radius: $br8;
+ height: 100%;
+ svg {
+ @extend .button-icon-small;
+ color: transparent;
+ }
+ }
+ }
+ }
+ .close-search {
+ @extend .button-primary;
+ height: $s-32;
+ width: $s-28;
+ margin-bottom: $s-4;
+ border-radius: $br8;
+ svg {
+ @extend .button-icon-small;
+ }
+ }
+ }
+ .focus-title {
+ @include buttonStyle;
+ display: grid;
+ grid-template-columns: auto 1fr auto;
+ width: 100%;
+ padding: 0;
+ .back-button-icon {
+ @include flexCenter;
+ height: $s-32;
+ width: $s-24;
+ padding: 0 $s-4 0 $s-8;
+ svg {
+ @extend .button-icon-small;
+ transform: rotate(180deg);
+ }
+ }
+ .focus-name {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+ height: 100%;
+ padding-left: $s-4;
+ color: var(--title-foreground-color);
+ }
+ .focus-mode-tag-wrapper {
+ @include flexCenter;
+ height: 100%;
+ margin-right: $s-12;
+
+ .focus-mode-tag {
+ @include flexCenter;
+ @include titleTipography;
+ height: $s-20;
+ padding: $s-4 $s-6;
+ border: 1px solid var(--tag-background-color);
+ border-radius: $br6;
+ color: var(--tag-background-color);
+ }
+ }
+ }
+ }
+ .active-filters {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: $s-4;
+ margin: 0 $s-12;
+ .layer-filter {
+ @extend .button-secondary;
+ @include buttonStyle;
+ gap: $s-4;
+ height: $s-24;
+ margin: $s-2 0;
+ border-radius: $br6;
+ background-color: var(--pill-background-color);
+ cursor: pointer;
+ .layer-filter-icon,
+ .layer-filter-close {
+ @extend .button-icon-small;
+ stroke: var(--pill-foreground-color);
+ svg {
+ height: $s-12;
+ }
+ }
+ .layer-filter-name {
+ @include flexCenter;
+ @include buttonSmallTipography;
+ color: var(--pill-foreground-color);
+ }
+ }
+ }
+ .filters-container {
+ position: absolute;
+ top: $s-44;
+ left: $s-12;
+ display: flex;
+ flex-direction: column;
+ gap: $s-4;
+ width: $s-192;
+ padding: $s-4;
+ border-radius: $br8;
+ background-color: var(--menu-background-color);
+ z-index: $z-index-4;
+ box-shadow: 0px 0px 10px 0px var(--menu-shadow-color);
+ .filter-menu-item {
+ @include titleTipography;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: $s-6;
+ border-radius: $br8;
+
+ .filter-menu-item-name-wrapper {
+ display: flex;
+ align-items: center;
+ gap: $s-8;
+ .filter-menu-item-icon {
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ }
+ }
+ .filter-menu-item-name {
+ padding-top: $s-2;
+ color: var(--menu-foreground-color);
+ }
+ }
+ .filter-menu-item-tick {
+ svg {
+ @extend .button-icon-small;
+ stroke: var(--menu-foreground-color);
+ }
+ }
+
+ &.selected {
+ background-color: var(--menu-background-color-selected);
+ .filter-menu-item-name-wrapper {
+ .filter-menu-item-icon {
+ svg {
+ stroke: var(--menu-foreground-color-selected);
+ }
+ }
+ .filter-menu-item-name {
+ color: var(--menu-foreground-color-selected);
+ }
+ }
+ .filter-menu-item-tick {
+ svg {
+ stroke: var(--menu-foreground-color-selected);
+ }
+ }
+ }
+
+ &:hover {
+ background-color: var(--menu-background-color-hover);
+ .filter-menu-item-name-wrapper {
+ .filter-menu-item-icon {
+ svg {
+ stroke: var(--menu-foreground-color-hover);
+ }
+ }
+ .filter-menu-item-name {
+ color: var(--menu-foreground-color-hover);
+ }
+ }
+ .filter-menu-item-tick {
+ svg {
+ stroke: var(--menu-foreground-color-hover);
+ }
+ }
+ }
+ }
+ }
+ .tool-window-content {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+ overflow-y: auto;
+ overflow-x: hidden;
+ scrollbar-gutter: stable;
+ overflow-y: overlay;
+ .element-list {
+ width: 100%;
+ }
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs
index 9c98a763f..efe244bcd 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs
@@ -12,7 +12,7 @@
[app.main.data.workspace :as udw]
[app.main.refs :as refs]
[app.main.store :as st]
- [app.main.ui.components.tab-container :refer [tab-container tab-element]]
+ [app.main.ui.components.tabs-container :refer [tabs-container tabs-element]]
[app.main.ui.context :as ctx]
[app.main.ui.viewer.inspect.right-sidebar :as hrs]
[app.main.ui.workspace.sidebar.options.menus.align :refer [align-options]]
@@ -87,9 +87,9 @@
(st/emit! :interrupt (udw/set-workspace-read-only false))))]
[:div.tool-window
[:div.tool-window-content
- [:& tab-container {:on-change-tab on-change-tab
+ [:& tabs-container {:on-change-tab on-change-tab
:selected section}
- [:& tab-element {:id :design
+ [:& tabs-element {:id :design
:title (tr "workspace.options.design")}
[:div.element-options
[:& align-options]
@@ -115,12 +115,12 @@
:file-id file-id
:shared-libs shared-libs}])]]
- [:& tab-element {:id :prototype
+ [:& tabs-element {:id :prototype
:title (tr "workspace.options.prototype")}
[:div.element-options
[:& interactions-menu {:shape (first shapes)}]]]
- [:& tab-element {:id :inspect
+ [:& tabs-element {:id :inspect
:title (tr "workspace.options.inspect")}
[:div.element-options
[:& hrs/right-sidebar {:page-id page-id
diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
index 72017a3e3..1cbec5117 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs
@@ -213,14 +213,8 @@
[{:keys [content command] :as props}]
(let [managed-list (if (coll? content)
content
- (conj () content))
- split-sc (fn [sc]
- (let [sc (cond-> sc (str/includes? sc "++")
- (str/replace "++" "+plus"))]
- (if (= (count sc) 1)
- [sc]
- (str/split sc #"\+| "))))
- chars-list (map split-sc managed-list)
+ (conj () content))
+ chars-list (map ds/split-sc managed-list)
last-element (last chars-list)
short-char-list (if (= 1 (count chars-list))
chars-list
diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.cljs
similarity index 52%
rename from frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs
rename to frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.cljs
index 50a98a7a1..568277040 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.cljs
@@ -4,7 +4,8 @@
;;
;; Copyright (c) KALEIDOS INC
-(ns app.main.ui.workspace.sidebar.sitemap
+(ns app.main.ui.workspace.sidebar.sitemap.sitemap
+ (:require-macros [app.main.style :refer [css]])
(:require
[app.common.data :as d]
[app.main.data.modal :as modal]
@@ -24,11 +25,10 @@
;; --- Page Item
-(mf/defc page-item
- [{:keys [page index deletable? selected? editing?] :as props}]
+(mf/defc page-item [{:keys [page index deletable? selected? editing?] :as props}]
(let [input-ref (mf/use-ref)
id (:id page)
-
+ new-css-system (mf/use-ctx ctx/new-css-system)
delete-fn (mf/use-callback (mf/deps id) #(st/emit! (dw/delete-page id)))
navigate-fn (mf/use-callback (mf/deps id) #(st/emit! :interrupt (dw/go-to-page id)))
workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
@@ -95,17 +95,17 @@
(dom/stop-propagation event)
(when-not workspace-read-only?
(let [position (dom/get-client-position event)]
- (st/emit! (dw/show-page-item-context-menu
- {:position position
- :page page
+ (st/emit! (dw/show-page-item-context-menu
+ {:position position
+ :page page
:deletable? deletable?}))))))]
(mf/use-effect
- (mf/deps selected?)
- (fn []
- (when selected?
- (let [node (mf/ref-val dref)]
- (dom/scroll-into-view-if-needed! node)))))
+ (mf/deps selected?)
+ (fn []
+ (when selected?
+ (let [node (mf/ref-val dref)]
+ (dom/scroll-into-view-if-needed! node)))))
(mf/use-layout-effect
(mf/deps editing?)
@@ -116,32 +116,62 @@
nil)))
[:*
- [:li {:class (dom/classnames
- :selected selected?
- :dnd-over-top (= (:over dprops) :top)
- :dnd-over-bot (= (:over dprops) :bot))
+ [:li {:class (if new-css-system
+ (dom/classnames
+ (css :page-element) true
+ (css :selected) selected?
+ (css :dnd-over-top) (= (:over dprops) :top)
+ (css :dnd-over-bot) (= (:over dprops) :bot))
+ (dom/classnames
+ :selected selected?
+ :dnd-over-top (= (:over dprops) :top)
+ :dnd-over-bot (= (:over dprops) :bot)))
:ref dref}
- [:div.element-list-body
- {:class (dom/classnames
- :selected selected?)
+ [:div
+ {:class (if new-css-system
+ (dom/classnames
+ (css :element-list-body) true
+ (css :selected) selected?)
+ (dom/classnames
+ :element-list-body true
+ :selected selected?))
+ :tab-index "0"
:on-click navigate-fn
:on-double-click on-double-click
:on-context-menu on-context-menu}
- [:div.page-icon i/file-html]
+ [:div {:class (if new-css-system
+ (dom/classnames (css :page-icon) true)
+ (dom/classnames :page-icon true))}
+ (if new-css-system
+ i/document-refactor
+ i/file-html)]
(if editing?
[:*
- [:input.element-name {:type "text"
- :ref input-ref
- :on-blur on-blur
- :on-key-down on-key-down
- :auto-focus true
- :default-value (:name page "")}]]
+ [:input {:class (if new-css-system
+ (dom/classnames (css :element-name) true)
+ (dom/classnames :element-name true))
+ :type "text"
+ :ref input-ref
+ :on-blur on-blur
+ :on-key-down on-key-down
+ :auto-focus true
+ :default-value (:name page "")}]]
[:*
- [:span (:name page)]
- [:div.page-actions
+ [:span {:class (if new-css-system
+ (dom/classnames (css :page-name) true)
+ (dom/classnames :page-name true))}
+ (:name page)]
+ [:div
+ {:class (if new-css-system
+ (dom/classnames (css :page-actions) true)
+ (dom/classnames :page-actions true))}
(when (and deletable? (not workspace-read-only?))
- [:a {:on-click on-delete} i/trash])]])]]]))
-
+ [:button {:on-click on-delete}
+ (if new-css-system
+ i/delete-refactor
+ i/trash
+ )
+ ])]])]]]))
;; --- Page Item Wrapper
@@ -150,7 +180,7 @@
(l/derived (fn [state]
(let [page (get-in state [:workspace-data :pages-index page-id])]
(select-keys page [:id :name])))
- st/state =))
+ st/state =))
(mf/defc page-item-wrapper
[{:keys [page-id index deletable? selected? editing?] :as props}]
@@ -169,16 +199,20 @@
(let [pages (:pages file)
deletable? (> (count pages) 1)
editing-page-id (mf/deref refs/editing-page-item)
- current-page-id (mf/use-ctx ctx/current-page-id)]
- [:ul.element-list.pages-list
+ current-page-id (mf/use-ctx ctx/current-page-id)
+ new-css-system (mf/use-ctx ctx/new-css-system)]
+ [:ul
+ {:class (if new-css-system
+ (dom/classnames (css :pages-list) true)
+ (dom/classnames :pages-list true))}
[:& hooks/sortable-container {}
(for [[index page-id] (d/enumerate pages)]
[:& page-item-wrapper
{:page-id page-id
:index index
:deletable? deletable?
- :selected? (= page-id current-page-id)
:editing? (= page-id editing-page-id)
+ :selected? (= page-id current-page-id)
:key page-id}])]]))
;; --- Sitemap Toolbox
@@ -195,24 +229,57 @@
(st/emit! (dw/create-page {:file-id (:id file)
:project-id (:project-id file)}))))
show-pages? (mf/use-state true)
- size (if @show-pages? size 38)
+ size (if @show-pages? size 32)
toggle-pages (mf/use-callback #(reset! show-pages? not))
- workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)]
+ workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
+ new-css-system (mf/use-ctx ctx/new-css-system)]
- [:div#sitemap.tool-window {:ref parent-ref
- :style #js {"--height" (str size "px")}}
- [:div.tool-window-bar
- [:span (tr "workspace.sidebar.sitemap")]
- (if workspace-read-only?
- [:div.view-only-mode (tr "labels.view-only")]
- [:div.add-page {:on-click create} i/close])
- [:div.collapse-pages {:on-click toggle-pages
- :style {:transform (when (not @show-pages?) "rotate(-90deg)")}} i/arrow-slide]]
+ (if new-css-system
+ [:div {:class (dom/classnames (css :sitemap) true)
+ :ref parent-ref
+ :style #js {"--height" (str size "px")}}
+ [:div {:class (dom/classnames (css :pages-tool-bar) true)}
- [:div.tool-window-content
- [:& pages-list {:file file :key (:id file)}]]
+ [:button {:class (dom/classnames (css :page-tool-bar-title) true)
+ :on-click toggle-pages}
+ [:span {:class (dom/classnames (css :collapsable-button) true)
+ :style {:transform (when (not @show-pages?) "rotate(-90deg)")}}
+ i/arrow-refactor]
+ (tr "workspace.sidebar.sitemap")]
+ (if workspace-read-only?
+ [:div
+ {:class (dom/classnames (css :view-only-mode) true)}
+ (tr "labels.view-only")]
+ [:*
+ [:button {:class (dom/classnames (css :add-page) true)
+ :on-click create}
+ i/add-refactor]])]
- (when @show-pages?
- [:div.resize-area {:on-pointer-down on-pointer-down
- :on-lost-pointer-capture on-lost-pointer-capture
- :on-pointer-move on-pointer-move}])]))
+ [:div {:class (dom/classnames (css :tool-window-content) true)}
+ [:& pages-list {:file file :key (:id file)}]]
+
+ (when @show-pages?
+ [:div {:class (dom/classnames (css :resize-area) true)
+ :on-pointer-down on-pointer-down
+ :on-lost-pointer-capture on-lost-pointer-capture
+ :on-pointer-move on-pointer-move}])]
+
+
+
+ [:div#sitemap.tool-window {:ref parent-ref
+ :style #js {"--height" (str size "px")}}
+ [:div.tool-window-bar
+ [:span (tr "workspace.sidebar.sitemap")]
+ (if workspace-read-only?
+ [:div.view-only-mode (tr "labels.view-only")]
+ [:div.add-page {:on-click create} i/close])
+ [:div.collapse-pages {:on-click toggle-pages
+ :style {:transform (when (not @show-pages?) "rotate(-90deg)")}} i/arrow-slide]]
+
+ [:div.tool-window-content
+ [:& pages-list {:file file :key (:id file)}]]
+
+ (when @show-pages?
+ [:div.resize-area {:on-pointer-down on-pointer-down
+ :on-lost-pointer-capture on-lost-pointer-capture
+ :on-pointer-move on-pointer-move}])])))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.css.json b/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.css.json
new file mode 100644
index 000000000..9a4d84fc8
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.css.json
@@ -0,0 +1 @@
+{"button-primary":"sitemap_sitemap_button-primary_1gEjD","sitemap":"sitemap_sitemap_sitemap_m6IpN","pages-tool-bar":"sitemap_sitemap_pages-tool-bar_p1-rd","add-page":"sitemap_sitemap_add-page_kW83X","button-secondary":"sitemap_sitemap_button-secondary_7vEHl","button-icon":"sitemap_sitemap_button-icon_Z3FXu","page-tool-bar-title":"sitemap_sitemap_page-tool-bar-title_CnAA4","collapsable-button":"sitemap_sitemap_collapsable-button_4Ro7F","button-icon-small":"sitemap_sitemap_button-icon-small_KzWqW","tool-window-content":"sitemap_sitemap_tool-window-content_nNkLz","pages-list":"sitemap_sitemap_pages-list_DQpTN","page-element":"sitemap_sitemap_page-element_Rmi9A","element-list-body":"sitemap_sitemap_element-list-body_KTWqV","page-actions":"sitemap_sitemap_page-actions_h1mkc","page-icon":"sitemap_sitemap_page-icon_r-7lT","view-only-mode":"sitemap_sitemap_view-only-mode_-cCDa","resize-area":"sitemap_sitemap_resize-area_K6Zed","dnd-over-top":"sitemap_sitemap_dnd-over-top_Ol01I","dnd-over-bot":"sitemap_sitemap_dnd-over-bot_Ovzua","dnd-over":"sitemap_sitemap_dnd-over_AJCMi","page-name":"sitemap_sitemap_page-name_eRLcv","element-name":"sitemap_sitemap_element-name_pP758","on-drag":"sitemap_sitemap_on-drag_ORh57","selected":"sitemap_sitemap_selected_eF0GM","hidden":"sitemap_sitemap_hidden_Iayiv"}
\ No newline at end of file
diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.scss b/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.scss
new file mode 100644
index 000000000..3aafc3f3e
--- /dev/null
+++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.scss
@@ -0,0 +1,260 @@
+// 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";
+
+.sitemap {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ width: 100%;
+ height: var(--height, 200px);
+
+ .pages-tool-bar {
+ display: flex;
+ align-items: center;
+ min-height: $s-32;
+ padding: 0 $s-12 0 0;
+ .page-tool-bar-title {
+ @include flexCenter;
+ @include tabTitleTipography;
+ @include buttonStyle;
+ flex-grow: 1;
+ gap: $s-4;
+ justify-content: flex-start;
+ padding: 0;
+ margin: 0;
+ color: var(--title-foreground-color);
+ .collapsable-button {
+ @include flexCenter;
+ height: $s-24;
+ width: $s-24;
+ padding: 0 $s-4 0 $s-8;
+ border-radius: $br8;
+ svg {
+ @extend .button-icon;
+ height: $s-12;
+ width: $s-12;
+ transform: rotate(90deg);
+ }
+ }
+ &:hover {
+ color: var(--title-foreground-color-hover);
+ svg {
+ stroke: var(--icon-foreground-hover);
+ }
+ }
+ }
+ .add-page {
+ @extend .button-primary;
+ height: $s-24;
+ width: $s-24;
+ border-radius: $br8;
+ svg {
+ @extend .button-icon;
+ height: $s-12;
+ width: $s-12;
+ transform: rotate(90deg);
+ }
+ }
+ .view-only-mode {
+ @include flexCenter;
+ @include titleTipography;
+ height: $s-20;
+ padding: $s-4 $s-6;
+ border: 1px solid var(--tag-background-color);
+ border-radius: $br6;
+ color: var(--tag-background-color);
+ }
+ }
+ .resize-area {
+ position: absolute;
+ bottom: -8px;
+ left: 0;
+ width: 100%;
+ height: $s-12;
+ border-top: 2px solid var(--color-background-secondary);
+ background-color: var(--color-background-primary);
+ cursor: ns-resize;
+ &:hover {
+ border-color: var(--color-background-quaternary);
+ }
+ }
+ .tool-window-content {
+ display: flex;
+ flex-direction: column;
+ overflow-y: auto;
+ overflow-x: hidden;
+ scrollbar-gutter: stable;
+ overflow-y: overlay;
+ height: 100%;
+ width: 100%;
+
+ .pages-list {
+ width: 100%;
+ max-height: $s-152;
+ margin-bottom: $s-12;
+ .page-element {
+ @include titleTipography;
+ min-height: $s-32;
+ width: 100%;
+ cursor: pointer;
+ &.dnd-over-top {
+ border-top: 1px solid var(--layer-row-foreground-color-drag);
+ }
+ &.dnd-over-bot {
+ border-bottom: 1px solid var(--layer-row-foreground-color-drag);
+ }
+ .dnd-over > .element-list-body {
+ border: 1px solid var(--layer-row-foreground-color-drag);
+ }
+ .element-list-body {
+ display: flex;
+ align-items: center;
+ height: $s-32;
+ width: 100%;
+ padding: 0 $s-12 0 0;
+ transition: none;
+ color: var(--layer-row-foreground-color);
+ .page-name {
+ flex-grow: 1;
+ padding-left: $s-2;
+ }
+ .page-icon {
+ @include flexCenter;
+ height: $s-32;
+ width: $s-24;
+ padding: 0 $s-4 0 $s-8;
+ svg {
+ @extend .button-icon-small;
+ height: $s-12;
+ width: $s-12;
+ color: transparent;
+ fill: none;
+ stroke: var(--icon-foreground);
+ }
+ }
+ .page-actions {
+ height: $s-32;
+ button {
+ @include buttonStyle;
+ @include flexCenter;
+ width: $s-24;
+ height: 100%;
+ opacity: 0;
+ svg {
+ @extend .button-icon-small;
+ height: $s-12;
+ width: $s-12;
+ color: transparent;
+ fill: none;
+ stroke: var(--icon-foreground);
+ }
+ }
+ }
+ .element-name {
+ @include textEllipsis;
+ color: var(--color-foreground-primary);
+ }
+ input.element-name {
+ @include textEllipsis;
+ @include titleTipography;
+ flex-grow: 1;
+ height: $s-28;
+ max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
+ margin: 0;
+ padding-left: $s-6;
+ border-radius: $br8;
+ border: 1px solid var(--input-border-color-focus);
+ outline: none;
+ background-color: transparent;
+ color: var(--layer-row-foreground-color);
+ }
+ }
+ &:active,
+ &.on-drag {
+ .element-list-body {
+ color: var(--layer-row-foreground-color-drag);
+ background-color: var(--layer-row-background-color-drag);
+ .page-actions button {
+ svg {
+ stroke: var(--layer-row-foreground-color-drag);
+ }
+ }
+ .page-icon svg {
+ stroke: var(--layer-row-foreground-color-drag);
+ }
+ }
+ }
+ &.selected,
+ &.selected:hover {
+ .element-list-body {
+ color: var(--layer-row-foreground-color-selected);
+ background-color: var(--layer-row-background-color-selected);
+ .page-actions button {
+ svg {
+ stroke: var(--layer-row-foreground-color-selected);
+ }
+ }
+ .page-icon svg {
+ stroke: var(--layer-row-foreground-color-selected);
+ }
+ }
+ }
+ &:hover {
+ .element-list-body {
+ color: var(--layer-row-foreground-color-hover);
+ background-color: var(--layer-row-background-color-hover);
+ .page-actions button {
+ opacity: 1;
+ svg {
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ }
+ .page-icon svg {
+ stroke: var(--layer-row-foreground-color-hover);
+ }
+ }
+ }
+ &:focus {
+ .element-list-body {
+ color: var(--layer-row-foreground-color-focus);
+ border: 1px solid var(--layer-row-border-color-focus);
+ outline: none;
+ .page-actions button {
+ opacity: 1;
+ }
+ }
+ }
+ &:focus-within {
+ .element-list-body {
+ outline: none;
+ .page-actions button {
+ opacity: 1;
+ }
+ }
+ }
+
+ &.hidden {
+ .element-list-body {
+ color: var(--layer-row-foreground-color-hidden);
+ background-color: var(--layer-row-background-color-hidden);
+ opacity: 70%;
+ .page-actions button {
+ svg {
+ stroke: var(--layer-row-foreground-color-hidden);
+ }
+ }
+ .page-icon svg {
+ stroke: var(--layer-row-foreground-color-hidden);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/frontend/src/features.cljs b/frontend/src/features.cljs
index a0f6cdd76..c129ae84e 100644
--- a/frontend/src/features.cljs
+++ b/frontend/src/features.cljs
@@ -16,3 +16,6 @@
(defn ^:export is-components-v2 []
(let [active? (features/active-feature :components-v2)]
@active?))
+
+(defn ^:export new-css-system []
+ (features/toggle-feature! :new-css-system))
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index dd0a773d4..6b3b15d8d 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -1551,7 +1551,7 @@ msgid "labels.uploading"
msgstr "Uploading…"
msgid "labels.view-only"
-msgstr "VIEW ONLY"
+msgstr "View only"
#: src/app/main/ui/dashboard/team.cljs
msgid "labels.viewer"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index 910d72438..cf4006f53 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -1606,7 +1606,7 @@ msgid "labels.uploading"
msgstr "Subiendo…"
msgid "labels.view-only"
-msgstr "SOLO LECTURA"
+msgstr "Solo lectura"
#: src/app/main/ui/dashboard/team.cljs
msgid "labels.viewer"