Update Panel, Telegram, Scroller layouts. (#1621)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2022-05-03 19:04:21 +03:00 committed by GitHub
parent 797e72332e
commit 864095e324
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 257 additions and 407 deletions

View File

@ -19,18 +19,19 @@
import type { Doc } from '@anticrm/core' import type { Doc } from '@anticrm/core'
import notification from '@anticrm/notification' import notification from '@anticrm/notification'
import type { Asset } from '@anticrm/platform' import type { Asset } from '@anticrm/platform'
import { AnyComponent, AnySvelteComponent, Component, Panel, Icon } from '@anticrm/ui' import { AnySvelteComponent, Component, Panel, Icon, Scroller } from '@anticrm/ui'
export let title: string | undefined = undefined export let title: string | undefined = undefined
export let subtitle: string | undefined = undefined export let subtitle: string | undefined = undefined
export let icon: Asset | AnySvelteComponent | undefined = undefined export let icon: Asset | AnySvelteComponent | undefined = undefined
export let rightSection: AnyComponent | undefined = undefined export let withoutActivity: boolean = false
export let object: Doc export let object: Doc
export let panelWidth: number = 0 export let panelWidth: number = 0
export let innerWidth: number = 0 export let innerWidth: number = 0
export let isHeader: boolean = true export let isHeader: boolean = true
export let isSub: boolean = true export let isSub: boolean = true
export let isAside: boolean = true export let isAside: boolean = true
export let isCustomAttr: boolean = true
export let minimize: boolean = false export let minimize: boolean = false
let docWidth: number = 0 let docWidth: number = 0
@ -39,14 +40,7 @@
</script> </script>
<svelte:window bind:innerWidth={docWidth} /> <svelte:window bind:innerWidth={docWidth} />
<Panel <Panel bind:isAside isHeader={needHeader} bind:panelWidth bind:innerWidth on:close>
rightSection={rightSection !== undefined}
bind:isAside
isHeader={needHeader}
bind:panelWidth
bind:innerWidth
on:close
>
<svelte:fragment slot="title"> <svelte:fragment slot="title">
<div class="popupPanel-title__content-container antiTitle"> <div class="popupPanel-title__content-container antiTitle">
{#if $$slots.navigator} {#if $$slots.navigator}
@ -90,7 +84,7 @@
</div> </div>
</div> </div>
{/if} {/if}
{#if $$slots['custom-attributes']} {#if $$slots['custom-attributes'] && isCustomAttr}
{#if isSub}<div class="header-row"><slot name="custom-attributes" direction="row" /></div>{/if} {#if isSub}<div class="header-row"><slot name="custom-attributes" direction="row" /></div>{/if}
{:else if $$slots.attributes && minimize}<div class="header-row"> {:else if $$slots.attributes && minimize}<div class="header-row">
<slot name="attributes" direction="row" /> <slot name="attributes" direction="row" />
@ -107,18 +101,22 @@
</div> </div>
</div> </div>
{/if} {/if}
{#if $$slots['custom-attributes']} {#if $$slots['custom-attributes'] && isCustomAttr}
<slot name="custom-attributes" direction="column" /> <slot name="custom-attributes" direction="column" />
{:else if $$slots.attributes}<slot name="attributes" direction="column" />{/if} {:else if $$slots.attributes}<slot name="attributes" direction="column" />{/if}
{#if $$slots.aside}<slot name="aside" />{/if} {#if $$slots.aside}<slot name="aside" />{/if}
</div> </div>
</svelte:fragment> </svelte:fragment>
{#if rightSection !== undefined} {#if withoutActivity}
<slot /> <slot />
{:else} {:else}
<Scroller>
<div class="popupPanel-body__main-content py-10 clear-mins">
<Component is={activity.component.Activity} props={{ object, integrate: true }}> <Component is={activity.component.Activity} props={{ object, integrate: true }}>
<slot /> <slot />
</Component> </Component>
</div>
</Scroller>
{/if} {/if}
</Panel> </Panel>

View File

@ -370,9 +370,11 @@ p:last-child { margin-block-end: 0; }
.pb-2 { padding-bottom: .5rem; } .pb-2 { padding-bottom: .5rem; }
.pb-3 { padding-bottom: .75rem; } .pb-3 { padding-bottom: .75rem; }
.pb-4 { padding-bottom: 1rem; } .pb-4 { padding-bottom: 1rem; }
.pb-6 { padding-bottom: 1.5rem; }
.px-2 { padding: 0 .5rem; } .px-2 { padding: 0 .5rem; }
.px-3 { padding: 0 .75rem; } .px-3 { padding: 0 .75rem; }
.px-4 { padding: 0 1rem; } .px-4 { padding: 0 1rem; }
.py-10 { padding: 2.5rem 0; }
.p-1 { padding: .25rem; } .p-1 { padding: .25rem; }
.p-2 { padding: .5rem; } .p-2 { padding: .5rem; }

View File

@ -202,6 +202,10 @@
.antiNav-bottomFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1px, rgba(0, 0, 0, 1) calc(100% - 2rem), rgba(0, 0, 0, 0) 100%); } .antiNav-bottomFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1px, rgba(0, 0, 0, 1) calc(100% - 2rem), rgba(0, 0, 0, 0) 100%); }
.antiNav-bothFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 2rem, rgba(0, 0, 0, 1) calc(100% - 2rem), rgba(0, 0, 0, 0) 100%); } .antiNav-bothFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 2rem, rgba(0, 0, 0, 1) calc(100% - 2rem), rgba(0, 0, 0, 0) 100%); }
.antiNav-noneFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1px, rgba(0, 0, 0, 1) calc(100% - 1px), rgba(0, 0, 0, 0) 100%); } .antiNav-noneFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1px, rgba(0, 0, 0, 1) calc(100% - 1px), rgba(0, 0, 0, 0) 100%); }
.tableFade.antiNav-topFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 2rem, rgba(0, 0, 0, 1) calc(100% - 1px), rgba(0, 0, 0, 0) 100%); }
.tableFade.antiNav-bottomFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1px, rgba(0, 0, 0, 1) calc(100% - 4.5rem - 1px), rgba(0, 0, 0, 0) calc(100% - 2.5rem), rgba(0, 0, 0, 1) calc(100% - 2.5rem + .5px)); }
.tableFade.antiNav-bothFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 2rem, rgba(0, 0, 0, 1) calc(100% - 4.5rem - 1px), rgba(0, 0, 0, 0) calc(100% - 2.5rem), rgba(0, 0, 0, 1) calc(100% - 2.5rem + .5px)); }
.tableFade.antiNav-noneFade { mask-image: linear-gradient(0deg, rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 1) 1px, rgba(0, 0, 0, 1) calc(100% - 1px), rgba(0, 0, 0, 0) 100%); }
/* Basic */ /* Basic */
.antiTitle { .antiTitle {

View File

@ -324,6 +324,7 @@
/* Table */ /* Table */
.antiTable { .antiTable {
position: relative;
width: 100%; width: 100%;
th, td { th, td {
@ -415,6 +416,13 @@
&.checking { background-color: var(--highlight-select); } // --theme-table-bg-hover &.checking { background-color: var(--highlight-select); } // --theme-table-bg-hover
&.selected { background-color: var(--highlight-hover); } // --menu-bg-select &.selected { background-color: var(--highlight-hover); } // --menu-bg-select
} }
.scroller-thead {
position: sticky;
top: 0;
z-index: 999;
background-color: var(--body-color);
}
} }
// Hide row menu in Tooltip // Hide row menu in Tooltip

View File

@ -127,8 +127,9 @@
width: calc(100% - 5rem); width: calc(100% - 5rem);
min-width: 0; min-width: 0;
max-width: 900px; max-width: 900px;
border-bottom: 1px solid var(--divider-color);
&.bottom-divider { border-bottom: 1px solid var(--divider-color); }
&.top-divider { border-top: 1px solid var(--divider-color); }
.header-row { .header-row {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -14,9 +14,8 @@
--> -->
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import { Button, IconClose, IconDetails, Scroller } from '..' import { Button, IconClose, IconDetails } from '..'
export let rightSection: boolean = false
export let innerWidth: number = 0 export let innerWidth: number = 0
export let panelWidth: number = 0 export let panelWidth: number = 0
export let isHeader: boolean = true export let isHeader: boolean = true
@ -65,16 +64,12 @@
<div class="popupPanel-body" class:asideShown> <div class="popupPanel-body" class:asideShown>
<div class="popupPanel-body__main" bind:clientWidth={innerWidth}> <div class="popupPanel-body__main" bind:clientWidth={innerWidth}>
{#if $$slots.header && isHeader} {#if $$slots.header && isHeader}
<div class="popupPanel-body__main-header"> <div class="popupPanel-body__main-header bottom-divider">
<slot name="header" /> <slot name="header" />
</div> </div>
{/if} {/if}
<Scroller>
<div class="popupPanel-body__main-content">
<slot /> <slot />
</div> </div>
</Scroller>
</div>
{#if $$slots.aside && isAside} {#if $$slots.aside && isAside}
<div class="popupPanel-body__aside" class:float={asideFloat} class:shown={asideShown}> <div class="popupPanel-body__aside" class:float={asideFloat} class:shown={asideShown}>
<slot name="aside" /> <slot name="aside" />

View File

@ -17,8 +17,9 @@
export let padding: boolean = false export let padding: boolean = false
export let autoscroll: boolean = false export let autoscroll: boolean = false
export let correctPadding: number = 0 // export let correctPadding: number = 0
export let bottomStart: boolean = false export let bottomStart: boolean = false
export let tableFade: boolean = false
let mask: 'top' | 'bottom' | 'both' | 'none' = 'bottom' let mask: 'top' | 'bottom' | 'both' | 'none' = 'bottom'
@ -27,17 +28,11 @@
let divBack: HTMLElement let divBack: HTMLElement
let divBar: HTMLElement let divBar: HTMLElement
let divTrack: HTMLElement let divTrack: HTMLElement
let divTHead: HTMLElement
let elTHead: Element
let isBack: boolean = false // ? let isBack: boolean = false // ?
let isTHead: boolean = false
let hasTHeads: boolean = false // ?
let isScrolling: boolean = false let isScrolling: boolean = false
let enabledChecking: boolean = false
let dY: number let dY: number
let visibleEl: number | undefined = undefined
let belowContent: number | undefined = undefined let belowContent: number | undefined = undefined
let scrolling: boolean = false let scrolling: boolean = autoscroll
let firstScroll: boolean = autoscroll let firstScroll: boolean = autoscroll
const checkBack = (): void => { const checkBack = (): void => {
@ -65,86 +60,6 @@
} }
} }
const checkTHeadSizes = (): void => {
if (elTHead && divTHead && divScroll) {
const elems = divTHead.querySelectorAll('div')
elems.forEach((el, i) => {
const th = elTHead.children.item(i)
if (th) el.style.width = th.clientWidth + 'px'
})
}
}
const clearTHead = (): void => {
visibleEl = undefined
divTHead.innerHTML = ''
divTHead.style.visibility = 'hidden'
divTHead.style.opacity = '0'
isTHead = false
}
const fillTHead = (el: Element): boolean => {
const tr: Element | null = el.children.item(0)
if (tr) {
for (let i = 0; i < tr.children.length; i++) {
const th = tr.children.item(i)
if (th) {
let newStyle = `flex-shrink: 0; width: ${th.clientWidth}px; `
if ((i === 0 && !enabledChecking) || (i === 1 && enabledChecking)) newStyle += 'padding-right: 1.5rem;'
else if (i === tr.children.length - 1) newStyle += 'padding-left: 1.5rem;'
else if (i === 0 && enabledChecking) newStyle += 'padding: 0 .75rem;'
else newStyle += 'padding: 0 1.5rem;'
if (th.classList.contains('sorted')) newStyle += ' margin-right: .25rem;'
divTHead.insertAdjacentHTML('beforeend', `<div style="${newStyle}">${tr.children.item(i)?.textContent}</div>`)
}
}
isTHead = true
elTHead = tr
}
return isTHead
}
const findTHeaders = (): void => {
if (divBox) {
const elements = divBox.querySelectorAll('.scroller-thead')
if (elements && elements.length > 0 && divScroll) {
const rectScroll = divScroll.getBoundingClientRect()
hasTHeads = true
elements.forEach((el, i) => {
const rect = el.getBoundingClientRect()
enabledChecking = el.parentElement?.classList.contains('enableChecking') ?? false
const rectTable = el.parentElement?.getBoundingClientRect()
if (rectTable) {
if (rectTable.top < rectScroll.top && rectTable.bottom > rectScroll.top + rect.height) {
if (!isTHead && divTHead) if (fillTHead(el)) visibleEl = i
if (isTHead) {
if (rect.width > rectScroll.width) divTHead.style.width = rectScroll.width - correctPadding + 'px'
else divTHead.style.width = rect.width + 'px'
divTHead.style.height = rect.height + 'px'
divTHead.style.left = rect.left + 'px'
if (rect.bottom - 16 < rectScroll.top && rectTable.bottom > rectScroll.top + rect.height) {
divTHead.style.top = rectScroll.top + 'px'
divTHead.style.visibility = 'visible'
divTHead.style.opacity = '.9'
} else {
divTHead.style.top = rect.top + 'px'
divTHead.style.visibility = 'hidden'
divTHead.style.opacity = '0'
}
}
} else if (
(rectTable.top > rectScroll.top + rect.height || rectTable.bottom < rectScroll.top + rect.height) &&
isTHead &&
visibleEl === i
) {
clearTHead()
}
}
})
} else hasTHeads = false
}
}
const checkBar = (): void => { const checkBar = (): void => {
if (divBar && divScroll) { if (divBar && divScroll) {
const proc = (divScroll.clientHeight / divScroll.scrollHeight) * 100 const proc = (divScroll.clientHeight / divScroll.scrollHeight) * 100
@ -195,7 +110,6 @@
const checkFade = (): void => { const checkFade = (): void => {
if (divScroll) { if (divScroll) {
scrolling = false
const t = divScroll.scrollTop const t = divScroll.scrollTop
const b = divScroll.scrollHeight - divScroll.clientHeight - t const b = divScroll.scrollHeight - divScroll.clientHeight - t
if (t > 0 && b > 0) mask = 'both' if (t > 0 && b > 0) mask = 'both'
@ -204,19 +118,19 @@
else mask = 'none' else mask = 'none'
} }
checkBack() checkBack()
findTHeaders()
if (isTHead) checkTHeadSizes()
if (!isScrolling) checkBar() if (!isScrolling) checkBar()
if (scrolling && belowContent && belowContent > 1) {
divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
}
} }
const observer = new IntersectionObserver(() => checkFade(), { root: null, threshold: 0.1 }) const observer = new IntersectionObserver(() => checkFade(), { root: null, threshold: 0.1 })
$: if (firstScroll && divScroll && divScroll.clientHeight !== divScroll.scrollHeight) { $: if (autoscroll && !scrolling && belowContent && belowContent < 1 && divScroll) {
divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
firstScroll = false scrolling = true
} }
$: if (autoscroll && belowContent && belowContent <= 50) scrolling = true $: if (scrolling && divScroll && divScroll.scrollHeight - divScroll.scrollTop - divScroll.clientHeight < 5) {
$: if (scrolling && belowContent && belowContent > 50) {
divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
} }
@ -237,19 +151,26 @@
const tempEl = divBox.querySelector('*') as HTMLElement const tempEl = divBox.querySelector('*') as HTMLElement
if (tempEl) observer.observe(tempEl) if (tempEl) observer.observe(tempEl)
if (scrolling) divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight if (scrolling) divScroll.scrollTop = divScroll.scrollHeight - divScroll.clientHeight
checkFade()
clearTHead()
findTHeaders()
belowContent = divScroll.scrollHeight - divScroll.clientHeight - divScroll.scrollTop belowContent = divScroll.scrollHeight - divScroll.clientHeight - divScroll.scrollTop
checkFade()
} }
}) })
let divWidth: number = 0 let divWidth: number = 0
const _resize = (): void => { const _resize = (): void => {
clearTHead()
checkFade() checkFade()
} }
$: if (divWidth) _resize() $: if (divWidth) _resize()
const _scroll = (ev: Event): void => {
if (ev.type === 'scroll') {
firstScroll ? (firstScroll = false) : (scrolling = false)
if (ev.target) {
const el: HTMLElement = ev.target as HTMLElement
if (el.scrollHeight - el.scrollTop - el.clientHeight < 5) scrolling = true
}
}
}
</script> </script>
<svelte:window on:resize={_resize} /> <svelte:window on:resize={_resize} />
@ -257,7 +178,9 @@
<div <div
bind:this={divScroll} bind:this={divScroll}
bind:clientWidth={divWidth} bind:clientWidth={divWidth}
on:scroll={_scroll}
class="scroll relative" class="scroll relative"
class:tableFade
class:antiNav-topFade={mask === 'top'} class:antiNav-topFade={mask === 'top'}
class:antiNav-bottomFade={mask === 'bottom'} class:antiNav-bottomFade={mask === 'bottom'}
class:antiNav-bothFade={mask === 'both'} class:antiNav-bothFade={mask === 'both'}
@ -270,7 +193,6 @@
<div bind:this={divBack} class="back" /> <div bind:this={divBack} class="back" />
<div class="bar" class:hovered={isScrolling} bind:this={divBar} on:mousedown={onScrollStart} /> <div class="bar" class:hovered={isScrolling} bind:this={divBar} on:mousedown={onScrollStart} />
<div class="track" class:hovered={isScrolling} bind:this={divTrack} /> <div class="track" class:hovered={isScrolling} bind:this={divTrack} />
<div bind:this={divTHead} class="fly-head thead-style" />
</div> </div>
<style lang="scss"> <style lang="scss">
@ -366,23 +288,4 @@
background-color: var(--body-color); background-color: var(--body-color);
z-index: -1; z-index: -1;
} }
.fly-head {
overflow: hidden;
position: fixed;
pointer-events: none;
visibility: hidden;
transition: top 0.2s ease-out, opacity 0.2s;
}
.thead-style {
display: flex;
align-items: center;
min-width: 0;
height: 2.5rem;
font-weight: 500;
font-size: 0.75rem;
color: var(--dark-color);
background-color: var(--board-bg-color);
box-shadow: inset 0 -1px 0 0 var(--theme-bg-focused-color);
user-select: none;
}
</style> </style>

View File

@ -20,6 +20,6 @@
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M12.7,7.5H3.9L7,4.4L6.3,3.6l-4,4L2,8l0.4,0.4l4,4L7,11.6L3.9,8.5h8.8c0.3,0,0.5-0.2,0.5-0.5S12.9,7.5,12.7,7.5z" d="M13.1,7.5H4.3l3.1-3.1L6.7,3.6l-4,4L2.4,8l0.4,0.4l4,4l0.6-0.8L4.3,8.5h8.8c0.3,0,0.5-0.2,0.5-0.5S13.3,7.5,13.1,7.5z"
/> />
</svg> </svg>

View File

@ -0,0 +1,25 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
export let size: 'small' | 'medium' | 'large'
const fill: string = 'currentColor'
</script>
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path
d="M2.4,8c0,0.3,0.2,0.5,0.5,0.5h8.8l-3.1,3.1l0.6,0.8l4-4L13.6,8l-0.3-0.4l-4-4L8.6,4.4l3.1,3.1l-8.8,0C2.7,7.5,2.4,7.7,2.4,8z"
/>
</svg>

View File

@ -114,6 +114,7 @@ export { default as IconInfo } from './components/icons/Info.svelte'
export { default as IconBlueCheck } from './components/icons/BlueCheck.svelte' export { default as IconBlueCheck } from './components/icons/BlueCheck.svelte'
export { default as IconCheck } from './components/icons/Check.svelte' export { default as IconCheck } from './components/icons/Check.svelte'
export { default as IconArrowLeft } from './components/icons/ArrowLeft.svelte' export { default as IconArrowLeft } from './components/icons/ArrowLeft.svelte'
export { default as IconArrowRight } from './components/icons/ArrowRight.svelte'
export { default as IconNavPrev } from './components/icons/NavPrev.svelte' export { default as IconNavPrev } from './components/icons/NavPrev.svelte'
export { default as IconNavNext } from './components/icons/NavNext.svelte' export { default as IconNavNext } from './components/icons/NavNext.svelte'
export { default as IconDPCalendar } from './components/calendar/icons/DPCalendar.svelte' export { default as IconDPCalendar } from './components/calendar/icons/DPCalendar.svelte'

View File

@ -8,7 +8,6 @@ export interface PanelProps {
_class: string _class: string
element?: PopupAlignment element?: PopupAlignment
rightSection?: AnyComponent rightSection?: AnyComponent
fullSize?: boolean
} }
export const panelstore = writable<{ panel?: PanelProps | undefined }>({ panel: undefined }) export const panelstore = writable<{ panel?: PanelProps | undefined }>({ panel: undefined })
@ -17,7 +16,13 @@ let currentLocation: string | undefined
location.subscribe((loc) => { location.subscribe((loc) => {
if (loc.fragment !== currentLocation && loc.fragment !== undefined && loc.fragment.trim().length > 0) { if (loc.fragment !== currentLocation && loc.fragment !== undefined && loc.fragment.trim().length > 0) {
const props = decodeURIComponent(loc.fragment).split('|') const props = decodeURIComponent(loc.fragment).split('|')
showPanel(props[0] as AnyComponent, props[1], props[2], (props[3] ?? undefined) as PopupAlignment) showPanel(
props[0] as AnyComponent,
props[1],
props[2],
(props[3] ?? undefined) as PopupAlignment,
(props[4] ?? undefined) as AnyComponent
)
} else if ( } else if (
(loc.fragment === undefined || (loc.fragment !== undefined && loc.fragment.trim().length === 0)) && (loc.fragment === undefined || (loc.fragment !== undefined && loc.fragment.trim().length === 0)) &&
currentLocation !== undefined currentLocation !== undefined
@ -47,7 +52,7 @@ export function showPanel (
element?: PopupAlignment, element?: PopupAlignment,
rightSection?: AnyComponent rightSection?: AnyComponent
): void { ): void {
const newLoc = getPanelURI(component, _id, _class, element) const newLoc = getPanelURI(component, _id, _class, element, rightSection)
if (currentLocation === newLoc) { if (currentLocation === newLoc) {
return return
} }

View File

@ -198,8 +198,8 @@ export function fitPopupElement (modalHTML: HTMLElement, element?: PopupAlignmen
} else if (element === 'float') { } else if (element === 'float') {
newProps.top = 'calc(var(--status-bar-height) + .25rem)' newProps.top = 'calc(var(--status-bar-height) + .25rem)'
newProps.bottom = '.25rem' newProps.bottom = '.25rem'
newProps.width = '40rem' newProps.width = '40%'
newProps.maxWidth = '40%' newProps.maxWidth = '60%'
newProps.right = '.25rem' newProps.right = '.25rem'
show = true show = true
} else if (element === 'account') { } else if (element === 'account') {

View File

@ -87,7 +87,7 @@
{/if} {/if}
</div> </div>
{:else} {:else}
<div class="mt-4 pb-4 bottom-highlight-select"> <div class="pb-6 bottom-highlight-select">
<slot /> <slot />
</div> </div>
<div class="flex-row-center h-14 px-3 mt-4 antiTitle"> <div class="flex-row-center h-14 px-3 mt-4 antiTitle">

View File

@ -16,7 +16,7 @@
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher, onMount } from 'svelte'
import type { IntlString } from '@anticrm/platform' import type { IntlString } from '@anticrm/platform'
import { translate } from '@anticrm/platform' import { translate } from '@anticrm/platform'
import { Button, Icon, IconClose, IconBlueCheck } from '@anticrm/ui' import { Button, Icon, IconClose, IconBlueCheck, IconArrowRight } from '@anticrm/ui'
export let value: string = '' export let value: string = ''
export let placeholder: IntlString export let placeholder: IntlString
@ -60,6 +60,7 @@
> >
<div class="icon"><Icon icon={IconClose} size={'inline'} /></div> <div class="icon"><Icon icon={IconClose} size={'inline'} /></div>
</div> </div>
<Button kind={'transparent'} size={'small'} icon={IconArrowRight} on:click={() => dispatch('update', 'open')} />
<Button kind={'transparent'} size={'small'} icon={IconBlueCheck} on:click={() => dispatch('close', value)} /> <Button kind={'transparent'} size={'small'} icon={IconBlueCheck} on:click={() => dispatch('close', value)} />
</div> </div>
</div> </div>

View File

@ -25,23 +25,19 @@
import { getChannelProviders } from '../utils' import { getChannelProviders } from '../utils'
import ChannelEditor from './ChannelEditor.svelte' import ChannelEditor from './ChannelEditor.svelte'
import { NotificationClientImpl } from '@anticrm/notification-resources' import { NotificationClientImpl } from '@anticrm/notification-resources'
import { onDestroy } from 'svelte'
export let value: AttachedData<Channel>[] | Channel | null export let value: AttachedData<Channel>[] | Channel | null
export let editable = false export let editable: boolean = false
export let kind: ButtonKind = 'no-border' export let kind: ButtonKind = 'no-border'
export let size: ButtonSize = 'small' export let size: ButtonSize = 'small'
export let length: 'short' | 'full' = 'full' export let length: 'short' | 'full' = 'full'
export let shape: 'circle' | undefined = undefined export let shape: 'circle' | undefined = undefined
// export let reverse: boolean = false
export let integrations: Set<Ref<Doc>> = new Set<Ref<Doc>>() export let integrations: Set<Ref<Doc>> = new Set<Ref<Doc>>()
const notificationClient = NotificationClientImpl.getClient() const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews() const lastViews = notificationClient.getLastViews()
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
let editMode = false
interface Item { interface Item {
label: IntlString label: IntlString
icon: Asset icon: Asset
@ -140,8 +136,8 @@
} }
$: if (providers) updateMenu() $: if (providers) updateMenu()
const dropItem = (n: number): void => { const dropItem = (n: number): Item[] => {
displayItems = displayItems.filter((it, i) => i !== n) return displayItems.filter((it, i) => i !== n)
} }
const saveItems = (): void => { const saveItems = (): void => {
value = filterUndefined(displayItems) value = filterUndefined(displayItems)
@ -156,15 +152,10 @@
ev.target as HTMLElement, ev.target as HTMLElement,
(result) => { (result) => {
if (result !== undefined) { if (result !== undefined) {
if (result == null || result === '') dropItem(n) if (result === null || result === '') displayItems = dropItem(n)
else displayItems[n].value = result else displayItems[n].value = result
} else if (displayItems[n].value === '') dropItem(n)
saveItems() saveItems()
if (actions.length > 0 && addBtn) { if (displayItems.length < providers.size && addBtn) addBtn.click()
if (result !== undefined) addBtn.click()
else disableEdit()
} else {
disableEdit()
} }
}, },
(result) => { (result) => {
@ -172,22 +163,26 @@
if (result === 'left') { if (result === 'left') {
closePopup() closePopup()
if (displayItems[n].value === '') { if (displayItems[n].value === '') {
dropItem(n) displayItems = dropItem(n)
saveItems() saveItems()
} }
if (n === 0) addBtn.click() if (n === 0) {
else btns[n - 1].click() if (addBtn) addBtn.click()
else btns[displayItems.length - 1].click()
} else btns[n - 1].click()
} else if (result === 'right') { } else if (result === 'right') {
closePopup() closePopup()
if (displayItems[n].value === '') { if (displayItems[n].value === '') {
dropItem(n) displayItems = dropItem(n)
saveItems() saveItems()
if (n === displayItems.length) addBtn.click()
else btns[n + 1].click()
} else {
if (n === displayItems.length - 1) addBtn.click()
else btns[n + 1].click()
} }
if (n === displayItems.length - 1) {
if (addBtn) addBtn.click()
else btns[0].click()
} else btns[n + 1].click()
} else if (result === 'open') {
closePopup()
dispatch('open', { presenter: channel.presenter })
} }
} }
} }
@ -198,11 +193,7 @@
Menu, Menu,
{ actions }, { actions },
ev.target as HTMLElement, ev.target as HTMLElement,
(result) => { () => {},
if (result === undefined) {
disableEdit()
}
},
(result) => { (result) => {
if (result !== undefined && displayItems.length > 0) { if (result !== undefined && displayItems.length > 0) {
if (result === 'left') { if (result === 'left') {
@ -217,31 +208,9 @@
) )
} }
let copied: boolean = false let copied: boolean = false
let div: HTMLDivElement
function listener (e: MouseEvent): void {
if (e.target !== null && !div.contains(e.target as Node)) {
disableEdit()
}
}
function enableEdit () {
window.addEventListener('click', listener)
editMode = true
}
function disableEdit () {
window.removeEventListener('click', listener)
editMode = false
}
onDestroy(() => {
window.removeEventListener('click', listener)
})
</script> </script>
<div <div
bind:this={div}
class="{displayItems.length === 0 ? 'clear-mins' : 'buttons-group'} {kind === 'no-border' class="{displayItems.length === 0 ? 'clear-mins' : 'buttons-group'} {kind === 'no-border'
? 'xsmall-gap' ? 'xsmall-gap'
: 'xxsmall-gap'}" : 'xxsmall-gap'}"
@ -256,7 +225,7 @@
{shape} {shape}
click={item.value === ''} click={item.value === ''}
on:click={(ev) => { on:click={(ev) => {
if (editMode) editChannel(item, i, ev) if (editable) editChannel(item, i, ev)
}} }}
/> />
{:else} {:else}
@ -270,12 +239,12 @@
{kind} {kind}
{size} {size}
{shape} {shape}
highlight={item.integration || item.notification || editMode} highlight={item.integration || item.notification}
on:click={(ev) => { on:click={(ev) => {
if (editMode) { if (editable) {
editChannel(item, i, ev) editChannel(item, i, ev)
} else { } else {
dispatch('click', item) dispatch('open', item)
if (!copied) { if (!copied) {
navigator.clipboard.writeText(item.value) navigator.clipboard.writeText(item.value)
copied = true copied = true
@ -293,12 +262,11 @@
<Button <Button
bind:input={addBtn} bind:input={addBtn}
icon={contact.icon.SocialEdit} icon={contact.icon.SocialEdit}
highlight={editMode}
label={displayItems.length === 0 ? presentation.string.AddSocialLinks : undefined} label={displayItems.length === 0 ? presentation.string.AddSocialLinks : undefined}
{kind} {kind}
{size} {size}
{shape} {shape}
on:click={editMode ? showMenu : enableEdit} on:click={showMenu}
/> />
{/if} {/if}
</div> </div>
@ -334,6 +302,7 @@
transition-duration: 0.15s; transition-duration: 0.15s;
transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275); transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
pointer-events: none; pointer-events: none;
z-index: 1000;
} }
&:hover .tooltip { &:hover .tooltip {
transform: translate(-50%, -0.5rem) scale(1); transform: translate(-50%, -0.5rem) scale(1);

View File

@ -20,7 +20,6 @@
import { ChannelProvider, Channel } from '@anticrm/contact' import { ChannelProvider, Channel } from '@anticrm/contact'
import { showPanel } from '@anticrm/ui' import { showPanel } from '@anticrm/ui'
import view from '@anticrm/view'
import contact from '../plugin' import contact from '../plugin'
import ChannelsDropdown from './ChannelsDropdown.svelte' import ChannelsDropdown from './ChannelsDropdown.svelte'
@ -105,11 +104,11 @@
Promise.all(promises) Promise.all(promises)
} }
function click (ev: any) { function _open (ev: any) {
if (ev.detail.presenter !== undefined && Array.isArray(channels)) { if (ev.detail.presenter !== undefined && Array.isArray(channels)) {
const channel = channels[0] const channel = channels[0]
if (channel !== undefined) { if (channel !== undefined) {
showPanel(view.component.EditDoc, channel.attachedTo, channel.attachedToClass, 'content', ev.detail.presenter) showPanel(ev.detail.presenter, channel.attachedTo, channel.attachedToClass, 'float')
} }
} }
} }
@ -126,5 +125,5 @@
on:change={(e) => { on:change={(e) => {
if (editable) save(e.detail) if (editable) save(e.detail)
}} }}
on:click={click} on:open={_open}
/> />

View File

@ -27,14 +27,14 @@
export let length: 'short' | 'full' = 'short' export let length: 'short' | 'full' = 'short'
export let shape: 'circle' | undefined = 'circle' export let shape: 'circle' | undefined = 'circle'
function click (ev: any) { function _open (ev: any) {
if (ev.detail.presenter !== undefined && Array.isArray(value)) { if (ev.detail.presenter !== undefined && Array.isArray(value)) {
const channel = value[0] const channel = value[0]
if (channel !== undefined) { if (channel !== undefined) {
showPanel(ev.detail.presenter, channel.attachedTo, channel.attachedToClass, 'float', ev.detail.presenter) showPanel(ev.detail.presenter, channel.attachedTo, channel.attachedToClass, 'float')
} }
} }
} }
</script> </script>
<ChannelsDropdown bind:value {length} {kind} {size} {shape} {editable} on:click={click} /> <ChannelsDropdown bind:value {length} {kind} {size} {shape} {editable} on:open={_open} />

View File

@ -66,7 +66,7 @@
/> />
</div> </div>
<Scroller> <Scroller tableFade>
{#await tableDescriptor then descr} {#await tableDescriptor then descr}
{#if descr} {#if descr}
<TableBrowser <TableBrowser

View File

@ -143,9 +143,8 @@
attachedTo={object._id} attachedTo={object._id}
attachedClass={object._class} attachedClass={object._class}
{editable} {editable}
{integrations} bind:integrations
shape={'circle'} shape={'circle'}
on:click
/> />
</div> </div>

View File

@ -14,7 +14,6 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import type { AnyComponent } from '@anticrm/ui'
import { Ref, Doc, Class } from '@anticrm/core' import { Ref, Doc, Class } from '@anticrm/core'
import contact, { Channel } from '@anticrm/contact' import contact, { Channel } from '@anticrm/contact'
import { SharedMessage } from '@anticrm/gmail' import { SharedMessage } from '@anticrm/gmail'
@ -28,10 +27,8 @@
export let _id: Ref<Doc> export let _id: Ref<Doc>
export let _class: Ref<Class<Doc>> export let _class: Ref<Class<Doc>>
export let rightSection: AnyComponent | undefined = undefined
// export let object: Contact // export let object: Contact
// $: console.log('!!!!!!!!!!!! id: ', _id, ' - class: ', _class)
let object: any let object: any
let newMessage: boolean = false let newMessage: boolean = false
let currentMessage: SharedMessage | undefined = undefined let currentMessage: SharedMessage | undefined = undefined
@ -76,7 +73,7 @@
<Panel <Panel
icon={contact.icon.Email} icon={contact.icon.Email}
title={'Email'} title={'Email'}
{rightSection} withoutActivity
{object} {object}
isHeader={false} isHeader={false}
isAside={false} isAside={false}

View File

@ -67,7 +67,7 @@
/> />
</div> </div>
<Scroller> <Scroller tableFade>
{#await tableDescriptor then descr} {#await tableDescriptor then descr}
{#if descr} {#if descr}
<Table <Table

View File

@ -49,7 +49,7 @@
/> />
</div> </div>
<Scroller> <Scroller tableFade>
{#await tableDescriptor then descr} {#await tableDescriptor then descr}
{#if descr} {#if descr}
<Table <Table

View File

@ -82,6 +82,6 @@
<Button icon={IconAdd} label={recruit.string.ApplicationCreateLabel} kind={'primary'} on:click={showCreateDialog} /> <Button icon={IconAdd} label={recruit.string.ApplicationCreateLabel} kind={'primary'} on:click={showCreateDialog} />
</div> </div>
<Scroller> <Scroller tableFade>
<TableBrowser _class={recruit.class.Applicant} {config} {options} query={resultQuery} showNotification /> <TableBrowser _class={recruit.class.Applicant} {config} {options} query={resultQuery} showNotification />
</Scroller> </Scroller>

View File

@ -93,7 +93,7 @@
mode: 'browser' mode: 'browser'
}} }}
/> />
<Scroller> <Scroller tableFade>
{#await tableDescriptor then descr} {#await tableDescriptor then descr}
{#if descr} {#if descr}
<TableBrowser <TableBrowser

View File

@ -89,7 +89,7 @@
/> />
<Button icon={IconAdd} label={recruit.string.VacancyCreateLabel} kind={'primary'} on:click={showCreateDialog} /> <Button icon={IconAdd} label={recruit.string.VacancyCreateLabel} kind={'primary'} on:click={showCreateDialog} />
</div> </div>
<Scroller> <Scroller tableFade>
<Table <Table
_class={recruit.class.Vacancy} _class={recruit.class.Vacancy}
config={[ config={[

View File

@ -183,13 +183,13 @@
</div> </div>
<style lang="scss"> <style lang="scss">
.counter { // .counter {
padding-right: 0.125rem; // padding-right: 0.125rem;
min-width: 1.5rem; // min-width: 1.5rem;
text-align: right; // text-align: right;
font-size: 0.8125rem; // font-size: 0.8125rem;
color: var(--caption-color); // color: var(--caption-color);
} // }
.empty { .empty {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -108,7 +108,7 @@
updateResultQuery(search, category) updateResultQuery(search, category)
}} }}
/> />
<Scroller> <Scroller tableFade>
<TableBrowser <TableBrowser
_class={tags.class.TagElement} _class={tags.class.TagElement}
config={[ config={[

View File

@ -99,7 +99,7 @@
on:change={(evt) => updateCategory(evt.detail)} on:change={(evt) => updateCategory(evt.detail)}
/> />
<Scroller> <Scroller tableFade>
<Table <Table
{_class} {_class}
config={[ config={[

View File

@ -24,7 +24,6 @@
import { createQuery, getClient } from '@anticrm/presentation' import { createQuery, getClient } from '@anticrm/presentation'
import setting, { Integration } from '@anticrm/setting' import setting, { Integration } from '@anticrm/setting'
import type { NewTelegramMessage, SharedTelegramMessage, TelegramMessage } from '@anticrm/telegram' import type { NewTelegramMessage, SharedTelegramMessage, TelegramMessage } from '@anticrm/telegram'
import type { AnyComponent } from '@anticrm/ui'
import { Button, eventToHTMLElement, IconShare, Tooltip, Scroller, showPopup } from '@anticrm/ui' import { Button, eventToHTMLElement, IconShare, Tooltip, Scroller, showPopup } from '@anticrm/ui'
import telegram from '../plugin' import telegram from '../plugin'
import Connect from './Connect.svelte' import Connect from './Connect.svelte'
@ -34,7 +33,6 @@
export let _id: Ref<Contact> export let _id: Ref<Contact>
export let _class: Ref<Class<Contact>> export let _class: Ref<Class<Contact>>
export let rightSection: AnyComponent | undefined = undefined
let object: Contact let object: Contact
let channel: Channel | undefined = undefined let channel: Channel | undefined = undefined
@ -77,7 +75,7 @@
telegram.class.Message, telegram.class.Message,
{ attachedTo: channelId }, { attachedTo: channelId },
(res) => { (res) => {
messages = res.reverse() messages = res
if (channel !== undefined) { if (channel !== undefined) {
notificationClient.updateLastView(channel._id, channel._class, undefined, true) notificationClient.updateLastView(channel._id, channel._class, undefined, true)
} }
@ -191,7 +189,7 @@
<Panel <Panel
icon={TelegramIcon} icon={TelegramIcon}
title={'Telegram'} title={'Telegram'}
{rightSection} withoutActivity
{object} {object}
isHeader={false} isHeader={false}
isAside={false} isAside={false}
@ -203,6 +201,23 @@
You and {formatName(object.name)} You and {formatName(object.name)}
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="tools"> <svelte:fragment slot="tools">
{#if integration === undefined}
<Button
label={telegram.string.Connect}
kind={'primary'}
on:click={(e) => {
showPopup(Connect, {}, eventToHTMLElement(e), onConnectClose)
}}
/>
{:else if integration.disabled}
<Button
label={setting.string.Reconnect}
kind={'primary'}
on:click={(e) => {
showPopup(Reconnect, {}, eventToHTMLElement(e), onReconnect)
}}
/>
{:else}
<Tooltip label={telegram.string.Share}> <Tooltip label={telegram.string.Share}>
<Button <Button
icon={IconShare} icon={IconShare}
@ -213,17 +228,16 @@
}} }}
/> />
</Tooltip> </Tooltip>
{/if}
</svelte:fragment> </svelte:fragment>
<div class="telegram-content" class:selectable>
<Scroller bottomStart autoscroll> <Scroller bottomStart autoscroll>
{#if messages && accounts} {#if messages && accounts}
<Messages messages={convertMessages(messages, accounts)} {selectable} bind:selected /> <Messages messages={convertMessages(messages, accounts)} {selectable} bind:selected />
{/if} {/if}
</Scroller> </Scroller>
</div>
<div class="ref-input" class:selectable> <div class="popupPanel-body__main-header ref-input" class:selectable>
{#if selectable} {#if selectable}
<div class="flex-between"> <div class="flex-between">
<span>{selected.size} messages selected</span> <span>{selected.size} messages selected</span>
@ -242,26 +256,8 @@
</div> </div>
</div> </div>
</div> </div>
{:else if integration === undefined} {:else if integration === undefined || integration.disabled}
<div class="flex-center"> <div class="flex-center h-18">No integration</div>
<Button
label={telegram.string.Connect}
kind={'primary'}
on:click={(e) => {
showPopup(Connect, {}, eventToHTMLElement(e), onConnectClose)
}}
/>
</div>
{:else if integration.disabled}
<div class="flex-center">
<Button
label={setting.string.Reconnect}
kind={'primary'}
on:click={(e) => {
showPopup(Reconnect, {}, eventToHTMLElement(e), onReconnect)
}}
/>
</div>
{:else} {:else}
<AttachmentRefInput <AttachmentRefInput
space={telegram.space.Telegram} space={telegram.space.Telegram}
@ -276,7 +272,7 @@
<style lang="scss"> <style lang="scss">
.ref-input { .ref-input {
padding: 0 0 1.5rem; padding: 0.5rem 0 1.5rem;
&.selectable { &.selectable {
padding: 1rem 0; padding: 1rem 0;
@ -284,14 +280,4 @@
border-top: 1px solid var(--divider-color); border-top: 1px solid var(--divider-color);
} }
} }
.telegram-content {
padding-bottom: 1.5rem;
min-height: 0;
height: 100%;
&.selectable {
padding-bottom: 0;
}
}
</style> </style>

View File

@ -32,6 +32,7 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
</script> </script>
<div class="message-row-bg" class:selectable class:selected-row={selected}>
<div <div
class="message-row" class="message-row"
class:selectable class:selectable
@ -60,24 +61,40 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<style lang="scss"> <style lang="scss">
.message-row-bg {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
max-width: 100%;
min-width: 0;
min-height: 0;
}
.message-row { .message-row {
display: flex; display: flex;
justify-content: stretch; justify-content: stretch;
align-items: center; align-items: center;
margin: 0 auto;
width: 100%;
min-width: 0;
max-width: 900px;
}
&.selectable { .message-row.selectable,
.message-row-bg.selectable {
cursor: pointer; cursor: pointer;
&:hover { &:hover {
background-color: var(--highlight-hover); background-color: var(--button-bg-hover);
} }
&.selected-row { &.selected-row {
background-color: var(--highlight-select); background-color: var(--button-bg-color);
&:hover { &:hover {
background-color: var(--highlight-hover); background-color: var(--button-bg-hover);
} }
} }
.message { .message {
@ -91,7 +108,7 @@
} }
} }
} }
}
.check-box { .check-box {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -69,6 +69,7 @@
span { span {
margin-left: 0.25rem; margin-left: 0.25rem;
width: 1.6rem; width: 1.6rem;
white-space: nowrap;
text-transform: capitalize; text-transform: capitalize;
font-weight: 500; font-weight: 500;
color: var(--theme-caption-color); color: var(--theme-caption-color);

View File

@ -59,6 +59,7 @@
span { span {
margin-left: 0.25rem; margin-left: 0.25rem;
width: 1.6rem; width: 1.6rem;
white-space: nowrap;
text-transform: capitalize; text-transform: capitalize;
font-weight: 500; font-weight: 500;
color: var(--theme-caption-color); color: var(--theme-caption-color);

View File

@ -14,11 +14,11 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import contact, { ChannelProvider, formatName } from '@anticrm/contact' import contact, { formatName } from '@anticrm/contact'
import core, { Class, ClassifierKind, Doc, getCurrentAccount, Mixin, Obj, Ref, Space } from '@anticrm/core' import core, { Class, ClassifierKind, Doc, Mixin, Obj, Ref } from '@anticrm/core'
import notification from '@anticrm/notification' import notification from '@anticrm/notification'
import { Panel } from '@anticrm/panel' import { Panel } from '@anticrm/panel'
import { Asset, getResource, IntlString, translate } from '@anticrm/platform' import { Asset, getResource, translate } from '@anticrm/platform'
import { import {
AttributesBar, AttributesBar,
createQuery, createQuery,
@ -26,7 +26,6 @@
getClient, getClient,
KeyedAttribute KeyedAttribute
} from '@anticrm/presentation' } from '@anticrm/presentation'
import setting, { IntegrationType } from '@anticrm/setting'
import { AnyComponent, Component } from '@anticrm/ui' import { AnyComponent, Component } from '@anticrm/ui'
import view from '@anticrm/view' import view from '@anticrm/view'
import { createEventDispatcher, onDestroy } from 'svelte' import { createEventDispatcher, onDestroy } from 'svelte'
@ -36,7 +35,6 @@
export let _id: Ref<Doc> export let _id: Ref<Doc>
export let _class: Ref<Class<Doc>> export let _class: Ref<Class<Doc>>
export let rightSection: AnyComponent | undefined = undefined
let lastId: Ref<Doc> = _id let lastId: Ref<Doc> = _id
let lastClass: Ref<Class<Doc>> = _class let lastClass: Ref<Class<Doc>> = _class
@ -237,51 +235,6 @@
} }
let panelWidth: number = 0 let panelWidth: number = 0
let innerWidth: number = 0 let innerWidth: number = 0
const accountId = getCurrentAccount()._id
let channelProviders: ChannelProvider[] | undefined
let currentProviders: ChannelProvider[] | undefined
let integrations: Set<Ref<IntegrationType>> = new Set<Ref<IntegrationType>>()
let displayedIntegrations:
| {
icon: Asset | undefined
label: IntlString
presenter: AnyComponent | undefined
value: string
}[]
| undefined = []
client.findAll(contact.class.ChannelProvider, {}).then((res) => {
channelProviders = res
})
const settingsQuery = createQuery()
$: settingsQuery.query(
setting.class.Integration,
{ space: accountId as string as Ref<Space>, disabled: false },
(res) => {
integrations = new Set(res.map((p) => p.type))
}
)
const channelsQuery = createQuery()
$: _id &&
integrations &&
channelProviders &&
channelsQuery.query(contact.class.Channel, { attachedTo: _id }, (res) => {
const channels = res
currentProviders = channelProviders?.filter((provider) =>
provider.integrationType ? integrations.has(provider.integrationType as Ref<IntegrationType>) : false
)
displayedIntegrations = []
currentProviders?.forEach((provider) => {
displayedIntegrations?.push({
icon: provider.icon,
label: provider.label,
presenter: provider.presenter,
value: channels.filter((ch) => ch.provider === provider._id)[0].value
})
})
})
let minimize: boolean = false let minimize: boolean = false
</script> </script>
@ -295,7 +248,6 @@
<Panel <Panel
{icon} {icon}
{title} {title}
{rightSection}
{object} {object}
bind:minimize bind:minimize
isHeader={false} isHeader={false}
@ -321,7 +273,6 @@
{/if} {/if}
</svelte:fragment> </svelte:fragment>
<div class="main-editor">
{#if mainEditor} {#if mainEditor}
<Component <Component
is={mainEditor} is={mainEditor}
@ -332,12 +283,8 @@
updateKeys() updateKeys()
getMixins() getMixins()
}} }}
on:click={(ev) => {
rightSection = ev.detail.presenter
}}
/> />
{/if} {/if}
</div>
{#each collectionEditors as collection} {#each collectionEditors as collection}
{#if collection.editor} {#if collection.editor}
<div class="mt-6"> <div class="mt-6">
@ -357,11 +304,3 @@
{/each} {/each}
</Panel> </Panel>
{/if} {/if}
<style lang="scss">
.main-editor {
display: flex;
justify-content: center;
flex-direction: column;
}
</style>

View File

@ -35,6 +35,6 @@
mode: 'browser' mode: 'browser'
}} }}
/> />
<Scroller> <Scroller tableFade>
<TableBrowser {_class} {config} {options} query={resultQuery} {baseMenuClass} showNotification /> <TableBrowser {_class} {config} {options} query={resultQuery} {baseMenuClass} showNotification />
</Scroller> </Scroller>

View File

@ -27,14 +27,13 @@ test.describe('contact tests', () => {
await page.fill('[placeholder="Location"]', 'LoPlaza') await page.fill('[placeholder="Location"]', 'LoPlaza')
// Click .flex-center.icon-button // Click .flex-center.icon-button
await page.click('text=Edit profile John Appleseed LoPlaza >> button') await page.click('text=Edit profile John Appleseed LoPlaza >> button')
await page.click('text=Edit profile John Appleseed LoPlaza >> button')
// await page.click('button:has-text("Add social links")') // await page.click('button:has-text("Add social links")')
// Click [placeholder="john\.appleseed\@apple\.com"] // Click [placeholder="john\.appleseed\@apple\.com"]
await page.click('button:has-text("Email")') await page.click('button:has-text("Email")')
// Fill [placeholder="john\.appleseed\@apple\.com"] // Fill [placeholder="john\.appleseed\@apple\.com"]
await page.fill('[placeholder="john\\.appleseed\\@apple\\.com"]', 'wer@qwe.com') await page.fill('[placeholder="john\\.appleseed\\@apple\\.com"]', 'wer@qwe.com')
// Click text=Apply // Click text=Apply
await page.click('.button.transparent') await page.click('button:nth-child(3)')
}) })
test('create-template', async ({ page }) => { test('create-template', async ({ page }) => {
// Go to http://localhost:8083/workbench%3Acomponent%3AWorkbenchApp // Go to http://localhost:8083/workbench%3Acomponent%3AWorkbenchApp