rune-lab 0.0.21 → 0.1.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 +107 -0
- package/dist/components/ApiMonitor.svelte.d.ts +3 -0
- package/dist/components/Icon.svelte +52 -12
- package/dist/components/Icon.svelte.d.ts +2 -1
- package/dist/components/RuneProvider.svelte +49 -10
- package/dist/components/RuneProvider.svelte.d.ts +11 -1
- package/dist/{devtools → components}/Toaster.svelte +2 -2
- package/dist/features/config/{components/AppSettingSelector.svelte → AppSettingSelector.svelte} +9 -3
- package/dist/features/config/{components/CurrencySelector.svelte → CurrencySelector.svelte} +6 -4
- package/dist/features/config/{components/LanguageSelector.svelte → LanguageSelector.svelte} +7 -7
- package/dist/features/config/{components/ThemeSelector.svelte → ThemeSelector.svelte} +6 -4
- package/dist/features/detail-panels/ShowcasePanel.svelte +4 -6
- package/dist/index.d.ts +12 -13
- package/dist/index.js +10 -13
- package/dist/layout/WorkspaceLayout.svelte +81 -40
- package/dist/layout/WorkspaceLayout.svelte.d.ts +18 -4
- package/dist/persistence/drivers.js +10 -12
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +20 -0
- package/dist/showcase/AppStateInspector.svelte +27 -9
- package/dist/showcase/Showcase.svelte +5 -4
- package/dist/showcase/state.svelte.d.ts +3 -0
- package/dist/showcase/state.svelte.js +3 -0
- package/dist/state/api.svelte.d.ts +2 -1
- package/dist/state/api.svelte.js +16 -4
- package/dist/state/app.svelte.d.ts +5 -0
- package/dist/state/app.svelte.js +7 -0
- package/dist/state/commands.svelte.d.ts +1 -1
- package/dist/state/currency.svelte.d.ts +1 -1
- package/dist/state/currency.svelte.js +1 -1
- package/dist/state/index.d.ts +3 -1
- package/dist/state/index.js +3 -1
- package/dist/state/language.svelte.d.ts +6 -2
- package/dist/state/language.svelte.js +12 -4
- package/dist/state/layout.svelte.d.ts +0 -2
- package/dist/state/layout.svelte.js +0 -4
- package/dist/state/shortcuts.svelte.d.ts +14 -14
- package/dist/state/shortcuts.svelte.js +0 -10
- package/dist/state/theme.svelte.d.ts +1 -1
- package/dist/state/theme.svelte.js +1 -1
- package/dist/state/toast-bridge.d.ts +29 -0
- package/dist/state/toast-bridge.js +43 -0
- package/package.json +10 -6
- package/dist/devtools/API_Monitor.svelte.d.ts +0 -3
- /package/dist/{devtools/API_Monitor.svelte → components/ApiMonitor.svelte} +0 -0
- /package/dist/{devtools → components}/Toaster.svelte.d.ts +0 -0
- /package/dist/features/config/{components/AppSettingSelector.svelte.d.ts → AppSettingSelector.svelte.d.ts} +0 -0
- /package/dist/features/config/{components/CurrencySelector.svelte.d.ts → CurrencySelector.svelte.d.ts} +0 -0
- /package/dist/features/config/{components/LanguageSelector.svelte.d.ts → LanguageSelector.svelte.d.ts} +0 -0
- /package/dist/features/config/{components/ThemeSelector.svelte.d.ts → ThemeSelector.svelte.d.ts} +0 -0
- /package/dist/{devtools → internal}/message-resolver.d.ts +0 -0
- /package/dist/{devtools → internal}/message-resolver.js +0 -0
- /package/dist/{devtools → state}/createConfigStore.svelte.d.ts +0 -0
- /package/dist/{devtools → state}/createConfigStore.svelte.js +0 -0
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
<!-- src/lib/layout/WorkspaceLayout.svelte -->
|
|
2
|
-
<script lang="ts">
|
|
2
|
+
<script module lang="ts">
|
|
3
3
|
import type { Snippet } from "svelte";
|
|
4
|
+
|
|
5
|
+
export interface WorkspaceLayoutProps {
|
|
6
|
+
/** Content for the far-left vertical strip */
|
|
7
|
+
workspaceStrip?: Snippet;
|
|
8
|
+
/** Main navigation tree panel */
|
|
9
|
+
navigationPanel?: Snippet;
|
|
10
|
+
/** The primary application view */
|
|
11
|
+
content?: Snippet;
|
|
12
|
+
/** Right-side contextual detail panel */
|
|
13
|
+
detailPanel?: Snippet;
|
|
14
|
+
namespace?: string;
|
|
15
|
+
|
|
16
|
+
/** Width of the left workspace strip */
|
|
17
|
+
stripWidth?: string;
|
|
18
|
+
/** Width of the navigation tree panel */
|
|
19
|
+
navWidth?: string;
|
|
20
|
+
/** Width of the contextual detail panel */
|
|
21
|
+
detailWidth?: string;
|
|
22
|
+
|
|
23
|
+
/** Controlled override for navigation panel visibility */
|
|
24
|
+
navOpen?: boolean;
|
|
25
|
+
/** Controlled override for detail panel visibility */
|
|
26
|
+
detailOpen?: boolean;
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script lang="ts">
|
|
4
31
|
import { getLayoutStore } from "../state/layout.svelte";
|
|
5
32
|
import {
|
|
6
33
|
getShortcutStore,
|
|
@@ -9,22 +36,36 @@
|
|
|
9
36
|
} from "../state/shortcuts.svelte";
|
|
10
37
|
import { onMount } from "svelte";
|
|
11
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @component WorkspaceLayout
|
|
41
|
+
* The main application shell managing navigational zones.
|
|
42
|
+
*/
|
|
43
|
+
const layoutStore = getLayoutStore();
|
|
44
|
+
|
|
12
45
|
let {
|
|
46
|
+
/** Content for the far-left vertical strip */
|
|
13
47
|
workspaceStrip,
|
|
48
|
+
/** Main navigation tree panel */
|
|
14
49
|
navigationPanel,
|
|
50
|
+
/** The primary application view */
|
|
15
51
|
content,
|
|
52
|
+
/** Right-side contextual detail panel */
|
|
16
53
|
detailPanel,
|
|
17
54
|
namespace = "default",
|
|
18
|
-
} = $props<{
|
|
19
|
-
workspaceStrip?: Snippet;
|
|
20
|
-
navigationPanel?: Snippet;
|
|
21
|
-
content: Snippet;
|
|
22
|
-
detailPanel?: Snippet;
|
|
23
|
-
namespace?: string;
|
|
24
|
-
}>();
|
|
25
55
|
|
|
26
|
-
|
|
27
|
-
|
|
56
|
+
/** Width of the left workspace strip */
|
|
57
|
+
stripWidth = "72px",
|
|
58
|
+
/** Width of the navigation tree panel */
|
|
59
|
+
navWidth = "240px",
|
|
60
|
+
/** Width of the contextual detail panel */
|
|
61
|
+
detailWidth = "320px",
|
|
62
|
+
|
|
63
|
+
/** Controlled override for navigation panel visibility */
|
|
64
|
+
navOpen = $bindable(layoutStore.navOpen),
|
|
65
|
+
/** Controlled override for detail panel visibility */
|
|
66
|
+
detailOpen = $bindable(layoutStore.detailOpen),
|
|
67
|
+
}: WorkspaceLayoutProps = $props();
|
|
68
|
+
|
|
28
69
|
const shortcutStore = getShortcutStore();
|
|
29
70
|
|
|
30
71
|
// Initial configuration based on props
|
|
@@ -35,17 +76,18 @@
|
|
|
35
76
|
const shortcuts = [
|
|
36
77
|
{
|
|
37
78
|
...LAYOUT_SHORTCUTS.TOGGLE_NAV,
|
|
38
|
-
handler: () =>
|
|
79
|
+
handler: (e: KeyboardEvent) => {
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
navOpen = !navOpen;
|
|
82
|
+
},
|
|
39
83
|
},
|
|
40
84
|
{
|
|
41
85
|
...LAYOUT_SHORTCUTS.TOGGLE_DETAIL,
|
|
42
|
-
handler: () =>
|
|
86
|
+
handler: (e: KeyboardEvent) => {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
detailOpen = !detailOpen;
|
|
89
|
+
},
|
|
43
90
|
},
|
|
44
|
-
// Workspace shortcuts (ctrl+1 to ctrl+9)
|
|
45
|
-
...Array.from({ length: 9 }, (_, i) => ({
|
|
46
|
-
...(LAYOUT_SHORTCUTS as any)[`WORKSPACE_${i + 1}`],
|
|
47
|
-
handler: () => layoutStore.activateWorkspaceByIndex(i),
|
|
48
|
-
})),
|
|
49
91
|
];
|
|
50
92
|
|
|
51
93
|
for (const s of shortcuts) {
|
|
@@ -55,11 +97,6 @@
|
|
|
55
97
|
return () => {
|
|
56
98
|
shortcutStore.unregister(LAYOUT_SHORTCUTS.TOGGLE_NAV.id);
|
|
57
99
|
shortcutStore.unregister(LAYOUT_SHORTCUTS.TOGGLE_DETAIL.id);
|
|
58
|
-
for (let i = 1; i <= 9; i++) {
|
|
59
|
-
shortcutStore.unregister(
|
|
60
|
-
(LAYOUT_SHORTCUTS as any)[`WORKSPACE_${i}`].id,
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
100
|
};
|
|
64
101
|
});
|
|
65
102
|
</script>
|
|
@@ -79,10 +116,11 @@
|
|
|
79
116
|
{/if}
|
|
80
117
|
|
|
81
118
|
<!-- Mobile Nav Backdrop -->
|
|
82
|
-
{#if navigationPanel &&
|
|
119
|
+
{#if navigationPanel && navOpen}
|
|
83
120
|
<button
|
|
84
|
-
class="fixed inset-0 bg-black/50
|
|
85
|
-
|
|
121
|
+
class="fixed inset-0 bg-black/50 md:hidden cursor-default border-none"
|
|
122
|
+
style="z-index: var(--rl-z-backdrop, 40);"
|
|
123
|
+
onclick={() => (navOpen = false)}
|
|
86
124
|
aria-label="Close navigation"
|
|
87
125
|
></button>
|
|
88
126
|
{/if}
|
|
@@ -90,19 +128,18 @@
|
|
|
90
128
|
<!-- Zone 2: Navigation Panel -->
|
|
91
129
|
{#if navigationPanel}
|
|
92
130
|
<aside
|
|
93
|
-
class="rl-nav h-full shrink-0 bg-base-200 overflow-hidden flex flex-col transition-all duration-300 ease-in-out
|
|
94
|
-
class:border-r={
|
|
131
|
+
class="rl-nav h-full shrink-0 bg-base-200 overflow-hidden flex flex-col transition-all duration-300 ease-in-out"
|
|
132
|
+
class:border-r={navOpen}
|
|
95
133
|
class:border-base-content={true}
|
|
96
134
|
style="
|
|
97
135
|
border-opacity: 0.05;
|
|
98
|
-
|
|
99
|
-
? 'var(--rl-nav-width, 240px)'
|
|
100
|
-
: '0px'};
|
|
136
|
+
z-index: var(--rl-z-nav, 50);
|
|
137
|
+
width: {navOpen ? 'var(--rl-nav-width, 240px)' : '0px'};
|
|
101
138
|
left: {workspaceStrip ? 'var(--rl-strip-width, 72px)' : '0px'};
|
|
102
139
|
"
|
|
103
140
|
class:max-md:!w-[var(--rl-nav-width,240px)]={true}
|
|
104
141
|
class:max-md:fixed={true}
|
|
105
|
-
class:max-md:-translate-x-[200%]={!
|
|
142
|
+
class:max-md:-translate-x-[200%]={!navOpen}
|
|
106
143
|
data-rl-panel="navigation"
|
|
107
144
|
>
|
|
108
145
|
<div class="w-[var(--rl-nav-width,240px)] h-full flex flex-col">
|
|
@@ -115,14 +152,19 @@
|
|
|
115
152
|
<main
|
|
116
153
|
class="rl-content h-full flex-1 min-w-0 bg-base-100 flex flex-col overflow-hidden relative"
|
|
117
154
|
>
|
|
118
|
-
{
|
|
155
|
+
{#if content}
|
|
156
|
+
{@render content()}
|
|
157
|
+
{:else}
|
|
158
|
+
<div></div>
|
|
159
|
+
{/if}
|
|
119
160
|
</main>
|
|
120
161
|
|
|
121
162
|
<!-- Mobile Detail Backdrop -->
|
|
122
|
-
{#if detailPanel &&
|
|
163
|
+
{#if detailPanel && detailOpen}
|
|
123
164
|
<button
|
|
124
|
-
class="fixed inset-0 bg-black/50
|
|
125
|
-
|
|
165
|
+
class="fixed inset-0 bg-black/50 md:hidden cursor-default border-none"
|
|
166
|
+
style="z-index: var(--rl-z-backdrop, 40);"
|
|
167
|
+
onclick={() => (detailOpen = false)}
|
|
126
168
|
aria-label="Close detail panel"
|
|
127
169
|
></button>
|
|
128
170
|
{/if}
|
|
@@ -130,14 +172,13 @@
|
|
|
130
172
|
<!-- Zone 4: Detail Panel -->
|
|
131
173
|
{#if detailPanel}
|
|
132
174
|
<aside
|
|
133
|
-
class="rl-detail h-full shrink-0 bg-base-100 overflow-y-auto overflow-x-hidden transition-all duration-300 ease-in-out
|
|
134
|
-
class:border-l={
|
|
175
|
+
class="rl-detail h-full shrink-0 bg-base-100 overflow-y-auto overflow-x-hidden transition-all duration-300 ease-in-out"
|
|
176
|
+
class:border-l={detailOpen}
|
|
135
177
|
class:border-base-content={true}
|
|
136
178
|
style="
|
|
137
179
|
border-opacity: 0.05;
|
|
138
|
-
|
|
139
|
-
? 'var(--rl-detail-width, 320px)'
|
|
140
|
-
: '0px'};
|
|
180
|
+
z-index: var(--rl-z-detail, 50);
|
|
181
|
+
width: {detailOpen ? 'var(--rl-detail-width, 320px)' : '0px'};
|
|
141
182
|
"
|
|
142
183
|
class:max-md:!w-[var(--rl-detail-width,320px)]={true}
|
|
143
184
|
class:max-md:fixed={true}
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
-
|
|
2
|
+
export interface WorkspaceLayoutProps {
|
|
3
|
+
/** Content for the far-left vertical strip */
|
|
3
4
|
workspaceStrip?: Snippet;
|
|
5
|
+
/** Main navigation tree panel */
|
|
4
6
|
navigationPanel?: Snippet;
|
|
5
|
-
|
|
7
|
+
/** The primary application view */
|
|
8
|
+
content?: Snippet;
|
|
9
|
+
/** Right-side contextual detail panel */
|
|
6
10
|
detailPanel?: Snippet;
|
|
7
11
|
namespace?: string;
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
/** Width of the left workspace strip */
|
|
13
|
+
stripWidth?: string;
|
|
14
|
+
/** Width of the navigation tree panel */
|
|
15
|
+
navWidth?: string;
|
|
16
|
+
/** Width of the contextual detail panel */
|
|
17
|
+
detailWidth?: string;
|
|
18
|
+
/** Controlled override for navigation panel visibility */
|
|
19
|
+
navOpen?: boolean;
|
|
20
|
+
/** Controlled override for detail panel visibility */
|
|
21
|
+
detailOpen?: boolean;
|
|
22
|
+
}
|
|
23
|
+
declare const WorkspaceLayout: import("svelte").Component<WorkspaceLayoutProps, {}, "navOpen" | "detailOpen">;
|
|
10
24
|
type WorkspaceLayout = ReturnType<typeof WorkspaceLayout>;
|
|
11
25
|
export default WorkspaceLayout;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { browser } from "$app/environment";
|
|
1
2
|
export function createInMemoryDriver() {
|
|
2
3
|
const store = new Map();
|
|
3
4
|
return {
|
|
@@ -9,50 +10,48 @@ export function createInMemoryDriver() {
|
|
|
9
10
|
export const inMemoryDriver = createInMemoryDriver();
|
|
10
11
|
export const localStorageDriver = {
|
|
11
12
|
get: (key) => {
|
|
12
|
-
if (
|
|
13
|
+
if (!browser)
|
|
13
14
|
return null;
|
|
14
15
|
return window.localStorage.getItem(key);
|
|
15
16
|
},
|
|
16
17
|
set: (key, value) => {
|
|
17
|
-
if (
|
|
18
|
+
if (!browser)
|
|
18
19
|
return;
|
|
19
20
|
window.localStorage.setItem(key, value);
|
|
20
21
|
},
|
|
21
22
|
remove: (key) => {
|
|
22
|
-
if (
|
|
23
|
+
if (!browser)
|
|
23
24
|
return;
|
|
24
25
|
window.localStorage.removeItem(key);
|
|
25
26
|
},
|
|
26
27
|
};
|
|
27
28
|
export const sessionStorageDriver = {
|
|
28
29
|
get: (key) => {
|
|
29
|
-
if (
|
|
30
|
+
if (!browser)
|
|
30
31
|
return null;
|
|
31
32
|
return window.sessionStorage.getItem(key);
|
|
32
33
|
},
|
|
33
34
|
set: (key, value) => {
|
|
34
|
-
if (
|
|
35
|
+
if (!browser)
|
|
35
36
|
return;
|
|
36
37
|
window.sessionStorage.setItem(key, value);
|
|
37
38
|
},
|
|
38
39
|
remove: (key) => {
|
|
39
|
-
if (
|
|
40
|
+
if (!browser)
|
|
40
41
|
return;
|
|
41
42
|
window.sessionStorage.removeItem(key);
|
|
42
43
|
},
|
|
43
44
|
};
|
|
44
45
|
export const cookieDriver = (options = {}) => ({
|
|
45
46
|
get: (key) => {
|
|
46
|
-
if (
|
|
47
|
+
if (!browser)
|
|
47
48
|
return null;
|
|
48
|
-
}
|
|
49
49
|
const match = document.cookie.match(new RegExp(`(^| )${key}=([^;]+)`));
|
|
50
50
|
return match ? decodeURIComponent(match[2]) : null;
|
|
51
51
|
},
|
|
52
52
|
set: (key, value) => {
|
|
53
|
-
if (
|
|
53
|
+
if (!browser)
|
|
54
54
|
return;
|
|
55
|
-
}
|
|
56
55
|
let cookie = `${key}=${encodeURIComponent(value)}`;
|
|
57
56
|
if (options.path)
|
|
58
57
|
cookie += `; path=${options.path}`;
|
|
@@ -63,9 +62,8 @@ export const cookieDriver = (options = {}) => ({
|
|
|
63
62
|
document.cookie = cookie;
|
|
64
63
|
},
|
|
65
64
|
remove: (key) => {
|
|
66
|
-
if (
|
|
65
|
+
if (!browser)
|
|
67
66
|
return;
|
|
68
|
-
}
|
|
69
67
|
document.cookie = `${key}=; max-age=0; path=${options.path || "/"}`;
|
|
70
68
|
},
|
|
71
69
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Handle } from "@sveltejs/kit";
|
|
2
|
+
/**
|
|
3
|
+
* A SvelteKit Handle hook that prevents Flash of Unstyled Content (FOUC)
|
|
4
|
+
* by injecting the saved theme straight into the HTML before it leaves the server.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* // src/hooks.server.ts
|
|
9
|
+
* import { sequence } from "@sveltejs/kit/hooks";
|
|
10
|
+
* import { runeLabThemeHandler } from "rune-lab/server";
|
|
11
|
+
*
|
|
12
|
+
* export const handle = sequence(runeLabThemeHandler);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare const runeLabThemeHandler: Handle;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A SvelteKit Handle hook that prevents Flash of Unstyled Content (FOUC)
|
|
3
|
+
* by injecting the saved theme straight into the HTML before it leaves the server.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* // src/hooks.server.ts
|
|
8
|
+
* import { sequence } from "@sveltejs/kit/hooks";
|
|
9
|
+
* import { runeLabThemeHandler } from "rune-lab/server";
|
|
10
|
+
*
|
|
11
|
+
* export const handle = sequence(runeLabThemeHandler);
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const runeLabThemeHandler = async ({ event, resolve }) => {
|
|
15
|
+
// Assuming 'theme' is the default storageKey mapped from cookieDriver
|
|
16
|
+
const theme = event.cookies.get("theme") || "system";
|
|
17
|
+
return resolve(event, {
|
|
18
|
+
transformPageChunk: ({ html }) => html.replace("<html", `<html data-theme="${theme}"`),
|
|
19
|
+
});
|
|
20
|
+
};
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { getContext } from "svelte";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @devOnly Renders a live debug view of all Rune Lab store state.
|
|
6
|
+
* Should only be rendered in development:
|
|
7
|
+
* ```svelte
|
|
8
|
+
* {#if import.meta.env.DEV}
|
|
9
|
+
* <AppStateInspector />
|
|
10
|
+
* {/if}
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
2
13
|
import * as m from "../paraglide/messages.js";
|
|
3
14
|
import StoreDetailCard from "./StoreDetailCard.svelte";
|
|
4
15
|
import { getAppStore } from "../state/app.svelte";
|
|
@@ -83,8 +94,15 @@
|
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
96
|
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
const dictionary = getContext<Record<string, any>>("rl:dictionary") || {};
|
|
98
|
+
|
|
99
|
+
function t(key: string, fallback: string) {
|
|
100
|
+
if (dictionary[key]) {
|
|
101
|
+
return typeof dictionary[key] === "function"
|
|
102
|
+
? dictionary[key]()
|
|
103
|
+
: dictionary[key];
|
|
104
|
+
}
|
|
105
|
+
return fallback;
|
|
88
106
|
}
|
|
89
107
|
</script>
|
|
90
108
|
|
|
@@ -94,11 +112,11 @@
|
|
|
94
112
|
<div class="flex flex-col gap-2 px-4">
|
|
95
113
|
<h2 class="text-3xl font-black tracking-tight flex items-center gap-3">
|
|
96
114
|
<span class="p-2 bg-primary/10 rounded-xl">🔍</span>
|
|
97
|
-
{t(
|
|
115
|
+
{t("live_store_dashboard", "Live Store Dashboard")}
|
|
98
116
|
</h2>
|
|
99
117
|
<p class="text-base-content/50 font-medium">
|
|
100
118
|
{t(
|
|
101
|
-
|
|
119
|
+
"real_time_monitor_desc",
|
|
102
120
|
"Real-time reactive state monitor for Rune Lab stores",
|
|
103
121
|
)}
|
|
104
122
|
</p>
|
|
@@ -112,7 +130,7 @@
|
|
|
112
130
|
<div
|
|
113
131
|
class="stat-title uppercase text-[10px] font-bold tracking-widest opacity-60"
|
|
114
132
|
>
|
|
115
|
-
{t(
|
|
133
|
+
{t("api_status", "API Status")}
|
|
116
134
|
</div>
|
|
117
135
|
<div
|
|
118
136
|
class="stat-value capitalize {getStatusClass(
|
|
@@ -132,13 +150,13 @@
|
|
|
132
150
|
<div
|
|
133
151
|
class="stat-title uppercase text-[10px] font-bold tracking-widest opacity-60"
|
|
134
152
|
>
|
|
135
|
-
{t(
|
|
153
|
+
{t("active_toasts", "Active Toasts")}
|
|
136
154
|
</div>
|
|
137
155
|
<div class="stat-value text-2xl">
|
|
138
156
|
{toastStore.toasts.length}
|
|
139
157
|
</div>
|
|
140
158
|
<div class="stat-desc font-mono text-[10px] opacity-50">
|
|
141
|
-
{t(
|
|
159
|
+
{t("currently_in_queue", "Currently in queue")}
|
|
142
160
|
</div>
|
|
143
161
|
</div>
|
|
144
162
|
|
|
@@ -146,13 +164,13 @@
|
|
|
146
164
|
<div
|
|
147
165
|
class="stat-title uppercase text-[10px] font-bold tracking-widest opacity-60"
|
|
148
166
|
>
|
|
149
|
-
{t(
|
|
167
|
+
{t("commands_label", "Commands")}
|
|
150
168
|
</div>
|
|
151
169
|
<div class="stat-value text-2xl">
|
|
152
170
|
{commandStore.commands.length}
|
|
153
171
|
</div>
|
|
154
172
|
<div class="stat-desc font-mono text-[10px] opacity-50">
|
|
155
|
-
{t(
|
|
173
|
+
{t("registered_in_registry", "Registered in registry")}
|
|
156
174
|
</div>
|
|
157
175
|
</div>
|
|
158
176
|
</div>
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
{ label: "Actions", icon: "⚡", component: Actions },
|
|
15
15
|
{ label: "Data Input", icon: "📥", component: DataInput },
|
|
16
16
|
{ label: "Display", icon: "📊", component: Display },
|
|
17
|
-
{ label: "Navigation", icon: "🧭", component: Navigation },
|
|
18
17
|
{ label: "Feedback", icon: "💬", component: Feedback },
|
|
19
18
|
{ label: "Visual", icon: "🎨", component: Visual },
|
|
20
19
|
];
|
|
20
|
+
|
|
21
|
+
import { showcaseState } from "./state.svelte";
|
|
21
22
|
</script>
|
|
22
23
|
|
|
23
24
|
<section
|
|
@@ -27,11 +28,11 @@
|
|
|
27
28
|
{#each tabs as tab, i (tab.label)}
|
|
28
29
|
<button
|
|
29
30
|
role="tab"
|
|
30
|
-
class="tab gap-2 transition-all duration-300 {
|
|
31
|
+
class="tab gap-2 transition-all duration-300 {showcaseState.activeTab ===
|
|
31
32
|
i
|
|
32
33
|
? 'tab-active shadow-lg'
|
|
33
34
|
: ''}"
|
|
34
|
-
onclick={() =>
|
|
35
|
+
onclick={() => (showcaseState.activeTab = i)}
|
|
35
36
|
>
|
|
36
37
|
<span class="text-xl">{tab.icon}</span>
|
|
37
38
|
<span class="hidden md:inline font-bold">{tab.label}</span>
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
class="min-h-[600px] bg-base-200/50 rounded-3xl border border-base-content/5 overflow-hidden"
|
|
44
45
|
>
|
|
45
46
|
{#each tabs as tab, i (tab.label)}
|
|
46
|
-
{#if
|
|
47
|
+
{#if showcaseState.activeTab === i}
|
|
47
48
|
<div class="animate-in fade-in zoom-in-95 duration-500">
|
|
48
49
|
<tab.component />
|
|
49
50
|
</div>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type ConnectionState = "connected" | "connecting" | "disconnected";
|
|
5
5
|
export declare class ApiStore {
|
|
6
|
+
#private;
|
|
6
7
|
url: string;
|
|
7
8
|
version: string;
|
|
8
9
|
connectionState: ConnectionState;
|
|
@@ -19,7 +20,7 @@ export declare class ApiStore {
|
|
|
19
20
|
/**
|
|
20
21
|
* Initialize API settings
|
|
21
22
|
*/
|
|
22
|
-
init(url: string, version?: string): void;
|
|
23
|
+
init(url: string, version?: string, healthCheck?: () => Promise<boolean>): void;
|
|
23
24
|
}
|
|
24
25
|
export declare function createApiStore(): ApiStore;
|
|
25
26
|
export declare function getApiStore(): ApiStore;
|
package/dist/state/api.svelte.js
CHANGED
|
@@ -5,6 +5,7 @@ export class ApiStore {
|
|
|
5
5
|
url = $state("http://localhost:8000");
|
|
6
6
|
version = $state("v1");
|
|
7
7
|
connectionState = $state("disconnected");
|
|
8
|
+
#healthCheck;
|
|
8
9
|
// Derived
|
|
9
10
|
isConnected = $derived(this.connectionState === "connected");
|
|
10
11
|
isLoading = $derived(this.connectionState === "connecting");
|
|
@@ -26,10 +27,19 @@ export class ApiStore {
|
|
|
26
27
|
*/
|
|
27
28
|
async reconnect() {
|
|
28
29
|
this.connectionState = "connecting";
|
|
29
|
-
// Simulate connection
|
|
30
30
|
try {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
if (this.#healthCheck) {
|
|
32
|
+
const isHealthy = await this.#healthCheck();
|
|
33
|
+
this.connectionState = isHealthy ? "connected" : "disconnected";
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Simulate connection if no health check provided
|
|
37
|
+
if (import.meta.env.DEV) {
|
|
38
|
+
console.warn("[rune-lab] ApiStore: No healthCheck provided to init(). Using simulated connection delay.");
|
|
39
|
+
}
|
|
40
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
41
|
+
this.connectionState = "connected";
|
|
42
|
+
}
|
|
33
43
|
}
|
|
34
44
|
catch (e) {
|
|
35
45
|
this.connectionState = "disconnected";
|
|
@@ -38,9 +48,11 @@ export class ApiStore {
|
|
|
38
48
|
/**
|
|
39
49
|
* Initialize API settings
|
|
40
50
|
*/
|
|
41
|
-
init(url, version = "v1") {
|
|
51
|
+
init(url, version = "v1", healthCheck) {
|
|
42
52
|
this.url = url;
|
|
43
53
|
this.version = version;
|
|
54
|
+
if (healthCheck)
|
|
55
|
+
this.#healthCheck = healthCheck;
|
|
44
56
|
this.reconnect();
|
|
45
57
|
}
|
|
46
58
|
}
|
|
@@ -23,6 +23,7 @@ export declare class AppStore {
|
|
|
23
23
|
repository: string;
|
|
24
24
|
license: string;
|
|
25
25
|
homepage: string;
|
|
26
|
+
customIcons: Record<string, string>;
|
|
26
27
|
/**
|
|
27
28
|
* Initialize app store with metadata
|
|
28
29
|
*/
|
|
@@ -31,6 +32,10 @@ export declare class AppStore {
|
|
|
31
32
|
* Get full app information object
|
|
32
33
|
*/
|
|
33
34
|
get info(): AppData;
|
|
35
|
+
/**
|
|
36
|
+
* Registers custom SVG icons to be available globally in the Icon component
|
|
37
|
+
*/
|
|
38
|
+
registerIcons(icons: Record<string, string>): void;
|
|
34
39
|
}
|
|
35
40
|
export declare function createAppStore(): AppStore;
|
|
36
41
|
export declare function getAppStore(): AppStore;
|
package/dist/state/app.svelte.js
CHANGED
|
@@ -14,6 +14,7 @@ export class AppStore {
|
|
|
14
14
|
repository = $state("https://github.com/Yrrrrrf/rune-lab");
|
|
15
15
|
license = $state("MIT");
|
|
16
16
|
homepage = $state("https://jsr.io/@yrrrrrf/rune-lab");
|
|
17
|
+
customIcons = $state({});
|
|
17
18
|
#initialized = false;
|
|
18
19
|
/**
|
|
19
20
|
* Initialize app store with metadata
|
|
@@ -55,6 +56,12 @@ export class AppStore {
|
|
|
55
56
|
homepage: this.homepage,
|
|
56
57
|
};
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Registers custom SVG icons to be available globally in the Icon component
|
|
61
|
+
*/
|
|
62
|
+
registerIcons(icons) {
|
|
63
|
+
this.customIcons = { ...this.customIcons, ...icons };
|
|
64
|
+
}
|
|
58
65
|
}
|
|
59
66
|
// Export singleton instance
|
|
60
67
|
export function createAppStore() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AppStore } from "./app.svelte";
|
|
2
2
|
import type { ApiStore } from "./api.svelte";
|
|
3
|
-
import type { ConfigStore } from "
|
|
3
|
+
import type { ConfigStore } from "./createConfigStore.svelte";
|
|
4
4
|
import type { ToastStore } from "./toast.svelte";
|
|
5
5
|
import type { Theme } from "./theme.svelte";
|
|
6
6
|
import type { Language } from "./language.svelte";
|
package/dist/state/index.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { type AppData, AppStore, createAppStore, getAppStore, } from "./app.svelte";
|
|
2
2
|
export { createLayoutStore, getLayoutStore, LayoutStore, type NavigationItem, type NavigationSection, type WorkspaceItem, } from "./layout.svelte";
|
|
3
|
-
export { ApiStore, createApiStore, getApiStore } from "./api.svelte";
|
|
3
|
+
export { ApiStore, type ConnectionState, createApiStore, getApiStore, } from "./api.svelte";
|
|
4
4
|
export { createLanguageStore, getLanguageStore, type Language, } from "./language.svelte";
|
|
5
5
|
export { createCurrencyStore, type Currency, getCurrencyStore, } from "./currency.svelte";
|
|
6
6
|
export { createToastStore, getToastStore, ToastStore } from "./toast.svelte";
|
|
7
7
|
export { type Command, CommandStore, createCommandStore, getCommandStore, } from "./commands.svelte";
|
|
8
8
|
export { createShortcutStore, getShortcutStore, LAYOUT_SHORTCUTS, type ShortcutEntry, shortcutListener, type ShortcutMeta, ShortcutStore, } from "./shortcuts.svelte";
|
|
9
9
|
export { createThemeStore, getThemeStore, type Theme } from "./theme.svelte";
|
|
10
|
+
export { type ConfigStore, createConfigStore, } from "./createConfigStore.svelte";
|
|
11
|
+
export { createToastBridge, notify } from "./toast-bridge";
|
package/dist/state/index.js
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
// Stores
|
|
4
4
|
export { AppStore, createAppStore, getAppStore, } from "./app.svelte";
|
|
5
5
|
export { createLayoutStore, getLayoutStore, LayoutStore, } from "./layout.svelte";
|
|
6
|
-
export { ApiStore, createApiStore, getApiStore } from "./api.svelte";
|
|
6
|
+
export { ApiStore, createApiStore, getApiStore, } from "./api.svelte";
|
|
7
7
|
export { createLanguageStore, getLanguageStore, } from "./language.svelte";
|
|
8
8
|
export { createCurrencyStore, getCurrencyStore, } from "./currency.svelte";
|
|
9
9
|
export { createToastStore, getToastStore, ToastStore } from "./toast.svelte";
|
|
10
10
|
export { CommandStore, createCommandStore, getCommandStore, } from "./commands.svelte";
|
|
11
11
|
export { createShortcutStore, getShortcutStore, LAYOUT_SHORTCUTS, shortcutListener, ShortcutStore, } from "./shortcuts.svelte";
|
|
12
12
|
export { createThemeStore, getThemeStore } from "./theme.svelte";
|
|
13
|
+
export { createConfigStore, } from "./createConfigStore.svelte";
|
|
14
|
+
export { createToastBridge, notify } from "./toast-bridge";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ConfigStore } from "
|
|
1
|
+
import { type ConfigStore } from "./createConfigStore.svelte";
|
|
2
2
|
/**
|
|
3
3
|
* Language configuration
|
|
4
4
|
* Represents a supported language in the application
|
|
@@ -48,7 +48,11 @@ export declare const LANGUAGES: readonly [{
|
|
|
48
48
|
readonly flag: "🇻🇳";
|
|
49
49
|
}];
|
|
50
50
|
import type { PersistenceDriver } from "../persistence/types";
|
|
51
|
-
export
|
|
51
|
+
export interface LanguageStoreOptions {
|
|
52
|
+
driver?: PersistenceDriver | (() => PersistenceDriver | undefined);
|
|
53
|
+
onLocaleChange?: (code: string) => void;
|
|
54
|
+
}
|
|
55
|
+
export declare function createLanguageStore(options?: LanguageStoreOptions): {
|
|
52
56
|
current: string | undefined;
|
|
53
57
|
available: Language[];
|
|
54
58
|
set(id: string | undefined): void;
|