-
Notifications
You must be signed in to change notification settings - Fork 0
/
MainLayout.svelte
148 lines (135 loc) · 5.34 KB
/
MainLayout.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<!--
@component
the main wrapper for any content displayed in the application
this component is meant to render only once as it is meant to be used as a root component and it handles the initialization of different parts of the application
@slot `default` - the main content of the screen
@slot `header-right` passed to the `right` slot of the header component
@slot `sidebar-foot` passed to the `sidebar-foot` slot of the header component
@slot `footer-foot` passed to `foot` slot of the footer component
@slot `footer-metadata` passed to `metadata` slot of the footer component
-->
<script context="module" lang="ts">
export const intro = true
export const backdropStyle = Symbol()
export type BackdropStyleContext = {
blur: Readable<number>
isBlurred: Readable<boolean>
}
</script>
<script lang="ts">
import './globals.css'
import MobileVhFix from './helpers/mobile-vh-fix.svelte'
import MobileHoverFix from './helpers/mobile-hover-fix.svelte'
import MainLoadingOverlay from './MainLoadingOverlay.svelte'
import { portalMap, create_portal_root } from './actions/portal'
import _ from 'lodash'
import { onMount, setContext, tick } from 'svelte'
import Footer from './Footer.svelte'
import cn from 'classnames'
import HeaderLayout from './HeaderLayout.svelte'
import { Routes } from './configs/routes'
import BodyScrollHint from './BodyScrollHint.svelte'
import { create_fixed_root } from './actions/fixed'
import { create_backdrop_root } from './actions/backdrop'
import { Readable, writable } from 'svelte/store'
import ToastContainer from './toast/ToastContainer.svelte'
import NavigationLoadingJob from './helpers/navigation-loading-job.svelte'
import { isPageLoading$ } from './observables/is-page-loading'
import { animationFrameF, waitFor, waitForF } from './helpers/wait-for'
import { isChrome$ } from './contexts/is-firefox'
import { page } from '$app/stores'
const blurMultiplier = 20
$: shouldBlur = $portalMap.some(x => x.index !== null) || $isPageLoading$
const blur = writable(blurMultiplier)
const isBlurred = writable(true)
$: shouldBlur && isBlurred.set(true)
$: shouldBlur && $isChrome$ && $page.url.pathname === '/'
? tick()
.then(waitForF(75))
.then(animationFrameF(10))
.then(() => shouldBlur && blur.set(blurMultiplier))
: blur.set(blurMultiplier)
$: !shouldBlur && waitFor(500).then(() => isBlurred.set(false))
$: !shouldBlur && blur.set(0)
setContext<BackdropStyleContext>(backdropStyle, {
blur,
isBlurred,
})
let isReady = false
onMount(() => (isReady = true))
let footerHeight: number
export let footerRoutes: Routes[]
export let headerRoutes: Routes[]
export let headerCollapsedRoutes: Routes[]
export let sidebarRoutes: Routes[]
export let small = false
export let className: {
[key in
| 'headerContainer'
| 'headerWrapper'
| 'headerNavDropContainer'
| 'headerNavDropItem']?: string
} = {}
export let floatingHeader = false
export let hintDownscaleFactor: { start?: number; end?: number } = { start: 25 }
export let headerBlurContainer = false
</script>
<MobileHoverFix />
<MobileVhFix />
<MainLoadingOverlay />
<ToastContainer />
<NavigationLoadingJob />
<div class="hidden animate-pulse" />
{#if isReady}
<div
id="app"
class="w-screen relative z-0 transition-[filter] duration-500"
style={$blur === 0 ? '' : `filter: blur(${$blur}px);`}>
<main
style="padding-bottom: calc({footerHeight}px + 1.25rem);"
class={cn(
floatingHeader
? 'min-h-[calc(var(--h-screen)+theme(spacing.72))] md:min-h-[var(--h-screen)]'
: 'min-h-[calc(var(--h-screen)+theme(spacing.72))] md:min-h-[calc(var(--h-screen)-theme(spacing.28))]',
!floatingHeader && 'mt-24 md:mt-28',
small
? 'max-w-[min(calc(100%-theme(spacing.10)),theme(screens.lg))]'
: 'max-w-[min(calc(100%-theme(spacing.10)),theme(screens.xl))]',
'relative z-0 w-screen children:max-w-full mx-auto py-5 grow flex flex-col overflow-y-clip',
)}>
<HeaderLayout
blurContainer={headerBlurContainer}
className={{
container: className.headerContainer,
wrapper: className.headerWrapper,
navDropContainer: className.headerNavDropContainer,
navDropItem: className.headerNavDropItem,
}}
routes={headerRoutes}
collapsedRoutes={headerCollapsedRoutes}
{sidebarRoutes}
{small}>
<slot name="header-right" slot="right" />
<slot name="sidebar-foot" slot="sidebar-foot" />
</HeaderLayout>
<slot />
<Footer routes={footerRoutes} bind:clientHeight={footerHeight} {small}>
<slot name="footer-foot" slot="foot" />
<slot name="footer-metadata" slot="metadata" />
</Footer>
<BodyScrollHint {hintDownscaleFactor} {floatingHeader} />
</main>
</div>
{/if}
<div class="fixed inset-0 pointer-events-none z-0">
<div
data-name="fixed-root"
use:create_fixed_root
class="children:pointer-events-auto absolute z-0 inset-0 transition-[filter] duration-500"
style={$blur === 0 ? '' : `filter: blur(${$blur}px);`} />
<div
data-name="backdrop-root"
use:create_backdrop_root
class="children:pointer-events-auto absolute z-0 inset-0" />
</div>
<div id="portal_root" class="z-index-bug-fix-children" use:create_portal_root />