mirror of
https://github.com/penpot/penpot.git
synced 2026-09-14 07:59:36 +00:00
Merge pull request #3853 from penpot/alotor-dashboard-ui
Refactor Dashboard UI
This commit is contained in:
commit
ffd36df0e1
@ -29,7 +29,7 @@ paths.resources = "./resources/";
|
|||||||
paths.output = "./resources/public/";
|
paths.output = "./resources/public/";
|
||||||
paths.dist = "./target/dist/";
|
paths.dist = "./target/dist/";
|
||||||
|
|
||||||
const touchSourceOnStyleChange = true;
|
const touchSourceOnStyleChange = false;
|
||||||
|
|
||||||
/***********************************************
|
/***********************************************
|
||||||
* Marked Extensions
|
* Marked Extensions
|
||||||
@ -234,7 +234,11 @@ gulp.task("scss:modules", function () {
|
|||||||
gulp.task("scss:main", function () {
|
gulp.task("scss:main", function () {
|
||||||
return gulp
|
return gulp
|
||||||
.src(paths.resources + "styles/main-default.scss")
|
.src(paths.resources + "styles/main-default.scss")
|
||||||
.pipe(gulpSass.sync().on("error", gulpSass.logError))
|
.pipe(gulpSass.sync({
|
||||||
|
includePaths: [
|
||||||
|
"./node_modules/animate.css"
|
||||||
|
]
|
||||||
|
}))
|
||||||
.pipe(gulpPostcss([autoprefixer]))
|
.pipe(gulpPostcss([autoprefixer]))
|
||||||
.pipe(gulp.dest(paths.output + "css/"));
|
.pipe(gulp.dest(paths.output + "css/"));
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"test:compile": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
|
"test:compile": "clojure -M:dev:shadow-cljs compile test --config-merge '{:autorun false}'",
|
||||||
"lint:clj": "clj-kondo --parallel --lint src/",
|
"lint:clj": "clj-kondo --parallel --lint src/",
|
||||||
"lint:scss": "yarn run prettier -c resources/styles -c src/**/*.scss",
|
"lint:scss": "yarn run prettier -c resources/styles -c src/**/*.scss",
|
||||||
|
"lint:fix": "yarn run prettier -c resources/styles -c src/**/*.scss -w",
|
||||||
"test:run": "node target/tests.js",
|
"test:run": "node target/tests.js",
|
||||||
"test:watch": "clojure -M:dev:shadow-cljs watch test",
|
"test:watch": "clojure -M:dev:shadow-cljs watch test",
|
||||||
"test": "yarn run test:compile && yarn run test:run",
|
"test": "yarn run test:compile && yarn run test:run",
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"@storybook/react": "^7.5.3",
|
"@storybook/react": "^7.5.3",
|
||||||
"@storybook/react-vite": "^7.5.3",
|
"@storybook/react-vite": "^7.5.3",
|
||||||
"@storybook/testing-library": "^0.2.2",
|
"@storybook/testing-library": "^0.2.2",
|
||||||
|
"animate.css": "^4.1.1",
|
||||||
"autoprefixer": "^10.4.15",
|
"autoprefixer": "^10.4.15",
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"cypress": "^10.3.0",
|
"cypress": "^10.3.0",
|
||||||
|
|||||||
3
frontend/resources/images/icons/logo-error-screen.svg
Normal file
3
frontend/resources/images/icons/logo-error-screen.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="79" xmlns="http://www.w3.org/2000/svg" height="1537" viewBox="2462.648 7069.559 79 1537">
|
||||||
|
<path d="m2483.255 7069.559-10.973 15.432v1441.521l-9.547 4.535-.087-.039v56.915l37.226 17.564 2.274 1.072 2.276-1.072 37.224-17.564v-56.915l-.07.032-9.55-4.536V7084.991l-.334-.468-10.639-14.964-10.973 15.432v.016l-7.983-11.231-7.923 11.144-.282-.397-10.639-14.964Zm1.941 8.964 4.244 5.968h-12.37l4.195-5.899 3.931-.069Zm37.8 0 4.244 5.968h-12.37l4.193-5.899 3.933-.069Zm-18.956 4.219 4.244 5.968h-12.37l4.194-5.898 3.932-.07Zm-28.143 4.758h5.866v1452.525l-5.866-2.768V7087.5Zm8.878 0h5.838v1456.7l-5.838-2.754V7087.5Zm28.923 0h5.866v1453.925l-5.866 2.768V7087.5Zm8.877 0h5.838v1449.75l-5.838 2.754V7087.5Zm-27.834 4.219h5.866v1457.196l-5.866-2.768V7091.719Zm8.879 0h5.837v1454.476l-5.837 2.754v-1457.23Zm28.407 1439.28 5.165 2.11-5.165 2.437v-4.547Zm-59.745.009v4.544l-5.164-2.436 5.164-2.108Zm-5.084 7.17 32.676 15.416v46.867l-32.676-15.415v-46.868Zm69.901 0v46.868l-32.675 15.415v-46.867l32.675-15.416Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1020 B |
22
frontend/resources/styles/common/refactor/animations.scss
Normal file
22
frontend/resources/styles/common/refactor/animations.scss
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// 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 animation($delay, $duration, $animation) {
|
||||||
|
-webkit-animation-delay: $delay;
|
||||||
|
-webkit-animation-duration: $duration;
|
||||||
|
-webkit-animation-name: $animation;
|
||||||
|
-webkit-animation-fill-mode: both;
|
||||||
|
|
||||||
|
-moz-animation-delay: $delay;
|
||||||
|
-moz-animation-duration: $duration;
|
||||||
|
-moz-animation-name: $animation;
|
||||||
|
-moz-animation-fill-mode: both;
|
||||||
|
|
||||||
|
animation-delay: $delay;
|
||||||
|
animation-duration: $duration;
|
||||||
|
animation-name: $animation;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
}
|
||||||
@ -854,5 +854,4 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: normal;
|
justify-content: normal;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|||||||
168
frontend/resources/styles/common/refactor/common-dashboard.scss
Normal file
168
frontend/resources/styles/common/refactor/common-dashboard.scss
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor" as *;
|
||||||
|
|
||||||
|
.dashboard-header {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: $s-64;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $s-4 $s-16 $s-4 $s-8;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&.team {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 20% 1fr 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-name {
|
||||||
|
margin-right: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: $s-32;
|
||||||
|
svg {
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $db-secondary;
|
||||||
|
height: $s-12;
|
||||||
|
margin-right: $s-4;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-14;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-basis: $s-140;
|
||||||
|
border-bottom: $s-3 solid transparent;
|
||||||
|
color: $df-secondary;
|
||||||
|
height: $s-40;
|
||||||
|
padding: $s-4 $s-24;
|
||||||
|
font-weight: $fw400;
|
||||||
|
&:hover {
|
||||||
|
color: $db-secondary;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: $s-12;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: $df-primary;
|
||||||
|
display: block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: $fs-24;
|
||||||
|
font-weight: $fw400;
|
||||||
|
max-width: $s-712;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
user-select: all;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu.is-open {
|
||||||
|
margin-top: $s-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: $s-8;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-header-actions {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin-icon {
|
||||||
|
margin: 0 $s-8 0 $s-24;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
svg {
|
||||||
|
fill: $db-cuaternary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dashboard-header-options {
|
||||||
|
li {
|
||||||
|
a {
|
||||||
|
font-size: $s-16;
|
||||||
|
color: $df-secondary;
|
||||||
|
border-color: transparent;
|
||||||
|
&:hover {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
a {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
@extend .button-primary;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
@extend .button-secondary;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
}
|
||||||
@ -16,4 +16,21 @@
|
|||||||
@import "common/refactor/z-index.scss";
|
@import "common/refactor/z-index.scss";
|
||||||
@import "common/refactor/mixins.scss";
|
@import "common/refactor/mixins.scss";
|
||||||
@import "common/refactor/focus.scss";
|
@import "common/refactor/focus.scss";
|
||||||
|
@import "common/refactor/animations.scss";
|
||||||
@import "common/refactor/basic-rules.scss";
|
@import "common/refactor/basic-rules.scss";
|
||||||
|
|
||||||
|
// Variables to use the library colors
|
||||||
|
$db-primary: var(--color-background-primary);
|
||||||
|
$db-secondary: var(--color-background-secondary);
|
||||||
|
$db-tertiary: var(--color-background-tertiary);
|
||||||
|
$db-cuaternary: var(--color-background-quaternary);
|
||||||
|
$db-subtle: var(--color-background-subtle);
|
||||||
|
$db-disabled: var(--color-background-disabled);
|
||||||
|
|
||||||
|
$df-primary: var(--color-foreground-primary);
|
||||||
|
$df-secondary: var(--color-foreground-secondary);
|
||||||
|
$df-tertiary: var(--color-foreground-tertiary);
|
||||||
|
$da-primary: var(--color-accent-primary);
|
||||||
|
$da-primary-muted: var(--color-accent-primary-muted);
|
||||||
|
$da-secondary: var(--color-accent-secondary);
|
||||||
|
$da-tertiary: var(--color-accent-tertiary);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ $fs-12: math.div(12, $fs-base) + rem;
|
|||||||
$fs-14: math.div(14, $fs-base) + rem;
|
$fs-14: math.div(14, $fs-base) + rem;
|
||||||
$fs-16: math.div(16, $fs-base) + rem;
|
$fs-16: math.div(16, $fs-base) + rem;
|
||||||
$fs-24: math.div(24, $fs-base) + rem;
|
$fs-24: math.div(24, $fs-base) + rem;
|
||||||
|
$fs-36: math.div(36, $fs-base) + rem;
|
||||||
|
|
||||||
// Font weight
|
// Font weight
|
||||||
$fw400: 400; // Regular (CSS value: 'normal')
|
$fw400: 400; // Regular (CSS value: 'normal')
|
||||||
|
|||||||
@ -10,77 +10,142 @@ $s-0: 0px;
|
|||||||
$s-1: 1px;
|
$s-1: 1px;
|
||||||
$s-2: math.div(0.25rem, 2);
|
$s-2: math.div(0.25rem, 2);
|
||||||
$s-3: calc($s-1 + $s-2);
|
$s-3: calc($s-1 + $s-2);
|
||||||
$s-4: var(--s-4);
|
$s-4: 0.25rem;
|
||||||
$s-6: calc($s-2 + $s-4);
|
$s-6: #{0.25 + math.div(0.25, 2)}rem;
|
||||||
$s-8: calc(var(--s-4) * 2);
|
|
||||||
$s-12: calc(var(--s-4) * 3);
|
// To calculate:
|
||||||
$s-16: calc(var(--s-4) * 4);
|
// https://docs.google.com/spreadsheets/d/1YVEfudB3bdO2ZOo5azZLJzZgA0Fkt1C85-1jVjuSYXg/edit?usp=sharing
|
||||||
$s-20: calc(var(--s-4) * 5);
|
$s-8: #{0.25 * 2}rem;
|
||||||
$s-24: calc(var(--s-4) * 6);
|
$s-12: #{0.25 * 3}rem;
|
||||||
$s-28: calc(var(--s-4) * 7);
|
$s-16: #{0.25 * 4}rem;
|
||||||
$s-32: calc(var(--s-4) * 8);
|
$s-20: #{0.25 * 5}rem;
|
||||||
$s-36: calc(var(--s-4) * 9);
|
$s-24: #{0.25 * 6}rem;
|
||||||
$s-40: calc(var(--s-4) * 10);
|
$s-28: #{0.25 * 7}rem;
|
||||||
$s-44: calc(var(--s-4) * 11);
|
$s-32: #{0.25 * 8}rem;
|
||||||
$s-48: calc(var(--s-4) * 12);
|
$s-36: #{0.25 * 9}rem;
|
||||||
$s-52: calc(var(--s-4) * 13);
|
$s-40: #{0.25 * 10}rem;
|
||||||
$s-56: calc(var(--s-4) * 14);
|
$s-44: #{0.25 * 11}rem;
|
||||||
$s-60: calc(var(--s-4) * 15);
|
$s-48: #{0.25 * 12}rem;
|
||||||
$s-64: calc(var(--s-4) * 16);
|
$s-52: #{0.25 * 13}rem;
|
||||||
$s-68: calc(var(--s-4) * 17);
|
$s-56: #{0.25 * 14}rem;
|
||||||
$s-72: calc(var(--s-4) * 18);
|
$s-60: #{0.25 * 15}rem;
|
||||||
$s-76: calc(var(--s-4) * 19);
|
$s-64: #{0.25 * 16}rem;
|
||||||
$s-80: calc(var(--s-4) * 20);
|
$s-68: #{0.25 * 17}rem;
|
||||||
$s-84: calc(var(--s-4) * 21);
|
$s-72: #{0.25 * 18}rem;
|
||||||
$s-92: calc(var(--s-4) * 23);
|
$s-76: #{0.25 * 19}rem;
|
||||||
$s-96: calc(var(--s-4) * 24);
|
$s-80: #{0.25 * 20}rem;
|
||||||
$s-100: calc(var(--s-4) * 25);
|
$s-84: #{0.25 * 21}rem;
|
||||||
$s-104: calc(var(--s-4) * 26);
|
$s-88: #{0.25 * 22}rem;
|
||||||
$s-108: calc(var(--s-4) * 27);
|
$s-92: #{0.25 * 23}rem;
|
||||||
$s-116: calc(var(--s-4) * 29);
|
$s-96: #{0.25 * 24}rem;
|
||||||
$s-120: calc(var(--s-4) * 30);
|
$s-100: #{0.25 * 25}rem;
|
||||||
$s-124: calc(var(--s-4) * 31);
|
$s-104: #{0.25 * 26}rem;
|
||||||
$s-128: calc(var(--s-4) * 32);
|
$s-108: #{0.25 * 27}rem;
|
||||||
$s-136: calc(var(--s-4) * 34);
|
$s-112: #{0.25 * 28}rem;
|
||||||
$s-140: calc(var(--s-4) * 35);
|
$s-116: #{0.25 * 29}rem;
|
||||||
$s-148: calc(var(--s-4) * 37);
|
$s-120: #{0.25 * 30}rem;
|
||||||
$s-156: calc(var(--s-4) * 39);
|
$s-124: #{0.25 * 31}rem;
|
||||||
$s-152: calc(var(--s-4) * 38);
|
$s-128: #{0.25 * 32}rem;
|
||||||
$s-160: calc(var(--s-4) * 40);
|
$s-132: #{0.25 * 33}rem;
|
||||||
$s-168: calc(var(--s-4) * 42);
|
$s-136: #{0.25 * 34}rem;
|
||||||
$s-172: calc(var(--s-4) * 43);
|
$s-140: #{0.25 * 35}rem;
|
||||||
$s-180: calc(var(--s-4) * 45);
|
$s-144: #{0.25 * 36}rem;
|
||||||
$s-184: calc(var(--s-4) * 46);
|
$s-148: #{0.25 * 37}rem;
|
||||||
$s-188: calc(var(--s-4) * 47);
|
$s-152: #{0.25 * 38}rem;
|
||||||
$s-192: calc(var(--s-4) * 48);
|
$s-156: #{0.25 * 39}rem;
|
||||||
$s-196: calc(var(--s-4) * 49);
|
$s-160: #{0.25 * 40}rem;
|
||||||
$s-200: calc(var(--s-4) * 50);
|
$s-164: #{0.25 * 41}rem;
|
||||||
$s-216: calc(var(--s-4) * 54);
|
$s-168: #{0.25 * 42}rem;
|
||||||
$s-220: calc(var(--s-4) * 55);
|
$s-172: #{0.25 * 43}rem;
|
||||||
$s-228: calc(var(--s-4) * 57);
|
$s-176: #{0.25 * 44}rem;
|
||||||
$s-240: calc(var(--s-4) * 60);
|
$s-180: #{0.25 * 45}rem;
|
||||||
$s-248: calc(var(--s-4) * 62);
|
$s-184: #{0.25 * 46}rem;
|
||||||
$s-252: calc(var(--s-4) * 63);
|
$s-188: #{0.25 * 47}rem;
|
||||||
$s-256: calc(var(--s-4) * 64);
|
$s-192: #{0.25 * 48}rem;
|
||||||
$s-260: calc(var(--s-4) * 65);
|
$s-196: #{0.25 * 49}rem;
|
||||||
$s-272: calc(var(--s-4) * 68);
|
$s-200: #{0.25 * 50}rem;
|
||||||
$s-276: calc(var(--s-4) * 69);
|
$s-204: #{0.25 * 51}rem;
|
||||||
$s-280: calc(var(--s-4) * 70);
|
$s-208: #{0.25 * 52}rem;
|
||||||
$s-284: calc(var(--s-4) * 71);
|
$s-212: #{0.25 * 53}rem;
|
||||||
$s-300: calc(var(--s-4) * 75);
|
$s-216: #{0.25 * 54}rem;
|
||||||
$s-320: calc(var(--s-4) * 80);
|
$s-220: #{0.25 * 55}rem;
|
||||||
$s-348: calc(var(--s-4) * 87);
|
$s-224: #{0.25 * 56}rem;
|
||||||
$s-356: calc(var(--s-4) * 89);
|
$s-228: #{0.25 * 57}rem;
|
||||||
$s-364: calc(var(--s-4) * 91);
|
$s-232: #{0.25 * 58}rem;
|
||||||
$s-380: calc(var(--s-4) * 95);
|
$s-236: #{0.25 * 59}rem;
|
||||||
$s-400: calc(var(--s-4) * 100);
|
$s-240: #{0.25 * 60}rem;
|
||||||
$s-408: calc(var(--s-4) * 102);
|
$s-244: #{0.25 * 61}rem;
|
||||||
$s-440: calc(var(--s-4) * 110);
|
$s-248: #{0.25 * 62}rem;
|
||||||
$s-480: calc(var(--s-4) * 120);
|
$s-252: #{0.25 * 63}rem;
|
||||||
$s-500: calc(var(--s-4) * 125);
|
$s-256: #{0.25 * 64}rem;
|
||||||
$s-512: calc(var(--s-4) * 128);
|
$s-260: #{0.25 * 65}rem;
|
||||||
$s-520: calc(var(--s-4) * 130);
|
$s-264: #{0.25 * 66}rem;
|
||||||
$s-640: calc(var(--s-4) * 160);
|
$s-268: #{0.25 * 67}rem;
|
||||||
$s-664: calc(var(--s-4) * 166);
|
$s-272: #{0.25 * 68}rem;
|
||||||
$s-712: calc(var(--s-4) * 178);
|
$s-276: #{0.25 * 69}rem;
|
||||||
$s-736: calc(var(--s-4) * 184);
|
$s-280: #{0.25 * 70}rem;
|
||||||
|
$s-284: #{0.25 * 71}rem;
|
||||||
|
$s-288: #{0.25 * 72}rem;
|
||||||
|
$s-292: #{0.25 * 73}rem;
|
||||||
|
$s-296: #{0.25 * 74}rem;
|
||||||
|
$s-300: #{0.25 * 75}rem;
|
||||||
|
$s-304: #{0.25 * 76}rem;
|
||||||
|
$s-308: #{0.25 * 77}rem;
|
||||||
|
$s-312: #{0.25 * 78}rem;
|
||||||
|
$s-316: #{0.25 * 79}rem;
|
||||||
|
$s-320: #{0.25 * 80}rem;
|
||||||
|
$s-324: #{0.25 * 81}rem;
|
||||||
|
$s-328: #{0.25 * 82}rem;
|
||||||
|
$s-332: #{0.25 * 83}rem;
|
||||||
|
$s-336: #{0.25 * 84}rem;
|
||||||
|
$s-340: #{0.25 * 85}rem;
|
||||||
|
$s-344: #{0.25 * 86}rem;
|
||||||
|
$s-348: #{0.25 * 87}rem;
|
||||||
|
$s-352: #{0.25 * 88}rem;
|
||||||
|
$s-356: #{0.25 * 89}rem;
|
||||||
|
$s-360: #{0.25 * 90}rem;
|
||||||
|
$s-364: #{0.25 * 91}rem;
|
||||||
|
$s-368: #{0.25 * 92}rem;
|
||||||
|
$s-372: #{0.25 * 93}rem;
|
||||||
|
$s-376: #{0.25 * 94}rem;
|
||||||
|
$s-380: #{0.25 * 95}rem;
|
||||||
|
$s-384: #{0.25 * 96}rem;
|
||||||
|
$s-388: #{0.25 * 97}rem;
|
||||||
|
$s-392: #{0.25 * 98}rem;
|
||||||
|
$s-396: #{0.25 * 99}rem;
|
||||||
|
$s-400: #{0.25 * 100}rem;
|
||||||
|
$s-404: #{0.25 * 101}rem;
|
||||||
|
$s-408: #{0.25 * 102}rem;
|
||||||
|
$s-412: #{0.25 * 103}rem;
|
||||||
|
$s-416: #{0.25 * 104}rem;
|
||||||
|
$s-420: #{0.25 * 105}rem;
|
||||||
|
$s-424: #{0.25 * 106}rem;
|
||||||
|
$s-428: #{0.25 * 107}rem;
|
||||||
|
$s-432: #{0.25 * 108}rem;
|
||||||
|
$s-436: #{0.25 * 109}rem;
|
||||||
|
$s-440: #{0.25 * 110}rem;
|
||||||
|
$s-444: #{0.25 * 111}rem;
|
||||||
|
$s-448: #{0.25 * 112}rem;
|
||||||
|
$s-452: #{0.25 * 113}rem;
|
||||||
|
$s-456: #{0.25 * 114}rem;
|
||||||
|
$s-460: #{0.25 * 115}rem;
|
||||||
|
$s-464: #{0.25 * 116}rem;
|
||||||
|
$s-468: #{0.25 * 117}rem;
|
||||||
|
$s-472: #{0.25 * 118}rem;
|
||||||
|
$s-476: #{0.25 * 119}rem;
|
||||||
|
$s-480: #{0.25 * 120}rem;
|
||||||
|
$s-484: #{0.25 * 121}rem;
|
||||||
|
$s-488: #{0.25 * 122}rem;
|
||||||
|
$s-492: #{0.25 * 123}rem;
|
||||||
|
$s-496: #{0.25 * 124}rem;
|
||||||
|
$s-500: #{0.25 * 125}rem;
|
||||||
|
$s-512: #{0.25 * 128}rem;
|
||||||
|
$s-520: #{0.25 * 130}rem;
|
||||||
|
$s-580: #{0.25 * 145}rem;
|
||||||
|
$s-612: #{0.25 * 153}rem;
|
||||||
|
$s-640: #{0.25 * 160}rem;
|
||||||
|
$s-664: #{0.25 * 166}rem;
|
||||||
|
$s-712: #{0.25 * 178}rem;
|
||||||
|
$s-736: #{0.25 * 184}rem;
|
||||||
|
$s-800: #{0.25 * 200}rem;
|
||||||
|
$s-1000: #{0.25 * 250}rem;
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
@import "common/dependencies/z-index";
|
@import "common/dependencies/z-index";
|
||||||
@import "common/dependencies/highlightjs-theme";
|
@import "common/dependencies/highlightjs-theme";
|
||||||
|
|
||||||
|
@import "animate";
|
||||||
@import "common/refactor/color-defs.scss";
|
@import "common/refactor/color-defs.scss";
|
||||||
@import "common/refactor/themes.scss";
|
@import "common/refactor/themes.scss";
|
||||||
@import "common/refactor/design-tokens.scss";
|
@import "common/refactor/design-tokens.scss";
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@
|
|||||||
(case kns
|
(case kns
|
||||||
"global" knm
|
"global" knm
|
||||||
"old-css" (if (nil? *css-data*) knm "")
|
"old-css" (if (nil? *css-data*) knm "")
|
||||||
(or (get *css-data* (keyword knm)) knm)))
|
(or (get *css-data* (keyword knm)) (str "_not_found_" knm))))
|
||||||
|
|
||||||
(string? k)
|
(string? k)
|
||||||
k))))
|
k))))
|
||||||
|
|||||||
@ -9,6 +9,10 @@
|
|||||||
// Comment-thread-group
|
// Comment-thread-group
|
||||||
.thread-group {
|
.thread-group {
|
||||||
padding: 0 $s-12;
|
padding: 0 $s-12;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: $br-8;
|
||||||
|
padding: $s-8 $s-16;
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
@include titleTipography;
|
@include titleTipography;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
@ -39,6 +43,10 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $s-24;
|
gap: $s-24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $db-primary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comment-thread
|
// Comment-thread
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.components.context-menu-a11y
|
(ns app.main.ui.components.context-menu-a11y
|
||||||
(:require-macros [app.main.style :refer [css]])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
@ -66,7 +66,6 @@
|
|||||||
left (gobj/get props "left" 0)
|
left (gobj/get props "left" 0)
|
||||||
fixed? (gobj/get props "fixed?" false)
|
fixed? (gobj/get props "fixed?" false)
|
||||||
min-width? (gobj/get props "min-width?" false)
|
min-width? (gobj/get props "min-width?" false)
|
||||||
workspace? (gobj/get props "workspace?" false)
|
|
||||||
origin (gobj/get props "origin")
|
origin (gobj/get props "origin")
|
||||||
route (mf/deref refs/route)
|
route (mf/deref refs/route)
|
||||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
@ -192,107 +191,149 @@
|
|||||||
(tm/schedule-on-idle
|
(tm/schedule-on-idle
|
||||||
#(dom/focus! (dom/get-element (first ids)))))
|
#(dom/focus! (dom/get-element (first ids)))))
|
||||||
|
|
||||||
(when (and open? (some? (:levels @local)))
|
(if new-css-system
|
||||||
[:> dropdown' props
|
(when (and open? (some? (:levels @local)))
|
||||||
|
[:> dropdown' props
|
||||||
|
(let [level (-> @local :levels peek)
|
||||||
|
original-options (:options level)
|
||||||
|
parent-original (:parent-option level)]
|
||||||
|
[:div {:class (stl/css-case :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 (stl/css-case :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 (stl/css :context-menu-item)
|
||||||
|
:tab-index "0"
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(dom/prevent-default event))}
|
||||||
|
[:button {:class (stl/css :context-menu-action :submenu-back)
|
||||||
|
:data-no-close true
|
||||||
|
:on-click exit-submenu}
|
||||||
|
[:span {:class (stl/css :submenu-icon-back)} i/arrow-refactor]
|
||||||
|
parent-option]]
|
||||||
|
|
||||||
(let [level (-> @local :levels peek)
|
[:li {:class (stl/css :separator)}]])
|
||||||
original-options (:options level)
|
|
||||||
parent-original (:parent-option level)]
|
(for [[index option] (d/enumerate (:options level))]
|
||||||
[:div {:class (if (and new-css-system workspace?)
|
(let [option-name (:option-name option)
|
||||||
(dom/classnames (css :is-selectable) is-selectable
|
id (:id option)
|
||||||
(css :context-menu) true
|
sub-options (:sub-options option)
|
||||||
(css :is-open) open?
|
option-handler (:option-handler option)
|
||||||
(css :fixed) fixed?)
|
data-test (:data-test option)]
|
||||||
(dom/classnames :is-selectable is-selectable
|
(when option-name
|
||||||
|
(if (= option-name :separator)
|
||||||
|
[:li {:key (dm/str "context-item-" index)
|
||||||
|
:class (stl/css :separator)}]
|
||||||
|
[:& context-menu-a11y-item
|
||||||
|
{:id id
|
||||||
|
:key id
|
||||||
|
:class (stl/css-case
|
||||||
|
:is-selected (and selected (= option-name selected))
|
||||||
|
:selected (and selected (= data-test selected))
|
||||||
|
:context-menu-item true)
|
||||||
|
: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 (stl/css :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)
|
||||||
|
|
||||||
|
(when (and selected (= data-test selected))
|
||||||
|
[:span {:class (stl/css :selected-icon)} i/tick-refactor])]
|
||||||
|
|
||||||
|
[:a {:class (stl/css :context-menu-action :submenu)
|
||||||
|
:data-no-close true
|
||||||
|
:on-click (enter-submenu option-name sub-options)
|
||||||
|
:data-test data-test}
|
||||||
|
option-name
|
||||||
|
[:span {:class (stl/css :submenu-icon)} i/arrow-refactor]])]))))])])])
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
(when (and open? (some? (:levels @local)))
|
||||||
|
[:> dropdown' props
|
||||||
|
|
||||||
|
(let [level (-> @local :levels peek)
|
||||||
|
original-options (:options level)
|
||||||
|
parent-original (:parent-option level)]
|
||||||
|
[:div {:class (dom/classnames :is-selectable is-selectable
|
||||||
:context-menu true
|
:context-menu true
|
||||||
:is-open open?
|
:is-open open?
|
||||||
:fixed fixed?))
|
:fixed fixed?)
|
||||||
:style {:top (+ top (:offset-y @local))
|
:style {:top (+ top (:offset-y @local))
|
||||||
:left (+ left (:offset-x @local))}
|
:left (+ left (:offset-x @local))}
|
||||||
:on-key-down (on-key-down original-options parent-original)}
|
:on-key-down (on-key-down original-options parent-original)}
|
||||||
(let [level (-> @local :levels peek)]
|
(let [level (-> @local :levels peek)]
|
||||||
[:ul {:class (if (and new-css-system workspace?)
|
[:ul {:class (dom/classnames :min-width min-width?
|
||||||
(dom/classnames (css :min-width) min-width?
|
:context-menu-items true)
|
||||||
(css :context-menu-items) true)
|
:role "menu"
|
||||||
(dom/classnames :min-width min-width?
|
:ref check-menu-offscreen}
|
||||||
:context-menu-items true))
|
(when-let [parent-option (:parent-option level)]
|
||||||
:role "menu"
|
[:*
|
||||||
:ref check-menu-offscreen}
|
[:& context-menu-a11y-item
|
||||||
(when-let [parent-option (:parent-option level)]
|
{:id "go-back-sub-option"
|
||||||
[:*
|
:tab-index "0"
|
||||||
[:& context-menu-a11y-item
|
:on-key-down (fn [event]
|
||||||
{:id "go-back-sub-option"
|
(dom/prevent-default event))}
|
||||||
:class (dom/classnames (css :context-menu-item) (and new-css-system workspace?))
|
[:div {:class (dom/classnames :context-menu-action true
|
||||||
:tab-index "0"
|
:submenu-back true)
|
||||||
:on-key-down (fn [event]
|
:data-no-close true
|
||||||
(dom/prevent-default event))}
|
:on-click exit-submenu}
|
||||||
[:div {:class (if (and new-css-system workspace?)
|
[:span i/arrow-slide]
|
||||||
(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
|
|
||||||
:key id
|
|
||||||
:class (if (and new-css-system workspace?)
|
|
||||||
(dom/classnames (css :is-selected) (and selected (= option-name selected))
|
|
||||||
(css :selected) (and selected (= data-test 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)
|
|
||||||
|
|
||||||
(when (and new-css-system selected (= data-test selected))
|
parent-option]]
|
||||||
[:span {:class (dom/classnames (css :selected-icon) true)}
|
|
||||||
i/tick-refactor])]
|
[:li.separator]])
|
||||||
[:a {:class (if (and new-css-system workspace?)
|
|
||||||
(dom/classnames (css :context-menu-action) true
|
(for [[index option] (d/enumerate (:options level))]
|
||||||
(css :submenu) true)
|
(let [option-name (:option-name option)
|
||||||
(dom/classnames :context-menu-action true
|
id (:id option)
|
||||||
:submenu true))
|
sub-options (:sub-options option)
|
||||||
:data-no-close true
|
option-handler (:option-handler option)
|
||||||
:on-click (enter-submenu option-name sub-options)
|
data-test (:data-test option)]
|
||||||
:data-test data-test}
|
(when option-name
|
||||||
option-name
|
(if (= option-name :separator)
|
||||||
[:span {:class (dom/classnames (css :submenu-icon) (and new-css-system workspace?))}
|
[:li.separator {:key (dm/str "context-item-" index)}]
|
||||||
(if (and new-css-system workspace?)
|
[:& context-menu-a11y-item
|
||||||
i/arrow-refactor
|
{:id id
|
||||||
i/arrow-slide)]])]))))])])])))
|
:key id
|
||||||
|
:class (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 (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.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/defc context-menu-a11y
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
|
|||||||
@ -72,6 +72,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: $fw700;
|
font-weight: $fw700;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
.submenu-icon-back svg {
|
.submenu-icon-back svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--menu-foreground-color);
|
stroke: var(--menu-foreground-color);
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.ui.components.select :as cs]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.hooks :as hooks]
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
@ -252,10 +253,10 @@
|
|||||||
value (or (get-in @form [:data input-name]) default)
|
value (or (get-in @form [:data input-name]) default)
|
||||||
cvalue (d/seek #(= value (:value %)) options)
|
cvalue (d/seek #(= value (:value %)) options)
|
||||||
focus? (mf/use-state false)
|
focus? (mf/use-state false)
|
||||||
on-change
|
|
||||||
|
handle-change
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [target (dom/get-target event)
|
(let [value (if (string? event) event (dom/get-target-val event))]
|
||||||
value (dom/get-value target)]
|
|
||||||
(fm/on-input-change form input-name value)))
|
(fm/on-input-change form input-name value)))
|
||||||
|
|
||||||
on-focus
|
on-focus
|
||||||
@ -267,33 +268,16 @@
|
|||||||
(reset! focus? false))]
|
(reset! focus? false))]
|
||||||
|
|
||||||
(if new-css-system
|
(if new-css-system
|
||||||
[:div {:class (stl/css :custom-select)}
|
[:div {:class (stl/css :select-wrapper)}
|
||||||
[:select {:value value
|
[:& cs/select
|
||||||
:on-change on-change
|
{:default-value value
|
||||||
:on-focus on-focus
|
:options options
|
||||||
:on-blur on-blur
|
:on-change handle-change}]]
|
||||||
:disabled disabled
|
|
||||||
:data-test data-test}
|
|
||||||
(for [item options]
|
|
||||||
[:> :option (clj->js (cond-> {:key (:value item) :value (:value item)}
|
|
||||||
(:disabled item) (assoc :disabled "disabled")
|
|
||||||
(:hidden item) (assoc :style {:display "none"})))
|
|
||||||
(:label item)])]
|
|
||||||
|
|
||||||
[:div {:class (stl/css-case :input-container true
|
|
||||||
:disabled disabled
|
|
||||||
:focus @focus?)}
|
|
||||||
[:div {:class (stl/css :main-content)}
|
|
||||||
[:label {:class (stl/css :label)} label]
|
|
||||||
[:span {:class (stl/css :value)} (:label cvalue "")]]
|
|
||||||
|
|
||||||
[:div {:class (stl/css :icon)}
|
|
||||||
i/arrow-refactor]]]
|
|
||||||
|
|
||||||
|
|
||||||
[:div.custom-select
|
[:div.custom-select
|
||||||
[:select {:value value
|
[:select {:value value
|
||||||
:on-change on-change
|
:on-change handle-change
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:on-blur on-blur
|
:on-blur on-blur
|
||||||
:disabled disabled
|
:disabled disabled
|
||||||
|
|||||||
@ -23,12 +23,18 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: var(--modal-title-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
text-transform: none;
|
text-transform: uppercase;
|
||||||
input {
|
input {
|
||||||
@extend .input-element;
|
@extend .input-element;
|
||||||
color: var(--input-foreground-color-active);
|
color: var(--input-foreground-color-active);
|
||||||
width: calc(100% - $s-1);
|
width: calc(100% - $s-1);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border: $s-1 solid var(--input-border-color-focus);
|
||||||
|
border-radius: $br-8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Input autofill
|
// Input autofill
|
||||||
input:-webkit-autofill,
|
input:-webkit-autofill,
|
||||||
@ -39,11 +45,6 @@
|
|||||||
-webkit-box-shadow: 0 0 0 28px var(--input-background-color) inset !important;
|
-webkit-box-shadow: 0 0 0 28px var(--input-background-color) inset !important;
|
||||||
border: $s-1 solid var(--input-background-color);
|
border: $s-1 solid var(--input-background-color);
|
||||||
}
|
}
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
border: $s-1 solid var(--input-border-color-focus);
|
|
||||||
border-radius: $br-8;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
&:global(.invalid) {
|
&:global(.invalid) {
|
||||||
input {
|
input {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard
|
(ns app.main.ui.dashboard
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
@ -52,7 +53,8 @@
|
|||||||
|
|
||||||
(mf/defc dashboard-content
|
(mf/defc dashboard-content
|
||||||
[{:keys [team projects project section search-term profile] :as props}]
|
[{:keys [team projects project section search-term profile] :as props}]
|
||||||
(let [container (mf/use-ref)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
container (mf/use-ref)
|
||||||
content-width (mf/use-state 0)
|
content-width (mf/use-state 0)
|
||||||
project-id (:id project)
|
project-id (:id project)
|
||||||
team-id (:id team)
|
team-id (:id team)
|
||||||
@ -81,60 +83,118 @@
|
|||||||
|
|
||||||
(mf/use-effect on-resize)
|
(mf/use-effect on-resize)
|
||||||
|
|
||||||
[:div.dashboard-content {:on-click clear-selected-fn :ref container}
|
(if new-css-system
|
||||||
(case section
|
[:div {:class (stl/css :dashboard-content)
|
||||||
:dashboard-projects
|
:on-click clear-selected-fn :ref container}
|
||||||
[:*
|
(case section
|
||||||
[:& projects-section
|
:dashboard-projects
|
||||||
{:team team
|
|
||||||
:projects projects
|
|
||||||
:profile profile
|
|
||||||
:default-project-id default-project-id}]
|
|
||||||
|
|
||||||
(when (contains? cf/flags :dashboard-templates-section)
|
|
||||||
[:& templates-section {:profile profile
|
|
||||||
:project-id project-id
|
|
||||||
:team-id team-id
|
|
||||||
:default-project-id default-project-id
|
|
||||||
:content-width @content-width}])]
|
|
||||||
|
|
||||||
:dashboard-fonts
|
|
||||||
[:& fonts-page {:team team}]
|
|
||||||
|
|
||||||
:dashboard-font-providers
|
|
||||||
[:& font-providers-page {:team team}]
|
|
||||||
|
|
||||||
:dashboard-files
|
|
||||||
(when project
|
|
||||||
[:*
|
[:*
|
||||||
[:& files-section {:team team :project project}]
|
[:& projects-section
|
||||||
|
{:team team
|
||||||
|
:projects projects
|
||||||
|
:profile profile
|
||||||
|
:default-project-id default-project-id}]
|
||||||
|
|
||||||
(when (contains? cf/flags :dashboard-templates-section)
|
(when (contains? cf/flags :dashboard-templates-section)
|
||||||
[:& templates-section {:profile profile
|
[:& templates-section {:profile profile
|
||||||
:team-id team-id
|
|
||||||
:project-id project-id
|
:project-id project-id
|
||||||
|
:team-id team-id
|
||||||
:default-project-id default-project-id
|
:default-project-id default-project-id
|
||||||
:content-width @content-width}])])
|
:content-width @content-width}])]
|
||||||
|
|
||||||
:dashboard-search
|
:dashboard-fonts
|
||||||
[:& search-page {:team team
|
[:& fonts-page {:team team}]
|
||||||
:search-term search-term}]
|
|
||||||
|
|
||||||
:dashboard-libraries
|
:dashboard-font-providers
|
||||||
[:& libraries-page {:team team}]
|
[:& font-providers-page {:team team}]
|
||||||
|
|
||||||
:dashboard-team-members
|
:dashboard-files
|
||||||
[:& team-members-page {:team team :profile profile}]
|
(when project
|
||||||
|
[:*
|
||||||
|
[:& files-section {:team team :project project}]
|
||||||
|
(when (contains? cf/flags :dashboard-templates-section)
|
||||||
|
[:& templates-section {:profile profile
|
||||||
|
:team-id team-id
|
||||||
|
:project-id project-id
|
||||||
|
:default-project-id default-project-id
|
||||||
|
:content-width @content-width}])])
|
||||||
|
|
||||||
:dashboard-team-invitations
|
:dashboard-search
|
||||||
[:& team-invitations-page {:team team}]
|
[:& search-page {:team team
|
||||||
|
:search-term search-term}]
|
||||||
|
|
||||||
:dashboard-team-webhooks
|
:dashboard-libraries
|
||||||
[:& team-webhooks-page {:team team}]
|
[:& libraries-page {:team team}]
|
||||||
|
|
||||||
:dashboard-team-settings
|
:dashboard-team-members
|
||||||
[:& team-settings-page {:team team :profile profile}]
|
[:& team-members-page {:team team :profile profile}]
|
||||||
|
|
||||||
nil)]))
|
:dashboard-team-invitations
|
||||||
|
[:& team-invitations-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-team-webhooks
|
||||||
|
[:& team-webhooks-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-team-settings
|
||||||
|
[:& team-settings-page {:team team :profile profile}]
|
||||||
|
|
||||||
|
nil)]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-content {:on-click clear-selected-fn :ref container}
|
||||||
|
(case section
|
||||||
|
:dashboard-projects
|
||||||
|
[:*
|
||||||
|
[:& projects-section
|
||||||
|
{:team team
|
||||||
|
:projects projects
|
||||||
|
:profile profile
|
||||||
|
:default-project-id default-project-id}]
|
||||||
|
|
||||||
|
(when (contains? cf/flags :dashboard-templates-section)
|
||||||
|
[:& templates-section {:profile profile
|
||||||
|
:project-id project-id
|
||||||
|
:team-id team-id
|
||||||
|
:default-project-id default-project-id
|
||||||
|
:content-width @content-width}])]
|
||||||
|
|
||||||
|
:dashboard-fonts
|
||||||
|
[:& fonts-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-font-providers
|
||||||
|
[:& font-providers-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-files
|
||||||
|
(when project
|
||||||
|
[:*
|
||||||
|
[:& files-section {:team team :project project}]
|
||||||
|
(when (contains? cf/flags :dashboard-templates-section)
|
||||||
|
[:& templates-section {:profile profile
|
||||||
|
:team-id team-id
|
||||||
|
:project-id project-id
|
||||||
|
:default-project-id default-project-id
|
||||||
|
:content-width @content-width}])])
|
||||||
|
|
||||||
|
:dashboard-search
|
||||||
|
[:& search-page {:team team
|
||||||
|
:search-term search-term}]
|
||||||
|
|
||||||
|
:dashboard-libraries
|
||||||
|
[:& libraries-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-team-members
|
||||||
|
[:& team-members-page {:team team :profile profile}]
|
||||||
|
|
||||||
|
:dashboard-team-invitations
|
||||||
|
[:& team-invitations-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-team-webhooks
|
||||||
|
[:& team-webhooks-page {:team team}]
|
||||||
|
|
||||||
|
:dashboard-team-settings
|
||||||
|
[:& team-settings-page {:team team :profile profile}]
|
||||||
|
|
||||||
|
nil)])))
|
||||||
|
|
||||||
(mf/defc dashboard
|
(mf/defc dashboard
|
||||||
[{:keys [route profile] :as props}]
|
[{:keys [route profile] :as props}]
|
||||||
@ -168,31 +228,59 @@
|
|||||||
(fn []
|
(fn []
|
||||||
(events/unlistenByKey key))))
|
(events/unlistenByKey key))))
|
||||||
|
|
||||||
[:& (mf/provider ctx/current-team-id) {:value team-id}
|
(if new-css-system
|
||||||
[:& (mf/provider ctx/current-project-id) {:value project-id}
|
[:& (mf/provider ctx/current-team-id) {:value team-id}
|
||||||
;; NOTE: dashboard events and other related functions assumes
|
[:& (mf/provider ctx/current-project-id) {:value project-id}
|
||||||
;; that the team is a implicit context variable that is
|
;; NOTE: dashboard events and other related functions assumes
|
||||||
;; available using react context or accessing
|
;; that the team is a implicit context variable that is
|
||||||
;; the :current-team-id on the state. We set the key to the
|
;; available using react context or accessing
|
||||||
;; team-id because we want to completely refresh all the
|
;; the :current-team-id on the state. We set the key to the
|
||||||
;; components on team change. Many components assumes that the
|
;; team-id because we want to completely refresh all the
|
||||||
;; team is already set so don't put the team into mf/deps.
|
;; components on team change. Many components assumes that the
|
||||||
(when team
|
;; team is already set so don't put the team into mf/deps.
|
||||||
[:main {:class (dom/classnames :dashboard-layout (not new-css-system)
|
(when team
|
||||||
:dashboard-layout-refactor new-css-system)
|
[:main {:class (stl/css :dashboard)
|
||||||
:key (:id team)}
|
:key (:id team)}
|
||||||
[:& sidebar
|
[:& sidebar
|
||||||
{:team team
|
{:team team
|
||||||
:projects projects
|
:projects projects
|
||||||
:project project
|
|
||||||
:profile profile
|
|
||||||
:section section
|
|
||||||
:search-term search-term}]
|
|
||||||
(when (and team profile (seq projects))
|
|
||||||
[:& dashboard-content
|
|
||||||
{:projects projects
|
|
||||||
:profile profile
|
|
||||||
:project project
|
:project project
|
||||||
|
:profile profile
|
||||||
:section section
|
:section section
|
||||||
:search-term search-term
|
:search-term search-term}]
|
||||||
:team team}])])]]))
|
(when (and team profile (seq projects))
|
||||||
|
[:& dashboard-content
|
||||||
|
{:projects projects
|
||||||
|
:profile profile
|
||||||
|
:project project
|
||||||
|
:section section
|
||||||
|
:search-term search-term
|
||||||
|
:team team}])])]]
|
||||||
|
|
||||||
|
[:& (mf/provider ctx/current-team-id) {:value team-id}
|
||||||
|
[:& (mf/provider ctx/current-project-id) {:value project-id}
|
||||||
|
;; NOTE: dashboard events and other related functions assumes
|
||||||
|
;; that the team is a implicit context variable that is
|
||||||
|
;; available using react context or accessing
|
||||||
|
;; the :current-team-id on the state. We set the key to the
|
||||||
|
;; team-id because we want to completely refresh all the
|
||||||
|
;; components on team change. Many components assumes that the
|
||||||
|
;; team is already set so don't put the team into mf/deps.
|
||||||
|
(when team
|
||||||
|
[:main {:class (dom/classnames :dashboard-layout true) :key (:id team)}
|
||||||
|
[:& sidebar
|
||||||
|
{:team team
|
||||||
|
:projects projects
|
||||||
|
:project project
|
||||||
|
:profile profile
|
||||||
|
:section section
|
||||||
|
:search-term search-term}]
|
||||||
|
(when (and team profile (seq projects))
|
||||||
|
[:& dashboard-content
|
||||||
|
{:projects projects
|
||||||
|
:profile profile
|
||||||
|
:project project
|
||||||
|
:section section
|
||||||
|
:search-term search-term
|
||||||
|
:team team}])])]])))
|
||||||
|
|
||||||
|
|||||||
28
frontend/src/app/main/ui/dashboard.scss
Normal file
28
frontend/src/app/main/ui/dashboard.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.dashboard {
|
||||||
|
background-color: $db-primary;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: $s-40 $s-256 1fr;
|
||||||
|
grid-template-rows: $s-52 1fr;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
:global(svg#loader-pencil) {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
grid-row: 1 / span 2;
|
||||||
|
padding: $s-16 $s-16 0 0;
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.comments
|
(ns app.main.ui.dashboard.comments
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.comments :as dcm]
|
[app.main.data.comments :as dcm]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
@ -13,6 +14,7 @@
|
|||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.comments :as cmt]
|
[app.main.ui.comments :as cmt]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
@ -20,11 +22,40 @@
|
|||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
(mf/defc comments-icon
|
||||||
|
[{:keys [profile show? on-show-comments]}]
|
||||||
|
|
||||||
|
(let [threads-map (mf/deref refs/comment-threads)
|
||||||
|
|
||||||
|
tgroups
|
||||||
|
(->> (vals threads-map)
|
||||||
|
(sort-by :modified-at)
|
||||||
|
(reverse)
|
||||||
|
(dcm/apply-filters {} profile)
|
||||||
|
(dcm/group-threads-by-file-and-page))
|
||||||
|
|
||||||
|
handle-keydown
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps on-show-comments)
|
||||||
|
(fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-show-comments event))))]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :dashboard-comments-section)}
|
||||||
|
[:button
|
||||||
|
{:tab-index "0"
|
||||||
|
:on-click on-show-comments
|
||||||
|
:on-key-down handle-keydown
|
||||||
|
:data-test "open-comments"
|
||||||
|
:class (stl/css-case :button true
|
||||||
|
:open show?
|
||||||
|
:unread (boolean (seq tgroups)))}
|
||||||
|
i/chat]]))
|
||||||
|
|
||||||
(mf/defc comments-section
|
(mf/defc comments-section
|
||||||
[{:keys [profile team]}]
|
[{:keys [profile team show? on-show-comments on-hide-comments]}]
|
||||||
(let [show-dropdown? (mf/use-state false)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
show-dropdown (mf/use-fn #(reset! show-dropdown? true))
|
|
||||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
|
||||||
threads-map (mf/deref refs/comment-threads)
|
threads-map (mf/deref refs/comment-threads)
|
||||||
users (mf/deref refs/current-team-comments-users)
|
users (mf/deref refs/current-team-comments-users)
|
||||||
team-id (:id team)
|
team-id (:id team)
|
||||||
@ -35,6 +66,13 @@
|
|||||||
(dcm/apply-filters {} profile)
|
(dcm/apply-filters {} profile)
|
||||||
(dcm/group-threads-by-file-and-page))
|
(dcm/group-threads-by-file-and-page))
|
||||||
|
|
||||||
|
handle-keydown
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps on-hide-comments)
|
||||||
|
(fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-hide-comments event))))
|
||||||
|
|
||||||
on-navigate
|
on-navigate
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [thread]
|
(fn [thread]
|
||||||
@ -45,58 +83,87 @@
|
|||||||
(mf/deps team-id)
|
(mf/deps team-id)
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (dcm/retrieve-unread-comment-threads team-id))))
|
(st/emit! (dcm/retrieve-unread-comment-threads team-id))))
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(mf/deps @show-dropdown?)
|
(mf/deps show?)
|
||||||
(fn []
|
(fn []
|
||||||
(when @show-dropdown?
|
(when show?
|
||||||
(st/emit! (ptk/event ::ev/event {::ev/name "open-comment-notifications"
|
(st/emit! (ptk/event ::ev/event {::ev/name "open-comment-notifications"
|
||||||
::ev/origin "dashboard"})))))
|
::ev/origin "dashboard"})))))
|
||||||
|
|
||||||
[:div.dashboard-comments-section
|
(if new-css-system
|
||||||
[:div.button
|
[:div {:class (stl/css :dashboard-comments-section)}
|
||||||
{:tab-index "0"
|
[:& dropdown {:show show? :on-close on-hide-comments}
|
||||||
:on-click show-dropdown
|
[:div {:class (stl/css :dropdown :comments-section :comment-threads-section)}
|
||||||
:on-key-down (fn [event]
|
[:div {:class (stl/css :header)}
|
||||||
(when (kbd/enter? event)
|
[:h3 (tr "labels.comments")]
|
||||||
(show-dropdown event)))
|
[:button
|
||||||
:data-test "open-comments"
|
{:class (stl/css :close)
|
||||||
:class (dom/classnames :open @show-dropdown?
|
:tab-index (if show? "0" "-1")
|
||||||
:unread (boolean (seq tgroups)))}
|
:on-click on-hide-comments
|
||||||
i/chat]
|
:on-key-down handle-keydown} i/close]]
|
||||||
|
|
||||||
[:& dropdown {:show @show-dropdown? :on-close hide-dropdown}
|
(if (seq tgroups)
|
||||||
[:div.dropdown.comments-section.comment-threads-section.
|
[:div {:class (stl/css :thread-groups)}
|
||||||
[:div.header
|
[:& cmt/comment-thread-group
|
||||||
[:h3 (tr "labels.comments")]
|
{:group (first tgroups)
|
||||||
[:span.close {:tab-index (if @show-dropdown?
|
:on-thread-click on-navigate
|
||||||
"0"
|
:show-file-name true
|
||||||
"-1")
|
:users users}]
|
||||||
:on-click hide-dropdown
|
(for [tgroup (rest tgroups)]
|
||||||
:on-key-down (fn [event]
|
[:& cmt/comment-thread-group
|
||||||
(when (kbd/enter? event)
|
{:group tgroup
|
||||||
(hide-dropdown event)))} i/close]]
|
:on-thread-click on-navigate
|
||||||
|
:show-file-name true
|
||||||
|
:users users
|
||||||
|
:key (:page-id tgroup)}])]
|
||||||
|
|
||||||
[:hr]
|
[:div {:class (stl/css :thread-groups-placeholder)}
|
||||||
|
i/chat
|
||||||
|
(tr "labels.no-comments-available")])]]]
|
||||||
|
|
||||||
(if (seq tgroups)
|
;; OLD
|
||||||
[:div.thread-groups
|
[:div.dashboard-comments-section
|
||||||
[:& cmt/comment-thread-group
|
[:div.button
|
||||||
{:group (first tgroups)
|
{:tab-index "0"
|
||||||
:on-thread-click on-navigate
|
:on-click on-show-comments
|
||||||
:show-file-name true
|
:on-key-down (fn [event]
|
||||||
:users users}]
|
(when (kbd/enter? event)
|
||||||
(for [tgroup (rest tgroups)]
|
(on-show-comments event)))
|
||||||
[:*
|
:data-test "open-comments"
|
||||||
[:hr]
|
:class (dom/classnames :open show?
|
||||||
|
:unread (boolean (seq tgroups)))}
|
||||||
|
i/chat]
|
||||||
|
|
||||||
[:& cmt/comment-thread-group
|
[:& dropdown {:show show? :on-close on-hide-comments}
|
||||||
{:group tgroup
|
[:div.dropdown.comments-section.comment-threads-section.
|
||||||
:on-thread-click on-navigate
|
[:div.header
|
||||||
:show-file-name true
|
[:h3 (tr "labels.comments")]
|
||||||
:users users
|
[:span.close {:tab-index (if show? "0" "-1")
|
||||||
:key (:page-id tgroup)}]])]
|
:on-click on-hide-comments
|
||||||
|
:on-key-down handle-keydown}
|
||||||
|
i/close]]
|
||||||
|
|
||||||
[:div.thread-groups-placeholder
|
[:hr]
|
||||||
i/chat
|
|
||||||
(tr "labels.no-comments-available")])]]]))
|
(if (seq tgroups)
|
||||||
|
[:div.thread-groups
|
||||||
|
[:& cmt/comment-thread-group
|
||||||
|
{:group (first tgroups)
|
||||||
|
:on-thread-click on-navigate
|
||||||
|
:show-file-name true
|
||||||
|
:users users}]
|
||||||
|
(for [tgroup (rest tgroups)]
|
||||||
|
[:*
|
||||||
|
[:hr]
|
||||||
|
|
||||||
|
[:& cmt/comment-thread-group
|
||||||
|
{:group tgroup
|
||||||
|
:on-thread-click on-navigate
|
||||||
|
:show-file-name true
|
||||||
|
:users users
|
||||||
|
:key (:page-id tgroup)}]])]
|
||||||
|
|
||||||
|
[:div.thread-groups-placeholder
|
||||||
|
i/chat
|
||||||
|
(tr "labels.no-comments-available")])]]])))
|
||||||
|
|||||||
131
frontend/src/app/main/ui/dashboard/comments.scss
Normal file
131
frontend/src/app/main/ui/dashboard/comments.scss
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.dashboard-comments-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
border-radius: $br-8;
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-groups {
|
||||||
|
height: calc(100% - $s-32);
|
||||||
|
overflow-y: scroll;
|
||||||
|
max-height: $s-440;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
background-color: $df-primary;
|
||||||
|
border: 0;
|
||||||
|
height: $s-1;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-groups-placeholder {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-12;
|
||||||
|
padding: $s-24;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: $s-24;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
width: $s-24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-32;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unread svg,
|
||||||
|
&.open svg {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
@include menuShadow;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
bottom: $s-4;
|
||||||
|
height: 40vh;
|
||||||
|
max-height: $s-480;
|
||||||
|
min-height: $s-200;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
z-index: $z-index-3;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 0;
|
||||||
|
border-color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
height: $s-40;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 $s-12;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-11;
|
||||||
|
line-height: 1.28;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
svg {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,28 +5,29 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.files
|
(ns app.main.ui.dashboard.files
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.main.data.dashboard :as dd]
|
[app.main.data.dashboard :as dd]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.dashboard.grid :refer [grid]]
|
[app.main.ui.dashboard.grid :refer [grid]]
|
||||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||||
[app.main.ui.dashboard.project-menu :refer [project-menu]]
|
[app.main.ui.dashboard.project-menu :refer [project-menu]]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.keyboard :as kbd]
|
[app.util.keyboard :as kbd]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
[app.util.webapi :as wapi]
|
|
||||||
[beicon.core :as rx]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc header
|
(mf/defc header
|
||||||
[{:keys [project create-fn] :as props}]
|
[{:keys [project create-fn] :as props}]
|
||||||
(let [local (mf/use-state
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
local (mf/use-state
|
||||||
{:menu-open false
|
{:menu-open false
|
||||||
:edition false})
|
:edition false})
|
||||||
|
|
||||||
@ -63,79 +64,140 @@
|
|||||||
(dd/clear-selected-files))))]
|
(dd/clear-selected-files))))]
|
||||||
|
|
||||||
|
|
||||||
[:header.dashboard-header
|
(if new-css-system
|
||||||
(if (:is-default project)
|
[:header {:class (stl/css :dashboard-header)}
|
||||||
[:div.dashboard-title#dashboard-drafts-title
|
(if (:is-default project)
|
||||||
[:h1 (tr "labels.drafts")]]
|
[:div#dashboard-drafts-title {:class (stl/css :dashboard-title)}
|
||||||
|
[:h1 (tr "labels.drafts")]]
|
||||||
|
|
||||||
(if (:edition @local)
|
(if (:edition @local)
|
||||||
[:& inline-edition {:content (:name project)
|
[:& inline-edition
|
||||||
:on-end (fn [name]
|
{:content (:name project)
|
||||||
(let [name (str/trim name)]
|
:on-end (fn [name]
|
||||||
(when-not (str/empty? name)
|
(let [name (str/trim name)]
|
||||||
(st/emit! (-> (dd/rename-project (assoc project :name name))
|
(when-not (str/empty? name)
|
||||||
(with-meta {::ev/origin "project"}))))
|
(st/emit! (-> (dd/rename-project (assoc project :name name))
|
||||||
(swap! local assoc :edition false)))}]
|
(with-meta {::ev/origin "project"}))))
|
||||||
[:div.dashboard-title
|
(swap! local assoc :edition false)))}]
|
||||||
[:h1 {:on-double-click on-edit
|
[:div {:class (stl/css :dashboard-title)}
|
||||||
:data-test "project-title"
|
[:h1 {:on-double-click on-edit
|
||||||
:id (:id project)}
|
:data-test "project-title"
|
||||||
(:name project)]]))
|
:id (:id project)}
|
||||||
|
(:name project)]]))
|
||||||
|
|
||||||
[:& project-menu {:project project
|
[:& project-menu {:project project
|
||||||
:show? (:menu-open @local)
|
:show? (:menu-open @local)
|
||||||
:left (- (:x (:menu-pos @local)) 180)
|
:left (- (:x (:menu-pos @local)) 180)
|
||||||
:top (:y (:menu-pos @local))
|
:top (:y (:menu-pos @local))
|
||||||
:on-edit on-edit
|
:on-edit on-edit
|
||||||
:on-menu-close on-menu-close
|
:on-menu-close on-menu-close
|
||||||
:on-import on-import}]
|
:on-import on-import}]
|
||||||
|
|
||||||
[:div.dashboard-header-actions
|
[:div {:class (stl/css :dashboard-header-actions)}
|
||||||
[:a.btn-secondary.btn-small
|
[:a
|
||||||
{:tab-index "0"
|
{:class (stl/css :btn-secondary :btn-small)
|
||||||
:on-click on-create-click
|
:tab-index "0"
|
||||||
:data-test "new-file"
|
:on-click on-create-click
|
||||||
:on-key-down (fn [event]
|
:data-test "new-file"
|
||||||
(when (kbd/enter? event)
|
|
||||||
(on-create-click event)))}
|
|
||||||
(tr "dashboard.new-file")]
|
|
||||||
|
|
||||||
(when-not (:is-default project)
|
|
||||||
[:button.icon.pin-icon.tooltip.tooltip-bottom
|
|
||||||
{:tab-index "0"
|
|
||||||
:class (when (:is-pinned project) "active")
|
|
||||||
:on-click toggle-pin
|
|
||||||
:alt (tr "dashboard.pin-unpin")
|
|
||||||
:on-key-down (fn [event]
|
:on-key-down (fn [event]
|
||||||
(when (kbd/enter? event)
|
(when (kbd/enter? event)
|
||||||
(toggle-pin event)))}
|
(on-create-click event)))}
|
||||||
(if (:is-pinned project)
|
(tr "dashboard.new-file")]
|
||||||
i/pin-fill
|
|
||||||
i/pin)])
|
|
||||||
|
|
||||||
[:div.icon.tooltip.tooltip-bottom-left
|
(when-not (:is-default project)
|
||||||
{:tab-index "0"
|
[:button
|
||||||
:on-click on-menu-click
|
{:class (stl/css-case :icon true
|
||||||
:alt (tr "dashboard.options")
|
:pin-icon true
|
||||||
:on-key-down (fn [event]
|
:tooltip true
|
||||||
(when (kbd/enter? event)
|
:tooltip-bottom true
|
||||||
(on-menu-click event)))}
|
:active (:is-pinned project))
|
||||||
i/actions]]]))
|
:tab-index "0"
|
||||||
|
:on-click toggle-pin
|
||||||
|
:alt (tr "dashboard.pin-unpin")
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(toggle-pin event)))}
|
||||||
|
(if (:is-pinned project)
|
||||||
|
i/pin-fill
|
||||||
|
i/pin)])
|
||||||
|
|
||||||
|
[:div
|
||||||
|
{:class (stl/css :icon :tooltip :tooltip-bottom-left)
|
||||||
|
:tab-index "0"
|
||||||
|
:on-click on-menu-click
|
||||||
|
:alt (tr "dashboard.options")
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-menu-click event)))}
|
||||||
|
i/actions]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:header.dashboard-header
|
||||||
|
(if (:is-default project)
|
||||||
|
[:div.dashboard-title#dashboard-drafts-title
|
||||||
|
[:h1 (tr "labels.drafts")]]
|
||||||
|
|
||||||
|
(if (:edition @local)
|
||||||
|
[:& inline-edition {:content (:name project)
|
||||||
|
:on-end (fn [name]
|
||||||
|
(let [name (str/trim name)]
|
||||||
|
(when-not (str/empty? name)
|
||||||
|
(st/emit! (-> (dd/rename-project (assoc project :name name))
|
||||||
|
(with-meta {::ev/origin "project"}))))
|
||||||
|
(swap! local assoc :edition false)))}]
|
||||||
|
[:div.dashboard-title
|
||||||
|
[:h1 {:on-double-click on-edit
|
||||||
|
:data-test "project-title"
|
||||||
|
:id (:id project)}
|
||||||
|
(:name project)]]))
|
||||||
|
|
||||||
|
[:& project-menu {:project project
|
||||||
|
:show? (:menu-open @local)
|
||||||
|
:left (- (:x (:menu-pos @local)) 180)
|
||||||
|
:top (:y (:menu-pos @local))
|
||||||
|
:on-edit on-edit
|
||||||
|
:on-menu-close on-menu-close
|
||||||
|
:on-import on-import}]
|
||||||
|
|
||||||
|
[:div.dashboard-header-actions
|
||||||
|
[:a.btn-secondary.btn-small
|
||||||
|
{:tab-index "0"
|
||||||
|
:on-click on-create-click
|
||||||
|
:data-test "new-file"
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-create-click event)))}
|
||||||
|
(tr "dashboard.new-file")]
|
||||||
|
|
||||||
|
(when-not (:is-default project)
|
||||||
|
[:button.icon.pin-icon.tooltip.tooltip-bottom
|
||||||
|
{:tab-index "0"
|
||||||
|
:class (when (:is-pinned project) "active")
|
||||||
|
:on-click toggle-pin
|
||||||
|
:alt (tr "dashboard.pin-unpin")
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(toggle-pin event)))}
|
||||||
|
(if (:is-pinned project)
|
||||||
|
i/pin-fill
|
||||||
|
i/pin)])
|
||||||
|
|
||||||
|
[:div.icon.tooltip.tooltip-bottom-left
|
||||||
|
{:tab-index "0"
|
||||||
|
:on-click on-menu-click
|
||||||
|
:alt (tr "dashboard.options")
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-menu-click event)))}
|
||||||
|
i/actions]]])))
|
||||||
|
|
||||||
(mf/defc files-section
|
(mf/defc files-section
|
||||||
[{:keys [project team] :as props}]
|
[{:keys [project team] :as props}]
|
||||||
(let [files-map (mf/deref refs/dashboard-files)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
files-map (mf/deref refs/dashboard-files)
|
||||||
project-id (:id project)
|
project-id (:id project)
|
||||||
width (mf/use-state nil)
|
|
||||||
rowref (mf/use-ref)
|
|
||||||
itemsize (if (>= @width 1030)
|
|
||||||
280
|
|
||||||
230)
|
|
||||||
|
|
||||||
ratio (if (some? @width) (/ @width itemsize) 0)
|
[rowref limit] (hooks/use-dynamic-grid-item-width)
|
||||||
nitems (mth/floor ratio)
|
|
||||||
limit (min 10 nitems)
|
|
||||||
limit (max 1 limit)
|
|
||||||
|
|
||||||
files (mf/with-memo [project-id files-map]
|
files (mf/with-memo [project-id files-map]
|
||||||
(->> (vals files-map)
|
(->> (vals files-map)
|
||||||
@ -160,21 +222,6 @@
|
|||||||
(st/emit! (-> (dd/create-file (with-meta params mdata))
|
(st/emit! (-> (dd/create-file (with-meta params mdata))
|
||||||
(with-meta {::ev/origin origin}))))))]
|
(with-meta {::ev/origin origin}))))))]
|
||||||
|
|
||||||
(mf/with-effect []
|
|
||||||
(let [node (mf/ref-val rowref)
|
|
||||||
mnt? (volatile! true)
|
|
||||||
sub (->> (wapi/observe-resize node)
|
|
||||||
(rx/observe-on :af)
|
|
||||||
(rx/subs (fn [entries]
|
|
||||||
(let [row (first entries)
|
|
||||||
row-rect (.-contentRect ^js row)
|
|
||||||
row-width (.-width ^js row-rect)]
|
|
||||||
(when @mnt?
|
|
||||||
(reset! width row-width))))))]
|
|
||||||
(fn []
|
|
||||||
(vreset! mnt? false)
|
|
||||||
(rx/dispose! sub))))
|
|
||||||
|
|
||||||
(mf/with-effect [project]
|
(mf/with-effect [project]
|
||||||
(when project
|
(when project
|
||||||
(let [pname (if (:is-default project)
|
(let [pname (if (:is-default project)
|
||||||
@ -186,14 +233,28 @@
|
|||||||
(st/emit! (dd/fetch-files {:project-id project-id})
|
(st/emit! (dd/fetch-files {:project-id project-id})
|
||||||
(dd/clear-selected-files)))
|
(dd/clear-selected-files)))
|
||||||
|
|
||||||
[:*
|
(if new-css-system
|
||||||
[:& header {:team team
|
[:*
|
||||||
:project project
|
[:& header {:team team
|
||||||
:create-fn create-file}]
|
:project project
|
||||||
[:section.dashboard-container.no-bg {:ref rowref}
|
:create-fn create-file}]
|
||||||
[:& grid {:project project
|
[:section {:class (stl/css :dashboard-container :no-bg)
|
||||||
:files files
|
:ref rowref}
|
||||||
:origin :files
|
[:& grid {:project project
|
||||||
:create-fn create-file
|
:files files
|
||||||
:limit limit}]]]))
|
:origin :files
|
||||||
|
:create-fn create-file
|
||||||
|
:limit limit}]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:*
|
||||||
|
[:& header {:team team
|
||||||
|
:project project
|
||||||
|
:create-fn create-file}]
|
||||||
|
[:section.dashboard-container.no-bg {:ref rowref}
|
||||||
|
[:& grid {:project project
|
||||||
|
:files files
|
||||||
|
:origin :files
|
||||||
|
:create-fn create-file
|
||||||
|
:limit limit}]]])))
|
||||||
|
|
||||||
|
|||||||
28
frontend/src/app/main/ui/dashboard/files.scss
Normal file
28
frontend/src/app/main/ui/dashboard/files.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: $s-16;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
&.dashboard-projects {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.dashboard-shared {
|
||||||
|
width: calc(100vw - $s-320);
|
||||||
|
margin-right: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.fonts
|
(ns app.main.ui.dashboard.fonts
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.media :as cm]
|
[app.common.media :as cm]
|
||||||
[app.main.data.fonts :as df]
|
[app.main.data.fonts :as df]
|
||||||
@ -14,6 +15,7 @@
|
|||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.context-menu :refer [context-menu]]
|
[app.main.ui.components.context-menu :refer [context-menu]]
|
||||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
@ -38,29 +40,17 @@
|
|||||||
(mf/defc header
|
(mf/defc header
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [section team] :as props}]
|
[{:keys [section team] :as props}]
|
||||||
;; (let [go-fonts
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
;; (mf/use-callback
|
(use-set-page-title team section)
|
||||||
;; (mf/deps team)
|
(if new-css-system
|
||||||
;; #(st/emit! (rt/nav :dashboard-fonts {:team-id (:id team)})))
|
[:header {:class (stl/css :dashboard-header)}
|
||||||
|
[:div#dashboard-fonts-title {:class (stl/css :dashboard-title)}
|
||||||
|
[:h1 (tr "labels.fonts")]]]
|
||||||
|
|
||||||
;; go-providers
|
;; OLD
|
||||||
;; (mf/use-callback
|
[:header.dashboard-header
|
||||||
;; (mf/deps team)
|
[:div.dashboard-title#dashboard-fonts-title
|
||||||
;; #(st/emit! (rt/nav :dashboard-font-providers {:team-id (:id team)})))]
|
[:h1 (tr "labels.fonts")]]])))
|
||||||
|
|
||||||
(use-set-page-title team section)
|
|
||||||
|
|
||||||
[:header.dashboard-header
|
|
||||||
[:div.dashboard-title#dashboard-fonts-title
|
|
||||||
[:h1 (tr "labels.fonts")]]
|
|
||||||
[:nav
|
|
||||||
#_[:ul
|
|
||||||
[:li {:class (when (= section :fonts) "active")}
|
|
||||||
[:a {:on-click go-fonts} (tr "labels.custom-fonts")]]
|
|
||||||
[:li {:class (when (= section :providers) "active")}
|
|
||||||
[:a {:on-click go-providers} (tr "labels.font-providers")]]]]
|
|
||||||
|
|
||||||
[:div]])
|
|
||||||
|
|
||||||
(mf/defc font-variant-display-name
|
(mf/defc font-variant-display-name
|
||||||
[{:keys [variant]}]
|
[{:keys [variant]}]
|
||||||
@ -71,7 +61,8 @@
|
|||||||
|
|
||||||
(mf/defc fonts-upload
|
(mf/defc fonts-upload
|
||||||
[{:keys [team installed-fonts] :as props}]
|
[{:keys [team installed-fonts] :as props}]
|
||||||
(let [fonts (mf/use-state {})
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
fonts (mf/use-state {})
|
||||||
input-ref (mf/use-ref)
|
input-ref (mf/use-ref)
|
||||||
|
|
||||||
uploading (mf/use-state #{})
|
uploading (mf/use-state #{})
|
||||||
@ -122,78 +113,159 @@
|
|||||||
(fn [items]
|
(fn [items]
|
||||||
(run! on-delete items))
|
(run! on-delete items))
|
||||||
|
|
||||||
problematic-fonts? (some :height-warning? (vals @fonts))]
|
problematic-fonts? (some :height-warning? (vals @fonts))
|
||||||
|
|
||||||
[:div.dashboard-fonts-upload
|
handle-upload-all
|
||||||
[:div.dashboard-fonts-hero
|
(mf/use-callback (mf/deps @fonts) #(on-upload-all (vals @fonts)))
|
||||||
[:div.desc
|
|
||||||
[:h2 (tr "labels.upload-custom-fonts")]
|
|
||||||
[:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}]
|
|
||||||
|
|
||||||
[:div.banner
|
handle-dismiss-all
|
||||||
[:div.icon i/msg-info]
|
(mf/use-callback (mf/deps @fonts) #(on-dismiss-all (vals @fonts)))]
|
||||||
[:div.content
|
|
||||||
[:& i18n/tr-html {:tag-name "span"
|
|
||||||
:label "dashboard.fonts.hero-text2"}]]]
|
|
||||||
|
|
||||||
(when problematic-fonts?
|
(if new-css-system
|
||||||
[:div.banner.warning
|
[:div {:class (stl/css :dashboard-fonts-upload)}
|
||||||
[:div.icon i/msg-warning]
|
[:div {:class (stl/css :dashboard-fonts-hero)}
|
||||||
|
[:div {:class (stl/css :desc)}
|
||||||
|
[:h2 (tr "labels.upload-custom-fonts")]
|
||||||
|
[:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}]
|
||||||
|
|
||||||
|
[:button
|
||||||
|
{:class (stl/css :btn-primary)
|
||||||
|
:on-click on-click
|
||||||
|
:tab-index "0"}
|
||||||
|
[:span (tr "labels.add-custom-font")]
|
||||||
|
[:& file-uploader {:input-id "font-upload"
|
||||||
|
:accept cm/str-font-types
|
||||||
|
:multi true
|
||||||
|
:ref input-ref
|
||||||
|
:on-selected on-selected}]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :banner)}
|
||||||
|
[:div {:class (stl/css :icon)} i/msg-info]
|
||||||
|
[:div {:class (stl/css :content)}
|
||||||
|
[:& i18n/tr-html {:tag-name "span"
|
||||||
|
:label "dashboard.fonts.hero-text2"}]]]
|
||||||
|
|
||||||
|
(when problematic-fonts?
|
||||||
|
[:div {:class (stl/css :banner :warning)}
|
||||||
|
[:div {:class (stl/css :icon)} i/msg-warning]
|
||||||
|
[:div {:class (stl/css :content)}
|
||||||
|
[:& i18n/tr-html {:tag-name "span"
|
||||||
|
:label "dashboard.fonts.warning-text"}]]])]]
|
||||||
|
|
||||||
|
[:*
|
||||||
|
(when (some? (vals @fonts))
|
||||||
|
[:div {:class (stl/css :font-item :table-row)}
|
||||||
|
[:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))]
|
||||||
|
[:div {:class (stl/css :table-field :options)}
|
||||||
|
[:button {:class (stl/css :btn-primary)
|
||||||
|
:on-click handle-upload-all :data-test "upload-all"}
|
||||||
|
[:span (tr "dashboard.fonts.upload-all")]]
|
||||||
|
[:button {:class (stl/css :btn-secondary)
|
||||||
|
:on-click handle-dismiss-all :data-test "dismiss-all"}
|
||||||
|
[:span (tr "dashboard.fonts.dismiss-all")]]]])
|
||||||
|
|
||||||
|
(for [item (sort-by :font-family (vals @fonts))]
|
||||||
|
(let [uploading? (contains? @uploading (:id item))]
|
||||||
|
[:div {:class (stl/css :font-item :table-row) :key (:id item)}
|
||||||
|
[:div {:class (stl/css :table-field :family)}
|
||||||
|
[:input {:type "text"
|
||||||
|
:on-blur #(on-blur-name (:id item) %)
|
||||||
|
:default-value (:font-family item)}]]
|
||||||
|
[:div {:class (stl/css :table-field :variants)}
|
||||||
|
[:span {:class (stl/css :label)}
|
||||||
|
[:& font-variant-display-name {:variant item}]]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :table-field :filenames)}
|
||||||
|
(for [item (:names item)]
|
||||||
|
[:span item])]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :table-field :options)}
|
||||||
|
(when (:height-warning? item)
|
||||||
|
[:span {:class (stl/css :icon :failure)} i/msg-warning])
|
||||||
|
|
||||||
|
[:button
|
||||||
|
{:on-click #(on-upload item)
|
||||||
|
:class (stl/css-case :btn-primary true
|
||||||
|
:upload-button true
|
||||||
|
:disabled uploading?)
|
||||||
|
:disabled uploading?}
|
||||||
|
(if uploading?
|
||||||
|
(tr "labels.uploading")
|
||||||
|
(tr "labels.upload"))]
|
||||||
|
[:span {:class (stl/css :icon :close)
|
||||||
|
:on-click #(on-delete item)} i/close]]]))]]
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-fonts-upload
|
||||||
|
[:div.dashboard-fonts-hero
|
||||||
|
[:div.desc
|
||||||
|
[:h2 (tr "labels.upload-custom-fonts")]
|
||||||
|
[:& i18n/tr-html {:label "dashboard.fonts.hero-text1"}]
|
||||||
|
|
||||||
|
[:div.banner
|
||||||
|
[:div.icon i/msg-info]
|
||||||
[:div.content
|
[:div.content
|
||||||
[:& i18n/tr-html {:tag-name "span"
|
[:& i18n/tr-html {:tag-name "span"
|
||||||
:label "dashboard.fonts.warning-text"}]]])]
|
:label "dashboard.fonts.hero-text2"}]]]
|
||||||
|
|
||||||
[:button.btn-primary
|
(when problematic-fonts?
|
||||||
{:on-click on-click
|
[:div.banner.warning
|
||||||
:tab-index "0"}
|
[:div.icon i/msg-warning]
|
||||||
[:span (tr "labels.add-custom-font")]
|
[:div.content
|
||||||
[:& file-uploader {:input-id "font-upload"
|
[:& i18n/tr-html {:tag-name "span"
|
||||||
:accept cm/str-font-types
|
:label "dashboard.fonts.warning-text"}]]])]
|
||||||
:multi true
|
|
||||||
:ref input-ref
|
|
||||||
:on-selected on-selected}]]]
|
|
||||||
|
|
||||||
[:*
|
[:button.btn-primary
|
||||||
(when (some? (vals @fonts))
|
{:on-click on-click
|
||||||
[:div.font-item.table-row
|
:tab-index "0"}
|
||||||
[:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))]
|
[:span (tr "labels.add-custom-font")]
|
||||||
[:div.table-field.options
|
[:& file-uploader {:input-id "font-upload"
|
||||||
[:div.btn-primary
|
:accept cm/str-font-types
|
||||||
{:on-click #(on-upload-all (vals @fonts)) :data-test "upload-all"}
|
:multi true
|
||||||
[:span (tr "dashboard.fonts.upload-all")]]
|
:ref input-ref
|
||||||
[:div.btn-secondary
|
:on-selected on-selected}]]]
|
||||||
{:on-click #(on-dismiss-all (vals @fonts)) :data-test "dismiss-all"}
|
|
||||||
[:span (tr "dashboard.fonts.dismiss-all")]]]])
|
|
||||||
|
|
||||||
(for [item (sort-by :font-family (vals @fonts))]
|
|
||||||
(let [uploading? (contains? @uploading (:id item))]
|
|
||||||
[:div.font-item.table-row {:key (:id item)}
|
|
||||||
[:div.table-field.family
|
|
||||||
[:input {:type "text"
|
|
||||||
:on-blur #(on-blur-name (:id item) %)
|
|
||||||
:default-value (:font-family item)}]]
|
|
||||||
[:div.table-field.variants
|
|
||||||
[:span.label
|
|
||||||
[:& font-variant-display-name {:variant item}]]]
|
|
||||||
[:div.table-field.filenames
|
|
||||||
(for [item (:names item)]
|
|
||||||
[:span item])]
|
|
||||||
|
|
||||||
|
[:*
|
||||||
|
(when (some? (vals @fonts))
|
||||||
|
[:div.font-item.table-row
|
||||||
|
[:span (tr "dashboard.fonts.fonts-added" (i18n/c (count (vals @fonts))))]
|
||||||
[:div.table-field.options
|
[:div.table-field.options
|
||||||
(when (:height-warning? item)
|
[:div.btn-primary
|
||||||
[:span.icon.failure i/msg-warning])
|
{:on-click #(on-upload-all (vals @fonts)) :data-test "upload-all"}
|
||||||
[:button.btn-primary.upload-button
|
[:span (tr "dashboard.fonts.upload-all")]]
|
||||||
{:on-click #(on-upload item)
|
[:div.btn-secondary
|
||||||
:class (dom/classnames :disabled uploading?)
|
{:on-click #(on-dismiss-all (vals @fonts)) :data-test "dismiss-all"}
|
||||||
:disabled uploading?}
|
[:span (tr "dashboard.fonts.dismiss-all")]]]])
|
||||||
(if uploading?
|
|
||||||
(tr "labels.uploading")
|
(for [item (sort-by :font-family (vals @fonts))]
|
||||||
(tr "labels.upload"))]
|
(let [uploading? (contains? @uploading (:id item))]
|
||||||
[:span.icon.close {:on-click #(on-delete item)} i/close]]]))]]))
|
[:div.font-item.table-row {:key (:id item)}
|
||||||
|
[:div.table-field.family
|
||||||
|
[:input {:type "text"
|
||||||
|
:on-blur #(on-blur-name (:id item) %)
|
||||||
|
:default-value (:font-family item)}]]
|
||||||
|
[:div.table-field.variants
|
||||||
|
[:span.label
|
||||||
|
[:& font-variant-display-name {:variant item}]]]
|
||||||
|
[:div.table-field.filenames
|
||||||
|
(for [item (:names item)]
|
||||||
|
[:span item])]
|
||||||
|
|
||||||
|
[:div.table-field.options
|
||||||
|
(when (:height-warning? item)
|
||||||
|
[:span.icon.failure i/msg-warning])
|
||||||
|
[:button.btn-primary.upload-button
|
||||||
|
{:on-click #(on-upload item)
|
||||||
|
:class (dom/classnames :disabled uploading?)
|
||||||
|
:disabled uploading?}
|
||||||
|
(if uploading?
|
||||||
|
(tr "labels.uploading")
|
||||||
|
(tr "labels.upload"))]
|
||||||
|
[:span.icon.close {:on-click #(on-delete item)} i/close]]]))]])))
|
||||||
|
|
||||||
(mf/defc installed-font
|
(mf/defc installed-font
|
||||||
[{:keys [font-id variants] :as props}]
|
[{:keys [font-id variants] :as props}]
|
||||||
(let [font (first variants)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
font (first variants)
|
||||||
|
|
||||||
variants (sort-by (fn [item]
|
variants (sort-by (fn [item]
|
||||||
[(:font-weight item)
|
[(:font-weight item)
|
||||||
@ -252,50 +324,94 @@
|
|||||||
:on-accept (fn [_props]
|
:on-accept (fn [_props]
|
||||||
(delete-variant-fn id))})))]
|
(delete-variant-fn id))})))]
|
||||||
|
|
||||||
[:div.font-item.table-row
|
(if new-css-system
|
||||||
[:div.table-field.family
|
[:div {:class (stl/css :font-item :table-row)}
|
||||||
(if @edit?
|
[:div {:class (stl/css :table-field :family)}
|
||||||
[:input {:type "text"
|
(if @edit?
|
||||||
:default-value @state
|
[:input {:type "text"
|
||||||
:on-key-down on-key-down
|
:default-value @state
|
||||||
:on-change on-change}]
|
:on-key-down on-key-down
|
||||||
[:span (:font-family font)])]
|
:on-change on-change}]
|
||||||
|
[:span (:font-family font)])]
|
||||||
|
|
||||||
[:div.table-field.variants
|
[:div {:class (stl/css :table-field :variants)}
|
||||||
(for [item variants]
|
(for [item variants]
|
||||||
[:div.variant
|
[:div {:class (stl/css :variant)}
|
||||||
[:span.label
|
[:span {:class (stl/css :label)}
|
||||||
[:& font-variant-display-name {:variant item}]]
|
[:& font-variant-display-name {:variant item}]]
|
||||||
[:span.icon.close
|
[:span
|
||||||
{:on-click #(on-delete-variant (:id item))}
|
{:class (stl/css :icon :close)
|
||||||
i/plus]])]
|
:on-click #(on-delete-variant (:id item))}
|
||||||
|
i/plus]])]
|
||||||
|
|
||||||
[:div]
|
(if @edit?
|
||||||
|
[:div {:class (stl/css :table-field :options)}
|
||||||
|
[:button
|
||||||
|
{:disabled (str/blank? @state)
|
||||||
|
:on-click on-save
|
||||||
|
:class (stl/css-case :btn-primary true
|
||||||
|
:btn-disabled (str/blank? @state))}
|
||||||
|
(tr "labels.save")]
|
||||||
|
[:button {:class (stl/css :icon :close)
|
||||||
|
:on-click on-cancel} i/close]]
|
||||||
|
|
||||||
(if @edit?
|
[:div {:class (stl/css :table-field :options)}
|
||||||
[:div.table-field.options
|
[:span {:class (stl/css :icon)
|
||||||
[:button.btn-primary
|
:on-click #(reset! open-menu? true)} i/actions]
|
||||||
{:disabled (str/blank? @state)
|
[:& context-menu
|
||||||
:on-click on-save
|
{:on-close #(reset! open-menu? false)
|
||||||
:class (dom/classnames :btn-disabled (str/blank? @state))}
|
:show @open-menu?
|
||||||
(tr "labels.save")]
|
:fixed? false
|
||||||
[:span.icon.close {:on-click on-cancel} i/close]]
|
:top -15
|
||||||
|
:left -115
|
||||||
|
:options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"]
|
||||||
|
[(tr "labels.delete") on-delete nil "font-delete"]]}]])]
|
||||||
|
;;OLD
|
||||||
|
[:div.font-item.table-row
|
||||||
|
[:div.table-field.family
|
||||||
|
(if @edit?
|
||||||
|
[:input {:type "text"
|
||||||
|
:default-value @state
|
||||||
|
:on-key-down on-key-down
|
||||||
|
:on-change on-change}]
|
||||||
|
[:span (:font-family font)])]
|
||||||
|
|
||||||
[:div.table-field.options
|
[:div.table-field.variants
|
||||||
[:span.icon {:on-click #(reset! open-menu? true)} i/actions]
|
(for [item variants]
|
||||||
[:& context-menu
|
[:div.variant
|
||||||
{:on-close #(reset! open-menu? false)
|
[:span.label
|
||||||
:show @open-menu?
|
[:& font-variant-display-name {:variant item}]]
|
||||||
:fixed? false
|
[:span.icon.close
|
||||||
:top -15
|
{:on-click #(on-delete-variant (:id item))}
|
||||||
:left -115
|
i/plus]])]
|
||||||
:options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"]
|
|
||||||
[(tr "labels.delete") on-delete nil "font-delete"]]}]])]))
|
[:div]
|
||||||
|
|
||||||
|
(if @edit?
|
||||||
|
[:div.table-field.options
|
||||||
|
[:button.btn-primary
|
||||||
|
{:disabled (str/blank? @state)
|
||||||
|
:on-click on-save
|
||||||
|
:class (dom/classnames :btn-disabled (str/blank? @state))}
|
||||||
|
(tr "labels.save")]
|
||||||
|
[:span.icon.close {:on-click on-cancel} i/close]]
|
||||||
|
|
||||||
|
[:div.table-field.options
|
||||||
|
[:span.icon {:on-click #(reset! open-menu? true)} i/actions]
|
||||||
|
[:& context-menu
|
||||||
|
{:on-close #(reset! open-menu? false)
|
||||||
|
:show @open-menu?
|
||||||
|
:fixed? false
|
||||||
|
:top -15
|
||||||
|
:left -115
|
||||||
|
:options [[(tr "labels.edit") #(reset! edit? true) nil "font-edit"]
|
||||||
|
[(tr "labels.delete") on-delete nil "font-delete"]]}]])])))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc installed-fonts
|
(mf/defc installed-fonts
|
||||||
[{:keys [fonts] :as props}]
|
[{:keys [fonts] :as props}]
|
||||||
(let [sterm (mf/use-state "")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
sterm (mf/use-state "")
|
||||||
|
|
||||||
matches?
|
matches?
|
||||||
#(str/includes? (str/lower (:font-family %)) @sterm)
|
#(str/includes? (str/lower (:font-family %)) @sterm)
|
||||||
@ -306,48 +422,98 @@
|
|||||||
(let [val (dom/get-target-val event)]
|
(let [val (dom/get-target-val event)]
|
||||||
(reset! sterm (str/lower val)))))]
|
(reset! sterm (str/lower val)))))]
|
||||||
|
|
||||||
[:div.dashboard-installed-fonts
|
(if new-css-system
|
||||||
[:h3 (tr "labels.installed-fonts")]
|
[:div {:class (stl/css :dashboard-installed-fonts)}
|
||||||
[:div.installed-fonts-header
|
[:h3 (tr "labels.installed-fonts")]
|
||||||
[:div.table-field.family (tr "labels.font-family")]
|
[:div {:class (stl/css :installed-fonts-header)}
|
||||||
[:div.table-field.variants (tr "labels.font-variants")]
|
[:div {:class (stl/css :table-field :family)} (tr "labels.font-family")]
|
||||||
[:div]
|
[:div {:class (stl/css :table-field :variants)} (tr "labels.font-variants")]
|
||||||
[:div.table-field.search-input
|
[:div {:class (stl/css :table-field :search-input)}
|
||||||
[:input {:placeholder (tr "labels.search-font")
|
[:input {:placeholder (tr "labels.search-font")
|
||||||
:default-value ""
|
:default-value ""
|
||||||
:on-change on-change}]]]
|
:on-change on-change}]]]
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(seq fonts)
|
(seq fonts)
|
||||||
(for [[font-id variants] (->> (vals fonts)
|
(for [[font-id variants] (->> (vals fonts)
|
||||||
(filter matches?)
|
(filter matches?)
|
||||||
(group-by :font-id))]
|
(group-by :font-id))]
|
||||||
[:& installed-font {:key (str font-id)
|
[:& installed-font {:key (str font-id)
|
||||||
:font-id font-id
|
:font-id font-id
|
||||||
:variants variants}])
|
:variants variants}])
|
||||||
|
|
||||||
(nil? fonts)
|
(nil? fonts)
|
||||||
[:div.fonts-placeholder
|
[:div {:class (stl/css :fonts-placeholder)}
|
||||||
[:div.icon i/loader]
|
[:div {:class (stl/css :icon)} i/loader]
|
||||||
[:div.label (tr "dashboard.loading-fonts")]]
|
[:div {:class (stl/css :label)} (tr "dashboard.loading-fonts")]]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[:div.fonts-placeholder
|
[:div {:class (stl/css :fonts-placeholder)}
|
||||||
[:div.icon i/text]
|
[:div {:class (stl/css :icon)} i/text]
|
||||||
[:div.label (tr "dashboard.fonts.empty-placeholder")]])]))
|
[:div {:class (stl/css :label)} (tr "dashboard.fonts.empty-placeholder")]])]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-installed-fonts
|
||||||
|
[:h3 (tr "labels.installed-fonts")]
|
||||||
|
[:div.installed-fonts-header
|
||||||
|
[:div.table-field.family (tr "labels.font-family")]
|
||||||
|
[:div.table-field.variants (tr "labels.font-variants")]
|
||||||
|
[:div]
|
||||||
|
[:div.table-field.search-input
|
||||||
|
[:input {:placeholder (tr "labels.search-font")
|
||||||
|
:default-value ""
|
||||||
|
:on-change on-change}]]]
|
||||||
|
|
||||||
|
(cond
|
||||||
|
(seq fonts)
|
||||||
|
(for [[font-id variants] (->> (vals fonts)
|
||||||
|
(filter matches?)
|
||||||
|
(group-by :font-id))]
|
||||||
|
[:& installed-font {:key (str font-id)
|
||||||
|
:font-id font-id
|
||||||
|
:variants variants}])
|
||||||
|
|
||||||
|
(nil? fonts)
|
||||||
|
[:div.fonts-placeholder
|
||||||
|
[:div.icon i/loader]
|
||||||
|
[:div.label (tr "dashboard.loading-fonts")]]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:div.fonts-placeholder
|
||||||
|
[:div.icon i/text]
|
||||||
|
[:div.label (tr "dashboard.fonts.empty-placeholder")]])])))
|
||||||
|
|
||||||
(mf/defc fonts-page
|
(mf/defc fonts-page
|
||||||
[{:keys [team] :as props}]
|
[{:keys [team] :as props}]
|
||||||
(let [fonts (mf/deref refs/dashboard-fonts)]
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
[:*
|
fonts (mf/deref refs/dashboard-fonts)]
|
||||||
[:& header {:team team :section :fonts}]
|
(if new-css-system
|
||||||
[:section.dashboard-container.dashboard-fonts
|
[:*
|
||||||
[:& fonts-upload {:team team :installed-fonts fonts}]
|
[:& header {:team team :section :fonts}]
|
||||||
[:& installed-fonts {:team team :fonts fonts}]]]))
|
[:section {:class (stl/css :dashboard-container :dashboard-fonts)}
|
||||||
|
[:& fonts-upload {:team team :installed-fonts fonts}]
|
||||||
|
[:& installed-fonts {:team team :fonts fonts}]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:*
|
||||||
|
[:& header {:team team :section :fonts}]
|
||||||
|
[:section.dashboard-container.dashboard-fonts
|
||||||
|
[:& fonts-upload {:team team :installed-fonts fonts}]
|
||||||
|
[:& installed-fonts {:team team :fonts fonts}]]])))
|
||||||
|
|
||||||
(mf/defc font-providers-page
|
(mf/defc font-providers-page
|
||||||
[{:keys [team] :as props}]
|
[{:keys [team] :as props}]
|
||||||
[:*
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:& header {:team team :section :providers}]
|
(if new-css-system
|
||||||
[:section.dashboard-container
|
[:*
|
||||||
[:span "font providers"]]])
|
[:& header {:team team :section :providers}]
|
||||||
|
[:section {:class (stl/css :dashboard-container)}
|
||||||
|
[:span "font providers"]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:*
|
||||||
|
[:& header {:team team :section :providers}]
|
||||||
|
[:section.dashboard-container
|
||||||
|
[:span "font providers"]]])))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
322
frontend/src/app/main/ui/dashboard/fonts.scss
Normal file
322
frontend/src/app/main/ui/dashboard/fonts.scss
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard-fonts {
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: $s-120;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: $s-120;
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
font-size: $fs-11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-installed-fonts {
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
margin-top: $s-24;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: $fs-14;
|
||||||
|
color: $df-secondary;
|
||||||
|
margin: $s-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-item {
|
||||||
|
color: $db-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.installed-fonts-header {
|
||||||
|
align-items: center;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-12;
|
||||||
|
height: $s-40;
|
||||||
|
padding-left: $s-24;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
> .family {
|
||||||
|
min-width: $s-200;
|
||||||
|
width: $s-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .variants {
|
||||||
|
padding-left: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
input {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-color: transparent;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
height: $s-32;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 $s-8;
|
||||||
|
width: $s-152;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
&::placeholder {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-item {
|
||||||
|
align-items: center;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-4;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-14;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: $s-4;
|
||||||
|
max-width: $s-1000;
|
||||||
|
padding: $s-12 $s-24;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
margin: 0;
|
||||||
|
padding: $s-8;
|
||||||
|
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .family {
|
||||||
|
min-width: $s-200;
|
||||||
|
width: $s-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .filenames {
|
||||||
|
min-width: $s-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .variants {
|
||||||
|
font-size: $fs-14;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-left: $s-16;
|
||||||
|
|
||||||
|
.variant {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: $s-8 $s-12;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
margin-left: $s-6;
|
||||||
|
align-items: center;
|
||||||
|
svg {
|
||||||
|
fill: transparent;
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.icon svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-field {
|
||||||
|
color: $df-primary;
|
||||||
|
.variant {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
margin-right: $s-4;
|
||||||
|
padding-right: $s-4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filenames {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-width: $s-180;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: $s-24;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
margin-left: $s-12;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
&.failure {
|
||||||
|
margin-right: $s-12;
|
||||||
|
svg {
|
||||||
|
fill: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
svg {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-fonts-upload {
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.upload-button {
|
||||||
|
width: $s-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
margin-left: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-fonts-hero {
|
||||||
|
font-size: $fs-14;
|
||||||
|
padding: $s-32 0;
|
||||||
|
margin-top: $s-80;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
height: $s-40;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $s-24;
|
||||||
|
color: $db-secondary;
|
||||||
|
width: $s-500;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $df-primary;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: $s-40 1fr;
|
||||||
|
|
||||||
|
background-color: $db-primary;
|
||||||
|
border-radius: $br-12;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-bottom: $s-12;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: $s-12;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: $s-20;
|
||||||
|
width: $s-20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
margin: $s-12;
|
||||||
|
a {
|
||||||
|
color: $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
.icon svg {
|
||||||
|
fill: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fonts-placeholder {
|
||||||
|
align-items: center;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: $s-160;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: $s-16;
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.icon svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-32;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.grid
|
(ns app.main.ui.dashboard.grid
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
@ -19,6 +20,7 @@
|
|||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.color-bullet :as bc]
|
[app.main.ui.components.color-bullet :as bc]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.dashboard.file-menu :refer [file-menu]]
|
[app.main.ui.dashboard.file-menu :refer [file-menu]]
|
||||||
[app.main.ui.dashboard.import :refer [use-import-file]]
|
[app.main.ui.dashboard.import :refer [use-import-file]]
|
||||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||||
@ -66,7 +68,8 @@
|
|||||||
(mf/defc grid-item-thumbnail
|
(mf/defc grid-item-thumbnail
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [file-id revn thumbnail-uri background-color]}]
|
[{:keys [file-id revn thumbnail-uri background-color]}]
|
||||||
(let [container (mf/use-ref)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
container (mf/use-ref)
|
||||||
visible? (h/use-visible container :once? true)]
|
visible? (h/use-visible container :once? true)]
|
||||||
|
|
||||||
(mf/with-effect [file-id revn visible? thumbnail-uri]
|
(mf/with-effect [file-id revn visible? thumbnail-uri]
|
||||||
@ -80,13 +83,24 @@
|
|||||||
:revn revn
|
:revn revn
|
||||||
:message (ex-message cause)))))))
|
:message (ex-message cause)))))))
|
||||||
|
|
||||||
[:div.grid-item-th
|
(if new-css-system
|
||||||
{:style {:background-color background-color}
|
[:div {:class (stl/css :grid-item-th)
|
||||||
:ref container}
|
:style {:background-color background-color}
|
||||||
(when visible?
|
:ref container}
|
||||||
(if thumbnail-uri
|
(when visible?
|
||||||
[:img.grid-item-thumbnail-image {:src thumbnail-uri}]
|
(if thumbnail-uri
|
||||||
i/loader-pencil))]))
|
[:img {:class (stl/css :grid-item-thumbnail-image)
|
||||||
|
:src thumbnail-uri}]
|
||||||
|
i/loader-pencil))]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.grid-item-th
|
||||||
|
{:style {:background-color background-color}
|
||||||
|
:ref container}
|
||||||
|
(when visible?
|
||||||
|
(if thumbnail-uri
|
||||||
|
[:img.grid-item-thumbnail-image {:src thumbnail-uri}]
|
||||||
|
i/loader-pencil))])))
|
||||||
|
|
||||||
;; --- Grid Item Library
|
;; --- Grid Item Library
|
||||||
|
|
||||||
@ -94,120 +108,228 @@
|
|||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [file] :as props}]
|
[{:keys [file] :as props}]
|
||||||
|
|
||||||
(mf/with-effect [file]
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
(when file
|
(mf/with-effect [file]
|
||||||
(let [font-ids (map :font-id (get-in file [:library-summary :typographies :sample] []))]
|
(when file
|
||||||
(run! fonts/ensure-loaded! font-ids))))
|
(let [font-ids (map :font-id (get-in file [:library-summary :typographies :sample] []))]
|
||||||
|
(run! fonts/ensure-loaded! font-ids))))
|
||||||
|
|
||||||
[:div.grid-item-th.library
|
(if new-css-system
|
||||||
(if (nil? file)
|
[:div {:class (stl/css :grid-item-th :library)}
|
||||||
i/loader-pencil
|
(if (nil? file)
|
||||||
(let [summary (:library-summary file)
|
i/loader-pencil
|
||||||
components (:components summary)
|
(let [summary (:library-summary file)
|
||||||
colors (:colors summary)
|
components (:components summary)
|
||||||
typographies (:typographies summary)]
|
colors (:colors summary)
|
||||||
[:*
|
typographies (:typographies summary)]
|
||||||
|
[:*
|
||||||
(when (and (zero? (:count components)) (zero? (:count colors)) (zero? (:count typographies)))
|
(when (and (zero? (:count components)) (zero? (:count colors)) (zero? (:count typographies)))
|
||||||
[:*
|
[:*
|
||||||
[:div.asset-section
|
[:div {:class (stl/css :asset-section)}
|
||||||
[:div.asset-title
|
[:div {:class (stl/css :asset-title)}
|
||||||
[:span (tr "workspace.assets.components")]
|
[:span (tr "workspace.assets.components")]
|
||||||
[:span.num-assets (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space
|
[:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space
|
||||||
[:div.asset-section
|
[:div {:class (stl/css :asset-section)}
|
||||||
[:div.asset-title
|
[:div {:class (stl/css :asset-title)}
|
||||||
[:span (tr "workspace.assets.colors")]
|
[:span (tr "workspace.assets.colors")]
|
||||||
[:span.num-assets (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space
|
[:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space
|
||||||
[:div.asset-section
|
[:div {:class (stl/css :asset-section)}
|
||||||
[:div.asset-title
|
[:div {:class (stl/css :asset-title)}
|
||||||
[:span (tr "workspace.assets.typography")]
|
[:span (tr "workspace.assets.typography")]
|
||||||
[:span.num-assets (str "\u00A0(") 0 ")"]]]]) ;; Unicode 00A0 is non-breaking space
|
[:span {:class (stl/css :num-assets)} (str "\u00A0(") 0 ")"]]]]) ;; Unicode 00A0 is non-breaking space
|
||||||
|
|
||||||
|
|
||||||
(when (pos? (:count components))
|
(when (pos? (:count components))
|
||||||
[:div.asset-section
|
[:div {:class (stl/css :asset-section)}
|
||||||
[:div.asset-title
|
[:div {:class (stl/css :asset-title)}
|
||||||
[:span (tr "workspace.assets.components")]
|
[:span (tr "workspace.assets.components")]
|
||||||
[:span.num-assets (str "\u00A0(") (:count components) ")"]] ;; Unicode 00A0 is non-breaking space
|
[:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count components) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||||
[:div.asset-list
|
[:div {:class (stl/css :asset-list)}
|
||||||
(for [component (:sample components)]
|
(for [component (:sample components)]
|
||||||
(let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library
|
(let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library
|
||||||
[:div.asset-list-item {:key (str "assets-component-" (:id component))}
|
[:div {:class (stl/css :asset-list-item)
|
||||||
[:& component-svg {:root-shape (get-in component [:objects root-id])
|
:key (str "assets-component-" (:id component))}
|
||||||
:objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2
|
[:& component-svg {:root-shape (get-in component [:objects root-id])
|
||||||
[:div.name-block
|
:objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2
|
||||||
[:span.item-name {:title (:name component)}
|
[:div {:class (stl/css :name-block)}
|
||||||
(:name component)]]]))
|
[:span {:class (stl/css :item-name)
|
||||||
(when (> (:count components) (count (:sample components)))
|
:title (:name component)}
|
||||||
[:div.asset-list-item
|
(:name component)]]]))
|
||||||
[:div.name-block
|
(when (> (:count components) (count (:sample components)))
|
||||||
[:span.item-name "(...)"]]])]])
|
[:div {:class (stl/css :asset-list-item)}
|
||||||
|
[:div {:class (stl/css :name-block)}
|
||||||
|
[:span {:class (stl/css :item-name)} "(...)"]]])]])
|
||||||
|
|
||||||
(when (pos? (:count colors))
|
(when (pos? (:count colors))
|
||||||
[:div.asset-section
|
[:div {:class (stl/css :asset-section)}
|
||||||
[:div.asset-title
|
[:div {:class (stl/css :asset-title)}
|
||||||
[:span (tr "workspace.assets.colors")]
|
[:span (tr "workspace.assets.colors")]
|
||||||
[:span.num-assets (str "\u00A0(") (:count colors) ")"]] ;; Unicode 00A0 is non-breaking space
|
[:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count colors) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||||
[:div.asset-list
|
[:div {:class (stl/css :asset-list)}
|
||||||
(for [color (:sample colors)]
|
(for [color (:sample colors)]
|
||||||
(let [default-name (cond
|
(let [default-name (cond
|
||||||
(:gradient color) (uc/gradient-type->string (get-in color [:gradient :type]))
|
(:gradient color) (uc/gradient-type->string (get-in color [:gradient :type]))
|
||||||
(:color color) (:color color)
|
(:color color) (:color color)
|
||||||
:else (:value color))]
|
:else (:value color))]
|
||||||
[:div.asset-list-item {:key (str "assets-color-" (:id color))}
|
[:div {:class (stl/css :asset-list-item)
|
||||||
[:& bc/color-bullet {:color {:color (:color color)
|
:key (str "assets-color-" (:id color))}
|
||||||
:opacity (:opacity color)}}]
|
[:& bc/color-bullet {:color {:color (:color color)
|
||||||
[:div.name-block
|
:opacity (:opacity color)}}]
|
||||||
[:span.color-name (:name color)]
|
[:div {:class (stl/css :name-block)}
|
||||||
(when-not (= (:name color) default-name)
|
[:span {:class (stl/css :color-name)} (:name color)]
|
||||||
[:span.color-value (:color color)])]]))
|
(when-not (= (:name color) default-name)
|
||||||
(when (> (:count colors) (count (:sample colors)))
|
[:span {:class (stl/css :color-value)} (:color color)])]]))
|
||||||
[:div.asset-list-item
|
|
||||||
[:div.name-block
|
|
||||||
[:span.item-name "(...)"]]])]])
|
|
||||||
|
|
||||||
(when (pos? (:count typographies))
|
(when (> (:count colors) (count (:sample colors)))
|
||||||
[:div.asset-section
|
[:div {:class (stl/css :asset-list-item)}
|
||||||
[:div.asset-title
|
[:div {:class (stl/css :name-block)}
|
||||||
[:span (tr "workspace.assets.typography")]
|
[:span {:class (stl/css :item-name)} "(...)"]]])]])
|
||||||
[:span.num-assets (str "\u00A0(") (:count typographies) ")"]] ;; Unicode 00A0 is non-breaking space
|
|
||||||
[:div.asset-list
|
(when (pos? (:count typographies))
|
||||||
(for [typography (:sample typographies)]
|
[:div {:class (stl/css :asset-section)}
|
||||||
[:div.asset-list-item {:key (str "assets-typography-" (:id typography))}
|
[:div {:class (stl/css :asset-title)}
|
||||||
[:div.typography-sample
|
[:span (tr "workspace.assets.typography")]
|
||||||
{:style {:font-family (:font-family typography)
|
[:span {:class (stl/css :num-assets)} (str "\u00A0(") (:count typographies) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||||
:font-weight (:font-weight typography)
|
[:div {:class (stl/css :asset-list)}
|
||||||
:font-style (:font-style typography)}}
|
(for [typography (:sample typographies)]
|
||||||
(tr "workspace.assets.typography.sample")]
|
[:div {:class (stl/css :asset-list-item)
|
||||||
[:div.name-block
|
:key (str "assets-typography-" (:id typography))}
|
||||||
[:span.item-name {:title (:name typography)}
|
[:div {:class (stl/css :typography-sample)
|
||||||
(:name typography)]]])
|
:style {:font-family (:font-family typography)
|
||||||
(when (> (:count typographies) (count (:sample typographies)))
|
:font-weight (:font-weight typography)
|
||||||
[:div.asset-list-item
|
:font-style (:font-style typography)}}
|
||||||
[:div.name-block
|
(tr "workspace.assets.typography.sample")]
|
||||||
[:span.item-name "(...)"]]])]])]))])
|
[:div {:class (stl/css :name-block)}
|
||||||
|
[:span {:class (stl/css :item-name)
|
||||||
|
:title (:name typography)}
|
||||||
|
(:name typography)]]])
|
||||||
|
|
||||||
|
(when (> (:count typographies) (count (:sample typographies)))
|
||||||
|
[:div {:class (stl/css :asset-list-item)}
|
||||||
|
[:div {:class (stl/css :name-block)}
|
||||||
|
[:span {:class (stl/css :item-name)} "(...)"]]])]])]))]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.grid-item-th.library
|
||||||
|
(if (nil? file)
|
||||||
|
i/loader-pencil
|
||||||
|
(let [summary (:library-summary file)
|
||||||
|
components (:components summary)
|
||||||
|
colors (:colors summary)
|
||||||
|
typographies (:typographies summary)]
|
||||||
|
[:*
|
||||||
|
|
||||||
|
(when (and (zero? (:count components)) (zero? (:count colors)) (zero? (:count typographies)))
|
||||||
|
[:*
|
||||||
|
[:div.asset-section
|
||||||
|
[:div.asset-title
|
||||||
|
[:span (tr "workspace.assets.components")]
|
||||||
|
[:span.num-assets (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space
|
||||||
|
[:div.asset-section
|
||||||
|
[:div.asset-title
|
||||||
|
[:span (tr "workspace.assets.colors")]
|
||||||
|
[:span.num-assets (str "\u00A0(") 0 ")"]]] ;; Unicode 00A0 is non-breaking space
|
||||||
|
[:div.asset-section
|
||||||
|
[:div.asset-title
|
||||||
|
[:span (tr "workspace.assets.typography")]
|
||||||
|
[:span.num-assets (str "\u00A0(") 0 ")"]]]]) ;; Unicode 00A0 is non-breaking space
|
||||||
|
|
||||||
|
|
||||||
|
(when (pos? (:count components))
|
||||||
|
[:div.asset-section
|
||||||
|
[:div.asset-title
|
||||||
|
[:span (tr "workspace.assets.components")]
|
||||||
|
[:span.num-assets (str "\u00A0(") (:count components) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||||
|
[:div.asset-list
|
||||||
|
(for [component (:sample components)]
|
||||||
|
(let [root-id (or (:main-instance-id component) (:id component))] ;; Check for components-v2 in library
|
||||||
|
[:div.asset-list-item {:key (str "assets-component-" (:id component))}
|
||||||
|
[:& component-svg {:root-shape (get-in component [:objects root-id])
|
||||||
|
:objects (:objects component)}] ;; Components in the summary come loaded with objects, even in v2
|
||||||
|
[:div.name-block
|
||||||
|
[:span.item-name {:title (:name component)}
|
||||||
|
(:name component)]]]))
|
||||||
|
(when (> (:count components) (count (:sample components)))
|
||||||
|
[:div.asset-list-item
|
||||||
|
[:div.name-block
|
||||||
|
[:span.item-name "(...)"]]])]])
|
||||||
|
|
||||||
|
(when (pos? (:count colors))
|
||||||
|
[:div.asset-section
|
||||||
|
[:div.asset-title
|
||||||
|
[:span (tr "workspace.assets.colors")]
|
||||||
|
[:span.num-assets (str "\u00A0(") (:count colors) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||||
|
[:div.asset-list
|
||||||
|
(for [color (:sample colors)]
|
||||||
|
(let [default-name (cond
|
||||||
|
(:gradient color) (uc/gradient-type->string (get-in color [:gradient :type]))
|
||||||
|
(:color color) (:color color)
|
||||||
|
:else (:value color))]
|
||||||
|
[:div.asset-list-item {:key (str "assets-color-" (:id color))}
|
||||||
|
[:& bc/color-bullet {:color {:color (:color color)
|
||||||
|
:opacity (:opacity color)}}]
|
||||||
|
[:div.name-block
|
||||||
|
[:span.color-name (:name color)]
|
||||||
|
(when-not (= (:name color) default-name)
|
||||||
|
[:span.color-value (:color color)])]]))
|
||||||
|
(when (> (:count colors) (count (:sample colors)))
|
||||||
|
[:div.asset-list-item
|
||||||
|
[:div.name-block
|
||||||
|
[:span.item-name "(...)"]]])]])
|
||||||
|
|
||||||
|
(when (pos? (:count typographies))
|
||||||
|
[:div.asset-section
|
||||||
|
[:div.asset-title
|
||||||
|
[:span (tr "workspace.assets.typography")]
|
||||||
|
[:span.num-assets (str "\u00A0(") (:count typographies) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||||
|
[:div.asset-list
|
||||||
|
(for [typography (:sample typographies)]
|
||||||
|
[:div.asset-list-item {:key (str "assets-typography-" (:id typography))}
|
||||||
|
[:div.typography-sample
|
||||||
|
{:style {:font-family (:font-family typography)
|
||||||
|
:font-weight (:font-weight typography)
|
||||||
|
:font-style (:font-style typography)}}
|
||||||
|
(tr "workspace.assets.typography.sample")]
|
||||||
|
[:div.name-block
|
||||||
|
[:span.item-name {:title (:name typography)}
|
||||||
|
(:name typography)]]])
|
||||||
|
(when (> (:count typographies) (count (:sample typographies)))
|
||||||
|
[:div.asset-list-item
|
||||||
|
[:div.name-block
|
||||||
|
[:span.item-name "(...)"]]])]])]))])))
|
||||||
|
|
||||||
;; --- Grid Item
|
;; --- Grid Item
|
||||||
|
|
||||||
(mf/defc grid-item-metadata
|
(mf/defc grid-item-metadata
|
||||||
[{:keys [modified-at]}]
|
[{:keys [modified-at]}]
|
||||||
|
|
||||||
(let [locale (mf/deref i18n/locale)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
locale (mf/deref i18n/locale)
|
||||||
time (dt/timeago modified-at {:locale locale})]
|
time (dt/timeago modified-at {:locale locale})]
|
||||||
[:span.date
|
(if new-css-system
|
||||||
time]))
|
[:span {:class (stl/css :date)} time]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:span.date time])))
|
||||||
|
|
||||||
(defn create-counter-element
|
(defn create-counter-element
|
||||||
[_element file-count]
|
[_element file-count new-css-system]
|
||||||
(let [counter-el (dom/create-element "div")]
|
(if new-css-system
|
||||||
(dom/set-property! counter-el "class" "drag-counter")
|
(let [counter-el (dom/create-element "div")]
|
||||||
(dom/set-text! counter-el (str file-count))
|
(dom/set-property! counter-el "class" (stl/css :drag-counter))
|
||||||
counter-el))
|
(dom/set-text! counter-el (str file-count))
|
||||||
|
counter-el)
|
||||||
|
|
||||||
|
(let [counter-el (dom/create-element "div")]
|
||||||
|
(dom/set-property! counter-el "class" "drag-counter")
|
||||||
|
(dom/set-text! counter-el (str file-count))
|
||||||
|
counter-el)))
|
||||||
|
|
||||||
(mf/defc grid-item
|
(mf/defc grid-item
|
||||||
{:wrap [mf/memo]}
|
{:wrap [mf/memo]}
|
||||||
[{:keys [file navigate? origin library-view?] :as props}]
|
[{:keys [file navigate? origin library-view?] :as props}]
|
||||||
(let [file-id (:id file)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
file-id (:id file)
|
||||||
local (mf/use-state {:menu-open false
|
local (mf/use-state {:menu-open false
|
||||||
:menu-pos nil
|
:menu-pos nil
|
||||||
:edition false})
|
:edition false})
|
||||||
@ -250,10 +372,12 @@
|
|||||||
select-current? (not (contains? selected-files (:id file)))
|
select-current? (not (contains? selected-files (:id file)))
|
||||||
|
|
||||||
item-el (mf/ref-val node-ref)
|
item-el (mf/ref-val node-ref)
|
||||||
counter-el (create-counter-element item-el
|
counter-el (create-counter-element
|
||||||
(if select-current?
|
item-el
|
||||||
1
|
(if select-current?
|
||||||
(count selected-files)))]
|
1
|
||||||
|
(count selected-files))
|
||||||
|
new-css-system)]
|
||||||
(when select-current?
|
(when select-current?
|
||||||
(st/emit! (dd/clear-selected-files))
|
(st/emit! (dd/clear-selected-files))
|
||||||
(st/emit! (dd/toggle-file-select file)))
|
(st/emit! (dd/toggle-file-select file)))
|
||||||
@ -307,77 +431,149 @@
|
|||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(swap! local assoc
|
(swap! local assoc
|
||||||
:edition true
|
:edition true
|
||||||
:menu-open false)))]
|
:menu-open false)))
|
||||||
|
|
||||||
|
handle-key-down
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps on-navigate on-select)
|
||||||
|
(fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-navigate event))
|
||||||
|
(when (kbd/shift? event)
|
||||||
|
(when (or (kbd/down-arrow? event) (kbd/left-arrow? event) (kbd/up-arrow? event) (kbd/right-arrow? event))
|
||||||
|
(on-select event)) ;; TODO Fix this
|
||||||
|
)))]
|
||||||
|
|
||||||
(mf/with-effect [selected? local]
|
(mf/with-effect [selected? local]
|
||||||
(when (and (not selected?) (:menu-open @local))
|
(when (and (not selected?) (:menu-open @local))
|
||||||
(swap! local assoc :menu-open false)))
|
(swap! local assoc :menu-open false)))
|
||||||
|
|
||||||
[:li.grid-item.project-th {:class (dom/classnames :library library-view?)}
|
(if new-css-system
|
||||||
[:button
|
[:li
|
||||||
{:tab-index "0"
|
{:class (stl/css-case :grid-item true :project-th true :library library-view?)}
|
||||||
:class (dom/classnames :selected selected?
|
[:button
|
||||||
:library library-view?)
|
{:class (stl/css-case :selected selected? :library library-view?)
|
||||||
:ref node-ref
|
:ref node-ref
|
||||||
:draggable true
|
:draggable true
|
||||||
:on-click on-select
|
:on-click on-select
|
||||||
:on-key-down (fn [event]
|
:on-key-down handle-key-down
|
||||||
(dom/stop-propagation event)
|
:on-double-click on-navigate
|
||||||
(when (kbd/enter? event)
|
:on-drag-start on-drag-start
|
||||||
(on-navigate event))
|
:on-context-menu on-menu-click}
|
||||||
(when (kbd/shift? event)
|
|
||||||
(when (or (kbd/down-arrow? event) (kbd/left-arrow? event) (kbd/up-arrow? event) (kbd/right-arrow? event))
|
|
||||||
(on-select event)) ;; TODO Fix this
|
|
||||||
))
|
|
||||||
:on-double-click on-navigate
|
|
||||||
:on-drag-start on-drag-start
|
|
||||||
:on-context-menu on-menu-click}
|
|
||||||
|
|
||||||
[:div.overlay]
|
[:div {:class (stl/css :overlay)}]
|
||||||
(if library-view?
|
|
||||||
[:& grid-item-library {:file file}]
|
|
||||||
[:& grid-item-thumbnail
|
|
||||||
{:file-id (:id file)
|
|
||||||
:revn (:revn file)
|
|
||||||
:thumbnail-uri (:thumbnail-uri file)
|
|
||||||
:background-color (dm/get-in file [:data :options :background])}])
|
|
||||||
|
|
||||||
(when (and (:is-shared file) (not library-view?))
|
(if library-view?
|
||||||
[:div.item-badge i/library])
|
[:& grid-item-library {:file file}]
|
||||||
[:div.info-wrapper
|
[:& grid-item-thumbnail
|
||||||
[:div.item-info
|
{:file-id (:id file)
|
||||||
(if (:edition @local)
|
:revn (:revn file)
|
||||||
[:& inline-edition {:content (:name file)
|
:thumbnail-uri (:thumbnail-uri file)
|
||||||
:on-end edit}]
|
:background-color (dm/get-in file [:data :options :background])}])
|
||||||
[:h3 (:name file)])
|
|
||||||
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
|
(when (and (:is-shared file) (not library-view?))
|
||||||
[:div.project-th-actions {:class (dom/classnames
|
[:div {:class (stl/css :item-badge)} i/library])
|
||||||
:force-display (:menu-open @local))}
|
|
||||||
[:div.project-th-icon.menu
|
[:div {:class (stl/css :info-wrapper)}
|
||||||
{:tab-index "0"
|
[:div {:class (stl/css :item-info)}
|
||||||
:ref menu-ref
|
(if (:edition @local)
|
||||||
:id (str file-id "-action-menu")
|
[:& inline-edition {:content (:name file)
|
||||||
:on-click on-menu-click
|
:on-end edit}]
|
||||||
:on-key-down (fn [event]
|
[:h3 (:name file)])
|
||||||
(when (kbd/enter? event)
|
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
|
||||||
(dom/stop-propagation event)
|
|
||||||
(on-menu-click event)))}
|
[:div {:class (stl/css-case :project-th-actions true :force-display (:menu-open @local))}
|
||||||
i/actions
|
[:div
|
||||||
(when selected?
|
{:class (stl/css :project-th-icon :menu)
|
||||||
[:& file-menu {:files (vals selected-files)
|
:tab-index "0"
|
||||||
:show? (:menu-open @local)
|
:ref menu-ref
|
||||||
:left (+ 24 (:x (:menu-pos @local)))
|
:id (str file-id "-action-menu")
|
||||||
:top (:y (:menu-pos @local))
|
:on-click on-menu-click
|
||||||
:navigate? navigate?
|
:on-key-down (fn [event]
|
||||||
:on-edit on-edit
|
(when (kbd/enter? event)
|
||||||
:on-menu-close on-menu-close
|
(dom/stop-propagation event)
|
||||||
:origin origin
|
(on-menu-click event)))}
|
||||||
:dashboard-local dashboard-local
|
i/actions
|
||||||
:parent-id (str file-id "-action-menu")}])]]]]]))
|
(when selected?
|
||||||
|
[:& file-menu {:files (vals selected-files)
|
||||||
|
:show? (:menu-open @local)
|
||||||
|
:left (+ 24 (:x (:menu-pos @local)))
|
||||||
|
:top (:y (:menu-pos @local))
|
||||||
|
:navigate? navigate?
|
||||||
|
:on-edit on-edit
|
||||||
|
:on-menu-close on-menu-close
|
||||||
|
:origin origin
|
||||||
|
:dashboard-local dashboard-local
|
||||||
|
:parent-id (str file-id "-action-menu")}])]]]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:li.grid-item.project-th {:class (dom/classnames :library library-view?)}
|
||||||
|
[:button
|
||||||
|
{:tab-index "0"
|
||||||
|
:class (dom/classnames :selected selected?
|
||||||
|
:library library-view?)
|
||||||
|
:ref node-ref
|
||||||
|
:draggable true
|
||||||
|
:on-click on-select
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-navigate event))
|
||||||
|
(when (kbd/shift? event)
|
||||||
|
(when (or (kbd/down-arrow? event) (kbd/left-arrow? event) (kbd/up-arrow? event) (kbd/right-arrow? event))
|
||||||
|
(on-select event)) ;; TODO Fix this
|
||||||
|
))
|
||||||
|
:on-double-click on-navigate
|
||||||
|
:on-drag-start on-drag-start
|
||||||
|
:on-context-menu on-menu-click}
|
||||||
|
|
||||||
|
[:div.overlay]
|
||||||
|
(if library-view?
|
||||||
|
[:& grid-item-library {:file file}]
|
||||||
|
[:& grid-item-thumbnail
|
||||||
|
{:file-id (:id file)
|
||||||
|
:revn (:revn file)
|
||||||
|
:thumbnail-uri (:thumbnail-uri file)
|
||||||
|
:background-color (dm/get-in file [:data :options :background])}])
|
||||||
|
|
||||||
|
(when (and (:is-shared file) (not library-view?))
|
||||||
|
[:div.item-badge i/library])
|
||||||
|
[:div.info-wrapper
|
||||||
|
[:div.item-info
|
||||||
|
(if (:edition @local)
|
||||||
|
[:& inline-edition {:content (:name file)
|
||||||
|
:on-end edit}]
|
||||||
|
[:h3 (:name file)])
|
||||||
|
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
|
||||||
|
[:div.project-th-actions {:class (dom/classnames
|
||||||
|
:force-display (:menu-open @local))}
|
||||||
|
[:div.project-th-icon.menu
|
||||||
|
{:tab-index "0"
|
||||||
|
:ref menu-ref
|
||||||
|
:id (str file-id "-action-menu")
|
||||||
|
:on-click on-menu-click
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(on-menu-click event)))}
|
||||||
|
i/actions
|
||||||
|
(when selected?
|
||||||
|
[:& file-menu {:files (vals selected-files)
|
||||||
|
:show? (:menu-open @local)
|
||||||
|
:left (+ 24 (:x (:menu-pos @local)))
|
||||||
|
:top (:y (:menu-pos @local))
|
||||||
|
:navigate? navigate?
|
||||||
|
:on-edit on-edit
|
||||||
|
:on-menu-close on-menu-close
|
||||||
|
:origin origin
|
||||||
|
:dashboard-local dashboard-local
|
||||||
|
:parent-id (str file-id "-action-menu")}])]]]]])))
|
||||||
|
|
||||||
(mf/defc grid
|
(mf/defc grid
|
||||||
[{:keys [files project origin limit library-view? create-fn] :as props}]
|
[{:keys [files project origin limit library-view? create-fn] :as props}]
|
||||||
(let [dragging? (mf/use-state false)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
dragging? (mf/use-state false)
|
||||||
project-id (:id project)
|
project-id (:id project)
|
||||||
node-ref (mf/use-var nil)
|
node-ref (mf/use-var nil)
|
||||||
|
|
||||||
@ -420,57 +616,112 @@
|
|||||||
(reset! dragging? false)
|
(reset! dragging? false)
|
||||||
(import-files (.-files (.-dataTransfer e))))))]
|
(import-files (.-files (.-dataTransfer e))))))]
|
||||||
|
|
||||||
[:div.dashboard-grid
|
(if new-css-system
|
||||||
{:on-drag-enter on-drag-enter
|
[:div
|
||||||
:on-drag-over on-drag-over
|
{:class (stl/css :dashboard-grid)
|
||||||
:on-drag-leave on-drag-leave
|
:on-drag-enter on-drag-enter
|
||||||
:on-drop on-drop
|
:on-drag-over on-drag-over
|
||||||
:ref node-ref}
|
:on-drag-leave on-drag-leave
|
||||||
(cond
|
:on-drop on-drop
|
||||||
(nil? files)
|
:ref node-ref}
|
||||||
[:& loading-placeholder]
|
|
||||||
|
|
||||||
(seq files)
|
(cond
|
||||||
[:ul.grid-row
|
(nil? files)
|
||||||
{:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
[:& loading-placeholder]
|
||||||
|
|
||||||
(when @dragging?
|
(seq files)
|
||||||
[:li.grid-item])
|
[:ul
|
||||||
|
{:class (stl/css :grid-row)
|
||||||
|
:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||||
|
|
||||||
(for [item files]
|
(when @dragging?
|
||||||
[:& grid-item
|
[:li {:class (stl/css :grid-item)}])
|
||||||
{:file item
|
|
||||||
:key (:id item)
|
|
||||||
:navigate? true
|
|
||||||
:origin origin
|
|
||||||
:library-view? library-view?}])]
|
|
||||||
|
|
||||||
:else
|
(for [item files]
|
||||||
[:& empty-placeholder
|
[:& grid-item
|
||||||
{:limit limit
|
{:file item
|
||||||
:create-fn create-fn
|
:key (:id item)
|
||||||
:origin origin}])]))
|
:navigate? true
|
||||||
|
:origin origin
|
||||||
|
:library-view? library-view?}])]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:& empty-placeholder
|
||||||
|
{:limit limit
|
||||||
|
:create-fn create-fn
|
||||||
|
:origin origin}])]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-grid
|
||||||
|
{:on-drag-enter on-drag-enter
|
||||||
|
:on-drag-over on-drag-over
|
||||||
|
:on-drag-leave on-drag-leave
|
||||||
|
:on-drop on-drop
|
||||||
|
:ref node-ref}
|
||||||
|
(cond
|
||||||
|
(nil? files)
|
||||||
|
[:& loading-placeholder]
|
||||||
|
|
||||||
|
(seq files)
|
||||||
|
[:ul.grid-row
|
||||||
|
{:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||||
|
|
||||||
|
(when @dragging?
|
||||||
|
[:li.grid-item])
|
||||||
|
|
||||||
|
(for [item files]
|
||||||
|
[:& grid-item
|
||||||
|
{:file item
|
||||||
|
:key (:id item)
|
||||||
|
:navigate? true
|
||||||
|
:origin origin
|
||||||
|
:library-view? library-view?}])]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:& empty-placeholder
|
||||||
|
{:limit limit
|
||||||
|
:create-fn create-fn
|
||||||
|
:origin origin}])])))
|
||||||
|
|
||||||
(mf/defc line-grid-row
|
(mf/defc line-grid-row
|
||||||
[{:keys [files selected-files dragging? limit] :as props}]
|
[{:keys [files selected-files dragging? limit] :as props}]
|
||||||
(let [elements limit
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
elements limit
|
||||||
limit (if dragging? (dec limit) limit)]
|
limit (if dragging? (dec limit) limit)]
|
||||||
[:ul.grid-row.no-wrap
|
(if new-css-system
|
||||||
{:style {:grid-template-columns (dm/str "repeat(" elements ", 1fr)")}}
|
[:ul
|
||||||
|
{:class (stl/css :grid-row :no-wrap)
|
||||||
|
:style {:grid-template-columns (dm/str "repeat(" elements ", 1fr)")}}
|
||||||
|
|
||||||
(when dragging?
|
(when dragging?
|
||||||
[:li.grid-item.dragged])
|
[:li {:class (stl/css :grid-item :dragged)}])
|
||||||
(for [item (take limit files)]
|
|
||||||
[:& grid-item
|
(for [item (take limit files)]
|
||||||
{:id (:id item)
|
[:& grid-item
|
||||||
:file item
|
{:id (:id item)
|
||||||
:selected-files selected-files
|
:file item
|
||||||
:key (:id item)
|
:selected-files selected-files
|
||||||
:navigate? false}])]))
|
:key (:id item)
|
||||||
|
:navigate? false}])]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:ul.grid-row.no-wrap
|
||||||
|
{:style {:grid-template-columns (dm/str "repeat(" elements ", 1fr)")}}
|
||||||
|
|
||||||
|
(when dragging?
|
||||||
|
[:li.grid-item.dragged])
|
||||||
|
(for [item (take limit files)]
|
||||||
|
[:& grid-item
|
||||||
|
{:id (:id item)
|
||||||
|
:file item
|
||||||
|
:selected-files selected-files
|
||||||
|
:key (:id item)
|
||||||
|
:navigate? false}])])))
|
||||||
|
|
||||||
(mf/defc line-grid
|
(mf/defc line-grid
|
||||||
[{:keys [project team files limit create-fn] :as props}]
|
[{:keys [project team files limit create-fn] :as props}]
|
||||||
(let [dragging? (mf/use-state false)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
dragging? (mf/use-state false)
|
||||||
project-id (:id project)
|
project-id (:id project)
|
||||||
team-id (:id team)
|
team-id (:id team)
|
||||||
|
|
||||||
@ -546,24 +797,47 @@
|
|||||||
(reset! dragging? false)
|
(reset! dragging? false)
|
||||||
(import-files (.-files (.-dataTransfer e)))))))]
|
(import-files (.-files (.-dataTransfer e)))))))]
|
||||||
|
|
||||||
[:div.dashboard-grid {:on-drag-enter on-drag-enter
|
(if new-css-system
|
||||||
:on-drag-over on-drag-over
|
[:div {:class (stl/css :dashboard-grid)
|
||||||
:on-drag-leave on-drag-leave
|
:on-drag-enter on-drag-enter
|
||||||
:on-drop on-drop}
|
:on-drag-over on-drag-over
|
||||||
(cond
|
:on-drag-leave on-drag-leave
|
||||||
(nil? files)
|
:on-drop on-drop}
|
||||||
[:& loading-placeholder]
|
(cond
|
||||||
|
(nil? files)
|
||||||
|
[:& loading-placeholder]
|
||||||
|
|
||||||
(seq files)
|
(seq files)
|
||||||
[:& line-grid-row {:files files
|
[:& line-grid-row {:files files
|
||||||
:team-id team-id
|
:team-id team-id
|
||||||
:selected-files selected-files
|
:selected-files selected-files
|
||||||
:dragging? @dragging?
|
:dragging? @dragging?
|
||||||
:limit limit}]
|
:limit limit}]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[:& empty-placeholder
|
[:& empty-placeholder
|
||||||
{:dragging? @dragging?
|
{:dragging? @dragging?
|
||||||
:limit limit
|
:limit limit
|
||||||
:create-fn create-fn}])]))
|
:create-fn create-fn}])]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-grid {:on-drag-enter on-drag-enter
|
||||||
|
:on-drag-over on-drag-over
|
||||||
|
:on-drag-leave on-drag-leave
|
||||||
|
:on-drop on-drop}
|
||||||
|
(cond
|
||||||
|
(nil? files)
|
||||||
|
[:& loading-placeholder]
|
||||||
|
|
||||||
|
(seq files)
|
||||||
|
[:& line-grid-row {:files files
|
||||||
|
:team-id team-id
|
||||||
|
:selected-files selected-files
|
||||||
|
:dragging? @dragging?
|
||||||
|
:limit limit}]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:& empty-placeholder
|
||||||
|
{:dragging? @dragging?
|
||||||
|
:limit limit
|
||||||
|
:create-fn create-fn}])])))
|
||||||
|
|||||||
375
frontend/src/app/main/ui/dashboard/grid.scss
Normal file
375
frontend/src/app/main/ui/dashboard/grid.scss
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
// 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";
|
||||||
|
|
||||||
|
.dashboard-grid {
|
||||||
|
font-size: $fs-14;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-row {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 0 $s-260;
|
||||||
|
height: $s-232;
|
||||||
|
margin: $s-12 $s-16 $s-16 $s-8;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a,
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
font-weight: $fw400;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media #{$bp-max-1366} {
|
||||||
|
height: $s-200;
|
||||||
|
flex: 1 0 $s-232;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item-th {
|
||||||
|
border-radius: $br-4;
|
||||||
|
text-align: initial;
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dragged {
|
||||||
|
border-radius: $br-4;
|
||||||
|
border: $br-2 solid $da-primary;
|
||||||
|
text-align: initial;
|
||||||
|
max-height: $s-160;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.overlay {
|
||||||
|
border-radius: $br-4;
|
||||||
|
border: $s-2 solid $da-tertiary;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
z-index: $z-index-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .overlay {
|
||||||
|
display: block;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-info {
|
||||||
|
display: grid;
|
||||||
|
padding: $s-8;
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
font-size: $fs-12;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-16;
|
||||||
|
font-weight: $fw400;
|
||||||
|
height: $s-28;
|
||||||
|
line-height: 1.92;
|
||||||
|
max-width: $s-260;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-right: $s-8;
|
||||||
|
padding: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
@media #{$bp-max-1366} {
|
||||||
|
max-width: $s-232;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
color: $df-secondary;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: $s-260;
|
||||||
|
&::first-letter {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
@media #{$bp-max-1366} {
|
||||||
|
max-width: $s-232;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-badge {
|
||||||
|
background-color: $da-primary;
|
||||||
|
border: none;
|
||||||
|
border-radius: $br-4;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-8;
|
||||||
|
right: $s-8;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-32;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $db-secondary;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.add-file {
|
||||||
|
border: $s-1 dashed $df-secondary;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $db-primary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $df-primary;
|
||||||
|
border: $s-2 solid $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-counter {
|
||||||
|
position: absolute;
|
||||||
|
top: $s-4;
|
||||||
|
left: $s-4;
|
||||||
|
width: $s-32;
|
||||||
|
height: $s-32;
|
||||||
|
background-color: $da-tertiary;
|
||||||
|
border-radius: $br-circle;
|
||||||
|
color: $db-secondary;
|
||||||
|
font-size: $fs-16;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROJECTS, ELEMENTS & ICONS GRID
|
||||||
|
.project-th {
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: $br-8;
|
||||||
|
padding-top: $s-6;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:focus-within {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
.project-th-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
.grid-item-th {
|
||||||
|
border: 2px solid $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-th-actions {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
right: $s-6;
|
||||||
|
width: $s-32;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $db-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-th-icon {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin-right: $s-8;
|
||||||
|
margin-top: 0;
|
||||||
|
|
||||||
|
&.menu {
|
||||||
|
align-items: flex-end;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: $s-32;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-top: $s-20;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
margin-right: 0;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
> svg {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-th-actions.force-display {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item-th {
|
||||||
|
border-radius: $br-4;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background-position: center;
|
||||||
|
background-size: auto 80%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
|
height: $s-232;
|
||||||
|
max-height: $s-160;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
background-color: var(--canvas-color);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.img-th {
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg#loader-pencil {
|
||||||
|
fill: $db-cuaternary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LIBRARY VIEW
|
||||||
|
.library {
|
||||||
|
height: $s-580;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item.project-th.library {
|
||||||
|
height: $s-612;
|
||||||
|
width: $s-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item-th.library {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 90%;
|
||||||
|
justify-content: flex-start;
|
||||||
|
max-height: 550px;
|
||||||
|
padding: $s-32;
|
||||||
|
|
||||||
|
.asset-section {
|
||||||
|
font-size: $fs-12;
|
||||||
|
color: $df-secondary;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-title {
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-12;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
.num-assets {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.asset-list-item {
|
||||||
|
align-items: center;
|
||||||
|
border-radius: $br-4;
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
color: $df-primary;
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-12;
|
||||||
|
margin-top: $s-4;
|
||||||
|
padding: $s-2;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.name-block {
|
||||||
|
color: $df-secondary;
|
||||||
|
width: calc(100% - $s-24 - $s-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
background-color: var(--canvas-color);
|
||||||
|
border-radius: $br-4;
|
||||||
|
border: $s-2 solid transparent;
|
||||||
|
height: $s-24;
|
||||||
|
margin-right: $s-8;
|
||||||
|
width: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-name {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-value {
|
||||||
|
color: $df-secondary;
|
||||||
|
margin-left: $s-4;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typography-sample {
|
||||||
|
height: $s-20;
|
||||||
|
margin-right: $s-4;
|
||||||
|
width: $s-20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,9 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.inline-edition
|
(ns app.main.ui.dashboard.inline-edition
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.keyboard :as kbd]
|
[app.util.keyboard :as kbd]
|
||||||
@ -13,7 +15,8 @@
|
|||||||
|
|
||||||
(mf/defc inline-edition
|
(mf/defc inline-edition
|
||||||
[{:keys [content on-end] :as props}]
|
[{:keys [content on-end] :as props}]
|
||||||
(let [name (mf/use-state content)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
name (mf/use-state content)
|
||||||
input-ref (mf/use-ref)
|
input-ref (mf/use-ref)
|
||||||
|
|
||||||
on-input
|
on-input
|
||||||
@ -59,13 +62,25 @@
|
|||||||
(dom/focus! node)
|
(dom/focus! node)
|
||||||
(dom/select-text! node))))
|
(dom/select-text! node))))
|
||||||
|
|
||||||
[:div.edit-wrapper
|
(if new-css-system
|
||||||
[:input.element-title {:value @name
|
[:div {:class (stl/css :edit-wrapper)}
|
||||||
:ref input-ref
|
[:input {:class (stl/css :element-title)
|
||||||
:on-click on-click
|
:value @name
|
||||||
:on-change on-input
|
:ref input-ref
|
||||||
:on-key-down on-keyup
|
:on-click on-click
|
||||||
:on-blur on-blur}]
|
:on-change on-input
|
||||||
[:span.close {:on-click on-cancel} i/close]]))
|
:on-key-down on-keyup
|
||||||
|
:on-blur on-blur}]
|
||||||
|
[:span {:class (stl/css :close)
|
||||||
|
:on-click on-cancel} i/close]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.edit-wrapper
|
||||||
|
[:input.element-title {:value @name
|
||||||
|
:ref input-ref
|
||||||
|
:on-click on-click
|
||||||
|
:on-change on-input
|
||||||
|
:on-key-down on-keyup
|
||||||
|
:on-blur on-blur}]
|
||||||
|
[:span.close {:on-click on-cancel} i/close]])))
|
||||||
|
|
||||||
|
|||||||
53
frontend/src/app/main/ui/dashboard/inline_edition.scss
Normal file
53
frontend/src/app/main/ui/dashboard/inline_edition.scss
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.edit-wrapper {
|
||||||
|
border-radius: $br-4;
|
||||||
|
display: flex;
|
||||||
|
padding-right: $s-24;
|
||||||
|
position: relative;
|
||||||
|
margin-right: $s-24;
|
||||||
|
|
||||||
|
input.element-title {
|
||||||
|
background-color: $db-primary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-16;
|
||||||
|
height: $s-32;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
padding: $s-6;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
border: $s-1 solid $da-primary;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
top: $s-1;
|
||||||
|
right: calc(-1 * $s-8);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: $s-16;
|
||||||
|
transform: rotate(45deg) translateY(7px);
|
||||||
|
width: $s-16;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
svg {
|
||||||
|
fill: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,23 +5,24 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.libraries
|
(ns app.main.ui.dashboard.libraries
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.main.data.dashboard :as dd]
|
[app.main.data.dashboard :as dd]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.dashboard.grid :refer [grid]]
|
[app.main.ui.dashboard.grid :refer [grid]]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.webapi :as wapi]
|
|
||||||
[beicon.core :as rx]
|
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc libraries-page
|
(mf/defc libraries-page
|
||||||
[{:keys [team] :as props}]
|
[{:keys [team] :as props}]
|
||||||
(let [files-map (mf/deref refs/dashboard-shared-files)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
files-map (mf/deref refs/dashboard-shared-files)
|
||||||
projects (mf/deref refs/dashboard-projects)
|
projects (mf/deref refs/dashboard-projects)
|
||||||
|
|
||||||
default-project (->> projects vals (d/seek :is-default))
|
default-project (->> projects vals (d/seek :is-default))
|
||||||
@ -35,16 +36,7 @@
|
|||||||
|
|
||||||
components-v2 (features/use-feature "components/v2")
|
components-v2 (features/use-feature "components/v2")
|
||||||
|
|
||||||
width (mf/use-state nil)
|
[rowref limit] (hooks/use-dynamic-grid-item-width 350)]
|
||||||
rowref (mf/use-ref)
|
|
||||||
|
|
||||||
itemsize (if components-v2
|
|
||||||
350
|
|
||||||
(if (>= @width 1030) 280 230))
|
|
||||||
ratio (if (some? @width) (/ @width itemsize) 0)
|
|
||||||
nitems (mth/floor ratio)
|
|
||||||
limit (min 10 nitems)
|
|
||||||
limit (max 1 limit)]
|
|
||||||
|
|
||||||
(mf/with-effect [team]
|
(mf/with-effect [team]
|
||||||
(when team
|
(when team
|
||||||
@ -57,29 +49,27 @@
|
|||||||
(st/emit! (dd/fetch-shared-files)
|
(st/emit! (dd/fetch-shared-files)
|
||||||
(dd/clear-selected-files)))
|
(dd/clear-selected-files)))
|
||||||
|
|
||||||
(mf/with-effect []
|
(if new-css-system
|
||||||
(let [node (mf/ref-val rowref)
|
[:*
|
||||||
mnt? (volatile! true)
|
[:header {:class (stl/css :dashboard-header) :ref rowref}
|
||||||
sub (->> (wapi/observe-resize node)
|
[:div#dashboard-libraries-title {:class (stl/css :dashboard-title)}
|
||||||
(rx/observe-on :af)
|
[:h1 (tr "dashboard.libraries-title")]]]
|
||||||
(rx/subs (fn [entries]
|
[:section {:class (stl/css :dashboard-container :no-bg :dashboard-shared)}
|
||||||
(let [row (first entries)
|
[:& grid {:files files
|
||||||
row-rect (.-contentRect ^js row)
|
:project default-project
|
||||||
row-width (.-width ^js row-rect)]
|
:origin :libraries
|
||||||
(when @mnt?
|
:limit limit
|
||||||
(reset! width row-width))))))]
|
:library-view? components-v2}]]]
|
||||||
(fn []
|
|
||||||
(vreset! mnt? false)
|
|
||||||
(rx/dispose! sub))))
|
|
||||||
|
|
||||||
[:*
|
;; OLD
|
||||||
[:header.dashboard-header {:ref rowref}
|
[:*
|
||||||
[:div.dashboard-title#dashboard-libraries-title
|
[:header.dashboard-header {:ref rowref}
|
||||||
[:h1 (tr "dashboard.libraries-title")]]]
|
[:div.dashboard-title#dashboard-libraries-title
|
||||||
[:section.dashboard-container.no-bg.dashboard-shared
|
[:h1 (tr "dashboard.libraries-title")]]]
|
||||||
[:& grid {:files files
|
[:section.dashboard-container.no-bg.dashboard-shared
|
||||||
:project default-project
|
[:& grid {:files files
|
||||||
:origin :libraries
|
:project default-project
|
||||||
:limit limit
|
:origin :libraries
|
||||||
:library-view? components-v2}]]]))
|
:limit limit
|
||||||
|
:library-view? components-v2}]]])))
|
||||||
|
|
||||||
|
|||||||
28
frontend/src/app/main/ui/dashboard/libraries.scss
Normal file
28
frontend/src/app/main/ui/dashboard/libraries.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: $s-16;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
&.dashboard-projects {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.dashboard-shared {
|
||||||
|
width: calc(100vw - $s-320);
|
||||||
|
margin-right: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,37 +5,68 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.placeholder
|
(ns app.main.ui.dashboard.placeholder
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc empty-placeholder
|
(mf/defc empty-placeholder
|
||||||
[{:keys [dragging? limit origin create-fn] :as props}]
|
[{:keys [dragging? limit origin create-fn] :as props}]
|
||||||
(let [on-click
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
on-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps create-fn)
|
(mf/deps create-fn)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(create-fn "dashboard:empty-folder-placeholder")))]
|
(create-fn "dashboard:empty-folder-placeholder")))]
|
||||||
(cond
|
(if new-css-system
|
||||||
(true? dragging?)
|
(cond
|
||||||
[:ul.grid-row.no-wrap
|
(true? dragging?)
|
||||||
{:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
[:ul
|
||||||
[:li.grid-item]]
|
{:class (stl/css :grid-row :no-wrap)
|
||||||
|
:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||||
|
[:li {:class (stl/css :grid-item :grid-empty-placeholder :dragged)}]]
|
||||||
|
|
||||||
(= :libraries origin)
|
(= :libraries origin)
|
||||||
[:div.grid-empty-placeholder.libs {:data-test "empty-placeholder"}
|
[:div {:class (stl/css :grid-empty-placeholder :libs)
|
||||||
[:div.text
|
:data-test "empty-placeholder"}
|
||||||
[:& i18n/tr-html {:label "dashboard.empty-placeholder-drafts"}]]]
|
[:div {:class (stl/css :text)}
|
||||||
|
[:& i18n/tr-html {:label "dashboard.empty-placeholder-drafts"}]]]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[:div.grid-empty-placeholder
|
[:div
|
||||||
{:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
{:class (stl/css :grid-empty-placeholder)
|
||||||
[:button.create-new {:on-click on-click} (tr "dashboard.new-file")]])))
|
:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||||
|
[:button {:class (stl/css :create-new)
|
||||||
|
:on-click on-click}
|
||||||
|
i/add-refactor]])
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
(cond
|
||||||
|
(true? dragging?)
|
||||||
|
[:ul.grid-row.no-wrap
|
||||||
|
{:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||||
|
[:li.grid-item]]
|
||||||
|
|
||||||
|
(= :libraries origin)
|
||||||
|
[:div.grid-empty-placeholder.libs {:data-test "empty-placeholder"}
|
||||||
|
[:div.text
|
||||||
|
[:& i18n/tr-html {:label "dashboard.empty-placeholder-drafts"}]]]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:div.grid-empty-placeholder
|
||||||
|
{:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||||
|
[:button.create-new {:on-click on-click} (tr "dashboard.new-file")]]))))
|
||||||
|
|
||||||
(mf/defc loading-placeholder
|
(mf/defc loading-placeholder
|
||||||
[]
|
[]
|
||||||
[:div.grid-empty-placeholder.loader
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:div.icon i/loader]
|
(if new-css-system
|
||||||
[:div.text (tr "dashboard.loading-files")]])
|
[:div {:class (stl/css :grid-empty-placeholder :loader)}
|
||||||
|
[:div {:class (stl/css :icon)} i/loader]
|
||||||
|
[:div {:class (stl/css :text)} (tr "dashboard.loading-files")]]
|
||||||
|
|
||||||
|
[:div.grid-empty-placeholder.loader
|
||||||
|
[:div.icon i/loader]
|
||||||
|
[:div.text (tr "dashboard.loading-files")]])))
|
||||||
|
|||||||
92
frontend/src/app/main/ui/dashboard/placeholder.scss
Normal file
92
frontend/src/app/main/ui/dashboard/placeholder.scss
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "./grid.scss";
|
||||||
|
|
||||||
|
.grid-empty-placeholder {
|
||||||
|
border-radius: $br-12;
|
||||||
|
display: grid;
|
||||||
|
padding: $s-12;
|
||||||
|
margin-right: $s-12;
|
||||||
|
height: $s-232;
|
||||||
|
|
||||||
|
&.loader {
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
svg {
|
||||||
|
width: $s-64;
|
||||||
|
height: $s-64;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.libs {
|
||||||
|
background-image: url(/images/ph-left.svg), url(/images/ph-right.svg);
|
||||||
|
background-position:
|
||||||
|
15% bottom,
|
||||||
|
85% top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
align-items: center;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
border-radius: $br-4;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: $s-200;
|
||||||
|
margin: $s-16;
|
||||||
|
padding: $s-48;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
a {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
max-width: $s-360;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-new {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-primary;
|
||||||
|
cursor: pointer;
|
||||||
|
height: $s-160;
|
||||||
|
margin: $s-8;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border: $s-2 solid transparent;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-32;
|
||||||
|
height: $s-32;
|
||||||
|
stroke: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: $s-2 solid $da-tertiary;
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
color: $da-primary;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
stroke: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin-top: $s-12;
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,10 +5,10 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.projects
|
(ns app.main.ui.dashboard.projects
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.data.dashboard :as dd]
|
[app.main.data.dashboard :as dd]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
@ -17,17 +17,17 @@
|
|||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.dashboard.grid :refer [line-grid]]
|
[app.main.ui.dashboard.grid :refer [line-grid]]
|
||||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||||
[app.main.ui.dashboard.project-menu :refer [project-menu]]
|
[app.main.ui.dashboard.project-menu :refer [project-menu]]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.keyboard :as kbd]
|
[app.util.keyboard :as kbd]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
[app.util.time :as dt]
|
[app.util.time :as dt]
|
||||||
[app.util.webapi :as wapi]
|
|
||||||
[beicon.core :as rx]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
@ -36,19 +36,32 @@
|
|||||||
(mf/defc header
|
(mf/defc header
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[]
|
[]
|
||||||
(let [on-click (mf/use-fn #(st/emit! (dd/create-project)))]
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
[:header.dashboard-header
|
on-click (mf/use-fn #(st/emit! (dd/create-project)))]
|
||||||
[:div.dashboard-title#dashboard-projects-title
|
(if new-css-system
|
||||||
[:h1 (tr "dashboard.projects-title")]]
|
[:header {:class (stl/css :dashboard-header)}
|
||||||
[:button.btn-secondary.btn-small
|
[:div#dashboard-projects-title {:class (stl/css :dashboard-title)}
|
||||||
{:on-click on-click
|
[:h1 (tr "dashboard.projects-title")]]
|
||||||
:data-test "new-project-button"}
|
[:button
|
||||||
(tr "dashboard.new-project")]]))
|
{:class (stl/css :btn-secondary :btn-small)
|
||||||
|
:on-click on-click
|
||||||
|
:data-test "new-project-button"}
|
||||||
|
(tr "dashboard.new-project")]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:header.dashboard-header
|
||||||
|
[:div.dashboard-title#dashboard-projects-title
|
||||||
|
[:h1 (tr "dashboard.projects-title")]]
|
||||||
|
[:button.btn-secondary.btn-small
|
||||||
|
{:on-click on-click
|
||||||
|
:data-test "new-project-button"}
|
||||||
|
(tr "dashboard.new-project")]])))
|
||||||
|
|
||||||
(mf/defc team-hero
|
(mf/defc team-hero
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [team close-fn] :as props}]
|
[{:keys [team close-fn] :as props}]
|
||||||
(let [on-nav-members-click (mf/use-fn #(st/emit! (dd/go-to-team-members)))
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
on-nav-members-click (mf/use-fn #(st/emit! (dd/go-to-team-members)))
|
||||||
|
|
||||||
on-invite-click
|
on-invite-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -64,28 +77,52 @@
|
|||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(close-fn)))]
|
(close-fn)))]
|
||||||
|
|
||||||
[:div.team-hero
|
(if new-css-system
|
||||||
[:img {:src "images/deco-team-banner.png" :border "0"
|
[:div {:class (stl/css :team-hero)}
|
||||||
:role "presentation"}]
|
[:div {:class (stl/css :img-wrapper)}
|
||||||
[:div.text
|
[:img {:src "images/deco-team-banner.png"
|
||||||
[:div.title (tr "dasboard.team-hero.title")]
|
:border "0"
|
||||||
[:div.info
|
:role "presentation"}]]
|
||||||
[:span (tr "dasboard.team-hero.text")]
|
[:div {:class (stl/css :text)}
|
||||||
[:a {:on-click on-nav-members-click} (tr "dasboard.team-hero.management")]]]
|
[:div {:class (stl/css :title)} (tr "dasboard.team-hero.title")]
|
||||||
[:button.btn-primary.invite
|
[:div {:class (stl/css :info)}
|
||||||
{:on-click on-invite-click}
|
[:span (tr "dasboard.team-hero.text")]
|
||||||
(tr "onboarding.choice.team-up.invite-members")]
|
[:a {:on-click on-nav-members-click} (tr "dasboard.team-hero.management")]]
|
||||||
[:button.close
|
[:button
|
||||||
{:on-click on-close-click
|
{:class (stl/css :btn-primary :invite)
|
||||||
:aria-label (tr "labels.close")}
|
:on-click on-invite-click}
|
||||||
[:span i/close]]]))
|
(tr "onboarding.choice.team-up.invite-members")]]
|
||||||
|
|
||||||
|
[:button
|
||||||
|
{:class (stl/css :close)
|
||||||
|
:on-click on-close-click
|
||||||
|
:aria-label (tr "labels.close")}
|
||||||
|
[:span i/close]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.team-hero
|
||||||
|
[:img {:src "images/deco-team-banner.png" :border "0"
|
||||||
|
:role "presentation"}]
|
||||||
|
[:div.text
|
||||||
|
[:div.title (tr "dasboard.team-hero.title")]
|
||||||
|
[:div.info
|
||||||
|
[:span (tr "dasboard.team-hero.text")]
|
||||||
|
[:a {:on-click on-nav-members-click} (tr "dasboard.team-hero.management")]]]
|
||||||
|
[:button.btn-primary.invite
|
||||||
|
{:on-click on-invite-click}
|
||||||
|
(tr "onboarding.choice.team-up.invite-members")]
|
||||||
|
[:button.close
|
||||||
|
{:on-click on-close-click
|
||||||
|
:aria-label (tr "labels.close")}
|
||||||
|
[:span i/close]]])))
|
||||||
|
|
||||||
(def builtin-templates
|
(def builtin-templates
|
||||||
(l/derived :builtin-templates st/state))
|
(l/derived :builtin-templates st/state))
|
||||||
|
|
||||||
(mf/defc tutorial-project
|
(mf/defc tutorial-project
|
||||||
[{:keys [close-tutorial default-project-id] :as props}]
|
[{:keys [close-tutorial default-project-id] :as props}]
|
||||||
(let [state (mf/use-state {:status :waiting
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
state (mf/use-state {:status :waiting
|
||||||
:file nil})
|
:file nil})
|
||||||
|
|
||||||
templates (mf/deref builtin-templates)
|
templates (mf/deref builtin-templates)
|
||||||
@ -115,48 +152,88 @@
|
|||||||
(swap! state #(assoc % :status :importing))
|
(swap! state #(assoc % :status :importing))
|
||||||
(st/emit! (with-meta (dd/clone-template (with-meta params mdata))
|
(st/emit! (with-meta (dd/clone-template (with-meta params mdata))
|
||||||
{::ev/origin "get-started-hero-block"})))))]
|
{::ev/origin "get-started-hero-block"})))))]
|
||||||
[:article.tutorial
|
(if new-css-system
|
||||||
[:div.thumbnail]
|
[:article {:class (stl/css :tutorial)}
|
||||||
[:div.text
|
[:div {:class (stl/css :thumbnail)}]
|
||||||
[:h2.title (tr "dasboard.tutorial-hero.title")]
|
[:div {:class (stl/css :text)}
|
||||||
[:p.info (tr "dasboard.tutorial-hero.info")]
|
[:h2 {:class (stl/css :title)} (tr "dasboard.tutorial-hero.title")]
|
||||||
[:button.btn-primary.action {:on-click download-tutorial}
|
[:p {:class (stl/css :info)} (tr "dasboard.tutorial-hero.info")]
|
||||||
(case (:status @state)
|
[:button {:class (stl/css :btn-primary :action)
|
||||||
:waiting (tr "dasboard.tutorial-hero.start")
|
:on-click download-tutorial}
|
||||||
:importing [:span.loader i/loader-pencil]
|
(case (:status @state)
|
||||||
:success "")]]
|
:waiting (tr "dasboard.tutorial-hero.start")
|
||||||
|
:importing [:span.loader i/loader-pencil]
|
||||||
|
:success "")]]
|
||||||
|
|
||||||
[:button.close
|
[:button
|
||||||
{:on-click close-tutorial
|
{:class (stl/css :close)
|
||||||
:aria-label (tr "labels.close")}
|
:on-click close-tutorial
|
||||||
[:span.icon i/close]]]))
|
:aria-label (tr "labels.close")}
|
||||||
|
[:span {:class (stl/css :icon)} i/close]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:article.tutorial
|
||||||
|
[:div.thumbnail]
|
||||||
|
[:div.text
|
||||||
|
[:h2.title (tr "dasboard.tutorial-hero.title")]
|
||||||
|
[:p.info (tr "dasboard.tutorial-hero.info")]
|
||||||
|
[:button.btn-primary.action {:on-click download-tutorial}
|
||||||
|
(case (:status @state)
|
||||||
|
:waiting (tr "dasboard.tutorial-hero.start")
|
||||||
|
:importing [:span.loader i/loader-pencil]
|
||||||
|
:success "")]]
|
||||||
|
|
||||||
|
[:button.close
|
||||||
|
{:on-click close-tutorial
|
||||||
|
:aria-label (tr "labels.close")}
|
||||||
|
[:span.icon i/close]]])))
|
||||||
|
|
||||||
(mf/defc interface-walkthrough
|
(mf/defc interface-walkthrough
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [close-walkthrough] :as props}]
|
[{:keys [close-walkthrough] :as props}]
|
||||||
(let [handle-walkthrough-link
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
handle-walkthrough-link
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-walkthrough"
|
(st/emit! (ptk/event ::ev/event {::ev/name "show-walkthrough"
|
||||||
::ev/origin "get-started-hero-block"
|
::ev/origin "get-started-hero-block"
|
||||||
:section "dashboard"})))]
|
:section "dashboard"})))]
|
||||||
[:article.walkthrough
|
(if new-css-system
|
||||||
[:div.thumbnail]
|
[:article {:class (stl/css :walkthrough)}
|
||||||
[:div.text
|
[:div {:class (stl/css :thumbnail)}]
|
||||||
[:h2.title (tr "dasboard.walkthrough-hero.title")]
|
[:div {:class (stl/css :text)}
|
||||||
[:p.info (tr "dasboard.walkthrough-hero.info")]
|
[:h2 {:class (stl/css :title)} (tr "dasboard.walkthrough-hero.title")]
|
||||||
[:a.btn-primary.action
|
[:p {:class (stl/css :info)} (tr "dasboard.walkthrough-hero.info")]
|
||||||
{:href " https://design.penpot.app/walkthrough"
|
[:a {:class (stl/css :btn-primary :action)
|
||||||
:target "_blank"
|
:href " https://design.penpot.app/walkthrough"
|
||||||
:on-click handle-walkthrough-link}
|
:target "_blank"
|
||||||
(tr "dasboard.walkthrough-hero.start")]]
|
:on-click handle-walkthrough-link}
|
||||||
[:button.close
|
(tr "dasboard.walkthrough-hero.start")]]
|
||||||
{:on-click close-walkthrough
|
[:button
|
||||||
:aria-label (tr "labels.close")}
|
{:class (stl/css :close)
|
||||||
[:span.icon i/close]]]))
|
:on-click close-walkthrough
|
||||||
|
:aria-label (tr "labels.close")}
|
||||||
|
[:span {:class (stl/css :icon)} i/close]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:article.walkthrough
|
||||||
|
[:div.thumbnail]
|
||||||
|
[:div.text
|
||||||
|
[:h2.title (tr "dasboard.walkthrough-hero.title")]
|
||||||
|
[:p.info (tr "dasboard.walkthrough-hero.info")]
|
||||||
|
[:a.btn-primary.action
|
||||||
|
{:href " https://design.penpot.app/walkthrough"
|
||||||
|
:target "_blank"
|
||||||
|
:on-click handle-walkthrough-link}
|
||||||
|
(tr "dasboard.walkthrough-hero.start")]]
|
||||||
|
[:button.close
|
||||||
|
{:on-click close-walkthrough
|
||||||
|
:aria-label (tr "labels.close")}
|
||||||
|
[:span.icon i/close]]])))
|
||||||
|
|
||||||
(mf/defc project-item
|
(mf/defc project-item
|
||||||
[{:keys [project first? team files] :as props}]
|
[{:keys [project first? team files] :as props}]
|
||||||
(let [locale (mf/deref i18n/locale)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
locale (mf/deref i18n/locale)
|
||||||
file-count (or (:count project) 0)
|
file-count (or (:count project) 0)
|
||||||
project-id (:id project)
|
project-id (:id project)
|
||||||
team-id (:id team)
|
team-id (:id team)
|
||||||
@ -168,16 +245,7 @@
|
|||||||
:menu-pos nil
|
:menu-pos nil
|
||||||
:edition? (= (:id project) edit-id)})
|
:edition? (= (:id project) edit-id)})
|
||||||
|
|
||||||
width (mf/use-state nil)
|
[rowref limit] (hooks/use-dynamic-grid-item-width)
|
||||||
rowref (mf/use-ref)
|
|
||||||
itemsize (if (>= @width 1030)
|
|
||||||
280
|
|
||||||
230)
|
|
||||||
|
|
||||||
ratio (if (some? @width) (/ @width itemsize) 0)
|
|
||||||
nitems (mth/floor ratio)
|
|
||||||
limit (min 10 nitems)
|
|
||||||
limit (max 1 limit)
|
|
||||||
|
|
||||||
on-nav
|
on-nav
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -189,9 +257,9 @@
|
|||||||
toggle-pin
|
toggle-pin
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps project)
|
(mf/deps project)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(st/emit! (dd/toggle-project-pin project))))
|
(st/emit! (dd/toggle-project-pin project))))
|
||||||
|
|
||||||
on-menu-click
|
on-menu-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -256,101 +324,183 @@
|
|||||||
(st/emit! (dd/fetch-files {:project-id project-id})
|
(st/emit! (dd/fetch-files {:project-id project-id})
|
||||||
(dd/fetch-recent-files (:id team))
|
(dd/fetch-recent-files (:id team))
|
||||||
(dd/fetch-projects (:id team))
|
(dd/fetch-projects (:id team))
|
||||||
(dd/clear-selected-files))))]
|
(dd/clear-selected-files))))
|
||||||
|
|
||||||
(mf/with-effect
|
handle-create-click
|
||||||
(let [node (mf/ref-val rowref)
|
(mf/use-callback
|
||||||
mnt? (volatile! true)
|
(mf/deps on-create-click)
|
||||||
sub (->> (wapi/observe-resize node)
|
(fn [event]
|
||||||
(rx/observe-on :af)
|
(when (kbd/enter? event)
|
||||||
(rx/subs (fn [entries]
|
(on-create-click event))))
|
||||||
(let [row (first entries)
|
|
||||||
row-rect (.-contentRect ^js row)
|
|
||||||
row-width (.-width ^js row-rect)]
|
|
||||||
(when @mnt?
|
|
||||||
(reset! width row-width))))))]
|
|
||||||
(fn []
|
|
||||||
(vreset! mnt? false)
|
|
||||||
(rx/dispose! sub))))
|
|
||||||
|
|
||||||
[:article.dashboard-project-row
|
|
||||||
{:class (when first? "first")}
|
|
||||||
[:header.project {:ref rowref}
|
|
||||||
[:div.project-name-wrapper
|
|
||||||
(if (:edition? @local)
|
|
||||||
[:& inline-edition {:content (:name project)
|
|
||||||
:on-end on-edit}]
|
|
||||||
[:h2 {:on-click on-nav
|
|
||||||
:on-context-menu on-menu-click}
|
|
||||||
(if (:is-default project)
|
|
||||||
(tr "labels.drafts")
|
|
||||||
(:name project))])
|
|
||||||
|
|
||||||
[:& project-menu
|
handle-menu-click
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps on-menu-click)
|
||||||
|
(fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(on-menu-click event))))]
|
||||||
|
|
||||||
|
(if new-css-system
|
||||||
|
[:article {:class (stl/css-case :dashboard-project-row true :first first?)}
|
||||||
|
[:header {:class (stl/css :project) :ref rowref}
|
||||||
|
[:div {:class (stl/css :project-name-wrapper)}
|
||||||
|
(if (:edition? @local)
|
||||||
|
[:& inline-edition {:content (:name project)
|
||||||
|
:on-end on-edit}]
|
||||||
|
[:h2 {:on-click on-nav
|
||||||
|
:on-context-menu on-menu-click}
|
||||||
|
(if (:is-default project)
|
||||||
|
(tr "labels.drafts")
|
||||||
|
(:name project))])
|
||||||
|
|
||||||
|
[:& project-menu
|
||||||
|
{:project project
|
||||||
|
:show? (:menu-open @local)
|
||||||
|
:left (+ 24 (:x (:menu-pos @local)))
|
||||||
|
:top (:y (:menu-pos @local))
|
||||||
|
:on-edit on-edit-open
|
||||||
|
:on-menu-close on-menu-close
|
||||||
|
:on-import on-import}]
|
||||||
|
|
||||||
|
[:span {:class (stl/css :info)} (str (tr "labels.num-of-files" (i18n/c file-count)))]
|
||||||
|
|
||||||
|
(let [time (-> (:modified-at project)
|
||||||
|
(dt/timeago {:locale locale}))]
|
||||||
|
[:span {:class (stl/css :recent-files-row-title-info)} (str ", " time)])
|
||||||
|
|
||||||
|
[:div {:class (stl/css :project-actions)}
|
||||||
|
(when-not (:is-default project)
|
||||||
|
[:button
|
||||||
|
{:class (stl/css-case :pin-icon true
|
||||||
|
:tooltip true
|
||||||
|
:tooltip-bottom true
|
||||||
|
:active (:is-pinned project))
|
||||||
|
:on-click toggle-pin
|
||||||
|
:alt (tr "dashboard.pin-unpin")
|
||||||
|
:aria-label (tr "dashboard.pin-unpin")
|
||||||
|
:tab-index "0"}
|
||||||
|
(if (:is-pinned project)
|
||||||
|
i/pin-fill
|
||||||
|
i/pin)])
|
||||||
|
|
||||||
|
[:button
|
||||||
|
{:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom)
|
||||||
|
:on-click on-create-click
|
||||||
|
:alt (tr "dashboard.new-file")
|
||||||
|
:aria-label (tr "dashboard.new-file")
|
||||||
|
:data-test "project-new-file"
|
||||||
|
:on-key-down handle-create-click}
|
||||||
|
i/close]
|
||||||
|
|
||||||
|
[:button
|
||||||
|
{:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom)
|
||||||
|
:on-click on-menu-click
|
||||||
|
:alt (tr "dashboard.options")
|
||||||
|
:aria-label (tr "dashboard.options")
|
||||||
|
:data-test "project-options"
|
||||||
|
:on-key-down handle-menu-click}
|
||||||
|
i/actions]]]]
|
||||||
|
|
||||||
|
[:& line-grid
|
||||||
{:project project
|
{:project project
|
||||||
:show? (:menu-open @local)
|
:team team
|
||||||
:left (+ 24 (:x (:menu-pos @local)))
|
:files files
|
||||||
:top (:y (:menu-pos @local))
|
:create-fn create-file
|
||||||
:on-edit on-edit-open
|
:limit limit}]
|
||||||
:on-menu-close on-menu-close
|
|
||||||
:on-import on-import}]
|
|
||||||
|
|
||||||
[:span.info (str (tr "labels.num-of-files" (i18n/c file-count)))]
|
(when (and (> limit 0)
|
||||||
(let [time (-> (:modified-at project)
|
(> file-count limit))
|
||||||
(dt/timeago {:locale locale}))]
|
[:button
|
||||||
[:span.recent-files-row-title-info (str ", " time)])
|
{:class (stl/css :show-more)
|
||||||
[:div.project-actions
|
:on-click on-nav
|
||||||
(when-not (:is-default project)
|
:tab-index "0"
|
||||||
[:button.pin-icon.tooltip.tooltip-bottom
|
:on-key-down (fn [event]
|
||||||
{:class (when (:is-pinned project) "active")
|
(when (kbd/enter? event)
|
||||||
:on-click toggle-pin
|
(on-nav)))}
|
||||||
:alt (tr "dashboard.pin-unpin")
|
[:div {:class (stl/css :placeholder-label)} (tr "dashboard.show-all-files")]
|
||||||
:aria-label (tr "dashboard.pin-unpin")
|
[:div {:class (stl/css :placeholder-icon)} i/arrow-down]])]
|
||||||
:tab-index "0"}
|
|
||||||
(if (:is-pinned project)
|
|
||||||
i/pin-fill
|
|
||||||
i/pin)])
|
|
||||||
|
|
||||||
[:button.btn-secondary.btn-small.tooltip.tooltip-bottom
|
;; OLD
|
||||||
{:on-click on-create-click
|
[:article.dashboard-project-row
|
||||||
:alt (tr "dashboard.new-file")
|
{:class (when first? "first")}
|
||||||
:aria-label (tr "dashboard.new-file")
|
[:header.project {:ref rowref}
|
||||||
:data-test "project-new-file"
|
[:div.project-name-wrapper
|
||||||
:tab-index "0"
|
(if (:edition? @local)
|
||||||
:on-key-down (fn [event]
|
[:& inline-edition {:content (:name project)
|
||||||
(when (kbd/enter? event)
|
:on-end on-edit}]
|
||||||
(on-create-click event)))}
|
[:h2 {:on-click on-nav
|
||||||
i/close]
|
:on-context-menu on-menu-click}
|
||||||
|
(if (:is-default project)
|
||||||
|
(tr "labels.drafts")
|
||||||
|
(:name project))])
|
||||||
|
|
||||||
[:button.btn-secondary.btn-small.tooltip.tooltip-bottom
|
[:& project-menu
|
||||||
{:on-click on-menu-click
|
{:project project
|
||||||
:alt (tr "dashboard.options")
|
:show? (:menu-open @local)
|
||||||
:aria-label (tr "dashboard.options")
|
:left (+ 24 (:x (:menu-pos @local)))
|
||||||
:data-test "project-options"
|
:top (:y (:menu-pos @local))
|
||||||
:tab-index "0"
|
:on-edit on-edit-open
|
||||||
:on-key-down (fn [event]
|
:on-menu-close on-menu-close
|
||||||
(when (kbd/enter? event)
|
:on-import on-import}]
|
||||||
(dom/stop-propagation event)
|
|
||||||
(on-menu-click event)))}
|
|
||||||
i/actions]]]]
|
|
||||||
|
|
||||||
[:& line-grid
|
[:span.info (str (tr "labels.num-of-files" (i18n/c file-count)))]
|
||||||
{:project project
|
(let [time (-> (:modified-at project)
|
||||||
:team team
|
(dt/timeago {:locale locale}))]
|
||||||
:files files
|
[:span.recent-files-row-title-info (str ", " time)])
|
||||||
:create-fn create-file
|
[:div.project-actions
|
||||||
:limit limit}]
|
(when-not (:is-default project)
|
||||||
|
[:button.pin-icon.tooltip.tooltip-bottom
|
||||||
|
{:class (when (:is-pinned project) "active")
|
||||||
|
:on-click toggle-pin
|
||||||
|
:alt (tr "dashboard.pin-unpin")
|
||||||
|
:aria-label (tr "dashboard.pin-unpin")
|
||||||
|
:tab-index "0"}
|
||||||
|
(if (:is-pinned project)
|
||||||
|
i/pin-fill
|
||||||
|
i/pin)])
|
||||||
|
|
||||||
(when (and (> limit 0)
|
[:button.btn-secondary.btn-small.tooltip.tooltip-bottom
|
||||||
(> file-count limit))
|
{:on-click on-create-click
|
||||||
[:button.show-more {:on-click on-nav
|
:alt (tr "dashboard.new-file")
|
||||||
:tab-index "0"
|
:aria-label (tr "dashboard.new-file")
|
||||||
:on-key-down (fn [event]
|
:data-test "project-new-file"
|
||||||
(when (kbd/enter? event)
|
:tab-index "0"
|
||||||
(on-nav)))}
|
:on-key-down (fn [event]
|
||||||
[:div.placeholder-label
|
(when (kbd/enter? event)
|
||||||
(tr "dashboard.show-all-files")]
|
(on-create-click event)))}
|
||||||
[:div.placeholder-icon i/arrow-down]])]))
|
i/close]
|
||||||
|
|
||||||
|
[:button.btn-secondary.btn-small.tooltip.tooltip-bottom
|
||||||
|
{:on-click on-menu-click
|
||||||
|
:alt (tr "dashboard.options")
|
||||||
|
:aria-label (tr "dashboard.options")
|
||||||
|
:data-test "project-options"
|
||||||
|
:tab-index "0"
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(on-menu-click event)))}
|
||||||
|
i/actions]]]]
|
||||||
|
|
||||||
|
[:& line-grid
|
||||||
|
{:project project
|
||||||
|
:team team
|
||||||
|
:files files
|
||||||
|
:create-fn create-file
|
||||||
|
:limit limit}]
|
||||||
|
|
||||||
|
(when (and (> limit 0)
|
||||||
|
(> file-count limit))
|
||||||
|
[:button.show-more {:on-click on-nav
|
||||||
|
:tab-index "0"
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(on-nav)))}
|
||||||
|
[:div.placeholder-label
|
||||||
|
(tr "dashboard.show-all-files")]
|
||||||
|
[:div.placeholder-icon i/arrow-down]])])))
|
||||||
|
|
||||||
|
|
||||||
(def recent-files-ref
|
(def recent-files-ref
|
||||||
@ -358,7 +508,8 @@
|
|||||||
|
|
||||||
(mf/defc projects-section
|
(mf/defc projects-section
|
||||||
[{:keys [team projects profile default-project-id] :as props}]
|
[{:keys [team projects profile default-project-id] :as props}]
|
||||||
(let [projects (->> (vals projects)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
projects (->> (vals projects)
|
||||||
(sort-by :modified-at)
|
(sort-by :modified-at)
|
||||||
(reverse))
|
(reverse))
|
||||||
recent-map (mf/deref recent-files-ref)
|
recent-map (mf/deref recent-files-ref)
|
||||||
@ -408,35 +559,68 @@
|
|||||||
(st/emit! (dd/fetch-recent-files team-id)
|
(st/emit! (dd/fetch-recent-files team-id)
|
||||||
(dd/clear-selected-files)))
|
(dd/clear-selected-files)))
|
||||||
|
|
||||||
(when (seq projects)
|
(if new-css-system
|
||||||
[:*
|
(when (seq projects)
|
||||||
[:& header]
|
[:*
|
||||||
|
[:& header]
|
||||||
|
|
||||||
(when team-hero?
|
(when team-hero?
|
||||||
[:& team-hero {:team team :close-fn close-banner}])
|
[:& team-hero {:team team :close-fn close-banner}])
|
||||||
|
|
||||||
(when (and (contains? cf/flags :dashboard-templates-section)
|
(when (and (contains? cf/flags :dashboard-templates-section)
|
||||||
(or (not tutorial-viewed?)
|
(or (not tutorial-viewed?)
|
||||||
(not walkthrough-viewed?)))
|
(not walkthrough-viewed?)))
|
||||||
[:div.hero-projects
|
[:div {:class (stl/css :hero-projects)}
|
||||||
(when (and (not tutorial-viewed?) (:is-default team))
|
(when (and (not tutorial-viewed?) (:is-default team))
|
||||||
[:& tutorial-project
|
[:& tutorial-project
|
||||||
{:close-tutorial close-tutorial
|
{:close-tutorial close-tutorial
|
||||||
:default-project-id default-project-id}])
|
:default-project-id default-project-id}])
|
||||||
|
|
||||||
(when (and (not walkthrough-viewed?) (:is-default team))
|
(when (and (not walkthrough-viewed?) (:is-default team))
|
||||||
[:& interface-walkthrough
|
[:& interface-walkthrough
|
||||||
{:close-walkthrough close-walkthrough}])])
|
{:close-walkthrough close-walkthrough}])])
|
||||||
|
|
||||||
[:div.dashboard-container.no-bg.dashboard-projects
|
[:div {:class (stl/css :dashboard-container :no-bg :dashboard-projects)}
|
||||||
(for [{:keys [id] :as project} projects]
|
(for [{:keys [id] :as project} projects]
|
||||||
(let [files (when recent-map
|
(let [files (when recent-map
|
||||||
(->> (vals recent-map)
|
(->> (vals recent-map)
|
||||||
(filterv #(= id (:project-id %)))
|
(filterv #(= id (:project-id %)))
|
||||||
(sort-by :modified-at #(compare %2 %1))))]
|
(sort-by :modified-at #(compare %2 %1))))]
|
||||||
[:& project-item {:project project
|
[:& project-item {:project project
|
||||||
:team team
|
:team team
|
||||||
:files files
|
:files files
|
||||||
:first? (= project (first projects))
|
:first? (= project (first projects))
|
||||||
:key id}]))]])))
|
:key id}]))]])
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
(when (seq projects)
|
||||||
|
[:*
|
||||||
|
[:& header]
|
||||||
|
|
||||||
|
(when team-hero?
|
||||||
|
[:& team-hero {:team team :close-fn close-banner}])
|
||||||
|
|
||||||
|
(when (and (contains? cf/flags :dashboard-templates-section)
|
||||||
|
(or (not tutorial-viewed?)
|
||||||
|
(not walkthrough-viewed?)))
|
||||||
|
[:div.hero-projects
|
||||||
|
(when (and (not tutorial-viewed?) (:is-default team))
|
||||||
|
[:& tutorial-project
|
||||||
|
{:close-tutorial close-tutorial
|
||||||
|
:default-project-id default-project-id}])
|
||||||
|
|
||||||
|
(when (and (not walkthrough-viewed?) (:is-default team))
|
||||||
|
[:& interface-walkthrough
|
||||||
|
{:close-walkthrough close-walkthrough}])])
|
||||||
|
|
||||||
|
[:div.dashboard-container.no-bg.dashboard-projects
|
||||||
|
(for [{:keys [id] :as project} projects]
|
||||||
|
(let [files (when recent-map
|
||||||
|
(->> (vals recent-map)
|
||||||
|
(filterv #(= id (:project-id %)))
|
||||||
|
(sort-by :modified-at #(compare %2 %1))))]
|
||||||
|
[:& project-item {:project project
|
||||||
|
:team team
|
||||||
|
:files files
|
||||||
|
:first? (= project (first projects))
|
||||||
|
:key id}]))]]))))
|
||||||
|
|||||||
391
frontend/src/app/main/ui/dashboard/projects.scss
Normal file
391
frontend/src/app/main/ui/dashboard/projects.scss
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: $s-16;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
&.dashboard-projects {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.dashboard-shared {
|
||||||
|
width: calc(100vw - $s-320);
|
||||||
|
margin-right: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-project-row {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.project {
|
||||||
|
align-items: center;
|
||||||
|
background: $df-primary;
|
||||||
|
border-radius: $br-4;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: $s-16;
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-16;
|
||||||
|
width: 99%;
|
||||||
|
max-height: $s-40;
|
||||||
|
gap: $s-8;
|
||||||
|
|
||||||
|
.project-name-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
min-height: $s-32;
|
||||||
|
margin-left: $s-8;
|
||||||
|
}
|
||||||
|
.show-more {
|
||||||
|
align-items: center;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-14;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
.placeholder-icon {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
margin-left: $s-12;
|
||||||
|
svg {
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: $da-tertiary;
|
||||||
|
svg {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
border: none;
|
||||||
|
padding: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: $fs-16;
|
||||||
|
line-height: 0.8;
|
||||||
|
font-weight: $fw700;
|
||||||
|
color: $db-secondary;
|
||||||
|
margin-right: $s-4;
|
||||||
|
margin-right: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info,
|
||||||
|
.recent-files-row-title-info {
|
||||||
|
font-size: $fs-14;
|
||||||
|
line-height: 1.15;
|
||||||
|
font-weight: $fw400;
|
||||||
|
color: $db-primary;
|
||||||
|
@media (max-width: 760px) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-actions {
|
||||||
|
display: flex;
|
||||||
|
opacity: 1;
|
||||||
|
margin-left: $s-32;
|
||||||
|
|
||||||
|
.btn-small {
|
||||||
|
height: $s-32;
|
||||||
|
margin: 0 $s-8;
|
||||||
|
width: $s-32;
|
||||||
|
|
||||||
|
&:not(:hover) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: $s-16;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
svg {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
svg {
|
||||||
|
fill: $db-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:focus-within {
|
||||||
|
.project-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-more {
|
||||||
|
align-items: center;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
font-size: $fs-14;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-8;
|
||||||
|
right: $s-52;
|
||||||
|
.placeholder-icon {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
margin-left: $s-8;
|
||||||
|
svg {
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: $da-tertiary;
|
||||||
|
svg {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-project-row .project {
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $df-primary;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
span,
|
||||||
|
.info,
|
||||||
|
.recent-files-row-title-info {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
.project-actions {
|
||||||
|
svg {
|
||||||
|
fill: $df-primary;
|
||||||
|
}
|
||||||
|
.pin-icon svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-hero {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
margin: $s-16;
|
||||||
|
padding: $s-8;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: $s-20 $s-20;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: $fs-24;
|
||||||
|
color: $df-primary;
|
||||||
|
font-weight: $fw400;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
flex: 1;
|
||||||
|
font-size: $fs-16;
|
||||||
|
span {
|
||||||
|
color: $df-secondary;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: $da-primary;
|
||||||
|
}
|
||||||
|
padding-top: $s-8;
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: $s-20;
|
||||||
|
right: $s-20;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
svg {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.invite {
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-180;
|
||||||
|
}
|
||||||
|
.img-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: $s-200;
|
||||||
|
height: $s-200;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: $br-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: $br-4;
|
||||||
|
height: $s-200;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
display: none;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-projects {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: $s-32;
|
||||||
|
margin: 0 $s-16 $s-16 $s-20;
|
||||||
|
|
||||||
|
@media (max-width: 1366px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tutorial,
|
||||||
|
.walkthrough {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
position: relative;
|
||||||
|
border-radius: $br-8;
|
||||||
|
min-height: $s-216;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
padding: $s-8;
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
width: $s-200;
|
||||||
|
height: $s-200;
|
||||||
|
border-radius: $br-6;
|
||||||
|
padding: $s-32;
|
||||||
|
display: block;
|
||||||
|
background-color: var(--color-canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: $br-4;
|
||||||
|
margin-bottom: 0;
|
||||||
|
width: $s-232;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
padding: $s-32;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-24;
|
||||||
|
font-weight: $fw400;
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
flex: 1;
|
||||||
|
color: $df-secondary;
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
.invite {
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
width: $s-180;
|
||||||
|
height: $s-40;
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: $s-24;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
margin: $s-20;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
.icon {
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
&:hover {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.walkthrough {
|
||||||
|
.thumbnail {
|
||||||
|
background-image: url("/images/walkthrough-cover.png");
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tutorial {
|
||||||
|
.thumbnail {
|
||||||
|
background-image: url("/images/hands-on-tutorial.png");
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
.loader {
|
||||||
|
display: flex;
|
||||||
|
svg#loader-pencil {
|
||||||
|
width: $s-32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,87 +5,94 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.search
|
(ns app.main.ui.dashboard.search
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.main.data.dashboard :as dd]
|
[app.main.data.dashboard :as dd]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.dashboard.grid :refer [grid]]
|
[app.main.ui.dashboard.grid :refer [grid]]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[app.util.webapi :as wapi]
|
|
||||||
[beicon.core :as rx]
|
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc search-page
|
(mf/defc search-page
|
||||||
[{:keys [team search-term] :as props}]
|
[{:keys [team search-term] :as props}]
|
||||||
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
result (mf/deref refs/dashboard-search-result)
|
||||||
|
[rowref limit] (hooks/use-dynamic-grid-item-width)]
|
||||||
|
|
||||||
(mf/use-effect
|
|
||||||
(mf/deps team)
|
|
||||||
(fn []
|
|
||||||
(when team
|
|
||||||
(let [tname (if (:is-default team)
|
|
||||||
(tr "dashboard.your-penpot")
|
|
||||||
(:name team))]
|
|
||||||
(dom/set-html-title (tr "title.dashboard.search" tname))))))
|
|
||||||
|
|
||||||
(mf/use-effect
|
|
||||||
(mf/deps search-term)
|
|
||||||
(fn []
|
|
||||||
(st/emit! (dd/search {:search-term search-term})
|
|
||||||
(dd/clear-selected-files))))
|
|
||||||
|
|
||||||
(let [result (mf/deref refs/dashboard-search-result)
|
|
||||||
width (mf/use-state nil)
|
|
||||||
rowref (mf/use-ref)
|
|
||||||
itemsize (if (>= @width 1030)
|
|
||||||
280
|
|
||||||
230)
|
|
||||||
|
|
||||||
ratio (if (some? @width) (/ @width itemsize) 0)
|
|
||||||
nitems (mth/floor ratio)
|
|
||||||
limit (min 10 nitems)
|
|
||||||
limit (max 1 limit)]
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
|
(mf/deps team)
|
||||||
(fn []
|
(fn []
|
||||||
(let [node (mf/ref-val rowref)
|
(when team
|
||||||
mnt? (volatile! true)
|
(let [tname (if (:is-default team)
|
||||||
sub (->> (wapi/observe-resize node)
|
(tr "dashboard.your-penpot")
|
||||||
(rx/observe-on :af)
|
(:name team))]
|
||||||
(rx/subs (fn [entries]
|
(dom/set-html-title (tr "title.dashboard.search" tname))))))
|
||||||
(let [row (first entries)
|
|
||||||
row-rect (.-contentRect ^js row)
|
|
||||||
row-width (.-width ^js row-rect)]
|
|
||||||
(when @mnt?
|
|
||||||
(reset! width row-width))))))]
|
|
||||||
(fn []
|
|
||||||
(vreset! mnt? false)
|
|
||||||
(rx/dispose! sub)))))
|
|
||||||
[:*
|
|
||||||
[:header.dashboard-header
|
|
||||||
[:div.dashboard-title#dashboard-search-title
|
|
||||||
[:h1 (tr "dashboard.title-search")]]]
|
|
||||||
|
|
||||||
[:section.dashboard-container.search.no-bg {:ref rowref}
|
(mf/use-effect
|
||||||
(cond
|
(mf/deps search-term)
|
||||||
(empty? search-term)
|
(fn []
|
||||||
[:div.grid-empty-placeholder.search
|
(st/emit! (dd/search {:search-term search-term})
|
||||||
[:div.icon i/search]
|
(dd/clear-selected-files))))
|
||||||
[:div.text (tr "dashboard.type-something")]]
|
(if new-css-system
|
||||||
|
[:*
|
||||||
|
[:header {:class (stl/css :dashboard-header)}
|
||||||
|
[:div#dashboard-search-title {:class (stl/css :dashboard-title)}
|
||||||
|
[:h1 (tr "dashboard.title-search")]]]
|
||||||
|
|
||||||
(nil? result)
|
[:section {:class (stl/css :dashboard-container :search :no-bg)
|
||||||
[:div.grid-empty-placeholder.search
|
:ref rowref}
|
||||||
[:div.icon i/search]
|
(cond
|
||||||
[:div.text (tr "dashboard.searching-for" search-term)]]
|
(empty? search-term)
|
||||||
|
[:div {:class (stl/css :grid-empty-placeholder :search)}
|
||||||
|
[:div {:class (stl/css :icon)} i/search]
|
||||||
|
[:div {:class (stl/css :text)} (tr "dashboard.type-something")]]
|
||||||
|
|
||||||
(empty? result)
|
(nil? result)
|
||||||
[:div.grid-empty-placeholder.search
|
[:div {:class (stl/css :grid-empty-placeholder :search)}
|
||||||
[:div.icon i/search]
|
[:div {:class (stl/css :icon)} i/search]
|
||||||
[:div.text (tr "dashboard.no-matches-for" search-term)]]
|
[:div {:class (stl/css :text)} (tr "dashboard.searching-for" search-term)]]
|
||||||
|
|
||||||
:else
|
(empty? result)
|
||||||
[:& grid {:files result
|
[:div {:class (stl/css :grid-empty-placeholder :search)}
|
||||||
:hide-new? true
|
[:div {:class (stl/css :icon)} i/search]
|
||||||
:origin :search
|
[:div {:class (stl/css :text)} (tr "dashboard.no-matches-for" search-term)]]
|
||||||
:limit limit}])]]))
|
|
||||||
|
:else
|
||||||
|
[:& grid {:files result
|
||||||
|
:hide-new? true
|
||||||
|
:origin :search
|
||||||
|
:limit limit}])]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:*
|
||||||
|
[:header.dashboard-header
|
||||||
|
[:div.dashboard-title#dashboard-search-title
|
||||||
|
[:h1 (tr "dashboard.title-search")]]]
|
||||||
|
|
||||||
|
[:section.dashboard-container.search.no-bg {:ref rowref}
|
||||||
|
(cond
|
||||||
|
(empty? search-term)
|
||||||
|
[:div.grid-empty-placeholder.search
|
||||||
|
[:div.icon i/search]
|
||||||
|
[:div.text (tr "dashboard.type-something")]]
|
||||||
|
|
||||||
|
(nil? result)
|
||||||
|
[:div.grid-empty-placeholder.search
|
||||||
|
[:div.icon i/search]
|
||||||
|
[:div.text (tr "dashboard.searching-for" search-term)]]
|
||||||
|
|
||||||
|
(empty? result)
|
||||||
|
[:div.grid-empty-placeholder.search
|
||||||
|
[:div.icon i/search]
|
||||||
|
[:div.text (tr "dashboard.no-matches-for" search-term)]]
|
||||||
|
|
||||||
|
:else
|
||||||
|
[:& grid {:files result
|
||||||
|
:hide-new? true
|
||||||
|
:origin :search
|
||||||
|
:limit limit}])]])))
|
||||||
|
|||||||
49
frontend/src/app/main/ui/dashboard/search.scss
Normal file
49
frontend/src/app/main/ui/dashboard/search.scss
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
@use "./placeholder.scss";
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: $s-16;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
&.dashboard-projects {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.dashboard-shared {
|
||||||
|
width: calc(100vw - $s-320);
|
||||||
|
margin-right: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-empty-placeholder.search {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
height: $s-200;
|
||||||
|
background: transparent;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
.icon svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-32;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
500
frontend/src/app/main/ui/dashboard/sidebar.scss
Normal file
500
frontend/src/app/main/ui/dashboard/sidebar.scss
Normal file
@ -0,0 +1,500 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard-sidebar {
|
||||||
|
grid-row: 1 / span 2;
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
|
||||||
|
background-color: $db-primary;
|
||||||
|
border-right: $s-1 solid $db-cuaternary;
|
||||||
|
margin: 0 $s-16 0 0;
|
||||||
|
padding: $s-16 0 0 0;
|
||||||
|
|
||||||
|
z-index: $z-index-1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: transparent;
|
||||||
|
margin: $s-12 $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-team-switch {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
margin: $s-4 $s-16;
|
||||||
|
|
||||||
|
.switch-content {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-48;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: #8f9da3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-team {
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: $fs-14;
|
||||||
|
padding: 0 $s-12;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
border-right: $s-1 solid $db-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-name {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
height: $s-40;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-text {
|
||||||
|
color: $df-primary;
|
||||||
|
width: $s-144;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: $s-12;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: $s-24;
|
||||||
|
width: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-24;
|
||||||
|
height: $s-24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-options {
|
||||||
|
display: flex;
|
||||||
|
max-width: $s-24;
|
||||||
|
min-width: $s-28;
|
||||||
|
border-left: $s-1 solid $df-primary;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
right: $s-2;
|
||||||
|
top: $s-52;
|
||||||
|
min-width: $s-160;
|
||||||
|
max-height: $s-480;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
@include menuShadow;
|
||||||
|
position: absolute;
|
||||||
|
z-index: $z-index-4;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
border-color: transparent;
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-40;
|
||||||
|
margin: $s-6;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: $fs-14;
|
||||||
|
padding: $s-6 $s-16;
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
color: var(--dark-warning-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
height: $s-12;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: transparent;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.options-dropdown {
|
||||||
|
li {
|
||||||
|
color: $df-primary;
|
||||||
|
&.warning {
|
||||||
|
color: var(--dark-warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.teams-dropdown {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
min-width: $s-248;
|
||||||
|
|
||||||
|
left: 0;
|
||||||
|
top: $s-52;
|
||||||
|
|
||||||
|
max-height: $s-480;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
li {
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-40;
|
||||||
|
padding: 0 $s-6;
|
||||||
|
margin: $s-6;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
.team-icon {
|
||||||
|
&.new-team {
|
||||||
|
background-color: $da-primary;
|
||||||
|
svg {
|
||||||
|
fill: $db-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.team-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.team-text {
|
||||||
|
color: $df-primary;
|
||||||
|
width: $s-168;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-team {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.action {
|
||||||
|
.team-icon {
|
||||||
|
background-color: #2e3434;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: $s-24;
|
||||||
|
margin-right: $s-12;
|
||||||
|
padding: $s-6;
|
||||||
|
width: $s-24;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: $s-12;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-empty-placeholder {
|
||||||
|
padding: $s-12;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
padding: 0 $s-12;
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
font-size: $fs-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-search {
|
||||||
|
align-items: center;
|
||||||
|
border: $s-1 solid transparent;
|
||||||
|
display: flex;
|
||||||
|
margin: $s-6 $s-16;
|
||||||
|
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
margin-top: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.input-text {
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
font-size: $fs-14;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: $s-40;
|
||||||
|
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-primary;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: $s-6 $s-12;
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:focus-within {
|
||||||
|
border: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::placeholder {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search,
|
||||||
|
.clear-search {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
height: $s-24;
|
||||||
|
margin-left: auto;
|
||||||
|
padding: 0 $s-8;
|
||||||
|
width: $s-32;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: $s-12;
|
||||||
|
right: $s-2;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-search svg {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
fill: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin: 0;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&.no-overflow {
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > li {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-24;
|
||||||
|
a {
|
||||||
|
font-weight: $fw400;
|
||||||
|
width: 100%;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $db-secondary;
|
||||||
|
margin-right: $s-8;
|
||||||
|
height: $s-12;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-title {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.recent-projects {
|
||||||
|
svg {
|
||||||
|
fill: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.element-title {
|
||||||
|
border: 0;
|
||||||
|
height: $s-32;
|
||||||
|
padding: $s-6;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: $df-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
background-color: $df-primary;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-left: $s-6;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: $s-16;
|
||||||
|
transform: rotate(45deg) translateY(7px);
|
||||||
|
width: $s-16;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-subtitle {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
.element-title {
|
||||||
|
color: $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-section {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
padding: $s-12 $s-16;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
span {
|
||||||
|
@include text-ellipsis;
|
||||||
|
color: $df-primary;
|
||||||
|
margin: $s-12;
|
||||||
|
font-size: $fs-14;
|
||||||
|
max-width: $s-160;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: $s-40;
|
||||||
|
width: $s-40;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
height: $s-12;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: $s-8;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
left: $s-16;
|
||||||
|
bottom: $s-44;
|
||||||
|
|
||||||
|
background-color: $db-primary;
|
||||||
|
border: $s-1 solid $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
min-width: $s-252;
|
||||||
|
|
||||||
|
@include animation(0, 0.2s, fadeInUp);
|
||||||
|
|
||||||
|
li {
|
||||||
|
font-size: $fs-14;
|
||||||
|
padding: $s-8 $s-16;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
margin-right: $s-8;
|
||||||
|
|
||||||
|
height: $s-12;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.separator {
|
||||||
|
border-top: $s-1 solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,582 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
@import "refactor/common-refactor.scss";
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: $s-16;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
&.dashboard-projects {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.dashboard-shared {
|
||||||
|
width: calc(100vw - $s-320);
|
||||||
|
margin-right: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-team-webhooks {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: $s-800;
|
||||||
|
margin-left: $s-120;
|
||||||
|
margin-top: $s-80;
|
||||||
|
border: none;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webhooks-empty {
|
||||||
|
align-items: center;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-12;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: $s-32;
|
||||||
|
max-width: $s-1000;
|
||||||
|
min-height: $s-136;
|
||||||
|
padding: $s-32;
|
||||||
|
text-align: center;
|
||||||
|
width: $s-468;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webhooks-hero-container {
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
width: $s-468;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
|
.upload-button {
|
||||||
|
width: $s-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
margin-left: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.webhooks-hero {
|
||||||
|
font-size: $fs-14;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $s-32;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: $s-32;
|
||||||
|
margin: 0;
|
||||||
|
padding: $s-32;
|
||||||
|
padding: 0;
|
||||||
|
width: $s-468;
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
color: $df-secondary;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-24;
|
||||||
|
font-weight: regular;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: $df-secondary;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
@extends .button-primary;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
box-shadow: 0 $s-2 $s-8 rgba(0, 0, 0, 0.25);
|
||||||
|
left: calc(-1 * $s-144);
|
||||||
|
max-height: $s-480;
|
||||||
|
min-width: $s-252;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-32;
|
||||||
|
width: $s-152;
|
||||||
|
z-index: $z-index-4;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 0;
|
||||||
|
border-color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: $fs-14;
|
||||||
|
padding: $s-4 $s-16;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-40;
|
||||||
|
margin: $s-6;
|
||||||
|
color: $df-primary;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.title {
|
||||||
|
font-weight: $fw700;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
border-color: transparent;
|
||||||
|
margin-top: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.options-dropdown {
|
||||||
|
li {
|
||||||
|
color: $df-primary;
|
||||||
|
&.warning {
|
||||||
|
color: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: $s-20;
|
||||||
|
font-size: $fs-16;
|
||||||
|
|
||||||
|
.table-header {
|
||||||
|
color: $df-secondary;
|
||||||
|
display: grid;
|
||||||
|
font-size: $fs-12;
|
||||||
|
grid-template-columns: 43% 1fr $s-108 $s-12;
|
||||||
|
height: $s-40;
|
||||||
|
max-width: $s-1000;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
text-transform: uppercase;
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.table-rows {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: $s-16;
|
||||||
|
color: $db-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
align-items: center;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-primary;
|
||||||
|
display: flex;
|
||||||
|
height: $s-64;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-field {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
padding-left: $s-12;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.name {
|
||||||
|
width: 43%;
|
||||||
|
min-width: $s-300;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
&.roles {
|
||||||
|
flex-grow: 1;
|
||||||
|
cursor: default;
|
||||||
|
position: relative;
|
||||||
|
.rol-label {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.rol-selector {
|
||||||
|
&.has-priv {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
min-width: $s-160;
|
||||||
|
height: $s-32;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: $s-4 $s-8;
|
||||||
|
font-size: $fs-14;
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
border-color: transparent;
|
||||||
|
border-radius: $br-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.actions {
|
||||||
|
position: relative;
|
||||||
|
.actions-dropdown {
|
||||||
|
max-height: $s-480;
|
||||||
|
min-width: $s-180;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.status {
|
||||||
|
.status-badge {
|
||||||
|
min-width: $s-76;
|
||||||
|
height: $s-24;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $db-primary;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
&.pending {
|
||||||
|
background-color: var(--warning-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.expired {
|
||||||
|
background-color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-label {
|
||||||
|
font-size: $fs-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.uri {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
min-width: $s-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.last-delivery {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: $s-52;
|
||||||
|
position: relative;
|
||||||
|
.success svg {
|
||||||
|
fill: $da-tertiary;
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
}
|
||||||
|
.failure svg {
|
||||||
|
fill: var(--warning-color);
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-container {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
overflow-x: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(-1 * $s-56);
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
border-radius: $br-4;
|
||||||
|
color: $df-primary;
|
||||||
|
background-color: $db-secondary;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: $s-12 $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-down {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: $s-8 solid transparent;
|
||||||
|
border-right: $s-8 solid transparent;
|
||||||
|
border-top: $s-8 solid $db-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.last-delivery-icon:hover {
|
||||||
|
.tooltip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: $s-16;
|
||||||
|
}
|
||||||
|
.member-name {
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
.you {
|
||||||
|
color: $df-secondary;
|
||||||
|
margin-left: $s-6;
|
||||||
|
}
|
||||||
|
.member-email {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
}
|
||||||
|
.member-image {
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-32;
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-team-webhooks & {
|
||||||
|
width: $s-800;
|
||||||
|
.table-rows {
|
||||||
|
padding-top: 0;
|
||||||
|
.table-row {
|
||||||
|
font-size: $fs-16;
|
||||||
|
min-height: $s-40;
|
||||||
|
height: fit-content;
|
||||||
|
.name {
|
||||||
|
color: $df-primary;
|
||||||
|
max-width: $s-480;
|
||||||
|
}
|
||||||
|
.expiration-date {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.team-members {
|
||||||
|
margin-bottom: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.invitations {
|
||||||
|
.table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 43% 1fr $s-108 $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-invitations {
|
||||||
|
height: $s-156;
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: $s-16;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-settings {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: $s-16;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-20;
|
||||||
|
height: $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal-blocks {
|
||||||
|
display: flex;
|
||||||
|
max-width: $s-1000;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
display: flex;
|
||||||
|
max-width: $s-324;
|
||||||
|
width: $s-324;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: $s-12;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.icon svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
.name,
|
||||||
|
.text {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-block {
|
||||||
|
position: relative;
|
||||||
|
padding-top: $s-180;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
margin-top: $s-12;
|
||||||
|
font-size: $fs-24;
|
||||||
|
color: $df-primary;
|
||||||
|
@include text-ellipsis;
|
||||||
|
margin-right: $s-88;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
padding: $s-16;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: $s-120;
|
||||||
|
width: $s-120;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: $s-120;
|
||||||
|
height: $s-120;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-overlay {
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: $df-primary;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
|
||||||
|
background-color: $da-primary;
|
||||||
|
height: $s-120;
|
||||||
|
width: $s-120;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $db-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.update-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
width: $s-72;
|
||||||
|
height: $s-72;
|
||||||
|
top: $s-16;
|
||||||
|
left: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.owner-block {
|
||||||
|
img {
|
||||||
|
width: $s-32;
|
||||||
|
height: $s-32;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
fill: $db-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.owner {
|
||||||
|
margin-top: $s-6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: $db-secondary;
|
||||||
|
.icon {
|
||||||
|
margin-right: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary {
|
||||||
|
margin-top: $s-6;
|
||||||
|
color: $db-secondary;
|
||||||
|
.icon {
|
||||||
|
padding: 0 $s-12;
|
||||||
|
margin-right: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-block {
|
||||||
|
svg {
|
||||||
|
fill: $db-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects,
|
||||||
|
.files {
|
||||||
|
margin-top: $s-8;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: $db-secondary;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 $s-2;
|
||||||
|
margin-right: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.modal-team-container {
|
.modal-team-container {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.templates
|
(ns app.main.ui.dashboard.templates
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
@ -15,6 +16,7 @@
|
|||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
@ -57,7 +59,8 @@
|
|||||||
(mf/defc title
|
(mf/defc title
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [collapsed]}]
|
[{:keys [collapsed]}]
|
||||||
(let [on-click
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
on-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps collapsed)
|
(mf/deps collapsed)
|
||||||
(fn [_event]
|
(fn [_event]
|
||||||
@ -73,17 +76,27 @@
|
|||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(on-click event))))]
|
(on-click event))))]
|
||||||
|
|
||||||
[:div.title
|
(if new-css-system
|
||||||
[:button {:tab-index "0"
|
[:div {:class (stl/css :title)}
|
||||||
:on-click on-click
|
[:button {:tab-index "0"
|
||||||
:on-key-down on-key-down}
|
:on-click on-click
|
||||||
[:span (tr "dashboard.libraries-and-templates")]
|
:on-key-down on-key-down}
|
||||||
[:span.icon (if ^boolean collapsed i/arrow-up i/arrow-down)]]]))
|
[:span (tr "dashboard.libraries-and-templates")]
|
||||||
|
[:span {:class (stl/css :icon)} (if ^boolean collapsed i/arrow-up i/arrow-down)]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.title
|
||||||
|
[:button {:tab-index "0"
|
||||||
|
:on-click on-click
|
||||||
|
:on-key-down on-key-down}
|
||||||
|
[:span (tr "dashboard.libraries-and-templates")]
|
||||||
|
[:span.icon (if ^boolean collapsed i/arrow-up i/arrow-down)]]])))
|
||||||
|
|
||||||
(mf/defc card-item
|
(mf/defc card-item
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [item index is-visible collapsed on-import]}]
|
[{:keys [item index is-visible collapsed on-import]}]
|
||||||
(let [id (dm/str "card-container-" index)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
id (dm/str "card-container-" index)
|
||||||
thb (assoc cf/public-uri :path (dm/str "/images/thumbnails/template-" (:id item) ".jpg"))
|
thb (assoc cf/public-uri :path (dm/str "/images/thumbnails/template-" (:id item) ".jpg"))
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
@ -100,23 +113,41 @@
|
|||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(on-import item event))))]
|
(on-import item event))))]
|
||||||
|
|
||||||
[:a.card-container
|
(if new-css-system
|
||||||
{:tab-index (if (or (not is-visible) collapsed) "-1" "0")
|
[:a
|
||||||
:id id
|
{:class (stl/css :card-container)
|
||||||
:data-index index
|
:tab-index (if (or (not is-visible) collapsed) "-1" "0")
|
||||||
:on-click on-click
|
:id id
|
||||||
:on-key-down on-key-down}
|
:data-index index
|
||||||
[:div.template-card
|
:on-click on-click
|
||||||
[:div.img-container
|
:on-key-down on-key-down}
|
||||||
[:img {:src (dm/str thb)
|
[:div {:class (stl/css :template-card)}
|
||||||
:alt (:name item)}]]
|
[:div {:class (stl/css :img-container)}
|
||||||
[:div.card-name [:span (:name item)]
|
[:img {:src (dm/str thb)
|
||||||
[:span.icon i/download]]]]))
|
:alt (:name item)}]]
|
||||||
|
[:div {:class (stl/css :card-name)}
|
||||||
|
[:span (:name item)]
|
||||||
|
[:span {:class (stl/css :icon)} i/download]]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:a.card-container
|
||||||
|
{:tab-index (if (or (not is-visible) collapsed) "-1" "0")
|
||||||
|
:id id
|
||||||
|
:data-index index
|
||||||
|
:on-click on-click
|
||||||
|
:on-key-down on-key-down}
|
||||||
|
[:div.template-card
|
||||||
|
[:div.img-container
|
||||||
|
[:img {:src (dm/str thb)
|
||||||
|
:alt (:name item)}]]
|
||||||
|
[:div.card-name [:span (:name item)]
|
||||||
|
[:span.icon i/download]]]])))
|
||||||
|
|
||||||
(mf/defc card-item-link
|
(mf/defc card-item-link
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [total is-visible collapsed section]}]
|
[{:keys [total is-visible collapsed section]}]
|
||||||
(let [id (dm/str "card-container-" total)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
id (dm/str "card-container-" total)
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
@ -134,23 +165,39 @@
|
|||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(on-click event))))]
|
(on-click event))))]
|
||||||
|
|
||||||
[:div.card-container
|
(if new-css-system
|
||||||
[:div.template-card
|
[:div {:class (stl/css :card-container)}
|
||||||
[:div.img-container
|
[:div {:class (stl/css :template-card)}
|
||||||
[:a {:id id
|
[:div {:class (stl/css :img-container)}
|
||||||
:tab-index (if (or (not is-visible) collapsed) "-1" "0")
|
[:a {:id id
|
||||||
:href "https://penpot.app/libraries-templates.html"
|
:tab-index (if (or (not is-visible) collapsed) "-1" "0")
|
||||||
:target "_blank"
|
:href "https://penpot.app/libraries-templates.html"
|
||||||
:on-click on-click
|
:target "_blank"
|
||||||
:on-key-down on-key-down}
|
:on-click on-click
|
||||||
[:div.template-link
|
:on-key-down on-key-down}
|
||||||
[:div.template-link-title (tr "dashboard.libraries-and-templates")]
|
[:div {:class (stl/css :template-link)}
|
||||||
[:div.template-link-text (tr "dashboard.libraries-and-templates.explore")]]]]]]))
|
[:div {:class (stl/css :template-link-title)} (tr "dashboard.libraries-and-templates")]
|
||||||
|
[:div {:class (stl/css :template-link-text)} (tr "dashboard.libraries-and-templates.explore")]]]]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.card-container
|
||||||
|
[:div.template-card
|
||||||
|
[:div.img-container
|
||||||
|
[:a {:id id
|
||||||
|
:tab-index (if (or (not is-visible) collapsed) "-1" "0")
|
||||||
|
:href "https://penpot.app/libraries-templates.html"
|
||||||
|
:target "_blank"
|
||||||
|
:on-click on-click
|
||||||
|
:on-key-down on-key-down}
|
||||||
|
[:div.template-link
|
||||||
|
[:div.template-link-title (tr "dashboard.libraries-and-templates")]
|
||||||
|
[:div.template-link-text (tr "dashboard.libraries-and-templates.explore")]]]]]])))
|
||||||
|
|
||||||
(mf/defc templates-section
|
(mf/defc templates-section
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [default-project-id profile project-id team-id content-width]}]
|
[{:keys [default-project-id profile project-id team-id content-width]}]
|
||||||
(let [templates (mf/deref builtin-templates)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
templates (mf/deref builtin-templates)
|
||||||
templates (mf/with-memo [templates]
|
templates (mf/with-memo [templates]
|
||||||
(filterv #(not= (:id %) "tutorial-for-beginners") templates))
|
(filterv #(not= (:id %) "tutorial-for-beginners") templates))
|
||||||
|
|
||||||
@ -234,42 +281,86 @@
|
|||||||
(when (and profile (not collapsed))
|
(when (and profile (not collapsed))
|
||||||
(st/emit! (dd/fetch-builtin-templates))))
|
(st/emit! (dd/fetch-builtin-templates))))
|
||||||
|
|
||||||
[:div.dashboard-templates-section
|
(if new-css-system
|
||||||
{:class (when ^boolean collapsed "collapsed")}
|
[:div
|
||||||
[:& title {:collapsed collapsed}]
|
{:class (stl/css-case :dashboard-templates-section true
|
||||||
|
:collapsed collapsed)}
|
||||||
|
[:& title {:collapsed collapsed}]
|
||||||
|
|
||||||
[:div.content {:ref content-ref
|
[:div {:class (stl/css :content)
|
||||||
:style {:left card-offset
|
:ref content-ref
|
||||||
:width (dm/str container-size "px")}}
|
:style {:left card-offset
|
||||||
|
:width (dm/str container-size "px")}}
|
||||||
|
|
||||||
(for [index (range (count templates))]
|
(for [index (range (count templates))]
|
||||||
[:& card-item
|
[:& card-item
|
||||||
{:on-import on-import-template
|
{:on-import on-import-template
|
||||||
:item (nth templates index)
|
:item (nth templates index)
|
||||||
:index index
|
:index index
|
||||||
:key index
|
:key index
|
||||||
:is-visible (and (>= index first-card)
|
:is-visible (and (>= index first-card)
|
||||||
(<= index last-card))
|
(<= index last-card))
|
||||||
:collapsed collapsed}])
|
:collapsed collapsed}])
|
||||||
|
|
||||||
[:& card-item-link
|
[:& card-item-link
|
||||||
{:is-visible (and (>= total first-card) (<= total last-card))
|
{:is-visible (and (>= total first-card) (<= total last-card))
|
||||||
:collapsed collapsed
|
:collapsed collapsed
|
||||||
:section section
|
:section section
|
||||||
:total total}]]
|
:total total}]]
|
||||||
|
|
||||||
(when (< card-offset 0)
|
(when (< card-offset 0)
|
||||||
[:button.button.left
|
[:button
|
||||||
{:tab-index (if ^boolean collapsed "-1" "0")
|
{:class (stl/css :button :left)
|
||||||
:on-click on-move-left
|
:tab-index (if ^boolean collapsed "-1" "0")
|
||||||
:on-key-down on-move-left-key-down}
|
:on-click on-move-left
|
||||||
i/go-prev])
|
:on-key-down on-move-left-key-down}
|
||||||
|
i/go-prev])
|
||||||
|
|
||||||
(when more-cards
|
(when more-cards
|
||||||
[:button.button.right
|
[:button
|
||||||
{:tab-index (if collapsed "-1" "0")
|
{:class (stl/css :button :right)
|
||||||
:on-click on-move-right
|
:tab-index (if collapsed "-1" "0")
|
||||||
:aria-label (tr "labels.next")
|
:on-click on-move-right
|
||||||
:on-key-down on-move-right-key-down}
|
:aria-label (tr "labels.next")
|
||||||
i/go-next])]))
|
:on-key-down on-move-right-key-down}
|
||||||
|
i/go-next])]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-templates-section
|
||||||
|
{:class (when ^boolean collapsed "collapsed")}
|
||||||
|
[:& title {:collapsed collapsed}]
|
||||||
|
|
||||||
|
[:div.content {:ref content-ref
|
||||||
|
:style {:left card-offset
|
||||||
|
:width (dm/str container-size "px")}}
|
||||||
|
|
||||||
|
(for [index (range (count templates))]
|
||||||
|
[:& card-item
|
||||||
|
{:on-import on-import-template
|
||||||
|
:item (nth templates index)
|
||||||
|
:index index
|
||||||
|
:key index
|
||||||
|
:is-visible (and (>= index first-card)
|
||||||
|
(<= index last-card))
|
||||||
|
:collapsed collapsed}])
|
||||||
|
|
||||||
|
[:& card-item-link
|
||||||
|
{:is-visible (and (>= total first-card) (<= total last-card))
|
||||||
|
:collapsed collapsed
|
||||||
|
:section section
|
||||||
|
:total total}]]
|
||||||
|
|
||||||
|
(when (< card-offset 0)
|
||||||
|
[:button.button.left
|
||||||
|
{:tab-index (if ^boolean collapsed "-1" "0")
|
||||||
|
:on-click on-move-left
|
||||||
|
:on-key-down on-move-left-key-down}
|
||||||
|
i/go-prev])
|
||||||
|
|
||||||
|
(when more-cards
|
||||||
|
[:button.button.right
|
||||||
|
{:tab-index (if collapsed "-1" "0")
|
||||||
|
:on-click on-move-right
|
||||||
|
:aria-label (tr "labels.next")
|
||||||
|
:on-key-down on-move-right-key-down}
|
||||||
|
i/go-next])])))
|
||||||
|
|||||||
191
frontend/src/app/main/ui/dashboard/templates.scss
Normal file
191
frontend/src/app/main/ui/dashboard/templates.scss
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.dashboard-templates-section {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: $s-228;
|
||||||
|
transition: bottom 300ms;
|
||||||
|
pointer-events: none;
|
||||||
|
&.collapsed {
|
||||||
|
bottom: calc(-1 * $s-228);
|
||||||
|
transition: bottom 300ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
pointer-events: all;
|
||||||
|
width: fit-content;
|
||||||
|
top: calc(-1 * $s-56);
|
||||||
|
text-align: right;
|
||||||
|
height: $s-56;
|
||||||
|
position: absolute;
|
||||||
|
right: calc(-1 * $s-24);
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
height: $s-56;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
border-top-left-radius: $br-10;
|
||||||
|
border-top-right-radius: $br-10;
|
||||||
|
margin-right: $s-32;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 1.2;
|
||||||
|
font-size: $fs-16;
|
||||||
|
margin-left: $s-16;
|
||||||
|
margin-right: $s-8;
|
||||||
|
color: $df-primary;
|
||||||
|
font-weight: $fw400;
|
||||||
|
&.icon {
|
||||||
|
margin-left: $s-16;
|
||||||
|
margin-right: $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
position: absolute;
|
||||||
|
top: $s-136;
|
||||||
|
border: $s-2 solid $df-secondary;
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
width: $s-36;
|
||||||
|
height: $s-36;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: $df-primary;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: all;
|
||||||
|
svg {
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
left: 0;
|
||||||
|
margin-left: $s-44;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.right {
|
||||||
|
right: 0;
|
||||||
|
margin-right: $s-44;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border: $s-2 solid $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
pointer-events: all;
|
||||||
|
width: 200%;
|
||||||
|
height: $s-228;
|
||||||
|
margin-left: $s-6;
|
||||||
|
position: absolute;
|
||||||
|
border-top-left-radius: $s-8;
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
|
||||||
|
.card-container {
|
||||||
|
width: $s-276;
|
||||||
|
margin-top: $s-20;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: top;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-card {
|
||||||
|
display: inline-block;
|
||||||
|
width: $s-256;
|
||||||
|
font-size: $fs-16;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $df-primary;
|
||||||
|
padding: $s-3 $s-6 $s-16 $s-6;
|
||||||
|
border-radius: $br-8;
|
||||||
|
|
||||||
|
.img-container {
|
||||||
|
width: 100%;
|
||||||
|
height: $s-136;
|
||||||
|
margin-bottom: $s-16;
|
||||||
|
border-radius: $br-5;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: $br-4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-name {
|
||||||
|
padding: 0 $s-6;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: $s-24;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-16;
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-weight: $fw500;
|
||||||
|
font-size: $fs-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-link {
|
||||||
|
border: $s-2 solid transparent;
|
||||||
|
margin: $s-32;
|
||||||
|
padding: $s-32 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-link-title {
|
||||||
|
font-size: $fs-14;
|
||||||
|
color: $df-primary;
|
||||||
|
font-weight: $fw400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-link-text {
|
||||||
|
font-size: $fs-12;
|
||||||
|
margin-top: $s-8;
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@
|
|||||||
"A collection of general purpose react hooks."
|
"A collection of general purpose react hooks."
|
||||||
(:require
|
(:require
|
||||||
[app.common.files.focus :as cpf]
|
[app.common.files.focus :as cpf]
|
||||||
|
[app.common.math :as mth]
|
||||||
[app.main.broadcast :as mbc]
|
[app.main.broadcast :as mbc]
|
||||||
[app.main.data.shortcuts :as dsc]
|
[app.main.data.shortcuts :as dsc]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
@ -16,6 +17,7 @@
|
|||||||
[app.util.dom.dnd :as dnd]
|
[app.util.dom.dnd :as dnd]
|
||||||
[app.util.storage :refer [storage]]
|
[app.util.storage :refer [storage]]
|
||||||
[app.util.timers :as ts]
|
[app.util.timers :as ts]
|
||||||
|
[app.util.webapi :as wapi]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[goog.functions :as f]
|
[goog.functions :as f]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
@ -345,3 +347,38 @@
|
|||||||
|
|
||||||
state))
|
state))
|
||||||
|
|
||||||
|
(defn use-dynamic-grid-item-width
|
||||||
|
([]
|
||||||
|
(use-dynamic-grid-item-width nil))
|
||||||
|
|
||||||
|
([itemsize]
|
||||||
|
(let [width (mf/use-state (:items-width @storage))
|
||||||
|
rowref (mf/use-ref)
|
||||||
|
|
||||||
|
itemsize (cond
|
||||||
|
(some? itemsize) itemsize
|
||||||
|
(>= @width 1030) 280
|
||||||
|
:else 230)
|
||||||
|
|
||||||
|
ratio (if (some? @width) (/ @width itemsize) 0)
|
||||||
|
nitems (mth/floor ratio)
|
||||||
|
limit (min 10 nitems)
|
||||||
|
limit (max 1 limit)]
|
||||||
|
|
||||||
|
(mf/with-effect
|
||||||
|
(let [node (mf/ref-val rowref)
|
||||||
|
mnt? (volatile! true)
|
||||||
|
sub (->> (wapi/observe-resize node)
|
||||||
|
(rx/observe-on :af)
|
||||||
|
(rx/subs (fn [entries]
|
||||||
|
(let [row (first entries)
|
||||||
|
row-rect (.-contentRect ^js row)
|
||||||
|
row-width (.-width ^js row-rect)]
|
||||||
|
(when @mnt?
|
||||||
|
(reset! width row-width)
|
||||||
|
(swap! storage assoc :items-width row-width))))))]
|
||||||
|
(fn []
|
||||||
|
(vreset! mnt? false)
|
||||||
|
(rx/dispose! sub))))
|
||||||
|
|
||||||
|
[rowref limit])))
|
||||||
|
|||||||
@ -170,6 +170,7 @@
|
|||||||
(def lock (icon-xref :lock))
|
(def lock (icon-xref :lock))
|
||||||
(def logo (icon-xref :penpot-logo))
|
(def logo (icon-xref :penpot-logo))
|
||||||
(def logo-icon (icon-xref :penpot-logo-icon))
|
(def logo-icon (icon-xref :penpot-logo-icon))
|
||||||
|
(def logo-error-screen (icon-xref :logo-error-screen))
|
||||||
(def logout (icon-xref :logout))
|
(def logout (icon-xref :logout))
|
||||||
(def lowercase (icon-xref :lowercase))
|
(def lowercase (icon-xref :lowercase))
|
||||||
(def mail (icon-xref :mail))
|
(def mail (icon-xref :mail))
|
||||||
|
|||||||
@ -5,10 +5,13 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings
|
(ns app.main.ui.settings
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.main.data.dashboard.shortcuts :as sc]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.context :as ctx]
|
[app.main.ui.context :as ctx]
|
||||||
|
[app.main.ui.hooks :as hooks]
|
||||||
[app.main.ui.settings.access-tokens :refer [access-tokens-page]]
|
[app.main.ui.settings.access-tokens :refer [access-tokens-page]]
|
||||||
[app.main.ui.settings.change-email]
|
[app.main.ui.settings.change-email]
|
||||||
[app.main.ui.settings.delete-account]
|
[app.main.ui.settings.delete-account]
|
||||||
@ -25,9 +28,16 @@
|
|||||||
(mf/defc header
|
(mf/defc header
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[]
|
[]
|
||||||
[:header.dashboard-header
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:div.dashboard-title
|
(if new-css-system
|
||||||
[:h1 {:data-test "account-title"} (tr "dashboard.your-account-title")]]])
|
[:header {:class (stl/css :dashboard-header)}
|
||||||
|
[:div {:class (stl/css :dashboard-title)}
|
||||||
|
[:h1 {:data-test "account-title"} (tr "dashboard.your-account-title")]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:header.dashboard-header
|
||||||
|
[:div.dashboard-title
|
||||||
|
[:h1 {:data-test "account-title"} (tr "dashboard.your-account-title")]]])))
|
||||||
|
|
||||||
(mf/defc settings
|
(mf/defc settings
|
||||||
[{:keys [route] :as props}]
|
[{:keys [route] :as props}]
|
||||||
@ -36,32 +46,59 @@
|
|||||||
profile (mf/deref refs/profile)
|
profile (mf/deref refs/profile)
|
||||||
locale (mf/deref i18n/locale)]
|
locale (mf/deref i18n/locale)]
|
||||||
|
|
||||||
|
(hooks/use-shortcuts ::dashboard sc/shortcuts)
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
#(when (nil? profile)
|
#(when (nil? profile)
|
||||||
(st/emit! (rt/nav :auth-login))))
|
(st/emit! (rt/nav :auth-login))))
|
||||||
|
|
||||||
[:section {:class (dom/classnames :dashboard-layout (not new-css-system)
|
(if new-css-system
|
||||||
:dashboard-layout-refactor new-css-system)}
|
[:section {:class (stl/css :dashboard-layout-refactor :dashboard)}
|
||||||
[:& sidebar {:profile profile
|
[:& sidebar {:profile profile
|
||||||
:locale locale
|
:locale locale
|
||||||
:section section}]
|
:section section}]
|
||||||
|
|
||||||
[:div.dashboard-content
|
[:div {:class (stl/css :dashboard-content)}
|
||||||
[:& header]
|
[:& header]
|
||||||
[:section.dashboard-container
|
[:section {:class (stl/css :dashboard-container)}
|
||||||
(case section
|
(case section
|
||||||
:settings-profile
|
:settings-profile
|
||||||
[:& profile-page {:locale locale}]
|
[:& profile-page {:locale locale}]
|
||||||
|
|
||||||
:settings-feedback
|
:settings-feedback
|
||||||
[:& feedback-page]
|
[:& feedback-page]
|
||||||
|
|
||||||
:settings-password
|
:settings-password
|
||||||
[:& password-page {:locale locale}]
|
[:& password-page {:locale locale}]
|
||||||
|
|
||||||
:settings-options
|
:settings-options
|
||||||
[:& options-page {:locale locale}]
|
[:& options-page {:locale locale}]
|
||||||
|
|
||||||
:settings-access-tokens
|
:settings-access-tokens
|
||||||
[:& access-tokens-page])]]]))
|
[:& access-tokens-page])]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:section {:class (dom/classnames :dashboard-layout (not new-css-system)
|
||||||
|
:dashboard-layout-refactor new-css-system)}
|
||||||
|
[:& sidebar {:profile profile
|
||||||
|
:locale locale
|
||||||
|
:section section}]
|
||||||
|
|
||||||
|
[:div.dashboard-content
|
||||||
|
[:& header]
|
||||||
|
[:section.dashboard-container
|
||||||
|
(case section
|
||||||
|
:settings-profile
|
||||||
|
[:& profile-page {:locale locale}]
|
||||||
|
|
||||||
|
:settings-feedback
|
||||||
|
[:& feedback-page]
|
||||||
|
|
||||||
|
:settings-password
|
||||||
|
[:& password-page {:locale locale}]
|
||||||
|
|
||||||
|
:settings-options
|
||||||
|
[:& options-page {:locale locale}]
|
||||||
|
|
||||||
|
:settings-access-tokens
|
||||||
|
[:& access-tokens-page])]]])))
|
||||||
|
|||||||
273
frontend/src/app/main/ui/settings.scss
Normal file
273
frontend/src/app/main/ui/settings.scss
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
@use "common/refactor/common-dashboard";
|
||||||
|
|
||||||
|
.dashboard {
|
||||||
|
background-color: $db-primary;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: $s-48 1fr;
|
||||||
|
grid-template-columns: $s-40 $s-256 1fr;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
grid-row: 1 / span 2;
|
||||||
|
padding: $s-16 $s-16 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
flex: 1 0 0;
|
||||||
|
margin-right: $s-16;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 100%;
|
||||||
|
border-top: $s-1 solid $db-cuaternary;
|
||||||
|
|
||||||
|
&.dashboard-projects {
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
&.dashboard-shared {
|
||||||
|
width: calc(100vw - $s-320);
|
||||||
|
margin-right: $s-52;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.search {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-settings {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
a {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
width: $s-800;
|
||||||
|
margin: $s-48 auto $s-32 $s-120;
|
||||||
|
display: flex;
|
||||||
|
max-width: $s-368;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.two-columns {
|
||||||
|
max-width: $s-520;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
width: $s-468;
|
||||||
|
|
||||||
|
.custom-input,
|
||||||
|
.custom-select {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-11;
|
||||||
|
margin-bottom: $s-12;
|
||||||
|
margin-left: calc(-1 * $s-4);
|
||||||
|
}
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $s-8;
|
||||||
|
border-color: transparent;
|
||||||
|
color: $df-primary;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
::placeholder {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.help-icon {
|
||||||
|
bottom: $s-12;
|
||||||
|
top: auto;
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
input {
|
||||||
|
background-color: $db-primary;
|
||||||
|
border-color: $db-cuaternary;
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.input-container {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $s-8;
|
||||||
|
border-color: transparent;
|
||||||
|
margin-top: $s-24;
|
||||||
|
.main-content {
|
||||||
|
label {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(-1 * $s-24);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
border: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
border-radius: $s-8;
|
||||||
|
padding: $s-12 $s-16;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
color: $df-primary;
|
||||||
|
border: none;
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-title {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
.field-title:not(:first-child) {
|
||||||
|
margin-top: $s-64;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-text {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
button,
|
||||||
|
.btn-secondary {
|
||||||
|
width: 100%;
|
||||||
|
font-size: $fs-11;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
color: $df-primary;
|
||||||
|
&:hover {
|
||||||
|
color: $da-primary;
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.links {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: $s-368;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.newsletter-subs {
|
||||||
|
border-bottom: $s-1 solid $df-secondary;
|
||||||
|
border-top: $s-1 solid $df-secondary;
|
||||||
|
padding: $s-32 0;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
|
||||||
|
.newsletter-title {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $db-primary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
margin-right: calc(-1 * $s-16);
|
||||||
|
margin-bottom: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-checkbox label {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: $s-120;
|
||||||
|
min-width: $s-120;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: $s-120;
|
||||||
|
margin-right: $s-16;
|
||||||
|
width: $s-120;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-change-field {
|
||||||
|
position: relative;
|
||||||
|
width: $s-120;
|
||||||
|
height: $s-120;
|
||||||
|
|
||||||
|
.update-overlay {
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
width: $s-120;
|
||||||
|
height: $s-120;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: $fs-24;
|
||||||
|
color: $df-primary;
|
||||||
|
line-height: 5;
|
||||||
|
text-align: center;
|
||||||
|
background: $da-tertiary;
|
||||||
|
z-index: 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="file"] {
|
||||||
|
width: $s-120;
|
||||||
|
height: $s-120;
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
z-index: 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.update-overlay {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.options-form,
|
||||||
|
.password-form {
|
||||||
|
h2 {
|
||||||
|
font-size: $fs-14;
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -247,20 +247,35 @@
|
|||||||
|
|
||||||
(mf/defc access-tokens-hero
|
(mf/defc access-tokens-hero
|
||||||
[]
|
[]
|
||||||
(let [on-click (mf/use-fn #(st/emit! (modal/show :access-token {})))]
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
[:div.access-tokens-hero-container
|
on-click (mf/use-fn #(st/emit! (modal/show :access-token {})))]
|
||||||
[:div.access-tokens-hero
|
(if new-css-system
|
||||||
[:div.desc
|
[:div {:class (stl/css :access-tokens-hero-container)}
|
||||||
[:h2 (tr "dashboard.access-tokens.personal")]
|
[:div {:class (stl/css :access-tokens-hero)}
|
||||||
[:p (tr "dashboard.access-tokens.personal.description")]]
|
[:div {:class (stl/css :desc)}
|
||||||
|
[:h2 (tr "dashboard.access-tokens.personal")]
|
||||||
|
[:p (tr "dashboard.access-tokens.personal.description")]]
|
||||||
|
|
||||||
[:button.btn-primary
|
[:button
|
||||||
{:on-click on-click}
|
{:class (stl/css :btn-primary)
|
||||||
[:span (tr "dashboard.access-tokens.create")]]]]))
|
:on-click on-click}
|
||||||
|
[:span (tr "dashboard.access-tokens.create")]]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.access-tokens-hero-container
|
||||||
|
[:div.access-tokens-hero
|
||||||
|
[:div.desc
|
||||||
|
[:h2 (tr "dashboard.access-tokens.personal")]
|
||||||
|
[:p (tr "dashboard.access-tokens.personal.description")]]
|
||||||
|
|
||||||
|
[:button.btn-primary
|
||||||
|
{:on-click on-click}
|
||||||
|
[:span (tr "dashboard.access-tokens.create")]]]])))
|
||||||
|
|
||||||
(mf/defc access-token-actions
|
(mf/defc access-token-actions
|
||||||
[{:keys [on-delete]}]
|
[{:keys [on-delete]}]
|
||||||
(let [local (mf/use-state {:menu-open false})
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
local (mf/use-state {:menu-open false})
|
||||||
show? (:menu-open @local)
|
show? (:menu-open @local)
|
||||||
options (mf/with-memo [on-delete]
|
options (mf/with-memo [on-delete]
|
||||||
[{:option-name (tr "labels.delete")
|
[{:option-name (tr "labels.delete")
|
||||||
@ -276,30 +291,57 @@
|
|||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(swap! local assoc :menu-open true)))]
|
(swap! local assoc :menu-open true)))
|
||||||
|
|
||||||
[:div.icon
|
on-keydown
|
||||||
{:tab-index "0"
|
(mf/use-callback
|
||||||
:ref menu-ref
|
(mf/deps on-menu-click)
|
||||||
:on-click on-menu-click
|
(fn [event]
|
||||||
:on-key-down (fn [event]
|
(when (kbd/enter? event)
|
||||||
(when (kbd/enter? event)
|
(dom/stop-propagation event)
|
||||||
(dom/stop-propagation event)
|
(on-menu-click event))))]
|
||||||
(on-menu-click event)))}
|
|
||||||
i/actions
|
(if new-css-system
|
||||||
[:& context-menu-a11y
|
[:div
|
||||||
{:on-close on-menu-close
|
{:class (stl/css :icon)
|
||||||
:show show?
|
:tab-index "0"
|
||||||
:fixed? true
|
:ref menu-ref
|
||||||
:min-width? true
|
:on-click on-menu-click
|
||||||
:top "auto"
|
:on-key-down on-keydown}
|
||||||
:left "auto"
|
i/actions
|
||||||
:options options}]]))
|
[:& context-menu-a11y
|
||||||
|
{:on-close on-menu-close
|
||||||
|
:show show?
|
||||||
|
:fixed? true
|
||||||
|
:min-width? true
|
||||||
|
:top "auto"
|
||||||
|
:left "auto"
|
||||||
|
:options options}]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.icon
|
||||||
|
{:tab-index "0"
|
||||||
|
:ref menu-ref
|
||||||
|
:on-click on-menu-click
|
||||||
|
:on-key-down (fn [event]
|
||||||
|
(when (kbd/enter? event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(on-menu-click event)))}
|
||||||
|
i/actions
|
||||||
|
[:& context-menu-a11y
|
||||||
|
{:on-close on-menu-close
|
||||||
|
:show show?
|
||||||
|
:fixed? true
|
||||||
|
:min-width? true
|
||||||
|
:top "auto"
|
||||||
|
:left "auto"
|
||||||
|
:options options}]])))
|
||||||
|
|
||||||
(mf/defc access-token-item
|
(mf/defc access-token-item
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [token] :as props}]
|
[{:keys [token] :as props}]
|
||||||
(let [locale (mf/deref i18n/locale)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
locale (mf/deref i18n/locale)
|
||||||
expires-at (:expires-at token)
|
expires-at (:expires-at token)
|
||||||
expires-txt (some-> expires-at (dt/format-date-locale {:locale locale}))
|
expires-txt (some-> expires-at (dt/format-date-locale {:locale locale}))
|
||||||
expired? (and (some? expires-at) (> (dt/now) expires-at))
|
expired? (and (some? expires-at) (> (dt/now) expires-at))
|
||||||
@ -323,36 +365,66 @@
|
|||||||
:accept-label (tr "modals.delete-acces-token.accept")
|
:accept-label (tr "modals.delete-acces-token.accept")
|
||||||
:on-accept delete-fn}))))]
|
:on-accept delete-fn}))))]
|
||||||
|
|
||||||
[:div.table-row
|
(if new-css-system
|
||||||
[:div.table-field.name
|
[:div {:class (stl/css :table-row)}
|
||||||
(str (:name token))]
|
[:div {:class (stl/css :table-field :name)}
|
||||||
[:div.table-field.expiration-date
|
(str (:name token))]
|
||||||
[:span.content {:class (when expired? "expired")}
|
|
||||||
(cond
|
[:div {:class (stl/css :table-field :expiration-date)}
|
||||||
(nil? expires-at) (tr "dashboard.access-tokens.no-expiration")
|
[:span {:class (stl/css-case :expired expired? :content true)}
|
||||||
expired? (tr "dashboard.access-tokens.expired-on" expires-txt)
|
(cond
|
||||||
:else (tr "dashboard.access-tokens.expires-on" expires-txt))]]
|
(nil? expires-at) (tr "dashboard.access-tokens.no-expiration")
|
||||||
[:div.table-field.actions
|
expired? (tr "dashboard.access-tokens.expired-on" expires-txt)
|
||||||
[:& access-token-actions
|
:else (tr "dashboard.access-tokens.expires-on" expires-txt))]]
|
||||||
{:on-delete on-delete}]]]))
|
[:div {:class (stl/css :table-field :actions)}
|
||||||
|
[:& access-token-actions
|
||||||
|
{:on-delete on-delete}]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.table-row
|
||||||
|
[:div.table-field.name
|
||||||
|
(str (:name token))]
|
||||||
|
[:div.table-field.expiration-date
|
||||||
|
[:span.content {:class (when expired? "expired")}
|
||||||
|
(cond
|
||||||
|
(nil? expires-at) (tr "dashboard.access-tokens.no-expiration")
|
||||||
|
expired? (tr "dashboard.access-tokens.expired-on" expires-txt)
|
||||||
|
:else (tr "dashboard.access-tokens.expires-on" expires-txt))]]
|
||||||
|
[:div.table-field.actions
|
||||||
|
[:& access-token-actions
|
||||||
|
{:on-delete on-delete}]]])))
|
||||||
|
|
||||||
(mf/defc access-tokens-page
|
(mf/defc access-tokens-page
|
||||||
[]
|
[]
|
||||||
(mf/with-effect []
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
(dom/set-html-title (tr "title.settings.access-tokens"))
|
tokens (mf/deref tokens-ref)]
|
||||||
(st/emit! (du/fetch-access-tokens)))
|
(mf/with-effect []
|
||||||
|
(dom/set-html-title (tr "title.settings.access-tokens"))
|
||||||
|
(st/emit! (du/fetch-access-tokens)))
|
||||||
|
|
||||||
(let [tokens (mf/deref tokens-ref)]
|
(if new-css-system
|
||||||
[:div.dashboard-access-tokens
|
[:div {:class (stl/css :dashboard-access-tokens)}
|
||||||
[:div
|
[:div
|
||||||
[:& access-tokens-hero]
|
[:& access-tokens-hero]
|
||||||
(if (empty? tokens)
|
(if (empty? tokens)
|
||||||
[:div.access-tokens-empty
|
[:div {:class (stl/css :access-tokens-empty)}
|
||||||
[:div (tr "dashboard.access-tokens.empty.no-access-tokens")]
|
[:div (tr "dashboard.access-tokens.empty.no-access-tokens")]
|
||||||
[:div (tr "dashboard.access-tokens.empty.add-one")]]
|
[:div (tr "dashboard.access-tokens.empty.add-one")]]
|
||||||
[:div.dashboard-table
|
[:div {:class (stl/css :dashboard-table)}
|
||||||
[:div.table-rows
|
[:div {:class (stl/css :table-rows)}
|
||||||
(for [token tokens]
|
(for [token tokens]
|
||||||
[:& access-token-item {:token token :key (:id token)}])]])]]))
|
[:& access-token-item {:token token :key (:id token)}])]])]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-access-tokens
|
||||||
|
[:div
|
||||||
|
[:& access-tokens-hero]
|
||||||
|
(if (empty? tokens)
|
||||||
|
[:div.access-tokens-empty
|
||||||
|
[:div (tr "dashboard.access-tokens.empty.no-access-tokens")]
|
||||||
|
[:div (tr "dashboard.access-tokens.empty.add-one")]]
|
||||||
|
[:div.dashboard-table
|
||||||
|
[:div.table-rows
|
||||||
|
(for [token tokens]
|
||||||
|
[:& access-token-item {:token token :key (:id token)}])]])]])))
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,170 @@
|
|||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
@import "refactor/common-refactor.scss";
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.dashboard-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-16;
|
||||||
|
margin-top: $s-20;
|
||||||
|
width: $s-800;
|
||||||
|
|
||||||
|
.table-header {
|
||||||
|
color: $df-secondary;
|
||||||
|
display: grid;
|
||||||
|
font-size: $fs-12;
|
||||||
|
grid-template-columns: 43% 1fr $s-108 $s-12;
|
||||||
|
height: $s-40;
|
||||||
|
max-width: $s-1000;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
text-transform: uppercase;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-rows {
|
||||||
|
color: $db-secondary;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: $s-16;
|
||||||
|
max-width: $s-1000;
|
||||||
|
padding-top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
align-items: center;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
color: $df-primary;
|
||||||
|
display: grid;
|
||||||
|
font-size: $fs-14;
|
||||||
|
grid-template-columns: 1fr 43% $s-12;
|
||||||
|
height: fit-content;
|
||||||
|
min-height: $s-40;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $s-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-field {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
padding-left: $s-12;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.name {
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
color: $df-primary;
|
||||||
|
display: -webkit-box;
|
||||||
|
max-width: $s-480;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.expiration-date {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: $s-2 $s-6;
|
||||||
|
&.expired {
|
||||||
|
background-color: var(--warning-color);
|
||||||
|
border-radius: $br-4;
|
||||||
|
color: $db-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.access-token-created {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.actions {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
fill: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-access-tokens {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: $s-120;
|
||||||
|
margin-top: $s-80;
|
||||||
|
width: $s-800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-tokens-hero-container {
|
||||||
|
background-color: transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: $s-1000;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-tokens-hero {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-14;
|
||||||
|
gap: $s-32;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: $s-468;
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
background-color: transparent;
|
||||||
|
color: $df-secondary;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-24;
|
||||||
|
font-weight: regular;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: $df-secondary;
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-size: $fs-14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.access-tokens-empty {
|
||||||
|
align-items: center;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid $db-cuaternary;
|
||||||
|
color: $df-secondary;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: $fs-14;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: $s-32;
|
||||||
|
max-width: $s-1000;
|
||||||
|
min-height: $s-136;
|
||||||
|
padding: $s-32;
|
||||||
|
text-align: center;
|
||||||
|
width: $s-468;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
@extend .button-primary;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
@extend .modal-overlay-base;
|
@extend .modal-overlay-base;
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
(ns app.main.ui.settings.feedback
|
(ns app.main.ui.settings.feedback
|
||||||
"Feedback form."
|
"Feedback form."
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
@ -13,6 +14,7 @@
|
|||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
@ -27,7 +29,8 @@
|
|||||||
|
|
||||||
(mf/defc feedback-form
|
(mf/defc feedback-form
|
||||||
[]
|
[]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
profile (mf/deref refs/profile)
|
||||||
form (fm/use-form :spec ::feedback-form
|
form (fm/use-form :spec ::feedback-form
|
||||||
:validators [(fm/validate-length :subject fm/max-length-allowed (tr "auth.name.too-long"))
|
:validators [(fm/validate-length :subject fm/max-length-allowed (tr "auth.name.too-long"))
|
||||||
(fm/validate-not-empty :subject (tr "auth.name.not-all-space"))])
|
(fm/validate-not-empty :subject (tr "auth.name.not-all-space"))])
|
||||||
@ -59,49 +62,100 @@
|
|||||||
(->> (rp/cmd! :send-user-feedback data)
|
(->> (rp/cmd! :send-user-feedback data)
|
||||||
(rx/subs on-succes on-error)))))]
|
(rx/subs on-succes on-error)))))]
|
||||||
|
|
||||||
[:& fm/form {:class "feedback-form"
|
(if new-css-system
|
||||||
:on-submit on-submit
|
[:& fm/form {:class (stl/css :feedback-form)
|
||||||
:form form}
|
:on-submit on-submit
|
||||||
|
:form form}
|
||||||
|
|
||||||
;; --- Feedback section
|
;; --- Feedback section
|
||||||
[:h2.field-title (tr "feedback.title")]
|
[:h2 {:class (stl/css :field-title)} (tr "feedback.title")]
|
||||||
[:p.field-text (tr "feedback.subtitle")]
|
[:p {:class (stl/css :field-text)} (tr "feedback.subtitle")]
|
||||||
|
|
||||||
[:div.fields-row
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:& fm/input {:label (tr "feedback.subject")
|
[:& fm/input {:label (tr "feedback.subject")
|
||||||
:name :subject}]]
|
:name :subject}]]
|
||||||
[:div.fields-row
|
[:div {:class (stl/css :fields-row :description)}
|
||||||
[:& fm/textarea
|
[:& fm/textarea
|
||||||
{:label (tr "feedback.description")
|
{:label (tr "feedback.description")
|
||||||
:name :content
|
:name :content
|
||||||
:rows 5}]]
|
:rows 5}]]
|
||||||
|
|
||||||
[:> fm/submit-button*
|
[:> fm/submit-button*
|
||||||
{:label (if @loading (tr "labels.sending") (tr "labels.send"))
|
{:label (if @loading (tr "labels.sending") (tr "labels.send"))
|
||||||
:disabled @loading}]
|
:disabled @loading}]
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
|
||||||
[:h2.field-title (tr "feedback.discourse-title")]
|
[:h2 {:class (stl/css :field-title)} (tr "feedback.discourse-title")]
|
||||||
[:p.field-text (tr "feedback.discourse-subtitle1")]
|
[:p {:class (stl/css :field-text)} (tr "feedback.discourse-subtitle1")]
|
||||||
|
|
||||||
[:a.btn-secondary.btn-large
|
[:a
|
||||||
{:href "https://community.penpot.app" :target "_blank"}
|
{:class (stl/css :btn-secondary :btn-large)
|
||||||
(tr "feedback.discourse-go-to")]
|
:href "https://community.penpot.app"
|
||||||
[:hr]
|
:target "_blank"}
|
||||||
|
(tr "feedback.discourse-go-to")]
|
||||||
|
[:hr]
|
||||||
|
|
||||||
[:h2.field-title (tr "feedback.twitter-title")]
|
[:h2 {:class (stl/css :field-title)} (tr "feedback.twitter-title")]
|
||||||
[:p.field-text (tr "feedback.twitter-subtitle1")]
|
[:p {:class (stl/css :field-text)} (tr "feedback.twitter-subtitle1")]
|
||||||
|
|
||||||
[:a.btn-secondary.btn-large
|
[:a
|
||||||
{:href "https://twitter.com/penpotapp" :target "_blank"}
|
{:class (stl/css :btn-secondary :btn-large)
|
||||||
(tr "feedback.twitter-go-to")]]))
|
:href "https://twitter.com/penpotapp"
|
||||||
|
:target "_blank"}
|
||||||
|
(tr "feedback.twitter-go-to")]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:& fm/form {:class "feedback-form"
|
||||||
|
:on-submit on-submit
|
||||||
|
:form form}
|
||||||
|
|
||||||
|
;; --- Feedback section
|
||||||
|
[:h2.field-title (tr "feedback.title")]
|
||||||
|
[:p.field-text (tr "feedback.subtitle")]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input {:label (tr "feedback.subject")
|
||||||
|
:name :subject}]]
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/textarea
|
||||||
|
{:label (tr "feedback.description")
|
||||||
|
:name :content
|
||||||
|
:rows 5}]]
|
||||||
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (if @loading (tr "labels.sending") (tr "labels.send"))
|
||||||
|
:disabled @loading}]
|
||||||
|
|
||||||
|
[:hr]
|
||||||
|
|
||||||
|
[:h2.field-title (tr "feedback.discourse-title")]
|
||||||
|
[:p.field-text (tr "feedback.discourse-subtitle1")]
|
||||||
|
|
||||||
|
[:a.btn-secondary.btn-large
|
||||||
|
{:href "https://community.penpot.app" :target "_blank"}
|
||||||
|
(tr "feedback.discourse-go-to")]
|
||||||
|
[:hr]
|
||||||
|
|
||||||
|
[:h2.field-title (tr "feedback.twitter-title")]
|
||||||
|
[:p.field-text (tr "feedback.twitter-subtitle1")]
|
||||||
|
|
||||||
|
[:a.btn-secondary.btn-large
|
||||||
|
{:href "https://twitter.com/penpotapp" :target "_blank"}
|
||||||
|
(tr "feedback.twitter-go-to")]])))
|
||||||
|
|
||||||
(mf/defc feedback-page
|
(mf/defc feedback-page
|
||||||
[]
|
[]
|
||||||
(mf/use-effect
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
#(dom/set-html-title (tr "title.settings.feedback")))
|
(mf/use-effect
|
||||||
|
#(dom/set-html-title (tr "title.settings.feedback")))
|
||||||
|
|
||||||
[:div.dashboard-settings
|
(if new-css-system
|
||||||
[:div.form-container
|
[:div {:class (stl/css :dashboard-settings)}
|
||||||
[:& feedback-form]]])
|
[:div {:class (stl/css :form-container)}
|
||||||
|
[:& feedback-form]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-settings
|
||||||
|
[:div.form-container
|
||||||
|
[:& feedback-form]]])))
|
||||||
|
|||||||
25
frontend/src/app/main/ui/settings/feedback.scss
Normal file
25
frontend/src/app/main/ui/settings/feedback.scss
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor" as *;
|
||||||
|
@use "./profile";
|
||||||
|
|
||||||
|
.feedback-form {
|
||||||
|
textarea {
|
||||||
|
border-radius: $br-8;
|
||||||
|
padding: $br-12;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
color: $df-primary;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
::placeholder {
|
||||||
|
color: $db-disabled;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,14 +5,15 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.options
|
(ns app.main.ui.settings.options
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.features :as features]
|
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
@ -37,48 +38,78 @@
|
|||||||
(mf/defc options-form
|
(mf/defc options-form
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
profile (mf/deref refs/profile)
|
||||||
initial (mf/with-memo [profile]
|
initial (mf/with-memo [profile]
|
||||||
(update profile :lang #(or % "")))
|
(update profile :lang #(or % "")))
|
||||||
form (fm/use-form :spec ::options-form
|
form (fm/use-form :spec ::options-form
|
||||||
:initial initial)
|
:initial initial)]
|
||||||
new-css-system (features/use-feature "styles/v2")]
|
|
||||||
|
|
||||||
[:& fm/form {:class "options-form"
|
(if new-css-system
|
||||||
:on-submit on-submit
|
[:& fm/form {:class (stl/css :options-form)
|
||||||
:form form}
|
:on-submit on-submit
|
||||||
|
:form form}
|
||||||
|
|
||||||
[:h2 (tr "labels.language")]
|
[:h3 (tr "labels.language")]
|
||||||
|
|
||||||
[:div.fields-row
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:& fm/select {:options (into [{:label "Auto (browser)" :value ""}]
|
[:& fm/select {:options (into [{:label "Auto (browser)" :value ""}]
|
||||||
i18n/supported-locales)
|
i18n/supported-locales)
|
||||||
:label (tr "dashboard.select-ui-language")
|
:label (tr "dashboard.select-ui-language")
|
||||||
:default ""
|
:default ""
|
||||||
:name :lang
|
:name :lang
|
||||||
:data-test "setting-lang"}]]
|
:data-test "setting-lang"}]]
|
||||||
|
|
||||||
(when new-css-system
|
[:h3 (tr "dashboard.theme-change")]
|
||||||
[:h2 (tr "dashboard.theme-change")]
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:div.fields-row
|
|
||||||
[:& fm/select {:label (tr "dashboard.select-ui-theme")
|
[:& fm/select {:label (tr "dashboard.select-ui-theme")
|
||||||
:name :theme
|
:name :theme
|
||||||
:default "default"
|
:default "default"
|
||||||
:options [{:label "Penpot Dark (default)" :value "default"}
|
:options [{:label "Penpot Dark (default)" :value "default"}
|
||||||
{:label "Penpot Light" :value "light"}]
|
{:label "Penpot Light" :value "light"}]
|
||||||
:data-test "setting-theme"}]])
|
:data-test "setting-theme"}]]
|
||||||
[:> fm/submit-button*
|
|
||||||
{:label (tr "dashboard.update-settings")
|
[:> fm/submit-button*
|
||||||
:data-test "submit-lang-change"}]]))
|
{:label (tr "dashboard.update-settings")
|
||||||
|
:data-test "submit-lang-change"
|
||||||
|
:class (stl/css :btn-primary)}]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:& fm/form {:class "options-form"
|
||||||
|
:on-submit on-submit
|
||||||
|
:form form}
|
||||||
|
|
||||||
|
[:h2 (tr "labels.language")]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/select {:options (into [{:label "Auto (browser)" :value ""}]
|
||||||
|
i18n/supported-locales)
|
||||||
|
:label (tr "dashboard.select-ui-language")
|
||||||
|
:default ""
|
||||||
|
:name :lang
|
||||||
|
:data-test "setting-lang"}]]
|
||||||
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "dashboard.update-settings")
|
||||||
|
:data-test "submit-lang-change"}]])))
|
||||||
|
|
||||||
;; --- Password Page
|
;; --- Password Page
|
||||||
|
|
||||||
(mf/defc options-page
|
(mf/defc options-page
|
||||||
[]
|
[]
|
||||||
(mf/use-effect
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
#(dom/set-html-title (tr "title.settings.options")))
|
(mf/use-effect
|
||||||
|
#(dom/set-html-title (tr "title.settings.options")))
|
||||||
|
|
||||||
|
(if new-css-system
|
||||||
|
[:div {:class (stl/css :dashboard-settings)}
|
||||||
|
[:div {:class (stl/css :form-container) :data-test "settings-form"}
|
||||||
|
[:h2 (tr "labels.settings")]
|
||||||
|
[:& options-form {}]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-settings
|
||||||
|
[:div.form-container
|
||||||
|
{:data-test "settings-form"}
|
||||||
|
[:& options-form {}]]])))
|
||||||
|
|
||||||
[:div.dashboard-settings
|
|
||||||
[:div.form-container
|
|
||||||
{:data-test "settings-form"}
|
|
||||||
[:& options-form {}]]])
|
|
||||||
|
|||||||
7
frontend/src/app/main/ui/settings/options.scss
Normal file
7
frontend/src/app/main/ui/settings/options.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "./profile" as *;
|
||||||
@ -5,12 +5,14 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.password
|
(ns app.main.ui.settings.password
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[app.main.data.users :as udu]
|
[app.main.data.users :as udu]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [t tr]]
|
[app.util.i18n :as i18n :refer [t tr]]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
@ -69,47 +71,86 @@
|
|||||||
|
|
||||||
(mf/defc password-form
|
(mf/defc password-form
|
||||||
[{:keys [locale] :as props}]
|
[{:keys [locale] :as props}]
|
||||||
(let [initial (mf/use-memo (constantly {:password-old nil}))
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
initial (mf/use-memo (constantly {:password-old nil}))
|
||||||
form (fm/use-form :spec ::password-form
|
form (fm/use-form :spec ::password-form
|
||||||
:validators [(fm/validate-not-all-spaces :password-old (tr "auth.password-not-empty"))
|
:validators [(fm/validate-not-all-spaces :password-old (tr "auth.password-not-empty"))
|
||||||
(fm/validate-not-empty :password-1 (tr "auth.password-not-empty"))
|
(fm/validate-not-empty :password-1 (tr "auth.password-not-empty"))
|
||||||
(fm/validate-not-empty :password-2 (tr "auth.password-not-empty"))
|
(fm/validate-not-empty :password-2 (tr "auth.password-not-empty"))
|
||||||
password-equality]
|
password-equality]
|
||||||
:initial initial)]
|
:initial initial)]
|
||||||
[:& fm/form {:class "password-form"
|
(if new-css-system
|
||||||
:on-submit on-submit
|
[:& fm/form {:class (stl/css :password-form)
|
||||||
:form form}
|
:on-submit on-submit
|
||||||
[:h2 (t locale "dashboard.password-change")]
|
:form form}
|
||||||
[:div.fields-row
|
|
||||||
[:& fm/input
|
|
||||||
{:type "password"
|
|
||||||
:name :password-old
|
|
||||||
:auto-focus? true
|
|
||||||
:label (t locale "labels.old-password")}]]
|
|
||||||
|
|
||||||
[:div.fields-row
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:& fm/input
|
[:& fm/input
|
||||||
{:type "password"
|
{:type "password"
|
||||||
:name :password-1
|
:name :password-old
|
||||||
:label (t locale "labels.new-password")}]]
|
:auto-focus? true
|
||||||
|
:label (t locale "labels.old-password")}]]
|
||||||
|
|
||||||
[:div.fields-row
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:& fm/input
|
[:& fm/input
|
||||||
{:type "password"
|
{:type "password"
|
||||||
:name :password-2
|
:name :password-1
|
||||||
:label (t locale "labels.confirm-password")}]]
|
:label (t locale "labels.new-password")}]]
|
||||||
|
|
||||||
[:> fm/submit-button*
|
[:div {:class (stl/css :fields-row)}
|
||||||
{:label (t locale "dashboard.update-settings")
|
[:& fm/input
|
||||||
:data-test "submit-password"}]]))
|
{:type "password"
|
||||||
|
:name :password-2
|
||||||
|
:label (t locale "labels.confirm-password")}]]
|
||||||
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (t locale "dashboard.update-settings")
|
||||||
|
:data-test "submit-password"}]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:& fm/form {:class "password-form"
|
||||||
|
:on-submit on-submit
|
||||||
|
:form form}
|
||||||
|
[:h2 (t locale "dashboard.password-change")]
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input
|
||||||
|
{:type "password"
|
||||||
|
:name :password-old
|
||||||
|
:auto-focus? true
|
||||||
|
:label (t locale "labels.old-password")}]]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input
|
||||||
|
{:type "password"
|
||||||
|
:name :password-1
|
||||||
|
:label (t locale "labels.new-password")}]]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input
|
||||||
|
{:type "password"
|
||||||
|
:name :password-2
|
||||||
|
:label (t locale "labels.confirm-password")}]]
|
||||||
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (t locale "dashboard.update-settings")
|
||||||
|
:data-test "submit-password"}]])))
|
||||||
|
|
||||||
;; --- Password Page
|
;; --- Password Page
|
||||||
|
|
||||||
(mf/defc password-page
|
(mf/defc password-page
|
||||||
[{:keys [locale]}]
|
[{:keys [locale]}]
|
||||||
(mf/use-effect
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
#(dom/set-html-title (tr "title.settings.password")))
|
(mf/use-effect
|
||||||
|
#(dom/set-html-title (tr "title.settings.password")))
|
||||||
|
|
||||||
|
(if new-css-system
|
||||||
|
[:section {:class (stl/css :dashboard-settings)}
|
||||||
|
[:div {:class (stl/css :form-container)}
|
||||||
|
[:h2 (t locale "dashboard.password-change")]
|
||||||
|
[:& password-form {:locale locale}]]]
|
||||||
|
|
||||||
|
;; old
|
||||||
|
[:section.dashboard-settings.form-container
|
||||||
|
[:div.form-container
|
||||||
|
[:& password-form {:locale locale}]]])))
|
||||||
|
|
||||||
[:section.dashboard-settings.form-container
|
|
||||||
[:div.form-container
|
|
||||||
[:& password-form {:locale locale}]]])
|
|
||||||
|
|||||||
7
frontend/src/app/main/ui/settings/password.scss
Normal file
7
frontend/src/app/main/ui/settings/password.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "./profile" as *;
|
||||||
@ -5,6 +5,7 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.profile
|
(ns app.main.ui.settings.profile
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
@ -15,6 +16,7 @@
|
|||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
@ -41,48 +43,95 @@
|
|||||||
|
|
||||||
(mf/defc profile-form
|
(mf/defc profile-form
|
||||||
[]
|
[]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
|
||||||
|
profile (mf/deref refs/profile)
|
||||||
form (fm/use-form :spec ::profile-form
|
form (fm/use-form :spec ::profile-form
|
||||||
:initial profile
|
:initial profile
|
||||||
:validators [(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))
|
:validators [(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))
|
||||||
(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))])]
|
(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))])
|
||||||
|
|
||||||
[:& fm/form {:on-submit on-submit
|
handle-show-change-email
|
||||||
:form form
|
(mf/use-callback
|
||||||
:class "profile-form"}
|
#(modal/show! :change-email {}))
|
||||||
[:div.fields-row
|
|
||||||
[:& fm/input
|
|
||||||
{:type "text"
|
|
||||||
:name :fullname
|
|
||||||
:label (tr "dashboard.your-name")}]]
|
|
||||||
|
|
||||||
[:div.fields-row
|
handle-show-delete-account
|
||||||
[:& fm/input
|
(mf/use-callback
|
||||||
{:type "email"
|
#(modal/show! :delete-account {}))]
|
||||||
:name :email
|
|
||||||
:disabled true
|
|
||||||
:help-icon i/at
|
|
||||||
:label (tr "dashboard.your-email")}]
|
|
||||||
|
|
||||||
[:div.options
|
(if new-css-system
|
||||||
[:div.change-email
|
[:& fm/form {:on-submit on-submit
|
||||||
[:a {:on-click #(modal/show! :change-email {})}
|
:form form
|
||||||
(tr "dashboard.change-email")]]]]
|
:class (stl/css :profile-form)}
|
||||||
|
[:div {:class (stl/css :fields-row)}
|
||||||
|
[:& fm/input
|
||||||
|
{:type "text"
|
||||||
|
:name :fullname
|
||||||
|
:label (tr "dashboard.your-name")}]]
|
||||||
|
|
||||||
[:> fm/submit-button*
|
[:div {:class (stl/css :fields-row)
|
||||||
{:label (tr "dashboard.save-settings")
|
:on-click handle-show-change-email}
|
||||||
:disabled (empty? (:touched @form))}]
|
[:& fm/input
|
||||||
|
{:type "email"
|
||||||
|
:name :email
|
||||||
|
:disabled true
|
||||||
|
:help-icon i/at
|
||||||
|
:label (tr "dashboard.your-email")}]
|
||||||
|
|
||||||
[:div.links
|
[:div {:class (stl/css :options)}
|
||||||
[:div.link-item
|
[:div.change-email
|
||||||
[:a {:on-click #(modal/show! :delete-account {})
|
[:a {:on-click handle-show-change-email}
|
||||||
:data-test "remove-acount-btn"}
|
(tr "dashboard.change-email")]]]]
|
||||||
(tr "dashboard.remove-account")]]]]))
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "dashboard.save-settings")
|
||||||
|
:disabled (empty? (:touched @form))
|
||||||
|
:className (stl/css :btn-primary)}]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :links)}
|
||||||
|
[:div {:class (stl/css :link-item)}
|
||||||
|
[:a {:on-click handle-show-delete-account
|
||||||
|
:data-test "remove-acount-btn"}
|
||||||
|
(tr "dashboard.remove-account")]]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:& fm/form {:on-submit on-submit
|
||||||
|
:form form
|
||||||
|
:class "profile-form"}
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input
|
||||||
|
{:type "text"
|
||||||
|
:name :fullname
|
||||||
|
:label (tr "dashboard.your-name")}]]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input
|
||||||
|
{:type "email"
|
||||||
|
:name :email
|
||||||
|
:disabled true
|
||||||
|
:help-icon i/at
|
||||||
|
:label (tr "dashboard.your-email")}]
|
||||||
|
|
||||||
|
[:div.options
|
||||||
|
[:div.change-email
|
||||||
|
[:a {:on-click #(modal/show! :change-email {})}
|
||||||
|
(tr "dashboard.change-email")]]]]
|
||||||
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "dashboard.save-settings")
|
||||||
|
:disabled (empty? (:touched @form))}]
|
||||||
|
|
||||||
|
[:div.links
|
||||||
|
[:div.link-item
|
||||||
|
[:a {:on-click #(modal/show! :delete-account {})
|
||||||
|
:data-test "remove-acount-btn"}
|
||||||
|
(tr "dashboard.remove-account")]]]])))
|
||||||
|
|
||||||
;; --- Profile Photo Form
|
;; --- Profile Photo Form
|
||||||
|
|
||||||
(mf/defc profile-photo-form []
|
(mf/defc profile-photo-form []
|
||||||
(let [file-input (mf/use-ref nil)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
file-input (mf/use-ref nil)
|
||||||
profile (mf/deref refs/profile)
|
profile (mf/deref refs/profile)
|
||||||
photo (cf/resolve-profile-photo-url profile)
|
photo (cf/resolve-profile-photo-url profile)
|
||||||
on-image-click #(dom/click (mf/ref-val file-input))
|
on-image-click #(dom/click (mf/ref-val file-input))
|
||||||
@ -91,23 +140,44 @@
|
|||||||
(fn [file]
|
(fn [file]
|
||||||
(st/emit! (du/update-photo file)))]
|
(st/emit! (du/update-photo file)))]
|
||||||
|
|
||||||
[:form.avatar-form
|
(if new-css-system
|
||||||
[:div.image-change-field
|
[:form {:class (stl/css :avatar-form)}
|
||||||
[:span.update-overlay {:on-click on-image-click} (tr "labels.update")]
|
[:div {:class (stl/css :image-change-field)}
|
||||||
[:img {:src photo}]
|
[:span {:class (stl/css :update-overlay)
|
||||||
[:& file-uploader {:accept "image/jpeg,image/png"
|
:on-click on-image-click} (tr "labels.update")]
|
||||||
:multi false
|
[:img {:src photo}]
|
||||||
:ref file-input
|
[:& file-uploader {:accept "image/jpeg,image/png"
|
||||||
:on-selected on-file-selected
|
:multi false
|
||||||
:data-test "profile-image-input"}]]]))
|
:ref file-input
|
||||||
|
:on-selected on-file-selected
|
||||||
|
:data-test "profile-image-input"}]]]
|
||||||
|
;; OLD
|
||||||
|
[:form.avatar-form
|
||||||
|
[:div.image-change-field
|
||||||
|
[:span.update-overlay {:on-click on-image-click} (tr "labels.update")]
|
||||||
|
[:img {:src photo}]
|
||||||
|
[:& file-uploader {:accept "image/jpeg,image/png"
|
||||||
|
:multi false
|
||||||
|
:ref file-input
|
||||||
|
:on-selected on-file-selected
|
||||||
|
:data-test "profile-image-input"}]]])))
|
||||||
|
|
||||||
;; --- Profile Page
|
;; --- Profile Page
|
||||||
|
|
||||||
(mf/defc profile-page []
|
(mf/defc profile-page []
|
||||||
(mf/with-effect []
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
(dom/set-html-title (tr "title.settings.profile")))
|
(mf/with-effect []
|
||||||
[:div.dashboard-settings
|
(dom/set-html-title (tr "title.settings.profile")))
|
||||||
[:div.form-container.two-columns
|
(if new-css-system
|
||||||
[:& profile-photo-form]
|
[:div {:class (stl/css :dashboard-settings)}
|
||||||
[:& profile-form]]])
|
[:div {:class (stl/css :form-container)}
|
||||||
|
[:h2 (tr "labels.profile")]
|
||||||
|
[:& profile-photo-form]
|
||||||
|
[:& profile-form]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-settings
|
||||||
|
[:div.form-container.two-columns
|
||||||
|
[:& profile-photo-form]
|
||||||
|
[:& profile-form]]])))
|
||||||
|
|
||||||
|
|||||||
335
frontend/src/app/main/ui/settings/profile.scss
Normal file
335
frontend/src/app/main/ui/settings/profile.scss
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor" as *;
|
||||||
|
|
||||||
|
.dashboard-settings {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
a {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: $s-368;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
width: $s-580;
|
||||||
|
margin: $s-80 auto auto $s-120;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: $s-500;
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
width: 100%;
|
||||||
|
font-size: $fs-11;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
color: $df-primary;
|
||||||
|
&:hover {
|
||||||
|
color: $da-primary;
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields-row {
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
font-size: $fs-14;
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(input) {
|
||||||
|
height: $s-40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-title {
|
||||||
|
color: $df-primary;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $s-64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-text {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-input,
|
||||||
|
.custom-select {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
label {
|
||||||
|
position: relative;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: $df-primary;
|
||||||
|
font-size: $fs-11;
|
||||||
|
margin-bottom: $s-12;
|
||||||
|
margin-left: calc(-1 * $s-4);
|
||||||
|
}
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border-color: transparent;
|
||||||
|
color: $df-primary;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
::placeholder {
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.help-icon {
|
||||||
|
bottom: $s-12;
|
||||||
|
top: auto;
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
input {
|
||||||
|
background-color: $db-primary;
|
||||||
|
border-color: $db-cuaternary;
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.input-container {
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border-color: transparent;
|
||||||
|
margin-top: $s-24;
|
||||||
|
.main-content {
|
||||||
|
label {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(-1 * $s-24);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
border: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
border-radius: $br-8;
|
||||||
|
padding: $s-12 $s-16;
|
||||||
|
background-color: $db-tertiary;
|
||||||
|
color: $df-primary;
|
||||||
|
border: none;
|
||||||
|
&:focus {
|
||||||
|
outline: $s-1 solid $da-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.two-columns {
|
||||||
|
max-width: $s-520;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: $fs-36;
|
||||||
|
color: $db-tertiary;
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: $fs-24;
|
||||||
|
color: $db-tertiary;
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-icon {
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: $s-48;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $db-primary;
|
||||||
|
height: 40%;
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-text {
|
||||||
|
font-size: $fs-16;
|
||||||
|
color: $db-primary;
|
||||||
|
margin-bottom: $s-20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-text-email {
|
||||||
|
background: $df-primary;
|
||||||
|
border-radius: $br-4;
|
||||||
|
color: $db-primary;
|
||||||
|
font-size: $fs-16;
|
||||||
|
font-weight: $fw500;
|
||||||
|
margin: $s-24 0 $s-40 0;
|
||||||
|
padding: $s-16;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: $fs-24;
|
||||||
|
font-weight: $fw400;
|
||||||
|
color: $df-primary;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: $s-16 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: $fs-12;
|
||||||
|
font-weight: $fw400;
|
||||||
|
color: $df-primary;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: $s-8 0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: $db-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
margin-top: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.avatar-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: $s-148;
|
||||||
|
height: $s-148;
|
||||||
|
margin: $s-16 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 100%;
|
||||||
|
margin-right: $s-16;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-change-field {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.update-overlay {
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: $fs-24;
|
||||||
|
color: $df-primary;
|
||||||
|
line-height: 6;
|
||||||
|
text-align: center;
|
||||||
|
background: $da-tertiary;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="file"] {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.update-overlay {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-width: $s-368;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-subs {
|
||||||
|
border-bottom: $s-1 solid $df-secondary;
|
||||||
|
border-top: $s-1 solid $df-secondary;
|
||||||
|
padding: $s-32 0;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
|
||||||
|
.newsletter-title {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
color: $db-primary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
margin-right: calc(-1 * $s-16);
|
||||||
|
margin-bottom: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-12;
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-checkbox label {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
@extend .button-secondary;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
@extend .button-primary;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
@ -5,12 +5,14 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.sidebar
|
(ns app.main.ui.settings.sidebar
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.dashboard.sidebar :refer [profile-section]]
|
[app.main.ui.dashboard.sidebar :refer [profile-section]]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
@ -21,7 +23,8 @@
|
|||||||
|
|
||||||
(mf/defc sidebar-content
|
(mf/defc sidebar-content
|
||||||
[{:keys [profile section] :as props}]
|
[{:keys [profile section] :as props}]
|
||||||
(let [profile? (= section :settings-profile)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
profile? (= section :settings-profile)
|
||||||
password? (= section :settings-password)
|
password? (= section :settings-password)
|
||||||
options? (= section :settings-options)
|
options? (= section :settings-options)
|
||||||
feedback? (= section :settings-feedback)
|
feedback? (= section :settings-feedback)
|
||||||
@ -66,55 +69,107 @@
|
|||||||
(st/emit! (modal/show {:type :onboarding}))
|
(st/emit! (modal/show {:type :onboarding}))
|
||||||
(st/emit! (modal/show {:type :release-notes :version version}))))))]
|
(st/emit! (modal/show {:type :release-notes :version version}))))))]
|
||||||
|
|
||||||
[:div.sidebar-content
|
(if new-css-system
|
||||||
[:div.sidebar-content-section
|
[:div {:class (stl/css :sidebar-content)}
|
||||||
[:div.back-to-dashboard {:on-click go-dashboard}
|
[:div {:class (stl/css :sidebar-content-section)}
|
||||||
[:span.icon i/arrow-down]
|
[:div {:class (stl/css :back-to-dashboard)
|
||||||
[:span.text (tr "labels.dashboard")]]]
|
:on-click go-dashboard}
|
||||||
[:hr]
|
[:span {:class (stl/css :icon)} i/arrow-down]
|
||||||
|
[:span {:class (stl/css :text)} (tr "labels.dashboard")]]]
|
||||||
[:div.sidebar-content-section
|
|
||||||
[:ul.sidebar-nav.no-overflow
|
|
||||||
[:li {:class (when profile? "current")
|
|
||||||
:on-click go-settings-profile}
|
|
||||||
i/user
|
|
||||||
[:span.element-title (tr "labels.profile")]]
|
|
||||||
|
|
||||||
[:li {:class (when password? "current")
|
|
||||||
:on-click go-settings-password}
|
|
||||||
i/lock
|
|
||||||
[:span.element-title (tr "labels.password")]]
|
|
||||||
|
|
||||||
[:li {:class (when options? "current")
|
|
||||||
:on-click go-settings-options
|
|
||||||
:data-test "settings-profile"}
|
|
||||||
i/tree
|
|
||||||
[:span.element-title (tr "labels.settings")]]
|
|
||||||
|
|
||||||
(when (contains? cf/flags :access-tokens)
|
|
||||||
[:li {:class (when access-tokens? "current")
|
|
||||||
:on-click go-settings-access-tokens
|
|
||||||
:data-test "settings-access-tokens"}
|
|
||||||
i/icon-key
|
|
||||||
[:span.element-title (tr "labels.access-tokens")]])
|
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
|
||||||
[:li {:on-click show-release-notes :data-test "release-notes"}
|
[:div {:class (stl/css :sidebar-content-section)}
|
||||||
i/pencil
|
[:ul {:class (stl/css :sidebar-nav :no-overflow)}
|
||||||
[:span.element-title (tr "labels.release-notes")]]
|
[:li {:class (when profile? (stl/css :current))
|
||||||
|
:on-click go-settings-profile}
|
||||||
|
[:span {:class (stl/css :element-title)} (tr "labels.profile")]]
|
||||||
|
|
||||||
(when (contains? cf/flags :user-feedback)
|
[:li {:class (when password? (stl/css :current))
|
||||||
[:li {:class (when feedback? "current")
|
:on-click go-settings-password}
|
||||||
:on-click go-settings-feedback}
|
[:span {:class (stl/css :element-title)} (tr "labels.password")]]
|
||||||
i/msg-info
|
|
||||||
[:span.element-title (tr "labels.give-feedback")]])]]]))
|
[:li {:class (when options? (stl/css :current))
|
||||||
|
:on-click go-settings-options
|
||||||
|
:data-test "settings-profile"}
|
||||||
|
[:span {:class (stl/css :element-title)} (tr "labels.settings")]]
|
||||||
|
|
||||||
|
(when (contains? cf/flags :access-tokens)
|
||||||
|
[:li {:class (when access-tokens? (stl/css :current))
|
||||||
|
:on-click go-settings-access-tokens
|
||||||
|
:data-test "settings-access-tokens"}
|
||||||
|
[:span {:class (stl/css :element-title)} (tr "labels.access-tokens")]])
|
||||||
|
|
||||||
|
[:hr]
|
||||||
|
|
||||||
|
[:li {:on-click show-release-notes :data-test "release-notes"}
|
||||||
|
[:span {:class (stl/css :element-title)} (tr "labels.release-notes")]]
|
||||||
|
|
||||||
|
(when (contains? cf/flags :user-feedback)
|
||||||
|
[:li {:class (when feedback? (stl/css :current))
|
||||||
|
:on-click go-settings-feedback}
|
||||||
|
i/msg-info
|
||||||
|
[:span {:class (stl/css :element-title)} (tr "labels.give-feedback")]])]]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.sidebar-content
|
||||||
|
[:div.sidebar-content-section
|
||||||
|
[:div.back-to-dashboard {:on-click go-dashboard}
|
||||||
|
[:span.icon i/arrow-down]
|
||||||
|
[:span.text (tr "labels.dashboard")]]]
|
||||||
|
[:hr]
|
||||||
|
|
||||||
|
[:div.sidebar-content-section
|
||||||
|
[:ul.sidebar-nav.no-overflow
|
||||||
|
[:li {:class (when profile? "current")
|
||||||
|
:on-click go-settings-profile}
|
||||||
|
i/user
|
||||||
|
[:span.element-title (tr "labels.profile")]]
|
||||||
|
|
||||||
|
[:li {:class (when password? "current")
|
||||||
|
:on-click go-settings-password}
|
||||||
|
i/lock
|
||||||
|
[:span.element-title (tr "labels.password")]]
|
||||||
|
|
||||||
|
[:li {:class (when options? "current")
|
||||||
|
:on-click go-settings-options
|
||||||
|
:data-test "settings-profile"}
|
||||||
|
i/tree
|
||||||
|
[:span.element-title (tr "labels.settings")]]
|
||||||
|
|
||||||
|
(when (contains? cf/flags :access-tokens)
|
||||||
|
[:li {:class (when access-tokens? "current")
|
||||||
|
:on-click go-settings-access-tokens
|
||||||
|
:data-test "settings-access-tokens"}
|
||||||
|
i/icon-key
|
||||||
|
[:span.element-title (tr "labels.access-tokens")]])
|
||||||
|
|
||||||
|
[:hr]
|
||||||
|
|
||||||
|
[:li {:on-click show-release-notes :data-test "release-notes"}
|
||||||
|
i/pencil
|
||||||
|
[:span.element-title (tr "labels.release-notes")]]
|
||||||
|
|
||||||
|
(when (contains? cf/flags :user-feedback)
|
||||||
|
[:li {:class (when feedback? "current")
|
||||||
|
:on-click go-settings-feedback}
|
||||||
|
i/msg-info
|
||||||
|
[:span.element-title (tr "labels.give-feedback")]])]]])))
|
||||||
|
|
||||||
(mf/defc sidebar
|
(mf/defc sidebar
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [profile locale section]}]
|
[{:keys [profile locale section]}]
|
||||||
[:div.dashboard-sidebar.settings
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:& sidebar-content {:profile profile
|
(if new-css-system
|
||||||
:section section}]
|
[:div {:class (stl/css :dashboard-sidebar :settings)}
|
||||||
[:& profile-section {:profile profile
|
[:& sidebar-content {:profile profile
|
||||||
:locale locale}]])
|
:section section}]
|
||||||
|
[:& profile-section {:profile profile
|
||||||
|
:locale locale}]]
|
||||||
|
|
||||||
|
;; OLD
|
||||||
|
[:div.dashboard-sidebar.settings
|
||||||
|
[:& sidebar-content {:profile profile
|
||||||
|
:section section}]
|
||||||
|
[:& profile-section {:profile profile
|
||||||
|
:locale locale}]])))
|
||||||
|
|
||||||
|
|||||||
159
frontend/src/app/main/ui/settings/sidebar.scss
Normal file
159
frontend/src/app/main/ui/settings/sidebar.scss
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.dashboard-sidebar {
|
||||||
|
background-color: $db-primary;
|
||||||
|
border-right: $s-1 solid $db-cuaternary;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
grid-column: 1 / span 2;
|
||||||
|
grid-row: 1 / span 2;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 $s-16 0 0;
|
||||||
|
padding: $s-16 0 0 0;
|
||||||
|
z-index: $z-index-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color: transparent;
|
||||||
|
margin: $s-12 $s-16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&.no-overflow {
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-24;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: $fw400;
|
||||||
|
width: 100%;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $db-secondary;
|
||||||
|
margin-right: $s-8;
|
||||||
|
height: $s-12;
|
||||||
|
width: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-size: $fs-14;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
display: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: $br-4;
|
||||||
|
content: "";
|
||||||
|
height: $s-24;
|
||||||
|
margin-right: $s-8;
|
||||||
|
width: $s-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.recent-projects {
|
||||||
|
svg {
|
||||||
|
fill: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .edit-wrapper {
|
||||||
|
border: $s-1 solid $df-primary;
|
||||||
|
border-radius: $br-4;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.element-title {
|
||||||
|
border: 0;
|
||||||
|
height: $s-32;
|
||||||
|
padding: $s-6;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: $df-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.element-subtitle {
|
||||||
|
color: $df-secondary;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
&::before {
|
||||||
|
background-color: $df-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.current {
|
||||||
|
background-color: $db-cuaternary;
|
||||||
|
a {
|
||||||
|
font-weight: $fw400;
|
||||||
|
color: $da-primary;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
color: $da-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background-color: $da-tertiary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-dashboard {
|
||||||
|
padding: $s-12 $s-16;
|
||||||
|
font-size: $fs-14;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $df-secondary;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
width: $s-12;
|
||||||
|
height: $s-12;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,8 +5,11 @@
|
|||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.static
|
(ns app.main.ui.static
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.util.globals :as globals]
|
[app.util.globals :as globals]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
@ -17,66 +20,112 @@
|
|||||||
(mf/defc static-header
|
(mf/defc static-header
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [children (obj/get props "children")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
children (obj/get props "children")
|
||||||
on-click (mf/use-callback #(set! (.-href globals/location) "/"))]
|
on-click (mf/use-callback #(set! (.-href globals/location) "/"))]
|
||||||
[:section.exception-layout
|
(if new-css-system
|
||||||
[:div.exception-header
|
[:section {:class (stl/css :exception-layout)}
|
||||||
{:on-click on-click}
|
[:div
|
||||||
i/logo]
|
{:class (stl/css :exception-header)
|
||||||
[:div.exception-content
|
:on-click on-click}
|
||||||
[:div.container children]]]))
|
i/logo-icon]
|
||||||
|
[:div {:class (stl/css :deco-before)} i/logo-error-screen]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :exception-content)}
|
||||||
|
[:div {:class (stl/css :container)} children]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :deco-after)} i/logo-error-screen]]
|
||||||
|
[:section.exception-layout
|
||||||
|
[:div.exception-header
|
||||||
|
{:on-click on-click}
|
||||||
|
i/logo]
|
||||||
|
[:div.exception-content
|
||||||
|
[:div.container children]]])))
|
||||||
|
|
||||||
(mf/defc not-found
|
(mf/defc not-found
|
||||||
[]
|
[]
|
||||||
[:> static-header {}
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:div.image i/icon-empty]
|
(if new-css-system
|
||||||
[:div.main-message (tr "labels.not-found.main-message")]
|
[:> static-header {}
|
||||||
[:div.desc-message (tr "labels.not-found.desc-message")]])
|
[:div {:class (stl/css :main-message)} (tr "labels.not-found.main-message")]
|
||||||
|
[:div {:class (stl/css :desc-message)} (tr "labels.not-found.desc-message")]]
|
||||||
|
|
||||||
|
[:> static-header {}
|
||||||
|
[:div.image i/icon-empty]
|
||||||
|
[:div.main-message (tr "labels.not-found.main-message")]
|
||||||
|
[:div.desc-message (tr "labels.not-found.desc-message")]])))
|
||||||
|
|
||||||
(mf/defc bad-gateway
|
(mf/defc bad-gateway
|
||||||
[]
|
[]
|
||||||
[:> static-header {}
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
[:div.image i/icon-empty]
|
handle-retry
|
||||||
[:div.main-message (tr "labels.bad-gateway.main-message")]
|
(mf/use-callback
|
||||||
[:div.desc-message (tr "labels.bad-gateway.desc-message")]
|
(fn [] (st/emit! (rt/assign-exception nil))))]
|
||||||
[:div.sign-info
|
(if new-css-system
|
||||||
[:a.btn-primary.btn-small
|
[:> static-header {}
|
||||||
{:on-click (fn [] (st/emit! #(dissoc % :exception)))}
|
[:div {:class (stl/css :main-message)} (tr "labels.bad-gateway.main-message")]
|
||||||
(tr "labels.retry")]]])
|
[:div {:class (stl/css :desc-message)} (tr "labels.bad-gateway.desc-message")]
|
||||||
|
[:div {:class (stl/css :sign-info)}
|
||||||
|
[:button {:on-click handle-retry} (tr "labels.retry")]]]
|
||||||
|
|
||||||
|
[:> static-header {}
|
||||||
|
[:div.image i/icon-empty]
|
||||||
|
[:div.main-message (tr "labels.bad-gateway.main-message")]
|
||||||
|
[:div.desc-message (tr "labels.bad-gateway.desc-message")]
|
||||||
|
[:div.sign-info
|
||||||
|
[:a.btn-primary.btn-small {:on-click handle-retry} (tr "labels.retry")]]])))
|
||||||
|
|
||||||
(mf/defc service-unavailable
|
(mf/defc service-unavailable
|
||||||
[]
|
[]
|
||||||
[:> static-header {}
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
[:div.image i/icon-empty]
|
handle-retry
|
||||||
[:div.main-message (tr "labels.service-unavailable.main-message")]
|
(mf/use-callback
|
||||||
[:div.desc-message (tr "labels.service-unavailable.desc-message")]
|
(fn [] (st/emit! (rt/assign-exception nil))))]
|
||||||
[:div.sign-info
|
(if new-css-system
|
||||||
[:a.btn-primary.btn-small
|
[:> static-header {}
|
||||||
{:on-click (fn [] (st/emit! #(dissoc % :exception)))}
|
[:div {:class (stl/css :main-message)} (tr "labels.service-unavailable.main-message")]
|
||||||
(tr "labels.retry")]]])
|
[:div {:class (stl/css :desc-message)} (tr "labels.service-unavailable.desc-message")]
|
||||||
|
[:div {:class (stl/css :sign-info)}
|
||||||
|
[:button {:on-click handle-retry} (tr "labels.retry")]]]
|
||||||
|
|
||||||
|
[:> static-header {}
|
||||||
|
[:div.main-message (tr "labels.service-unavailable.main-message")]
|
||||||
|
[:div.desc-message (tr "labels.service-unavailable.desc-message")]
|
||||||
|
[:div.sign-info
|
||||||
|
[:a.btn-primary.btn-small {:on-click handle-retry} (tr "labels.retry")]]])))
|
||||||
|
|
||||||
(mf/defc internal-error
|
(mf/defc internal-error
|
||||||
[]
|
[]
|
||||||
[:> static-header {}
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
[:div.image i/icon-empty]
|
handle-retry
|
||||||
[:div.main-message (tr "labels.internal-error.main-message")]
|
(mf/use-callback
|
||||||
[:div.desc-message (tr "labels.internal-error.desc-message")]
|
(fn [] (st/emit! (rt/assign-exception nil))))]
|
||||||
[:div.sign-info
|
(if new-css-system
|
||||||
[:a.btn-primary.btn-small
|
[:> static-header {}
|
||||||
{:on-click (fn [] (st/emit! (rt/assign-exception nil)))}
|
[:div {:class (stl/css :main-message)} (tr "labels.internal-error.main-message")]
|
||||||
(tr "labels.retry")]]])
|
[:div {:class (stl/css :desc-message)} (tr "labels.internal-error.desc-message")]
|
||||||
|
[:div {:class (stl/css :sign-info)}
|
||||||
|
[:button {:on-click handle-retry} (tr "labels.retry")]]]
|
||||||
|
|
||||||
|
[:> static-header {}
|
||||||
|
[:div.image i/icon-empty]
|
||||||
|
[:div.main-message (tr "labels.internal-error.main-message")]
|
||||||
|
[:div.desc-message (tr "labels.internal-error.desc-message")]
|
||||||
|
[:div.sign-info
|
||||||
|
[:a.btn-primary.btn-small {:on-click handle-retry} (tr "labels.retry")]]])))
|
||||||
|
|
||||||
(mf/defc exception-page
|
(mf/defc exception-page
|
||||||
[{:keys [data] :as props}]
|
[{:keys [data] :as props}]
|
||||||
(case (:type data)
|
(let [new-css-system (features/use-feature "styles/v2")]
|
||||||
:not-found
|
[:& (mf/provider ctx/new-css-system) {:value new-css-system}
|
||||||
[:& not-found]
|
(case (:type data)
|
||||||
|
:not-found
|
||||||
|
[:& not-found]
|
||||||
|
|
||||||
:bad-gateway
|
:bad-gateway
|
||||||
[:& bad-gateway]
|
[:& bad-gateway]
|
||||||
|
|
||||||
:service-unavailable
|
:service-unavailable
|
||||||
[:& service-unavailable]
|
[:& service-unavailable]
|
||||||
|
|
||||||
[:& internal-error]))
|
|
||||||
|
|
||||||
|
[:& internal-error])]))
|
||||||
|
|||||||
91
frontend/src/app/main/ui/static.scss
Normal file
91
frontend/src/app/main/ui/static.scss
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
@use "common/refactor/common-refactor.scss" as *;
|
||||||
|
|
||||||
|
.exception-layout {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: $db-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deco-before,
|
||||||
|
.deco-after {
|
||||||
|
position: absolute;
|
||||||
|
left: calc(50% - $s-40);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
position: absolute;
|
||||||
|
fill: $df-secondary;
|
||||||
|
height: 1537px;
|
||||||
|
width: $s-80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.deco-before {
|
||||||
|
height: 34vh;
|
||||||
|
top: 0;
|
||||||
|
svg {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.deco-after {
|
||||||
|
height: 34vh;
|
||||||
|
bottom: 0;
|
||||||
|
svg {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.exception-header {
|
||||||
|
padding: $s-24 $s-32;
|
||||||
|
position: fixed;
|
||||||
|
svg {
|
||||||
|
fill: $df-primary;
|
||||||
|
width: $s-48;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.exception-content {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $s-16;
|
||||||
|
height: 34vh;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 33vh;
|
||||||
|
text-align: center;
|
||||||
|
width: $s-640;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-message {
|
||||||
|
@include bigTitleTipography;
|
||||||
|
color: $df-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-message {
|
||||||
|
@include bigTitleTipography;
|
||||||
|
color: $df-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sign-info {
|
||||||
|
text-align: center;
|
||||||
|
button {
|
||||||
|
@extend .button-primary;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: $s-8 $s-16;
|
||||||
|
font-size: $fs-11;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3249,6 +3249,11 @@ aggregate-error@^3.0.0:
|
|||||||
clean-stack "^2.0.0"
|
clean-stack "^2.0.0"
|
||||||
indent-string "^4.0.0"
|
indent-string "^4.0.0"
|
||||||
|
|
||||||
|
animate.css@^4.1.1:
|
||||||
|
version "4.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/animate.css/-/animate.css-4.1.1.tgz#614ec5a81131d7e4dc362a58143f7406abd68075"
|
||||||
|
integrity sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==
|
||||||
|
|
||||||
ansi-colors@^1.0.1:
|
ansi-colors@^1.0.1:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
|
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user