@svadmin/lite 0.3.7 → 0.3.10

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 (172) hide show
  1. package/README.md +19 -13
  2. package/dist/components/LiteAlert.svelte +19 -0
  3. package/dist/components/LiteAlert.svelte.d.ts +11 -0
  4. package/dist/components/LiteArrayField.svelte +60 -0
  5. package/dist/components/LiteArrayField.svelte.d.ts +17 -0
  6. package/dist/components/LiteArrayItem.svelte +146 -0
  7. package/dist/components/LiteArrayItem.svelte.d.ts +13 -0
  8. package/dist/components/LiteAuditLog.svelte +104 -0
  9. package/dist/components/LiteAuditLog.svelte.d.ts +23 -0
  10. package/dist/components/LiteBreadcrumbs.svelte +39 -0
  11. package/dist/components/LiteBreadcrumbs.svelte.d.ts +16 -0
  12. package/dist/components/LiteChatDialog.svelte +101 -0
  13. package/dist/components/LiteChatDialog.svelte.d.ts +20 -0
  14. package/dist/components/LiteConfirmDialog.svelte +60 -0
  15. package/dist/components/LiteConfirmDialog.svelte.d.ts +22 -0
  16. package/dist/components/LiteEmptyState.svelte +39 -0
  17. package/dist/components/LiteEmptyState.svelte.d.ts +16 -0
  18. package/dist/components/LiteForm.svelte +165 -0
  19. package/dist/components/LiteForm.svelte.d.ts +26 -0
  20. package/dist/components/LiteLayout.svelte +147 -0
  21. package/dist/components/LiteLayout.svelte.d.ts +19 -0
  22. package/dist/components/LiteLogin.svelte +41 -0
  23. package/dist/components/LiteLogin.svelte.d.ts +8 -0
  24. package/dist/components/LitePagination.svelte +73 -0
  25. package/dist/components/LitePagination.svelte.d.ts +11 -0
  26. package/dist/components/LitePermissionMatrix.svelte +147 -0
  27. package/dist/components/LitePermissionMatrix.svelte.d.ts +32 -0
  28. package/dist/components/LiteSearch.svelte +41 -0
  29. package/dist/components/LiteSearch.svelte.d.ts +9 -0
  30. package/dist/components/LiteShow.svelte +61 -0
  31. package/dist/components/LiteShow.svelte.d.ts +14 -0
  32. package/dist/components/LiteShowField.svelte +62 -0
  33. package/dist/components/LiteShowField.svelte.d.ts +12 -0
  34. package/dist/components/LiteStatsCard.svelte +70 -0
  35. package/dist/components/LiteStatsCard.svelte.d.ts +24 -0
  36. package/dist/components/LiteTable.svelte +132 -0
  37. package/dist/components/LiteTable.svelte.d.ts +19 -0
  38. package/dist/components/LiteTabs.svelte +57 -0
  39. package/dist/components/LiteTabs.svelte.d.ts +16 -0
  40. package/dist/components/advanced/LiteAutoSaveIndicator.svelte +26 -0
  41. package/dist/components/advanced/LiteAutoSaveIndicator.svelte.d.ts +12 -0
  42. package/dist/components/advanced/LiteDraggableHeader.svelte +33 -0
  43. package/dist/components/advanced/LiteDraggableHeader.svelte.d.ts +15 -0
  44. package/dist/components/advanced/LiteDrawerForm.svelte +42 -0
  45. package/dist/components/advanced/LiteDrawerForm.svelte.d.ts +16 -0
  46. package/dist/components/advanced/LiteInlineEdit.svelte +32 -0
  47. package/dist/components/advanced/LiteInlineEdit.svelte.d.ts +15 -0
  48. package/dist/components/advanced/LiteModalForm.svelte +44 -0
  49. package/dist/components/advanced/LiteModalForm.svelte.d.ts +17 -0
  50. package/dist/components/advanced/LiteToast.svelte +34 -0
  51. package/dist/components/advanced/LiteToast.svelte.d.ts +14 -0
  52. package/dist/components/advanced/LiteUndoableNotification.svelte +25 -0
  53. package/dist/components/advanced/LiteUndoableNotification.svelte.d.ts +13 -0
  54. package/dist/components/advanced/LiteVirtualTable.svelte +44 -0
  55. package/dist/components/advanced/LiteVirtualTable.svelte.d.ts +20 -0
  56. package/dist/components/advanced/index.js +8 -0
  57. package/dist/components/buttons/LiteCloneButton.svelte +33 -0
  58. package/dist/components/buttons/LiteCloneButton.svelte.d.ts +11 -0
  59. package/dist/components/buttons/LiteCreateButton.svelte +31 -0
  60. package/dist/components/buttons/LiteCreateButton.svelte.d.ts +10 -0
  61. package/dist/components/buttons/LiteDeleteButton.svelte +57 -0
  62. package/dist/components/buttons/LiteDeleteButton.svelte.d.ts +12 -0
  63. package/dist/components/buttons/LiteEditButton.svelte +33 -0
  64. package/dist/components/buttons/LiteEditButton.svelte.d.ts +11 -0
  65. package/dist/components/buttons/LiteExportButton.svelte +31 -0
  66. package/dist/components/buttons/LiteExportButton.svelte.d.ts +10 -0
  67. package/dist/components/buttons/LiteImportButton.svelte +50 -0
  68. package/dist/components/buttons/LiteImportButton.svelte.d.ts +10 -0
  69. package/dist/components/buttons/LiteListButton.svelte +31 -0
  70. package/dist/components/buttons/LiteListButton.svelte.d.ts +10 -0
  71. package/dist/components/buttons/LiteRefreshButton.svelte +34 -0
  72. package/dist/components/buttons/LiteRefreshButton.svelte.d.ts +8 -0
  73. package/dist/components/buttons/LiteSaveButton.svelte +27 -0
  74. package/dist/components/buttons/LiteSaveButton.svelte.d.ts +8 -0
  75. package/dist/components/buttons/LiteShowButton.svelte +33 -0
  76. package/dist/components/buttons/LiteShowButton.svelte.d.ts +11 -0
  77. package/dist/components/buttons/index.js +10 -0
  78. package/dist/components/fields/LiteBooleanField.svelte +42 -0
  79. package/dist/components/fields/LiteBooleanField.svelte.d.ts +10 -0
  80. package/dist/components/fields/LiteDateField.svelte +51 -0
  81. package/dist/components/fields/LiteDateField.svelte.d.ts +10 -0
  82. package/dist/components/fields/LiteEmailField.svelte +41 -0
  83. package/dist/components/fields/LiteEmailField.svelte.d.ts +10 -0
  84. package/dist/components/fields/LiteFileField.svelte +59 -0
  85. package/dist/components/fields/LiteFileField.svelte.d.ts +10 -0
  86. package/dist/components/fields/LiteImageField.svelte +57 -0
  87. package/dist/components/fields/LiteImageField.svelte.d.ts +10 -0
  88. package/dist/components/fields/LiteJsonField.svelte +43 -0
  89. package/dist/components/fields/LiteJsonField.svelte.d.ts +10 -0
  90. package/dist/components/fields/LiteMarkdownField.svelte +33 -0
  91. package/dist/components/fields/LiteMarkdownField.svelte.d.ts +10 -0
  92. package/dist/components/fields/LiteMultiSelectField.svelte +57 -0
  93. package/dist/components/fields/LiteMultiSelectField.svelte.d.ts +10 -0
  94. package/dist/components/fields/LiteNumberField.svelte +35 -0
  95. package/dist/components/fields/LiteNumberField.svelte.d.ts +10 -0
  96. package/dist/components/fields/LiteRelationField.svelte +67 -0
  97. package/dist/components/fields/LiteRelationField.svelte.d.ts +10 -0
  98. package/dist/components/fields/LiteRichTextField.svelte +44 -0
  99. package/dist/components/fields/LiteRichTextField.svelte.d.ts +10 -0
  100. package/dist/components/fields/LiteSelectField.svelte +47 -0
  101. package/dist/components/fields/LiteSelectField.svelte.d.ts +10 -0
  102. package/dist/components/fields/LiteTagField.svelte +44 -0
  103. package/dist/components/fields/LiteTagField.svelte.d.ts +10 -0
  104. package/dist/components/fields/LiteTextField.svelte +35 -0
  105. package/dist/components/fields/LiteTextField.svelte.d.ts +10 -0
  106. package/dist/components/fields/LiteUrlField.svelte +52 -0
  107. package/dist/components/fields/LiteUrlField.svelte.d.ts +10 -0
  108. package/dist/components/fields/index.js +15 -0
  109. package/dist/components/layout/LiteAuthenticated.svelte +23 -0
  110. package/dist/components/layout/LiteAuthenticated.svelte.d.ts +10 -0
  111. package/dist/components/layout/LiteCanAccess.svelte +27 -0
  112. package/dist/components/layout/LiteCanAccess.svelte.d.ts +10 -0
  113. package/dist/components/layout/LiteCatchAllNavigate.svelte +20 -0
  114. package/dist/components/layout/LiteCatchAllNavigate.svelte.d.ts +7 -0
  115. package/dist/components/layout/LiteErrorBoundary.svelte +20 -0
  116. package/dist/components/layout/LiteErrorBoundary.svelte.d.ts +13 -0
  117. package/dist/components/layout/LiteErrorComponent.svelte +37 -0
  118. package/dist/components/layout/LiteErrorComponent.svelte.d.ts +9 -0
  119. package/dist/components/layout/LiteHeader.svelte +19 -0
  120. package/dist/components/layout/LiteHeader.svelte.d.ts +8 -0
  121. package/dist/components/layout/LiteNavigateToResource.svelte +25 -0
  122. package/dist/components/layout/LiteNavigateToResource.svelte.d.ts +7 -0
  123. package/dist/components/layout/LiteSidebar.svelte +93 -0
  124. package/dist/components/layout/LiteSidebar.svelte.d.ts +12 -0
  125. package/dist/components/layout/index.js +8 -0
  126. package/dist/components/pages/LiteCreatePage.svelte +39 -0
  127. package/dist/components/pages/LiteCreatePage.svelte.d.ts +10 -0
  128. package/dist/components/pages/LiteEditPage.svelte +54 -0
  129. package/dist/components/pages/LiteEditPage.svelte.d.ts +12 -0
  130. package/dist/components/pages/LiteForgotPasswordPage.svelte +60 -0
  131. package/dist/components/pages/LiteForgotPasswordPage.svelte.d.ts +11 -0
  132. package/dist/components/pages/LiteListPage.svelte +81 -0
  133. package/dist/components/pages/LiteListPage.svelte.d.ts +20 -0
  134. package/dist/components/pages/LiteProfilePage.svelte +61 -0
  135. package/dist/components/pages/LiteProfilePage.svelte.d.ts +14 -0
  136. package/dist/components/pages/LiteRegisterPage.svelte +63 -0
  137. package/dist/components/pages/LiteRegisterPage.svelte.d.ts +10 -0
  138. package/dist/components/pages/LiteShowPage.svelte +61 -0
  139. package/dist/components/pages/LiteShowPage.svelte.d.ts +11 -0
  140. package/dist/components/pages/LiteUpdatePasswordPage.svelte +51 -0
  141. package/dist/components/pages/LiteUpdatePasswordPage.svelte.d.ts +9 -0
  142. package/dist/components/pages/index.js +8 -0
  143. package/dist/components/widgets/LiteAnomalyBadge.svelte +40 -0
  144. package/dist/components/widgets/LiteAnomalyBadge.svelte.d.ts +15 -0
  145. package/dist/components/widgets/LiteBarChart.svelte +45 -0
  146. package/dist/components/widgets/LiteBarChart.svelte.d.ts +17 -0
  147. package/dist/components/widgets/LiteInsightCard.svelte +31 -0
  148. package/dist/components/widgets/LiteInsightCard.svelte.d.ts +13 -0
  149. package/dist/components/widgets/LiteLineChart.svelte +48 -0
  150. package/dist/components/widgets/LiteLineChart.svelte.d.ts +17 -0
  151. package/dist/components/widgets/LitePieChart.svelte +44 -0
  152. package/dist/components/widgets/LitePieChart.svelte.d.ts +17 -0
  153. package/dist/components/widgets/index.js +5 -0
  154. package/dist/enhance.js +112 -0
  155. package/dist/index.d.ts +27 -0
  156. package/{src/index.ts → dist/index.js} +3 -26
  157. package/dist/lite.css +817 -0
  158. package/dist/schema-generator.d.ts +29 -0
  159. package/dist/schema-generator.js +226 -0
  160. package/dist/security.d.ts +14 -0
  161. package/dist/security.js +59 -0
  162. package/dist/server-adapter.d.ts +111 -0
  163. package/dist/server-adapter.js +422 -0
  164. package/package.json +55 -18
  165. package/src/schema-generator.ts +0 -147
  166. package/src/server-adapter.ts +0 -307
  167. /package/{src/components/advanced/index.ts → dist/components/advanced/index.d.ts} +0 -0
  168. /package/{src/components/buttons/index.ts → dist/components/buttons/index.d.ts} +0 -0
  169. /package/{src/components/fields/index.ts → dist/components/fields/index.d.ts} +0 -0
  170. /package/{src/components/layout/index.ts → dist/components/layout/index.d.ts} +0 -0
  171. /package/{src/components/pages/index.ts → dist/components/pages/index.d.ts} +0 -0
  172. /package/{src/components/widgets/index.ts → dist/components/widgets/index.d.ts} +0 -0
package/README.md CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  **Lightweight, SSR-compatible admin UI for [@svadmin](https://github.com/zuohuadong/svadmin).**
4
4
 
5
- Zero client-side JavaScript required. Works in IE11 and all modern browsers.
5
+ Core server-driven CRUD flows can run without hydration. An optional `enhance.js` asset adds progressive client-side conveniences.
6
+
7
+ The bundled CSS follows an IE11-oriented baseline, but Svelte 5, SvelteKit, Tailwind-based companion packages, and each consumer's transpilation target determine the final browser support. This package therefore does not make a blanket IE11 compatibility guarantee.
6
8
 
7
9
  ## Why?
8
10
 
9
- The main `@svadmin/ui` package delivers a premium SPA experience using Svelte 5, Tailwind CSS v4, and TanStack.
10
- However, some enterprise/government environments require IE11 compatibility.
11
+ The main `@svadmin/ui` package delivers a premium SPA experience using Svelte 5, Tailwind CSS v4, and TanStack. Those tools target modern browsers. Some enterprise/government environments instead prefer server-driven navigation, native forms, and a smaller client-side runtime.
11
12
 
12
13
  `@svadmin/lite` provides a server-rendered fallback that **shares the same DataProvider, AuthProvider, and Resource definitions** — only the rendering layer is different.
13
14
 
@@ -23,7 +24,7 @@ However, some enterprise/government environments require IE11 compatibility.
23
24
  | **Pagination** | Pure `<a>` page links |
24
25
  | **Login/Logout** | Cookie-based auth via SvelteKit Form Actions |
25
26
  | **Auth Guard** | Server hook redirects unauthenticated users |
26
- | **UA Detection** | Auto-redirect IE11 users to `/lite/` routes |
27
+ | **UA Detection** | Optional legacy-browser detection hook redirects users to `/lite/` routes |
27
28
  | **i18n** | Uses `@svadmin/core` `t()` translations |
28
29
  | **Multi-level Menu** | Config-driven 2/3 level menus via `MenuItem[]` |
29
30
  | **Print** | `@media print` optimized styles |
@@ -49,13 +50,16 @@ export const load = createListLoader(dataProvider, postsResource);
49
50
  export const actions = createCrudActions(dataProvider, postsResource);
50
51
  ```
51
52
 
53
+ ```typescript
54
+ // src/routes/lite/posts/+page.ts
55
+ export const csr = false;
56
+ ```
57
+
52
58
  ```svelte
53
59
  <!-- src/routes/lite/posts/+page.svelte -->
54
60
  <script lang="ts">
55
- export const csr = false; // ← Critical: disable client-side rendering
56
-
57
61
  import { LiteLayout, LiteTable, LitePagination, LiteSearch, LiteAlert } from '@svadmin/lite';
58
- import '@svadmin/lite/src/lite.css';
62
+ import '@svadmin/lite/lite.css';
59
63
  import { resources } from '$lib/admin';
60
64
 
61
65
  let { data, form } = $props();
@@ -121,7 +125,7 @@ Pass a `menu` prop to `LiteLayout` to replace the auto-generated flat resource l
121
125
  </LiteLayout>
122
126
  ```
123
127
 
124
- ### 3. Auto-redirect legacy browsers
128
+ ### 3. Optionally route legacy browsers to Lite pages
125
129
 
126
130
  ```typescript
127
131
  // src/hooks.server.ts
@@ -130,7 +134,7 @@ import { createLegacyRedirectHook } from '@svadmin/lite';
130
134
  export const handle = createLegacyRedirectHook('/lite');
131
135
  ```
132
136
 
133
- ### 4. Add the `<meta>` tags for dual-core browsers
137
+ ### 4. Optional legacy-browser metadata
134
138
 
135
139
  ```html
136
140
  <!-- src/app.html -->
@@ -168,8 +172,8 @@ export const handle = createLegacyRedirectHook('/lite');
168
172
 
169
173
  ## CSS
170
174
 
171
- Import `@svadmin/lite/src/lite.css` in your layout. It's fully self-contained:
172
- - IE11+ baseline (standard flexbox, no CSS variables)
175
+ Import `@svadmin/lite/lite.css` in your layout. It's fully self-contained:
176
+ - IE11-oriented CSS baseline (standard flexbox, no CSS variables)
173
177
  - Custom-styled checkboxes, radios, and selects (no `appearance: none` needed)
174
178
  - Indigo/Slate color system aligned with `@svadmin/ui`
175
179
  - Modern focus rings (`box-shadow` based)
@@ -178,14 +182,16 @@ Import `@svadmin/lite/src/lite.css` in your layout. It's fully self-contained:
178
182
  - Print-optimized styles
179
183
  - ~500 lines, ~14KB unminified
180
184
 
185
+ This CSS baseline helps older browsers, but the generated Svelte/SvelteKit application and any Tailwind v4 UI used alongside Lite still require the browser targets configured by those tools (Tailwind v4 itself targets modern browsers).
186
+
181
187
  ## Optional: Progressive Enhancement
182
188
 
183
- Copy `packages/lite/static/enhance.js` to your static folder. This ES5 script adds:
189
+ Copy the exported `@svadmin/lite/enhance.js` asset to your application's static folder. This ES5 script adds:
184
190
  - Auto-close delete confirmation when clicking outside
185
191
  - Auto-focus first form input
186
192
  - Unsaved changes warning
187
193
 
188
- **100% optional** everything works without it.
194
+ The asset is optional for core server-rendered navigation and form submission; the conveniences listed above require it.
189
195
 
190
196
  ## License
191
197
 
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ /**
3
+ * LiteAlert — Success/error feedback banner for form actions.
4
+ * Renders from SvelteKit form action results.
5
+ */
6
+ interface Props {
7
+ type: 'success' | 'error' | 'info';
8
+ message: string;
9
+ }
10
+
11
+ let { type, message }: Props = $props();
12
+ </script>
13
+
14
+ {#if message}
15
+ <div class="lite-alert {type === 'success' ? 'lite-alert-success' : type === 'error' ? 'lite-alert-error' : ''}">
16
+ {#if type === 'success'}✓{:else if type === 'error'}✗{:else}ℹ{/if}
17
+ {message}
18
+ </div>
19
+ {/if}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * LiteAlert — Success/error feedback banner for form actions.
3
+ * Renders from SvelteKit form action results.
4
+ */
5
+ interface Props {
6
+ type: 'success' | 'error' | 'info';
7
+ message: string;
8
+ }
9
+ declare const LiteAlert: import("svelte").Component<Props, {}, "">;
10
+ type LiteAlert = ReturnType<typeof LiteAlert>;
11
+ export default LiteAlert;
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ /**
3
+ * LiteArrayField — SSR-compatible array sub-form.
4
+ * One row and remove-on-save controls work without JavaScript; enhance.js
5
+ * progressively adds in-place add/remove controls.
6
+ */
7
+ import type { FieldDefinition } from '@svadmin/core';
8
+ import LiteArrayItem from './LiteArrayItem.svelte';
9
+
10
+ interface Props {
11
+ field: FieldDefinition;
12
+ /** Current array values */
13
+ values?: Record<string, unknown>[];
14
+ /** Form field name prefix (for nested form encoding) */
15
+ namePrefix?: string;
16
+ mode?: 'create' | 'edit';
17
+ }
18
+
19
+ let {
20
+ field,
21
+ values = [],
22
+ namePrefix = field.key,
23
+ mode = 'create',
24
+ }: Props = $props();
25
+
26
+ const subFields = $derived(field.subFields || []);
27
+ const renderedValues = $derived(values.length > 0 ? values : [{}]);
28
+ const hasServerValues = $derived(values.length > 0);
29
+ </script>
30
+
31
+ <fieldset
32
+ class="lite-array-field"
33
+ data-lite-array
34
+ data-lite-array-name={namePrefix}
35
+ data-next-index={renderedValues.length}
36
+ >
37
+ <legend>
38
+ {field.label}
39
+ {#if field.required}<span class="required">*</span>{/if}
40
+ </legend>
41
+
42
+ {#each renderedValues as item, i (i)}
43
+ <LiteArrayItem
44
+ {subFields}
45
+ {item}
46
+ {namePrefix}
47
+ index={i}
48
+ isDraft={!field.required && !hasServerValues}
49
+ {mode}
50
+ />
51
+ {/each}
52
+
53
+ <button type="button" class="lite-btn" data-lite-array-add hidden>
54
+ + Add Item
55
+ </button>
56
+
57
+ <template data-lite-array-template>
58
+ <LiteArrayItem {subFields} item={{}} {namePrefix} index="__INDEX__" isDraft={false} {mode} />
59
+ </template>
60
+ </fieldset>
@@ -0,0 +1,17 @@
1
+ /**
2
+ * LiteArrayField — SSR-compatible array sub-form.
3
+ * One row and remove-on-save controls work without JavaScript; enhance.js
4
+ * progressively adds in-place add/remove controls.
5
+ */
6
+ import type { FieldDefinition } from '@svadmin/core';
7
+ interface Props {
8
+ field: FieldDefinition;
9
+ /** Current array values */
10
+ values?: Record<string, unknown>[];
11
+ /** Form field name prefix (for nested form encoding) */
12
+ namePrefix?: string;
13
+ mode?: 'create' | 'edit';
14
+ }
15
+ declare const LiteArrayField: import("svelte").Component<Props, {}, "">;
16
+ type LiteArrayField = ReturnType<typeof LiteArrayField>;
17
+ export default LiteArrayField;
@@ -0,0 +1,146 @@
1
+ <script lang="ts">
2
+ import type { FieldDefinition } from '@svadmin/core';
3
+ import { fieldToInputType, fieldToPlaceholder } from '../schema-generator';
4
+
5
+ interface Props {
6
+ subFields: FieldDefinition[];
7
+ item: Record<string, unknown>;
8
+ namePrefix: string;
9
+ index: number | string;
10
+ /** Empty optional-array placeholder that remains server-submittable without JS. */
11
+ isDraft?: boolean;
12
+ mode?: 'create' | 'edit';
13
+ }
14
+
15
+ let { subFields, item, namePrefix, index, isDraft = false, mode = 'create' }: Props = $props();
16
+
17
+ function fieldName(key: string): string {
18
+ return `${namePrefix}[${index}][${key}]`;
19
+ }
20
+
21
+ function fieldId(key: string): string {
22
+ return `${namePrefix}_${index}_${key}`;
23
+ }
24
+
25
+ function displayValue(value: unknown): string {
26
+ if (value == null) return '';
27
+ if (typeof value === 'object') {
28
+ try {
29
+ return JSON.stringify(value);
30
+ } catch {
31
+ return '';
32
+ }
33
+ }
34
+ return String(value);
35
+ }
36
+
37
+ function retainedUploadReferences(value: unknown): string[] {
38
+ if (typeof value === 'string') return value.trim() ? [value] : [];
39
+ if (Array.isArray(value)) return value.flatMap(retainedUploadReferences);
40
+ return [];
41
+ }
42
+ </script>
43
+
44
+ <div
45
+ class="lite-array-item"
46
+ data-lite-array-item
47
+ data-lite-array-draft={isDraft ? '' : undefined}
48
+ >
49
+ <input type="hidden" name={fieldName('_present')} value="1" />
50
+ <div class="lite-array-item-header">
51
+ <span class="lite-array-item-number">#{typeof index === 'number' ? index + 1 : ''}</span>
52
+ {#if !isDraft}
53
+ <button
54
+ type="submit"
55
+ name={fieldName('_delete')}
56
+ value="1"
57
+ formnovalidate
58
+ class="lite-btn lite-btn-sm lite-array-remove-nojs"
59
+ >
60
+ Remove item
61
+ </button>
62
+ {/if}
63
+ <button type="button" class="lite-btn lite-btn-sm lite-array-remove" data-lite-array-remove hidden>
64
+ Remove
65
+ </button>
66
+ </div>
67
+
68
+ {#each subFields as sub (sub.key)}
69
+ <div class="lite-array-subfield">
70
+ <label for={fieldId(sub.key)}>
71
+ {sub.label}
72
+ {#if sub.required}<span class="required">*</span>{/if}
73
+ </label>
74
+ {#if sub.type === 'textarea' || sub.type === 'richtext'}
75
+ <textarea
76
+ id={fieldId(sub.key)}
77
+ name={fieldName(sub.key)}
78
+ class="lite-input"
79
+ rows="3"
80
+ required={sub.required && !isDraft}
81
+ placeholder={fieldToPlaceholder(sub)}
82
+ >{displayValue(item[sub.key])}</textarea>
83
+ {:else if sub.type === 'boolean'}
84
+ <div class="lite-checkbox-group">
85
+ <input
86
+ id={fieldId(sub.key)}
87
+ name={fieldName(sub.key)}
88
+ type="checkbox"
89
+ value="1"
90
+ checked={Boolean(item[sub.key])}
91
+ />
92
+ <label for={fieldId(sub.key)}>{sub.label}</label>
93
+ </div>
94
+ {:else if (sub.type === 'select' || sub.type === 'multiselect') && sub.options}
95
+ <select
96
+ id={fieldId(sub.key)}
97
+ name={fieldName(sub.key)}
98
+ class="lite-select"
99
+ required={sub.required && !isDraft}
100
+ multiple={sub.type === 'multiselect'}
101
+ >
102
+ {#if sub.type !== 'multiselect'}
103
+ <option value="">-- Select --</option>
104
+ {/if}
105
+ {#each sub.options as opt (opt.value)}
106
+ {@const selectedValue = item[sub.key]}
107
+ <option
108
+ value={String(opt.value)}
109
+ selected={sub.type === 'multiselect'
110
+ ? Array.isArray(selectedValue) && selectedValue.map(String).includes(String(opt.value))
111
+ : String(selectedValue ?? '') === String(opt.value)}
112
+ >
113
+ {opt.label}
114
+ </option>
115
+ {/each}
116
+ </select>
117
+ {:else if sub.type === 'file' || sub.type === 'image' || sub.type === 'images'}
118
+ {#if mode === 'edit'}
119
+ {#each retainedUploadReferences(item[sub.key]) as reference, referenceIndex (`${reference}:${referenceIndex}`)}
120
+ <input type="hidden" name={fieldName(sub.key)} value={reference} />
121
+ {/each}
122
+ {/if}
123
+ <input
124
+ id={fieldId(sub.key)}
125
+ name={fieldName(sub.key)}
126
+ type="file"
127
+ class="lite-input"
128
+ required={sub.required
129
+ && !isDraft
130
+ && (mode === 'create' || retainedUploadReferences(item[sub.key]).length === 0)}
131
+ multiple={sub.type === 'images'}
132
+ />
133
+ {:else}
134
+ <input
135
+ id={fieldId(sub.key)}
136
+ name={fieldName(sub.key)}
137
+ type={fieldToInputType(sub)}
138
+ value={displayValue(item[sub.key])}
139
+ class="lite-input"
140
+ required={sub.required && !isDraft}
141
+ placeholder={fieldToPlaceholder(sub)}
142
+ />
143
+ {/if}
144
+ </div>
145
+ {/each}
146
+ </div>
@@ -0,0 +1,13 @@
1
+ import type { FieldDefinition } from '@svadmin/core';
2
+ interface Props {
3
+ subFields: FieldDefinition[];
4
+ item: Record<string, unknown>;
5
+ namePrefix: string;
6
+ index: number | string;
7
+ /** Empty optional-array placeholder that remains server-submittable without JS. */
8
+ isDraft?: boolean;
9
+ mode?: 'create' | 'edit';
10
+ }
11
+ declare const LiteArrayItem: import("svelte").Component<Props, {}, "">;
12
+ type LiteArrayItem = ReturnType<typeof LiteArrayItem>;
13
+ export default LiteArrayItem;
@@ -0,0 +1,104 @@
1
+ <script lang="ts">
2
+ /**
3
+ * LiteAuditLog — SSR-compatible audit log viewer.
4
+ * Pure HTML table with pagination links. No client-side JS required.
5
+ */
6
+
7
+ interface AuditEntry {
8
+ id: string | number;
9
+ userName?: string;
10
+ action: string;
11
+ resource?: string;
12
+ createdAt: string;
13
+ ipAddress?: string;
14
+ details?: string;
15
+ }
16
+
17
+ interface Props {
18
+ logs: AuditEntry[];
19
+ total?: number;
20
+ page?: number;
21
+ pageSize?: number;
22
+ basePath?: string;
23
+ }
24
+
25
+ let {
26
+ logs,
27
+ total = 0,
28
+ page = 1,
29
+ pageSize = 20,
30
+ basePath = '?',
31
+ }: Props = $props();
32
+
33
+ const totalPages = $derived(Math.ceil(total / pageSize) || 1);
34
+
35
+ function formatDate(d: string) {
36
+ return new Date(d).toLocaleString();
37
+ }
38
+
39
+ function actionClass(action: string): string {
40
+ const a = action.toLowerCase();
41
+ if (a.includes('delete') || a.includes('remove')) return 'lite-badge-danger';
42
+ if (a.includes('create') || a.includes('add')) return 'lite-badge-success';
43
+ if (a.includes('update') || a.includes('edit')) return 'lite-badge-warning';
44
+ return 'lite-badge-default';
45
+ }
46
+ </script>
47
+
48
+ <div class="lite-audit-log">
49
+ <h2 style="margin-bottom:16px;">Audit Logs</h2>
50
+
51
+ <table class="lite-table">
52
+ <thead>
53
+ <tr>
54
+ <th style="width:160px;">Time</th>
55
+ <th>User</th>
56
+ <th>Action</th>
57
+ <th>Resource</th>
58
+ <th style="width:120px;">IP Address</th>
59
+ </tr>
60
+ </thead>
61
+ <tbody>
62
+ {#each logs as log, _i (_i)}
63
+ <tr>
64
+ <td style="font-family:monospace;font-size:12px;color:#64748b;">{formatDate(log.createdAt)}</td>
65
+ <td>{log.userName ?? '—'}</td>
66
+ <td><span class="lite-badge {actionClass(log.action)}">{log.action}</span></td>
67
+ <td style="color:#64748b;">{log.resource ?? '—'}</td>
68
+ <td style="font-family:monospace;font-size:12px;color:#64748b;">{log.ipAddress ?? '—'}</td>
69
+ </tr>
70
+ {:else}
71
+ <tr>
72
+ <td colspan="5" style="text-align:center;padding:24px;color:#94a3b8;">No audit logs found.</td>
73
+ </tr>
74
+ {/each}
75
+ </tbody>
76
+ </table>
77
+
78
+ <!-- Pagination -->
79
+ {#if totalPages > 1}
80
+ <div class="lite-pagination" style="margin-top:12px;">
81
+ {#if page > 1}
82
+ <a href={`${basePath}page={page - 1}`} class="lite-btn lite-btn-sm">&laquo; Prev</a>
83
+ {/if}
84
+ <span style="padding:0 12px;font-size:14px;color:#64748b;">Page {page} / {totalPages} ({total} total)</span>
85
+ {#if page < totalPages}
86
+ <a href={`${basePath}page={page + 1}`} class="lite-btn lite-btn-sm">Next &raquo;</a>
87
+ {/if}
88
+ </div>
89
+ {/if}
90
+ </div>
91
+
92
+ <style>
93
+ .lite-badge {
94
+ display: inline-block;
95
+ padding: 2px 8px;
96
+ border-radius: 4px;
97
+ font-size: 12px;
98
+ font-weight: 600;
99
+ }
100
+ .lite-badge-danger { background: #fef2f2; color: #dc2626; border: 1px solid #fecaca; }
101
+ .lite-badge-success { background: #f0fdf4; color: #166534; border: 1px solid #bbf7d0; }
102
+ .lite-badge-warning { background: #fffbeb; color: #92400e; border: 1px solid #fde68a; }
103
+ .lite-badge-default { background: #f1f5f9; color: #475569; border: 1px solid #e2e8f0; }
104
+ </style>
@@ -0,0 +1,23 @@
1
+ /**
2
+ * LiteAuditLog — SSR-compatible audit log viewer.
3
+ * Pure HTML table with pagination links. No client-side JS required.
4
+ */
5
+ interface AuditEntry {
6
+ id: string | number;
7
+ userName?: string;
8
+ action: string;
9
+ resource?: string;
10
+ createdAt: string;
11
+ ipAddress?: string;
12
+ details?: string;
13
+ }
14
+ interface Props {
15
+ logs: AuditEntry[];
16
+ total?: number;
17
+ page?: number;
18
+ pageSize?: number;
19
+ basePath?: string;
20
+ }
21
+ declare const LiteAuditLog: import("svelte").Component<Props, {}, "">;
22
+ type LiteAuditLog = ReturnType<typeof LiteAuditLog>;
23
+ export default LiteAuditLog;
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ /**
3
+ * LiteBreadcrumbs — SSR-compatible breadcrumb navigation.
4
+ * Pure HTML <nav> with <a> links. No client-side JS required.
5
+ */
6
+
7
+ interface BreadcrumbItem {
8
+ label: string;
9
+ href?: string;
10
+ }
11
+
12
+ interface Props {
13
+ items: BreadcrumbItem[];
14
+ /** Separator character between items */
15
+ separator?: string;
16
+ }
17
+
18
+ let {
19
+ items,
20
+ separator = '/',
21
+ }: Props = $props();
22
+ </script>
23
+
24
+ <nav class="lite-breadcrumbs" aria-label="Breadcrumb">
25
+ <ol>
26
+ {#each items as item, i (i)}
27
+ <li>
28
+ {#if item.href && i < items.length - 1}
29
+ <a href={item.href}>{item.label}</a>
30
+ {:else}
31
+ <span class="current">{item.label}</span>
32
+ {/if}
33
+ {#if i < items.length - 1}
34
+ <span class="lite-breadcrumb-sep" aria-hidden="true">{separator}</span>
35
+ {/if}
36
+ </li>
37
+ {/each}
38
+ </ol>
39
+ </nav>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * LiteBreadcrumbs — SSR-compatible breadcrumb navigation.
3
+ * Pure HTML <nav> with <a> links. No client-side JS required.
4
+ */
5
+ interface BreadcrumbItem {
6
+ label: string;
7
+ href?: string;
8
+ }
9
+ interface Props {
10
+ items: BreadcrumbItem[];
11
+ /** Separator character between items */
12
+ separator?: string;
13
+ }
14
+ declare const LiteBreadcrumbs: import("svelte").Component<Props, {}, "">;
15
+ type LiteBreadcrumbs = ReturnType<typeof LiteBreadcrumbs>;
16
+ export default LiteBreadcrumbs;
@@ -0,0 +1,101 @@
1
+ <script lang="ts">
2
+ /**
3
+ * LiteChatDialog — SSR-compatible AI Chat Dialog fallback.
4
+ * Relies on standard <form> POST without polling or WebSockets.
5
+ * No client-side JS required.
6
+ */
7
+ import type { ChatMessage } from '@svadmin/core';
8
+
9
+ interface Props {
10
+ /** History of messages */
11
+ messages: ChatMessage[];
12
+ /** URL to handle the POST request for new messages */
13
+ actionRoute: string;
14
+ /** If true, shows a "Thinking..." indicator */
15
+ isLoading?: boolean;
16
+ title?: string;
17
+ placeholder?: string;
18
+ submitLabel?: string;
19
+ }
20
+
21
+ let {
22
+ messages = [],
23
+ actionRoute,
24
+ isLoading = false,
25
+ title = 'AI Assistant',
26
+ placeholder = 'Type your message...',
27
+ submitLabel = 'Send'
28
+ }: Props = $props();
29
+
30
+ function formatDate(ts: number) {
31
+ if (!ts) return '';
32
+ return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
33
+ }
34
+
35
+ // Auto-scroll anchor logic: pure HTML way to scroll to bottom after page load
36
+ // User should include "#latest-msg" in the form action if possible
37
+ </script>
38
+
39
+ <div class="lite-chat-dialog lite-card" style="display:flex;flex-direction:column;height:560px;padding:0;overflow:hidden;max-width:400px;margin:0 auto;">
40
+ <!-- Header -->
41
+ <div style="background:#0f172a;color:#fff;padding:14px 16px;font-weight:600;flex-shrink:0;display:flex;align-items:center;border-top-left-radius:8px;border-top-right-radius:8px;">
42
+ {title}
43
+ </div>
44
+
45
+ <!-- Message History -->
46
+ <div class="lite-chat-history" style="flex:1;overflow-y:auto;padding:16px;background:#f8fafc;">
47
+ {#if messages.length === 0}
48
+ <div style="text-align:center;color:#64748b;margin-top:60px;font-size:14px;">
49
+ How can I help you today?
50
+ </div>
51
+ {/if}
52
+
53
+ {#each messages as msg, i (i)}
54
+ {#if msg.role === 'user' || msg.role === 'assistant'}
55
+ <div
56
+ id={i === messages.length - 1 ? 'latest-msg' : ''}
57
+ style="margin-bottom:16px;display:flex;flex-direction:column;align-items:{msg.role === 'user' ? 'flex-end' : 'flex-start'};"
58
+ >
59
+ <div style="
60
+ max-width:85%;
61
+ padding:10px 14px;
62
+ border-radius:12px;
63
+ font-size:14px;
64
+ line-height:1.5;
65
+ {msg.role === 'user'
66
+ ? 'background:#4f46e5;color:#fff;border-bottom-right-radius:2px;'
67
+ : 'background:#e2e8f0;color:#0f172a;border-bottom-left-radius:2px;'}"
68
+ >
69
+ <div style="white-space:pre-wrap;word-break:break-word;">{msg.content}</div>
70
+ </div>
71
+ <div style="font-size:11px;color:#94a3b8;margin-top:4px;">
72
+ {msg.role === 'user' ? 'You' : 'Assistant'} • {formatDate(msg.timestamp)}
73
+ </div>
74
+ </div>
75
+ {/if}
76
+ {/each}
77
+
78
+ {#if isLoading}
79
+ <div id="latest-msg" style="display:flex;flex-direction:column;align-items:flex-start;margin-bottom:16px;">
80
+ <div style="background:#e2e8f0;color:#64748b;padding:10px 14px;border-radius:12px;border-bottom-left-radius:2px;font-size:13px;font-style:italic;">
81
+ Thinking...
82
+ </div>
83
+ </div>
84
+ {/if}
85
+ </div>
86
+
87
+ <!-- Input Form -->
88
+ <form method="POST" action={actionRoute} style="display:flex;padding:12px;background:#fff;border-top:1px solid #e2e8f0;align-items:stretch;margin:0;flex-shrink:0;">
89
+ <textarea
90
+ name="message"
91
+ class="lite-input"
92
+ placeholder={placeholder}
93
+ required
94
+ rows="1"
95
+ style="min-height:40px;resize:none;margin-right:8px;"
96
+ ></textarea>
97
+ <button type="submit" class="lite-btn lite-btn-primary" disabled={isLoading} style="display:flex;align-items:center;padding:0 16px;">
98
+ {submitLabel}
99
+ </button>
100
+ </form>
101
+ </div>
@@ -0,0 +1,20 @@
1
+ /**
2
+ * LiteChatDialog — SSR-compatible AI Chat Dialog fallback.
3
+ * Relies on standard <form> POST without polling or WebSockets.
4
+ * No client-side JS required.
5
+ */
6
+ import type { ChatMessage } from '@svadmin/core';
7
+ interface Props {
8
+ /** History of messages */
9
+ messages: ChatMessage[];
10
+ /** URL to handle the POST request for new messages */
11
+ actionRoute: string;
12
+ /** If true, shows a "Thinking..." indicator */
13
+ isLoading?: boolean;
14
+ title?: string;
15
+ placeholder?: string;
16
+ submitLabel?: string;
17
+ }
18
+ declare const LiteChatDialog: import("svelte").Component<Props, {}, "">;
19
+ type LiteChatDialog = ReturnType<typeof LiteChatDialog>;
20
+ export default LiteChatDialog;