Skip to content

Commit e4870ab

Browse files
authored
Merge pull request #104 from devforth/implement-dialog-component
refactor dialog and add docs
2 parents 031641a + 206aaf7 commit e4870ab

File tree

7 files changed

+228
-44
lines changed

7 files changed

+228
-44
lines changed

adminforth/documentation/docs/tutorial/03-Customization/14-afcl.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,186 @@ const enable = ref(false)
338338
</div>
339339
</div>
340340

341+
## Dialog (Pop-up)
342+
343+
<div class="split-screen" >
344+
<div>
345+
346+
```ts
347+
import { Dialog } from '@/afcl';
348+
import { Button } from '@/afcl';
349+
```
350+
351+
```html
352+
<Dialog class="w-96">
353+
<template #trigger>
354+
<Button>Dialog Toggle</Button>
355+
</template>
356+
357+
<div class="space-y-4">
358+
<p>This is the first paragraph of dialog content.</p>
359+
<p>And this is the second paragraph.</p>
360+
</div>
361+
</Dialog>
362+
```
363+
</div>
364+
<div>
365+
![AFCL Dialog](image-87.png)
366+
</div>
367+
</div>
368+
369+
### Header
370+
You can add header to the dialog by using header prop.
371+
372+
<div class="split-screen" >
373+
<div>
374+
375+
```html
376+
//diff-remove
377+
<Dialog class="w-96">
378+
//diff-add
379+
<Dialog
380+
//diff-add
381+
class="w-96"
382+
//diff-add
383+
header="Dialog Header"
384+
//diff-add
385+
>
386+
<template #trigger>
387+
<Button>Dialog Toggle</Button>
388+
</template>
389+
390+
<div class="space-y-4">
391+
<p>This is the first paragraph of dialog content.</p>
392+
<p>And this is the second paragraph.</p>
393+
</div>
394+
</Dialog>
395+
```
396+
</div>
397+
<div>
398+
![AFCL Dialog](image-88.png)
399+
</div>
400+
</div>
401+
402+
If you want to remove close button in header, you can add `:header-close-button="false"` prop to `<Dialog>`.
403+
404+
### Buttons
405+
By default dialog will have just one "Close" button. If you want to change that, you can set `buttons` to a desirable array.
406+
407+
<div class="split-screen" >
408+
<div>
409+
410+
```html
411+
<Dialog
412+
class="w-96"
413+
header="Dialog Header"
414+
//diff-add
415+
:buttons="[
416+
//diff-add
417+
{ label: 'Save', onclick: (dialog) => { doSave(); dialog.hide(); } },
418+
//diff-add
419+
{ label: 'Close', onclick: (dialog) => dialog.hide() },
420+
//diff-add
421+
]"
422+
>
423+
<template #trigger>
424+
<Button>Dialog Toggle</Button>
425+
</template>
426+
427+
<div class="space-y-4">
428+
<p>This is the first paragraph of dialog content.</p>
429+
<p>And this is the second paragraph.</p>
430+
</div>
431+
</Dialog>
432+
```
433+
</div>
434+
<div>
435+
![AFCL Dialog](image-89.png)
436+
</div>
437+
</div>
438+
439+
Dialog component will render each button using afcl `Button` component. You can pass any props to those buttons by adding `options` field to a button item.
440+
441+
<div class="split-screen" >
442+
<div>
443+
444+
```html
445+
<Dialog
446+
class="w-96"
447+
header="Dialog Header"
448+
:buttons="[
449+
//diff-remove
450+
{ label: 'Save', onclick: (dialog) => { doSave(); dialog.hide(); } },
451+
//diff-add
452+
{
453+
//diff-add
454+
label: 'Save',
455+
//diff-add
456+
options: {
457+
//diff-add
458+
disabled: savingIsAllowed,
459+
//diff-add
460+
},
461+
//diff-add
462+
onclick: (dialog) => { doSave(); dialog.hide(); },
463+
//diff-add
464+
},
465+
{ label: 'Close', onclick: (dialog) => dialog.hide() },
466+
]"
467+
>
468+
<template #trigger>
469+
<Button>Dialog Toggle</Button>
470+
</template>
471+
472+
<div class="space-y-4">
473+
<p>This is the first paragraph of dialog content.</p>
474+
<p>And this is the second paragraph.</p>
475+
</div>
476+
</Dialog>
477+
```
478+
</div>
479+
<div>
480+
![AFCL Dialog](image-90.png)
481+
</div>
482+
</div>
483+
484+
### Dialog persistence
485+
Default behavior of the Dialog component will allow user to close it by just clicking outside. You can prevent that by setting `clickToCloseOutside` to `false`.
486+
487+
<div class="split-screen" >
488+
<div>
489+
490+
```html
491+
<Dialog
492+
class="w-96"
493+
header="Dialog Header"
494+
:buttons="[
495+
{
496+
label: 'Save',
497+
options: {
498+
disabled: savingIsAllowed,
499+
},
500+
onclick: (dialog) => { doSave(); dialog.hide(); },
501+
},
502+
{ label: 'Close', onclick: (dialog) => dialog.hide() },
503+
]"
504+
//diff-add
505+
:click-to-close-outside="false"
506+
>
507+
<template #trigger>
508+
<Button>Dialog Toggle</Button>
509+
</template>
510+
511+
<div class="space-y-4">
512+
<p>This is the first paragraph of dialog content.</p>
513+
<p>And this is the second paragraph.</p>
514+
</div>
515+
</Dialog>
516+
```
517+
</div>
518+
<div>
519+
</div>
520+
</div>
341521

342522
## Dropzone
343523

26.8 KB
Loading
31.3 KB
Loading
33.4 KB
Loading
33.8 KB
Loading

adminforth/spa/src/afcl/Dialog.vue

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,54 @@
11
<template>
2-
<div @click="modal?.show()" class="inline-flex items-center cursor-pointer">
3-
<slot></slot>
2+
<div
3+
v-if="$slots.trigger"
4+
@click="modal?.show()" class="inline-flex items-center cursor-pointer"
5+
>
6+
<slot name="trigger"></slot>
47
</div>
58
<div ref="modalEl" tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
6-
<div class="relative p-4 w-full max-w-2xl max-h-full">
7-
<!-- Modal content -->
8-
<div class="relative bg-white rounded-lg shadow-sm dark:bg-gray-700">
9-
<!-- Modal header -->
10-
<div
11-
v-if="header"
12-
class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600 border-gray-200"
13-
>
14-
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
15-
{{ header }}
16-
</h3>
17-
<button
18-
v-if="headerCloseButton"
19-
type="button"
20-
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white"
21-
@click="modal?.hide()"
22-
>
23-
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
24-
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
25-
</svg>
26-
<span class="sr-only">Close modal</span>
27-
</button>
28-
</div>
29-
<!-- Modal body -->
30-
<div class="p-4 md:p-5 space-y-4">
31-
<slot name="content"></slot>
32-
</div>
33-
<!-- Modal footer -->
34-
<div
35-
v-if="buttons.length"
36-
class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600"
37-
>
38-
<Button
39-
v-for="(button, buttonIndex) in buttons"
40-
:key="buttonIndex"
41-
v-bind="button.options"
42-
:class="{ 'ms-3': buttonIndex > 0 }"
43-
@click="button.onclick(modal)"
44-
>
45-
{{ button.label }}
46-
</Button>
47-
</div>
9+
<div v-bind="$attrs" class="relative p-4 max-w-2xl max-h-full" :class="$attrs.class?.includes('w-') ? '' : 'w-full'">
10+
<!-- Modal content -->
11+
<div class="relative bg-white rounded-lg shadow-sm dark:bg-gray-700">
12+
<!-- Modal header -->
13+
<div
14+
v-if="header"
15+
class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600 border-gray-200"
16+
>
17+
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
18+
{{ header }}
19+
</h3>
20+
<button
21+
v-if="headerCloseButton"
22+
type="button"
23+
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white"
24+
@click="modal?.hide()"
25+
>
26+
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
27+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
28+
</svg>
29+
<span class="sr-only">Close modal</span>
30+
</button>
4831
</div>
32+
<!-- Modal body -->
33+
<div class="p-4 md:p-5 space-y-4 text-gray-700 dark:text-gray-400">
34+
<slot></slot>
35+
</div>
36+
<!-- Modal footer -->
37+
<div
38+
v-if="buttons.length"
39+
class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600"
40+
>
41+
<Button
42+
v-for="(button, buttonIndex) in buttons"
43+
:key="buttonIndex"
44+
v-bind="button.options"
45+
:class="{ 'ms-3': buttonIndex > 0 }"
46+
@click="button.onclick(modal)"
47+
>
48+
{{ button.label }}
49+
</Button>
50+
</div>
51+
</div>
4952
</div>
5053
</div>
5154
</template>

adminforth/spa/src/afcl/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export { default as Table } from './Table.vue';
1616
export { default as ProgressBar } from './ProgressBar.vue';
1717
export { default as Spinner } from './Spinner.vue';
1818
export { default as Skeleton } from './Skeleton.vue';
19+
export { default as Dialog } from './Dialog.vue';
1920

2021

0 commit comments

Comments
 (0)