rune-lab 0.0.19 → 0.0.20
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 +28 -6
- package/dist/actions/portal.js +6 -1
- package/dist/components/Icon.svelte +13 -2
- package/dist/components/RuneProvider.svelte +78 -0
- package/dist/components/RuneProvider.svelte.d.ts +9 -0
- package/dist/composables/useRuneLab.d.ts +17 -0
- package/dist/composables/useRuneLab.js +19 -0
- package/dist/config.d.ts +4 -85
- package/dist/config.js +6 -32
- package/dist/context.d.ts +11 -0
- package/dist/context.js +12 -0
- package/dist/devtools/API_Monitor.svelte +5 -2
- package/dist/devtools/Toaster.svelte +13 -8
- package/dist/devtools/createConfigStore.svelte.d.ts +11 -1
- package/dist/devtools/createConfigStore.svelte.js +13 -11
- package/dist/features/command-palette/CommandPalette.svelte +12 -4
- package/dist/features/config/components/AppSettingSelector.svelte +85 -3
- package/dist/features/config/components/AppSettingSelector.svelte.d.ts +2 -0
- package/dist/features/config/components/CurrencySelector.svelte +27 -9
- package/dist/features/config/components/CurrencySelector.svelte.d.ts +3 -1
- package/dist/features/config/components/LanguageSelector.svelte +21 -6
- package/dist/features/config/components/LanguageSelector.svelte.d.ts +3 -1
- package/dist/features/config/components/ThemeSelector.svelte +23 -8
- package/dist/features/config/components/ThemeSelector.svelte.d.ts +3 -1
- package/dist/features/detail-panels/DashboardPanel.svelte +34 -17
- package/dist/features/detail-panels/ShortcutsPanel.svelte +185 -88
- package/dist/features/detail-panels/ShowcasePanel.svelte +20 -6
- package/dist/features/shortcuts/ShortcutPalette.svelte +14 -6
- package/dist/index.d.ts +7 -1
- package/dist/index.js +9 -6
- package/dist/layout/NavigationPanel.svelte +63 -117
- package/dist/layout/WorkspaceLayout.svelte +74 -30
- package/dist/layout/WorkspaceLayout.svelte.d.ts +2 -2
- package/dist/layout/WorkspaceStrip.svelte +11 -3
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/index.js +1 -1
- package/dist/paraglide/runtime.d.ts +43 -2
- package/dist/paraglide/runtime.js +143 -23
- package/dist/paraglide/server.js +37 -14
- package/dist/persistence/drivers.d.ts +10 -0
- package/dist/persistence/drivers.js +71 -0
- package/dist/persistence/types.d.ts +17 -0
- package/dist/persistence/types.js +2 -0
- package/dist/showcase/AppStateInspector.svelte +26 -11
- package/dist/showcase/Showcase.svelte +4 -1
- package/dist/state/api.svelte.d.ts +3 -3
- package/dist/state/api.svelte.js +9 -2
- package/dist/state/app.svelte.d.ts +3 -3
- package/dist/state/app.svelte.js +14 -4
- package/dist/state/commands.svelte.d.ts +21 -4
- package/dist/state/commands.svelte.js +92 -90
- package/dist/state/currency.svelte.d.ts +4 -1
- package/dist/state/currency.svelte.js +16 -8
- package/dist/state/index.d.ts +9 -9
- package/dist/state/index.js +10 -9
- package/dist/state/language.svelte.d.ts +4 -1
- package/dist/state/language.svelte.js +27 -8
- package/dist/state/layout.svelte.d.ts +10 -3
- package/dist/state/layout.svelte.js +56 -14
- package/dist/state/shortcuts.svelte.d.ts +56 -6
- package/dist/state/shortcuts.svelte.js +21 -69
- package/dist/state/theme.svelte.d.ts +4 -1
- package/dist/state/theme.svelte.js +16 -8
- package/dist/state/toast.svelte.d.ts +3 -3
- package/dist/state/toast.svelte.js +9 -2
- package/package.json +9 -9
- package/dist/features/command-palette/commands.svelte.d.ts +0 -8
- package/dist/features/command-palette/commands.svelte.js +0 -5
- package/dist/features/config/stores/api.svelte.d.ts +0 -13
- package/dist/features/config/stores/api.svelte.js +0 -5
- package/dist/features/config/stores/app.svelte.d.ts +0 -13
- package/dist/features/config/stores/app.svelte.js +0 -5
- package/dist/features/config/stores/currency.svelte.d.ts +0 -8
- package/dist/features/config/stores/currency.svelte.js +0 -5
- package/dist/features/config/stores/language.svelte.d.ts +0 -8
- package/dist/features/config/stores/language.svelte.js +0 -5
- package/dist/features/config/stores/theme.svelte.d.ts +0 -8
- package/dist/features/config/stores/theme.svelte.js +0 -5
- package/dist/features/config/stores/toast.svelte.d.ts +0 -9
- package/dist/features/config/stores/toast.svelte.js +0 -5
package/README.md
CHANGED
|
@@ -60,16 +60,18 @@ bun install rune-lab
|
|
|
60
60
|
|
|
61
61
|
## Project Configuration
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
After installing, two configuration steps are required to ensure components are
|
|
64
|
+
compiled and styled correctly in your consuming project.
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
`.svelte` files from this package would be loaded as raw ES modules, bypassing
|
|
67
|
-
the Svelte compiler. To prevent this, you need to tell Vite to process
|
|
68
|
-
`rune-lab` through its plugin pipeline.
|
|
66
|
+
### Step 1 — Vite: process `rune-lab` through the Svelte compiler
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
Vite's SSR module runner externalizes `node_modules` by default, which means
|
|
69
|
+
`.svelte` files from this package would be loaded as raw ES modules, bypassing
|
|
70
|
+
the Svelte compiler entirely. Add the following to your `vite.config.ts` to
|
|
71
|
+
force Vite to process `rune-lab` through its plugin pipeline:
|
|
71
72
|
|
|
72
73
|
```ts
|
|
74
|
+
// vite.config.ts
|
|
73
75
|
export default defineConfig({
|
|
74
76
|
plugins: [sveltekit()],
|
|
75
77
|
ssr: {
|
|
@@ -81,6 +83,26 @@ export default defineConfig({
|
|
|
81
83
|
This ensures the Svelte plugin transforms the components correctly during SSR,
|
|
82
84
|
just as it would for your own source files.
|
|
83
85
|
|
|
86
|
+
### Step 2 — Tailwind CSS: scan `rune-lab` for utility classes
|
|
87
|
+
|
|
88
|
+
Tailwind only generates CSS for the classes it can find by scanning your source
|
|
89
|
+
files. Because `rune-lab` lives in `node_modules`, its DaisyUI classes are not
|
|
90
|
+
scanned by default and the components will appear unstyled.
|
|
91
|
+
|
|
92
|
+
Add a `@source` directive to your project's main CSS file to tell Tailwind to
|
|
93
|
+
also scan the `rune-lab` dist output:
|
|
94
|
+
|
|
95
|
+
```css
|
|
96
|
+
/* app.css / layout.css / global.css — wherever you import Tailwind */
|
|
97
|
+
@import "tailwindcss";
|
|
98
|
+
@source "../node_modules/rune-lab/dist"; /* 👈 add this */
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> **Note:** Adjust the relative path to `node_modules` if your CSS file lives at
|
|
102
|
+
> a different depth in your project tree. With both steps in place, all DaisyUI
|
|
103
|
+
> component classes used by `rune-lab` will be included in your build and theme
|
|
104
|
+
> switching will work across library components and your own code alike.
|
|
105
|
+
|
|
84
106
|
## License
|
|
85
107
|
|
|
86
108
|
MIT License - See [LICENSE](LICENSE) for details.
|
package/dist/actions/portal.js
CHANGED
|
@@ -3,22 +3,27 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export function portal(node, target = "body") {
|
|
5
5
|
let targetNode;
|
|
6
|
+
let isTeleported = false;
|
|
6
7
|
function update(newTarget) {
|
|
7
8
|
if (typeof newTarget === "string") {
|
|
8
9
|
targetNode = document.querySelector(newTarget);
|
|
10
|
+
if (!targetNode && import.meta.env?.DEV) {
|
|
11
|
+
console.warn(`portal target selector "${newTarget}" not found in document.`);
|
|
12
|
+
}
|
|
9
13
|
}
|
|
10
14
|
else {
|
|
11
15
|
targetNode = newTarget;
|
|
12
16
|
}
|
|
13
17
|
if (targetNode) {
|
|
14
18
|
targetNode.appendChild(node);
|
|
19
|
+
isTeleported = true;
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
22
|
update(target);
|
|
18
23
|
return {
|
|
19
24
|
update,
|
|
20
25
|
destroy() {
|
|
21
|
-
if (node.parentNode) {
|
|
26
|
+
if (isTeleported && node.parentNode) {
|
|
22
27
|
node.parentNode.removeChild(node);
|
|
23
28
|
}
|
|
24
29
|
},
|
|
@@ -15,8 +15,19 @@
|
|
|
15
15
|
info: '<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>',
|
|
16
16
|
shortcut: '<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
|
|
17
17
|
close: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
|
|
18
|
-
external: '<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>'
|
|
18
|
+
external: '<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>',
|
|
19
|
+
unknown: '<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>'
|
|
19
20
|
};
|
|
21
|
+
|
|
22
|
+
const path = $derived.by(() => {
|
|
23
|
+
if (!paths[name]) {
|
|
24
|
+
if (import.meta.env?.DEV) {
|
|
25
|
+
console.warn(`[Icon] Unknown icon name: "${name}"`);
|
|
26
|
+
}
|
|
27
|
+
return paths.unknown;
|
|
28
|
+
}
|
|
29
|
+
return paths[name];
|
|
30
|
+
});
|
|
20
31
|
</script>
|
|
21
32
|
|
|
22
33
|
<svg
|
|
@@ -30,5 +41,5 @@
|
|
|
30
41
|
class="{size} {className}"
|
|
31
42
|
>
|
|
32
43
|
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
33
|
-
{@html
|
|
44
|
+
{@html path}
|
|
34
45
|
</svg>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { setContext, type Snippet } from "svelte";
|
|
3
|
+
import {
|
|
4
|
+
createAppStore,
|
|
5
|
+
createLayoutStore,
|
|
6
|
+
createCommandStore,
|
|
7
|
+
createApiStore,
|
|
8
|
+
createToastStore,
|
|
9
|
+
createThemeStore,
|
|
10
|
+
createLanguageStore,
|
|
11
|
+
createCurrencyStore,
|
|
12
|
+
createShortcutStore,
|
|
13
|
+
} from "../state/index";
|
|
14
|
+
import { Toaster, CommandPalette, ShortcutPalette } from "../index";
|
|
15
|
+
|
|
16
|
+
import type { PersistenceDriver } from "../persistence/types";
|
|
17
|
+
import { RUNE_LAB_CONTEXT } from "../context";
|
|
18
|
+
|
|
19
|
+
let { children, persistence } = $props<{
|
|
20
|
+
children: Snippet;
|
|
21
|
+
persistence?: PersistenceDriver;
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
// 1. Initialize Base Configuration Stores
|
|
25
|
+
const appStore = createAppStore();
|
|
26
|
+
const apiStore = createApiStore();
|
|
27
|
+
const toastStore = createToastStore();
|
|
28
|
+
// We use a closure approach (`() => persistence`) as supported by the updated config definitions,
|
|
29
|
+
// to strictly respect Svelte 5 state capturing validations without disabling them globally.
|
|
30
|
+
const themeStore = createThemeStore(() => persistence);
|
|
31
|
+
const languageStore = createLanguageStore(() => persistence);
|
|
32
|
+
const currencyStore = createCurrencyStore(() => persistence);
|
|
33
|
+
const shortcutStore = createShortcutStore();
|
|
34
|
+
|
|
35
|
+
// 2. Initialize Complex Stores (Dependency Injection)
|
|
36
|
+
const layoutStore = createLayoutStore(() => persistence);
|
|
37
|
+
const commandStore = createCommandStore({
|
|
38
|
+
appStore,
|
|
39
|
+
apiStore,
|
|
40
|
+
toastStore,
|
|
41
|
+
themeStore,
|
|
42
|
+
languageStore,
|
|
43
|
+
currencyStore,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// 3. Provide Contexts
|
|
47
|
+
setContext(RUNE_LAB_CONTEXT.app, appStore);
|
|
48
|
+
setContext(RUNE_LAB_CONTEXT.api, apiStore);
|
|
49
|
+
setContext(RUNE_LAB_CONTEXT.toast, toastStore);
|
|
50
|
+
setContext(RUNE_LAB_CONTEXT.theme, themeStore);
|
|
51
|
+
setContext(RUNE_LAB_CONTEXT.language, languageStore);
|
|
52
|
+
setContext(RUNE_LAB_CONTEXT.currency, currencyStore);
|
|
53
|
+
setContext(RUNE_LAB_CONTEXT.shortcut, shortcutStore);
|
|
54
|
+
setContext(RUNE_LAB_CONTEXT.layout, layoutStore);
|
|
55
|
+
setContext(RUNE_LAB_CONTEXT.commands, commandStore);
|
|
56
|
+
|
|
57
|
+
// Meta tags derived from app store state
|
|
58
|
+
const metaTags = $derived([
|
|
59
|
+
{ name: "description", content: appStore.description },
|
|
60
|
+
{ name: "author", content: appStore.author },
|
|
61
|
+
]);
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<svelte:head>
|
|
65
|
+
<title>{appStore.name}</title>
|
|
66
|
+
<link rel="icon" href={"/img/rune.png"} />
|
|
67
|
+
{#each metaTags as meta}
|
|
68
|
+
<meta name={meta.name} content={meta.content} />
|
|
69
|
+
{/each}
|
|
70
|
+
</svelte:head>
|
|
71
|
+
|
|
72
|
+
<!-- Global Overlays -->
|
|
73
|
+
<Toaster />
|
|
74
|
+
<CommandPalette />
|
|
75
|
+
<ShortcutPalette />
|
|
76
|
+
|
|
77
|
+
<!-- Render Children -->
|
|
78
|
+
{@render children()}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Snippet } from "svelte";
|
|
2
|
+
import type { PersistenceDriver } from "../persistence/types";
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
children: Snippet;
|
|
5
|
+
persistence?: PersistenceDriver;
|
|
6
|
+
};
|
|
7
|
+
declare const RuneProvider: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type RuneProvider = ReturnType<typeof RuneProvider>;
|
|
9
|
+
export default RuneProvider;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getApiStore, getAppStore, getCommandStore, getCurrencyStore, getLanguageStore, getLayoutStore, getShortcutStore, getThemeStore, getToastStore } from "../state/index";
|
|
2
|
+
export interface RuneLabContext {
|
|
3
|
+
app: ReturnType<typeof getAppStore>;
|
|
4
|
+
api: ReturnType<typeof getApiStore>;
|
|
5
|
+
toast: ReturnType<typeof getToastStore>;
|
|
6
|
+
theme: ReturnType<typeof getThemeStore>;
|
|
7
|
+
language: ReturnType<typeof getLanguageStore>;
|
|
8
|
+
currency: ReturnType<typeof getCurrencyStore>;
|
|
9
|
+
shortcut: ReturnType<typeof getShortcutStore>;
|
|
10
|
+
layout: ReturnType<typeof getLayoutStore>;
|
|
11
|
+
commands: ReturnType<typeof getCommandStore>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Retrieves all Rune Lab stores from the Svelte context tree.
|
|
15
|
+
* Must be called during component initialization (in the `<script>` block).
|
|
16
|
+
*/
|
|
17
|
+
export declare function useRuneLab(): RuneLabContext;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/lib/composables/useRuneLab.ts
|
|
2
|
+
import { getApiStore, getAppStore, getCommandStore, getCurrencyStore, getLanguageStore, getLayoutStore, getShortcutStore, getThemeStore, getToastStore, } from "../state/index";
|
|
3
|
+
/**
|
|
4
|
+
* Retrieves all Rune Lab stores from the Svelte context tree.
|
|
5
|
+
* Must be called during component initialization (in the `<script>` block).
|
|
6
|
+
*/
|
|
7
|
+
export function useRuneLab() {
|
|
8
|
+
return {
|
|
9
|
+
app: getAppStore(),
|
|
10
|
+
api: getApiStore(),
|
|
11
|
+
toast: getToastStore(),
|
|
12
|
+
theme: getThemeStore(),
|
|
13
|
+
language: getLanguageStore(),
|
|
14
|
+
currency: getCurrencyStore(),
|
|
15
|
+
shortcut: getShortcutStore(),
|
|
16
|
+
layout: getLayoutStore(),
|
|
17
|
+
commands: getCommandStore(),
|
|
18
|
+
};
|
|
19
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,85 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* @example
|
|
6
|
-
* ```ts
|
|
7
|
-
* import { appConfig } from 'rune-lab/config';
|
|
8
|
-
*
|
|
9
|
-
* appConfig.app.init({ name: 'My App', version: '1.0.0' });
|
|
10
|
-
* appConfig.api.init('https://api.example.com', 'v1');
|
|
11
|
-
* appConfig.toast.success('Ready!');
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
export declare const appConfig: {
|
|
15
|
-
/** Application metadata (name, version, description…) */
|
|
16
|
-
readonly app: {
|
|
17
|
-
name: string;
|
|
18
|
-
version: string;
|
|
19
|
-
description: string;
|
|
20
|
-
author: string;
|
|
21
|
-
repository: string;
|
|
22
|
-
license: string;
|
|
23
|
-
homepage: string;
|
|
24
|
-
"__#private@#initialized": boolean;
|
|
25
|
-
init(data: Partial<import(".").AppData>): void;
|
|
26
|
-
get info(): import(".").AppData;
|
|
27
|
-
};
|
|
28
|
-
/** API connection state and base URL */
|
|
29
|
-
readonly api: {
|
|
30
|
-
url: string;
|
|
31
|
-
version: string;
|
|
32
|
-
connectionState: import("./state/api.svelte").ConnectionState;
|
|
33
|
-
isConnected: boolean;
|
|
34
|
-
isLoading: boolean;
|
|
35
|
-
get URL(): string;
|
|
36
|
-
get VERSION(): string;
|
|
37
|
-
get IS_CONNECTED(): boolean;
|
|
38
|
-
get IS_LOADING(): boolean;
|
|
39
|
-
reconnect(): Promise<void>;
|
|
40
|
-
init(url: string, version?: string): void;
|
|
41
|
-
};
|
|
42
|
-
/** Active theme + available themes */
|
|
43
|
-
readonly theme: {
|
|
44
|
-
current: string;
|
|
45
|
-
available: import(".").Theme[];
|
|
46
|
-
set(id: string): void;
|
|
47
|
-
get(id: string): import(".").Theme | undefined;
|
|
48
|
-
getProp<K extends keyof import(".").Theme>(prop: K, id?: string | undefined): import(".").Theme[K] | undefined;
|
|
49
|
-
};
|
|
50
|
-
/** Active language / locale */
|
|
51
|
-
readonly language: {
|
|
52
|
-
current: string | undefined;
|
|
53
|
-
available: import(".").Language[];
|
|
54
|
-
set(id: string | undefined): void;
|
|
55
|
-
get(id: string | undefined): import(".").Language | undefined;
|
|
56
|
-
getProp<K extends keyof import(".").Language>(prop: K, id?: string | undefined): import(".").Language[K] | undefined;
|
|
57
|
-
};
|
|
58
|
-
/** Active currency */
|
|
59
|
-
readonly currency: {
|
|
60
|
-
current: string | number;
|
|
61
|
-
available: import(".").Currency[];
|
|
62
|
-
set(id: string | number): void;
|
|
63
|
-
get(id: string | number): import(".").Currency | undefined;
|
|
64
|
-
getProp<K extends keyof import(".").Currency>(prop: K, id?: string | number | undefined): import(".").Currency[K] | undefined;
|
|
65
|
-
};
|
|
66
|
-
/** Toast notification queue */
|
|
67
|
-
readonly toast: {
|
|
68
|
-
toasts: import("./state/toast.svelte").Toast[];
|
|
69
|
-
send(message: string, type?: import("./state/toast.svelte").ToastType, duration?: number): void;
|
|
70
|
-
dismiss(id: string): void;
|
|
71
|
-
success(msg: string): void;
|
|
72
|
-
error(msg: string): void;
|
|
73
|
-
warn(msg: string): void;
|
|
74
|
-
info(msg: string): void;
|
|
75
|
-
};
|
|
76
|
-
/** Command palette registry */
|
|
77
|
-
readonly commands: {
|
|
78
|
-
commands: import(".").Command[];
|
|
79
|
-
register(command: import(".").Command): void;
|
|
80
|
-
unregister(id: string): void;
|
|
81
|
-
search(query: string, parentId?: string): import(".").Command[];
|
|
82
|
-
"__#private@#findById"(id: string, list: import(".").Command[]): import(".").Command | undefined;
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
export { apiStore, appStore, commandStore, currencyStore, languageStore, themeStore, toastStore, };
|
|
1
|
+
export { AppStore, createAppStore, getAppStore } from "./state/app.svelte";
|
|
2
|
+
export { createLayoutStore, getLayoutStore, LayoutStore, } from "./state/layout.svelte";
|
|
3
|
+
export { type Command, CommandStore, createCommandStore, getCommandStore, } from "./state/commands.svelte";
|
|
4
|
+
export { createApiStore, createCurrencyStore, createLanguageStore, createShortcutStore, createThemeStore, createToastStore, getApiStore, getCurrencyStore, getLanguageStore, getShortcutStore, getThemeStore, getToastStore, } from "./state/index";
|
package/dist/config.js
CHANGED
|
@@ -1,34 +1,8 @@
|
|
|
1
1
|
// src/lib/config.ts
|
|
2
2
|
// Unified facade over all app-level stores.
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* ```ts
|
|
10
|
-
* import { appConfig } from 'rune-lab/config';
|
|
11
|
-
*
|
|
12
|
-
* appConfig.app.init({ name: 'My App', version: '1.0.0' });
|
|
13
|
-
* appConfig.api.init('https://api.example.com', 'v1');
|
|
14
|
-
* appConfig.toast.success('Ready!');
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
export const appConfig = {
|
|
18
|
-
/** Application metadata (name, version, description…) */
|
|
19
|
-
app: appStore,
|
|
20
|
-
/** API connection state and base URL */
|
|
21
|
-
api: apiStore,
|
|
22
|
-
/** Active theme + available themes */
|
|
23
|
-
theme: themeStore,
|
|
24
|
-
/** Active language / locale */
|
|
25
|
-
language: languageStore,
|
|
26
|
-
/** Active currency */
|
|
27
|
-
currency: currencyStore,
|
|
28
|
-
/** Toast notification queue */
|
|
29
|
-
toast: toastStore,
|
|
30
|
-
/** Command palette registry */
|
|
31
|
-
commands: commandStore,
|
|
32
|
-
};
|
|
33
|
-
// Re-export individual stores for consumers who want fine-grained imports
|
|
34
|
-
export { apiStore, appStore, commandStore, currencyStore, languageStore, themeStore, toastStore, };
|
|
3
|
+
// Updated for SSR safety: Re-exports factories for context-aware stores.
|
|
4
|
+
export { AppStore, createAppStore, getAppStore } from "./state/app.svelte";
|
|
5
|
+
export { createLayoutStore, getLayoutStore, LayoutStore, } from "./state/layout.svelte";
|
|
6
|
+
export { CommandStore, createCommandStore, getCommandStore, } from "./state/commands.svelte";
|
|
7
|
+
// These stores are factories now
|
|
8
|
+
export { createApiStore, createCurrencyStore, createLanguageStore, createShortcutStore, createThemeStore, createToastStore, getApiStore, getCurrencyStore, getLanguageStore, getShortcutStore, getThemeStore, getToastStore, } from "./state/index";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const RUNE_LAB_CONTEXT: {
|
|
2
|
+
readonly app: symbol;
|
|
3
|
+
readonly api: symbol;
|
|
4
|
+
readonly toast: symbol;
|
|
5
|
+
readonly theme: symbol;
|
|
6
|
+
readonly language: symbol;
|
|
7
|
+
readonly currency: symbol;
|
|
8
|
+
readonly shortcut: symbol;
|
|
9
|
+
readonly layout: symbol;
|
|
10
|
+
readonly commands: symbol;
|
|
11
|
+
};
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/lib/context.ts
|
|
2
|
+
export const RUNE_LAB_CONTEXT = {
|
|
3
|
+
app: Symbol("rl:app"),
|
|
4
|
+
api: Symbol("rl:api"),
|
|
5
|
+
toast: Symbol("rl:toast"),
|
|
6
|
+
theme: Symbol("rl:theme"),
|
|
7
|
+
language: Symbol("rl:language"),
|
|
8
|
+
currency: Symbol("rl:currency"),
|
|
9
|
+
shortcut: Symbol("rl:shortcut"),
|
|
10
|
+
layout: Symbol("rl:layout"),
|
|
11
|
+
commands: Symbol("rl:commands"),
|
|
12
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { getApiStore } from "../state/api.svelte";
|
|
3
|
+
import { getToastStore } from "../state/toast.svelte";
|
|
4
|
+
|
|
5
|
+
const apiStore = getApiStore();
|
|
6
|
+
const toastStore = getToastStore();
|
|
4
7
|
|
|
5
8
|
let copied = $state(false);
|
|
6
9
|
let isVisible = $state(true);
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { getToastStore } from "../state/toast.svelte";
|
|
3
3
|
import { portal } from "../actions/portal";
|
|
4
4
|
import { flip } from "svelte/animate";
|
|
5
5
|
import { fade, fly } from "svelte/transition";
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const toastStore = getToastStore();
|
|
8
|
+
|
|
9
|
+
const typeDetails: Record<
|
|
10
|
+
string,
|
|
11
|
+
{ colors: string; iconColor: string; iconPath: string }
|
|
12
|
+
> = {
|
|
8
13
|
info: {
|
|
9
14
|
colors:
|
|
10
15
|
"bg-blue-500/10 border-blue-500/20 text-blue-600 dark:text-blue-400",
|
|
11
16
|
iconColor: "text-blue-500",
|
|
12
17
|
iconPath:
|
|
13
|
-
"
|
|
18
|
+
"M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.72 6.97a.75.75 0 1 0-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 1 0 1.06 1.06L12 13.06l1.72 1.72a.75.75 0 1 0 1.06-1.06L13.06 12l1.72-1.72a.75.75 0 1 0-1.06-1.06L12 10.94l-1.72-1.72Z",
|
|
14
19
|
},
|
|
15
20
|
success: {
|
|
16
21
|
colors:
|
|
@@ -24,7 +29,7 @@
|
|
|
24
29
|
"bg-amber-500/10 border-amber-500/20 text-amber-600 dark:text-amber-400",
|
|
25
30
|
iconColor: "text-amber-500",
|
|
26
31
|
iconPath:
|
|
27
|
-
"
|
|
32
|
+
"M12 9a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z", // This path looks wrong in original, replacing with simpler
|
|
28
33
|
},
|
|
29
34
|
error: {
|
|
30
35
|
colors: "bg-red-500/10 border-red-500/20 text-red-600 dark:text-red-400",
|
|
@@ -35,13 +40,13 @@
|
|
|
35
40
|
};
|
|
36
41
|
</script>
|
|
37
42
|
|
|
38
|
-
<
|
|
39
|
-
this={"div"}
|
|
43
|
+
<div
|
|
40
44
|
use:portal
|
|
41
45
|
class="toast toast-end toast-bottom z-[9999] p-4 gap-3 pointer-events-none"
|
|
42
46
|
>
|
|
43
47
|
{#each toastStore.toasts as toast (toast.id)}
|
|
44
|
-
{@const styles = typeDetails[toast.type]}
|
|
48
|
+
{@const styles = typeDetails[toast.type] || typeDetails.info}
|
|
49
|
+
|
|
45
50
|
<div
|
|
46
51
|
animate:flip={{ duration: 300 }}
|
|
47
52
|
in:fly={{ y: 20, duration: 300 }}
|
|
@@ -96,4 +101,4 @@
|
|
|
96
101
|
></div>
|
|
97
102
|
</div>
|
|
98
103
|
{/each}
|
|
99
|
-
</
|
|
104
|
+
</div>
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import { type PersistenceDriver } from "../persistence/types";
|
|
2
|
+
export type ConfigStore<T extends ConfigItem> = {
|
|
3
|
+
current: T[keyof T];
|
|
4
|
+
available: T[];
|
|
5
|
+
set: (id: T[keyof T]) => void;
|
|
6
|
+
get: (id: T[keyof T]) => T | undefined;
|
|
7
|
+
getProp: <K extends keyof T>(prop: K, id?: T[keyof T]) => T[K] | undefined;
|
|
8
|
+
};
|
|
1
9
|
/**
|
|
2
10
|
* Generic configuration store factory
|
|
3
11
|
* Creates type-safe stores for theme, language, currency, etc.
|
|
@@ -9,7 +17,7 @@ interface ConfigItem {
|
|
|
9
17
|
interface ConfigStoreOptions<T extends ConfigItem> {
|
|
10
18
|
/** Array of available items */
|
|
11
19
|
items: readonly T[];
|
|
12
|
-
/**
|
|
20
|
+
/** Storage key used by the persistence driver */
|
|
13
21
|
storageKey: string;
|
|
14
22
|
/** Display name for logging (e.g., "Theme", "Language") */
|
|
15
23
|
displayName: string;
|
|
@@ -17,6 +25,8 @@ interface ConfigStoreOptions<T extends ConfigItem> {
|
|
|
17
25
|
idKey: keyof T;
|
|
18
26
|
/** Icon for logs */
|
|
19
27
|
icon?: string;
|
|
28
|
+
/** Persistence driver */
|
|
29
|
+
driver?: PersistenceDriver;
|
|
20
30
|
}
|
|
21
31
|
/**
|
|
22
32
|
* Creates a reactive configuration store with persistence
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
// client/sdk/devtools/src/patterns/createConfigStore.svelte.ts
|
|
2
|
+
import {} from "../persistence/types";
|
|
3
|
+
import { createInMemoryDriver } from "../persistence/drivers";
|
|
2
4
|
/**
|
|
3
5
|
* Creates a reactive configuration store with persistence
|
|
4
6
|
*/
|
|
5
7
|
export function createConfigStore(options) {
|
|
6
|
-
const { items, storageKey, displayName, idKey, icon = "⚙️" } = options;
|
|
8
|
+
const { items, storageKey, displayName, idKey, icon = "⚙️", driver = createInMemoryDriver(), } = options;
|
|
7
9
|
class ConfigStore {
|
|
8
10
|
current = $state(items[0]?.[idKey] ?? "");
|
|
9
11
|
available = $state([...items]);
|
|
10
12
|
constructor() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const saved = driver.get(storageKey);
|
|
14
|
+
// Only load saved if it actually exists in our available items
|
|
15
|
+
if (saved && this.get(saved)) {
|
|
16
|
+
this.current = saved;
|
|
17
|
+
}
|
|
18
|
+
if (import.meta.env?.DEV) {
|
|
19
|
+
console.log(`${icon} ${displayName} configured:`, {
|
|
20
|
+
current: this.current,
|
|
21
|
+
});
|
|
17
22
|
}
|
|
18
|
-
console.log(`${icon} ${displayName} configured:`, {
|
|
19
|
-
current: this.current,
|
|
20
|
-
});
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Set current item with validation
|
|
@@ -29,7 +31,7 @@ export function createConfigStore(options) {
|
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
33
|
this.current = id;
|
|
32
|
-
|
|
34
|
+
driver.set(storageKey, String(id));
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* Get item by id
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
<!-- src/client/sdk/ui/src/features/config/CommandPalette.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
3
|
import { onMount, tick } from "svelte";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { getCommandStore, type Command } from "../../state/commands.svelte";
|
|
5
|
+
import { getShortcutStore } from "../../state/shortcuts.svelte";
|
|
6
6
|
import { Icon } from "../../index";
|
|
7
7
|
|
|
8
8
|
let { shortcutKey = "shift+k" } = $props<{ shortcutKey?: string }>();
|
|
9
9
|
|
|
10
|
+
const commandStore = getCommandStore();
|
|
11
|
+
const shortcutStore = getShortcutStore();
|
|
12
|
+
|
|
10
13
|
let dialog: HTMLDialogElement;
|
|
11
14
|
let input: HTMLInputElement;
|
|
12
15
|
let query = $state("");
|
|
@@ -176,7 +179,7 @@
|
|
|
176
179
|
{/if}
|
|
177
180
|
<div class="flex flex-col items-start">
|
|
178
181
|
<span class="font-medium"
|
|
179
|
-
>{cmd.
|
|
182
|
+
>{cmd.label}</span
|
|
180
183
|
>
|
|
181
184
|
{#if cmd.category}
|
|
182
185
|
<span class="text-xs opacity-70"
|
|
@@ -214,6 +217,11 @@
|
|
|
214
217
|
</div>
|
|
215
218
|
</div>
|
|
216
219
|
<form method="dialog" class="modal-backdrop">
|
|
217
|
-
<button
|
|
220
|
+
<button
|
|
221
|
+
onclick={(e) => {
|
|
222
|
+
e.preventDefault();
|
|
223
|
+
isOpen = false;
|
|
224
|
+
}}>close</button
|
|
225
|
+
>
|
|
218
226
|
</form>
|
|
219
227
|
</dialog>
|