mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-24 12:06:57 +03:00
Update activity layout (#430)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
c06d48e0b0
commit
c72376987e
@ -36,11 +36,11 @@
|
||||
action.action()
|
||||
}}>
|
||||
{#if action.icon}
|
||||
<div class="icon">
|
||||
<Icon icon={action.icon} size={'large'} />
|
||||
<div class="scale-75">
|
||||
<Icon icon={action.icon} size={'medium'} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="label"><Label label={action.label} /></div>
|
||||
<div class="ml-3"><Label label={action.label} /></div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@ -59,19 +59,13 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .375rem 1rem .375rem .5rem;
|
||||
color: var(--theme-content-color);
|
||||
border-radius: .5rem;
|
||||
cursor: pointer;
|
||||
|
||||
.icon {
|
||||
margin-right: .75rem;
|
||||
transform-origin: center center;
|
||||
transform: scale(.75);
|
||||
opacity: .3;
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
.label {
|
||||
flex-grow: 1;
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
&:hover { background-color: var(--theme-button-bg-hovered); }
|
||||
}
|
||||
</style>
|
||||
|
@ -3,6 +3,8 @@
|
||||
"Delete": "Delete",
|
||||
"Edit": "Edit",
|
||||
"Options": "Options",
|
||||
"Edited": "edited"
|
||||
"Edited": "edited",
|
||||
"ShowMore": "Show more",
|
||||
"ShowLess": "Show less"
|
||||
}
|
||||
}
|
@ -133,7 +133,7 @@
|
||||
|
||||
.right-content {
|
||||
flex-grow: 1;
|
||||
padding: 2.5rem 2.5rem 0;
|
||||
padding: 2.25rem 2.5rem 0;
|
||||
background-color: var(--theme-dialog-accent);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { TxViewlet } from '@anticrm/activity'
|
||||
import activity from '@anticrm/activity'
|
||||
@ -34,6 +35,7 @@
|
||||
} from '@anticrm/ui'
|
||||
import type { Action, AttributeModel } from '@anticrm/view'
|
||||
import { buildModel, getActions, getObjectPresenter } from '@anticrm/view-resources'
|
||||
import { afterUpdate } from 'svelte'
|
||||
import { activityKey, ActivityKey, DisplayTx } from '../activity'
|
||||
|
||||
export let tx: DisplayTx
|
||||
@ -54,6 +56,20 @@
|
||||
let actions: Action[] = []
|
||||
|
||||
let edit = false
|
||||
let contentHTML: HTMLElement
|
||||
let bigMsg: boolean | undefined = undefined
|
||||
let outterBtn: boolean | undefined = undefined
|
||||
|
||||
const showContent = (): void => { bigMsg = outterBtn = true }
|
||||
const hideContent = (): void => { bigMsg = outterBtn = false }
|
||||
const toggleContent = (): void => bigMsg ? hideContent() : showContent()
|
||||
|
||||
afterUpdate(() => {
|
||||
if (contentHTML) {
|
||||
if (contentHTML.scrollHeight !== contentHTML.clientHeight) (edit) ? showContent() : hideContent()
|
||||
if (contentHTML.clientHeight < 240) bigMsg = outterBtn = undefined
|
||||
}
|
||||
})
|
||||
|
||||
$: if (tx.tx._id !== ptx?.tx._id) {
|
||||
viewlet = undefined
|
||||
@ -163,68 +179,80 @@
|
||||
</script>
|
||||
|
||||
{#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0}
|
||||
<div class="flex-col msgactivity-container">
|
||||
<div class="flex-between">
|
||||
<div class="flex-center icon">
|
||||
<div class="scale-75">
|
||||
{#if viewlet}
|
||||
<Icon icon={viewlet.icon} size="medium" />
|
||||
{:else}
|
||||
<Icon icon={activity.icon.Activity} size="medium" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow label">
|
||||
<div class="bold">
|
||||
{#if employee}
|
||||
{formatName(employee.name)}
|
||||
{:else}
|
||||
No employee
|
||||
{/if}
|
||||
</div>
|
||||
{#if viewlet && viewlet?.editable}
|
||||
<div class="edited">
|
||||
{#if viewlet.label}
|
||||
<Label label={viewlet.label} />
|
||||
{/if}
|
||||
{#if tx.updated}
|
||||
<Label label={activity.string.Edited} />
|
||||
{/if}
|
||||
<div class="menuOptions" on:click={(ev) => showMenu(ev)}>
|
||||
<IconMoreH size={'small'} />
|
||||
</div>
|
||||
</div>
|
||||
{:else if viewlet && viewlet.label}
|
||||
<div>
|
||||
<Label label={viewlet.label} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if viewlet === undefined && model.length > 0 && tx.updateTx}
|
||||
{#each model as m}
|
||||
<span>changed {m.label} to</span>
|
||||
<div class="strong"><svelte:component this={m.presenter} value={getValue(tx.updateTx, m.key)} /></div>
|
||||
{/each}
|
||||
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
||||
<div>
|
||||
{#if typeof viewlet.component === 'string'}
|
||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||
{:else}
|
||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
||||
</div>
|
||||
{#if viewlet && viewlet.component && viewlet.display !== 'inline'}
|
||||
<div class="content" class:emphasize={viewlet.display === 'emphasized'}>
|
||||
{#if typeof viewlet.component === 'string'}
|
||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||
<div class="flex-between msgactivity-container">
|
||||
|
||||
<div class="flex-center icon">
|
||||
<div class="scale-75">
|
||||
{#if viewlet}
|
||||
<Icon icon={viewlet.icon} size="medium" />
|
||||
{:else}
|
||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||
<Icon icon={activity.icon.Activity} size="medium" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex-grow flex-col relative">
|
||||
|
||||
<div class="flex-between">
|
||||
<div class="flex-grow label">
|
||||
<div class="bold">
|
||||
{#if employee}
|
||||
{formatName(employee.name)}
|
||||
{:else}
|
||||
No employee
|
||||
{/if}
|
||||
</div>
|
||||
{#if viewlet && viewlet?.editable}
|
||||
<div class="edited">
|
||||
{#if viewlet.label}
|
||||
<Label label={viewlet.label} />
|
||||
{/if}
|
||||
{#if tx.updated}
|
||||
<Label label={activity.string.Edited} />
|
||||
{/if}
|
||||
<div class="menuOptions" on:click={(ev) => showMenu(ev)}>
|
||||
<IconMoreH size={'medium'} />
|
||||
</div>
|
||||
</div>
|
||||
{:else if viewlet && viewlet.label}
|
||||
<div>
|
||||
<Label label={viewlet.label} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if viewlet === undefined && model.length > 0 && tx.updateTx}
|
||||
{#each model as m}
|
||||
<span>changed {m.label} to</span>
|
||||
<div class="strong"><svelte:component this={m.presenter} value={getValue(tx.updateTx, m.key)} /></div>
|
||||
{/each}
|
||||
{:else if viewlet && viewlet.display === 'inline' && viewlet.component}
|
||||
<div>
|
||||
{#if typeof viewlet.component === 'string'}
|
||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||
{:else}
|
||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
|
||||
</div>
|
||||
|
||||
{#if viewlet && viewlet.component && viewlet.display !== 'inline'}
|
||||
<div bind:this={contentHTML} class={viewlet.display} class:full={bigMsg || edit} class:mask={bigMsg === false && !edit}>
|
||||
{#if typeof viewlet.component === 'string'}
|
||||
<Component is={viewlet.component} {props} on:close={onCancelEdit} />
|
||||
{:else}
|
||||
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if typeof outterBtn !== 'undefined' && !edit}
|
||||
<div class="showMore" class:outter={outterBtn} on:click={toggleContent}>
|
||||
<Label label={(bigMsg) ? activity.string.ShowLess : activity.string.ShowMore} />
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -254,12 +282,10 @@
|
||||
// :global(.msgactivity-container > *:last-child::after) { content: none; }
|
||||
|
||||
.menuOptions {
|
||||
margin-left: 0.5rem;
|
||||
opacity: 0.6;
|
||||
margin-left: .5rem;
|
||||
opacity: .6;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
&:hover { opacity: 1; }
|
||||
}
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
@ -272,20 +298,6 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 0.5rem 0 0.5rem 3.25rem;
|
||||
}
|
||||
.emphasize {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: 0.75rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
.time {
|
||||
margin-left: 1rem;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
|
||||
.edited {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -297,12 +309,8 @@
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
& > * {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
& > *:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
& > * { margin-right: .5rem; }
|
||||
& > *:last-child { margin-right: 0; }
|
||||
.bold {
|
||||
font-weight: 500;
|
||||
color: var(--theme-caption-color);
|
||||
@ -312,4 +320,61 @@
|
||||
color: var(--theme-content-accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
.time {
|
||||
margin-left: 1rem;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
margin-top: .5rem;
|
||||
height: max-content;
|
||||
max-height: 15rem;
|
||||
|
||||
&.full { max-height: max-content; }
|
||||
&.mask { mask: linear-gradient(to top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 75%); }
|
||||
}
|
||||
|
||||
.showMore {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 0 auto;
|
||||
padding: .5rem 1rem;
|
||||
width: fit-content;
|
||||
|
||||
font-size: .75rem;
|
||||
color: var(--theme-caption-color);
|
||||
background: var(--theme-card-bg);
|
||||
border: .5px solid var(--theme-card-divider);
|
||||
box-shadow: 0px 8px 15px rgba(0, 0, 0, .1);
|
||||
backdrop-filter: blur(120px);
|
||||
border-radius: 2.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
opacity: .3;
|
||||
transform: scale(.9);
|
||||
transition: opacity .1s ease-in-out, transform .1s ease-in-out;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
&:active {
|
||||
opacity: .9;
|
||||
transform: scale(.95);
|
||||
}
|
||||
|
||||
&.outter { bottom: -1.5rem; }
|
||||
}
|
||||
|
||||
.emphasized {
|
||||
margin-top: .5rem;
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border: 1px solid var(--theme-bg-accent-color);
|
||||
border-radius: .75rem;
|
||||
padding: 1rem 1.25rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -52,7 +52,9 @@ export default plugin(activityId, {
|
||||
Delete: '' as IntlString,
|
||||
Edit: '' as IntlString,
|
||||
Options: '' as IntlString,
|
||||
Edited: '' as IntlString
|
||||
Edited: '' as IntlString,
|
||||
ShowMore: '' as IntlString,
|
||||
ShowLess: '' as IntlString
|
||||
},
|
||||
icon: {
|
||||
Activity: '' as Asset
|
||||
|
@ -110,23 +110,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
top: -.5rem;
|
||||
right: -.5rem;
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
user-select: none;
|
||||
// .buttons {
|
||||
// position: absolute;
|
||||
// visibility: hidden;
|
||||
// top: -.5rem;
|
||||
// right: -.5rem;
|
||||
// display: flex;
|
||||
// flex-direction: row-reverse;
|
||||
// user-select: none;
|
||||
|
||||
.tool + .tool {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
}
|
||||
// .tool + .tool {
|
||||
// margin-right: .5rem;
|
||||
// }
|
||||
// }
|
||||
|
||||
&:hover > .buttons {
|
||||
visibility: visible;
|
||||
}
|
||||
// &:hover > .buttons {
|
||||
// visibility: visible;
|
||||
// }
|
||||
&:hover::before {
|
||||
content: '';
|
||||
}
|
||||
|
@ -14,8 +14,8 @@
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Comment } from "@anticrm/chunter";
|
||||
import type { TxCreateDoc } from "@anticrm/core";
|
||||
import type { Comment } from "@anticrm/chunter"
|
||||
import type { TxCreateDoc } from "@anticrm/core"
|
||||
import { getClient, MessageViewer } from '@anticrm/presentation'
|
||||
import { ReferenceInput } from "@anticrm/text-editor"
|
||||
import { Button } from "@anticrm/ui"
|
||||
@ -39,30 +39,23 @@
|
||||
}
|
||||
let refInput: ReferenceInput
|
||||
</script>
|
||||
<div class='container' class:editing={editing}>
|
||||
<div class="text">
|
||||
{#if edit}
|
||||
<ReferenceInput bind:this={refInput} content={value.message} on:message={onMessage} showSend={false}/>
|
||||
<div class='flex-row-reverse flex-grab'>
|
||||
<Button label={chunter.string.EditCancel} on:click={() => {
|
||||
dispatch('close', false)
|
||||
}}/>
|
||||
<Button label={chunter.string.EditUpdate} on:click={() => refInput.submit()} />
|
||||
</div>
|
||||
{:else}
|
||||
<MessageViewer message={value.message}/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class:editing={editing}>
|
||||
{#if edit}
|
||||
<ReferenceInput bind:this={refInput} content={value.message} on:message={onMessage} showSend={false}/>
|
||||
<div class='flex-row-reverse safari-gap-2 reverse'>
|
||||
<Button label={chunter.string.EditCancel} on:click={() => {
|
||||
dispatch('close', false)
|
||||
}}/>
|
||||
<Button label={chunter.string.EditUpdate} on:click={() => refInput.submit()} />
|
||||
</div>
|
||||
{:else}
|
||||
<MessageViewer message={value.message}/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
.text {
|
||||
line-height: 150%;
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
.editing {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
}
|
||||
.editing {
|
||||
border: 1px solid var(--primary-button-focused-border);
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user