mirror of
https://github.com/hcengineering/platform.git
synced 2025-06-08 00:37:42 +00:00
Updated mobile layout: collapsing WorkbenchTabs, floating aSide. UI fixes. (#7066)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
parent
e4bf53ad1b
commit
11a6236712
@ -501,6 +501,7 @@ input.search {
|
|||||||
.ml-8 { margin-left: 2rem; }
|
.ml-8 { margin-left: 2rem; }
|
||||||
.ml-10 { margin-left: 2.5rem; }
|
.ml-10 { margin-left: 2.5rem; }
|
||||||
.ml-12 { margin-left: 3rem; }
|
.ml-12 { margin-left: 3rem; }
|
||||||
|
.ml-14 { margin-left: 3.5rem; }
|
||||||
.ml-22 { margin-left: 5.5rem; }
|
.ml-22 { margin-left: 5.5rem; }
|
||||||
.ml-auto { margin-left: auto; }
|
.ml-auto { margin-left: auto; }
|
||||||
.mr-0-5 { margin-right: .125rem; }
|
.mr-0-5 { margin-right: .125rem; }
|
||||||
@ -744,6 +745,7 @@ input.search {
|
|||||||
.min-h-16 { min-height: 4rem; }
|
.min-h-16 { min-height: 4rem; }
|
||||||
.min-h-30 { min-height: 7.5rem; }
|
.min-h-30 { min-height: 7.5rem; }
|
||||||
.min-h-60 { min-height: 15rem; }
|
.min-h-60 { min-height: 15rem; }
|
||||||
|
.max-w-0 { max-width: 0; }
|
||||||
.max-w-2 { max-width: .5rem; }
|
.max-w-2 { max-width: .5rem; }
|
||||||
.max-w-4 { max-width: 1rem; }
|
.max-w-4 { max-width: 1rem; }
|
||||||
.max-w-9 { max-width: 2.25rem; }
|
.max-w-9 { max-width: 2.25rem; }
|
||||||
|
@ -141,23 +141,40 @@
|
|||||||
}
|
}
|
||||||
.antiPanel-navigator {
|
.antiPanel-navigator {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 12.5rem;
|
|
||||||
max-width: 22.5rem;
|
|
||||||
width: 17.5rem;
|
|
||||||
background-color: var(--theme-navpanel-color);
|
background-color: var(--theme-navpanel-color);
|
||||||
|
|
||||||
|
&:not(.right) {
|
||||||
|
min-width: 12.5rem;
|
||||||
|
max-width: 22.5rem;
|
||||||
|
width: 17.5rem;
|
||||||
|
}
|
||||||
|
&.right {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: var(--medium-BorderRadius) 0 0 var(--medium-BorderRadius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.antiPanel-navigator {
|
.antiPanel-navigator {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: calc(var(--status-bar-height) + 1px);
|
|
||||||
height: calc(100% - var(--status-bar-height) - 1px);
|
|
||||||
background-color: var(--theme-navpanel-color);
|
background-color: var(--theme-navpanel-color);
|
||||||
filter: drop-shadow(2px 0 1px rgba(0, 0, 0, .2));
|
|
||||||
z-index: 450;
|
z-index: 450;
|
||||||
|
|
||||||
|
&:not(.right) {
|
||||||
|
top: calc(var(--status-bar-height) + 1px);
|
||||||
|
height: calc(100% - var(--status-bar-height) - 1px);
|
||||||
|
filter: drop-shadow(2px 0 5px rgba(0, 0, 0, .2));
|
||||||
|
|
||||||
&.portrait { left: 0; }
|
&.portrait { left: 0; }
|
||||||
&.landscape { left: var(--app-panel-width); }
|
&.landscape { left: var(--app-panel-width); }
|
||||||
|
}
|
||||||
|
&.right {
|
||||||
|
top: var(--status-bar-height);
|
||||||
|
right: 0;
|
||||||
|
height: calc(100% - var(--status-bar-height) - 1px);
|
||||||
|
background-color: var(--theme-statusbar-color);
|
||||||
|
filter: drop-shadow(-2px 0 5px rgba(0, 0, 0, .2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.antiPanel-component {
|
.antiPanel-component {
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
--body-font-size: .875rem;
|
--body-font-size: .875rem;
|
||||||
--status-bar-height: 36px;
|
--status-bar-height: 36px;
|
||||||
|
--status-bar-normal-height: 36px;
|
||||||
--panel-aside-width: 25rem; // 20rem;
|
--panel-aside-width: 25rem; // 20rem;
|
||||||
--font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
|
--font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
|
||||||
--mono-font: 'IBM Plex Mono', monospace;
|
--mono-font: 'IBM Plex Mono', monospace;
|
||||||
@ -89,6 +90,10 @@
|
|||||||
|
|
||||||
&::after,
|
&::after,
|
||||||
&::before { box-sizing: border-box; }
|
&::before { box-sizing: border-box; }
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
--status-bar-height: 70px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
:root {
|
:root {
|
||||||
--app-height: 100%;
|
--app-height: 100%;
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<div
|
<div
|
||||||
class="container main flex-row-center flex-gap-2 {orientation} {kind}"
|
class="container main flex-between flex-gap-2 {orientation} {kind}"
|
||||||
style:max-width={orientation === 'horizontal' ? maxSize : 'auto'}
|
style:max-width={orientation === 'horizontal' ? maxSize : 'auto'}
|
||||||
style:max-height={orientation === 'vertical' ? maxSize : 'auto'}
|
style:max-height={orientation === 'vertical' ? maxSize : 'auto'}
|
||||||
class:active={highlighted}
|
class:active={highlighted}
|
||||||
@ -52,7 +52,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<span class="overflow-label">
|
<span class="overflow-label flex-grow">
|
||||||
{#if label}
|
{#if label}
|
||||||
{label}
|
{label}
|
||||||
{:else if labelIntl}
|
{:else if labelIntl}
|
||||||
@ -100,11 +100,14 @@
|
|||||||
&.horizontal {
|
&.horizontal {
|
||||||
padding: 0.125rem 0.125rem 0.125rem 0.5rem;
|
padding: 0.125rem 0.125rem 0.125rem 0.5rem;
|
||||||
height: 1.625rem;
|
height: 1.625rem;
|
||||||
|
min-height: 1.625rem;
|
||||||
|
min-width: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.vertical {
|
&.vertical {
|
||||||
padding: 0.5rem 0.125rem 0.125rem 0.125rem;
|
padding: 0.5rem 0.125rem 0.125rem 0.125rem;
|
||||||
width: 1.625rem;
|
width: 1.625rem;
|
||||||
|
min-height: 6rem;
|
||||||
writing-mode: vertical-rl;
|
writing-mode: vertical-rl;
|
||||||
text-orientation: sideways;
|
text-orientation: sideways;
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@
|
|||||||
<Header
|
<Header
|
||||||
type={'type-panel'}
|
type={'type-panel'}
|
||||||
noPrint={!printHeader}
|
noPrint={!printHeader}
|
||||||
{adaptive}
|
adaptive={$deviceInfo.isMobile ? 'disabled' : adaptive}
|
||||||
{hideBefore}
|
{hideBefore}
|
||||||
{hideSearch}
|
{hideSearch}
|
||||||
{hideActions}
|
{hideActions}
|
||||||
@ -261,21 +261,21 @@
|
|||||||
</Header>
|
</Header>
|
||||||
<div class="popupPanel-body {$deviceInfo.isMobile ? 'mobile' : 'main'}" class:asideShown>
|
<div class="popupPanel-body {$deviceInfo.isMobile ? 'mobile' : 'main'}" class:asideShown>
|
||||||
{#if $deviceInfo.isMobile}
|
{#if $deviceInfo.isMobile}
|
||||||
<Scroller horizontal padding={'.5rem .75rem'}>
|
<div
|
||||||
<div
|
class="popupPanel-body__mobile"
|
||||||
class="popupPanel-body__mobile"
|
use:resizeObserver={(element) => {
|
||||||
use:resizeObserver={(element) => {
|
innerWidth = element.clientWidth
|
||||||
innerWidth = element.clientWidth
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<Scroller horizontal padding={'.5rem .75rem'}>
|
||||||
{#if $$slots.header && isHeader}
|
{#if $$slots.header && isHeader}
|
||||||
<div class="popupPanel-body__header mobile bottom-divider" class:max={useMaxWidth}>
|
<div class="popupPanel-body__header mobile bottom-divider" class:max={useMaxWidth}>
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</Scroller>
|
||||||
</Scroller>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div
|
<div
|
||||||
class="popupPanel-body__main"
|
class="popupPanel-body__main"
|
||||||
|
@ -14,10 +14,12 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy, onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
|
import { resizeObserver } from '..'
|
||||||
|
|
||||||
export let scroller: HTMLElement
|
export let scroller: HTMLElement
|
||||||
export let gap: 'none' | 'small' | 'big' = 'small'
|
export let gap: 'none' | 'small' | 'big' = 'small'
|
||||||
|
export let padding: string | undefined = undefined
|
||||||
|
|
||||||
let divBar: HTMLElement
|
let divBar: HTMLElement
|
||||||
let isScrolling: boolean = false
|
let isScrolling: boolean = false
|
||||||
@ -31,7 +33,7 @@
|
|||||||
$: stepStyle = gap === 'small' ? 'gap-1' : gap === 'big' ? 'gap-2' : ''
|
$: stepStyle = gap === 'small' ? 'gap-1' : gap === 'big' ? 'gap-2' : ''
|
||||||
|
|
||||||
const checkBar = (): void => {
|
const checkBar = (): void => {
|
||||||
if (divBar && scroller) {
|
if (divBar !== undefined && scroller !== undefined) {
|
||||||
const trackW = scroller.clientWidth
|
const trackW = scroller.clientWidth
|
||||||
const scrollW = scroller.scrollWidth
|
const scrollW = scroller.scrollWidth
|
||||||
const proc = scrollW / trackW
|
const proc = scrollW / trackW
|
||||||
@ -40,13 +42,13 @@
|
|||||||
if (mask === 'none') divBar.style.visibility = 'hidden'
|
if (mask === 'none') divBar.style.visibility = 'hidden'
|
||||||
else {
|
else {
|
||||||
divBar.style.visibility = 'visible'
|
divBar.style.visibility = 'visible'
|
||||||
if (divBar) {
|
if (divBar !== undefined) {
|
||||||
if (timer) {
|
if (timer != null) {
|
||||||
clearTimeout(timer)
|
clearTimeout(timer)
|
||||||
divBar.style.opacity = '1'
|
divBar.style.opacity = '1'
|
||||||
}
|
}
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
if (divBar) divBar.style.opacity = '0'
|
if (divBar != null) divBar.style.opacity = '0'
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,8 +56,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onScroll = (event: MouseEvent): void => {
|
const onScroll = (event: PointerEvent): void => {
|
||||||
if (isScrolling && divBar && scroller) {
|
if (isScrolling && divBar !== undefined && scroller !== undefined) {
|
||||||
const rectScroll = scroller.getBoundingClientRect()
|
const rectScroll = scroller.getBoundingClientRect()
|
||||||
let X = event.clientX - dX
|
let X = event.clientX - dX
|
||||||
if (X < rectScroll.left) X = rectScroll.left
|
if (X < rectScroll.left) X = rectScroll.left
|
||||||
@ -67,22 +69,22 @@
|
|||||||
scroller.scrollLeft = (scroller.scrollWidth - scroller.clientWidth) * procBar
|
scroller.scrollLeft = (scroller.scrollWidth - scroller.clientWidth) * procBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onScrollEnd = (event: MouseEvent): void => {
|
const onScrollEnd = (event: PointerEvent): void => {
|
||||||
const el: HTMLElement = event.currentTarget as HTMLElement
|
const el: HTMLElement = event.currentTarget as HTMLElement
|
||||||
if (el && isScrolling) {
|
if (el !== undefined && isScrolling) {
|
||||||
document.removeEventListener('mousemove', onScroll)
|
document.removeEventListener('pointermove', onScroll)
|
||||||
document.body.style.userSelect = 'auto'
|
document.body.style.userSelect = 'auto'
|
||||||
document.body.style.webkitUserSelect = 'auto'
|
document.body.style.webkitUserSelect = 'auto'
|
||||||
}
|
}
|
||||||
document.removeEventListener('mouseup', onScrollEnd)
|
document.removeEventListener('pointerup', onScrollEnd)
|
||||||
isScrolling = false
|
isScrolling = false
|
||||||
}
|
}
|
||||||
const onScrollStart = (event: MouseEvent): void => {
|
const onScrollStart = (event: PointerEvent): void => {
|
||||||
const el: HTMLElement = event.currentTarget as HTMLElement
|
const el: HTMLElement = event.currentTarget as HTMLElement
|
||||||
if (el && scroller) {
|
if (el !== undefined && scroller !== undefined) {
|
||||||
dX = event.clientX - el.getBoundingClientRect().x
|
dX = event.clientX - el.getBoundingClientRect().x
|
||||||
document.addEventListener('mouseup', onScrollEnd)
|
document.addEventListener('pointerup', onScrollEnd)
|
||||||
document.addEventListener('mousemove', onScroll)
|
document.addEventListener('pointermove', onScroll)
|
||||||
document.body.style.userSelect = 'none'
|
document.body.style.userSelect = 'none'
|
||||||
document.body.style.webkitUserSelect = 'none'
|
document.body.style.webkitUserSelect = 'none'
|
||||||
isScrolling = true
|
isScrolling = true
|
||||||
@ -90,8 +92,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const checkMask = (): void => {
|
const checkMask = (): void => {
|
||||||
maskLeft = !!(scroller && scroller.scrollLeft > 1)
|
maskLeft = scroller !== undefined && scroller.scrollLeft > 1
|
||||||
maskRight = !!(scroller && scroller.scrollWidth - scroller.scrollLeft - scroller.clientWidth > 1)
|
maskRight = scroller !== undefined && scroller.scrollWidth - scroller.scrollLeft - scroller.clientWidth > 1
|
||||||
if (maskLeft || maskRight) {
|
if (maskLeft || maskRight) {
|
||||||
if (maskLeft && maskRight) mask = 'both'
|
if (maskLeft && maskRight) mask = 'both'
|
||||||
else if (maskLeft) mask = 'left'
|
else if (maskLeft) mask = 'left'
|
||||||
@ -102,30 +104,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (scroller) {
|
if (scroller !== undefined) checkMask()
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
() => {
|
|
||||||
checkMask()
|
|
||||||
},
|
|
||||||
{ root: null, threshold: 0.1 }
|
|
||||||
)
|
|
||||||
const tempEl = scroller.querySelector('*') as HTMLElement
|
|
||||||
if (tempEl) observer.observe(tempEl)
|
|
||||||
checkMask()
|
|
||||||
scroller.addEventListener('scroll', checkMask)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
onDestroy(() => {
|
|
||||||
if (scroller) scroller.removeEventListener('scroll', checkMask)
|
|
||||||
})
|
|
||||||
const _resize = (): void => {
|
|
||||||
checkMask()
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:resize={_resize} />
|
<div class="scrollerbar-container" use:resizeObserver={checkMask}>
|
||||||
<div class="scrollerbar-container">
|
<div bind:this={scroller} class="antiStatesBar mask-{mask} {stepStyle}" style:padding on:scroll={checkMask}>
|
||||||
<div bind:this={scroller} class="antiStatesBar mask-{mask} {stepStyle}">
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
@ -133,8 +117,8 @@
|
|||||||
class="bar"
|
class="bar"
|
||||||
class:hovered={isScrolling}
|
class:hovered={isScrolling}
|
||||||
bind:this={divBar}
|
bind:this={divBar}
|
||||||
on:mousedown={onScrollStart}
|
on:pointerdown={onScrollStart}
|
||||||
on:mouseleave={checkMask}
|
on:pointerleave={checkMask}
|
||||||
/>
|
/>
|
||||||
<div class="track" class:hovered={isScrolling} />
|
<div class="track" class:hovered={isScrolling} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
||||||
export let filled: boolean = false
|
export let filled: boolean = false
|
||||||
const fill: string = 'currentColor'
|
export let fill: string = 'currentColor'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
export let size: 'x-small' | 'small' | 'medium' | 'large'
|
||||||
const fill: string = 'currentColor'
|
export let fill: string = 'currentColor'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let size: 'small' | 'medium' | 'large'
|
export let size: 'small' | 'medium' | 'large'
|
||||||
const fill: string = 'currentColor'
|
export let fill: string = 'currentColor'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
@ -5,7 +5,16 @@
|
|||||||
import { deviceSizes, deviceWidths } from '../../types'
|
import { deviceSizes, deviceWidths } from '../../types'
|
||||||
// import { applicationShortcutKey } from '../../utils'
|
// import { applicationShortcutKey } from '../../utils'
|
||||||
import { Theme } from '@hcengineering/theme'
|
import { Theme } from '@hcengineering/theme'
|
||||||
import { IconArrowLeft, IconArrowRight, checkMobile, deviceOptionsStore as deviceInfo } from '../../'
|
import {
|
||||||
|
IconArrowLeft,
|
||||||
|
IconArrowRight,
|
||||||
|
checkMobile,
|
||||||
|
deviceOptionsStore as deviceInfo,
|
||||||
|
checkAdaptiveMatching,
|
||||||
|
ButtonIcon,
|
||||||
|
IconDetailsFilled,
|
||||||
|
IconDetails
|
||||||
|
} from '../../'
|
||||||
import { desktopPlatform, getCurrentLocation, location, locationStorageKeyId, navigate } from '../../location'
|
import { desktopPlatform, getCurrentLocation, location, locationStorageKeyId, navigate } from '../../location'
|
||||||
import uiPlugin from '../../plugin'
|
import uiPlugin from '../../plugin'
|
||||||
import Component from '../Component.svelte'
|
import Component from '../Component.svelte'
|
||||||
@ -129,6 +138,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateDeviceSize()
|
updateDeviceSize()
|
||||||
|
|
||||||
|
$: secondRow = checkAdaptiveMatching($deviceInfo.size, 'xs')
|
||||||
|
$: asideFloat = $deviceInfo.navigator.float
|
||||||
|
$: asideOpen = $deviceInfo.aside.visible
|
||||||
|
$: appsMini =
|
||||||
|
$deviceInfo.isMobile &&
|
||||||
|
(($deviceInfo.isPortrait && $deviceInfo.docWidth <= 480) ||
|
||||||
|
(!$deviceInfo.isPortrait && $deviceInfo.docHeight <= 480))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window bind:innerWidth={docWidth} bind:innerHeight={docHeight} />
|
<svelte:window bind:innerWidth={docWidth} bind:innerHeight={docHeight} />
|
||||||
@ -161,9 +178,15 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="flex-row-center left-items flex-gap-0-5" style:-webkit-app-region={'no-drag'}>
|
{#if !secondRow}
|
||||||
<RootBarExtension position="left" />
|
<div
|
||||||
</div>
|
class="flex-row-center left-items flex-gap-0-5"
|
||||||
|
class:ml-14={appsMini}
|
||||||
|
style:-webkit-app-region={'no-drag'}
|
||||||
|
>
|
||||||
|
<RootBarExtension position="left" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div
|
<div
|
||||||
class="flex-row-center justify-center status-info"
|
class="flex-row-center justify-center status-info"
|
||||||
style:margin-left={(isPortrait && docWidth <= 480) || (!isPortrait && docHeight <= 480) ? '1.5rem' : '0'}
|
style:margin-left={(isPortrait && docWidth <= 480) || (!isPortrait && docHeight <= 480) ? '1.5rem' : '0'}
|
||||||
@ -177,17 +200,54 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row-reverse" style:-webkit-app-region={'no-drag'}>
|
<div class="flex-row-reverse" style:-webkit-app-region={'no-drag'}>
|
||||||
|
{#if asideFloat && !secondRow}
|
||||||
|
<div class="antiHSpacer x2" />
|
||||||
|
<ButtonIcon
|
||||||
|
icon={asideOpen ? IconDetailsFilled : IconDetails}
|
||||||
|
iconProps={{ fill: 'var(--theme-dark-color)' }}
|
||||||
|
kind={'tertiary'}
|
||||||
|
size={'extra-small'}
|
||||||
|
hasMenu
|
||||||
|
pressed={$deviceInfo.aside.visible}
|
||||||
|
on:click={() => {
|
||||||
|
$deviceInfo.aside.visible = !$deviceInfo.aside.visible
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
<div class="clock">
|
<div class="clock">
|
||||||
<Clock />
|
<Clock />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row-center gap-statusbar">
|
<div class="flex-row-center gap-statusbar">
|
||||||
<RootBarExtension position="right" />
|
{#if !secondRow}
|
||||||
|
<RootBarExtension position="right" />
|
||||||
|
{/if}
|
||||||
<FontSizeSelector />
|
<FontSizeSelector />
|
||||||
<ThemeSelector />
|
<ThemeSelector />
|
||||||
<LangSelector />
|
<LangSelector />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{#if secondRow}
|
||||||
|
<div class="flex-between h-full content-color gap-3 px-2 second-row" style:-webkit-app-region={'no-drag'}>
|
||||||
|
<div class="flex-row-center flex-gap-0-5">
|
||||||
|
<RootBarExtension position="left" />
|
||||||
|
</div>
|
||||||
|
<div class="flex-row-center flex-gap-0-5">
|
||||||
|
<RootBarExtension position="right" />
|
||||||
|
<ButtonIcon
|
||||||
|
icon={asideOpen ? IconDetailsFilled : IconDetails}
|
||||||
|
iconProps={{ fill: 'var(--theme-dark-color)' }}
|
||||||
|
kind={'tertiary'}
|
||||||
|
size={'extra-small'}
|
||||||
|
hasMenu
|
||||||
|
pressed={$deviceInfo.aside.visible}
|
||||||
|
on:click={() => {
|
||||||
|
$deviceInfo.aside.visible = !$deviceInfo.aside.visible
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="app">
|
<div class="app">
|
||||||
{#if application}
|
{#if application}
|
||||||
@ -213,6 +273,7 @@
|
|||||||
|
|
||||||
.antiStatusBar {
|
.antiStatusBar {
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
|
min-width: 0;
|
||||||
min-height: var(--status-bar-height);
|
min-height: var(--status-bar-height);
|
||||||
height: var(--status-bar-height);
|
height: var(--status-bar-height);
|
||||||
// min-width: 600px;
|
// min-width: 600px;
|
||||||
@ -248,6 +309,21 @@
|
|||||||
margin: 0 12px 0 8px;
|
margin: 0 12px 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.second-row {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
padding: 2px 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.second-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
@media print {
|
@media print {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
{#each sorted as ext (ext[1].id)}
|
{#each sorted as ext (ext[1].id)}
|
||||||
{#if ext[0] === position}
|
{#if ext[0] === position}
|
||||||
<div id={ext[1].id} style:margin-right={'1px'}>
|
<div id={ext[1].id} class="clear-mins" style:margin-right={'1px'}>
|
||||||
<Component
|
<Component
|
||||||
is={ext[1].component}
|
is={ext[1].component}
|
||||||
props={ext[1].props}
|
props={ext[1].props}
|
||||||
|
@ -311,6 +311,7 @@ export const deviceOptionsStore = writable<DeviceOptions>({
|
|||||||
isPortrait: false,
|
isPortrait: false,
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
navigator: { visible: true, float: false, direction: 'vertical' },
|
navigator: { visible: true, float: false, direction: 'vertical' },
|
||||||
|
aside: { visible: true },
|
||||||
fontSize: 0,
|
fontSize: 0,
|
||||||
size: null,
|
size: null,
|
||||||
sizes: { xs: false, sm: false, md: false, lg: false, xl: false, xxl: false },
|
sizes: { xs: false, sm: false, md: false, lg: false, xl: false, xxl: false },
|
||||||
|
@ -166,7 +166,7 @@ export const settingsSeparators: DefSeparators = [
|
|||||||
|
|
||||||
export const mainSeparators: DefSeparators = [
|
export const mainSeparators: DefSeparators = [
|
||||||
{ minSize: 30, size: 'auto', maxSize: 'auto' },
|
{ minSize: 30, size: 'auto', maxSize: 'auto' },
|
||||||
{ minSize: 20, size: 30, maxSize: 80, float: 'sidebar' }
|
{ minSize: 25, size: 30, maxSize: 80, float: 'sidebar' }
|
||||||
]
|
]
|
||||||
|
|
||||||
export const secondNavSeparators: DefSeparators = [{ minSize: 7, size: 7.5, maxSize: 15, float: 'navigator' }, null]
|
export const secondNavSeparators: DefSeparators = [{ minSize: 7, size: 7.5, maxSize: 15, float: 'navigator' }, null]
|
||||||
|
@ -378,6 +378,7 @@ export interface DeviceOptions {
|
|||||||
isPortrait: boolean
|
isPortrait: boolean
|
||||||
isMobile: boolean
|
isMobile: boolean
|
||||||
navigator: { visible: boolean, float: boolean, direction: 'vertical' | 'horizontal' }
|
navigator: { visible: boolean, float: boolean, direction: 'vertical' | 'horizontal' }
|
||||||
|
aside: { visible: boolean }
|
||||||
fontSize: number
|
fontSize: number
|
||||||
size: WidthType | null
|
size: WidthType | null
|
||||||
sizes: Record<WidthType, boolean>
|
sizes: Record<WidthType, boolean>
|
||||||
|
@ -5,7 +5,8 @@ import {
|
|||||||
getLocation,
|
getLocation,
|
||||||
type Location,
|
type Location,
|
||||||
navigate,
|
navigate,
|
||||||
languageStore
|
languageStore,
|
||||||
|
deviceOptionsStore as deviceInfo
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { type Ref, type Doc, type Class, generateId } from '@hcengineering/core'
|
import { type Ref, type Doc, type Class, generateId } from '@hcengineering/core'
|
||||||
import activity, { type ActivityMessage } from '@hcengineering/activity'
|
import activity, { type ActivityMessage } from '@hcengineering/activity'
|
||||||
@ -179,6 +180,10 @@ export async function replyToThread (message: ActivityMessage, e: Event): Promis
|
|||||||
const fromSidebar = isElementFromSidebar(e.target as HTMLElement)
|
const fromSidebar = isElementFromSidebar(e.target as HTMLElement)
|
||||||
const loc = getCurrentLocation()
|
const loc = getCurrentLocation()
|
||||||
|
|
||||||
|
const dev = get(deviceInfo)
|
||||||
|
dev.aside.visible = true
|
||||||
|
deviceInfo.set(dev)
|
||||||
|
|
||||||
threadMessagesStore.set(message)
|
threadMessagesStore.set(message)
|
||||||
|
|
||||||
if (fromSidebar) {
|
if (fromSidebar) {
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
export let targetEmp: Person
|
export let targetEmp: Person
|
||||||
export let key: string
|
export let key: string
|
||||||
export let onChange: (key: string, value: boolean) => void
|
export let onChange: (key: string, value: boolean) => void
|
||||||
export let selected = false
|
export let selected: boolean = false
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
|
@ -16,13 +16,14 @@
|
|||||||
import { Person } from '@hcengineering/contact'
|
import { Person } from '@hcengineering/contact'
|
||||||
import { Doc, Mixin, Ref } from '@hcengineering/core'
|
import { Doc, Mixin, Ref } from '@hcengineering/core'
|
||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { CheckBox, Label } from '@hcengineering/ui'
|
import { Label, RadioButton } from '@hcengineering/ui'
|
||||||
|
import { FixedColumn } from '@hcengineering/view-resources'
|
||||||
|
|
||||||
export let value: Person
|
export let value: Person
|
||||||
export let targetEmp: Person
|
export let targetEmp: Person
|
||||||
export let cast: Ref<Mixin<Doc>> | undefined = undefined
|
export let cast: Ref<Mixin<Doc>> | undefined = undefined
|
||||||
export let key: string
|
export let key: string
|
||||||
export let selected = false
|
export let selected: boolean = false
|
||||||
export let onChange: (key: string, value: boolean) => void
|
export let onChange: (key: string, value: boolean) => void
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
@ -38,51 +39,51 @@
|
|||||||
return (value as any)[key] === (targetEmp as any)[key]
|
return (value as any)[key] === (targetEmp as any)[key]
|
||||||
}
|
}
|
||||||
$: attribute = hierarchy.findAttribute(cast ?? value._class, key)
|
$: attribute = hierarchy.findAttribute(cast ?? value._class, key)
|
||||||
|
const change = (sel: boolean): void => {
|
||||||
|
selected = sel
|
||||||
|
onChange(key, sel)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !isEqual(value, targetEmp, key)}
|
{#if !isEqual(value, targetEmp, key)}
|
||||||
<div class="box flex-row-center flex-between">
|
<div class="box flex-row-center flex-gap-4 flex-grow">
|
||||||
<div class="ml-4">
|
<FixedColumn key={'mergeLabel'} addClass={'ml-4'}>
|
||||||
{#if attribute?.label}
|
{#if attribute?.label}
|
||||||
<Label label={attribute.label} />
|
<Label label={attribute.label} />
|
||||||
{:else}
|
{:else}
|
||||||
{key}
|
{key}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</FixedColumn>
|
||||||
|
|
||||||
<div class="flex-center">
|
<FixedColumn key={'mergeFirst'} addClass="flex-row-center flex-gap-2 cursor-pointer">
|
||||||
<div class="mr-2">
|
<RadioButton
|
||||||
<CheckBox
|
bind:group={selected}
|
||||||
circle
|
value={false}
|
||||||
checked={selected}
|
action={() => {
|
||||||
on:value={(e) => {
|
if (selected) change(false)
|
||||||
selected = false
|
}}
|
||||||
onChange(key, false)
|
>
|
||||||
}}
|
<slot name="item" item={value} />
|
||||||
/>
|
</RadioButton>
|
||||||
</div>
|
</FixedColumn>
|
||||||
<slot name="item" item={value} />
|
|
||||||
</div>
|
<FixedColumn key={'mergeSecond'} addClass="flex-row-center flex-gap-2 cursor-pointer">
|
||||||
<div class="flex-row-center" />
|
<RadioButton
|
||||||
<div class="flex-center">
|
bind:group={selected}
|
||||||
<div class="mr-2">
|
value={true}
|
||||||
<CheckBox
|
action={() => {
|
||||||
circle
|
if (!selected) change(true)
|
||||||
checked={!selected}
|
}}
|
||||||
on:value={(e) => {
|
>
|
||||||
selected = true
|
<slot name="item" item={targetEmp} />
|
||||||
onChange(key, true)
|
</RadioButton>
|
||||||
}}
|
</FixedColumn>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<slot name="item" item={targetEmp} />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.box {
|
.box {
|
||||||
margin: 0.5rem;
|
margin: 0.5rem 0;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border: 1px dashed var(--accent-color);
|
border: 1px dashed var(--accent-color);
|
||||||
|
@ -225,7 +225,7 @@
|
|||||||
function selectMixin (mixin: Ref<Mixin<Doc>>, field: string, targetValue: boolean) {
|
function selectMixin (mixin: Ref<Mixin<Doc>>, field: string, targetValue: boolean) {
|
||||||
const upd = mixinUpdate[mixin] ?? {}
|
const upd = mixinUpdate[mixin] ?? {}
|
||||||
if (!targetValue) {
|
if (!targetValue) {
|
||||||
;(upd as any)[field] = (value as any)[field]
|
;(upd as any)[field] = (sourcePerson as any)[mixin][field]
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
delete (upd as any)[field]
|
delete (upd as any)[field]
|
||||||
@ -354,7 +354,7 @@
|
|||||||
shape={'circle'}
|
shape={'circle'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
>>
|
<span class="mx-4">>></span>
|
||||||
<div class="flex-row-center">
|
<div class="flex-row-center">
|
||||||
<UserBox
|
<UserBox
|
||||||
_class={contact.class.Person}
|
_class={contact.class.Person}
|
||||||
@ -387,13 +387,7 @@
|
|||||||
<Avatar person={item} size={'x-large'} icon={contact.icon.Person} name={item.name} />
|
<Avatar person={item} size={'x-large'} icon={contact.icon.Person} name={item.name} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</MergeComparer>
|
</MergeComparer>
|
||||||
<MergeComparer
|
<MergeComparer key="name" value={sourcePerson} targetEmp={targetPerson} onChange={select} selected>
|
||||||
key="name"
|
|
||||||
value={sourcePerson}
|
|
||||||
targetEmp={targetPerson}
|
|
||||||
onChange={select}
|
|
||||||
selected={update.name !== undefined}
|
|
||||||
>
|
|
||||||
<svelte:fragment slot="item" let:item>
|
<svelte:fragment slot="item" let:item>
|
||||||
{getName(client.getHierarchy(), item)}
|
{getName(client.getHierarchy(), item)}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
@ -405,7 +399,7 @@
|
|||||||
targetEmp={targetPerson}
|
targetEmp={targetPerson}
|
||||||
onChange={select}
|
onChange={select}
|
||||||
_class={contact.mixin.Employee}
|
_class={contact.mixin.Employee}
|
||||||
selected={toAny(update)[attribute[0]] !== undefined}
|
selected
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{#each mixins as mixin}
|
{#each mixins as mixin}
|
||||||
@ -419,7 +413,7 @@
|
|||||||
selectMixin(mixin, key, value)
|
selectMixin(mixin, key, value)
|
||||||
}}
|
}}
|
||||||
_class={mixin}
|
_class={mixin}
|
||||||
selected={toAny(mixinUpdate)?.[mixin]?.[attribute] !== undefined}
|
selected
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -48,4 +48,4 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={parentElement}></div>
|
<div bind:this={parentElement} class="hidden"></div>
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
import { uploads } from '../store'
|
import { uploads } from '../store'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex-row-center flex-gap-2">
|
{#if $uploads.length > 0}
|
||||||
{#each $uploads as upload}
|
<div class="flex-row-center flex-gap-2">
|
||||||
<FileUploadStatusBar {upload} />
|
{#each $uploads as upload}
|
||||||
{/each}
|
<FileUploadStatusBar {upload} />
|
||||||
</div>
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
let parentElement: HTMLDivElement
|
let parentElement: HTMLDivElement
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
pushRootBarComponent('right', uploader.component.FileUploadExt)
|
pushRootBarComponent('right', uploader.component.FileUploadExt, 10)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={parentElement}></div>
|
<div bind:this={parentElement} class="hidden"></div>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<!--
|
<!--
|
||||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||||
// Copyright © 2021 Hardcore Engineering Inc.
|
// Copyright © 2021 Hardcore Engineering Inc.
|
||||||
@ -43,11 +44,13 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div
|
<div
|
||||||
class="flex-no-shrink{addClass ? ` ${addClass}` : ''}"
|
class="flex-no-shrink{addClass ? ` ${addClass}` : ''}"
|
||||||
style:text-align={justify !== '' ? justify : ''}
|
style:text-align={justify !== '' ? justify : ''}
|
||||||
style:min-width={`${$fixedWidthStore[key] ?? 0}px`}
|
style:min-width={`${$fixedWidthStore[key] ?? 0}px`}
|
||||||
use:resizeObserver={resize}
|
use:resizeObserver={resize}
|
||||||
|
on:click
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,8 +69,8 @@
|
|||||||
}
|
}
|
||||||
&.small,
|
&.small,
|
||||||
&.small .icon-container {
|
&.small .icon-container {
|
||||||
width: calc(var(--status-bar-height) - 8px);
|
width: calc(var(--status-bar-normal-height) - 8px);
|
||||||
height: calc(var(--status-bar-height) - 8px);
|
height: calc(var(--status-bar-normal-height) - 8px);
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
}
|
}
|
||||||
&.small.selected {
|
&.small.selected {
|
||||||
|
@ -54,8 +54,8 @@
|
|||||||
height: 2rem;
|
height: 2rem;
|
||||||
}
|
}
|
||||||
&.mini {
|
&.mini {
|
||||||
width: 1.5rem;
|
width: 1.75rem;
|
||||||
height: 1.5rem;
|
height: 1.75rem;
|
||||||
}
|
}
|
||||||
&.red {
|
&.red {
|
||||||
background-color: rgb(246, 105, 77);
|
background-color: rgb(246, 105, 77);
|
||||||
|
@ -158,6 +158,7 @@
|
|||||||
const linkProviders = client.getModel().findAllSync(view.mixin.LinkIdProvider, {})
|
const linkProviders = client.getModel().findAllSync(view.mixin.LinkIdProvider, {})
|
||||||
|
|
||||||
$deviceInfo.navigator.visible = getMetadata(workbench.metadata.NavigationExpandedDefault) ?? true
|
$deviceInfo.navigator.visible = getMetadata(workbench.metadata.NavigationExpandedDefault) ?? true
|
||||||
|
$deviceInfo.aside.visible = getMetadata(workbench.metadata.NavigationExpandedDefault) ?? true
|
||||||
|
|
||||||
async function toggleNav (): Promise<void> {
|
async function toggleNav (): Promise<void> {
|
||||||
$deviceInfo.navigator.visible = !$deviceInfo.navigator.visible
|
$deviceInfo.navigator.visible = !$deviceInfo.navigator.visible
|
||||||
@ -635,10 +636,12 @@
|
|||||||
$: if ($deviceInfo.docWidth <= 1024 && !$deviceInfo.navigator.float) {
|
$: if ($deviceInfo.docWidth <= 1024 && !$deviceInfo.navigator.float) {
|
||||||
$deviceInfo.navigator.visible = false
|
$deviceInfo.navigator.visible = false
|
||||||
$deviceInfo.navigator.float = true
|
$deviceInfo.navigator.float = true
|
||||||
|
$deviceInfo.aside.visible = false
|
||||||
} else if ($deviceInfo.docWidth > 1024 && $deviceInfo.navigator.float) {
|
} else if ($deviceInfo.docWidth > 1024 && $deviceInfo.navigator.float) {
|
||||||
if (getMetadata(workbench.metadata.NavigationExpandedDefault) === undefined) {
|
if (getMetadata(workbench.metadata.NavigationExpandedDefault) === undefined) {
|
||||||
$deviceInfo.navigator.float = false
|
$deviceInfo.navigator.float = false
|
||||||
$deviceInfo.navigator.visible = true
|
$deviceInfo.navigator.visible = true
|
||||||
|
$deviceInfo.aside.visible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const checkOnHide = (): void => {
|
const checkOnHide = (): void => {
|
||||||
@ -975,13 +978,28 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if $sidebarStore.variant === SidebarVariant.EXPANDED}
|
{#if !$deviceInfo.navigator.float}
|
||||||
<Separator name={'main'} index={0} color={'transparent'} separatorSize={0} short />
|
{#if $sidebarStore.variant === SidebarVariant.EXPANDED}
|
||||||
|
<Separator name={'main'} index={0} color={'transparent'} separatorSize={0} short />
|
||||||
|
{/if}
|
||||||
|
<WidgetsBar />
|
||||||
{/if}
|
{/if}
|
||||||
<WidgetsBar />
|
|
||||||
</div>
|
</div>
|
||||||
<Dock />
|
<Dock />
|
||||||
<div bind:this={cover} class="cover" />
|
<div bind:this={cover} class="cover" />
|
||||||
|
{#if $deviceInfo.navigator.float}
|
||||||
|
<div
|
||||||
|
class="antiPanel-navigator right no-print {$deviceInfo.navigator.direction === 'horizontal'
|
||||||
|
? 'portrait'
|
||||||
|
: 'landscape'}"
|
||||||
|
style:display={$deviceInfo.aside.visible ? 'flex' : 'none'}
|
||||||
|
>
|
||||||
|
<Separator name={'main'} index={0} color={'transparent'} separatorSize={0} short float={'sidebar'} />
|
||||||
|
<div class="antiPanel-wrap__content hulyNavPanel-container">
|
||||||
|
<WidgetsBar />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<TooltipInstance />
|
<TooltipInstance />
|
||||||
<PanelInstance bind:this={panelInstance} contentPanel={elementPanel}>
|
<PanelInstance bind:this={panelInstance} contentPanel={elementPanel}>
|
||||||
<svelte:fragment slot="panel-header">
|
<svelte:fragment slot="panel-header">
|
||||||
@ -993,7 +1011,9 @@
|
|||||||
<ActionContext context={{ mode: 'popup' }} />
|
<ActionContext context={{ mode: 'popup' }} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</Popup>
|
</Popup>
|
||||||
<ComponentExtensions extension={workbench.extensions.WorkbenchExtensions} />
|
<div class="hidden max-w-0 max-h-0">
|
||||||
|
<ComponentExtensions extension={workbench.extensions.WorkbenchExtensions} />
|
||||||
|
</div>
|
||||||
<BrowserNotificatator />
|
<BrowserNotificatator />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -1071,11 +1091,11 @@
|
|||||||
}
|
}
|
||||||
.logo-container.mini {
|
.logo-container.mini {
|
||||||
left: 4px;
|
left: 4px;
|
||||||
width: 1.5rem;
|
width: 1.75rem;
|
||||||
height: 1.5rem;
|
height: 1.75rem;
|
||||||
}
|
}
|
||||||
.topmenu-container.mini {
|
.topmenu-container.mini {
|
||||||
left: calc(1.5rem + 8px);
|
left: calc(1.75rem + 8px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,26 +13,75 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createTab, tabsStore } from '../workbench'
|
import { createTab, tabsStore, tabIdStore } from '../workbench'
|
||||||
|
import { WorkbenchTabs } from '../index'
|
||||||
import WorkbenchTabPresenter from './WorkbenchTabPresenter.svelte'
|
import WorkbenchTabPresenter from './WorkbenchTabPresenter.svelte'
|
||||||
import { IconAdd, ButtonIcon } from '@hcengineering/ui'
|
import {
|
||||||
|
IconAdd,
|
||||||
|
IconMoreH,
|
||||||
|
ButtonIcon,
|
||||||
|
ScrollerBar,
|
||||||
|
deviceOptionsStore as deviceInfo,
|
||||||
|
checkAdaptiveMatching,
|
||||||
|
showPopup
|
||||||
|
} from '@hcengineering/ui'
|
||||||
|
|
||||||
|
export let popup: boolean = false
|
||||||
|
|
||||||
|
let scroller: HTMLElement
|
||||||
|
let element: HTMLButtonElement
|
||||||
|
let pressed: boolean = false
|
||||||
|
|
||||||
|
$: devSize = $deviceInfo.size
|
||||||
|
$: mini = checkAdaptiveMatching(devSize, 'md')
|
||||||
|
$: selectedTab = $tabsStore.find((ts) => ts._id === $tabIdStore)
|
||||||
|
|
||||||
|
const showTabs = (): void => {
|
||||||
|
pressed = true
|
||||||
|
showPopup(WorkbenchTabs, { popup: true }, element, () => {
|
||||||
|
pressed = false
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="root flex-gap-1">
|
<div
|
||||||
{#each $tabsStore as tab (tab._id)}
|
class={popup ? 'selectPopup' : 'flex-row-center flex-gap-2'}
|
||||||
<WorkbenchTabPresenter {tab} />
|
style:padding={popup ? '.5rem' : mini ? '.25rem .25rem .25rem 0' : '0 .25rem 0 0'}
|
||||||
{/each}
|
>
|
||||||
<div class="ml-1-5 plus-button mr-1">
|
{#if popup}
|
||||||
<ButtonIcon icon={IconAdd} size="min" kind="tertiary" on:click={createTab} />
|
<div class="scroll">
|
||||||
</div>
|
<div class="box flex-gap-1">
|
||||||
|
{#each $tabsStore.filter((ts) => ts._id !== $tabIdStore) as tab (tab._id)}
|
||||||
|
<WorkbenchTabPresenter {tab} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else if !mini}
|
||||||
|
<ScrollerBar bind:scroller padding={'.25rem 0'}>
|
||||||
|
{#each $tabsStore as tab (tab._id)}
|
||||||
|
<WorkbenchTabPresenter {tab} />
|
||||||
|
{/each}
|
||||||
|
</ScrollerBar>
|
||||||
|
{:else if selectedTab !== undefined}
|
||||||
|
<WorkbenchTabPresenter tab={selectedTab} />
|
||||||
|
<ButtonIcon
|
||||||
|
bind:element
|
||||||
|
icon={IconMoreH}
|
||||||
|
iconProps={{ fill: 'var(--theme-dark-color)' }}
|
||||||
|
size={'extra-small'}
|
||||||
|
kind={'tertiary'}
|
||||||
|
hasMenu
|
||||||
|
{pressed}
|
||||||
|
on:click={showTabs}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
{#if !popup}
|
||||||
|
<ButtonIcon
|
||||||
|
icon={IconAdd}
|
||||||
|
iconProps={{ fill: 'var(--theme-dark-color)' }}
|
||||||
|
size={'extra-small'}
|
||||||
|
kind={'tertiary'}
|
||||||
|
on:click={createTab}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.plus-button {
|
|
||||||
height: 0.875rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import { WidgetPreference, SidebarEvent, TxSidebarEvent, OpenSidebarWidgetParams } from '@hcengineering/workbench'
|
import { WidgetPreference, SidebarEvent, TxSidebarEvent, OpenSidebarWidgetParams } from '@hcengineering/workbench'
|
||||||
import { Tx } from '@hcengineering/core'
|
import { Tx } from '@hcengineering/core'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { panelstore } from '@hcengineering/ui'
|
import { panelstore, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||||
|
|
||||||
import workbench from '../../plugin'
|
import workbench from '../../plugin'
|
||||||
import { createWidgetTab, openWidget, sidebarStore, SidebarVariant } from '../../sidebar'
|
import { createWidgetTab, openWidget, sidebarStore, SidebarVariant } from '../../sidebar'
|
||||||
@ -61,7 +61,12 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="antiPanel-application vertical root" class:mini id="sidebar">
|
<div
|
||||||
|
id="sidebar"
|
||||||
|
class="antiPanel-application vertical sidebar-container"
|
||||||
|
class:mini
|
||||||
|
class:float={$deviceInfo.navigator.float}
|
||||||
|
>
|
||||||
{#if mini}
|
{#if mini}
|
||||||
<SidebarMini {widgets} {preferences} />
|
<SidebarMini {widgets} {preferences} />
|
||||||
{:else if $sidebarStore.variant === SidebarVariant.EXPANDED}
|
{:else if $sidebarStore.variant === SidebarVariant.EXPANDED}
|
||||||
@ -70,15 +75,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.root {
|
.sidebar-container {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
min-width: 25rem;
|
min-width: 25rem;
|
||||||
border-radius: 0 var(--medium-BorderRadius) var(--medium-BorderRadius) 0;
|
border-radius: 0 var(--medium-BorderRadius) var(--medium-BorderRadius) 0;
|
||||||
|
|
||||||
&.mini {
|
&.mini:not(.float) {
|
||||||
width: 3.5rem !important;
|
width: 3.5rem !important;
|
||||||
min-width: 3.5rem !important;
|
min-width: 3.5rem !important;
|
||||||
max-width: 3.5rem !important;
|
max-width: 3.5rem !important;
|
||||||
}
|
}
|
||||||
|
&.mini.float {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.sidebar-container {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--theme-navpanel-divider);
|
||||||
|
border-radius: var(--medium-BorderRadius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Widget, WidgetPreference, WidgetType } from '@hcengineering/workbench'
|
import { Widget, WidgetPreference, WidgetType } from '@hcengineering/workbench'
|
||||||
import { IconSettings, ModernButton, showPopup } from '@hcengineering/ui'
|
import { IconSettings, ModernButton, showPopup, deviceOptionsStore as deviceInfo } from '@hcengineering/ui'
|
||||||
import { Ref } from '@hcengineering/core'
|
import { Ref } from '@hcengineering/core'
|
||||||
|
|
||||||
import WidgetPresenter from './/WidgetPresenter.svelte'
|
import WidgetPresenter from './/WidgetPresenter.svelte'
|
||||||
@ -31,7 +31,8 @@
|
|||||||
|
|
||||||
function handleSelectWidget (widget: Widget): void {
|
function handleSelectWidget (widget: Widget): void {
|
||||||
if (selected === widget._id) {
|
if (selected === widget._id) {
|
||||||
minimizeSidebar(true)
|
if ($deviceInfo.navigator.float) $deviceInfo.aside.visible = false
|
||||||
|
else minimizeSidebar(true)
|
||||||
} else {
|
} else {
|
||||||
openWidget(widget, $sidebarStore.widgetsState.get(widget._id)?.data, { active: true, openedByUser: true })
|
openWidget(widget, $sidebarStore.widgetsState.get(widget._id)?.data, { active: true, openedByUser: true })
|
||||||
}
|
}
|
||||||
@ -100,6 +101,7 @@
|
|||||||
width: 3.5rem;
|
width: 3.5rem;
|
||||||
min-width: 3.5rem;
|
min-width: 3.5rem;
|
||||||
max-width: 3.5rem;
|
max-width: 3.5rem;
|
||||||
|
background-color: var(--theme-navpanel-color);
|
||||||
border-radius: 0 var(--medium-BorderRadius) var(--medium-BorderRadius) 0;
|
border-radius: 0 var(--medium-BorderRadius) var(--medium-BorderRadius) 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ export { default as NavHeader } from './components/NavHeader.svelte'
|
|||||||
export { default as SpecialElement } from './components/navigator/SpecialElement.svelte'
|
export { default as SpecialElement } from './components/navigator/SpecialElement.svelte'
|
||||||
export { default as SpaceView } from './components/SpaceView.svelte'
|
export { default as SpaceView } from './components/SpaceView.svelte'
|
||||||
export { default as TreeSeparator } from './components/navigator/TreeSeparator.svelte'
|
export { default as TreeSeparator } from './components/navigator/TreeSeparator.svelte'
|
||||||
|
export { default as WorkbenchTabs } from './components/WorkbenchTabs.svelte'
|
||||||
export { SpecialView }
|
export { SpecialView }
|
||||||
|
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
|
@ -23,7 +23,9 @@ export class TalentDetailsPage extends CommonRecruitingPage {
|
|||||||
|
|
||||||
readonly buttonFinalContact = (): Locator => this.formMergeContacts().locator('button', { hasText: 'Final contact' })
|
readonly buttonFinalContact = (): Locator => this.formMergeContacts().locator('button', { hasText: 'Final contact' })
|
||||||
|
|
||||||
readonly buttonMergeRow = (): Locator => this.formMergeContacts().locator('div.box')
|
readonly buttonMergeRow = (hasText: string): Locator =>
|
||||||
|
this.formMergeContacts().locator('div.box.flex-row-center div.antiRadio', { hasText }).locator('label')
|
||||||
|
|
||||||
readonly buttonPopupMergeContacts = (): Locator =>
|
readonly buttonPopupMergeContacts = (): Locator =>
|
||||||
this.formMergeContacts().locator('button:has-text("Merge contacts")')
|
this.formMergeContacts().locator('button:has-text("Merge contacts")')
|
||||||
|
|
||||||
@ -66,32 +68,17 @@ export class TalentDetailsPage extends CommonRecruitingPage {
|
|||||||
await this.buttonFinalContact().click()
|
await this.buttonFinalContact().click()
|
||||||
await this.selectMenuItem(this.page, talentName.finalContactName)
|
await this.selectMenuItem(this.page, talentName.finalContactName)
|
||||||
|
|
||||||
await expect(
|
await expect(this.buttonMergeRow(talentName.name)).toBeVisible()
|
||||||
this.buttonMergeRow().locator('div.flex-center', { hasText: talentName.name }).locator('label.checkbox-container')
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
await this.buttonMergeRow()
|
|
||||||
.locator('div.flex-center', { hasText: talentName.name })
|
|
||||||
.locator('label.checkbox-container')
|
|
||||||
.click()
|
|
||||||
|
|
||||||
|
await this.buttonMergeRow(talentName.name).click()
|
||||||
if (talentName.mergeLocation) {
|
if (talentName.mergeLocation) {
|
||||||
await this.buttonMergeRow()
|
await this.buttonMergeRow(talentName.location).click()
|
||||||
.locator('div.flex-center', { hasText: talentName.location })
|
|
||||||
.locator('label.checkbox-container')
|
|
||||||
.click()
|
|
||||||
}
|
}
|
||||||
if (talentName.mergeTitle) {
|
if (talentName.mergeTitle) {
|
||||||
await this.buttonMergeRow()
|
await this.buttonMergeRow(talentName.title).click()
|
||||||
.locator('div.flex-center', { hasText: talentName.title })
|
|
||||||
.locator('label.checkbox-container')
|
|
||||||
.click()
|
|
||||||
}
|
}
|
||||||
if (talentName.mergeSource) {
|
if (talentName.mergeSource) {
|
||||||
await this.buttonMergeRow()
|
await this.buttonMergeRow(talentName.source).click()
|
||||||
.locator('div.flex-center', { hasText: talentName.source })
|
|
||||||
.locator('label.checkbox-container')
|
|
||||||
.click()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.buttonPopupMergeContacts().click()
|
await this.buttonPopupMergeContacts().click()
|
||||||
|
Loading…
Reference in New Issue
Block a user