mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 12:25:17 +00:00
Fix UI. Update Scroller. (#2270)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
13b6459c95
commit
719da02f7c
@ -15,6 +15,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { setContext, onMount } from 'svelte'
|
import { setContext, onMount } from 'svelte'
|
||||||
import platform, { loadPluginStrings, setMetadata } from '@anticrm/platform'
|
import platform, { loadPluginStrings, setMetadata } from '@anticrm/platform'
|
||||||
|
import { themeStore as themeOptions } from './'
|
||||||
|
|
||||||
const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
|
const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
|
||||||
const getCurrnetFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
|
const getCurrnetFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
|
||||||
@ -28,6 +29,9 @@
|
|||||||
}
|
}
|
||||||
const setRootFontSize = (fontsize: string) => {
|
const setRootFontSize = (fontsize: string) => {
|
||||||
document.documentElement.setAttribute('class', `${getCurrentTheme()} ${fontsize}`)
|
document.documentElement.setAttribute('class', `${getCurrentTheme()} ${fontsize}`)
|
||||||
|
themeOptions.update((opt) => {
|
||||||
|
return { ...opt, fontSize: fontsize === 'normal-font' ? 16 : 14 }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
setContext('theme', {
|
setContext('theme', {
|
||||||
|
@ -14,5 +14,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import '@anticrm/platform-rig/profiles/ui/svelte'
|
import '@anticrm/platform-rig/profiles/ui/svelte'
|
||||||
|
import { writable } from 'svelte/store'
|
||||||
|
|
||||||
export { default as Theme } from './Theme.svelte'
|
export { default as Theme } from './Theme.svelte'
|
||||||
|
|
||||||
|
export interface ThemeOptions {
|
||||||
|
fontSize: number
|
||||||
|
}
|
||||||
|
export const themeStore = writable<ThemeOptions>()
|
||||||
|
@ -202,14 +202,6 @@
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
.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%); }
|
|
||||||
.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-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% - var(--scroller-header-height, 2.5rem) - 2rem - 1px), rgba(0, 0, 0, 0) calc(100% - var(--scroller-header-height, 2.5rem)), rgba(0, 0, 0, 1) calc(100% - var(--scroller-header-height, 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% - var(--scroller-header-height, 2.5rem) - 2rem - 1px), rgba(0, 0, 0, 0) calc(100% - var(--scroller-header-height, 2.5rem)), rgba(0, 0, 0, 1) calc(100% - var(--scroller-header-height, 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 {
|
||||||
|
@ -81,7 +81,6 @@
|
|||||||
function showActionPopup (action: Action, target: HTMLElement): void {
|
function showActionPopup (action: Action, target: HTMLElement): void {
|
||||||
closePopup(category)
|
closePopup(category)
|
||||||
if (action.component !== undefined) {
|
if (action.component !== undefined) {
|
||||||
console.log(action.props)
|
|
||||||
showPopup(
|
showPopup(
|
||||||
action.component,
|
action.component,
|
||||||
action.props,
|
action.props,
|
||||||
|
@ -146,7 +146,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
max-height: calc(100vh - 2rem);
|
max-height: calc(100vh - 32px);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
|
||||||
&.anim {
|
&.anim {
|
||||||
|
@ -15,13 +15,17 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy, onMount } from 'svelte'
|
import { onDestroy, onMount } from 'svelte'
|
||||||
import { resizeObserver } from '../resize'
|
import { resizeObserver } from '../resize'
|
||||||
|
import { themeStore as themeOptions } from '@anticrm/theme'
|
||||||
|
import type { FadeOptions } from '../types'
|
||||||
|
import { defaultSP } from '../types'
|
||||||
|
|
||||||
export let padding: string | undefined = undefined
|
export let padding: string | undefined = undefined
|
||||||
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
|
export let fade: FadeOptions = defaultSP
|
||||||
export let fadeTopOffset: number = 40
|
// export let verticalFade: boolean = false
|
||||||
|
export let invertScroll: boolean = false
|
||||||
|
|
||||||
let mask: 'top' | 'bottom' | 'both' | 'none' = 'none'
|
let mask: 'top' | 'bottom' | 'both' | 'none' = 'none'
|
||||||
|
|
||||||
@ -38,15 +42,16 @@
|
|||||||
|
|
||||||
let timer: number
|
let timer: number
|
||||||
|
|
||||||
$: shift = tableFade ? fadeTopOffset : 0
|
$: shiftTop = fade.offset?.top ? (fade.multipler?.top ?? 0) * $themeOptions.fontSize : 0
|
||||||
|
$: shiftBottom = fade.offset?.bottom ? fade.multipler?.bottom! * $themeOptions.fontSize : 0
|
||||||
|
|
||||||
const checkBar = (): void => {
|
const checkBar = (): void => {
|
||||||
if (divBar && divScroll) {
|
if (divBar && divScroll) {
|
||||||
const trackH = divScroll.clientHeight - shift - 4
|
const trackH = divScroll.clientHeight - shiftTop - shiftBottom - 4
|
||||||
const scrollH = divScroll.scrollHeight
|
const scrollH = divScroll.scrollHeight
|
||||||
const proc = scrollH / trackH
|
const proc = scrollH / trackH
|
||||||
divBar.style.height = divScroll.clientHeight / proc + 'px'
|
divBar.style.height = divScroll.clientHeight / proc + 'px'
|
||||||
divBar.style.top = divScroll.scrollTop / proc + shift + 2 + 'px'
|
divBar.style.top = divScroll.scrollTop / proc + shiftTop + shiftBottom + 2 + 'px'
|
||||||
if (mask === 'none') divBar.style.visibility = 'hidden'
|
if (mask === 'none') divBar.style.visibility = 'hidden'
|
||||||
else {
|
else {
|
||||||
divBar.style.visibility = 'visible'
|
divBar.style.visibility = 'visible'
|
||||||
@ -57,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
timer = setTimeout(() => {
|
timer = setTimeout(() => {
|
||||||
if (divBar) divBar.style.opacity = '0'
|
if (divBar) divBar.style.opacity = '0'
|
||||||
}, 2000)
|
}, 1500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (divScroll.clientHeight >= divScroll.scrollHeight) divBar.style.visibility = 'hidden'
|
if (divScroll.clientHeight >= divScroll.scrollHeight) divBar.style.visibility = 'hidden'
|
||||||
@ -69,11 +74,13 @@
|
|||||||
if (isScrolling && divBar && divScroll) {
|
if (isScrolling && divBar && divScroll) {
|
||||||
const rectScroll = divScroll.getBoundingClientRect()
|
const rectScroll = divScroll.getBoundingClientRect()
|
||||||
let Y = event.clientY - dY
|
let Y = event.clientY - dY
|
||||||
if (Y < rectScroll.top + shift + 2) Y = rectScroll.top + shift + 2
|
if (Y < rectScroll.top + shiftTop + 2) Y = rectScroll.top + shiftTop + 2
|
||||||
if (Y > rectScroll.bottom - divBar.clientHeight - 2) Y = rectScroll.bottom - divBar.clientHeight - 2
|
if (Y > rectScroll.bottom - divBar.clientHeight - shiftBottom - 2) {
|
||||||
|
Y = rectScroll.bottom - divBar.clientHeight - shiftBottom - 2
|
||||||
|
}
|
||||||
divBar.style.top = Y - rectScroll.y + 'px'
|
divBar.style.top = Y - rectScroll.y + 'px'
|
||||||
const topBar = Y - rectScroll.y - shift - 2
|
const topBar = Y - rectScroll.y - shiftTop - 2
|
||||||
const heightScroll = rectScroll.height - 4 - divBar.clientHeight - shift
|
const heightScroll = rectScroll.height - 4 - divBar.clientHeight - shiftTop - shiftBottom
|
||||||
const procBar = topBar / heightScroll
|
const procBar = topBar / heightScroll
|
||||||
divScroll.scrollTop = (divScroll.scrollHeight - divScroll.clientHeight) * procBar
|
divScroll.scrollTop = (divScroll.scrollHeight - divScroll.clientHeight) * procBar
|
||||||
}
|
}
|
||||||
@ -146,21 +153,28 @@
|
|||||||
|
|
||||||
let boxHeight: number
|
let boxHeight: number
|
||||||
$: if (boxHeight) checkFade()
|
$: if (boxHeight) checkFade()
|
||||||
|
|
||||||
|
$: scrollerVars = `
|
||||||
|
--scroller-header-height: ${
|
||||||
|
(fade.multipler && fade.multipler.top ? fade.multipler.top : 0) * $themeOptions.fontSize
|
||||||
|
}px;
|
||||||
|
--scroller-footer-height: ${
|
||||||
|
(fade.multipler && fade.multipler.bottom ? fade.multipler.bottom : 0) * $themeOptions.fontSize
|
||||||
|
}px;
|
||||||
|
--scroller-header-fade: ${mask === 'none' || mask === 'top' ? '0px' : '2rem'};
|
||||||
|
--scroller-footer-fade: ${mask === 'none' || mask === 'bottom' ? '0px' : '2rem'};
|
||||||
|
`
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:resize={_resize} />
|
<svelte:window on:resize={_resize} />
|
||||||
<div class="scroller-container" class:bottomStart style="--scroller-header-height: {shift}px;">
|
|
||||||
|
<div class="scroller-container {invertScroll ? 'invert' : 'normal'}" class:bottomStart style={scrollerVars}>
|
||||||
<div
|
<div
|
||||||
bind:this={divScroll}
|
bind:this={divScroll}
|
||||||
use:resizeObserver={(element) => {
|
use:resizeObserver={(element) => {
|
||||||
divHeight = element.clientHeight
|
divHeight = element.clientHeight
|
||||||
}}
|
}}
|
||||||
class="scroll relative"
|
class="scroll relative verticalFade"
|
||||||
class:tableFade
|
|
||||||
class:antiNav-topFade={mask === 'top'}
|
|
||||||
class:antiNav-bottomFade={mask === 'bottom'}
|
|
||||||
class:antiNav-bothFade={mask === 'both'}
|
|
||||||
class:antiNav-noneFade={mask === 'none'}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
bind:this={divBox}
|
bind:this={divBox}
|
||||||
@ -182,7 +196,13 @@
|
|||||||
on:mousedown={onScrollStart}
|
on:mousedown={onScrollStart}
|
||||||
on:mouseleave={checkFade}
|
on:mouseleave={checkFade}
|
||||||
/>
|
/>
|
||||||
<div class="track" class:hovered={isScrolling} class:tableFade bind:this={divTrack} />
|
<div
|
||||||
|
class="track"
|
||||||
|
class:hovered={isScrolling}
|
||||||
|
class:fadeTopOffset={fade.offset?.top}
|
||||||
|
class:fadeBottomOffset={fade.offset?.bottom}
|
||||||
|
bind:this={divTrack}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -193,6 +213,15 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
|
||||||
|
&.normal .track,
|
||||||
|
&.normal .bar {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
&.invert .track,
|
||||||
|
&.invert .bar {
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.scroll {
|
.scroll {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
@ -204,6 +233,17 @@
|
|||||||
&::-webkit-scrollbar:vertical {
|
&::-webkit-scrollbar:vertical {
|
||||||
width: 0;
|
width: 0;
|
||||||
}
|
}
|
||||||
|
&.verticalFade {
|
||||||
|
mask-image: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(0, 0, 0, 1) calc(var(--scroller-footer-height, 2.5rem)),
|
||||||
|
rgba(0, 0, 0, 0) calc(var(--scroller-footer-height, 2.5rem)),
|
||||||
|
rgba(0, 0, 0, 1) calc(var(--scroller-footer-height, 2.5rem) + var(--scroller-footer-fade, 0) + 1px),
|
||||||
|
rgba(0, 0, 0, 1) calc(100% - var(--scroller-header-height, 0) - var(--scroller-header-fade, 0) - 1px),
|
||||||
|
rgba(0, 0, 0, 0) calc(100% - var(--scroller-header-height, 0)),
|
||||||
|
rgba(0, 0, 0, 1) calc(100% - var(--scroller-header-height, 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.box {
|
.box {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -227,7 +267,6 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
bottom: 2px;
|
bottom: 2px;
|
||||||
right: 2px;
|
|
||||||
width: 8px;
|
width: 8px;
|
||||||
transform-origin: center;
|
transform-origin: center;
|
||||||
transform: scaleX(0);
|
transform: scaleX(0);
|
||||||
@ -235,8 +274,11 @@
|
|||||||
background-color: var(--scrollbar-track-color);
|
background-color: var(--scrollbar-track-color);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
&.tableFade {
|
&.fadeTopOffset {
|
||||||
top: 42px;
|
top: var(--scroller-header-height);
|
||||||
|
}
|
||||||
|
&.fadeBottomOffset {
|
||||||
|
top: var(--scroller-footer-height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.bar {
|
.bar {
|
||||||
@ -267,7 +309,6 @@
|
|||||||
|
|
||||||
& + .track {
|
& + .track {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
right: 2px;
|
|
||||||
transform: scaleX(1);
|
transform: scaleX(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,17 +156,18 @@ export function fitPopupPositionedElement (
|
|||||||
newProps.maxWidth = newProps.width = ''
|
newProps.maxWidth = newProps.width = ''
|
||||||
if (alignment?.kind === 'submenu') {
|
if (alignment?.kind === 'submenu') {
|
||||||
const dirH =
|
const dirH =
|
||||||
docWidth - rect.right - rectPopup.width - 16 > 0 ? 'right' : rect.left > docWidth - rect.right ? 'left' : 'right'
|
docWidth - rect.right - rectPopup.width - 12 > 0 ? 'right' : rect.left > docWidth - rect.left ? 'left' : 'right'
|
||||||
const dirV =
|
const dirV =
|
||||||
docHeight - rect.top - rectPopup.height - 16 > 0
|
docHeight - rect.top - rectPopup.height - 20 > 0
|
||||||
? 'bottom'
|
? 'bottom'
|
||||||
: rect.bottom > docHeight - rect.top
|
: rect.bottom > rectPopup.height + 20
|
||||||
? 'top'
|
? 'top'
|
||||||
: 'bottom'
|
: 'bottom'
|
||||||
if (dirH === 'right') newProps.left = `${rect.right - 4}px`
|
if (dirH === 'right') newProps.left = `${rect.right - 4}px`
|
||||||
else newProps.right = `${docWidth - rect.left - 4}px`
|
else newProps.right = `${docWidth - rect.left - 4}px`
|
||||||
if (dirV === 'bottom') newProps.top = `${rect.top - 4}px`
|
if (dirV === 'bottom') newProps.top = `${rect.top - 4}px`
|
||||||
else newProps.bottom = `${docHeight - rect.bottom - 4}px`
|
else newProps.bottom = `${docHeight - rect.bottom - 4}px`
|
||||||
|
direction = `${dirV}|${dirH}`
|
||||||
} else if (alignment.position !== undefined) {
|
} else if (alignment.position !== undefined) {
|
||||||
if (alignment.position.v === 'top') {
|
if (alignment.position.v === 'top') {
|
||||||
newProps.top = `${rect.top}px`
|
newProps.top = `${rect.top}px`
|
||||||
@ -175,9 +176,9 @@ export function fitPopupPositionedElement (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (alignment.position.h === 'right') {
|
if (alignment.position.h === 'right') {
|
||||||
newProps.left = `calc(${rect.right}px + .125rem)`
|
newProps.left = `${rect.right + 4}px`
|
||||||
} else if (alignment.position.h === 'left') {
|
} else if (alignment.position.h === 'left') {
|
||||||
newProps.left = `calc(${rect.left - rectPopup.width}px - .125rem)`
|
newProps.left = `${rect.left - rectPopup.width - 4}px`
|
||||||
}
|
}
|
||||||
direction = alignment.position.v + '|' + alignment.position.h
|
direction = alignment.position.v + '|' + alignment.position.h
|
||||||
} else {
|
} else {
|
||||||
@ -189,7 +190,7 @@ export function fitPopupPositionedElement (
|
|||||||
newProps.bottom = `${document.body.clientHeight - rect.top + 1}px`
|
newProps.bottom = `${document.body.clientHeight - rect.top + 1}px`
|
||||||
direction = 'top'
|
direction = 'top'
|
||||||
} else {
|
} else {
|
||||||
newProps.top = modalHTML.style.bottom = '1rem'
|
newProps.top = modalHTML.style.bottom = '16px'
|
||||||
direction = 'top'
|
direction = 'top'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +202,7 @@ export function fitPopupPositionedElement (
|
|||||||
newProps.right = `${docWidth - rect.right}px`
|
newProps.right = `${docWidth - rect.right}px`
|
||||||
direction += '|left'
|
direction += '|left'
|
||||||
} else {
|
} else {
|
||||||
newProps.left = '1rem'
|
newProps.left = '16px'
|
||||||
direction += '|center'
|
direction += '|center'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,7 +234,7 @@ export function fitPopupElement (
|
|||||||
return result
|
return result
|
||||||
} else if (element === 'right' && contentPanel !== undefined) {
|
} else if (element === 'right' && contentPanel !== undefined) {
|
||||||
const rect = contentPanel.getBoundingClientRect()
|
const rect = contentPanel.getBoundingClientRect()
|
||||||
newProps.top = `calc(${rect.top}px + 0.5rem)`
|
newProps.top = `calc(${rect.top}px + 8px)`
|
||||||
newProps.bottom = '0.75rem'
|
newProps.bottom = '0.75rem'
|
||||||
newProps.right = '0.75rem'
|
newProps.right = '0.75rem'
|
||||||
newProps.maxWidth = '50%'
|
newProps.maxWidth = '50%'
|
||||||
@ -244,10 +245,10 @@ export function fitPopupElement (
|
|||||||
newProps.transform = 'translateX(-50%)'
|
newProps.transform = 'translateX(-50%)'
|
||||||
show = true
|
show = true
|
||||||
} else if (element === 'float') {
|
} else if (element === 'float') {
|
||||||
newProps.top = 'calc(var(--status-bar-height) + .25rem)'
|
newProps.top = 'calc(var(--status-bar-height) + 4px)'
|
||||||
newProps.bottom = '.25rem'
|
newProps.bottom = '4px'
|
||||||
newProps.left = '60%'
|
newProps.left = '60%'
|
||||||
newProps.right = '.25rem'
|
newProps.right = '4px'
|
||||||
show = true
|
show = true
|
||||||
} else if (element === 'account') {
|
} else if (element === 'account') {
|
||||||
newProps.bottom = '2.75rem'
|
newProps.bottom = '2.75rem'
|
||||||
@ -263,9 +264,9 @@ export function fitPopupElement (
|
|||||||
} else if (element === 'full' && contentPanel !== undefined) {
|
} else if (element === 'full' && contentPanel !== undefined) {
|
||||||
const rect = contentPanel.getBoundingClientRect()
|
const rect = contentPanel.getBoundingClientRect()
|
||||||
newProps.top = `${rect.top + 1}px`
|
newProps.top = `${rect.top + 1}px`
|
||||||
newProps.bottom = '.25rem'
|
newProps.bottom = '4px'
|
||||||
newProps.left = '.25rem'
|
newProps.left = '4px'
|
||||||
newProps.right = '.25rem'
|
newProps.right = '4px'
|
||||||
show = true
|
show = true
|
||||||
} else if (element === 'content' && contentPanel !== undefined) {
|
} else if (element === 'content' && contentPanel !== undefined) {
|
||||||
const rect = contentPanel.getBoundingClientRect()
|
const rect = contentPanel.getBoundingClientRect()
|
||||||
@ -282,7 +283,7 @@ export function fitPopupElement (
|
|||||||
} else {
|
} else {
|
||||||
newProps.top = '15%'
|
newProps.top = '15%'
|
||||||
}
|
}
|
||||||
newProps.bottom = '0.75rem'
|
newProps.bottom = '12px'
|
||||||
newProps.left = '50%'
|
newProps.left = '50%'
|
||||||
newProps.transform = 'translateX(-50%)'
|
newProps.transform = 'translateX(-50%)'
|
||||||
}
|
}
|
||||||
|
@ -200,3 +200,17 @@ export interface DashboardGroup {
|
|||||||
value: number
|
value: number
|
||||||
color: number
|
color: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Sides<T> {
|
||||||
|
top?: T
|
||||||
|
bottom?: T
|
||||||
|
left?: T
|
||||||
|
right?: T
|
||||||
|
}
|
||||||
|
export interface FadeOptions {
|
||||||
|
offset?: Sides<boolean>
|
||||||
|
multipler?: Sides<number>
|
||||||
|
}
|
||||||
|
export const defaultSP: FadeOptions = { multipler: { top: 0, bottom: 0 } }
|
||||||
|
export const tableSP: FadeOptions = { offset: { top: true }, multipler: { top: 2.5, bottom: 0 } }
|
||||||
|
export const issueSP: FadeOptions = { offset: { top: true }, multipler: { top: 3, bottom: 0 } }
|
||||||
|
@ -325,11 +325,12 @@
|
|||||||
.comment,
|
.comment,
|
||||||
.mention {
|
.mention {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: -0.5rem;
|
bottom: -0.75rem;
|
||||||
left: -0.625rem;
|
left: -0.625rem;
|
||||||
right: -0.625rem;
|
right: -0.625rem;
|
||||||
background-color: var(--accent-bg-color);
|
background-color: var(--accent-bg-color);
|
||||||
@ -339,10 +340,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.comment::after {
|
.comment::after {
|
||||||
top: -0.25rem;
|
top: -0.375rem;
|
||||||
}
|
}
|
||||||
.mention::after {
|
.mention::after {
|
||||||
top: -0.625rem;
|
top: -0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.msgactivity-container {
|
.msgactivity-container {
|
||||||
@ -351,7 +352,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.isNew {
|
.isNew {
|
||||||
padding-bottom: 0.25rem;
|
padding-bottom: 0.5rem;
|
||||||
border-bottom: 1px solid var(--highlight-red);
|
border-bottom: 1px solid var(--highlight-red);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import type { Request, RequestType, Staff } from '@anticrm/hr'
|
import type { Request, RequestType, Staff } from '@anticrm/hr'
|
||||||
import { getEmbeddedLabel } from '@anticrm/platform'
|
import { getEmbeddedLabel } from '@anticrm/platform'
|
||||||
import { createQuery, getClient } from '@anticrm/presentation'
|
import { createQuery, getClient } from '@anticrm/presentation'
|
||||||
import { Button, Label, Loading, Scroller } from '@anticrm/ui'
|
import { Button, Label, Loading, Scroller, tableSP } from '@anticrm/ui'
|
||||||
import view, { BuildModelKey, Viewlet, ViewletPreference } from '@anticrm/view'
|
import view, { BuildModelKey, Viewlet, ViewletPreference } from '@anticrm/view'
|
||||||
import { Table, ViewletSettingButton } from '@anticrm/view-resources'
|
import { Table, ViewletSettingButton } from '@anticrm/view-resources'
|
||||||
import hr from '../../plugin'
|
import hr from '../../plugin'
|
||||||
@ -196,7 +196,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if departmentStaff.length}
|
{#if departmentStaff.length}
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
{#if descr}
|
{#if descr}
|
||||||
{#if loading}
|
{#if loading}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
Label,
|
Label,
|
||||||
LabelAndProps,
|
LabelAndProps,
|
||||||
Scroller,
|
Scroller,
|
||||||
|
tableSP,
|
||||||
showPopup,
|
showPopup,
|
||||||
tooltip
|
tooltip
|
||||||
} from '@anticrm/ui'
|
} from '@anticrm/ui'
|
||||||
@ -103,7 +104,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if departmentStaff.length}
|
{#if departmentStaff.length}
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<table>
|
<table>
|
||||||
<thead class="scroller-thead">
|
<thead class="scroller-thead">
|
||||||
<tr class="scroller-thead__tr">
|
<tr class="scroller-thead__tr">
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import contact from '@anticrm/contact-resources/src/plugin'
|
import contact from '@anticrm/contact-resources/src/plugin'
|
||||||
import { Ref } from '@anticrm/core'
|
import { Ref } from '@anticrm/core'
|
||||||
import type { Request, RequestType, Staff } from '@anticrm/hr'
|
import type { Request, RequestType, Staff } from '@anticrm/hr'
|
||||||
import { Label, LabelAndProps, Scroller, tooltip } from '@anticrm/ui'
|
import { Label, LabelAndProps, Scroller, tableSP, tooltip } from '@anticrm/ui'
|
||||||
import hr from '../../plugin'
|
import hr from '../../plugin'
|
||||||
import { fromTzDate, getMonth, getTotal, weekDays } from '../../utils'
|
import { fromTzDate, getMonth, getTotal, weekDays } from '../../utils'
|
||||||
import RequestsPopup from '../RequestsPopup.svelte'
|
import RequestsPopup from '../RequestsPopup.svelte'
|
||||||
@ -67,7 +67,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if departmentStaff.length}
|
{#if departmentStaff.length}
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<table>
|
<table>
|
||||||
<thead class="scroller-thead">
|
<thead class="scroller-thead">
|
||||||
<tr class="scroller-thead__tr">
|
<tr class="scroller-thead__tr">
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, afterUpdate } from 'svelte'
|
||||||
import { Class, Doc, Ref, RelatedDocument } from '@anticrm/core'
|
import { Class, Doc, Ref, RelatedDocument } from '@anticrm/core'
|
||||||
import { getResource, IntlString, translate } from '@anticrm/platform'
|
import { getResource, IntlString, translate } from '@anticrm/platform'
|
||||||
import { createQuery, getClient, ObjectSearchPopup, ObjectSearchResult } from '@anticrm/presentation'
|
import { createQuery, getClient, ObjectSearchPopup, ObjectSearchResult } from '@anticrm/presentation'
|
||||||
@ -10,6 +11,8 @@
|
|||||||
|
|
||||||
export let value: Issue
|
export let value: Issue
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
const client = getClient()
|
const client = getClient()
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
$: relations = {
|
$: relations = {
|
||||||
@ -119,6 +122,10 @@
|
|||||||
},
|
},
|
||||||
...(hasRelation ? removeRelationAction : [])
|
...(hasRelation ? removeRelationAction : [])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
afterUpdate(() => dispatch('changeContent', true))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Menu {actions} />
|
{#if actions}
|
||||||
|
<Menu {actions} on:changeContent={() => dispatch('changeContent', true)} />
|
||||||
|
{/if}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Scroller } from '@anticrm/ui'
|
import { Scroller, issueSP, defaultSP } from '@anticrm/ui'
|
||||||
import IssuesListBrowser from './IssuesListBrowser.svelte'
|
import IssuesListBrowser from './IssuesListBrowser.svelte'
|
||||||
import tracker from '../../plugin'
|
import tracker from '../../plugin'
|
||||||
import { Issue, IssueStatus, ViewOptions } from '@anticrm/tracker'
|
import { Issue, IssueStatus, ViewOptions } from '@anticrm/tracker'
|
||||||
@ -68,7 +68,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-full h-full clear-mins">
|
<div class="w-full h-full clear-mins">
|
||||||
<Scroller tableFade={categories[0] !== undefined} fadeTopOffset={48}>
|
<Scroller fade={categories[0] !== undefined ? issueSP : defaultSP}>
|
||||||
<IssuesListBrowser
|
<IssuesListBrowser
|
||||||
{_class}
|
{_class}
|
||||||
{currentSpace}
|
{currentSpace}
|
||||||
|
@ -18,7 +18,17 @@
|
|||||||
import { FindOptions } from '@anticrm/core'
|
import { FindOptions } from '@anticrm/core'
|
||||||
import presentation, { Card } from '@anticrm/presentation'
|
import presentation, { Card } from '@anticrm/presentation'
|
||||||
import { Issue, TimeSpendReport } from '@anticrm/tracker'
|
import { Issue, TimeSpendReport } from '@anticrm/tracker'
|
||||||
import { Button, EditBox, EditStyle, eventToHTMLElement, IconAdd, Label, Scroller, showPopup } from '@anticrm/ui'
|
import {
|
||||||
|
Button,
|
||||||
|
EditBox,
|
||||||
|
EditStyle,
|
||||||
|
eventToHTMLElement,
|
||||||
|
IconAdd,
|
||||||
|
Label,
|
||||||
|
Scroller,
|
||||||
|
tableSP,
|
||||||
|
showPopup
|
||||||
|
} from '@anticrm/ui'
|
||||||
import { TableBrowser } from '@anticrm/view-resources'
|
import { TableBrowser } from '@anticrm/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
@ -75,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<Label label={tracker.string.ChildEstimation} />:
|
<Label label={tracker.string.ChildEstimation} />:
|
||||||
<div class="h-50">
|
<div class="h-50">
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<TableBrowser
|
<TableBrowser
|
||||||
showFilterBar={false}
|
showFilterBar={false}
|
||||||
_class={tracker.class.Issue}
|
_class={tracker.class.Issue}
|
||||||
@ -91,7 +101,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<Label label={tracker.string.ReportedTime} />:
|
<Label label={tracker.string.ReportedTime} />:
|
||||||
<div class="h-50">
|
<div class="h-50">
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<TableBrowser
|
<TableBrowser
|
||||||
_class={tracker.class.TimeSpendReport}
|
_class={tracker.class.TimeSpendReport}
|
||||||
query={{ attachedTo: { $in: [object._id, ...childIds] } }}
|
query={{ attachedTo: { $in: [object._id, ...childIds] } }}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import { FindOptions } from '@anticrm/core'
|
import { FindOptions } from '@anticrm/core'
|
||||||
import presentation, { Card } from '@anticrm/presentation'
|
import presentation, { Card } from '@anticrm/presentation'
|
||||||
import { Issue, TimeSpendReport } from '@anticrm/tracker'
|
import { Issue, TimeSpendReport } from '@anticrm/tracker'
|
||||||
import { Button, eventToHTMLElement, IconAdd, Scroller, showPopup } from '@anticrm/ui'
|
import { Button, eventToHTMLElement, IconAdd, Scroller, tableSP, showPopup } from '@anticrm/ui'
|
||||||
import { TableBrowser } from '@anticrm/view-resources'
|
import { TableBrowser } from '@anticrm/view-resources'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import IssuePresenter from '../IssuePresenter.svelte'
|
import IssuePresenter from '../IssuePresenter.svelte'
|
||||||
@ -54,7 +54,7 @@
|
|||||||
<IssuePresenter value={issue} disableClick />
|
<IssuePresenter value={issue} disableClick />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<div class="h-50">
|
<div class="h-50">
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<TableBrowser
|
<TableBrowser
|
||||||
showFilterBar={false}
|
showFilterBar={false}
|
||||||
_class={tracker.class.TimeSpendReport}
|
_class={tracker.class.TimeSpendReport}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
import type { Class, Doc, DocumentQuery, FindOptions, Ref } from '@anticrm/core'
|
||||||
import { Scroller } from '@anticrm/ui'
|
import { Scroller, tableSP } from '@anticrm/ui'
|
||||||
import { BuildModelKey } from '@anticrm/view'
|
import { BuildModelKey } from '@anticrm/view'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { ActionContext } from '..'
|
import { ActionContext } from '..'
|
||||||
@ -57,7 +57,7 @@
|
|||||||
{#if showFilterBar}
|
{#if showFilterBar}
|
||||||
<FilterBar {_class} {query} on:change={(e) => (resultQuery = e.detail)} />
|
<FilterBar {_class} {query} on:change={(e) => (resultQuery = e.detail)} />
|
||||||
{/if}
|
{/if}
|
||||||
<Scroller tableFade>
|
<Scroller fade={tableSP}>
|
||||||
<Table
|
<Table
|
||||||
bind:this={table}
|
bind:this={table}
|
||||||
{_class}
|
{_class}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import type { Application } from '@anticrm/workbench'
|
import type { Application } from '@anticrm/workbench'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import AppItem from './AppItem.svelte'
|
import AppItem from './AppItem.svelte'
|
||||||
|
import { Scroller } from '@anticrm/ui'
|
||||||
|
|
||||||
export let active: Ref<Application> | undefined
|
export let active: Ref<Application> | undefined
|
||||||
export let apps: Application[] = []
|
export let apps: Application[] = []
|
||||||
@ -24,16 +25,18 @@
|
|||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex-col">
|
<div class="flex-col align-center py-1">
|
||||||
{#each apps as app}
|
<Scroller invertScroll padding={'.5rem .5rem'}>
|
||||||
<AppItem
|
{#each apps as app}
|
||||||
selected={app._id === active}
|
<AppItem
|
||||||
icon={app.icon}
|
selected={app._id === active}
|
||||||
label={app.label}
|
icon={app.icon}
|
||||||
action={async () => {
|
label={app.label}
|
||||||
dispatch('active', app)
|
action={async () => {
|
||||||
}}
|
dispatch('active', app)
|
||||||
notify={false}
|
}}
|
||||||
/>
|
notify={false}
|
||||||
{/each}
|
/>
|
||||||
|
{/each}
|
||||||
|
</Scroller>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user