@smartnet360/svelte-components 0.0.123 → 0.0.125

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 (36) hide show
  1. package/dist/apps/antenna-tools/components/AntennaControls.svelte +71 -9
  2. package/dist/apps/antenna-tools/components/AntennaControls.svelte.d.ts +2 -0
  3. package/dist/apps/antenna-tools/components/AntennaSettingsModal.svelte +4 -174
  4. package/dist/apps/antenna-tools/components/AntennaTools.svelte +48 -82
  5. package/dist/apps/antenna-tools/components/DatabaseViewer.svelte +5 -8
  6. package/dist/apps/antenna-tools/components/MSIConverter.svelte +377 -52
  7. package/dist/apps/antenna-tools/db.js +4 -0
  8. package/dist/apps/antenna-tools/utils/db-utils.d.ts +19 -0
  9. package/dist/apps/antenna-tools/utils/db-utils.js +108 -0
  10. package/dist/apps/antenna-tools/utils/msi-parser.d.ts +35 -1
  11. package/dist/apps/antenna-tools/utils/msi-parser.js +105 -35
  12. package/dist/core/Auth/LoginForm.svelte +397 -0
  13. package/dist/core/Auth/LoginForm.svelte.d.ts +16 -0
  14. package/dist/core/Auth/auth.svelte.d.ts +22 -0
  15. package/dist/core/Auth/auth.svelte.js +184 -0
  16. package/dist/core/Auth/config.d.ts +25 -0
  17. package/dist/core/Auth/config.js +256 -0
  18. package/dist/core/Auth/index.d.ts +4 -0
  19. package/dist/core/Auth/index.js +5 -0
  20. package/dist/core/Auth/types.d.ts +140 -0
  21. package/dist/core/Auth/types.js +2 -0
  22. package/dist/core/Benchmark/Benchmark.svelte +662 -0
  23. package/dist/core/Benchmark/Benchmark.svelte.d.ts +3 -0
  24. package/dist/core/Benchmark/benchmark-utils.d.ts +48 -0
  25. package/dist/core/Benchmark/benchmark-utils.js +80 -0
  26. package/dist/core/Benchmark/index.d.ts +2 -0
  27. package/dist/core/Benchmark/index.js +3 -0
  28. package/dist/core/LandingPage/App.svelte +102 -0
  29. package/dist/core/LandingPage/App.svelte.d.ts +20 -0
  30. package/dist/core/LandingPage/LandingPage.svelte +480 -0
  31. package/dist/core/LandingPage/LandingPage.svelte.d.ts +21 -0
  32. package/dist/core/LandingPage/index.d.ts +2 -0
  33. package/dist/core/LandingPage/index.js +3 -0
  34. package/dist/core/index.d.ts +3 -0
  35. package/dist/core/index.js +6 -0
  36. package/package.json +1 -1
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Benchmark utilities for measuring Svelte reactivity performance
3
+ */
4
+ /**
5
+ * Generate test data array
6
+ */
7
+ export function generateTestData(count) {
8
+ const categories = ['A', 'B', 'C', 'D', 'E'];
9
+ const items = [];
10
+ for (let i = 0; i < count; i++) {
11
+ items.push({
12
+ id: i,
13
+ name: `Item ${i}`,
14
+ value: Math.random() * 1000,
15
+ category: categories[i % categories.length],
16
+ active: i % 2 === 0,
17
+ data: Array.from({ length: 10 }, () => Math.random() * 100)
18
+ });
19
+ }
20
+ return items;
21
+ }
22
+ /**
23
+ * Measure execution time of a function
24
+ */
25
+ export function measure(fn) {
26
+ const start = performance.now();
27
+ const result = fn();
28
+ const duration = performance.now() - start;
29
+ return { result, duration };
30
+ }
31
+ /**
32
+ * Measure async execution time
33
+ */
34
+ export async function measureAsync(fn) {
35
+ const start = performance.now();
36
+ const result = await fn();
37
+ const duration = performance.now() - start;
38
+ return { result, duration };
39
+ }
40
+ /**
41
+ * Format duration for display
42
+ */
43
+ export function formatDuration(ms) {
44
+ if (ms < 1) {
45
+ return `${(ms * 1000).toFixed(2)} µs`;
46
+ }
47
+ else if (ms < 1000) {
48
+ return `${ms.toFixed(2)} ms`;
49
+ }
50
+ else {
51
+ return `${(ms / 1000).toFixed(2)} s`;
52
+ }
53
+ }
54
+ /**
55
+ * Create a detailed log entry
56
+ */
57
+ export function logBenchmark(result) {
58
+ const opsFormatted = result.opsPerSecond > 1000
59
+ ? `${(result.opsPerSecond / 1000).toFixed(2)}K ops/s`
60
+ : `${result.opsPerSecond.toFixed(2)} ops/s`;
61
+ console.log(`%c[BENCHMARK] ${result.name}%c\n` +
62
+ ` Duration: ${formatDuration(result.duration)}\n` +
63
+ ` Items: ${result.itemCount.toLocaleString()}\n` +
64
+ ` Performance: ${opsFormatted}`, 'color: #4CAF50; font-weight: bold;', 'color: inherit;');
65
+ }
66
+ /**
67
+ * Run a benchmark and return result
68
+ */
69
+ export function runBenchmark(name, fn, itemCount) {
70
+ const { duration } = measure(fn);
71
+ const result = {
72
+ name,
73
+ duration,
74
+ itemCount,
75
+ opsPerSecond: (itemCount / duration) * 1000,
76
+ timestamp: new Date()
77
+ };
78
+ logBenchmark(result);
79
+ return result;
80
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Benchmark } from './Benchmark.svelte';
2
+ export * from './benchmark-utils';
@@ -0,0 +1,3 @@
1
+ // Benchmark component for testing Svelte reactivity performance
2
+ export { default as Benchmark } from './Benchmark.svelte';
3
+ export * from './benchmark-utils';
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import { browser } from '$app/environment';
3
+ import { LoginForm } from '../Auth/index.js';
4
+ import { LandingPage } from '../LandingPage/index.js';
5
+ import { createAuthState } from '../Auth/auth.svelte.js';
6
+ import { getDevConfig, isDevMode, DEFAULT_CATEGORIES, DEFAULT_APPS } from '../Auth/config.js';
7
+ import type { CategoryInfo, AppDefinition, AuthConfig } from '../Auth/types.js';
8
+
9
+ interface Props {
10
+ /** Page title */
11
+ title?: string;
12
+ /** Page subtitle */
13
+ subtitle?: string;
14
+ /** Logo URL */
15
+ logo?: string;
16
+ /** Categories to display */
17
+ categories?: CategoryInfo[];
18
+ /** Apps to display */
19
+ apps?: AppDefinition[];
20
+ /** Auth configuration */
21
+ authConfig?: Partial<AuthConfig>;
22
+ /** Force dev mode (auto-login) */
23
+ forceDevMode?: boolean;
24
+ }
25
+
26
+ let {
27
+ title = 'RF Tool Components',
28
+ subtitle = 'Network Planning and Visualization Suite',
29
+ logo,
30
+ categories = DEFAULT_CATEGORIES,
31
+ apps = DEFAULT_APPS,
32
+ authConfig = {},
33
+ forceDevMode = false
34
+ }: Props = $props();
35
+
36
+ // Create auth state
37
+ const auth = createAuthState(authConfig);
38
+
39
+ // Auto-login in dev mode
40
+ const devMode = forceDevMode || isDevMode();
41
+
42
+ $effect(() => {
43
+ if (browser && devMode && !auth.isAuthenticated && auth.initialized) {
44
+ const config = getDevConfig();
45
+ auth.loginDev(config.devUser, config.devPermissions);
46
+ }
47
+ });
48
+
49
+ // Show loading state until initialized
50
+ const showLoading = $derived(!auth.initialized);
51
+
52
+ // Show login form if not authenticated and not in dev mode
53
+ const showLogin = $derived(auth.initialized && !auth.isAuthenticated && !devMode);
54
+
55
+ // Show landing page if authenticated
56
+ const showLandingPage = $derived(auth.initialized && auth.isAuthenticated);
57
+ </script>
58
+
59
+ {#if showLoading}
60
+ <!-- Loading State -->
61
+ <div class="loading-container d-flex justify-content-center align-items-center vh-100">
62
+ <div class="text-center">
63
+ <div class="spinner-border text-primary mb-3" role="status">
64
+ <span class="visually-hidden">Loading...</span>
65
+ </div>
66
+ <p class="text-muted">Loading application...</p>
67
+ </div>
68
+ </div>
69
+ {:else if showLogin}
70
+ <!-- Login Form -->
71
+ <LoginForm
72
+ {auth}
73
+ {title}
74
+ {subtitle}
75
+ {logo}
76
+ />
77
+ {:else if showLandingPage}
78
+ <!-- Landing Page -->
79
+ <LandingPage
80
+ {auth}
81
+ {title}
82
+ {subtitle}
83
+ {logo}
84
+ {categories}
85
+ {apps}
86
+ />
87
+ {/if}
88
+
89
+ <style>
90
+ .loading-container {
91
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
92
+ }
93
+
94
+ .loading-container .spinner-border {
95
+ width: 3rem;
96
+ height: 3rem;
97
+ }
98
+
99
+ .loading-container p {
100
+ color: white !important;
101
+ }
102
+ </style>
@@ -0,0 +1,20 @@
1
+ import type { CategoryInfo, AppDefinition, AuthConfig } from '../Auth/types.js';
2
+ interface Props {
3
+ /** Page title */
4
+ title?: string;
5
+ /** Page subtitle */
6
+ subtitle?: string;
7
+ /** Logo URL */
8
+ logo?: string;
9
+ /** Categories to display */
10
+ categories?: CategoryInfo[];
11
+ /** Apps to display */
12
+ apps?: AppDefinition[];
13
+ /** Auth configuration */
14
+ authConfig?: Partial<AuthConfig>;
15
+ /** Force dev mode (auto-login) */
16
+ forceDevMode?: boolean;
17
+ }
18
+ declare const App: import("svelte").Component<Props, {}, "">;
19
+ type App = ReturnType<typeof App>;
20
+ export default App;
@@ -0,0 +1,480 @@
1
+ <script lang="ts">
2
+ import type { AppDefinition, CategoryInfo } from '../Auth/types.js';
3
+ import type { AuthState } from '../Auth/auth.svelte.js';
4
+ import { base } from '$app/paths';
5
+
6
+ interface Props {
7
+ /** Auth state instance */
8
+ auth: AuthState;
9
+ /** Page title */
10
+ title?: string;
11
+ /** Page subtitle */
12
+ subtitle?: string;
13
+ /** Logo URL */
14
+ logo?: string;
15
+ /** Categories to display */
16
+ categories: CategoryInfo[];
17
+ /** Apps to display */
18
+ apps: AppDefinition[];
19
+ /** Show only accessible apps (based on permissions) */
20
+ filterByPermissions?: boolean;
21
+ }
22
+
23
+ let {
24
+ auth,
25
+ title = 'RF Tool Components',
26
+ subtitle = 'Network Planning and Visualization Suite',
27
+ logo,
28
+ categories,
29
+ apps,
30
+ filterByPermissions = true
31
+ }: Props = $props();
32
+
33
+ // Filter apps based on permissions if enabled
34
+ const accessibleApps = $derived(
35
+ filterByPermissions && auth.isAuthenticated
36
+ ? apps.filter(app => {
37
+ if (!app.enabled) return false;
38
+ if (!app.requiredPermission) return true;
39
+ return auth.hasPermission(app.requiredPermission, 'view');
40
+ })
41
+ : apps.filter(app => app.enabled)
42
+ );
43
+
44
+ // Group apps by category
45
+ const appsByCategory = $derived(
46
+ categories
47
+ .map(cat => ({
48
+ category: cat,
49
+ apps: accessibleApps.filter(app => app.category === cat.id)
50
+ }))
51
+ .filter(group => group.apps.length > 0)
52
+ );
53
+
54
+ function handleLogout() {
55
+ auth.logout();
56
+ }
57
+ </script>
58
+
59
+ <div class="landing-page">
60
+ <!-- Navbar -->
61
+ <nav class="navbar">
62
+ <div class="navbar-brand">
63
+ {#if logo}
64
+ <img src={logo} alt="Logo" class="navbar-logo" />
65
+ {:else}
66
+ <i class="bi bi-broadcast-pin"></i>
67
+ {/if}
68
+ <div class="navbar-title">
69
+ <span class="title">{title}</span>
70
+ <span class="subtitle">{subtitle}</span>
71
+ </div>
72
+ </div>
73
+
74
+ {#if auth.isAuthenticated && auth.user}
75
+ <div class="navbar-user">
76
+ <div class="user-info">
77
+ <span class="user-name">{auth.user.displayName}</span>
78
+ <span class="user-email">{auth.user.email || auth.user.username}</span>
79
+ </div>
80
+ <button class="logout-btn" onclick={handleLogout} title="Sign Out" aria-label="Sign Out">
81
+ <i class="bi bi-box-arrow-right"></i>
82
+ </button>
83
+ </div>
84
+ {/if}
85
+ </nav>
86
+
87
+ <!-- Content -->
88
+ <main class="content">
89
+ {#each appsByCategory as { category, apps: categoryApps }, index (category.id)}
90
+ <!-- Category Section -->
91
+ <section class="category-section">
92
+ <div class="category-header">
93
+ <div class="category-icon" style="--cat-color: {category.color}">
94
+ <i class="bi {category.icon}"></i>
95
+ </div>
96
+ <div class="category-info">
97
+ <h2>{category.title}</h2>
98
+ <p>{category.description}</p>
99
+ </div>
100
+ <span class="category-count">{categoryApps.length}</span>
101
+ </div>
102
+
103
+ <div class="apps-grid">
104
+ {#each categoryApps as app (app.id)}
105
+ <a href="{base}{app.route}" class="app-card" style="--cat-color: {category.color}">
106
+ <div class="app-icon">
107
+ <i class="bi {app.icon}"></i>
108
+ </div>
109
+ <div class="app-info">
110
+ <h3>
111
+ {app.title}
112
+ {#if app.badge}
113
+ <span class="app-badge" class:new={app.badge === 'New'} class:beta={app.badge === 'Beta'}>
114
+ {app.badge}
115
+ </span>
116
+ {/if}
117
+ </h3>
118
+ <p>{app.description}</p>
119
+ </div>
120
+ <i class="bi bi-chevron-right app-arrow"></i>
121
+ </a>
122
+ {/each}
123
+ </div>
124
+ </section>
125
+
126
+ {#if index < appsByCategory.length - 1}
127
+ <div class="section-divider"></div>
128
+ {/if}
129
+ {/each}
130
+
131
+ <!-- Empty State -->
132
+ {#if appsByCategory.length === 0}
133
+ <div class="empty-state">
134
+ <i class="bi bi-inbox"></i>
135
+ <h3>No Applications Available</h3>
136
+ <p>You don't have access to any applications yet.</p>
137
+ </div>
138
+ {/if}
139
+ </main>
140
+
141
+ <!-- Footer -->
142
+ <footer class="footer">
143
+ <div class="footer-left">
144
+ <i class="bi bi-shield-check"></i>
145
+ {#if auth.isAuthenticated}
146
+ Signed in as <strong>{auth.user?.username}</strong>
147
+ {:else}
148
+ Not authenticated
149
+ {/if}
150
+ </div>
151
+ <div class="footer-right">
152
+ RF Tool Components © {new Date().getFullYear()}
153
+ </div>
154
+ </footer>
155
+ </div>
156
+
157
+ <style>
158
+ .landing-page {
159
+ min-height: 100vh;
160
+ display: flex;
161
+ flex-direction: column;
162
+ background: #f1f5f9;
163
+ }
164
+
165
+ /* Navbar */
166
+ .navbar {
167
+ display: flex;
168
+ align-items: center;
169
+ justify-content: space-between;
170
+ padding: 0 1.5rem;
171
+ height: 64px;
172
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
173
+ color: #fff;
174
+ flex-shrink: 0;
175
+ }
176
+
177
+ .navbar-brand {
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 0.75rem;
181
+ }
182
+
183
+ .navbar-brand > i {
184
+ font-size: 1.75rem;
185
+ color: #3b82f6;
186
+ }
187
+
188
+ .navbar-logo {
189
+ height: 36px;
190
+ }
191
+
192
+ .navbar-title {
193
+ display: flex;
194
+ flex-direction: column;
195
+ }
196
+
197
+ .navbar-title .title {
198
+ font-size: 1.125rem;
199
+ font-weight: 600;
200
+ line-height: 1.2;
201
+ }
202
+
203
+ .navbar-title .subtitle {
204
+ font-size: 0.75rem;
205
+ color: #94a3b8;
206
+ }
207
+
208
+ .navbar-user {
209
+ display: flex;
210
+ align-items: center;
211
+ gap: 0.75rem;
212
+ }
213
+
214
+ .user-info {
215
+ display: flex;
216
+ flex-direction: column;
217
+ align-items: flex-end;
218
+ }
219
+
220
+ .user-name {
221
+ font-size: 0.875rem;
222
+ font-weight: 500;
223
+ }
224
+
225
+ .user-email {
226
+ font-size: 0.75rem;
227
+ color: #94a3b8;
228
+ }
229
+
230
+ .logout-btn {
231
+ width: 36px;
232
+ height: 36px;
233
+ border-radius: 8px;
234
+ border: 1px solid rgba(255, 255, 255, 0.2);
235
+ background: rgba(255, 255, 255, 0.05);
236
+ color: #fff;
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: center;
240
+ cursor: pointer;
241
+ transition: all 0.15s;
242
+ }
243
+
244
+ .logout-btn:hover {
245
+ background: rgba(239, 68, 68, 0.2);
246
+ border-color: #ef4444;
247
+ color: #ef4444;
248
+ }
249
+
250
+ /* Content */
251
+ .content {
252
+ flex: 1;
253
+ overflow-y: auto;
254
+ padding: 2rem;
255
+ }
256
+
257
+ /* Category Section */
258
+ .category-section {
259
+ max-width: 1400px;
260
+ margin: 0 auto;
261
+ }
262
+
263
+ .category-header {
264
+ display: flex;
265
+ align-items: center;
266
+ gap: 1rem;
267
+ margin-bottom: 1.25rem;
268
+ }
269
+
270
+ .category-icon {
271
+ width: 48px;
272
+ height: 48px;
273
+ border-radius: 12px;
274
+ background: color-mix(in srgb, var(--cat-color, #3b82f6) 15%, transparent);
275
+ color: var(--cat-color, #3b82f6);
276
+ display: flex;
277
+ align-items: center;
278
+ justify-content: center;
279
+ font-size: 1.25rem;
280
+ }
281
+
282
+ .category-info h2 {
283
+ font-size: 1.25rem;
284
+ font-weight: 600;
285
+ color: #0f172a;
286
+ margin: 0;
287
+ }
288
+
289
+ .category-info p {
290
+ font-size: 0.875rem;
291
+ color: #64748b;
292
+ margin: 0.125rem 0 0;
293
+ }
294
+
295
+ .category-count {
296
+ margin-left: auto;
297
+ background: #e2e8f0;
298
+ color: #475569;
299
+ padding: 0.25rem 0.625rem;
300
+ border-radius: 999px;
301
+ font-size: 0.75rem;
302
+ font-weight: 500;
303
+ }
304
+
305
+ /* Apps Grid */
306
+ .apps-grid {
307
+ display: grid;
308
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
309
+ gap: 1rem;
310
+ }
311
+
312
+ .app-card {
313
+ display: flex;
314
+ align-items: center;
315
+ gap: 1rem;
316
+ padding: 1rem 1.25rem;
317
+ background: #fff;
318
+ border-radius: 12px;
319
+ border: 1px solid #e2e8f0;
320
+ text-decoration: none;
321
+ color: inherit;
322
+ transition: all 0.2s;
323
+ }
324
+
325
+ .app-card:hover {
326
+ border-color: var(--cat-color, #3b82f6);
327
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
328
+ transform: translateY(-2px);
329
+ }
330
+
331
+ .app-icon {
332
+ width: 44px;
333
+ height: 44px;
334
+ border-radius: 10px;
335
+ background: color-mix(in srgb, var(--cat-color, #3b82f6) 12%, transparent);
336
+ color: var(--cat-color, #3b82f6);
337
+ display: flex;
338
+ align-items: center;
339
+ justify-content: center;
340
+ font-size: 1.25rem;
341
+ flex-shrink: 0;
342
+ }
343
+
344
+ .app-info {
345
+ flex: 1;
346
+ min-width: 0;
347
+ }
348
+
349
+ .app-info h3 {
350
+ font-size: 0.9375rem;
351
+ font-weight: 600;
352
+ color: #0f172a;
353
+ margin: 0;
354
+ display: flex;
355
+ align-items: center;
356
+ gap: 0.5rem;
357
+ }
358
+
359
+ .app-info p {
360
+ font-size: 0.8125rem;
361
+ color: #64748b;
362
+ margin: 0.25rem 0 0;
363
+ white-space: nowrap;
364
+ overflow: hidden;
365
+ text-overflow: ellipsis;
366
+ }
367
+
368
+ .app-badge {
369
+ font-size: 0.625rem;
370
+ font-weight: 600;
371
+ text-transform: uppercase;
372
+ padding: 0.125rem 0.375rem;
373
+ border-radius: 4px;
374
+ background: #e2e8f0;
375
+ color: #475569;
376
+ }
377
+
378
+ .app-badge.new {
379
+ background: #dcfce7;
380
+ color: #16a34a;
381
+ }
382
+
383
+ .app-badge.beta {
384
+ background: #fef3c7;
385
+ color: #d97706;
386
+ }
387
+
388
+ .app-arrow {
389
+ color: #cbd5e1;
390
+ transition: color 0.15s, transform 0.15s;
391
+ }
392
+
393
+ .app-card:hover .app-arrow {
394
+ color: var(--cat-color, #3b82f6);
395
+ transform: translateX(3px);
396
+ }
397
+
398
+ /* Section Divider */
399
+ .section-divider {
400
+ max-width: 1400px;
401
+ margin: 2rem auto;
402
+ height: 1px;
403
+ background: linear-gradient(90deg, transparent, #cbd5e1, transparent);
404
+ }
405
+
406
+ /* Empty State */
407
+ .empty-state {
408
+ text-align: center;
409
+ padding: 4rem 2rem;
410
+ color: #64748b;
411
+ }
412
+
413
+ .empty-state i {
414
+ font-size: 4rem;
415
+ color: #cbd5e1;
416
+ }
417
+
418
+ .empty-state h3 {
419
+ font-size: 1.25rem;
420
+ font-weight: 600;
421
+ margin: 1rem 0 0.5rem;
422
+ color: #475569;
423
+ }
424
+
425
+ .empty-state p {
426
+ margin: 0;
427
+ }
428
+
429
+ /* Footer */
430
+ .footer {
431
+ display: flex;
432
+ align-items: center;
433
+ justify-content: space-between;
434
+ padding: 1rem 2rem;
435
+ background: #fff;
436
+ border-top: 1px solid #e2e8f0;
437
+ font-size: 0.8125rem;
438
+ color: #64748b;
439
+ flex-shrink: 0;
440
+ }
441
+
442
+ .footer-left {
443
+ display: flex;
444
+ align-items: center;
445
+ gap: 0.375rem;
446
+ }
447
+
448
+ .footer-left strong {
449
+ color: #334155;
450
+ }
451
+
452
+ /* Responsive */
453
+ @media (max-width: 640px) {
454
+ .navbar {
455
+ padding: 0 1rem;
456
+ }
457
+
458
+ .navbar-title .subtitle {
459
+ display: none;
460
+ }
461
+
462
+ .user-info {
463
+ display: none;
464
+ }
465
+
466
+ .content {
467
+ padding: 1.5rem 1rem;
468
+ }
469
+
470
+ .apps-grid {
471
+ grid-template-columns: 1fr;
472
+ }
473
+
474
+ .footer {
475
+ flex-direction: column;
476
+ gap: 0.5rem;
477
+ text-align: center;
478
+ }
479
+ }
480
+ </style>
@@ -0,0 +1,21 @@
1
+ import type { AppDefinition, CategoryInfo } from '../Auth/types.js';
2
+ import type { AuthState } from '../Auth/auth.svelte.js';
3
+ interface Props {
4
+ /** Auth state instance */
5
+ auth: AuthState;
6
+ /** Page title */
7
+ title?: string;
8
+ /** Page subtitle */
9
+ subtitle?: string;
10
+ /** Logo URL */
11
+ logo?: string;
12
+ /** Categories to display */
13
+ categories: CategoryInfo[];
14
+ /** Apps to display */
15
+ apps: AppDefinition[];
16
+ /** Show only accessible apps (based on permissions) */
17
+ filterByPermissions?: boolean;
18
+ }
19
+ declare const LandingPage: import("svelte").Component<Props, {}, "">;
20
+ type LandingPage = ReturnType<typeof LandingPage>;
21
+ export default LandingPage;
@@ -0,0 +1,2 @@
1
+ export { default as LandingPage } from './LandingPage.svelte';
2
+ export { default as App } from './App.svelte';
@@ -0,0 +1,3 @@
1
+ // LandingPage module barrel export
2
+ export { default as LandingPage } from './LandingPage.svelte';
3
+ export { default as App } from './App.svelte';