mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-23 11:31:57 +03:00
Optimize components, dialogs. Fix issues. Update Scroller. (#945)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
11abc2f38c
commit
bff122ee8c
@ -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>
|
||||
|
@ -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>
|
||||
</style>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
@ -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}
|
||||
|
@ -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);
|
||||
|
@ -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); }
|
||||
|
@ -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 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.ac-header__wrap-description,
|
||||
.ac-header__wrap-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
min-width: 0;
|
||||
cursor: default;
|
||||
}
|
||||
.ac-header__wrap-description {
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
||||
@ -84,7 +109,32 @@
|
||||
cursor: default;
|
||||
&:hover { color: var(--theme-caption-color); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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 {
|
||||
@ -108,7 +158,7 @@
|
||||
max-width: 25rem;
|
||||
height: 100%;
|
||||
border-right: 1px solid var(--theme-menu-divider);
|
||||
|
||||
|
||||
&.max {
|
||||
flex-grow: 1;
|
||||
min-width: 25rem;
|
||||
@ -149,4 +199,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.ac-column__list-item + .ac-column__list-item { margin-top: .75rem; }
|
||||
.ac-column__list-item + .ac-column__list-item { margin-top: .75rem; }
|
||||
|
70
packages/theme/styles/dialogs.scss
Normal file
70
packages/theme/styles/dialogs.scss
Normal 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;
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
@import "./_layouts.scss";
|
||||
@import "./common.scss";
|
||||
@import "./components.scss";
|
||||
@import "./dialogs.scss";
|
||||
@import "./popups.scss";
|
||||
@import "./mixins.scss";
|
||||
|
||||
|
@ -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;
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
<div class="flex-row-center">
|
||||
<button
|
||||
bind:this={container}
|
||||
class="focused-button btn"
|
||||
class:selected={show}
|
||||
on:click|preventDefault={() => {
|
||||
|
@ -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);
|
||||
|
@ -16,11 +16,53 @@
|
||||
<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
|
||||
const b = divScroll.scrollHeight - divScroll.clientHeight - t
|
||||
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
&.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); }
|
||||
|
||||
:global(.grid .msgactivity-container:last-child::after) { content: none; } // Remove the line in the last Activity message
|
||||
</style>
|
||||
|
@ -292,6 +292,7 @@
|
||||
}
|
||||
|
||||
.time {
|
||||
align-self: baseline;
|
||||
margin-left: 1rem;
|
||||
color: var(--theme-content-trans-color);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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={() => {
|
||||
|
@ -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>
|
||||
</style>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
|
||||
<style lang="scss">
|
||||
.color {
|
||||
flex-shrink: 0;
|
||||
margin-right: .75rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
@ -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> -->
|
||||
|
@ -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} />
|
||||
|
@ -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} />
|
||||
|
Loading…
Reference in New Issue
Block a user