@svadmin/lite 0.8.2 → 0.9.1
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 +4 -5
- package/dist/components/LiteBadge.svelte +43 -0
- package/dist/components/LiteBadge.svelte.d.ts +12 -0
- package/dist/components/LiteChatDialog.svelte +9 -2
- package/dist/components/LiteMetricStrip.svelte +96 -0
- package/dist/components/LiteMetricStrip.svelte.d.ts +33 -0
- package/dist/components/LiteTable.svelte +12 -4
- package/dist/components/LiteTable.svelte.d.ts +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/lite.css +91 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -263,7 +263,7 @@ IE11 before the decision is made.
|
|
|
263
263
|
| `LiteProfilePage` | User profile management page with avatar and info |
|
|
264
264
|
| `LiteRegisterPage` | User registration page with server-side validation |
|
|
265
265
|
| `LiteForgotPasswordPage` / `LiteUpdatePasswordPage` | Password recovery and credential rotation flows |
|
|
266
|
-
| `LiteTable` | HTML table with sort links, selectable rows,
|
|
266
|
+
| `LiteTable` | HTML table with sort links, selectable rows, delete confirmation, and optional sticky edge/action columns |
|
|
267
267
|
| `LiteForm` | Schema-driven form renderer supporting all field definitions |
|
|
268
268
|
| `LiteShow` | Detailed field-by-field record viewer |
|
|
269
269
|
| `LitePagination` / `LiteSearch` | URL-driven pagination and GET search controls |
|
|
@@ -272,14 +272,13 @@ IE11 before the decision is made.
|
|
|
272
272
|
| `LiteCanAccess` / `LiteErrorBoundary` | Server-side access gate and constrained-environment error boundary |
|
|
273
273
|
| `LiteSplitPaneLayout` / `LiteMultiTabKeepAlive` | Dense two-pane layouts and multi-workspace navigation |
|
|
274
274
|
|
|
275
|
-
### Field Components (
|
|
275
|
+
### Field Components (32 Fields)
|
|
276
276
|
|
|
277
277
|
| Category | Components |
|
|
278
278
|
|----------|------------|
|
|
279
279
|
| **Text & Numeric** | `LiteTextField`, `LiteNumberField`, `LiteCurrencyField`, `LitePercentField`, `LitePhoneField`, `LiteEmailField`, `LiteUrlField`, `LiteRatingField`, `LiteCopyField` |
|
|
280
280
|
| **Date & Choice** | `LiteDateField`, `LiteDateRangeField`, `LiteBooleanField`, `LiteSelectField`, `LiteMultiSelectField`, `LiteTreeSelect`, `LiteCascader`, `LiteTagField`, `LiteRelationField` |
|
|
281
281
|
| **Media & Rich & Array** | `LiteAvatarField`, `LiteImageField`, `LiteFileField`, `LiteCodeField`, `LiteMarkdownField`, `LiteRichTextField`, `LiteJsonField`, `LiteArrayField`, `LiteDynamicFormList`, `LiteTransfer`, `LiteImageCropper`, `LiteJsonSchemaForm`, `LiteMentionsInput`, `LiteSignaturePad` |
|
|
282
|
-
| **SPA-only** | `VoiceInput` (Web Speech API; no SSR counterpart) |
|
|
283
282
|
|
|
284
283
|
### Action Buttons (10 Buttons)
|
|
285
284
|
|
|
@@ -293,7 +292,7 @@ IE11 before the decision is made.
|
|
|
293
292
|
|
|
294
293
|
| Component | Description |
|
|
295
294
|
|-----------|-------------|
|
|
296
|
-
| `LiteStatsCard`, `LiteInsightCard`, `LiteAnomalyBadge` | Metric KPI cards and status badges |
|
|
295
|
+
| `LiteStatsCard`, `LiteMetricStrip`, `LiteInsightCard`, `LiteAnomalyBadge`, `LiteBadge` | Metric KPI cards/strips and semantic status badges |
|
|
297
296
|
| `LiteBarChart`, `LiteLineChart`, `LitePieChart` | Server-rendered SVG/HTML charts with fallback data tables |
|
|
298
297
|
| `LitePresenceAvatarGroup`, `LiteGanttChart`, `LiteOfflineSyncBanner` | Presence, schedule, and offline mutation status rendered without client hydration |
|
|
299
298
|
|
|
@@ -320,7 +319,7 @@ IE11 before the decision is made.
|
|
|
320
319
|
| `LiteStepForm`, `LiteTableSummary`, `LiteVersionDiffViewer`, `LiteEditableTable`, `LiteDraggableRowTable` | Server-driven enterprise data interaction components |
|
|
321
320
|
| `LiteMediaLibraryModal`, `LiteActivityFeed`, `LiteKanbanBoard`, `LitePivotTable` | Media, activity, workflow, and analysis views |
|
|
322
321
|
| `LiteCanvasAnnotation`, `LiteSpreadsheetView`, `LiteDecisionTable` | SSR-compatible annotation, spreadsheet, and rules views |
|
|
323
|
-
| `DevTools
|
|
322
|
+
| `DevTools` | SPA-only component with no Lite counterpart |
|
|
324
323
|
|
|
325
324
|
## Parity Tracking & Visualization
|
|
326
325
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
3
|
+
|
|
4
|
+
export type LiteBadgeVariant =
|
|
5
|
+
| 'default'
|
|
6
|
+
| 'secondary'
|
|
7
|
+
| 'destructive'
|
|
8
|
+
| 'subtle'
|
|
9
|
+
| 'subtle-success'
|
|
10
|
+
| 'subtle-warning'
|
|
11
|
+
| 'subtle-destructive'
|
|
12
|
+
| 'subtle-pill'
|
|
13
|
+
| 'outline'
|
|
14
|
+
| 'ghost'
|
|
15
|
+
| 'link'
|
|
16
|
+
| 'info'
|
|
17
|
+
| 'success'
|
|
18
|
+
| 'warning';
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
variant?: LiteBadgeVariant;
|
|
22
|
+
href?: string;
|
|
23
|
+
class?: string;
|
|
24
|
+
children?: import('svelte').Snippet;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
variant = 'default',
|
|
29
|
+
href,
|
|
30
|
+
class: className = '',
|
|
31
|
+
children,
|
|
32
|
+
...restProps
|
|
33
|
+
}: Props & HTMLAnchorAttributes = $props();
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<svelte:element
|
|
37
|
+
this={href ? 'a' : 'span'}
|
|
38
|
+
{href}
|
|
39
|
+
class={'lite-badge lite-badge-' + variant + (className ? ' ' + className : '')}
|
|
40
|
+
{...restProps}
|
|
41
|
+
>
|
|
42
|
+
{@render children?.()}
|
|
43
|
+
</svelte:element>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HTMLAnchorAttributes } from 'svelte/elements';
|
|
2
|
+
export type LiteBadgeVariant = 'default' | 'secondary' | 'destructive' | 'subtle' | 'subtle-success' | 'subtle-warning' | 'subtle-destructive' | 'subtle-pill' | 'outline' | 'ghost' | 'link' | 'info' | 'success' | 'warning';
|
|
3
|
+
interface Props {
|
|
4
|
+
variant?: LiteBadgeVariant;
|
|
5
|
+
href?: string;
|
|
6
|
+
class?: string;
|
|
7
|
+
children?: import('svelte').Snippet;
|
|
8
|
+
}
|
|
9
|
+
type $$ComponentProps = Props & HTMLAnchorAttributes;
|
|
10
|
+
declare const LiteBadge: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type LiteBadge = ReturnType<typeof LiteBadge>;
|
|
12
|
+
export default LiteBadge;
|
|
@@ -32,6 +32,13 @@
|
|
|
32
32
|
return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function messageText(message: ChatMessage): string {
|
|
36
|
+
return message.parts
|
|
37
|
+
.filter((part): part is Extract<ChatMessage['parts'][number], { type: 'text' }> => part.type === 'text')
|
|
38
|
+
.map((part) => part.text)
|
|
39
|
+
.join('');
|
|
40
|
+
}
|
|
41
|
+
|
|
35
42
|
// Auto-scroll anchor logic: pure HTML way to scroll to bottom after page load
|
|
36
43
|
// User should include "#latest-msg" in the form action if possible
|
|
37
44
|
</script>
|
|
@@ -66,10 +73,10 @@
|
|
|
66
73
|
? 'background:#4f46e5;color:#fff;border-bottom-right-radius:2px;'
|
|
67
74
|
: 'background:#e2e8f0;color:#0f172a;border-bottom-left-radius:2px;'}"
|
|
68
75
|
>
|
|
69
|
-
<div style="white-space:pre-wrap;word-break:break-word;">{msg
|
|
76
|
+
<div style="white-space:pre-wrap;word-break:break-word;">{messageText(msg)}</div>
|
|
70
77
|
</div>
|
|
71
78
|
<div style="font-size:11px;color:#94a3b8;margin-top:4px;">
|
|
72
|
-
{msg.role === 'user' ? 'You' : 'Assistant'}
|
|
79
|
+
{msg.role === 'user' ? 'You' : 'Assistant'} · {formatDate(msg.createdAt)}
|
|
73
80
|
</div>
|
|
74
81
|
</div>
|
|
75
82
|
{/if}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Component, Snippet } from 'svelte';
|
|
3
|
+
import LiteBadge from './LiteBadge.svelte';
|
|
4
|
+
|
|
5
|
+
export type LiteMetricTone = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
|
|
6
|
+
export type LiteMetricBadgeTone = 'default' | 'success' | 'warning' | 'danger' | 'info';
|
|
7
|
+
|
|
8
|
+
export interface LiteMetricStripItem {
|
|
9
|
+
id?: string;
|
|
10
|
+
label: string;
|
|
11
|
+
value: string | number;
|
|
12
|
+
tone?: LiteMetricTone;
|
|
13
|
+
badge?: { text: string; tone?: LiteMetricBadgeTone };
|
|
14
|
+
icon?: Component<{ class?: string }>;
|
|
15
|
+
href?: string;
|
|
16
|
+
trend?: { value: number; label?: string };
|
|
17
|
+
loading?: boolean;
|
|
18
|
+
class?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface Props {
|
|
22
|
+
items?: LiteMetricStripItem[];
|
|
23
|
+
columns?: 2 | 3 | 4 | 5 | 6 | 'auto';
|
|
24
|
+
ariaLabel?: string;
|
|
25
|
+
class?: string;
|
|
26
|
+
children?: Snippet;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
items = [],
|
|
31
|
+
columns = 'auto',
|
|
32
|
+
ariaLabel = 'Metrics overview',
|
|
33
|
+
class: className = '',
|
|
34
|
+
children,
|
|
35
|
+
}: Props = $props();
|
|
36
|
+
|
|
37
|
+
const toneClass: Record<LiteMetricTone, string> = {
|
|
38
|
+
default: '',
|
|
39
|
+
primary: 'lite-metric-value-primary',
|
|
40
|
+
success: 'lite-metric-value-success',
|
|
41
|
+
warning: 'lite-metric-value-warning',
|
|
42
|
+
danger: 'lite-metric-value-danger',
|
|
43
|
+
info: 'lite-metric-value-info',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const badgeVariant: Record<LiteMetricBadgeTone, 'default' | 'subtle-success' | 'subtle-warning' | 'subtle-destructive' | 'info'> = {
|
|
47
|
+
default: 'default',
|
|
48
|
+
success: 'subtle-success',
|
|
49
|
+
warning: 'subtle-warning',
|
|
50
|
+
danger: 'subtle-destructive',
|
|
51
|
+
info: 'info',
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<div
|
|
56
|
+
role="region"
|
|
57
|
+
aria-label={ariaLabel}
|
|
58
|
+
class={'lite-metric-strip lite-metric-strip-' + columns + (className ? ' ' + className : '')}
|
|
59
|
+
>
|
|
60
|
+
{#if children}
|
|
61
|
+
{@render children()}
|
|
62
|
+
{:else}
|
|
63
|
+
{#each items as item, index (item.id || index)}
|
|
64
|
+
{@const interactive = Boolean(item.href)}
|
|
65
|
+
<svelte:element
|
|
66
|
+
this={interactive ? 'a' : 'div'}
|
|
67
|
+
href={item.href}
|
|
68
|
+
class={'lite-metric-item' + (interactive ? ' lite-metric-item-link' : '') + (item.class ? ' ' + item.class : '')}
|
|
69
|
+
>
|
|
70
|
+
<div class="lite-metric-label">
|
|
71
|
+
<span>{item.label}</span>
|
|
72
|
+
{#if item.icon}<span class="lite-metric-icon" aria-hidden="true"><item.icon class="lite-metric-icon-svg" /></span>{/if}
|
|
73
|
+
</div>
|
|
74
|
+
{#if item.loading}
|
|
75
|
+
<span class="lite-metric-loading" aria-label="Loading"> </span>
|
|
76
|
+
{:else}
|
|
77
|
+
<div class="lite-metric-value-row">
|
|
78
|
+
<strong class={'lite-metric-value ' + (toneClass[item.tone || 'default'] || '')}>{item.value}</strong>
|
|
79
|
+
{#if item.badge}
|
|
80
|
+
<LiteBadge variant={badgeVariant[item.badge.tone || 'default']}>{item.badge.text}</LiteBadge>
|
|
81
|
+
{:else if item.trend}
|
|
82
|
+
<span
|
|
83
|
+
class={'lite-metric-trend ' + (item.trend.value >= 0 ? 'lite-metric-trend-up' : 'lite-metric-trend-down')}
|
|
84
|
+
aria-label={(item.trend.value >= 0 ? 'Up ' : 'Down ') + Math.abs(item.trend.value) + ' percent'}
|
|
85
|
+
>
|
|
86
|
+
<span aria-hidden="true">{item.trend.value >= 0 ? '↑' : '↓'}</span>
|
|
87
|
+
{Math.abs(item.trend.value)}%
|
|
88
|
+
{#if item.trend.label}<span class="lite-metric-trend-label">{item.trend.label}</span>{/if}
|
|
89
|
+
</span>
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
92
|
+
{/if}
|
|
93
|
+
</svelte:element>
|
|
94
|
+
{/each}
|
|
95
|
+
{/if}
|
|
96
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Component, Snippet } from 'svelte';
|
|
2
|
+
export type LiteMetricTone = 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'info';
|
|
3
|
+
export type LiteMetricBadgeTone = 'default' | 'success' | 'warning' | 'danger' | 'info';
|
|
4
|
+
export interface LiteMetricStripItem {
|
|
5
|
+
id?: string;
|
|
6
|
+
label: string;
|
|
7
|
+
value: string | number;
|
|
8
|
+
tone?: LiteMetricTone;
|
|
9
|
+
badge?: {
|
|
10
|
+
text: string;
|
|
11
|
+
tone?: LiteMetricBadgeTone;
|
|
12
|
+
};
|
|
13
|
+
icon?: Component<{
|
|
14
|
+
class?: string;
|
|
15
|
+
}>;
|
|
16
|
+
href?: string;
|
|
17
|
+
trend?: {
|
|
18
|
+
value: number;
|
|
19
|
+
label?: string;
|
|
20
|
+
};
|
|
21
|
+
loading?: boolean;
|
|
22
|
+
class?: string;
|
|
23
|
+
}
|
|
24
|
+
interface Props {
|
|
25
|
+
items?: LiteMetricStripItem[];
|
|
26
|
+
columns?: 2 | 3 | 4 | 5 | 6 | 'auto';
|
|
27
|
+
ariaLabel?: string;
|
|
28
|
+
class?: string;
|
|
29
|
+
children?: Snippet;
|
|
30
|
+
}
|
|
31
|
+
declare const LiteMetricStrip: Component<Props, {}, "">;
|
|
32
|
+
type LiteMetricStrip = ReturnType<typeof LiteMetricStrip>;
|
|
33
|
+
export default LiteMetricStrip;
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
canEdit?: boolean;
|
|
21
21
|
canDelete?: boolean;
|
|
22
22
|
enableBatch?: boolean;
|
|
23
|
+
/** One field key per edge; left is ignored while batch selection is active. */
|
|
24
|
+
stickyColumns?: { left?: string; right?: string };
|
|
25
|
+
/** Pin actions on the right; this takes precedence over stickyColumns.right. */
|
|
26
|
+
stickyActions?: boolean;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
let {
|
|
@@ -33,6 +37,8 @@
|
|
|
33
37
|
canEdit,
|
|
34
38
|
canDelete,
|
|
35
39
|
enableBatch = false,
|
|
40
|
+
stickyColumns = {},
|
|
41
|
+
stickyActions = false,
|
|
36
42
|
}: Props = $props();
|
|
37
43
|
|
|
38
44
|
const tableId = $props.id();
|
|
@@ -45,6 +51,8 @@
|
|
|
45
51
|
const listFields = $derived(
|
|
46
52
|
resource.fields.filter(f => f.showInList !== false)
|
|
47
53
|
);
|
|
54
|
+
const stickyLeft = $derived(showBatch ? undefined : stickyColumns.left);
|
|
55
|
+
const stickyRight = $derived(stickyActions ? undefined : stickyColumns.right);
|
|
48
56
|
|
|
49
57
|
function sortUrl(field: FieldDefinition): string {
|
|
50
58
|
const newOrder = currentSort === field.key && currentOrder === "asc" ? "desc" : "asc";
|
|
@@ -103,7 +111,7 @@
|
|
|
103
111
|
</th>
|
|
104
112
|
{/if}
|
|
105
113
|
{#each listFields as field, _i (_i)}
|
|
106
|
-
<th>
|
|
114
|
+
<th class={stickyLeft === field.key ? 'lite-table-sticky-left' : stickyRight === field.key ? 'lite-table-sticky-right' : undefined} data-sticky={stickyLeft === field.key ? 'left' : stickyRight === field.key ? 'right' : undefined}>
|
|
107
115
|
{#if field.sortable !== false}
|
|
108
116
|
<a href={sortUrl(field)}>
|
|
109
117
|
{field.label}
|
|
@@ -115,7 +123,7 @@
|
|
|
115
123
|
</th>
|
|
116
124
|
{/each}
|
|
117
125
|
{#if showView || showEdit || showDelete}
|
|
118
|
-
<th style="text-align:right;">{t("common.actions") || "Actions"}</th>
|
|
126
|
+
<th class={stickyActions ? 'lite-table-sticky-right' : undefined} data-sticky={stickyActions ? 'right' : undefined} style="text-align:right;">{t("common.actions") || "Actions"}</th>
|
|
119
127
|
{/if}
|
|
120
128
|
</tr>
|
|
121
129
|
</thead>
|
|
@@ -129,7 +137,7 @@
|
|
|
129
137
|
</td>
|
|
130
138
|
{/if}
|
|
131
139
|
{#each listFields as field, _i (_i)}
|
|
132
|
-
<td>
|
|
140
|
+
<td class={stickyLeft === field.key ? 'lite-table-sticky-left' : stickyRight === field.key ? 'lite-table-sticky-right' : undefined} data-sticky={stickyLeft === field.key ? 'left' : stickyRight === field.key ? 'right' : undefined}>
|
|
133
141
|
{#if field.type === "boolean"}
|
|
134
142
|
<span class="lite-bool {isExplicitBooleanTrue(record[field.key]) ? "lite-bool-true" : ""}"></span>
|
|
135
143
|
{:else if field.type === "tags" && Array.isArray(record[field.key])}
|
|
@@ -148,7 +156,7 @@
|
|
|
148
156
|
</td>
|
|
149
157
|
{/each}
|
|
150
158
|
{#if showView || showEdit || showDelete}
|
|
151
|
-
<td class=
|
|
159
|
+
<td class={'actions' + (stickyActions ? ' lite-table-sticky-right' : '')} data-sticky={stickyActions ? 'right' : undefined}>
|
|
152
160
|
{#if showView}
|
|
153
161
|
<a href={basePath + "/" + resource.name + "/show/" + id} class="lite-btn lite-btn-sm">{t("common.show") || "Show"}</a>
|
|
154
162
|
{/if}
|
|
@@ -15,6 +15,13 @@ interface Props {
|
|
|
15
15
|
canEdit?: boolean;
|
|
16
16
|
canDelete?: boolean;
|
|
17
17
|
enableBatch?: boolean;
|
|
18
|
+
/** One field key per edge; left is ignored while batch selection is active. */
|
|
19
|
+
stickyColumns?: {
|
|
20
|
+
left?: string;
|
|
21
|
+
right?: string;
|
|
22
|
+
};
|
|
23
|
+
/** Pin actions on the right; this takes precedence over stickyColumns.right. */
|
|
24
|
+
stickyActions?: boolean;
|
|
18
25
|
}
|
|
19
26
|
declare const LiteTable: import("svelte").Component<Props, {}, "">;
|
|
20
27
|
type LiteTable = ReturnType<typeof LiteTable>;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,10 @@ export { default as LiteFilterBuilder } from './components/LiteFilterBuilder.sve
|
|
|
22
22
|
export type { FilterRuleItem } from './components/LiteFilterBuilder.svelte';
|
|
23
23
|
export { default as LiteBreadcrumbs } from './components/LiteBreadcrumbs.svelte';
|
|
24
24
|
export { default as LiteStatsCard } from './components/LiteStatsCard.svelte';
|
|
25
|
+
export { default as LiteMetricStrip } from './components/LiteMetricStrip.svelte';
|
|
26
|
+
export type { LiteMetricStripItem, LiteMetricTone, LiteMetricBadgeTone, } from './components/LiteMetricStrip.svelte';
|
|
27
|
+
export { default as LiteBadge } from './components/LiteBadge.svelte';
|
|
28
|
+
export type { LiteBadgeVariant } from './components/LiteBadge.svelte';
|
|
25
29
|
export { default as LiteConfirmDialog } from './components/LiteConfirmDialog.svelte';
|
|
26
30
|
export { default as LiteEmptyState } from './components/LiteEmptyState.svelte';
|
|
27
31
|
export { default as LiteTabs } from './components/LiteTabs.svelte';
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,8 @@ export { default as LiteTransfer } from './components/LiteTransfer.svelte';
|
|
|
24
24
|
export { default as LiteFilterBuilder } from './components/LiteFilterBuilder.svelte';
|
|
25
25
|
export { default as LiteBreadcrumbs } from './components/LiteBreadcrumbs.svelte';
|
|
26
26
|
export { default as LiteStatsCard } from './components/LiteStatsCard.svelte';
|
|
27
|
+
export { default as LiteMetricStrip } from './components/LiteMetricStrip.svelte';
|
|
28
|
+
export { default as LiteBadge } from './components/LiteBadge.svelte';
|
|
27
29
|
export { default as LiteConfirmDialog } from './components/LiteConfirmDialog.svelte';
|
|
28
30
|
export { default as LiteEmptyState } from './components/LiteEmptyState.svelte';
|
|
29
31
|
export { default as LiteTabs } from './components/LiteTabs.svelte';
|
package/dist/lite.css
CHANGED
|
@@ -862,6 +862,22 @@ textarea.lite-input {
|
|
|
862
862
|
overflow-x: auto;
|
|
863
863
|
}
|
|
864
864
|
|
|
865
|
+
.lite-table .lite-table-sticky-left,
|
|
866
|
+
.lite-table .lite-table-sticky-right {
|
|
867
|
+
position: sticky;
|
|
868
|
+
z-index: 2;
|
|
869
|
+
background: #fff;
|
|
870
|
+
}
|
|
871
|
+
.lite-table th.lite-table-sticky-left,
|
|
872
|
+
.lite-table th.lite-table-sticky-right {
|
|
873
|
+
z-index: 3;
|
|
874
|
+
background: #f8fafc;
|
|
875
|
+
}
|
|
876
|
+
.lite-table .lite-table-sticky-left { left: 0; box-shadow: 1px 0 0 #e2e8f0; }
|
|
877
|
+
.lite-table .lite-table-sticky-right { right: 0; box-shadow: -1px 0 0 #e2e8f0; }
|
|
878
|
+
.lite-table tr:hover .lite-table-sticky-left,
|
|
879
|
+
.lite-table tr:hover .lite-table-sticky-right { background: #f8f7fd; }
|
|
880
|
+
|
|
865
881
|
.lite-muted {
|
|
866
882
|
color: #64748b;
|
|
867
883
|
font-size: 12px;
|
|
@@ -1044,6 +1060,70 @@ textarea.lite-input {
|
|
|
1044
1060
|
border-color: #fde68a;
|
|
1045
1061
|
}
|
|
1046
1062
|
|
|
1063
|
+
.lite-badge-subtle {
|
|
1064
|
+
background: #eef2ff;
|
|
1065
|
+
color: #4338ca;
|
|
1066
|
+
border-color: #c7d2fe;
|
|
1067
|
+
}
|
|
1068
|
+
.lite-badge-default { background: #4f46e5; color: #fff; border-color: #4f46e5; }
|
|
1069
|
+
.lite-badge-secondary { background: #f1f5f9; color: #334155; border-color: #e2e8f0; }
|
|
1070
|
+
.lite-badge-destructive,
|
|
1071
|
+
.lite-badge-subtle-destructive { background: #fef2f2; color: #dc2626; border-color: #fecaca; }
|
|
1072
|
+
.lite-badge-subtle-success { background: #f0fdf4; color: #166534; border-color: #bbf7d0; }
|
|
1073
|
+
.lite-badge-subtle-warning { background: #fffbeb; color: #92400e; border-color: #fde68a; }
|
|
1074
|
+
.lite-badge-subtle-pill {
|
|
1075
|
+
border-radius: 999px;
|
|
1076
|
+
background: #f8fafc;
|
|
1077
|
+
color: #475569;
|
|
1078
|
+
font-weight: 500;
|
|
1079
|
+
}
|
|
1080
|
+
.lite-badge-outline { background: transparent; color: #0f172a; }
|
|
1081
|
+
.lite-badge-ghost { background: transparent; border-color: transparent; color: #475569; }
|
|
1082
|
+
.lite-badge-link { padding-left: 0; padding-right: 0; background: transparent; border-color: transparent; color: #4f46e5; text-decoration: underline; }
|
|
1083
|
+
|
|
1084
|
+
/* ─── Metric strip ────────────────────────────────────────── */
|
|
1085
|
+
.lite-metric-strip {
|
|
1086
|
+
display: flex;
|
|
1087
|
+
flex-wrap: wrap;
|
|
1088
|
+
overflow: hidden;
|
|
1089
|
+
border: 1px solid #e2e8f0;
|
|
1090
|
+
border-radius: 8px;
|
|
1091
|
+
background: #e2e8f0;
|
|
1092
|
+
}
|
|
1093
|
+
.lite-metric-item {
|
|
1094
|
+
flex: 1 1 160px;
|
|
1095
|
+
min-width: 0;
|
|
1096
|
+
padding: 14px 16px;
|
|
1097
|
+
background: #fff;
|
|
1098
|
+
color: #0f172a;
|
|
1099
|
+
text-decoration: none;
|
|
1100
|
+
border-right: 1px solid #e2e8f0;
|
|
1101
|
+
border-bottom: 1px solid #e2e8f0;
|
|
1102
|
+
}
|
|
1103
|
+
.lite-metric-item-link:hover { background: #f8fafc; text-decoration: none; }
|
|
1104
|
+
.lite-metric-label,
|
|
1105
|
+
.lite-metric-value-row { display: flex; align-items: center; justify-content: space-between; }
|
|
1106
|
+
.lite-metric-label { color: #64748b; font-size: 12px; font-weight: 600; }
|
|
1107
|
+
.lite-metric-icon { margin-left: 8px; color: #94a3b8; }
|
|
1108
|
+
.lite-metric-icon-svg { width: 14px; height: 14px; }
|
|
1109
|
+
.lite-metric-value { margin-top: 4px; font-size: 23px; line-height: 1.2; color: #0f172a; }
|
|
1110
|
+
.lite-metric-value-primary { color: #4f46e5; }
|
|
1111
|
+
.lite-metric-value-success { color: #16a34a; }
|
|
1112
|
+
.lite-metric-value-warning { color: #d97706; }
|
|
1113
|
+
.lite-metric-value-danger { color: #dc2626; }
|
|
1114
|
+
.lite-metric-value-info { color: #2563eb; }
|
|
1115
|
+
.lite-metric-loading { display: block; width: 64px; height: 24px; margin-top: 6px; background: #e2e8f0; border-radius: 4px; }
|
|
1116
|
+
.lite-metric-trend { margin-left: 8px; font-size: 12px; font-weight: 600; white-space: nowrap; }
|
|
1117
|
+
.lite-metric-trend-up { color: #16a34a; }
|
|
1118
|
+
.lite-metric-trend-down { color: #dc2626; }
|
|
1119
|
+
.lite-metric-trend-label { margin-left: 4px; color: #64748b; font-weight: 400; }
|
|
1120
|
+
.lite-metric-strip-2 .lite-metric-item { flex-basis: 45%; }
|
|
1121
|
+
.lite-metric-strip-3 .lite-metric-item { flex-basis: 30%; }
|
|
1122
|
+
.lite-metric-strip-4 .lite-metric-item { flex-basis: 22%; }
|
|
1123
|
+
.lite-metric-strip-5 .lite-metric-item { flex-basis: 18%; }
|
|
1124
|
+
.lite-metric-strip-6 .lite-metric-item,
|
|
1125
|
+
.lite-metric-strip-auto .lite-metric-item { flex-basis: 15%; }
|
|
1126
|
+
|
|
1047
1127
|
/* ─── Boolean indicator ────────────────────────────────────── */
|
|
1048
1128
|
.lite-bool {
|
|
1049
1129
|
display: inline-block;
|
|
@@ -1317,6 +1397,17 @@ textarea.lite-input {
|
|
|
1317
1397
|
.lite-realtime-status > .lite-btn {
|
|
1318
1398
|
margin-top: 10px;
|
|
1319
1399
|
}
|
|
1400
|
+
.lite-metric-strip-3 .lite-metric-item,
|
|
1401
|
+
.lite-metric-strip-4 .lite-metric-item,
|
|
1402
|
+
.lite-metric-strip-5 .lite-metric-item,
|
|
1403
|
+
.lite-metric-strip-6 .lite-metric-item,
|
|
1404
|
+
.lite-metric-strip-auto .lite-metric-item {
|
|
1405
|
+
flex-basis: 45%;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
@media (max-width: 420px) {
|
|
1410
|
+
.lite-metric-strip .lite-metric-item { flex-basis: 100%; }
|
|
1320
1411
|
}
|
|
1321
1412
|
|
|
1322
1413
|
/* ─── Print ────────────────────────────────────────────────── */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/lite",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "SSR-first lightweight admin UI for @svadmin with optional progressive enhancement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"svelte": "^5.56.10",
|
|
52
|
-
"@svadmin/core": ">=0.34.2 <0.
|
|
52
|
+
"@svadmin/core": ">=0.34.2 <0.50.0",
|
|
53
53
|
"@sveltejs/kit": "^2.70.3"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|