mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 08:57:14 +03:00
UBER-504: fix presenters on ListItem. Add DeviceSizes. (#3463)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
dbfbcc12ee
commit
c7ade707c6
@ -474,14 +474,19 @@ export function createModel (builder: Builder): void {
|
||||
props: {},
|
||||
displayProps: { key: 'title' }
|
||||
},
|
||||
{ key: 'comments', displayProps: { key: 'comments' } },
|
||||
{ key: 'attachments', displayProps: { key: 'attachments' } },
|
||||
{ key: '', label: tracker.string.SubIssues, presenter: tracker.component.SubIssuesSelector, props: {} },
|
||||
{
|
||||
key: '',
|
||||
label: tracker.string.SubIssues,
|
||||
presenter: tracker.component.SubIssuesSelector,
|
||||
props: {}
|
||||
},
|
||||
{ key: 'comments', displayProps: { key: 'comments', suffix: true } },
|
||||
{ key: 'attachments', displayProps: { key: 'attachments', suffix: true } },
|
||||
{ key: '', displayProps: { grow: true } },
|
||||
{
|
||||
key: 'labels',
|
||||
presenter: tags.component.LabelsPresenter,
|
||||
displayProps: { optional: true, compression: true },
|
||||
displayProps: { optional: true },
|
||||
props: { kind: 'list', full: false }
|
||||
},
|
||||
{
|
||||
@ -497,7 +502,6 @@ export function createModel (builder: Builder): void {
|
||||
displayProps: {
|
||||
key: 'milestone',
|
||||
excludeByKey: 'milestone',
|
||||
compression: true,
|
||||
optional: true
|
||||
}
|
||||
},
|
||||
@ -514,7 +518,6 @@ export function createModel (builder: Builder): void {
|
||||
displayProps: {
|
||||
key: 'component',
|
||||
excludeByKey: 'component',
|
||||
compression: true,
|
||||
optional: true
|
||||
}
|
||||
},
|
||||
@ -522,7 +525,7 @@ export function createModel (builder: Builder): void {
|
||||
key: '',
|
||||
label: tracker.string.DueDate,
|
||||
presenter: tracker.component.DueDatePresenter,
|
||||
displayProps: { key: 'dueDate', optional: true, compression: true },
|
||||
displayProps: { key: 'dueDate', optional: true },
|
||||
props: { kind: 'list' }
|
||||
},
|
||||
{
|
||||
@ -530,7 +533,7 @@ export function createModel (builder: Builder): void {
|
||||
label: tracker.string.Estimation,
|
||||
presenter: tracker.component.EstimationEditor,
|
||||
props: { kind: 'list', size: 'small' },
|
||||
displayProps: { key: 'estimation', fixed: 'left', compression: true, dividerBefore: true }
|
||||
displayProps: { key: 'estimation', fixed: 'left', dividerBefore: true }
|
||||
},
|
||||
{
|
||||
key: 'modifiedOn',
|
||||
@ -697,7 +700,7 @@ export function createModel (builder: Builder): void {
|
||||
size: 'small',
|
||||
shouldShowPlaceholder: false
|
||||
},
|
||||
displayProps: { key: 'component', optional: true, compression: true }
|
||||
displayProps: { key: 'component', optional: true }
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
@ -708,7 +711,7 @@ export function createModel (builder: Builder): void {
|
||||
size: 'small',
|
||||
shouldShowPlaceholder: false
|
||||
},
|
||||
displayProps: { key: 'milestone', optional: true, compression: true }
|
||||
displayProps: { key: 'milestone', optional: true }
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
@ -718,7 +721,7 @@ export function createModel (builder: Builder): void {
|
||||
kind: 'list',
|
||||
size: 'small'
|
||||
},
|
||||
displayProps: { key: 'estimation', optional: true, compression: true }
|
||||
displayProps: { key: 'estimation', optional: true }
|
||||
},
|
||||
{ key: '', displayProps: { grow: true } },
|
||||
{
|
||||
|
@ -453,6 +453,7 @@ input.search {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
&.halfcontent { color: var(--theme-halfcontent-color); }
|
||||
}
|
||||
&:hover .icon { color: var(--theme-caption-color); }
|
||||
}
|
||||
@ -904,6 +905,7 @@ a.no-line {
|
||||
|
||||
.content-trans-color { color: var(--theme-trans-color); }
|
||||
.content-darker-color { color: var(--theme-darker-color); }
|
||||
.content-halfcontent-color { color: var(--theme-halfcontent-color); }
|
||||
.content-dark-color { color: var(--theme-dark-color); }
|
||||
.content-color { color: var(--theme-content-color); }
|
||||
.caption-color { color: var(--theme-caption-color); }
|
||||
|
@ -890,27 +890,28 @@
|
||||
.optional-bar {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
border-radius: 0 1.49rem 1.49rem 0;
|
||||
flex-grow: 1;
|
||||
border-radius: 1.625rem;
|
||||
transition: flex-shrink 0.25s cubic-bezier(0.38, 0.01, 0.33, 1) 0s;
|
||||
|
||||
&:hover {
|
||||
flex-shrink: .5;
|
||||
min-width: initial;
|
||||
}
|
||||
.label-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 10;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
& > *:not(:last-child) {
|
||||
flex-shrink: 10;
|
||||
width: min-content;
|
||||
}
|
||||
& > *:last-child {
|
||||
flex-shrink: 0;
|
||||
width: max-content;
|
||||
}
|
||||
& > * { margin-left: .375rem; }
|
||||
& > *:not(:first-child) { margin-left: .25rem; }
|
||||
& > * > * { min-width: fit-content; }
|
||||
}
|
||||
}
|
||||
// Labels on the ListView
|
||||
@ -920,10 +921,13 @@
|
||||
.list-container .antiButton.list:hover,
|
||||
.list-container .datetime-button,
|
||||
.list-container .datetime-button:hover {
|
||||
padding-left: .5rem !important;
|
||||
padding-right: .5rem !important;
|
||||
font-size: 0.8125rem !important;
|
||||
background-color: var(--theme-list-button-color) !important;
|
||||
|
||||
&:not(.only-icon) .btn-icon,
|
||||
&:not(.only-icon) .icon { margin-right: .5rem !important; }
|
||||
&:not(.only-icon) .icon { margin-right: .375rem !important; }
|
||||
.icon, .btn-icon { color: var(--theme-halfcontent-color) !important; }
|
||||
.label {
|
||||
font-size: 0.8125rem !important;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import platform, { addEventListener, getMetadata, OK, PlatformEvent, Status } from '@hcengineering/platform'
|
||||
import { onDestroy } from 'svelte'
|
||||
import type { AnyComponent } from '../../types'
|
||||
import type { AnyComponent, WidthType } from '../../types'
|
||||
// import { applicationShortcutKey } from '../../utils'
|
||||
import { getCurrentLocation, location, navigate, locationStorageKeyId } from '../../location'
|
||||
|
||||
@ -100,6 +100,41 @@
|
||||
document.addEventListener('dblclick', (event) => {
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
let remove: any = null
|
||||
const sizes: Record<WidthType, boolean> = { xs: false, sm: false, md: false, lg: false, xl: false, xxl: false }
|
||||
const css: Record<WidthType, string> = { xs: '', sm: '', md: '', lg: '', xl: '', xxl: '' }
|
||||
const deviceSizes: WidthType[] = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl']
|
||||
const deviceWidths = [480, 680, 760, 1024, 1208, -1]
|
||||
deviceSizes.forEach((ds, i) => {
|
||||
if (i === 0) css[ds] = `(max-width: ${deviceWidths[i]}px)`
|
||||
else if (i === deviceSizes.length - 1) css[ds] = `(min-width: ${deviceWidths[i - 1]}.01px)`
|
||||
else css[ds] = `(min-width: ${deviceWidths[i - 1]}.01px) and (max-width: ${deviceWidths[i]}px)`
|
||||
})
|
||||
const getSize = (width: number): WidthType => {
|
||||
return deviceSizes[
|
||||
deviceWidths.findIndex((it) => (it === -1 ? deviceWidths[deviceWidths.length - 2] < width : it > width))
|
||||
]
|
||||
}
|
||||
const updateDeviceSize = () => {
|
||||
if (remove !== null) remove()
|
||||
const size = getSize(docWidth)
|
||||
const mqString = css[size]
|
||||
const media = matchMedia(mqString)
|
||||
|
||||
deviceWidths.forEach((_, i) => (sizes[deviceSizes[i]] = false))
|
||||
deviceWidths.forEach((dw, i) => {
|
||||
sizes[deviceSizes[i]] =
|
||||
dw === -1 ? deviceWidths[deviceWidths.length - 2] < docWidth : docWidth > dw || size === deviceSizes[i]
|
||||
})
|
||||
$deviceInfo.size = size
|
||||
$deviceInfo.sizes = sizes
|
||||
media.addEventListener('change', updateDeviceSize)
|
||||
remove = () => {
|
||||
media.removeEventListener('change', updateDeviceSize)
|
||||
}
|
||||
}
|
||||
updateDeviceSize()
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth={docWidth} bind:innerHeight={docHeight} />
|
||||
|
@ -220,6 +220,8 @@ export const deviceOptionsStore = writable<DeviceOptions>({
|
||||
isPortrait: false,
|
||||
isMobile: false,
|
||||
fontSize: 0,
|
||||
size: null,
|
||||
sizes: { xs: false, sm: false, md: false, lg: false, xl: false, xxl: false },
|
||||
minWidth: false,
|
||||
twoRows: false
|
||||
})
|
||||
|
@ -295,12 +295,16 @@ export const tableHRscheduleY: FadeOptions = { multipler: { top: 5, bottom: 0 }
|
||||
export const issueSP: FadeOptions = { multipler: { top: 2.75, bottom: 0 } }
|
||||
export const emojiSP: FadeOptions = { multipler: { top: 1.5, bottom: 0 } }
|
||||
|
||||
export type WidthType = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
|
||||
|
||||
export interface DeviceOptions {
|
||||
docWidth: number
|
||||
docHeight: number
|
||||
isPortrait: boolean
|
||||
isMobile: boolean
|
||||
fontSize: number
|
||||
size: WidthType | null
|
||||
sizes: Record<WidthType, boolean>
|
||||
minWidth: boolean
|
||||
twoRows: boolean
|
||||
theme?: any
|
||||
|
@ -23,29 +23,40 @@
|
||||
export let object: Doc
|
||||
export let size: ButtonSize = 'small'
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let showCounter = true
|
||||
export let showCounter: boolean = true
|
||||
export let compactMode: boolean = false
|
||||
</script>
|
||||
|
||||
{#if value && value > 0}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<DocNavLink {object} inline noUnderline={true}>
|
||||
<DocNavLink {object} inline noUnderline={true} shrink={0}>
|
||||
{#if kind === 'list'}
|
||||
<div
|
||||
use:tooltip={{
|
||||
component: AttachmentPopup,
|
||||
props: { objectId: object._id, attachments: value, object }
|
||||
}}
|
||||
class="sm-tool-icon"
|
||||
>
|
||||
<Button {kind} {size}>
|
||||
<div slot="content" class="flex-row-center">
|
||||
<span class="icon"><IconAttachment {size} /></span>
|
||||
{#if showCounter}
|
||||
{value}
|
||||
{/if}
|
||||
</div></Button
|
||||
{#if compactMode}
|
||||
<div
|
||||
use:tooltip={{
|
||||
component: AttachmentPopup,
|
||||
props: { objectId: object._id, attachments: value, object }
|
||||
}}
|
||||
class="sm-tool-icon"
|
||||
>
|
||||
</div>
|
||||
<div class="icon halfcontent"><IconAttachment {size} /></div>
|
||||
{#if showCounter}{value ?? 0}{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
{kind}
|
||||
{size}
|
||||
showTooltip={{
|
||||
component: AttachmentPopup,
|
||||
props: { objectId: object._id, attachments: value, object }
|
||||
}}
|
||||
>
|
||||
<div slot="icon"><IconAttachment {size} /></div>
|
||||
<div slot="content" style:margin-left={showCounter ? '.375rem' : '0'}>
|
||||
{#if showCounter}{value ?? 0}{/if}
|
||||
</div>
|
||||
</Button>
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
use:tooltip={{
|
||||
|
@ -23,30 +23,41 @@
|
||||
export let object: Doc
|
||||
export let size: ButtonSize = 'small'
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let showCounter = true
|
||||
export let showCounter: boolean = true
|
||||
export let compactMode: boolean = false
|
||||
export let withInput: boolean = true
|
||||
</script>
|
||||
|
||||
{#if value && value > 0}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<DocNavLink {object} inline noUnderline={true}>
|
||||
<DocNavLink {object} inline noUnderline={true} shrink={0}>
|
||||
{#if kind === 'list'}
|
||||
<div
|
||||
use:tooltip={{
|
||||
component: CommentPopup,
|
||||
props: { objectId: object._id, object, withInput }
|
||||
}}
|
||||
class="sm-tool-icon"
|
||||
>
|
||||
<Button {kind} {size}>
|
||||
<div slot="content" class="flex-row-center">
|
||||
<span class="icon"><IconThread size={'small'} /></span>
|
||||
{#if showCounter}
|
||||
{value ?? 0}
|
||||
{/if}
|
||||
{#if compactMode}
|
||||
<div
|
||||
use:tooltip={{
|
||||
component: CommentPopup,
|
||||
props: { objectId: object._id, object, withInput }
|
||||
}}
|
||||
class="sm-tool-icon"
|
||||
>
|
||||
<div class="icon halfcontent"><IconThread {size} /></div>
|
||||
{#if showCounter}{value ?? 0}{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
{kind}
|
||||
{size}
|
||||
showTooltip={{
|
||||
component: CommentPopup,
|
||||
props: { objectId: object._id, object, withInput }
|
||||
}}
|
||||
>
|
||||
<div slot="icon"><IconThread {size} /></div>
|
||||
<div slot="content" style:margin-left={showCounter ? '.375rem' : '0'}>
|
||||
{#if showCounter}{value ?? 0}{/if}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
use:tooltip={{
|
||||
|
@ -37,6 +37,7 @@
|
||||
"Weight": "Weight",
|
||||
"Expert": "Expert",
|
||||
"Meaningfull": "Meaningfull",
|
||||
"Initial": "Initial"
|
||||
"Initial": "Initial",
|
||||
"NumberLabels": "{count, plural, =0 {no labels} =1 {1 label} other {# labels}}"
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@
|
||||
"Weight": "Вес",
|
||||
"Expert": "Эксперт",
|
||||
"Meaningfull": "Значимый",
|
||||
"Initial": "Начальный"
|
||||
"Initial": "Начальный",
|
||||
"NumberLabels": "{count, plural, =0 {нет меток} one {# метка} few {# метки} other {# меток}}"
|
||||
}
|
||||
}
|
@ -3,10 +3,12 @@
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import type { TagReference } from '@hcengineering/tags'
|
||||
import tags from '@hcengineering/tags'
|
||||
import { getEventPopupPositionElement, resizeObserver, showPopup } from '@hcengineering/ui'
|
||||
import { getEventPopupPositionElement, resizeObserver, showPopup, tooltip } from '@hcengineering/ui'
|
||||
import { afterUpdate, createEventDispatcher } from 'svelte'
|
||||
import TagReferencePresenter from './TagReferencePresenter.svelte'
|
||||
import TagsReferencePresenter from './TagsReferencePresenter.svelte'
|
||||
import TagsEditorPopup from './TagsEditorPopup.svelte'
|
||||
import TagsItemPresenter from './TagsItemPresenter.svelte'
|
||||
|
||||
export let value: number
|
||||
export let object: WithLookup<Doc>
|
||||
@ -51,11 +53,23 @@
|
||||
</script>
|
||||
|
||||
{#if kind === 'list' || kind === 'link'}
|
||||
{#each items as value}
|
||||
<div class="label-box no-shrink" title={value.title}>
|
||||
<TagReferencePresenter attr={undefined} {value} {kind} />
|
||||
{#if items.length > 4}
|
||||
<div
|
||||
class="label-box no-shrink"
|
||||
use:tooltip={{
|
||||
component: TagsItemPresenter,
|
||||
props: { value: items, kind: 'list' }
|
||||
}}
|
||||
>
|
||||
<TagsReferencePresenter {items} {kind} />
|
||||
</div>
|
||||
{/each}
|
||||
{:else}
|
||||
{#each items as value}
|
||||
<div class="label-box no-shrink" title={value.title}>
|
||||
<TagReferencePresenter attr={undefined} {value} {kind} />
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{:else}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
@ -93,15 +107,15 @@
|
||||
.label-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 10;
|
||||
// flex-shrink: 10;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
border-radius: 0.25rem;
|
||||
transition: box-shadow 0.15s ease-in-out;
|
||||
|
||||
&:not(.no-shrink):last-child {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
// &:not(.no-shrink):last-child {
|
||||
// flex-shrink: 0;
|
||||
// }
|
||||
}
|
||||
.wrap-short:not(:last-child) {
|
||||
margin-right: 0.375rem;
|
||||
|
@ -14,13 +14,25 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { TagReference } from '@hcengineering/tags'
|
||||
import TagReferencePresenter from './TagReferencePresenter.svelte'
|
||||
import TagItem from './TagItem.svelte'
|
||||
|
||||
export let value: TagReference[] | TagReference
|
||||
export let kind: 'tag' | 'list' = 'tag'
|
||||
|
||||
$: values = Array.isArray(value) ? value : [value]
|
||||
</script>
|
||||
|
||||
{#each values as v}
|
||||
<TagItem tag={v} />
|
||||
{/each}
|
||||
{#if kind === 'list'}
|
||||
<div class="flex-center flex-wrap">
|
||||
{#each values as v}
|
||||
<div class="m-0-5">
|
||||
<TagReferencePresenter attr={undefined} value={v} {kind} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
{#each values as v}
|
||||
<TagItem tag={v} />
|
||||
{/each}
|
||||
{/if}
|
||||
|
@ -0,0 +1,119 @@
|
||||
<!--
|
||||
// Copyright © 2023 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 type { TagReference } from '@hcengineering/tags'
|
||||
import plugin from '../plugin'
|
||||
import { getPlatformColorDef, themeStore, Label } from '@hcengineering/ui'
|
||||
|
||||
export let items: TagReference[]
|
||||
export let kind: 'list' | 'link' = 'list'
|
||||
|
||||
$: colors = items.slice(0, 3).map((it) => {
|
||||
return getPlatformColorDef(it.color ?? 0, $themeStore.dark)
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if items}
|
||||
{#if kind === 'link'}
|
||||
<button class="link-container">
|
||||
{#each colors as color}
|
||||
<div class="color" style:background-color={color.color} />
|
||||
{/each}
|
||||
<span class="label overflow-label ml-1 text-sm caption-color max-w-40">
|
||||
<Label label={plugin.string.NumberLabels} params={{ count: items.length }} />
|
||||
</span>
|
||||
</button>
|
||||
{:else if kind === 'list'}
|
||||
<div class="listitems-container">
|
||||
{#each colors as color}
|
||||
<div class="color" style:background-color={color.color} />
|
||||
{/each}
|
||||
<span class="label overflow-label ml-1-5 max-w-40">
|
||||
<Label label={plugin.string.NumberLabels} params={{ count: items.length }} />
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.listitems-container {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding-left: 0.5rem;
|
||||
height: 1.75rem;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
background-color: var(--theme-button-enabled);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 1.5rem;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-hovered);
|
||||
}
|
||||
.label {
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
}
|
||||
|
||||
.link-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 0 0.375rem;
|
||||
height: 1.5rem;
|
||||
min-width: 1.5rem;
|
||||
font-size: 0.75rem;
|
||||
line-height: 0.75rem;
|
||||
white-space: nowrap;
|
||||
color: var(--theme-content-color);
|
||||
background-color: var(--theme-link-button-color);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 0.25rem;
|
||||
transition-property: border, background-color, color, box-shadow;
|
||||
transition-duration: 0.15s;
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-link-button-hover);
|
||||
border-color: var(--theme-list-divider-color);
|
||||
transition-duration: 0;
|
||||
}
|
||||
&:focus {
|
||||
border-color: var(--primary-edit-border-color) !important;
|
||||
}
|
||||
&:disabled {
|
||||
color: rgb(var(--theme-caption-color) / 40%);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.color {
|
||||
flex-shrink: 0;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
border-radius: 50%;
|
||||
|
||||
&:not(:nth-child(3)) {
|
||||
mask: radial-gradient(circle at 100% 50%, rgba(0, 0, 0, 0) 48.5%, rgb(0, 0, 0) 50%);
|
||||
}
|
||||
&:not(:first-child) {
|
||||
margin-left: calc(1px - 0.25rem);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -49,7 +49,8 @@ export default mergeIds(tagsId, tags, {
|
||||
Weight: '' as IntlString,
|
||||
Expert: '' as IntlString,
|
||||
Meaningfull: '' as IntlString,
|
||||
Initial: '' as IntlString
|
||||
Initial: '' as IntlString,
|
||||
NumberLabels: '' as IntlString
|
||||
},
|
||||
function: {
|
||||
FilterTagsInResult: '' as FilterFunction,
|
||||
|
@ -56,9 +56,8 @@
|
||||
|
||||
{#if (value.component && value.component !== $activeComponent && groupBy !== 'component') || shouldShowPlaceholder}
|
||||
<div
|
||||
class="clear-mins"
|
||||
class="label-wrapper"
|
||||
class:minus-margin={kind === 'list-header'}
|
||||
class:label-wrapper={compression}
|
||||
use:tooltip={{ label: value.component ? tracker.string.MoveToComponent : tracker.string.AddToComponent }}
|
||||
>
|
||||
<ComponentSelector
|
||||
@ -74,7 +73,7 @@
|
||||
{onlyIcon}
|
||||
{enlargedText}
|
||||
value={value.component}
|
||||
short={compression}
|
||||
short
|
||||
onChange={handleComponentIdChanged}
|
||||
/>
|
||||
</div>
|
||||
|
@ -39,6 +39,7 @@
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'left'
|
||||
export let width: string | undefined = 'min-contet'
|
||||
export let compactMode: boolean = false
|
||||
|
||||
let btn: HTMLElement
|
||||
|
||||
@ -150,9 +151,11 @@
|
||||
<svelte:fragment slot="content">
|
||||
{#if subIssues}
|
||||
<div class="flex-row-center content-color text-sm pointer-events-none">
|
||||
<div class="mr-1-5">
|
||||
<ProgressCircle bind:value={countComplete} bind:max={subIssues.length} size={'small'} primary />
|
||||
</div>
|
||||
{#if !compactMode}
|
||||
<div class="mr-1-5">
|
||||
<ProgressCircle bind:value={countComplete} bind:max={subIssues.length} size={'small'} primary />
|
||||
</div>
|
||||
{/if}
|
||||
{countComplete}/{subIssues.length}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -78,7 +78,7 @@
|
||||
|
||||
{#if kind === 'list'}
|
||||
{#if value.milestone}
|
||||
<div class="clear-mins" class:label-wrapper={compression}>
|
||||
<div class="label-wrapper">
|
||||
<MilestoneSelector
|
||||
{kind}
|
||||
{size}
|
||||
@ -90,7 +90,7 @@
|
||||
{popupPlaceholder}
|
||||
{onlyIcon}
|
||||
{enlargedText}
|
||||
short={compression}
|
||||
short
|
||||
showTooltip={{ label: value.milestone ? tracker.string.MoveToMilestone : tracker.string.AddToMilestone }}
|
||||
value={value.milestone}
|
||||
onChange={handleMilestoneIdChanged}
|
||||
|
@ -38,6 +38,7 @@
|
||||
export let disableHeader = false
|
||||
export let props: Record<string, any> = {}
|
||||
export let selection: number | undefined = undefined
|
||||
export let compactMode: boolean = false
|
||||
|
||||
export let documents: Doc[] | undefined = undefined
|
||||
|
||||
@ -138,6 +139,7 @@
|
||||
{disableHeader}
|
||||
{props}
|
||||
{listDiv}
|
||||
{compactMode}
|
||||
bind:dragItem
|
||||
on:select={(evt) => {
|
||||
select(0, evt.detail)
|
||||
|
@ -58,6 +58,7 @@
|
||||
export let listDiv: HTMLDivElement
|
||||
export let selection: number | undefined = undefined
|
||||
export let groupPersistKey: string
|
||||
export let compactMode: boolean = false
|
||||
|
||||
$: groupByKey = viewOptions.groupBy[level] ?? noCategory
|
||||
let categories: CategoryType[] = []
|
||||
@ -310,6 +311,7 @@
|
||||
{createItemDialogProps}
|
||||
{createItemLabel}
|
||||
{viewOptionsConfig}
|
||||
{compactMode}
|
||||
on:check
|
||||
on:uncheckAll
|
||||
on:row-focus
|
||||
|
@ -66,6 +66,7 @@
|
||||
export let listDiv: HTMLDivElement
|
||||
export let index: number
|
||||
export let groupPersistKey: string
|
||||
export let compactMode: boolean = false
|
||||
|
||||
$: lastLevel = level + 1 >= viewOptions.groupBy.length
|
||||
|
||||
@ -448,6 +449,7 @@
|
||||
on:mouseover={mouseAttractor(() => handleRowFocused(docObject))}
|
||||
on:mouseenter={mouseAttractor(() => handleRowFocused(docObject))}
|
||||
{props}
|
||||
{compactMode}
|
||||
on:on-mount={() => {
|
||||
wasLoaded = true
|
||||
}}
|
||||
|
@ -16,7 +16,7 @@
|
||||
import { AnyAttribute, Doc, getObjectValue } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { getClient, updateAttribute } from '@hcengineering/presentation'
|
||||
import { CheckBox, Component, deviceOptionsStore as deviceInfo, IconCircles, tooltip } from '@hcengineering/ui'
|
||||
import { CheckBox, Component, IconCircles, tooltip } from '@hcengineering/ui'
|
||||
import { AttributeModel } from '@hcengineering/view'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import view from '../../plugin'
|
||||
@ -31,6 +31,7 @@
|
||||
export let last: boolean = false
|
||||
export let lastCat: boolean = false
|
||||
export let props: Record<string, any> = {}
|
||||
export let compactMode: boolean = false
|
||||
|
||||
export function scroll () {
|
||||
elem?.scrollIntoView({ behavior: 'auto', block: 'nearest' })
|
||||
@ -48,8 +49,6 @@
|
||||
return elem
|
||||
}
|
||||
|
||||
$: compactMode = $deviceInfo.twoRows
|
||||
|
||||
const client = getClient()
|
||||
|
||||
function onChange (value: any, doc: Doc, key: string, attribute: AnyAttribute) {
|
||||
@ -64,13 +63,6 @@
|
||||
return (value: any) => onChange(value, docObject, attribute.key, attr)
|
||||
}
|
||||
|
||||
let noCompressed: number
|
||||
$: if (model) {
|
||||
noCompressed = -1
|
||||
model.forEach((m, i) => {
|
||||
if (m.displayProps?.compression) noCompressed = i
|
||||
})
|
||||
}
|
||||
onMount(() => {
|
||||
dispatch('on-mount')
|
||||
})
|
||||
@ -120,32 +112,55 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{#each model.filter((p) => !(p.displayProps?.optional === true)) as attributeModel, i}
|
||||
{#each model.filter((p) => !(p.displayProps?.optional === true || p.displayProps?.suffix === true)) as attributeModel, i}
|
||||
{@const displayProps = attributeModel.displayProps}
|
||||
{#if !groupByKey || displayProps?.excludeByKey !== groupByKey}
|
||||
{#if displayProps?.grow}
|
||||
<GrowPresenter />
|
||||
{#if !compactMode}
|
||||
{#each model.filter((p) => p.displayProps?.optional === true) as attrModel, j}
|
||||
{#each model.filter((p) => p.displayProps?.suffix === true) as attrModel}
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
compression={j !== noCompressed}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
<GrowPresenter />
|
||||
{#if !compactMode}
|
||||
<div class="optional-bar">
|
||||
{#each model.filter((p) => p.displayProps?.optional === true) as attrModel}
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
{#each model.filter((p) => p.displayProps?.suffix === true) as attrModel}
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
{props}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
compactMode
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
{:else}
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
{attributeModel}
|
||||
{props}
|
||||
compression={i !== noCompressed}
|
||||
value={getObjectValue(attributeModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attributeModel)}
|
||||
hideDivider={i === 0}
|
||||
{compactMode}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
@ -164,7 +179,7 @@
|
||||
<IconCircles />
|
||||
</div>
|
||||
<div class="scroll-box gap-2">
|
||||
{#each model.filter((m) => m.displayProps?.optional || m.displayProps?.compression) as attributeModel, j}
|
||||
{#each model.filter((m) => m.displayProps?.optional) as attributeModel, j}
|
||||
{@const displayProps = attributeModel.displayProps}
|
||||
{@const value = getObjectValue(attributeModel.key, docObject)}
|
||||
{#if displayProps?.excludeByKey !== groupByKey && value !== undefined}
|
||||
|
@ -25,6 +25,7 @@
|
||||
export let props: Record<string, any>
|
||||
export let compression: boolean = false
|
||||
export let hideDivider: boolean = false
|
||||
export let compactMode: boolean = false
|
||||
|
||||
$: dp = attributeModel?.displayProps
|
||||
|
||||
@ -47,6 +48,7 @@
|
||||
{value}
|
||||
{onChange}
|
||||
kind={'list'}
|
||||
{compactMode}
|
||||
{...joinProps(attributeModel, docObject, props)}
|
||||
/>
|
||||
</FixedColumn>
|
||||
@ -56,7 +58,7 @@
|
||||
{value}
|
||||
{onChange}
|
||||
kind={'list'}
|
||||
compression={dp?.compression && compression}
|
||||
{compactMode}
|
||||
{...joinProps(attributeModel, docObject, props)}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -24,6 +24,7 @@
|
||||
let list: List
|
||||
let scroll: Scroller
|
||||
let divScroll: HTMLDivElement
|
||||
let listWidth: number
|
||||
|
||||
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
|
||||
if (dir === 'vertical') {
|
||||
@ -43,7 +44,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="w-full h-full py-4 clear-mins">
|
||||
<div bind:clientWidth={listWidth} class="w-full h-full py-4 clear-mins">
|
||||
<Scroller
|
||||
bind:this={scroll}
|
||||
bind:divScroll
|
||||
@ -64,6 +65,7 @@
|
||||
{createItemLabel}
|
||||
{viewOptions}
|
||||
{props}
|
||||
compactMode={listWidth <= 800}
|
||||
viewOptionsConfig={viewlet.viewOptions?.other}
|
||||
selectedObjectIds={$selectionStore ?? []}
|
||||
selection={listProvider.current($focusStore)}
|
||||
|
@ -535,8 +535,8 @@ export interface DisplayProps {
|
||||
key?: string
|
||||
excludeByKey?: string
|
||||
fixed?: 'left' | 'right' // using for align items in row
|
||||
suffix?: boolean
|
||||
optional?: boolean
|
||||
compression?: boolean
|
||||
grow?: boolean
|
||||
dividerBefore?: boolean // should show divider before
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user