negodesign 0.0.74 → 0.0.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/pages/security/auth/PageAuth01.svelte +65 -0
- package/dist/components/pages/security/auth/PageAuth01.svelte.d.ts +17 -0
- package/dist/components/pages/security/auth/PageAuth02.svelte +45 -0
- package/dist/components/pages/security/auth/PageAuth02.svelte.d.ts +17 -0
- package/dist/components/pages/security/auth/PageAuth03.svelte +45 -0
- package/dist/components/pages/security/auth/PageAuth03.svelte.d.ts +17 -0
- package/dist/components/pages/security/login/01/ui/PageLogin01.svelte +15 -40
- package/dist/components/pages/security/login/02/ui/LoginCard02.svelte +15 -4
- package/dist/components/pages/security/login/02/ui/PageLogin02.svelte +15 -20
- package/dist/components/pages/security/login/03/ui/LoginCard03.svelte +34 -16
- package/dist/components/pages/security/login/03/ui/PageLogin03.svelte +15 -20
- package/dist/components/pages/security/register/01/ui/PageRegister01.svelte +64 -0
- package/dist/components/pages/security/register/01/ui/PageRegister01.svelte.d.ts +3 -0
- package/dist/components/pages/security/register/01/ui/RegisterCard.svelte +100 -0
- package/dist/components/pages/security/register/01/ui/RegisterCard.svelte.d.ts +12 -0
- package/dist/components/pages/security/register/02/ui/PageRegister02.svelte +76 -0
- package/dist/components/pages/security/register/02/ui/PageRegister02.svelte.d.ts +4 -0
- package/dist/components/pages/security/register/02/ui/RegisterCard02.svelte +98 -0
- package/dist/components/pages/security/register/02/ui/RegisterCard02.svelte.d.ts +12 -0
- package/dist/components/pages/security/register/03/ui/PageRegister03.svelte +76 -0
- package/dist/components/pages/security/register/03/ui/PageRegister03.svelte.d.ts +4 -0
- package/dist/components/pages/security/register/03/ui/RegisterCard03.svelte +103 -0
- package/dist/components/pages/security/register/03/ui/RegisterCard03.svelte.d.ts +12 -0
- package/dist/components/pages/security/register/FormRegister.svelte +120 -0
- package/dist/components/pages/security/register/FormRegister.svelte.d.ts +8 -0
- package/dist/components/pages/security/register/PageRegister.svelte +30 -0
- package/dist/components/pages/security/register/PageRegister.svelte.d.ts +8 -0
- package/dist/components/pages/security/register/types.d.ts +51 -0
- package/dist/components/pages/security/register/types.js +1 -0
- package/dist/components/ui/form/Form.svelte +171 -0
- package/dist/components/ui/form/Form.svelte.d.ts +4 -0
- package/dist/components/ui/form/types.d.ts +78 -0
- package/dist/components/ui/form/types.js +1 -0
- package/dist/components/ui/form/ui/input-badges.svelte +214 -0
- package/dist/components/ui/form/ui/input-badges.svelte.d.ts +14 -0
- package/dist/components/ui/form/ui/input-checkbox.svelte +86 -0
- package/dist/components/ui/form/ui/input-checkbox.svelte.d.ts +17 -0
- package/dist/components/ui/form/ui/input-radio.svelte +82 -0
- package/dist/components/ui/form/ui/input-radio.svelte.d.ts +17 -0
- package/dist/components/ui/form/ui/input-select.svelte +195 -0
- package/dist/components/ui/form/ui/input-select.svelte.d.ts +17 -0
- package/dist/components/ui/form/ui/input-textarea.svelte +61 -0
- package/dist/components/ui/form/ui/input-textarea.svelte.d.ts +13 -0
- package/dist/components/ui/form/ui/input-toggle.svelte +89 -0
- package/dist/components/ui/form/ui/input-toggle.svelte.d.ts +11 -0
- package/dist/components/ui/modal/badge/index.d.ts +3 -0
- package/dist/components/ui/modal/badge/index.js +2 -0
- package/dist/components/ui/modal/badge/types.d.ts +35 -0
- package/dist/components/ui/modal/badge/types.js +1 -0
- package/dist/components/ui/modal/badge/ui/ModalBadgeSelection.svelte +87 -0
- package/dist/components/ui/modal/badge/ui/ModalBadgeSelection.svelte.d.ts +4 -0
- package/dist/components/ui/modal/core/index.d.ts +3 -0
- package/dist/components/ui/modal/core/index.js +2 -0
- package/dist/components/ui/modal/core/types.d.ts +84 -0
- package/dist/components/ui/modal/core/types.js +1 -0
- package/dist/components/ui/modal/core/ui/ModalCore.svelte +132 -0
- package/dist/components/ui/modal/core/ui/ModalCore.svelte.d.ts +4 -0
- package/dist/components/ui/modal/feedback/index.d.ts +3 -0
- package/dist/components/ui/modal/feedback/index.js +2 -0
- package/dist/components/ui/modal/feedback/types.d.ts +32 -0
- package/dist/components/ui/modal/feedback/types.js +1 -0
- package/dist/components/ui/modal/feedback/ui/ModalFeedback.svelte +135 -0
- package/dist/components/ui/modal/feedback/ui/ModalFeedback.svelte.d.ts +4 -0
- package/dist/components/ui/modal/form/index.d.ts +3 -0
- package/dist/components/ui/modal/form/index.js +2 -0
- package/dist/components/ui/modal/form/types.d.ts +38 -0
- package/dist/components/ui/modal/form/types.js +1 -0
- package/dist/components/ui/modal/form/ui/ModalForm.svelte +67 -0
- package/dist/components/ui/modal/form/ui/ModalForm.svelte.d.ts +4 -0
- package/dist/components/ui/modal/grid/index.d.ts +5 -0
- package/dist/components/ui/modal/grid/index.js +4 -0
- package/dist/components/ui/modal/grid/types.d.ts +51 -0
- package/dist/components/ui/modal/grid/types.js +1 -0
- package/dist/components/ui/modal/grid/ui/01/ModalGridSelection01.svelte +83 -0
- package/dist/components/ui/modal/grid/ui/01/ModalGridSelection01.svelte.d.ts +4 -0
- package/dist/components/ui/modal/grid/ui/02/ModalGridSelection02.svelte +146 -0
- package/dist/components/ui/modal/grid/ui/02/ModalGridSelection02.svelte.d.ts +4 -0
- package/dist/components/ui/modal/grid/ui/ModalGridSelection.svelte +60 -0
- package/dist/components/ui/modal/grid/ui/ModalGridSelection.svelte.d.ts +4 -0
- package/dist/components/ui/modal/map/index.d.ts +3 -0
- package/dist/components/ui/modal/map/index.js +2 -0
- package/dist/components/ui/modal/map/types.d.ts +48 -0
- package/dist/components/ui/modal/map/types.js +1 -0
- package/dist/components/ui/modal/map/ui/ModalMap.svelte +187 -0
- package/dist/components/ui/modal/map/ui/ModalMap.svelte.d.ts +4 -0
- package/dist/components/ui/modal/notification/index.d.ts +3 -0
- package/dist/components/ui/modal/notification/index.js +2 -0
- package/dist/components/ui/modal/notification/types.d.ts +26 -0
- package/dist/components/ui/modal/notification/types.js +1 -0
- package/dist/components/ui/modal/notification/ui/ModalNotification.svelte +65 -0
- package/dist/components/ui/modal/notification/ui/ModalNotification.svelte.d.ts +4 -0
- package/dist/components/ui/modal/share/index.d.ts +3 -0
- package/dist/components/ui/modal/share/index.js +2 -0
- package/dist/components/ui/modal/share/types.d.ts +47 -0
- package/dist/components/ui/modal/share/types.js +1 -0
- package/dist/components/ui/modal/share/ui/ModalShareSelection.svelte +156 -0
- package/dist/components/ui/modal/share/ui/ModalShareSelection.svelte.d.ts +4 -0
- package/dist/components/ui/modal/upload/index.d.ts +3 -0
- package/dist/components/ui/modal/upload/index.js +2 -0
- package/dist/components/ui/modal/upload/types.d.ts +79 -0
- package/dist/components/ui/modal/upload/types.js +1 -0
- package/dist/components/ui/modal/upload/ui/ModalUpload.svelte +268 -0
- package/dist/components/ui/modal/upload/ui/ModalUpload.svelte.d.ts +4 -0
- package/dist/components/ui/section/Section01.svelte +90 -0
- package/dist/components/ui/section/Section01.svelte.d.ts +4 -0
- package/dist/components/ui/section/Section02.svelte +68 -0
- package/dist/components/ui/section/Section02.svelte.d.ts +4 -0
- package/dist/components/ui/section/Section03.svelte +52 -0
- package/dist/components/ui/section/Section03.svelte.d.ts +4 -0
- package/dist/components/ui/section/index.d.ts +4 -0
- package/dist/components/ui/section/index.js +3 -0
- package/dist/components/ui/section/types.d.ts +46 -0
- package/dist/components/ui/section/types.js +1 -0
- package/dist/docs/DocsSidebar.svelte +58 -1
- package/dist/docs/components.d.ts +1 -1
- package/dist/docs/components.js +968 -0
- package/dist/globals.css +360 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +185 -0
- package/dist/types/index.d.ts +53 -0
- package/package.json +1 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../../../utils";
|
|
3
|
+
import {
|
|
4
|
+
ArrowLeft01Icon,
|
|
5
|
+
ArrowRight01Icon,
|
|
6
|
+
} from "@hugeicons/core-free-icons";
|
|
7
|
+
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
8
|
+
import type { ModalCoreProps } from "../types";
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
isOpen = $bindable(false),
|
|
12
|
+
title,
|
|
13
|
+
subtitle,
|
|
14
|
+
totalSteps = 1,
|
|
15
|
+
currentStep = 1,
|
|
16
|
+
showProgress = true,
|
|
17
|
+
showBack = true,
|
|
18
|
+
showSkip = false,
|
|
19
|
+
skipText = "Skip This Step",
|
|
20
|
+
continueText = "Continue",
|
|
21
|
+
backText = "Back",
|
|
22
|
+
onBack,
|
|
23
|
+
onContinue,
|
|
24
|
+
onSkip,
|
|
25
|
+
onClose,
|
|
26
|
+
content,
|
|
27
|
+
footer,
|
|
28
|
+
class: className,
|
|
29
|
+
}: ModalCoreProps = $props();
|
|
30
|
+
|
|
31
|
+
function handleClose() {
|
|
32
|
+
isOpen = false;
|
|
33
|
+
onClose?.();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const progressPercent = $derived(
|
|
37
|
+
totalSteps > 0 ? (currentStep / totalSteps) * 100 : 0,
|
|
38
|
+
);
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
{#if isOpen}
|
|
42
|
+
<div class="fixed inset-0 z-50 flex items-center justify-center">
|
|
43
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
44
|
+
<div
|
|
45
|
+
class="absolute inset-0 bg-black/50 backdrop-blur-sm"
|
|
46
|
+
onclick={handleClose}
|
|
47
|
+
onkeydown={(e) => {
|
|
48
|
+
if (e.key === "Escape") handleClose();
|
|
49
|
+
}}
|
|
50
|
+
></div>
|
|
51
|
+
|
|
52
|
+
<div
|
|
53
|
+
class={cn(
|
|
54
|
+
"relative z-10 mx-4 flex max-h-[90vh] w-full max-w-3xl flex-col overflow-hidden rounded-3xl border border-border shadow-lg bg-background",
|
|
55
|
+
"before:absolute before:-inset-px before:z-[-1] before:rounded-3xl",
|
|
56
|
+
"animate-in fade-in zoom-in-95 duration-200",
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
>
|
|
60
|
+
<!-- Header -->
|
|
61
|
+
<div class="px-8 pt-8">
|
|
62
|
+
<h2 class="text-2xl font-semibold tracking-tight">
|
|
63
|
+
{title}
|
|
64
|
+
</h2>
|
|
65
|
+
{#if subtitle}
|
|
66
|
+
<p class="mt-2 text-sm text-muted-foreground">{subtitle}</p>
|
|
67
|
+
{/if}
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- Content -->
|
|
71
|
+
<div class="flex-1 overflow-y-auto px-8 py-6">
|
|
72
|
+
{#if content}
|
|
73
|
+
{@render content()}
|
|
74
|
+
{/if}
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<!-- Footer -->
|
|
78
|
+
{#if footer}
|
|
79
|
+
<div class="border-t border-border px-8 py-5">
|
|
80
|
+
{@render footer()}
|
|
81
|
+
</div>
|
|
82
|
+
{:else}
|
|
83
|
+
<div class="border-t border-border px-8 py-5">
|
|
84
|
+
{#if showProgress}
|
|
85
|
+
<div class="mb-5 h-1.5 w-full overflow-hidden rounded-full">
|
|
86
|
+
<div
|
|
87
|
+
class="h-full rounded-full transition-all duration-300"
|
|
88
|
+
style="width: {progressPercent}%"
|
|
89
|
+
></div>
|
|
90
|
+
</div>
|
|
91
|
+
{/if}
|
|
92
|
+
|
|
93
|
+
<div class="flex items-center justify-between">
|
|
94
|
+
<div class="flex items-center gap-4">
|
|
95
|
+
{#if showSkip}
|
|
96
|
+
<button
|
|
97
|
+
type="button"
|
|
98
|
+
class="text-sm font-medium text-muted-foreground transition hover:text-foreground"
|
|
99
|
+
onclick={onSkip}
|
|
100
|
+
>
|
|
101
|
+
{skipText}
|
|
102
|
+
</button>
|
|
103
|
+
{/if}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div class="flex items-center gap-3">
|
|
107
|
+
{#if showBack && currentStep > 1}
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
class="inline-flex items-center gap-2 rounded-full border border-border px-5 py-2.5 text-sm font-semibold transition"
|
|
111
|
+
onclick={onBack}
|
|
112
|
+
>
|
|
113
|
+
<HugeiconsIcon icon={ArrowLeft01Icon} class="size-4" />
|
|
114
|
+
{backText}
|
|
115
|
+
</button>
|
|
116
|
+
{/if}
|
|
117
|
+
|
|
118
|
+
<button
|
|
119
|
+
type="button"
|
|
120
|
+
class="inline-flex items-center gap-2 rounded-full px-6 py-2.5 text-sm font-semibold bg-primary transition"
|
|
121
|
+
onclick={onContinue}
|
|
122
|
+
>
|
|
123
|
+
{continueText}
|
|
124
|
+
<HugeiconsIcon icon={ArrowRight01Icon} class="size-4" />
|
|
125
|
+
</button>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
{/if}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Props do componente ModalFeedback — modal de feedback com editor de texto rico.
|
|
3
|
+
* Quinta variação do sistema de modais do NegoDesign.
|
|
4
|
+
* @property title - Título principal do modal (ex: "Your Feedback").
|
|
5
|
+
* @property icon - Emoji/ícone exibido ao lado do título.
|
|
6
|
+
* @property placeholder - Texto placeholder da área de texto.
|
|
7
|
+
* @property buttonText - Texto do botão de submissão.
|
|
8
|
+
* @property buttonLoadingText - Texto exibido durante o carregamento.
|
|
9
|
+
* @property cancelText - Texto do botão cancelar.
|
|
10
|
+
* @property addImageText - Texto do botão de adicionar imagem.
|
|
11
|
+
* @property isLoading - Estado de carregamento do botão.
|
|
12
|
+
* @property isOpen - Controla a visibilidade do modal.
|
|
13
|
+
* @property onSubmit - Chamado ao submeter o feedback (conteúdo HTML + imagens).
|
|
14
|
+
* @property onAddImage - Chamado ao clicar no botão de adicionar imagem.
|
|
15
|
+
* @property onClose - Chamado ao fechar o modal.
|
|
16
|
+
* @property class - Classe CSS extra no container do modal.
|
|
17
|
+
*/
|
|
18
|
+
export type ModalFeedbackProps = {
|
|
19
|
+
title?: string;
|
|
20
|
+
icon?: string;
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
buttonText?: string;
|
|
23
|
+
buttonLoadingText?: string;
|
|
24
|
+
cancelText?: string;
|
|
25
|
+
addImageText?: string;
|
|
26
|
+
isLoading?: boolean;
|
|
27
|
+
isOpen?: boolean;
|
|
28
|
+
onSubmit?: (content: string, images: File[]) => void;
|
|
29
|
+
onAddImage?: () => void;
|
|
30
|
+
onClose?: () => void;
|
|
31
|
+
class?: string;
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../../../utils";
|
|
3
|
+
import ModalCore from "../../core/ui/ModalCore.svelte";
|
|
4
|
+
import type { ModalFeedbackProps } from "../types";
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
title = "Your Feedback",
|
|
8
|
+
icon = "🔥",
|
|
9
|
+
placeholder = "Write your feedback here...",
|
|
10
|
+
buttonText = "Send",
|
|
11
|
+
buttonLoadingText = "Sending...",
|
|
12
|
+
cancelText = "Cancel",
|
|
13
|
+
addImageText = "Add an Image",
|
|
14
|
+
isLoading = false,
|
|
15
|
+
isOpen = $bindable(false),
|
|
16
|
+
onSubmit,
|
|
17
|
+
onAddImage,
|
|
18
|
+
onClose,
|
|
19
|
+
class: className,
|
|
20
|
+
}: ModalFeedbackProps = $props();
|
|
21
|
+
|
|
22
|
+
let editorRef = $state<HTMLDivElement | null>(null);
|
|
23
|
+
let images = $state<File[]>([]);
|
|
24
|
+
|
|
25
|
+
function execCmd(command: string, value?: string) {
|
|
26
|
+
document.execCommand(command, false, value);
|
|
27
|
+
editorRef?.focus();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function handleAddImage() {
|
|
31
|
+
onAddImage?.();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function handleSubmit() {
|
|
35
|
+
const content = editorRef?.innerHTML ?? "";
|
|
36
|
+
if (!content.trim() || isLoading) return;
|
|
37
|
+
onSubmit?.(content, images);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function handleCancel() {
|
|
41
|
+
isOpen = false;
|
|
42
|
+
onClose?.();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const toolbarButtons = [
|
|
46
|
+
{ command: "bold", label: "B", class: "font-bold" },
|
|
47
|
+
{ command: "italic", label: "I", class: "italic" },
|
|
48
|
+
{ command: "underline", label: "U", class: "underline" },
|
|
49
|
+
{ command: "insertUnorderedList", label: "•", class: "" },
|
|
50
|
+
{ command: "insertOrderedList", label: "1.", class: "" },
|
|
51
|
+
{ command: "undo", label: "↶", class: "" },
|
|
52
|
+
{ command: "redo", label: "↷", class: "" },
|
|
53
|
+
{ command: "justifyLeft", label: "⫷", class: "" },
|
|
54
|
+
{ command: "justifyCenter", label: "⫿", class: "" },
|
|
55
|
+
{ command: "justifyRight", label: "⫸", class: "" },
|
|
56
|
+
] as const;
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<ModalCore
|
|
60
|
+
bind:isOpen
|
|
61
|
+
{title}
|
|
62
|
+
showProgress={false}
|
|
63
|
+
showBack={false}
|
|
64
|
+
{onClose}
|
|
65
|
+
class={cn("max-w-lg", className)}
|
|
66
|
+
>
|
|
67
|
+
{#snippet content()}
|
|
68
|
+
<!-- Toolbar -->
|
|
69
|
+
<div class="mb-3 flex flex-wrap items-center gap-1 rounded-t-lg border border-border bg-muted/50 px-3 py-2">
|
|
70
|
+
{#each toolbarButtons as btn (btn.command)}
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
class={cn(
|
|
74
|
+
"flex size-8 items-center justify-center rounded text-sm text-muted-foreground transition hover:bg-border hover:text-foreground",
|
|
75
|
+
btn.class
|
|
76
|
+
)}
|
|
77
|
+
onclick={() => execCmd(btn.command)}
|
|
78
|
+
title={btn.command}
|
|
79
|
+
>
|
|
80
|
+
{btn.label}
|
|
81
|
+
</button>
|
|
82
|
+
{/each}
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<!-- Editor -->
|
|
86
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
87
|
+
<div
|
|
88
|
+
bind:this={editorRef}
|
|
89
|
+
contenteditable="true"
|
|
90
|
+
class="min-h-[160px] rounded-b-lg border border-t-0 border-border bg-card px-4 py-3 text-sm text-foreground outline-none focus:ring-2 focus:ring-primary/20"
|
|
91
|
+
data-placeholder={placeholder}
|
|
92
|
+
onkeydown={(e) => {
|
|
93
|
+
if (e.key === "Enter" && e.ctrlKey) handleSubmit();
|
|
94
|
+
}}
|
|
95
|
+
></div>
|
|
96
|
+
|
|
97
|
+
<!-- Add Image Button -->
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
class="mt-4 flex w-full items-center justify-center gap-2 rounded-lg border-2 border-dashed border-orange-300 bg-orange-50/50 py-3 text-sm font-medium text-orange-600 transition hover:bg-orange-50 dark:bg-orange-950/20 dark:text-orange-400 dark:hover:bg-orange-950/30"
|
|
101
|
+
onclick={handleAddImage}
|
|
102
|
+
>
|
|
103
|
+
<span class="text-lg">🖼️</span>
|
|
104
|
+
{addImageText}
|
|
105
|
+
</button>
|
|
106
|
+
{/snippet}
|
|
107
|
+
|
|
108
|
+
{#snippet footer()}
|
|
109
|
+
<div class="flex items-center justify-end gap-3">
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
class="rounded-lg border border-border px-5 py-2.5 text-sm font-semibold transition hover:bg-muted"
|
|
113
|
+
onclick={handleCancel}
|
|
114
|
+
>
|
|
115
|
+
{cancelText}
|
|
116
|
+
</button>
|
|
117
|
+
<button
|
|
118
|
+
type="button"
|
|
119
|
+
disabled={isLoading}
|
|
120
|
+
class="rounded-lg bg-orange-500 px-6 py-2.5 text-sm font-semibold text-white transition hover:bg-orange-600 disabled:cursor-not-allowed disabled:opacity-50"
|
|
121
|
+
onclick={handleSubmit}
|
|
122
|
+
>
|
|
123
|
+
{isLoading ? buttonLoadingText : buttonText}
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
{/snippet}
|
|
127
|
+
</ModalCore>
|
|
128
|
+
|
|
129
|
+
<style>
|
|
130
|
+
[contenteditable]:empty:before {
|
|
131
|
+
content: attr(data-placeholder);
|
|
132
|
+
color: oklch(0.56 0.021 213.5);
|
|
133
|
+
pointer-events: none;
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { FormInputConfig } from "../../form/types";
|
|
2
|
+
export type { FormInputConfig, FormOption, FormProps } from "../../form/types";
|
|
3
|
+
/**
|
|
4
|
+
* Props do componente ModalForm — formulário dentro de um modal.
|
|
5
|
+
* Reutiliza o componente Form com a mesma API de inputs, adicionando
|
|
6
|
+
* overlay, título, subtítulo e botões de navegação do modal.
|
|
7
|
+
*
|
|
8
|
+
* @property title - Título principal do modal.
|
|
9
|
+
* @property subtitle - Subtítulo/descrição abaixo do título.
|
|
10
|
+
* @property inputs - Array de configurações dos inputs do formulário.
|
|
11
|
+
* @property isOpen - Controla a visibilidade do modal (bindable).
|
|
12
|
+
* @property submitText - Texto do botão de submissão.
|
|
13
|
+
* @property submitLoadingText - Texto durante carregamento.
|
|
14
|
+
* @property cancelText - Texto do botão cancelar.
|
|
15
|
+
* @property isLoading - Estado de carregamento.
|
|
16
|
+
* @property showCancel - Exibe o botão cancelar.
|
|
17
|
+
* @property columns - Número de colunas da grid (padrão: 2).
|
|
18
|
+
* @property onSubmit - Callback ao submeter o formulário.
|
|
19
|
+
* @property onCancel - Chamado ao clicar no botão cancelar ou fechar.
|
|
20
|
+
* @property onClose - Chamado ao fechar o modal.
|
|
21
|
+
* @property class - Classe CSS extra no container do modal.
|
|
22
|
+
*/
|
|
23
|
+
export type ModalFormProps = {
|
|
24
|
+
title: string;
|
|
25
|
+
subtitle?: string;
|
|
26
|
+
inputs: FormInputConfig[];
|
|
27
|
+
isOpen?: boolean;
|
|
28
|
+
submitText?: string;
|
|
29
|
+
submitLoadingText?: string;
|
|
30
|
+
cancelText?: string;
|
|
31
|
+
isLoading?: boolean;
|
|
32
|
+
showCancel?: boolean;
|
|
33
|
+
columns?: 1 | 2;
|
|
34
|
+
onSubmit?: (data: Record<string, string | string[] | boolean>) => void;
|
|
35
|
+
onCancel?: () => void;
|
|
36
|
+
onClose?: () => void;
|
|
37
|
+
class?: string;
|
|
38
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../../../utils";
|
|
3
|
+
import ModalCore from "../../core/ui/ModalCore.svelte";
|
|
4
|
+
import Form from "../../../form/Form.svelte";
|
|
5
|
+
import type { ModalFormProps } from "../types";
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
title,
|
|
9
|
+
subtitle,
|
|
10
|
+
inputs = [],
|
|
11
|
+
isOpen = $bindable(false),
|
|
12
|
+
submitText = "Submit",
|
|
13
|
+
submitLoadingText = "Submitting...",
|
|
14
|
+
cancelText = "Cancel",
|
|
15
|
+
isLoading = false,
|
|
16
|
+
showCancel = true,
|
|
17
|
+
columns = 2,
|
|
18
|
+
onSubmit,
|
|
19
|
+
onCancel,
|
|
20
|
+
onClose,
|
|
21
|
+
class: className,
|
|
22
|
+
}: ModalFormProps = $props();
|
|
23
|
+
|
|
24
|
+
function handleSubmit(data: Record<string, string | string[] | boolean>) {
|
|
25
|
+
onSubmit?.(data);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function handleCancel() {
|
|
29
|
+
isOpen = false;
|
|
30
|
+
onCancel?.();
|
|
31
|
+
}
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<ModalCore
|
|
35
|
+
bind:isOpen
|
|
36
|
+
{title}
|
|
37
|
+
{subtitle}
|
|
38
|
+
showProgress={false}
|
|
39
|
+
showBack={false}
|
|
40
|
+
{onClose}
|
|
41
|
+
class={cn("max-w-2xl", className)}
|
|
42
|
+
>
|
|
43
|
+
{#snippet content()}
|
|
44
|
+
<Form
|
|
45
|
+
{inputs}
|
|
46
|
+
{columns}
|
|
47
|
+
{submitText}
|
|
48
|
+
{submitLoadingText}
|
|
49
|
+
{isLoading}
|
|
50
|
+
onSubmit={handleSubmit}
|
|
51
|
+
/>
|
|
52
|
+
{/snippet}
|
|
53
|
+
|
|
54
|
+
{#snippet footer()}
|
|
55
|
+
{#if showCancel}
|
|
56
|
+
<div class="flex items-center justify-end gap-3">
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
class="rounded-lg border border-border px-5 py-2.5 text-sm font-semibold transition hover:bg-muted"
|
|
60
|
+
onclick={handleCancel}
|
|
61
|
+
>
|
|
62
|
+
{cancelText}
|
|
63
|
+
</button>
|
|
64
|
+
</div>
|
|
65
|
+
{/if}
|
|
66
|
+
{/snippet}
|
|
67
|
+
</ModalCore>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import Root from "./ui/ModalGridSelection.svelte";
|
|
2
|
+
import ModalGridSelection01 from "./ui/01/ModalGridSelection01.svelte";
|
|
3
|
+
import ModalGridSelection02 from "./ui/02/ModalGridSelection02.svelte";
|
|
4
|
+
export { Root, Root as ModalGridSelection, ModalGridSelection01, ModalGridSelection02, };
|
|
5
|
+
export type { ModelGridCard, ModelGridCategory, ModalGridSelectionProps } from "./types";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import Root from "./ui/ModalGridSelection.svelte";
|
|
2
|
+
import ModalGridSelection01 from "./ui/01/ModalGridSelection01.svelte";
|
|
3
|
+
import ModalGridSelection02 from "./ui/02/ModalGridSelection02.svelte";
|
|
4
|
+
export { Root, Root as ModalGridSelection, ModalGridSelection01, ModalGridSelection02, };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type { ModelGridCard } from "../core/types";
|
|
2
|
+
/**
|
|
3
|
+
* Modelo de dados para uma categoria/selecção no topo do modal (variante 2).
|
|
4
|
+
* Cada categoria filtra ou indica o contexto dos cards.
|
|
5
|
+
* @property label - Texto visível da categoria.
|
|
6
|
+
* @property value - Valor identificador da categoria.
|
|
7
|
+
*/
|
|
8
|
+
export type ModelGridCategory = {
|
|
9
|
+
label: string;
|
|
10
|
+
value: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Props do componente ModalGridSelection — modal de seleção em grid.
|
|
14
|
+
* Suporta duas variantes visuais: 1 (centrado 3 colunas) e 2 (dark 2 colunas + categorias).
|
|
15
|
+
* @property variant - Variante visual do modal (1 ou 2).
|
|
16
|
+
* @property title - Título principal do modal.
|
|
17
|
+
* @property subtitle - Subtítulo/descrição abaixo do título.
|
|
18
|
+
* @property categories - Lista de categorias no topo (apenas variante 2).
|
|
19
|
+
* @property selectedCategory - Categoria seleccionada (apenas variante 2).
|
|
20
|
+
* @property cards - Lista de cards seleccionáveis.
|
|
21
|
+
* @property selectedCard - Card actualmente seleccionado.
|
|
22
|
+
* @property selectedCards - Cards seleccionados (modo múltiplo, variante 2).
|
|
23
|
+
* @property multiple - Permite seleção múltipla (variante 2).
|
|
24
|
+
* @property totalSteps - Número total de passos (para pagination dots).
|
|
25
|
+
* @property currentStep - Passo actual (para pagination dots).
|
|
26
|
+
* @property isOpen - Controla a visibilidade do modal.
|
|
27
|
+
* @property onSelect - Chamado ao seleccionar um card.
|
|
28
|
+
* @property onSelectCategory - Chamado ao seleccionar uma categoria (variante 2).
|
|
29
|
+
* @property onBack - Chamado ao clicar no botão "Back".
|
|
30
|
+
* @property onContinue - Chamado ao clicar no botão "Continue".
|
|
31
|
+
* @property class - Classe CSS extra no container do modal.
|
|
32
|
+
*/
|
|
33
|
+
export type ModalGridSelectionProps = {
|
|
34
|
+
variant?: 1 | 2;
|
|
35
|
+
title: string;
|
|
36
|
+
subtitle?: string;
|
|
37
|
+
categories?: ModelGridCategory[];
|
|
38
|
+
selectedCategory?: ModelGridCategory | null;
|
|
39
|
+
cards: import("../core/types").ModelGridCard[];
|
|
40
|
+
selectedCard?: import("../core/types").ModelGridCard | null;
|
|
41
|
+
selectedCards?: import("../core/types").ModelGridCard[];
|
|
42
|
+
multiple?: boolean;
|
|
43
|
+
totalSteps?: number;
|
|
44
|
+
currentStep?: number;
|
|
45
|
+
isOpen?: boolean;
|
|
46
|
+
onSelect?: (card: import("../core/types").ModelGridCard) => void;
|
|
47
|
+
onSelectCategory?: (category: ModelGridCategory) => void;
|
|
48
|
+
onBack?: () => void;
|
|
49
|
+
onContinue?: () => void;
|
|
50
|
+
class?: string;
|
|
51
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "../../../../../../utils";
|
|
3
|
+
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
4
|
+
import ModalCore from "../../../core/ui/ModalCore.svelte";
|
|
5
|
+
import type { ModalGridSelectionProps, ModelGridCard } from "../../types";
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
title,
|
|
9
|
+
subtitle,
|
|
10
|
+
cards = [],
|
|
11
|
+
selectedCard = $bindable(null),
|
|
12
|
+
totalSteps = 1,
|
|
13
|
+
currentStep = 1,
|
|
14
|
+
isOpen = $bindable(false),
|
|
15
|
+
onSelect,
|
|
16
|
+
onBack,
|
|
17
|
+
onContinue,
|
|
18
|
+
class: className,
|
|
19
|
+
}: ModalGridSelectionProps = $props();
|
|
20
|
+
|
|
21
|
+
let hoveredIndex = $state<number | null>(null);
|
|
22
|
+
|
|
23
|
+
function handleSelect(card: ModelGridCard) {
|
|
24
|
+
selectedCard = card;
|
|
25
|
+
onSelect?.(card);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isSelected(card: ModelGridCard): boolean {
|
|
29
|
+
return selectedCard?.title === card.title;
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<ModalCore
|
|
34
|
+
bind:isOpen
|
|
35
|
+
{title}
|
|
36
|
+
{subtitle}
|
|
37
|
+
{totalSteps}
|
|
38
|
+
{currentStep}
|
|
39
|
+
showProgress={false}
|
|
40
|
+
showBack={currentStep > 1}
|
|
41
|
+
{onBack}
|
|
42
|
+
{onContinue}
|
|
43
|
+
class={className}
|
|
44
|
+
>
|
|
45
|
+
{#snippet content()}
|
|
46
|
+
<div class="grid grid-cols-2 gap-4 md:grid-cols-3">
|
|
47
|
+
{#each cards as card, i (i)}
|
|
48
|
+
{@const selected = isSelected(card)}
|
|
49
|
+
{@const hovered = hoveredIndex === i}
|
|
50
|
+
<button
|
|
51
|
+
type="button"
|
|
52
|
+
class={cn(
|
|
53
|
+
"flex flex-col items-center gap-3 rounded-xl border-2 p-6 text-center transition-all duration-200",
|
|
54
|
+
selected
|
|
55
|
+
? "border-primary bg-primary/5 shadow-md"
|
|
56
|
+
: "border-border hover:border-primary/50 hover:shadow-sm",
|
|
57
|
+
hovered && !selected && "border-primary/30"
|
|
58
|
+
)}
|
|
59
|
+
onclick={() => handleSelect(card)}
|
|
60
|
+
onmouseenter={() => (hoveredIndex = i)}
|
|
61
|
+
onmouseleave={() => (hoveredIndex = null)}
|
|
62
|
+
>
|
|
63
|
+
{#if typeof card.icon === "string"}
|
|
64
|
+
<i class="{card.icon} text-4xl text-muted-foreground md:text-5xl"></i>
|
|
65
|
+
{:else}
|
|
66
|
+
<HugeiconsIcon
|
|
67
|
+
icon={card.icon}
|
|
68
|
+
class="size-10 text-muted-foreground md:size-12"
|
|
69
|
+
/>
|
|
70
|
+
{/if}
|
|
71
|
+
|
|
72
|
+
<p class="text-sm font-bold md:text-base">{card.title}</p>
|
|
73
|
+
|
|
74
|
+
{#if card.description}
|
|
75
|
+
<p class="line-clamp-2 text-xs text-muted-foreground md:text-sm">
|
|
76
|
+
{card.description}
|
|
77
|
+
</p>
|
|
78
|
+
{/if}
|
|
79
|
+
</button>
|
|
80
|
+
{/each}
|
|
81
|
+
</div>
|
|
82
|
+
{/snippet}
|
|
83
|
+
</ModalCore>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ModalGridSelectionProps } from "../../types";
|
|
2
|
+
declare const ModalGridSelection01: import("svelte").Component<ModalGridSelectionProps, {}, "isOpen" | "selectedCard">;
|
|
3
|
+
type ModalGridSelection01 = ReturnType<typeof ModalGridSelection01>;
|
|
4
|
+
export default ModalGridSelection01;
|