@svadmin/lite 0.3.4 → 0.3.6

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 (76) hide show
  1. package/package.json +9 -6
  2. package/src/server-adapter.ts +1 -1
  3. package/src/components/LiteAlert.svelte +0 -19
  4. package/src/components/LiteArrayField.svelte +0 -113
  5. package/src/components/LiteAuditLog.svelte +0 -104
  6. package/src/components/LiteBreadcrumbs.svelte +0 -39
  7. package/src/components/LiteChatDialog.svelte +0 -101
  8. package/src/components/LiteConfirmDialog.svelte +0 -60
  9. package/src/components/LiteEmptyState.svelte +0 -39
  10. package/src/components/LiteForm.svelte +0 -138
  11. package/src/components/LiteLayout.svelte +0 -106
  12. package/src/components/LiteLogin.svelte +0 -41
  13. package/src/components/LitePagination.svelte +0 -73
  14. package/src/components/LitePermissionMatrix.svelte +0 -147
  15. package/src/components/LiteSearch.svelte +0 -41
  16. package/src/components/LiteShow.svelte +0 -61
  17. package/src/components/LiteShowField.svelte +0 -51
  18. package/src/components/LiteStatsCard.svelte +0 -70
  19. package/src/components/LiteTable.svelte +0 -132
  20. package/src/components/LiteTabs.svelte +0 -57
  21. package/src/components/advanced/LiteAutoSaveIndicator.svelte +0 -26
  22. package/src/components/advanced/LiteDraggableHeader.svelte +0 -33
  23. package/src/components/advanced/LiteDrawerForm.svelte +0 -42
  24. package/src/components/advanced/LiteInlineEdit.svelte +0 -32
  25. package/src/components/advanced/LiteModalForm.svelte +0 -44
  26. package/src/components/advanced/LiteToast.svelte +0 -34
  27. package/src/components/advanced/LiteUndoableNotification.svelte +0 -25
  28. package/src/components/advanced/LiteVirtualTable.svelte +0 -44
  29. package/src/components/buttons/LiteCloneButton.svelte +0 -33
  30. package/src/components/buttons/LiteCreateButton.svelte +0 -31
  31. package/src/components/buttons/LiteDeleteButton.svelte +0 -57
  32. package/src/components/buttons/LiteEditButton.svelte +0 -33
  33. package/src/components/buttons/LiteExportButton.svelte +0 -31
  34. package/src/components/buttons/LiteImportButton.svelte +0 -50
  35. package/src/components/buttons/LiteListButton.svelte +0 -31
  36. package/src/components/buttons/LiteRefreshButton.svelte +0 -27
  37. package/src/components/buttons/LiteSaveButton.svelte +0 -27
  38. package/src/components/buttons/LiteShowButton.svelte +0 -33
  39. package/src/components/fields/LiteBooleanField.svelte +0 -41
  40. package/src/components/fields/LiteDateField.svelte +0 -51
  41. package/src/components/fields/LiteEmailField.svelte +0 -40
  42. package/src/components/fields/LiteFileField.svelte +0 -53
  43. package/src/components/fields/LiteImageField.svelte +0 -57
  44. package/src/components/fields/LiteJsonField.svelte +0 -43
  45. package/src/components/fields/LiteMarkdownField.svelte +0 -33
  46. package/src/components/fields/LiteMultiSelectField.svelte +0 -57
  47. package/src/components/fields/LiteNumberField.svelte +0 -34
  48. package/src/components/fields/LiteRelationField.svelte +0 -66
  49. package/src/components/fields/LiteRichTextField.svelte +0 -45
  50. package/src/components/fields/LiteSelectField.svelte +0 -47
  51. package/src/components/fields/LiteTagField.svelte +0 -44
  52. package/src/components/fields/LiteTextField.svelte +0 -34
  53. package/src/components/fields/LiteUrlField.svelte +0 -40
  54. package/src/components/layout/LiteAuthenticated.svelte +0 -23
  55. package/src/components/layout/LiteCanAccess.svelte +0 -27
  56. package/src/components/layout/LiteCatchAllNavigate.svelte +0 -20
  57. package/src/components/layout/LiteErrorBoundary.svelte +0 -20
  58. package/src/components/layout/LiteErrorComponent.svelte +0 -37
  59. package/src/components/layout/LiteHeader.svelte +0 -19
  60. package/src/components/layout/LiteNavigateToResource.svelte +0 -25
  61. package/src/components/layout/LiteSidebar.svelte +0 -93
  62. package/src/components/pages/LiteCreatePage.svelte +0 -39
  63. package/src/components/pages/LiteEditPage.svelte +0 -54
  64. package/src/components/pages/LiteForgotPasswordPage.svelte +0 -60
  65. package/src/components/pages/LiteListPage.svelte +0 -81
  66. package/src/components/pages/LiteProfilePage.svelte +0 -61
  67. package/src/components/pages/LiteRegisterPage.svelte +0 -64
  68. package/src/components/pages/LiteShowPage.svelte +0 -61
  69. package/src/components/pages/LiteUpdatePasswordPage.svelte +0 -51
  70. package/src/components/widgets/LiteAnomalyBadge.svelte +0 -40
  71. package/src/components/widgets/LiteBarChart.svelte +0 -45
  72. package/src/components/widgets/LiteInsightCard.svelte +0 -28
  73. package/src/components/widgets/LiteLineChart.svelte +0 -48
  74. package/src/components/widgets/LitePieChart.svelte +0 -44
  75. package/src/lite.css +0 -708
  76. package/static/enhance.js +0 -56
@@ -1,50 +0,0 @@
1
- <script lang="ts">
2
- import { t } from '@svadmin/core/i18n';
3
- import { Upload } from '@lucide/svelte';
4
-
5
- interface Props {
6
- resource: string;
7
- basePath?: string;
8
- hideText?: boolean;
9
- class?: string;
10
- size?: 'sm' | 'default' | 'icon';
11
- }
12
-
13
- let {
14
- resource,
15
- basePath = '/lite',
16
- hideText = false,
17
- class: className = '',
18
- size = 'default'
19
- }: Props = $props();
20
- </script>
21
-
22
- <details class="lite-confirm-details {className}">
23
- <summary
24
- class="lite-btn {size === 'sm' ? 'lite-btn-sm' : ''}"
25
- title={t('common.import') || 'Import'}
26
- >
27
- <Upload class="h-4 w-4" />
28
- {#if !hideText}
29
- <span style="marginLeft: 4px">{t('common.import') || 'Import'}</span>
30
- {/if}
31
- </summary>
32
- <div class="lite-confirm-panel">
33
- <p style="margin: 0 0 8px; font-size: 13px;">{t('common.importData') || 'Import data (CSV/JSON)'}</p>
34
- <form method="POST" action="?/${resource}_import" enctype="multipart/form-data" style="display:flex; flex-direction: column; gap: 8px;">
35
- <input type="file" name="file" accept=".csv,.json" required style="font-size: 13px;" />
36
- <div style="display:flex; gap: 8px; justify-content: flex-end;">
37
- <button
38
- type="button"
39
- class="lite-btn lite-btn-sm"
40
- onclick={(e) => (e.currentTarget as HTMLElement).closest('details')?.removeAttribute('open')}
41
- >
42
- {t('common.cancel') || 'Cancel'}
43
- </button>
44
- <button type="submit" class="lite-btn lite-btn-sm lite-btn-primary">
45
- {t('common.upload') || 'Upload'}
46
- </button>
47
- </div>
48
- </form>
49
- </div>
50
- </details>
@@ -1,31 +0,0 @@
1
- <script lang="ts">
2
- import { t } from '@svadmin/core/i18n';
3
- import { List } from '@lucide/svelte';
4
-
5
- interface Props {
6
- resource: string;
7
- basePath?: string;
8
- hideText?: boolean;
9
- class?: string;
10
- size?: 'sm' | 'default' | 'icon';
11
- }
12
-
13
- let {
14
- resource,
15
- basePath = '/lite',
16
- hideText = false,
17
- class: className = '',
18
- size = 'default'
19
- }: Props = $props();
20
- </script>
21
-
22
- <a
23
- href={`${basePath}/${resource}`}
24
- class="lite-btn {size === 'sm' ? 'lite-btn-sm' : ''} {className}"
25
- title={t('common.list') || 'List'}
26
- >
27
- <List class="h-4 w-4" />
28
- {#if !hideText}
29
- <span style="marginLeft: 4px">{t('common.list') || 'List'}</span>
30
- {/if}
31
- </a>
@@ -1,27 +0,0 @@
1
- <script lang="ts">
2
- import { t } from '@svadmin/core/i18n';
3
- import { RefreshCw } from '@lucide/svelte';
4
-
5
- interface Props {
6
- hideText?: boolean;
7
- class?: string;
8
- size?: 'sm' | 'default' | 'icon';
9
- }
10
-
11
- let {
12
- hideText = false,
13
- class: className = '',
14
- size = 'default'
15
- }: Props = $props();
16
- </script>
17
-
18
- <a
19
- href=""
20
- class="lite-btn {size === 'sm' ? 'lite-btn-sm' : ''} {className}"
21
- title={t('common.refresh') || 'Refresh'}
22
- >
23
- <RefreshCw class="h-4 w-4" />
24
- {#if !hideText}
25
- <span style="marginLeft: 4px">{t('common.refresh') || 'Refresh'}</span>
26
- {/if}
27
- </a>
@@ -1,27 +0,0 @@
1
- <script lang="ts">
2
- import { t } from '@svadmin/core/i18n';
3
- import { Save } from '@lucide/svelte';
4
-
5
- interface Props {
6
- hideText?: boolean;
7
- class?: string;
8
- size?: 'sm' | 'default' | 'icon';
9
- }
10
-
11
- let {
12
- hideText = false,
13
- class: className = '',
14
- size = 'default'
15
- }: Props = $props();
16
- </script>
17
-
18
- <button
19
- type="submit"
20
- class="lite-btn lite-btn-primary {size === 'sm' ? 'lite-btn-sm' : ''} {className}"
21
- title={t('common.save') || 'Save'}
22
- >
23
- <Save class="h-4 w-4" />
24
- {#if !hideText}
25
- <span style="marginLeft: 4px">{t('common.save') || 'Save'}</span>
26
- {/if}
27
- </button>
@@ -1,33 +0,0 @@
1
- <script lang="ts">
2
- import { t } from '@svadmin/core/i18n';
3
- import { Eye } from '@lucide/svelte';
4
-
5
- interface Props {
6
- resource: string;
7
- recordItemId: string | number;
8
- basePath?: string;
9
- hideText?: boolean;
10
- class?: string;
11
- size?: 'sm' | 'default' | 'icon';
12
- }
13
-
14
- let {
15
- resource,
16
- recordItemId,
17
- basePath = '/lite',
18
- hideText = false,
19
- class: className = '',
20
- size = 'default'
21
- }: Props = $props();
22
- </script>
23
-
24
- <a
25
- href={`${basePath}/${resource}/show/${recordItemId}`}
26
- class="lite-btn {size === 'sm' ? 'lite-btn-sm' : ''} {className}"
27
- title={t('common.show') || 'Show'}
28
- >
29
- <Eye class="h-4 w-4" />
30
- {#if !hideText}
31
- <span style="marginLeft: 4px">{t('common.show') || 'Show'}</span>
32
- {/if}
33
- </a>
@@ -1,41 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
- </script>
14
-
15
- {#if mode === 'show'}
16
- <div>
17
- <span class="lite-bool {value ? 'lite-bool-true' : ''}"></span>
18
- {value ? '✓ Yes' : '✗ No'}
19
- </div>
20
- {:else}
21
- <div class="lite-checkbox-group">
22
- <input
23
- type="checkbox"
24
- name={field.key}
25
- id={field.key}
26
- checked={!!value}
27
- value="true"
28
- />
29
- <!-- Fallback hidden input so unchecked boxes submit "false" -->
30
- <input type="hidden" name={field.key} value="false" />
31
-
32
- <label for={field.key}>
33
- {(field as any).placeholder ?? (field.label || 'Yes')}
34
- </label>
35
- {#if hasError}
36
- {#each error as err}
37
- <div class="lite-error-text">{err}</div>
38
- {/each}
39
- {/if}
40
- </div>
41
- {/if}
@@ -1,51 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
-
14
- function formatDate(v: unknown): string {
15
- if (!v) return '';
16
- try {
17
- return new Date(v as string).toISOString().substring(0, 16); // Formats for html datetime-local
18
- } catch {
19
- return '';
20
- }
21
- }
22
-
23
- function displayDate(v: unknown): string {
24
- if (!v) return '—';
25
- try {
26
- return new Date(v as string).toLocaleString();
27
- } catch {
28
- return String(v);
29
- }
30
- }
31
- </script>
32
-
33
- {#if mode === 'show'}
34
- <span>{displayDate(value)}</span>
35
- {:else}
36
- <div>
37
- <input
38
- type="datetime-local"
39
- name={field.key}
40
- id={field.key}
41
- value={formatDate(value)}
42
- class="lite-input {hasError ? 'lite-input-error' : ''}"
43
- {...field.required ? { required: true } : {}}
44
- />
45
- {#if hasError}
46
- {#each error as err}
47
- <div class="lite-error-text">{err}</div>
48
- {/each}
49
- {/if}
50
- </div>
51
- {/if}
@@ -1,40 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
- </script>
14
-
15
- {#if mode === 'show'}
16
- <span>
17
- {#if value}
18
- <a href="mailto:{value}">{value}</a>
19
- {:else}
20
-
21
- {/if}
22
- </span>
23
- {:else}
24
- <div>
25
- <input
26
- type="email"
27
- name={field.key}
28
- id={field.key}
29
- value={String(value ?? '')}
30
- class="lite-input {hasError ? 'lite-input-error' : ''}"
31
- placeholder={(field as any).placeholder ?? field.label}
32
- {...field.required ? { required: true } : {}}
33
- />
34
- {#if hasError}
35
- {#each error as err}
36
- <div class="lite-error-text">{err}</div>
37
- {/each}
38
- {/if}
39
- </div>
40
- {/if}
@@ -1,53 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
-
14
- function getFiles(v: unknown): string[] {
15
- if (!v) return [];
16
- if (Array.isArray(v)) return v.map(String);
17
- if (typeof v === 'string') return [v];
18
- return [];
19
- }
20
- </script>
21
-
22
- {#if mode === 'show'}
23
- {@const files = getFiles(value)}
24
- <div style="display:flex; flex-direction: column; gap: 4px;">
25
- {#each files as f}
26
- <a href={f} target="_blank" rel="noopener noreferrer">{f.split('/').pop() || 'Download'}</a>
27
- {:else}
28
- <span>—</span>
29
- {/each}
30
- </div>
31
- {:else}
32
- {@const files = getFiles(value)}
33
- <div>
34
- {#if files.length > 0 && mode === 'edit'}
35
- <div style="margin-bottom: 8px;">
36
- <span style="font-size: 12px;">Current files: {files.length}</span>
37
- </div>
38
- {/if}
39
- <input
40
- type="file"
41
- name={field.key}
42
- id={field.key}
43
- class="lite-input {hasError ? 'lite-input-error' : ''}"
44
- {...(field.type as string) === 'files' ? { multiple: true } : {}}
45
- {...field.required && !files.length ? { required: true } : {}}
46
- />
47
- {#if hasError}
48
- {#each error as err}
49
- <div class="lite-error-text">{err}</div>
50
- {/each}
51
- {/if}
52
- </div>
53
- {/if}
@@ -1,57 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
-
14
- function getUrls(v: unknown): string[] {
15
- if (!v) return [];
16
- if (Array.isArray(v)) return v.map(String);
17
- if (typeof v === 'string') return [v];
18
- return [];
19
- }
20
- </script>
21
-
22
- {#if mode === 'show'}
23
- {@const urls = getUrls(value)}
24
- <div style="display:flex; gap: 8px; flex-wrap: wrap;">
25
- {#each urls as url}
26
- <img src={url} alt={field.label} style="max-height: 100px; border-radius: 4px; border: 1px solid #e5e7eb;" />
27
- {:else}
28
- <span>—</span>
29
- {/each}
30
- </div>
31
- {:else}
32
- {@const urls = getUrls(value)}
33
- <div>
34
- {#if urls.length > 0 && mode === 'edit'}
35
- <div style="margin-bottom: 8px; display:flex; gap: 8px;">
36
- {#each urls as url}
37
- <img src={url} alt="Current" style="height: 60px; border-radius: 4px; border: 1px solid #e5e7eb; opacity: 0.6;" />
38
- {/each}
39
- </div>
40
- <p style="font-size: 11px; color:#6b7280; margin: 0 0 4px;">Uploading new ones will overwrite.</p>
41
- {/if}
42
- <input
43
- type="file"
44
- name={field.key}
45
- id={field.key}
46
- accept="image/*"
47
- class="lite-input {hasError ? 'lite-input-error' : ''}"
48
- {...(field.type as string) === 'images' ? { multiple: true } : {}}
49
- {...field.required && !urls.length ? { required: true } : {}}
50
- />
51
- {#if hasError}
52
- {#each error as err}
53
- <div class="lite-error-text">{err}</div>
54
- {/each}
55
- {/if}
56
- </div>
57
- {/if}
@@ -1,43 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
-
14
- function getJsonString(v: unknown): string {
15
- if (v == null) return '';
16
- if (typeof v === 'string') return v;
17
- try {
18
- return JSON.stringify(v, null, 2);
19
- } catch {
20
- return String(v);
21
- }
22
- }
23
- </script>
24
-
25
- {#if mode === 'show'}
26
- <pre style="padding: 12px; background: #1e293b; color: #f8fafc; border-radius: 4px; overflow-x: auto; font-size: 13px;">{getJsonString(value)}</pre>
27
- {:else}
28
- <div>
29
- <textarea
30
- name={field.key}
31
- id={field.key}
32
- class="lite-input {hasError ? 'lite-input-error' : ''}"
33
- style="min-height: 150px; font-family: monospace;"
34
- placeholder="&lbrace;&rbrace;"
35
- {...field.required ? { required: true } : {}}
36
- >{getJsonString(value)}</textarea>
37
- {#if hasError}
38
- {#each error as err}
39
- <div class="lite-error-text">{err}</div>
40
- {/each}
41
- {/if}
42
- </div>
43
- {/if}
@@ -1,33 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
- </script>
14
-
15
- {#if mode === 'show'}
16
- <pre style="white-space: pre-wrap; padding: 12px; background: #f8fafc; border: 1px solid #e5e7eb; border-radius: 4px;">{String(value ?? '—')}</pre>
17
- {:else}
18
- <div>
19
- <textarea
20
- name={field.key}
21
- id={field.key}
22
- class="lite-input {hasError ? 'lite-input-error' : ''}"
23
- style="min-height: 200px; font-family: monospace;"
24
- placeholder="Enter markdown..."
25
- {...field.required ? { required: true } : {}}
26
- >{String(value ?? '')}</textarea>
27
- {#if hasError}
28
- {#each error as err}
29
- <div class="lite-error-text">{err}</div>
30
- {/each}
31
- {/if}
32
- </div>
33
- {/if}
@@ -1,57 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
-
14
- function displayOptions(valuesRaw: unknown): string[] {
15
- if (!valuesRaw || !Array.isArray(valuesRaw)) return [];
16
- return valuesRaw.map(v => {
17
- const opt = field.options?.find(o => String(o.value) === String(v));
18
- return opt?.label ?? String(v);
19
- });
20
- }
21
-
22
- const valuesArray = $derived(Array.isArray(value) ? value.map(String) : []);
23
- </script>
24
-
25
- {#if mode === 'show'}
26
- <div style="display:flex; gap: 4px; flex-wrap: wrap;">
27
- {#each displayOptions(value) as opt}
28
- <span class="lite-badge">{opt}</span>
29
- {:else}
30
- <span>—</span>
31
- {/each}
32
- </div>
33
- {:else}
34
- <div>
35
- <select
36
- name={field.key}
37
- id={field.key}
38
- multiple
39
- class="lite-select {hasError ? 'lite-input-error' : ''}"
40
- style="height: 120px;"
41
- {...field.required ? { required: true } : {}}
42
- >
43
- {#if field.options}
44
- {#each field.options as opt}
45
- <option value={String(opt.value)} selected={valuesArray.includes(String(opt.value))}>
46
- {opt.label}
47
- </option>
48
- {/each}
49
- {/if}
50
- </select>
51
- {#if hasError}
52
- {#each error as err}
53
- <div class="lite-error-text">{err}</div>
54
- {/each}
55
- {/if}
56
- </div>
57
- {/if}
@@ -1,34 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
-
4
- interface Props {
5
- field: FieldDefinition;
6
- value?: unknown;
7
- error?: string[];
8
- mode?: 'show' | 'edit' | 'create';
9
- }
10
-
11
- let { field, value, error = [], mode = 'show' }: Props = $props();
12
- let hasError = $derived(error.length > 0);
13
- </script>
14
-
15
- {#if mode === 'show'}
16
- <span>{value == null ? '—' : Number(value).toLocaleString()}</span>
17
- {:else}
18
- <div>
19
- <input
20
- type="number"
21
- name={field.key}
22
- id={field.key}
23
- value={value == null ? '' : Number(value)}
24
- class="lite-input {hasError ? 'lite-input-error' : ''}"
25
- placeholder={(field as any).placeholder ?? field.label}
26
- {...field.required ? { required: true } : {}}
27
- />
28
- {#if hasError}
29
- {#each error as err}
30
- <div class="lite-error-text">{err}</div>
31
- {/each}
32
- {/if}
33
- </div>
34
- {/if}
@@ -1,66 +0,0 @@
1
- <script lang="ts">
2
- import type { FieldDefinition } from '@svadmin/core';
3
- import { t } from '@svadmin/core/i18n';
4
-
5
- interface Props {
6
- field: FieldDefinition;
7
- value?: unknown;
8
- error?: string[];
9
- mode?: 'show' | 'edit' | 'create';
10
- }
11
-
12
- let { field, value, error = [], mode = 'show' }: Props = $props();
13
- let hasError = $derived(error.length > 0);
14
-
15
- // In Lite version, relations might need to be rendered via server-side joined data
16
- // passed through options, or just standard inputs requesting ID.
17
- function displayRelation(v: unknown): string {
18
- if (v == null) return '—';
19
- if (typeof v === 'object' && v !== null && 'id' in v) {
20
- // It's a populated relation object
21
- const labelField = (field as any).relation?.labelField || 'name';
22
- return String((v as Record<string, unknown>)[labelField] || (v as Record<string, unknown>).id);
23
- }
24
- // Try options
25
- const opt = field.options?.find(o => String(o.value) === String(v));
26
- return opt?.label ?? String(v);
27
- }
28
- </script>
29
-
30
- {#if mode === 'show'}
31
- <span class="lite-badge">{displayRelation(value)}</span>
32
- {:else}
33
- <div>
34
- {#if field.options && field.options.length > 0}
35
- <!-- Render as select if options provided by loader -->
36
- <select
37
- name={field.key}
38
- id={field.key}
39
- class="lite-select {hasError ? 'lite-input-error' : ''}"
40
- >
41
- <option value="">-- {t('common.select') || 'Select'} Reference --</option>
42
- {#each field.options as opt}
43
- <option value={String(opt.value)} selected={String(value) === String(opt.value)}>
44
- {opt.label}
45
- </option>
46
- {/each}
47
- </select>
48
- {:else}
49
- <!-- Fallback text input for target ID -->
50
- <input
51
- type="text"
52
- name={field.key}
53
- id={field.key}
54
- value={typeof value === 'object' && value ? String((value as Record<string, unknown>).id || '') : String(value ?? '')}
55
- class="lite-input {hasError ? 'lite-input-error' : ''}"
56
- placeholder="Enter reference ID"
57
- {...field.required ? { required: true } : {}}
58
- />
59
- {/if}
60
- {#if hasError}
61
- {#each error as err}
62
- <div class="lite-error-text">{err}</div>
63
- {/each}
64
- {/if}
65
- </div>
66
- {/if}