@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.
- package/README.md +19 -13
- package/dist/components/LiteAlert.svelte +19 -0
- package/dist/components/LiteAlert.svelte.d.ts +11 -0
- package/dist/components/LiteArrayField.svelte +60 -0
- package/dist/components/LiteArrayField.svelte.d.ts +17 -0
- package/dist/components/LiteArrayItem.svelte +146 -0
- package/dist/components/LiteArrayItem.svelte.d.ts +13 -0
- package/dist/components/LiteAuditLog.svelte +104 -0
- package/dist/components/LiteAuditLog.svelte.d.ts +23 -0
- package/dist/components/LiteBreadcrumbs.svelte +39 -0
- package/dist/components/LiteBreadcrumbs.svelte.d.ts +16 -0
- package/dist/components/LiteChatDialog.svelte +101 -0
- package/dist/components/LiteChatDialog.svelte.d.ts +20 -0
- package/dist/components/LiteConfirmDialog.svelte +60 -0
- package/dist/components/LiteConfirmDialog.svelte.d.ts +22 -0
- package/dist/components/LiteEmptyState.svelte +39 -0
- package/dist/components/LiteEmptyState.svelte.d.ts +16 -0
- package/dist/components/LiteForm.svelte +165 -0
- package/dist/components/LiteForm.svelte.d.ts +26 -0
- package/dist/components/LiteLayout.svelte +147 -0
- package/dist/components/LiteLayout.svelte.d.ts +19 -0
- package/dist/components/LiteLogin.svelte +41 -0
- package/dist/components/LiteLogin.svelte.d.ts +8 -0
- package/dist/components/LitePagination.svelte +73 -0
- package/dist/components/LitePagination.svelte.d.ts +11 -0
- package/dist/components/LitePermissionMatrix.svelte +147 -0
- package/dist/components/LitePermissionMatrix.svelte.d.ts +32 -0
- package/dist/components/LiteSearch.svelte +41 -0
- package/dist/components/LiteSearch.svelte.d.ts +9 -0
- package/dist/components/LiteShow.svelte +61 -0
- package/dist/components/LiteShow.svelte.d.ts +14 -0
- package/dist/components/LiteShowField.svelte +62 -0
- package/dist/components/LiteShowField.svelte.d.ts +12 -0
- package/dist/components/LiteStatsCard.svelte +70 -0
- package/dist/components/LiteStatsCard.svelte.d.ts +24 -0
- package/dist/components/LiteTable.svelte +132 -0
- package/dist/components/LiteTable.svelte.d.ts +19 -0
- package/dist/components/LiteTabs.svelte +57 -0
- package/dist/components/LiteTabs.svelte.d.ts +16 -0
- package/dist/components/advanced/LiteAutoSaveIndicator.svelte +26 -0
- package/dist/components/advanced/LiteAutoSaveIndicator.svelte.d.ts +12 -0
- package/dist/components/advanced/LiteDraggableHeader.svelte +33 -0
- package/dist/components/advanced/LiteDraggableHeader.svelte.d.ts +15 -0
- package/dist/components/advanced/LiteDrawerForm.svelte +42 -0
- package/dist/components/advanced/LiteDrawerForm.svelte.d.ts +16 -0
- package/dist/components/advanced/LiteInlineEdit.svelte +32 -0
- package/dist/components/advanced/LiteInlineEdit.svelte.d.ts +15 -0
- package/dist/components/advanced/LiteModalForm.svelte +44 -0
- package/dist/components/advanced/LiteModalForm.svelte.d.ts +17 -0
- package/dist/components/advanced/LiteToast.svelte +34 -0
- package/dist/components/advanced/LiteToast.svelte.d.ts +14 -0
- package/dist/components/advanced/LiteUndoableNotification.svelte +25 -0
- package/dist/components/advanced/LiteUndoableNotification.svelte.d.ts +13 -0
- package/dist/components/advanced/LiteVirtualTable.svelte +44 -0
- package/dist/components/advanced/LiteVirtualTable.svelte.d.ts +20 -0
- package/dist/components/advanced/index.js +8 -0
- package/dist/components/buttons/LiteCloneButton.svelte +33 -0
- package/dist/components/buttons/LiteCloneButton.svelte.d.ts +11 -0
- package/dist/components/buttons/LiteCreateButton.svelte +31 -0
- package/dist/components/buttons/LiteCreateButton.svelte.d.ts +10 -0
- package/dist/components/buttons/LiteDeleteButton.svelte +57 -0
- package/dist/components/buttons/LiteDeleteButton.svelte.d.ts +12 -0
- package/dist/components/buttons/LiteEditButton.svelte +33 -0
- package/dist/components/buttons/LiteEditButton.svelte.d.ts +11 -0
- package/dist/components/buttons/LiteExportButton.svelte +31 -0
- package/dist/components/buttons/LiteExportButton.svelte.d.ts +10 -0
- package/dist/components/buttons/LiteImportButton.svelte +50 -0
- package/dist/components/buttons/LiteImportButton.svelte.d.ts +10 -0
- package/dist/components/buttons/LiteListButton.svelte +31 -0
- package/dist/components/buttons/LiteListButton.svelte.d.ts +10 -0
- package/dist/components/buttons/LiteRefreshButton.svelte +34 -0
- package/dist/components/buttons/LiteRefreshButton.svelte.d.ts +8 -0
- package/dist/components/buttons/LiteSaveButton.svelte +27 -0
- package/dist/components/buttons/LiteSaveButton.svelte.d.ts +8 -0
- package/dist/components/buttons/LiteShowButton.svelte +33 -0
- package/dist/components/buttons/LiteShowButton.svelte.d.ts +11 -0
- package/dist/components/buttons/index.js +10 -0
- package/dist/components/fields/LiteBooleanField.svelte +42 -0
- package/dist/components/fields/LiteBooleanField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteDateField.svelte +51 -0
- package/dist/components/fields/LiteDateField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteEmailField.svelte +41 -0
- package/dist/components/fields/LiteEmailField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteFileField.svelte +59 -0
- package/dist/components/fields/LiteFileField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteImageField.svelte +57 -0
- package/dist/components/fields/LiteImageField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteJsonField.svelte +43 -0
- package/dist/components/fields/LiteJsonField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteMarkdownField.svelte +33 -0
- package/dist/components/fields/LiteMarkdownField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteMultiSelectField.svelte +57 -0
- package/dist/components/fields/LiteMultiSelectField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteNumberField.svelte +35 -0
- package/dist/components/fields/LiteNumberField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteRelationField.svelte +67 -0
- package/dist/components/fields/LiteRelationField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteRichTextField.svelte +44 -0
- package/dist/components/fields/LiteRichTextField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteSelectField.svelte +47 -0
- package/dist/components/fields/LiteSelectField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteTagField.svelte +44 -0
- package/dist/components/fields/LiteTagField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteTextField.svelte +35 -0
- package/dist/components/fields/LiteTextField.svelte.d.ts +10 -0
- package/dist/components/fields/LiteUrlField.svelte +52 -0
- package/dist/components/fields/LiteUrlField.svelte.d.ts +10 -0
- package/dist/components/fields/index.js +15 -0
- package/dist/components/layout/LiteAuthenticated.svelte +23 -0
- package/dist/components/layout/LiteAuthenticated.svelte.d.ts +10 -0
- package/dist/components/layout/LiteCanAccess.svelte +27 -0
- package/dist/components/layout/LiteCanAccess.svelte.d.ts +10 -0
- package/dist/components/layout/LiteCatchAllNavigate.svelte +20 -0
- package/dist/components/layout/LiteCatchAllNavigate.svelte.d.ts +7 -0
- package/dist/components/layout/LiteErrorBoundary.svelte +20 -0
- package/dist/components/layout/LiteErrorBoundary.svelte.d.ts +13 -0
- package/dist/components/layout/LiteErrorComponent.svelte +37 -0
- package/dist/components/layout/LiteErrorComponent.svelte.d.ts +9 -0
- package/dist/components/layout/LiteHeader.svelte +19 -0
- package/dist/components/layout/LiteHeader.svelte.d.ts +8 -0
- package/dist/components/layout/LiteNavigateToResource.svelte +25 -0
- package/dist/components/layout/LiteNavigateToResource.svelte.d.ts +7 -0
- package/dist/components/layout/LiteSidebar.svelte +93 -0
- package/dist/components/layout/LiteSidebar.svelte.d.ts +12 -0
- package/dist/components/layout/index.js +8 -0
- package/dist/components/pages/LiteCreatePage.svelte +39 -0
- package/dist/components/pages/LiteCreatePage.svelte.d.ts +10 -0
- package/dist/components/pages/LiteEditPage.svelte +54 -0
- package/dist/components/pages/LiteEditPage.svelte.d.ts +12 -0
- package/dist/components/pages/LiteForgotPasswordPage.svelte +60 -0
- package/dist/components/pages/LiteForgotPasswordPage.svelte.d.ts +11 -0
- package/dist/components/pages/LiteListPage.svelte +81 -0
- package/dist/components/pages/LiteListPage.svelte.d.ts +20 -0
- package/dist/components/pages/LiteProfilePage.svelte +61 -0
- package/dist/components/pages/LiteProfilePage.svelte.d.ts +14 -0
- package/dist/components/pages/LiteRegisterPage.svelte +63 -0
- package/dist/components/pages/LiteRegisterPage.svelte.d.ts +10 -0
- package/dist/components/pages/LiteShowPage.svelte +61 -0
- package/dist/components/pages/LiteShowPage.svelte.d.ts +11 -0
- package/dist/components/pages/LiteUpdatePasswordPage.svelte +51 -0
- package/dist/components/pages/LiteUpdatePasswordPage.svelte.d.ts +9 -0
- package/dist/components/pages/index.js +8 -0
- package/dist/components/widgets/LiteAnomalyBadge.svelte +40 -0
- package/dist/components/widgets/LiteAnomalyBadge.svelte.d.ts +15 -0
- package/dist/components/widgets/LiteBarChart.svelte +45 -0
- package/dist/components/widgets/LiteBarChart.svelte.d.ts +17 -0
- package/dist/components/widgets/LiteInsightCard.svelte +31 -0
- package/dist/components/widgets/LiteInsightCard.svelte.d.ts +13 -0
- package/dist/components/widgets/LiteLineChart.svelte +48 -0
- package/dist/components/widgets/LiteLineChart.svelte.d.ts +17 -0
- package/dist/components/widgets/LitePieChart.svelte +44 -0
- package/dist/components/widgets/LitePieChart.svelte.d.ts +17 -0
- package/dist/components/widgets/index.js +5 -0
- package/dist/enhance.js +112 -0
- package/dist/index.d.ts +27 -0
- package/{src/index.ts → dist/index.js} +3 -26
- package/dist/lite.css +817 -0
- package/dist/schema-generator.d.ts +29 -0
- package/dist/schema-generator.js +226 -0
- package/dist/security.d.ts +14 -0
- package/dist/security.js +59 -0
- package/dist/server-adapter.d.ts +111 -0
- package/dist/server-adapter.js +422 -0
- package/package.json +55 -18
- package/src/schema-generator.ts +0 -147
- package/src/server-adapter.ts +0 -307
- /package/{src/components/advanced/index.ts → dist/components/advanced/index.d.ts} +0 -0
- /package/{src/components/buttons/index.ts → dist/components/buttons/index.d.ts} +0 -0
- /package/{src/components/fields/index.ts → dist/components/fields/index.d.ts} +0 -0
- /package/{src/components/layout/index.ts → dist/components/layout/index.d.ts} +0 -0
- /package/{src/components/pages/index.ts → dist/components/pages/index.d.ts} +0 -0
- /package/{src/components/widgets/index.ts → dist/components/widgets/index.d.ts} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
action?: string;
|
|
7
|
+
loginUrl?: string;
|
|
8
|
+
errors?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
title = 'Register',
|
|
13
|
+
description = 'Create a new account',
|
|
14
|
+
action = '?/register',
|
|
15
|
+
loginUrl = '/lite/login',
|
|
16
|
+
errors = [],
|
|
17
|
+
}: Props = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<div style="min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #f8fafc; padding: 20px;">
|
|
21
|
+
<div class="lite-card" style="width: 100%; max-width: 400px; padding: 32px;">
|
|
22
|
+
<div style="text-align: center; margin-bottom: 24px;">
|
|
23
|
+
<h1 style="font-size: 24px; font-weight: 600; color: #0f172a; margin: 0 0 8px;">{title}</h1>
|
|
24
|
+
<p style="font-size: 14px; color: #64748b; margin: 0;">{description}</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<!-- We use native form action -->
|
|
28
|
+
<form method="POST" {action} style="display: flex; flex-direction: column; gap: 16px;">
|
|
29
|
+
<div class="lite-form-group">
|
|
30
|
+
<label for="email">Email</label>
|
|
31
|
+
<input type="email" id="email" name="email" class="lite-input" required />
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="lite-form-group">
|
|
35
|
+
<label for="password">Password</label>
|
|
36
|
+
<input type="password" id="password" name="password" class="lite-input" required minlength="6" />
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div class="lite-form-group">
|
|
40
|
+
<label for="confirmPassword">Confirm Password</label>
|
|
41
|
+
<input type="password" id="confirmPassword" name="confirmPassword" class="lite-input" required minlength="6" />
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
{#if errors.length > 0}
|
|
45
|
+
<div style="padding: 12px; background: #fef2f2; border-radius: 6px; color: #ef4444; font-size: 13px;">
|
|
46
|
+
<ul style="margin: 0; padding-left: 20px;">
|
|
47
|
+
{#each errors as err, _i (_i)}
|
|
48
|
+
<li>{err}</li>
|
|
49
|
+
{/each}
|
|
50
|
+
</ul>
|
|
51
|
+
</div>
|
|
52
|
+
{/if}
|
|
53
|
+
|
|
54
|
+
<button type="submit" class="lite-btn lite-btn-primary" style="width: 100%; justify-content: center; padding: 10px;">
|
|
55
|
+
Register
|
|
56
|
+
</button>
|
|
57
|
+
|
|
58
|
+
<div style="text-align: center; font-size: 13px; color: #64748b; margin-top: 8px;">
|
|
59
|
+
Already have an account? <a href={loginUrl} style="color: #2563eb; text-decoration: none;">Login</a>
|
|
60
|
+
</div>
|
|
61
|
+
</form>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
action?: string;
|
|
5
|
+
loginUrl?: string;
|
|
6
|
+
errors?: string[];
|
|
7
|
+
}
|
|
8
|
+
declare const LiteRegisterPage: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type LiteRegisterPage = ReturnType<typeof LiteRegisterPage>;
|
|
10
|
+
export default LiteRegisterPage;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ResourceDefinition } from '@svadmin/core';
|
|
3
|
+
import { t } from '@svadmin/core/i18n';
|
|
4
|
+
import LiteShowField from '../LiteShowField.svelte';
|
|
5
|
+
import LiteListButton from '../buttons/LiteListButton.svelte';
|
|
6
|
+
import LiteEditButton from '../buttons/LiteEditButton.svelte';
|
|
7
|
+
import LiteDeleteButton from '../buttons/LiteDeleteButton.svelte';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
resource: ResourceDefinition;
|
|
11
|
+
record: Record<string, unknown>;
|
|
12
|
+
basePath?: string;
|
|
13
|
+
canEdit?: boolean;
|
|
14
|
+
canDelete?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
resource,
|
|
19
|
+
record,
|
|
20
|
+
basePath = '/lite',
|
|
21
|
+
canEdit = true,
|
|
22
|
+
canDelete = true,
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
|
|
25
|
+
let pk = $derived(resource.primaryKey ?? 'id');
|
|
26
|
+
let idStr = $derived(String(record[pk]));
|
|
27
|
+
|
|
28
|
+
const showFields = $derived(
|
|
29
|
+
resource.fields.filter(f => f.showInShow !== false)
|
|
30
|
+
);
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<div class="lite-page">
|
|
34
|
+
<div class="lite-page-header">
|
|
35
|
+
<h1 class="lite-page-title">{t('common.show') || 'Show'} {resource.label || resource.name} #{idStr}</h1>
|
|
36
|
+
<div class="lite-page-actions">
|
|
37
|
+
{#if canEdit}
|
|
38
|
+
<LiteEditButton resource={resource.name} recordItemId={idStr} {basePath} />
|
|
39
|
+
{/if}
|
|
40
|
+
<LiteListButton resource={resource.name} {basePath} />
|
|
41
|
+
{#if canDelete}
|
|
42
|
+
<LiteDeleteButton resource={resource.name} recordItemId={idStr} redirectUrl={`${basePath}/${resource.name}`} {basePath} />
|
|
43
|
+
{/if}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="lite-card" style="padding: 24px;">
|
|
48
|
+
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 24px;">
|
|
49
|
+
{#each showFields as field, _i (_i)}
|
|
50
|
+
<div>
|
|
51
|
+
<div style="display: block; font-size: 13px; font-weight: 500; color: #64748b; margin-bottom: 8px;">
|
|
52
|
+
{field.label}
|
|
53
|
+
</div>
|
|
54
|
+
<div style="color: #0f172a; font-size: 14px;">
|
|
55
|
+
<LiteShowField {field} value={record[field.key]} />
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
{/each}
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ResourceDefinition } from '@svadmin/core';
|
|
2
|
+
interface Props {
|
|
3
|
+
resource: ResourceDefinition;
|
|
4
|
+
record: Record<string, unknown>;
|
|
5
|
+
basePath?: string;
|
|
6
|
+
canEdit?: boolean;
|
|
7
|
+
canDelete?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare const LiteShowPage: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type LiteShowPage = ReturnType<typeof LiteShowPage>;
|
|
11
|
+
export default LiteShowPage;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
title?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
action?: string;
|
|
6
|
+
errors?: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
title = 'Update Password',
|
|
11
|
+
description = 'Enter your new password below.',
|
|
12
|
+
action = '?/update_password',
|
|
13
|
+
errors = [],
|
|
14
|
+
}: Props = $props();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<div style="min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #f8fafc; padding: 20px;">
|
|
18
|
+
<div class="lite-card" style="width: 100%; max-width: 400px; padding: 32px;">
|
|
19
|
+
<div style="text-align: center; margin-bottom: 24px;">
|
|
20
|
+
<h1 style="font-size: 24px; font-weight: 600; color: #0f172a; margin: 0 0 8px;">{title}</h1>
|
|
21
|
+
<p style="font-size: 14px; color: #64748b; margin: 0;">{description}</p>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<!-- Native form action -->
|
|
25
|
+
<form method="POST" {action} style="display: flex; flex-direction: column; gap: 16px;">
|
|
26
|
+
<div class="lite-form-group">
|
|
27
|
+
<label for="password">New Password</label>
|
|
28
|
+
<input type="password" id="password" name="password" class="lite-input" required minlength="6" />
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="lite-form-group">
|
|
32
|
+
<label for="confirmPassword">Confirm New Password</label>
|
|
33
|
+
<input type="password" id="confirmPassword" name="confirmPassword" class="lite-input" required minlength="6" />
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
{#if errors.length > 0}
|
|
37
|
+
<div style="padding: 12px; background: #fef2f2; border-radius: 6px; color: #ef4444; font-size: 13px;">
|
|
38
|
+
<ul style="margin: 0; padding-left: 20px;">
|
|
39
|
+
{#each errors as err, _i (_i)}
|
|
40
|
+
<li>{err}</li>
|
|
41
|
+
{/each}
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
{/if}
|
|
45
|
+
|
|
46
|
+
<button type="submit" class="lite-btn lite-btn-primary" style="width: 100%; justify-content: center; padding: 10px;">
|
|
47
|
+
Update Password
|
|
48
|
+
</button>
|
|
49
|
+
</form>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
action?: string;
|
|
5
|
+
errors?: string[];
|
|
6
|
+
}
|
|
7
|
+
declare const LiteUpdatePasswordPage: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type LiteUpdatePasswordPage = ReturnType<typeof LiteUpdatePasswordPage>;
|
|
9
|
+
export default LiteUpdatePasswordPage;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { default as LiteListPage } from './LiteListPage.svelte';
|
|
2
|
+
export { default as LiteCreatePage } from './LiteCreatePage.svelte';
|
|
3
|
+
export { default as LiteEditPage } from './LiteEditPage.svelte';
|
|
4
|
+
export { default as LiteShowPage } from './LiteShowPage.svelte';
|
|
5
|
+
export { default as LiteRegisterPage } from './LiteRegisterPage.svelte';
|
|
6
|
+
export { default as LiteForgotPasswordPage } from './LiteForgotPasswordPage.svelte';
|
|
7
|
+
export { default as LiteUpdatePasswordPage } from './LiteUpdatePasswordPage.svelte';
|
|
8
|
+
export { default as LiteProfilePage } from './LiteProfilePage.svelte';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SSR AnomalyBadge — Rendered as a static colored badge.
|
|
4
|
+
* The SPA version has tooltips (requires JS). In lite mode,
|
|
5
|
+
* we use a title attribute for the tooltip fallback.
|
|
6
|
+
*/
|
|
7
|
+
interface Props {
|
|
8
|
+
value: number;
|
|
9
|
+
baseline: number;
|
|
10
|
+
threshold?: number;
|
|
11
|
+
formatter?: (val: number) => string;
|
|
12
|
+
lowerIsBetter?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
value,
|
|
17
|
+
baseline,
|
|
18
|
+
threshold = 0.2,
|
|
19
|
+
formatter = (v: number) => v.toString(),
|
|
20
|
+
lowerIsBetter = false,
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
const diff = $derived(baseline === 0 ? 0 : (value - baseline) / Math.abs(baseline));
|
|
24
|
+
const isAnomaly = $derived(Math.abs(diff) >= threshold);
|
|
25
|
+
const isGood = $derived(!isAnomaly ? null : (lowerIsBetter ? diff < 0 : diff > 0));
|
|
26
|
+
const percentLabel = $derived(`${Math.abs(diff * 100).toFixed(1)}%`);
|
|
27
|
+
const arrow = $derived(diff > 0 ? '↑' : '↓');
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
{#if !isAnomaly}
|
|
31
|
+
<span style="font-size: 14px; color: #64748b;">{formatter(value)}</span>
|
|
32
|
+
{:else}
|
|
33
|
+
<span
|
|
34
|
+
title="Baseline: {formatter(baseline)} ({diff > 0 ? '+' : '-'}{percentLabel})"
|
|
35
|
+
class="lite-badge"
|
|
36
|
+
style="background: {isGood ? '#ecfdf5' : '#fef2f2'}; color: {isGood ? '#065f46' : '#991b1b'}; border: 1px solid {isGood ? '#a7f3d0' : '#fecaca'};"
|
|
37
|
+
>
|
|
38
|
+
{arrow} {formatter(value)}
|
|
39
|
+
</span>
|
|
40
|
+
{/if}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR AnomalyBadge — Rendered as a static colored badge.
|
|
3
|
+
* The SPA version has tooltips (requires JS). In lite mode,
|
|
4
|
+
* we use a title attribute for the tooltip fallback.
|
|
5
|
+
*/
|
|
6
|
+
interface Props {
|
|
7
|
+
value: number;
|
|
8
|
+
baseline: number;
|
|
9
|
+
threshold?: number;
|
|
10
|
+
formatter?: (val: number) => string;
|
|
11
|
+
lowerIsBetter?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const LiteAnomalyBadge: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type LiteAnomalyBadge = ReturnType<typeof LiteAnomalyBadge>;
|
|
15
|
+
export default LiteAnomalyBadge;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SSR BarChart — Rendered as a pure CSS horizontal bar chart.
|
|
4
|
+
* No charting library needed. Data is rendered server-side as
|
|
5
|
+
* colored div bars with percentage widths.
|
|
6
|
+
*/
|
|
7
|
+
interface DataPoint {
|
|
8
|
+
label: string;
|
|
9
|
+
value: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
data: DataPoint[];
|
|
15
|
+
title?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { data, title }: Props = $props();
|
|
19
|
+
|
|
20
|
+
const maxValue = $derived(Math.max(...data.map(d => d.value), 1));
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<div class="lite-card" style="margin-bottom: 16px;">
|
|
24
|
+
{#if title}
|
|
25
|
+
<div style="padding: 12px 16px; border-bottom: 1px solid #e2e8f0; font-weight: 600; font-size: 14px; color: #0f172a;">
|
|
26
|
+
{title}
|
|
27
|
+
</div>
|
|
28
|
+
{/if}
|
|
29
|
+
<div style="padding: 16px; display: flex; flex-direction: column; gap: 12px;">
|
|
30
|
+
{#each data as point, _i (_i)}
|
|
31
|
+
<div>
|
|
32
|
+
<div style="display: flex; justify-content: space-between; margin-bottom: 4px; font-size: 13px;">
|
|
33
|
+
<span style="color: #334155;">{point.label}</span>
|
|
34
|
+
<span style="color: #64748b; font-weight: 500;">{point.value}</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div style="height: 20px; background: #f1f5f9; border-radius: 4px; overflow: hidden;">
|
|
37
|
+
<div style="height: 100%; width: {(point.value / maxValue) * 100}%; background: {point.color ?? '#6366f1'}; border-radius: 4px; transition: width 0.3s;"></div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
{/each}
|
|
41
|
+
{#if data.length === 0}
|
|
42
|
+
<p style="color: #94a3b8; font-style: italic; text-align: center;">No data</p>
|
|
43
|
+
{/if}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR BarChart — Rendered as a pure CSS horizontal bar chart.
|
|
3
|
+
* No charting library needed. Data is rendered server-side as
|
|
4
|
+
* colored div bars with percentage widths.
|
|
5
|
+
*/
|
|
6
|
+
interface DataPoint {
|
|
7
|
+
label: string;
|
|
8
|
+
value: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Props {
|
|
12
|
+
data: DataPoint[];
|
|
13
|
+
title?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const LiteBarChart: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type LiteBarChart = ReturnType<typeof LiteBarChart>;
|
|
17
|
+
export default LiteBarChart;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { toSafeText } from '../../security.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SSR InsightCard — Degraded to static pre-rendered content.
|
|
6
|
+
* The SPA version streams AI-generated insights via ChatProvider.
|
|
7
|
+
* In lite mode, insights must be pre-computed on the server and
|
|
8
|
+
* passed as a static string. No AI streaming is available.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
title?: string;
|
|
12
|
+
content?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { title = 'Insights', content = '' }: Props = $props();
|
|
16
|
+
const displayContent = $derived(toSafeText(content));
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<div class="lite-card" style="margin-bottom: 16px;">
|
|
20
|
+
<div style="padding: 12px 16px; border-bottom: 1px solid #e2e8f0; font-weight: 600; font-size: 14px; color: #0f172a; display: flex; align-items: center; gap: 8px;">
|
|
21
|
+
<span style="color: #f59e0b;">✦</span>
|
|
22
|
+
{title}
|
|
23
|
+
</div>
|
|
24
|
+
<div style="padding: 16px; font-size: 14px; color: #334155; line-height: 1.6;">
|
|
25
|
+
{#if displayContent}
|
|
26
|
+
<p style="white-space: pre-wrap; margin: 0;">{displayContent}</p>
|
|
27
|
+
{:else}
|
|
28
|
+
<p style="color: #94a3b8; font-style: italic;">No insights available. AI analysis requires JavaScript.</p>
|
|
29
|
+
{/if}
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR InsightCard — Degraded to static pre-rendered content.
|
|
3
|
+
* The SPA version streams AI-generated insights via ChatProvider.
|
|
4
|
+
* In lite mode, insights must be pre-computed on the server and
|
|
5
|
+
* passed as a static string. No AI streaming is available.
|
|
6
|
+
*/
|
|
7
|
+
interface Props {
|
|
8
|
+
title?: string;
|
|
9
|
+
content?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const LiteInsightCard: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type LiteInsightCard = ReturnType<typeof LiteInsightCard>;
|
|
13
|
+
export default LiteInsightCard;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SSR LineChart — Degraded to an HTML data table.
|
|
4
|
+
* Drawing SVG/Canvas line charts inline is possible but complex.
|
|
5
|
+
* For maximum compatibility (IE11), we render data as a simple table.
|
|
6
|
+
*/
|
|
7
|
+
interface DataPoint {
|
|
8
|
+
label: string;
|
|
9
|
+
value: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
data: DataPoint[];
|
|
14
|
+
title?: string;
|
|
15
|
+
valueLabel?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { data, title, valueLabel = 'Value' }: Props = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<div class="lite-card" style="margin-bottom: 16px;">
|
|
22
|
+
{#if title}
|
|
23
|
+
<div style="padding: 12px 16px; border-bottom: 1px solid #e2e8f0; font-weight: 600; font-size: 14px; color: #0f172a;">
|
|
24
|
+
{title}
|
|
25
|
+
</div>
|
|
26
|
+
{/if}
|
|
27
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
28
|
+
<thead>
|
|
29
|
+
<tr>
|
|
30
|
+
<th style="text-align: left; padding: 10px 16px; font-size: 12px; color: #64748b; border-bottom: 1px solid #e2e8f0;">Label</th>
|
|
31
|
+
<th style="text-align: right; padding: 10px 16px; font-size: 12px; color: #64748b; border-bottom: 1px solid #e2e8f0;">{valueLabel}</th>
|
|
32
|
+
</tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
{#each data as point, i (i)}
|
|
36
|
+
<tr style="background: {i % 2 === 0 ? '#ffffff' : '#f8fafc'};">
|
|
37
|
+
<td style="padding: 8px 16px; font-size: 13px; color: #334155;">{point.label}</td>
|
|
38
|
+
<td style="padding: 8px 16px; font-size: 13px; color: #0f172a; text-align: right; font-weight: 500;">{point.value}</td>
|
|
39
|
+
</tr>
|
|
40
|
+
{/each}
|
|
41
|
+
{#if data.length === 0}
|
|
42
|
+
<tr>
|
|
43
|
+
<td colspan="2" style="padding: 16px; text-align: center; color: #94a3b8; font-style: italic;">No data</td>
|
|
44
|
+
</tr>
|
|
45
|
+
{/if}
|
|
46
|
+
</tbody>
|
|
47
|
+
</table>
|
|
48
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR LineChart — Degraded to an HTML data table.
|
|
3
|
+
* Drawing SVG/Canvas line charts inline is possible but complex.
|
|
4
|
+
* For maximum compatibility (IE11), we render data as a simple table.
|
|
5
|
+
*/
|
|
6
|
+
interface DataPoint {
|
|
7
|
+
label: string;
|
|
8
|
+
value: number;
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
data: DataPoint[];
|
|
12
|
+
title?: string;
|
|
13
|
+
valueLabel?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const LiteLineChart: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type LiteLineChart = ReturnType<typeof LiteLineChart>;
|
|
17
|
+
export default LiteLineChart;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* SSR PieChart — Degraded to a list with colored dots.
|
|
4
|
+
* Drawing SVG pie charts inline is technically possible but IE11
|
|
5
|
+
* doesn't support CSS conic-gradient. We fall back to a plain list.
|
|
6
|
+
*/
|
|
7
|
+
interface DataPoint {
|
|
8
|
+
label: string;
|
|
9
|
+
value: number;
|
|
10
|
+
color?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
data: DataPoint[];
|
|
15
|
+
title?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { data, title }: Props = $props();
|
|
19
|
+
|
|
20
|
+
const total = $derived(data.reduce((sum, d) => sum + d.value, 0));
|
|
21
|
+
const defaultColors = ['#6366f1', '#f59e0b', '#10b981', '#ef4444', '#8b5cf6', '#06b6d4', '#f97316', '#ec4899'];
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div class="lite-card" style="margin-bottom: 16px;">
|
|
25
|
+
{#if title}
|
|
26
|
+
<div style="padding: 12px 16px; border-bottom: 1px solid #e2e8f0; font-weight: 600; font-size: 14px; color: #0f172a;">
|
|
27
|
+
{title}
|
|
28
|
+
</div>
|
|
29
|
+
{/if}
|
|
30
|
+
<div style="padding: 16px; display: flex; flex-direction: column; gap: 10px;">
|
|
31
|
+
{#each data as point, i (i)}
|
|
32
|
+
{@const pct = total > 0 ? ((point.value / total) * 100).toFixed(1) : '0.0'}
|
|
33
|
+
<div style="display: flex; align-items: center; gap: 10px; font-size: 13px;">
|
|
34
|
+
<span style="width: 12px; height: 12px; border-radius: 50%; background: {point.color ?? defaultColors[i % defaultColors.length]}; flex-shrink: 0;"></span>
|
|
35
|
+
<span style="flex: 1; color: #334155;">{point.label}</span>
|
|
36
|
+
<span style="color: #64748b; font-weight: 500;">{point.value}</span>
|
|
37
|
+
<span style="color: #94a3b8; font-size: 12px; min-width: 48px; text-align: right;">{pct}%</span>
|
|
38
|
+
</div>
|
|
39
|
+
{/each}
|
|
40
|
+
{#if data.length === 0}
|
|
41
|
+
<p style="color: #94a3b8; font-style: italic; text-align: center;">No data</p>
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR PieChart — Degraded to a list with colored dots.
|
|
3
|
+
* Drawing SVG pie charts inline is technically possible but IE11
|
|
4
|
+
* doesn't support CSS conic-gradient. We fall back to a plain list.
|
|
5
|
+
*/
|
|
6
|
+
interface DataPoint {
|
|
7
|
+
label: string;
|
|
8
|
+
value: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Props {
|
|
12
|
+
data: DataPoint[];
|
|
13
|
+
title?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const LitePieChart: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type LitePieChart = ReturnType<typeof LitePieChart>;
|
|
17
|
+
export default LitePieChart;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as LiteInsightCard } from './LiteInsightCard.svelte';
|
|
2
|
+
export { default as LiteAnomalyBadge } from './LiteAnomalyBadge.svelte';
|
|
3
|
+
export { default as LiteBarChart } from './LiteBarChart.svelte';
|
|
4
|
+
export { default as LiteLineChart } from './LiteLineChart.svelte';
|
|
5
|
+
export { default as LitePieChart } from './LitePieChart.svelte';
|
package/dist/enhance.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @svadmin/lite — Optional Progressive Enhancement
|
|
3
|
+
*
|
|
4
|
+
* This script is optional and uses ES5 syntax for broad compatibility.
|
|
5
|
+
* If included, it adds minor UX improvements. If not, everything still works.
|
|
6
|
+
*
|
|
7
|
+
* Include in your app.html:
|
|
8
|
+
* <script src="/enhance.js"></script>
|
|
9
|
+
*/
|
|
10
|
+
(function() {
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
function closestByAttribute(element, attribute) {
|
|
14
|
+
var current = element;
|
|
15
|
+
while (current && current.nodeType === 1) {
|
|
16
|
+
if (current.hasAttribute(attribute)) return current;
|
|
17
|
+
current = current.parentElement;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function bindArrayRemoveButtons(fieldset) {
|
|
23
|
+
var buttons = fieldset.querySelectorAll('[data-lite-array-remove]');
|
|
24
|
+
for (var i = 0; i < buttons.length; i++) {
|
|
25
|
+
var button = buttons[i];
|
|
26
|
+
button.removeAttribute('hidden');
|
|
27
|
+
if (button.getAttribute('data-lite-array-bound') === 'true') continue;
|
|
28
|
+
button.setAttribute('data-lite-array-bound', 'true');
|
|
29
|
+
button.addEventListener('click', function() {
|
|
30
|
+
var item = closestByAttribute(this, 'data-lite-array-item');
|
|
31
|
+
if (item && item.parentNode) item.parentNode.removeChild(item);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function enhanceArrayField(fieldset) {
|
|
37
|
+
var addButton = fieldset.querySelector('[data-lite-array-add]');
|
|
38
|
+
var template = fieldset.querySelector('template[data-lite-array-template]');
|
|
39
|
+
bindArrayRemoveButtons(fieldset);
|
|
40
|
+
if (!addButton || !template) return;
|
|
41
|
+
|
|
42
|
+
addButton.removeAttribute('hidden');
|
|
43
|
+
addButton.addEventListener('click', function() {
|
|
44
|
+
var nextIndex = Number(fieldset.getAttribute('data-next-index') || '0');
|
|
45
|
+
var holder = document.createElement('div');
|
|
46
|
+
holder.innerHTML = template.innerHTML.replace(/__INDEX__/g, String(nextIndex));
|
|
47
|
+
var item = holder.firstElementChild;
|
|
48
|
+
if (!item || !addButton.parentNode) return;
|
|
49
|
+
addButton.parentNode.insertBefore(item, addButton);
|
|
50
|
+
fieldset.setAttribute('data-next-index', String(nextIndex + 1));
|
|
51
|
+
bindArrayRemoveButtons(fieldset);
|
|
52
|
+
var firstInput = item.querySelector('input:not([type="hidden"]), textarea, select');
|
|
53
|
+
if (firstInput) firstInput.focus();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function init() {
|
|
58
|
+
document.documentElement.className += ' lite-js';
|
|
59
|
+
|
|
60
|
+
// 1. Delete confirmation — close <details> when clicking outside
|
|
61
|
+
document.addEventListener('click', function(e) {
|
|
62
|
+
var details = document.querySelectorAll('details.lite-confirm-details');
|
|
63
|
+
for (var i = 0; i < details.length; i++) {
|
|
64
|
+
if (!details[i].contains(e.target)) {
|
|
65
|
+
details[i].removeAttribute('open');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// 2. Highlight current table row on hover (for older browsers without :hover)
|
|
71
|
+
var rows = document.querySelectorAll('.lite-table tbody tr');
|
|
72
|
+
for (var j = 0; j < rows.length; j++) {
|
|
73
|
+
rows[j].addEventListener('mouseenter', function() {
|
|
74
|
+
this.style.backgroundColor = '#f8fafc';
|
|
75
|
+
});
|
|
76
|
+
rows[j].addEventListener('mouseleave', function() {
|
|
77
|
+
this.style.backgroundColor = '';
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 3. Auto-focus first input on form pages
|
|
82
|
+
var firstInput = document.querySelector('.lite-form-group input, .lite-form-group textarea');
|
|
83
|
+
if (firstInput && firstInput.offsetParent !== null) {
|
|
84
|
+
firstInput.focus();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 4. Confirm before leaving dirty forms
|
|
88
|
+
var form = document.querySelector('form.lite-card');
|
|
89
|
+
if (form) {
|
|
90
|
+
var dirty = false;
|
|
91
|
+
form.addEventListener('change', function() { dirty = true; });
|
|
92
|
+
window.addEventListener('beforeunload', function(e) {
|
|
93
|
+
if (dirty) {
|
|
94
|
+
e.returnValue = 'You have unsaved changes.';
|
|
95
|
+
return e.returnValue;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
form.addEventListener('submit', function() { dirty = false; });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 5. Dynamic array rows. The initial row and no-JS removal submitters
|
|
102
|
+
// remain fully server-submittable when this optional script is absent.
|
|
103
|
+
var arrays = document.querySelectorAll('[data-lite-array]');
|
|
104
|
+
for (var k = 0; k < arrays.length; k++) enhanceArrayField(arrays[k]);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (document.readyState === 'loading') {
|
|
108
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
109
|
+
} else {
|
|
110
|
+
init();
|
|
111
|
+
}
|
|
112
|
+
})();
|