rune-lab 0.0.1 → 0.0.2-alpha-2

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.
@@ -58,8 +58,6 @@
58
58
  ];
59
59
  </script>
60
60
 
61
- <ThemeSelector />
62
-
63
61
  <div class="min-h-screen bg-base-200 p-4">
64
62
  <!-- Header with Theme Demo -->
65
63
  <div class="text-center mb-8 hero bg-base-100 rounded-box p-8">
@@ -70,6 +68,7 @@
70
68
  <div class="flex justify-center gap-2">
71
69
  <button class="btn btn-primary" onclick={() => modalOpen = true}>Open Modal</button>
72
70
  <button class="btn btn-secondary" onclick={() => drawerOpen = true}>Open Drawer</button>
71
+ <ThemeSelector />
73
72
  </div>
74
73
  </div>
75
74
  </div>
@@ -337,7 +336,7 @@
337
336
  class="drawer-overlay"
338
337
  onclick={() => drawerOpen = false}
339
338
  onkeydown={(e) => e.key === 'Escape' && (drawerOpen = false)}
340
- ></button>
339
+ >.</button>
341
340
  <ul class="menu p-4 w-80 min-h-full bg-base-200 text-base-content">
342
341
  <li><button class="w-full text-left">Sidebar Item 1</button></li>
343
342
  <li><button class="w-full text-left">Sidebar Item 2</button></li>
@@ -0,0 +1,96 @@
1
+ <!-- Altharun (from Old Norse "aldir" = age, wisdom) -->
2
+ <!-- src/lib/components/data/Altharun.svelte -->
3
+ <script lang="ts">
4
+ import { onMount } from 'svelte';
5
+ import { databaseStore } from 'rune-lab';
6
+
7
+ onMount(async () => {
8
+ await databaseStore.init();
9
+ });
10
+
11
+ // Debug the schemas whenever they change
12
+ $effect(() => {
13
+ console.log('Current schemas:', Object.keys(databaseStore.schemas));
14
+ if (databaseStore.activeSchema) {
15
+ console.log('Active schema tables:',
16
+ Object.keys(databaseStore.schemas[databaseStore.activeSchema]));
17
+ }
18
+ });
19
+ </script>
20
+
21
+ <div class="container mx-auto px-4 py-8">
22
+ <h1 class="text-3xl font-bold mb-8">Database Management</h1>
23
+
24
+ {#each Object.keys(databaseStore.schemas) as schemaName}
25
+ {@const currentSchema = databaseStore.schemas[schemaName]}
26
+ <div class="mb-6">
27
+ <button
28
+ class="w-full flex items-center justify-between p-4 bg-base-200 rounded-lg"
29
+ onclick={() => databaseStore.toggleSchema(schemaName)}
30
+ >
31
+ <span class="text-xl font-semibold">{schemaName}</span>
32
+ <span class="transform transition-transform duration-200"
33
+ class:rotate-180={databaseStore.activeSchema === schemaName}>
34
+
35
+ </span>
36
+ </button>
37
+
38
+ {#if databaseStore.activeSchema === schemaName && currentSchema}
39
+ <div class="mt-4 space-y-2 pl-4">
40
+ {#each Object.keys(currentSchema) as tableName}
41
+ <div class="card bg-base-100 shadow-lg hover:shadow-xl transition-all">
42
+ <div class="card-body">
43
+ <div class="flex justify-between items-center mb-4">
44
+ <h3 class="card-title text-xl">{tableName}</h3>
45
+ <span class="badge badge-outline">{currentSchema[tableName].columns.length} columns</span>
46
+ </div>
47
+
48
+ <div class="overflow-x-auto">
49
+ <table class="table table-sm w-full">
50
+ <thead>
51
+ <tr>
52
+ <th>Column</th>
53
+ <th>Type</th>
54
+ <th class="text-center">Key</th>
55
+ <th class="text-center">Required</th>
56
+ </tr>
57
+ </thead>
58
+ <tbody>
59
+ {#each currentSchema[tableName].columns as column}
60
+ <tr class="hover">
61
+ <td class="font-mono">{column.name}</td>
62
+ <td class="text-sm opacity-75">{column.type}</td>
63
+ <td class="text-center">
64
+ {#if column.is_primary_key}
65
+ <span class="badge badge-primary badge-sm">PK</span>
66
+ {:else if column.is_foreign_key}
67
+ <span class="badge badge-secondary badge-sm">FK</span>
68
+ {/if}
69
+ </td>
70
+ <td class="text-center">
71
+ {#if column.is_primary_key || !column.nullable}
72
+ <span class="text-error">*</span>
73
+ {/if}
74
+ </td>
75
+ </tr>
76
+ {/each}
77
+ </tbody>
78
+ </table>
79
+ </div>
80
+
81
+ <div class="card-actions justify-end mt-4">
82
+ <button
83
+ class="btn btn-sm btn-primary"
84
+ onclick={() => databaseStore.setActiveTable(schemaName, tableName)}
85
+ >
86
+ Manage Table
87
+ </button>
88
+ </div>
89
+ </div>
90
+ </div>
91
+ {/each}
92
+ </div>
93
+ {/if}
94
+ </div>
95
+ {/each}
96
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const Altharun: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Altharun = ReturnType<typeof Altharun>;
3
+ export default Altharun;
@@ -0,0 +1,337 @@
1
+ <!-- Kyntharil (from Old Norse "kyn" = kind, kin + suffix -tharil suggesting evolution) -->
2
+ <!-- src/lib/components/dt/Kyntharil.svelte -->
3
+ <script lang="ts">
4
+ import { Gear, Database, User, X } from 'phosphor-svelte';
5
+ import { appData } from '../../stores/app.svelte.js';
6
+ import { apiStore } from '../../stores/api.svelte.js';
7
+ import { authStore } from '../../stores/auth.svelte.js';
8
+
9
+ // Local state management with runes
10
+ let isOpen = $state(false);
11
+ let activeTab = $state('app');
12
+ let testApiConnection = $state(false);
13
+ let showToast = $state(false);
14
+ let toastMessage = $state('');
15
+ let toastType = $state<'success' | 'error'>('success');
16
+
17
+ // Form states using runes
18
+ let appForm = $state({
19
+ name: appData.name,
20
+ version: appData.version,
21
+ description: appData.description,
22
+ author: appData.author
23
+ });
24
+
25
+ let apiForm = $state({
26
+ URL: apiStore.URL,
27
+ VERSION: apiStore.VERSION,
28
+ TIMEOUT: apiStore.TIMEOUT
29
+ });
30
+
31
+ let authForm = $state({
32
+ id: authStore.user?.id || '',
33
+ name: authStore.user?.name || '',
34
+ email: authStore.user?.email || '',
35
+ role: authStore.user?.role || 'user'
36
+ });
37
+
38
+ // Toast handler
39
+ function displayToast(message: string, type: 'success' | 'error' = 'success') {
40
+ toastMessage = message;
41
+ toastType = type;
42
+ showToast = true;
43
+ setTimeout(() => showToast = false, 3000);
44
+ }
45
+
46
+ // Form submission handlers
47
+ function handleAppSubmit() {
48
+ appData.init(appForm);
49
+ displayToast('App settings updated successfully');
50
+ }
51
+
52
+ async function handleApiSubmit() {
53
+ apiStore.init(apiForm);
54
+ if (testApiConnection) {
55
+ try {
56
+ await apiStore.checkConnection();
57
+ displayToast(
58
+ apiStore.IS_CONNECTED ? 'API connected successfully' : 'API connection failed',
59
+ apiStore.IS_CONNECTED ? 'success' : 'error'
60
+ );
61
+ } catch (error) {
62
+ displayToast('API connection check failed', 'error');
63
+ }
64
+ }
65
+ }
66
+
67
+ function handleAuthSubmit() {
68
+ if (authStore.isAuthenticated) {
69
+ authStore.login({
70
+ id: authForm.id,
71
+ name: authForm.name,
72
+ email: authForm.email,
73
+ role: authForm.role as 'admin' | 'staff' | 'user'
74
+ });
75
+ displayToast('Auth settings updated successfully');
76
+ } else {
77
+ displayToast('Please log in first', 'error');
78
+ }
79
+ }
80
+
81
+ // Tab configuration
82
+ const tabs = [
83
+ { id: 'app', icon: Gear, label: 'App Settings' },
84
+ { id: 'api', icon: Database, label: 'API Configuration' },
85
+ { id: 'auth', icon: User, label: 'Auth Management' }
86
+ ];
87
+ </script>
88
+
89
+ <div class="fixed bottom-4 right-4 z-50">
90
+ <!-- Toggle Button -->
91
+ <button
92
+ class="btn btn-circle btn-lg btn-primary"
93
+ onclick={() => isOpen = !isOpen}
94
+ aria-label="Toggle Store Manager"
95
+ >
96
+ <Gear size={24} class={isOpen ? 'animate-spin' : ''} />
97
+ </button>
98
+
99
+ <!-- Manager Panel -->
100
+ {#if isOpen}
101
+ <div class="fixed inset-0 bg-base-300 bg-opacity-50 backdrop-blur-sm">
102
+ <div class="absolute right-0 top-0 h-full w-96 bg-base-100 shadow-xl">
103
+ <!-- Header -->
104
+ <div class="flex items-center justify-between p-4 border-b border-base-200">
105
+ <h2 class="text-xl font-bold">Store Manager</h2>
106
+ <button
107
+ class="btn btn-ghost btn-circle"
108
+ onclick={() => isOpen = false}
109
+ aria-label="Close"
110
+ >
111
+ <X size={20} />
112
+ </button>
113
+ </div>
114
+
115
+ <!-- Tabs -->
116
+ <div class="tabs tabs-boxed m-4">
117
+ {#each tabs as tab}
118
+ <button
119
+ class="tab flex-1 {activeTab === tab.id ? 'tab-active' : ''}"
120
+ onclick={() => activeTab = tab.id}
121
+ >
122
+ <tab.icon size={16} class="mr-2" />
123
+ {tab.label}
124
+ </button>
125
+ {/each}
126
+ </div>
127
+
128
+ <!-- Content -->
129
+ <div class="p-4">
130
+ {#if activeTab === 'app'}
131
+ <form class="space-y-4" onsubmit={handleAppSubmit}>
132
+ <div class="form-control">
133
+ <label class="label" for="app-name">
134
+ <span class="label-text">App Name</span>
135
+ </label>
136
+ <input
137
+ id="app-name"
138
+ type="text"
139
+ class="input input-bordered"
140
+ bind:value={appForm.name}
141
+ />
142
+ </div>
143
+
144
+ <div class="form-control">
145
+ <label class="label" for="app-version">
146
+ <span class="label-text">Version</span>
147
+ </label>
148
+ <input
149
+ id="app-version"
150
+ type="text"
151
+ class="input input-bordered"
152
+ bind:value={appForm.version}
153
+ />
154
+ </div>
155
+
156
+ <div class="form-control">
157
+ <label class="label" for="app-description">
158
+ <span class="label-text">Description</span>
159
+ </label>
160
+ </div>
161
+
162
+ <div class="form-control">
163
+ <label class="label" for="app-author">
164
+ <span class="label-text">Author</span>
165
+ </label>
166
+ <input
167
+ id="app-author"
168
+ type="text"
169
+ class="input input-bordered"
170
+ bind:value={appForm.author}
171
+ />
172
+ </div>
173
+
174
+ <button type="submit" class="btn btn-primary w-full">
175
+ Update App Settings
176
+ </button>
177
+ </form>
178
+
179
+ {:else if activeTab === 'api'}
180
+ <form class="space-y-4" onsubmit={handleApiSubmit}>
181
+ <div class="form-control">
182
+ <label class="label" for="api-url">
183
+ <span class="label-text">API URL</span>
184
+ </label>
185
+ <input
186
+ id="api-url"
187
+ type="url"
188
+ class="input input-bordered"
189
+ bind:value={apiForm.URL}
190
+ />
191
+ </div>
192
+
193
+ <div class="form-control">
194
+ <label class="label" for="api-version">
195
+ <span class="label-text">API Version</span>
196
+ </label>
197
+ <input
198
+ id="api-version"
199
+ type="text"
200
+ class="input input-bordered"
201
+ bind:value={apiForm.VERSION}
202
+ />
203
+ </div>
204
+
205
+ <div class="form-control">
206
+ <label class="label" for="api-timeout">
207
+ <span class="label-text">Timeout (ms)</span>
208
+ </label>
209
+ <input
210
+ id="api-timeout"
211
+ type="number"
212
+ class="input input-bordered"
213
+ bind:value={apiForm.TIMEOUT}
214
+ />
215
+ </div>
216
+
217
+ <div class="form-control">
218
+ <label class="label cursor-pointer">
219
+ <span class="label-text">Test connection after update</span>
220
+ <input
221
+ type="checkbox"
222
+ class="toggle toggle-primary"
223
+ bind:checked={testApiConnection}
224
+ />
225
+ </label>
226
+ </div>
227
+
228
+ <div class="flex gap-2">
229
+ <button type="submit" class="btn btn-primary flex-1">
230
+ Update API Settings
231
+ </button>
232
+ <button
233
+ type="button"
234
+ class="btn btn-outline"
235
+ onclick={() => apiStore.checkConnection()}
236
+ >
237
+ Test Connection
238
+ </button>
239
+ </div>
240
+ </form>
241
+
242
+ {:else if activeTab === 'auth'}
243
+ <form class="space-y-4" onsubmit={handleAuthSubmit}>
244
+ <div class="form-control">
245
+ <label class="label" for="auth-id">
246
+ <span class="label-text">User ID</span>
247
+ </label>
248
+ <input
249
+ id="auth-id"
250
+ type="text"
251
+ class="input input-bordered"
252
+ bind:value={authForm.id}
253
+ />
254
+ </div>
255
+
256
+ <div class="form-control">
257
+ <label class="label" for="auth-name">
258
+ <span class="label-text">Name</span>
259
+ </label>
260
+ <input
261
+ id="auth-name"
262
+ type="text"
263
+ class="input input-bordered"
264
+ bind:value={authForm.name}
265
+ />
266
+ </div>
267
+
268
+ <div class="form-control">
269
+ <label class="label" for="auth-email">
270
+ <span class="label-text">Email</span>
271
+ </label>
272
+ <input
273
+ id="auth-email"
274
+ type="email"
275
+ class="input input-bordered"
276
+ bind:value={authForm.email}
277
+ />
278
+ </div>
279
+
280
+ <div class="form-control">
281
+ <label class="label" for="auth-role">
282
+ <span class="label-text">Role</span>
283
+ </label>
284
+ <select
285
+ id="auth-role"
286
+ class="select select-bordered"
287
+ bind:value={authForm.role}
288
+ >
289
+ <option value="user">User</option>
290
+ <option value="staff">Staff</option>
291
+ <option value="admin">Admin</option>
292
+ </select>
293
+ </div>
294
+
295
+ <div class="flex gap-2">
296
+ <button type="submit" class="btn btn-primary flex-1">
297
+ Update Auth Settings
298
+ </button>
299
+ <button
300
+ type="button"
301
+ class="btn btn-outline"
302
+ onclick={() => authStore.logout()}
303
+ >
304
+ Logout
305
+ </button>
306
+ </div>
307
+ </form>
308
+ {/if}
309
+ </div>
310
+
311
+ <!-- Status Bar -->
312
+ <div class="absolute bottom-0 w-full p-4 bg-base-200 border-t border-base-300">
313
+ <div class="flex items-center justify-between text-sm">
314
+ <div class="flex items-center gap-2">
315
+ <div class="badge badge-sm {apiStore.IS_CONNECTED ? 'badge-success' : 'badge-error'}">
316
+ API {apiStore.IS_CONNECTED ? 'Connected' : 'Disconnected'}
317
+ </div>
318
+ <div class="badge badge-sm {authStore.isAuthenticated ? 'badge-success' : 'badge-error'}">
319
+ {authStore.isAuthenticated ? 'Authenticated' : 'Not Authenticated'}
320
+ </div>
321
+ </div>
322
+ <span class="opacity-50">v{appData.version}</span>
323
+ </div>
324
+ </div>
325
+ </div>
326
+ </div>
327
+ {/if}
328
+
329
+ <!-- Toast Notification -->
330
+ {#if showToast}
331
+ <div class="toast toast-end">
332
+ <div class="alert alert-{toastType}">
333
+ <span>{toastMessage}</span>
334
+ </div>
335
+ </div>
336
+ {/if}
337
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const Kyntharil: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Kyntharil = ReturnType<typeof Kyntharil>;
3
+ export default Kyntharil;