zabi-components 4.0.2 → 5.0.1
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/README.md +2 -2
- package/dist/SSRSafe.svelte +47 -0
- package/dist/SSRSafe.svelte.d.ts +11 -0
- package/dist/atoms/Badge.svelte +76 -0
- package/dist/atoms/Badge.svelte.d.ts +9 -0
- package/dist/atoms/Button.svelte +72 -0
- package/dist/atoms/Button.svelte.d.ts +13 -0
- package/dist/atoms/Card.svelte +59 -0
- package/dist/atoms/Card.svelte.d.ts +12 -0
- package/dist/atoms/Checkbox.svelte +60 -0
- package/dist/atoms/Checkbox.svelte.d.ts +10 -0
- package/dist/atoms/CodeBlock.svelte +125 -0
- package/dist/atoms/CodeBlock.svelte.d.ts +8 -0
- package/dist/atoms/ColorPicker.svelte +171 -0
- package/dist/atoms/ColorPicker.svelte.d.ts +9 -0
- package/dist/atoms/FeatureCard.svelte +74 -0
- package/dist/atoms/FeatureCard.svelte.d.ts +17 -0
- package/dist/atoms/Heading.svelte +5 -0
- package/dist/atoms/Heading.svelte.d.ts +7 -0
- package/dist/atoms/Input.svelte +98 -0
- package/dist/atoms/Input.svelte.d.ts +14 -0
- package/dist/atoms/OptimizedImage.svelte +32 -0
- package/dist/atoms/OptimizedImage.svelte.d.ts +13 -0
- package/dist/atoms/Progress.svelte +61 -0
- package/dist/atoms/Progress.svelte.d.ts +9 -0
- package/dist/atoms/Select.svelte +85 -0
- package/dist/atoms/Select.svelte.d.ts +16 -0
- package/dist/atoms/Skeleton.svelte +20 -0
- package/dist/atoms/Skeleton.svelte.d.ts +8 -0
- package/dist/atoms/Textarea.svelte +116 -0
- package/dist/atoms/Textarea.svelte.d.ts +14 -0
- package/dist/atoms/ThemeToggle.svelte +89 -0
- package/dist/atoms/ThemeToggle.svelte.d.ts +7 -0
- package/dist/atoms/Toast.svelte +58 -0
- package/dist/atoms/Toast.svelte.d.ts +9 -0
- package/dist/atoms/Toggle.svelte +94 -0
- package/dist/atoms/Toggle.svelte.d.ts +12 -0
- package/dist/atoms/Tooltip.svelte +188 -0
- package/dist/atoms/Tooltip.svelte.d.ts +12 -0
- package/dist/atoms/index.d.ts +4 -15
- package/dist/atoms/index.js +10 -23
- package/dist/components/atoms/index.d.ts +10 -0
- package/dist/components/atoms/index.d.ts.map +1 -0
- package/dist/components/index.d.ts +31 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/molecules/index.d.ts +1 -0
- package/dist/components/molecules/index.d.ts.map +1 -0
- package/dist/components/organisms/index.d.ts +1 -0
- package/dist/components/organisms/index.d.ts.map +1 -0
- package/dist/index.d.ts +30 -15
- package/dist/index.js +74 -0
- package/dist/molecules/Alert.svelte +114 -0
- package/dist/molecules/Alert.svelte.d.ts +14 -0
- package/dist/molecules/ComponentDemo.svelte +96 -0
- package/dist/molecules/ComponentDemo.svelte.d.ts +13 -0
- package/dist/molecules/ContactForm.svelte +98 -0
- package/dist/molecules/ContactForm.svelte.d.ts +10 -0
- package/dist/molecules/Dropdown.svelte +128 -0
- package/dist/molecules/Dropdown.svelte.d.ts +11 -0
- package/dist/molecules/Form.svelte +37 -0
- package/dist/molecules/Form.svelte.d.ts +12 -0
- package/dist/molecules/ImageUpload.svelte +112 -0
- package/dist/molecules/ImageUpload.svelte.d.ts +14 -0
- package/dist/molecules/Modal.svelte +85 -0
- package/dist/molecules/Modal.svelte.d.ts +13 -0
- package/dist/molecules/SlideUp.svelte +73 -0
- package/dist/molecules/SlideUp.svelte.d.ts +12 -0
- package/dist/molecules/Tabs.svelte +68 -0
- package/dist/molecules/Tabs.svelte.d.ts +17 -0
- package/dist/molecules/index.d.ts +0 -11
- package/dist/molecules/index.js +2 -13
- package/dist/organisms/Navbar.svelte +99 -0
- package/dist/organisms/Navbar.svelte.d.ts +14 -0
- package/dist/organisms/Navigation.svelte +48 -0
- package/dist/organisms/Navigation.svelte.d.ts +15 -0
- package/dist/organisms/index.d.ts +0 -4
- package/dist/organisms/index.js +2 -5
- package/dist/routes/lib/ssr-safe.ts +57 -0
- package/dist/routes/lib/variant-utils.ts +98 -0
- package/dist/zabi-components.css +399 -1
- package/package.json +41 -17
- package/dist/CodeBlock-pT5-FgZd.js +0 -431
- package/dist/ContactForm-CHI_jeFY.js +0 -580
- package/dist/FeatureCard-iBFGbgVE.js +0 -656
- package/dist/Navigation-BOT-UHg0.js +0 -104
- package/dist/ThemeToggle-BlNPkAQy.js +0 -48
- package/dist/index/index.js +0 -63
- package/dist/molecules/KeyValueForm.types.d.ts +0 -11
- package/dist/ssr-safe-bsWGK4V4.js +0 -2232
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.js +0 -1
- package/dist/vite.svg +0 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { default as Toggle } from './atoms/Toggle.svelte';
|
|
2
|
+
export { default as Badge } from './atoms/Badge.svelte';
|
|
3
|
+
export { default as Button } from './atoms/Button.svelte';
|
|
4
|
+
export { default as Card } from './atoms/Card.svelte';
|
|
5
|
+
export { default as Input } from './atoms/Input.svelte';
|
|
6
|
+
export { default as Textarea } from './atoms/Textarea.svelte';
|
|
7
|
+
export { default as Select } from './atoms/Select.svelte';
|
|
8
|
+
export { default as ColorPicker } from './atoms/ColorPicker.svelte';
|
|
9
|
+
export { default as Heading } from './atoms/Heading.svelte';
|
|
10
|
+
export { default as Alert } from './molecules/Alert.svelte';
|
|
11
|
+
export { default as ComponentDemo } from './molecules/ComponentDemo.svelte';
|
|
12
|
+
export { default as ContactForm } from './molecules/ContactForm.svelte';
|
|
13
|
+
export { default as Dropdown } from './molecules/Dropdown.svelte';
|
|
14
|
+
export { default as Form } from './molecules/Form.svelte';
|
|
15
|
+
export { default as ImageUpload } from './molecules/ImageUpload.svelte';
|
|
16
|
+
export { default as Modal } from './molecules/Modal.svelte';
|
|
17
|
+
export { default as SlideUp } from './molecules/SlideUp.svelte';
|
|
18
|
+
export { default as Tabs } from './molecules/Tabs.svelte';
|
|
19
|
+
export { default as Navbar } from './organisms/Navbar.svelte';
|
|
20
|
+
export { default as Navigation } from './organisms/Navigation.svelte';
|
|
21
|
+
export declare const createId: (prefix?: string) => string;
|
|
22
|
+
export declare const cn: (...classes: (string | undefined | null | false)[]) => string;
|
|
23
|
+
export declare const getFormData: (form: HTMLFormElement) => Record<string, any>;
|
|
24
|
+
export declare const validateEmail: (email: string) => boolean;
|
|
25
|
+
export declare const validateRequired: (value: any) => boolean;
|
|
26
|
+
export declare const isBrowser: () => boolean;
|
|
27
|
+
export declare const safeWindow: () => Window | undefined;
|
|
28
|
+
export declare const safeDocument: () => Document | undefined;
|
|
29
|
+
export declare const safeLocalStorage: () => Storage | undefined;
|
|
30
|
+
export declare const generateId: (prefix?: string) => string;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAM5D,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAM1D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAOtE,eAAO,MAAM,QAAQ,GAAI,SAAQ,MAAa,KAAG,MAMhD,CAAC;AAEF,eAAO,MAAM,EAAE,GAAI,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC,EAAE,KAAG,MAClC,CAAC;AAGtC,eAAO,MAAM,WAAW,GAAI,MAAM,eAAe,KAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAGrE,CAAC;AAGF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,OAG7C,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,GAAG,KAAG,OAE7C,CAAC;AAGF,eAAO,MAAM,SAAS,QAAO,OAE5B,CAAC;AAEF,eAAO,MAAM,UAAU,QAAO,MAAM,GAAG,SAEtC,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,QAAQ,GAAG,SAE1C,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAO,OAAO,GAAG,SAE7C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAQ,MAAa,KAAG,MAElD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/molecules/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/organisms/index.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
export
|
|
1
|
+
export { default as Toggle } from './atoms/Toggle.svelte';
|
|
2
|
+
export { default as Badge } from './atoms/Badge.svelte';
|
|
3
|
+
export { default as Button } from './atoms/Button.svelte';
|
|
4
|
+
export { default as Card } from './atoms/Card.svelte';
|
|
5
|
+
export { default as Input } from './atoms/Input.svelte';
|
|
6
|
+
export { default as Textarea } from './atoms/Textarea.svelte';
|
|
7
|
+
export { default as Select } from './atoms/Select.svelte';
|
|
8
|
+
export { default as ColorPicker } from './atoms/ColorPicker.svelte';
|
|
9
|
+
export { default as Heading } from './atoms/Heading.svelte';
|
|
10
|
+
export { default as Alert } from './molecules/Alert.svelte';
|
|
11
|
+
export { default as ComponentDemo } from './molecules/ComponentDemo.svelte';
|
|
12
|
+
export { default as ContactForm } from './molecules/ContactForm.svelte';
|
|
13
|
+
export { default as Dropdown } from './molecules/Dropdown.svelte';
|
|
14
|
+
export { default as Form } from './molecules/Form.svelte';
|
|
15
|
+
export { default as ImageUpload } from './molecules/ImageUpload.svelte';
|
|
16
|
+
export { default as Modal } from './molecules/Modal.svelte';
|
|
17
|
+
export { default as SlideUp } from './molecules/SlideUp.svelte';
|
|
18
|
+
export { default as Tabs } from './molecules/Tabs.svelte';
|
|
19
|
+
export { default as Navbar } from './organisms/Navbar.svelte';
|
|
20
|
+
export { default as Navigation } from './organisms/Navigation.svelte';
|
|
21
|
+
export declare const createId: (prefix?: string) => string;
|
|
22
|
+
export declare const cn: (...classes: (string | undefined | null | false)[]) => string;
|
|
23
|
+
export declare const getFormData: (form: HTMLFormElement) => Record<string, any>;
|
|
24
|
+
export declare const validateEmail: (email: string) => boolean;
|
|
25
|
+
export declare const validateRequired: (value: any) => boolean;
|
|
26
|
+
export declare const isBrowser: () => boolean;
|
|
27
|
+
export declare const safeWindow: () => Window | undefined;
|
|
28
|
+
export declare const safeDocument: () => Document | undefined;
|
|
29
|
+
export declare const safeLocalStorage: () => Storage | undefined;
|
|
30
|
+
export declare const generateId: (prefix?: string) => string;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Zabi Components - Clean & Simple Svelte Component Library
|
|
2
|
+
// Main library entry point - All components in one place
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// ATOM COMPONENTS - Basic UI building blocks
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Form Controls - All SSR-safe components
|
|
7
|
+
export { default as Toggle } from './atoms/Toggle.svelte';
|
|
8
|
+
export { default as Badge } from './atoms/Badge.svelte';
|
|
9
|
+
export { default as Button } from './atoms/Button.svelte';
|
|
10
|
+
export { default as Card } from './atoms/Card.svelte';
|
|
11
|
+
export { default as Input } from './atoms/Input.svelte';
|
|
12
|
+
export { default as Textarea } from './atoms/Textarea.svelte';
|
|
13
|
+
export { default as Select } from './atoms/Select.svelte';
|
|
14
|
+
export { default as ColorPicker } from './atoms/ColorPicker.svelte';
|
|
15
|
+
export { default as Heading } from './atoms/Heading.svelte';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// MOLECULE COMPONENTS - Composite UI elements
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export { default as Alert } from './molecules/Alert.svelte';
|
|
20
|
+
export { default as ComponentDemo } from './molecules/ComponentDemo.svelte';
|
|
21
|
+
export { default as ContactForm } from './molecules/ContactForm.svelte';
|
|
22
|
+
export { default as Dropdown } from './molecules/Dropdown.svelte';
|
|
23
|
+
export { default as Form } from './molecules/Form.svelte';
|
|
24
|
+
export { default as ImageUpload } from './molecules/ImageUpload.svelte';
|
|
25
|
+
export { default as Modal } from './molecules/Modal.svelte';
|
|
26
|
+
export { default as SlideUp } from './molecules/SlideUp.svelte';
|
|
27
|
+
export { default as Tabs } from './molecules/Tabs.svelte';
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// ORGANISM COMPONENTS - Complex UI sections
|
|
30
|
+
// ============================================================================
|
|
31
|
+
export { default as Navbar } from './organisms/Navbar.svelte';
|
|
32
|
+
export { default as Navigation } from './organisms/Navigation.svelte';
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// UTILITIES - Helper functions and utilities
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Simple utility functions
|
|
37
|
+
export const createId = (prefix = 'id') => {
|
|
38
|
+
if (typeof window !== 'undefined') {
|
|
39
|
+
return `${prefix}-${Math.random().toString(36).substr(2, 9)}`;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return `${prefix}-ssr-${Date.now()}`;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export const cn = (...classes) => classes.filter(Boolean).join(' ');
|
|
46
|
+
// Form utilities
|
|
47
|
+
export const getFormData = (form) => {
|
|
48
|
+
const formData = new FormData(form);
|
|
49
|
+
return Object.fromEntries(formData.entries());
|
|
50
|
+
};
|
|
51
|
+
// Validation utilities
|
|
52
|
+
export const validateEmail = (email) => {
|
|
53
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
54
|
+
return emailRegex.test(email);
|
|
55
|
+
};
|
|
56
|
+
export const validateRequired = (value) => {
|
|
57
|
+
return value !== null && value !== undefined && value !== '';
|
|
58
|
+
};
|
|
59
|
+
// SSR-safe utilities
|
|
60
|
+
export const isBrowser = () => {
|
|
61
|
+
return typeof window !== 'undefined';
|
|
62
|
+
};
|
|
63
|
+
export const safeWindow = () => {
|
|
64
|
+
return isBrowser() ? window : undefined;
|
|
65
|
+
};
|
|
66
|
+
export const safeDocument = () => {
|
|
67
|
+
return isBrowser() ? document : undefined;
|
|
68
|
+
};
|
|
69
|
+
export const safeLocalStorage = () => {
|
|
70
|
+
return isBrowser() ? localStorage : undefined;
|
|
71
|
+
};
|
|
72
|
+
export const generateId = (prefix = 'id') => {
|
|
73
|
+
return createId(prefix);
|
|
74
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
variant?: "info" | "success" | "warning" | "error";
|
|
4
|
+
title?: string;
|
|
5
|
+
message?: string;
|
|
6
|
+
closable?: boolean;
|
|
7
|
+
className?: string;
|
|
8
|
+
onclick?: (event: Event) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
variant = "info",
|
|
13
|
+
title = "",
|
|
14
|
+
message = "",
|
|
15
|
+
closable = false,
|
|
16
|
+
className = "",
|
|
17
|
+
onclick,
|
|
18
|
+
children,
|
|
19
|
+
...restProps
|
|
20
|
+
}: Props & { children?: any } = $props();
|
|
21
|
+
|
|
22
|
+
function handleDismiss(event: MouseEvent) {
|
|
23
|
+
// Call the parent's onclick handler if provided
|
|
24
|
+
if (onclick) {
|
|
25
|
+
onclick(event);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let alertClasses = $derived({
|
|
30
|
+
info: "bg-info-surface text-body border border-info",
|
|
31
|
+
success: "bg-success-surface text-success border border-success",
|
|
32
|
+
warning: "bg-warning-surface text-warning border border-warning",
|
|
33
|
+
error: "bg-error-surface text-error border border-error",
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
let alertRole = $derived(
|
|
37
|
+
variant === "success" || variant === "info" ? "status" : "alert",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
let iconSvg = $derived({
|
|
41
|
+
info: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
42
|
+
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
|
|
43
|
+
</svg>`,
|
|
44
|
+
success: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
45
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
|
46
|
+
</svg>`,
|
|
47
|
+
warning: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
48
|
+
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
|
|
49
|
+
</svg>`,
|
|
50
|
+
error: `<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
|
51
|
+
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />
|
|
52
|
+
</svg>`,
|
|
53
|
+
});
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<div
|
|
57
|
+
class="relative rounded-md p-4 border {alertClasses[
|
|
58
|
+
variant
|
|
59
|
+
]} transition-all duration-200 motion-reduce:transition-none {className}"
|
|
60
|
+
role={alertRole}
|
|
61
|
+
aria-live={variant === "success" || variant === "info"
|
|
62
|
+
? "polite"
|
|
63
|
+
: "assertive"}
|
|
64
|
+
aria-atomic="true"
|
|
65
|
+
{...restProps}
|
|
66
|
+
>
|
|
67
|
+
<!-- Dismiss button (X in top right) -->
|
|
68
|
+
{#if closable}
|
|
69
|
+
<button
|
|
70
|
+
onclick={handleDismiss}
|
|
71
|
+
class="absolute top-2 right-2 z-10 w-6 h-6 flex items-center justify-center rounded-full text-description hover:text-body transition-colors duration-200 motion-reduce:transition-none group focus:outline-none focus:ring-2 focus:ring-focus-ring focus:ring-offset-2"
|
|
72
|
+
aria-label="Dismiss alert"
|
|
73
|
+
type="button"
|
|
74
|
+
>
|
|
75
|
+
<svg
|
|
76
|
+
class="w-4 h-4 text-current group-hover:scale-110 transition-transform duration-200 motion-reduce:transition-none"
|
|
77
|
+
fill="none"
|
|
78
|
+
stroke="currentColor"
|
|
79
|
+
viewBox="0 0 24 24"
|
|
80
|
+
>
|
|
81
|
+
<path
|
|
82
|
+
stroke-linecap="round"
|
|
83
|
+
stroke-linejoin="round"
|
|
84
|
+
stroke-width="2"
|
|
85
|
+
d="M6 18L18 6M6 6l12 12"
|
|
86
|
+
/>
|
|
87
|
+
</svg>
|
|
88
|
+
</button>
|
|
89
|
+
{/if}
|
|
90
|
+
|
|
91
|
+
<!-- Content -->
|
|
92
|
+
<div class="flex items-start gap-3 {closable ? 'pr-8' : ''}">
|
|
93
|
+
<!-- Icon -->
|
|
94
|
+
<div class="shrink-0 mt-0.5">
|
|
95
|
+
{@html iconSvg[variant]}
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<!-- Text content -->
|
|
99
|
+
<div class="flex-1 min-w-0">
|
|
100
|
+
{#if title}
|
|
101
|
+
<h4 class="font-semibold text-sm mb-1 text-headline">
|
|
102
|
+
{title}
|
|
103
|
+
</h4>
|
|
104
|
+
{/if}
|
|
105
|
+
{#if message}
|
|
106
|
+
<p class="text-sm leading-relaxed text-body">
|
|
107
|
+
{message}
|
|
108
|
+
</p>
|
|
109
|
+
{/if}
|
|
110
|
+
<!-- Default slot for custom content -->
|
|
111
|
+
{@render children?.()}
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
variant?: "info" | "success" | "warning" | "error";
|
|
3
|
+
title?: string;
|
|
4
|
+
message?: string;
|
|
5
|
+
closable?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
onclick?: (event: Event) => void;
|
|
8
|
+
}
|
|
9
|
+
type $$ComponentProps = Props & {
|
|
10
|
+
children?: any;
|
|
11
|
+
};
|
|
12
|
+
declare const Alert: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
13
|
+
type Alert = ReturnType<typeof Alert>;
|
|
14
|
+
export default Alert;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CodeBlock from "../atoms/CodeBlock.svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
code: string;
|
|
8
|
+
language?: string;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
title,
|
|
14
|
+
description = "",
|
|
15
|
+
code,
|
|
16
|
+
language = "svelte",
|
|
17
|
+
className = "",
|
|
18
|
+
children,
|
|
19
|
+
...restProps
|
|
20
|
+
} = $props<Props & { children?: any }>();
|
|
21
|
+
|
|
22
|
+
let showCode = $state(false);
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<div
|
|
26
|
+
class="component-demo bg-surface border border-border rounded-lg overflow-hidden {className}"
|
|
27
|
+
{...restProps}
|
|
28
|
+
>
|
|
29
|
+
<!-- Header -->
|
|
30
|
+
<div class="px-6 py-4 border-b border-border bg-surface-secondary">
|
|
31
|
+
<div class="flex items-center justify-between">
|
|
32
|
+
<div>
|
|
33
|
+
<h3 class="text-lg font-semibold text-text">{title}</h3>
|
|
34
|
+
{#if description}
|
|
35
|
+
<p class="text-sm text-text-secondary mt-1">
|
|
36
|
+
{description}
|
|
37
|
+
</p>
|
|
38
|
+
{/if}
|
|
39
|
+
</div>
|
|
40
|
+
<button
|
|
41
|
+
onclick={() => (showCode = !showCode)}
|
|
42
|
+
class="flex items-center gap-2 px-3 py-1.5 text-sm text-text-secondary hover:text-text hover:bg-surface rounded-md transition-colors duration-200"
|
|
43
|
+
aria-label={showCode ? "Show preview" : "Show code"}
|
|
44
|
+
>
|
|
45
|
+
{#if showCode}
|
|
46
|
+
<svg
|
|
47
|
+
class="w-4 h-4"
|
|
48
|
+
fill="none"
|
|
49
|
+
stroke="currentColor"
|
|
50
|
+
viewBox="0 0 24 24"
|
|
51
|
+
>
|
|
52
|
+
<path
|
|
53
|
+
stroke-linecap="round"
|
|
54
|
+
stroke-linejoin="round"
|
|
55
|
+
stroke-width="2"
|
|
56
|
+
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
57
|
+
/>
|
|
58
|
+
<path
|
|
59
|
+
stroke-linecap="round"
|
|
60
|
+
stroke-linejoin="round"
|
|
61
|
+
stroke-width="2"
|
|
62
|
+
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
|
63
|
+
/>
|
|
64
|
+
</svg>
|
|
65
|
+
Preview
|
|
66
|
+
{:else}
|
|
67
|
+
<svg
|
|
68
|
+
class="w-4 h-4"
|
|
69
|
+
fill="none"
|
|
70
|
+
stroke="currentColor"
|
|
71
|
+
viewBox="0 0 24 24"
|
|
72
|
+
>
|
|
73
|
+
<path
|
|
74
|
+
stroke-linecap="round"
|
|
75
|
+
stroke-linejoin="round"
|
|
76
|
+
stroke-width="2"
|
|
77
|
+
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
|
|
78
|
+
/>
|
|
79
|
+
</svg>
|
|
80
|
+
Code
|
|
81
|
+
{/if}
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<!-- Content -->
|
|
87
|
+
<div class="p-6">
|
|
88
|
+
{#if showCode}
|
|
89
|
+
<CodeBlock {code} {language} />
|
|
90
|
+
{:else}
|
|
91
|
+
<div class="min-h-[100px] flex items-center justify-center">
|
|
92
|
+
{@render children?.()}
|
|
93
|
+
</div>
|
|
94
|
+
{/if}
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
code: string;
|
|
5
|
+
language?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
type $$ComponentProps = Props & {
|
|
9
|
+
children?: any;
|
|
10
|
+
};
|
|
11
|
+
declare const ComponentDemo: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
12
|
+
type ComponentDemo = ReturnType<typeof ComponentDemo>;
|
|
13
|
+
export default ComponentDemo;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Form from "./Form.svelte";
|
|
3
|
+
import Input from "../atoms/Input.svelte";
|
|
4
|
+
import Textarea from "../atoms/Textarea.svelte";
|
|
5
|
+
import Checkbox from "../atoms/Checkbox.svelte";
|
|
6
|
+
import Button from "../atoms/Button.svelte";
|
|
7
|
+
import type { ContactFormData } from "../../types/page.types";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
className?: string;
|
|
11
|
+
onsubmit?: (event: SubmitEvent) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
className = "",
|
|
16
|
+
children,
|
|
17
|
+
...restProps
|
|
18
|
+
} = $props<Props & { children?: any }>();
|
|
19
|
+
|
|
20
|
+
let formData = $state<ContactFormData>({
|
|
21
|
+
name: "",
|
|
22
|
+
email: "",
|
|
23
|
+
message: "",
|
|
24
|
+
subscribe: false,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function handleFormSubmit(event: SubmitEvent) {
|
|
28
|
+
const formData = new FormData(event.target as HTMLFormElement);
|
|
29
|
+
const data: ContactFormData = {
|
|
30
|
+
name: (formData.get("name") as string) || "",
|
|
31
|
+
email: (formData.get("email") as string) || "",
|
|
32
|
+
message: (formData.get("message") as string) || "",
|
|
33
|
+
subscribe: formData.get("subscribe") === "on" || false,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Form submission is now handled by the parent component
|
|
37
|
+
// through event forwarding. The data is available for processing.
|
|
38
|
+
console.log("Form submitted with data:", data);
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<div class="max-w-md mx-auto {className}">
|
|
43
|
+
<div class="mb-6">
|
|
44
|
+
<h2 class="text-2xl font-bold text-headline mb-2">Get in Touch</h2>
|
|
45
|
+
<p class="text-description">
|
|
46
|
+
We'd love to hear from you. Send us a message and we'll respond as
|
|
47
|
+
soon as possible.
|
|
48
|
+
</p>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<Form onsubmit={handleFormSubmit} className="space-y-4">
|
|
52
|
+
<div class="space-y-4">
|
|
53
|
+
<Input
|
|
54
|
+
type="text"
|
|
55
|
+
name="name"
|
|
56
|
+
label="Name"
|
|
57
|
+
placeholder="Enter your name"
|
|
58
|
+
value={formData.name}
|
|
59
|
+
oninput={(e) =>
|
|
60
|
+
(formData.name = (e.target as HTMLInputElement).value)}
|
|
61
|
+
/>
|
|
62
|
+
<Input
|
|
63
|
+
type="email"
|
|
64
|
+
name="email"
|
|
65
|
+
label="Email"
|
|
66
|
+
placeholder="Enter your email"
|
|
67
|
+
value={formData.email}
|
|
68
|
+
oninput={(e) =>
|
|
69
|
+
(formData.email = (e.target as HTMLInputElement).value)}
|
|
70
|
+
/>
|
|
71
|
+
<Textarea
|
|
72
|
+
name="message"
|
|
73
|
+
label="Message"
|
|
74
|
+
placeholder="Enter your message"
|
|
75
|
+
rows={4}
|
|
76
|
+
value={formData.message}
|
|
77
|
+
oninput={(e) =>
|
|
78
|
+
(formData.message = (
|
|
79
|
+
e.target as HTMLTextAreaElement
|
|
80
|
+
).value)}
|
|
81
|
+
/>
|
|
82
|
+
<Checkbox
|
|
83
|
+
name="subscribe"
|
|
84
|
+
label="Subscribe to updates"
|
|
85
|
+
checked={formData.subscribe}
|
|
86
|
+
onchange={(e) =>
|
|
87
|
+
(formData.subscribe = (
|
|
88
|
+
e.target as HTMLInputElement
|
|
89
|
+
).checked)}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="pt-4">
|
|
93
|
+
<Button type="submit" variant="primary" size="md">
|
|
94
|
+
Send Message
|
|
95
|
+
</Button>
|
|
96
|
+
</div>
|
|
97
|
+
</Form>
|
|
98
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
className?: string;
|
|
3
|
+
onsubmit?: (event: SubmitEvent) => void;
|
|
4
|
+
}
|
|
5
|
+
type $$ComponentProps = Props & {
|
|
6
|
+
children?: any;
|
|
7
|
+
};
|
|
8
|
+
declare const ContactForm: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type ContactForm = ReturnType<typeof ContactForm>;
|
|
10
|
+
export default ContactForm;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
isOpen?: boolean;
|
|
4
|
+
placement?: "bottom-start" | "bottom-end" | "top-start" | "top-end";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
isOpen = false,
|
|
9
|
+
placement = "bottom-start",
|
|
10
|
+
children,
|
|
11
|
+
trigger,
|
|
12
|
+
...restProps
|
|
13
|
+
}: Props & { children?: any; trigger?: any } = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div
|
|
17
|
+
class="dropdown-container group relative inline-block"
|
|
18
|
+
data-placement={placement}
|
|
19
|
+
>
|
|
20
|
+
{@render trigger?.()}
|
|
21
|
+
|
|
22
|
+
{#if isOpen}
|
|
23
|
+
<div
|
|
24
|
+
class="dropdown-content opacity-100 visible transform-none group-hover:opacity-100 group-hover:visible group-focus-within:opacity-100 group-focus-within:visible"
|
|
25
|
+
>
|
|
26
|
+
{@render children?.()}
|
|
27
|
+
</div>
|
|
28
|
+
{/if}
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
.dropdown-container {
|
|
33
|
+
position: relative;
|
|
34
|
+
display: inline-block;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.dropdown-content {
|
|
38
|
+
position: absolute;
|
|
39
|
+
z-index: 50;
|
|
40
|
+
background-color: white;
|
|
41
|
+
border: 1px solid #e5e7eb;
|
|
42
|
+
border-radius: 0.5rem;
|
|
43
|
+
box-shadow:
|
|
44
|
+
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
|
45
|
+
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
46
|
+
min-width: 12rem;
|
|
47
|
+
opacity: 0;
|
|
48
|
+
visibility: hidden;
|
|
49
|
+
transition:
|
|
50
|
+
opacity 0.2s ease-in-out,
|
|
51
|
+
visibility 0.2s ease-in-out,
|
|
52
|
+
transform 0.2s ease-in-out;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Positioning based on data-placement */
|
|
56
|
+
.dropdown-container[data-placement="bottom-start"] .dropdown-content {
|
|
57
|
+
top: calc(100% + 8px);
|
|
58
|
+
left: 0;
|
|
59
|
+
transform: translateY(4px);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.dropdown-container[data-placement="bottom-end"] .dropdown-content {
|
|
63
|
+
top: calc(100% + 8px);
|
|
64
|
+
right: 0;
|
|
65
|
+
transform: translateY(4px);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.dropdown-container[data-placement="top-start"] .dropdown-content {
|
|
69
|
+
bottom: calc(100% + 8px);
|
|
70
|
+
left: 0;
|
|
71
|
+
transform: translateY(-4px);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.dropdown-container[data-placement="top-end"] .dropdown-content {
|
|
75
|
+
bottom: calc(100% + 8px);
|
|
76
|
+
right: 0;
|
|
77
|
+
transform: translateY(-4px);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Show on hover/focus */
|
|
81
|
+
.dropdown-container:hover .dropdown-content,
|
|
82
|
+
.dropdown-container:focus-within .dropdown-content {
|
|
83
|
+
opacity: 1;
|
|
84
|
+
visibility: visible;
|
|
85
|
+
transform: translateY(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Arrow styling */
|
|
89
|
+
.dropdown-content::before {
|
|
90
|
+
content: "";
|
|
91
|
+
position: absolute;
|
|
92
|
+
width: 0;
|
|
93
|
+
height: 0;
|
|
94
|
+
border-style: solid;
|
|
95
|
+
border-width: 6px;
|
|
96
|
+
border-color: transparent;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.dropdown-container[data-placement="bottom-start"]
|
|
100
|
+
.dropdown-content::before,
|
|
101
|
+
.dropdown-container[data-placement="bottom-end"] .dropdown-content::before {
|
|
102
|
+
top: -6px;
|
|
103
|
+
border-bottom-color: white;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.dropdown-container[data-placement="top-start"] .dropdown-content::before,
|
|
107
|
+
.dropdown-container[data-placement="top-end"] .dropdown-content::before {
|
|
108
|
+
bottom: -6px;
|
|
109
|
+
border-top-color: white;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.dropdown-container[data-placement="bottom-start"]
|
|
113
|
+
.dropdown-content::before {
|
|
114
|
+
left: 1rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.dropdown-container[data-placement="bottom-end"] .dropdown-content::before {
|
|
118
|
+
right: 1rem;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.dropdown-container[data-placement="top-start"] .dropdown-content::before {
|
|
122
|
+
left: 1rem;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.dropdown-container[data-placement="top-end"] .dropdown-content::before {
|
|
126
|
+
right: 1rem;
|
|
127
|
+
}
|
|
128
|
+
</style>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
isOpen?: boolean;
|
|
3
|
+
placement?: "bottom-start" | "bottom-end" | "top-start" | "top-end";
|
|
4
|
+
}
|
|
5
|
+
type $$ComponentProps = Props & {
|
|
6
|
+
children?: any;
|
|
7
|
+
trigger?: any;
|
|
8
|
+
};
|
|
9
|
+
declare const Dropdown: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type Dropdown = ReturnType<typeof Dropdown>;
|
|
11
|
+
export default Dropdown;
|