fix: combine presence avatars (#7551)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Alexander Onnikov 2024-12-26 15:33:43 +07:00 committed by GitHub
parent fb5df1681d
commit b2419221fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 65 additions and 19 deletions

View File

@ -7,5 +7,6 @@
"CALENDAR_URL": "https://calendar.hc.engineering", "CALENDAR_URL": "https://calendar.hc.engineering",
"REKONI_URL": "https://rekoni.hc.engineering", "REKONI_URL": "https://rekoni.hc.engineering",
"COLLABORATOR_URL": "wss://collaborator.hc.engineering", "COLLABORATOR_URL": "wss://collaborator.hc.engineering",
"STATS_URL": "https://stats.hc.engineering" "STATS_URL": "https://stats.hc.engineering",
"PRESENCE_URL": "wss://presence.hc.engineering"
} }

View File

@ -122,7 +122,7 @@
<svelte:fragment slot="presence"> <svelte:fragment slot="presence">
{#if withPresence && object} {#if withPresence && object}
<PresenceAvatars {object} size="x-small" limit={3} /> <PresenceAvatars {object} size="x-small" limit={4} />
{/if} {/if}
</svelte:fragment> </svelte:fragment>

View File

@ -15,35 +15,47 @@
<script lang="ts"> <script lang="ts">
import { type Doc } from '@hcengineering/core' import { type Doc } from '@hcengineering/core'
import contact, { formatName } from '@hcengineering/contact' import { type Person, formatName } from '@hcengineering/contact'
import { Avatar, CombineAvatars, personByIdStore } from '@hcengineering/contact-resources' import { Avatar, personByIdStore } from '@hcengineering/contact-resources'
import { getEmbeddedLabel } from '@hcengineering/platform' import { getEmbeddedLabel } from '@hcengineering/platform'
import { IconSize, tooltip } from '@hcengineering/ui' import { IconSize, tooltip } from '@hcengineering/ui'
import PresenceList from './PresenceList.svelte'
import { presenceByObjectId } from '../store' import { presenceByObjectId } from '../store'
export let object: Doc export let object: Doc
export let size: IconSize = 'small' export let size: IconSize = 'small'
export let limit: number = 5 export let limit: number = 4
export let hideLimit: boolean = false
export let combine = false
$: presence = $presenceByObjectId?.get(object._id) ?? [] $: presence = $presenceByObjectId?.get(object._id) ?? []
$: items = presence.map((it) => it.person) $: persons = presence
.map((it) => it.person)
.map((p) => $personByIdStore.get(p))
.filter((p): p is Person => p !== undefined)
$: overLimit = persons.length > limit
</script> </script>
{#if items.length > 0} {#if persons.length > 0}
{#if combine} {#if overLimit}
<CombineAvatars _class={contact.mixin.Employee} {items} {size} {limit} {hideLimit} /> <div
class="hulyCombineAvatars-container"
use:tooltip={{ component: PresenceList, props: { persons, size }, direction: 'bottom' }}
>
{#each persons.slice(0, limit) as person, i}
<div
class="hulyCombineAvatar tiny"
data-over={i === limit - 1 && overLimit ? `+${persons.length - limit + 1}` : undefined}
>
<Avatar name={person.name} {size} {person} />
</div>
{/each}
</div>
{:else} {:else}
<div class="flex-row-center flex-gap-0-5"> <div class="flex-row-center flex-gap-1">
{#each items as item} {#each persons as person}
{@const person = $personByIdStore.get(item)} <div use:tooltip={{ label: getEmbeddedLabel(formatName(person.name)) }}>
{#if person} <Avatar name={person.name} {size} {person} />
<div use:tooltip={{ label: getEmbeddedLabel(formatName(person.name)) }}> </div>
<Avatar name={person.name} {size} {person} />
</div>
{/if}
{/each} {/each}
</div> </div>
{/if} {/if}

View File

@ -0,0 +1,33 @@
<!--
// Copyright © 2024 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 { Person, formatName } from '@hcengineering/contact'
import { Avatar } from '@hcengineering/contact-resources'
import { IconSize, Scroller } from '@hcengineering/ui'
export let persons: Person[]
export let size: IconSize
</script>
<Scroller padding={'.25rem'} gap={'flex-gap-2'}>
{#each persons as person}
<div class="flex-row-center flex-no-shrink flex-gap-2">
<div class="min-w-6">
<Avatar name={person.name} {size} {person} />
</div>
{formatName(person.name)}
</div>
{/each}
</Scroller>