UBER-64,-231,-229: updated CreateProject and SelectAvatar layouts, fixed bugs (#3253)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-05-26 06:02:47 +03:00 committed by GitHub
parent 0298ff1c8d
commit ea6612cdb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 419 additions and 257 deletions

View File

@ -127,7 +127,7 @@ export class TTypeMilestoneStatus extends TType {}
@Model(tracker.class.Project, core.class.Space, DOMAIN_SPACE) @Model(tracker.class.Project, core.class.Space, DOMAIN_SPACE)
@UX(tracker.string.Project, tracker.icon.Issues, 'Project', 'name') @UX(tracker.string.Project, tracker.icon.Issues, 'Project', 'name')
export class TProject extends TSpace implements Project { export class TProject extends TSpace implements Project {
@Prop(TypeString(), tracker.string.Identifier) @Prop(TypeString(), tracker.string.ProjectIdentifier)
@Index(IndexKind.FullText) @Index(IndexKind.FullText)
identifier!: IntlString identifier!: IntlString

View File

@ -30,7 +30,9 @@
export let fullSize: boolean = false export let fullSize: boolean = false
export let hideAttachments: boolean = false export let hideAttachments: boolean = false
export let hideSubheader: boolean = false export let hideSubheader: boolean = false
export let accentHeader: boolean = false
export let gap: string | undefined = undefined export let gap: string | undefined = undefined
export let width: 'large' | 'medium' | 'small' | 'x-small' = 'large'
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -39,7 +41,7 @@
<form <form
id={label} id={label}
class="antiCard {$deviceInfo.isMobile ? 'mobile' : 'dialog'}" class="antiCard {$deviceInfo.isMobile ? 'mobile' : 'dialog'} {width}"
class:full={fullSize} class:full={fullSize}
on:submit|preventDefault={() => {}} on:submit|preventDefault={() => {}}
use:resizeObserver={() => { use:resizeObserver={() => {
@ -52,7 +54,7 @@
<slot name="header" /> <slot name="header" />
<span class="antiCard-header__divider"><IconForward size={'small'} /></span> <span class="antiCard-header__divider"><IconForward size={'small'} /></span>
{/if} {/if}
<span class="antiCard-header__title"> <span class="antiCard-header__title" class:accentHeader>
{#if $$slots.title} {#if $$slots.title}
<slot name="title" {label} labelProps={labelProps ?? {}} /> <slot name="title" {label} labelProps={labelProps ?? {}} />
{:else} {:else}

View File

@ -36,6 +36,7 @@
export let enableFormatting = false export let enableFormatting = false
export let autofocus = false export let autofocus = false
export let enableBackReferences: boolean = false export let enableBackReferences: boolean = false
export let isScrollable: boolean = true
const Mode = { const Mode = {
View: 1, View: 1,
@ -159,6 +160,7 @@
{focusable} {focusable}
{enableFormatting} {enableFormatting}
{autofocus} {autofocus}
{isScrollable}
extensions={enableBackReferences ? [completionPlugin] : []} extensions={enableBackReferences ? [completionPlugin] : []}
bind:content={rawValue} bind:content={rawValue}
bind:this={textEditor} bind:this={textEditor}

View File

@ -646,13 +646,19 @@
// max-height: 100%; // max-height: 100%;
height: 100%; height: 100%;
} }
&:not(.showScroll)::-webkit-scrollbar-thumb {
background-color: transparent;
}
&.scrollable { &.scrollable {
overflow: auto;
max-height: var(--texteditor-maxheight); max-height: var(--texteditor-maxheight);
&.showScroll {
overflow: auto;
}
}
&:not(.showScroll) {
overflow-y: hidden;
&::-webkit-scrollbar-thumb {
background-color: transparent;
}
} }
} }

View File

@ -59,7 +59,7 @@
--primary-button-hovered: #1A53AF; --primary-button-hovered: #1A53AF;
--primary-button-pressed: #144CA8; --primary-button-pressed: #144CA8;
--primary-button-focused: #144CA8; --primary-button-focused: #144CA8;
--primary-button-disabled: #6E9FED; --primary-button-disabled: #484662;
--primary-button-focused-border: #6E9FED; --primary-button-focused-border: #6E9FED;
--primary-button-border: rgba(255, 255, 255, .09); --primary-button-border: rgba(255, 255, 255, .09);
--primary-button-outline: rgba(87, 132, 255, .3); // OLD --primary-button-outline: rgba(87, 132, 255, .3); // OLD
@ -142,6 +142,13 @@
--theme-calendar-holiday-bgcolor: rgba(235, 87, 87, .1); --theme-calendar-holiday-bgcolor: rgba(235, 87, 87, .1);
--theme-calendar-weekend-bgcolor: rgba(242, 153, 74, .05); --theme-calendar-weekend-bgcolor: rgba(242, 153, 74, .05);
--theme-toggle-sw-color: #fff;
--theme-toggle-on-sw-color: #fff;
--theme-toggle-bg-color: rgba(120, 120, 128, 0.32);
--theme-toggle-bg-hover: rgba(120, 120, 128, 0.64);
--theme-toggle-on-bg-color: #205dc2;
--theme-toggle-on-bg-hover: #1A53AF;
--theme-error-color: #eb5757; --theme-error-color: #eb5757;
--theme-urgent-color: #F5694A; --theme-urgent-color: #F5694A;
--theme-warning-color: #f2994a; --theme-warning-color: #f2994a;
@ -208,13 +215,6 @@
--dangerous-bg-hover: #ff6464; --dangerous-bg-hover: #ff6464;
--dangerous-shadow: var(--dangerous-bg-color) 0px 0px 12px -1px; --dangerous-shadow: var(--dangerous-bg-color) 0px 0px 12px -1px;
--toggle-sw-color: #27282b;
--toggle-on-sw-color: #fff;
--toggle-bg-color: #3c3f44;
--toggle-bg-hover: #45484e;
--toggle-on-bg-color: #5e6ad2;
--toggle-on-bg-hover: #828fff;
--incoming-msg: rgba(67, 67, 72, .3); --incoming-msg: rgba(67, 67, 72, .3);
--outcoming-msg: rgba(67, 67, 72, .6); --outcoming-msg: rgba(67, 67, 72, .6);
@ -226,12 +226,12 @@
/* Light Theme */ /* Light Theme */
.theme-light { .theme-light {
--primary-button-color: #fff; --primary-button-color: #fff;
--primary-button-enabled: rgb(43, 82, 144); --primary-button-enabled: #205DC2;
--primary-button-transparent: rgba(43, 82, 144, 0.2); --primary-button-transparent: rgba(32, 93, 194, 0.2);
--primary-button-hovered: #1A53AF; // DARK --primary-button-hovered: #1A53AF;
--primary-button-pressed: #144CA8; // DARK --primary-button-pressed: #144CA8;
--primary-button-focused: #144CA8; // DARK --primary-button-focused: #144CA8;
--primary-button-disabled: #6E9FED; // DARK --primary-button-disabled: #EBEBEB;
--primary-button-focused-border: #6E9FED; // DARK --primary-button-focused-border: #6E9FED; // DARK
--primary-button-border: rgba(255, 255, 255, .09); --primary-button-border: rgba(255, 255, 255, .09);
--primary-button-outline: rgba(87, 132, 255, .3); // OLD --primary-button-outline: rgba(87, 132, 255, .3); // OLD
@ -313,6 +313,12 @@
--theme-calendar-today-bgcolor: rgba(43, 81, 144, .1); --theme-calendar-today-bgcolor: rgba(43, 81, 144, .1);
--theme-calendar-holiday-bgcolor: rgba(235, 87, 87, .1); --theme-calendar-holiday-bgcolor: rgba(235, 87, 87, .1);
--theme-calendar-weekend-bgcolor: rgba(242, 153, 74, .1); --theme-calendar-weekend-bgcolor: rgba(242, 153, 74, .1);
--theme-toggle-sw-color: #fff;
--theme-toggle-on-sw-color: #fff;
--theme-toggle-bg-color: rgba(120, 120, 128, 0.32);
--theme-toggle-bg-hover: rgba(120, 120, 128, 0.64);
--theme-toggle-on-bg-color: #205dc2;
--theme-toggle-on-bg-hover: #1A53AF;
--theme-error-color: #eb5757; // Dark --theme-error-color: #eb5757; // Dark
--theme-urgent-color: #F5694A; --theme-urgent-color: #F5694A;
@ -380,13 +386,6 @@
--dangerous-bg-hover: #d44e4e; --dangerous-bg-hover: #d44e4e;
--dangerous-shadow: var(--dangerous-bg-color) 0px 0px 12px -1px; --dangerous-shadow: var(--dangerous-bg-color) 0px 0px 12px -1px;
--toggle-sw-color: #fff;
--toggle-on-sw-color: #fff;
--toggle-bg-color: #dfe1e4;
--toggle-bg-hover: #c9cbcd;
--toggle-on-bg-color: #6e79d6;
--toggle-on-bg-hover: #535db3;
--incoming-msg: rgba(67, 67, 72, .1); --incoming-msg: rgba(67, 67, 72, .1);
--outcoming-msg: rgba(67, 67, 72, .2); --outcoming-msg: rgba(67, 67, 72, .2);

View File

@ -413,6 +413,8 @@ input.search {
&.reverse > *:not(:last-child) { margin-right: 1rem; } &.reverse > *:not(:last-child) { margin-right: 1rem; }
} }
.gapV-4 > *:not(:last-child) { margin-bottom: 1rem; } .gapV-4 > *:not(:last-child) { margin-bottom: 1rem; }
.gapV-6 > *:not(:last-child) { margin-bottom: 1.5rem; }
.gapV-8 > *:not(:last-child) { margin-bottom: 2rem; }
.gap-around-2 > * { margin: .25rem; } .gap-around-2 > * { margin: .25rem; }
.gap-around-4 > * { margin: .5rem; } .gap-around-4 > * { margin: .5rem; }

View File

@ -256,6 +256,49 @@
padding: .5rem 0 1.25rem; padding: .5rem 0 1.25rem;
} }
/* Basic */
.antiGrid {
display: flex;
flex-direction: column;
flex-shrink: 0;
min-width: 0;
min-height: 0;
&-row {
display: flex;
align-items: center;
min-width: 0;
&__header {
width: 15rem;
padding-right: 1rem;
color: var(--theme-caption-color);
&.withDesciption {
display: flex;
flex-direction: column;
min-width: 0;
min-height: 0;
span {
font-size: .75rem;
color: var(--theme-halfcontent-color);
}
}
&.topAlign {
align-self: flex-start;
margin-top: .75rem;
}
}
.padding {
flex-grow: 1;
padding: .75rem 0;
}
&:not(:last-child) { margin-bottom: .5rem; }
& > *:not(.padding, .topAlign) { margin: .25rem 0; }
}
}
/* Basic */ /* Basic */
.antiTitle { .antiTitle {
.icon-wrapper, &.icon-wrapper, .icon-wrapper, &.icon-wrapper,

View File

@ -58,6 +58,8 @@
min-width: 0; min-width: 0;
line-height: 150%; line-height: 150%;
color: var(--theme-caption-color); color: var(--theme-caption-color);
&.accentHeader { font-size: 1rem; }
} }
&__divider { color: var(--theme-dark-color); } &__divider { color: var(--theme-dark-color); }
&__error { &__error {
@ -190,10 +192,25 @@
} }
&.dialog { &.dialog {
width: 45rem;
height: auto; height: auto;
max-width: 60rem;
max-height: inherit; max-height: inherit;
&.large {
width: 45rem;
max-width: 60rem;
}
&.medium {
width: 37.5rem;
max-width: 37.5rem;
}
&.small {
width: 30rem;
max-width: 30rem;
}
&.x-small {
width: 25rem;
max-width: 25rem;
}
&.full { &.full {
width: max-content; width: max-content;
// max-width: 100%; // max-width: 100%;

View File

@ -37,8 +37,9 @@
export let select: boolean = false export let select: boolean = false
export let focusable: boolean = false export let focusable: boolean = false
export let disabled: boolean = false export let disabled: boolean = false
export let fullSize = false export let fullSize: boolean = false
export let required = false export let required: boolean = false
export let uppercase: boolean = false
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -134,6 +135,7 @@
class="editbox-container" class="editbox-container"
class:flex-grow={fullSize} class:flex-grow={fullSize}
class:w-full={focusable || fullSize} class:w-full={focusable || fullSize}
class:uppercase
on:click={() => { on:click={() => {
input.focus() input.focus()
}} }}
@ -210,8 +212,8 @@
align-items: flex-start; align-items: flex-start;
.large-style { .large-style {
font-weight: 500; font-weight: 400;
font-size: 1.125rem; font-size: 1.25rem;
} }
.small-style { .small-style {
font-weight: 400; font-weight: 400;
@ -271,5 +273,9 @@
input[type='number'] { input[type='number'] {
-moz-appearance: textfield; -moz-appearance: textfield;
} }
&.uppercase .hidden-text,
&.uppercase input {
text-transform: uppercase;
}
} }
</style> </style>

View File

@ -22,7 +22,7 @@
export let selected: string | string[] = '' export let selected: string | string[] = ''
export let multiselect: boolean = false export let multiselect: boolean = false
export let items: TabItem[] export let items: TabItem[]
export let kind: 'normal' | 'secondary' | 'plain' | 'separated' = 'normal' export let kind: 'normal' | 'secondary' | 'plain' | 'separated' | 'separated-free' = 'normal'
export let onlyIcons: boolean = false export let onlyIcons: boolean = false
export let size: 'small' | 'medium' = 'medium' export let size: 'small' | 'medium' = 'medium'
@ -50,7 +50,8 @@
<div <div
bind:this={tabs[i]} bind:this={tabs[i]}
class={kind === 'normal' || kind === 'secondary' ? 'button' : 'plain'} class={kind === 'normal' || kind === 'secondary' ? 'button' : 'plain'}
class:separated={kind === 'separated'} class:separated={kind === 'separated' || kind === 'separated-free'}
class:free={kind === 'separated-free'}
class:onlyIcons class:onlyIcons
class:selected={getSelected(item.id, selected)} class:selected={getSelected(item.id, selected)}
data-view={item.tooltip} data-view={item.tooltip}
@ -234,6 +235,9 @@
background-color: var(--theme-tablist-plain-divider); background-color: var(--theme-tablist-plain-divider);
transform: translateY(-50%); transform: translateY(-50%);
} }
&.free:first-child::before {
content: none;
}
} }
} }
} }

View File

@ -37,9 +37,9 @@
<style lang="scss"> <style lang="scss">
.toggle { .toggle {
display: inline-block; display: inline-block;
width: 2rem; width: 2.25rem;
min-width: 2rem; min-width: 2.25rem;
height: 1.5rem; height: 1.25rem;
// line-height: 1.75rem; // line-height: 1.75rem;
vertical-align: middle; vertical-align: middle;
font-size: inherit; font-size: inherit;
@ -55,13 +55,13 @@
overflow: hidden; overflow: hidden;
&:checked + .toggle-switch { &:checked + .toggle-switch {
background-color: var(--toggle-on-bg-color); background-color: var(--theme-toggle-on-bg-color);
&:hover { &:hover {
background-color: var(--toggle-on-bg-hover); background-color: var(--theme-toggle-on-bg-hover);
} }
&:before { &:before {
left: 0.75rem; left: 1.125rem;
background: var(--toggle-on-sw-color); background: var(--theme-toggle-on-sw-color);
} }
} }
&:not(:disabled) + .toggle-switch { &:not(:disabled) + .toggle-switch {
@ -79,26 +79,26 @@
.toggle-switch { .toggle-switch {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 2rem; width: 2.25rem;
height: 1.5rem; height: 1.25rem;
border-radius: 4.5rem; border-radius: 1.25rem;
background-color: var(--toggle-bg-color); background-color: var(--theme-toggle-bg-color);
transition: left 0.2s, background-color 0.2s; transition: left 0.2s, background-color 0.2s;
&:before { &:before {
content: ''; content: '';
position: absolute; position: absolute;
top: 0.25rem; top: 0.125rem;
left: 0.25rem; left: 0.125rem;
display: inline-block; display: inline-block;
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
border-radius: 50%; border-radius: 50%;
background: var(--toggle-sw-color); background: var(--theme-toggle-sw-color);
box-shadow: 1px 2px 7px rgba(119, 129, 142, 0.1); box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.15), 0px 3px 1px rgba(0, 0, 0, 0.06);
transition: 0.15s; transition: 0.15s;
} }
&:hover { &:hover {
background-color: var(--toggle-bg-hover); background-color: var(--theme-toggle-bg-hover);
} }
} }
} }

View File

@ -71,6 +71,7 @@
class:dateTimeButtonNoLabel={!shouldShowLabel} class:dateTimeButtonNoLabel={!shouldShowLabel}
class:text-xs={size === 'x-small'} class:text-xs={size === 'x-small'}
class:noDate={!value} class:noDate={!value}
class:withIcon={showIcon}
style:width style:width
on:click={(e) => { on:click={(e) => {
if (editable && !opened) { if (editable && !opened) {
@ -292,12 +293,17 @@
} }
} }
&.secondary { &.secondary {
padding: 0 0.625rem;
color: var(--theme-caption-color); color: var(--theme-caption-color);
background-color: var(--theme-button-enabled); background-color: var(--theme-button-enabled);
border-color: var(--theme-button-border); border-color: var(--theme-button-border);
border-radius: 0.25rem; border-radius: 0.25rem;
&.withIcon {
padding: 0 1rem 0 0.75rem;
}
&:not(.withIcon) {
padding: 0 0.75rem;
}
.btn-icon { .btn-icon {
color: var(--theme-content-color); color: var(--theme-content-color);
} }

View File

@ -185,6 +185,7 @@ export type IconSize =
| 'medium' | 'medium'
| 'large' | 'large'
| 'x-large' | 'x-large'
| '2x-large'
| 'full' | 'full'
export interface DateOrShift { export interface DateOrShift {

View File

@ -94,25 +94,28 @@
{trimFilename(value.name)} {trimFilename(value.name)}
</a> </a>
</div> </div>
<div class="info-content"> <div class="info-content flex-row-center">
{filesize(value.size, { spacer: '' })} {filesize(value.size, { spacer: '' })}
<a class="no-line colorInherit" href={getFileUrl(value.file)} download={value.name} bind:this={download}> <span class="actions inline-flex clear-mins ml-1 gap-1">
<Label label={presentation.string.Download} /> <span></span>
</a> <a class="no-line colorInherit" href={getFileUrl(value.file)} download={value.name} bind:this={download}>
{#if removable} <Label label={presentation.string.Download} />
<!-- svelte-ignore a11y-click-events-have-key-events --> </a>
{#if removable}
<span <span></span>
class="remove-link" <!-- svelte-ignore a11y-click-events-have-key-events -->
on:click={(ev) => { <span
ev.stopPropagation() class="remove-link"
ev.preventDefault() on:click={(ev) => {
dispatch('remove', value) ev.stopPropagation()
}} ev.preventDefault()
> dispatch('remove', value)
<Label label={presentation.string.Delete} /> }}
</span> >
{/if} <Label label={presentation.string.Delete} />
</span>
{/if}
</span>
</div> </div>
</div> </div>
</div> </div>
@ -124,7 +127,6 @@
height: 3rem; height: 3rem;
min-width: 14rem; min-width: 14rem;
max-width: 19rem; max-width: 19rem;
background-color: var(--theme-button-hovered);
border-radius: 0.25rem; border-radius: 0.25rem;
.icon { .icon {
@ -152,20 +154,41 @@
padding: 0.5rem 0.75rem; padding: 0.5rem 0.75rem;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: var(--theme-button-enabled);
border: 1px solid var(--theme-button-border); border: 1px solid var(--theme-button-border);
border-left: none; border-left: none;
border-radius: 0 0.25rem 0.25rem 0; border-radius: 0 0.25rem 0.25rem 0;
} }
.no-line:hover ~ .info-container,
.info-container:hover {
background-color: var(--theme-button-hovered);
.actions {
opacity: 1;
}
}
.name { .name {
white-space: nowrap; white-space: nowrap;
font-size: 0.8125rem; font-size: 0.8125rem;
color: var(--theme-caption-color); color: var(--theme-caption-color);
cursor: pointer; cursor: pointer;
&:hover ~ .info-content .actions {
opacity: 1;
}
} }
.info-content { .info-content {
white-space: nowrap; white-space: nowrap;
font-size: 0.6875rem; font-size: 0.6875rem;
color: var(--theme-darker-color); color: var(--theme-darker-color);
.actions {
opacity: 0;
transition: opacity 0.1s var(--timing-main);
}
&:hover .actions {
opacity: 1;
}
} }
.remove-link { .remove-link {
color: var(--theme-error-color); color: var(--theme-error-color);

View File

@ -339,7 +339,7 @@
on:dragleave={() => {}} on:dragleave={() => {}}
on:drop|preventDefault|stopPropagation={(ev) => { on:drop|preventDefault|stopPropagation={(ev) => {
if (fakeAttach === 'fake') dispatch('attach', { action: 'drop', event: ev }) if (fakeAttach === 'fake') dispatch('attach', { action: 'drop', event: ev })
else if (fakeAttach === 'normal') fileDrop(ev) else fileDrop(ev)
}} }}
> >
<div class="expand-collapse"> <div class="expand-collapse">

View File

@ -84,7 +84,8 @@
"DisplayName": "Display name", "DisplayName": "Display name",
"SelectAvatar": "Select avatar", "SelectAvatar": "Select avatar",
"AvatarProvider": "Avatar provider", "AvatarProvider": "Avatar provider",
"GravatarsManaged": "Gravatars are managed through", "GravatarsManaged": "Gravatars are managed",
"Through": "through",
"CategoryProjectMembers": "Project members", "CategoryProjectMembers": "Project members",
"AddMembersHeader": "Add members to {value}:", "AddMembersHeader": "Add members to {value}:",
"Assigned": "Assigned", "Assigned": "Assigned",

View File

@ -84,7 +84,8 @@
"MergeEmployeeTo": "В сотрудника", "MergeEmployeeTo": "В сотрудника",
"DisplayName": "Отображаемое имя", "DisplayName": "Отображаемое имя",
"SelectAvatar": "Выбрать аватар", "SelectAvatar": "Выбрать аватар",
"GravatarsManaged": "Граватары управляются через", "GravatarsManaged": "Граватары управляются",
"Through": "через",
"AddMembersHeader": "Добавить пользователей в {value}:", "AddMembersHeader": "Добавить пользователей в {value}:",
"NumberMembers": "{count, plural, =0 {нет участников} =1 {1 участник} =2 {2 участника} =3 {3 участника} =4 {4 участника} other {# участников}}", "NumberMembers": "{count, plural, =0 {нет участников} =1 {1 участник} =2 {2 участника} =3 {3 участника} =4 {4 участника} other {# участников}}",
"Assigned": "Назначен", "Assigned": "Назначен",

View File

@ -156,7 +156,7 @@
<div class="flex-presenter not-selected"> <div class="flex-presenter not-selected">
{#if icon} {#if icon}
<div class="icon w-4 flex-no-shrink" class:small-gap={size === 'inline' || size === 'small'}> <div class="icon w-4 flex-no-shrink" class:small-gap={size === 'inline' || size === 'small'}>
<Icon {icon} size={avatarSize} /> <Icon {icon} size={'small'} />
</div> </div>
{/if} {/if}
<div class="label no-underline"> <div class="label no-underline">

View File

@ -73,7 +73,7 @@
<div class="ava-{size} flex-center avatar-container" class:no-img={!url}> <div class="ava-{size} flex-center avatar-container" class:no-img={!url}>
{#if url} {#if url}
{#if size === 'large' || size === 'x-large'} {#if size === 'large' || size === 'x-large' || size === '2x-large'}
<img class="ava-{size} ava-blur" src={url} alt={''} bind:this={imageElement} /> <img class="ava-{size} ava-blur" src={url} alt={''} bind:this={imageElement} />
{/if} {/if}
<img class="ava-{size} ava-mask" src={url} alt={''} bind:this={imageElement} /> <img class="ava-{size} ava-mask" src={url} alt={''} bind:this={imageElement} />
@ -138,6 +138,10 @@
width: 7.5rem; // 120 width: 7.5rem; // 120
height: 7.5rem; height: 7.5rem;
} }
.ava-2x-large {
width: 10rem; // 120
height: 10rem;
}
.ava-blur { .ava-blur {
position: absolute; position: absolute;
@ -148,6 +152,11 @@
border: 1px solid var(--avatar-border-color); border: 1px solid var(--avatar-border-color);
border-radius: 50%; border-radius: 50%;
} }
.ava-large .ava-mask,
.ava-x-large .ava-mask,
.ava-2x-large .ava-mask {
border-width: 2px;
}
.ava-inline .ava-mask, .ava-inline .ava-mask,
.ava-inline.no-img, .ava-inline.no-img,

View File

@ -60,21 +60,17 @@
dispatch('close') dispatch('close')
}} }}
/> />
<div class="root"> <div class="editavatar-container">
{#await CropperP then Cropper} {#await CropperP then Cropper}
<div class="cropper"> <div class="cropper">
<Cropper bind:this={cropper} image={file} /> <Cropper bind:this={cropper} image={file} />
</div> </div>
<div class="footer"> <div class="footer">
<div> <Button label={presentation.string.Save} kind={'primary'} size={'large'} on:click={onCrop} />
<Button label={presentation.string.Save} kind={'primary'} on:click={onCrop} /> <div class="mx-3 clear-mins">
</div> <Button label={presentation.string.Change} size={'large'} on:click={selectAnother} />
<div class="ml-4 mr-4">
<Button label={presentation.string.Change} on:click={selectAnother} />
</div>
<div>
<Button label={presentation.string.Remove} on:click={remove} />
</div> </div>
<Button label={presentation.string.Remove} size={'large'} on:click={remove} />
</div> </div>
{/await} {/await}
</div> </div>
@ -87,11 +83,11 @@
bottom: 0; bottom: 0;
right: 0; right: 0;
background: var(--card-overlay-color); background: var(--theme-overlay-color);
touch-action: none; touch-action: none;
} }
.root { .editavatar-container {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
@ -105,21 +101,20 @@
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
background: var(--popup-bg-color); background: var(--theme-popup-color);
border-radius: 1.25rem; border-radius: 1.25rem;
box-shadow: 0px 44px 154px rgba(0, 0, 0, 0.75); box-shadow: var(--theme-popup-shadow);
display: grid; display: grid;
grid-template-rows: minmax(min-content, 1fr) auto; grid-template-rows: minmax(min-content, 1fr) auto;
}
.cropper { .cropper {
width: inherit; width: inherit;
} }
.footer {
.footer { display: flex;
display: flex; flex-direction: row-reverse;
flex-direction: row-reverse; padding: 1rem 1.5rem;
padding: 1rem 1.5rem; }
} }
</style> </style>

View File

@ -17,7 +17,7 @@
import { AvatarType, buildGravatarId, checkHasGravatar, getAvatarColorForId } from '@hcengineering/contact' import { AvatarType, buildGravatarId, checkHasGravatar, getAvatarColorForId } from '@hcengineering/contact'
import { Asset } from '@hcengineering/platform' import { Asset } from '@hcengineering/platform'
import { AnySvelteComponent, DropdownLabelsIntl, Label, showPopup } from '@hcengineering/ui' import { AnySvelteComponent, Label, showPopup, TabList } from '@hcengineering/ui'
import presentation, { Card, getFileUrl } from '@hcengineering/presentation' import presentation, { Card, getFileUrl } from '@hcengineering/presentation'
import contact from '../plugin' import contact from '../plugin'
@ -29,7 +29,7 @@
export let email: string | undefined export let email: string | undefined
export let id: string export let id: string
export let file: Blob | undefined export let file: Blob | undefined
export let icon: Asset | AnySvelteComponent | undefined export let icon: Asset | AnySvelteComponent | undefined = undefined
export let onSubmit: (avatarType?: AvatarType, avatar?: string, file?: Blob) => void export let onSubmit: (avatarType?: AvatarType, avatar?: string, file?: Blob) => void
const [schema, uri] = avatar?.split('://') || [] const [schema, uri] = avatar?.split('://') || []
@ -151,6 +151,8 @@
<Card <Card
label={contact.string.SelectAvatar} label={contact.string.SelectAvatar}
okLabel={presentation.string.Save} okLabel={presentation.string.Save}
width={'x-small'}
accentHeader
canSave={selectedAvatarType !== initialSelectedType || canSave={selectedAvatarType !== initialSelectedType ||
selectedAvatar !== initialSelectedAvatar || selectedAvatar !== initialSelectedAvatar ||
selectedFile !== file || selectedFile !== file ||
@ -161,36 +163,39 @@
}} }}
on:changeContent on:changeContent
> >
<div class="flex-row-center"> <div class="flex-col-center gapV-4 mx-6">
<Label label={contact.string.AvatarProvider} /> {#if selectedAvatarType === AvatarType.IMAGE}
<DropdownLabelsIntl <!-- svelte-ignore a11y-click-events-have-key-events -->
kind={'link-bordered'} <div class="cursor-pointer" on:click|self={handleImageAvatarClick}>
<AvatarComponent avatar={selectedAvatar} direct={selectedFile} size={'2x-large'} {icon} />
</div>
{:else}
<AvatarComponent avatar={`${selectedAvatarType}://${selectedAvatar}`} size={'2x-large'} {icon} />
{/if}
<TabList
items={getAvatarTypeDropdownItems(hasGravatar)} items={getAvatarTypeDropdownItems(hasGravatar)}
label={contact.string.SelectAvatar} kind={'separated-free'}
bind:selected={selectedAvatarType} bind:selected={selectedAvatarType}
on:selected={handleDropdownSelection} on:select={handleDropdownSelection}
/> />
</div> </div>
{#if selectedAvatarType === AvatarType.IMAGE} <svelte:fragment slot="footer">
<!-- svelte-ignore a11y-click-events-have-key-events --> {#if selectedAvatarType === AvatarType.GRAVATAR}
<div class="cursor-pointer" on:click|self={handleImageAvatarClick}> <div class="flex-col">
<AvatarComponent avatar={selectedAvatar} direct={selectedFile} size={'x-large'} {icon} /> <Label label={contact.string.GravatarsManaged} />
</div> <span class="inline-flex clear-mins">
{:else} <Label label={contact.string.Through} />
<AvatarComponent avatar={`${selectedAvatarType}://${selectedAvatar}`} size={'x-large'} {icon} /> <a target="”_blank”" class="ml-1" href="//gravatar.com">Gravatar.com</a>
{/if} </span>
{#if selectedAvatarType === AvatarType.GRAVATAR} </div>
<span> {/if}
<Label label={contact.string.GravatarsManaged} /> <input
<a target="”_blank”" href="//gravatar.com">Gravatar.com</a> style="display: none;"
</span> type="file"
{/if} bind:this={inputRef}
<input on:change={onSelectFile}
style="display: none;" on:click={() => (document.body.onfocus = handleFileSelectionCancel)}
type="file" accept={targetMimes.join(',')}
bind:this={inputRef} />
on:change={onSelectFile} </svelte:fragment>
on:click={() => (document.body.onfocus = handleFileSelectionCancel)}
accept={targetMimes.join(',')}
/>
</Card> </Card>

View File

@ -85,9 +85,9 @@
{#if persons.length > 0} {#if persons.length > 0}
<div class="flex-row-center flex-nowrap pointer-events-none"> <div class="flex-row-center flex-nowrap pointer-events-none">
{#if persons.length === 1} {#if persons.length === 1}
<UserInfo value={persons[0]} size={'inline'} /> <UserInfo value={persons[0]} size={'card'} />
{:else} {:else}
<CombineAvatars {_class} bind:items size={'inline'} hideLimit /> <CombineAvatars {_class} bind:items size={'card'} hideLimit />
<span class="overflow-label ml-1-5"> <span class="overflow-label ml-1-5">
<Label label={plugin.string.NumberMembers} params={{ count: persons.length }} /> <Label label={plugin.string.NumberMembers} params={{ count: persons.length }} />
</span> </span>

View File

@ -21,7 +21,7 @@
export let fill: string = 'var(--caption-color)' export let fill: string = 'var(--caption-color)'
</script> </script>
<svg class="svg-avatar {size}" {fill} viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg"> <svg class="svg-avatar avaicon-{size}" {fill} viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
<circle class="op" cx="20" cy="13.6" r="6.4" /> <circle class="op" cx="20" cy="13.6" r="6.4" />
<path <path
d="M33.1,33.3c-0.8-2.2-2.5-4.2-4.9-5.5c-2.3-1.3-5.2-2.1-8.2-2.1s-5.8,0.7-8.2,2.1c-2.4,1.4-4.1,3.3-4.9,5.5 c-0.1,0.4,0.1,0.8,0.5,1c0.4,0.1,0.8-0.1,1-0.5c0.7-1.9,2.2-3.5,4.2-4.7c2.1-1.2,4.7-1.9,7.4-1.9c2.7,0,5.3,0.7,7.4,1.9 c2.1,1.2,3.6,2.9,4.2,4.7c0.1,0.3,0.4,0.5,0.7,0.5c0.1,0,0.2,0,0.3,0C33,34.1,33.2,33.7,33.1,33.3z" d="M33.1,33.3c-0.8-2.2-2.5-4.2-4.9-5.5c-2.3-1.3-5.2-2.1-8.2-2.1s-5.8,0.7-8.2,2.1c-2.4,1.4-4.1,3.3-4.9,5.5 c-0.1,0.4,0.1,0.8,0.5,1c0.4,0.1,0.8-0.1,1-0.5c0.7-1.9,2.2-3.5,4.2-4.7c2.1-1.2,4.7-1.9,7.4-1.9c2.7,0,5.3,0.7,7.4,1.9 c2.1,1.2,3.6,2.9,4.2,4.7c0.1,0.3,0.4,0.5,0.7,0.5c0.1,0,0.2,0,0.3,0C33,34.1,33.2,33.7,33.1,33.3z"
@ -37,38 +37,42 @@
opacity: 0.05; opacity: 0.05;
} }
} }
.inline { .avaicon-inline {
width: 0.75rem; width: 0.75rem;
height: 0.75rem; height: 0.75rem;
} }
.tiny { .avaicon-tiny {
width: 0.875rem; width: 0.875rem;
height: 0.875rem; height: 0.875rem;
} }
.x-small { .avaicon-x-small {
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
} }
.smaller { .avaicon-smaller {
width: 1.125rem; width: 1.125rem;
height: 1.125rem; height: 1.125rem;
} }
.small { .avaicon-small {
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;
} }
.medium { .avaicon-medium {
width: 1.5rem; width: 1.5rem;
height: 1.5rem; height: 1.5rem;
} }
.large { .avaicon-large {
width: 1.75rem; width: 1.75rem;
height: 1.75rem; height: 1.75rem;
} }
.x-large { .avaicon-x-large {
width: 3rem; width: 3rem;
height: 3rem; height: 3rem;
} }
.avaicon-2x-large {
width: 4rem;
height: 4rem;
}
</style> </style>

View File

@ -66,6 +66,7 @@ export default mergeIds(contactId, contact, {
MergeEmployeeTo: '' as IntlString, MergeEmployeeTo: '' as IntlString,
SelectAvatar: '' as IntlString, SelectAvatar: '' as IntlString,
GravatarsManaged: '' as IntlString, GravatarsManaged: '' as IntlString,
Through: '' as IntlString,
AvatarProvider: '' as IntlString, AvatarProvider: '' as IntlString,
CategoryProjectMembers: '' as IntlString, CategoryProjectMembers: '' as IntlString,

View File

@ -30,13 +30,7 @@ import {
import { Client, Doc, getCurrentAccount, IdMap, ObjQueryType, Ref, Timestamp, toIdMap } from '@hcengineering/core' import { Client, Doc, getCurrentAccount, IdMap, ObjQueryType, Ref, Timestamp, toIdMap } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation' import { createQuery, getClient } from '@hcengineering/presentation'
import { TemplateDataProvider } from '@hcengineering/templates' import { TemplateDataProvider } from '@hcengineering/templates'
import { import { TabItem, getCurrentResolvedLocation, getPanelURI, Location, ResolvedLocation } from '@hcengineering/ui'
DropdownIntlItem,
getCurrentResolvedLocation,
getPanelURI,
Location,
ResolvedLocation
} from '@hcengineering/ui'
import view, { Filter } from '@hcengineering/view' import view, { Filter } from '@hcengineering/view'
import { FilterQuery } from '@hcengineering/view-resources' import { FilterQuery } from '@hcengineering/view-resources'
import { get, writable } from 'svelte/store' import { get, writable } from 'svelte/store'
@ -269,21 +263,21 @@ function fillStores (): void {
fillStores() fillStores()
export function getAvatarTypeDropdownItems (hasGravatar: boolean): DropdownIntlItem[] { export function getAvatarTypeDropdownItems (hasGravatar: boolean): TabItem[] {
return [ return [
{ {
id: AvatarType.COLOR, id: AvatarType.COLOR,
label: contact.string.UseColor labelIntl: contact.string.UseColor
}, },
{ {
id: AvatarType.IMAGE, id: AvatarType.IMAGE,
label: contact.string.UseImage labelIntl: contact.string.UseImage
}, },
...(hasGravatar ...(hasGravatar
? [ ? [
{ {
id: AvatarType.GRAVATAR, id: AvatarType.GRAVATAR,
label: contact.string.UseGravatar labelIntl: contact.string.UseGravatar
} }
] ]
: []) : [])

View File

@ -40,10 +40,13 @@
"Canceled": "Canceled", "Canceled": "Canceled",
"CreateProject": "Create project", "CreateProject": "Create project",
"NewProject": "New project", "NewProject": "New project",
"ProjectTitlePlaceholder": "Project title", "ProjectTitle": "Project title",
"Identifier": "Project Identifier", "ProjectTitlePlaceholder": "New project",
"UsedInIssueIDs": "Used in issue IDs",
"Identifier": "Identifier",
"ProjectIdentifier": "Project Identifier",
"IdentifierExists": "Project identifier already exists", "IdentifierExists": "Project identifier already exists",
"ProjectIdentifierPlaceholder": "Project Identifier", "ProjectIdentifierPlaceholder": "PRJCT",
"ChooseIcon": "Choose icon", "ChooseIcon": "Choose icon",
"AddIssue": "Add Issue", "AddIssue": "Add Issue",
"NewIssue": "New issue", "NewIssue": "New issue",
@ -78,7 +81,7 @@
"AssignTo": "Assign to...", "AssignTo": "Assign to...",
"AssignedTo": "Assigned to {value}", "AssignedTo": "Assigned to {value}",
"Parent": "Parent issue", "Parent": "Parent issue",
"SetParent": "Set parent issue", "SetParent": "Set parent issue\u2026",
"ChangeParent": "Change parent issue\u2026", "ChangeParent": "Change parent issue\u2026",
"RemoveParent": "Remove parent issue", "RemoveParent": "Remove parent issue",
"OpenParent": "Open parent issue", "OpenParent": "Open parent issue",
@ -93,7 +96,6 @@
"Labels": "Labels", "Labels": "Labels",
"Component": "Component", "Component": "Component",
"Space": "", "Space": "",
"NoDueDate": "No due date",
"SetDueDate": "Set due date\u2026", "SetDueDate": "Set due date\u2026",
"ChangeDueDate": "Change due date\u2026", "ChangeDueDate": "Change due date\u2026",
"ModificationDate": "Updated {value}", "ModificationDate": "Updated {value}",
@ -106,7 +108,7 @@
"TypeIssuePriority": "Issue priority", "TypeIssuePriority": "Issue priority",
"IssueTitlePlaceholder": "Issue title", "IssueTitlePlaceholder": "Issue title",
"SubIssueTitlePlaceholder": "Sub-issue title", "SubIssueTitlePlaceholder": "Sub-issue title",
"IssueDescriptionPlaceholder": "Add description", "IssueDescriptionPlaceholder": "Add description\u2026",
"SubIssueDescriptionPlaceholder": "Add sub-issue description", "SubIssueDescriptionPlaceholder": "Add sub-issue description",
"AddIssueTooltip": "Add issue...", "AddIssueTooltip": "Add issue...",
"NewIssueDialogClose": "Do you want to close this dialog?", "NewIssueDialogClose": "Do you want to close this dialog?",
@ -264,7 +266,7 @@
"CurrentWorkDay": "Current Working Day", "CurrentWorkDay": "Current Working Day",
"PreviousWorkDay": "Previous Working Day", "PreviousWorkDay": "Previous Working Day",
"TimeReportDayTypeLabel": "Select time report day type", "TimeReportDayTypeLabel": "Select time report day type",
"DefaultAssignee": "Select default assignee for issues", "DefaultAssignee": "Default assignee for issues",
"SevenHoursLength": "Seven Hours", "SevenHoursLength": "Seven Hours",
"EightHoursLength": "Eight Hours", "EightHoursLength": "Eight Hours",

View File

@ -40,10 +40,13 @@
"Canceled": "Отменено", "Canceled": "Отменено",
"CreateProject": "Создать проект", "CreateProject": "Создать проект",
"NewProject": "Новый проект", "NewProject": "Новый проект",
"ProjectTitlePlaceholder": "Название проекта", "ProjectTitle": "Название проекта",
"Identifier": "Идентификатор проекта", "ProjectTitlePlaceholder": "Новый проект",
"UsedInIssueIDs": "Используется в идентификаторах задач",
"Identifier": "Идентификатор",
"ProjectIdentifier": "Идентификатор проекта",
"IdentifierExists": "Идентификатор уже существует проекта", "IdentifierExists": "Идентификатор уже существует проекта",
"ProjectIdentifierPlaceholder": "Идентификатор проекта", "ProjectIdentifierPlaceholder": "ПКТ",
"ChooseIcon": "Выбрать иконку", "ChooseIcon": "Выбрать иконку",
"AddIssue": "Добавить задачу", "AddIssue": "Добавить задачу",
"NewIssue": "Новая задача", "NewIssue": "Новая задача",
@ -78,7 +81,7 @@
"AssignTo": "Назначить...", "AssignTo": "Назначить...",
"AssignedTo": "Назначен на {value}", "AssignedTo": "Назначен на {value}",
"Parent": "Родительская задача", "Parent": "Родительская задача",
"SetParent": "Задать родительскую задачу", "SetParent": "Задать родительскую задачу\u2026",
"ChangeParent": "Изменить родительскую задачу\u2026", "ChangeParent": "Изменить родительскую задачу\u2026",
"RemoveParent": "Удалить родительскую задачу", "RemoveParent": "Удалить родительскую задачу",
"OpenParent": "Открыть родительскую задачу", "OpenParent": "Открыть родительскую задачу",
@ -93,7 +96,6 @@
"Labels": "Метки", "Labels": "Метки",
"Component": "Компонент", "Component": "Компонент",
"Space": "", "Space": "",
"NoDueDate": "Нет срока выполнения",
"SetDueDate": "Указать срок выполнения\u2026", "SetDueDate": "Указать срок выполнения\u2026",
"ChangeDueDate": "Изменить срок выполнения\u2026", "ChangeDueDate": "Изменить срок выполнения\u2026",
"ModificationDate": "Изменено {value}", "ModificationDate": "Изменено {value}",
@ -106,7 +108,7 @@
"TypeIssuePriority": "Приоритет задачи", "TypeIssuePriority": "Приоритет задачи",
"IssueTitlePlaceholder": "Имя задачи", "IssueTitlePlaceholder": "Имя задачи",
"SubIssueTitlePlaceholder": "Имя подзадачи", "SubIssueTitlePlaceholder": "Имя подзадачи",
"IssueDescriptionPlaceholder": "Описание задачи", "IssueDescriptionPlaceholder": "Добавить описание\u2026",
"SubIssueDescriptionPlaceholder": "Описание подзадачи", "SubIssueDescriptionPlaceholder": "Описание подзадачи",
"AddIssueTooltip": "Добавить задачу\u2026", "AddIssueTooltip": "Добавить задачу\u2026",
"NewIssueDialogClose": "Вы действительно хотите закрыть окно?", "NewIssueDialogClose": "Вы действительно хотите закрыть окно?",
@ -264,7 +266,7 @@
"CurrentWorkDay": "Текущий Рабочий День", "CurrentWorkDay": "Текущий Рабочий День",
"PreviousWorkDay": "Предыдущий Рабочий День", "PreviousWorkDay": "Предыдущий Рабочий День",
"TimeReportDayTypeLabel": "Выберите тип дня для временного отчета", "TimeReportDayTypeLabel": "Выберите тип дня для временного отчета",
"DefaultAssignee": "Выберите исполнителя по умолчанию", "DefaultAssignee": "Исполнитель задачи по умолчанию",
"SevenHoursLength": "Семь Часов", "SevenHoursLength": "Семь Часов",
"EightHoursLength": "Восемь Часов", "EightHoursLength": "Восемь Часов",

View File

@ -587,7 +587,6 @@
alwaysEdit alwaysEdit
showButtons={false} showButtons={false}
kind={'indented'} kind={'indented'}
fakeAttach={'hidden'}
enableBackReferences={true} enableBackReferences={true}
bind:content={object.description} bind:content={object.description}
placeholder={tracker.string.IssueDescriptionPlaceholder} placeholder={tracker.string.IssueDescriptionPlaceholder}
@ -708,8 +707,7 @@
<div id="duedate-editor" class="new-line"> <div id="duedate-editor" class="new-line">
<DatePresenter <DatePresenter
bind:value={object.dueDate} bind:value={object.dueDate}
labelNull={tracker.string.NoDueDate} labelNull={tracker.string.DueDate}
icon={tracker.icon.DueDate}
kind={'secondary'} kind={'secondary'}
size={'large'} size={'large'}
editable editable

View File

@ -59,7 +59,7 @@
$: handleSelectedMilestoneIdUpdated(value, rawMilestones) $: handleSelectedMilestoneIdUpdated(value, rawMilestones)
$: translate(tracker.string.NoMilestone, {}).then((result) => (defaultMilestoneLabel = result)) $: translate(tracker.string.Milestone, {}).then((result) => (defaultMilestoneLabel = result))
const milestoneIcon = tracker.icon.Milestone const milestoneIcon = tracker.icon.Milestone
$: milestoneText = shouldShowLabel ? selectedMilestone?.label ?? defaultMilestoneLabel : undefined $: milestoneText = shouldShowLabel ? selectedMilestone?.label ?? defaultMilestoneLabel : undefined
@ -81,7 +81,7 @@
{ {
id: null, id: null,
icon: tracker.icon.Milestone, icon: tracker.icon.Milestone,
label: tracker.string.NoMilestone, label: tracker.string.Milestone,
isSelected: sp === undefined isSelected: sp === undefined
}, },
...rawMilestones.map((p) => ({ ...rawMilestones.map((p) => ({

View File

@ -25,7 +25,7 @@
</script> </script>
<Card <Card
label={projects.has(identifier) ? tracker.string.IdentifierExists : tracker.string.Identifier} label={projects.has(identifier) ? tracker.string.IdentifierExists : tracker.string.ProjectIdentifier}
okLabel={presentation.string.Save} okLabel={presentation.string.Save}
okAction={save} okAction={save}
canSave={identifier !== project.identifier && !projects.has(identifier)} canSave={identifier !== project.identifier && !projects.has(identifier)}

View File

@ -26,7 +26,7 @@
IconEdit, IconEdit,
IconWithEmojii, IconWithEmojii,
Label, Label,
ToggleWithLabel, Toggle,
eventToHTMLElement, eventToHTMLElement,
getColorNumberByText, getColorNumberByText,
getPlatformColorDef, getPlatformColorDef,
@ -184,92 +184,124 @@
okLabel={isNew ? presentation.string.Create : presentation.string.Save} okLabel={isNew ? presentation.string.Create : presentation.string.Save}
okAction={handleSave} okAction={handleSave}
canSave={name.length > 0 && !(members.length === 0 && isPrivate)} canSave={name.length > 0 && !(members.length === 0 && isPrivate)}
gap={'gapV-4'} accentHeader
width={'medium'}
gap={'gapV-6'}
on:close={() => { on:close={() => {
dispatch('close') dispatch('close')
}} }}
on:changeContent on:changeContent
> >
<div class="flex-row-center flex-between"> <div class="antiGrid">
<EditBox <div class="antiGrid-row">
bind:value={name} <div class="antiGrid-row__header">
placeholder={tracker.string.ProjectTitlePlaceholder} <Label label={tracker.string.ProjectTitle} />
kind={'large-style'} </div>
focus <div class="padding">
on:input={() => { <EditBox
if (isNew) { bind:value={name}
identifier = name.toLocaleUpperCase().replaceAll(' ', '_').substring(0, 5) placeholder={tracker.string.ProjectTitlePlaceholder}
} kind={'large-style'}
}} focus
/> on:input={() => {
<div class="flex-row-center"> if (isNew) {
<EditBox identifier = name.toLocaleUpperCase().replaceAll(' ', '_').substring(0, 5)
bind:value={identifier} }
disabled={!isNew}
placeholder={tracker.string.ProjectIdentifierPlaceholder}
kind={'large-style'}
/>
{#if !isNew}
<Button size={'small'} icon={IconEdit} on:click={changeIdentity} />
{/if}
</div>
</div>
<StyledTextBox
alwaysEdit
showButtons={false}
bind:content={description}
placeholder={tracker.string.IssueDescriptionPlaceholder}
/>
<ToggleWithLabel
label={presentation.string.MakePrivate}
description={presentation.string.MakePrivateDescription}
bind:on={isPrivate}
disabled={!isPrivate && members.length === 0}
/>
<div class="flex-between">
<div class="caption">
<Label label={tracker.string.ChooseIcon} />
</div>
<Button
icon={icon === tracker.component.IconWithEmojii ? IconWithEmojii : icon ?? tracker.icon.Home}
iconProps={icon === tracker.component.IconWithEmojii
? { icon: color }
: {
fill:
color !== undefined
? getPlatformColorDef(color, $themeStore.dark).icon
: getPlatformColorForTextDef(name, $themeStore.dark).icon
}} }}
kind="no-border" />
size="medium" </div>
on:click={chooseIcon} </div>
/>
<div class="antiGrid-row">
<div class="antiGrid-row__header withDesciption">
<Label label={tracker.string.Identifier} />
<span><Label label={tracker.string.UsedInIssueIDs} /></span>
</div>
<div class="padding flex-row-center">
<EditBox
bind:value={identifier}
disabled={!isNew}
placeholder={tracker.string.ProjectIdentifierPlaceholder}
kind={'large-style'}
uppercase
/>
{#if !isNew}
<Button size={'small'} icon={IconEdit} on:click={changeIdentity} />
{/if}
</div>
</div>
<div class="antiGrid-row">
<div class="antiGrid-row__header topAlign">
<Label label={tracker.string.Description} />
</div>
<div class="padding clear-mins">
<StyledTextBox
alwaysEdit
showButtons={false}
bind:content={description}
placeholder={tracker.string.IssueDescriptionPlaceholder}
/>
</div>
</div>
</div> </div>
<div class="flex-between"> <div class="antiGrid">
<div class="caption"> <div class="antiGrid-row">
<Label label={tracker.string.Members} /> <div class="antiGrid-row__header">
<Label label={tracker.string.ChooseIcon} />
</div>
<Button
icon={icon === tracker.component.IconWithEmojii ? IconWithEmojii : icon ?? tracker.icon.Home}
iconProps={icon === tracker.component.IconWithEmojii
? { icon: color }
: {
fill:
color !== undefined
? getPlatformColorDef(color, $themeStore.dark).icon
: getPlatformColorForTextDef(name, $themeStore.dark).icon
}}
size={'large'}
on:click={chooseIcon}
/>
</div> </div>
<AccountArrayEditor
value={members}
label={tracker.string.Members}
onChange={(refs) => (members = refs)}
kind="link-bordered"
/>
</div>
<div class="flex-between"> <div class="antiGrid-row">
<div class="caption"> <div class="antiGrid-row__header withDesciption">
<Label label={tracker.string.DefaultAssignee} /> <Label label={presentation.string.MakePrivate} />
<span><Label label={presentation.string.MakePrivateDescription} /></span>
</div>
<Toggle bind:on={isPrivate} disabled={!isPrivate && members.length === 0} />
</div>
<div class="antiGrid-row">
<div class="antiGrid-row__header">
<Label label={tracker.string.Members} />
</div>
<AccountArrayEditor
value={members}
label={tracker.string.Members}
onChange={(refs) => (members = refs)}
kind={'secondary'}
size={'large'}
/>
</div>
<div class="antiGrid-row">
<div class="antiGrid-row__header">
<Label label={tracker.string.DefaultAssignee} />
</div>
<AssigneeBox
label={tracker.string.Assignee}
placeholder={tracker.string.Assignee}
kind={'secondary'}
size={'large'}
avatarSize={'card'}
bind:value={defaultAssignee}
titleDeselect={tracker.string.Unassigned}
showNavigate={false}
showTooltip={{ label: tracker.string.DefaultAssignee }}
/>
</div> </div>
<AssigneeBox
label={tracker.string.Assignee}
placeholder={tracker.string.Assignee}
kind="link-bordered"
bind:value={defaultAssignee}
titleDeselect={tracker.string.Unassigned}
showNavigate={false}
showTooltip={{ label: tracker.string.DefaultAssignee }}
/>
</div> </div>
</Card> </Card>

View File

@ -66,6 +66,7 @@ export default mergeIds(trackerId, tracker, {
Canceled: '' as IntlString, Canceled: '' as IntlString,
CreateProject: '' as IntlString, CreateProject: '' as IntlString,
NewProject: '' as IntlString, NewProject: '' as IntlString,
ProjectTitle: '' as IntlString,
ProjectTitlePlaceholder: '' as IntlString, ProjectTitlePlaceholder: '' as IntlString,
ProjectIdentifierPlaceholder: '' as IntlString, ProjectIdentifierPlaceholder: '' as IntlString,
ChooseIcon: '' as IntlString, ChooseIcon: '' as IntlString,
@ -88,7 +89,9 @@ export default mergeIds(trackerId, tracker, {
Medium: '' as IntlString, Medium: '' as IntlString,
Low: '' as IntlString, Low: '' as IntlString,
Title: '' as IntlString, Title: '' as IntlString,
UsedInIssueIDs: '' as IntlString,
Identifier: '' as IntlString, Identifier: '' as IntlString,
ProjectIdentifier: '' as IntlString,
IdentifierExists: '' as IntlString, IdentifierExists: '' as IntlString,
Description: '' as IntlString, Description: '' as IntlString,
Status: '' as IntlString, Status: '' as IntlString,
@ -131,7 +134,6 @@ export default mergeIds(trackerId, tracker, {
Attachments: '' as IntlString, Attachments: '' as IntlString,
Labels: '' as IntlString, Labels: '' as IntlString,
Space: '' as IntlString, Space: '' as IntlString,
NoDueDate: '' as IntlString,
SetDueDate: '' as IntlString, SetDueDate: '' as IntlString,
ChangeDueDate: '' as IntlString, ChangeDueDate: '' as IntlString,
ModificationDate: '' as IntlString, ModificationDate: '' as IntlString,

View File

@ -140,10 +140,15 @@ test('report-time-from-issue-card', async ({ page }) => {
const random = Math.floor(Math.random() * values.length) const random = Math.floor(Math.random() * values.length)
const time = values[random] const time = values[random]
const name = getIssueName() const name = getIssueName()
await createIssue(page, { name, assignee, status }) try {
await page.waitForSelector(`text="${name}"`) await page.evaluate(() => localStorage.setItem('#platform.notification.timeout', '5000'))
await page.waitForSelector('text="View issue"') await createIssue(page, { name, assignee, status })
await page.click('text="View issue"') await page.waitForSelector(`text="${name}"`)
await page.waitForSelector('text="View issue"')
await page.click('text="View issue"')
} finally {
await page.evaluate(() => localStorage.setItem('#platform.notification.timeout', '1'))
}
await page.click('#ReportedTimeEditor') await page.click('#ReportedTimeEditor')
await page.waitForSelector('text="Time spend reports"') await page.waitForSelector('text="Time spend reports"')
@ -246,7 +251,7 @@ test('create-issue-draft', async ({ page }) => {
await page.locator('.ml-2 > .antiButton').click() await page.locator('.ml-2 > .antiButton').click()
// Click button:has-text("No due date") // Click button:has-text("No due date")
await page.locator('button:has-text("No due date")').click() await page.locator('button:has-text("Due date")').click()
// Click text=24 >> nth=0 // Click text=24 >> nth=0
await page.locator('.date-popup-container >> text=24').first().click() await page.locator('.date-popup-container >> text=24').first().click()

View File

@ -83,7 +83,7 @@ export async function fillIssueForm (page: Page, props: IssueProps): Promise<voi
await page.click(`.selectPopup button:has-text("${component}")`) await page.click(`.selectPopup button:has-text("${component}")`)
} }
if (milestone !== undefined) { if (milestone !== undefined) {
await page.click(af + '.antiButton:has-text("No Milestone")') await page.click(af + '.antiButton:has-text("Milestone")')
await page.click(`.selectPopup button:has-text("${milestone}")`) await page.click(`.selectPopup button:has-text("${milestone}")`)
} }
} }