Update activity layout (#430)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2021-11-30 14:12:14 +03:00 committed by GitHub
parent c06d48e0b0
commit c72376987e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 195 additions and 139 deletions

View File

@ -36,11 +36,11 @@
action.action() action.action()
}}> }}>
{#if action.icon} {#if action.icon}
<div class="icon"> <div class="scale-75">
<Icon icon={action.icon} size={'large'} /> <Icon icon={action.icon} size={'medium'} />
</div> </div>
{/if} {/if}
<div class="label"><Label label={action.label} /></div> <div class="ml-3"><Label label={action.label} /></div>
</div> </div>
{/each} {/each}
</div> </div>
@ -59,19 +59,13 @@
display: flex; display: flex;
align-items: center; align-items: center;
padding: .375rem 1rem .375rem .5rem; padding: .375rem 1rem .375rem .5rem;
color: var(--theme-content-color);
border-radius: .5rem; border-radius: .5rem;
cursor: pointer; cursor: pointer;
.icon { &:hover {
margin-right: .75rem; background-color: var(--theme-button-bg-hovered);
transform-origin: center center; color: var(--theme-caption-color);
transform: scale(.75);
opacity: .3;
} }
.label {
flex-grow: 1;
color: var(--theme-content-accent-color);
}
&:hover { background-color: var(--theme-button-bg-hovered); }
} }
</style> </style>

View File

@ -3,6 +3,8 @@
"Delete": "Delete", "Delete": "Delete",
"Edit": "Edit", "Edit": "Edit",
"Options": "Options", "Options": "Options",
"Edited": "edited" "Edited": "edited",
"ShowMore": "Show more",
"ShowLess": "Show less"
} }
} }

View File

@ -133,7 +133,7 @@
.right-content { .right-content {
flex-grow: 1; flex-grow: 1;
padding: 2.5rem 2.5rem 0; padding: 2.25rem 2.5rem 0;
background-color: var(--theme-dialog-accent); background-color: var(--theme-dialog-accent);
} }

View File

@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import type { TxViewlet } from '@anticrm/activity' import type { TxViewlet } from '@anticrm/activity'
import activity from '@anticrm/activity' import activity from '@anticrm/activity'
@ -34,6 +35,7 @@
} from '@anticrm/ui' } from '@anticrm/ui'
import type { Action, AttributeModel } from '@anticrm/view' import type { Action, AttributeModel } from '@anticrm/view'
import { buildModel, getActions, getObjectPresenter } from '@anticrm/view-resources' import { buildModel, getActions, getObjectPresenter } from '@anticrm/view-resources'
import { afterUpdate } from 'svelte'
import { activityKey, ActivityKey, DisplayTx } from '../activity' import { activityKey, ActivityKey, DisplayTx } from '../activity'
export let tx: DisplayTx export let tx: DisplayTx
@ -54,6 +56,20 @@
let actions: Action[] = [] let actions: Action[] = []
let edit = false 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) { $: if (tx.tx._id !== ptx?.tx._id) {
viewlet = undefined viewlet = undefined
@ -163,68 +179,80 @@
</script> </script>
{#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0} {#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0}
<div class="flex-col msgactivity-container"> <div class="flex-between msgactivity-container">
<div class="flex-between">
<div class="flex-center icon"> <div class="flex-center icon">
<div class="scale-75"> <div class="scale-75">
{#if viewlet} {#if viewlet}
<Icon icon={viewlet.icon} size="medium" /> <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} />
{:else} {:else}
<svelte:component this={viewlet.component} {...props} on:close={onCancelEdit} /> <Icon icon={activity.icon.Activity} size="medium" />
{/if} {/if}
</div> </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> </div>
{/if} {/if}
@ -254,12 +282,10 @@
// :global(.msgactivity-container > *:last-child::after) { content: none; } // :global(.msgactivity-container > *:last-child::after) { content: none; }
.menuOptions { .menuOptions {
margin-left: 0.5rem; margin-left: .5rem;
opacity: 0.6; opacity: .6;
cursor: pointer; cursor: pointer;
&:hover { &:hover { opacity: 1; }
opacity: 1;
}
} }
.icon { .icon {
flex-shrink: 0; flex-shrink: 0;
@ -272,20 +298,6 @@
border-radius: 50%; 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 { .edited {
display: flex; display: flex;
align-items: center; align-items: center;
@ -297,12 +309,8 @@
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
& > * { & > * { margin-right: .5rem; }
margin-right: 0.5rem; & > *:last-child { margin-right: 0; }
}
& > *:last-child {
margin-right: 0;
}
.bold { .bold {
font-weight: 500; font-weight: 500;
color: var(--theme-caption-color); color: var(--theme-caption-color);
@ -312,4 +320,61 @@
color: var(--theme-content-accent-color); 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> </style>

View File

@ -52,7 +52,9 @@ export default plugin(activityId, {
Delete: '' as IntlString, Delete: '' as IntlString,
Edit: '' as IntlString, Edit: '' as IntlString,
Options: '' as IntlString, Options: '' as IntlString,
Edited: '' as IntlString Edited: '' as IntlString,
ShowMore: '' as IntlString,
ShowLess: '' as IntlString
}, },
icon: { icon: {
Activity: '' as Asset Activity: '' as Asset

View File

@ -110,23 +110,23 @@
} }
} }
.buttons { // .buttons {
position: absolute; // position: absolute;
visibility: hidden; // visibility: hidden;
top: -.5rem; // top: -.5rem;
right: -.5rem; // right: -.5rem;
display: flex; // display: flex;
flex-direction: row-reverse; // flex-direction: row-reverse;
user-select: none; // user-select: none;
.tool + .tool { // .tool + .tool {
margin-right: .5rem; // margin-right: .5rem;
} // }
} // }
&:hover > .buttons { // &:hover > .buttons {
visibility: visible; // visibility: visible;
} // }
&:hover::before { &:hover::before {
content: ''; content: '';
} }

View File

@ -14,8 +14,8 @@
--> -->
<script lang="ts"> <script lang="ts">
import type { Comment } from "@anticrm/chunter"; import type { Comment } from "@anticrm/chunter"
import type { TxCreateDoc } from "@anticrm/core"; import type { TxCreateDoc } from "@anticrm/core"
import { getClient, MessageViewer } from '@anticrm/presentation' import { getClient, MessageViewer } from '@anticrm/presentation'
import { ReferenceInput } from "@anticrm/text-editor" import { ReferenceInput } from "@anticrm/text-editor"
import { Button } from "@anticrm/ui" import { Button } from "@anticrm/ui"
@ -39,30 +39,23 @@
} }
let refInput: ReferenceInput let refInput: ReferenceInput
</script> </script>
<div class='container' class:editing={editing}>
<div class="text"> <div class:editing={editing}>
{#if edit} {#if edit}
<ReferenceInput bind:this={refInput} content={value.message} on:message={onMessage} showSend={false}/> <ReferenceInput bind:this={refInput} content={value.message} on:message={onMessage} showSend={false}/>
<div class='flex-row-reverse flex-grab'> <div class='flex-row-reverse safari-gap-2 reverse'>
<Button label={chunter.string.EditCancel} on:click={() => { <Button label={chunter.string.EditCancel} on:click={() => {
dispatch('close', false) dispatch('close', false)
}}/> }}/>
<Button label={chunter.string.EditUpdate} on:click={() => refInput.submit()} /> <Button label={chunter.string.EditUpdate} on:click={() => refInput.submit()} />
</div> </div>
{:else} {:else}
<MessageViewer message={value.message}/> <MessageViewer message={value.message}/>
{/if} {/if}
</div>
</div> </div>
<style lang="scss"> <style lang="scss">
.container { .editing {
.text { border: 1px solid var(--primary-button-focused-border);
line-height: 150%;
color: var(--theme-content-color);
}
.editing {
border: 1px solid var(--primary-button-focused-border);
}
} }
</style> </style>