-
Notifications
You must be signed in to change notification settings - Fork 103
/
Drawer.svelte
100 lines (92 loc) · 3.57 KB
/
Drawer.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
<script lang="ts">
import { Icon as IconEnum } from '@lib/auxiliary/icon'
import { Icon, Text, TextType } from '@ui'
import { fade, fly } from 'svelte/transition'
import { DRAWER_IN_ANIMATION_DURATION_MS, DRAWER_OUT_ANIMATION_DURATION_MS } from '@/contexts/dashboard'
export let onClose: () => unknown = () => {}
export let onBackClick: () => unknown = () => {}
export let allowBack: boolean = false
export let title: string | undefined = undefined
export let fullScreen: boolean = false
export let enterFromSide: boolean = false
let position = 0
let moving = false
let panelHeight = 0
let panelWidth = 0
let touchStart = 0
const directon = enterFromSide ? { x: -100 } : { y: 100 }
function onTouchStart(event): void {
moving = true
const { pageX, pageY } = event.touches[0]
touchStart = enterFromSide ? -pageX : pageY
}
function onTouchMove(event): void {
if (moving && event.targetTouches.length === 1) {
const { pageX, pageY } = event.touches[0]
const nextTouch = enterFromSide ? -pageX : pageY
position = Math.min(touchStart - nextTouch, 0)
}
}
function onTouchEnd(): void {
moving = false
const panelSize = enterFromSide ? panelWidth : panelHeight
if (position < -panelSize / 3) {
onClose()
} else {
position = 0
}
}
</script>
<svelte:window on:touchend={onTouchEnd} on:touchmove={onTouchMove} />
<drawer class="fixed top-0 left-0 w-screen h-screen">
<overlay
in:fade|local={{ duration: DRAWER_IN_ANIMATION_DURATION_MS }}
out:fade|local={{ duration: DRAWER_OUT_ANIMATION_DURATION_MS }}
on:click={onClose}
class="fixed top-0 left-0 w-full h-full z-0 bg-gray-700 dark:bg-gray-900 bg-opacity-60 dark:bg-opacity-60"
/>
<panel
on:touchstart={onTouchStart}
in:fly|local={{ ...directon, duration: DRAWER_IN_ANIMATION_DURATION_MS }}
out:fly|local={{ ...directon, duration: DRAWER_OUT_ANIMATION_DURATION_MS }}
bind:clientHeight={panelHeight}
bind:clientWidth={panelWidth}
class:moving
class="py-6 px-5 fixed w-full flex flex-col flex-auto overflow-hidden {fullScreen
? 'h-screen'
: ''} bg-white dark:bg-gray-800 {enterFromSide ? '' : 'rounded-t-2xl'}"
style={enterFromSide ? `left: ${position}px;` : `bottom: ${position}px;`}
>
{#if enterFromSide === false}
<decorator
class="absolute top-2 left-1/2 transform -translate-x-1/2 w-12 h-1 bg-gray-300 dark:bg-gray-700 rounded"
/>
{/if}
{#if title || (allowBack && onBackClick)}
<div class="grid grid-cols-4 h-6 mb-6">
<div class="col-span-1">
{#if allowBack && onBackClick}
<button type="button" on:click={onBackClick}>
<Icon width="24" height="24" icon={IconEnum.ArrowLeft} classes="text-gray-500" />
</button>
{/if}
</div>
<div class="flex justify-center col-span-2 content-center">
{#if title}
<Text type={TextType.h4} classes="text-center">{title}</Text>
{/if}
</div>
</div>
{/if}
<slot />
</panel>
</drawer>
<style type="text/scss">
panel {
transition: bottom 0.2s ease;
max-height: 100%;
&.moving {
transition: none;
}
}
</style>