@aphexcms/cms-core 0.1.3 → 0.1.4
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/api/assets.d.ts +48 -0
- package/dist/api/assets.d.ts.map +1 -0
- package/dist/api/assets.js +52 -0
- package/dist/api/client.d.ts +37 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +125 -0
- package/dist/api/documents.d.ts +56 -0
- package/dist/api/documents.d.ts.map +1 -0
- package/dist/api/documents.js +77 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +5 -0
- package/dist/api/organizations.d.ts +101 -0
- package/dist/api/organizations.d.ts.map +1 -0
- package/dist/api/organizations.js +92 -0
- package/dist/api/types.d.ts +23 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +1 -0
- package/dist/app.d.ts +19 -0
- package/dist/auth/MULTI_TENANCY_PLAN.md +1183 -0
- package/dist/auth/auth-errors.d.ts +7 -0
- package/dist/auth/auth-errors.d.ts.map +1 -0
- package/dist/auth/auth-errors.js +13 -0
- package/dist/auth/auth-hooks.d.ts +6 -0
- package/dist/auth/auth-hooks.d.ts.map +1 -0
- package/dist/auth/auth-hooks.js +108 -0
- package/dist/auth/provider.d.ts +17 -0
- package/dist/auth/provider.d.ts.map +1 -0
- package/dist/auth/provider.js +1 -0
- package/dist/client/index.d.ts +24 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +31 -0
- package/dist/components/AdminApp.svelte +1077 -0
- package/dist/components/AdminApp.svelte.d.ts +24 -0
- package/dist/components/AdminApp.svelte.d.ts.map +1 -0
- package/dist/components/admin/AdminLayout.svelte +115 -0
- package/dist/components/admin/AdminLayout.svelte.d.ts +15 -0
- package/dist/components/admin/AdminLayout.svelte.d.ts.map +1 -0
- package/dist/components/admin/DocumentEditor.svelte +795 -0
- package/dist/components/admin/DocumentEditor.svelte.d.ts +18 -0
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -0
- package/dist/components/admin/DocumentTypesList.svelte +97 -0
- package/dist/components/admin/DocumentTypesList.svelte.d.ts +14 -0
- package/dist/components/admin/DocumentTypesList.svelte.d.ts.map +1 -0
- package/dist/components/admin/ObjectModal.svelte +135 -0
- package/dist/components/admin/ObjectModal.svelte.d.ts +15 -0
- package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -0
- package/dist/components/admin/SchemaField.svelte +171 -0
- package/dist/components/admin/SchemaField.svelte.d.ts +19 -0
- package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/ArrayField.svelte +266 -0
- package/dist/components/admin/fields/ArrayField.svelte.d.ts +12 -0
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/BooleanField.svelte +35 -0
- package/dist/components/admin/fields/BooleanField.svelte.d.ts +13 -0
- package/dist/components/admin/fields/BooleanField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/ImageField.svelte +284 -0
- package/dist/components/admin/fields/ImageField.svelte.d.ts +15 -0
- package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/NumberField.svelte +82 -0
- package/dist/components/admin/fields/NumberField.svelte.d.ts +14 -0
- package/dist/components/admin/fields/NumberField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/ReferenceField.svelte +260 -0
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts +12 -0
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/SlugField.svelte +74 -0
- package/dist/components/admin/fields/SlugField.svelte.d.ts +15 -0
- package/dist/components/admin/fields/SlugField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/StringField.svelte +40 -0
- package/dist/components/admin/fields/StringField.svelte.d.ts +14 -0
- package/dist/components/admin/fields/StringField.svelte.d.ts.map +1 -0
- package/dist/components/admin/fields/TextareaField.svelte +40 -0
- package/dist/components/admin/fields/TextareaField.svelte.d.ts +14 -0
- package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +1 -0
- package/dist/components/fields/index.d.ts +9 -0
- package/dist/components/fields/index.d.ts.map +1 -0
- package/dist/components/fields/index.js +9 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +12 -0
- package/dist/components/layout/OrganizationSwitcher.svelte +218 -0
- package/dist/components/layout/OrganizationSwitcher.svelte.d.ts +11 -0
- package/dist/components/layout/OrganizationSwitcher.svelte.d.ts.map +1 -0
- package/dist/components/layout/Sidebar.svelte +88 -0
- package/dist/components/layout/Sidebar.svelte.d.ts +14 -0
- package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -0
- package/dist/components/layout/sidebar/AppSidebar.svelte +63 -0
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts +11 -0
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -0
- package/dist/components/layout/sidebar/NavMain.svelte +95 -0
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts +19 -0
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +1 -0
- package/dist/components/layout/sidebar/NavSecondary.svelte +69 -0
- package/dist/components/layout/sidebar/NavSecondary.svelte.d.ts +9 -0
- package/dist/components/layout/sidebar/NavSecondary.svelte.d.ts.map +1 -0
- package/dist/components/layout/sidebar/NavUser.svelte +85 -0
- package/dist/components/layout/sidebar/NavUser.svelte.d.ts +9 -0
- package/dist/components/layout/sidebar/NavUser.svelte.d.ts.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +15 -0
- package/dist/db/adapters/index.d.ts +1 -0
- package/dist/db/adapters/index.d.ts.map +1 -0
- package/dist/db/adapters/index.js +4 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +4 -0
- package/dist/db/interfaces/asset.d.ts +51 -0
- package/dist/db/interfaces/asset.d.ts.map +1 -0
- package/dist/db/interfaces/asset.js +1 -0
- package/dist/db/interfaces/document.d.ts +36 -0
- package/dist/db/interfaces/document.d.ts.map +1 -0
- package/dist/db/interfaces/document.js +1 -0
- package/dist/db/interfaces/index.d.ts +73 -0
- package/dist/db/interfaces/index.d.ts.map +1 -0
- package/dist/db/interfaces/index.js +1 -0
- package/dist/db/interfaces/organization.d.ts +27 -0
- package/dist/db/interfaces/organization.d.ts.map +1 -0
- package/dist/db/interfaces/organization.js +1 -0
- package/dist/db/interfaces/schema.d.ts +21 -0
- package/dist/db/interfaces/schema.d.ts.map +1 -0
- package/dist/db/interfaces/schema.js +1 -0
- package/dist/db/interfaces/user.d.ts +15 -0
- package/dist/db/interfaces/user.d.ts.map +1 -0
- package/dist/db/interfaces/user.js +1 -0
- package/dist/db/utils/reference-resolver.d.ts +18 -0
- package/dist/db/utils/reference-resolver.d.ts.map +1 -0
- package/dist/db/utils/reference-resolver.js +80 -0
- package/dist/define.d.ts +3 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +4 -0
- package/dist/email/index.d.ts +2 -0
- package/dist/email/index.d.ts.map +1 -0
- package/dist/email/index.js +4 -0
- package/dist/email/interfaces/email.d.ts +42 -0
- package/dist/email/interfaces/email.d.ts.map +1 -0
- package/dist/email/interfaces/email.js +1 -0
- package/dist/engine.d.ts +26 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +66 -0
- package/dist/field-validation/rule.d.ts +51 -0
- package/dist/field-validation/rule.d.ts.map +1 -0
- package/dist/field-validation/rule.js +221 -0
- package/dist/field-validation/utils.d.ts +21 -0
- package/dist/field-validation/utils.d.ts.map +1 -0
- package/dist/field-validation/utils.js +66 -0
- package/dist/hooks.d.ts +23 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +96 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/plugins/README.md +154 -0
- package/dist/routes/assets-by-id.d.ts +5 -0
- package/dist/routes/assets-by-id.d.ts.map +1 -0
- package/dist/routes/assets-by-id.js +138 -0
- package/dist/routes/assets-cdn.d.ts +3 -0
- package/dist/routes/assets-cdn.d.ts.map +1 -0
- package/dist/routes/assets-cdn.js +155 -0
- package/dist/routes/assets.d.ts +4 -0
- package/dist/routes/assets.d.ts.map +1 -0
- package/dist/routes/assets.js +94 -0
- package/dist/routes/documents-by-id.d.ts +5 -0
- package/dist/routes/documents-by-id.d.ts.map +1 -0
- package/dist/routes/documents-by-id.js +142 -0
- package/dist/routes/documents-publish.d.ts +4 -0
- package/dist/routes/documents-publish.d.ts.map +1 -0
- package/dist/routes/documents-publish.js +151 -0
- package/dist/routes/documents.d.ts +4 -0
- package/dist/routes/documents.d.ts.map +1 -0
- package/dist/routes/documents.js +131 -0
- package/dist/routes/index.d.ts +6 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +10 -0
- package/dist/routes/organizations-by-id.d.ts +5 -0
- package/dist/routes/organizations-by-id.d.ts.map +1 -0
- package/dist/routes/organizations-by-id.js +187 -0
- package/dist/routes/organizations-invitations.d.ts +4 -0
- package/dist/routes/organizations-invitations.d.ts.map +1 -0
- package/dist/routes/organizations-invitations.js +125 -0
- package/dist/routes/organizations-members.d.ts +5 -0
- package/dist/routes/organizations-members.d.ts.map +1 -0
- package/dist/routes/organizations-members.js +206 -0
- package/dist/routes/organizations-switch.d.ts +3 -0
- package/dist/routes/organizations-switch.d.ts.map +1 -0
- package/dist/routes/organizations-switch.js +53 -0
- package/dist/routes/organizations.d.ts +4 -0
- package/dist/routes/organizations.d.ts.map +1 -0
- package/dist/routes/organizations.js +108 -0
- package/dist/routes/schemas-by-type.d.ts +3 -0
- package/dist/routes/schemas-by-type.d.ts.map +1 -0
- package/dist/routes/schemas-by-type.js +25 -0
- package/dist/routes/schemas.d.ts +3 -0
- package/dist/routes/schemas.d.ts.map +1 -0
- package/dist/routes/schemas.js +11 -0
- package/dist/routes-exports.d.ts +14 -0
- package/dist/routes-exports.d.ts.map +1 -0
- package/dist/routes-exports.js +19 -0
- package/dist/schema-context.svelte.d.ts +10 -0
- package/dist/schema-context.svelte.d.ts.map +1 -0
- package/dist/schema-context.svelte.js +18 -0
- package/dist/schema-utils/cleanup.d.ts +21 -0
- package/dist/schema-utils/cleanup.d.ts.map +1 -0
- package/dist/schema-utils/cleanup.js +80 -0
- package/dist/schema-utils/index.d.ts +4 -0
- package/dist/schema-utils/index.d.ts.map +1 -0
- package/dist/schema-utils/index.js +4 -0
- package/dist/schema-utils/utils.d.ts +30 -0
- package/dist/schema-utils/utils.d.ts.map +1 -0
- package/dist/schema-utils/utils.js +37 -0
- package/dist/schema-utils/validator.d.ts +6 -0
- package/dist/schema-utils/validator.d.ts.map +1 -0
- package/dist/schema-utils/validator.js +45 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +28 -0
- package/dist/services/asset-service.d.ts +86 -0
- package/dist/services/asset-service.d.ts.map +1 -0
- package/dist/services/asset-service.js +187 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +4 -0
- package/dist/storage/adapters/index.d.ts +2 -0
- package/dist/storage/adapters/index.d.ts.map +1 -0
- package/dist/storage/adapters/index.js +2 -0
- package/dist/storage/adapters/local-storage-adapter.d.ts +54 -0
- package/dist/storage/adapters/local-storage-adapter.d.ts.map +1 -0
- package/dist/storage/adapters/local-storage-adapter.js +187 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/interfaces/index.d.ts +2 -0
- package/dist/storage/interfaces/index.d.ts.map +1 -0
- package/dist/storage/interfaces/index.js +2 -0
- package/dist/storage/interfaces/storage.d.ts +91 -0
- package/dist/storage/interfaces/storage.d.ts.map +1 -0
- package/dist/storage/interfaces/storage.js +1 -0
- package/dist/storage/providers/storage.d.ts +43 -0
- package/dist/storage/providers/storage.d.ts.map +1 -0
- package/dist/storage/providers/storage.js +64 -0
- package/dist/types/asset.d.ts +73 -0
- package/dist/types/asset.d.ts.map +1 -0
- package/dist/types/asset.js +2 -0
- package/dist/types/auth.d.ts +50 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +41 -0
- package/dist/types/config.d.ts +47 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +1 -0
- package/dist/types/document.d.ts +34 -0
- package/dist/types/document.d.ts.map +1 -0
- package/dist/types/document.js +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/organization.d.ts +105 -0
- package/dist/types/organization.d.ts.map +1 -0
- package/dist/types/organization.js +3 -0
- package/dist/types/schemas.d.ts +114 -0
- package/dist/types/schemas.d.ts.map +1 -0
- package/dist/types/schemas.js +1 -0
- package/dist/types/sidebar.d.ts +33 -0
- package/dist/types/sidebar.d.ts.map +1 -0
- package/dist/types/sidebar.js +1 -0
- package/dist/types/user.d.ts +14 -0
- package/dist/types/user.d.ts.map +1 -0
- package/dist/types/user.js +1 -0
- package/dist/utils/content-hash.d.ts +22 -0
- package/dist/utils/content-hash.d.ts.map +1 -0
- package/dist/utils/content-hash.js +67 -0
- package/dist/utils/image-url.d.ts +88 -0
- package/dist/utils/image-url.d.ts.map +1 -0
- package/dist/utils/image-url.js +165 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/slug.d.ts +13 -0
- package/dist/utils/slug.d.ts.map +1 -0
- package/dist/utils/slug.js +30 -0
- package/package.json +11 -41
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
3
|
+
import * as DropdownMenu from '@aphexcms/ui/shadcn/dropdown-menu';
|
|
4
|
+
import type { ArrayField as ArrayFieldType, SchemaType } from '../../../types/schemas.js';
|
|
5
|
+
import { getArrayTypes, getSchemaByName } from '../../../schema-utils/utils.js';
|
|
6
|
+
import { getSchemaContext } from '../../../schema-context.svelte.js';
|
|
7
|
+
import ObjectModal from '../ObjectModal.svelte';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
field: ArrayFieldType;
|
|
11
|
+
value: any;
|
|
12
|
+
onUpdate: (value: any) => void;
|
|
13
|
+
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
14
|
+
readonly?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let { field, value, onUpdate, onOpenReference, readonly = false }: Props = $props();
|
|
18
|
+
|
|
19
|
+
// Get schemas from context
|
|
20
|
+
const schemas = getSchemaContext();
|
|
21
|
+
|
|
22
|
+
// Get available types for this array field
|
|
23
|
+
const availableTypes = $derived(getArrayTypes(schemas, field));
|
|
24
|
+
|
|
25
|
+
// Modal state
|
|
26
|
+
let modalOpen = $state(false);
|
|
27
|
+
let editingIndex = $state<number | null>(null);
|
|
28
|
+
let editingType = $state<string | null>(null);
|
|
29
|
+
let editingSchema = $state<SchemaType | null>(null);
|
|
30
|
+
let editingValue = $state<Record<string, any>>({});
|
|
31
|
+
|
|
32
|
+
// Ensure value is always an array
|
|
33
|
+
const arrayValue = $derived(Array.isArray(value) ? value : []);
|
|
34
|
+
|
|
35
|
+
function handleTypeSelected(selectedType: string) {
|
|
36
|
+
if (readonly || !selectedType) return;
|
|
37
|
+
|
|
38
|
+
// Get the schema for the selected type
|
|
39
|
+
const schema = getSchemaByName(schemas, selectedType);
|
|
40
|
+
if (!schema) return;
|
|
41
|
+
|
|
42
|
+
// Initialize empty object with default values
|
|
43
|
+
const newItem: Record<string, any> = { _type: selectedType };
|
|
44
|
+
|
|
45
|
+
if (schema.fields) {
|
|
46
|
+
schema.fields.forEach((field) => {
|
|
47
|
+
if (field.type === 'boolean' && 'initialValue' in field) {
|
|
48
|
+
newItem[field.name] = field.initialValue;
|
|
49
|
+
} else {
|
|
50
|
+
newItem[field.name] = '';
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Set modal state directly
|
|
56
|
+
editingIndex = arrayValue.length; // New item index
|
|
57
|
+
editingType = selectedType;
|
|
58
|
+
editingSchema = schema;
|
|
59
|
+
editingValue = newItem;
|
|
60
|
+
modalOpen = true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function handleEditItem(index: number) {
|
|
64
|
+
const item = arrayValue[index];
|
|
65
|
+
if (!item._type) return;
|
|
66
|
+
|
|
67
|
+
const schema = getSchemaByName(schemas, item._type);
|
|
68
|
+
if (!schema) return;
|
|
69
|
+
|
|
70
|
+
editingIndex = index;
|
|
71
|
+
editingType = item._type;
|
|
72
|
+
editingSchema = schema;
|
|
73
|
+
editingValue = item;
|
|
74
|
+
modalOpen = true;
|
|
75
|
+
console.log('MODAL IS OPEN: ', modalOpen);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function handleRemoveItem(index: number) {
|
|
79
|
+
if (readonly) return;
|
|
80
|
+
const newArray = arrayValue.filter((_, i) => i !== index);
|
|
81
|
+
onUpdate(newArray);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function handleModalSave(editedData: Record<string, any>) {
|
|
85
|
+
if (editingIndex === null || !editingType) return;
|
|
86
|
+
|
|
87
|
+
// Add the type information to the data
|
|
88
|
+
const itemData = { ...editedData, _type: editingType };
|
|
89
|
+
|
|
90
|
+
const newArray = [...arrayValue];
|
|
91
|
+
|
|
92
|
+
if (editingIndex >= newArray.length) {
|
|
93
|
+
// Adding new item
|
|
94
|
+
newArray.push(itemData);
|
|
95
|
+
} else {
|
|
96
|
+
// Editing existing item
|
|
97
|
+
newArray[editingIndex] = itemData;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onUpdate(newArray);
|
|
101
|
+
|
|
102
|
+
// Reset modal state
|
|
103
|
+
modalOpen = false;
|
|
104
|
+
editingIndex = null;
|
|
105
|
+
editingType = null;
|
|
106
|
+
editingSchema = null;
|
|
107
|
+
editingValue = {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function handleModalClose() {
|
|
111
|
+
modalOpen = false;
|
|
112
|
+
editingIndex = null;
|
|
113
|
+
editingType = null;
|
|
114
|
+
editingSchema = null;
|
|
115
|
+
editingValue = {};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Get the title to display for an item
|
|
119
|
+
function getItemTitle(item: any): string {
|
|
120
|
+
if (!item._type) return 'Unknown Item';
|
|
121
|
+
|
|
122
|
+
const schema = getSchemaByName(schemas, item._type);
|
|
123
|
+
if (!schema) return item._type;
|
|
124
|
+
|
|
125
|
+
// Try to find a meaningful field to use as title
|
|
126
|
+
const titleField = item.title || item.heading || item.name || item.label;
|
|
127
|
+
if (titleField && typeof titleField === 'string' && titleField.trim()) {
|
|
128
|
+
return titleField;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return schema.title || item._type;
|
|
132
|
+
}
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<div class="border-border space-y-4 rounded-md border p-4">
|
|
136
|
+
<h4 class="text-sm font-medium">{field.title}</h4>
|
|
137
|
+
|
|
138
|
+
<!-- Array items -->
|
|
139
|
+
{#if arrayValue.length > 0}
|
|
140
|
+
<div class="space-y-2">
|
|
141
|
+
{#each arrayValue as item, index (index)}
|
|
142
|
+
<div class="border-border/50 space-y-2 rounded border p-3">
|
|
143
|
+
<div class="flex items-center justify-between">
|
|
144
|
+
<div class="flex items-center gap-2">
|
|
145
|
+
<span class="text-muted-foreground text-xs">#{index + 1}</span>
|
|
146
|
+
<h5 class="text-sm font-medium">{getItemTitle(item)}</h5>
|
|
147
|
+
{#if item._type}
|
|
148
|
+
<span class="bg-muted rounded px-2 py-1 text-xs">{item._type}</span>
|
|
149
|
+
{/if}
|
|
150
|
+
</div>
|
|
151
|
+
<div class="flex items-center gap-2">
|
|
152
|
+
<Button
|
|
153
|
+
variant="ghost"
|
|
154
|
+
size="sm"
|
|
155
|
+
onclick={() => {
|
|
156
|
+
handleEditItem(index);
|
|
157
|
+
}}
|
|
158
|
+
class="h-8 w-8 p-0"
|
|
159
|
+
title={readonly ? 'View item' : 'Edit item'}
|
|
160
|
+
>
|
|
161
|
+
{#if readonly}
|
|
162
|
+
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
163
|
+
<path
|
|
164
|
+
stroke-linecap="round"
|
|
165
|
+
stroke-linejoin="round"
|
|
166
|
+
stroke-width="2"
|
|
167
|
+
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
168
|
+
/>
|
|
169
|
+
<path
|
|
170
|
+
stroke-linecap="round"
|
|
171
|
+
stroke-linejoin="round"
|
|
172
|
+
stroke-width="2"
|
|
173
|
+
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"
|
|
174
|
+
/>
|
|
175
|
+
</svg>
|
|
176
|
+
{:else}
|
|
177
|
+
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
178
|
+
<path
|
|
179
|
+
stroke-linecap="round"
|
|
180
|
+
stroke-linejoin="round"
|
|
181
|
+
stroke-width="2"
|
|
182
|
+
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
|
183
|
+
/>
|
|
184
|
+
</svg>
|
|
185
|
+
{/if}
|
|
186
|
+
</Button>
|
|
187
|
+
|
|
188
|
+
{#if !readonly}
|
|
189
|
+
<Button
|
|
190
|
+
variant="ghost"
|
|
191
|
+
size="sm"
|
|
192
|
+
onclick={() => handleRemoveItem(index)}
|
|
193
|
+
class="text-destructive hover:text-destructive h-8 w-8 p-0"
|
|
194
|
+
title="Remove item"
|
|
195
|
+
>
|
|
196
|
+
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
197
|
+
<path
|
|
198
|
+
stroke-linecap="round"
|
|
199
|
+
stroke-linejoin="round"
|
|
200
|
+
stroke-width="2"
|
|
201
|
+
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
202
|
+
/>
|
|
203
|
+
</svg>
|
|
204
|
+
</Button>
|
|
205
|
+
{/if}
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<!-- Show a preview of the item content -->
|
|
210
|
+
<div class="text-muted-foreground pl-6 text-xs">
|
|
211
|
+
{#if item.title || item.heading}
|
|
212
|
+
{item.title || item.heading}
|
|
213
|
+
{:else if item.description}
|
|
214
|
+
{item.description.substring(0, 100)}{item.description.length > 100 ? '...' : ''}
|
|
215
|
+
{:else}
|
|
216
|
+
{readonly ? 'Click view to see details' : 'Click edit to configure this item'}
|
|
217
|
+
{/if}
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
{/each}
|
|
221
|
+
</div>
|
|
222
|
+
{/if}
|
|
223
|
+
|
|
224
|
+
<!-- Add Item section (hidden for read-only) -->
|
|
225
|
+
{#if !readonly}
|
|
226
|
+
<div class="border-border border-t pt-2">
|
|
227
|
+
<DropdownMenu.Root>
|
|
228
|
+
<DropdownMenu.Trigger>
|
|
229
|
+
{#snippet child({ props })}
|
|
230
|
+
<Button {...props} variant="outline" class="w-full cursor-pointer">
|
|
231
|
+
<svg class="mr-2 h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
232
|
+
<path
|
|
233
|
+
stroke-linecap="round"
|
|
234
|
+
stroke-linejoin="round"
|
|
235
|
+
stroke-width="2"
|
|
236
|
+
d="M12 4v16m8-8H4"
|
|
237
|
+
/>
|
|
238
|
+
</svg>
|
|
239
|
+
Add Item
|
|
240
|
+
</Button>
|
|
241
|
+
{/snippet}
|
|
242
|
+
</DropdownMenu.Trigger>
|
|
243
|
+
<DropdownMenu.Content class="w-56">
|
|
244
|
+
{#each availableTypes as type, index (index)}
|
|
245
|
+
<DropdownMenu.Item onclick={() => handleTypeSelected(type.name)}>
|
|
246
|
+
{type.title}
|
|
247
|
+
</DropdownMenu.Item>
|
|
248
|
+
{/each}
|
|
249
|
+
</DropdownMenu.Content>
|
|
250
|
+
</DropdownMenu.Root>
|
|
251
|
+
</div>
|
|
252
|
+
{/if}
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<!-- Object editing modal -->
|
|
256
|
+
{#if editingSchema}
|
|
257
|
+
<ObjectModal
|
|
258
|
+
open={modalOpen}
|
|
259
|
+
schema={editingSchema}
|
|
260
|
+
value={editingValue}
|
|
261
|
+
onClose={handleModalClose}
|
|
262
|
+
onSave={handleModalSave}
|
|
263
|
+
{onOpenReference}
|
|
264
|
+
{readonly}
|
|
265
|
+
/>
|
|
266
|
+
{/if}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ArrayField as ArrayFieldType } from '../../../types/schemas.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
field: ArrayFieldType;
|
|
4
|
+
value: any;
|
|
5
|
+
onUpdate: (value: any) => void;
|
|
6
|
+
onOpenReference?: (documentId: string, documentType: string) => void;
|
|
7
|
+
readonly?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const ArrayField: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type ArrayField = ReturnType<typeof ArrayField>;
|
|
11
|
+
export default ArrayField;
|
|
12
|
+
//# sourceMappingURL=ArrayField.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArrayField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ArrayField.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAc,MAAM,2BAA2B,CAAC;AAMzF,UAAU,KAAK;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AA0NF,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Label } from '@aphexcms/ui/shadcn/label';
|
|
3
|
+
import type { Field } from '../../../types/schemas.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
field: Field;
|
|
7
|
+
value: any;
|
|
8
|
+
onUpdate: (value: any) => void;
|
|
9
|
+
validationClasses?: string;
|
|
10
|
+
onBlur?: (event: any) => void;
|
|
11
|
+
readonly?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { field, value, onUpdate, validationClasses, onBlur, readonly = false }: Props = $props();
|
|
15
|
+
|
|
16
|
+
function handleBooleanChange(event: Event) {
|
|
17
|
+
const target = event.target as HTMLInputElement;
|
|
18
|
+
onUpdate(target.checked);
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class="flex items-center space-x-2">
|
|
23
|
+
<input
|
|
24
|
+
id={field.name}
|
|
25
|
+
type="checkbox"
|
|
26
|
+
checked={value || false}
|
|
27
|
+
onchange={handleBooleanChange}
|
|
28
|
+
onblur={onBlur}
|
|
29
|
+
class="border-input h-4 w-4 rounded border {validationClasses}"
|
|
30
|
+
disabled={readonly}
|
|
31
|
+
/>
|
|
32
|
+
<Label for={field.name} class="text-sm font-normal">
|
|
33
|
+
{field.title}
|
|
34
|
+
</Label>
|
|
35
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Field } from '../../../types/schemas.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
field: Field;
|
|
4
|
+
value: any;
|
|
5
|
+
onUpdate: (value: any) => void;
|
|
6
|
+
validationClasses?: string;
|
|
7
|
+
onBlur?: (event: any) => void;
|
|
8
|
+
readonly?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare const BooleanField: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type BooleanField = ReturnType<typeof BooleanField>;
|
|
12
|
+
export default BooleanField;
|
|
13
|
+
//# sourceMappingURL=BooleanField.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BooleanField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/BooleanField.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAGtD,UAAU,KAAK;IACd,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,GAAG,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAuBF,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '@aphexcms/ui/shadcn/button';
|
|
3
|
+
import { Trash2, Upload, Image as ImageIcon, FileImage } from 'lucide-svelte';
|
|
4
|
+
import type { ImageValue } from '../../../types/asset.js';
|
|
5
|
+
import type { ImageField as ImageFieldType } from '../../../types/schemas.js';
|
|
6
|
+
import { assets } from '../../../api/assets';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
field: ImageFieldType;
|
|
10
|
+
value: ImageValue | null;
|
|
11
|
+
validationClasses?: string;
|
|
12
|
+
onUpdate: (value: ImageValue | null) => void;
|
|
13
|
+
schemaType?: string;
|
|
14
|
+
fieldPath?: string;
|
|
15
|
+
readonly?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let {
|
|
19
|
+
field,
|
|
20
|
+
value,
|
|
21
|
+
onUpdate,
|
|
22
|
+
validationClasses,
|
|
23
|
+
schemaType,
|
|
24
|
+
fieldPath,
|
|
25
|
+
readonly = false
|
|
26
|
+
}: Props = $props();
|
|
27
|
+
|
|
28
|
+
// Component state
|
|
29
|
+
let isDragging = $state(false);
|
|
30
|
+
let isUploading = $state(false);
|
|
31
|
+
let uploadError = $state<string | null>(null);
|
|
32
|
+
let fileInputRef: HTMLInputElement;
|
|
33
|
+
|
|
34
|
+
// Upload file to server
|
|
35
|
+
async function uploadFile(file: File): Promise<ImageValue | null> {
|
|
36
|
+
isUploading = true;
|
|
37
|
+
uploadError = null;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const formData = new FormData();
|
|
41
|
+
formData.append('file', file);
|
|
42
|
+
|
|
43
|
+
// Add field metadata for privacy checking
|
|
44
|
+
if (schemaType) formData.append('schemaType', schemaType);
|
|
45
|
+
if (fieldPath) formData.append('fieldPath', fieldPath);
|
|
46
|
+
|
|
47
|
+
const result = await assets.upload(formData);
|
|
48
|
+
|
|
49
|
+
if (!result.success) {
|
|
50
|
+
throw new Error(result.error || 'Upload failed');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Extract asset from response
|
|
54
|
+
const asset = result.data;
|
|
55
|
+
|
|
56
|
+
// Return Sanity-style image value
|
|
57
|
+
return {
|
|
58
|
+
_type: 'image',
|
|
59
|
+
asset: {
|
|
60
|
+
_type: 'reference',
|
|
61
|
+
_ref: asset!.id
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
} catch (error) {
|
|
65
|
+
uploadError = error instanceof Error ? error.message : 'Upload failed';
|
|
66
|
+
return null;
|
|
67
|
+
} finally {
|
|
68
|
+
isUploading = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Handle file selection
|
|
73
|
+
async function handleFileSelect(files: FileList | null) {
|
|
74
|
+
if (readonly || !files || files.length === 0) return;
|
|
75
|
+
|
|
76
|
+
const file = files[0];
|
|
77
|
+
|
|
78
|
+
const imageValue = await uploadFile(file);
|
|
79
|
+
if (imageValue) {
|
|
80
|
+
onUpdate(imageValue);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Drag and drop handlers
|
|
85
|
+
function handleDragOver(event: DragEvent) {
|
|
86
|
+
if (readonly) return;
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
isDragging = true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function handleDragLeave(event: DragEvent) {
|
|
92
|
+
if (readonly) return;
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
isDragging = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function handleDrop(event: DragEvent) {
|
|
98
|
+
if (readonly) return;
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
isDragging = false;
|
|
101
|
+
handleFileSelect(event.dataTransfer?.files || null);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// File input handlers
|
|
105
|
+
function handleFileInputChange(event: Event) {
|
|
106
|
+
if (readonly) return;
|
|
107
|
+
const target = event.target as HTMLInputElement;
|
|
108
|
+
handleFileSelect(target.files);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function openFileDialog() {
|
|
112
|
+
if (readonly) return;
|
|
113
|
+
fileInputRef?.click();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Remove image
|
|
117
|
+
function removeImage() {
|
|
118
|
+
if (readonly) return;
|
|
119
|
+
onUpdate(null);
|
|
120
|
+
uploadError = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Asset data state
|
|
124
|
+
let assetData = $state<any>(null);
|
|
125
|
+
let loadingAsset = $state(false);
|
|
126
|
+
|
|
127
|
+
// Fetch asset details when asset reference changes
|
|
128
|
+
$effect(() => {
|
|
129
|
+
async function loadAsset() {
|
|
130
|
+
if (value?.asset?._ref) {
|
|
131
|
+
loadingAsset = true;
|
|
132
|
+
try {
|
|
133
|
+
const result = await assets.getById(value.asset._ref);
|
|
134
|
+
if (result.success) {
|
|
135
|
+
assetData = result.data;
|
|
136
|
+
} else {
|
|
137
|
+
console.error('Failed to fetch asset details');
|
|
138
|
+
assetData = null;
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error('Error fetching asset:', error);
|
|
142
|
+
assetData = null;
|
|
143
|
+
} finally {
|
|
144
|
+
loadingAsset = false;
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
assetData = null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
loadAsset();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Get asset URL for preview
|
|
154
|
+
const previewUrl = $derived(assetData?.url || null);
|
|
155
|
+
</script>
|
|
156
|
+
|
|
157
|
+
<!-- Hidden file input -->
|
|
158
|
+
<input
|
|
159
|
+
bind:this={fileInputRef}
|
|
160
|
+
type="file"
|
|
161
|
+
accept={field.accept || 'image/*'}
|
|
162
|
+
style="display: none"
|
|
163
|
+
onchange={handleFileInputChange}
|
|
164
|
+
/>
|
|
165
|
+
|
|
166
|
+
{#if value && value.asset}
|
|
167
|
+
<!-- Image preview with controls -->
|
|
168
|
+
<div class="border-border overflow-hidden rounded-md border {validationClasses}">
|
|
169
|
+
<div class="group relative">
|
|
170
|
+
<!-- Image preview (Sanity-style aspect ratio ~2.75:1) -->
|
|
171
|
+
<div class="bg-muted flex items-center justify-center" style="aspect-ratio: 2.75 / 1;">
|
|
172
|
+
{#if loadingAsset}
|
|
173
|
+
<div class="text-muted-foreground flex flex-col items-center gap-2">
|
|
174
|
+
<div class="border-primary h-8 w-8 animate-spin rounded-full border-b-2"></div>
|
|
175
|
+
<span class="text-sm">Loading image...</span>
|
|
176
|
+
</div>
|
|
177
|
+
{:else if previewUrl}
|
|
178
|
+
<img
|
|
179
|
+
src={previewUrl}
|
|
180
|
+
alt={assetData?.alt || 'Uploaded image'}
|
|
181
|
+
class="h-full w-full object-contain"
|
|
182
|
+
loading="lazy"
|
|
183
|
+
/>
|
|
184
|
+
{:else}
|
|
185
|
+
<div class="text-muted-foreground flex flex-col items-center gap-2">
|
|
186
|
+
<ImageIcon size={32} />
|
|
187
|
+
<span class="text-sm">Image: {value.asset._ref}</span>
|
|
188
|
+
<span class="text-xs">Failed to load preview</span>
|
|
189
|
+
</div>
|
|
190
|
+
{/if}
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<!-- Overlay controls (hidden for read-only) -->
|
|
194
|
+
{#if !readonly}
|
|
195
|
+
<div
|
|
196
|
+
class="absolute inset-0 flex items-center justify-center gap-2 bg-black/50 opacity-0 transition-opacity group-hover:opacity-100"
|
|
197
|
+
>
|
|
198
|
+
<Button variant="secondary" size="sm" onclick={openFileDialog} disabled={isUploading}>
|
|
199
|
+
<Upload size={16} class="mr-1" />
|
|
200
|
+
Replace
|
|
201
|
+
</Button>
|
|
202
|
+
<Button variant="destructive" size="sm" onclick={removeImage} disabled={isUploading}>
|
|
203
|
+
<Trash2 size={16} class="mr-1" />
|
|
204
|
+
Remove
|
|
205
|
+
</Button>
|
|
206
|
+
</div>
|
|
207
|
+
{/if}
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<!-- Additional image controls/metadata could go here -->
|
|
211
|
+
{#if field.fields}
|
|
212
|
+
<div class="border-border space-y-2 border-t p-3">
|
|
213
|
+
<!-- Custom fields like caption, alt text, etc. would be rendered here -->
|
|
214
|
+
<p class="text-muted-foreground text-xs">Custom fields coming soon...</p>
|
|
215
|
+
</div>
|
|
216
|
+
{/if}
|
|
217
|
+
</div>
|
|
218
|
+
{:else}
|
|
219
|
+
<!-- Sanity-style upload bar -->
|
|
220
|
+
<div class="border-border overflow-hidden rounded-md border {validationClasses}">
|
|
221
|
+
<div class="flex items-center">
|
|
222
|
+
<!-- Drag and drop area (left side) -->
|
|
223
|
+
<div
|
|
224
|
+
class="flex-1 px-4 py-3 transition-colors {readonly
|
|
225
|
+
? ''
|
|
226
|
+
: isDragging
|
|
227
|
+
? 'bg-primary/5'
|
|
228
|
+
: 'hover:bg-muted/50'}"
|
|
229
|
+
ondragover={readonly ? undefined : handleDragOver}
|
|
230
|
+
ondragleave={readonly ? undefined : handleDragLeave}
|
|
231
|
+
ondrop={readonly ? undefined : handleDrop}
|
|
232
|
+
tabindex={readonly ? -1 : 0}
|
|
233
|
+
role={readonly ? undefined : 'button'}
|
|
234
|
+
>
|
|
235
|
+
{#if isUploading}
|
|
236
|
+
<div class="flex items-center gap-3">
|
|
237
|
+
<div class="border-primary h-5 w-5 animate-spin rounded-full border-b-2"></div>
|
|
238
|
+
<span class="text-muted-foreground text-sm">Uploading...</span>
|
|
239
|
+
</div>
|
|
240
|
+
{:else}
|
|
241
|
+
<div class="flex items-center gap-3">
|
|
242
|
+
<FileImage size={20} class="text-muted-foreground" />
|
|
243
|
+
<span class="text-muted-foreground text-sm">
|
|
244
|
+
{readonly ? 'No image' : isDragging ? 'Drop image here' : 'Drag or paste image here'}
|
|
245
|
+
</span>
|
|
246
|
+
</div>
|
|
247
|
+
{/if}
|
|
248
|
+
</div>
|
|
249
|
+
|
|
250
|
+
<!-- Buttons (right side) -->
|
|
251
|
+
<div class="border-border bg-muted/20 flex items-center gap-2 border-l px-3 py-2">
|
|
252
|
+
<Button
|
|
253
|
+
variant="outline"
|
|
254
|
+
size="sm"
|
|
255
|
+
onclick={openFileDialog}
|
|
256
|
+
disabled={isUploading || readonly}
|
|
257
|
+
type="button"
|
|
258
|
+
>
|
|
259
|
+
<Upload size={16} class="mr-1" />
|
|
260
|
+
Upload
|
|
261
|
+
</Button>
|
|
262
|
+
|
|
263
|
+
<Button
|
|
264
|
+
variant="outline"
|
|
265
|
+
size="sm"
|
|
266
|
+
disabled={isUploading || readonly}
|
|
267
|
+
type="button"
|
|
268
|
+
onclick={() => {
|
|
269
|
+
// TODO: Open asset browser/selector
|
|
270
|
+
console.log('Open asset selector');
|
|
271
|
+
}}
|
|
272
|
+
>
|
|
273
|
+
<ImageIcon size={16} class="mr-1" />
|
|
274
|
+
Select
|
|
275
|
+
</Button>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
{/if}
|
|
280
|
+
|
|
281
|
+
<!-- Error display -->
|
|
282
|
+
{#if uploadError}
|
|
283
|
+
<p class="text-destructive mt-2 text-sm">{uploadError}</p>
|
|
284
|
+
{/if}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImageValue } from '../../../types/asset.js';
|
|
2
|
+
import type { ImageField as ImageFieldType } from '../../../types/schemas.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
field: ImageFieldType;
|
|
5
|
+
value: ImageValue | null;
|
|
6
|
+
validationClasses?: string;
|
|
7
|
+
onUpdate: (value: ImageValue | null) => void;
|
|
8
|
+
schemaType?: string;
|
|
9
|
+
fieldPath?: string;
|
|
10
|
+
readonly?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare const ImageField: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type ImageField = ReturnType<typeof ImageField>;
|
|
14
|
+
export default ImageField;
|
|
15
|
+
//# sourceMappingURL=ImageField.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImageField.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/fields/ImageField.svelte.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI7E,UAAU,KAAK;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAuPF,QAAA,MAAM,UAAU,2CAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|