@svadmin/lite 0.6.0 → 0.8.0

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.
Files changed (104) hide show
  1. package/README.md +85 -9
  2. package/dist/components/LiteActivityFeed.svelte +98 -0
  3. package/dist/components/LiteActivityFeed.svelte.d.ts +19 -0
  4. package/dist/components/LiteApprovalActionCard.svelte +75 -0
  5. package/dist/components/LiteApprovalActionCard.svelte.d.ts +10 -0
  6. package/dist/components/LiteCanvasAnnotation.svelte +136 -0
  7. package/dist/components/LiteCanvasAnnotation.svelte.d.ts +16 -0
  8. package/dist/components/LiteColumnHeaderFilter.svelte +38 -0
  9. package/dist/components/LiteColumnHeaderFilter.svelte.d.ts +8 -0
  10. package/dist/components/LiteColumnSettings.svelte +82 -0
  11. package/dist/components/LiteColumnSettings.svelte.d.ts +15 -0
  12. package/dist/components/LiteDecisionTable.svelte +178 -0
  13. package/dist/components/LiteDecisionTable.svelte.d.ts +21 -0
  14. package/dist/components/LiteDraggableRowTable.svelte +70 -0
  15. package/dist/components/LiteDraggableRowTable.svelte.d.ts +14 -0
  16. package/dist/components/LiteDrawerForm.svelte +85 -0
  17. package/dist/components/LiteDrawerForm.svelte.d.ts +13 -0
  18. package/dist/components/LiteDynamicFormList.svelte +169 -0
  19. package/dist/components/LiteDynamicFormList.svelte.d.ts +45 -0
  20. package/dist/components/LiteEditableTable.svelte +84 -0
  21. package/dist/components/LiteEditableTable.svelte.d.ts +19 -0
  22. package/dist/components/LiteFilterBuilder.svelte +205 -0
  23. package/dist/components/LiteFilterBuilder.svelte.d.ts +19 -0
  24. package/dist/components/LiteGanttChart.svelte +144 -0
  25. package/dist/components/LiteGanttChart.svelte.d.ts +17 -0
  26. package/dist/components/LiteImageCropper.svelte +81 -0
  27. package/dist/components/LiteImageCropper.svelte.d.ts +9 -0
  28. package/dist/components/LiteImportWizard.svelte +99 -0
  29. package/dist/components/LiteImportWizard.svelte.d.ts +11 -0
  30. package/dist/components/LiteJsonSchemaForm.svelte +102 -0
  31. package/dist/components/LiteJsonSchemaForm.svelte.d.ts +10 -0
  32. package/dist/components/LiteKanbanBoard.svelte +169 -0
  33. package/dist/components/LiteKanbanBoard.svelte.d.ts +21 -0
  34. package/dist/components/LiteMasterDetailView.svelte +113 -0
  35. package/dist/components/LiteMasterDetailView.svelte.d.ts +11 -0
  36. package/dist/components/LiteMediaLibraryModal.svelte +110 -0
  37. package/dist/components/LiteMediaLibraryModal.svelte.d.ts +17 -0
  38. package/dist/components/LiteMentionsInput.svelte +98 -0
  39. package/dist/components/LiteMentionsInput.svelte.d.ts +19 -0
  40. package/dist/components/LiteModalForm.svelte +84 -0
  41. package/dist/components/LiteModalForm.svelte.d.ts +13 -0
  42. package/dist/components/LiteMultiTabKeepAlive.svelte +79 -0
  43. package/dist/components/LiteMultiTabKeepAlive.svelte.d.ts +15 -0
  44. package/dist/components/LiteOfflineSyncBanner.svelte +75 -0
  45. package/dist/components/LiteOfflineSyncBanner.svelte.d.ts +15 -0
  46. package/dist/components/LitePdfDocumentViewer.svelte +138 -0
  47. package/dist/components/LitePdfDocumentViewer.svelte.d.ts +17 -0
  48. package/dist/components/LitePivotTable.svelte +163 -0
  49. package/dist/components/LitePivotTable.svelte.d.ts +15 -0
  50. package/dist/components/LitePresenceAvatarGroup.svelte +52 -0
  51. package/dist/components/LitePresenceAvatarGroup.svelte.d.ts +12 -0
  52. package/dist/components/LitePrintableBill.svelte +119 -0
  53. package/dist/components/LitePrintableBill.svelte.d.ts +19 -0
  54. package/dist/components/LiteSensitiveDataMask.svelte +35 -0
  55. package/dist/components/LiteSensitiveDataMask.svelte.d.ts +7 -0
  56. package/dist/components/LiteShowField.svelte +22 -0
  57. package/dist/components/LiteSignaturePad.svelte +99 -0
  58. package/dist/components/LiteSignaturePad.svelte.d.ts +11 -0
  59. package/dist/components/LiteSplitPaneLayout.svelte +66 -0
  60. package/dist/components/LiteSplitPaneLayout.svelte.d.ts +9 -0
  61. package/dist/components/LiteSpreadsheetView.svelte +148 -0
  62. package/dist/components/LiteSpreadsheetView.svelte.d.ts +16 -0
  63. package/dist/components/LiteStepForm.svelte +144 -0
  64. package/dist/components/LiteStepForm.svelte.d.ts +18 -0
  65. package/dist/components/LiteTableSummary.svelte +93 -0
  66. package/dist/components/LiteTableSummary.svelte.d.ts +17 -0
  67. package/dist/components/LiteTransfer.svelte +185 -0
  68. package/dist/components/LiteTransfer.svelte.d.ts +18 -0
  69. package/dist/components/LiteTreeTable.svelte +85 -0
  70. package/dist/components/LiteTreeTable.svelte.d.ts +13 -0
  71. package/dist/components/LiteVersionDiffViewer.svelte +129 -0
  72. package/dist/components/LiteVersionDiffViewer.svelte.d.ts +10 -0
  73. package/dist/components/LiteVirtualTable.svelte +52 -0
  74. package/dist/components/LiteVirtualTable.svelte.d.ts +14 -0
  75. package/dist/components/LiteWatermark.svelte +35 -0
  76. package/dist/components/LiteWatermark.svelte.d.ts +11 -0
  77. package/dist/components/fields/LiteAvatarField.svelte +127 -0
  78. package/dist/components/fields/LiteAvatarField.svelte.d.ts +21 -0
  79. package/dist/components/fields/LiteCascader.svelte +119 -0
  80. package/dist/components/fields/LiteCascader.svelte.d.ts +24 -0
  81. package/dist/components/fields/LiteCodeField.svelte +71 -0
  82. package/dist/components/fields/LiteCodeField.svelte.d.ts +16 -0
  83. package/dist/components/fields/LiteCopyField.svelte +74 -0
  84. package/dist/components/fields/LiteCopyField.svelte.d.ts +18 -0
  85. package/dist/components/fields/LiteCurrencyField.svelte +126 -0
  86. package/dist/components/fields/LiteCurrencyField.svelte.d.ts +21 -0
  87. package/dist/components/fields/LiteDateRangeField.svelte +147 -0
  88. package/dist/components/fields/LiteDateRangeField.svelte.d.ts +26 -0
  89. package/dist/components/fields/LitePercentField.svelte +124 -0
  90. package/dist/components/fields/LitePercentField.svelte.d.ts +17 -0
  91. package/dist/components/fields/LitePhoneField.svelte +81 -0
  92. package/dist/components/fields/LitePhoneField.svelte.d.ts +17 -0
  93. package/dist/components/fields/LiteRatingField.svelte +105 -0
  94. package/dist/components/fields/LiteRatingField.svelte.d.ts +16 -0
  95. package/dist/components/fields/LiteTreeSelect.svelte +143 -0
  96. package/dist/components/fields/LiteTreeSelect.svelte.d.ts +23 -0
  97. package/dist/components/fields/index.d.ts +12 -0
  98. package/dist/components/fields/index.js +10 -0
  99. package/dist/components/pages/LiteListPage.svelte +14 -12
  100. package/dist/index.d.ts +40 -0
  101. package/dist/index.js +37 -0
  102. package/dist/lite.css +205 -0
  103. package/dist/schema-generator.js +15 -4
  104. package/package.json +4 -3
@@ -0,0 +1,19 @@
1
+ interface LiteEditableTableColumn {
2
+ key: string;
3
+ label: string;
4
+ type?: 'text' | 'number' | 'select' | 'boolean' | 'date';
5
+ options?: Array<{
6
+ label: string;
7
+ value: string | number;
8
+ }>;
9
+ }
10
+ interface Props {
11
+ columns: LiteEditableTableColumn[];
12
+ data?: Record<string, unknown>[];
13
+ action?: string;
14
+ method?: 'get' | 'post' | 'dialog' | 'GET' | 'POST' | 'DIALOG' | null;
15
+ rowKey?: string;
16
+ }
17
+ declare const LiteEditableTable: import("svelte").Component<Props, {}, "">;
18
+ type LiteEditableTable = ReturnType<typeof LiteEditableTable>;
19
+ export default LiteEditableTable;
@@ -0,0 +1,205 @@
1
+ <script lang="ts">
2
+ import type { CrudOperator, FieldDefinition, Filter } from '@svadmin/core';
3
+ import { t } from '@svadmin/core/i18n';
4
+
5
+ export interface FilterRuleItem {
6
+ id: string;
7
+ field: string;
8
+ operator: CrudOperator;
9
+ value: unknown;
10
+ }
11
+
12
+ interface Props {
13
+ fields?: FieldDefinition[];
14
+ filters?: Filter[];
15
+ logicalOperator?: 'and' | 'or';
16
+ action?: string;
17
+ method?: 'GET' | 'POST';
18
+ disabled?: boolean;
19
+ onApply?: (filters: Filter[]) => void;
20
+ }
21
+
22
+ let {
23
+ fields = [],
24
+ filters = [],
25
+ logicalOperator = 'and',
26
+ action = '',
27
+ disabled = false,
28
+ }: Props = $props();
29
+
30
+ const operatorOptions: { value: CrudOperator; label: string }[] = [
31
+ { value: 'eq', label: '= 等于' },
32
+ { value: 'ne', label: '!= 不等于' },
33
+ { value: 'contains', label: '包含' },
34
+ { value: 'ncontains', label: '不包含' },
35
+ { value: 'gt', label: '> 大于' },
36
+ { value: 'gte', label: '>= 大于等于' },
37
+ { value: 'lt', label: '< 小于' },
38
+ { value: 'lte', label: '<= 小于等于' },
39
+ { value: 'null', label: '为空 (null)' },
40
+ { value: 'nnull', label: '不为空' },
41
+ ];
42
+
43
+ // Flatten initial filters or fallback to 1 empty rule
44
+ const initialRules = $derived.by(() => {
45
+ if (filters.length > 0) {
46
+ return filters.map((f, i) => ({
47
+ id: `rule_${i}`,
48
+ field: 'field' in f ? String(f.field) : (fields[0]?.key ?? ''),
49
+ operator: ('operator' in f ? f.operator : 'eq') as CrudOperator,
50
+ value: 'value' in f ? f.value : '',
51
+ }));
52
+ }
53
+ return [
54
+ {
55
+ id: 'rule_0',
56
+ field: fields[0]?.key ?? '',
57
+ operator: 'eq' as CrudOperator,
58
+ value: '',
59
+ },
60
+ ];
61
+ });
62
+ </script>
63
+
64
+ <div class="lite-filter-builder lite-form-group">
65
+ <div class="lite-filter-header">
66
+ <div class="lite-filter-title">
67
+ <strong>{t('common.filters') || '高级多条件筛选'}</strong>
68
+ <select
69
+ name="logical_op"
70
+ class="lite-select lite-select-sm"
71
+ style="width: 120px; display: inline-block; margin-left: 8px;"
72
+ value={logicalOperator}
73
+ {disabled}
74
+ >
75
+ <option value="and">符合全部 (AND)</option>
76
+ <option value="or">符合任一 (OR)</option>
77
+ </select>
78
+ </div>
79
+ <div>
80
+ <button type="submit" name="_action" value="add_filter_rule" class="lite-btn lite-btn-sm" {disabled}>
81
+ + 添加条件
82
+ </button>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="lite-filter-rules">
87
+ {#each initialRules as rule, idx (rule.id)}
88
+ <div class="lite-filter-row">
89
+ <!-- Field select -->
90
+ <select
91
+ name="filter_field_{idx}"
92
+ class="lite-select lite-filter-field"
93
+ value={rule.field}
94
+ {disabled}
95
+ >
96
+ {#each fields as fld (fld.key)}
97
+ <option value={fld.key}>{fld.label || fld.key}</option>
98
+ {/each}
99
+ </select>
100
+
101
+ <!-- Operator select -->
102
+ <select
103
+ name="filter_op_{idx}"
104
+ class="lite-select lite-filter-op"
105
+ value={rule.operator}
106
+ {disabled}
107
+ >
108
+ {#each operatorOptions as op (op.value)}
109
+ <option value={op.value}>{op.label}</option>
110
+ {/each}
111
+ </select>
112
+
113
+ <!-- Value input -->
114
+ {#if rule.operator !== 'null' && rule.operator !== 'nnull'}
115
+ <input
116
+ type="text"
117
+ name="filter_val_{idx}"
118
+ class="lite-input lite-filter-val"
119
+ value={String(rule.value ?? '')}
120
+ placeholder="输入筛选值..."
121
+ {disabled}
122
+ />
123
+ {/if}
124
+
125
+ <!-- Remove row button -->
126
+ <button
127
+ type="submit"
128
+ name="_action"
129
+ value="remove_filter_rule_{idx}"
130
+ class="lite-btn lite-btn-sm lite-btn-danger"
131
+ {disabled}
132
+ title="删除此行条件"
133
+ >
134
+
135
+ </button>
136
+ </div>
137
+ {/each}
138
+ </div>
139
+
140
+ <div class="lite-filter-footer">
141
+ <button type="submit" class="lite-btn lite-btn-primary">
142
+ 应用筛选
143
+ </button>
144
+ <a href={action || '?'} class="lite-btn" style="margin-left: 8px;">
145
+ 重置
146
+ </a>
147
+ </div>
148
+ </div>
149
+
150
+ <style>
151
+ .lite-filter-builder {
152
+ border: 1px solid #cbd5e1;
153
+ border-radius: 6px;
154
+ padding: 14px;
155
+ background: #f8fafc;
156
+ margin-bottom: 16px;
157
+ }
158
+ .lite-filter-header {
159
+ display: flex;
160
+ justify-content: space-between;
161
+ align-items: center;
162
+ margin-bottom: 12px;
163
+ }
164
+ .lite-filter-rules {
165
+ display: flex;
166
+ flex-direction: column;
167
+ margin-bottom: 12px;
168
+ }
169
+ .lite-filter-row {
170
+ display: flex;
171
+ align-items: center;
172
+ background: #ffffff;
173
+ padding: 8px;
174
+ border: 1px solid #e2e8f0;
175
+ border-radius: 4px;
176
+ margin-bottom: 8px;
177
+ }
178
+ .lite-filter-row:last-child {
179
+ margin-bottom: 0;
180
+ }
181
+ .lite-filter-row > * {
182
+ margin-right: 8px;
183
+ }
184
+ .lite-filter-row > *:last-child {
185
+ margin-right: 0;
186
+ }
187
+ .lite-filter-field {
188
+ flex: 2;
189
+ min-width: 130px;
190
+ }
191
+ .lite-filter-op {
192
+ flex: 2;
193
+ min-width: 120px;
194
+ }
195
+ .lite-filter-val {
196
+ flex: 3;
197
+ min-width: 140px;
198
+ }
199
+ .lite-filter-footer {
200
+ display: flex;
201
+ align-items: center;
202
+ border-top: 1px solid #e2e8f0;
203
+ padding-top: 10px;
204
+ }
205
+ </style>
@@ -0,0 +1,19 @@
1
+ import type { CrudOperator, FieldDefinition, Filter } from '@svadmin/core';
2
+ export interface FilterRuleItem {
3
+ id: string;
4
+ field: string;
5
+ operator: CrudOperator;
6
+ value: unknown;
7
+ }
8
+ interface Props {
9
+ fields?: FieldDefinition[];
10
+ filters?: Filter[];
11
+ logicalOperator?: 'and' | 'or';
12
+ action?: string;
13
+ method?: 'GET' | 'POST';
14
+ disabled?: boolean;
15
+ onApply?: (filters: Filter[]) => void;
16
+ }
17
+ declare const LiteFilterBuilder: import("svelte").Component<Props, {}, "">;
18
+ type LiteFilterBuilder = ReturnType<typeof LiteFilterBuilder>;
19
+ export default LiteFilterBuilder;
@@ -0,0 +1,144 @@
1
+ <script lang="ts">
2
+ export interface GanttTask {
3
+ id: string;
4
+ title: string;
5
+ startDay: number;
6
+ durationDays: number;
7
+ progress?: number;
8
+ status?: 'planned' | 'in_progress' | 'completed' | 'delayed';
9
+ }
10
+
11
+ interface Props {
12
+ tasks?: GanttTask[];
13
+ totalDays?: number;
14
+ dayLabelPrefix?: string;
15
+ class?: string;
16
+ }
17
+
18
+ let {
19
+ tasks = [],
20
+ totalDays = 14,
21
+ dayLabelPrefix = 'D',
22
+ class: className = '',
23
+ }: Props = $props();
24
+
25
+ const days = $derived(
26
+ Array.from({ length: totalDays }, (_, i) => `${dayLabelPrefix}${i + 1}`)
27
+ );
28
+ </script>
29
+
30
+ <div class="sv-lite-gantt-container {className}">
31
+ <div class="sv-lite-gantt-title">
32
+ <strong>Project Schedule</strong> ({tasks.length} tasks / {totalDays} days)
33
+ </div>
34
+
35
+ <table class="sv-lite-gantt-table">
36
+ <thead>
37
+ <tr>
38
+ <th class="sv-lite-th-task">Task</th>
39
+ <th class="sv-lite-th-status">Status</th>
40
+ {#each days as day (day)}
41
+ <th class="sv-lite-th-day">{day}</th>
42
+ {/each}
43
+ </tr>
44
+ </thead>
45
+ <tbody>
46
+ {#each tasks as task (task.id)}
47
+ <tr>
48
+ <td class="sv-lite-td-task">{task.title}</td>
49
+ <td class="sv-lite-td-status">
50
+ <span class="sv-lite-gantt-badge sv-lite-{task.status ?? 'planned'}">{task.status ?? 'planned'}</span>
51
+ </td>
52
+ {#each days as _, dIdx (dIdx)}
53
+ {@const isCovered = dIdx >= task.startDay && dIdx < task.startDay + task.durationDays}
54
+ <td class="sv-lite-td-cell {isCovered ? 'sv-lite-cell-active sv-lite-bg-' + (task.status ?? 'planned') : ''}">
55
+ {#if isCovered && dIdx === task.startDay && task.progress !== undefined}
56
+ <span class="sv-lite-cell-progress">{task.progress}%</span>
57
+ {/if}
58
+ </td>
59
+ {/each}
60
+ </tr>
61
+ {/each}
62
+ </tbody>
63
+ </table>
64
+ </div>
65
+
66
+ <style>
67
+ .sv-lite-gantt-container {
68
+ display: block;
69
+ border: 1px solid #e2e8f0;
70
+ border-radius: 6px;
71
+ padding: 12px;
72
+ background-color: #ffffff;
73
+ font-size: 12px;
74
+ overflow-x: auto;
75
+ }
76
+ .sv-lite-gantt-title {
77
+ margin-bottom: 10px;
78
+ font-size: 13px;
79
+ color: #0f172a;
80
+ }
81
+ .sv-lite-gantt-table {
82
+ width: 100%;
83
+ border-collapse: collapse;
84
+ text-align: center;
85
+ }
86
+ .sv-lite-gantt-table th, .sv-lite-gantt-table td {
87
+ border: 1px solid #e2e8f0;
88
+ padding: 6px;
89
+ }
90
+ .sv-lite-th-task, .sv-lite-td-task {
91
+ text-align: left;
92
+ min-width: 140px;
93
+ font-weight: 500;
94
+ }
95
+ .sv-lite-th-day {
96
+ min-width: 28px;
97
+ font-size: 10px;
98
+ background-color: #f8fafc;
99
+ color: #64748b;
100
+ }
101
+ .sv-lite-gantt-badge {
102
+ display: inline-block;
103
+ padding: 2px 6px;
104
+ border-radius: 3px;
105
+ font-size: 10px;
106
+ text-transform: uppercase;
107
+ }
108
+ .sv-lite-completed {
109
+ background-color: #dcfce7;
110
+ color: #166534;
111
+ }
112
+ .sv-lite-delayed {
113
+ background-color: #fee2e2;
114
+ color: #991b1b;
115
+ }
116
+ .sv-lite-in_progress {
117
+ background-color: #e0e7ff;
118
+ color: #3730a3;
119
+ }
120
+ .sv-lite-planned {
121
+ background-color: #f1f5f9;
122
+ color: #475569;
123
+ }
124
+ .sv-lite-cell-active {
125
+ background-color: #818cf8;
126
+ color: #ffffff;
127
+ }
128
+ .sv-lite-bg-completed {
129
+ background-color: #4ade80;
130
+ }
131
+ .sv-lite-bg-delayed {
132
+ background-color: #f87171;
133
+ }
134
+ .sv-lite-bg-in_progress {
135
+ background-color: #6366f1;
136
+ }
137
+ .sv-lite-bg-planned {
138
+ background-color: #94a3b8;
139
+ }
140
+ .sv-lite-cell-progress {
141
+ font-size: 9px;
142
+ font-weight: bold;
143
+ }
144
+ </style>
@@ -0,0 +1,17 @@
1
+ export interface GanttTask {
2
+ id: string;
3
+ title: string;
4
+ startDay: number;
5
+ durationDays: number;
6
+ progress?: number;
7
+ status?: 'planned' | 'in_progress' | 'completed' | 'delayed';
8
+ }
9
+ interface Props {
10
+ tasks?: GanttTask[];
11
+ totalDays?: number;
12
+ dayLabelPrefix?: string;
13
+ class?: string;
14
+ }
15
+ declare const LiteGanttChart: import("svelte").Component<Props, {}, "">;
16
+ type LiteGanttChart = ReturnType<typeof LiteGanttChart>;
17
+ export default LiteGanttChart;
@@ -0,0 +1,81 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ imageUrl: string;
4
+ aspectRatio?: number;
5
+ action?: string;
6
+ method?: 'get' | 'post' | 'dialog' | 'GET' | 'POST' | 'DIALOG' | null;
7
+ }
8
+
9
+ let {
10
+ imageUrl,
11
+ aspectRatio = 1,
12
+ action = '',
13
+ method = 'POST',
14
+ }: Props = $props();
15
+ </script>
16
+
17
+ <div class="lite-cropper-card">
18
+ <div class="lite-cropper-header">
19
+ <strong>Image Crop (Aspect Ratio: {aspectRatio}:1)</strong>
20
+ </div>
21
+
22
+ <div class="lite-cropper-preview">
23
+ <img src={imageUrl} alt="Source Preview" class="lite-cropper-img" />
24
+ </div>
25
+
26
+ <form {action} {method} class="lite-cropper-form">
27
+ <input type="hidden" name="imageUrl" value={imageUrl} />
28
+ <input type="hidden" name="aspectRatio" value={aspectRatio} />
29
+
30
+ <div class="lite-cropper-row">
31
+ <label for="lite_crop_scale_input" class="lite-label">Scale Factor:</label>
32
+ <select id="lite_crop_scale_input" name="zoom" class="lite-select" style="width: 100px;">
33
+ <option value="1">100%</option>
34
+ <option value="1.2">120%</option>
35
+ <option value="1.5">150%</option>
36
+ <option value="2">200%</option>
37
+ </select>
38
+ </div>
39
+
40
+ <div class="lite-cropper-footer">
41
+ <button type="submit" class="lite-btn lite-btn-primary lite-btn-sm">
42
+ Save Image
43
+ </button>
44
+ </div>
45
+ </form>
46
+ </div>
47
+
48
+ <style>
49
+ .lite-cropper-card {
50
+ background: #ffffff;
51
+ border: 1px solid #cbd5e1;
52
+ border-radius: 6px;
53
+ padding: 16px;
54
+ margin-bottom: 16px;
55
+ max-width: 480px;
56
+ }
57
+ .lite-cropper-header {
58
+ padding-bottom: 8px;
59
+ border-bottom: 1px solid #e2e8f0;
60
+ margin-bottom: 12px;
61
+ font-size: 13px;
62
+ }
63
+ .lite-cropper-preview {
64
+ text-align: center;
65
+ background: #f1f5f9;
66
+ padding: 12px;
67
+ border-radius: 4px;
68
+ margin-bottom: 12px;
69
+ }
70
+ .lite-cropper-img {
71
+ max-width: 100%;
72
+ max-height: 200px;
73
+ }
74
+ .lite-cropper-row {
75
+ margin-bottom: 12px;
76
+ }
77
+ .lite-cropper-footer {
78
+ display: flex;
79
+ justify-content: flex-end;
80
+ }
81
+ </style>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ imageUrl: string;
3
+ aspectRatio?: number;
4
+ action?: string;
5
+ method?: 'get' | 'post' | 'dialog' | 'GET' | 'POST' | 'DIALOG' | null;
6
+ }
7
+ declare const LiteImageCropper: import("svelte").Component<Props, {}, "">;
8
+ type LiteImageCropper = ReturnType<typeof LiteImageCropper>;
9
+ export default LiteImageCropper;
@@ -0,0 +1,99 @@
1
+ <script lang="ts">
2
+ import type { FieldDefinition } from '@svadmin/core';
3
+
4
+ interface Props {
5
+ resourceName: string;
6
+ fields?: FieldDefinition[];
7
+ action?: string;
8
+ method?: 'POST' | 'post';
9
+ submitText?: string;
10
+ }
11
+
12
+ let {
13
+ resourceName,
14
+ fields = [],
15
+ action = '',
16
+ method = 'POST',
17
+ submitText = 'Upload & Import CSV',
18
+ }: Props = $props();
19
+ </script>
20
+
21
+ <div class="lite-import-wizard lite-form-group">
22
+ <div class="lite-import-title">
23
+ <strong>📥 Import {resourceName}</strong>
24
+ </div>
25
+ <form {action} {method} enctype="multipart/form-data" class="lite-import-form">
26
+ <div class="lite-file-row">
27
+ <label for="import_file" class="lite-label">Select CSV / JSON file:</label>
28
+ <input type="file" id="import_file" name="file" accept=".csv,.json" class="lite-input" required />
29
+ </div>
30
+
31
+ {#if fields.length > 0}
32
+ <div class="lite-field-mapping-hints">
33
+ <span class="lite-hint-title">Target Schema Fields:</span>
34
+ <div class="lite-field-tags">
35
+ {#each fields as field (field.key)}
36
+ <span class="lite-badge">{field.label} ({field.key})</span>
37
+ {/each}
38
+ </div>
39
+ </div>
40
+ {/if}
41
+
42
+ <div class="lite-import-actions">
43
+ <button type="submit" class="lite-btn lite-btn-primary">
44
+ {submitText}
45
+ </button>
46
+ </div>
47
+ </form>
48
+ </div>
49
+
50
+ <style>
51
+ .lite-import-wizard {
52
+ padding: 12px;
53
+ background: #f8fafc;
54
+ border: 1px solid #cbd5e1;
55
+ border-radius: 6px;
56
+ margin-bottom: 16px;
57
+ }
58
+ .lite-import-title {
59
+ font-size: 13px;
60
+ color: #334155;
61
+ margin-bottom: 8px;
62
+ }
63
+ .lite-file-row {
64
+ margin-bottom: 10px;
65
+ }
66
+ .lite-label {
67
+ display: block;
68
+ font-size: 12px;
69
+ color: #475569;
70
+ margin-bottom: 4px;
71
+ }
72
+ .lite-field-mapping-hints {
73
+ margin-bottom: 12px;
74
+ font-size: 11px;
75
+ color: #64748b;
76
+ }
77
+ .lite-hint-title {
78
+ display: block;
79
+ margin-bottom: 4px;
80
+ font-weight: 600;
81
+ }
82
+ .lite-field-tags {
83
+ display: flex;
84
+ flex-wrap: wrap;
85
+ }
86
+ .lite-badge {
87
+ display: inline-block;
88
+ background: #e2e8f0;
89
+ color: #334155;
90
+ padding: 2px 6px;
91
+ border-radius: 3px;
92
+ margin-right: 6px;
93
+ margin-bottom: 4px;
94
+ font-size: 11px;
95
+ }
96
+ .lite-import-actions {
97
+ margin-top: 8px;
98
+ }
99
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { FieldDefinition } from '@svadmin/core';
2
+ interface Props {
3
+ resourceName: string;
4
+ fields?: FieldDefinition[];
5
+ action?: string;
6
+ method?: 'POST' | 'post';
7
+ submitText?: string;
8
+ }
9
+ declare const LiteImportWizard: import("svelte").Component<Props, {}, "">;
10
+ type LiteImportWizard = ReturnType<typeof LiteImportWizard>;
11
+ export default LiteImportWizard;