platform/packages/ui/src/components/Panel.svelte
Alexander Platov 71e2fc5453
Updated Header layout (#6298)
Signed-off-by: Alexander Platov <alexander.platov@hardcoreeng.com>
2024-08-09 11:49:40 +07:00

314 lines
8.9 KiB
Svelte

<!--
// Copyright © 2022, 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { afterUpdate, createEventDispatcher, onMount } from 'svelte'
import {
deviceOptionsStore as deviceInfo,
Separator,
defineSeparators,
resizeObserver,
Button,
ButtonGroup,
Scroller,
panelSeparators,
ButtonItem,
Header,
HeaderAdaptive
} from '../../'
import IconClose from './icons/Close.svelte'
import IconDetails from './icons/Details.svelte'
import IconMaxWidth from './icons/MaxWidth.svelte'
import IconMinWidth from './icons/MinWidth.svelte'
import IconScale from './icons/Scale.svelte'
import IconScaleFull from './icons/ScaleFull.svelte'
export let innerWidth: number = 0
export let panelWidth: number = 0
export let isHeader: boolean = true
export let isAside: boolean = true
export let isFullSize: boolean = false
export let withoutTitle: boolean = false
export let floatAside: boolean = false
export let allowClose: boolean = true
export let embedded: boolean = false
export let useMaxWidth: boolean | undefined = undefined
export let customAside: ButtonItem[] | undefined = undefined
export let selectedAside: string | boolean = customAside ? customAside[0].id : isAside
export let printHeader = true
export let printAside = false
export let adaptive: HeaderAdaptive = 'default'
export let hideBefore: boolean = false
export let hideSearch: boolean = true
export let hideActions: boolean = false
export let hideExtra: boolean = false
export let overflowExtra: boolean = false
export function getAside (): string | boolean {
if (customAside) return selectedAside
return asideShown
}
export function setAside (id: string | boolean): void {
if (typeof id === 'string' && customAside) {
const i = customAside.findIndex((as) => as.id === id)
if (i === -1) return
handleSelectAside({ detail: id })
} else {
asideShown = id !== false
hideAside = !asideShown
if (id === false) selectedAside = false
}
}
const dispatch = createEventDispatcher()
let el: HTMLElement
let asideFloat: boolean = false
let asideShown: boolean = selectedAside !== false
let hideAside: boolean = !asideShown
let fullSize: boolean = false
let oldAside: string | boolean = selectedAside
$: if (typeof selectedAside === 'string' && oldAside !== selectedAside) oldAside = selectedAside
$: setAside(selectedAside)
$: if (el !== undefined) {
panelWidth = el.clientWidth
checkPanel()
}
let oldWidth = ''
let hideTimer: any | undefined
const checkPanel = (): void => {
const k = `${panelWidth}-${asideFloat}`
if (oldWidth === k) {
return
}
oldWidth = k
if (floatAside) {
asideFloat = true
} else if (panelWidth <= 900 && !asideFloat) {
asideFloat = true
if (asideShown) {
asideShown = false
if (customAside) handleSelectAside({ detail: false }, false)
}
} else if (panelWidth > 900) {
if (asideFloat) asideFloat = false
if (!asideShown && !hideAside) {
asideShown = true
if (customAside) handleSelectAside({ detail: oldAside }, false)
}
}
}
afterUpdate(() => {
if (hideTimer) {
clearTimeout(hideTimer)
}
hideTimer = setTimeout(() => {
checkPanel()
}, 500)
})
onMount(() => dispatch('open'))
defineSeparators('panel-aside', panelSeparators)
const handleAside = (): void => {
asideShown = !asideShown
hideAside = !asideShown
}
const handleSelectAside = (result: { detail: any }, sw: boolean = true): void => {
selectedAside = result.detail
if (sw) {
asideShown = selectedAside !== false
hideAside = !asideShown
}
dispatch('select', result.detail)
}
let isPrinting = false
</script>
<svelte:window
on:beforeprint={() => {
isPrinting = true
}}
on:afterprint={() => {
isPrinting = false
}}
/>
<div
bind:this={el}
class="popupPanel panel"
class:withPageHeader={$$slots['page-header'] !== undefined}
class:withPageFooter={$$slots['page-footer'] !== undefined}
class:embedded
use:resizeObserver={(element) => {
panelWidth = element.clientWidth
checkPanel()
}}
>
<Header
type={'type-panel'}
noPrint={!printHeader}
{adaptive}
{hideBefore}
{hideSearch}
{hideActions}
{hideExtra}
{overflowExtra}
>
<svelte:fragment slot="beforeTitle">
{#if allowClose}
<Button
id={'btnPClose'}
focusIndex={10001}
icon={IconClose}
iconProps={{ size: 'medium' }}
kind={'icon'}
noPrint
on:click={() => {
dispatch('close')
}}
/>
{#if $$slots.beforeTitle}
<div class="hulyHeader-divider short no-print" />
{/if}
{/if}
<slot name="beforeTitle" />
</svelte:fragment>
{#if !withoutTitle}<slot name="title" />{/if}
<svelte:fragment slot="search">
<slot name="search" />
</svelte:fragment>
<svelte:fragment slot="actions">
<slot name="actions" />
<slot name="pre-utils" />
<slot name="utils" />
{#if useMaxWidth !== undefined}
<Button
focusIndex={10009}
icon={useMaxWidth ? IconMaxWidth : IconMinWidth}
iconProps={{ size: 'medium' }}
kind={'icon'}
selected={useMaxWidth}
on:click={() => {
useMaxWidth = !useMaxWidth
dispatch('maxWidth', useMaxWidth)
}}
/>
{/if}
{#if isFullSize}
<Button
focusIndex={100010}
icon={fullSize ? IconScale : IconScaleFull}
iconProps={{ size: 'medium' }}
kind={'icon'}
selected={fullSize}
on:click={() => {
fullSize = !fullSize
dispatch('fullsize')
}}
/>
{/if}
{#if $$slots.aside && isAside}
{#if customAside}
<ButtonGroup
items={customAside}
props={{ kind: 'icon', iconProps: { size: 'medium' } }}
bind:selected={selectedAside}
on:select={handleSelectAside}
/>
{:else}
<Button
id={'btnPAside'}
focusIndex={10008}
icon={IconDetails}
iconProps={{ size: 'medium', filled: asideShown }}
kind={'icon'}
selected={asideShown}
on:click={handleAside}
/>
{/if}
{/if}
<slot name="post-utils" />
</svelte:fragment>
<svelte:fragment slot="extra">
<slot name="extra" />
</svelte:fragment>
</Header>
<div class="popupPanel-body {$deviceInfo.isMobile ? 'mobile' : 'main'}" class:asideShown>
{#if $deviceInfo.isMobile}
<Scroller horizontal padding={'.5rem .75rem'}>
<div
class="popupPanel-body__mobile"
use:resizeObserver={(element) => {
innerWidth = element.clientWidth
}}
>
{#if $$slots.header && isHeader}
<div class="popupPanel-body__header mobile bottom-divider" class:max={useMaxWidth}>
<slot name="header" />
</div>
{/if}
<slot />
</div>
</Scroller>
{:else}
<div
class="popupPanel-body__main"
use:resizeObserver={(element) => {
innerWidth = element.clientWidth
}}
>
{#if $$slots.header && isHeader}
<div class="popupPanel-body__header-wrapper">
<div class="popupPanel-body__header main" class:max={useMaxWidth}>
<slot name="header" />
</div>
</div>
{/if}
<slot />
{#if isPrinting && printAside}
<div class="only-print pagebreak">
<slot name="aside" />
</div>
{/if}
</div>
{/if}
{#if $$slots.aside && isAside && asideShown}
<Separator name={'panel-aside'} float={asideFloat} index={0} />
<div class="popupPanel-body__aside no-print" class:float={asideFloat} class:shown={asideShown}>
<Separator name={'panel-aside'} float={asideFloat ? 'aside' : true} index={0} />
<div class="antiPanel-wrap__content">
<slot name="aside" />
</div>
</div>
{/if}
</div>
<div class="popupPanel-pageHeader only-print" id="page-header">
<slot name="page-header" />
</div>
<div class="popupPanel-pageFooter only-print" id="page-footer">
<slot name="page-footer" />
</div>
</div>