mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 11:42:30 +03:00
TSK-930, TSK-933. Update Activity feed layout (#2834)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
dafb569f44
commit
78248b84f3
@ -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}
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -306,6 +306,11 @@
|
||||
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 {
|
||||
|
@ -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}
|
||||
|
72
packages/ui/src/components/Like.svelte
Normal file
72
packages/ui/src/components/Like.svelte
Normal 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>
|
@ -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">
|
||||
|
@ -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>
|
||||
|
||||
|
25
packages/ui/src/components/icons/Like.svelte
Normal file
25
packages/ui/src/components/icons/Like.svelte
Normal 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>
|
@ -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'
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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}
|
||||
|
24
plugins/activity-resources/src/components/icons/Close.svelte
Normal file
24
plugins/activity-resources/src/components/icons/Close.svelte
Normal 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>
|
25
plugins/activity-resources/src/components/icons/Edit.svelte
Normal file
25
plugins/activity-resources/src/components/icons/Edit.svelte
Normal 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>
|
@ -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>
|
@ -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>
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user