Fix UI. Update Scroller. (#2270)

Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
Alexander Platov 2022-09-16 05:59:16 +03:00 committed by GitHub
parent 13b6459c95
commit 719da02f7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 157 additions and 78 deletions

View File

@ -15,6 +15,7 @@
<script lang="ts">
import { setContext, onMount } from 'svelte'
import platform, { loadPluginStrings, setMetadata } from '@anticrm/platform'
import { themeStore as themeOptions } from './'
const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
const getCurrnetFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
@ -28,6 +29,9 @@
}
const setRootFontSize = (fontsize: string) => {
document.documentElement.setAttribute('class', `${getCurrentTheme()} ${fontsize}`)
themeOptions.update((opt) => {
return { ...opt, fontSize: fontsize === 'normal-font' ? 16 : 14 }
})
}
setContext('theme', {

View File

@ -14,5 +14,11 @@
//
import '@anticrm/platform-rig/profiles/ui/svelte'
import { writable } from 'svelte/store'
export { default as Theme } from './Theme.svelte'
export interface ThemeOptions {
fontSize: number
}
export const themeStore = writable<ThemeOptions>()

View File

@ -202,14 +202,6 @@
flex-shrink: 0;
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 */
.antiTitle {

View File

@ -81,7 +81,6 @@
function showActionPopup (action: Action, target: HTMLElement): void {
closePopup(category)
if (action.component !== undefined) {
console.log(action.props)
showPopup(
action.component,
action.props,

View File

@ -146,7 +146,7 @@
display: flex;
flex-direction: column;
justify-content: center;
max-height: calc(100vh - 2rem);
max-height: calc(100vh - 32px);
background-color: transparent;
&.anim {

View File

@ -15,13 +15,17 @@
<script lang="ts">
import { onDestroy, onMount } from 'svelte'
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 autoscroll: boolean = false
// export let correctPadding: number = 0
export let bottomStart: boolean = false
export let tableFade: boolean = false
export let fadeTopOffset: number = 40
export let fade: FadeOptions = defaultSP
// export let verticalFade: boolean = false
export let invertScroll: boolean = false
let mask: 'top' | 'bottom' | 'both' | 'none' = 'none'
@ -38,15 +42,16 @@
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 => {
if (divBar && divScroll) {
const trackH = divScroll.clientHeight - shift - 4
const trackH = divScroll.clientHeight - shiftTop - shiftBottom - 4
const scrollH = divScroll.scrollHeight
const proc = scrollH / trackH
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'
else {
divBar.style.visibility = 'visible'
@ -57,7 +62,7 @@
}
timer = setTimeout(() => {
if (divBar) divBar.style.opacity = '0'
}, 2000)
}, 1500)
}
}
if (divScroll.clientHeight >= divScroll.scrollHeight) divBar.style.visibility = 'hidden'
@ -69,11 +74,13 @@
if (isScrolling && divBar && divScroll) {
const rectScroll = divScroll.getBoundingClientRect()
let Y = event.clientY - dY
if (Y < rectScroll.top + shift + 2) Y = rectScroll.top + shift + 2
if (Y > rectScroll.bottom - divBar.clientHeight - 2) Y = rectScroll.bottom - divBar.clientHeight - 2
if (Y < rectScroll.top + shiftTop + 2) Y = rectScroll.top + shiftTop + 2
if (Y > rectScroll.bottom - divBar.clientHeight - shiftBottom - 2) {
Y = rectScroll.bottom - divBar.clientHeight - shiftBottom - 2
}
divBar.style.top = Y - rectScroll.y + 'px'
const topBar = Y - rectScroll.y - shift - 2
const heightScroll = rectScroll.height - 4 - divBar.clientHeight - shift
const topBar = Y - rectScroll.y - shiftTop - 2
const heightScroll = rectScroll.height - 4 - divBar.clientHeight - shiftTop - shiftBottom
const procBar = topBar / heightScroll
divScroll.scrollTop = (divScroll.scrollHeight - divScroll.clientHeight) * procBar
}
@ -146,21 +153,28 @@
let boxHeight: number
$: 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>
<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
bind:this={divScroll}
use:resizeObserver={(element) => {
divHeight = element.clientHeight
}}
class="scroll relative"
class:tableFade
class:antiNav-topFade={mask === 'top'}
class:antiNav-bottomFade={mask === 'bottom'}
class:antiNav-bothFade={mask === 'both'}
class:antiNav-noneFade={mask === 'none'}
class="scroll relative verticalFade"
>
<div
bind:this={divBox}
@ -182,7 +196,13 @@
on:mousedown={onScrollStart}
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>
<style lang="scss">
@ -193,6 +213,15 @@
height: 100%;
min-width: 0;
min-height: 0;
&.normal .track,
&.normal .bar {
right: 2px;
}
&.invert .track,
&.invert .bar {
left: 2px;
}
}
.scroll {
flex-grow: 1;
@ -204,6 +233,17 @@
&::-webkit-scrollbar:vertical {
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 {
display: flex;
@ -227,7 +267,6 @@
position: absolute;
top: 2px;
bottom: 2px;
right: 2px;
width: 8px;
transform-origin: center;
transform: scaleX(0);
@ -235,8 +274,11 @@
background-color: var(--scrollbar-track-color);
border-radius: 0.5rem;
&.tableFade {
top: 42px;
&.fadeTopOffset {
top: var(--scroller-header-height);
}
&.fadeBottomOffset {
top: var(--scroller-footer-height);
}
}
.bar {
@ -267,7 +309,6 @@
& + .track {
visibility: visible;
right: 2px;
transform: scaleX(1);
}
}

View File

@ -156,17 +156,18 @@ export function fitPopupPositionedElement (
newProps.maxWidth = newProps.width = ''
if (alignment?.kind === 'submenu') {
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 =
docHeight - rect.top - rectPopup.height - 16 > 0
docHeight - rect.top - rectPopup.height - 20 > 0
? 'bottom'
: rect.bottom > docHeight - rect.top
: rect.bottom > rectPopup.height + 20
? 'top'
: 'bottom'
if (dirH === 'right') newProps.left = `${rect.right - 4}px`
else newProps.right = `${docWidth - rect.left - 4}px`
if (dirV === 'bottom') newProps.top = `${rect.top - 4}px`
else newProps.bottom = `${docHeight - rect.bottom - 4}px`
direction = `${dirV}|${dirH}`
} else if (alignment.position !== undefined) {
if (alignment.position.v === 'top') {
newProps.top = `${rect.top}px`
@ -175,9 +176,9 @@ export function fitPopupPositionedElement (
}
if (alignment.position.h === 'right') {
newProps.left = `calc(${rect.right}px + .125rem)`
newProps.left = `${rect.right + 4}px`
} 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
} else {
@ -189,7 +190,7 @@ export function fitPopupPositionedElement (
newProps.bottom = `${document.body.clientHeight - rect.top + 1}px`
direction = 'top'
} else {
newProps.top = modalHTML.style.bottom = '1rem'
newProps.top = modalHTML.style.bottom = '16px'
direction = 'top'
}
@ -201,7 +202,7 @@ export function fitPopupPositionedElement (
newProps.right = `${docWidth - rect.right}px`
direction += '|left'
} else {
newProps.left = '1rem'
newProps.left = '16px'
direction += '|center'
}
}
@ -233,7 +234,7 @@ export function fitPopupElement (
return result
} else if (element === 'right' && contentPanel !== undefined) {
const rect = contentPanel.getBoundingClientRect()
newProps.top = `calc(${rect.top}px + 0.5rem)`
newProps.top = `calc(${rect.top}px + 8px)`
newProps.bottom = '0.75rem'
newProps.right = '0.75rem'
newProps.maxWidth = '50%'
@ -244,10 +245,10 @@ export function fitPopupElement (
newProps.transform = 'translateX(-50%)'
show = true
} else if (element === 'float') {
newProps.top = 'calc(var(--status-bar-height) + .25rem)'
newProps.bottom = '.25rem'
newProps.top = 'calc(var(--status-bar-height) + 4px)'
newProps.bottom = '4px'
newProps.left = '60%'
newProps.right = '.25rem'
newProps.right = '4px'
show = true
} else if (element === 'account') {
newProps.bottom = '2.75rem'
@ -263,9 +264,9 @@ export function fitPopupElement (
} else if (element === 'full' && contentPanel !== undefined) {
const rect = contentPanel.getBoundingClientRect()
newProps.top = `${rect.top + 1}px`
newProps.bottom = '.25rem'
newProps.left = '.25rem'
newProps.right = '.25rem'
newProps.bottom = '4px'
newProps.left = '4px'
newProps.right = '4px'
show = true
} else if (element === 'content' && contentPanel !== undefined) {
const rect = contentPanel.getBoundingClientRect()
@ -282,7 +283,7 @@ export function fitPopupElement (
} else {
newProps.top = '15%'
}
newProps.bottom = '0.75rem'
newProps.bottom = '12px'
newProps.left = '50%'
newProps.transform = 'translateX(-50%)'
}

View File

@ -200,3 +200,17 @@ export interface DashboardGroup {
value: 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 } }

View File

@ -325,11 +325,12 @@
.comment,
.mention {
position: relative;
margin-top: 0.25rem;
&::after {
content: '';
position: absolute;
bottom: -0.5rem;
bottom: -0.75rem;
left: -0.625rem;
right: -0.625rem;
background-color: var(--accent-bg-color);
@ -339,10 +340,10 @@
}
}
.comment::after {
top: -0.25rem;
top: -0.375rem;
}
.mention::after {
top: -0.625rem;
top: -0.5rem;
}
.msgactivity-container {
@ -351,7 +352,7 @@
}
.isNew {
padding-bottom: 0.25rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--highlight-red);
}

View File

@ -17,7 +17,7 @@
import type { Request, RequestType, Staff } from '@anticrm/hr'
import { getEmbeddedLabel } from '@anticrm/platform'
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 { Table, ViewletSettingButton } from '@anticrm/view-resources'
import hr from '../../plugin'
@ -196,7 +196,7 @@
</script>
{#if departmentStaff.length}
<Scroller tableFade>
<Scroller fade={tableSP}>
<div class="p-2">
{#if descr}
{#if loading}

View File

@ -28,6 +28,7 @@
Label,
LabelAndProps,
Scroller,
tableSP,
showPopup,
tooltip
} from '@anticrm/ui'
@ -103,7 +104,7 @@
</script>
{#if departmentStaff.length}
<Scroller tableFade>
<Scroller fade={tableSP}>
<table>
<thead class="scroller-thead">
<tr class="scroller-thead__tr">

View File

@ -17,7 +17,7 @@
import contact from '@anticrm/contact-resources/src/plugin'
import { Ref } from '@anticrm/core'
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 { fromTzDate, getMonth, getTotal, weekDays } from '../../utils'
import RequestsPopup from '../RequestsPopup.svelte'
@ -67,7 +67,7 @@
</script>
{#if departmentStaff.length}
<Scroller tableFade>
<Scroller fade={tableSP}>
<table>
<thead class="scroller-thead">
<tr class="scroller-thead__tr">

View File

@ -1,4 +1,5 @@
<script lang="ts">
import { createEventDispatcher, afterUpdate } from 'svelte'
import { Class, Doc, Ref, RelatedDocument } from '@anticrm/core'
import { getResource, IntlString, translate } from '@anticrm/platform'
import { createQuery, getClient, ObjectSearchPopup, ObjectSearchResult } from '@anticrm/presentation'
@ -10,6 +11,8 @@
export let value: Issue
const dispatch = createEventDispatcher()
const client = getClient()
const query = createQuery()
$: relations = {
@ -119,6 +122,10 @@
},
...(hasRelation ? removeRelationAction : [])
]
afterUpdate(() => dispatch('changeContent', true))
</script>
<Menu {actions} />
{#if actions}
<Menu {actions} on:changeContent={() => dispatch('changeContent', true)} />
{/if}

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { Scroller } from '@anticrm/ui'
import { Scroller, issueSP, defaultSP } from '@anticrm/ui'
import IssuesListBrowser from './IssuesListBrowser.svelte'
import tracker from '../../plugin'
import { Issue, IssueStatus, ViewOptions } from '@anticrm/tracker'
@ -68,7 +68,7 @@
</script>
<div class="w-full h-full clear-mins">
<Scroller tableFade={categories[0] !== undefined} fadeTopOffset={48}>
<Scroller fade={categories[0] !== undefined ? issueSP : defaultSP}>
<IssuesListBrowser
{_class}
{currentSpace}

View File

@ -18,7 +18,17 @@
import { FindOptions } from '@anticrm/core'
import presentation, { Card } from '@anticrm/presentation'
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 { createEventDispatcher } from 'svelte'
import tracker from '../../../plugin'
@ -75,7 +85,7 @@
</div>
<Label label={tracker.string.ChildEstimation} />:
<div class="h-50">
<Scroller tableFade>
<Scroller fade={tableSP}>
<TableBrowser
showFilterBar={false}
_class={tracker.class.Issue}
@ -91,7 +101,7 @@
</div>
<Label label={tracker.string.ReportedTime} />:
<div class="h-50">
<Scroller tableFade>
<Scroller fade={tableSP}>
<TableBrowser
_class={tracker.class.TimeSpendReport}
query={{ attachedTo: { $in: [object._id, ...childIds] } }}

View File

@ -17,7 +17,7 @@
import { FindOptions } from '@anticrm/core'
import presentation, { Card } from '@anticrm/presentation'
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 tracker from '../../../plugin'
import IssuePresenter from '../IssuePresenter.svelte'
@ -54,7 +54,7 @@
<IssuePresenter value={issue} disableClick />
</svelte:fragment>
<div class="h-50">
<Scroller tableFade>
<Scroller fade={tableSP}>
<TableBrowser
showFilterBar={false}
_class={tracker.class.TimeSpendReport}

View File

@ -14,7 +14,7 @@
-->
<script lang="ts">
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 { onMount } from 'svelte'
import { ActionContext } from '..'
@ -57,7 +57,7 @@
{#if showFilterBar}
<FilterBar {_class} {query} on:change={(e) => (resultQuery = e.detail)} />
{/if}
<Scroller tableFade>
<Scroller fade={tableSP}>
<Table
bind:this={table}
{_class}

View File

@ -17,6 +17,7 @@
import type { Application } from '@anticrm/workbench'
import { createEventDispatcher } from 'svelte'
import AppItem from './AppItem.svelte'
import { Scroller } from '@anticrm/ui'
export let active: Ref<Application> | undefined
export let apps: Application[] = []
@ -24,16 +25,18 @@
const dispatch = createEventDispatcher()
</script>
<div class="flex-col">
{#each apps as app}
<AppItem
selected={app._id === active}
icon={app.icon}
label={app.label}
action={async () => {
dispatch('active', app)
}}
notify={false}
/>
{/each}
<div class="flex-col align-center py-1">
<Scroller invertScroll padding={'.5rem .5rem'}>
{#each apps as app}
<AppItem
selected={app._id === active}
icon={app.icon}
label={app.label}
action={async () => {
dispatch('active', app)
}}
notify={false}
/>
{/each}
</Scroller>
</div>