From 86b0e95458510d8f1c74f20fdcc6d2bba3e3317e Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 15 Mar 2023 18:02:57 +0100 Subject: [PATCH] :sparkles:Add new layers panel UI design --- frontend/gulpfile.js | 8 +- frontend/package.json | 2 +- .../resources/images/icons/add-refactor.svg | 3 + .../images/icons/align-bottom-refactor.svg | 3 + .../icons/align-content-center-refactor.svg | 3 + .../icons/align-content-end-refactor.svg | 3 + .../align-content-space-around-refactor.svg | 3 + .../align-content-space-between-refactor.svg | 3 + .../align-content-space-evenly-refactor.svg | 3 + .../icons/align-content-start-refactor.svg | 3 + .../align-horizontal-center-refactor.svg | 3 + .../icons/align-items-center-refactor.svg | 3 + .../images/icons/align-items-end-refactor.svg | 3 + .../icons/align-items-start-refactor.svg | 3 + .../images/icons/align-items-start.svg | 3 + .../images/icons/align-left-refactor.svg | 3 + .../images/icons/align-right-refactor.svg | 3 + .../images/icons/align-top-refactor.svg | 3 + .../icons/align-vertical-center-refactor.svg | 3 + .../resources/images/icons/arrow-refactor.svg | 3 + .../resources/images/icons/board-refactor.svg | 3 + .../icons/boards-thumbnail-refactor.svg | 3 + .../icons/boolean-difference-refactor.svg | 3 + .../images/icons/boolean-exclude-refactor.svg | 3 + .../images/icons/boolean-flatten-refactor.svg | 3 + .../icons/boolean-intersection-refactor.svg | 3 + .../images/icons/boolean-union-refactor.svg | 3 + .../resources/images/icons/close-refactor.svg | 3 + .../images/icons/close-small-refactor.svg | 3 + .../images/icons/column-refactor.svg | 1 + .../images/icons/column-reverse-refactor.svg | 3 + .../images/icons/component-refactor.svg | 3 + .../icons/constraint-horizontal-refactor.svg | 3 + .../icons/constraint-vertical-refactor.svg | 3 + .../resources/images/icons/copy-refactor.svg | 3 + .../images/icons/corner-radius-refactor.svg | 3 + .../resources/images/icons/curve-refactor.svg | 3 + .../images/icons/delete-refactor.svg | 3 + .../images/icons/delete-text-refactor.svg | 3 + .../distribute-vertical-spacing-refactor.svg | 3 + .../images/icons/document-refactor.svg | 3 + .../images/icons/effects-refactor.svg | 3 + .../images/icons/elipse-refactor.svg | 3 + .../images/icons/filter-refactor.svg | 3 + .../images/icons/flex-grid-refactor.svg | 3 + .../images/icons/flex-horizontal-refactor.svg | 3 + .../resources/images/icons/flex-refactor.svg | 3 + .../images/icons/flex-vertical-refactor.svg | 3 + .../images/icons/flip-horizontal-refactor.svg | 3 + .../images/icons/flip-vertical-refactor.svg | 3 + .../images/icons/grid-column-refactor.svg | 3 + .../images/icons/grid-columns-refactor.svg | 3 + .../images/icons/grid-gutter-refactor.svg | 3 + .../images/icons/grid-margin-refactor.svg | 3 + .../resources/images/icons/grid-refactor.svg | 3 + .../images/icons/grid-row-refactor.svg | 3 + .../images/icons/grid-rows-refactor.svg | 3 + .../images/icons/grid-square-refactor.svg | 3 + .../resources/images/icons/group-refactor.svg | 3 + .../icons/gutter-horizontal-refactor.svg | 3 + .../images/icons/gutter-vertical-refactor.svg | 3 + .../resources/images/icons/hide-refactor.svg | 3 + .../resources/images/icons/icon-refactor.svg | 3 + .../resources/images/icons/img-refactor.svg | 3 + .../icons/justify-content-center-refactor.svg | 3 + .../icons/justify-content-end-refactor.svg | 3 + .../justify-content-space-around-refactor.svg | 3 + ...justify-content-space-between-refactor.svg | 3 + .../justify-content-space-evenly-refactor.svg | 3 + .../icons/justify-content-start-refactor.svg | 3 + .../resources/images/icons/lock-refactor.svg | 3 + .../images/icons/margin-bottom-refactor.svg | 3 + .../images/icons/margin-left-refactor.svg | 3 + .../icons/margin-left-right-refactor.svg | 3 + .../images/icons/margin-right-refactor.svg | 3 + .../icons/margin-top-bottom-refactor.svg | 3 + .../images/icons/margin-top-refactor.svg | 3 + .../resources/images/icons/mask-refactor.svg | 3 + .../images/icons/masked-refactor.svg | 3 + .../resources/images/icons/menu-refactor.svg | 3 + .../resources/images/icons/move-refactor.svg | 3 + .../images/icons/padding-bottom-refactor.svg | 3 + .../icons/padding-extended-refactor.svg | 3 + .../images/icons/padding-left-refactor.svg | 3 + .../icons/padding-left-right-refactor.svg | 3 + .../images/icons/padding-right-refactor.svg | 3 + .../icons/padding-top-bottom-refactor.svg | 3 + .../images/icons/padding-top-refactor.svg | 3 + .../resources/images/icons/path-refactor.svg | 3 + .../images/icons/pentool-refactor.svg | 3 + .../images/icons/rectangle-refactor.svg | 3 + .../images/icons/remove-refactor.svg | 3 + .../images/icons/rotation-refactor.svg | 3 + .../resources/images/icons/row-refactor.svg | 1 + .../images/icons/row-reverse-refactor.svg | 3 + .../images/icons/search-refactor.svg | 3 + .../resources/images/icons/shown-refactor.svg | 3 + .../images/icons/size-horizontal-refactor.svg | 3 + .../images/icons/size-vertical-refactor.svg | 3 + .../images/icons/stroke-size-refactor.svg | 3 + .../images/icons/swatches-refactor.svg | 3 + .../images/icons/text-Paragraph-refactor.svg | 3 + .../icons/text-align-center-refactor.svg | 3 + .../images/icons/text-align-left-refactor.svg | 3 + .../icons/text-align-right-refactor.svg | 3 + .../icons/text-auto-height-refactor.svg | 3 + .../images/icons/text-auto-width-refactor.svg | 3 + .../resources/images/icons/text-refactor.svg | 3 + .../images/icons/thumbnail-refactor.svg | 3 + .../resources/images/icons/tick-refactor.svg | 3 + .../images/icons/unlock-refactor.svg | 3 + .../vertical-align-items-center-refactor.svg | 3 + .../vertical-align-items-end-refactor.svg | 3 + .../vertical-align-items-start-refactor.svg | 3 + .../images/icons/view-as-icons-refactor.svg | 3 + .../resources/images/icons/wrap-refactor.svg | 3 + .../styles/common/refactor/basic-rules.scss | 64 ++ .../styles/common/refactor/borders.scss | 8 +- .../styles/common/refactor/color-defs.scss | 8 +- .../common/refactor/common-refactor.scss | 37 ++ .../styles/common/refactor/design-tokens.scss | 71 +- .../styles/common/refactor/fonts.scss | 3 + .../styles/common/refactor/mixins.scss | 46 ++ .../styles/common/refactor/spacing.scss | 55 +- .../common/refactor/themes/default-theme.scss | 9 +- .../common/refactor/themes/light-theme.scss | 9 +- .../styles/common/refactor/z-index.scss | 11 + frontend/resources/styles/main-default.scss | 22 +- .../styles/main/partials/dashboard-fonts.scss | 2 +- .../styles/main/partials/dashboard-grid.scss | 2 +- .../main/partials/debug-icons-preview.scss | 6 + .../partials/sidebar-element-options.scss | 12 +- .../styles/main/partials/sidebar-layers.scss | 8 +- .../styles/main/partials/sidebar-sitemap.scss | 12 +- .../styles/main/partials/sidebar.scss | 9 +- frontend/src/app/main/data/shortcuts.cljs | 23 +- frontend/src/app/main/data/workspace.cljs | 1 + frontend/src/app/main/features.cljs | 3 +- frontend/src/app/main/style.clj | 10 + frontend/src/app/main/ui.cljs | 6 + .../context_menu_a11y.cljs | 192 +++--- .../context_menu_a11y.css.json | 1 + .../context_menu_a11y/context_menu_a11y.scss | 127 ++++ .../ui/components/shape_icon_refactor.cljs | 63 ++ .../tab_container/tab_container.cljs | 89 +++ .../tab_container/tab_container.css.json | 1 + .../tab_container/tab_container.scss | 89 +++ ...tab_container.cljs => tabs_container.cljs} | 6 +- .../ui/components/tests/test_component.cljs | 23 + .../components/tests/test_component.css.json | 1 + .../ui/components/tests/test_component.scss | 4 + frontend/src/app/main/ui/context.cljs | 1 + .../src/app/main/ui/dashboard/file_menu.cljs | 5 +- .../app/main/ui/dashboard/project_menu.cljs | 5 +- .../app/main/ui/debug/components_preview.cljs | 60 ++ .../main/ui/debug/components_preview.css.json | 1 + .../app/main/ui/debug/components_preview.scss | 85 +++ frontend/src/app/main/ui/icons.cljs | 36 ++ frontend/src/app/main/ui/routes.cljs | 2 + .../src/app/main/ui/settings/options.cljs | 4 +- .../main/ui/viewer/inspect/left_sidebar.cljs | 12 +- .../main/ui/viewer/inspect/right_sidebar.cljs | 8 +- frontend/src/app/main/ui/workspace.cljs | 19 +- .../{ => context_menu}/context_menu.cljs | 148 +++-- .../context_menu/context_menu.css.json | 1 + .../workspace/context_menu/context_menu.scss | 112 ++++ .../src/app/main/ui/workspace/sidebar.cljs | 121 ---- .../collapsable_button.cljs | 33 + .../collapsable_button.css.json | 1 + .../collapsable_button.scss | 44 ++ .../workspace/sidebar/component/sidebar.cljs | 151 +++++ .../sidebar/component/sidebar.css.json | 1 + .../workspace/sidebar/component/sidebar.scss | 44 ++ .../app/main/ui/workspace/sidebar/layers.cljs | 610 ------------------ .../sidebar/layers/layer_item/layer_item.cljs | 346 ++++++++++ .../layers/layer_item/layer_item.css.json | 1 + .../sidebar/layers/layer_item/layer_item.scss | 380 +++++++++++ .../sidebar/layers/layer_name/layer_name.cljs | 86 +++ .../layers/layer_name/layer_name.css.json | 1 + .../sidebar/layers/layer_name/layer_name.scss | 41 ++ .../ui/workspace/sidebar/layers/layers.cljs | 531 +++++++++++++++ .../workspace/sidebar/layers/layers.css.json | 1 + .../ui/workspace/sidebar/layers/layers.scss | 306 +++++++++ .../main/ui/workspace/sidebar/options.cljs | 10 +- .../main/ui/workspace/sidebar/shortcuts.cljs | 10 +- .../sidebar/{ => sitemap}/sitemap.cljs | 169 +++-- .../sidebar/sitemap/sitemap.css.json | 1 + .../ui/workspace/sidebar/sitemap/sitemap.scss | 260 ++++++++ frontend/src/features.cljs | 3 + frontend/translations/en.po | 2 +- frontend/translations/es.po | 2 +- 191 files changed, 3998 insertions(+), 1037 deletions(-) create mode 100644 frontend/resources/images/icons/add-refactor.svg create mode 100644 frontend/resources/images/icons/align-bottom-refactor.svg create mode 100644 frontend/resources/images/icons/align-content-center-refactor.svg create mode 100644 frontend/resources/images/icons/align-content-end-refactor.svg create mode 100644 frontend/resources/images/icons/align-content-space-around-refactor.svg create mode 100644 frontend/resources/images/icons/align-content-space-between-refactor.svg create mode 100644 frontend/resources/images/icons/align-content-space-evenly-refactor.svg create mode 100644 frontend/resources/images/icons/align-content-start-refactor.svg create mode 100644 frontend/resources/images/icons/align-horizontal-center-refactor.svg create mode 100644 frontend/resources/images/icons/align-items-center-refactor.svg create mode 100644 frontend/resources/images/icons/align-items-end-refactor.svg create mode 100644 frontend/resources/images/icons/align-items-start-refactor.svg create mode 100644 frontend/resources/images/icons/align-items-start.svg create mode 100644 frontend/resources/images/icons/align-left-refactor.svg create mode 100644 frontend/resources/images/icons/align-right-refactor.svg create mode 100644 frontend/resources/images/icons/align-top-refactor.svg create mode 100644 frontend/resources/images/icons/align-vertical-center-refactor.svg create mode 100644 frontend/resources/images/icons/arrow-refactor.svg create mode 100644 frontend/resources/images/icons/board-refactor.svg create mode 100644 frontend/resources/images/icons/boards-thumbnail-refactor.svg create mode 100644 frontend/resources/images/icons/boolean-difference-refactor.svg create mode 100644 frontend/resources/images/icons/boolean-exclude-refactor.svg create mode 100644 frontend/resources/images/icons/boolean-flatten-refactor.svg create mode 100644 frontend/resources/images/icons/boolean-intersection-refactor.svg create mode 100644 frontend/resources/images/icons/boolean-union-refactor.svg create mode 100644 frontend/resources/images/icons/close-refactor.svg create mode 100644 frontend/resources/images/icons/close-small-refactor.svg create mode 100644 frontend/resources/images/icons/column-refactor.svg create mode 100644 frontend/resources/images/icons/column-reverse-refactor.svg create mode 100644 frontend/resources/images/icons/component-refactor.svg create mode 100644 frontend/resources/images/icons/constraint-horizontal-refactor.svg create mode 100644 frontend/resources/images/icons/constraint-vertical-refactor.svg create mode 100644 frontend/resources/images/icons/copy-refactor.svg create mode 100644 frontend/resources/images/icons/corner-radius-refactor.svg create mode 100644 frontend/resources/images/icons/curve-refactor.svg create mode 100644 frontend/resources/images/icons/delete-refactor.svg create mode 100644 frontend/resources/images/icons/delete-text-refactor.svg create mode 100644 frontend/resources/images/icons/distribute-vertical-spacing-refactor.svg create mode 100644 frontend/resources/images/icons/document-refactor.svg create mode 100644 frontend/resources/images/icons/effects-refactor.svg create mode 100644 frontend/resources/images/icons/elipse-refactor.svg create mode 100644 frontend/resources/images/icons/filter-refactor.svg create mode 100644 frontend/resources/images/icons/flex-grid-refactor.svg create mode 100644 frontend/resources/images/icons/flex-horizontal-refactor.svg create mode 100644 frontend/resources/images/icons/flex-refactor.svg create mode 100644 frontend/resources/images/icons/flex-vertical-refactor.svg create mode 100644 frontend/resources/images/icons/flip-horizontal-refactor.svg create mode 100644 frontend/resources/images/icons/flip-vertical-refactor.svg create mode 100644 frontend/resources/images/icons/grid-column-refactor.svg create mode 100644 frontend/resources/images/icons/grid-columns-refactor.svg create mode 100644 frontend/resources/images/icons/grid-gutter-refactor.svg create mode 100644 frontend/resources/images/icons/grid-margin-refactor.svg create mode 100644 frontend/resources/images/icons/grid-refactor.svg create mode 100644 frontend/resources/images/icons/grid-row-refactor.svg create mode 100644 frontend/resources/images/icons/grid-rows-refactor.svg create mode 100644 frontend/resources/images/icons/grid-square-refactor.svg create mode 100644 frontend/resources/images/icons/group-refactor.svg create mode 100644 frontend/resources/images/icons/gutter-horizontal-refactor.svg create mode 100644 frontend/resources/images/icons/gutter-vertical-refactor.svg create mode 100644 frontend/resources/images/icons/hide-refactor.svg create mode 100644 frontend/resources/images/icons/icon-refactor.svg create mode 100644 frontend/resources/images/icons/img-refactor.svg create mode 100644 frontend/resources/images/icons/justify-content-center-refactor.svg create mode 100644 frontend/resources/images/icons/justify-content-end-refactor.svg create mode 100644 frontend/resources/images/icons/justify-content-space-around-refactor.svg create mode 100644 frontend/resources/images/icons/justify-content-space-between-refactor.svg create mode 100644 frontend/resources/images/icons/justify-content-space-evenly-refactor.svg create mode 100644 frontend/resources/images/icons/justify-content-start-refactor.svg create mode 100644 frontend/resources/images/icons/lock-refactor.svg create mode 100644 frontend/resources/images/icons/margin-bottom-refactor.svg create mode 100644 frontend/resources/images/icons/margin-left-refactor.svg create mode 100644 frontend/resources/images/icons/margin-left-right-refactor.svg create mode 100644 frontend/resources/images/icons/margin-right-refactor.svg create mode 100644 frontend/resources/images/icons/margin-top-bottom-refactor.svg create mode 100644 frontend/resources/images/icons/margin-top-refactor.svg create mode 100644 frontend/resources/images/icons/mask-refactor.svg create mode 100644 frontend/resources/images/icons/masked-refactor.svg create mode 100644 frontend/resources/images/icons/menu-refactor.svg create mode 100644 frontend/resources/images/icons/move-refactor.svg create mode 100644 frontend/resources/images/icons/padding-bottom-refactor.svg create mode 100644 frontend/resources/images/icons/padding-extended-refactor.svg create mode 100644 frontend/resources/images/icons/padding-left-refactor.svg create mode 100644 frontend/resources/images/icons/padding-left-right-refactor.svg create mode 100644 frontend/resources/images/icons/padding-right-refactor.svg create mode 100644 frontend/resources/images/icons/padding-top-bottom-refactor.svg create mode 100644 frontend/resources/images/icons/padding-top-refactor.svg create mode 100644 frontend/resources/images/icons/path-refactor.svg create mode 100644 frontend/resources/images/icons/pentool-refactor.svg create mode 100644 frontend/resources/images/icons/rectangle-refactor.svg create mode 100644 frontend/resources/images/icons/remove-refactor.svg create mode 100644 frontend/resources/images/icons/rotation-refactor.svg create mode 100644 frontend/resources/images/icons/row-refactor.svg create mode 100644 frontend/resources/images/icons/row-reverse-refactor.svg create mode 100644 frontend/resources/images/icons/search-refactor.svg create mode 100644 frontend/resources/images/icons/shown-refactor.svg create mode 100644 frontend/resources/images/icons/size-horizontal-refactor.svg create mode 100644 frontend/resources/images/icons/size-vertical-refactor.svg create mode 100644 frontend/resources/images/icons/stroke-size-refactor.svg create mode 100644 frontend/resources/images/icons/swatches-refactor.svg create mode 100644 frontend/resources/images/icons/text-Paragraph-refactor.svg create mode 100644 frontend/resources/images/icons/text-align-center-refactor.svg create mode 100644 frontend/resources/images/icons/text-align-left-refactor.svg create mode 100644 frontend/resources/images/icons/text-align-right-refactor.svg create mode 100644 frontend/resources/images/icons/text-auto-height-refactor.svg create mode 100644 frontend/resources/images/icons/text-auto-width-refactor.svg create mode 100644 frontend/resources/images/icons/text-refactor.svg create mode 100644 frontend/resources/images/icons/thumbnail-refactor.svg create mode 100644 frontend/resources/images/icons/tick-refactor.svg create mode 100644 frontend/resources/images/icons/unlock-refactor.svg create mode 100644 frontend/resources/images/icons/vertical-align-items-center-refactor.svg create mode 100644 frontend/resources/images/icons/vertical-align-items-end-refactor.svg create mode 100644 frontend/resources/images/icons/vertical-align-items-start-refactor.svg create mode 100644 frontend/resources/images/icons/view-as-icons-refactor.svg create mode 100644 frontend/resources/images/icons/wrap-refactor.svg create mode 100644 frontend/resources/styles/common/refactor/basic-rules.scss create mode 100644 frontend/resources/styles/common/refactor/common-refactor.scss create mode 100644 frontend/resources/styles/common/refactor/mixins.scss create mode 100644 frontend/resources/styles/common/refactor/z-index.scss rename frontend/src/app/main/ui/components/{ => context_menu_a11y}/context_menu_a11y.cljs (51%) create mode 100644 frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.css.json create mode 100644 frontend/src/app/main/ui/components/context_menu_a11y/context_menu_a11y.scss create mode 100644 frontend/src/app/main/ui/components/shape_icon_refactor.cljs create mode 100644 frontend/src/app/main/ui/components/tab_container/tab_container.cljs create mode 100644 frontend/src/app/main/ui/components/tab_container/tab_container.css.json create mode 100644 frontend/src/app/main/ui/components/tab_container/tab_container.scss rename frontend/src/app/main/ui/components/{tab_container.cljs => tabs_container.cljs} (94%) create mode 100644 frontend/src/app/main/ui/components/tests/test_component.cljs create mode 100644 frontend/src/app/main/ui/components/tests/test_component.css.json create mode 100644 frontend/src/app/main/ui/components/tests/test_component.scss create mode 100644 frontend/src/app/main/ui/debug/components_preview.cljs create mode 100644 frontend/src/app/main/ui/debug/components_preview.css.json create mode 100644 frontend/src/app/main/ui/debug/components_preview.scss rename frontend/src/app/main/ui/workspace/{ => context_menu}/context_menu.cljs (86%) create mode 100644 frontend/src/app/main/ui/workspace/context_menu/context_menu.css.json create mode 100644 frontend/src/app/main/ui/workspace/context_menu/context_menu.scss delete mode 100644 frontend/src/app/main/ui/workspace/sidebar.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.css.json create mode 100644 frontend/src/app/main/ui/workspace/sidebar/collapsable_button/collapsable_button.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/component/sidebar.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/component/sidebar.css.json create mode 100644 frontend/src/app/main/ui/workspace/sidebar/component/sidebar.scss delete mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.css.json create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layer_item/layer_item.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.css.json create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layer_name/layer_name.scss create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layers.cljs create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layers.css.json create mode 100644 frontend/src/app/main/ui/workspace/sidebar/layers/layers.scss rename frontend/src/app/main/ui/workspace/sidebar/{ => sitemap}/sitemap.cljs (52%) create mode 100644 frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.css.json create mode 100644 frontend/src/app/main/ui/workspace/sidebar/sitemap/sitemap.scss 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"