@svadmin/lite 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +190 -9
- package/dist/compatibility.d.ts +23 -0
- package/dist/compatibility.js +95 -0
- package/dist/components/LiteDynamicFormList.svelte +169 -0
- package/dist/components/LiteDynamicFormList.svelte.d.ts +45 -0
- package/dist/components/LiteFilterBuilder.svelte +205 -0
- package/dist/components/LiteFilterBuilder.svelte.d.ts +19 -0
- package/dist/components/LiteShowField.svelte +52 -22
- package/dist/components/LiteShowField.svelte.d.ts +3 -2
- package/dist/components/LiteTable.svelte +89 -36
- package/dist/components/LiteTable.svelte.d.ts +3 -2
- package/dist/components/LiteTransfer.svelte +185 -0
- package/dist/components/LiteTransfer.svelte.d.ts +18 -0
- package/dist/components/compatibility/LiteCapabilityBoundary.svelte +51 -0
- package/dist/components/compatibility/LiteCapabilityBoundary.svelte.d.ts +13 -0
- package/dist/components/compatibility/LiteClipboardFallback.svelte +16 -0
- package/dist/components/compatibility/LiteClipboardFallback.svelte.d.ts +8 -0
- package/dist/components/compatibility/LiteComputeFallback.svelte +50 -0
- package/dist/components/compatibility/LiteComputeFallback.svelte.d.ts +14 -0
- package/dist/components/compatibility/LiteDirectoryUpload.svelte +44 -0
- package/dist/components/compatibility/LiteDirectoryUpload.svelte.d.ts +11 -0
- package/dist/components/compatibility/LiteOrderedList.svelte +47 -0
- package/dist/components/compatibility/LiteOrderedList.svelte.d.ts +14 -0
- package/dist/components/compatibility/LiteRealtimeStatus.svelte +43 -0
- package/dist/components/compatibility/LiteRealtimeStatus.svelte.d.ts +11 -0
- package/dist/components/compatibility/LiteVisualFallback.svelte +80 -0
- package/dist/components/compatibility/LiteVisualFallback.svelte.d.ts +18 -0
- package/dist/components/compatibility/index.d.ts +7 -0
- package/dist/components/compatibility/index.js +7 -0
- package/dist/components/fields/LiteAvatarField.svelte +127 -0
- package/dist/components/fields/LiteAvatarField.svelte.d.ts +21 -0
- package/dist/components/fields/LiteCascader.svelte +119 -0
- package/dist/components/fields/LiteCascader.svelte.d.ts +24 -0
- package/dist/components/fields/LiteCodeField.svelte +71 -0
- package/dist/components/fields/LiteCodeField.svelte.d.ts +16 -0
- package/dist/components/fields/LiteCopyField.svelte +74 -0
- package/dist/components/fields/LiteCopyField.svelte.d.ts +18 -0
- package/dist/components/fields/LiteCurrencyField.svelte +126 -0
- package/dist/components/fields/LiteCurrencyField.svelte.d.ts +21 -0
- package/dist/components/fields/LiteDateRangeField.svelte +147 -0
- package/dist/components/fields/LiteDateRangeField.svelte.d.ts +26 -0
- package/dist/components/fields/LitePercentField.svelte +124 -0
- package/dist/components/fields/LitePercentField.svelte.d.ts +17 -0
- package/dist/components/fields/LitePhoneField.svelte +81 -0
- package/dist/components/fields/LitePhoneField.svelte.d.ts +17 -0
- package/dist/components/fields/LiteRatingField.svelte +105 -0
- package/dist/components/fields/LiteRatingField.svelte.d.ts +16 -0
- package/dist/components/fields/LiteTreeSelect.svelte +143 -0
- package/dist/components/fields/LiteTreeSelect.svelte.d.ts +23 -0
- package/dist/components/fields/index.d.ts +12 -0
- package/dist/components/fields/index.js +10 -0
- package/dist/components/pages/LiteCreatePage.svelte +15 -6
- package/dist/components/pages/LiteCreatePage.svelte.d.ts +1 -1
- package/dist/components/pages/LiteEditPage.svelte +18 -9
- package/dist/components/pages/LiteEditPage.svelte.d.ts +1 -1
- package/dist/components/pages/LiteListPage.svelte +99 -27
- package/dist/components/pages/LiteListPage.svelte.d.ts +4 -2
- package/dist/components/pages/LiteShowPage.svelte +19 -10
- package/dist/components/pages/LiteShowPage.svelte.d.ts +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +8 -1
- package/dist/lite.css +444 -0
- package/dist/schema-generator.js +15 -4
- package/dist/server-adapter.d.ts +18 -1
- package/dist/server-adapter.js +73 -16
- package/package.json +5 -4
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { t } from '@svadmin/core/i18n';
|
|
3
|
+
|
|
4
|
+
export interface TransferItem {
|
|
5
|
+
key: string | number;
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
dataSource?: TransferItem[];
|
|
13
|
+
targetKeys?: (string | number)[];
|
|
14
|
+
titles?: [string, string];
|
|
15
|
+
name?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
label?: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
dataSource = [],
|
|
23
|
+
targetKeys = [],
|
|
24
|
+
titles = ['Available', 'Selected'],
|
|
25
|
+
name = 'targetKeys',
|
|
26
|
+
disabled = false,
|
|
27
|
+
label,
|
|
28
|
+
description,
|
|
29
|
+
}: Props = $props();
|
|
30
|
+
|
|
31
|
+
const targetKeySet = $derived(new Set(targetKeys.map(String)));
|
|
32
|
+
const sourceItems = $derived(dataSource.filter((item) => !targetKeySet.has(String(item.key))));
|
|
33
|
+
const targetItems = $derived(dataSource.filter((item) => targetKeySet.has(String(item.key))));
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<div class="lite-transfer-container lite-form-group">
|
|
37
|
+
{#if label}
|
|
38
|
+
<span class="lite-label">{label}</span>
|
|
39
|
+
{/if}
|
|
40
|
+
{#if description}
|
|
41
|
+
<p class="lite-help-text">{description}</p>
|
|
42
|
+
{/if}
|
|
43
|
+
|
|
44
|
+
<div class="lite-transfer-boxes">
|
|
45
|
+
<!-- Source Box -->
|
|
46
|
+
<div class="lite-transfer-panel">
|
|
47
|
+
<div class="lite-transfer-header">
|
|
48
|
+
<strong>{titles[0]}</strong>
|
|
49
|
+
<span class="lite-badge">{sourceItems.length}</span>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="lite-transfer-body">
|
|
52
|
+
{#if sourceItems.length === 0}
|
|
53
|
+
<div class="lite-transfer-empty">{t('common.empty') || 'No items'}</div>
|
|
54
|
+
{:else}
|
|
55
|
+
{#each sourceItems as item (item.key)}
|
|
56
|
+
<label class="lite-transfer-item">
|
|
57
|
+
<input
|
|
58
|
+
type="checkbox"
|
|
59
|
+
name="_transfer_source_keys"
|
|
60
|
+
value={String(item.key)}
|
|
61
|
+
disabled={disabled || item.disabled}
|
|
62
|
+
/>
|
|
63
|
+
<span class="lite-transfer-item-title">{item.title}</span>
|
|
64
|
+
</label>
|
|
65
|
+
{/each}
|
|
66
|
+
{/if}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<!-- Move Actions -->
|
|
71
|
+
<div class="lite-transfer-operations">
|
|
72
|
+
<button
|
|
73
|
+
type="submit"
|
|
74
|
+
name="_action"
|
|
75
|
+
value="transfer_to_target"
|
|
76
|
+
class="lite-btn lite-btn-sm lite-btn-primary"
|
|
77
|
+
{disabled}
|
|
78
|
+
title="Move selected right"
|
|
79
|
+
>
|
|
80
|
+
→
|
|
81
|
+
</button>
|
|
82
|
+
<button
|
|
83
|
+
type="submit"
|
|
84
|
+
name="_action"
|
|
85
|
+
value="transfer_to_source"
|
|
86
|
+
class="lite-btn lite-btn-sm"
|
|
87
|
+
{disabled}
|
|
88
|
+
title="Move selected left"
|
|
89
|
+
>
|
|
90
|
+
←
|
|
91
|
+
</button>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<!-- Target Box -->
|
|
95
|
+
<div class="lite-transfer-panel">
|
|
96
|
+
<div class="lite-transfer-header">
|
|
97
|
+
<strong>{titles[1]}</strong>
|
|
98
|
+
<span class="lite-badge lite-badge-indigo">{targetItems.length}</span>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="lite-transfer-body">
|
|
101
|
+
{#if targetItems.length === 0}
|
|
102
|
+
<div class="lite-transfer-empty">{t('common.empty') || 'No items selected'}</div>
|
|
103
|
+
{:else}
|
|
104
|
+
{#each targetItems as item (item.key)}
|
|
105
|
+
<label class="lite-transfer-item">
|
|
106
|
+
<input
|
|
107
|
+
type="checkbox"
|
|
108
|
+
name="_transfer_target_keys"
|
|
109
|
+
value={String(item.key)}
|
|
110
|
+
disabled={disabled || item.disabled}
|
|
111
|
+
/>
|
|
112
|
+
<input type="hidden" {name} value={String(item.key)} />
|
|
113
|
+
<span class="lite-transfer-item-title">{item.title}</span>
|
|
114
|
+
</label>
|
|
115
|
+
{/each}
|
|
116
|
+
{/if}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<style>
|
|
123
|
+
.lite-transfer-container {
|
|
124
|
+
margin-bottom: 16px;
|
|
125
|
+
}
|
|
126
|
+
.lite-transfer-boxes {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
}
|
|
130
|
+
.lite-transfer-panel {
|
|
131
|
+
flex: 1;
|
|
132
|
+
border: 1px solid #cbd5e1;
|
|
133
|
+
border-radius: 6px;
|
|
134
|
+
background: #ffffff;
|
|
135
|
+
min-height: 180px;
|
|
136
|
+
max-height: 280px;
|
|
137
|
+
display: flex;
|
|
138
|
+
flex-direction: column;
|
|
139
|
+
}
|
|
140
|
+
.lite-transfer-header {
|
|
141
|
+
display: flex;
|
|
142
|
+
justify-content: space-between;
|
|
143
|
+
align-items: center;
|
|
144
|
+
padding: 8px 12px;
|
|
145
|
+
background: #f8fafc;
|
|
146
|
+
border-bottom: 1px solid #e2e8f0;
|
|
147
|
+
font-size: 13px;
|
|
148
|
+
}
|
|
149
|
+
.lite-transfer-body {
|
|
150
|
+
flex: 1;
|
|
151
|
+
overflow-y: auto;
|
|
152
|
+
padding: 6px;
|
|
153
|
+
}
|
|
154
|
+
.lite-transfer-item {
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
padding: 6px 8px;
|
|
158
|
+
border-radius: 4px;
|
|
159
|
+
cursor: pointer;
|
|
160
|
+
font-size: 13px;
|
|
161
|
+
}
|
|
162
|
+
.lite-transfer-item:hover {
|
|
163
|
+
background: #f1f5f9;
|
|
164
|
+
}
|
|
165
|
+
.lite-transfer-item input {
|
|
166
|
+
margin-right: 8px;
|
|
167
|
+
}
|
|
168
|
+
.lite-transfer-operations {
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
margin: 0 12px;
|
|
172
|
+
}
|
|
173
|
+
.lite-transfer-operations .lite-btn:first-child {
|
|
174
|
+
margin-bottom: 6px;
|
|
175
|
+
}
|
|
176
|
+
.lite-transfer-boxes > .lite-transfer-panel:first-child {
|
|
177
|
+
margin-right: 0;
|
|
178
|
+
}
|
|
179
|
+
.lite-transfer-empty {
|
|
180
|
+
text-align: center;
|
|
181
|
+
padding: 30px 10px;
|
|
182
|
+
color: #94a3b8;
|
|
183
|
+
font-size: 12px;
|
|
184
|
+
}
|
|
185
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface TransferItem {
|
|
2
|
+
key: string | number;
|
|
3
|
+
title: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
interface Props {
|
|
8
|
+
dataSource?: TransferItem[];
|
|
9
|
+
targetKeys?: (string | number)[];
|
|
10
|
+
titles?: [string, string];
|
|
11
|
+
name?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
label?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const LiteTransfer: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type LiteTransfer = ReturnType<typeof LiteTransfer>;
|
|
18
|
+
export default LiteTransfer;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { LiteCapability, LiteFallbackKind } from '../../compatibility';
|
|
4
|
+
import { detectLiteCapabilities, resolveLiteCompatibility } from '../../compatibility';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
capability: LiteCapability;
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
fallback?: Snippet;
|
|
11
|
+
children?: Snippet;
|
|
12
|
+
enhanced?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { capability, title, description, fallback, children, enhanced = false }: Props = $props();
|
|
16
|
+
const resolution = $derived(resolveLiteCompatibility(capability, {
|
|
17
|
+
...detectLiteCapabilities(null),
|
|
18
|
+
[capability]: enhanced,
|
|
19
|
+
}));
|
|
20
|
+
const kindLabel: Record<LiteFallbackKind, string> = {
|
|
21
|
+
'structured-data': 'Structured view',
|
|
22
|
+
'static-snapshot': 'Static snapshot',
|
|
23
|
+
'server-action': 'Server action',
|
|
24
|
+
'server-refresh': 'Server refresh',
|
|
25
|
+
'server-pagination': 'Server pagination',
|
|
26
|
+
'standard-upload': 'Standard upload',
|
|
27
|
+
'manual-copy': 'Manual copy',
|
|
28
|
+
'server-storage': 'Server storage',
|
|
29
|
+
'in-page-status': 'In-page status',
|
|
30
|
+
download: 'Download',
|
|
31
|
+
};
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<section class="lite-compatibility" data-lite-capability={capability} data-lite-mode={resolution.mode}>
|
|
35
|
+
<div class="lite-compatibility-header">
|
|
36
|
+
<div>
|
|
37
|
+
<h2>{title ?? capability}</h2>
|
|
38
|
+
{#if description}<p>{description}</p>{/if}
|
|
39
|
+
</div>
|
|
40
|
+
<span class="lite-badge lite-badge-info">{kindLabel[resolution.fallbackKind]}</span>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="lite-compatibility-body">
|
|
43
|
+
{#if resolution.mode === 'enhanced' && children}
|
|
44
|
+
{@render children()}
|
|
45
|
+
{:else if fallback}
|
|
46
|
+
{@render fallback()}
|
|
47
|
+
{:else}
|
|
48
|
+
<p>{resolution.fallback}</p>
|
|
49
|
+
{/if}
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { LiteCapability } from '../../compatibility';
|
|
3
|
+
interface Props {
|
|
4
|
+
capability: LiteCapability;
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
fallback?: Snippet;
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
enhanced?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const LiteCapabilityBoundary: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type LiteCapabilityBoundary = ReturnType<typeof LiteCapabilityBoundary>;
|
|
13
|
+
export default LiteCapabilityBoundary;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
value: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
rows?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let { value, label = 'Copy value', rows = 4 }: Props = $props();
|
|
9
|
+
const controlId = $props.id();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div class="lite-form-group lite-clipboard-fallback">
|
|
13
|
+
<label for={controlId}>{label}</label>
|
|
14
|
+
<textarea id={controlId} class="lite-input" readonly {rows}>{value}</textarea>
|
|
15
|
+
<p class="lite-muted">Select the text and use the browser command for manual copy.</p>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
rows?: number;
|
|
5
|
+
}
|
|
6
|
+
declare const LiteClipboardFallback: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type LiteClipboardFallback = ReturnType<typeof LiteClipboardFallback>;
|
|
8
|
+
export default LiteClipboardFallback;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { toSafeHref } from '../../security';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
action: string;
|
|
8
|
+
actionLabel?: string;
|
|
9
|
+
status?: string;
|
|
10
|
+
engine?: string;
|
|
11
|
+
values?: Record<string, string | number | boolean>;
|
|
12
|
+
downloadHref?: string;
|
|
13
|
+
downloadLabel?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
title = 'Server computation',
|
|
18
|
+
description = 'This task runs through a normal server request when browser compute is unavailable.',
|
|
19
|
+
action,
|
|
20
|
+
actionLabel = 'Run task',
|
|
21
|
+
status = 'Ready',
|
|
22
|
+
engine = 'Server',
|
|
23
|
+
values = {},
|
|
24
|
+
downloadHref,
|
|
25
|
+
downloadLabel = 'Download result',
|
|
26
|
+
}: Props = $props();
|
|
27
|
+
|
|
28
|
+
const safeAction = $derived(toSafeHref(action));
|
|
29
|
+
const safeDownloadHref = $derived(toSafeHref(downloadHref));
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<section class="lite-card lite-compute-fallback">
|
|
33
|
+
<div class="lite-section-header">
|
|
34
|
+
<div><h2>{title}</h2><p>{description}</p></div>
|
|
35
|
+
<span class="lite-badge">{engine}: {status}</span>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="lite-inline-actions">
|
|
38
|
+
{#if safeAction}
|
|
39
|
+
<form method="POST" action={safeAction}>
|
|
40
|
+
{#each Object.entries(values) as [name, value] (name)}
|
|
41
|
+
<input type="hidden" {name} value={String(value)} />
|
|
42
|
+
{/each}
|
|
43
|
+
<button class="lite-btn lite-btn-primary" type="submit">{actionLabel}</button>
|
|
44
|
+
</form>
|
|
45
|
+
{:else}
|
|
46
|
+
<button class="lite-btn lite-btn-primary" type="button" disabled>{actionLabel}</button>
|
|
47
|
+
{/if}
|
|
48
|
+
{#if safeDownloadHref}<a class="lite-btn" href={safeDownloadHref}>{downloadLabel}</a>{/if}
|
|
49
|
+
</div>
|
|
50
|
+
</section>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
description?: string;
|
|
4
|
+
action: string;
|
|
5
|
+
actionLabel?: string;
|
|
6
|
+
status?: string;
|
|
7
|
+
engine?: string;
|
|
8
|
+
values?: Record<string, string | number | boolean>;
|
|
9
|
+
downloadHref?: string;
|
|
10
|
+
downloadLabel?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const LiteComputeFallback: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type LiteComputeFallback = ReturnType<typeof LiteComputeFallback>;
|
|
14
|
+
export default LiteComputeFallback;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
name?: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
accept?: string;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
zipName?: string;
|
|
8
|
+
helpText?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
name = 'files',
|
|
13
|
+
label = 'Files or folder',
|
|
14
|
+
accept,
|
|
15
|
+
disabled = false,
|
|
16
|
+
zipName = 'archive',
|
|
17
|
+
helpText = 'Select a folder where supported, choose multiple files, or upload a ZIP archive.',
|
|
18
|
+
}: Props = $props();
|
|
19
|
+
|
|
20
|
+
const controlId = $props.id();
|
|
21
|
+
const directoryAttributes = { webkitdirectory: true, directory: true };
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<fieldset class="lite-directory-upload">
|
|
25
|
+
<legend>{label}</legend>
|
|
26
|
+
<p class="lite-muted">{helpText}</p>
|
|
27
|
+
<div class="lite-form-group">
|
|
28
|
+
<label for={controlId}>{label}</label>
|
|
29
|
+
<input
|
|
30
|
+
id={controlId}
|
|
31
|
+
class="lite-input"
|
|
32
|
+
type="file"
|
|
33
|
+
{name}
|
|
34
|
+
{accept}
|
|
35
|
+
{disabled}
|
|
36
|
+
multiple
|
|
37
|
+
{...directoryAttributes}
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="lite-form-group">
|
|
41
|
+
<label for={`${controlId}-zip`}>ZIP archive fallback</label>
|
|
42
|
+
<input id={`${controlId}-zip`} class="lite-input" type="file" name={zipName} accept=".zip,application/zip" {disabled} />
|
|
43
|
+
</div>
|
|
44
|
+
</fieldset>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
name?: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
accept?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
zipName?: string;
|
|
7
|
+
helpText?: string;
|
|
8
|
+
}
|
|
9
|
+
declare const LiteDirectoryUpload: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type LiteDirectoryUpload = ReturnType<typeof LiteDirectoryUpload>;
|
|
11
|
+
export default LiteDirectoryUpload;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { toSafeHref } from '../../security';
|
|
3
|
+
|
|
4
|
+
interface Item {
|
|
5
|
+
id: string | number;
|
|
6
|
+
label: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
items: Item[];
|
|
12
|
+
action: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
itemName?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let { items, action, title = 'Ordered items', itemName = 'itemId' }: Props = $props();
|
|
18
|
+
const safeAction = $derived(toSafeHref(action));
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<section class="lite-card lite-ordered-list">
|
|
22
|
+
<h2>{title}</h2>
|
|
23
|
+
<ol>
|
|
24
|
+
{#each items as item, index (item.id)}
|
|
25
|
+
<li>
|
|
26
|
+
<div><strong>{item.label}</strong>{#if item.description}<span>{item.description}</span>{/if}</div>
|
|
27
|
+
<div class="lite-inline-actions">
|
|
28
|
+
{#if safeAction}
|
|
29
|
+
<form method="POST" action={safeAction}>
|
|
30
|
+
<input type="hidden" name={itemName} value={String(item.id)} />
|
|
31
|
+
<input type="hidden" name="direction" value="up" />
|
|
32
|
+
<button class="lite-btn lite-btn-sm" type="submit" disabled={index === 0}>Move up</button>
|
|
33
|
+
</form>
|
|
34
|
+
<form method="POST" action={safeAction}>
|
|
35
|
+
<input type="hidden" name={itemName} value={String(item.id)} />
|
|
36
|
+
<input type="hidden" name="direction" value="down" />
|
|
37
|
+
<button class="lite-btn lite-btn-sm" type="submit" disabled={index === items.length - 1}>Move down</button>
|
|
38
|
+
</form>
|
|
39
|
+
{:else}
|
|
40
|
+
<button class="lite-btn lite-btn-sm" type="button" disabled>Move up</button>
|
|
41
|
+
<button class="lite-btn lite-btn-sm" type="button" disabled>Move down</button>
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
</li>
|
|
45
|
+
{/each}
|
|
46
|
+
</ol>
|
|
47
|
+
</section>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Item {
|
|
2
|
+
id: string | number;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
interface Props {
|
|
7
|
+
items: Item[];
|
|
8
|
+
action: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
itemName?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const LiteOrderedList: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type LiteOrderedList = ReturnType<typeof LiteOrderedList>;
|
|
14
|
+
export default LiteOrderedList;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { toSafeHref } from '../../security';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
title?: string;
|
|
6
|
+
status?: string;
|
|
7
|
+
lastUpdated?: string;
|
|
8
|
+
refreshHref?: string;
|
|
9
|
+
refreshLabel?: string;
|
|
10
|
+
refreshSeconds?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
title = 'Live status',
|
|
15
|
+
status = 'Snapshot',
|
|
16
|
+
lastUpdated,
|
|
17
|
+
refreshHref = '',
|
|
18
|
+
refreshLabel = 'Refresh status',
|
|
19
|
+
refreshSeconds = 0,
|
|
20
|
+
}: Props = $props();
|
|
21
|
+
|
|
22
|
+
const safeRefreshSeconds = $derived(
|
|
23
|
+
Number.isFinite(refreshSeconds) && refreshSeconds >= 5
|
|
24
|
+
? Math.floor(refreshSeconds)
|
|
25
|
+
: 0,
|
|
26
|
+
);
|
|
27
|
+
const safeRefreshHref = $derived(toSafeHref(refreshHref));
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<svelte:head>
|
|
31
|
+
{#if safeRefreshSeconds > 0 && safeRefreshHref}
|
|
32
|
+
<meta http-equiv="refresh" content={`${safeRefreshSeconds}; url=${safeRefreshHref}`} />
|
|
33
|
+
{/if}
|
|
34
|
+
</svelte:head>
|
|
35
|
+
|
|
36
|
+
<section class="lite-realtime-status" aria-live="polite">
|
|
37
|
+
<div>
|
|
38
|
+
<strong>{title}</strong>
|
|
39
|
+
<span class="lite-badge lite-badge-info">{status}</span>
|
|
40
|
+
{#if lastUpdated}<span class="lite-muted">Updated {lastUpdated}</span>{/if}
|
|
41
|
+
</div>
|
|
42
|
+
{#if safeRefreshHref}<a href={safeRefreshHref} class="lite-btn lite-btn-sm">{refreshLabel}</a>{/if}
|
|
43
|
+
</section>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
title?: string;
|
|
3
|
+
status?: string;
|
|
4
|
+
lastUpdated?: string;
|
|
5
|
+
refreshHref?: string;
|
|
6
|
+
refreshLabel?: string;
|
|
7
|
+
refreshSeconds?: number;
|
|
8
|
+
}
|
|
9
|
+
declare const LiteRealtimeStatus: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type LiteRealtimeStatus = ReturnType<typeof LiteRealtimeStatus>;
|
|
11
|
+
export default LiteRealtimeStatus;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { toSafeHref } from '../../security';
|
|
3
|
+
|
|
4
|
+
interface Column {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
snapshotSrc?: string;
|
|
13
|
+
snapshotAlt?: string;
|
|
14
|
+
columns?: Column[];
|
|
15
|
+
rows?: Record<string, unknown>[];
|
|
16
|
+
downloadHref?: string;
|
|
17
|
+
downloadLabel?: string;
|
|
18
|
+
emptyLabel?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let {
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
snapshotSrc,
|
|
25
|
+
snapshotAlt = '',
|
|
26
|
+
columns = [],
|
|
27
|
+
rows = [],
|
|
28
|
+
downloadHref,
|
|
29
|
+
downloadLabel = 'Download source data',
|
|
30
|
+
emptyLabel = 'No structured data is available.',
|
|
31
|
+
}: Props = $props();
|
|
32
|
+
|
|
33
|
+
function displayValue(value: unknown): string {
|
|
34
|
+
if (value == null) return '-';
|
|
35
|
+
if (Array.isArray(value)) return value.map(String).join(', ');
|
|
36
|
+
if (typeof value === 'object') {
|
|
37
|
+
try {
|
|
38
|
+
return JSON.stringify(value);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error instanceof TypeError) return String(value);
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return String(value);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const safeSnapshotSrc = $derived(toSafeHref(snapshotSrc));
|
|
48
|
+
const safeDownloadHref = $derived(toSafeHref(downloadHref));
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<section class="lite-card lite-visual-fallback">
|
|
52
|
+
<div class="lite-section-header">
|
|
53
|
+
<div>
|
|
54
|
+
<h2>{title}</h2>
|
|
55
|
+
{#if description}<p>{description}</p>{/if}
|
|
56
|
+
</div>
|
|
57
|
+
{#if safeDownloadHref}<a class="lite-btn lite-btn-sm" href={safeDownloadHref}>{downloadLabel}</a>{/if}
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
{#if safeSnapshotSrc}
|
|
61
|
+
<div class="lite-visual-snapshot">
|
|
62
|
+
<img src={safeSnapshotSrc} alt={snapshotAlt} />
|
|
63
|
+
</div>
|
|
64
|
+
{/if}
|
|
65
|
+
|
|
66
|
+
{#if columns.length > 0 && rows.length > 0}
|
|
67
|
+
<div class="lite-table-scroll">
|
|
68
|
+
<table class="lite-table">
|
|
69
|
+
<thead><tr>{#each columns as column (column.key)}<th>{column.label}</th>{/each}</tr></thead>
|
|
70
|
+
<tbody>
|
|
71
|
+
{#each rows as row, rowIndex (rowIndex)}
|
|
72
|
+
<tr>{#each columns as column (column.key)}<td>{displayValue(row[column.key])}</td>{/each}</tr>
|
|
73
|
+
{/each}
|
|
74
|
+
</tbody>
|
|
75
|
+
</table>
|
|
76
|
+
</div>
|
|
77
|
+
{:else if !safeSnapshotSrc}
|
|
78
|
+
<p class="lite-muted">{emptyLabel}</p>
|
|
79
|
+
{/if}
|
|
80
|
+
</section>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface Column {
|
|
2
|
+
key: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
interface Props {
|
|
6
|
+
title: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
snapshotSrc?: string;
|
|
9
|
+
snapshotAlt?: string;
|
|
10
|
+
columns?: Column[];
|
|
11
|
+
rows?: Record<string, unknown>[];
|
|
12
|
+
downloadHref?: string;
|
|
13
|
+
downloadLabel?: string;
|
|
14
|
+
emptyLabel?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const LiteVisualFallback: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type LiteVisualFallback = ReturnType<typeof LiteVisualFallback>;
|
|
18
|
+
export default LiteVisualFallback;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as LiteCapabilityBoundary } from './LiteCapabilityBoundary.svelte';
|
|
2
|
+
export { default as LiteClipboardFallback } from './LiteClipboardFallback.svelte';
|
|
3
|
+
export { default as LiteComputeFallback } from './LiteComputeFallback.svelte';
|
|
4
|
+
export { default as LiteDirectoryUpload } from './LiteDirectoryUpload.svelte';
|
|
5
|
+
export { default as LiteOrderedList } from './LiteOrderedList.svelte';
|
|
6
|
+
export { default as LiteRealtimeStatus } from './LiteRealtimeStatus.svelte';
|
|
7
|
+
export { default as LiteVisualFallback } from './LiteVisualFallback.svelte';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as LiteCapabilityBoundary } from './LiteCapabilityBoundary.svelte';
|
|
2
|
+
export { default as LiteClipboardFallback } from './LiteClipboardFallback.svelte';
|
|
3
|
+
export { default as LiteComputeFallback } from './LiteComputeFallback.svelte';
|
|
4
|
+
export { default as LiteDirectoryUpload } from './LiteDirectoryUpload.svelte';
|
|
5
|
+
export { default as LiteOrderedList } from './LiteOrderedList.svelte';
|
|
6
|
+
export { default as LiteRealtimeStatus } from './LiteRealtimeStatus.svelte';
|
|
7
|
+
export { default as LiteVisualFallback } from './LiteVisualFallback.svelte';
|