Optimize components, dialogs. Fix issues. Update Scroller. (#945)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2022-02-07 16:39:23 +07:00 committed by GitHub
parent 11abc2f38c
commit bff122ee8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 385 additions and 469 deletions

View File

@ -18,7 +18,7 @@
import type { Doc } from '@anticrm/core'
import type { Asset } from '@anticrm/platform'
import type { AnyComponent, AnySvelteComponent } from '@anticrm/ui'
import { Icon, IconClose, IconExpand, IconMoreH, Component, ActionIcon } from '@anticrm/ui'
import { Icon, IconClose, IconExpand, IconMoreH, Component, ActionIcon, Scroller } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
export let title: string
@ -31,183 +31,63 @@
const dispatch = createEventDispatcher()
</script>
<div
class="overlay"
on:click={() => {
dispatch('close')
}}
/>
<div class="dialog-container" class:fullSize>
<div class="antiOverlay" on:click={() => { dispatch('close') }} />
<div class="antiDialogs antiComponent" class:fullSize>
{#if fullSize}
<div class="leftSection">
<div class="flex-between header">
<Icon {icon} size={'large'} />
<div class="flex-grow ml-4 flex-col">
<div class="fs-title">{title}</div>
{#if subtitle}
<div class="text-sm content-dark-color">{subtitle}</div>
{/if}
<div class="ad-section-50 divide">
<div class="ac-header short mirror divide">
<div class="ac-header__wrap-title">
{#if icon }<div class="ac-header__icon"><Icon {icon} size={'large'}/></div>{/if}
<div class="ac-header__wrap-description">
<span class="ac-header__title">{title}</span>
{#if subtitle }<span class="ac-header__description">{subtitle}</span>{/if}
</div>
</div>
<!-- <ActionIcon icon={IconMoreH} size={'medium'} /> -->
</div>
{#if $$slots.subtitle}
<div class="flex-row-center subtitle">
<div class="flex-grow flex-row-center ml-10 mr-10">
<div class="ac-subtitle">
<div class="ac-subtitle-content">
<slot name="subtitle" />
</div>
</div>
{/if}
<div class="flex-col scroll-container">
<div class="flex-col content">
<slot />
</div>
</div>
<Scroller>
<div class="p-10"><slot /></div>
</Scroller>
</div>
<div class="rightSection">
<div class="ad-section-50">
<Component is={rightSection ?? activity.component.Activity} props={{ object, fullSize }} />
</div>
{:else}
<div class="unionSection">
<div class="flex-row-center header">
<Icon {icon} size={'large'} />
<div class="flex-grow ml-4 flex-col">
<div class="fs-title">{title}</div>
<div class="text-sm content-dark-color">Candidate pool name</div>
<div class="ac-header short mirror-tool divide">
<div class="ac-header__wrap-title">
{#if icon }<div class="ac-header__icon"><Icon {icon} size={'large'}/></div>{/if}
<div class="ac-header__wrap-description">
<span class="ac-header__title">{title}</span>
{#if subtitle }<span class="ac-header__description">{subtitle}</span>{/if}
</div>
<!-- <ActionIcon icon={IconMoreH} size={'medium'} /> -->
</div>
{#if $$slots.subtitle}<div class="flex-row-center subtitle"><slot name="subtitle" /></div>{/if}
<Component is={activity.component.Activity} props={{ object, fullSize }}>
<slot />
</Component>
<ActionIcon icon={IconMoreH} size={'medium'} />
</div>
{#if $$slots.subtitle}
<div class="ac-subtitle">
<div class="ac-subtitle-content">
<slot name="subtitle" />
</div>
</div>
{/if}
<Component is={activity.component.Activity} props={{ object, fullSize }}>
<slot />
</Component>
{/if}
<div class="tools">
<div
class="tool"
on:click={() => {
fullSize = !fullSize
}}
>
<div class="icon"><IconExpand size={'small'} /></div>
<div class="ad-tools">
<div class="tool">
<ActionIcon icon={IconExpand} size={'medium'} action={() => { fullSize = !fullSize }} />
</div>
<div
class="tool"
on:click={() => {
dispatch('close')
}}
>
<div class="icon"><IconClose size={'small'} /></div>
<div class="tool">
<ActionIcon icon={IconClose} size={'medium'} action={() => { dispatch('close') }} />
</div>
</div>
</div>
<style lang="scss">
.dialog-container {
overflow: hidden;
position: fixed;
top: 32px;
bottom: 1.25rem;
left: 50%;
right: 1rem;
display: flex;
flex-direction: column;
height: calc(100% - 32px - 1.25rem);
background: var(--theme-bg-color);
border-radius: 1.25rem;
.header {
flex-shrink: 0;
padding: 0 2.5rem 0 2.5rem;
min-height: 0;
height: 4rem;
color: var(--theme-content-accent-color);
border-bottom: 1px solid var(--theme-zone-bg);
}
.subtitle {
overflow-x: auto;
flex-shrink: 0;
min-height: 0;
height: 3.5rem;
border-bottom: 1px solid var(--theme-zone-bg);
&::-webkit-scrollbar:horizontal { height: .25rem; }
&::-webkit-scrollbar-track { margin: 0; }
&::-webkit-scrollbar-thumb {
background-color: var(--theme-menu-divider);
border-radius: .25rem;
&:hover { background-color: var(--theme-card-divider); }
}
}
}
.unionSection {
flex-grow: 1;
display: flex;
flex-direction: column;
height: max-content;
.header {
padding: 0 6rem 0 2.5rem;
}
}
.fullSize {
flex-direction: row;
left: 1rem;
}
.leftSection,
.rightSection {
flex-basis: 50%;
width: 50%;
min-height: 0;
display: flex;
flex-direction: column;
}
.leftSection {
border-right: 1px solid var(--theme-card-divider);
.scroll-container {
overflow: auto;
margin: 2.5rem 2rem 1.5rem;
.content {
flex-shrink: 0;
margin: 0.5rem 0.5rem 0;
}
}
}
// .rightSection {
// background-color: transparent;
// }
.tools {
position: absolute;
display: flex;
top: 1.5rem;
right: 2rem;
.tool {
margin-left: 1rem;
color: var(--theme-content-accent-color);
cursor: pointer;
&:hover {
color: var(--theme-caption-color);
}
}
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: .5;
}
</style>

View File

@ -24,10 +24,10 @@
</script>
<div class="flex-row-center">
<div class="flex-center {size} caption-color"><IconFolder size={'small'} /></div>
<div class="flex-col user-info">
{#if subtitle}<div class="subtitle">{subtitle}</div>{/if}
<div class="title">{value.name}</div>
<div class="flex-center {size} caption-color flex-no-shrink"><IconFolder size={'small'} /></div>
<div class="flex-col ml-2 min-w-0">
{#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if}
<div class="content-accent-color overflow-label">{value.name}</div>
</div>
</div>
@ -40,19 +40,4 @@
width: 2.25rem;
height: 2.25rem;
}
.user-info {
margin-left: .5rem;
color: var(--theme-content-accent-color);
.subtitle {
font-size: .75rem;
color: var(--theme-content-dark-color);
}
.title {
text-align: left;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
</style>

View File

@ -96,7 +96,7 @@
<div class="selectUser">
<div class="title"><Label label={title} /></div>
<div class:caption-color={selected} class:content-dark-color={!selected}>
<div class="overflow-label" class:caption-color={selected} class:content-dark-color={!selected}>
{#if selected}{getName(selected)}{:else}<Label label={presentation.string.NotSelected} />{/if}
</div>
</div>
@ -115,6 +115,7 @@
.selectUser {
margin-left: .75rem;
min-width: 0;
.title {
font-size: .75rem;
font-weight: 500;

View File

@ -25,26 +25,8 @@
<div class="flex-row-center" on:click>
<Avatar avatar={value.avatar} {size} />
<div class="flex-col user-info">
{#if subtitle}<div class="subtitle">{subtitle}</div>{/if}
<div class="title">{formatName(value.name)}</div>
<div class="flex-col ml-2 min-w-0">
{#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if}
<div class="content-accent-color overflow-label text-left">{formatName(value.name)}</div>
</div>
</div>
<style lang="scss">
.user-info {
margin-left: .5rem;
color: var(--theme-content-accent-color);
.subtitle {
font-size: .75rem;
color: var(--theme-content-dark-color);
}
.title {
text-align: left;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
</style>

View File

@ -53,9 +53,7 @@
<div class="ap-box">
{#each objects as person}
<button class="ap-menuItem" on:click={() => { dispatch('close', person) }}>
<div class='flex-grow'>
<UserInfo size={'medium'} value={person} />
</div>
<UserInfo size={'medium'} value={person} />
{#if allowDeselect && person._id === selected}
<ActionIcon direction={'top'} label={titleDeselect ?? presentation.string.Deselect} icon={IconBlueCheck} action={() => { dispatch('close', null) }} size={'small'}/>
{/if}

View File

@ -80,6 +80,7 @@
--theme-zone-border: rgba(255, 255, 255, .2);
--theme-zone-border-lite: rgba(255, 255, 255, .16);
--theme-bg-accent-normal: #1f1f25;
--theme-bg-accent-color: rgba(255, 255, 255, .03);
--theme-bg-accent-hover: rgba(255, 255, 255, .06);
--theme-bg-accent-press: rgba(255, 255, 255, .07);

View File

@ -123,6 +123,7 @@ p:last-child { margin-block-end: 0; }
display: flex;
align-items: center;
flex-wrap: nowrap;
min-width: 0;
}
.flex-row-streach {
display: flex;
@ -163,14 +164,24 @@ p:last-child { margin-block-end: 0; }
cursor: pointer;
.icon {
margin-right: .25rem;
margin-right: .5rem;
color: var(--theme-content-dark-color);
}
.label {
min-width: 0;
font-weight: 500;
text-align: left;
color: var(--theme-content-accent-color);
}
overflow: hidden;
visibility: visible;
display: -webkit-box;
/* autoprefixer: ignore next */
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
user-select: none;
}
&:hover .icon { color: var(--theme-caption-color); }
&:hover .label {
text-decoration: underline;
@ -260,6 +271,7 @@ p:last-child { margin-block-end: 0; }
.pr-1 { padding-right: .25rem; }
.pr-4 { padding-right: 1rem; }
.pr-24 { padding-right: 6rem; }
.p-10 { padding: 2.5rem; }
@ -375,6 +387,7 @@ a.no-line {
}
.fs-bold { font-weight: 500; }
.uppercase { text-transform: uppercase; }
.text-left { text-align: left; }
.over-underline {
cursor: pointer;
@ -454,6 +467,7 @@ a.no-line {
.background-card-divider { background-color: var(--theme-card-divider); }
.background-primary-color { background-color: var(--primary-button-enabled); }
.background-bg-accent { background-color: var(--theme-bg-accent-color); }
.background-bg-accent-normal { background-color: var(--theme-bg-accent-normal); }
.content-color { color: var(--theme-content-color); }
.content-trans-color { color: var(--theme-content-trans-color); }

View File

@ -37,32 +37,57 @@
gap: .75rem;
align-items: center;
}
&.mirror {
justify-content: space-between;
padding: 0 2.5rem;
&-tool {
justify-content: space-between;
padding: 0 6.5rem 0 2.5rem;
}
}
&.divide { border-bottom: 1px solid var(--theme-menu-divider); }
.ac-header__wrap-description {
.ac-header__wrap-description,
.ac-header__wrap-title {
display: flex;
flex-wrap: nowrap;
min-width: 0;
cursor: default;
}
.ac-header__wrap-description {
flex-direction: column;
flex-grow: 1;
}
.ac-header__wrap-title {
display: flex;
align-items: center;
flex-wrap: nowrap;
}
.ac-header__wrap-title { align-items: center; }
.ac-header__icon {
margin-right: .5rem;
color: var(--theme-content-color);
}
.ac-header__title {
min-width: 0;
font-weight: 500;
font-size: 1rem;
color: var(--theme-caption-color);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
}
.ac-header__description {
min-width: 0;
font-size: .75rem;
color: var(--theme-content-dark-color);
overflow: hidden;
visibility: visible;
display: -webkit-box;
/* autoprefixer: ignore next */
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
user-select: none;
}
@ -87,6 +112,31 @@
}
}
.ac-subtitle {
display: flex;
align-items: center;
overflow-x: auto;
flex-shrink: 0;
min-height: 0;
height: 3.5rem;
border-bottom: 1px solid var(--theme-zone-bg);
&::-webkit-scrollbar:horizontal { height: .25rem; }
&::-webkit-scrollbar-track { margin: 0; }
&::-webkit-scrollbar-thumb {
background-color: var(--theme-menu-divider);
border-radius: .25rem;
&:hover { background-color: var(--theme-card-divider); }
}
.ac-subtitle-content {
flex-grow: 1;
display: flex;
align-items: center;
margin: 0 2.5rem;
}
}
.ac-body {
display: flex;
flex-direction: column;

View File

@ -0,0 +1,70 @@
//
// Copyright © 2021 Anticrm Platform Contributors.
//
// 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.
//
/* Dialogs */
.antiDialogs {
overflow: hidden;
position: fixed;
top: 32px;
bottom: 1.25rem;
left: 50%;
right: 1rem;
height: calc(100% - 32px - 1.25rem);
background: var(--theme-bg-color);
border-radius: 1.25rem;
&.fullSize {
flex-direction: row;
left: 1rem;
}
.ac-header.divide { border-bottom: 1px solid var(--theme-card-divider); }
.ad-section-50 {
display: flex;
flex-direction: column;
flex-basis: 50%;
min-height: 0;
width: 50%;
&.divide { border-right: 1px solid var(--theme-card-divider); }
}
.ad-tools {
position: absolute;
display: flex;
top: 1.375rem;
right: 2rem;
}
.tool {
margin-left: 1rem;
color: var(--theme-content-accent-color);
cursor: pointer;
&:hover { color: var(--theme-caption-color); }
}
}
/* Overlays */
.antiOverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: .5;
}

View File

@ -17,6 +17,7 @@
@import "./_layouts.scss";
@import "./common.scss";
@import "./components.scss";
@import "./dialogs.scss";
@import "./popups.scss";
@import "./mixins.scss";

View File

@ -18,6 +18,7 @@
display: flex;
flex-direction: column;
min-height: 0;
max-width: 30rem;
background-color: var(--theme-button-bg-focused);
border: 1px solid var(--theme-button-border-enabled);
border-radius: .75rem;

View File

@ -28,6 +28,7 @@
<div class="flex-row-center">
<button
bind:this={container}
class="focused-button btn"
class:selected={show}
on:click|preventDefault={() => {

View File

@ -106,6 +106,7 @@
.popup {
display: flex;
flex-direction: column;
padding: 1rem;
min-height: 0;
color: var(--theme-caption-color);
background-color: var(--theme-button-bg-focused);

View File

@ -16,10 +16,52 @@
<script lang="ts">
import { afterUpdate, onDestroy, onMount } from 'svelte'
let mask: string = 'bottom'
export let padding: boolean = false
export let isBack: boolean = false
let mask: 'top' | 'bottom' | 'both' | 'none' = 'bottom'
let divScroll: HTMLElement
let divBox: HTMLElement
let divBack: HTMLElement
let divEl: HTMLElement
const checkBack = (): void => {
const rectScroll = divScroll.getBoundingClientRect()
const el = divBox.querySelector('.scroller-back')
if (el && divScroll) {
const rectEl = el.getBoundingClientRect()
const bottom = document.body.clientHeight - rectScroll.bottom
let top = rectEl.top
if (top < rectScroll.top) top = rectScroll.top
if (top > rectScroll.bottom) top = rectScroll.top + rectScroll.height
divBack.style.left = rectScroll.left + 'px'
divBack.style.right = document.body.clientWidth - rectScroll.right + 'px'
divBack.style.top = top + 'px'
divBack.style.bottom = bottom + 'px'
divBack.style.height = 'auto'
divBack.style.width = 'auto'
divBack.style.visibility = 'visible'
} else divBack.style.visibility = 'hidden'
}
let observer = new IntersectionObserver(changes => {
for (const change of changes) {
if (divBack) {
let rect = change.intersectionRect
if (rect) {
divBack.style.left = rect.left + 'px'
divBack.style.right = document.body.clientWidth - rect.right + 'px'
divBack.style.top = rect.top + 'px'
divBack.style.bottom = document.body.clientHeight - rect.bottom + 'px'
if (change.target) {
const temp: HTMLElement = change.target as HTMLElement
divBack.style.backgroundColor = temp.style.backgroundColor
}
} else divBack.style.visibility = 'hidden'
}
}
}, { root: null, threshold: .1 })
const checkFade = (): void => {
const t = divScroll.scrollTop
@ -28,17 +70,39 @@
else if (t > 0) mask = 'bottom'
else if (b > 0) mask = 'top'
else mask = 'none'
if (isBack) checkBack()
}
onMount(() => { if (divScroll && divBox) divScroll.addEventListener('scroll', checkFade) })
onMount(() => {
if (divScroll && divBox) {
divScroll.addEventListener('scroll', checkFade)
const tempEl = divBox.querySelector('*') as HTMLElement
observer.observe(tempEl)
if (divBox.querySelector('.scroller-back')) {
divEl = divBox.querySelector('.scroller-back') as HTMLElement
observer.observe(divEl)
}
}
if (divBack) checkBack()
})
onDestroy(() => { if (divScroll) divScroll.removeEventListener('scroll', checkFade) })
afterUpdate(() => { if (divScroll) checkFade() })
</script>
<div bind:this={divScroll} class="scroll relative antiNav-{mask}Fade">
<div bind:this={divBox} class="box">
<svelte:window on:resize={checkFade} />
<div
bind:this={divScroll}
class="scroll relative"
class:antiNav-topFade={mask === 'top'}
class:antiNav-bottomFade={mask === 'bottom'}
class:antiNav-bothFade={mask === 'both'}
class:antiNav-noneFade={mask === 'none'}
>
<div bind:this={divBox} class="box" class:p-10={padding}>
<slot />
</div>
</div>
<div bind:this={divBack} class="back" />
<style lang="scss">
.scroll {
@ -60,4 +124,14 @@
flex-direction: column;
height: 100%;
}
.back {
visibility: hidden;
position: fixed;
// left: 0;
// right: 0;
width: 0;
height: 0;
background-color: var(--theme-bg-accent-color);
z-index: -1;
}
</style>

View File

@ -18,7 +18,7 @@
import { CommentInput } from '@anticrm/chunter-resources'
import { Doc, SortingOrder } from '@anticrm/core'
import { createQuery, getClient } from '@anticrm/presentation'
import { Grid, IconActivity, ScrollBox } from '@anticrm/ui'
import { Grid, IconActivity, Scroller } from '@anticrm/ui'
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
import TxView from './TxView.svelte'
@ -50,37 +50,43 @@
</script>
{#if fullSize || transparent}
{#if transparent !== undefined && !transparent}
<div class="flex-row-center header">
<div class="flex-center icon"><IconActivity size={'small'} /></div>
<div class="fs-title">Activity</div>
{#if transparent !== undefined && !transparent}
<div class="ac-header short mirror-tool divide">
<div class="ac-header__wrap-title">
<div class="ac-header__icon flex-center icon"><IconActivity size={'small'} /></div>
<span class="ac-header__title">Activity</span>
</div>
</div>
{/if}
<div class="h-full right-content" class:transparent>
<ScrollBox vertical stretch>
{#if txes}
<Grid column={1} rowGap={1.5}>
{#each txes as tx (tx.tx._id)}
<TxView {tx} {viewlets} />
{/each}
</Grid>
{/if}
</ScrollBox>
</div>
<div class="ref-input" class:transparent>
<CommentInput bind:object/>
<div class="flex-col h-full min-h-0" class:background-bg-accent={!transparent}>
<Scroller>
<div class="p-10">
{#if txes}
<Grid column={1} rowGap={1.5}>
{#each txes as tx (tx.tx._id)}
<TxView {tx} {viewlets} />
{/each}
</Grid>
{/if}
</div>
</Scroller>
<div class="ref-input">
<CommentInput bind:object/>
</div>
</div>
{:else}
<div class="unionSection">
<ScrollBox vertical stretch noShift>
<div class="flex-col content">
<slot />
<Scroller isBack>
<div class="p-10">
<slot />
</div>
<div class="scroller-back">
<div class="ac-header short mirror-tool">
<div class="ac-header__wrap-title">
<div class="ac-header__icon flex-center icon"><IconActivity size={'small'} /></div>
<span class="ac-header__title">Activity</span>
</div>
</div>
<div class="flex-row-center activity header">
<div class="flex-center icon"><IconActivity size={'small'} /></div>
<div class="fs-title">Activity</div>
</div>
<div class="flex-col activity content">
<div class="p-activity">
{#if txes}
<Grid column={1} rowGap={1.5}>
{#each txes as tx}
@ -89,77 +95,30 @@
</Grid>
{/if}
</div>
</ScrollBox>
<div class="ref-input">
<CommentInput bind:object/>
</div>
</Scroller>
<div class="ref-input fill">
<CommentInput bind:object/>
</div>
{/if}
<style lang="scss">
.header {
flex-shrink: 0;
padding: 0 2.5rem;
height: 4rem;
border-bottom: 1px solid var(--theme-zone-bg);
.icon {
margin-right: 1rem;
width: 2.25rem;
height: 2.25rem;
color: var(--primary-button-color);
background-color: var(--primary-button-enabled);
border-radius: 50%;
}
.icon {
margin-right: 1rem;
width: 2.25rem;
height: 2.25rem;
color: var(--primary-button-color);
background-color: var(--primary-button-enabled);
border-radius: 50%;
}
.activity {
background-color: var(--theme-bg-accent-color);
&.header {
border-bottom: none;
}
&.content {
flex-grow: 1;
padding-bottom: 0;
background-color: var(--theme-bg-accent-color);
}
}
.ref-input {
background-color: var(--theme-bg-accent-color);
flex-shrink: 0;
padding: 1.5rem 2.5rem;
&.transparent {
padding: 1.5rem 0 0;
background-color: transparent;
}
&.fill { background-color: var(--theme-bg-accent-normal); }
}
.p-activity { padding: 1.5rem 2.5rem 2.5rem; }
.scroller-back { background-color: var(--theme-bg-accent-normal); }
.right-content {
flex-grow: 1;
padding: 1.5rem 2.5rem 0;
background-color: var(--theme-dialog-accent);
&.transparent {
min-height: 0;
height: 100%;
max-height: 100%;
padding: 0;
background-color: transparent;
}
}
.unionSection {
flex-grow: 1;
display: flex;
flex-direction: column;
height: max-content;
.content {
flex-shrink: 0;
display: flex;
flex-direction: column;
padding: 3rem 2.5rem;
height: max-content;
}
}
:global(.grid .msgactivity-container:last-child::after) { content: none; } // Remove the line in the last Activity message
</style>

View File

@ -292,6 +292,7 @@
}
.time {
align-self: baseline;
margin-left: 1rem;
color: var(--theme-content-trans-color);
}

View File

@ -42,9 +42,9 @@
<div class="label">CANDIDATE</div>
<Avatar avatar={candidate.avatar} size={'large'} />
{#if candidate}
<div class="name">{formatName(candidate.name)}</div>
<div class="description">{candidate.title ?? ''}</div>
<div class="description">{candidate.city ?? ''}</div>
<div class="name lines-limit-2">{formatName(candidate.name)}</div>
<div class="description lines-limit-2">{candidate.title ?? ''}</div>
<div class="description overflow-label">{candidate.city ?? ''}</div>
<div class="footer"><ChannelsView value={channels} size={'small'} on:click /></div>
{/if}
</div>

View File

@ -43,7 +43,7 @@
<div class="ac-header full">
<div class="ac-header__wrap-title">
<div class="ac-header__icon"><Icon icon={contact.icon.Person} size={'small'} /></div>
<span class="ac-title"><Label label={recruit.string.Candidates} /></span>
<span class="ac-header__title"><Label label={recruit.string.Candidates} /></span>
</div>
<SearchEdit bind:value={search} on:change={() => {

View File

@ -22,7 +22,7 @@
import { AttributesBar, createQuery, getClient } from '@anticrm/presentation'
import { Vacancy } from '@anticrm/recruit'
import { StyledTextBox } from '@anticrm/text-editor'
import { Component, EditBox, Grid, Icon, IconClose, Label, ToggleWithLabel } from '@anticrm/ui'
import { Component, EditBox, Grid, Icon, IconClose, Label, ToggleWithLabel, ActionIcon, Scroller } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import recruit from '../plugin'
@ -51,28 +51,25 @@
function onChange (key:string, value: any): void {
client.updateDoc(object._class, object.space, object._id, { [key]: value })
}
</script>
<div class="overlay" on:click={() => { dispatch('close') }}/>
<div class="dialog-container">
<div class="antiOverlay" on:click={() => { dispatch('close') }}/>
<div class="antiDialogs antiComponent">
{#if object}
<div class="flex-row-center header">
<div class="flex-grow">
<div class="flex">
<div class="svg-medium flex-no-shrink">
{#if clazz.icon}<Icon icon={clazz.icon} size={'medium'} />{/if}
</div>
<div class="flex-grow fs-title ml-2">
{object.name}
</div>
<div class="ac-header short mirror divide">
<div class="ac-header__wrap-description">
<div class="ac-header__wrap-title">
<div class="ac-header__icon">{#if clazz.icon}<Icon icon={clazz.icon} size={'medium'} />{/if}</div>
<div class="ac-header__title">{object.name}</div>
</div>
<div class="text-sm">{object.description}</div>
<div class="ac-header__description">{object.description}</div>
</div>
<div class="tool" on:click={() => { dispatch('close') }}><IconClose size={'small'} /></div>
<div class="tool"><ActionIcon icon={IconClose} size={'small'} action={() => { dispatch('close') }} /></div>
</div>
<div class="flex-row-center subtitle">
<AttributesBar {object} keys={['dueTo', 'location', 'company']} />
<div class="ac-subtitle">
<div class="ac-subtitle-content">
<AttributesBar {object} keys={['dueTo', 'location', 'company']} />
</div>
</div>
<div class="flex-stretch tab-container">
{#each tabs as tab, i}
@ -83,76 +80,40 @@
{/each}
<div class="grow"/>
</div>
<div class="scroll">
<div class="flex-col box">
{#if selected === 0}
<Grid column={1} rowGap={1.5}>
<EditBox label={recruit.string.VacancyName} bind:value={object.name} placeholder={recruit.string.VacancyPlaceholder} maxWidth="39rem" focus on:change={() => {
if (object.name.trim().length > 0) {
onChange('name', object.name)
} else {
// Revert previos object.name
updateObject(_id)
}
}}/>
<EditBox label={recruit.string.Description} bind:value={object.description} placeholder={recruit.string.VacancyDescription} maxWidth="39rem" focus on:change={() => { onChange('description', object.description) }}/>
</Grid>
<div class="mt-10">
<span class="title">Details</span>
<div class="description-container">
<StyledTextBox bind:content={object.fullDescription} on:value={(evt) => { onChange('fullDescription', evt.detail) }} />
</div>
{#if selected === 0}
<Scroller padding>
<Grid column={1} rowGap={1.5}>
<EditBox label={recruit.string.VacancyName} bind:value={object.name} placeholder={recruit.string.VacancyPlaceholder} maxWidth="39rem" focus on:change={() => {
if (object.name.trim().length > 0) {
onChange('name', object.name)
} else {
// Revert previos object.name
updateObject(_id)
}
}}/>
<EditBox label={recruit.string.Description} bind:value={object.description} placeholder={recruit.string.VacancyDescription} maxWidth="39rem" focus on:change={() => { onChange('description', object.description) }}/>
</Grid>
<div class="mt-10">
<span class="title">Details</span>
<div class="description-container">
<StyledTextBox bind:content={object.fullDescription} on:value={(evt) => { onChange('fullDescription', evt.detail) }} />
</div>
<div class="mt-14">
<Attachments objectId={object._id} _class={object._class} space={object.space} />
</div>
{:else if selected === 1}
<ToggleWithLabel label={recruit.string.ThisVacancyIsPrivate} description={recruit.string.MakePrivateDescription}/>
{:else if selected === 2}
<Component is={activity.component.Activity} props={{ object, transparent: true }} />
{/if}
</div>
</div>
</div>
<div class="mt-14">
<Attachments objectId={object._id} _class={object._class} space={object.space} />
</div>
</Scroller>
{:else if selected === 1}
<Scroller padding>
<ToggleWithLabel label={recruit.string.ThisVacancyIsPrivate} description={recruit.string.MakePrivateDescription}/>
</Scroller>
{:else if selected === 2}
<Component is={activity.component.Activity} props={{object, transparent: true}} />
{/if}
{/if}
</div>
<style lang="scss">
.dialog-container {
overflow: hidden;
position: fixed;
top: 32px;
bottom: 1.25rem;
left: 50%;
right: 1rem;
display: flex;
flex-direction: column;
height: calc(100% - 32px - 1.25rem);
background: var(--theme-bg-color);
border-radius: 1.25rem;
.header {
flex-shrink: 0;
padding: 0 2rem 0 2.5rem;
height: 4.5rem;
border-bottom: 1px solid var(--theme-dialog-divider);
.tool {
margin-left: .75rem;
color: var(--theme-content-accent-color);
cursor: pointer;
&:hover { color: var(--theme-caption-color); }
}
}
.subtitle {
flex-shrink: 0;
padding: 0 2.5rem;
height: 3.5rem;
border-bottom: 1px solid var(--theme-dialog-divider);
}
}
.tab-container {
flex-shrink: 0;
flex-wrap: nowrap;
@ -182,49 +143,4 @@
flex-grow: 1;
}
}
.scroll {
flex-grow: 1;
overflow-x: hidden;
overflow-y: auto;
margin: 1rem 2rem;
padding: 1.5rem .5rem;
height: 100%;
.box {
margin-right: 1px;
height: 100%;
}
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: .5;
}
.title {
margin-right: .75rem;
font-weight: 500;
font-size: 1.25rem;
color: var(--theme-caption-color);
}
.description-container {
display: flex;
justify-content: space-between;
overflow-y: auto;
height: 15rem;
padding: 0px 16px;
background-color: var(--theme-bg-accent-color);
border: 1px solid var(--theme-bg-accent-color);
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-radius: .75rem;
margin-top: 1.5rem;
}
</style>

View File

@ -26,8 +26,8 @@
<Company size={'large'} />
</div>
{#if vacancy}
<div class="name">{vacancy.name}</div>
<div class="description">{vacancy.description ?? ''}</div>
<div class="name lines-limit-2">{vacancy.name}</div>
<div class="description lines-limit-2">{vacancy.description ?? ''}</div>
{/if}
</div>

View File

@ -56,6 +56,7 @@
<style lang="scss">
.color {
flex-shrink: 0;
margin-right: .75rem;
width: 1rem;
height: 1rem;

View File

@ -33,24 +33,3 @@
</div>
<div class="ap-space" />
</div>
<!-- <style lang="scss">
.popup {
padding: .5rem;
min-width: 12rem;
background-color: var(--theme-button-bg-focused);
border: 1px solid var(--theme-button-border-enabled);
border-radius: .75rem;
box-shadow: 0 .75rem 1.25rem rgba(0, 0, 0, .2);
}
.menu-item {
display: flex;
align-items: center;
padding: .5rem;
border-radius: .5rem;
cursor: pointer;
&:hover { background-color: var(--theme-button-bg-hovered); }
}
</style> -->

View File

@ -69,7 +69,7 @@
bind:value={name}
icon={task.icon.Task}
placeholder={plugin.string.TodoDescriptionPlaceholder}
maxWidth="39rem"
maxWidth={'16rem'}
focus
/>
<DatePicker title={plugin.string.TodoDueDate} bind:selected={dueTo} />

View File

@ -67,14 +67,15 @@
on:close={() => {
dispatch('close')
}}
okLabel={plugin.string.TodoSave}>
<Grid column={1} rowGap={1.75}>
<EditBox
okLabel={plugin.string.TodoSave}
>
<Grid column={1} rowGap={1.75}>
<EditBox
label={plugin.string.TodoDescription}
bind:value={name}
icon={task.icon.Task}
placeholder={plugin.string.TodoDescriptionPlaceholder}
maxWidth="39rem"
maxWidth={'16rem'}
focus
/>
<DatePicker title={plugin.string.TodoDueDate} bind:selected={dueTo} />