From 835a37c6f04c6da4beb850bfb0de56efb2fd02a8 Mon Sep 17 00:00:00 2001 From: Alexander Platov <sas_lord@mail.ru> Date: Tue, 17 Jan 2023 04:07:05 +0300 Subject: [PATCH] Update EstimationPopup layout (#2513) --- packages/theme/styles/_layouts.scss | 27 ++++-- packages/theme/styles/common.scss | 3 + packages/theme/styles/dialogs.scss | 4 +- packages/ui/src/components/Chevron.svelte | 85 ++++++++++++++++++ .../ui/src/components/ExpandCollapse.svelte | 2 +- packages/ui/src/components/Expandable.svelte | 73 +++++++++------- packages/ui/src/components/ListView.svelte | 4 +- .../src/components/icons/DownOutline.svelte | 2 +- packages/ui/src/index.ts | 1 + .../src/components/EntityMapping.svelte | 4 +- .../FieldMappingSynchronizer.svelte | 69 ++++++++------- .../components/issues/edit/SubIssues.svelte | 14 +-- .../issues/timereport/EstimationPopup.svelte | 21 ++--- .../timereport/EstimationSubIssueList.svelte | 76 ++++++---------- .../timereport/SubIssuesEstimations.svelte | 14 +-- .../timereport/TimeReportDayDropdown.svelte | 4 +- .../timereport/TimeSpendReportPopup.svelte | 18 ++-- .../issues/timereport/TimeSpendReports.svelte | 18 ++-- .../timereport/TimeSpendReportsList.svelte | 86 +++++++------------ .../src/components/FixedColumn.svelte | 3 +- 20 files changed, 301 insertions(+), 227 deletions(-) create mode 100644 packages/ui/src/components/Chevron.svelte diff --git a/packages/theme/styles/_layouts.scss b/packages/theme/styles/_layouts.scss index fb202b6e21..980ff21b30 100644 --- a/packages/theme/styles/_layouts.scss +++ b/packages/theme/styles/_layouts.scss @@ -381,11 +381,6 @@ input.search { } /* Margins & Paddings */ -.step-lr25 + .step-lr25 { margin-left: .25rem; } -.step-lr75 + .step-lr75 { margin-left: .75rem; } -.step-tb75 + .step-tb75 { margin-top: .75rem; } -.step-tb-6 + .step-tb-6 { margin-top: 1.5rem; } - .ml-0-5 { margin-left: .125rem; } .ml-1 { margin-left: .25rem; } .ml-1-5 { margin-left: .375rem; } @@ -476,6 +471,28 @@ input.search { .p-6 { padding: 1.5rem; } .p-10 { padding: 2.5rem; } +.p-text { padding: .125rem .25rem; } +.p-text-2 { padding: .25rem .5rem; } + +.step-lr25 + .step-lr25 { margin-left: .25rem; } +.step-lr75 + .step-lr75 { margin-left: .75rem; } +.step-tb75 + .step-tb75 { margin-top: .75rem; } +.step-tb-6 + .step-tb-6 { margin-top: 1.5rem; } + +.step-tb-2-accent + .step-tb-2-accent { + position: relative; + margin-top: .5rem; + &::before { + content: ''; + position: absolute; + top: -.25rem; + left: 0; + width: 100%; + height: 1px; + background-color: var(--popup-bg-hover); + } +} + /* --------- */ .no-word-wrap { word-wrap: none; } .relative { position: relative; } diff --git a/packages/theme/styles/common.scss b/packages/theme/styles/common.scss index 0655b57b6f..b37399b398 100644 --- a/packages/theme/styles/common.scss +++ b/packages/theme/styles/common.scss @@ -275,6 +275,9 @@ min-height: 1px; height: 1px; background-color: var(--divider-color); + + &.dark { background-color: var(--body-accent); } + &.noMargin { margin: 0; } } .antiSection { diff --git a/packages/theme/styles/dialogs.scss b/packages/theme/styles/dialogs.scss index 119d21da8c..b827aea51f 100644 --- a/packages/theme/styles/dialogs.scss +++ b/packages/theme/styles/dialogs.scss @@ -173,10 +173,10 @@ .antiCard-pool { flex-direction: row; align-items: center; - margin: 0 .75rem .75rem; + margin: 0 .5rem .25rem; font-size: .75rem; - & > *:not(:last-child) { margin-right: .375rem; } + & > * { margin: 0 .25rem .5rem; } } .antiCard-footer { direction: ltr; diff --git a/packages/ui/src/components/Chevron.svelte b/packages/ui/src/components/Chevron.svelte new file mode 100644 index 0000000000..06dd53004f --- /dev/null +++ b/packages/ui/src/components/Chevron.svelte @@ -0,0 +1,85 @@ +<!-- +// Copyright © 2022 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +--> +<script lang="ts"> + import IconDownOutline from './icons/DownOutline.svelte' + + export let size: 'small' | 'medium' = 'medium' + export let fill = 'var(--dark-color)' + export let expanded: boolean = false + export let direction: 'left' | 'right' = 'right' + export let outline: boolean = false + export let marginRight: string | undefined = undefined + export let marginLeft: string | undefined = undefined + export let margin: string | undefined = undefined +</script> + +<div + class="chevron {size} {direction}" + class:outline + class:expanded + style:margin-right={marginRight} + style:margin-left={marginLeft} + style:margin +> + {#if outline} + <IconDownOutline {size} {fill} /> + {:else} + <svg {fill} viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg"> + <path d="M0,0L6,3L0,6Z" /> + </svg> + {/if} +</div> + +<style lang="scss"> + .chevron { + flex-shrink: 0; + transition: transform 0.15s var(--timing-main); + + &.outline { + transform-origin: center; + &.right { + transform: rotate(-90deg); + } + &.left { + transform: rotate(90deg); + } + &.expanded { + transform: rotate(0deg); + } + } + &:not(.outline) { + transform-origin: 35% center; + transform: rotate(0deg); + + &.small { + width: 0.325rem; + height: 0.325rem; + } + &.medium { + width: 0.375rem; + height: 0.375rem; + } + &.right { + transform: rotate(0deg); + } + &.left { + transform: rotate(180deg); + } + &.expanded { + transform: rotate(90deg); + } + } + } +</style> diff --git a/packages/ui/src/components/ExpandCollapse.svelte b/packages/ui/src/components/ExpandCollapse.svelte index 1ffcd64d1f..540be85b44 100644 --- a/packages/ui/src/components/ExpandCollapse.svelte +++ b/packages/ui/src/components/ExpandCollapse.svelte @@ -18,7 +18,7 @@ import { tweened } from 'svelte/motion' export let isExpanded = false - export let duration = 200 + export let duration = 150 export let easing: (t: number) => number = quintOut const dispatch = createEventDispatcher() diff --git a/packages/ui/src/components/Expandable.svelte b/packages/ui/src/components/Expandable.svelte index f23ddf82c7..98866f779f 100644 --- a/packages/ui/src/components/Expandable.svelte +++ b/packages/ui/src/components/Expandable.svelte @@ -17,51 +17,62 @@ import ExpandCollapse from './ExpandCollapse.svelte' import Icon from './Icon.svelte' import Label from './Label.svelte' + import Chevron from './Chevron.svelte' export let icon: Asset | undefined = undefined export let label: IntlString | undefined = undefined export let expanded: boolean = false + export let bordered: boolean = false export let expandable = true + export let contentColor = false </script> -<!-- svelte-ignore a11y-mouse-events-have-key-events --> -<!-- svelte-ignore a11y-click-events-have-key-events --> -<div class="flex-grow flex" class:expanded class:expandable> - <div - class="fs-title flex-row-center mr-4" - on:click|stopPropagation={() => { - expanded = !expanded - }} - > - <div class="chevron" class:expanded>▶</div> - <div class="an-element__icon"> +<div class="flex-col"> + <div class="expandable-header flex-between" class:expanded class:bordered> + <!-- svelte-ignore a11y-click-events-have-key-events --> + <div + class="flex-row-center mr-4" + class:cursor-pointer={expandable} + on:click|stopPropagation={() => { + if (expandable) expanded = !expanded + }} + > + <Chevron {expanded} marginRight={'.5rem'} /> {#if icon} - <Icon {icon} size={'small'} /> + <div class="min-w-4 mr-2"> + <Icon {icon} size={'small'} /> + </div> {/if} + <span class="fs-title overflow-label" class:content-color={contentColor}> + {#if label}<Label {label} />{/if}<slot name="title" /> + </span> </div> - <span class="an-element__label title"> - {#if label}<Label {label} />{/if} - <slot name="title" /> - </span> + {#if $$slots.tools} + <div class="buttons-group small-gap"> + <slot name="tools" /> + </div> + {/if} </div> - <slot name="tools" /> -</div> -<ExpandCollapse isExpanded={expanded}> - <div class="antiComponent p-2"> + <ExpandCollapse isExpanded={expanded}> <slot /> - </div> -</ExpandCollapse> + </ExpandCollapse> +</div> <style lang="scss"> - .expandable { - .chevron { - content: '▶'; - margin-right: 0.5rem; - font-size: 0.75rem; - color: var(--dark-color); - &.expanded { - transform: rotateZ(90deg); - } + .expandable-header { + transition: margin-bottom 0.15s var(--timing-main); + + &:not(.expanded) { + margin-bottom: 0; + } + &.expanded { + margin-bottom: 0.75rem; + } + &.bordered { + padding: 0.25rem 0.5rem; + background-color: var(--body-accent); + border: 1px solid var(--divider-color); + border-radius: 0.25rem; } } </style> diff --git a/packages/ui/src/components/ListView.svelte b/packages/ui/src/components/ListView.svelte index 36a1ab452b..b114942bad 100644 --- a/packages/ui/src/components/ListView.svelte +++ b/packages/ui/src/components/ListView.svelte @@ -18,6 +18,7 @@ export let selection: number = 0 export let count: number + export let addClass: string | undefined = undefined const refs: HTMLElement[] = [] @@ -66,8 +67,9 @@ > {#each Array(count) as _, row} <slot name="category" item={row} /> + <!-- svelte-ignore a11y-click-events-have-key-events --> <div - class="list-item" + class="list-item{addClass ? ` ${addClass}` : ''}" class:selection={row === selection} on:mouseover={() => onRow(row)} on:focus={() => {}} diff --git a/packages/ui/src/components/icons/DownOutline.svelte b/packages/ui/src/components/icons/DownOutline.svelte index ee3b5954f7..b8dcda616e 100644 --- a/packages/ui/src/components/icons/DownOutline.svelte +++ b/packages/ui/src/components/icons/DownOutline.svelte @@ -1,6 +1,6 @@ <script lang="ts"> export let size: 'x-small' | 'small' | 'medium' | 'large' | 'full' - const fill: string = 'currentColor' + export let fill: string = 'currentColor' </script> <svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 269e7f083d..13dcc14e52 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -99,6 +99,7 @@ export { default as ErrorPresenter } from './components/ErrorPresenter.svelte' export { default as Scroller } from './components/Scroller.svelte' export { default as ScrollerBar } from './components/ScrollerBar.svelte' export { default as TabList } from './components/TabList.svelte' +export { default as Chevron } from './components/Chevron.svelte' export { default as IconAdd } from './components/icons/Add.svelte' export { default as IconBack } from './components/icons/Back.svelte' diff --git a/plugins/bitrix-resources/src/components/EntityMapping.svelte b/plugins/bitrix-resources/src/components/EntityMapping.svelte index 77257794d7..2d1824c7be 100644 --- a/plugins/bitrix-resources/src/components/EntityMapping.svelte +++ b/plugins/bitrix-resources/src/components/EntityMapping.svelte @@ -75,9 +75,7 @@ <div class="antiComponent max-w-240 flex-grow p-1"> <Expandable icon={ofClass?.icon} label={getEmbeddedLabel(typeTitle?.label ?? '')}> <svelte:fragment slot="tools"> - <div class="flex flex-reverse flex-grow"> - <Button icon={IconDelete} on:click={() => client.remove(mapping)} size={'small'} /> - </div> + <Button icon={IconDelete} on:click={() => client.remove(mapping)} size={'small'} /> </svelte:fragment> <Expandable label={getEmbeddedLabel('Options')}> <div class="flex-col"> diff --git a/plugins/bitrix-resources/src/components/FieldMappingSynchronizer.svelte b/plugins/bitrix-resources/src/components/FieldMappingSynchronizer.svelte index e14de729e8..85cce34098 100644 --- a/plugins/bitrix-resources/src/components/FieldMappingSynchronizer.svelte +++ b/plugins/bitrix-resources/src/components/FieldMappingSynchronizer.svelte @@ -323,44 +323,43 @@ <Expandable label={getEmbeddedLabel(mapping.type)}> <svelte:fragment slot="tools"> - <div class="flex-row-center"> - <SpaceSelect - _class={core.class.Space} - label={core.string.Space} - bind:value={space} - on:change={(evt) => { - space = evt.detail + <SpaceSelect + _class={core.class.Space} + label={core.string.Space} + bind:value={space} + on:change={(evt) => { + space = evt.detail + }} + autoSelect + spaceQuery={{ _id: { $in: [contact.space.Contacts] } }} + /> + <DropdownLabels + label={getEmbeddedLabel('Direction')} + items={[ + { id: 'ASC', label: 'Ascending' }, + { id: 'DSC', label: 'Descending' } + ]} + bind:selected={direction} + /> + <div class="fs-title"> + <NumberEditor + kind={'button'} + value={limit} + focus={false} + placeholder={getEmbeddedLabel('Limit')} + onChange={(val) => { + if (val) { + limit = val + } }} - autoSelect - spaceQuery={{ _id: { $in: [contact.space.Contacts] } }} /> - <DropdownLabels - label={getEmbeddedLabel('Direction')} - items={[ - { id: 'ASC', label: 'Ascending' }, - { id: 'DSC', label: 'Descending' } - ]} - bind:selected={direction} - /> - <div class="fs-title flex-row-center"> - <NumberEditor - kind={'button'} - value={limit} - focus={false} - placeholder={getEmbeddedLabel('Limit')} - onChange={(val) => { - if (val) { - limit = val - } - }} - /> - </div> - <div class="ml-2 flex-row-center"> - <div class="p-1"> - {state} - </div> - <Button size={'large'} label={getEmbeddedLabel('Synchronize')} {loading} on:click={doSync} /> + </div> + <div class="buttons-divider" /> + <div class="flex-row-center"> + <div class="p-1"> + {state} </div> + <Button size={'large'} label={getEmbeddedLabel('Synchronize')} {loading} on:click={doSync} /> </div> </svelte:fragment> <div class="flex-row flex-grow bottom-divider p-2"> diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssues.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssues.svelte index 87d633e428..6ab8d78e8a 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssues.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssues.svelte @@ -16,10 +16,8 @@ import { Ref, SortingOrder, WithLookup } from '@hcengineering/core' import { createQuery, getClient } from '@hcengineering/presentation' import { calcRank, Issue, IssueStatus, Team } from '@hcengineering/tracker' - import { Button, Spinner, ExpandCollapse, closeTooltip, IconAdd } from '@hcengineering/ui' + import { Button, Spinner, ExpandCollapse, closeTooltip, IconAdd, Chevron, Label } from '@hcengineering/ui' import tracker from '../../../plugin' - import Collapsed from '../../icons/Collapsed.svelte' - import Expanded from '../../icons/Expanded.svelte' import CreateSubIssue from './CreateSubIssue.svelte' import SubIssueList from './SubIssueList.svelte' @@ -62,16 +60,18 @@ {#if hasSubIssues} <Button width="min-content" - icon={isCollapsed ? Collapsed : Expanded} size="small" kind="transparent" - label={tracker.string.SubIssuesList} - labelParams={{ subIssues: issue.subIssues }} on:click={() => { isCollapsed = !isCollapsed isCreating = false }} - /> + > + <svelte:fragment slot="content"> + <Chevron size={'small'} expanded={!isCollapsed} outline fill={'var(--caption-color)'} marginRight={'.375rem'} /> + <Label label={tracker.string.SubIssuesList} params={{ subIssues: issue.subIssues }} /> + </svelte:fragment> + </Button> {/if} <Button diff --git a/plugins/tracker-resources/src/components/issues/timereport/EstimationPopup.svelte b/plugins/tracker-resources/src/components/issues/timereport/EstimationPopup.svelte index d333c70e3b..5994500e8f 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/EstimationPopup.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/EstimationPopup.svelte @@ -120,9 +120,6 @@ <IssuePresenter value={object} disableClick /> </svelte:fragment> - <div class="header no-border flex-col p-1"> - <div class="flex-row-center flex-between" /> - </div> {#if currentTeam && issueStatuses} <SubIssuesEstimations issue={object} @@ -143,13 +140,17 @@ icon={IconAdd} size={'small'} on:click={(event) => { - showPopup(TimeSpendReportPopup, { - issueId: object._id, - issueClass: object._class, - space: object.space, - assignee: object.assignee, - defaultTimeReportDay - }) + showPopup( + TimeSpendReportPopup, + { + issueId: object._id, + issueClass: object._class, + space: object.space, + assignee: object.assignee, + defaultTimeReportDay + }, + 'top' + ) }} label={tracker.string.TimeSpendReportAdd} /> diff --git a/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte b/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte index da202ffdfd..843b4348d9 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/EstimationSubIssueList.svelte @@ -17,7 +17,7 @@ import { Doc, Ref } from '@hcengineering/core' import { UserBox } from '@hcengineering/presentation' import { Issue, Team } from '@hcengineering/tracker' - import { getEventPositionElement, ListView, showPopup } from '@hcengineering/ui' + import { getEventPositionElement, ListView, showPopup, deviceOptionsStore as deviceInfo } from '@hcengineering/ui' import { ContextMenu, FixedColumn, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources' import { getIssueId } from '../../../issues' import tracker from '../../../plugin' @@ -28,18 +28,19 @@ export let teams: Map<Ref<Team>, Team> function showContextMenu (ev: MouseEvent, object: Issue) { - showPopup(ContextMenu, { object }, getEventPositionElement(ev)) + showPopup(ContextMenu, { object }, $deviceInfo.isMobile ? 'top' : getEventPositionElement(ev)) } const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {}) + $: twoRows = $deviceInfo.twoRows </script> -<ListView count={issues.length}> +<ListView count={issues.length} addClass={'step-tb-2-accent'}> <svelte:fragment slot="item" let:item> {@const issue = issues[item]} {@const currentTeam = teams.get(issue.space)} <div - class="flex-between row" + class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2" on:contextmenu|preventDefault={(ev) => showContextMenu(ev, issue)} on:mouseover={() => { listProvider.updateFocus(issue) @@ -48,55 +49,32 @@ listProvider.updateFocus(issue) }} > - <div class="flex-row-center clear-mins gap-2 p-2 flex-grow"> - <span class="issuePresenter"> - <FixedColumn key={'estimation_issue'} justify={'left'}> - {#if currentTeam} - {getIssueId(currentTeam, issue)} - {/if} - </FixedColumn> - </span> - <span class="text name" title={issue.title}> + <div class="flex-row-center clear-mins gap-2 flex-grow mr-4" class:p-text={twoRows}> + <FixedColumn key={'estimation_issue'} justify={'left'} addClass={'fs-bold'}> + {#if currentTeam} + {getIssueId(currentTeam, issue)} + {/if} + </FixedColumn> + <span class="overflow-label fs-bold caption-color" title={issue.title}> {issue.title} </span> </div> - <FixedColumn key={'estimation_issue_assignee'} justify={'right'}> - <UserBox - width={'100%'} - label={tracker.string.Assignee} - _class={contact.class.Employee} - value={issue.assignee} - readonly - showNavigate={false} - /> - </FixedColumn> - <FixedColumn key={'estimation'} justify={'left'}> - <EstimationEditor value={issue} kind={'list'} /> - </FixedColumn> + <div class="flex-row-center clear-mins gap-2 self-end" class:p-text={twoRows}> + <FixedColumn key={'estimation_issue_assignee'} justify={'right'}> + <UserBox + width={'100%'} + label={tracker.string.Assignee} + _class={contact.class.Employee} + value={issue.assignee} + readonly + showNavigate={false} + /> + </FixedColumn> + <FixedColumn key={'estimation'} justify={'left'}> + <EstimationEditor value={issue} kind={'list'} /> + </FixedColumn> + </div> </div> </svelte:fragment> </ListView> - -<style lang="scss"> - .row { - .text { - font-weight: 500; - color: var(--caption-color); - } - - .issuePresenter { - flex-shrink: 0; - min-width: 0; - min-height: 0; - font-weight: 500; - color: var(--content-color); - } - - .name { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - } -</style> diff --git a/plugins/tracker-resources/src/components/issues/timereport/SubIssuesEstimations.svelte b/plugins/tracker-resources/src/components/issues/timereport/SubIssuesEstimations.svelte index e8689c12e0..556dadb62e 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/SubIssuesEstimations.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/SubIssuesEstimations.svelte @@ -16,7 +16,7 @@ import { Ref, SortingOrder, WithLookup } from '@hcengineering/core' import { createQuery } from '@hcengineering/presentation' import { Issue, IssueStatus, Team } from '@hcengineering/tracker' - import { Scroller, Spinner } from '@hcengineering/ui' + import { Spinner } from '@hcengineering/ui' import Expandable from '@hcengineering/ui/src/components/Expandable.svelte' import tracker from '../../../plugin' import EstimationSubIssueList from './EstimationSubIssueList.svelte' @@ -38,15 +38,9 @@ {#if subIssues && issueStatuses} {#if hasSubIssues} - <Expandable label={tracker.string.ChildEstimation}> - <svelte:fragment slot="title"> - : {total} - </svelte:fragment> - <div class="h-50"> - <Scroller> - <EstimationSubIssueList issues={subIssues} {teams} /> - </Scroller> - </div> + <Expandable label={tracker.string.ChildEstimation} contentColor bordered> + <svelte:fragment slot="title">: <span class="caption-color">{total}</span></svelte:fragment> + <EstimationSubIssueList issues={subIssues} {teams} /> </Expandable> {/if} {:else} diff --git a/plugins/tracker-resources/src/components/issues/timereport/TimeReportDayDropdown.svelte b/plugins/tracker-resources/src/components/issues/timereport/TimeReportDayDropdown.svelte index 1c97dec981..fccde324e3 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/TimeReportDayDropdown.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/TimeReportDayDropdown.svelte @@ -15,11 +15,13 @@ <script lang="ts"> import { TimeReportDayType } from '@hcengineering/tracker' import { DropdownIntlItem, DropdownLabelsIntl } from '@hcengineering/ui' + import type { ButtonKind } from '@hcengineering/ui' import tracker from '../../../plugin' import TimeReportDayIcon from './TimeReportDayIcon.svelte' export let label = tracker.string.TimeReportDayTypeLabel export let selected: TimeReportDayType | undefined + export let kind: ButtonKind = 'link-bordered' const workDaysDropdownItems: DropdownIntlItem[] = [ { @@ -34,7 +36,7 @@ </script> <DropdownLabelsIntl - kind="link-bordered" + {kind} icon={TimeReportDayIcon} shouldUpdateUndefined={false} {label} diff --git a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportPopup.svelte b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportPopup.svelte index c3e15265d5..c8ef856a53 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportPopup.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportPopup.svelte @@ -18,7 +18,7 @@ import type { IntlString } from '@hcengineering/platform' import presentation, { Card, getClient, UserBox } from '@hcengineering/presentation' import { Issue, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker' - import { DatePresenter, EditBox } from '@hcengineering/ui' + import { DatePresenter, EditBox, Button } from '@hcengineering/ui' import tracker from '../../../plugin' import { getTimeReportDate, getTimeReportDayType } from '../../../utils' import TimeReportDayDropdown from './TimeReportDayDropdown.svelte' @@ -85,23 +85,31 @@ > <div class="flex-row-center gap-2"> <EditBox focus bind:value={data.value} {placeholder} format={'number'} maxDigitsAfterPoint={3} kind={'editbox'} /> + <Button kind={'link-bordered'} on:click={() => (data.value = 0.125)}><span slot="content">1/8</span></Button> + <Button kind={'link-bordered'} on:click={() => (data.value = 0.25)}><span slot="content">1/4</span></Button> + <Button kind={'link-bordered'} on:click={() => (data.value = 0.5)}><span slot="content">1/2</span></Button> + <Button kind={'link-bordered'} on:click={() => (data.value = 0.75)}><span slot="content">3/4</span></Button> + <div class="buttons-divider" /> + <Button kind={'link-bordered'} on:click={() => (data.value = 1)}><span slot="content">1</span></Button> + </div> + <EditBox bind:value={data.description} placeholder={tracker.string.TimeSpendReportDescription} kind={'editbox'} /> + <svelte:fragment slot="pool"> <UserBox _class={contact.class.Employee} label={contact.string.Employee} - kind={'link-bordered'} + kind={'no-border'} bind:value={data.employee} showNavigate={false} /> <TimeReportDayDropdown + kind={'no-border'} bind:selected={selectedTimeReportDay} on:selected={({ detail }) => (data.date = getTimeReportDate(detail))} /> <DatePresenter - kind={'link'} bind:value={data.date} editable on:change={({ detail }) => (selectedTimeReportDay = getTimeReportDayType(detail))} /> - </div> - <EditBox bind:value={data.description} placeholder={tracker.string.TimeSpendReportDescription} kind={'editbox'} /> + </svelte:fragment> </Card> diff --git a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReports.svelte b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReports.svelte index cda62950e0..ae836d683a 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReports.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReports.svelte @@ -16,7 +16,7 @@ import { DocumentQuery, Ref, SortingOrder } from '@hcengineering/core' import { createQuery } from '@hcengineering/presentation' import { Issue, Team, TimeSpendReport } from '@hcengineering/tracker' - import { Expandable, floorFractionDigits, Label, Scroller, Spinner } from '@hcengineering/ui' + import { Expandable, floorFractionDigits, Label, Spinner } from '@hcengineering/ui' import tracker from '../../../plugin' import TimePresenter from './TimePresenter.svelte' import TimeSpendReportsList from './TimeSpendReportsList.svelte' @@ -42,21 +42,19 @@ </script> {#if reports} - <Expandable expanded={true}> + <Expandable expanded={true} contentColor bordered> <svelte:fragment slot="title"> <span class="overflow-label flex-nowrap"> - <Label label={tracker.string.ReportedTime} />: <TimePresenter value={reportedTime} {workDayLength} /> - <Label label={tracker.string.TimeSpendReports} />: <TimePresenter value={total} {workDayLength} /> + <Label label={tracker.string.ReportedTime} />: + <span class="caption-color"><TimePresenter value={reportedTime} {workDayLength} /></span>. + <Label label={tracker.string.TimeSpendReports} />: + <span class="caption-color"><TimePresenter value={total} {workDayLength} /></span> </span> </svelte:fragment> - <div class="h-50"> - <Scroller> - <TimeSpendReportsList {reports} {teams} /> - </Scroller> - </div> + <TimeSpendReportsList {reports} {teams} /> </Expandable> {:else} - <div class="flex-center pt-3"> + <div class="flex-center"> <Spinner /> </div> {/if} diff --git a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte index 713e3f9ca4..f99db970ce 100644 --- a/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte +++ b/plugins/tracker-resources/src/components/issues/timereport/TimeSpendReportsList.svelte @@ -18,6 +18,7 @@ import UserBox from '@hcengineering/presentation/src/components/UserBox.svelte' import { Team, TimeReportDayType, TimeSpendReport } from '@hcengineering/tracker' import { eventToHTMLElement, getEventPositionElement, ListView, showPopup } from '@hcengineering/ui' + import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' import DatePresenter from '@hcengineering/ui/src/components/calendar/DatePresenter.svelte' import { ContextMenu, FixedColumn, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources' import { getIssueId } from '../../../issues' @@ -51,18 +52,19 @@ assignee: value.employee, defaultTimeReportDay }, - eventToHTMLElement(event) + $deviceInfo.isMobile ? 'top' : eventToHTMLElement(event) ) } + $: twoRows = $deviceInfo.twoRows </script> <!-- svelte-ignore a11y-click-events-have-key-events --> -<ListView count={reports.length}> +<ListView count={reports.length} addClass={'step-tb-2-accent'}> <svelte:fragment slot="item" let:item> {@const report = reports[item]} {@const currentTeam = teams.get(toTeamId(report.space))} <div - class="flex-between row" + class="{twoRows ? 'flex-col' : 'flex-between'} p-text-2" on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)} on:mouseover={() => { listProvider.updateFocus(report) @@ -72,62 +74,36 @@ }} on:click={(evt) => editSpendReport(evt, report, currentTeam?.defaultTimeReportDay)} > - <div class="flex-row-center clear-mins gap-2 p-2 flex-grow"> - <span class="issuePresenter"> - <FixedColumn key={'tmiespend_issue'} justify={'left'}> - {#if currentTeam && report.$lookup?.attachedTo} - {getIssueId(currentTeam, report.$lookup?.attachedTo)} - {/if} - </FixedColumn> - </span> + <div class="flex-row-center clear-mins gap-2 flex-grow mr-4" class:p-text={twoRows}> + <FixedColumn key={'tmiespend_issue'} justify={'left'} addClass={'fs-bold'}> + {#if currentTeam && report.$lookup?.attachedTo} + {getIssueId(currentTeam, report.$lookup?.attachedTo)} + {/if} + </FixedColumn> {#if report.$lookup?.attachedTo?.title} - <span class="text name" title={report.$lookup?.attachedTo?.title}> + <span class="overflow-label fs-bold caption-color" title={report.$lookup?.attachedTo?.title}> {report.$lookup?.attachedTo?.title} </span> {/if} </div> - <FixedColumn key={'timespend_assignee'} justify={'left'}> - <UserBox - width={'100%'} - label={tracker.string.Assignee} - _class={contact.class.Employee} - value={report.employee} - readonly - showNavigate={false} - /> - </FixedColumn> - - <FixedColumn key={'timespend_reported'} justify={'center'}> - <div class="p-1"> + <div class="flex-row-center clear-mins gap-2 self-end" class:p-text={twoRows}> + <FixedColumn key={'timespend_assignee'} justify={'left'}> + <UserBox + width={'100%'} + label={tracker.string.Assignee} + _class={contact.class.Employee} + value={report.employee} + readonly + showNavigate={false} + /> + </FixedColumn> + <FixedColumn key={'timespend_reported'} justify={'center'}> <TimePresenter value={report.value} workDayLength={currentTeam?.workDayLength} /> - </div> - </FixedColumn> - <FixedColumn key={'timespend_date'} justify={'left'}> - <DatePresenter value={report.date} /> - </FixedColumn> - </div> - </svelte:fragment> + </FixedColumn> + <FixedColumn key={'timespend_date'} justify={'left'}> + <DatePresenter value={report.date} /> + </FixedColumn> + </div> + </div></svelte:fragment + > </ListView> - -<style lang="scss"> - .row { - .text { - font-weight: 500; - color: var(--caption-color); - } - - .issuePresenter { - flex-shrink: 0; - min-width: 0; - min-height: 0; - font-weight: 500; - color: var(--content-color); - } - - .name { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - } -</style> diff --git a/plugins/view-resources/src/components/FixedColumn.svelte b/plugins/view-resources/src/components/FixedColumn.svelte index 840d159b08..1654c50780 100644 --- a/plugins/view-resources/src/components/FixedColumn.svelte +++ b/plugins/view-resources/src/components/FixedColumn.svelte @@ -20,6 +20,7 @@ export let key: string export let justify: string = '' + export let addClass: string | undefined = undefined let prevKey = key let element: HTMLDivElement | undefined @@ -48,7 +49,7 @@ <div bind:this={element} - class="flex-no-shrink" + class="flex-no-shrink{addClass ? ` ${addClass}` : ''}" style="{justify !== '' ? `text-align: ${justify}; ` : ''} min-width: {$fixedWidthStore[key] ?? 0}px;" use:resizeObserver={resize} >