Skip to content

Commit 0b8e66f

Browse files
Merge pull request #637 from appwrite/chore-prerelease-modal
feat: pre release modal
2 parents ab9ef73 + fe16ac2 commit 0b8e66f

File tree

9 files changed

+361
-130
lines changed

9 files changed

+361
-130
lines changed

src/lib/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,5 @@ export { default as SvgIcon } from './svgIcon.svelte';
6060
export { default as MigrationBox } from './migrationBox.svelte';
6161
export { default as FloatingActionBar } from './floatingActionBar.svelte';
6262
export { default as LoadingDots } from './loadingDots.svelte';
63+
export { default as ModalWrapper } from './modalWrapper.svelte';
64+
export { default as ModalSideCol } from './modalSideCol.svelte';

src/lib/components/modal.svelte

Lines changed: 64 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script lang="ts">
2-
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
3-
import { Alert } from '$lib/components';
2+
import { Alert, ModalWrapper } from '$lib/components';
43
import { trackEvent } from '$lib/actions/analytics';
54
import { Form } from '$lib/elements/forms';
65
import { disableCommands } from '$lib/commandCenter';
@@ -18,144 +17,81 @@
1817
export let title = '';
1918
export let description = '';
2019
21-
let dialog: HTMLDialogElement;
2220
let alert: HTMLElement;
2321
24-
const dispatch = createEventDispatcher();
25-
26-
onMount(() => {
27-
if (show) openModal();
28-
});
29-
30-
onDestroy(() => {
31-
if (show) closeModal();
32-
});
33-
34-
function handleBLur(event: MouseEvent) {
35-
if (event.target === dialog) {
36-
trackEvent('click_close_modal', {
37-
from: 'backdrop'
38-
});
39-
closeModal();
40-
}
41-
}
42-
function openModal() {
43-
if (dialog && !dialog.open) {
44-
dialog.showModal();
45-
document.documentElement.classList.add('u-overflow-hidden');
46-
}
47-
}
48-
49-
function closeModal() {
50-
if (closable) {
51-
if (dialog && dialog.open) {
52-
dispatch('close');
53-
dialog.close();
54-
show = false;
55-
document.documentElement.classList.remove('u-overflow-hidden');
56-
}
57-
}
58-
}
59-
60-
function handleKeydown(event: KeyboardEvent) {
61-
if (event.key === 'Escape') {
62-
event.preventDefault();
63-
trackEvent('click_close_modal', {
64-
from: 'escape'
65-
});
66-
closeModal();
67-
}
68-
}
69-
70-
$: if (show) {
71-
openModal();
72-
} else {
73-
closeModal();
74-
}
75-
7622
$: $disableCommands(show);
7723
7824
$: if (error) {
7925
alert?.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' });
8026
}
8127
</script>
8228

83-
<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />
84-
85-
<dialog
86-
class="modal"
87-
class:is-small={size === 'small'}
88-
class:is-big={size === 'big'}
89-
class:is-separate-header={headerDivider}
90-
bind:this={dialog}
91-
on:cancel|preventDefault>
92-
{#if show}
93-
<Form isModal {onSubmit}>
94-
<header class="modal-header">
95-
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
96-
<div class="u-flex u-cross-center u-gap-16">
97-
{#if icon}
98-
<div
99-
class="avatar is-medium"
100-
class:is-success={state === 'success'}
101-
class:is-warning={state === 'warning'}
102-
class:is-danger={state === 'error'}
103-
class:is-info={state === 'info'}>
104-
<span class={`icon-${icon}`} aria-hidden="true" />
105-
</div>
106-
{/if}
107-
108-
<h4 class="modal-title heading-level-5">
109-
<slot name="title">
110-
{title}
111-
</slot>
112-
</h4>
113-
</div>
114-
{#if closable}
115-
<button
116-
type="button"
117-
class="button is-text is-only-icon"
118-
style="--button-size:1.5rem;"
119-
aria-label="Close Modal"
120-
title="Close Modal"
121-
on:click={() =>
122-
trackEvent('click_close_modal', {
123-
from: 'button'
124-
})}
125-
on:click={closeModal}>
126-
<span class="icon-x" aria-hidden="true" />
127-
</button>
29+
<ModalWrapper bind:show {size} {headerDivider} let:close>
30+
<Form isModal {onSubmit}>
31+
<header class="modal-header">
32+
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
33+
<div class="u-flex u-cross-center u-gap-16">
34+
{#if icon}
35+
<div
36+
class="avatar is-medium"
37+
class:is-success={state === 'success'}
38+
class:is-warning={state === 'warning'}
39+
class:is-danger={state === 'error'}
40+
class:is-info={state === 'info'}>
41+
<span class={`icon-${icon}`} aria-hidden="true" />
42+
</div>
12843
{/if}
44+
45+
<h4 class="modal-title heading-level-5">
46+
<slot name="title">
47+
{title}
48+
</slot>
49+
</h4>
12950
</div>
130-
<p class="u-margin-block-start-4">
131-
<slot name="description">
132-
{description}
133-
</slot>
134-
</p>
135-
</header>
136-
<div class="modal-content">
137-
{#if error}
138-
<div bind:this={alert}>
139-
<Alert
140-
dismissible
141-
type="warning"
142-
on:dismiss={() => {
143-
error = null;
144-
}}>
145-
{error}
146-
</Alert>
147-
</div>
51+
{#if closable}
52+
<button
53+
type="button"
54+
class="button is-text is-only-icon"
55+
style="--button-size:1.5rem;"
56+
aria-label="Close Modal"
57+
title="Close Modal"
58+
on:click={() =>
59+
trackEvent('click_close_modal', {
60+
from: 'button'
61+
})}
62+
on:click={close}>
63+
<span class="icon-x" aria-hidden="true" />
64+
</button>
14865
{/if}
149-
<slot />
15066
</div>
151-
152-
{#if $$slots.footer}
153-
<div class="modal-footer">
154-
<div class="u-flex u-main-end u-gap-16">
155-
<slot name="footer" />
156-
</div>
67+
<p class="u-margin-block-start-4">
68+
<slot name="description">
69+
{description}
70+
</slot>
71+
</p>
72+
</header>
73+
<div class="modal-content">
74+
{#if error}
75+
<div bind:this={alert}>
76+
<Alert
77+
dismissible
78+
type="warning"
79+
on:dismiss={() => {
80+
error = null;
81+
}}>
82+
{error}
83+
</Alert>
15784
</div>
15885
{/if}
159-
</Form>
160-
{/if}
161-
</dialog>
86+
<slot />
87+
</div>
88+
89+
{#if $$slots.footer}
90+
<div class="modal-footer">
91+
<div class="u-flex u-main-end u-gap-16">
92+
<slot name="footer" />
93+
</div>
94+
</div>
95+
{/if}
96+
</Form>
97+
</ModalWrapper>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<script lang="ts">
2+
import { ModalWrapper } from '$lib/components';
3+
import { trackEvent } from '$lib/actions/analytics';
4+
5+
export let show = false;
6+
export let title = '';
7+
export let description = '';
8+
export let style = '';
9+
</script>
10+
11+
<ModalWrapper bind:show let:close {style}>
12+
<div class="grid-1-1 u-width-full-line mk-grid">
13+
<div class="mk-grid-item-1 u-width-full-line">
14+
<slot name="side" />
15+
</div>
16+
<div class="u-padding-32 mk-grid-item-2">
17+
<header class="modal-header">
18+
<div class="u-flex u-main-space-between u-gap-16">
19+
<h4 class="modal-title heading-level-5">
20+
<slot name="title">
21+
{title}
22+
</slot>
23+
</h4>
24+
<button
25+
type="button"
26+
class="button is-text is-only-icon"
27+
style="--button-size:1.5rem;"
28+
aria-label="Close Modal"
29+
title="Close Modal"
30+
on:click={() =>
31+
trackEvent('click_close_modal', {
32+
from: 'button'
33+
})}
34+
on:click={close}>
35+
<span class="icon-x" aria-hidden="true" />
36+
</button>
37+
</div>
38+
<p class="u-margin-block-start-4">
39+
<slot name="description">
40+
{description}
41+
</slot>
42+
</p>
43+
</header>
44+
<div class="modal-content">
45+
<slot />
46+
</div>
47+
</div>
48+
</div>
49+
</ModalWrapper>
50+
51+
<style lang="scss">
52+
.mk-grid {
53+
overflow: hidden;
54+
}
55+
@media screen and (max-width: 768px) {
56+
.mk-grid {
57+
&-item-1 {
58+
order: 2;
59+
max-height: 16rem;
60+
}
61+
62+
&-item-2 {
63+
order: 1;
64+
}
65+
}
66+
}
67+
</style>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<script lang="ts">
2+
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
3+
import { trackEvent } from '$lib/actions/analytics';
4+
import { disableCommands } from '$lib/commandCenter';
5+
6+
export let show = false;
7+
export let size: 'small' | 'big' = null;
8+
export let closable = true;
9+
export let headerDivider = true;
10+
export let style = '';
11+
12+
let dialog: HTMLDialogElement;
13+
14+
const dispatch = createEventDispatcher();
15+
16+
onMount(() => {
17+
if (show) openModal();
18+
});
19+
20+
onDestroy(() => {
21+
if (show) closeModal();
22+
});
23+
24+
function handleBLur(event: MouseEvent) {
25+
if (event.target === dialog) {
26+
trackEvent('click_close_modal', {
27+
from: 'backdrop'
28+
});
29+
closeModal();
30+
}
31+
}
32+
function openModal() {
33+
if (dialog && !dialog.open) {
34+
dialog.showModal();
35+
document.documentElement.classList.add('u-overflow-hidden');
36+
}
37+
}
38+
39+
function closeModal() {
40+
if (closable) {
41+
if (dialog && dialog.open) {
42+
dispatch('close');
43+
dialog.close();
44+
show = false;
45+
document.documentElement.classList.remove('u-overflow-hidden');
46+
}
47+
}
48+
}
49+
50+
function handleKeydown(event: KeyboardEvent) {
51+
if (event.key === 'Escape') {
52+
event.preventDefault();
53+
trackEvent('click_close_modal', {
54+
from: 'escape'
55+
});
56+
closeModal();
57+
}
58+
}
59+
60+
$: if (show) {
61+
openModal();
62+
} else {
63+
closeModal();
64+
}
65+
66+
$: $disableCommands(show);
67+
</script>
68+
69+
<svelte:window on:mousedown={handleBLur} on:keydown={handleKeydown} />
70+
71+
<dialog
72+
class="modal"
73+
class:is-small={size === 'small'}
74+
class:is-big={size === 'big'}
75+
class:is-separate-header={headerDivider}
76+
{style}
77+
bind:this={dialog}
78+
on:cancel|preventDefault>
79+
{#if show}
80+
<slot close={closeModal} />
81+
{/if}
82+
</dialog>

0 commit comments

Comments
 (0)