mirror of
https://github.com/penpot/penpot.git
synced 2025-05-12 17:06:37 +02:00
💄 Add new UI at modals
This commit is contained in:
parent
59162e4f80
commit
6d64feda36
70 changed files with 4908 additions and 1138 deletions
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"**/.clj-kondo": true,
|
"**/.clj-kondo": true,
|
||||||
"**/.cpcache": true,
|
"**/.cpcache": true,
|
||||||
"**/.lsp": true,
|
"**/.lsp": true,
|
||||||
"**/.shadow-cljs": true,
|
"**/.shadow-cljs": true,
|
||||||
"**/node_modules": true
|
"**/node_modules": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
frontend/resources/images/icons/msg-error-refactor.svg
Normal file
3
frontend/resources/images/icons/msg-error-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M10.667 10.667S9.667 9.333 8 9.333c-1.667 0-2.667 1.334-2.667 1.334M8 1.333A6.671 6.671 0 0114.667 8 6.671 6.671 0 018 14.667 6.671 6.671 0 011.333 8 6.671 6.671 0 018 1.333zM5.5 5.667a.333.333 0 110 .666.333.333 0 010-.666zm5 0a.333.333 0 110 .666.333.333 0 010-.666z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 400 B |
3
frontend/resources/images/icons/msg-neutral-refactor.svg
Normal file
3
frontend/resources/images/icons/msg-neutral-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M6.86 1.608a1.333 1.333 0 012.28 0l5.647 9.426a1.332 1.332 0 01-1.14 2H2.353a1.332 1.332 0 01-1.14-2L6.86 1.608z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 244 B |
3
frontend/resources/images/icons/msg-success-refactor.svg
Normal file
3
frontend/resources/images/icons/msg-success-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M10.667 9.333s-1 1.334-2.667 1.334c-1.667 0-2.667-1.334-2.667-1.334m2.667-8A6.671 6.671 0 0114.667 8 6.671 6.671 0 018 14.667 6.671 6.671 0 011.333 8 6.671 6.671 0 018 1.333zm2.5 4.334a.333.333 0 100 .666.333.333 0 000-.666zm-5 0a.333.333 0 100 .666.333.333 0 000-.666z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 401 B |
3
frontend/resources/images/icons/msg-warning-refactor.svg
Normal file
3
frontend/resources/images/icons/msg-warning-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M10.667 10H5.333M8 1.333A6.671 6.671 0 0114.667 8 6.671 6.671 0 018 14.667 6.671 6.671 0 011.333 8 6.671 6.671 0 018 1.333zm2.5 4.334a.333.333 0 100 .666.333.333 0 000-.666zm-5 0a.333.333 0 100 .666.333.333 0 000-.666z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 350 B |
3
frontend/resources/images/icons/tree-refactor.svg
Normal file
3
frontend/resources/images/icons/tree-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M13 15a2 2 0 100-4 2 2 0 000 4zM8 5a2 2 0 100-4 2 2 0 000 4zM8 8h3.667A1.333 1.333 0 0113 9.333V11M3 15a2 2 0 110-4 2 2 0 010 4zM8 8H4.333A1.333 1.333 0 003 9.333V11M8 5v3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 303 B |
3
frontend/resources/images/icons/user-refactor.svg
Normal file
3
frontend/resources/images/icons/user-refactor.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path d="M13.333 14v-1.333A2.667 2.667 0 0010.667 10H5.333a2.667 2.667 0 00-2.666 2.667V14M8 7.333A2.667 2.667 0 108 2a2.667 2.667 0 000 5.333z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 266 B |
|
@ -66,7 +66,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:global(.disabled),
|
&:global(.disabled),
|
||||||
&[disabled] {
|
&[disabled],
|
||||||
|
&:disabled {
|
||||||
background-color: var(--button-background-color-disabled);
|
background-color: var(--button-background-color-disabled);
|
||||||
border: $s-1 solid var(--button-border-color-disabled);
|
border: $s-1 solid var(--button-border-color-disabled);
|
||||||
color: var(--button-foreground-color-disabled);
|
color: var(--button-foreground-color-disabled);
|
||||||
|
@ -107,7 +108,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:global(.disabled),
|
&:global(.disabled),
|
||||||
&[disabled] {
|
&[disabled],
|
||||||
|
&:disabled {
|
||||||
background-color: var(--button-background-color-disabled);
|
background-color: var(--button-background-color-disabled);
|
||||||
border: $s-1 solid var(--button-border-color-disabled);
|
border: $s-1 solid var(--button-border-color-disabled);
|
||||||
color: var(--button-foreground-color-disabled);
|
color: var(--button-foreground-color-disabled);
|
||||||
|
@ -147,7 +149,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:global(.disabled),
|
&:global(.disabled),
|
||||||
&[disabled] {
|
&[disabled],
|
||||||
|
&:disabled {
|
||||||
color: var(--button-foreground-color-disabled);
|
color: var(--button-foreground-color-disabled);
|
||||||
cursor: unset;
|
cursor: unset;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -202,9 +205,9 @@
|
||||||
.button-disabled {
|
.button-disabled {
|
||||||
@include buttonStyle;
|
@include buttonStyle;
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
background-color: var(--button-disabled-background-color-rest);
|
background-color: var(--button-background-color-disabled);
|
||||||
border: $s-1 solid var(--button-disabled-border-color-rest);
|
border: $s-1 solid var(--button-border-color-disabled);
|
||||||
color: var(--button-disabled-foreground-color-rest);
|
color: var(--button-foreground-color-disabled);
|
||||||
cursor: unset;
|
cursor: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +257,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// INPUTS
|
// INPUTS
|
||||||
|
|
||||||
.input-base {
|
.input-base {
|
||||||
@include removeInputStyle;
|
@include removeInputStyle;
|
||||||
@include titleTipography;
|
@include titleTipography;
|
||||||
|
@ -313,9 +315,11 @@
|
||||||
input {
|
input {
|
||||||
@extend .input-base;
|
@extend .input-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
::placeholder {
|
::placeholder {
|
||||||
color: var(--input-placeholder-color);
|
color: var(--input-placeholder-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
span {
|
span {
|
||||||
color: var(--input-foreground-color);
|
color: var(--input-foreground-color);
|
||||||
|
@ -327,9 +331,48 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-element-label {
|
||||||
|
@include titleTipography;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 0;
|
||||||
|
input {
|
||||||
|
@extend .input-base;
|
||||||
|
padding-left: $s-8;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
height: $s-32;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid var(--input-background-color);
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
}
|
||||||
|
::placeholder {
|
||||||
|
color: var(--input-placeholder-color);
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
input {
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
background-color: var(--input-background-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within,
|
||||||
|
&:active {
|
||||||
|
input {
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
background-color: var(--input-background-color-active);
|
||||||
|
border: $s-1 solid var(--input-border-color-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.disabled-input {
|
.disabled-input {
|
||||||
background-color: var(--input-background-color-disabled);
|
background-color: var(--input-background-color-disabled);
|
||||||
border: 1px solid var(--input-border-color-disabled);
|
border: $s-1 solid var(--input-border-color-disabled);
|
||||||
color: var(--input-foreground-color-disabled);
|
color: var(--input-foreground-color-disabled);
|
||||||
input {
|
input {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -348,17 +391,40 @@
|
||||||
min-width: $s-16;
|
min-width: $s-16;
|
||||||
min-height: $s-16;
|
min-height: $s-16;
|
||||||
border-radius: $br-6;
|
border-radius: $br-6;
|
||||||
background-color: var(--input-background-color);
|
background-color: var(--input-checkbox-background-color-rest);
|
||||||
|
border: $s-1 solid var(--input-checkbox-background-color-rest);
|
||||||
svg {
|
svg {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--input-checkbox-border-color-hover);
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--input-checkbox-border-color-focus);
|
||||||
|
}
|
||||||
&:global(.checked) {
|
&:global(.checked) {
|
||||||
background-color: var(--input-border-color-active);
|
background-color: var(--input-border-color-active);
|
||||||
|
border-color: var(--input-checkbox-border-color-active);
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--input-details-color);
|
stroke: var(--input-details-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&:global(.intermediate) {
|
||||||
|
background-color: var(--input-checkbox-background-color-intermediate);
|
||||||
|
border-color: var(--input-checkbox-border-color-active);
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: var(--input-details-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:global(.unchecked) {
|
||||||
|
background-color: var(--input-checkbox-background-color-rest);
|
||||||
|
border: $s-1 solid var(--input-checkbox-background-color-rest);
|
||||||
|
svg {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-checkbox {
|
.input-checkbox {
|
||||||
|
@ -376,6 +442,53 @@
|
||||||
input {
|
input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
&:hover {
|
||||||
|
span {
|
||||||
|
border-color: var(--input-checkbox-border-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-with-label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
label {
|
||||||
|
@include titleTipography;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
min-height: $s-16;
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
@extend .input-base;
|
||||||
|
@include titleTipography;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-32;
|
||||||
|
min-height: $s-32;
|
||||||
|
margin-top: $s-8;
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
border: $s-1 solid var(--input-background-color);
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
&:focus-within,
|
||||||
|
&:active {
|
||||||
|
input {
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
}
|
||||||
|
background-color: var(--input-background-color-active);
|
||||||
|
border: $s-1 solid var(--input-border-color-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:global(.disabled) {
|
||||||
|
@extend .disabled-input;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:global(.invalid) {
|
||||||
|
input {
|
||||||
|
border: $s-1 solid var(--input-border-color-error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +505,83 @@
|
||||||
background-color: var(--modal-background-color);
|
background-color: var(--modal-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-overlay-base {
|
||||||
|
@include flexCenter;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
background-color: var(--color-background-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container-base {
|
||||||
|
position: relative;
|
||||||
|
padding: $s-32;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--modal-background-color);
|
||||||
|
min-width: $s-364;
|
||||||
|
min-height: $s-192;
|
||||||
|
max-width: $s-512;
|
||||||
|
max-height: $s-512;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close-btn-base {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-8;
|
||||||
|
right: $s-6;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-28;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-hint-base {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
border-top: $s-1 solid var(--modal-hint-border-color);
|
||||||
|
border-bottom: $s-1 solid var(--modal-hint-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-action-btns {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-cancel-btn {
|
||||||
|
@extend .button-secondary;
|
||||||
|
@include tabTitleTipography;
|
||||||
|
padding: $s-8 $s-24;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-32;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-accept-btn {
|
||||||
|
@extend .button-primary;
|
||||||
|
@include tabTitleTipography;
|
||||||
|
padding: $s-8 $s-24;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-32;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-danger-btn {
|
||||||
|
@extend .button-primary;
|
||||||
|
@include tabTitleTipography;
|
||||||
|
padding: $s-8 $s-24;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-32;
|
||||||
|
margin: 0;
|
||||||
|
background-color: var(--modal-button-background-color-error);
|
||||||
|
border: $s-1 solid var(--modal-button-background-color-error);
|
||||||
|
color: var(--modal-button-foreground-color-error);
|
||||||
|
}
|
||||||
|
|
||||||
// UI ELEMENTS
|
// UI ELEMENTS
|
||||||
.asset-element {
|
.asset-element {
|
||||||
@include titleTipography;
|
@include titleTipography;
|
||||||
|
@ -641,3 +831,13 @@
|
||||||
background-color: var(--menu-background-color);
|
background-color: var(--menu-background-color);
|
||||||
color: var(--menu-foreground-color);
|
color: var(--menu-foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select-wrapper {
|
||||||
|
@include titleTipography;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: normal;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
|
|
||||||
// NOTIFICATION
|
// NOTIFICATION
|
||||||
--dark-ok-color: var(--strong-green);
|
--dark-ok-color: var(--strong-green);
|
||||||
--dark-warning-color: #ff9b49;
|
--dark-warning-color: #ff6432;
|
||||||
--dark-pending-color: var(--lilac);
|
--dark-pending-color: var(--lilac);
|
||||||
--dark-error-color: #ff4986;
|
--dark-error-color: #ec1f1f;
|
||||||
|
|
||||||
// LIGHT
|
// LIGHT
|
||||||
--light-gray-1: #fff;
|
--light-gray-1: #fff;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
.light,
|
.light,
|
||||||
.default {
|
.default {
|
||||||
|
// BASE COLORS
|
||||||
--canvas-background-color: var(--color-background-primary);
|
--canvas-background-color: var(--color-background-primary);
|
||||||
--canvas-fill-color: var(--canvas-color);
|
--canvas-fill-color: var(--canvas-color);
|
||||||
|
|
||||||
|
@ -15,7 +16,6 @@
|
||||||
--panel-title-background-color: var(--color-background-secondary);
|
--panel-title-background-color: var(--color-background-secondary);
|
||||||
|
|
||||||
// BUTTONS
|
// BUTTONS
|
||||||
|
|
||||||
--button-foreground-hover: var(--color-accent-primary);
|
--button-foreground-hover: var(--color-accent-primary);
|
||||||
--button-background-color-focus: var(--color-background-secondary);
|
--button-background-color-focus: var(--color-background-secondary);
|
||||||
--button-foreground-color-focus: var(--color-foreground-primary);
|
--button-foreground-color-focus: var(--color-foreground-primary);
|
||||||
|
@ -88,22 +88,19 @@
|
||||||
--constraint-widget-background-color: var(--color-background-tertiary);
|
--constraint-widget-background-color: var(--color-background-tertiary);
|
||||||
--constraint-center-area-background-color: var(--color-background-primary);
|
--constraint-center-area-background-color: var(--color-background-primary);
|
||||||
|
|
||||||
// ICONS
|
// TABS
|
||||||
--icon-foreground: var(--color-foreground-secondary);
|
|
||||||
--icon-foreground-hover: var(--color-foreground-primary);
|
|
||||||
|
|
||||||
--link-foreground-color: var(--color-accent-primary);
|
|
||||||
|
|
||||||
--tab-background-color-hover: var(--color-background-primary);
|
--tab-background-color-hover: var(--color-background-primary);
|
||||||
--tab-background-color-selected: var(--color-background-quaternary);
|
--tab-background-color-selected: var(--color-background-quaternary);
|
||||||
--tab-foreground-color: var(--color-foreground-secondary);
|
--tab-foreground-color: var(--color-foreground-secondary);
|
||||||
--tab-foreground-color-hover: var(--color-foreground-primary);
|
--tab-foreground-color-hover: var(--color-foreground-primary);
|
||||||
--tab-foreground-color-selected: var(--color-accent-primary);
|
--tab-foreground-color-selected: var(--color-accent-primary);
|
||||||
|
|
||||||
|
// SECTION TITLE
|
||||||
--title-background-color: var(--color-background-primary);
|
--title-background-color: var(--color-background-primary);
|
||||||
--title-foreground-color: var(--color-foreground-secondary);
|
--title-foreground-color: var(--color-foreground-secondary);
|
||||||
--title-foreground-color-hover: var(--color-foreground-primary);
|
--title-foreground-color-hover: var(--color-foreground-primary);
|
||||||
|
|
||||||
|
// LAYER ELEMENT
|
||||||
--layer-row-background-color: var(--color-background-primary);
|
--layer-row-background-color: var(--color-background-primary);
|
||||||
--layer-row-background-color-hover: var(--color-background-secondary);
|
--layer-row-background-color-hover: var(--color-background-secondary);
|
||||||
--layer-row-background-color-selected: var(--color-background-quaternary);
|
--layer-row-background-color-selected: var(--color-background-quaternary);
|
||||||
|
@ -118,9 +115,26 @@
|
||||||
--layer-child-row-foreground-color: var(--color-foreground-secondary);
|
--layer-child-row-foreground-color: var(--color-foreground-secondary);
|
||||||
--layer-row-component-foreground-color: var(--color-accent-secondary);
|
--layer-row-component-foreground-color: var(--color-accent-secondary);
|
||||||
|
|
||||||
--search-bar-background-color: var(--color-background-primary);
|
// PALETTE & COLOR BULLET
|
||||||
--search-bar-input-background-color: var(--color-background-tertiary);
|
--palette-background-color: var(--color-background-primary);
|
||||||
--search-bar-input-border-color: var(--color-background-tertiary);
|
--palette-btn-background-color-selected: var(--color-background-secondary);
|
||||||
|
--palette-btn-border-color-selected: var(--color-background-quaternary);
|
||||||
|
--palette-btn-foreground-color-selected: var(--color-accent-primary);
|
||||||
|
--palette-text-color: var(--color-foreground-secondary);
|
||||||
|
--palette-text-color-selected: var(--color-foreground-primary);
|
||||||
|
--palette-text-background-color: var(--color-background-tertiary);
|
||||||
|
--palette-text-background-color-hover: var(--color-background-quaternary);
|
||||||
|
--palette-button-shadow-initial: var(--color-background-primary);
|
||||||
|
--palette-button-shadow-final: transparent;
|
||||||
|
--palette-handler-background-color: var(--color-background-quaternary);
|
||||||
|
|
||||||
|
--color-bullet-background-color: var(--white); // We don't want this color to change with palette
|
||||||
|
--color-bullet-border-color: var(--color-background-quaternary);
|
||||||
|
--color-bullet-border-color-selected: var(--color-accent-primary);
|
||||||
|
|
||||||
|
// ICONS
|
||||||
|
--icon-foreground: var(--color-foreground-secondary);
|
||||||
|
--icon-foreground-hover: var(--color-foreground-primary);
|
||||||
|
|
||||||
// INPUTS, SELECTS, DROPDOWNS
|
// INPUTS, SELECTS, DROPDOWNS
|
||||||
--input-background-color: var(--color-background-tertiary);
|
--input-background-color: var(--color-background-tertiary);
|
||||||
|
@ -136,7 +150,14 @@
|
||||||
--input-background-color-disabled: var(--color-background-primary);
|
--input-background-color-disabled: var(--color-background-primary);
|
||||||
--input-foreground-color-disabled: var(--color-foreground-secondary);
|
--input-foreground-color-disabled: var(--color-foreground-secondary);
|
||||||
--input-border-color-disabled: var(--color-background-quaternary);
|
--input-border-color-disabled: var(--color-background-quaternary);
|
||||||
|
--input-border-color-error: var(--error-color);
|
||||||
--input-details-color: var(--color-background-primary);
|
--input-details-color: var(--color-background-primary);
|
||||||
|
--input-checkbox-background-color-rest: var(--color-background-quaternary);
|
||||||
|
--input-checkbox-border-color-active: var(--color-background-quaternary);
|
||||||
|
--input-checkbox-border-color-focus: var(--color-accent-primary);
|
||||||
|
--input-checkbox-border-color: var(--color-background-secondary);
|
||||||
|
--input-checkbox-border-color-hover: var(--color-accent-primary-muted);
|
||||||
|
--input-checkbox-background-color-intermediate: var(--color-foreground-secondary);
|
||||||
|
|
||||||
--menu-background-color: var(--color-background-tertiary);
|
--menu-background-color: var(--color-background-tertiary);
|
||||||
--menu-foreground-color: var(--color-foreground-primary);
|
--menu-foreground-color: var(--color-foreground-primary);
|
||||||
|
@ -156,32 +177,12 @@
|
||||||
--menu-foreground-color-disabled: var(--color-foreground-secondary);
|
--menu-foreground-color-disabled: var(--color-foreground-secondary);
|
||||||
--menu-border-color-disabled: var(--color-background-quaternary);
|
--menu-border-color-disabled: var(--color-background-quaternary);
|
||||||
|
|
||||||
--pill-background-color: var(--color-background-tertiary);
|
|
||||||
--pill-foreground-color: var(--color-foreground-primary);
|
|
||||||
|
|
||||||
--tag-background-color: var(--color-accent-primary);
|
|
||||||
|
|
||||||
--palette-background-color: var(--color-background-primary);
|
|
||||||
--palette-btn-background-color-selected: var(--color-background-secondary);
|
|
||||||
--palette-btn-border-color-selected: var(--color-background-quaternary);
|
|
||||||
--palette-btn-foreground-color-selected: var(--color-accent-primary);
|
|
||||||
--palette-text-color: var(--color-foreground-secondary);
|
|
||||||
--palette-text-color-selected: var(--color-foreground-primary);
|
|
||||||
--palette-text-background-color: var(--color-background-tertiary);
|
|
||||||
--palette-text-background-color-hover: var(--color-background-quaternary);
|
|
||||||
--palette-button-shadow-initial: var(--color-background-primary);
|
|
||||||
--palette-button-shadow-final: transparent;
|
|
||||||
|
|
||||||
--context-menu-background-color: var(--color-background-tertiary);
|
--context-menu-background-color: var(--color-background-tertiary);
|
||||||
--context-menu-foreground-color: var(--color-foreground-secondary);
|
--context-menu-foreground-color: var(--color-foreground-secondary);
|
||||||
--context-menu-background-color-selected: var(--color-background-quaternary);
|
--context-menu-background-color-selected: var(--color-background-quaternary);
|
||||||
--context-menu-foreground-color-selected: var(--color-foreground-primary);
|
--context-menu-foreground-color-selected: var(--color-foreground-primary);
|
||||||
|
|
||||||
--color-bullet-background-color: var(--white); // We don't want this color to change with palette
|
// ASSETS
|
||||||
--color-bullet-border-color: var(--color-background-quaternary);
|
|
||||||
--color-bullet-border-color-selected: var(--color-accent-primary);
|
|
||||||
--palette-handler-background-color: var(--color-background-quaternary);
|
|
||||||
|
|
||||||
--assets-title-background-color: var(--color-background-primary);
|
--assets-title-background-color: var(--color-background-primary);
|
||||||
--assets-item-background-color: var(--color-background-tertiary);
|
--assets-item-background-color: var(--color-background-tertiary);
|
||||||
--assets-item-background-color-hover: var(--color-background-quaternary);
|
--assets-item-background-color-hover: var(--color-background-quaternary);
|
||||||
|
@ -220,19 +221,10 @@
|
||||||
--empty-message-background-color: var(--color-background-tertiary);
|
--empty-message-background-color: var(--color-background-tertiary);
|
||||||
--empty-message-foreground-color: var(--color-foreground-secondary);
|
--empty-message-foreground-color: var(--color-foreground-secondary);
|
||||||
|
|
||||||
--status-ok-background-color: var(--ok-color);
|
|
||||||
--status-warning-background-color: var(--warning-color);
|
|
||||||
--status-pending-background-color: var(--pending-color);
|
|
||||||
--status-error-background-color: var(--error-color);
|
|
||||||
--status-icon-foreground-color: var(--color-background-primary);
|
|
||||||
|
|
||||||
--user-count-background-color: var(--color-background-secondary);
|
--user-count-background-color: var(--color-background-secondary);
|
||||||
--user-count-foreground-color: var(--color-accent-primary);
|
--user-count-foreground-color: var(--color-accent-primary);
|
||||||
|
|
||||||
--modal-background-color: var(--color-background-primary);
|
// COLORPICKER
|
||||||
--modal-foreground-color: var(--color-foreground-primary);
|
|
||||||
--modal-foreground-color-secondary: var(--color-foreground-secondary);
|
|
||||||
|
|
||||||
--colorpicker-details-color: var(--color-background-quaternary);
|
--colorpicker-details-color: var(--color-background-quaternary);
|
||||||
--colorpicker-details-color-selected: var(--color-accent-primary);
|
--colorpicker-details-color-selected: var(--color-accent-primary);
|
||||||
--colorpicker-handlers-color: var(--color-foreground-primary);
|
--colorpicker-handlers-color: var(--color-foreground-primary);
|
||||||
|
@ -259,4 +251,43 @@
|
||||||
--grid-editor-line-color: var(--color-foreground-tertiary);
|
--grid-editor-line-color: var(--color-foreground-tertiary);
|
||||||
--grid-editor-plus-btn-foreground: var(--white);
|
--grid-editor-plus-btn-foreground: var(--white);
|
||||||
--grid-editor-plus-btn-background: var(--color-foreground-tertiary);
|
--grid-editor-plus-btn-background: var(--color-foreground-tertiary);
|
||||||
|
|
||||||
|
// MODALS
|
||||||
|
--modal-background-color: var(--color-background-primary);
|
||||||
|
--modal-title-foreground-color: var(--color-foreground-primary);
|
||||||
|
--modal-text-foreground-color: var(--color-foreground-secondary);
|
||||||
|
--modal-hint-border-color: var(--color-background-quaternary);
|
||||||
|
--modal-button-background-color-error: var(--error-color);
|
||||||
|
--modal-button-foreground-color-error: var(--color-foreground-primary);
|
||||||
|
--modal-link-foreground-color: var(--color-accent-primary);
|
||||||
|
--modal-border-color: var(--color-background-quaternary);
|
||||||
|
|
||||||
|
// ALERTS & STATUS
|
||||||
|
--alert-background-color-ok: var(--ok-color);
|
||||||
|
--alert-foreground-color-ok: var(--color-background-secondary);
|
||||||
|
--alert-background-color-warning: var(--warning-color);
|
||||||
|
--alert-foreground-color-warning: var(--color-foreground-primary);
|
||||||
|
--alert-background-color-error: var(--error-color);
|
||||||
|
--alert-foreground-color-error: var(--color-foreground-primary);
|
||||||
|
--alert-background-color-neutral: var(--color-background-quaternary);
|
||||||
|
--alert-foreground-color-neutral: var(--color-foreground-secondary);
|
||||||
|
--alert-foreground-color-neutral-active: var(--color-foreground-primary);
|
||||||
|
|
||||||
|
--status-ok-background-color: var(--ok-color);
|
||||||
|
--status-warning-background-color: var(--warning-color);
|
||||||
|
--status-pending-background-color: var(--pending-color);
|
||||||
|
--status-error-background-color: var(--error-color);
|
||||||
|
--status-icon-foreground-color: var(--color-background-primary);
|
||||||
|
|
||||||
|
// INTERFACE ELEMENTS
|
||||||
|
--search-bar-background-color: var(--color-background-primary);
|
||||||
|
--search-bar-input-background-color: var(--color-background-tertiary);
|
||||||
|
--search-bar-input-border-color: var(--color-background-tertiary);
|
||||||
|
|
||||||
|
--pill-background-color: var(--color-background-tertiary);
|
||||||
|
--pill-foreground-color: var(--color-foreground-primary);
|
||||||
|
|
||||||
|
--tag-background-color: var(--color-accent-primary);
|
||||||
|
|
||||||
|
--link-foreground-color: var(--color-accent-primary);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,24 +7,15 @@
|
||||||
@use "sass:math";
|
@use "sass:math";
|
||||||
@import "common/dependencies/mixin";
|
@import "common/dependencies/mixin";
|
||||||
|
|
||||||
// Font sizes
|
|
||||||
$fs10: 0.625rem;
|
|
||||||
$fs-11: 0.688rem;
|
|
||||||
$fs12: 0.75rem;
|
|
||||||
$fs14: 0.875rem;
|
|
||||||
|
|
||||||
// Typography scale
|
// Typography scale
|
||||||
$fs-base: 16;
|
$fs-base: 16;
|
||||||
|
|
||||||
$fs-9: math.div(9, $fs-base) + rem;
|
|
||||||
$fs-10: math.div(10, $fs-base) + rem;
|
$fs-10: math.div(10, $fs-base) + rem;
|
||||||
|
$fs-11: 0.688rem;
|
||||||
$fs-12: math.div(12, $fs-base) + rem;
|
$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-19: math.div(19, $fs-base) + rem;
|
$fs-24: math.div(24, $fs-base) + rem;
|
||||||
$fs-25: math.div(25, $fs-base) + rem;
|
|
||||||
$fs-33: math.div(33, $fs-base) + rem;
|
|
||||||
$fs-44: math.div(44, $fs-base) + rem;
|
|
||||||
|
|
||||||
// Font weight
|
// Font weight
|
||||||
$fw400: 400; // Regular (CSS value: 'normal')
|
$fw400: 400; // Regular (CSS value: 'normal')
|
||||||
|
|
|
@ -49,13 +49,20 @@
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin titleBigTipography {
|
@mixin medTitleTipography {
|
||||||
font-family: "worksans", sans-serif;
|
font-family: "worksans", sans-serif;
|
||||||
font-size: $fs-14;
|
font-size: $fs-14;
|
||||||
font-weight: $fw400;
|
font-weight: $fw400;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin bigTitleTipography {
|
||||||
|
font-family: "worksans", sans-serif;
|
||||||
|
font-size: $fs-24;
|
||||||
|
font-weight: $fw400;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin textEllipsis {
|
@mixin textEllipsis {
|
||||||
max-width: 99%;
|
max-width: 99%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -7,3 +7,7 @@
|
||||||
@mixin menuShadow {
|
@mixin menuShadow {
|
||||||
box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
|
box-shadow: 0px 0px $s-12 0px var(--menu-shadow-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin alertShadow {
|
||||||
|
box-shadow: 0px $s-4 $s-4 var(--menu-shadow-color);
|
||||||
|
}
|
||||||
|
|
|
@ -70,12 +70,17 @@ $s-284: calc(var(--s-4) * 71);
|
||||||
$s-300: calc(var(--s-4) * 75);
|
$s-300: calc(var(--s-4) * 75);
|
||||||
$s-320: calc(var(--s-4) * 80);
|
$s-320: calc(var(--s-4) * 80);
|
||||||
$s-348: calc(var(--s-4) * 87);
|
$s-348: calc(var(--s-4) * 87);
|
||||||
|
$s-356: calc(var(--s-4) * 89);
|
||||||
|
$s-364: calc(var(--s-4) * 91);
|
||||||
$s-380: calc(var(--s-4) * 95);
|
$s-380: calc(var(--s-4) * 95);
|
||||||
$s-400: calc(var(--s-4) * 100);
|
$s-400: calc(var(--s-4) * 100);
|
||||||
|
$s-408: calc(var(--s-4) * 102);
|
||||||
|
$s-440: calc(var(--s-4) * 110);
|
||||||
$s-480: calc(var(--s-4) * 120);
|
$s-480: calc(var(--s-4) * 120);
|
||||||
$s-500: calc(var(--s-4) * 125);
|
$s-500: calc(var(--s-4) * 125);
|
||||||
$s-512: calc(var(--s-4) * 128);
|
$s-512: calc(var(--s-4) * 128);
|
||||||
$s-520: calc(var(--s-4) * 130);
|
$s-520: calc(var(--s-4) * 130);
|
||||||
|
$s-640: calc(var(--s-4) * 160);
|
||||||
$s-664: calc(var(--s-4) * 166);
|
$s-664: calc(var(--s-4) * 166);
|
||||||
$s-712: calc(var(--s-4) * 178);
|
$s-712: calc(var(--s-4) * 178);
|
||||||
$s-736: calc(var(--s-4) * 184);
|
$s-736: calc(var(--s-4) * 184);
|
||||||
|
|
|
@ -11,3 +11,4 @@ $z-index-4: 4; // modal
|
||||||
$z-index-10: 10;
|
$z-index-10: 10;
|
||||||
$z-index-20: 20;
|
$z-index-20: 20;
|
||||||
$z-index-modal: 30; // When refactor finish we can reduce this number,
|
$z-index-modal: 30; // When refactor finish we can reduce this number,
|
||||||
|
$z-index-alert: 40; // When refactor finish we can reduce this number,
|
||||||
|
|
|
@ -315,7 +315,7 @@
|
||||||
|
|
||||||
.slider-selector.opacity {
|
.slider-selector.opacity {
|
||||||
grid-area: "opacity";
|
grid-area: "opacity";
|
||||||
align-self: start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1522,7 +1522,7 @@
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
row-gap: 1.5rem;
|
row-gap: 1.5rem;
|
||||||
.custom-input {
|
.custom-input {
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.alert
|
(ns app.main.ui.alert
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.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]]
|
||||||
|
@ -25,7 +27,8 @@
|
||||||
hint
|
hint
|
||||||
accept-label
|
accept-label
|
||||||
accept-style] :as props}]
|
accept-style] :as props}]
|
||||||
(let [on-accept (or on-accept identity)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
on-accept (or on-accept identity)
|
||||||
message (or message (tr "ds.alert-title"))
|
message (or message (tr "ds.alert-title"))
|
||||||
accept-label (or accept-label (tr "ds.alert-ok"))
|
accept-label (or accept-label (tr "ds.alert-ok"))
|
||||||
accept-style (or accept-style :danger)
|
accept-style (or accept-style :danger)
|
||||||
|
@ -47,29 +50,54 @@
|
||||||
(on-accept props)))]
|
(on-accept props)))]
|
||||||
(->> (events/listen js/document "keydown" on-keydown)
|
(->> (events/listen js/document "keydown" on-keydown)
|
||||||
(partial events/unlistenByKey))))
|
(partial events/unlistenByKey))))
|
||||||
|
(if new-css-system
|
||||||
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
|
[:div {:class (stl/css :modal-container)}
|
||||||
|
[:div {:class (stl/css :modal-header)}
|
||||||
|
[:h2 {:class (stl/css :modal-title)} title]
|
||||||
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
|
:on-click accept-fn} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-overlay
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:div.modal-container.alert-dialog
|
(when (and (string? message) (not= message ""))
|
||||||
[:div.modal-header
|
[:h3 {:class (stl/css :modal-msg)} message])
|
||||||
[:div.modal-header-title
|
(when (and (string? scd-message) (not= scd-message ""))
|
||||||
[:h2 title]]
|
[:h3 {:class (stl/css :modal-scd-msg)} scd-message])
|
||||||
[:div.modal-close-button
|
(when (string? hint)
|
||||||
{:on-click accept-fn} i/close]]
|
[:p {:class (stl/css :modal-hint)} hint])]
|
||||||
|
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-footer)}
|
||||||
(when (and (string? message) (not= message ""))
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:h3 message])
|
[:input {:class (stl/css-case :accept-btn true
|
||||||
(when (and (string? scd-message) (not= scd-message ""))
|
:danger (= accept-style :danger)
|
||||||
[:h3 scd-message])
|
:primary (= accept-style :primary))
|
||||||
(when (string? hint)
|
:type "button"
|
||||||
[:p hint])]
|
:value accept-label
|
||||||
|
:on-click accept-fn}]]]]]
|
||||||
|
|
||||||
[:div.modal-footer
|
|
||||||
[:div.action-buttons
|
[:div.modal-overlay
|
||||||
[:input.accept-button
|
[:div.modal-container.alert-dialog
|
||||||
{:class (dom/classnames
|
[:div.modal-header
|
||||||
:danger (= accept-style :danger)
|
[:div.modal-header-title
|
||||||
:primary (= accept-style :primary))
|
[:h2 title]]
|
||||||
:type "button"
|
[:div.modal-close-button
|
||||||
:value accept-label
|
{:on-click accept-fn} i/close]]
|
||||||
:on-click accept-fn}]]]]]))
|
|
||||||
|
[:div.modal-content
|
||||||
|
(when (and (string? message) (not= message ""))
|
||||||
|
[:h3 message])
|
||||||
|
(when (and (string? scd-message) (not= scd-message ""))
|
||||||
|
[:h3 scd-message])
|
||||||
|
(when (string? hint)
|
||||||
|
[:p hint])]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.accept-button
|
||||||
|
{:class (dom/classnames
|
||||||
|
:danger (= accept-style :danger)
|
||||||
|
:primary (= accept-style :primary))
|
||||||
|
:type "button"
|
||||||
|
:value accept-label
|
||||||
|
:on-click accept-fn}]]]]])))
|
||||||
|
|
51
frontend/src/app/main/ui/alert.scss
Normal file
51
frontend/src/app/main/ui/alert.scss
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
&.transparent {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg,
|
||||||
|
.modal-scd-msg,
|
||||||
|
.modal-hint,
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,11 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.components.forms
|
(ns app.main.ui.components.forms
|
||||||
|
(: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]
|
||||||
|
[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]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -24,11 +26,13 @@
|
||||||
(def use-form fm/use-form)
|
(def use-form fm/use-form)
|
||||||
|
|
||||||
(mf/defc input
|
(mf/defc input
|
||||||
[{:keys [label help-icon disabled form hint trim children data-test on-change-value] :as props}]
|
[{:keys [label help-icon disabled form hint trim children data-test on-change-value placeholder] :as props}]
|
||||||
(let [input-type (get props :type "text")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
input-type (get props :type "text")
|
||||||
input-name (get props :name)
|
input-name (get props :name)
|
||||||
more-classes (get props :class)
|
more-classes (get props :class)
|
||||||
auto-focus? (get props :auto-focus? false)
|
auto-focus? (get props :auto-focus? false)
|
||||||
|
placeholder (or placeholder label)
|
||||||
|
|
||||||
form (or form (mf/use-ctx form-ctx))
|
form (or form (mf/use-ctx form-ctx))
|
||||||
|
|
||||||
|
@ -43,6 +47,7 @@
|
||||||
|
|
||||||
touched? (get-in @form [:touched input-name])
|
touched? (get-in @form [:touched input-name])
|
||||||
error (get-in @form [:errors input-name])
|
error (get-in @form [:errors input-name])
|
||||||
|
|
||||||
value (get-in @form [:data input-name] "")
|
value (get-in @form [:data input-name] "")
|
||||||
|
|
||||||
help-icon' (cond
|
help-icon' (cond
|
||||||
|
@ -71,6 +76,13 @@
|
||||||
:input-radio is-radio?
|
:input-radio is-radio?
|
||||||
:input-checkbox is-checkbox?))
|
:input-checkbox is-checkbox?))
|
||||||
|
|
||||||
|
new-classes (dm/str more-classes " "
|
||||||
|
(stl/css-case
|
||||||
|
:input-wrapper true
|
||||||
|
:global/invalid (and touched? error)
|
||||||
|
:checkbox is-checkbox?
|
||||||
|
:global/disabled disabled))
|
||||||
|
|
||||||
swap-text-password
|
swap-text-password
|
||||||
(fn []
|
(fn []
|
||||||
(swap! type' (fn [input-type]
|
(swap! type' (fn [input-type]
|
||||||
|
@ -96,6 +108,8 @@
|
||||||
(when-not (get-in @form [:touched input-name])
|
(when-not (get-in @form [:touched input-name])
|
||||||
(swap! form assoc-in [:touched input-name] true)))
|
(swap! form assoc-in [:touched input-name] true)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
props (-> props
|
props (-> props
|
||||||
(dissoc :help-icon :form :trim :children)
|
(dissoc :help-icon :form :trim :children)
|
||||||
(assoc :id (name input-name)
|
(assoc :id (name input-name)
|
||||||
|
@ -104,7 +118,7 @@
|
||||||
:on-click (when (or is-radio? is-checkbox?) on-click)
|
:on-click (when (or is-radio? is-checkbox?) on-click)
|
||||||
:on-focus on-focus
|
:on-focus on-focus
|
||||||
:on-blur on-blur
|
:on-blur on-blur
|
||||||
:placeholder label
|
:placeholder placeholder
|
||||||
:on-change on-change
|
:on-change on-change
|
||||||
:type @type'
|
:type @type'
|
||||||
:tab-index "0")
|
:tab-index "0")
|
||||||
|
@ -113,30 +127,67 @@
|
||||||
"aria-describedby" (dm/str "error-" input-name)))
|
"aria-describedby" (dm/str "error-" input-name)))
|
||||||
(obj/clj->props))]
|
(obj/clj->props))]
|
||||||
|
|
||||||
[:div
|
(if new-css-system
|
||||||
{:class klass}
|
[:div {:class new-classes}
|
||||||
[:*
|
[:*
|
||||||
[:> :input props]
|
(cond
|
||||||
(cond
|
(some? label)
|
||||||
(some? label)
|
[:label {:class (stl/css-case :input-with-label (not is-checkbox?)
|
||||||
[:label {:for (name input-name)} label]
|
:input-label is-text?
|
||||||
|
:radio-label is-radio?
|
||||||
|
:checkbox-label is-checkbox?)
|
||||||
|
:tab-index "0"
|
||||||
|
:for (name input-name)} label
|
||||||
|
(when is-checkbox?
|
||||||
|
[:span {:class (stl/css-case :global/checked value)} i/status-tick-refactor])
|
||||||
|
[:> :input props]]
|
||||||
|
|
||||||
(some? children)
|
(some? children)
|
||||||
[:label {:for (name input-name)} children])
|
[:label {:for (name input-name)}
|
||||||
|
|
||||||
(when help-icon'
|
[:> :input props]
|
||||||
[:div.help-icon
|
children])
|
||||||
{:style {:cursor "pointer"}
|
|
||||||
:on-click (when (= "password" input-type)
|
|
||||||
swap-text-password)}
|
|
||||||
help-icon'])
|
|
||||||
(cond
|
|
||||||
(and touched? (:message error))
|
|
||||||
[:span.error {:id (dm/str "error-" input-name)
|
|
||||||
:data-test (clojure.string/join [data-test "-error"])} (tr (:message error))]
|
|
||||||
|
|
||||||
(string? hint)
|
(when help-icon'
|
||||||
[:span.hint hint])]]))
|
[:span {:class (stl/css :help-icon)
|
||||||
|
:on-click (when (= "password" input-type)
|
||||||
|
swap-text-password)}
|
||||||
|
help-icon'])
|
||||||
|
(cond
|
||||||
|
(and touched? (:message error))
|
||||||
|
[:div {:id (dm/str "error-" input-name)
|
||||||
|
:class (stl/css :error)
|
||||||
|
:data-test (clojure.string/join [data-test "-error"])}
|
||||||
|
(tr (:message error))]
|
||||||
|
|
||||||
|
(string? hint)
|
||||||
|
[:div {:class (stl/css :hint)} hint])]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div
|
||||||
|
{:class klass}
|
||||||
|
[:*
|
||||||
|
[:> :input props]
|
||||||
|
(cond
|
||||||
|
(some? label)
|
||||||
|
[:label {:for (name input-name)} label]
|
||||||
|
|
||||||
|
(some? children)
|
||||||
|
[:label {:for (name input-name)} children])
|
||||||
|
|
||||||
|
(when help-icon'
|
||||||
|
[:div.help-icon
|
||||||
|
{:style {:cursor "pointer"}
|
||||||
|
:on-click (when (= "password" input-type)
|
||||||
|
swap-text-password)}
|
||||||
|
help-icon'])
|
||||||
|
(cond
|
||||||
|
(and touched? (:message error))
|
||||||
|
[:span.error {:id (dm/str "error-" input-name)
|
||||||
|
:data-test (clojure.string/join [data-test "-error"])} (tr (:message error))]
|
||||||
|
|
||||||
|
(string? hint)
|
||||||
|
[:span.hint hint])]])))
|
||||||
|
|
||||||
(mf/defc textarea
|
(mf/defc textarea
|
||||||
[{:keys [label disabled form hint trim] :as props}]
|
[{:keys [label disabled form hint trim] :as props}]
|
||||||
|
@ -195,7 +246,8 @@
|
||||||
(mf/defc select
|
(mf/defc select
|
||||||
[{:keys [options disabled label form default data-test] :as props
|
[{:keys [options disabled label form default data-test] :as props
|
||||||
:or {default ""}}]
|
:or {default ""}}]
|
||||||
(let [input-name (get props :name)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
input-name (get props :name)
|
||||||
form (or form (mf/use-ctx form-ctx))
|
form (or form (mf/use-ctx form-ctx))
|
||||||
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)
|
||||||
|
@ -214,31 +266,57 @@
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(reset! focus? false))]
|
(reset! focus? false))]
|
||||||
|
|
||||||
[:div.custom-select
|
(if new-css-system
|
||||||
[:select {:value value
|
[:div {:class (stl/css :custom-select)}
|
||||||
:on-change on-change
|
[:select {:value value
|
||||||
:on-focus on-focus
|
:on-change on-change
|
||||||
:on-blur on-blur
|
:on-focus on-focus
|
||||||
:disabled disabled
|
:on-blur on-blur
|
||||||
:data-test data-test}
|
:disabled disabled
|
||||||
(for [item options]
|
:data-test data-test}
|
||||||
[:> :option (clj->js (cond-> {:key (:value item) :value (:value item)}
|
(for [item options]
|
||||||
(:disabled item) (assoc :disabled "disabled")
|
[:> :option (clj->js (cond-> {:key (:value item) :value (:value item)}
|
||||||
(:hidden item) (assoc :style {:display "none"})))
|
(:disabled item) (assoc :disabled "disabled")
|
||||||
(:label item)])]
|
(:hidden item) (assoc :style {:display "none"})))
|
||||||
|
(:label item)])]
|
||||||
|
|
||||||
[:div.input-container {:class (dom/classnames :disabled disabled :focus @focus?)}
|
[:div {:class (stl/css-case :input-container true
|
||||||
[:div.main-content
|
:disabled disabled
|
||||||
[:label label]
|
:focus @focus?)}
|
||||||
[:span.value (:label cvalue "")]]
|
[:div {:class (stl/css :main-content)}
|
||||||
|
[:label {:class (stl/css :label)} label]
|
||||||
|
[:span {:class (stl/css :value)} (:label cvalue "")]]
|
||||||
|
|
||||||
[:div.icon
|
[:div {:class (stl/css :icon)}
|
||||||
i/arrow-slide]]]))
|
i/arrow-refactor]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.custom-select
|
||||||
|
[:select {:value value
|
||||||
|
:on-change on-change
|
||||||
|
:on-focus on-focus
|
||||||
|
:on-blur on-blur
|
||||||
|
: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.input-container {:class (dom/classnames :disabled disabled :focus @focus?)}
|
||||||
|
[:div.main-content
|
||||||
|
[:label label]
|
||||||
|
[:span.value (:label cvalue "")]]
|
||||||
|
|
||||||
|
[:div.icon
|
||||||
|
i/arrow-slide]]])))
|
||||||
|
|
||||||
(mf/defc radio-buttons
|
(mf/defc radio-buttons
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [form (or (unchecked-get props "form")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
form (or (unchecked-get props "form")
|
||||||
(mf/use-ctx form-ctx))
|
(mf/use-ctx form-ctx))
|
||||||
name (unchecked-get props "name")
|
name (unchecked-get props "name")
|
||||||
|
|
||||||
|
@ -261,28 +339,56 @@
|
||||||
|
|
||||||
(when (fn? on-change)
|
(when (fn? on-change)
|
||||||
(on-change name value)))))]
|
(on-change name value)))))]
|
||||||
|
(if new-css-system
|
||||||
|
[:div {:class (stl/css :custom-radio)}
|
||||||
|
(for [{:keys [image value label]} options]
|
||||||
|
(let [image? (some? image)
|
||||||
|
value' (encode-fn value)
|
||||||
|
checked? (= value current-value)
|
||||||
|
key (str/ffmt "%-%" name value')]
|
||||||
|
[:label {:for key
|
||||||
|
:style {:background-image (when image? (str/ffmt "url(%)" image))}
|
||||||
|
:class (stl/css-case :radio-label true
|
||||||
|
:global/checked checked?
|
||||||
|
:with-image image?)}
|
||||||
|
[:input {:on-change on-change'
|
||||||
|
:type "radio"
|
||||||
|
:class (stl/css :radio-input)
|
||||||
|
:id key
|
||||||
|
:name name
|
||||||
|
:value value'
|
||||||
|
:checked checked?}]
|
||||||
|
(when (not image?)
|
||||||
|
[:span {:class (stl/css-case :radio-icon true
|
||||||
|
:global/checked checked?)}
|
||||||
|
(when checked? [:span {:class (stl/css :radio-dot)}])])
|
||||||
|
|
||||||
[:div.custom-radio
|
label]))]
|
||||||
(for [{:keys [image value label]} options]
|
|
||||||
(let [image? (some? image)
|
|
||||||
value' (encode-fn value)
|
|
||||||
key (str/ffmt "%-%" name value')]
|
[:div.custom-radio
|
||||||
[:div.input-radio {:key key :class (when image? "with-image")}
|
(for [{:keys [image value label]} options]
|
||||||
[:input {:on-change on-change'
|
(let [image? (some? image)
|
||||||
:type "radio"
|
value' (encode-fn value)
|
||||||
:id key
|
key (str/ffmt "%-%" name value')]
|
||||||
:name name
|
[:div.input-radio {:key key :class (when image? "with-image")}
|
||||||
:value value'
|
[:input {:on-change on-change'
|
||||||
:checked (= value current-value)}]
|
:type "radio"
|
||||||
[:label {:for key
|
:id key
|
||||||
:style {:background-image (when image? (str/ffmt "url(%)" image))}
|
:name name
|
||||||
:class (when image? "with-image")}
|
:value value'
|
||||||
label]]))]))
|
:checked (= value current-value)}]
|
||||||
|
[:label {:for key
|
||||||
|
:style {:background-image (when image? (str/ffmt "url(%)" image))}
|
||||||
|
:class (when image? "with-image")}
|
||||||
|
label]]))])))
|
||||||
|
|
||||||
(mf/defc submit-button*
|
(mf/defc submit-button*
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [form (or (unchecked-get props "form")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
form (or (unchecked-get props "form")
|
||||||
(mf/use-ctx form-ctx))
|
(mf/use-ctx form-ctx))
|
||||||
|
|
||||||
label (unchecked-get props "label")
|
label (unchecked-get props "label")
|
||||||
|
@ -296,6 +402,7 @@
|
||||||
(true? (unchecked-get props "disabled")))
|
(true? (unchecked-get props "disabled")))
|
||||||
|
|
||||||
klass (dm/str class " " (if disabled? "btn-disabled" ""))
|
klass (dm/str class " " (if disabled? "btn-disabled" ""))
|
||||||
|
new-klass (if disabled? (stl/css :btn-disabled) class)
|
||||||
|
|
||||||
on-key-down
|
on-key-down
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -310,7 +417,7 @@
|
||||||
(obj/set! "onKeyDown" on-key-down)
|
(obj/set! "onKeyDown" on-key-down)
|
||||||
(obj/set! "name" name)
|
(obj/set! "name" name)
|
||||||
(obj/set! "label" mf/undefined)
|
(obj/set! "label" mf/undefined)
|
||||||
(obj/set! "className" klass)
|
(obj/set! "className" (if new-css-system new-klass klass))
|
||||||
(obj/set! "type" "submit"))]
|
(obj/set! "type" "submit"))]
|
||||||
|
|
||||||
[:> "button" props
|
[:> "button" props
|
||||||
|
@ -338,7 +445,8 @@
|
||||||
|
|
||||||
(mf/defc multi-input
|
(mf/defc multi-input
|
||||||
[{:keys [form label class name trim valid-item-fn caution-item-fn on-submit] :as props}]
|
[{:keys [form label class name trim valid-item-fn caution-item-fn on-submit] :as props}]
|
||||||
(let [form (or form (mf/use-ctx form-ctx))
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
form (or form (mf/use-ctx form-ctx))
|
||||||
input-name (get props :name)
|
input-name (get props :name)
|
||||||
touched? (get-in @form [:touched input-name])
|
touched? (get-in @form [:touched input-name])
|
||||||
error (get-in @form [:errors input-name])
|
error (get-in @form [:errors input-name])
|
||||||
|
@ -360,10 +468,24 @@
|
||||||
:custom-multi-input true
|
:custom-multi-input true
|
||||||
:custom-input true))
|
:custom-input true))
|
||||||
|
|
||||||
|
|
||||||
|
new-css-klass (str (get props :class) " "
|
||||||
|
(stl/css-case
|
||||||
|
:focus @focus?
|
||||||
|
:valid (and touched? (not error))
|
||||||
|
:invalid (and touched? error)
|
||||||
|
:empty empty?
|
||||||
|
:custom-multi-input true))
|
||||||
|
|
||||||
in-klass (str class " "
|
in-klass (str class " "
|
||||||
(dom/classnames
|
(dom/classnames
|
||||||
:no-padding (pos? (count @items))))
|
:no-padding (pos? (count @items))))
|
||||||
|
|
||||||
|
new-css-in-klass (str class " "
|
||||||
|
(stl/css-case
|
||||||
|
:inside-input true
|
||||||
|
:no-padding (pos? (count @items))))
|
||||||
|
|
||||||
on-focus
|
on-focus
|
||||||
(mf/use-fn #(reset! focus? true))
|
(mf/use-fn #(reset! focus? true))
|
||||||
|
|
||||||
|
@ -430,29 +552,59 @@
|
||||||
values (filterv #(:valid %) values)]
|
values (filterv #(:valid %) values)]
|
||||||
(update-form! values)))
|
(update-form! values)))
|
||||||
|
|
||||||
[:div {:class klass}
|
(if new-css-system
|
||||||
[:input {:id (name input-name)
|
[:div {:class new-css-klass}
|
||||||
:class in-klass
|
[:input {:id (name input-name)
|
||||||
:type "text"
|
:class new-css-in-klass
|
||||||
:auto-focus true
|
:type "text"
|
||||||
:on-focus on-focus
|
:auto-focus true
|
||||||
:on-blur on-blur
|
:on-focus on-focus
|
||||||
:on-key-down on-key-down
|
:on-blur on-blur
|
||||||
:value @value
|
:on-key-down on-key-down
|
||||||
:on-change on-change
|
:value @value
|
||||||
:placeholder (when empty? label)}]
|
:on-change on-change
|
||||||
[:label {:for (name input-name)} label]
|
:placeholder (when empty? label)}]
|
||||||
|
[:label {:for (name input-name)} label]
|
||||||
|
|
||||||
(when-let [items (seq @items)]
|
(when-let [items (seq @items)]
|
||||||
[:div.selected-items
|
[:div {:class (stl/css :selected-items)}
|
||||||
(for [item items]
|
(for [item items]
|
||||||
[:div.selected-item {:key (:text item)
|
[:div {:class (stl/css :selected-item)
|
||||||
:tab-index "0"
|
:key (:text item)
|
||||||
:on-key-down (partial manage-key-down item)}
|
:tab-index "0"
|
||||||
[:span.around {:class (dom/classnames "invalid" (not (:valid item))
|
:on-key-down (partial manage-key-down item)}
|
||||||
"caution" (:caution item))}
|
[:span {:class (stl/css-case :around true
|
||||||
[:span.text (:text item)]
|
:invalid (not (:valid item))
|
||||||
[:span.icon {:on-click #(remove-item! item)} i/cross]]])])]))
|
:caution (:caution item))}
|
||||||
|
[:span {:class (stl/css :text)} (:text item)]
|
||||||
|
[:button {:class (stl/css :icon)
|
||||||
|
:on-click #(remove-item! item)} i/close-refactor]]])])]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div {:class klass}
|
||||||
|
[:input {:id (name input-name)
|
||||||
|
:class in-klass
|
||||||
|
:type "text"
|
||||||
|
:auto-focus true
|
||||||
|
:on-focus on-focus
|
||||||
|
:on-blur on-blur
|
||||||
|
:on-key-down on-key-down
|
||||||
|
:value @value
|
||||||
|
:on-change on-change
|
||||||
|
:placeholder (when empty? label)}]
|
||||||
|
[:label {:for (name input-name)} label]
|
||||||
|
|
||||||
|
(when-let [items (seq @items)]
|
||||||
|
[:div.selected-items
|
||||||
|
(for [item items]
|
||||||
|
[:div.selected-item {:key (:text item)
|
||||||
|
:tab-index "0"
|
||||||
|
:on-key-down (partial manage-key-down item)}
|
||||||
|
[:span.around {:class (dom/classnames "invalid" (not (:valid item))
|
||||||
|
"caution" (:caution item))}
|
||||||
|
[:span.text (:text item)]
|
||||||
|
[:span.icon {:on-click #(remove-item! item)} i/cross]]])])])))
|
||||||
|
|
||||||
;; --- Validators
|
;; --- Validators
|
||||||
|
|
||||||
|
|
336
frontend/src/app/main/ui/components/forms.scss
Normal file
336
frontend/src/app/main/ui/components/forms.scss
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
// INPUT
|
||||||
|
.input-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $s-6;
|
||||||
|
align-items: center;
|
||||||
|
.input-with-label {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-8;
|
||||||
|
@include titleTipography;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
text-transform: none;
|
||||||
|
input {
|
||||||
|
@extend .input-element;
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
width: calc(100% - $s-1);
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
// Input autofill
|
||||||
|
input:-webkit-autofill,
|
||||||
|
input:-webkit-autofill:hover,
|
||||||
|
input:-webkit-autofill:focus,
|
||||||
|
input:-webkit-autofill:active {
|
||||||
|
-webkit-text-fill-color: var(--input-foreground-color-active) !important;
|
||||||
|
-webkit-box-shadow: 0 0 0 28px var(--input-background-color) inset !important;
|
||||||
|
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) {
|
||||||
|
input {
|
||||||
|
border: $s-1 solid var(--input-border-color-error);
|
||||||
|
@extend .disabled-input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: var(--input-details-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: var(--input-border-color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
@include titleTipography;
|
||||||
|
width: 99%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
@extend .input-checkbox;
|
||||||
|
.checkbox-label {
|
||||||
|
@include titleTipography;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
gap: $s-6;
|
||||||
|
min-height: $s-32;
|
||||||
|
cursor: pointer;
|
||||||
|
span {
|
||||||
|
@extend .checkbox-icon;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
span {
|
||||||
|
border-color: var(--input-checkbox-border-color-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SELECT
|
||||||
|
.custom-select {
|
||||||
|
@extend .select-wrapper;
|
||||||
|
height: $s-32;
|
||||||
|
.input-container {
|
||||||
|
@include flexRow;
|
||||||
|
height: $s-32;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: $s-1 solid var(--input-background-color);
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
.main-content {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
position: relative;
|
||||||
|
justify-content: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
height: 100%;
|
||||||
|
padding: $s-8;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: var(--input-foreground-color);
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
border: 0px;
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-24;
|
||||||
|
pointer-events: none;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: var(--input-background-color-disabled);
|
||||||
|
border: $s-1 solid var(--input-border-color-disabled);
|
||||||
|
color: var(--input-foreground-color-disabled);
|
||||||
|
}
|
||||||
|
&.focus {
|
||||||
|
outline: none;
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
background-color: var(--input-background-color-active);
|
||||||
|
border: $s-1 solid var(--input-border-color-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
@extend .menu-dropdown;
|
||||||
|
@include titleTipography;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
min-height: $s-32;
|
||||||
|
height: auto;
|
||||||
|
width: calc(100% - 1px);
|
||||||
|
padding: 0 $s-12;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: $z-index-10;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
option {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--title-foreground-color-hover);
|
||||||
|
background-color: var(--menu-background-color);
|
||||||
|
appearance: none;
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUBMIT-BUTTON
|
||||||
|
.btn-disabled {
|
||||||
|
@extend .button-disabled;
|
||||||
|
height: $s-32;
|
||||||
|
padding: $s-8 $s-24;
|
||||||
|
border-radius: $br-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MULTI INPUT
|
||||||
|
|
||||||
|
.custom-multi-input {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
min-height: $s-40;
|
||||||
|
max-height: $s-180;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: hidden;
|
||||||
|
.inside-input {
|
||||||
|
@include removeInputStyle;
|
||||||
|
@include titleTipography;
|
||||||
|
@include textEllipsis;
|
||||||
|
width: 100%;
|
||||||
|
max-width: calc(100% - $s-1);
|
||||||
|
min-height: $s-32;
|
||||||
|
padding-top: 0;
|
||||||
|
height: $s-32;
|
||||||
|
padding: $s-8;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
border: $s-1 solid var(--input-background-color);
|
||||||
|
color: var(--input-foreground-color-active);
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border: $s-1 solid var(--input-border-color-focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.selected-items {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: $s-4;
|
||||||
|
max-height: $s-136;
|
||||||
|
padding: $s-4 0;
|
||||||
|
overflow-y: scroll;
|
||||||
|
.selected-item {
|
||||||
|
.around {
|
||||||
|
@include flexRow;
|
||||||
|
height: $s-24;
|
||||||
|
width: fit-content;
|
||||||
|
padding-left: $s-6;
|
||||||
|
border-radius: $br-6;
|
||||||
|
background-color: var(--pill-background-color);
|
||||||
|
border: $s-1 solid var(--pill-background-color);
|
||||||
|
box-sizing: border-box;
|
||||||
|
.text {
|
||||||
|
@include titleTipography;
|
||||||
|
padding-right: $s-8;
|
||||||
|
color: var(--pill-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
@include buttonStyle;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-24;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.invalid {
|
||||||
|
background-color: var(--status-error-background-color);
|
||||||
|
.text {
|
||||||
|
color: var(--alert-foreground-color-error);
|
||||||
|
}
|
||||||
|
.icon svg {
|
||||||
|
stroke: var(--alert-foreground-color-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.empty {
|
||||||
|
}
|
||||||
|
&.invalid {
|
||||||
|
}
|
||||||
|
|
||||||
|
&.focus {
|
||||||
|
}
|
||||||
|
&.valid {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RADIO BUTTONS
|
||||||
|
|
||||||
|
.custom-radio {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-label {
|
||||||
|
@include titleTipography;
|
||||||
|
@include flexRow;
|
||||||
|
min-height: $s-32;
|
||||||
|
border-radius: $br-8;
|
||||||
|
padding: $s-0 $s-2;
|
||||||
|
&:focus,
|
||||||
|
&:focus-within {
|
||||||
|
outline: none;
|
||||||
|
border: $s-1 solid var(--input-border-color-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-dot {
|
||||||
|
height: $s-8;
|
||||||
|
width: $s-8;
|
||||||
|
border-radius: $br-circle;
|
||||||
|
background-color: var(--color-background-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-input {
|
||||||
|
width: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-icon {
|
||||||
|
@extend .checkbox-icon;
|
||||||
|
border-radius: $br-circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-label.with-image {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
height: $s-120;
|
||||||
|
width: $s-140;
|
||||||
|
padding: $s-64 $s-4 0 $s-4;
|
||||||
|
margin-top: $s-16;
|
||||||
|
margin-right: 0;
|
||||||
|
border-radius: $br-8;
|
||||||
|
border: 1px solid var(--color-background-tertiary);
|
||||||
|
background-size: 50px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
&:global(.checked) {
|
||||||
|
border: 1px solid var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
&:focus,
|
||||||
|
&:focus-within {
|
||||||
|
outline: none;
|
||||||
|
border: $s-1 solid var(--input-border-color-active);
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@
|
||||||
background: var(--color-background-secondary);
|
background: var(--color-background-secondary);
|
||||||
padding: $s-2;
|
padding: $s-2;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: $fs12;
|
font-size: $fs-12;
|
||||||
.tab-container-tab-wrapper {
|
.tab-container-tab-wrapper {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.confirm
|
(ns app.main.ui.confirm
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[app.main.ui.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 t]]
|
[app.util.i18n :as i18n :refer [tr t]]
|
||||||
|
@ -29,7 +31,8 @@
|
||||||
cancel-label
|
cancel-label
|
||||||
accept-label
|
accept-label
|
||||||
accept-style] :as props}]
|
accept-style] :as props}]
|
||||||
(let [locale (mf/deref i18n/locale)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
locale (mf/deref i18n/locale)
|
||||||
|
|
||||||
on-accept (or on-accept identity)
|
on-accept (or on-accept identity)
|
||||||
on-cancel (or on-cancel identity)
|
on-cancel (or on-cancel identity)
|
||||||
|
@ -63,42 +66,88 @@
|
||||||
(->> (events/listen js/document EventType.KEYDOWN on-keydown)
|
(->> (events/listen js/document EventType.KEYDOWN on-keydown)
|
||||||
(partial events/unlistenByKey))))
|
(partial events/unlistenByKey))))
|
||||||
|
|
||||||
[:div.modal-overlay
|
|
||||||
[:div.modal-container.confirm-dialog
|
|
||||||
[:div.modal-header
|
|
||||||
[:div.modal-header-title
|
|
||||||
[:h2 title]]
|
|
||||||
[:div.modal-close-button
|
|
||||||
{:on-click cancel-fn} i/close]]
|
|
||||||
|
|
||||||
[:div.modal-content
|
(if new-css-system
|
||||||
(when (and (string? message) (not= message ""))
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:h3 message])
|
[:div {:class (stl/css :modal-container)}
|
||||||
(when (and (string? scd-message) (not= scd-message ""))
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:h3 scd-message])
|
[:h2 {:class (stl/css :modal-title)} title]
|
||||||
(when (string? hint)
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
[:p hint])
|
:on-click cancel-fn} i/close-refactor]]
|
||||||
(when (> (count items) 0)
|
|
||||||
[:*
|
|
||||||
[:p (tr "ds.component-subtitle")]
|
|
||||||
[:ul.component-list
|
|
||||||
(for [item items]
|
|
||||||
[:li.modal-item-element
|
|
||||||
[:span.modal-component-icon i/component]
|
|
||||||
[:span (:name item)]])]])]
|
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:div.action-buttons
|
(when (and (string? message) (not= message ""))
|
||||||
(when-not (= cancel-label :omit)
|
[:h3 {:class (stl/css :modal-msg)} message])
|
||||||
[:input.cancel-button
|
(when (and (string? scd-message) (not= scd-message ""))
|
||||||
{:type "button"
|
[:h3 {:class (stl/css :modal-scd-msg)} scd-message])
|
||||||
:value cancel-label
|
(when (string? hint)
|
||||||
:on-click cancel-fn}])
|
[:p {:class (stl/css :modal-hint)} hint])
|
||||||
|
(when (> (count items) 0)
|
||||||
|
[:*
|
||||||
|
[:p {:class (stl/css :modal-subtitle)}
|
||||||
|
(tr "ds.component-subtitle")]
|
||||||
|
[:ul {:class (stl/css :component-list)}
|
||||||
|
(for [item items]
|
||||||
|
[:li {:class (stl/css :modal-item-element)}
|
||||||
|
[:span {:class (stl/css :modal-component-icon)}
|
||||||
|
i/component-refactor]
|
||||||
|
[:span {:class (stl/css :modal-component-name)}
|
||||||
|
(:name item)]])]])]
|
||||||
|
|
||||||
[:input.accept-button
|
[:div {:class (stl/css :modal-footer)}
|
||||||
{:class (dom/classnames
|
[:div {:class (stl/css :action-buttons)}
|
||||||
:danger (= accept-style :danger)
|
(when-not (= cancel-label :omit)
|
||||||
:primary (= accept-style :primary))
|
[:input
|
||||||
:type "button"
|
{:class (stl/css :cancel-button)
|
||||||
:value accept-label
|
:type "button"
|
||||||
:on-click accept-fn}]]]]]))
|
:value cancel-label
|
||||||
|
:on-click cancel-fn}])
|
||||||
|
|
||||||
|
[:input
|
||||||
|
{:class (stl/css-case :accept-btn true
|
||||||
|
:danger (= accept-style :danger)
|
||||||
|
:primary (= accept-style :primary))
|
||||||
|
:type "button"
|
||||||
|
:value accept-label
|
||||||
|
:on-click accept-fn}]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.confirm-dialog
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 title]]
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click cancel-fn} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content
|
||||||
|
(when (and (string? message) (not= message ""))
|
||||||
|
[:h3 message])
|
||||||
|
(when (and (string? scd-message) (not= scd-message ""))
|
||||||
|
[:h3 scd-message])
|
||||||
|
(when (string? hint)
|
||||||
|
[:p hint])
|
||||||
|
(when (> (count items) 0)
|
||||||
|
[:*
|
||||||
|
[:p (tr "ds.component-subtitle")]
|
||||||
|
[:ul.component-list
|
||||||
|
(for [item items]
|
||||||
|
[:li.modal-item-element
|
||||||
|
[:span.modal-component-icon i/component]
|
||||||
|
[:span (:name item)]])]])]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
(when-not (= cancel-label :omit)
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value cancel-label
|
||||||
|
:on-click cancel-fn}])
|
||||||
|
|
||||||
|
[:input.accept-button
|
||||||
|
{:class (dom/classnames
|
||||||
|
:danger (= accept-style :danger)
|
||||||
|
:primary (= accept-style :primary))
|
||||||
|
:type "button"
|
||||||
|
:value accept-label
|
||||||
|
:on-click accept-fn}]]]]])))
|
||||||
|
|
70
frontend/src/app/main/ui/confirm.scss
Normal file
70
frontend/src/app/main/ui/confirm.scss
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
&.transparent {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg,
|
||||||
|
.modal-scd-msg,
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
.component-list {
|
||||||
|
.modal-item-element {
|
||||||
|
@include flexRow;
|
||||||
|
.modal-component-icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: var(--color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-component-name {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-hint {
|
||||||
|
@extend .modal-hint-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,15 +5,17 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.change-owner
|
(ns app.main.ui.dashboard.change-owner
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[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.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(s/def ::member-id ::us/uuid)
|
(s/def ::member-id ::us/uuid)
|
||||||
|
@ -24,7 +26,8 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :leave-and-reassign}
|
::mf/register-as :leave-and-reassign}
|
||||||
[{:keys [profile team accept]}]
|
[{:keys [profile team accept]}]
|
||||||
(let [form (fm/use-form :spec ::leave-modal-form :initial {})
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
form (fm/use-form :spec ::leave-modal-form :initial {})
|
||||||
members-map (mf/deref refs/dashboard-team-members)
|
members-map (mf/deref refs/dashboard-team-members)
|
||||||
members (vals members-map)
|
members (vals members-map)
|
||||||
|
|
||||||
|
@ -39,34 +42,71 @@
|
||||||
(let [member-id (get-in @form [:clean-data :member-id])]
|
(let [member-id (get-in @form [:clean-data :member-id])]
|
||||||
(accept member-id)))]
|
(accept member-id)))]
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.confirm-dialog
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:div.modal-header-title
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:h2 (tr "modals.leave-and-reassign.title")]]
|
[:h2 {:class (stl/css :modal-title)} (tr "modals.leave-and-reassign.title")]
|
||||||
[:div.modal-close-button
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
{:on-click on-cancel} i/close]]
|
:on-click on-cancel} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-content.generic-form
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:p (tr "modals.leave-and-reassign.hint1" (:name team))]
|
[:p {:class (stl/css :modal-msg)}
|
||||||
|
(tr "modals.leave-and-reassign.hint1" (:name team))]
|
||||||
|
|
||||||
(if (empty? members)
|
(if (empty? members)
|
||||||
[:p (tr "modals.leave-and-reassign.forbidden")]
|
[:p {:class (stl/css :modal-msg)}
|
||||||
[:*
|
(tr "modals.leave-and-reassign.forbidden")]
|
||||||
[:& fm/form {:form form}
|
[:*
|
||||||
[:& fm/select {:name :member-id
|
[:& fm/form {:form form}
|
||||||
:options options}]]])]
|
[:& fm/select {:name :member-id
|
||||||
|
:options options}]]])]
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:input.cancel-button
|
[:input {:class (stl/css :cancel-button)
|
||||||
{:type "button"
|
:type "button"
|
||||||
:value (tr "labels.cancel")
|
:value (tr "labels.cancel")
|
||||||
:on-click on-cancel}]
|
:on-click on-cancel}]
|
||||||
|
|
||||||
[:input.accept-button
|
[:input.accept-button
|
||||||
{:type "button"
|
{:type "button"
|
||||||
:class (if (:valid @form) "danger" "btn-disabled")
|
:class (stl/css-case :accept-btn true
|
||||||
:disabled (not (:valid @form))
|
:danger (:valid @form)
|
||||||
:value (tr "modals.leave-and-reassign.promote-and-leave")
|
:global/disabled (not (:valid @form)))
|
||||||
:on-click on-accept}]]]]]))
|
:disabled (not (:valid @form))
|
||||||
|
:value (tr "modals.leave-and-reassign.promote-and-leave")
|
||||||
|
:on-click on-accept}]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.confirm-dialog
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 (tr "modals.leave-and-reassign.title")]]
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click on-cancel} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content.generic-form
|
||||||
|
[:p (tr "modals.leave-and-reassign.hint1" (:name team))]
|
||||||
|
|
||||||
|
(if (empty? members)
|
||||||
|
[:p (tr "modals.leave-and-reassign.forbidden")]
|
||||||
|
[:*
|
||||||
|
[:& fm/form {:form form}
|
||||||
|
[:& fm/select {:name :member-id
|
||||||
|
:options options}]]])]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click on-cancel}]
|
||||||
|
|
||||||
|
[:input.accept-button
|
||||||
|
{:type "button"
|
||||||
|
:class (if (:valid @form) "danger" "btn-disabled")
|
||||||
|
:disabled (not (:valid @form))
|
||||||
|
:value (tr "modals.leave-and-reassign.promote-and-leave")
|
||||||
|
:on-click on-accept}]]]]])))
|
||||||
|
|
46
frontend/src/app/main/ui/dashboard/change_owner.scss
Normal file
46
frontend/src/app/main/ui/dashboard/change_owner.scss
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.input-wrapper {
|
||||||
|
@extend .input-with-label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,12 +5,14 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.export
|
(ns app.main.ui.dashboard.export
|
||||||
|
(: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]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.features :as features]
|
[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.main.worker :as uw]
|
[app.main.worker :as uw]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -23,18 +25,36 @@
|
||||||
(mf/defc export-entry
|
(mf/defc export-entry
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [file]}]
|
[{:keys [file]}]
|
||||||
[:div.file-entry
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
{:class (dom/classnames
|
|
||||||
:loading (:loading? file)
|
|
||||||
:success (:export-success? file)
|
|
||||||
:error (:export-error? file))}
|
|
||||||
[:div.file-name
|
|
||||||
[:div.file-icon
|
|
||||||
(cond (:export-success? file) i/tick
|
|
||||||
(:export-error? file) i/close
|
|
||||||
(:loading? file) i/loader-pencil)]
|
|
||||||
|
|
||||||
[:div.file-name-label (:name file)]]])
|
(if new-css-system
|
||||||
|
[:div {:class (stl/css-case :file-entry true
|
||||||
|
:loading (:loading? file)
|
||||||
|
:success (:export-success? file)
|
||||||
|
:error (:export-error? file))}
|
||||||
|
|
||||||
|
[:div {:class (stl/css :file-name)}
|
||||||
|
[:span {:class (stl/css :file-icon)}
|
||||||
|
(cond (:export-success? file) i/tick-refactor
|
||||||
|
(:export-error? file) i/close-refactor
|
||||||
|
(:loading? file) i/loader-pencil)]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :file-name-label)}
|
||||||
|
(:name file)]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.file-entry
|
||||||
|
{:class (dom/classnames
|
||||||
|
:loading (:loading? file)
|
||||||
|
:success (:export-success? file)
|
||||||
|
:error (:export-error? file))}
|
||||||
|
[:div.file-name
|
||||||
|
[:div.file-icon
|
||||||
|
(cond (:export-success? file) i/tick
|
||||||
|
(:export-error? file) i/close
|
||||||
|
(:loading? file) i/loader-pencil)]
|
||||||
|
|
||||||
|
[:div.file-name-label (:name file)]]])))
|
||||||
|
|
||||||
(defn- mark-file-error
|
(defn- mark-file-error
|
||||||
[files file-id]
|
[files file-id]
|
||||||
|
@ -60,7 +80,8 @@
|
||||||
::mf/register-as :export
|
::mf/register-as :export
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[{:keys [team-id files has-libraries? binary?]}]
|
[{:keys [team-id files has-libraries? binary?]}]
|
||||||
(let [components-v2 (features/use-feature "components/v2")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
components-v2 (features/use-feature :components-v2)
|
||||||
state* (mf/use-state
|
state* (mf/use-state
|
||||||
#(let [files (mapv (fn [file] (assoc file :loading? true)) files)]
|
#(let [files (mapv (fn [file] (assoc file :loading? true)) files)]
|
||||||
{:status :prepare
|
{:status :prepare
|
||||||
|
@ -120,66 +141,136 @@
|
||||||
(when-not has-libraries?
|
(when-not has-libraries?
|
||||||
(start-export)))
|
(start-export)))
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.export-dialog
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:div.modal-header-title
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:h2 (tr "dashboard.export.title")]]
|
[:h2 {:class (stl/css :modal-title)}
|
||||||
|
(tr "dashboard.export.title")]
|
||||||
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
|
:on-click on-cancel} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-close-button
|
(cond
|
||||||
{:on-click on-cancel} i/close]]
|
(= status :prepare)
|
||||||
|
[:*
|
||||||
|
[:div {:class (stl/css :modal-content)}
|
||||||
|
[:p {:class (stl/css :modal-msg)} (tr "dashboard.export.explain")]
|
||||||
|
[:p {:class (stl/css :modal-scd-msg)} (tr "dashboard.export.detail")]
|
||||||
|
|
||||||
(cond
|
(for [type export-types]
|
||||||
(= status :prepare)
|
[:div {:class (stl/css :export-option true)
|
||||||
[:*
|
:key (name type)}
|
||||||
[:div.modal-content
|
[:label {:for (str "export-" type)
|
||||||
[:p.explain (tr "dashboard.export.explain")]
|
:class (stl/css-case :global/checked (= selected type))}
|
||||||
[:p.detail (tr "dashboard.export.detail")]
|
;; Execution time translation strings:
|
||||||
|
;; dashboard.export.options.all.message
|
||||||
|
;; dashboard.export.options.all.title
|
||||||
|
;; dashboard.export.options.detach.message
|
||||||
|
;; dashboard.export.options.detach.title
|
||||||
|
;; dashboard.export.options.merge.message
|
||||||
|
;; dashboard.export.options.merge.title
|
||||||
|
[:span {:class (stl/css-case :global/checked (= selected type))}
|
||||||
|
(when (= selected type)
|
||||||
|
i/status-tick-refactor)]
|
||||||
|
[:div {:class (stl/css :option-content)}
|
||||||
|
[:h3 {:class (stl/css :modal-subtitle)} (tr (dm/str "dashboard.export.options." (d/name type) ".title"))]
|
||||||
|
[:p {:class (stl/css :modal-msg)} (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]]
|
||||||
|
|
||||||
(for [type export-types]
|
[:input {:type "radio"
|
||||||
[:div.export-option {:class (when (= selected type) "selected")
|
:class (stl/css :option-input)
|
||||||
:key (name type)}
|
:id (str "export-" type)
|
||||||
[:label.option-container
|
:checked (= selected type)
|
||||||
;; Execution time translation strings:
|
:name "export-option"
|
||||||
;; dashboard.export.options.all.message
|
:data-type (name type)
|
||||||
;; dashboard.export.options.all.title
|
:on-change on-change}]]])]
|
||||||
;; dashboard.export.options.detach.message
|
|
||||||
;; dashboard.export.options.detach.title
|
|
||||||
;; dashboard.export.options.merge.message
|
|
||||||
;; dashboard.export.options.merge.title
|
|
||||||
[:h3 (tr (dm/str "dashboard.export.options." (d/name type) ".title"))]
|
|
||||||
[:p (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]
|
|
||||||
[:input {:type "radio"
|
|
||||||
:checked (= selected type)
|
|
||||||
:data-type (name type)
|
|
||||||
:on-change on-change
|
|
||||||
:name "export-option"}]
|
|
||||||
[:span {:class "option-radio-check"}]]])]
|
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:input.cancel-button
|
[:input {:class (stl/css :cancel-button)
|
||||||
{:type "button"
|
:type "button"
|
||||||
:value (tr "labels.cancel")
|
:value (tr "labels.cancel")
|
||||||
:on-click on-cancel}]
|
:on-click on-cancel}]
|
||||||
|
|
||||||
[:input.accept-button
|
[:input {:class (stl/css :accept-btn)
|
||||||
{:class "primary"
|
:type "button"
|
||||||
:type "button"
|
:value (tr "labels.continue")
|
||||||
:value (tr "labels.continue")
|
:on-click on-accept}]]]]
|
||||||
:on-click on-accept}]]]]
|
|
||||||
|
|
||||||
(= status :exporting)
|
(= status :exporting)
|
||||||
[:*
|
[:*
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-content)}
|
||||||
(for [file (:files state)]
|
(for [file (:files state)]
|
||||||
[:& export-entry {:file file :key (dm/str (:id file))}])]
|
[:& export-entry {:file file :key (dm/str (:id file))}])]
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:input.accept-button
|
[:input {:class (stl/css :accept-btn)
|
||||||
{:class "primary"
|
:type "button"
|
||||||
:type "button"
|
:value (tr "labels.close")
|
||||||
:value (tr "labels.close")
|
:disabled (->> state :files (some :loading?))
|
||||||
:disabled (->> state :files (some :loading?))
|
:on-click on-cancel}]]]])]]
|
||||||
:on-click on-cancel}]]]])]]))
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.export-dialog
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 (tr "dashboard.export.title")]]
|
||||||
|
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click on-cancel} i/close]]
|
||||||
|
|
||||||
|
(cond
|
||||||
|
(= status :prepare)
|
||||||
|
[:*
|
||||||
|
[:div.modal-content
|
||||||
|
[:p.explain (tr "dashboard.export.explain")]
|
||||||
|
[:p.detail (tr "dashboard.export.detail")]
|
||||||
|
|
||||||
|
(for [type export-types]
|
||||||
|
[:div.export-option {:class (when (= selected type) "selected")
|
||||||
|
:key (name type)}
|
||||||
|
[:label.option-container
|
||||||
|
;; Execution time translation strings:
|
||||||
|
;; dashboard.export.options.all.message
|
||||||
|
;; dashboard.export.options.all.title
|
||||||
|
;; dashboard.export.options.detach.message
|
||||||
|
;; dashboard.export.options.detach.title
|
||||||
|
;; dashboard.export.options.merge.message
|
||||||
|
;; dashboard.export.options.merge.title
|
||||||
|
[:h3 (tr (dm/str "dashboard.export.options." (d/name type) ".title"))]
|
||||||
|
[:p (tr (dm/str "dashboard.export.options." (d/name type) ".message"))]
|
||||||
|
[:input {:type "radio"
|
||||||
|
:checked (= selected type)
|
||||||
|
:data-type (name type)
|
||||||
|
:on-change on-change
|
||||||
|
:name "export-option"}]
|
||||||
|
[:span {:class "option-radio-check"}]]])]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click on-cancel}]
|
||||||
|
|
||||||
|
[:input.accept-button
|
||||||
|
{:class "primary"
|
||||||
|
:type "button"
|
||||||
|
:value (tr "labels.continue")
|
||||||
|
:on-click on-accept}]]]]
|
||||||
|
|
||||||
|
(= status :exporting)
|
||||||
|
[:*
|
||||||
|
[:div.modal-content
|
||||||
|
(for [file (:files state)]
|
||||||
|
[:& export-entry {:file file :key (dm/str (:id file))}])]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.accept-button
|
||||||
|
{:class "primary"
|
||||||
|
:type "button"
|
||||||
|
:value (tr "labels.close")
|
||||||
|
:disabled (->> state :files (some :loading?))
|
||||||
|
:on-click on-cancel}]]]])]])))
|
||||||
|
|
115
frontend/src/app/main/ui/dashboard/export.scss
Normal file
115
frontend/src/app/main/ui/dashboard/export.scss
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg,
|
||||||
|
.modal-scd-msg,
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
.export-option {
|
||||||
|
@extend .input-checkbox;
|
||||||
|
width: 100%;
|
||||||
|
align-items: flex-start;
|
||||||
|
label {
|
||||||
|
align-items: flex-start;
|
||||||
|
.modal-subtitle {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
margin-top: $s-8;
|
||||||
|
}
|
||||||
|
.option-content {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-entry {
|
||||||
|
.file-name {
|
||||||
|
@include flexRow;
|
||||||
|
.file-icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-16;
|
||||||
|
width: $s-16;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: var(--input-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.file-name-label {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
.file-name {
|
||||||
|
color: var(--pending-color);
|
||||||
|
.file-icon svg:global(#loader-pencil) {
|
||||||
|
color: var(--pending-color);
|
||||||
|
stroke: var(--pending-color);
|
||||||
|
fill: var(--pending-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.error {
|
||||||
|
.file-name {
|
||||||
|
color: var(--error-color);
|
||||||
|
.file-icon svg {
|
||||||
|
stroke: var(--error-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
.file-name {
|
||||||
|
color: var(--ok-color);
|
||||||
|
.file-icon svg {
|
||||||
|
stroke: var(--ok-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.import
|
(ns app.main.ui.dashboard.import
|
||||||
|
(: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]
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[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.context :as ctx]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.worker :as uw]
|
[app.main.worker :as uw]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -149,7 +151,8 @@
|
||||||
(mf/defc import-entry
|
(mf/defc import-entry
|
||||||
[{:keys [state file editing? can-be-deleted?]}]
|
[{:keys [state file editing? can-be-deleted?]}]
|
||||||
|
|
||||||
(let [loading? (or (= :analyzing (:status file))
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
loading? (or (= :analyzing (:status file))
|
||||||
(= :importing (:status file)))
|
(= :importing (:status file)))
|
||||||
analyze-error? (= :analyze-error (:status file))
|
analyze-error? (= :analyze-error (:status file))
|
||||||
import-finish? (= :import-finish (:status file))
|
import-finish? (= :import-finish (:status file))
|
||||||
|
@ -187,32 +190,89 @@
|
||||||
(fn []
|
(fn []
|
||||||
(swap! state update :files remove-file (:file-id file))))]
|
(swap! state update :files remove-file (:file-id file))))]
|
||||||
|
|
||||||
[:div.file-entry
|
(if new-css-system
|
||||||
{:class (dom/classnames
|
[:div {:class (stl/css-case :file-entry true
|
||||||
:loading loading?
|
:loading loading?
|
||||||
:success (and import-finish? (not import-warn?) (not import-error?))
|
:success (and import-finish? (not import-warn?) (not import-error?))
|
||||||
:warning (and import-finish? import-warn? (not import-error?))
|
:warning (and import-finish? import-warn? (not import-error?))
|
||||||
:error (or import-error? analyze-error?)
|
:error (or import-error? analyze-error?)
|
||||||
:editable (and ready? (not editing?)))}
|
:editable (and ready? (not editing?)))}
|
||||||
|
|
||||||
[:div.file-name
|
[:div {:class (stl/css :file-name)}
|
||||||
[:div.file-icon
|
[:div {:class (stl/css-case :file-icon true
|
||||||
(cond loading? i/loader-pencil
|
:icon-fill ready?)}
|
||||||
ready? i/logo-icon
|
(cond loading? i/loader-pencil
|
||||||
import-warn? i/msg-warning
|
ready? i/logo-icon
|
||||||
import-error? i/close
|
import-warn? i/msg-warning
|
||||||
import-finish? i/tick
|
import-error? i/close-refactor
|
||||||
analyze-error? i/close)]
|
import-finish? i/tick-refactor
|
||||||
|
analyze-error? i/close-refactor)]
|
||||||
|
|
||||||
(if editing?
|
(if editing?
|
||||||
[:div.file-name-edit
|
[:div {:class (stl/css :file-name-edit)}
|
||||||
[:input {:type "text"
|
[:input {:type "text"
|
||||||
:auto-focus true
|
:auto-focus true
|
||||||
:default-value (:name file)
|
:default-value (:name file)
|
||||||
:on-key-press handle-edit-key-press
|
:on-key-press handle-edit-key-press
|
||||||
:on-blur handle-edit-blur}]]
|
:on-blur handle-edit-blur}]]
|
||||||
|
|
||||||
[:div.file-name-label (:name file) (when is-shared? i/library)])
|
[:div {:class (stl/css :file-name-label)}
|
||||||
|
(:name file)
|
||||||
|
(when is-shared? i/library-refactor)])
|
||||||
|
|
||||||
|
[:div {:class (stl/css :edit-entry-buttons)}
|
||||||
|
(when (= "application/zip" (:type file))
|
||||||
|
[:button {:on-click handle-edit-entry} i/curve-refactor])
|
||||||
|
(when can-be-deleted?
|
||||||
|
[:button {:on-click handle-remove-entry} i/delete-refactor])]]
|
||||||
|
(cond
|
||||||
|
analyze-error?
|
||||||
|
[:div {:class (stl/css :error-message)}
|
||||||
|
(tr "dashboard.import.analyze-error")]
|
||||||
|
|
||||||
|
import-error?
|
||||||
|
[:div {:class (stl/css :error-message)}
|
||||||
|
(tr "dashboard.import.import-error")]
|
||||||
|
|
||||||
|
(and (not import-finish?) (some? progress))
|
||||||
|
[:div {:class (stl/css :progress-message)} (parse-progress-message progress)])
|
||||||
|
|
||||||
|
[:div {:class (stl/css :linked-libraries)}
|
||||||
|
(for [library-id (:libraries file)]
|
||||||
|
(let [library-data (->> @state :files (d/seek #(= library-id (:file-id %))))
|
||||||
|
error? (or (:deleted? library-data) (:import-error library-data))]
|
||||||
|
(when (some? library-data)
|
||||||
|
[:div {:class (stl/css-case :linked-library-tag true
|
||||||
|
:error error?)}
|
||||||
|
i/detach-refactor (:name library-data)])))]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.file-entry
|
||||||
|
{:class (dom/classnames
|
||||||
|
:loading loading?
|
||||||
|
:success (and import-finish? (not import-warn?) (not import-error?))
|
||||||
|
:warning (and import-finish? import-warn? (not import-error?))
|
||||||
|
:error (or import-error? analyze-error?)
|
||||||
|
:editable (and ready? (not editing?)))}
|
||||||
|
|
||||||
|
[:div.file-name
|
||||||
|
[:div.file-icon
|
||||||
|
(cond loading? i/loader-pencil
|
||||||
|
ready? i/logo-icon
|
||||||
|
import-warn? i/msg-warning
|
||||||
|
import-error? i/close
|
||||||
|
import-finish? i/tick
|
||||||
|
analyze-error? i/close)]
|
||||||
|
|
||||||
|
(if editing?
|
||||||
|
[:div.file-name-edit
|
||||||
|
[:input {:type "text"
|
||||||
|
:auto-focus true
|
||||||
|
:default-value (:name file)
|
||||||
|
:on-key-press handle-edit-key-press
|
||||||
|
:on-blur handle-edit-blur}]]
|
||||||
|
|
||||||
|
[:div.file-name-label (:name file) (when is-shared? i/library)])
|
||||||
|
|
||||||
[:div.edit-entry-buttons
|
[:div.edit-entry-buttons
|
||||||
(when (= "application/zip" (:type file))
|
(when (= "application/zip" (:type file))
|
||||||
|
@ -220,31 +280,32 @@
|
||||||
(when can-be-deleted?
|
(when can-be-deleted?
|
||||||
[:button {:on-click handle-remove-entry} i/trash])]]
|
[:button {:on-click handle-remove-entry} i/trash])]]
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
analyze-error?
|
analyze-error?
|
||||||
[:div.error-message
|
[:div.error-message
|
||||||
(tr "dashboard.import.analyze-error")]
|
(tr "dashboard.import.analyze-error")]
|
||||||
|
|
||||||
import-error?
|
import-error?
|
||||||
[:div.error-message
|
[:div.error-message
|
||||||
(tr "dashboard.import.import-error")]
|
(tr "dashboard.import.import-error")]
|
||||||
|
|
||||||
(and (not import-finish?) (some? progress))
|
(and (not import-finish?) (some? progress))
|
||||||
[:div.progress-message (parse-progress-message progress)])
|
[:div.progress-message (parse-progress-message progress)])
|
||||||
|
|
||||||
[:div.linked-libraries
|
[:div.linked-libraries
|
||||||
(for [library-id (:libraries file)]
|
(for [library-id (:libraries file)]
|
||||||
(let [library-data (->> @state :files (d/seek #(= library-id (:file-id %))))
|
(let [library-data (->> @state :files (d/seek #(= library-id (:file-id %))))
|
||||||
error? (or (:deleted? library-data) (:import-error library-data))]
|
error? (or (:deleted? library-data) (:import-error library-data))]
|
||||||
(when (some? library-data)
|
(when (some? library-data)
|
||||||
[:div.linked-library-tag {:class (when error? "error")}
|
[:div.linked-library-tag {:class (when error? "error")}
|
||||||
(if error? i/unchain i/chain) (:name library-data)])))]]))
|
(if error? i/unchain i/chain) (:name library-data)])))]])))
|
||||||
|
|
||||||
(mf/defc import-dialog
|
(mf/defc import-dialog
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :import}
|
::mf/register-as :import}
|
||||||
[{:keys [project-id files template on-finish-import]}]
|
[{:keys [project-id files template on-finish-import]}]
|
||||||
(let [state (mf/use-state
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
state (mf/use-state
|
||||||
{:status :analyzing
|
{:status :analyzing
|
||||||
:editing nil
|
:editing nil
|
||||||
:importing-templates 0
|
:importing-templates 0
|
||||||
|
@ -364,61 +425,122 @@
|
||||||
#(doseq [file files]
|
#(doseq [file files]
|
||||||
(wapi/revoke-uri (:uri file)))))
|
(wapi/revoke-uri (:uri file)))))
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.import-dialog
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:div.modal-header-title
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:h2 (tr "dashboard.import")]]
|
[:h2 {:class (stl/css :modal-title)} (tr "dashboard.import")]
|
||||||
|
|
||||||
[:div.modal-close-button
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
{:on-click handle-cancel} i/close]]
|
:on-click handle-cancel} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-content)}
|
||||||
(when (and (= :importing (:status @state)) (not pending-import?))
|
|
||||||
(if (> warning-files 0)
|
|
||||||
[:div.feedback-banner.warning
|
|
||||||
[:div.icon i/msg-warning]
|
|
||||||
[:div.message (tr "dashboard.import.import-warning" warning-files success-files)]]
|
|
||||||
|
|
||||||
[:div.feedback-banner
|
(when (and (= :importing (:status @state)) (not pending-import?))
|
||||||
[:div.icon i/checkbox-checked]
|
(if (> warning-files 0)
|
||||||
[:div.message (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]]))
|
[:div {:class (stl/css-case :feedback-banner true
|
||||||
|
:warning true)}
|
||||||
|
[:div {:class (stl/css :icon)} i/msg-warning-refactor]
|
||||||
|
[:div {:class (stl/css :message)} (tr "dashboard.import.import-warning" warning-files success-files)]]
|
||||||
|
|
||||||
(for [file files]
|
[:div {:class (stl/css :feedback-banner)}
|
||||||
(let [editing? (and (some? (:file-id file))
|
[:div {:class (stl/css :icon)} i/msg-success-refactor]
|
||||||
(= (:file-id file) (:editing @state)))]
|
[:div {:class (stl/css :message)} (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]]))
|
||||||
|
|
||||||
|
(for [file files]
|
||||||
|
(let [editing? (and (some? (:file-id file))
|
||||||
|
(= (:file-id file) (:editing @state)))]
|
||||||
|
[:& import-entry {:state state
|
||||||
|
:key (dm/str (:uri file))
|
||||||
|
:file file
|
||||||
|
:editing? editing?
|
||||||
|
:can-be-deleted? (> (count files) 1)}]))
|
||||||
|
|
||||||
|
(when (some? template)
|
||||||
[:& import-entry {:state state
|
[:& import-entry {:state state
|
||||||
:key (dm/str (:uri file))
|
:file (assoc template :status (if (= 1 (:importing-templates @state)) :importing :ready))
|
||||||
:file file
|
:editing? false
|
||||||
:editing? editing?
|
:can-be-deleted? false}])]
|
||||||
:can-be-deleted? (> (count files) 1)}]))
|
|
||||||
|
|
||||||
(when (some? template)
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:& import-entry {:state state
|
[:div {:class (stl/css :action-buttons)}
|
||||||
:file (assoc template :status (if (= 1 (:importing-templates @state)) :importing :ready))
|
(when (= :analyzing (:status @state))
|
||||||
:editing? false
|
[:input {:class (stl/css :cancel-button)
|
||||||
:can-be-deleted? false}])]
|
:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click handle-cancel}])
|
||||||
|
|
||||||
[:div.modal-footer
|
(when (= :analyzing (:status @state))
|
||||||
[:div.action-buttons
|
[:input {:class (stl/css :accept-btn)
|
||||||
(when (= :analyzing (:status @state))
|
:type "button"
|
||||||
[:input.cancel-button
|
:value (tr "labels.continue")
|
||||||
{:type "button"
|
:disabled (or pending-analysis? (not valid-files?))
|
||||||
:value (tr "labels.cancel")
|
:on-click handle-continue}])
|
||||||
:on-click handle-cancel}])
|
|
||||||
|
|
||||||
(when (= :analyzing (:status @state))
|
(when (= :importing (:status @state))
|
||||||
[:input.accept-button
|
[:input {:class (stl/css :accept-btn)
|
||||||
{:class "primary"
|
:type "button"
|
||||||
:type "button"
|
:value (tr "labels.accept")
|
||||||
:value (tr "labels.continue")
|
:disabled (or pending-import? (not valid-files?))
|
||||||
:disabled (or pending-analysis? (not valid-files?))
|
:on-click handle-accept}])]]]]
|
||||||
:on-click handle-continue}])
|
|
||||||
|
|
||||||
(when (= :importing (:status @state))
|
|
||||||
[:input.accept-button
|
|
||||||
{:class "primary"
|
[:div.modal-overlay
|
||||||
:type "button"
|
[:div.modal-container.import-dialog
|
||||||
:value (tr "labels.accept")
|
[:div.modal-header
|
||||||
:disabled (or pending-import? (not valid-files?))
|
[:div.modal-header-title
|
||||||
:on-click handle-accept}])]]]]))
|
[:h2 (tr "dashboard.import")]]
|
||||||
|
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click handle-cancel} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content
|
||||||
|
(when (and (= :importing (:status @state)) (not pending-import?))
|
||||||
|
(if (> warning-files 0)
|
||||||
|
[:div.feedback-banner.warning
|
||||||
|
[:div.icon i/msg-warning]
|
||||||
|
[:div.message (tr "dashboard.import.import-warning" warning-files success-files)]]
|
||||||
|
|
||||||
|
[:div.feedback-banner
|
||||||
|
[:div.icon i/checkbox-checked]
|
||||||
|
[:div.message (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]]))
|
||||||
|
|
||||||
|
(for [file files]
|
||||||
|
(let [editing? (and (some? (:file-id file))
|
||||||
|
(= (:file-id file) (:editing @state)))]
|
||||||
|
[:& import-entry {:state state
|
||||||
|
:key (dm/str (:uri file))
|
||||||
|
:file file
|
||||||
|
:editing? editing?
|
||||||
|
:can-be-deleted? (> (count files) 1)}]))
|
||||||
|
|
||||||
|
(when (some? template)
|
||||||
|
[:& import-entry {:state state
|
||||||
|
:file (assoc template :status (if (= 1 (:importing-templates @state)) :importing :ready))
|
||||||
|
:editing? false
|
||||||
|
:can-be-deleted? false}])]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
(when (= :analyzing (:status @state))
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click handle-cancel}])
|
||||||
|
|
||||||
|
(when (= :analyzing (:status @state))
|
||||||
|
[:input.accept-button
|
||||||
|
{:class "primary"
|
||||||
|
:type "button"
|
||||||
|
:value (tr "labels.continue")
|
||||||
|
:disabled (or pending-analysis? (not valid-files?))
|
||||||
|
:on-click handle-continue}])
|
||||||
|
|
||||||
|
(when (= :importing (:status @state))
|
||||||
|
[:input.accept-button
|
||||||
|
{:class "primary"
|
||||||
|
:type "button"
|
||||||
|
:value (tr "labels.accept")
|
||||||
|
:disabled (or pending-import? (not valid-files?))
|
||||||
|
:on-click handle-accept}])]]]])))
|
||||||
|
|
197
frontend/src/app/main/ui/dashboard/import.scss
vendored
Normal file
197
frontend/src/app/main/ui/dashboard/import.scss
vendored
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg,
|
||||||
|
.modal-scd-msg,
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
.feedback-banner {
|
||||||
|
@include flexRow;
|
||||||
|
height: $s-32;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--alert-background-color-ok);
|
||||||
|
color: var(--alert-foreground-color-ok);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-24;
|
||||||
|
width: $s-24;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--alert-foreground-color-ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
background-color: var(--alert-background-color-warning);
|
||||||
|
color: var(--alert-foreground-color-warning);
|
||||||
|
.icon svg {
|
||||||
|
stroke: var(--alert-foreground-color-warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-entry {
|
||||||
|
.file-name {
|
||||||
|
@include flexRow;
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
.file-icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-24;
|
||||||
|
width: $s-16;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
&.icon-fill svg {
|
||||||
|
fill: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.file-name-edit {
|
||||||
|
@extend .input-element;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.file-name-label {
|
||||||
|
@include titleTipography;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.edit-entry-buttons {
|
||||||
|
@include flexRow;
|
||||||
|
button {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
width: $s-28;
|
||||||
|
height: $s-32;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.error-message,
|
||||||
|
.progress-message {
|
||||||
|
height: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-libraries {
|
||||||
|
.linked-library-tag {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-24;
|
||||||
|
width: $s-16;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
&.error {
|
||||||
|
svg {
|
||||||
|
stroke: var(--error-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
.file-name {
|
||||||
|
color: var(--pending-color);
|
||||||
|
.file-icon {
|
||||||
|
:global(#loader-pencil) {
|
||||||
|
color: var(--pending-color);
|
||||||
|
stroke: var(--pending-color);
|
||||||
|
fill: var(--pending-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
.file-name {
|
||||||
|
color: var(--warning-color);
|
||||||
|
.file-icon svg {
|
||||||
|
stroke: var(--warning-color);
|
||||||
|
}
|
||||||
|
.file-icon.icon-fill svg {
|
||||||
|
fill: var(--warning-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.success {
|
||||||
|
.file-name {
|
||||||
|
color: var(--ok-color);
|
||||||
|
.file-icon svg {
|
||||||
|
stroke: var(--ok-color);
|
||||||
|
}
|
||||||
|
.file-icon.icon-fill svg {
|
||||||
|
fill: var(--ok-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.error {
|
||||||
|
.file-name {
|
||||||
|
color: var(--error-color);
|
||||||
|
.file-icon svg {
|
||||||
|
stroke: var(--error-color);
|
||||||
|
}
|
||||||
|
.file-icon.icon-fill svg {
|
||||||
|
fill: var(--error-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.editable {
|
||||||
|
.file-name {
|
||||||
|
color: var(--icon-foreground);
|
||||||
|
.file-icon svg {
|
||||||
|
stroke: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
.file-icon.icon-fill svg {
|
||||||
|
fill: var(--icon-foreground);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.team
|
(ns app.main.ui.dashboard.team
|
||||||
|
(: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]
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
[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.dashboard.change-owner]
|
[app.main.ui.dashboard.change-owner]
|
||||||
[app.main.ui.dashboard.team-form]
|
[app.main.ui.dashboard.team-form]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -107,7 +109,8 @@
|
||||||
::mf/register-as :invite-members
|
::mf/register-as :invite-members
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[{:keys [team origin]}]
|
[{:keys [team origin]}]
|
||||||
(let [members-map (mf/deref refs/dashboard-team-members)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
members-map (mf/deref refs/dashboard-team-members)
|
||||||
perms (:permissions team)
|
perms (:permissions team)
|
||||||
|
|
||||||
roles (mf/use-memo (mf/deps perms) #(get-available-roles perms))
|
roles (mf/use-memo (mf/deps perms) #(get-available-roles perms))
|
||||||
|
@ -153,42 +156,81 @@
|
||||||
(with-meta {::ev/origin origin}))
|
(with-meta {::ev/origin origin}))
|
||||||
(dd/fetch-team-invitations))))]
|
(dd/fetch-team-invitations))))]
|
||||||
|
|
||||||
[:div.modal.dashboard-invite-modal.form-container
|
|
||||||
{:class (dom/classnames
|
|
||||||
:hero (= origin :hero))}
|
|
||||||
[:& fm/form {:on-submit on-submit :form form}
|
|
||||||
[:div.title
|
|
||||||
[:span.text (tr "modals.invite-team-member.title")]]
|
|
||||||
|
|
||||||
(when-not (= "" @error-text)
|
(if new-css-system
|
||||||
[:div.error
|
[:div {:class (stl/css-case :modal-team-container true
|
||||||
[:span.icon i/msg-error]
|
:hero (= origin :hero))}
|
||||||
[:span.text @error-text]])
|
[:& fm/form {:on-submit on-submit :form form}
|
||||||
|
[:div {:class (stl/css :modal-title)}
|
||||||
|
(tr "modals.invite-team-member.title")]
|
||||||
|
|
||||||
(when (some current-data-emails current-members-emails)
|
(when-not (= "" @error-text)
|
||||||
[:div.warning
|
[:div {:class (stl/css :error-msg)}
|
||||||
[:span.icon i/msg-warning]
|
[:span {:class (stl/css :icon)} i/msg-error]
|
||||||
[:span.text (tr "modals.invite-member.repeated-invitation")]])
|
[:span {:class (stl/css :message)} @error-text]])
|
||||||
|
|
||||||
[:div.form-row
|
(when (some current-data-emails current-members-emails)
|
||||||
[:p.label (tr "onboarding.choice.team-up.roles")]
|
[:div {:class (stl/css :warning-msg)}
|
||||||
[:& fm/select {:name :role :options roles}]]
|
[:span {:class (stl/css :icon)} i/msg-warning]
|
||||||
|
[:span {:class (stl/css :message)} (tr "modals.invite-member.repeated-invitation")]])
|
||||||
|
|
||||||
[:div.form-row
|
[:div {:class (stl/css :role-select)}
|
||||||
[:& fm/multi-input {:type "email"
|
[:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")]
|
||||||
:name :emails
|
[:& fm/select {:name :role :options roles}]]
|
||||||
:auto-focus? true
|
|
||||||
:trim true
|
|
||||||
:valid-item-fn us/parse-email
|
|
||||||
:caution-item-fn current-members-emails
|
|
||||||
:label (tr "modals.invite-member.emails")
|
|
||||||
:on-submit on-submit}]]
|
|
||||||
|
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :invitation-row)}
|
||||||
[:> fm/submit-button*
|
[:& fm/multi-input {:type "email"
|
||||||
{:label (tr "modals.invite-member-confirm.accept")
|
:name :emails
|
||||||
:disabled (and (boolean (some current-data-emails current-members-emails))
|
:auto-focus? true
|
||||||
(empty? (remove current-members-emails current-data-emails)))}]]]]))
|
:trim true
|
||||||
|
:valid-item-fn us/parse-email
|
||||||
|
:caution-item-fn current-members-emails
|
||||||
|
:label (tr "modals.invite-member.emails")
|
||||||
|
:on-submit on-submit}]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :action-buttons)}
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "modals.invite-member-confirm.accept")
|
||||||
|
:disabled (and (boolean (some current-data-emails current-members-emails))
|
||||||
|
(empty? (remove current-members-emails current-data-emails)))}]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal.dashboard-invite-modal.form-container
|
||||||
|
{:class (dom/classnames
|
||||||
|
:hero (= origin :hero))}
|
||||||
|
[:& fm/form {:on-submit on-submit :form form}
|
||||||
|
[:div.title
|
||||||
|
[:span.text (tr "modals.invite-team-member.title")]]
|
||||||
|
|
||||||
|
(when-not (= "" @error-text)
|
||||||
|
[:div.error
|
||||||
|
[:span.icon i/msg-error]
|
||||||
|
[:span.text @error-text]])
|
||||||
|
|
||||||
|
(when (some current-data-emails current-members-emails)
|
||||||
|
[:div.warning
|
||||||
|
[:span.icon i/msg-warning]
|
||||||
|
[:span.text (tr "modals.invite-member.repeated-invitation")]])
|
||||||
|
|
||||||
|
[:div.form-row
|
||||||
|
[:p.label (tr "onboarding.choice.team-up.roles")]
|
||||||
|
[:& fm/select {:name :role :options roles}]]
|
||||||
|
|
||||||
|
[:div.form-row
|
||||||
|
[:& fm/multi-input {:type "email"
|
||||||
|
:name :emails
|
||||||
|
:auto-focus? true
|
||||||
|
:trim true
|
||||||
|
:valid-item-fn us/parse-email
|
||||||
|
:caution-item-fn current-members-emails
|
||||||
|
:label (tr "modals.invite-member.emails")
|
||||||
|
:on-submit on-submit}]]
|
||||||
|
|
||||||
|
[:div.action-buttons
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "modals.invite-member-confirm.accept")
|
||||||
|
:disabled (and (boolean (some current-data-emails current-members-emails))
|
||||||
|
(empty? (remove current-members-emails current-data-emails)))}]]]])))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; MEMBERS SECTION
|
;; MEMBERS SECTION
|
||||||
|
@ -710,7 +752,8 @@
|
||||||
::mf/register-as :webhook}
|
::mf/register-as :webhook}
|
||||||
[{:keys [webhook] :as props}]
|
[{:keys [webhook] :as props}]
|
||||||
;; FIXME: this is a workaround because input fields do not support rendering hooks
|
;; FIXME: this is a workaround because input fields do not support rendering hooks
|
||||||
(let [initial (mf/use-memo (fn [] (or (some-> webhook (update :uri str))
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
initial (mf/use-memo (fn [] (or (some-> webhook (update :uri str))
|
||||||
{:is-active false :mtype "application/json"})))
|
{:is-active false :mtype "application/json"})))
|
||||||
form (fm/use-form :spec ::webhook-form
|
form (fm/use-form :spec ::webhook-form
|
||||||
:initial initial
|
:initial initial
|
||||||
|
@ -771,54 +814,100 @@
|
||||||
(let [data (:clean-data @form)]
|
(let [data (:clean-data @form)]
|
||||||
(if (:id data)
|
(if (:id data)
|
||||||
(on-update-submit form)
|
(on-update-submit form)
|
||||||
(on-create-submit form)))))]
|
(on-create-submit form)))))
|
||||||
|
|
||||||
[:div.modal-overlay
|
on-modal-close #(st/emit! (modal/hide))]
|
||||||
[:div.modal-container.webhooks-modal
|
(if new-css-system
|
||||||
[:& fm/form {:form form :on-submit on-submit}
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
|
[:div {:class (stl/css :modal-container)}
|
||||||
|
[:& fm/form {:form form :on-submit on-submit}
|
||||||
|
[:div {:class (stl/css :modal-header)}
|
||||||
|
(if webhook
|
||||||
|
[:h2 {:class (stl/css :modal-title)} (tr "modals.edit-webhook.title")]
|
||||||
|
[:h2 {:class (stl/css :modal-title)} (tr "modals.create-webhook.title")])
|
||||||
|
|
||||||
[:div.modal-header
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
[:div.modal-header-title
|
:on-click on-modal-close} i/close-refactor]]
|
||||||
(if webhook
|
|
||||||
[:h2 (tr "modals.edit-webhook.title")]
|
|
||||||
[:h2 (tr "modals.create-webhook.title")])]
|
|
||||||
|
|
||||||
[:div.modal-close-button
|
[:div {:class (stl/css :modal-content)}
|
||||||
{:on-click #(st/emit! (modal/hide))} i/close]]
|
[:div {:class (stl/css :fields-row)}
|
||||||
|
[:& fm/input {:type "text"
|
||||||
[:div.modal-content.generic-form
|
:auto-focus? true
|
||||||
[:div.fields-container
|
:form form
|
||||||
[:div.fields-row
|
:name :uri
|
||||||
[:& fm/input {:type "text"
|
:label (tr "modals.create-webhook.url.label")
|
||||||
:auto-focus? true
|
:placeholder (tr "modals.create-webhook.url.placeholder")}]]
|
||||||
:form form
|
[:div {:class (stl/css :fields-row)}
|
||||||
:name :uri
|
[:div {:class (stl/css :select-title)} (tr "dashboard.webhooks.content-type")]
|
||||||
:label (tr "modals.create-webhook.url.label")
|
|
||||||
:placeholder (tr "modals.create-webhook.url.placeholder")}]]
|
|
||||||
|
|
||||||
[:div.fields-row
|
|
||||||
[:& fm/select {:options valid-webhook-mtypes
|
[:& fm/select {:options valid-webhook-mtypes
|
||||||
:label (tr "dashboard.webhooks.content-type")
|
|
||||||
:default "application/json"
|
:default "application/json"
|
||||||
:name :mtype}]]]
|
:name :mtype}]]
|
||||||
[:div.fields-row
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:div.input-checkbox.check-primary
|
[:& fm/input {:type "checkbox"
|
||||||
[:& fm/input {:type "checkbox"
|
:class (stl/css :custom-input-checkbox)
|
||||||
:form form
|
:form form
|
||||||
:name :is-active
|
:name :is-active
|
||||||
:label (tr "dashboard.webhooks.active")}]]
|
:label (tr "dashboard.webhooks.active")}]
|
||||||
[:div.explain (tr "dashboard.webhooks.active.explain")]]]
|
[:div {:class (stl/css :hint)} (tr "dashboard.webhooks.active.explain")]]]
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:input.cancel-button
|
[:input {:class (stl/css :cancel-button)
|
||||||
{:type "button"
|
:type "button"
|
||||||
:value (tr "labels.cancel")
|
:value (tr "labels.cancel")
|
||||||
:on-click #(modal/hide!)}]
|
:on-click #(modal/hide!)}]
|
||||||
[:> fm/submit-button*
|
[:> fm/submit-button*
|
||||||
{:label (if webhook
|
{:label (if webhook
|
||||||
(tr "modals.edit-webhook.submit-label")
|
(tr "modals.edit-webhook.submit-label")
|
||||||
(tr "modals.create-webhook.submit-label"))}]]]]]]))
|
(tr "modals.create-webhook.submit-label"))}]]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.webhooks-modal
|
||||||
|
[:& fm/form {:form form :on-submit on-submit}
|
||||||
|
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
(if webhook
|
||||||
|
[:h2 (tr "modals.edit-webhook.title")]
|
||||||
|
[:h2 (tr "modals.create-webhook.title")])]
|
||||||
|
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click #(st/emit! (modal/hide))} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content.generic-form
|
||||||
|
[:div.fields-container
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input {:type "text"
|
||||||
|
:auto-focus? true
|
||||||
|
:form form
|
||||||
|
:name :uri
|
||||||
|
:label (tr "modals.create-webhook.url.label")
|
||||||
|
:placeholder (tr "modals.create-webhook.url.placeholder")}]]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/select {:options valid-webhook-mtypes
|
||||||
|
:label (tr "dashboard.webhooks.content-type")
|
||||||
|
:default "application/json"
|
||||||
|
:name :mtype}]]]
|
||||||
|
[:div.fields-row
|
||||||
|
[:div.input-checkbox.check-primary
|
||||||
|
[:& fm/input {:type "checkbox"
|
||||||
|
:form form
|
||||||
|
:name :is-active
|
||||||
|
:label (tr "dashboard.webhooks.active")}]]
|
||||||
|
[:div.explain (tr "dashboard.webhooks.active.explain")]]]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click #(modal/hide!)}]
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (if webhook
|
||||||
|
(tr "modals.edit-webhook.submit-label")
|
||||||
|
(tr "modals.create-webhook.submit-label"))}]]]]]])))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc webhooks-hero
|
(mf/defc webhooks-hero
|
||||||
|
|
142
frontend/src/app/main/ui/dashboard/team.scss
Normal file
142
frontend/src/app/main/ui/dashboard/team.scss
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-team-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
@include menuShadow;
|
||||||
|
position: fixed;
|
||||||
|
top: $s-72;
|
||||||
|
right: $s-12;
|
||||||
|
left: unset;
|
||||||
|
width: $s-400;
|
||||||
|
padding: $s-32;
|
||||||
|
background-color: var(--modal-background-color);
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
&.hero {
|
||||||
|
top: $s-216;
|
||||||
|
right: $s-32;
|
||||||
|
}
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
height: $s-32;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.error-msg {
|
||||||
|
@include flexRow;
|
||||||
|
height: $s-32;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--alert-background-color-error);
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-24;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--alert-foreground-color-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--alert-foreground-color-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning-msg {
|
||||||
|
@include flexRow;
|
||||||
|
height: $s-32;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--alert-background-color-warning);
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
width: $s-16;
|
||||||
|
height: $s-24;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--alert-foreground-color-warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--alert-foreground-color-warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-select {
|
||||||
|
@include flexColumn;
|
||||||
|
.role-title {
|
||||||
|
@include titleTipography;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.invitation-row {
|
||||||
|
margin-top: $s-8;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&:disabled {
|
||||||
|
@extend .button-disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WEBHOOKS
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-24;
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
|
||||||
|
.fields-row {
|
||||||
|
@include flexColumn;
|
||||||
|
.select-title {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.custom-input-checkbox {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.dashboard.team-form
|
(ns app.main.ui.dashboard.team-form
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.main.data.dashboard :as dd]
|
[app.main.data.dashboard :as dd]
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
|
[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]]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
|
@ -68,36 +70,73 @@
|
||||||
(mf/defc team-form-modal {::mf/register modal/components
|
(mf/defc team-form-modal {::mf/register modal/components
|
||||||
::mf/register-as :team-form}
|
::mf/register-as :team-form}
|
||||||
[{:keys [team] :as props}]
|
[{:keys [team] :as props}]
|
||||||
(let [initial (mf/use-memo (fn [] (or team {})))
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
initial (mf/use-memo (fn [] (or team {})))
|
||||||
form (fm/use-form :spec ::team-form
|
form (fm/use-form :spec ::team-form
|
||||||
:validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
|
:validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
|
||||||
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))]
|
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))]
|
||||||
:initial initial)]
|
:initial initial)
|
||||||
[:div.modal-overlay
|
on-close #(st/emit! (modal/hide))]
|
||||||
[:div.modal-container.team-form-modal
|
|
||||||
[:& fm/form {:form form :on-submit on-submit}
|
|
||||||
|
|
||||||
[:div.modal-header
|
(if new-css-system
|
||||||
[:div.modal-header-title
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
(if team
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:h2 (tr "labels.rename-team")]
|
[:& fm/form {:form form :on-submit on-submit}
|
||||||
[:h2 (tr "labels.create-team")])]
|
|
||||||
|
|
||||||
[:div.modal-close-button
|
[:div {:class (stl/css :modal-header)}
|
||||||
{:on-click #(st/emit! (modal/hide))} i/close]]
|
(if team
|
||||||
|
[:h2 {:class (stl/css :modal-title)}
|
||||||
|
(tr "labels.rename-team")]
|
||||||
|
[:h2 {:class (stl/css :modal-title)}
|
||||||
|
(tr "labels.create-team")])
|
||||||
|
|
||||||
[:div.modal-content.generic-form
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
[:& fm/input {:type "text"
|
:on-click on-close} i/close-refactor]]
|
||||||
:auto-focus? true
|
|
||||||
:form form
|
|
||||||
:name :name
|
|
||||||
:label (tr "labels.create-team.placeholder")}]]
|
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:div.action-buttons
|
[:& fm/input {:type "text"
|
||||||
[:> fm/submit-button*
|
:auto-focus? true
|
||||||
{:label (if team
|
:class (stl/css :group-name-input)
|
||||||
(tr "labels.update-team")
|
:form form
|
||||||
(tr "labels.create-team"))}]]]]]]))
|
:name :name
|
||||||
|
:placeholder "E.g. Design"
|
||||||
|
:label (tr "labels.create-team.placeholder")}]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:div {:class (stl/css :action-buttons)}
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (if team
|
||||||
|
(tr "labels.update-team")
|
||||||
|
(tr "labels.create-team"))
|
||||||
|
:className (stl/css :accept-btn)}]]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.team-form-modal
|
||||||
|
[:& fm/form {:form form :on-submit on-submit}
|
||||||
|
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
(if team
|
||||||
|
[:h2 (tr "labels.rename-team")]
|
||||||
|
[:h2 (tr "labels.create-team")])]
|
||||||
|
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click #(st/emit! (modal/hide))} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content.generic-form
|
||||||
|
[:& fm/input {:type "text"
|
||||||
|
:auto-focus? true
|
||||||
|
:form form
|
||||||
|
:name :name
|
||||||
|
:label (tr "labels.create-team.placeholder")}]]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (if team
|
||||||
|
(tr "labels.update-team")
|
||||||
|
(tr "labels.create-team"))}]]]]]])))
|
||||||
|
|
||||||
|
|
||||||
|
|
65
frontend/src/app/main/ui/dashboard/team_form.scss
Normal file
65
frontend/src/app/main/ui/dashboard/team_form.scss
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-name-input {
|
||||||
|
@extend .input-element-label;
|
||||||
|
label {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
input {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-top: $s-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
|
@ -91,7 +91,7 @@
|
||||||
border-radius: $s-8;
|
border-radius: $s-8;
|
||||||
h3 {
|
h3 {
|
||||||
@include titleTipography;
|
@include titleTipography;
|
||||||
font-size: $fs-25;
|
font-size: $fs-24;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.component {
|
.component {
|
||||||
|
|
|
@ -5,11 +5,13 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.delete-shared
|
(ns app.main.ui.delete-shared
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
[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]]
|
||||||
|
@ -25,7 +27,8 @@
|
||||||
::mf/register-as :delete-shared-libraries
|
::mf/register-as :delete-shared-libraries
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[{:keys [ids on-accept on-cancel accept-style origin count-libraries]}]
|
[{:keys [ids on-accept on-cancel accept-style origin count-libraries]}]
|
||||||
(let [references* (mf/use-state {})
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
references* (mf/use-state {})
|
||||||
references (deref references*)
|
references (deref references*)
|
||||||
|
|
||||||
on-accept (or on-accept noop)
|
on-accept (or on-accept noop)
|
||||||
|
@ -93,45 +96,91 @@
|
||||||
(let [key (events/listen js/document "keydown" on-keydown)]
|
(let [key (events/listen js/document "keydown" on-keydown)]
|
||||||
(partial events/unlistenByKey key))))
|
(partial events/unlistenByKey key))))
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.confirm-dialog
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:div.modal-header-title
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:h2 title]]
|
[:h2 {:class (stl/css :modal-title)} title]
|
||||||
[:div.modal-close-button
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
{:on-click cancel-fn} i/close]]
|
:on-click cancel-fn} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-content.delete-shared
|
[:div {:class (stl/css :modal-content)}
|
||||||
(when (and (string? subtitle) (not= subtitle ""))
|
(when (and (string? subtitle) (not= subtitle ""))
|
||||||
[:h3 subtitle])
|
[:h3 {:class (stl/css :modal-subtitle)} subtitle])
|
||||||
(when (not= 0 count-libraries)
|
(when (not= 0 count-libraries)
|
||||||
(if (pos? (count references))
|
(if (pos? (count references))
|
||||||
[:*
|
[:*
|
||||||
[:div
|
[:div
|
||||||
(when (and (string? scd-msg) (not= scd-msg ""))
|
(when (and (string? scd-msg) (not= scd-msg ""))
|
||||||
[:h3 scd-msg])
|
[:h3 {:class (stl/css :modal-scd-msg)} scd-msg])
|
||||||
[:ul.file-list
|
[:ul {:class (stl/css :element-list)}
|
||||||
(for [[file-id file-name] references]
|
(for [[file-id file-name] references]
|
||||||
[:li.modal-item-element
|
[:li {:class (stl/css :list-item)
|
||||||
{:key (dm/str file-id)}
|
:key (dm/str file-id)}
|
||||||
[:span "- " file-name]])]]
|
[:span "- " file-name]])]]
|
||||||
(when (and (string? hint) (not= hint ""))
|
(when (and (string? hint) (not= hint ""))
|
||||||
[:h3 hint])]
|
[:h3 {:class (stl/css :modal-hint)}hint])]
|
||||||
[:*
|
[:*
|
||||||
[:h3 no-files-msg]]))]
|
[:h3 {:class (stl/css :modal-msg)} no-files-msg]]))]
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
(when-not (= cancel-label :omit)
|
(when-not (= cancel-label :omit)
|
||||||
[:input.cancel-button
|
[:input {:class (stl/css :cancel-button)
|
||||||
{:type "button"
|
:type "button"
|
||||||
:value cancel-label
|
:value cancel-label
|
||||||
:on-click cancel-fn}])
|
:on-click cancel-fn}])
|
||||||
|
|
||||||
[:input.accept-button
|
[:input {:class (stl/css-case :accept-btn true
|
||||||
{:class (dom/classnames
|
:danger (= accept-style :danger)
|
||||||
:danger (= accept-style :danger)
|
:primary (= accept-style :primary))
|
||||||
:primary (= accept-style :primary))
|
:type "button"
|
||||||
:type "button"
|
:value accept-label
|
||||||
:value accept-label
|
:on-click accept-fn}]]]]]
|
||||||
:on-click accept-fn}]]]]]))
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.confirm-dialog
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 title]]
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click cancel-fn} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content.delete-shared
|
||||||
|
(when (and (string? subtitle) (not= subtitle ""))
|
||||||
|
[:h3 subtitle])
|
||||||
|
(when (not= 0 count-libraries)
|
||||||
|
(if (pos? (count references))
|
||||||
|
[:*
|
||||||
|
[:div
|
||||||
|
(when (and (string? scd-msg) (not= scd-msg ""))
|
||||||
|
[:h3 scd-msg])
|
||||||
|
[:ul.file-list
|
||||||
|
(for [[file-id file-name] references]
|
||||||
|
[:li.modal-item-element
|
||||||
|
{:key (dm/str file-id)}
|
||||||
|
[:span "- " file-name]])]]
|
||||||
|
(when (and (string? hint) (not= hint ""))
|
||||||
|
[:h3 hint])]
|
||||||
|
[:*
|
||||||
|
[:h3 no-files-msg]]))]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
(when-not (= cancel-label :omit)
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value cancel-label
|
||||||
|
:on-click cancel-fn}])
|
||||||
|
|
||||||
|
[:input.accept-button
|
||||||
|
{:class (dom/classnames
|
||||||
|
:danger (= accept-style :danger)
|
||||||
|
:primary (= accept-style :primary))
|
||||||
|
:type "button"
|
||||||
|
:value accept-label
|
||||||
|
:on-click accept-fn}]]]]]
|
||||||
|
)
|
||||||
|
|
||||||
|
))
|
||||||
|
|
59
frontend/src/app/main/ui/delete_shared.scss
Normal file
59
frontend/src/app/main/ui/delete_shared.scss
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
&.transparent {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg,
|
||||||
|
.modal-scd-msg,
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
.modal-hint {
|
||||||
|
@extend .modal-hint-base;
|
||||||
|
}
|
||||||
|
.element-list {
|
||||||
|
@include titleTipography;
|
||||||
|
.list-item {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,8 @@
|
||||||
|
|
||||||
(mf/defc export-multiple-dialog
|
(mf/defc export-multiple-dialog
|
||||||
[{:keys [exports title cmd no-selection]}]
|
[{:keys [exports title cmd no-selection]}]
|
||||||
(let [lstate (mf/deref refs/export)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
lstate (mf/deref refs/export)
|
||||||
in-progress? (:in-progress lstate)
|
in-progress? (:in-progress lstate)
|
||||||
|
|
||||||
exports (mf/use-state exports)
|
exports (mf/use-state exports)
|
||||||
|
@ -61,91 +62,198 @@
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(swap! exports (fn [exports]
|
(swap! exports (fn [exports]
|
||||||
(mapv #(assoc % :enabled (not all-checked?)) exports))))]
|
(mapv #(assoc % :enabled (not all-checked?)) exports))))]
|
||||||
[:div.modal-overlay
|
|
||||||
[:div.modal-container.export-multiple-dialog
|
|
||||||
{:class (when (empty? all-exports) "empty")}
|
|
||||||
|
|
||||||
[:div.modal-header
|
(if new-css-system
|
||||||
[:div.modal-header-title
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:h2 title]]
|
[:div.modal-container.export-multiple-dialog
|
||||||
|
{:class (stl/css-case :modal-container true
|
||||||
|
:empty (empty? all-exports))}
|
||||||
|
|
||||||
[:div.modal-close-button
|
[:div {:class (stl/css :modal-header)}
|
||||||
{:on-click cancel-fn} i/close]]
|
[:h2 {:class (stl/css :modal-title)} title]
|
||||||
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
|
:on-click cancel-fn}
|
||||||
|
i/close-refactor]]
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-content)}
|
||||||
(if (> (count all-exports) 0)
|
(if (> (count all-exports) 0)
|
||||||
[:*
|
[:*
|
||||||
[:div.header
|
[:div {:class (stl/css :selection-header)}
|
||||||
[:div.field.check {:on-click change-all}
|
[:button {:class (stl/css :selection-btn)
|
||||||
(cond
|
:on-click change-all}
|
||||||
all-checked? [:span.checked i/checkbox-checked]
|
[:span {:class (stl/css :checkbox-wrapper)}
|
||||||
all-unchecked? [:span.unchecked i/checkbox-unchecked]
|
(cond
|
||||||
:else [:span.intermediate i/checkbox-intermediate])]
|
all-checked? [:span {:class (stl/css-case :checkbox-icon2 true
|
||||||
[:div.field.title (tr "dashboard.export-multiple.selected"
|
:global/checked true)} i/tick-refactor]
|
||||||
(c (count enabled-exports))
|
all-unchecked? [:span {:class (stl/css-case :checkbox-icon2 true
|
||||||
(c (count all-exports)))]]
|
:global/uncheked true)}]
|
||||||
|
:else [:span {:class (stl/css-case :checkbox-icon2 true
|
||||||
|
:global/intermediate true)} i/remove-refactor])]]
|
||||||
|
[:div {:class (stl/css :selection-title)} (tr "dashboard.export-multiple.selected"
|
||||||
|
(c (count enabled-exports))
|
||||||
|
(c (count all-exports)))]]
|
||||||
|
[:div {:class (stl/css :selection-wrapper)}
|
||||||
|
[:div {:class (stl/css-case :selection-list true
|
||||||
|
:selection-shadow (> (count all-exports) 8))}
|
||||||
|
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||||
|
(let [{:keys [x y width height]} (:selrect shape)]
|
||||||
|
[:div {:class (stl/css :selection-row)}
|
||||||
|
[:button {:class (stl/css :selection-btn)
|
||||||
|
:on-click #(on-toggle-enabled index)}
|
||||||
|
[:span {:class (stl/css :checkbox-wrapper)}
|
||||||
|
(if (:enabled export)
|
||||||
|
[:span {:class (stl/css-case :checkbox-icon2 true
|
||||||
|
:global/checked true)} i/tick-refactor]
|
||||||
|
[:span {:class (stl/css-case :checkbox-icon2 true
|
||||||
|
:global/uncheked true)}])]
|
||||||
|
|
||||||
[:div.body
|
[:div {:class (stl/css :image-wrapper)}
|
||||||
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
(if (some? (:thumbnail shape))
|
||||||
(let [{:keys [x y width height]} (:selrect shape)]
|
[:img {:src (:thumbnail shape)}]
|
||||||
[:div.row
|
[:svg {:view-box (dm/str x " " y " " width " " height)
|
||||||
[:div.field.check {:on-click #(on-toggle-enabled index)}
|
:width 24
|
||||||
(if (:enabled export)
|
:height 20
|
||||||
[:span.checked i/checkbox-checked]
|
:version "1.1"
|
||||||
[:span.unchecked i/checkbox-unchecked])]
|
:xmlns "http://www.w3.org/2000/svg"
|
||||||
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
|
;; Fix Chromium bug about color of html texts
|
||||||
|
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
|
||||||
|
:style {:-webkit-print-color-adjust :exact}
|
||||||
|
:fill "none"}
|
||||||
|
|
||||||
[:div.field.image
|
[:& shape-wrapper {:shape shape}]])]
|
||||||
(if (some? (:thumbnail shape))
|
|
||||||
[:img {:src (:thumbnail shape)}]
|
|
||||||
[:svg {:view-box (dm/str x " " y " " width " " height)
|
|
||||||
:width 24
|
|
||||||
:height 20
|
|
||||||
:version "1.1"
|
|
||||||
:xmlns "http://www.w3.org/2000/svg"
|
|
||||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
|
||||||
;; Fix Chromium bug about color of html texts
|
|
||||||
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
|
|
||||||
:style {:-webkit-print-color-adjust :exact}
|
|
||||||
:fill "none"}
|
|
||||||
|
|
||||||
[:& shape-wrapper {:shape shape}]])]
|
[:div {:class (stl/css :selection-name)} (cond-> (:name shape) suffix (str suffix))]
|
||||||
|
(when (:scale export)
|
||||||
|
[:div {:class (stl/css :selection-scale)}
|
||||||
|
(dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
||||||
|
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
||||||
|
|
||||||
[:div.field.name (cond-> (:name shape) suffix (str suffix))]
|
(when (:type export)
|
||||||
(when (:scale export)
|
[:div {:class (stl/css :selection-extension)}
|
||||||
[:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
(-> export :type d/name str/upper)])]]))]]]
|
||||||
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
|
||||||
|
|
||||||
(when (:type export)
|
[:& no-selection])]
|
||||||
[:div.field.extension (-> export :type d/name str/upper)])]))]
|
|
||||||
|
|
||||||
[:div.modal-footer
|
(when (> (count all-exports) 0)
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:input.cancel-button
|
[:div {:class (stl/css :action-buttons)}
|
||||||
{:type "button"
|
[:input
|
||||||
|
{:class (stl/css :cancel-button)
|
||||||
|
:type "button"
|
||||||
:value (tr "labels.cancel")
|
:value (tr "labels.cancel")
|
||||||
:on-click cancel-fn}]
|
:on-click cancel-fn}]
|
||||||
|
|
||||||
[:input.accept-button.primary
|
[:input {:class (stl/css-case :accept-btn true
|
||||||
{:class (dom/classnames
|
:btn-disabled (or in-progress? all-unchecked?))
|
||||||
:btn-disabled (or in-progress? all-unchecked?))
|
:disabled (or in-progress? all-unchecked?)
|
||||||
:disabled (or in-progress? all-unchecked?)
|
:type "button"
|
||||||
:type "button"
|
:value (if in-progress?
|
||||||
:value (if in-progress?
|
(tr "workspace.options.exporting-object")
|
||||||
(tr "workspace.options.exporting-object")
|
(tr "labels.export"))
|
||||||
(tr "labels.export"))
|
:on-click (when-not in-progress? accept-fn)}]]])]]]
|
||||||
:on-click (when-not in-progress? accept-fn)}]]]]
|
|
||||||
|
|
||||||
[:& no-selection])]]]]))
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.export-multiple-dialog
|
||||||
|
{:class (when (empty? all-exports) "empty")}
|
||||||
|
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 title]]
|
||||||
|
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click cancel-fn} i/close]]
|
||||||
|
|
||||||
|
[:*
|
||||||
|
[:div.modal-content
|
||||||
|
(if (> (count all-exports) 0)
|
||||||
|
[:*
|
||||||
|
|
||||||
|
|
||||||
|
[:div.header
|
||||||
|
[:div.field.check {:on-click change-all}
|
||||||
|
(cond
|
||||||
|
all-checked? [:span.checked i/checkbox-checked]
|
||||||
|
all-unchecked? [:span.unchecked i/checkbox-unchecked]
|
||||||
|
:else [:span.intermediate i/checkbox-intermediate])]
|
||||||
|
[:div.field.title (tr "dashboard.export-multiple.selected"
|
||||||
|
(c (count enabled-exports))
|
||||||
|
(c (count all-exports)))]]
|
||||||
|
|
||||||
|
[:div.body
|
||||||
|
(for [[index {:keys [shape suffix] :as export}] (d/enumerate @exports)]
|
||||||
|
(let [{:keys [x y width height]} (:selrect shape)]
|
||||||
|
[:div.row
|
||||||
|
[:div.field.check {:on-click #(on-toggle-enabled index)}
|
||||||
|
(if (:enabled export)
|
||||||
|
[:span.checked i/checkbox-checked]
|
||||||
|
[:span.unchecked i/checkbox-unchecked])]
|
||||||
|
|
||||||
|
[:div.field.image
|
||||||
|
(if (some? (:thumbnail shape))
|
||||||
|
[:img {:src (:thumbnail shape)}]
|
||||||
|
[:svg {:view-box (dm/str x " " y " " width " " height)
|
||||||
|
:width 24
|
||||||
|
:height 20
|
||||||
|
:version "1.1"
|
||||||
|
:xmlns "http://www.w3.org/2000/svg"
|
||||||
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
|
;; Fix Chromium bug about color of html texts
|
||||||
|
;; https://bugs.chromium.org/p/chromium/issues/detail?id=1244560#c5
|
||||||
|
:style {:-webkit-print-color-adjust :exact}
|
||||||
|
:fill "none"}
|
||||||
|
|
||||||
|
[:& shape-wrapper {:shape shape}]])]
|
||||||
|
|
||||||
|
[:div.field.name (cond-> (:name shape) suffix (str suffix))]
|
||||||
|
(when (:scale export)
|
||||||
|
[:div.field.scale (dm/str (ust/format-precision (* width (:scale export)) 2) "x"
|
||||||
|
(ust/format-precision (* height (:scale export)) 2) "px ")])
|
||||||
|
|
||||||
|
(when (:type export)
|
||||||
|
[:div.field.extension (-> export :type d/name str/upper)])]))]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click cancel-fn}]
|
||||||
|
|
||||||
|
[:input.accept-button.primary
|
||||||
|
{:class (dom/classnames
|
||||||
|
:btn-disabled (or in-progress? all-unchecked?))
|
||||||
|
:disabled (or in-progress? all-unchecked?)
|
||||||
|
:type "button"
|
||||||
|
:value (if in-progress?
|
||||||
|
(tr "workspace.options.exporting-object")
|
||||||
|
(tr "labels.export"))
|
||||||
|
:on-click (when-not in-progress? accept-fn)}]]]]
|
||||||
|
|
||||||
|
[:& no-selection])]]]])))
|
||||||
|
|
||||||
(mf/defc shapes-no-selection []
|
(mf/defc shapes-no-selection []
|
||||||
[:div.no-selection
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:img {:src "images/export-no-shapes.png" :border "0"}]
|
(if new-css-system
|
||||||
[:p (tr "dashboard.export-shapes.no-elements")]
|
[:div {:class (stl/css :no-selection)}
|
||||||
[:p (tr "dashboard.export-shapes.how-to")]
|
[:p {:class (stl/css :modal-msg)}(tr "dashboard.export-shapes.no-elements")]
|
||||||
[:p [:a {:target "_blank"
|
[:p {:class (stl/css :modal-scd-msg)}(tr "dashboard.export-shapes.how-to")]
|
||||||
|
[:a {:target "_blank"
|
||||||
|
:class (stl/css :modal-link)
|
||||||
:href "https://help.penpot.app/user-guide/exporting/ "}
|
:href "https://help.penpot.app/user-guide/exporting/ "}
|
||||||
(tr "dashboard.export-shapes.how-to-link")]]])
|
(tr "dashboard.export-shapes.how-to-link")]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.no-selection
|
||||||
|
[:img {:src "images/export-no-shapes.png" :border "0"}]
|
||||||
|
[:p (tr "dashboard.export-shapes.no-elements")]
|
||||||
|
[:p (tr "dashboard.export-shapes.how-to")]
|
||||||
|
[:p [:a {:target "_blank"
|
||||||
|
:href "https://help.penpot.app/user-guide/exporting/ "}
|
||||||
|
(tr "dashboard.export-shapes.how-to-link")]]])))
|
||||||
|
|
||||||
(mf/defc export-shapes-dialog
|
(mf/defc export-shapes-dialog
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
|
|
|
@ -38,14 +38,14 @@
|
||||||
@include titleTipography;
|
@include titleTipography;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--modal-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
padding-left: $s-4;
|
padding-left: $s-4;
|
||||||
}
|
}
|
||||||
.progress {
|
.progress {
|
||||||
@include titleTipography;
|
@include titleTipography;
|
||||||
padding-left: $s-8;
|
padding-left: $s-8;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--modal-foreground-color-secondary);
|
color: var(--modal-text-foreground-color);
|
||||||
}
|
}
|
||||||
.retry-btn {
|
.retry-btn {
|
||||||
@extend .button-tertiary;
|
@extend .button-tertiary;
|
||||||
|
@ -66,3 +66,159 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
&.transparent {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
max-height: calc(10 * $s-80);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-content,
|
||||||
|
.no-selection {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg,
|
||||||
|
.modal-scd-msg,
|
||||||
|
.modal-hint,
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-link {
|
||||||
|
@include titleTipography;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--modal-link-foreground-color);
|
||||||
|
}
|
||||||
|
.selection-header {
|
||||||
|
@include flexRow;
|
||||||
|
height: $s-32;
|
||||||
|
margin-bottom: $s-4;
|
||||||
|
.selection-btn {
|
||||||
|
@include buttonStyle;
|
||||||
|
@extend .input-checkbox;
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-24;
|
||||||
|
width: $s-24;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: $s-16;
|
||||||
|
span {
|
||||||
|
@extend .checkbox-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.selection-title {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.selection-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: fit-content;
|
||||||
|
}
|
||||||
|
.selection-shadow {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
background: linear-gradient(to top, rgba(24, 24, 26, 1) 0%, rgba(24, 24, 26, 0) 100%);
|
||||||
|
content: "";
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.selection-list {
|
||||||
|
@include flexColumn;
|
||||||
|
max-height: $s-400;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: $s-12;
|
||||||
|
.selection-row {
|
||||||
|
@include flexRow;
|
||||||
|
background-color: var(--entry-background-color);
|
||||||
|
min-height: $s-40;
|
||||||
|
border-radius: $br-8;
|
||||||
|
.selection-btn {
|
||||||
|
@include buttonStyle;
|
||||||
|
@include flexRow;
|
||||||
|
width: 100%;
|
||||||
|
height: 10%;
|
||||||
|
gap: $s-8;
|
||||||
|
padding: 0 $s-16;
|
||||||
|
.checkbox-wrapper {
|
||||||
|
@extend .input-checkbox;
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-24;
|
||||||
|
width: $s-24;
|
||||||
|
padding: 0;
|
||||||
|
.checkbox-icon2 {
|
||||||
|
@extend .checkbox-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.selection-name {
|
||||||
|
@include titleTipography;
|
||||||
|
@include textEllipsis;
|
||||||
|
flex-grow: 1;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
.selection-scale {
|
||||||
|
@include titleTipography;
|
||||||
|
@include textEllipsis;
|
||||||
|
min-width: $s-108;
|
||||||
|
padding: $s-12;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
}
|
||||||
|
.selection-extension {
|
||||||
|
@include titleTipography;
|
||||||
|
@include textEllipsis;
|
||||||
|
min-width: $s-72;
|
||||||
|
padding: $s-12;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.image-wrapper {
|
||||||
|
@include flexCenter;
|
||||||
|
height: 100%;
|
||||||
|
min-height: $s-32;
|
||||||
|
min-width: $s-32;
|
||||||
|
background-color: var(--white);
|
||||||
|
border-radius: $br-6;
|
||||||
|
margin: auto 0;
|
||||||
|
img,
|
||||||
|
svg {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -391,6 +391,10 @@
|
||||||
(def masked-refactor (icon-xref :masked-refactor))
|
(def masked-refactor (icon-xref :masked-refactor))
|
||||||
(def menu-refactor (icon-xref :menu-refactor))
|
(def menu-refactor (icon-xref :menu-refactor))
|
||||||
(def merge-nodes-refactor (icon-xref :merge-nodes-refactor))
|
(def merge-nodes-refactor (icon-xref :merge-nodes-refactor))
|
||||||
|
(def msg-error-refactor (icon-xref :msg-error-refactor))
|
||||||
|
(def msg-neutral-refactor (icon-xref :msg-neutral-refactor))
|
||||||
|
(def msg-success-refactor (icon-xref :msg-success-refactor))
|
||||||
|
(def msg-warning-refactor (icon-xref :msg-warning-refactor))
|
||||||
(def move-refactor (icon-xref :move-refactor))
|
(def move-refactor (icon-xref :move-refactor))
|
||||||
(def open-link-refactor (icon-xref :open-link-refactor))
|
(def open-link-refactor (icon-xref :open-link-refactor))
|
||||||
(def open-refactor (icon-xref :open-refactor))
|
(def open-refactor (icon-xref :open-refactor))
|
||||||
|
@ -448,9 +452,11 @@
|
||||||
(def text-underlined-refactor (icon-xref :text-underlined-refactor))
|
(def text-underlined-refactor (icon-xref :text-underlined-refactor))
|
||||||
(def text-uppercase-refactor (icon-xref :text-uppercase-refactor))
|
(def text-uppercase-refactor (icon-xref :text-uppercase-refactor))
|
||||||
(def tick-refactor (icon-xref :tick-refactor))
|
(def tick-refactor (icon-xref :tick-refactor))
|
||||||
|
(def tree-refactor (icon-xref :tree-refactor))
|
||||||
(def to-corner-refactor (icon-xref :to-corner-refactor))
|
(def to-corner-refactor (icon-xref :to-corner-refactor))
|
||||||
(def to-curve-refactor (icon-xref :to-curve-refactor))
|
(def to-curve-refactor (icon-xref :to-curve-refactor))
|
||||||
(def unlock-refactor (icon-xref :unlock-refactor))
|
(def unlock-refactor (icon-xref :unlock-refactor))
|
||||||
|
(def user-refactor (icon-xref :user-refactor))
|
||||||
(def vertical-align-items-center-refactor (icon-xref :vertical-align-items-center-refactor))
|
(def vertical-align-items-center-refactor (icon-xref :vertical-align-items-center-refactor))
|
||||||
(def vertical-align-items-end-refactor (icon-xref :vertical-align-items-end-refactor))
|
(def vertical-align-items-end-refactor (icon-xref :vertical-align-items-end-refactor))
|
||||||
(def vertical-align-items-start-refactor (icon-xref :vertical-align-items-start-refactor))
|
(def vertical-align-items-start-refactor (icon-xref :vertical-align-items-start-refactor))
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.messages
|
(ns app.main.ui.messages
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
@ -13,49 +14,96 @@
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.link-button :as lb]
|
[app.main.ui.components.link-button :as lb]
|
||||||
|
[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]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(mf/defc banner
|
(mf/defc banner
|
||||||
[{:keys [type position status controls content links actions on-close data-test role] :as props}]
|
[{:keys [type position status controls content links actions on-close data-test role] :as props}]
|
||||||
[:div.banner {:class (dom/classnames
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
:warning (= type :warning)
|
(if new-css-system
|
||||||
:error (= type :error)
|
[:div {:class (stl/css-case :banner true
|
||||||
:success (= type :success)
|
:warning (= type :warning)
|
||||||
:info (= type :info)
|
:error (= type :error)
|
||||||
:fixed (= position :fixed)
|
:success (= type :success)
|
||||||
:floating (= position :floating)
|
:info (= type :info)
|
||||||
:inline (= position :inline)
|
:fixed (= position :fixed)
|
||||||
:hide (= status :hide))}
|
:floating (= position :floating)
|
||||||
[:div.wrapper
|
:inline (= position :inline)
|
||||||
[:div.icon (case type
|
:hide (= status :hide))}
|
||||||
:warning i/msg-warning
|
[:div {:class (stl/css :wrapper)}
|
||||||
:error i/msg-error
|
[:div {:class (stl/css :icon)}
|
||||||
:success i/msg-success
|
(case type
|
||||||
:info i/msg-info
|
:warning i/msg-warning-refactor
|
||||||
i/msg-error)]
|
:error i/msg-error-refactor
|
||||||
[:div.content {:class (dom/classnames
|
:success i/msg-success-refactor
|
||||||
:inline-actions (= controls :inline-actions)
|
:info i/msg-neutral-refactor
|
||||||
:bottom-actions (= controls :bottom-actions))
|
i/msg-error-refactor)]
|
||||||
:data-test data-test
|
|
||||||
:role role}
|
|
||||||
[:span
|
|
||||||
content
|
|
||||||
(for [[index link] (d/enumerate links)]
|
|
||||||
[:* {:key (dm/str "link-" index)}
|
|
||||||
" " [:& lb/link-button {:class "link"
|
|
||||||
:on-click (:callback link)
|
|
||||||
:value (:label link)}]])]
|
|
||||||
|
|
||||||
(when (or (= controls :bottom-actions) (= controls :inline-actions))
|
[:div {:class (stl/css-case :content true
|
||||||
[:div.actions
|
:inline-actions (= controls :inline-actions)
|
||||||
(for [action actions]
|
:bottom-actions (= controls :bottom-actions))
|
||||||
[:div.btn-secondary.btn-small {:key (uuid/next)
|
:data-test data-test
|
||||||
:on-click (:callback action)}
|
:role role}
|
||||||
(:label action)])])]
|
[:span {:class (stl/css :text)}
|
||||||
(when (= controls :close)
|
content
|
||||||
[:div.btn-close {:on-click on-close} i/close])]])
|
(for [[index link] (d/enumerate links)]
|
||||||
|
[:* {:key (dm/str "link-" index)}
|
||||||
|
" " [:& lb/link-button {:class "link"
|
||||||
|
:on-click (:callback link)
|
||||||
|
:value (:label link)}]])]
|
||||||
|
|
||||||
|
(when (or (= controls :bottom-actions) (= controls :inline-actions))
|
||||||
|
[:div {:class (stl/css :actions)}
|
||||||
|
(for [action actions]
|
||||||
|
[:button {:key (uuid/next)
|
||||||
|
:class (stl/css :action-bnt)
|
||||||
|
:on-click (:callback action)}
|
||||||
|
(:label action)])])]
|
||||||
|
(when (= controls :close)
|
||||||
|
[:button {:class (stl/css :btn-close)
|
||||||
|
:on-click on-close} i/close-refactor])]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div.banner {:class (dom/classnames
|
||||||
|
:warning (= type :warning)
|
||||||
|
:error (= type :error)
|
||||||
|
:success (= type :success)
|
||||||
|
:info (= type :info)
|
||||||
|
:fixed (= position :fixed)
|
||||||
|
:floating (= position :floating)
|
||||||
|
:inline (= position :inline)
|
||||||
|
:hide (= status :hide))}
|
||||||
|
[:div.wrapper
|
||||||
|
[:div.icon (case type
|
||||||
|
:warning i/msg-warning
|
||||||
|
:error i/msg-error
|
||||||
|
:success i/msg-success
|
||||||
|
:info i/msg-info
|
||||||
|
i/msg-error)]
|
||||||
|
[:div.content {:class (dom/classnames
|
||||||
|
:inline-actions (= controls :inline-actions)
|
||||||
|
:bottom-actions (= controls :bottom-actions))
|
||||||
|
:data-test data-test
|
||||||
|
:role role}
|
||||||
|
[:span
|
||||||
|
content
|
||||||
|
(for [[index link] (d/enumerate links)]
|
||||||
|
[:* {:key (dm/str "link-" index)}
|
||||||
|
" " [:& lb/link-button {:class "link"
|
||||||
|
:on-click (:callback link)
|
||||||
|
:value (:label link)}]])]
|
||||||
|
|
||||||
|
(when (or (= controls :bottom-actions) (= controls :inline-actions))
|
||||||
|
[:div.actions
|
||||||
|
(for [action actions]
|
||||||
|
[:div.btn-secondary.btn-small {:key (uuid/next)
|
||||||
|
:on-click (:callback action)}
|
||||||
|
(:label action)])])]
|
||||||
|
(when (= controls :close)
|
||||||
|
[:div.btn-close {:on-click on-close} i/close])]])))
|
||||||
|
|
||||||
(mf/defc notifications
|
(mf/defc notifications
|
||||||
[]
|
[]
|
||||||
|
|
130
frontend/src/app/main/ui/messages.scss
Normal file
130
frontend/src/app/main/ui/messages.scss
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
//
|
||||||
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
|
.banner {
|
||||||
|
--bg-color: var(--alert-background-color-error);
|
||||||
|
--fg-color: var(--alert-foreground-color-error);
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
color: var(--fg-color);
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
--bg-color: var(--alert-background-color-warning);
|
||||||
|
--fg-color: var(--alert-foreground-color-warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
--bg-color: var(--alert-background-color-ok);
|
||||||
|
--fg-color: var(--alert-foreground-color-ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
--bg-color: var(--alert-background-color-neutral);
|
||||||
|
--fg-color: var(--alert-foreground-color-neutral-active);
|
||||||
|
}
|
||||||
|
.banner.info .icon {
|
||||||
|
--fg-color: var(--alert-foreground-color-neutral);
|
||||||
|
}
|
||||||
|
.banner.info:hover .icon {
|
||||||
|
--fg-color: var(--alert-foreground-color-neutral);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: $s-16 1fr $s-40;
|
||||||
|
padding: $s-8 $s-8 $s-8 $s-16;
|
||||||
|
gap: $s-8;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: 100%;
|
||||||
|
width: $s-16;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--fg-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed {
|
||||||
|
@include alertShadow;
|
||||||
|
position: fixed;
|
||||||
|
top: $s-16;
|
||||||
|
right: $s-16;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: $s-48;
|
||||||
|
min-width: $s-500;
|
||||||
|
max-width: calc(10 * $s-100);
|
||||||
|
padding-left: $s-16;
|
||||||
|
z-index: $z-index-alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating {
|
||||||
|
@include alertShadow;
|
||||||
|
position: absolute;
|
||||||
|
min-height: $s-32;
|
||||||
|
top: $s-72;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: $s-640;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
z-index: $z-index-modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
min-height: $s-40;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
@include flexRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline-actions {
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-actions {
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-32;
|
||||||
|
color: black;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-close {
|
||||||
|
@extend .button-tertiary;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-32;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
stroke: black;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.modal
|
(ns app.main.ui.modal
|
||||||
(:require-macros [app.main.style :refer [css]])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.modal :as dm]
|
[app.main.data.modal :as dm]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
|
@ -78,8 +78,9 @@
|
||||||
|
|
||||||
(when-let [component (get components (:type data))]
|
(when-let [component (get components (:type data))]
|
||||||
[:div {:ref wrapper-ref
|
[:div {:ref wrapper-ref
|
||||||
:class (dom/classnames (css :modal-wrapper) new-css-system
|
:class (stl/css-case
|
||||||
:modal-wrapper (not new-css-system))}
|
:modal-wrapper new-css-system
|
||||||
|
:old-css/modal-wrapper (not new-css-system))}
|
||||||
(mf/element component (:props data))])))
|
(mf/element component (:props data))])))
|
||||||
|
|
||||||
(def modal-ref
|
(def modal-ref
|
||||||
|
|
|
@ -5,12 +5,15 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.onboarding
|
(ns app.main.ui.onboarding
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[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.onboarding.newsletter]
|
[app.main.ui.onboarding.newsletter]
|
||||||
[app.main.ui.onboarding.questions]
|
[app.main.ui.onboarding.questions]
|
||||||
[app.main.ui.onboarding.team-choice]
|
[app.main.ui.onboarding.team-choice]
|
||||||
|
@ -30,80 +33,178 @@
|
||||||
|
|
||||||
(mf/defc onboarding-welcome
|
(mf/defc onboarding-welcome
|
||||||
[{:keys [next] :as props}]
|
[{:keys [next] :as props}]
|
||||||
(let [go-next
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
go-next
|
||||||
(fn []
|
(fn []
|
||||||
(send-event "onboarding-step1-continue")
|
(send-event "onboarding-step1-continue")
|
||||||
(next))]
|
(next))]
|
||||||
[:div.modal-container.onboarding.onboarding-v2
|
(if new-css-system
|
||||||
[:div.modal-left.welcome
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:img {:src "images/onboarding-welcome.png" :border "0" :alt (tr "onboarding.welcome.alt")}]]
|
[:div {:class (stl/css :modal-left)}
|
||||||
[:div.modal-right
|
[:img {:src "images/onboarding-welcome.png"
|
||||||
[:div.release-container [:span.release "Version " (:main cf/version)]]
|
:border "0"
|
||||||
[:div.right-content
|
:alt (tr "onboarding.welcome.alt")}]]
|
||||||
[:div.modal-title
|
[:div {:class (stl/css :modal-right)}
|
||||||
[:h2 {:data-test "onboarding-welcome"} (tr "onboarding-v2.welcome.title")]]
|
[:div {:class (stl/css :release)}
|
||||||
|
"Version " (:main cf/version)]
|
||||||
|
[:div {:class (stl/css :modal-content)}
|
||||||
|
[:div {:class (stl/css :modal-header)}
|
||||||
|
[:h2 {:class (stl/css :modal-title)
|
||||||
|
:data-test "onboarding-welcome"}
|
||||||
|
(tr "onboarding-v2.welcome.title")]]
|
||||||
|
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-info)}
|
||||||
[:p (tr "onboarding-v2.welcome.desc1")]
|
[:p {:class (stl/css :modal-text)}
|
||||||
[:div.welcome-card
|
(tr "onboarding-v2.welcome.desc1")]
|
||||||
[:img {:src "images/community.svg" :border "0"}]
|
[:div {:class (stl/css :property-block)}
|
||||||
[:div
|
[:img {:src "images/community.svg"
|
||||||
[:div.title [:a {:href "https://community.penpot.app/" :target "_blank" :on-click #(send-event "onboarding-community-link")} (tr "onboarding-v2.welcome.desc2.title")]]
|
:border "0"}]
|
||||||
[:div.description (tr "onboarding-v2.welcome.desc2")]]]
|
[:div {:class (stl/css :text-wrapper)}
|
||||||
|
[:div {:class (stl/css :property-title)}
|
||||||
|
[:a {:href "https://community.penpot.app/"
|
||||||
|
:target "_blank"
|
||||||
|
:on-click #(send-event "onboarding-community-link")}
|
||||||
|
(tr "onboarding-v2.welcome.desc2.title")]]
|
||||||
|
[:div {:class (stl/css :property-description)}
|
||||||
|
(tr "onboarding-v2.welcome.desc2")]]]
|
||||||
|
|
||||||
[:div.welcome-card
|
[:div {:class (stl/css :property-block)}
|
||||||
[:img {:src "images/contributing.svg" :border "0"}]
|
[:img {:src "images/contributing.svg"
|
||||||
[:div
|
:border "0"}]
|
||||||
[:div.title [:a {:href "https://help.penpot.app/contributing-guide/" :target "_blank" :on-click #(send-event "onboarding-contributing-link")} (tr "onboarding-v2.welcome.desc3.title")]]
|
[:div {:class (stl/css :text-wrapper)}
|
||||||
[:div.description (tr "onboarding-v2.welcome.desc3")]]]]]
|
[:div {:class (stl/css :property-title)}
|
||||||
[:div.modal-navigation
|
[:a {:href "https://help.penpot.app/contributing-guide/"
|
||||||
[:button.btn-secondary {:on-click go-next :data-test "onboarding-next-btn"} (tr "labels.continue")]]
|
:target "_blank" :on-click #(send-event "onboarding-contributing-link")}
|
||||||
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
(tr "onboarding-v2.welcome.desc3.title")]]
|
||||||
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
[:div {:class (stl/css :property-description)}
|
||||||
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
(tr "onboarding-v2.welcome.desc3")]]]]]
|
||||||
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]))
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:button {:on-click go-next
|
||||||
|
:data-test "onboarding-next-btn"}
|
||||||
|
(tr "labels.continue")]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-container.onboarding.onboarding-v2
|
||||||
|
[:div.modal-left.welcome
|
||||||
|
[:img {:src "images/onboarding-welcome.png" :border "0" :alt (tr "onboarding.welcome.alt")}]]
|
||||||
|
[:div.modal-right
|
||||||
|
[:div.release-container [:span.release "Version " (:main cf/version)]]
|
||||||
|
[:div.right-content
|
||||||
|
[:div.modal-title
|
||||||
|
[:h2 {:data-test "onboarding-welcome"} (tr "onboarding-v2.welcome.title")]]
|
||||||
|
|
||||||
|
[:div.modal-content
|
||||||
|
[:p (tr "onboarding-v2.welcome.desc1")]
|
||||||
|
[:div.welcome-card
|
||||||
|
[:img {:src "images/community.svg" :border "0"}]
|
||||||
|
[:div
|
||||||
|
[:div.title [:a {:href "https://community.penpot.app/" :target "_blank" :on-click #(send-event "onboarding-community-link")} (tr "onboarding-v2.welcome.desc2.title")]]
|
||||||
|
[:div.description (tr "onboarding-v2.welcome.desc2")]]]
|
||||||
|
|
||||||
|
[:div.welcome-card
|
||||||
|
[:img {:src "images/contributing.svg" :border "0"}]
|
||||||
|
[:div
|
||||||
|
[:div.title [:a {:href "https://help.penpot.app/contributing-guide/" :target "_blank" :on-click #(send-event "onboarding-contributing-link")} (tr "onboarding-v2.welcome.desc3.title")]]
|
||||||
|
[:div.description (tr "onboarding-v2.welcome.desc3")]]]]]
|
||||||
|
[:div.modal-navigation
|
||||||
|
[:button.btn-secondary {:on-click go-next :data-test "onboarding-next-btn"} (tr "labels.continue")]]
|
||||||
|
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
||||||
|
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
||||||
|
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
||||||
|
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]])))
|
||||||
|
|
||||||
(mf/defc onboarding-before-start
|
(mf/defc onboarding-before-start
|
||||||
[{:keys [next] :as props}]
|
[{:keys [next] :as props}]
|
||||||
(let [go-next
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
go-next
|
||||||
(fn []
|
(fn []
|
||||||
(send-event "onboarding-step2-continue")
|
(send-event "onboarding-step2-continue")
|
||||||
(next))]
|
(next))]
|
||||||
[:div.modal-container.onboarding.onboarding-v2
|
(if new-css-system
|
||||||
[:div.modal-left.welcome
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:img {:src "images/onboarding-people.png" :border "0" :alt (tr "onboarding.welcome.alt")}]]
|
[:div {:class (stl/css :modal-left)}
|
||||||
[:div.modal-right
|
[:img {:src "images/onboarding-people.png"
|
||||||
[:div.release-container [:span.release "Version " (:main cf/version)]]
|
:border "0"
|
||||||
[:div.right-content
|
:alt (tr "onboarding.welcome.alt")}]]
|
||||||
[:div.modal-title
|
[:div {:class (stl/css :modal-right)}
|
||||||
[:h2 {:data-test "onboarding-welcome"} (tr "onboarding-v2.before-start.title")]]
|
[:div {:class (stl/css :release)}
|
||||||
|
"Version " (:main cf/version)]
|
||||||
|
[:div {:class (stl/css :modal-content)}
|
||||||
|
[:div {:class (stl/css :modal-header)}
|
||||||
|
[:h2 {:class (stl/css :modal-title)
|
||||||
|
:data-test "onboarding-welcome"}
|
||||||
|
(tr "onboarding-v2.before-start.title")]]
|
||||||
|
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-info)}
|
||||||
[:p (tr "onboarding-v2.before-start.desc1")]
|
[:p {:class (stl/css :modal-text)}
|
||||||
[:div.welcome-card
|
(tr "onboarding-v2.before-start.desc1")]
|
||||||
[:img {:src "images/user-guide.svg" :border "0"}]
|
[:div {:class (stl/css :property-block)}
|
||||||
[:div
|
[:img {:src "images/user-guide.svg" :border "0"}]
|
||||||
[:div.title [:a {:href "https://help.penpot.app/user-guide/" :target "_blank" :on-click #(send-event "onboarding-user-guide-link")} (tr "onboarding-v2.before-start.desc2.title")]]
|
[:div {:class (stl/css :text-wrapper)}
|
||||||
[:div.description (tr "onboarding-v2.before-start.desc2")]]]
|
[:div {:class (stl/css :property-title)}
|
||||||
|
[:a {:class (stl/css :modal-link)
|
||||||
|
:href "https://help.penpot.app/user-guide/"
|
||||||
|
:target "_blank"
|
||||||
|
:on-click #(send-event "onboarding-user-guide-link")}
|
||||||
|
(tr "onboarding-v2.before-start.desc2.title")]]
|
||||||
|
[:div {:class (stl/css :property-description)}
|
||||||
|
(tr "onboarding-v2.before-start.desc2")]]]
|
||||||
|
|
||||||
[:div.welcome-card
|
[:div {:class (stl/css :property-block)}
|
||||||
[:img {:src "images/video-tutorials.svg" :border "0"}]
|
[:img {:src "images/video-tutorials.svg" :border "0"}]
|
||||||
[:div
|
[:div {:class (stl/css :text-wrapper)}
|
||||||
[:div.title [:a {:href "https://www.youtube.com/c/Penpot" :target "_blank" :on-click #(send-event "onboarding-video-tutorials-link")} (tr "onboarding-v2.before-start.desc3.title")]]
|
[:div {:class (stl/css :property-title)}
|
||||||
[:div.description (tr "onboarding-v2.before-start.desc3")]]]]]
|
[:a {:class (stl/css :modal-link)
|
||||||
[:div.modal-navigation
|
:href "https://www.youtube.com/c/Penpot"
|
||||||
[:button.btn-secondary {:on-click go-next :data-test "onboarding-next-btn"} (tr "labels.continue")]]
|
:target "_blank"
|
||||||
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
:on-click #(send-event "onboarding-video-tutorials-link")}
|
||||||
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
(tr "onboarding-v2.before-start.desc3.title")]]
|
||||||
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
[:div {:class (stl/css :property-description)}
|
||||||
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]))
|
(tr "onboarding-v2.before-start.desc3")]]]]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:button {:on-click go-next
|
||||||
|
:data-test "onboarding-next-btn"}
|
||||||
|
(tr "labels.continue")]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-container.onboarding.onboarding-v2
|
||||||
|
[:div.modal-left.welcome
|
||||||
|
[:img {:src "images/onboarding-people.png" :border "0" :alt (tr "onboarding.welcome.alt")}]]
|
||||||
|
[:div.modal-right
|
||||||
|
[:div.release-container [:span.release "Version " (:main cf/version)]]
|
||||||
|
[:div.right-content
|
||||||
|
[:div.modal-title
|
||||||
|
[:h2 {:data-test "onboarding-welcome"} (tr "onboarding-v2.before-start.title")]]
|
||||||
|
|
||||||
|
[:div.modal-content
|
||||||
|
[:p (tr "onboarding-v2.before-start.desc1")]
|
||||||
|
[:div.welcome-card
|
||||||
|
[:img {:src "images/user-guide.svg" :border "0"}]
|
||||||
|
[:div
|
||||||
|
[:div.title [:a {:href "https://help.penpot.app/user-guide/" :target "_blank" :on-click #(send-event "onboarding-user-guide-link")} (tr "onboarding-v2.before-start.desc2.title")]]
|
||||||
|
[:div.description (tr "onboarding-v2.before-start.desc2")]]]
|
||||||
|
|
||||||
|
[:div.welcome-card
|
||||||
|
[:img {:src "images/video-tutorials.svg" :border "0"}]
|
||||||
|
[:div
|
||||||
|
[:div.title [:a {:href "https://www.youtube.com/c/Penpot" :target "_blank" :on-click #(send-event "onboarding-video-tutorials-link")} (tr "onboarding-v2.before-start.desc3.title")]]
|
||||||
|
[:div.description (tr "onboarding-v2.before-start.desc3")]]]]]
|
||||||
|
[:div.modal-navigation
|
||||||
|
[:button.btn-secondary {:on-click go-next :data-test "onboarding-next-btn"} (tr "labels.continue")]]
|
||||||
|
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
||||||
|
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
||||||
|
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
||||||
|
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]])))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc onboarding-modal
|
(mf/defc onboarding-modal
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :onboarding}
|
::mf/register-as :onboarding}
|
||||||
[_]
|
[_]
|
||||||
(let [slide (mf/use-state :start)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
slide (mf/use-state :start)
|
||||||
klass (mf/use-state "fadeInDown")
|
klass (mf/use-state "fadeInDown")
|
||||||
|
|
||||||
navigate
|
navigate
|
||||||
|
@ -124,9 +225,17 @@
|
||||||
(fn []
|
(fn []
|
||||||
(reset! klass nil)
|
(reset! klass nil)
|
||||||
(tm/dispose! sem))))
|
(tm/dispose! sem))))
|
||||||
|
(if new-css-system
|
||||||
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
|
[:div.animated {:class(dm/str @klass " " (stl/css :animated))}
|
||||||
|
(case @slide
|
||||||
|
:start [:& onboarding-welcome {:next #(navigate :opensource)}]
|
||||||
|
:opensource [:& onboarding-before-start {:next skip}])]]
|
||||||
|
|
||||||
[:div.modal-overlay
|
|
||||||
[:div.animated {:class @klass}
|
|
||||||
(case @slide
|
[:div.modal-overlay
|
||||||
:start [:& onboarding-welcome {:next #(navigate :opensource)}]
|
[:div.animated {:class @klass}
|
||||||
:opensource [:& onboarding-before-start {:next skip}])]]))
|
(case @slide
|
||||||
|
:start [:& onboarding-welcome {:next #(navigate :opensource)}]
|
||||||
|
:opensource [:& onboarding-before-start {:next skip}])]])))
|
||||||
|
|
106
frontend/src/app/main/ui/onboarding.scss
Normal file
106
frontend/src/app/main/ui/onboarding.scss
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
min-width: $s-712;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-left {
|
||||||
|
width: $s-284;
|
||||||
|
img {
|
||||||
|
width: $s-284;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: $br-8 0 0 $br-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-right {
|
||||||
|
@include flexColumn;
|
||||||
|
position: relative;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release {
|
||||||
|
@include titleTipography;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: $s-8;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
gap: $s-24;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
@include bigTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-info {
|
||||||
|
@include flexColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-text {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-block {
|
||||||
|
@include flexRow;
|
||||||
|
gap: $s-16;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
img {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-40;
|
||||||
|
width: $s-40;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-link {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-link-foreground-color);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-wrapper {
|
||||||
|
@include flexColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-title a {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.property-description {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,11 +5,14 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.onboarding.newsletter
|
(ns app.main.ui.onboarding.newsletter
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[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.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]))
|
||||||
|
|
||||||
|
@ -17,9 +20,10 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :onboarding-newsletter-modal}
|
::mf/register-as :onboarding-newsletter-modal}
|
||||||
[]
|
[]
|
||||||
(let [message (tr "onboarding.newsletter.acceptance-message")
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
message (tr "onboarding.newsletter.acceptance-message")
|
||||||
newsletter-updates (mf/use-state false)
|
newsletter-updates (mf/use-state false)
|
||||||
newsletter-news (mf/use-state false)
|
newsletter-news (mf/use-state false)
|
||||||
toggle
|
toggle
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [option]
|
(fn [option]
|
||||||
|
@ -35,27 +39,78 @@
|
||||||
(modal/show {:type :onboarding-team})
|
(modal/show {:type :onboarding-team})
|
||||||
(du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))]
|
(du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))]
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.onboarding.newsletter.animated.fadeInDown
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-top
|
[:div.animated.fadeInDown {:class (stl/css :modal-container)}
|
||||||
[:h1.newsletter-title {:data-test "onboarding-newsletter-title"} (tr "onboarding.newsletter.title")]
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:p (tr "onboarding-v2.newsletter.desc")]]
|
[:h2 {:class (stl/css :modal-title)
|
||||||
[:div.modal-bottom
|
:data-test "onboarding-newsletter-title"}
|
||||||
[:div.newsletter-options
|
(tr "onboarding.newsletter.title")]
|
||||||
[:div.input-checkbox.check-primary
|
[:p {:class (stl/css :modal-text)}
|
||||||
[:input {:type "checkbox"
|
(tr "onboarding-v2.newsletter.desc")]]
|
||||||
:id "newsletter-updates"
|
[:div {:class (stl/css :modal-content)}
|
||||||
:on-change #(toggle newsletter-updates)}]
|
[:div {:class (stl/css :newsletter-options)}
|
||||||
[:label {:for "newsletter-updates"} (tr "onboarding-v2.newsletter.updates")]]
|
[:div {:class (stl/css :input-wrapper)}
|
||||||
[:div.input-checkbox.check-primary
|
[:label {:for "newsletter-updates"}
|
||||||
[:input {:type "checkbox"
|
[:span {:class (stl/css-case :global/checked @newsletter-updates)}
|
||||||
:id "newsletter-news"
|
(when @newsletter-updates
|
||||||
:on-change #(toggle newsletter-news)}]
|
i/status-tick-refactor)]
|
||||||
[:label {:for "newsletter-news"} (tr "onboarding-v2.newsletter.news")]]]
|
(tr "onboarding-v2.newsletter.updates")
|
||||||
[:p (tr "onboarding-v2.newsletter.privacy1") [:a {:target "_blank" :href "https://penpot.app/privacy"} (tr "onboarding.newsletter.policy")]]
|
[:input {:type "checkbox"
|
||||||
[:p (tr "onboarding-v2.newsletter.privacy2")]]
|
:id "newsletter-updates"
|
||||||
[:div.modal-footer
|
:on-change #(toggle newsletter-updates)}]]]
|
||||||
[:button.btn-primary {:on-click accept} (tr "labels.continue")]]
|
|
||||||
[:img.deco.top {:src "images/deco-newsletter.png" :border "0"}]
|
[:div {:class (stl/css :input-wrapper)}
|
||||||
[:img.deco.newsletter-left {:src "images/deco-news-left.png" :border "0"}]
|
[:label {:for "newsletter-news"}
|
||||||
[:img.deco.newsletter-right {:src "images/deco-news-right.png" :border "0"}]]]))
|
[:span {:class (stl/css-case :global/checked @newsletter-news)}
|
||||||
|
(when @newsletter-news
|
||||||
|
i/status-tick-refactor)]
|
||||||
|
(tr "onboarding-v2.newsletter.news")
|
||||||
|
[:input {:type "checkbox"
|
||||||
|
:id "newsletter-news"
|
||||||
|
:on-change #(toggle newsletter-news)}]]]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-info)}
|
||||||
|
[:p {:class (stl/css :modal-text)}
|
||||||
|
(tr "onboarding-v2.newsletter.privacy1")
|
||||||
|
[:a {:class (stl/css :modal-link)
|
||||||
|
:target "_blank"
|
||||||
|
:href "https://penpot.app/privacy"}
|
||||||
|
(tr "onboarding.newsletter.policy")]]
|
||||||
|
[:p {:class (stl/css :modal-text)}
|
||||||
|
(tr "onboarding-v2.newsletter.privacy2")]]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:button {:on-click accept} (tr "labels.continue")]]
|
||||||
|
|
||||||
|
[:img {:class (stl/css-case :deco true
|
||||||
|
:top true)
|
||||||
|
:src "images/deco-newsletter.png" :border "0"}]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.onboarding.newsletter.animated.fadeInDown
|
||||||
|
[:div.modal-top
|
||||||
|
[:h1.newsletter-title {:data-test "onboarding-newsletter-title"} (tr "onboarding.newsletter.title")]
|
||||||
|
[:p (tr "onboarding-v2.newsletter.desc")]]
|
||||||
|
[:div.modal-bottom
|
||||||
|
[:div.newsletter-options
|
||||||
|
[:div.input-checkbox.check-primary
|
||||||
|
[:input {:type "checkbox"
|
||||||
|
:id "newsletter-updates"
|
||||||
|
:on-change #(toggle newsletter-updates)}]
|
||||||
|
[:label {:for "newsletter-updates"} (tr "onboarding-v2.newsletter.updates")]]
|
||||||
|
[:div.input-checkbox.check-primary
|
||||||
|
[:input {:type "checkbox"
|
||||||
|
:id "newsletter-news"
|
||||||
|
:on-change #(toggle newsletter-news)}]
|
||||||
|
[:label {:for "newsletter-news"} (tr "onboarding-v2.newsletter.news")]]]
|
||||||
|
[:p (tr "onboarding-v2.newsletter.privacy1") [:a {:target "_blank" :href "https://penpot.app/privacy"} (tr "onboarding.newsletter.policy")]]
|
||||||
|
[:p (tr "onboarding-v2.newsletter.privacy2")]]
|
||||||
|
[:div.modal-footer
|
||||||
|
[:button.btn-primary {:on-click accept} (tr "labels.continue")]]
|
||||||
|
[:img.deco.top {:src "images/deco-newsletter.png" :border "0"}]
|
||||||
|
[:img.deco.newsletter-left {:src "images/deco-news-left.png" :border "0"}]
|
||||||
|
[:img.deco.newsletter-right {:src "images/deco-news-right.png" :border "0"}]]])
|
||||||
|
))
|
||||||
|
|
82
frontend/src/app/main/ui/onboarding/newsletter.scss
Normal file
82
frontend/src/app/main/ui/onboarding/newsletter.scss
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
position: relative;
|
||||||
|
min-width: $s-712;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: $s-80;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
@include bigTitleTipography;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
margin-bottom: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-text {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
gap: $s-32;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.newsletter-options {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
@extend .input-checkbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-info {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-16;
|
||||||
|
margin-bottom: $s-32;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-link {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-link-foreground-color);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.deco {
|
||||||
|
position: absolute;
|
||||||
|
width: 183px;
|
||||||
|
top: -106px;
|
||||||
|
left: 261px;
|
||||||
|
}
|
|
@ -6,12 +6,14 @@
|
||||||
|
|
||||||
(ns app.main.ui.onboarding.questions
|
(ns app.main.ui.onboarding.questions
|
||||||
"External form for onboarding questions."
|
"External form for onboarding questions."
|
||||||
|
(: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]
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.forms :as fm]
|
[app.main.ui.components.forms :as fm]
|
||||||
|
[app.main.ui.context :as ctx]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -19,67 +21,140 @@
|
||||||
|
|
||||||
(mf/defc step-container
|
(mf/defc step-container
|
||||||
[{:keys [form step on-next on-prev children] :as props}]
|
[{:keys [form step on-next on-prev children] :as props}]
|
||||||
[:& fm/form {:form form :on-submit on-next}
|
|
||||||
[:div.step-header
|
|
||||||
[:div.step-number (str/ffmt "%/4" step)]]
|
|
||||||
|
|
||||||
children
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:div.buttons
|
|
||||||
[:div.step-next
|
|
||||||
[:> fm/submit-button*
|
|
||||||
{:label (if (< step 4) (tr "questions.next") (tr "questions.start"))
|
|
||||||
:class "step-next"}]]
|
|
||||||
|
|
||||||
(when on-prev
|
(if new-css-system
|
||||||
[:div.step-prev
|
[:& fm/form {:form form :on-submit on-next}
|
||||||
[:button {:on-click on-prev} (tr "questions.previous")]])]])
|
[:div {:class (stl/css :paginator)} (str/ffmt "%/4" step)]
|
||||||
|
|
||||||
|
children
|
||||||
|
|
||||||
|
[:div {:class (stl/css :action-buttons)}
|
||||||
|
|
||||||
|
(when on-prev
|
||||||
|
[:button {:class (stl/css :prev-button)
|
||||||
|
:on-click on-prev} (tr "questions.previous")])
|
||||||
|
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (if (< step 4) (tr "questions.next") (tr "questions.start"))
|
||||||
|
:class (stl/css :next-button)}]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:& fm/form {:form form :on-submit on-next}
|
||||||
|
[:div.step-header
|
||||||
|
[:div.step-number (str/ffmt "%/4" step)]]
|
||||||
|
|
||||||
|
children
|
||||||
|
|
||||||
|
[:div.buttons
|
||||||
|
[:div.step-next
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (if (< step 4) (tr "questions.next") (tr "questions.start"))
|
||||||
|
:class "step-next"}]]
|
||||||
|
|
||||||
|
(when on-prev
|
||||||
|
[:div.step-prev
|
||||||
|
[:button {:on-click on-prev} (tr "questions.previous")]])]])))
|
||||||
|
|
||||||
(s/def ::questions-form-step-1
|
(s/def ::questions-form-step-1
|
||||||
(s/keys :req-un [::planning]))
|
(s/keys :req-un [::planning]))
|
||||||
|
|
||||||
(mf/defc step-1
|
(mf/defc step-1
|
||||||
[{:keys [on-next form] :as props}]
|
[{:keys [on-next form] :as props}]
|
||||||
[:& step-container {:form form :step 1 :on-next on-next}
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:img.header-image {:src "images/form/use-for-1.png" :alt (tr "questions.lets-get-started")}]
|
(if new-css-system
|
||||||
[:h1 (tr "questions.lets-get-started")]
|
[:& step-container {:form form :step 1 :on-next on-next}
|
||||||
[:p.intro (tr "questions.your-feedback-will-help-us")]
|
[:img {:class (stl/css :header-image)
|
||||||
[:h3 (tr "questions.questions-how-are-you-planning-to-use-penpot")]
|
:src "images/form/use-for-1.png" :alt (tr "questions.lets-get-started")}]
|
||||||
[:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "questions-how-are-you-planning-to-use-penpot" :disabled true}
|
[:h1 {:class (stl/css :modal-title)} (tr "questions.lets-get-started")]
|
||||||
{:label (tr "questions.discover-more-about-penpot") :value "discover-more-about-penpot" :key "discover-more-about-penpot"}
|
[:p {:class (stl/css :modal-text)} (tr "questions.your-feedback-will-help-us")]
|
||||||
{:label (tr "questions.test-penpot-to-see-if-its-a-fit-for-team") :value "test-penpot-to-see-if-its-a-fit-for-team" :key "test-penpot-to-see-if-its-a-fit-for-team"}
|
[:h3 {:class (stl/css :modal-subtitle)} (tr "questions.questions-how-are-you-planning-to-use-penpot")]
|
||||||
{:label (tr "questions.start-to-work-on-my-project") :value "start-to-work-on-my-project" :key "start-to-work-on-my-project"}
|
[:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "questions-how-are-you-planning-to-use-penpot" :disabled true}
|
||||||
{:label (tr "questions.get-the-code-from-my-team-project") :value "get-the-code-from-my-team-project" :key "get-the-code-from-my-team-project"}
|
{:label (tr "questions.discover-more-about-penpot") :value "discover-more-about-penpot" :key "discover-more-about-penpot"}
|
||||||
{:label (tr "questions.leave-feedback-for-my-team-project") :value "leave-feedback-for-my-team-project" :key "leave-feedback-for-my-team-project"}
|
{:label (tr "questions.test-penpot-to-see-if-its-a-fit-for-team") :value "test-penpot-to-see-if-its-a-fit-for-team" :key "test-penpot-to-see-if-its-a-fit-for-team"}
|
||||||
{:label (tr "questions.work-in-concept-ideas") :value "work-in-concept-ideas" :key "work-in-concept-ideas"}
|
{:label (tr "questions.start-to-work-on-my-project") :value "start-to-work-on-my-project" :key "start-to-work-on-my-project"}
|
||||||
{:label (tr "questions.try-out-before-using-penpot-on-premise") :value "try-out-before-using-penpot-on-premise" :key "try-out-before-using-penpot-on-premise"}]
|
{:label (tr "questions.get-the-code-from-my-team-project") :value "get-the-code-from-my-team-project" :key "get-the-code-from-my-team-project"}
|
||||||
:default ""
|
{:label (tr "questions.leave-feedback-for-my-team-project") :value "leave-feedback-for-my-team-project" :key "leave-feedback-for-my-team-project"}
|
||||||
:name :planning}]])
|
{:label (tr "questions.work-in-concept-ideas") :value "work-in-concept-ideas" :key "work-in-concept-ideas"}
|
||||||
|
{:label (tr "questions.try-out-before-using-penpot-on-premise") :value "try-out-before-using-penpot-on-premise" :key "try-out-before-using-penpot-on-premise"}]
|
||||||
|
:default ""
|
||||||
|
:name :planning}]]
|
||||||
|
|
||||||
|
|
||||||
|
[:& step-container {:form form :step 1 :on-next on-next}
|
||||||
|
[:img.header-image {:src "images/form/use-for-1.png" :alt (tr "questions.lets-get-started")}]
|
||||||
|
[:h1 (tr "questions.lets-get-started")]
|
||||||
|
[:p.intro (tr "questions.your-feedback-will-help-us")]
|
||||||
|
[:h3 (tr "questions.questions-how-are-you-planning-to-use-penpot")]
|
||||||
|
[:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "questions-how-are-you-planning-to-use-penpot" :disabled true}
|
||||||
|
{:label (tr "questions.discover-more-about-penpot") :value "discover-more-about-penpot" :key "discover-more-about-penpot"}
|
||||||
|
{:label (tr "questions.test-penpot-to-see-if-its-a-fit-for-team") :value "test-penpot-to-see-if-its-a-fit-for-team" :key "test-penpot-to-see-if-its-a-fit-for-team"}
|
||||||
|
{:label (tr "questions.start-to-work-on-my-project") :value "start-to-work-on-my-project" :key "start-to-work-on-my-project"}
|
||||||
|
{:label (tr "questions.get-the-code-from-my-team-project") :value "get-the-code-from-my-team-project" :key "get-the-code-from-my-team-project"}
|
||||||
|
{:label (tr "questions.leave-feedback-for-my-team-project") :value "leave-feedback-for-my-team-project" :key "leave-feedback-for-my-team-project"}
|
||||||
|
{:label (tr "questions.work-in-concept-ideas") :value "work-in-concept-ideas" :key "work-in-concept-ideas"}
|
||||||
|
{:label (tr "questions.try-out-before-using-penpot-on-premise") :value "try-out-before-using-penpot-on-premise" :key "try-out-before-using-penpot-on-premise"}]
|
||||||
|
:default ""
|
||||||
|
:name :planning}]])))
|
||||||
|
|
||||||
(s/def ::questions-form-step-2
|
(s/def ::questions-form-step-2
|
||||||
(s/keys :req-un [::experience-branding-illustrations-marketing-pieces ::experience-interface-design-visual-assets-design-systems ::experience-interface-wireframes-user-journeys-flows-navigation-trees]))
|
(s/keys :req-un [::experience-branding-illustrations-marketing-pieces ::experience-interface-design-visual-assets-design-systems ::experience-interface-wireframes-user-journeys-flows-navigation-trees]))
|
||||||
|
|
||||||
(mf/defc step-2
|
(mf/defc step-2
|
||||||
[{:keys [on-next on-prev form] :as props}]
|
[{:keys [on-next on-prev form] :as props}]
|
||||||
[:& step-container {:form form :step 2 :on-next on-next :on-prev on-prev}
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:h3 (tr "questions.describe-your-experience-working-on")]
|
(if new-css-system
|
||||||
|
[:& step-container {:form form :step 2 :on-next on-next :on-prev on-prev}
|
||||||
|
[:h3 {:class (stl/css :modal-subtitle)}
|
||||||
|
(tr "questions.describe-your-experience-working-on")]
|
||||||
|
|
||||||
[:div.section (tr "branding-illustrations-marketing-pieces")]
|
[:div {:class (stl/css :modal-question)}
|
||||||
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
[:div {:class (stl/css :modal-text)}
|
||||||
{:label (tr "questions.some") :value "some"}
|
(tr "branding-illustrations-marketing-pieces")]
|
||||||
{:label (tr "questions.a-lot") :value "a-lot"}]
|
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
||||||
:name :experience-branding-illustrations-marketing-pieces}]
|
{:label (tr "questions.some") :value "some"}
|
||||||
|
{:label (tr "questions.a-lot") :value "a-lot"}]
|
||||||
|
:name :experience-branding-illustrations-marketing-pieces}]]
|
||||||
|
|
||||||
[:div.section (tr "questions.interface-design-visual-assets-design-systems")]
|
[:div {:class (stl/css :modal-question)}
|
||||||
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
[:div {:class (stl/css :modal-text)}
|
||||||
{:label (tr "questions.some") :value "some"}
|
(tr "questions.interface-design-visual-assets-design-systems")]
|
||||||
{:label (tr "questions.a-lot") :value "a-lot"}]
|
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
||||||
:name :experience-interface-design-visual-assets-design-systems}]
|
{:label (tr "questions.some") :value "some"}
|
||||||
|
{:label (tr "questions.a-lot") :value "a-lot"}]
|
||||||
|
:name :experience-interface-design-visual-assets-design-systems}]]
|
||||||
|
|
||||||
[:div.section (tr "questions.wireframes-user-journeys-flows-navigation-trees")]
|
[:div {:class (stl/css :modal-question)}
|
||||||
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
[:div {:class (stl/css :modal-text)}
|
||||||
{:label (tr "questions.some") :value "some"}
|
(tr "questions.wireframes-user-journeys-flows-navigation-trees")]
|
||||||
{:label (tr "questions.a-lot") :value "a-lot"}]
|
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
||||||
:name :experience-interface-wireframes-user-journeys-flows-navigation-trees}]])
|
{:label (tr "questions.some") :value "some"}
|
||||||
|
{:label (tr "questions.a-lot") :value "a-lot"}]
|
||||||
|
:name :experience-interface-wireframes-user-journeys-flows-navigation-trees}]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:& step-container {:form form :step 2 :on-next on-next :on-prev on-prev}
|
||||||
|
[:h3 (tr "questions.describe-your-experience-working-on")]
|
||||||
|
|
||||||
|
[:div.section (tr "branding-illustrations-marketing-pieces")]
|
||||||
|
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
||||||
|
{:label (tr "questions.some") :value "some"}
|
||||||
|
{:label (tr "questions.a-lot") :value "a-lot"}]
|
||||||
|
:name :experience-branding-illustrations-marketing-pieces}]
|
||||||
|
|
||||||
|
[:div.section (tr "questions.interface-design-visual-assets-design-systems")]
|
||||||
|
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
||||||
|
{:label (tr "questions.some") :value "some"}
|
||||||
|
{:label (tr "questions.a-lot") :value "a-lot"}]
|
||||||
|
:name :experience-interface-design-visual-assets-design-systems}]
|
||||||
|
|
||||||
|
[:div.section (tr "questions.wireframes-user-journeys-flows-navigation-trees")]
|
||||||
|
[:& fm/radio-buttons {:options [{:label (tr "questions.none") :value "none"}
|
||||||
|
{:label (tr "questions.some") :value "some"}
|
||||||
|
{:label (tr "questions.a-lot") :value "a-lot"}]
|
||||||
|
:name :experience-interface-wireframes-user-journeys-flows-navigation-trees}]])))
|
||||||
|
|
||||||
(s/def ::questions-form-step-3
|
(s/def ::questions-form-step-3
|
||||||
(s/keys :req-un [::experience-design-tool]
|
(s/keys :req-un [::experience-design-tool]
|
||||||
|
@ -95,7 +170,8 @@
|
||||||
|
|
||||||
(mf/defc step-3
|
(mf/defc step-3
|
||||||
[{:keys [on-next on-prev form] :as props}]
|
[{:keys [on-next on-prev form] :as props}]
|
||||||
(let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])
|
||||||
on-design-tool-change
|
on-design-tool-change
|
||||||
(fn [_ _]
|
(fn [_ _]
|
||||||
(let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])]
|
(let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])]
|
||||||
|
@ -104,20 +180,40 @@
|
||||||
(swap! form d/dissoc-in [:data :experience-design-tool-other])
|
(swap! form d/dissoc-in [:data :experience-design-tool-other])
|
||||||
(swap! form d/dissoc-in [:errors :experience-design-tool-other])))))]
|
(swap! form d/dissoc-in [:errors :experience-design-tool-other])))))]
|
||||||
|
|
||||||
[:& step-container {:form form :step 3 :on-next on-next :on-prev on-prev}
|
(if new-css-system
|
||||||
[:h3 (tr "question.design-tool-more-experienced-with")]
|
[:& step-container {:form form :step 3 :on-next on-next :on-prev on-prev}
|
||||||
[:& fm/radio-buttons {:options [{:label (tr "questions.figma") :value "figma" :image "images/form/figma.png"}
|
[:h3 {:class (stl/css :modal-subtitle)}
|
||||||
{:label (tr "questions.sketch") :value "sketch" :image "images/form/sketch.png"}
|
(tr "question.design-tool-more-experienced-with")]
|
||||||
{:label (tr "questions.adobe-xd") :value "adobe-xd" :image "images/form/adobe-xd.png"}
|
[:& fm/radio-buttons {:options [{:label (tr "questions.figma") :value "figma" :image "images/form/figma.png"}
|
||||||
{:label (tr "questions.canva") :value "canva" :image "images/form/canva.png"}
|
{:label (tr "questions.sketch") :value "sketch" :image "images/form/sketch.png"}
|
||||||
{:label (tr "questions.invision") :value "invision" :image "images/form/invision.png"}
|
{:label (tr "questions.adobe-xd") :value "adobe-xd" :image "images/form/adobe-xd.png"}
|
||||||
{:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"}
|
{:label (tr "questions.canva") :value "canva" :image "images/form/canva.png"}
|
||||||
{:label (tr "questions.other") :value "other"}]
|
{:label (tr "questions.invision") :value "invision" :image "images/form/invision.png"}
|
||||||
:name :experience-design-tool
|
{:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"}
|
||||||
:on-change on-design-tool-change}]
|
{:label (tr "questions.other") :value "other"}]
|
||||||
[:div.other
|
:name :experience-design-tool
|
||||||
[:label (tr "questions.other")]
|
:on-change on-design-tool-change}]
|
||||||
[:& fm/input {:name :experience-design-tool-other :label (tr "questions.other") :disabled (not= experience-design-tool "other")}]]]))
|
|
||||||
|
[:& fm/input {:name :experience-design-tool-other
|
||||||
|
:placeholder (tr "questions.other")
|
||||||
|
:label ""
|
||||||
|
:disabled (not= experience-design-tool "other")}]]
|
||||||
|
|
||||||
|
|
||||||
|
[:& step-container {:form form :step 3 :on-next on-next :on-prev on-prev}
|
||||||
|
[:h3 (tr "question.design-tool-more-experienced-with")]
|
||||||
|
[:& fm/radio-buttons {:options [{:label (tr "questions.figma") :value "figma" :image "images/form/figma.png"}
|
||||||
|
{:label (tr "questions.sketch") :value "sketch" :image "images/form/sketch.png"}
|
||||||
|
{:label (tr "questions.adobe-xd") :value "adobe-xd" :image "images/form/adobe-xd.png"}
|
||||||
|
{:label (tr "questions.canva") :value "canva" :image "images/form/canva.png"}
|
||||||
|
{:label (tr "questions.invision") :value "invision" :image "images/form/invision.png"}
|
||||||
|
{:label (tr "questions.never-used-a-tool") :value "never-used-a-tool" :image "images/form/never-used.png"}
|
||||||
|
{:label (tr "questions.other") :value "other"}]
|
||||||
|
:name :experience-design-tool
|
||||||
|
:on-change on-design-tool-change}]
|
||||||
|
[:div.other
|
||||||
|
[:label (tr "questions.other")]
|
||||||
|
[:& fm/input {:name :experience-design-tool-other :label (tr "questions.other") :disabled (not= experience-design-tool "other")}]]])))
|
||||||
|
|
||||||
(s/def ::questions-form-step-4
|
(s/def ::questions-form-step-4
|
||||||
(s/keys :req-un [::team-size ::role]
|
(s/keys :req-un [::team-size ::role]
|
||||||
|
@ -133,7 +229,8 @@
|
||||||
|
|
||||||
(mf/defc step-4
|
(mf/defc step-4
|
||||||
[{:keys [on-next on-prev form] :as props}]
|
[{:keys [on-next on-prev form] :as props}]
|
||||||
(let [role (dm/get-in @form [:data :role])
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
role (dm/get-in @form [:data :role])
|
||||||
on-role-change
|
on-role-change
|
||||||
(fn [_ _]
|
(fn [_ _]
|
||||||
(let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])]
|
(let [experience-design-tool (dm/get-in @form [:clean-data :experience-design-tool])]
|
||||||
|
@ -142,83 +239,122 @@
|
||||||
(swap! form d/dissoc-in [:data :role-other])
|
(swap! form d/dissoc-in [:data :role-other])
|
||||||
(swap! form d/dissoc-in [:errors :role-other])))))]
|
(swap! form d/dissoc-in [:errors :role-other])))))]
|
||||||
|
|
||||||
[:& step-container {:form form :step 4 :on-next on-next :on-prev on-prev}
|
(if new-css-system
|
||||||
[:h3 (tr "questions.role")]
|
[:& step-container {:form form :step 4 :on-next on-next :on-prev on-prev}
|
||||||
[:& fm/radio-buttons {:options [{:label (tr "questions.designer") :value "designer"}
|
[:h3 {:class (stl/css :modal-subtitle)} (tr "questions.role")]
|
||||||
{:label (tr "questions.developer") :value "developer"}
|
[:& fm/radio-buttons {:options [{:label (tr "questions.designer") :value "designer"}
|
||||||
{:label (tr "questions.manager") :value "manager"}
|
{:label (tr "questions.developer") :value "developer"}
|
||||||
{:label (tr "questions.founder") :value "founder"}
|
{:label (tr "questions.manager") :value "manager"}
|
||||||
{:label (tr "questions.marketing") :value "marketing"}
|
{:label (tr "questions.founder") :value "founder"}
|
||||||
{:label (tr "questions.student-teacher") :value "student-teacher"}
|
{:label (tr "questions.marketing") :value "marketing"}
|
||||||
{:label (tr "questions.other") :value "other"}]
|
{:label (tr "questions.student-teacher") :value "student-teacher"}
|
||||||
:name :role
|
{:label (tr "questions.other") :value "other"}]
|
||||||
:on-change on-role-change}]
|
:name :role
|
||||||
[:div.other
|
:on-change on-role-change}]
|
||||||
[:label (tr "questions.other")]
|
[:& fm/input {:name :role-other :label "" :placeholder (tr "questions.other") :disabled (not= role "other")}]
|
||||||
[:& fm/input {:name :role-other :label (tr "questions.other") :disabled (not= role "other")}]]
|
|
||||||
|
|
||||||
[:h3 (tr "questions.team-size")]
|
[:div {:class (stl/css :modal-question)}
|
||||||
[:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "team-size" :disabled true}
|
[:h3 {:class (stl/css :modal-subtitle)} (tr "questions.team-size")]
|
||||||
{:label (tr "questions.more-than-50") :value "more-than-50" :key "more-than-50"}
|
[:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "team-size" :disabled true}
|
||||||
{:label (tr "questions.31-50") :value "31-50" :key "31-50"}
|
{:label (tr "questions.more-than-50") :value "more-than-50" :key "more-than-50"}
|
||||||
{:label (tr "questions.11-30") :value "11-30" :key "11-30"}
|
{:label (tr "questions.31-50") :value "31-50" :key "31-50"}
|
||||||
{:label (tr "questions.2-10") :value "2-10" :key "2-10"}
|
{:label (tr "questions.11-30") :value "11-30" :key "11-30"}
|
||||||
{:label (tr "questions.freelancer") :value "freelancer" :key "freelancer"}
|
{:label (tr "questions.2-10") :value "2-10" :key "2-10"}
|
||||||
{:label (tr "questions.personal-project") :value "personal-project" :key "personal-project"}]
|
{:label (tr "questions.freelancer") :value "freelancer" :key "freelancer"}
|
||||||
:default ""
|
{:label (tr "questions.personal-project") :value "personal-project" :key "personal-project"}]
|
||||||
:name :team-size}]]))
|
:default ""
|
||||||
|
:name :team-size}]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:& step-container {:form form :step 4 :on-next on-next :on-prev on-prev}
|
||||||
|
[:h3 (tr "questions.role")]
|
||||||
|
[:& fm/radio-buttons {:options [{:label (tr "questions.designer") :value "designer"}
|
||||||
|
{:label (tr "questions.developer") :value "developer"}
|
||||||
|
{:label (tr "questions.manager") :value "manager"}
|
||||||
|
{:label (tr "questions.founder") :value "founder"}
|
||||||
|
{:label (tr "questions.marketing") :value "marketing"}
|
||||||
|
{:label (tr "questions.student-teacher") :value "student-teacher"}
|
||||||
|
{:label (tr "questions.other") :value "other"}]
|
||||||
|
:name :role
|
||||||
|
:on-change on-role-change}]
|
||||||
|
[:div.other
|
||||||
|
[:label (tr "questions.other")]
|
||||||
|
[:& fm/input {:name :role-other :label (tr "questions.other") :disabled (not= role "other")}]]
|
||||||
|
|
||||||
|
[:h3 (tr "questions.team-size")]
|
||||||
|
[:& fm/select {:options [{:label (tr "questions.select-option") :value "" :key "team-size" :disabled true}
|
||||||
|
{:label (tr "questions.more-than-50") :value "more-than-50" :key "more-than-50"}
|
||||||
|
{:label (tr "questions.31-50") :value "31-50" :key "31-50"}
|
||||||
|
{:label (tr "questions.11-30") :value "11-30" :key "11-30"}
|
||||||
|
{:label (tr "questions.2-10") :value "2-10" :key "2-10"}
|
||||||
|
{:label (tr "questions.freelancer") :value "freelancer" :key "freelancer"}
|
||||||
|
{:label (tr "questions.personal-project") :value "personal-project" :key "personal-project"}]
|
||||||
|
:default ""
|
||||||
|
:name :team-size}]])))
|
||||||
|
|
||||||
(mf/defc questions
|
(mf/defc questions
|
||||||
[{:keys []}]
|
[{:keys []}]
|
||||||
(let [container (mf/use-ref)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
container (mf/use-ref)
|
||||||
step (mf/use-state 1)
|
step (mf/use-state 1)
|
||||||
clean-data (mf/use-state {})
|
clean-data (mf/use-state {})
|
||||||
|
|
||||||
;; Forms are initialized here because we can go back and forth between the steps
|
;; Forms are initialized here because we can go back and forth between the steps
|
||||||
;; and we want to keep the filled info
|
;; and we want to keep the filled info
|
||||||
step-1-form (fm/use-form
|
step-1-form (fm/use-form
|
||||||
:initial {}
|
:initial {}
|
||||||
:spec ::questions-form-step-1)
|
:spec ::questions-form-step-1)
|
||||||
step-2-form (fm/use-form
|
step-2-form (fm/use-form
|
||||||
:initial {}
|
:initial {}
|
||||||
:spec ::questions-form-step-2)
|
:spec ::questions-form-step-2)
|
||||||
step-3-form (fm/use-form
|
step-3-form (fm/use-form
|
||||||
:initial {}
|
:initial {}
|
||||||
:validators [step-3-form-validator]
|
:validators [step-3-form-validator]
|
||||||
:spec ::questions-form-step-3)
|
:spec ::questions-form-step-3)
|
||||||
|
|
||||||
step-4-form (fm/use-form
|
step-4-form (fm/use-form
|
||||||
:initial {}
|
:initial {}
|
||||||
:validators [step-4-form-validator]
|
:validators [step-4-form-validator]
|
||||||
:spec ::questions-form-step-4)
|
:spec ::questions-form-step-4)
|
||||||
|
|
||||||
on-next
|
on-next
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [form]
|
(fn [form]
|
||||||
(swap! step inc)
|
(swap! step inc)
|
||||||
(swap! clean-data merge (:clean-data @form))))
|
(swap! clean-data merge (:clean-data @form))))
|
||||||
|
|
||||||
on-prev
|
on-prev
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn []
|
(fn []
|
||||||
(swap! step dec)))
|
(swap! step dec)))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps @clean-data)
|
(mf/deps @clean-data)
|
||||||
(fn [form]
|
(fn [form]
|
||||||
(let [questionnaire (merge @clean-data (:clean-data @form))]
|
(let [questionnaire (merge @clean-data (:clean-data @form))]
|
||||||
(reset! clean-data questionnaire)
|
(reset! clean-data questionnaire)
|
||||||
(st/emit! (du/mark-questions-as-answered questionnaire)))))]
|
(st/emit! (du/mark-questions-as-answered questionnaire)))))]
|
||||||
|
|
||||||
[:div.modal-wrapper.questions-form
|
(if new-css-system
|
||||||
[:div.modal-overlay
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-container.onboarding.onboarding-v2 {:ref container}
|
[:div {:class (stl/css :modal-container)
|
||||||
[:img.deco.left {:src "images/deco-left.png" :border 0}]
|
:ref container}
|
||||||
[:img.deco.right {:src "images/deco-right.png" :border 0}]
|
|
||||||
[:div.signup-questions
|
|
||||||
(case @step
|
(case @step
|
||||||
1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}]
|
1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}]
|
||||||
2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}]
|
2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}]
|
||||||
3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}]
|
3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}]
|
||||||
4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form}])]]]]))
|
4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form}])]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-wrapper.questions-form
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.onboarding.onboarding-v2 {:ref container}
|
||||||
|
[:img.deco.left {:src "images/deco-left.png" :border 0}]
|
||||||
|
[:img.deco.right {:src "images/deco-right.png" :border 0}]
|
||||||
|
[:div.signup-questions
|
||||||
|
(case @step
|
||||||
|
1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}]
|
||||||
|
2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}]
|
||||||
|
3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}]
|
||||||
|
4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form}])]]]])))
|
||||||
|
|
72
frontend/src/app/main/ui/onboarding/questions.scss
Normal file
72
frontend/src/app/main/ui/onboarding/questions.scss
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
min-width: $s-512;
|
||||||
|
position: relative;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP CONTAINER
|
||||||
|
.paginator {
|
||||||
|
@include titleTipography;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-8;
|
||||||
|
right: $s-8;
|
||||||
|
padding: $s-4;
|
||||||
|
border-radius: $br-6;
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
margin-top: $s-32;
|
||||||
|
}
|
||||||
|
.next-button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prev-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 1
|
||||||
|
|
||||||
|
.header-image {
|
||||||
|
height: auto;
|
||||||
|
width: $s-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
@include bigTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
margin: $s-32 0 $s-8 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-subtitle {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP-2
|
||||||
|
|
||||||
|
.modal-text {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-question {
|
||||||
|
@include flexColumn;
|
||||||
|
margin-top: $s-32;
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.onboarding.team-choice
|
(ns app.main.ui.onboarding.team-choice
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.main.data.dashboard :as dd]
|
[app.main.data.dashboard :as dd]
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
[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.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]]
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
|
@ -28,31 +30,64 @@
|
||||||
|
|
||||||
(mf/defc team-modal-right
|
(mf/defc team-modal-right
|
||||||
[]
|
[]
|
||||||
[:div.team-right
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
|
||||||
[:h2.subtitle (tr "onboarding.team-modal.create-team")]
|
(if new-css-system
|
||||||
[:p.info (tr "onboarding.team-modal.create-team-desc")]
|
|
||||||
[:ul.team-features
|
[:div {:class (stl/css :modal-right)}
|
||||||
[:li.feature
|
[:h2 {:class (stl/css :modal-subtitle)}
|
||||||
[:span.icon i/file-html]
|
(tr "onboarding.team-modal.create-team")]
|
||||||
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-1")]]
|
[:p {:class (stl/css :modal-text)}
|
||||||
[:li.feature
|
(tr "onboarding.team-modal.create-team-desc")]
|
||||||
[:span.icon i/pointer-inner]
|
[:ul {:class (stl/css :team-features)}
|
||||||
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-2")]]
|
[:li {:class (stl/css :feature)}
|
||||||
[:li.feature
|
[:span {:class (stl/css :icon)} i/document-refactor]
|
||||||
[:span.icon i/tree]
|
[:p {:class (stl/css :modal-text)}
|
||||||
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-3")]]
|
(tr "onboarding.team-modal.create-team-feature-1")]]
|
||||||
[:li.feature
|
[:li {:class (stl/css :feature)}
|
||||||
[:span.icon i/user]
|
[:span {:class (stl/css :icon)} i/move-refactor]
|
||||||
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-4")]]
|
[:p {:class (stl/css :modal-text)}
|
||||||
[:li.feature
|
(tr "onboarding.team-modal.create-team-feature-2")]]
|
||||||
[:span.icon i/tick]
|
[:li {:class (stl/css :feature)}
|
||||||
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-5")]]]])
|
[:span {:class (stl/css :icon)} i/tree-refactor]
|
||||||
|
[:p {:class (stl/css :modal-text)}
|
||||||
|
(tr "onboarding.team-modal.create-team-feature-3")]]
|
||||||
|
[:li {:class (stl/css :feature)}
|
||||||
|
[:span {:class (stl/css :icon)} i/user-refactor]
|
||||||
|
[:p {:class (stl/css :modal-text)}
|
||||||
|
(tr "onboarding.team-modal.create-team-feature-4")]]
|
||||||
|
[:li {:class (stl/css :feature)}
|
||||||
|
[:span {:class (stl/css :icon)} i/tick-refactor]
|
||||||
|
[:p {:class (stl/css :modal-text)}
|
||||||
|
(tr "onboarding.team-modal.create-team-feature-5")]]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div.team-right
|
||||||
|
[:h2.subtitle (tr "onboarding.team-modal.create-team")]
|
||||||
|
[:p.info (tr "onboarding.team-modal.create-team-desc")]
|
||||||
|
[:ul.team-features
|
||||||
|
[:li.feature
|
||||||
|
[:span.icon i/file-html]
|
||||||
|
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-1")]]
|
||||||
|
[:li.feature
|
||||||
|
[:span.icon i/pointer-inner]
|
||||||
|
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-2")]]
|
||||||
|
[:li.feature
|
||||||
|
[:span.icon i/tree]
|
||||||
|
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-3")]]
|
||||||
|
[:li.feature
|
||||||
|
[:span.icon i/user]
|
||||||
|
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-4")]]
|
||||||
|
[:li.feature
|
||||||
|
[:span.icon i/tick]
|
||||||
|
[:p.feature-txt (tr "onboarding.team-modal.create-team-feature-5")]]]])))
|
||||||
|
|
||||||
(mf/defc onboarding-team-modal
|
(mf/defc onboarding-team-modal
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :onboarding-team}
|
::mf/register-as :onboarding-team}
|
||||||
[]
|
[]
|
||||||
(let [form (fm/use-form :spec ::team-form
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
form (fm/use-form :spec ::team-form
|
||||||
:initial {}
|
:initial {}
|
||||||
:validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
|
:validators [(fm/validate-not-empty :name (tr "auth.name.not-all-space"))
|
||||||
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))])
|
(fm/validate-length :name fm/max-length-allowed (tr "auth.name.too-long"))])
|
||||||
|
@ -73,36 +108,77 @@
|
||||||
:step 1}))))
|
:step 1}))))
|
||||||
|
|
||||||
teams (mf/deref refs/teams)]
|
teams (mf/deref refs/teams)]
|
||||||
(if (< (count teams) 2)
|
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.onboarding-team.animated.fadeIn
|
(if (< (count teams) 2)
|
||||||
[:div.team-left
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:h2.title (tr "onboarding.team-modal.create-team")]
|
[:div.animated.fadeIn {:class (stl/css :modal-container)}
|
||||||
[:p.info (tr "onboarding.choice.team-up.create-team-desc")]
|
[:div {:class (stl/css :modal-left)}
|
||||||
[:& fm/form {:form form
|
[:div {:class (stl/css :first-block)}
|
||||||
:on-submit on-submit}
|
[:h2 {:class (stl/css :modal-title)}
|
||||||
[:& fm/input {:type "text"
|
(tr "onboarding.team-modal.create-team")]
|
||||||
:name :name
|
[:p {:class (stl/css :modal-text)}
|
||||||
:label (tr "onboarding.choice.team-up.create-team-placeholder")}]
|
(tr "onboarding.choice.team-up.create-team-desc")]
|
||||||
|
[:& fm/form {:form form
|
||||||
|
:class (stl/css :modal-form)
|
||||||
|
:on-submit on-submit}
|
||||||
|
|
||||||
[:& fm/submit-button*
|
[:& fm/input {:type "text"
|
||||||
{:label (tr "onboarding.choice.team-up.continue-creating-team")}]]
|
:class (stl/css :team-name-input)
|
||||||
|
:name :name
|
||||||
|
:placeholder "Team name"
|
||||||
|
:label (tr "onboarding.choice.team-up.create-team-placeholder")}]
|
||||||
|
|
||||||
[:h2.title (tr "onboarding.choice.team-up.start-without-a-team")]
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:p.info (tr "onboarding.choice.team-up.start-without-a-team-description")]
|
[:& fm/submit-button*
|
||||||
|
{:className (stl/css :accept-button)
|
||||||
|
:label (tr "onboarding.choice.team-up.continue-creating-team")}]]]]
|
||||||
|
[:div {:class (stl/css :second-block)}
|
||||||
|
[:h2 {:class (stl/css :modal-title)}
|
||||||
|
(tr "onboarding.choice.team-up.start-without-a-team")]
|
||||||
|
[:p {:class (stl/css :modal-text)}
|
||||||
|
(tr "onboarding.choice.team-up.start-without-a-team-description")]
|
||||||
|
|
||||||
[:div
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:button.btn-primary.btn-large {:on-click on-skip} (tr "onboarding.choice.team-up.continue-without-a-team")]]]
|
[:button {:class (stl/css :accept-button)
|
||||||
[:& team-modal-right]
|
:on-click on-skip}
|
||||||
[:div.paginator "1/2"]
|
(tr "onboarding.choice.team-up.continue-without-a-team")]]]]
|
||||||
|
[:& team-modal-right]
|
||||||
|
[:div {:class (stl/css :paginator)} "1/2"]]]
|
||||||
|
|
||||||
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
(st/emit! (modal/hide)))
|
||||||
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
|
||||||
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
|
||||||
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]
|
|
||||||
|
|
||||||
(st/emit! (modal/hide)))))
|
|
||||||
|
(if (< (count teams) 2)
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.onboarding-team.animated.fadeIn
|
||||||
|
[:div.team-left
|
||||||
|
[:h2.title (tr "onboarding.team-modal.create-team")]
|
||||||
|
[:p.info (tr "onboarding.choice.team-up.create-team-desc")]
|
||||||
|
[:& fm/form {:form form
|
||||||
|
:on-submit on-submit}
|
||||||
|
[:& fm/input {:type "text"
|
||||||
|
:name :name
|
||||||
|
:label (tr "onboarding.choice.team-up.create-team-placeholder")}]
|
||||||
|
|
||||||
|
[:& fm/submit-button*
|
||||||
|
{:label (tr "onboarding.choice.team-up.continue-creating-team")}]]
|
||||||
|
|
||||||
|
[:h2.title (tr "onboarding.choice.team-up.start-without-a-team")]
|
||||||
|
[:p.info (tr "onboarding.choice.team-up.start-without-a-team-description")]
|
||||||
|
|
||||||
|
[:div
|
||||||
|
[:button.btn-primary.btn-large {:on-click on-skip} (tr "onboarding.choice.team-up.continue-without-a-team")]]]
|
||||||
|
[:& team-modal-right]
|
||||||
|
[:div.paginator "1/2"]
|
||||||
|
|
||||||
|
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
||||||
|
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
||||||
|
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
||||||
|
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]
|
||||||
|
|
||||||
|
(st/emit! (modal/hide))))))
|
||||||
|
|
||||||
(defn get-available-roles
|
(defn get-available-roles
|
||||||
[]
|
[]
|
||||||
|
@ -121,14 +197,15 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :onboarding-team-invitations}
|
::mf/register-as :onboarding-team-invitations}
|
||||||
[{:keys [name] :as props}]
|
[{:keys [name] :as props}]
|
||||||
(let [initial (mf/use-memo (constantly
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
initial (mf/use-memo (constantly
|
||||||
{:role "editor"
|
{:role "editor"
|
||||||
:name name}))
|
:name name}))
|
||||||
form (fm/use-form :spec ::invite-form
|
form (fm/use-form :spec ::invite-form
|
||||||
:initial initial)
|
:initial initial)
|
||||||
params (:clean-data @form)
|
params (:clean-data @form)
|
||||||
emails (:emails params)
|
emails (:emails params)
|
||||||
|
|
||||||
roles (mf/use-memo #(get-available-roles))
|
roles (mf/use-memo #(get-available-roles))
|
||||||
|
|
||||||
on-success
|
on-success
|
||||||
|
@ -167,7 +244,7 @@
|
||||||
:on-error (partial on-error form)}
|
:on-error (partial on-error form)}
|
||||||
params (:clean-data @form)
|
params (:clean-data @form)
|
||||||
emails (:emails params)]
|
emails (:emails params)]
|
||||||
|
|
||||||
(st/emit! (if (> (count emails) 0)
|
(st/emit! (if (> (count emails) 0)
|
||||||
;; If the user is only inviting to itself we don't call to create-team-with-invitations
|
;; If the user is only inviting to itself we don't call to create-team-with-invitations
|
||||||
(dd/create-team-with-invitations (with-meta params mdata))
|
(dd/create-team-with-invitations (with-meta params mdata))
|
||||||
|
@ -178,7 +255,7 @@
|
||||||
:role (:role params)
|
:role (:role params)
|
||||||
:name name
|
:name name
|
||||||
:step 2})))))
|
:step 2})))))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [_]
|
(fn [_]
|
||||||
|
@ -188,49 +265,96 @@
|
||||||
(on-invite-now form)
|
(on-invite-now form)
|
||||||
(on-invite-later form)))))]
|
(on-invite-later form)))))]
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.onboarding-team-members.animated.fadeIn
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.team-left
|
[:div.animated.fadeIn {:class (stl/css :modal-container)}
|
||||||
[:h2.title (tr "onboarding.choice.team-up.invite-members")]
|
[:div {:class (stl/css :modal-left)}
|
||||||
[:p.info (tr "onboarding.choice.team-up.invite-members-info")]
|
[:h2 {:class (stl/css :modal-title)} (tr "onboarding.choice.team-up.invite-members")]
|
||||||
|
[:p {:class (stl/css :modal-text)} (tr "onboarding.choice.team-up.invite-members-info")]
|
||||||
|
|
||||||
[:& fm/form {:form form
|
[:div {:class (stl/css :modal-form)}
|
||||||
:on-submit on-submit}
|
[:& fm/form {:form form
|
||||||
[:div.invite-row
|
:on-submit on-submit}
|
||||||
[:div.role-wrapper
|
[:div {:class (stl/css :role-select)}
|
||||||
[:span.rol (tr "onboarding.choice.team-up.roles")]
|
[:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")]
|
||||||
[:& fm/select {:name :role :options roles}]]
|
[:& fm/select {:name :role :options roles}]]
|
||||||
|
|
||||||
[:& fm/multi-input {:type "email"
|
[:div {:class (stl/css :invitation-row)}
|
||||||
:name :emails
|
[:& fm/multi-input {:type "email"
|
||||||
:auto-focus? true
|
:name :emails
|
||||||
:trim true
|
:auto-focus? true
|
||||||
:valid-item-fn us/parse-email
|
:trim true
|
||||||
:caution-item-fn #{}
|
:valid-item-fn us/parse-email
|
||||||
:on-submit on-submit
|
:caution-item-fn #{}
|
||||||
:label (tr "modals.invite-member.emails")}]]
|
:label (tr "modals.invite-member.emails")
|
||||||
|
:on-submit on-submit}]]]
|
||||||
|
|
||||||
[:div.buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:button.btn-secondary.btn-large
|
[:button {:class (stl/css :back-button)
|
||||||
{:on-click #(st/emit! (modal/show {:type :onboarding-team})
|
:on-click #(st/emit! (modal/show {:type :onboarding-team})
|
||||||
(ptk/event ::ev/event {::ev/name "invite-members-back"
|
(ptk/event ::ev/event {::ev/name "invite-members-back"
|
||||||
::ev/origin "onboarding"
|
::ev/origin "onboarding"
|
||||||
:name name
|
:name name
|
||||||
:step 2}))}
|
:step 2}))}
|
||||||
(tr "labels.back")]
|
(tr "labels.back")]
|
||||||
[:& fm/submit-button*
|
|
||||||
{:label
|
|
||||||
(if (> (count emails) 0)
|
|
||||||
(tr "onboarding.choice.team-up.create-team-and-send-invites")
|
|
||||||
(tr "onboarding.choice.team-up.create-team-without-inviting"))}]]
|
|
||||||
[:div.skip-action
|
|
||||||
(tr "onboarding.choice.team-up.create-team-and-send-invites-description")]]]
|
|
||||||
[:& team-modal-right]
|
|
||||||
[:div.paginator "2/2"]
|
|
||||||
|
|
||||||
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
[:& fm/submit-button*
|
||||||
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
{:className (stl/css :accept-button)
|
||||||
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
:label
|
||||||
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]]))
|
(if (> (count emails) 0)
|
||||||
|
(tr "onboarding.choice.team-up.create-team-and-invite")
|
||||||
|
(tr "onboarding.choice.team-up.create-team-without-invite"))}]]
|
||||||
|
[:div {:class (stl/css :modal-hint)}
|
||||||
|
(tr "onboarding.choice.team-up.create-team-and-send-invites-description")]]]
|
||||||
|
|
||||||
|
[:& team-modal-right]
|
||||||
|
[:div {:class (stl/css :paginator)} "2/2"]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.onboarding-team-members.animated.fadeIn
|
||||||
|
[:div.team-left
|
||||||
|
[:h2.title (tr "onboarding.choice.team-up.invite-members")]
|
||||||
|
[:p.info (tr "onboarding.choice.team-up.invite-members-info")]
|
||||||
|
|
||||||
|
[:& fm/form {:form form
|
||||||
|
:on-submit on-submit}
|
||||||
|
[:div.invite-row
|
||||||
|
[:div.role-wrapper
|
||||||
|
[:span.rol (tr "onboarding.choice.team-up.roles")]
|
||||||
|
[:& fm/select {:name :role :options roles}]]
|
||||||
|
|
||||||
|
[:& fm/multi-input {:type "email"
|
||||||
|
:name :emails
|
||||||
|
:auto-focus? true
|
||||||
|
:trim true
|
||||||
|
:valid-item-fn us/parse-email
|
||||||
|
:caution-item-fn #{}
|
||||||
|
:on-submit on-submit
|
||||||
|
:label (tr "modals.invite-member.emails")}]]
|
||||||
|
|
||||||
|
[:div.buttons
|
||||||
|
[:button.btn-secondary.btn-large
|
||||||
|
{:on-click #(st/emit! (modal/show {:type :onboarding-team})
|
||||||
|
(ptk/event ::ev/event {::ev/name "invite-members-back"
|
||||||
|
::ev/origin "onboarding"
|
||||||
|
:name name
|
||||||
|
:step 2}))}
|
||||||
|
(tr "labels.back")]
|
||||||
|
[:& fm/submit-button*
|
||||||
|
{:label
|
||||||
|
(if (> (count emails) 0)
|
||||||
|
(tr "onboarding.choice.team-up.create-team-and-send-invites")
|
||||||
|
(tr "onboarding.choice.team-up.create-team-without-inviting"))}]]
|
||||||
|
[:div.skip-action
|
||||||
|
(tr "onboarding.choice.team-up.create-team-and-send-invites-description")]]]
|
||||||
|
[:& team-modal-right]
|
||||||
|
[:div.paginator "2/2"]
|
||||||
|
|
||||||
|
[:img.deco.square {:src "images/deco-square.svg" :border "0"}]
|
||||||
|
[:img.deco.circle {:src "images/deco-circle.svg" :border "0"}]
|
||||||
|
[:img.deco.line1 {:src "images/deco-line1.svg" :border "0"}]
|
||||||
|
[:img.deco.line2 {:src "images/deco-line2.svg" :border "0"}]]])))
|
||||||
|
|
||||||
|
|
||||||
|
|
145
frontend/src/app/main/ui/onboarding/team_choice.scss
Normal file
145
frontend/src/app/main/ui/onboarding/team_choice.scss
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
min-width: $s-712;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-left {
|
||||||
|
width: $s-356;
|
||||||
|
padding: $s-48 $s-28 $s-48 $s-48;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-block,
|
||||||
|
.second-block {
|
||||||
|
@include flexColumn;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-block {
|
||||||
|
margin-bottom: $s-72;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-right {
|
||||||
|
width: $s-356;
|
||||||
|
padding: $s-48;
|
||||||
|
background-color: var(--color-background-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
@include bigTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-subtitle {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
margin-bottom: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-text,
|
||||||
|
.modal-hint {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-text-foreground-color);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.modal-hint {
|
||||||
|
margin-top: $s-24;
|
||||||
|
}
|
||||||
|
.modal-form {
|
||||||
|
margin: $s-24 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-name-input {
|
||||||
|
@extend .input-element-label;
|
||||||
|
label {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
input {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-top: $s-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-select {
|
||||||
|
@include flexColumn;
|
||||||
|
.role-title {
|
||||||
|
@include titleTipography;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.invitation-row {
|
||||||
|
margin-top: $s-8;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paginator {
|
||||||
|
@include titleTipography;
|
||||||
|
position: absolute;
|
||||||
|
top: $s-8;
|
||||||
|
right: $s-8;
|
||||||
|
padding: $s-4;
|
||||||
|
border-radius: $br-6;
|
||||||
|
color: var(--color-foreground-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
justify-content: flex-start;
|
||||||
|
margin-top: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accept-button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-features {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-24;
|
||||||
|
margin-top: $s-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature {
|
||||||
|
@include flexRow;
|
||||||
|
gap: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
@include flexCenter;
|
||||||
|
height: $s-32;
|
||||||
|
width: $s-32;
|
||||||
|
border-radius: $br-circle;
|
||||||
|
background-color: var(--color-accent-primary);
|
||||||
|
svg {
|
||||||
|
@extend .button-icon;
|
||||||
|
stroke: var(--color-background-tertiary);
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,8 +44,7 @@
|
||||||
(fn [error]
|
(fn [error]
|
||||||
(js/console.log "error" error))
|
(js/console.log "error" error))
|
||||||
(fn []
|
(fn []
|
||||||
(reset! downloading? false)))))
|
(reset! downloading? false)))))]
|
||||||
]
|
|
||||||
|
|
||||||
[:div.template-item
|
[:div.template-item
|
||||||
[:div.template-item-content
|
[:div.template-item-content
|
||||||
|
|
0
frontend/src/app/main/ui/releases.scss
Normal file
0
frontend/src/app/main/ui/releases.scss
Normal file
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.access-tokens
|
(ns app.main.ui.settings.access-tokens
|
||||||
|
(: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.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
|
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
|
||||||
[app.main.ui.components.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]]
|
||||||
|
@ -49,7 +51,8 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :access-token}
|
::mf/register-as :access-token}
|
||||||
[]
|
[]
|
||||||
(let [form (fm/use-form
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
form (fm/use-form
|
||||||
:initial initial-data
|
:initial initial-data
|
||||||
:spec ::access-token-form
|
:spec ::access-token-form
|
||||||
:validators [name-validator
|
:validators [name-validator
|
||||||
|
@ -61,38 +64,38 @@
|
||||||
|
|
||||||
on-success
|
on-success
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps created)
|
(mf/deps created)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(let [message (tr "dashboard.access-tokens.create.success")]
|
(let [message (tr "dashboard.access-tokens.create.success")]
|
||||||
(st/emit! (du/fetch-access-tokens)
|
(st/emit! (du/fetch-access-tokens)
|
||||||
(dm/success message)
|
(dm/success message)
|
||||||
(reset! created? true)))))
|
(reset! created? true)))))
|
||||||
|
|
||||||
on-close
|
on-close
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps created)
|
(mf/deps created)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(reset! created? false)
|
(reset! created? false)
|
||||||
(st/emit! (modal/hide))))
|
(st/emit! (modal/hide))))
|
||||||
|
|
||||||
on-error
|
on-error
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (dm/error (tr "errors.generic"))
|
(st/emit! (dm/error (tr "errors.generic"))
|
||||||
(modal/hide))))
|
(modal/hide))))
|
||||||
|
|
||||||
on-submit
|
on-submit
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(fn [form]
|
(fn [form]
|
||||||
(let [cdata (:clean-data @form)
|
(let [cdata (:clean-data @form)
|
||||||
mdata {:on-success (partial on-success form)
|
mdata {:on-success (partial on-success form)
|
||||||
:on-error (partial on-error form)}
|
:on-error (partial on-error form)}
|
||||||
expiration (:expiration-date cdata)
|
expiration (:expiration-date cdata)
|
||||||
params (cond-> {:name (:name cdata)
|
params (cond-> {:name (:name cdata)
|
||||||
:perms (:perms cdata)}
|
:perms (:perms cdata)}
|
||||||
(not= "never" expiration) (assoc :expiration expiration))]
|
(not= "never" expiration) (assoc :expiration expiration))]
|
||||||
(st/emit! (du/create-access-token
|
(st/emit! (du/create-access-token
|
||||||
(with-meta params mdata))))))
|
(with-meta params mdata))))))
|
||||||
|
|
||||||
copy-token
|
copy-token
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -104,70 +107,143 @@
|
||||||
:content (tr "dashboard.access-tokens.copied-success")
|
:content (tr "dashboard.access-tokens.copied-success")
|
||||||
:timeout 1000}))))]
|
:timeout 1000}))))]
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.access-tokens-modal
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:& fm/form {:form form :on-submit on-submit}
|
[:div {:class (stl/css :modal-container)}
|
||||||
|
[:& fm/form {:form form :on-submit on-submit}
|
||||||
|
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:div.modal-header-title
|
[:h2 {:class (stl/css :modal-title)} (tr "modals.create-access-token.title")]
|
||||||
[:h2 (tr "modals.create-access-token.title")]]
|
|
||||||
|
|
||||||
[:div.modal-close-button
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
{:on-click on-close} i/close]]
|
:on-click on-close} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-content.generic-form
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:div.fields-container
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:div.fields-row
|
[:& fm/input {:type "text"
|
||||||
[:& fm/input {:type "text"
|
:auto-focus? true
|
||||||
:auto-focus? true
|
:form form
|
||||||
:form form
|
:name :name
|
||||||
:name :name
|
|
||||||
:disabled @created?
|
|
||||||
:label (tr "modals.create-access-token.name.label")
|
|
||||||
:placeholder (tr "modals.create-access-token.name.placeholder")}]]
|
|
||||||
|
|
||||||
[:div.fields-row
|
|
||||||
[:& fm/select {:options [{:label (tr "dashboard.access-tokens.expiration-never") :value "never" :key "never"}
|
|
||||||
{:label (tr "dashboard.access-tokens.expiration-30-days") :value "720h" :key "720h"}
|
|
||||||
{:label (tr "dashboard.access-tokens.expiration-60-days") :value "1440h" :key "1440h"}
|
|
||||||
{:label (tr "dashboard.access-tokens.expiration-90-days") :value "2160h" :key "2160h"}
|
|
||||||
{:label (tr "dashboard.access-tokens.expiration-180-days") :value "4320h" :key "4320h"}]
|
|
||||||
:label (tr "modals.create-access-token.expiration-date.label")
|
|
||||||
:default "never"
|
|
||||||
:disabled @created?
|
:disabled @created?
|
||||||
:name :expiration-date}]
|
:label (tr "modals.create-access-token.name.label")
|
||||||
(when @created?
|
:placeholder (tr "modals.create-access-token.name.placeholder")}]]
|
||||||
[:span.token-created-info
|
|
||||||
(if (:expires-at created)
|
|
||||||
(tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale}))
|
|
||||||
(tr "dashboard.access-tokens.token-will-not-expire"))])]
|
|
||||||
|
|
||||||
[:div.fields-row.access-token-created
|
[:div {:class (stl/css :fields-row)}
|
||||||
(when @created?
|
[:div {:class (stl/css :select-title)} (tr "modals.create-access-token.expiration-date.label")]
|
||||||
[:div.custom-input.with-icon
|
[:& fm/select {:options [{:label (tr "dashboard.access-tokens.expiration-never") :value "never" :key "never"}
|
||||||
[:input {:type "text"
|
{:label (tr "dashboard.access-tokens.expiration-30-days") :value "720h" :key "720h"}
|
||||||
:value (:token created "")
|
{:label (tr "dashboard.access-tokens.expiration-60-days") :value "1440h" :key "1440h"}
|
||||||
:placeholder (tr "modals.create-access-token.token")
|
{:label (tr "dashboard.access-tokens.expiration-90-days") :value "2160h" :key "2160h"}
|
||||||
:read-only true}]
|
{:label (tr "dashboard.access-tokens.expiration-180-days") :value "4320h" :key "4320h"}]
|
||||||
[:button.help-icon {:title (tr "modals.create-access-token.copy-token")
|
:default "never"
|
||||||
:on-click copy-token}
|
:disabled @created?
|
||||||
|
:name :expiration-date}]
|
||||||
|
(when @created?
|
||||||
|
[:span.token-created-info
|
||||||
|
(if (:expires-at created)
|
||||||
|
(tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale}))
|
||||||
|
(tr "dashboard.access-tokens.token-will-not-expire"))])]
|
||||||
|
|
||||||
i/copy]])]]]
|
[:div {:class (stl/css :fields-row)}
|
||||||
|
(when @created?
|
||||||
|
[:div {:class (stl/css :custon-input-wrapper)}
|
||||||
|
[:input {:type "text"
|
||||||
|
:value (:token created "")
|
||||||
|
:class (stl/css :custom-input-token)
|
||||||
|
:placeholder (tr "modals.create-access-token.token")
|
||||||
|
:read-only true}]
|
||||||
|
[:button {:title (tr "modals.create-access-token.copy-token")
|
||||||
|
:class (stl/css :copy-btn)
|
||||||
|
:on-click copy-token}
|
||||||
|
i/clipboard-refactor]])
|
||||||
|
#_(when @created?
|
||||||
|
[:button {:class (stl/css :copy-btn)
|
||||||
|
:title (tr "modals.create-access-token.copy-token")
|
||||||
|
:on-click copy-token}
|
||||||
|
[:span {:class (stl/css :token-value)}(:token created "")]
|
||||||
|
[:span {:class (stl/css :icon)}
|
||||||
|
i/clipboard-refactor]])]]
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:div.action-buttons
|
[:div {:class (stl/css :action-buttons)}
|
||||||
(if @created?
|
|
||||||
[:input.cancel-button
|
(if @created?
|
||||||
{:type "button"
|
[:input {:class (stl/css :cancel-button)
|
||||||
:value (tr "labels.close")
|
:type "button"
|
||||||
:on-click #(modal/hide!)}]
|
:value (tr "labels.close")
|
||||||
[:*
|
:on-click #(modal/hide!)}]
|
||||||
[:input.cancel-button
|
[:*
|
||||||
{:type "button"
|
[:input {:class (stl/css :cancel-button)
|
||||||
:value (tr "labels.cancel")
|
:type "button"
|
||||||
:on-click #(modal/hide!)}]
|
:value (tr "labels.cancel")
|
||||||
[:> fm/submit-button*
|
:on-click #(modal/hide!)}]
|
||||||
{:label (tr "modals.create-access-token.submit-label")}]])]]]]]))
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "modals.create-access-token.submit-label")}]])]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.access-tokens-modal
|
||||||
|
[:& fm/form {:form form :on-submit on-submit}
|
||||||
|
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 (tr "modals.create-access-token.title")]]
|
||||||
|
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click on-close} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content.generic-form
|
||||||
|
[:div.fields-container
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input {:type "text"
|
||||||
|
:auto-focus? true
|
||||||
|
:form form
|
||||||
|
:name :name
|
||||||
|
:disabled @created?
|
||||||
|
:label (tr "modals.create-access-token.name.label")
|
||||||
|
:placeholder (tr "modals.create-access-token.name.placeholder")}]]
|
||||||
|
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/select {:options [{:label (tr "dashboard.access-tokens.expiration-never") :value "never" :key "never"}
|
||||||
|
{:label (tr "dashboard.access-tokens.expiration-30-days") :value "720h" :key "720h"}
|
||||||
|
{:label (tr "dashboard.access-tokens.expiration-60-days") :value "1440h" :key "1440h"}
|
||||||
|
{:label (tr "dashboard.access-tokens.expiration-90-days") :value "2160h" :key "2160h"}
|
||||||
|
{:label (tr "dashboard.access-tokens.expiration-180-days") :value "4320h" :key "4320h"}]
|
||||||
|
:label (tr "modals.create-access-token.expiration-date.label")
|
||||||
|
:default "never"
|
||||||
|
:disabled @created?
|
||||||
|
:name :expiration-date}]
|
||||||
|
(when @created?
|
||||||
|
[:span.token-created-info
|
||||||
|
(if (:expires-at created)
|
||||||
|
(tr "dashboard.access-tokens.token-will-expire" (dt/format-date-locale (:expires-at created) {:locale locale}))
|
||||||
|
(tr "dashboard.access-tokens.token-will-not-expire"))])]
|
||||||
|
|
||||||
|
[:div.fields-row.access-token-created
|
||||||
|
(when @created?
|
||||||
|
[:div.custom-input.with-icon
|
||||||
|
[:input {:type "text"
|
||||||
|
:value (:token created "")
|
||||||
|
:placeholder (tr "modals.create-access-token.token")
|
||||||
|
:read-only true}]
|
||||||
|
[:button.help-icon {:title (tr "modals.create-access-token.copy-token")
|
||||||
|
:on-click copy-token}
|
||||||
|
i/copy]])]]]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
(if @created?
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.close")
|
||||||
|
:on-click #(modal/hide!)}]
|
||||||
|
[:*
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click #(modal/hide!)}]
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "modals.create-access-token.submit-label")}]])]]]]])))
|
||||||
|
|
||||||
(mf/defc access-tokens-hero
|
(mf/defc access-tokens-hero
|
||||||
[]
|
[]
|
||||||
|
|
82
frontend/src/app/main/ui/settings/access_tokens.scss
Normal file
82
frontend/src/app/main/ui/settings/access_tokens.scss
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
min-width: $s-408;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-24;
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
|
||||||
|
.fields-row {
|
||||||
|
@include flexColumn;
|
||||||
|
.select-title {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.custon-input-wrapper {
|
||||||
|
@include flexRow;
|
||||||
|
border-radius: $br-8;
|
||||||
|
height: $s-32;
|
||||||
|
background-color: var(--input-background-color);
|
||||||
|
}
|
||||||
|
.custom-input-token {
|
||||||
|
@extend .input-element;
|
||||||
|
margin: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border: $s-1 solid var(--input-border-color-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.token-value {
|
||||||
|
@include textEllipsis;
|
||||||
|
@include titleTipography;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
.copy-btn {
|
||||||
|
@include flexCenter;
|
||||||
|
@extend .button-secondary;
|
||||||
|
height: $s-28;
|
||||||
|
width: $s-28;
|
||||||
|
svg {
|
||||||
|
@extend .button-icon-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.change-email
|
(ns app.main.ui.settings.change-email
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dma]
|
[app.common.data.macros :as dma]
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
[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.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.messages :as msgs]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -74,7 +76,8 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :change-email}
|
::mf/register-as :change-email}
|
||||||
[]
|
[]
|
||||||
(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 ::email-change-form
|
form (fm/use-form :spec ::email-change-form
|
||||||
:validators [email-equality]
|
:validators [email-equality]
|
||||||
:initial profile)
|
:initial profile)
|
||||||
|
@ -85,7 +88,7 @@
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(mf/deps profile)
|
(mf/deps profile)
|
||||||
(partial on-submit profile))
|
(partial on-submit profile))
|
||||||
|
|
||||||
on-email-change
|
on-email-change
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(fn [_ _]
|
(fn [_ _]
|
||||||
|
@ -96,41 +99,81 @@
|
||||||
(when (and different-emails-error? (= email-1 email-2))
|
(when (and different-emails-error? (= email-1 email-2))
|
||||||
(swap! form d/dissoc-in [:errors :email-2])))))]
|
(swap! form d/dissoc-in [:errors :email-2])))))]
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.change-email-modal.form-container
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:& fm/form {:form form
|
[:div {:class (stl/css :modal-container)}
|
||||||
:on-submit on-submit}
|
[:& fm/form {:form form
|
||||||
|
:on-submit on-submit}
|
||||||
|
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:div.modal-header-title
|
[:h2 {:class (stl/css :modal-title)
|
||||||
[:h2 {:data-test "change-email-title"}
|
:data-test "change-email-title"}
|
||||||
(tr "modals.change-email.title")]]
|
(tr "modals.change-email.title")]
|
||||||
[:div.modal-close-button
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
{:on-click on-close} i/close]]
|
:on-click on-close} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:& msgs/inline-banner
|
[:& msgs/inline-banner
|
||||||
{:type :info
|
{:type :info
|
||||||
:content (tr "modals.change-email.info" (:email profile))}]
|
:content (tr "modals.change-email.info" (:email profile))}]
|
||||||
|
|
||||||
[:div.fields-container
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:div.fields-row
|
[:& fm/input {:type "email"
|
||||||
[:& fm/input {:type "email"
|
:name :email-1
|
||||||
:name :email-1
|
:label (tr "modals.change-email.new-email")
|
||||||
:label (tr "modals.change-email.new-email")
|
:trim true
|
||||||
:trim true
|
:on-change-value on-email-change}]]
|
||||||
:on-change-value on-email-change}]]
|
|
||||||
[:div.fields-row
|
|
||||||
[:& fm/input {:type "email"
|
|
||||||
:name :email-2
|
|
||||||
:label (tr "modals.change-email.confirm-email")
|
|
||||||
:trim true
|
|
||||||
:on-change-value on-email-change}]]]]
|
|
||||||
|
|
||||||
[:div.modal-footer
|
[:div {:class (stl/css :fields-row)}
|
||||||
[:div.action-buttons {:data-test "change-email-submit"}
|
[:& fm/input {:type "email"
|
||||||
[:> fm/submit-button*
|
:name :email-2
|
||||||
{:label (tr "modals.change-email.submit")}]]]]]]))
|
:label (tr "modals.change-email.confirm-email")
|
||||||
|
:trim true
|
||||||
|
:on-change-value on-email-change}]]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:div {:class (stl/css :action-buttons)
|
||||||
|
:data-test "change-email-submit"}
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "modals.change-email.submit")}]]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.change-email-modal.form-container
|
||||||
|
[:& fm/form {:form form
|
||||||
|
:on-submit on-submit}
|
||||||
|
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 {:data-test "change-email-title"}
|
||||||
|
(tr "modals.change-email.title")]]
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click on-close} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content
|
||||||
|
[:& msgs/inline-banner
|
||||||
|
{:type :info
|
||||||
|
:content (tr "modals.change-email.info" (:email profile))}]
|
||||||
|
|
||||||
|
[:div.fields-container
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input {:type "email"
|
||||||
|
:name :email-1
|
||||||
|
:label (tr "modals.change-email.new-email")
|
||||||
|
:trim true
|
||||||
|
:on-change-value on-email-change}]]
|
||||||
|
[:div.fields-row
|
||||||
|
[:& fm/input {:type "email"
|
||||||
|
:name :email-2
|
||||||
|
:label (tr "modals.change-email.confirm-email")
|
||||||
|
:trim true
|
||||||
|
:on-change-value on-email-change}]]]]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons {:data-test "change-email-submit"}
|
||||||
|
[:> fm/submit-button*
|
||||||
|
{:label (tr "modals.change-email.submit")}]]]]]])
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
53
frontend/src/app/main/ui/settings/change_email.scss
Normal file
53
frontend/src/app/main/ui/settings/change_email.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
|
||||||
|
|
||||||
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
min-width: $s-408;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
gap: $s-24;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
|
||||||
|
.fields-row {
|
||||||
|
@include flexColumn;
|
||||||
|
.select-title {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
}
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,11 +5,13 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.settings.delete-account
|
(ns app.main.ui.settings.delete-account
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[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.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.messages :as msgs]
|
[app.main.ui.messages :as msgs]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
|
@ -27,33 +29,62 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :delete-account}
|
::mf/register-as :delete-account}
|
||||||
[]
|
[]
|
||||||
(let [on-close
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
on-close
|
||||||
(mf/use-callback #(st/emit! (modal/hide)))
|
(mf/use-callback #(st/emit! (modal/hide)))
|
||||||
|
|
||||||
on-accept
|
on-accept
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
#(st/emit! (modal/hide)
|
#(st/emit! (modal/hide)
|
||||||
(du/request-account-deletion
|
(du/request-account-deletion
|
||||||
(with-meta {} {:on-error on-error}))))]
|
(with-meta {} {:on-error on-error}))))]
|
||||||
|
|
||||||
[:div.modal-overlay
|
(if new-css-system
|
||||||
[:div.modal-container.change-email-modal
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.modal-header
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:div.modal-header-title
|
|
||||||
[:h2 (tr "modals.delete-account.title")]]
|
|
||||||
[:div.modal-close-button
|
|
||||||
{:on-click on-close} i/close]]
|
|
||||||
|
|
||||||
[:div.modal-content
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:& msgs/inline-banner
|
|
||||||
{:type :warning
|
|
||||||
:content (tr "modals.delete-account.info")}]]
|
|
||||||
|
|
||||||
[:div.modal-footer
|
[:h2 {:class (stl/css :modal-title)} (tr "modals.delete-account.title")]
|
||||||
[:div.action-buttons
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
[:button.btn-danger.btn-large {:on-click on-accept
|
:on-click on-close} i/close-refactor]]
|
||||||
:data-test "delete-account-btn"}
|
|
||||||
(tr "modals.delete-account.confirm")]
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:button.btn-secondary.btn-large {:on-click on-close}
|
[:& msgs/inline-banner
|
||||||
(tr "modals.delete-account.cancel")]]]]]))
|
{:type :warning
|
||||||
|
:content (tr "modals.delete-account.info")}]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :modal-footer)}
|
||||||
|
[:div {:class (stl/css :action-buttons)}
|
||||||
|
[:button {:class (stl/css :cancel-button)
|
||||||
|
:on-click on-close}
|
||||||
|
(tr "modals.delete-account.cancel")]
|
||||||
|
[:button {:class (stl/css-case :accept-button true
|
||||||
|
:danger true)
|
||||||
|
:on-click on-accept
|
||||||
|
:data-test "delete-account-btn"}
|
||||||
|
(tr "modals.delete-account.confirm")]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[:div.modal-overlay
|
||||||
|
[:div.modal-container.change-email-modal
|
||||||
|
[:div.modal-header
|
||||||
|
[:div.modal-header-title
|
||||||
|
[:h2 (tr "modals.delete-account.title")]]
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click on-close} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content
|
||||||
|
[:& msgs/inline-banner
|
||||||
|
{:type :warning
|
||||||
|
:content (tr "modals.delete-account.info")}]]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:button.btn-danger.btn-large {:on-click on-accept
|
||||||
|
:data-test "delete-account-btn"}
|
||||||
|
(tr "modals.delete-account.confirm")]
|
||||||
|
[:button.btn-secondary.btn-large {:on-click on-close}
|
||||||
|
(tr "modals.delete-account.cancel")]]]]])))
|
||||||
|
|
||||||
|
|
57
frontend/src/app/main/ui/settings/delete_account.scss
Normal file
57
frontend/src/app/main/ui/settings/delete_account.scss
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
min-width: $s-408;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
@include titleTipography;
|
||||||
|
gap: $s-24;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
|
||||||
|
.fields-row {
|
||||||
|
@include flexColumn;
|
||||||
|
.select-title {
|
||||||
|
@include titleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-button {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,6 @@
|
||||||
(set-current-section :register-validate))]
|
(set-current-section :register-validate))]
|
||||||
(mf/with-effect []
|
(mf/with-effect []
|
||||||
(swap! storage assoc :redirect-url uri))
|
(swap! storage assoc :redirect-url uri))
|
||||||
|
|
||||||
[:div.modal-overlay
|
[:div.modal-overlay
|
||||||
[:div.modal-container.login-register
|
[:div.modal-container.login-register
|
||||||
[:div.title
|
[:div.title
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.file-name {
|
.file-name {
|
||||||
@include titleBigTipography;
|
@include medTitleTipography;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
color: var(--title-foreground-color-hover);
|
color: var(--title-foreground-color-hover);
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,7 @@
|
||||||
grid-column: span 3;
|
grid-column: span 3;
|
||||||
grid-template-columns: repeat(auto-fill, minmax($s-160, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax($s-160, 1fr));
|
||||||
grid-gap: $s-24;
|
grid-gap: $s-24;
|
||||||
font-size: $fs12;
|
font-size: $fs-12;
|
||||||
margin-top: $s-16;
|
margin-top: $s-16;
|
||||||
|
|
||||||
.libraries-updates-item {
|
.libraries-updates-item {
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.workspace.nudge
|
(ns app.main.ui.workspace.nudge
|
||||||
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
[app.main.ui.components.numeric-input :refer [numeric-input*]]
|
||||||
|
[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]]
|
||||||
|
@ -30,7 +32,8 @@
|
||||||
{::mf/register modal/components
|
{::mf/register modal/components
|
||||||
::mf/register-as :nudge-option}
|
::mf/register-as :nudge-option}
|
||||||
[]
|
[]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
profile (mf/deref refs/profile)
|
||||||
nudge (or (get-in profile [:props :nudge]) {:big 10 :small 1})
|
nudge (or (get-in profile [:props :nudge]) {:big 10 :small 1})
|
||||||
update-big (mf/use-fn #(st/emit! (dw/update-nudge {:big %})))
|
update-big (mf/use-fn #(st/emit! (dw/update-nudge {:big %})))
|
||||||
update-small (mf/use-fn #(st/emit! (dw/update-nudge {:small %})))
|
update-small (mf/use-fn #(st/emit! (dw/update-nudge {:small %})))
|
||||||
|
@ -40,21 +43,45 @@
|
||||||
(->> (events/listen js/document EventType.KEYDOWN on-keydown)
|
(->> (events/listen js/document EventType.KEYDOWN on-keydown)
|
||||||
(partial events/unlistenByKey)))
|
(partial events/unlistenByKey)))
|
||||||
|
|
||||||
[:div.nudge-modal-overlay
|
(if new-css-system
|
||||||
[:div.nudge-modal-container
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
[:div.nudge-modal-header
|
[:div {:class (stl/css :modal-container)}
|
||||||
[:p.nudge-modal-title (tr "modals.nudge-title")]
|
[:div {:class (stl/css :modal-header)}
|
||||||
[:button.modal-close-button {:on-click on-close} i/close]]
|
[:h2 {:class (stl/css :modal-title)} (tr "modals.nudge-title")]
|
||||||
[:div.nudge-modal-body
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
[:div.input-wrapper
|
:on-click on-close} i/close-refactor]]
|
||||||
[:span
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:p.nudge-subtitle (tr "modals.small-nudge")]
|
[:div {:class (stl/css :input-wrapper)}
|
||||||
[:> numeric-input* {:min 0.01
|
[:label {:class (stl/css :modal-msg)
|
||||||
:value (:small nudge)
|
:for "nudge-small"} (tr "modals.small-nudge")]
|
||||||
:on-change update-small}]]]
|
[:> numeric-input* {:min 0.01
|
||||||
[:div.input-wrapper
|
:id "nudge-small"
|
||||||
[:span
|
:value (:small nudge)
|
||||||
[:p.nudge-subtitle (tr "modals.big-nudge")]
|
:on-change update-small}]]
|
||||||
[:> numeric-input* {:min 0.01
|
[:div {:class (stl/css :input-wrapper)}
|
||||||
:value (:big nudge)
|
[:label {:class (stl/css :modal-msg)
|
||||||
:on-change update-big}]]]]]]))
|
:for "nudge-big"} (tr "modals.big-nudge")]
|
||||||
|
[:> numeric-input* {:min 0.01
|
||||||
|
:id "nudge-big"
|
||||||
|
:value (:big nudge)
|
||||||
|
:on-change update-big}]]]]]
|
||||||
|
|
||||||
|
|
||||||
|
[:div.nudge-modal-overlay
|
||||||
|
[:div.nudge-modal-container
|
||||||
|
[:div.nudge-modal-header
|
||||||
|
[:p.nudge-modal-title (tr "modals.nudge-title")]
|
||||||
|
[:button.modal-close-button {:on-click on-close} i/close]]
|
||||||
|
[:div.nudge-modal-body
|
||||||
|
[:div.input-wrapper
|
||||||
|
[:span
|
||||||
|
[:p.nudge-subtitle (tr "modals.small-nudge")]
|
||||||
|
[:> numeric-input* {:min 0.01
|
||||||
|
:value (:small nudge)
|
||||||
|
:on-change update-small}]]]
|
||||||
|
[:div.input-wrapper
|
||||||
|
[:span
|
||||||
|
[:p.nudge-subtitle (tr "modals.big-nudge")]
|
||||||
|
[:> numeric-input* {:min 0.01
|
||||||
|
:value (:big nudge)
|
||||||
|
:on-change update-big}]]]]]])))
|
||||||
|
|
42
frontend/src/app/main/ui/workspace/nudge.scss
Normal file
42
frontend/src/app/main/ui/workspace/nudge.scss
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// 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";
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
min-width: $s-408;
|
||||||
|
border: $s-1 solid var(--modal-border-color);
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
@include flexColumn;
|
||||||
|
gap: $s-24;
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-msg {
|
||||||
|
@include titleTipography;
|
||||||
|
}
|
||||||
|
.input-wrapper {
|
||||||
|
@extend .input-with-label;
|
||||||
|
label {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -97,7 +97,7 @@
|
||||||
min-width: $s-68;
|
min-width: $s-68;
|
||||||
padding: 0 $s-8;
|
padding: 0 $s-8;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--modal-foreground-color);
|
color: var(--modal-title-foreground-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.reset-btn {
|
.reset-btn {
|
||||||
|
|
|
@ -66,8 +66,8 @@
|
||||||
:id "left-sidebar-aside"
|
:id "left-sidebar-aside"
|
||||||
:data-size size
|
:data-size size
|
||||||
:class (stl/css-case new-css-system
|
:class (stl/css-case new-css-system
|
||||||
:old-css/settings-bar true
|
:global/settings-bar true
|
||||||
:old-css/settings-bar-left true
|
:global/settings-bar-left true
|
||||||
:left-settings-bar true
|
:left-settings-bar true
|
||||||
:global/two-row (<= size 300)
|
:global/two-row (<= size 300)
|
||||||
:global/three-row (and (> size 300) (<= size 400))
|
:global/three-row (and (> size 300) (<= size 400))
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.workspace.sidebar.assets.groups
|
(ns app.main.ui.workspace.sidebar.assets.groups
|
||||||
(:require-macros [app.main.style :refer [css]])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
@ -47,17 +47,17 @@
|
||||||
on-close-menu
|
on-close-menu
|
||||||
(mf/use-fn #(swap! menu-state cmm/close-context-menu))]
|
(mf/use-fn #(swap! menu-state cmm/close-context-menu))]
|
||||||
(if new-css-system
|
(if new-css-system
|
||||||
[:div {:class (dom/classnames (css :group-title) true)
|
[:div {:class (stl/css :group-title)
|
||||||
:on-context-menu on-context-menu}
|
:on-context-menu on-context-menu}
|
||||||
[:& title-bar {:collapsable? true
|
[:& title-bar {:collapsable? true
|
||||||
:collapsed? (not group-open?)
|
:collapsed? (not group-open?)
|
||||||
:clickable-all? true
|
:clickable-all? true
|
||||||
:on-collapsed on-fold-group
|
:on-collapsed on-fold-group
|
||||||
:title (mf/html [:* (when-not (empty? other-path)
|
:title (mf/html [:* (when-not (empty? other-path)
|
||||||
[:span {:class (dom/classnames (css :pre-path) true)
|
[:span {:class (stl/css :pre-path)
|
||||||
:title (when truncated path)}
|
:title (when truncated path)}
|
||||||
other-path "\u00A0\u2022\u00A0"])
|
other-path "\u00A0\u2022\u00A0"])
|
||||||
[:span {:class (dom/classnames (css :path) true)
|
[:span {:class (stl/css :path)
|
||||||
:title (when truncated path)}
|
:title (when truncated path)}
|
||||||
last-path]])}]
|
last-path]])}]
|
||||||
[:& cmm/assets-context-menu
|
[:& cmm/assets-context-menu
|
||||||
|
@ -120,7 +120,8 @@
|
||||||
::mf/register-as :name-group-dialog}
|
::mf/register-as :name-group-dialog}
|
||||||
[{:keys [path last-path accept] :as ctx
|
[{:keys [path last-path accept] :as ctx
|
||||||
:or {path "" last-path ""}}]
|
:or {path "" last-path ""}}]
|
||||||
(let [initial (mf/use-memo
|
(let [new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
|
initial (mf/use-memo
|
||||||
(mf/deps last-path)
|
(mf/deps last-path)
|
||||||
(constantly {:asset-name last-path}))
|
(constantly {:asset-name last-path}))
|
||||||
form (fm/use-form :spec ::name-group-form
|
form (fm/use-form :spec ::name-group-form
|
||||||
|
@ -141,34 +142,69 @@
|
||||||
(accept asset-name)
|
(accept asset-name)
|
||||||
(accept path asset-name))
|
(accept path asset-name))
|
||||||
(modal/hide!))))]
|
(modal/hide!))))]
|
||||||
|
(if new-css-system
|
||||||
|
[:div {:class (stl/css :modal-overlay)}
|
||||||
|
[:div {:class (stl/css :modal-container)}
|
||||||
|
[:div {:class (stl/css :modal-header)}
|
||||||
|
[:h2 {:class (stl/css :modal-title)}
|
||||||
|
(if create?
|
||||||
|
(tr "workspace.assets.create-group")
|
||||||
|
(tr "workspace.assets.rename-group"))]
|
||||||
|
[:button {:class (stl/css :modal-close-btn)
|
||||||
|
:on-click on-close} i/close-refactor]]
|
||||||
|
|
||||||
[:div.modal-overlay
|
[:div {:class (stl/css :modal-content)}
|
||||||
[:div.modal-container.confirm-dialog
|
[:& fm/form {:form form :on-submit on-accept}
|
||||||
[:div.modal-header
|
[:& fm/input {:name :asset-name
|
||||||
[:div.modal-header-title
|
:class (stl/css :input-wrapper)
|
||||||
[:h2 (if create?
|
:auto-focus? true
|
||||||
(tr "workspace.assets.create-group")
|
:label (tr "workspace.assets.group-name")
|
||||||
(tr "workspace.assets.rename-group"))]]
|
:hint (tr "workspace.assets.create-group-hint")}]]]
|
||||||
[:div.modal-close-button
|
|
||||||
{:on-click on-close} i/close]]
|
|
||||||
|
|
||||||
[:div.modal-content.generic-form
|
[:div {:class (stl/css :modal-footer)}
|
||||||
[:& fm/form {:form form :on-submit on-accept}
|
[:div {:class (stl/css :action-buttons)}
|
||||||
[:& fm/input {:name :asset-name
|
[:input
|
||||||
:auto-focus? true
|
{:class (stl/css :cancel-button)
|
||||||
:label (tr "workspace.assets.group-name")
|
:type "button"
|
||||||
:hint (tr "workspace.assets.create-group-hint")}]]]
|
:value (tr "labels.cancel")
|
||||||
|
:on-click on-close}]
|
||||||
|
|
||||||
[:div.modal-footer
|
[:input
|
||||||
[:div.action-buttons
|
{:type "button"
|
||||||
[:input.cancel-button
|
:class (stl/css-case :accept-btn true
|
||||||
{:type "button"
|
:global/disabled (not (:valid @form) ))
|
||||||
:value (tr "labels.cancel")
|
:disabled (not (:valid @form))
|
||||||
:on-click on-close}]
|
:value (if create? (tr "labels.create") (tr "labels.rename"))
|
||||||
|
:on-click on-accept}]]]]]
|
||||||
|
|
||||||
[:input.accept-button.primary
|
|
||||||
{:type "button"
|
[:div.modal-overlay
|
||||||
:class (when-not (:valid @form) "btn-disabled")
|
[:div.modal-container.confirm-dialog
|
||||||
:disabled (not (:valid @form))
|
[:div.modal-header
|
||||||
:value (if create? (tr "labels.create") (tr "labels.rename"))
|
[:div.modal-header-title
|
||||||
:on-click on-accept}]]]]]))
|
[:h2 (if create?
|
||||||
|
(tr "workspace.assets.create-group")
|
||||||
|
(tr "workspace.assets.rename-group"))]]
|
||||||
|
[:div.modal-close-button
|
||||||
|
{:on-click on-close} i/close]]
|
||||||
|
|
||||||
|
[:div.modal-content.generic-form
|
||||||
|
[:& fm/form {:form form :on-submit on-accept}
|
||||||
|
[:& fm/input {:name :asset-name
|
||||||
|
:auto-focus? true
|
||||||
|
:label (tr "workspace.assets.group-name")
|
||||||
|
:hint (tr "workspace.assets.create-group-hint")}]]]
|
||||||
|
|
||||||
|
[:div.modal-footer
|
||||||
|
[:div.action-buttons
|
||||||
|
[:input.cancel-button
|
||||||
|
{:type "button"
|
||||||
|
:value (tr "labels.cancel")
|
||||||
|
:on-click on-close}]
|
||||||
|
|
||||||
|
[:input.accept-button.primary
|
||||||
|
{:type "button"
|
||||||
|
:class (when-not (:valid @form) "btn-disabled")
|
||||||
|
:disabled (not (:valid @form))
|
||||||
|
:value (if create? (tr "labels.create") (tr "labels.rename"))
|
||||||
|
:on-click on-accept}]]]]])))
|
||||||
|
|
|
@ -19,3 +19,41 @@
|
||||||
color: var(--title-foreground-color-hover);
|
color: var(--title-foreground-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
@extend .modal-overlay-base;
|
||||||
|
.modal-container {
|
||||||
|
@extend .modal-container-base;
|
||||||
|
.modal-header {
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.modal-title {
|
||||||
|
@include tabTitleTipography;
|
||||||
|
color: var(--modal-title-foreground-color);
|
||||||
|
}
|
||||||
|
.modal-close-btn {
|
||||||
|
@extend .modal-close-btn-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-content {
|
||||||
|
@include titleTipography;
|
||||||
|
margin-bottom: $s-24;
|
||||||
|
.input-wrapper {
|
||||||
|
@extend .input-with-label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-footer {
|
||||||
|
.action-buttons {
|
||||||
|
@extend .modal-action-btns;
|
||||||
|
.cancel-button {
|
||||||
|
@extend .modal-cancel-btn;
|
||||||
|
}
|
||||||
|
.accept-btn {
|
||||||
|
@extend .modal-accept-btn;
|
||||||
|
&.danger {
|
||||||
|
@extend .modal-danger-btn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2247,6 +2247,12 @@ msgstr "Create team and send invites"
|
||||||
msgid "onboarding.choice.team-up.create-team-without-inviting"
|
msgid "onboarding.choice.team-up.create-team-without-inviting"
|
||||||
msgstr "Create team without inviting"
|
msgstr "Create team without inviting"
|
||||||
|
|
||||||
|
msgid "onboarding.choice.team-up.create-team-and-invite"
|
||||||
|
msgstr "Create team & invite"
|
||||||
|
|
||||||
|
msgid "onboarding.choice.team-up.create-team-without-invite"
|
||||||
|
msgstr "Create team"
|
||||||
|
|
||||||
msgid "onboarding.choice.team-up.create-team-and-send-invites-description"
|
msgid "onboarding.choice.team-up.create-team-and-send-invites-description"
|
||||||
msgstr "You'll be able to invite later"
|
msgstr "You'll be able to invite later"
|
||||||
|
|
||||||
|
|
|
@ -2300,6 +2300,12 @@ msgstr "Crear equipo y enviar invitaciones"
|
||||||
msgid "onboarding.choice.team-up.create-team-without-inviting"
|
msgid "onboarding.choice.team-up.create-team-without-inviting"
|
||||||
msgstr "Crear equipo sin invitar"
|
msgstr "Crear equipo sin invitar"
|
||||||
|
|
||||||
|
msgid "onboarding.choice.team-up.create-team-and-invite"
|
||||||
|
msgstr "Crear equipo e invitar"
|
||||||
|
|
||||||
|
msgid "onboarding.choice.team-up.create-team-without-invite"
|
||||||
|
msgstr "Crear equipo"
|
||||||
|
|
||||||
msgid "onboarding.choice.team-up.create-team-and-send-invites-description"
|
msgid "onboarding.choice.team-up.create-team-and-send-invites-description"
|
||||||
msgstr "Podrás enviar invitaciones después"
|
msgstr "Podrás enviar invitaciones después"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue