TSK-930, TSK-933. Update Activity feed layout (#2834)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2023-03-27 09:16:20 +03:00 committed by GitHub
parent dafb569f44
commit 78248b84f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 682 additions and 380 deletions

View File

@ -91,16 +91,12 @@
{#if node.getAttribute('data-objectclass') !== undefined && node.getAttribute('data-id') !== undefined}
<Component
is={view.component.ObjectPresenter}
inline
props={{
objectId: node.getAttribute('data-id'),
title: node.getAttribute('data-label'),
_class: node.getAttribute('data-objectclass'),
props: {
inline: true,
avatarSize: 'x-small',
withIcon: true
// shouldShowAvatar: false
}
inline: true
}}
/>
{:else}

View File

@ -70,6 +70,8 @@
--scrollbar-bar-hover: #8a8f98;
--scrollbar-track-color: #303236;
--trans-color: rgba(255, 255, 255, .3);
--darker-color: rgba(255, 255, 255, .4);
--dark-color: #62666d;
--content-color: #8a8f98;
--accent-color: #d7d8db;
@ -82,6 +84,7 @@
--won-color: #34DB80;
--divider-color: #303236;
--divider-trans-color: rgba(255, 255, 255, .12);
--menu-bg-select: #2d2f36;
--menu-bg-select-trans: #2d2f3665;
--menu-icon-hover: #f3f3f8;
@ -149,6 +152,8 @@
--scrollbar-bar-hover: #90959d;
--scrollbar-track-color: #e0e0e0;
--trans-color: rgba(0, 0, 0, .3);
--darker-color: rgba(0, 0, 0, .4);
--dark-color: #90959d;
--content-color: #3c4149;
--accent-color: #282a30;
@ -161,6 +166,7 @@
--won-color: #34DB80; // Dark
--divider-color: #e0e0e0;
--divider-trans-color: rgba(0, 0, 0, .12);
--menu-bg-select: #f0f3f9;
--menu-bg-select-trans: #f0f3f965;
--menu-icon-hover: #282a30;

View File

@ -112,8 +112,8 @@ p:last-child { margin-block-end: 0; }
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
line-height: 180%;
color: var(--accent-color);
line-height: 150%;
color: var(--content-color);
a {
word-break: break-all;
@ -363,6 +363,30 @@ input.search {
background-color: var(--divider-color);
}
.labels-row {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
min-width: 0;
& > * {
margin-right: 0.5rem;
}
& > *:last-child {
margin-right: 0;
}
.bold {
font-weight: 500;
color: var(--caption-color);
}
.strong {
color: var(--accent-color);
}
.lower {
text-transform: lowercase;
}
}
.gap-1, .gap-1-5 {
& > *:not(:last-child) { margin-right: .25rem; }
&.reverse {
@ -569,6 +593,7 @@ input.search {
.h-60 { height: 15.0rem; }
.w-full { width: 100%; }
.w-2 { width: .5rem; }
.w-4 { width: 1rem; }
.w-9 { width: 2.25rem; }
.w-14 { width: 3.5rem; }
.w-16 { width: 4rem; }
@ -592,6 +617,7 @@ input.search {
.min-h-30 { min-height: 7.5rem; }
.min-h-60 { min-height: 15rem; }
.max-w-2 { max-width: .5rem; }
.max-w-4 { max-width: 1rem; }
.max-w-9 { max-width: 2.25rem; }
.max-w-30 { max-width: 7.5rem; }
.max-w-40 { max-width: 10rem; }

View File

@ -305,7 +305,12 @@
height: 2.5rem;
min-height: 2.5rem;
border-bottom: 1px solid var(--divider-color);
&.high {
padding-right: 1rem;
height: 3.5rem;
min-height: 3.5rem;
}
&__icon {
display: flex;
justify-content: center;
@ -316,7 +321,6 @@
}
&__title {
min-width: 0;
font-weight: 500;
font-size: 1rem;
color: var(--caption-color);
@ -353,16 +357,28 @@
border-radius: 1rem;
}
&__tag {
padding: .125rem .25rem;
display: flex;
align-items: center;
padding: .3125rem .5rem;
min-width: 0;
font-size: .8125rem;
font-size: .875rem;
background-color: var(--accent-bg-color);
color: var(--dark-color);
border: 1px solid var(--divider-color);
border-radius: .25rem;
.tag-icon {
margin-left: .5rem;
width: 1rem;
height: 1rem;
color: var(--accent-color);
&:hover { color: var(--caption-color); }
}
&.highlight { color: var(--content-color); }
}
&__tag + &__tag { margin-left: .125rem; }
&__tag + &__tag { margin-left: .375rem; }
}
.invisible { display: none; }
&-empty {

View File

@ -27,6 +27,7 @@
export let props = {}
export let shrink: boolean = false
export let showLoading = true
export let inline: boolean = false
$: component = is != null ? getResource(is) : Promise.reject(new Error('is not defined'))
</script>
@ -39,11 +40,11 @@
{:then Ctor}
<ErrorBoundary>
{#if $$slots.default !== undefined}
<Ctor bind:this={innerRef} {...props} on:change on:close on:open on:click on:delete on:action>
<Ctor bind:this={innerRef} {...props} {inline} on:change on:close on:open on:click on:delete on:action>
<slot />
</Ctor>
{:else}
<Ctor bind:this={innerRef} {...props} on:change on:close on:open on:click on:delete on:action />
<Ctor bind:this={innerRef} {...props} {inline} on:change on:close on:open on:click on:delete on:action />
{/if}
</ErrorBoundary>
{:catch err}

View File

@ -0,0 +1,72 @@
<!--
// 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 Like from './icons/Like.svelte'
export let value: number = Math.round(Math.random() * 100)
export let voted: boolean = !!Math.round(Math.random())
const vote = () => {
voted = !voted
value++
}
</script>
<div class="like-container" class:voted>
{#if value > 0}<span>{value}</span>{/if}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="icon" on:click={vote}>
<Like size={'small'} />
</div>
</div>
<style lang="scss">
.like-container {
display: flex;
align-items: center;
// line-height: 100%;
span {
text-align: right;
font-size: 0.8125rem;
color: var(--caption-color);
}
.icon {
margin-left: 0.25rem;
color: var(--trans-color);
cursor: pointer;
&:hover {
color: var(--dark-color);
}
&:active {
color: var(--darker-color);
}
}
&.voted {
.icon {
color: var(--primary-button-enabled);
&:hover {
color: var(--primary-button-hovered);
}
&:active {
color: var(--primary-button-pressed);
}
}
}
}
</style>

View File

@ -1,6 +1,6 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
export let size: 'x-small' | 'small' | 'medium' | 'large'
export let fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">

View File

@ -1,5 +1,5 @@
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
export let size: 'x-small' | 'small' | 'medium' | 'large'
export let fill: string = 'currentColor'
</script>

View File

@ -0,0 +1,25 @@
<!--
// 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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path d="M0.8,7.3v7c0,0.5,0.4,0.9,0.9,0.9h1.4V6.3H1.7C1.2,6.3,0.8,6.8,0.8,7.3z" />
<path
d="M13.3,6.3H9.8c0.5-0.9,1.3-3,0.8-4.2C10,0.7,8.2,0.6,8,0.9C7.8,1.3,5.8,4.7,4.8,6.3v8.9h6.5c1.9,0,2.6-0.7,2.8-1.5c0.2-0.9,0.7-3.3,1-5S14.2,6.3,13.3,6.3z"
/>
</svg>

View File

@ -85,6 +85,7 @@ export { default as Spinner } from './components/Spinner.svelte'
export { default as Popup } from './components/Popup.svelte'
export { default as CircleButton } from './components/CircleButton.svelte'
export { default as Link } from './components/Link.svelte'
export { default as Like } from './components/Like.svelte'
export { default as TimeSince } from './components/TimeSince.svelte'
export { default as Dropdown } from './components/Dropdown.svelte'
export { default as DropdownPopup } from './components/DropdownPopup.svelte'
@ -148,6 +149,7 @@ export { default as IconMinWidth } from './components/icons/MinWidth.svelte'
export { default as IconMaxWidth } from './components/icons/MaxWidth.svelte'
export { default as IconMixin } from './components/icons/Mixin.svelte'
export { default as IconCircles } from './components/icons/Circles.svelte'
export { default as IconLike } from './components/icons/Like.svelte'
export { default as PanelInstance } from './components/PanelInstance.svelte'
export { default as Panel } from './components/Panel.svelte'

View File

@ -19,14 +19,26 @@
import { getResource, IntlString } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import notification from '@hcengineering/notification'
import { Component, Grid, IconActivity, Label, Scroller, Button, showPopup, Spinner } from '@hcengineering/ui'
import {
Component,
Grid,
IconActivity,
Label,
Scroller,
Icon,
showPopup,
Spinner,
ActionIcon,
eventToHTMLElement
} from '@hcengineering/ui'
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
import TxView from './TxView.svelte'
import { filterCollectionTxes } from '../utils'
import { Writable } from 'svelte/store'
import view from '@hcengineering/view'
import activityPlg from '../plugin'
import FilterPopup from './FilterPopup.svelte'
import IconFilter from './icons/Filter.svelte'
import IconClose from './icons/Close.svelte'
export let object: Doc
export let integrate: boolean = false
@ -91,7 +103,7 @@
loading = false
}
},
SortingOrder.Descending,
SortingOrder.Ascending,
editableMap ?? new Map()
)
}
@ -110,12 +122,11 @@
return -1
}
let optionsBtn: HTMLButtonElement
const handleOptions = () => {
const handleOptions = (ev: MouseEvent) => {
showPopup(
FilterPopup,
{ selectedFilter, filters },
optionsBtn,
eventToHTMLElement(ev),
() => {},
(res) => {
if (res === undefined) return
@ -144,6 +155,7 @@
</script>
{#if !integrate || transparent}
<!-- OLD TRANSPARENT -->
{#if transparent !== undefined && !transparent}
<div class="ac-header short mirror-tool highlight">
<div class="ac-header__wrap-title">
@ -183,10 +195,10 @@
{/if}
</div>
{:else}
<!-- MODERN -->
<slot />
<!-- <div class="antiDivider" style:margin={'1rem -1.5rem'} /> -->
<div class="antiSection-header mt-6">
<div class="antiSection-header__icon"><IconActivity size={'small'} /></div>
<div class="antiSection-header high mt-9">
<span class="antiSection-header__title flex-row-center">
<Label label={activity.string.Activity} />
{#if loading}
@ -196,29 +208,25 @@
{/if}
</span>
{#if selectedFilter === 'All'}
<span class="antiSection-header__tag highlight"><Label label={activityPlg.string.All} /></span>
<div class="antiSection-header__tag highlight">
<Label label={activityPlg.string.All} />
</div>
{:else}
{#each labels as label}
<span class="antiSection-header__tag overflow-label"><Label {label} /></span>
<div class="antiSection-header__tag overflow-label">
<Label {label} />
<div class="tag-icon">
<Icon icon={IconClose} size={'small'} />
</div>
</div>
{/each}
{/if}
<div class="w-2 min-w-2 max-w-2" />
<Button
bind:input={optionsBtn}
icon={view.icon.ViewButton}
kind={'transparent'}
shape={'circle'}
on:click={handleOptions}
/>
<div class="w-4 min-w-4 max-w-4" />
<ActionIcon icon={IconFilter} size={'medium'} action={handleOptions} />
</div>
{#if showCommenInput}
<div class="ref-input">
<Component is={chunter.component.CommentInput} props={{ object }} />
</div>
{/if}
<div class="p-activity select-text" id={activity.string.Activity}>
{#if filtered}
<Grid column={1} rowGap={1.5}>
<Grid column={1} rowGap={0.75}>
{#each filtered as tx, i}
<TxView
{tx}
@ -230,6 +238,11 @@
</Grid>
{/if}
</div>
{#if showCommenInput}
<div class="ref-input">
<Component is={chunter.component.CommentInput} props={{ object }} />
</div>
{/if}
{/if}
<style lang="scss">
@ -240,13 +253,14 @@
}
.ref-input {
flex-shrink: 0;
padding: 0.75rem 0;
margin-top: 1.75rem;
padding-bottom: 2.5rem;
}
.p-activity {
padding: 1.5rem 0;
margin-top: 1.75rem;
}
:global(.grid .msgactivity-container:last-child::after) {
:global(.grid .msgactivity-container.showIcon:last-child::after) {
content: none;
} // Remove the line in the last Activity message
</style>

View File

@ -20,7 +20,7 @@
import { Asset } from '@hcengineering/platform'
import { createQuery, getClient } from '@hcengineering/presentation'
import {
Button,
ActionIcon,
Component,
Icon,
IconEdit,
@ -28,7 +28,8 @@
Label,
ShowMore,
showPopup,
TimeSince
TimeSince,
Like
} from '@hcengineering/ui'
import type { AttributeModel } from '@hcengineering/view'
import { Menu, ObjectPresenter } from '@hcengineering/view-resources'
@ -36,6 +37,8 @@
import activity from '../plugin'
import { getValue, TxDisplayViewlet, updateViewlet } from '../utils'
import TxViewTx from './TxViewTx.svelte'
import Edit from './icons/Edit.svelte'
import IconProfile from './icons/Profile.svelte'
export let tx: DisplayTx
export let viewlets: Map<ActivityKey, TxViewlet>
@ -146,132 +149,109 @@
$: updateMessageType(model, tx).then((res) => {
hasMessageType = res
})
$: isComment = viewlet && viewlet?.editable
$: isMention = viewlet?.display === 'emphasized' || isMessageType(model[0]?.attribute)
$: isColumn = isComment || isMention || hasMessageType
</script>
{#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0}
<div class="flex-between msgactivity-container" class:showIcon class:isNew class:isNextNew>
<div
class="msgactivity-container"
class:showIcon
class:withAvatar={isComment || isMention}
class:isNew
class:isNextNew
>
{#if showIcon}
<div class="flex-center icon">
{#if viewlet}
<Icon icon={viewlet.icon} size="small" />
{:else if viewlet === undefined && model.length > 0}
<Icon icon={modelIcon !== undefined ? modelIcon : IconEdit} size="small" />
{:else}
<Icon icon={activity.icon.Activity} size="small" />
{/if}
</div>
{#if isComment || isMention}
<div class="msgactivity-avatar">
<Icon icon={IconProfile} size={'medium'} />
</div>
{:else}
<div class="msgactivity-icon">
{#if viewlet}
<Icon icon={viewlet.icon} size="small" />
{:else if viewlet === undefined && model.length > 0}
<Icon icon={modelIcon !== undefined ? modelIcon : Edit} size="small" />
{:else}
<Icon icon={Edit} size="small" />
{/if}
</div>
{/if}
{/if}
<div
class="flex-grow flex-col clear-mins mr-2-5"
class:comment={viewlet && viewlet?.editable}
class:mention={viewlet?.display === 'emphasized' || isMessageType(model[0]?.attribute)}
>
<div class="flex-between">
<div class="flex-row-center flex-grow label">
<div class="bold">
<div class="msgactivity-content" class:content={isColumn} class:comment={isComment}>
<div class="msgactivity-content__header">
<div class="msgactivity-content__title labels-row">
<span class="bold">
{#if employee}
{getName(employee)}
{:else}
<Label label={core.string.System} />
{/if}
</div>
</span>
{#if viewlet && viewlet?.editable}
<div class="buttons-group small-gap">
<span class="buttons-group small-gap">
{#if viewlet.label}
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
{/if}
{#if tx.updated}
<Label label={activity.string.Edited} />
{/if}
{#if tx.tx.modifiedBy === getCurrentAccount()._id}
<Button
icon={IconMoreH}
kind={'transparent'}
shape={'circle'}
size={'medium'}
on:click={(ev) => showMenu(ev)}
/>
{/if}
</div>
<span class="time"><TimeSince value={tx.tx.modifiedOn} /></span>
</span>
{:else if viewlet && viewlet.label}
<div class="flex-row-center">
<span class="lower">
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
</span>
{#if viewlet.labelComponent}
<Component is={viewlet.labelComponent} {props} />
{/if}
</div>
<span class="lower">
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
</span>
{#if viewlet.labelComponent}
<Component is={viewlet.labelComponent} {props} />
{/if}
{/if}
{#if viewlet === undefined && model.length > 0 && tx.updateTx}
{#each model as m, i}
{#each model as m}
{#await getValue(client, m, tx) then value}
{#if value.added.length}
<span class="lower" class:flex-grow={hasMessageType}>
<Label label={activity.string.Added} />
<Label label={activity.string.To} />
<Label label={m.label} />
</span>
{#if hasMessageType && value.added.length < 2}
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
{/if}
<div class="strong">
<div class="flex flex-wrap gap-2" class:emphasized={value.added.length > 1}>
{#each value.added as cvalue}
{#if value.isObjectAdded}
<ObjectPresenter value={cvalue} />
{:else}
<svelte:component this={m.presenter} value={cvalue} />
{/if}
{/each}
</div>
</div>
{#if value.added.length > 1}
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
{/if}
{:else if value.removed.length}
<span class="lower" class:flex-grow={hasMessageType}>
<Label label={activity.string.Removed} />
<Label label={activity.string.From} />
<Label label={m.label} />
</span>
{#if hasMessageType}
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
{/if}
<div class="strong">
<div class="flex flex-wrap gap-2 flex-grow" class:emphasized={value.removed.length > 1}>
{#each value.removed as cvalue}
{#if value.isObjectRemoved}
<ObjectPresenter value={cvalue} />
{:else}
<svelte:component this={m.presenter} value={cvalue} />
{/if}
{/each}
</div>
</div>
{:else if value.set === null || value.set === undefined || value.set === ''}
<span class="lower"><Label label={activity.string.Unset} /> <Label label={m.label} /></span>
{:else}
<span class="lower" class:flex-grow={hasMessageType}>
<Label label={activity.string.Changed} />
<Label label={m.label} />
<Label label={activity.string.To} />
</span>
{#if hasMessageType}
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
{/if}
<div
class="strong"
class:message={isMessageType(m.attribute)}
class:emphasized={isMessageType(m.attribute)}
>
{#if value.isObjectSet}
<ObjectPresenter value={value.set} />
<span class="lower"><Label label={activity.string.Added} /></span>
<span class="lower"><Label label={activity.string.To} /></span>
<span class="lower"><Label label={m.label} /></span>
{#each value.added as cvalue}
{#if value.isObjectAdded}
<ObjectPresenter value={cvalue} inline />
{:else}
<svelte:component this={m.presenter} value={value.set} />
<svelte:component this={m.presenter} value={cvalue} inline />
{/if}
</div>
{/each}
{:else if value.removed.length}
<span class="lower"><Label label={activity.string.Removed} /></span>
<span class="lower"><Label label={activity.string.From} /></span>
<span class="lower"><Label label={m.label} /></span>
{#each value.removed as cvalue}
{#if value.isObjectRemoved}
<ObjectPresenter value={cvalue} inline />
{:else}
<svelte:component this={m.presenter} value={cvalue} inline />
{/if}
{/each}
{:else if value.set === null || value.set === undefined || value.set === ''}
<span class="lower"><Label label={activity.string.Unset} /></span>
<span class="lower"><Label label={m.label} /></span>
{:else}
<span class="lower"><Label label={activity.string.Changed} /></span>
<span class="lower"><Label label={m.label} /></span>
<span class="lower"><Label label={activity.string.To} /></span>
{#if !hasMessageType}
<span class="strong">
{#if value.isObjectSet}
<ObjectPresenter value={value.set} inline />
{:else}
<svelte:component this={m.presenter} value={value.set} inline />
{/if}
</span>
{/if}
{/if}
{/await}
{/each}
@ -279,49 +259,52 @@
{#each model as m}
{#await getValue(client, m, tx) then value}
{#if value.set === null || value.set === ''}
<span>
<Label label={activity.string.Unset} /> <span class="lower"><Label label={m.label} /></span>
</span>
<span class="lower"><Label label={activity.string.Unset} /></span>
<span class="lower"><Label label={m.label} /></span>
{:else}
<span>
<Label label={activity.string.Changed} />
<span class="lower"><Label label={m.label} /></span>
<Label label={activity.string.To} />
</span>
<div
class="strong"
class:message={isMessageType(m.attribute)}
class:emphasized={isMessageType(m.attribute)}
>
{#if value.isObjectSet}
<ObjectPresenter value={value.set} />
{:else}
<svelte:component this={m.presenter} value={value.set} />
{/if}
</div>
<span class="lower"><Label label={activity.string.Changed} /></span>
<span class="lower"><Label label={m.label} /></span>
<span class="lower"><Label label={activity.string.To} /></span>
{#if !hasMessageType}
<div class="strong">
{#if value.isObjectSet}
<ObjectPresenter value={value.set} inline />
{:else}
<svelte:component this={m.presenter} value={value.set} inline />
{/if}
</div>
{/if}
{/if}
{/await}
{/each}
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
{#if tx.collectionAttribute !== undefined && (tx.txDocIds?.size ?? 0) > 1}
<ShowMore ignore={edit}>
<div class="flex-row-center flex-grow flex-wrap clear-mins">
<TxViewTx {tx} {onCancelEdit} {edit} {viewlet} />
</div>
</ShowMore>
<TxViewTx {tx} {onCancelEdit} {edit} {viewlet} />
{:else if typeof viewlet.component === 'string'}
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
<Component is={viewlet.component} {props} on:close={onCancelEdit} inline />
{:else}
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} inline />
{/if}
{/if}
</div>
{#if !hasMessageType}
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
{#if isComment}
<div class="buttons-group">
<Like />
{#if tx.tx.modifiedBy === getCurrentAccount()._id}
<ActionIcon icon={IconMoreH} size={'small'} action={showMenu} />
{/if}
</div>
{:else if hasMessageType || isColumn}
<span class="time top ml-4"><TimeSince value={tx.tx.modifiedOn} /></span>
{/if}
</div>
{#if viewlet && viewlet.component && viewlet.display !== 'inline'}
{#if !isColumn}
<span class="time top ml-4"><TimeSince value={tx.tx.modifiedOn} /></span>
{/if}
{#if viewlet && viewlet.display !== 'inline'}
<div class="activity-content {viewlet.display}" class:contentHidden>
<ShowMore ignore={edit}>
{#if tx.collectionAttribute !== undefined && (tx.txDocIds?.size ?? 0) > 1}
@ -335,39 +318,83 @@
{/if}
</ShowMore>
</div>
{:else if hasMessageType && model.length > 0 && (tx.updateTx || tx.mixinTx)}
{#await getValue(client, model[0], tx) then value}
<div class="activity-content content" class:contentHidden>
<ShowMore ignore={edit}>
{#if value.isObjectSet}
<ObjectPresenter value={value.set} inline />
{:else}
<svelte:component this={model[0].presenter} value={value.set} inline />
{/if}
</ShowMore>
</div>
{/await}
{/if}
</div>
</div>
{/if}
<style lang="scss">
.comment,
.mention {
position: relative;
margin-top: 0.25rem;
&::after {
content: '';
position: absolute;
bottom: -0.75rem;
left: -0.625rem;
right: -0.625rem;
background-color: var(--accent-bg-color);
border: 1px solid var(--divider-color);
border-radius: 0.5rem;
z-index: -1;
}
}
.comment::after {
top: -0.375rem;
}
.mention::after {
top: -0.5rem;
}
.msgactivity-container {
position: relative;
min-width: 0;
display: flex;
justify-content: space-between;
&:hover .time {
opacity: 1;
}
.msgactivity-icon,
.msgactivity-avatar {
display: flex;
justify-content: center;
align-items: center;
margin-right: 1rem;
width: 2.25rem;
min-width: 2.25rem;
color: var(--darker-color);
}
.msgactivity-icon {
height: 1.75rem;
}
.msgactivity-avatar {
height: 2.25rem;
// background-color: var(--darker-color);
border: 1px dashed var(--divider-trans-color);
border-radius: 50%;
}
.msgactivity-content {
display: flex;
flex-grow: 1;
margin-right: 1rem;
color: var(--content-color);
.msgactivity-content__header {
display: flex;
justify-content: space-between;
align-items: center;
flex-grow: 1;
}
.msgactivity-content__title {
display: inline-flex;
align-items: center;
flex-grow: 1;
}
&.content {
flex-direction: column;
padding-bottom: 0.25rem;
}
&:not(.content) {
align-items: center;
.msgactivity-content__header {
justify-content: space-between;
}
}
}
}
.showIcon {
@ -376,7 +403,8 @@
position: absolute;
left: 1.125rem;
width: 1px;
background-color: var(--popup-divider);
background-color: var(--divider-trans-color);
z-index: 1;
}
&.isNew {
&::before {
@ -392,14 +420,19 @@
}
}
&::before {
top: -1.5rem;
height: 1.5rem;
top: -0.75rem;
height: 0.75rem;
}
&::after {
&.withAvatar::after {
content: '';
top: 2.25rem;
bottom: 0;
}
&:not(.withAvatar)::after {
content: '';
top: 1.75rem;
bottom: 0;
}
}
:global(.msgactivity-container + .msgactivity-container::before) {
content: '';
@ -413,69 +446,28 @@
opacity: 1;
}
}
.icon {
flex-shrink: 0;
align-self: flex-start;
margin-right: 1rem;
width: 2.25rem;
height: 2.25rem;
color: var(--caption-color);
border: 1px solid var(--popup-divider);
border-radius: 50%;
}
.label {
display: flex;
align-items: center;
flex-wrap: wrap;
& > * {
margin-right: 0.5rem;
}
& > *:last-child {
margin-right: 0;
}
.bold {
font-weight: 500;
color: var(--caption-color);
}
.strong {
font-weight: 500;
color: var(--accent-color);
}
}
.time {
align-self: baseline;
margin-left: 1rem;
color: var(--dark-color);
}
font-size: 0.75rem;
color: var(--trans-color);
opacity: 0.3;
.content {
flex-shrink: 0;
margin-top: 0.5rem;
min-width: 0;
min-height: 0;
}
.emphasized {
margin-top: 0.5rem;
background-color: var(--body-color);
border: 1px solid var(--divider-color);
border-radius: 0.5rem;
padding: 0.75rem 1rem;
&.top {
align-self: flex-start;
}
.comment & {
opacity: 1;
}
}
.message {
flex-basis: 100%;
}
.lower {
text-transform: lowercase;
}
.activity-content {
overflow: hidden;
visibility: visible;
margin-top: 0.25rem;
max-height: max-content;
opacity: 1;
transition-property: max-height, opacity;

View File

@ -21,40 +21,23 @@
}
</script>
<div class="flex-row-center flex-grow flex-wrap content">
{#each filterTx([...tx.txes, tx], core.class.TxCreateDoc) as ctx, i}
{#if i === 0}
<div class="mr-2"><IconAdd size={'small'} /></div>
{/if}
<div class="mr-2">
{#if typeof viewlet?.component === 'string'}
<Component is={viewlet?.component} props={getProps(ctx, edit)} on:close={onCancelEdit} />
{:else}
<svelte:component this={viewlet?.component} {...getProps(ctx, edit)} on:close={onCancelEdit} />
{/if}
</div>
{/each}
{#each filterTx([...tx.txes, tx], core.class.TxRemoveDoc) as ctx, i}
{#if i === 0}
<div class="mr-2"><IconDelete size={'small'} /></div>
{/if}
<div class="mr-2">
{#if typeof viewlet?.component === 'string'}
<Component is={viewlet?.component} props={getProps(ctx, edit)} on:close={onCancelEdit} />
{:else}
<svelte:component this={viewlet?.component} {...getProps(ctx, edit)} on:close={onCancelEdit} />
{/if}
</div>
{/each}
</div>
<style lang="scss">
.content {
padding: 0.5rem;
min-width: 0;
color: var(--accent-color);
background: var(--accent-bg-color);
border: 1px solid var(--divider-color);
border-radius: 0.75rem;
}
</style>
{#each filterTx([...tx.txes, tx], core.class.TxCreateDoc) as ctx, i}
{#if i === 0}
<IconAdd size={'x-small'} fill={'var(--trans-color)'} />
{/if}
{#if typeof viewlet?.component === 'string'}
<Component is={viewlet?.component} props={getProps(ctx, edit)} inline on:close={onCancelEdit} />
{:else}
<svelte:component this={viewlet?.component} {...getProps(ctx, edit)} inline on:close={onCancelEdit} />
{/if}
{/each}
{#each filterTx([...tx.txes, tx], core.class.TxRemoveDoc) as ctx, i}
{#if i === 0}
<IconDelete size={'x-small'} fill={'var(--trans-color)'} />
{/if}
{#if typeof viewlet?.component === 'string'}
<Component is={viewlet?.component} props={getProps(ctx, edit)} inline on:close={onCancelEdit} />
{:else}
<svelte:component this={viewlet?.component} {...getProps(ctx, edit)} inline on:close={onCancelEdit} />
{/if}
{/each}

View File

@ -0,0 +1,24 @@
<!--
// 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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path
d="M8.7,8l4.6-4.6c0.2-0.2,0.2-0.5,0-0.7s-0.5-0.2-0.7,0L8,7.3L3.4,2.6c-0.2-0.2-0.5-0.2-0.7,0s-0.2,0.5,0,0.7L7.3,8l-4.6,4.6c-0.2,0.2-0.2,0.5,0,0.7c0.1,0.1,0.2,0.1,0.4,0.1s0.3,0,0.4-0.1L8,8.7l4.6,4.6c0.1,0.1,0.2,0.1,0.4,0.1s0.3,0,0.4-0.1c0.2-0.2,0.2-0.5,0-0.7L8.7,8z"
/>
</svg>

View File

@ -0,0 +1,25 @@
<!--
// 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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path d="M15,14.2H9.4c-0.2,0-0.4,0.2-0.4,0.4S9.1,15,9.4,15H15c0.2,0,0.4-0.2,0.4-0.4S15.2,14.2,15,14.2z" />
<path
d="M11.8,6.8C11.8,6.8,11.8,6.8,11.8,6.8C13.2,5,13.3,5,13.3,5c0.3-0.5,0.4-1,0.3-1.6c-0.1-0.5-0.5-1-0.9-1.3c0,0-1.3-1-1.3-1c-0.9-0.7-2.2-0.6-3,0.3c0,0,0,0,0,0L1,10.5c-0.3,0.4-0.4,0.9-0.3,1.4l0.6,2.7c0,0.2,0.2,0.3,0.4,0.3c0,0,0,0,0,0l2.8,0c0.5,0,1-0.2,1.3-0.6C8.9,10.4,10.7,8.2,11.8,6.8C11.8,6.8,11.8,6.8,11.8,6.8z"
/>
</svg>

View File

@ -0,0 +1,27 @@
<!--
// 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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<path
d="M5.8,9.7c1.5,0,2.7-1.1,2.9-2.5h7.9c0.3,0,0.5-0.2,0.5-0.5s-0.2-0.5-0.5-0.5H8.8C8.5,4.8,7.3,3.7,5.8,3.7c-1.7,0-3,1.3-3,3S4.2,9.7,5.8,9.7z M5.8,4.7c1.1,0,2,0.9,2,2s-0.9,2-2,2s-2-0.9-2-2S4.7,4.7,5.8,4.7z"
/>
<path
d="M14.2,10.3c-1.5,0-2.7,1.1-2.9,2.5H3.3c-0.3,0-0.5,0.2-0.5,0.5s0.2,0.5,0.5,0.5h7.9c0.2,1.4,1.5,2.5,2.9,2.5c1.7,0,3-1.3,3-3S15.8,10.3,14.2,10.3z M14.2,15.3c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S15.3,15.3,14.2,15.3z"
/>
</svg>

View File

@ -0,0 +1,23 @@
<!--
// 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">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path d="M8,8.4c2,0,3.6-1.6,3.6-3.6S10,1.2,8,1.2S4.4,2.8,4.4,4.8S6,8.4,8,8.4z" />
<path d="M8,10.2c-2.9,0-5.4,0.5-5.4,2.3c0,1.9,2.5,2.3,5.4,2.3s5.4-0.5,5.4-2.3C13.3,10.6,10.9,10.2,8,10.2z" />
</svg>

View File

@ -135,7 +135,7 @@ async function checkInlineViewlets (
): Promise<{ viewlet: TxDisplayViewlet, model: AttributeModel[] }> {
if (dtx.collectionAttribute !== undefined && (dtx.txDocIds?.size ?? 0) > 1) {
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
viewlet = await createPseudoViewlet(client, dtx, activity.string.CollectionUpdated, 'content')
viewlet = await createPseudoViewlet(client, dtx, activity.string.CollectionUpdated, 'inline')
} else if (dtx.tx._class === core.class.TxCreateDoc) {
// Check if we have a class presenter we could have a pseudo viewlet based on class presenter.
viewlet = await createPseudoViewlet(client, dtx, activity.string.DocCreated)

View File

@ -127,7 +127,7 @@
color: var(--white-color);
background-color: var(--primary-bg-color);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 0.5rem;
border-radius: 0.25rem;
cursor: pointer;
.remove-btn {
@ -140,12 +140,20 @@
width: 100%;
height: 100%;
background-color: var(--primary-bg-hover);
border-radius: 0.5rem;
border-radius: 0.25rem;
opacity: 0;
}
}
.attachment-container {
margin-right: 1rem;
margin-right: 0.5rem;
// padding: .375rem;
// width: 14rem;
// min-width: 14rem;
// max-width: 14rem;
// background-color: var(--accent-bg-color);
// border: 1px solid var(--divider-color);
// border-radius: .25rem;
&:hover .remove-btn {
opacity: 1;
}

View File

@ -29,9 +29,11 @@
class:inline-presenter={inline}
href="#{getPanelURI(view.component.EditDoc, value._id, value._class, 'content')}"
>
<div class="icon">
<Icon icon={board.icon.Board} size={'small'} />
</div>
{#if !inline}
<div class="icon">
<Icon icon={board.icon.Board} size={'small'} />
</div>
{/if}
<span class="label">{value.name}</span>
</a>
{/if}

View File

@ -29,9 +29,11 @@
class:inline-presenter={inline}
href="#{getPanelURI(view.component.EditDoc, value._id, value._class, 'content')}"
>
<div class="icon">
<Icon icon={board.icon.Card} size={'small'} />
</div>
{#if !inline}
<div class="icon">
<Icon icon={board.icon.Card} size={'small'} />
</div>
{/if}
<span class="label">{value.title}</span>
</a>
{/if}

View File

@ -18,6 +18,7 @@
import { Icon, NavLink } from '@hcengineering/ui'
export let value: Channel
export let inline: boolean = false
const client = getClient()
$: icon = client.getHierarchy().getClass(value._class).icon
@ -26,11 +27,13 @@
{#if value}
<NavLink app={chunterId} space={value._id}>
<div class="flex-presenter">
<div class="icon">
{#if icon}
<Icon {icon} size={'small'} />
{/if}
</div>
{#if !inline}
<div class="icon">
{#if icon}
<Icon {icon} size={'small'} />
{/if}
</div>
{/if}
<span class="label">{value.name}</span>
</div>
</NavLink>

View File

@ -57,13 +57,11 @@
</script>
{#if presenter}
{#if targetPresenter}
<div class="mx-2">
<svelte:component this={targetPresenter.presenter} value={target} />
</div>
{/if}
<span style:text-transform={'lowercase'}><Label label={chunter.string.In} /></span>
<div class="ml-2">
<svelte:component this={presenter.presenter} value={doc} />
</div>
<span class="labels-row">
{#if targetPresenter}
<svelte:component this={targetPresenter.presenter} value={target} inline />
{/if}
<span style:text-transform={'lowercase'}><Label label={chunter.string.In} /></span>
<svelte:component this={presenter.presenter} value={doc} inline />
</span>
{/if}

View File

@ -27,7 +27,9 @@
{#if value}
<DocNavLink {inline} object={value}>
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
<div class="icon circle"><Company size={'small'} /></div>
{#if !inline}
<div class="icon circle"><Company size={'small'} /></div>
{/if}
<span class="label">{value.name}</span>
</div>
</DocNavLink>

View File

@ -48,7 +48,7 @@
class:text-base={enlargedText}
class:inline-presenter={inline}
>
{#if shouldShowAvatar}
{#if !inline && shouldShowAvatar}
<span
class="eContentPresenterIcon"
class:mr-2={shouldShowName && !enlargedText}
@ -70,7 +70,7 @@
{:else if shouldShowPlaceholder}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span use:tooltip={showTooltip} on:click={onEditClick} class="contentPresenter" class:text-base={enlargedText}>
{#if shouldShowAvatar}
{#if !inline && shouldShowAvatar}
<span
class="eContentPresenterIcon"
class:mr-2={shouldShowName && !enlargedText}

View File

@ -30,9 +30,11 @@
href="#{getPanelURI(document.component.EditDoc, value._id, value._class, 'content')}"
class:inline-presenter={inline}
>
<div class="icon">
<Icon icon={document.icon.Document} size={'small'} />
</div>
{#if !inline}
<div class="icon">
<Icon icon={document.icon.Document} size={'small'} />
</div>
{/if}
<span class="label">{value.name}-{value.version}</span>
</a>
{/if}

View File

@ -41,9 +41,11 @@
href="#{getPanelURI(document.component.EditDoc, value.attachedTo, value.attachedToClass, 'content')}"
class:inline-presenter={inline}
>
<div class="icon">
<Icon icon={document.icon.Document} size={'small'} />
</div>
{#if !inline}
<div class="icon">
<Icon icon={document.icon.Document} size={'small'} />
</div>
{/if}
<span class="label">
{doc?.name} - {value.version}
</span>

View File

@ -26,7 +26,9 @@
{#if value}
<DocNavLink {inline} object={value}>
<div class="flex-presenter" class:inline-presenter={inline}>
<div class="icon"><Icon icon={inventory.icon.Products} size={'small'} /></div>
{#if !inline}
<div class="icon"><Icon icon={inventory.icon.Products} size={'small'} /></div>
{/if}
<span class="label">{value.name}</span>
</div>
</DocNavLink>

View File

@ -26,9 +26,11 @@
{#if value}
<DocNavLink object={value} {inline}>
<div class="flex-presenter" class:inline-presenter={inline}>
<div class="icon">
<Icon icon={lead.icon.Lead} size={'small'} />
</div>
{#if !inline}
<div class="icon">
<Icon icon={lead.icon.Lead} size={'small'} />
</div>
{/if}
<span class="label nowrap">LEAD-{value.number}</span>
</div>
</DocNavLink>

View File

@ -31,9 +31,11 @@
{#if value && shortLabel}
<DocNavLink object={value} {inline} {disableClick}>
<div class="flex-presenter" class:inline-presenter={inline}>
<div class="icon">
<Icon icon={recruit.icon.Application} size={'small'} />
</div>
{#if !inline}
<div class="icon">
<Icon icon={recruit.icon.Application} size={'small'} />
</div>
{/if}
<span class="label nowrap">
{#if shortLabel}{shortLabel}-{/if}{value.number}
</span>

View File

@ -29,9 +29,9 @@
{#if value}
<DocNavLink {disableClick} object={value} {inline} component={recruit.component.EditVacancy}>
<div class="flex-presenter" class:inline-presenter={inline} use:tooltip={{ label: getEmbeddedLabel(value.name) }}>
<div class="icon">
<Icon icon={recruit.icon.Vacancy} size={'small'} />
</div>
{#if !inline}
<div class="icon"><Icon icon={recruit.icon.Vacancy} size={'small'} /></div>
{/if}
<span class="label">{value.name}</span>
</div>
</DocNavLink>

View File

@ -25,6 +25,7 @@
export let action: Asset | AnySvelteComponent | undefined = undefined
export let selected: boolean = false
export let schema: '0' | '3' | '9' = '9'
export let inline: boolean = false
const dispatch = createEventDispatcher()
@ -33,35 +34,51 @@
$: tagIcon = schema === '3' ? undefined : tagLevel[(((tag?.weight ?? 0) % 3) + 1) as 1 | 2 | 3]
</script>
<div
class="text-sm flex flex-between tag-item"
style={`${getTagStyle(getPlatformColor(tag?.color ?? element?.color ?? 0), selected)}`}
on:click
on:keydown
use:tooltip={{
label: element?.description ? tags.string.TagTooltip : undefined,
props: { text: element?.description },
direction: 'right'
}}
>
{name}
<span class="ml-1">
{#if tag && tagIcon && schema !== '0'}
<Icon icon={tagIcon} size={'small'} />
{/if}
{#if inline}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span
style={`--tag-color:${getPlatformColor(tag?.color ?? element?.color ?? 0)}`}
class="tag-item-inline"
on:click
use:tooltip={{
label: element?.description ? tags.string.TagTooltip : undefined,
props: { text: element?.description },
direction: 'right'
}}
>
{name}
</span>
{#if action}
<div class="ml-1">
<ActionIcon
icon={action}
size={'medium'}
action={() => {
dispatch('action')
}}
/>
</div>
{/if}
</div>
{:else}
<div
class="text-sm flex flex-between tag-item"
style={`${getTagStyle(getPlatformColor(tag?.color ?? element?.color ?? 0), selected)}`}
on:click
on:keydown
use:tooltip={{
label: element?.description ? tags.string.TagTooltip : undefined,
props: { text: element?.description },
direction: 'right'
}}
>
{name}
<span class="ml-1">
{#if tag && tagIcon && schema !== '0'}
<Icon icon={tagIcon} size={'small'} />
{/if}
</span>
{#if action}
<div class="ml-1">
<ActionIcon
icon={action}
size={'medium'}
action={() => {
dispatch('action')
}}
/>
</div>
{/if}
</div>
{/if}
<style lang="scss">
.tag-item {
@ -83,4 +100,23 @@
align-items: center;
justify-content: center;
}
.tag-item-inline {
position: relative;
padding-left: 0.75rem;
font-weight: 500;
color: var(--accent-color);
&::before {
position: absolute;
content: '';
top: 50%;
left: 0;
width: 0.25rem;
height: 0.25rem;
background-color: var(--tag-color);
border-radius: 50%;
transform: translateY(-50%);
z-index: 1;
}
}
</style>

View File

@ -25,13 +25,16 @@
export let kind: 'labels' | 'kanban-labels' | 'skills' = 'skills'
export let realWidth: number | undefined = undefined
export let attr: AnyAttribute | undefined
export let inline: boolean = false
const dispatch = createEventDispatcher()
$: tagIcon = tagLevel[(((value?.weight ?? 0) % 3) + 1) as 1 | 2 | 3]
</script>
{#if value}
{#if kind === 'skills'}
{#if inline}
<TagItem tag={value} schema={attr?.schema ?? '0'} inline />
{:else if kind === 'skills'}
<TagItem tag={value} schema={attr?.schema ?? '0'} />
{:else if kind === 'kanban-labels'}
<button

View File

@ -133,7 +133,7 @@
_class={tracker.class.Component}
itemsConfig={[
{ key: '', presenter: tracker.component.IconPresenter },
{ key: '', presenter: tracker.component.ComponentPresenter, props: { kind: 'list', withIcon: false } },
{ key: '', presenter: tracker.component.ComponentPresenter, props: { kind: 'list', shouldShowAvatar: false } },
{
key: '$lookup.lead',
presenter: tracker.component.LeadPresenter,

View File

@ -19,7 +19,7 @@
import tracker from '../../plugin'
export let value: WithLookup<Component>
export let withIcon = true
export let shouldShowAvatar = true
export let onClick: () => void | undefined
export let isInteractive = true
@ -43,7 +43,7 @@
{#if value}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex" on:click={navigateToComponent}>
{#if withIcon}
{#if shouldShowAvatar}
<div class="mr-2" use:tooltip={{ label: tracker.string.Component }}>
<Icon icon={tracker.icon.Component} size={'small'} />
</div>

View File

@ -23,7 +23,7 @@
export let value: WithLookup<Issue>
export let disableClick = false
export let onClick: (() => void) | undefined = undefined
export let withIcon = false
export let shouldShowAvatar: boolean = false
export let noUnderline = false
export let inline = false
@ -49,7 +49,7 @@
{#if value}
<DocNavLink object={value} {onClick} {disableClick} {noUnderline} {inline} component={tracker.component.EditIssue}>
<span class="issuePresenterRoot" class:inline>
{#if withIcon}
{#if shouldShowAvatar}
<div class="icon" use:tooltip={{ label: tracker.string.Issue }}>
<Icon icon={tracker.icon.Issues} size={'small'} />
</div>

View File

@ -37,5 +37,5 @@
</script>
{#if doc && presenter}
<svelte:component this={presenter.presenter} value={doc} onClick={onNavigate} withIcon noUnderline />
<svelte:component this={presenter.presenter} value={doc} onClick={onNavigate} shouldShowAvatar noUnderline />
{/if}

View File

@ -19,7 +19,7 @@
import tracker from '../../plugin'
export let value: WithLookup<Sprint>
export let withIcon = true
export let shouldShowAvatar: boolean = true
export let onClick: () => void | undefined
export let isInteractive = true
@ -42,7 +42,7 @@
{#if value}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex" on:click={navigateToSprint}>
{#if withIcon}
{#if shouldShowAvatar}
<div class="mr-2" use:tooltip={{ label: tracker.string.Sprint }}>
<Icon icon={tracker.icon.Sprint} size={'small'} />
</div>

View File

@ -17,11 +17,16 @@
import { ScrollerBar } from '@hcengineering/ui'
export let value: string
export let inline: boolean = false
let divScroll: HTMLElement
</script>
<div class="clear-mins max-w-80">
<ScrollerBar bind:scroller={divScroll}>
<a href={value} target="_blank" class="select-text">{value}</a>
</ScrollerBar>
</div>
{#if inline}
<a href={value} target="_blank" rel="noreferrer" class="select-text">{value}</a>
{:else}
<div class="clear-mins max-w-80">
<ScrollerBar bind:scroller={divScroll}>
<a href={value} target="_blank" rel="noreferrer" class="select-text">{value}</a>
</ScrollerBar>
</div>
{/if}

View File

@ -23,6 +23,7 @@
export let value: Doc | RelatedDocument | undefined = undefined
export let props: Record<string, any> = {}
export let inline: boolean = true
export let shouldShowAvatar: boolean = true
const client = getClient()
let presenter: AttributeModel | undefined
@ -57,5 +58,5 @@
</script>
{#if presenter}
<svelte:component this={presenter.presenter} value={doc} {...props} {inline} />
<svelte:component this={presenter.presenter} value={doc} {...props} {inline} {shouldShowAvatar} />
{/if}