Fixed Planner layout and Separator (#5410)

Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
This commit is contained in:
Alexander Platov 2024-04-24 09:59:32 +03:00 committed by GitHub
parent d1c4e35eda
commit 128f5f55ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 133 additions and 52 deletions

View File

@ -152,6 +152,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
min-width: 0; min-width: 0;
min-height: 0;
} }
.hulyHeader-titleGroup { .hulyHeader-titleGroup {
flex-grow: 1; flex-grow: 1;

View File

@ -36,7 +36,9 @@
</button> </button>
{/if} {/if}
<slot name="beforeTitle" /> <slot name="beforeTitle" />
<div class="hulyHeader-divider" /> {#if !noResize || $$slots.beforeTitle}
<div class="hulyHeader-divider" />
{/if}
{/if} {/if}
<div class="hulyHeader-titleGroup"> <div class="hulyHeader-titleGroup">
<slot /> <slot />

View File

@ -54,7 +54,7 @@
let correctedIndex: number = index let correctedIndex: number = index
let offset: number = 0 let offset: number = 0
let separatorsSizes: number[] | null = null let separatorsSizes: number[] | null = null
const separatorsWide: { start: number, end: number, total: number } = { start: 0, end: 0, total: 0 } const separatorsWide: { before: number, after: number, total: number } = { before: 0, after: 0, total: 0 }
const containers: { minStart: number, minEnd: number, maxStart: number, maxEnd: number } = { const containers: { minStart: number, minEnd: number, maxStart: number, maxEnd: number } = {
minStart: -1, minStart: -1,
minEnd: -1, minEnd: -1,
@ -105,7 +105,8 @@
element.style.maxHeight = s element.style.maxHeight = s
element.style.height = s element.style.height = s
} }
const sizePx = direction === 'horizontal' ? element.clientWidth : element.clientHeight const rect = element.getBoundingClientRect()
const sizePx = direction === 'horizontal' ? rect.width : rect.height
element.setAttribute('data-size', `${sizePx}`) element.setAttribute('data-size', `${sizePx}`)
if (sState === SeparatorState.NORMAL) { if (sState === SeparatorState.NORMAL) {
if (separators) separators[index + (next ? 1 : 0)].size = pxToRem(sizePx) if (separators) separators[index + (next ? 1 : 0)].size = pxToRem(sizePx)
@ -146,7 +147,8 @@
.forEach((st) => styles.set(st.split(':')[0], st.split(':')[1])) .forEach((st) => styles.set(st.split(':')[0], st.split(':')[1]))
dropStyles.forEach((key) => styles.delete(key)) dropStyles.forEach((key) => styles.delete(key))
} }
const size = direction === 'horizontal' ? elements[i].clientWidth : elements[i].clientHeight const rect = element.getBoundingClientRect()
const size = direction === 'horizontal' ? rect.width : rect.height
if (separators) { if (separators) {
sm.push({ sm.push({
id: ind, id: ind,
@ -190,16 +192,17 @@
setSize(element, remToPx(props.size), next) setSize(element, remToPx(props.size), next)
return return
} }
const rect = element.getBoundingClientRect()
if (direction === 'horizontal') { if (direction === 'horizontal') {
element.style.minWidth = minSizePx element.style.minWidth = minSizePx
element.style.maxWidth = maxSizePx element.style.maxWidth = maxSizePx
element.style.width = sizePx element.style.width = sizePx
element.setAttribute('data-auto', `${element.clientWidth}`) element.setAttribute('data-auto', `${rect.width}`)
} else { } else {
element.style.minHeight = minSizePx element.style.minHeight = minSizePx
element.style.maxHeight = maxSizePx element.style.maxHeight = maxSizePx
element.style.height = sizePx element.style.height = sizePx
element.setAttribute('data-auto', `${element.clientHeight}`) element.setAttribute('data-auto', `${rect.height}`)
} }
} }
@ -233,6 +236,13 @@
} }
if (isSeparate) style += 'pointer-events:none;' if (isSeparate) style += 'pointer-events:none;'
item.element.setAttribute('style', style) item.element.setAttribute('style', style)
if (final) {
const rect = item.element.getBoundingClientRect()
item.element.setAttribute(
item.maxSize === -1 ? 'data-auto' : 'data-size',
`${direction === 'horizontal' ? rect.width : rect.height}`
)
}
item.resize = false item.resize = false
} }
}) })
@ -306,15 +316,19 @@
.filter((f) => f.begin) .filter((f) => f.begin)
.map((m) => m.size) .map((m) => m.size)
.reduce((prev, a) => prev + a, 0) .reduce((prev, a) => prev + a, 0)
for (let i = 0; i < correctedIndex; i++) prevCoord += separatorsSizes[i] prevCoord += separatorsWide.before
const startSizeMin = containers.minStart + separatorsWide.start const startSizeMin = containers.minStart + separatorsWide.before
const startSizeMax = containers.maxStart === -1 ? -1 : containers.maxStart + separatorsWide.start const startSizeMax = containers.maxStart === -1 ? -1 : containers.maxStart + separatorsWide.before
if (parentCoord <= startSizeMin) parentCoord = startSizeMin + 1 if (parentCoord <= startSizeMin) parentCoord = startSizeMin + 1
if (startSizeMax !== -1 && parentCoord > startSizeMax) parentCoord = startSizeMax if (startSizeMax !== -1 && parentCoord > startSizeMax) parentCoord = startSizeMax
const endSizeMin = containers.minEnd + separatorsWide.end const endSizeMin = containers.minEnd + separatorsWide.after
const endSizeMax = containers.maxEnd === -1 ? -1 : containers.maxEnd + separatorsWide.end const endSizeMax = containers.maxEnd === -1 ? -1 : containers.maxEnd + separatorsWide.after
if (parentCoord > parentSize.size - endSizeMin) parentCoord = parentSize.size - endSizeMin - 1 if (parentCoord > parentSize.size - endSizeMin - separatorSize) {
if (endSizeMax !== -1 && parentCoord < parentSize.size - endSizeMax) parentCoord = parentSize.size - endSizeMax - 1 parentCoord = parentSize.size - endSizeMin - separatorSize
}
if (endSizeMax !== -1 && parentCoord < parentSize.size - endSizeMax - separatorSize) {
parentCoord = parentSize.size - endSizeMax - separatorSize
}
const diff = prevCoord - parentCoord // + <- - -> const diff = prevCoord - parentCoord // + <- - ->
let remains = diff let remains = diff
if (remains !== 0) { if (remains !== 0) {
@ -427,6 +441,7 @@
? { start: p.left, end: p.right, size: p.width } ? { start: p.left, end: p.right, size: p.width }
: { start: p.top, end: p.bottom, size: p.height } : { start: p.top, end: p.bottom, size: p.height }
if (sState === SeparatorState.NORMAL) { if (sState === SeparatorState.NORMAL) {
calculateSeparators()
generateMap() generateMap()
applyStyles(true) applyStyles(true)
} else if (sState === SeparatorState.FLOAT) preparePanel() } else if (sState === SeparatorState.FLOAT) preparePanel()
@ -462,11 +477,75 @@
.filter((el) => el.classList.contains('antiSeparator')) .filter((el) => el.classList.contains('antiSeparator'))
.map((el) => parseInt(el.getAttribute('data-size') ?? '0', 10)) .map((el) => parseInt(el.getAttribute('data-size') ?? '0', 10))
separatorsWide.total = separatorsSizes.reduce((prev, a) => prev + a, 0) separatorsWide.total = separatorsSizes.reduce((prev, a) => prev + a, 0)
separatorsWide.start = separatorsSizes.slice(0, index).reduce((prev, a) => prev + a, 0) separatorsWide.before = separatorsSizes.slice(0, index).reduce((prev, a) => prev + a, 0)
separatorsWide.end = separatorsSizes.slice(index + 1, separatorsSizes.length).reduce((prev, a) => prev + a, 0) separatorsWide.after = separatorsSizes.slice(index + 1, separatorsSizes.length).reduce((prev, a) => prev + a, 0)
} }
} }
let checkElements: boolean = false
const resizeDocument = (): void => {
if (parentElement == null || checkElements || sState !== SeparatorState.NORMAL) return
checkElements = true
setTimeout(() => {
if (parentElement != null && separators) {
const children: Element[] = Array.from(parentElement.children)
let totalSize: number = 0
let ind: number = 0
const rects = new Map<number, { size: number, element: HTMLElement }>()
const hasSep: string[] = []
children.forEach((ch) => {
const rect = ch.getBoundingClientRect()
if (
!ch.classList.contains('antiSeparator') &&
(ch.hasAttribute('data-size') || ch.hasAttribute('data-auto'))
) {
rects.set(ind++, {
size: direction === 'horizontal' ? rect.width : rect.height,
element: ch as HTMLElement
})
}
if (ch.hasAttribute('data-float')) hasSep.push(ch.getAttribute('data-float') ?? '')
totalSize += direction === 'horizontal' ? rect.width : rect.height
})
const parentRect = parentElement.getBoundingClientRect()
let diff = totalSize - (direction === 'horizontal' ? parentRect.width : parentRect.height)
if (diff > 0) {
const excluded = separators
.filter((separ) => separ.float !== undefined && !hasSep.includes(separ.float))
.map((separ) => separ.float)
const reverseSep = [...separators].reverse()
let ind: number = 0
reverseSep.forEach((separ, i) => {
const pass = excluded.includes(separ.float)
if (diff > 0 && !pass && separators) {
const box = rects.get(reverseSep.length - ind - 1)
if (box) {
const minSize: number = remToPx(separ.minSize === 'auto' ? 20 : separ.minSize)
const forCrop = box.size - minSize
if (forCrop > 0) {
const newSize = forCrop - diff < 0 ? minSize : box.size - diff
diff -= forCrop
if (direction === 'horizontal') {
box.element.style.width = `${newSize}px`
box.element.style.minWidth = `${newSize}px`
box.element.style.maxWidth = `${newSize}px`
} else {
box.element.style.height = `${newSize}px`
box.element.style.minHeight = `${newSize}px`
box.element.style.maxHeight = `${newSize}px`
}
separators[separators.length - i - 1].size = newSize
}
}
ind++
}
})
}
}
checkElements = false
}, 100)
}
onMount(() => { onMount(() => {
if (separator) { if (separator) {
parentElement = separator.parentElement as HTMLElement parentElement = separator.parentElement as HTMLElement
@ -478,13 +557,13 @@
checkSizes() checkSizes()
mounted = true mounted = true
} }
document.addEventListener('resize', checkSizes) window.addEventListener('resize', resizeDocument)
if (sState !== SeparatorState.FLOAT && $separatorsStore.filter((f) => f === name).length === 0) { if (sState !== SeparatorState.FLOAT && $separatorsStore.filter((f) => f === name).length === 0) {
$separatorsStore = [...$separatorsStore, name] $separatorsStore = [...$separatorsStore, name]
} }
}) })
onDestroy(() => { onDestroy(() => {
document.removeEventListener('resize', checkSizes) window.removeEventListener('resize', resizeDocument)
if (sState !== SeparatorState.FLOAT && $separatorsStore.filter((f) => f === name).length > 0) { if (sState !== SeparatorState.FLOAT && $separatorsStore.filter((f) => f === name).length > 0) {
$separatorsStore = $separatorsStore.filter((f) => f !== name) $separatorsStore = $separatorsStore.filter((f) => f !== name)
} }

View File

@ -36,12 +36,13 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const defaultDuration = 30 * 60 * 1000 const defaultDuration = 30 * 60 * 1000
let mainPanel: HTMLElement
let replacedPanel: HTMLElement let replacedPanel: HTMLElement
let isVisiblePlannerNav: boolean = true
let currentDate: Date = new Date() let currentDate: Date = new Date()
$: dragItem = $dragging.item $: dragItem = $dragging.item
$: visibleCalendar = $deviceInfo.docWidth > 800
const client = getClient() const client = getClient()
@ -78,33 +79,32 @@
dispatch('change', true) dispatch('change', true)
afterUpdate(() => { afterUpdate(() => {
$deviceInfo.replacedPanel = replacedPanel $deviceInfo.replacedPanel = replacedPanel ?? mainPanel
}) })
</script> </script>
{#if visibleNav} {#if visibleNav}
{#if isVisiblePlannerNav} <ToDosNavigator bind:mode bind:tag bind:currentDate {navFloat} {appsDirection} />
<ToDosNavigator bind:mode bind:tag bind:currentDate {navFloat} {appsDirection} /> <Separator
<Separator name={'time'}
name={'time'} float={navFloat}
float={navFloat} index={0}
index={0} disabledWhen={['panel-aside']}
disabledWhen={['panel-aside']} color={'var(--theme-navpanel-border)'}
color={'var(--theme-navpanel-border)'}
/>
{/if}
<div class="flex-col clear-mins">
<ToDos {mode} {tag} bind:isVisiblePlannerNav bind:currentDate />
</div>
<Separator name={'time'} float={navFloat} index={1} color={'transparent'} separatorSize={0} short />
{/if}
<div class="w-full clear-mins" bind:this={replacedPanel}>
<PlanningCalendar
{dragItem}
{visibleNav}
bind:currentDate
displayedDaysCount={3}
on:dragDrop={drop}
on:change={(event) => (visibleNav = event.detail)}
/> />
{/if}
<div class="flex-col w-full clear-mins" class:left-divider={!visibleNav} bind:this={mainPanel}>
<ToDos {mode} {tag} bind:visibleNav bind:currentDate />
</div> </div>
{#if visibleCalendar}
<Separator name={'time'} index={1} color={'transparent'} separatorSize={0} short />
<div class="flex-col clear-mins" bind:this={replacedPanel}>
<PlanningCalendar
{dragItem}
bind:currentDate
displayedDaysCount={3}
on:dragDrop={drop}
on:change={(event) => (visibleNav = event.detail)}
/>
</div>
{/if}

View File

@ -29,7 +29,6 @@
export let currentDate: Date = new Date() export let currentDate: Date = new Date()
export let displayedDaysCount = 1 export let displayedDaysCount = 1
export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent export let createComponent: AnyComponent | undefined = calendar.component.CreateEvent
export let visibleNav: boolean = true
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const q = createQuery() const q = createQuery()
@ -174,10 +173,10 @@
showLabel = showLabel ? element.clientWidth > rem(3.5) + 399 : element.clientWidth > rem(3.5) + 400 showLabel = showLabel ? element.clientWidth > rem(3.5) + 399 : element.clientWidth > rem(3.5) + 400
}} }}
> >
<Header minimize={!visibleNav} on:resize={(event) => dispatch('change', event.detail)}> <Header noResize>
<span class="heading-medium-20 overflow-label"> <div class="heading-medium-20 line-height-auto overflow-label">
<Label label={time.string.Schedule} />: <Label label={getTitle(currentDate, $ticker)} /> <Label label={time.string.Schedule} />: <Label label={getTitle(currentDate, $ticker)} />
</span> </div>
<svelte:fragment slot="actions"> <svelte:fragment slot="actions">
<ButtonIcon <ButtonIcon
icon={IconChevronLeft} icon={IconChevronLeft}

View File

@ -38,7 +38,7 @@
export let mode: ToDosMode export let mode: ToDosMode
export let tag: Ref<TagElement> | undefined export let tag: Ref<TagElement> | undefined
export let currentDate: Date export let currentDate: Date
export let isVisiblePlannerNav: boolean = true export let visibleNav: boolean = true
const acc = getCurrentAccount() as PersonAccount const acc = getCurrentAccount() as PersonAccount
const user = acc.person const user = acc.person
@ -59,7 +59,7 @@
$: updateTags(mode, tag) $: updateTags(mode, tag)
function togglePlannerNav (): void { function togglePlannerNav (): void {
isVisiblePlannerNav = !isVisiblePlannerNav visibleNav = !visibleNav
} }
function updateTags (mode: ToDosMode, tag: Ref<TagElement> | undefined): void { function updateTags (mode: ToDosMode, tag: Ref<TagElement> | undefined): void {
@ -279,10 +279,10 @@
<div class="toDos-container"> <div class="toDos-container">
<Header type={'type-panel'} hideSeparator> <Header type={'type-panel'} hideSeparator>
<ButtonIcon <ButtonIcon
icon={isVisiblePlannerNav ? MenuClose : MenuOpen} icon={visibleNav ? MenuClose : MenuOpen}
kind={'tertiary'} kind={'tertiary'}
size={'small'} size={'small'}
pressed={!isVisiblePlannerNav} pressed={!visibleNav}
on:click={togglePlannerNav} on:click={togglePlannerNav}
/> />
<div class="heading-bold-20 ml-4"> <div class="heading-bold-20 ml-4">

View File

@ -23,8 +23,8 @@ export function getNearest (events: WorkSlot[]): WorkSlot | undefined {
*/ */
export const timeSeparators: DefSeparators = [ export const timeSeparators: DefSeparators = [
{ minSize: 18, size: 18, maxSize: 22.5, float: 'navigator' }, { minSize: 18, size: 18, maxSize: 22.5, float: 'navigator' },
{ minSize: 15, size: 35, maxSize: 45, float: 'planner' }, null,
null { minSize: 20, size: 41.25, maxSize: 50 }
] ]
/** /**