mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 11:01:54 +03:00
Updated ListItem layout (#7008)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
parent
385bd572a3
commit
15ce5442c6
@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString, Asset } from '@hcengineering/platform'
|
||||
import { createEventDispatcher, ComponentType } from 'svelte'
|
||||
import { createEventDispatcher, ComponentType, afterUpdate } from 'svelte'
|
||||
|
||||
import { DateRangeMode } from '@hcengineering/core'
|
||||
import ui from '../../plugin'
|
||||
@ -86,6 +86,7 @@
|
||||
focusManager?.setFocus(idx)
|
||||
})
|
||||
}
|
||||
afterUpdate(() => dispatch('resize', input?.clientWidth))
|
||||
</script>
|
||||
|
||||
<button
|
||||
|
@ -75,6 +75,7 @@
|
||||
{width}
|
||||
{shouldIgnoreOverdue}
|
||||
on:change={handleDueDateChanged}
|
||||
on:resize
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -49,18 +49,32 @@
|
||||
|
||||
let allWidth: number
|
||||
const widths: number[] = []
|
||||
const elements: HTMLDivElement[] = []
|
||||
|
||||
afterUpdate(() => {
|
||||
let count: number = 0
|
||||
widths.forEach((i) => (count += i))
|
||||
full = count > allWidth
|
||||
dispatch('change', { full, ckeckFilled })
|
||||
if (elements.length > 0) {
|
||||
if (items.length > 4) dispatch('resize', elements[0]?.clientWidth)
|
||||
else {
|
||||
allWidth = 0
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (elements[i].clientWidth !== undefined && allWidth < elements[i].clientWidth) {
|
||||
allWidth = elements[i].clientWidth
|
||||
}
|
||||
}
|
||||
dispatch('resize', allWidth + (items.length - 1) * 3)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if kind === 'list' || kind === 'link'}
|
||||
{#if items.length > 4}
|
||||
<div
|
||||
bind:this={elements[0]}
|
||||
class="label-box no-shrink"
|
||||
use:tooltip={{
|
||||
component: TagsItemPresenter,
|
||||
@ -70,8 +84,8 @@
|
||||
<TagsReferencePresenter {items} {kind} />
|
||||
</div>
|
||||
{:else}
|
||||
{#each items as value}
|
||||
<div class="label-box no-shrink" title={value.title}>
|
||||
{#each items as value, i}
|
||||
<div bind:this={elements[i]} class="label-box no-shrink" title={value.title}>
|
||||
<TagReferencePresenter attr={undefined} {value} {kind} />
|
||||
</div>
|
||||
{/each}
|
||||
|
@ -18,7 +18,7 @@
|
||||
import { RuleApplyResult, getClient, getDocRules } from '@hcengineering/presentation'
|
||||
import { Component, Issue, IssueTemplate, Project, TrackerEvents } from '@hcengineering/tracker'
|
||||
import { ButtonKind, ButtonShape, ButtonSize, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
|
||||
import { activeComponent } from '../../issues'
|
||||
@ -47,6 +47,8 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let element: HTMLDivElement
|
||||
|
||||
const handleComponentIdChanged = async (newComponentId: Ref<Component> | null | undefined) => {
|
||||
if (!isEditable || newComponentId === undefined || (!Array.isArray(value) && value.component === newComponentId)) {
|
||||
return
|
||||
@ -101,11 +103,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterUpdate(() => dispatch('resize', element?.clientWidth))
|
||||
</script>
|
||||
|
||||
{#if kind === 'list'}
|
||||
{#if !Array.isArray(value) && value.component}
|
||||
<div class={compression ? 'label-wrapper' : 'clear-mins'}>
|
||||
<div bind:this={element} class={compression ? 'label-wrapper' : 'clear-mins'}>
|
||||
<ComponentSelector
|
||||
{kind}
|
||||
{size}
|
||||
@ -127,6 +131,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
bind:this={element}
|
||||
class="flex flex-wrap clear-mins"
|
||||
class:minus-margin={kind === 'list-header'}
|
||||
class:label-wrapper={compression}
|
||||
|
@ -55,4 +55,5 @@
|
||||
{size}
|
||||
{kind}
|
||||
shouldIgnoreOverdue={ignoreOverDue}
|
||||
on:resize
|
||||
/>
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||
import { WithLookup } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import type { Issue } from '@hcengineering/tracker'
|
||||
@ -26,13 +27,19 @@
|
||||
export let disabled: boolean = false
|
||||
export let maxWidth: string | undefined = undefined
|
||||
|
||||
let element: HTMLSpanElement
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: presenters =
|
||||
value !== undefined ? getClient().getHierarchy().findMixinMixins(value, view.mixin.ObjectPresenter) : []
|
||||
|
||||
afterUpdate(() => dispatch('resize', element?.clientWidth))
|
||||
</script>
|
||||
|
||||
{#if value}
|
||||
{#if value && presenters.length > 0}
|
||||
<span
|
||||
class="presenter-label select-text p-1"
|
||||
bind:this={element}
|
||||
class="presenter-label select-text"
|
||||
class:with-margin={shouldUseMargin}
|
||||
class:list={kind === 'list'}
|
||||
style:max-width={maxWidth}
|
||||
@ -41,7 +48,7 @@
|
||||
{#if presenters.length > 0}
|
||||
<div class="flex-row-center">
|
||||
{#each presenters as mixinPresenter}
|
||||
<Component is={mixinPresenter.presenter} props={{ value }} />
|
||||
<Component is={mixinPresenter.presenter} props={{ value, kind }} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
@ -50,7 +57,6 @@
|
||||
|
||||
<style lang="scss">
|
||||
.presenter-label {
|
||||
overflow: hidden;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-shrink: 1;
|
||||
|
@ -25,7 +25,7 @@
|
||||
DatePresenter,
|
||||
deviceOptionsStore as deviceInfo
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||
import { activeMilestone } from '../../issues'
|
||||
import tracker from '../../plugin'
|
||||
import MilestoneSelector from './MilestoneSelector.svelte'
|
||||
@ -51,6 +51,8 @@
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let element: HTMLDivElement
|
||||
|
||||
const handleMilestoneIdChanged = async (newMilestoneId: Ref<Milestone> | null | undefined) => {
|
||||
if (!isEditable || newMilestoneId === undefined || (!Array.isArray(value) && value.milestone === newMilestoneId)) {
|
||||
return
|
||||
@ -86,11 +88,12 @@
|
||||
$: _space = space ?? (!Array.isArray(value) ? value.space : { $in: Array.from(new Set(value.map((it) => it.space))) })
|
||||
|
||||
$: twoRows = $deviceInfo.twoRows
|
||||
afterUpdate(() => dispatch('resize', element?.clientWidth))
|
||||
</script>
|
||||
|
||||
{#if kind === 'list'}
|
||||
{#if !Array.isArray(value) && value.milestone}
|
||||
<div class={compression ? 'label-wrapper' : 'clear-mins'}>
|
||||
<div bind:this={element} class={compression ? 'label-wrapper' : 'clear-mins'}>
|
||||
<MilestoneSelector
|
||||
{kind}
|
||||
{size}
|
||||
@ -112,6 +115,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
bind:this={element}
|
||||
class="flex flex-wrap clear-mins"
|
||||
class:minus-margin={kind === 'list-header'}
|
||||
class:label-wrapper={compression}
|
||||
|
@ -60,11 +60,11 @@
|
||||
>
|
||||
<svelte:fragment slot="content">
|
||||
{#if title}
|
||||
<span class="caption-color overflow-label pointer-events-none">{title}</span>
|
||||
<span class="label caption-color overflow-label pointer-events-none">{title}</span>
|
||||
{:else if value}
|
||||
<span class="caption-color overflow-label pointer-events-none">{value}</span>
|
||||
<span class="label caption-color overflow-label pointer-events-none">{value}</span>
|
||||
{:else}
|
||||
<span class="content-dark-color pointer-events-none">
|
||||
<span class="label content-dark-color pointer-events-none">
|
||||
<Label label={placeholder} />
|
||||
</span>
|
||||
{/if}
|
||||
|
@ -84,6 +84,11 @@
|
||||
onMount(() => {
|
||||
dispatch('on-mount')
|
||||
})
|
||||
let minWidth: number | undefined = undefined
|
||||
const sizes = new Map<number, number>()
|
||||
const calcSizes = (): void => {
|
||||
minWidth = sizes.size > 0 ? Array.from(sizes.values()).reduce((a, b) => a + b, 0) : undefined
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
@ -147,14 +152,19 @@
|
||||
{/if}
|
||||
<GrowPresenter />
|
||||
{#if !compactMode}
|
||||
<div class="compression-bar">
|
||||
{#each model.filter((p) => p.displayProps?.compression === true) as attrModel}
|
||||
<div class="compression-bar" style:min-width={`${minWidth}px`}>
|
||||
{#each model.filter((p) => p.displayProps?.compression === true) as attrModel, index}
|
||||
<ListPresenter
|
||||
{docObject}
|
||||
attributeModel={attrModel}
|
||||
props={getProps(props, $restrictionStore.readonly)}
|
||||
value={getObjectValue(attrModel.key, docObject)}
|
||||
onChange={getOnChange(docObject, attrModel)}
|
||||
on:resize={(e) => {
|
||||
if (e.detail == null) return
|
||||
sizes.set(index, e.detail)
|
||||
calcSizes()
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import core, { Doc } from '@hcengineering/core'
|
||||
import { AttributeModel } from '@hcengineering/view'
|
||||
import { FixedColumn } from '../..'
|
||||
@ -26,6 +27,8 @@
|
||||
export let hideDivider: boolean = false
|
||||
export let compactMode: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: dp = attributeModel?.displayProps
|
||||
|
||||
function joinProps (attribute: AttributeModel, object: Doc, props: Record<string, any>) {
|
||||
@ -35,6 +38,10 @@
|
||||
}
|
||||
return { object, ...clearAttributeProps, space: object.space, ...props }
|
||||
}
|
||||
const translateSize = (e: CustomEvent): void => {
|
||||
if (e.detail === undefined) return
|
||||
dispatch('resize', e.detail)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if dp?.dividerBefore === true && !hideDivider}
|
||||
@ -49,6 +56,7 @@
|
||||
kind={'list'}
|
||||
{compactMode}
|
||||
{...joinProps(attributeModel, docObject, props)}
|
||||
on:resize={translateSize}
|
||||
/>
|
||||
</FixedColumn>
|
||||
{:else}
|
||||
@ -59,5 +67,6 @@
|
||||
kind={'list'}
|
||||
{compactMode}
|
||||
{...joinProps(attributeModel, docObject, props)}
|
||||
on:resize={translateSize}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -2,11 +2,13 @@
|
||||
import { Issue } from '@hcengineering/tracker'
|
||||
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import type { ButtonKind } from '@hcengineering/ui'
|
||||
import { HyperlinkEditor } from '@hcengineering/view-resources'
|
||||
import github from '../../plugin'
|
||||
import { integrationRepositories } from '../utils'
|
||||
|
||||
export let value: Issue
|
||||
export let kind: ButtonKind = 'ghost'
|
||||
|
||||
$: ghIssue = getClient().getHierarchy().asIf(value, github.mixin.GithubIssue)
|
||||
|
||||
@ -14,14 +16,12 @@
|
||||
</script>
|
||||
|
||||
{#if ghIssue !== undefined && ghIssue.url !== '' && repository !== undefined}
|
||||
<div class="flex flex-row-center">
|
||||
<HyperlinkEditor
|
||||
readonly
|
||||
icon={github.icon.Github}
|
||||
kind={'ghost'}
|
||||
value={ghIssue.url}
|
||||
placeholder={github.string.Issue}
|
||||
title={`${repository.name}`}
|
||||
/>
|
||||
</div>
|
||||
<HyperlinkEditor
|
||||
readonly
|
||||
icon={github.icon.Github}
|
||||
{kind}
|
||||
value={ghIssue.url}
|
||||
placeholder={github.string.Issue}
|
||||
title={`${repository.name}`}
|
||||
/>
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user