@salmexio/ui 0.3.1 → 1.0.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 +52 -3
- package/dist/dialogs/ContextMenu/ContextMenu.svelte +96 -93
- package/dist/dialogs/ContextMenu/ContextMenu.svelte.d.ts +3 -2
- package/dist/dialogs/ContextMenu/ContextMenu.svelte.d.ts.map +1 -1
- package/dist/dialogs/Modal/Modal.svelte +112 -102
- package/dist/dialogs/Modal/Modal.svelte.d.ts +1 -1
- package/dist/feedback/Alert/Alert.svelte +115 -221
- package/dist/feedback/Alert/Alert.svelte.d.ts +1 -1
- package/dist/feedback/ProgressBar/ProgressBar.svelte +246 -0
- package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts +40 -0
- package/dist/feedback/ProgressBar/ProgressBar.svelte.d.ts.map +1 -0
- package/dist/feedback/ProgressBar/index.d.ts +2 -0
- package/dist/feedback/ProgressBar/index.d.ts.map +1 -0
- package/dist/feedback/ProgressBar/index.js +1 -0
- package/dist/feedback/Skeleton/Skeleton.svelte +153 -0
- package/dist/feedback/Skeleton/Skeleton.svelte.d.ts +37 -0
- package/dist/feedback/Skeleton/Skeleton.svelte.d.ts.map +1 -0
- package/dist/feedback/Skeleton/index.d.ts +2 -0
- package/dist/feedback/Skeleton/index.d.ts.map +1 -0
- package/dist/feedback/Skeleton/index.js +1 -0
- package/dist/feedback/Spinner/Spinner.svelte +88 -154
- package/dist/feedback/Spinner/Spinner.svelte.d.ts +5 -3
- package/dist/feedback/Spinner/Spinner.svelte.d.ts.map +1 -1
- package/dist/feedback/Toast/Toaster.svelte +431 -0
- package/dist/feedback/Toast/Toaster.svelte.d.ts +22 -0
- package/dist/feedback/Toast/Toaster.svelte.d.ts.map +1 -0
- package/dist/feedback/Toast/index.d.ts +4 -0
- package/dist/feedback/Toast/index.d.ts.map +1 -0
- package/dist/feedback/Toast/index.js +2 -0
- package/dist/feedback/Toast/toastStore.d.ts +34 -0
- package/dist/feedback/Toast/toastStore.d.ts.map +1 -0
- package/dist/feedback/Toast/toastStore.js +43 -0
- package/dist/feedback/index.d.ts +4 -0
- package/dist/feedback/index.d.ts.map +1 -1
- package/dist/feedback/index.js +3 -0
- package/dist/forms/Checkbox/Checkbox.svelte +82 -103
- package/dist/forms/Checkbox/Checkbox.svelte.d.ts +1 -1
- package/dist/forms/Select/Select.svelte +136 -177
- package/dist/forms/Select/Select.svelte.d.ts +1 -1
- package/dist/forms/Slider/Slider.svelte +356 -0
- package/dist/forms/Slider/Slider.svelte.d.ts +50 -0
- package/dist/forms/Slider/Slider.svelte.d.ts.map +1 -0
- package/dist/forms/Slider/index.d.ts +2 -0
- package/dist/forms/Slider/index.d.ts.map +1 -0
- package/dist/forms/Slider/index.js +1 -0
- package/dist/forms/TextInput/TextInput.svelte +148 -164
- package/dist/forms/TextInput/TextInput.svelte.d.ts +1 -1
- package/dist/forms/Textarea/Textarea.svelte +615 -0
- package/dist/forms/Textarea/Textarea.svelte.d.ts +47 -0
- package/dist/forms/Textarea/Textarea.svelte.d.ts.map +1 -0
- package/dist/forms/Textarea/index.d.ts +2 -0
- package/dist/forms/Textarea/index.d.ts.map +1 -0
- package/dist/forms/Textarea/index.js +1 -0
- package/dist/forms/Toggle/Toggle.svelte +239 -0
- package/dist/forms/Toggle/Toggle.svelte.d.ts +39 -0
- package/dist/forms/Toggle/Toggle.svelte.d.ts.map +1 -0
- package/dist/forms/Toggle/index.d.ts +2 -0
- package/dist/forms/Toggle/index.d.ts.map +1 -0
- package/dist/forms/Toggle/index.js +1 -0
- package/dist/forms/index.d.ts +3 -0
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +3 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/layout/Card/Card.svelte +64 -40
- package/dist/layout/Card/Card.svelte.d.ts +1 -1
- package/dist/layout/Card/Card.svelte.d.ts.map +1 -1
- package/dist/layout/Container/Container.svelte +71 -71
- package/dist/layout/Container/Container.svelte.d.ts +2 -2
- package/dist/navigation/CommandPalette/CommandPalette.svelte +410 -181
- package/dist/navigation/CommandPalette/CommandPalette.svelte.d.ts +8 -3
- package/dist/navigation/CommandPalette/CommandPalette.svelte.d.ts.map +1 -1
- package/dist/navigation/Tabs/Tabs.svelte +94 -178
- package/dist/navigation/Tabs/Tabs.svelte.d.ts +2 -2
- package/dist/primitives/Badge/Badge.svelte +85 -223
- package/dist/primitives/Badge/Badge.svelte.d.ts +2 -2
- package/dist/primitives/Badge/Badge.svelte.d.ts.map +1 -1
- package/dist/primitives/Button/Button.svelte +138 -208
- package/dist/primitives/Button/Button.svelte.d.ts +3 -3
- package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
- package/dist/primitives/Tooltip/Tooltip.svelte +260 -0
- package/dist/primitives/Tooltip/Tooltip.svelte.d.ts +36 -0
- package/dist/primitives/Tooltip/Tooltip.svelte.d.ts.map +1 -0
- package/dist/primitives/Tooltip/index.d.ts +2 -0
- package/dist/primitives/Tooltip/index.d.ts.map +1 -0
- package/dist/primitives/Tooltip/index.js +1 -0
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +1 -0
- package/dist/styles/tokens.css +200 -259
- package/package.json +5 -5
- package/dist/windowing/Window/Window.svelte +0 -602
- package/dist/windowing/Window/Window.svelte.d.ts +0 -65
- package/dist/windowing/Window/Window.svelte.d.ts.map +0 -1
- package/dist/windowing/Window/index.d.ts +0 -2
- package/dist/windowing/Window/index.d.ts.map +0 -1
- package/dist/windowing/Window/index.js +0 -1
- package/dist/windowing/WindowManager/WindowManager.svelte +0 -410
- package/dist/windowing/WindowManager/WindowManager.svelte.d.ts +0 -38
- package/dist/windowing/WindowManager/WindowManager.svelte.d.ts.map +0 -1
- package/dist/windowing/WindowManager/index.d.ts +0 -2
- package/dist/windowing/WindowManager/index.d.ts.map +0 -1
- package/dist/windowing/WindowManager/index.js +0 -1
- package/dist/windowing/index.d.ts +0 -5
- package/dist/windowing/index.d.ts.map +0 -1
- package/dist/windowing/index.js +0 -3
- package/dist/windowing/windowStore.svelte.d.ts +0 -49
- package/dist/windowing/windowStore.svelte.d.ts.map +0 -1
- package/dist/windowing/windowStore.svelte.js +0 -170
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
@component WindowManager
|
|
3
|
-
|
|
4
|
-
Win2K x Basquiat -- Desktop-style container that manages Window components.
|
|
5
|
-
Provides a bounded area for windows to live in, with a taskbar at the bottom
|
|
6
|
-
showing all open windows (including minimized). Click-to-focus z-index stacking.
|
|
7
|
-
Keyboard: F6 cycles windows, Alt+Arrow Up maximizes, Alt+Arrow Down minimizes.
|
|
8
|
-
|
|
9
|
-
@example
|
|
10
|
-
<WindowManager height="500px">
|
|
11
|
-
<Window id="notes" title="Notes"><p>Content</p></Window>
|
|
12
|
-
<Window id="settings" title="Settings"><p>Content</p></Window>
|
|
13
|
-
</WindowManager>
|
|
14
|
-
-->
|
|
15
|
-
<script lang="ts">
|
|
16
|
-
import type { Snippet } from 'svelte';
|
|
17
|
-
import { setContext } from 'svelte';
|
|
18
|
-
import { cn } from '../../utils/cn.js';
|
|
19
|
-
import { generateId, Keys } from '../../utils/keyboard.js';
|
|
20
|
-
import { createWindowManager } from '../windowStore.svelte.js';
|
|
21
|
-
|
|
22
|
-
type TaskbarPosition = 'bottom' | 'top';
|
|
23
|
-
|
|
24
|
-
interface Props {
|
|
25
|
-
/** Height of the window manager area. */
|
|
26
|
-
height?: string;
|
|
27
|
-
/** Show the taskbar. */
|
|
28
|
-
showTaskbar?: boolean;
|
|
29
|
-
/** Taskbar position. */
|
|
30
|
-
taskbarPosition?: TaskbarPosition;
|
|
31
|
-
/** Show a desktop background pattern. */
|
|
32
|
-
showDesktopPattern?: boolean;
|
|
33
|
-
/** Desktop label in corner. */
|
|
34
|
-
desktopLabel?: string;
|
|
35
|
-
/** Window children (Window components). */
|
|
36
|
-
children?: Snippet;
|
|
37
|
-
/** Additional CSS class. */
|
|
38
|
-
class?: string;
|
|
39
|
-
/** Test ID for automated testing. */
|
|
40
|
-
testId?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
let {
|
|
44
|
-
height = '500px',
|
|
45
|
-
showTaskbar = true,
|
|
46
|
-
taskbarPosition = 'bottom',
|
|
47
|
-
showDesktopPattern = true,
|
|
48
|
-
desktopLabel = '',
|
|
49
|
-
children,
|
|
50
|
-
class: className = '',
|
|
51
|
-
testId
|
|
52
|
-
}: Props = $props();
|
|
53
|
-
|
|
54
|
-
const managerId = generateId('wm');
|
|
55
|
-
const manager = createWindowManager();
|
|
56
|
-
|
|
57
|
-
// Provide manager to child Window components
|
|
58
|
-
setContext('salmex-window-manager', manager);
|
|
59
|
-
|
|
60
|
-
let containerEl = $state<HTMLDivElement | null>(null);
|
|
61
|
-
|
|
62
|
-
function handleKeyDown(e: KeyboardEvent) {
|
|
63
|
-
// F6 / Shift+F6: cycle between windows
|
|
64
|
-
if (e.key === 'F6') {
|
|
65
|
-
e.preventDefault();
|
|
66
|
-
if (e.shiftKey) {
|
|
67
|
-
manager.focusPrevious();
|
|
68
|
-
} else {
|
|
69
|
-
manager.focusNext();
|
|
70
|
-
}
|
|
71
|
-
// Focus the window element
|
|
72
|
-
const focused = manager.getFocusedWindow();
|
|
73
|
-
if (focused && containerEl) {
|
|
74
|
-
const el = containerEl.querySelector<HTMLElement>(`[data-window-id="${focused.id}"]`);
|
|
75
|
-
el?.focus();
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const focusedWin = manager.getFocusedWindow();
|
|
80
|
-
if (!focusedWin) return;
|
|
81
|
-
|
|
82
|
-
// Alt+ArrowDown: minimize
|
|
83
|
-
if (e.altKey && e.key === Keys.ArrowDown) {
|
|
84
|
-
e.preventDefault();
|
|
85
|
-
manager.minimize(focusedWin.id);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Alt+ArrowUp: maximize / restore
|
|
89
|
-
if (e.altKey && e.key === Keys.ArrowUp) {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
if (focusedWin.maximized) {
|
|
92
|
-
manager.restore(focusedWin.id);
|
|
93
|
-
} else if (containerEl) {
|
|
94
|
-
const rect = containerEl.getBoundingClientRect();
|
|
95
|
-
const taskbarH = showTaskbar ? 36 : 0;
|
|
96
|
-
manager.maximize(focusedWin.id, rect.width, rect.height - taskbarH);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function handleTaskbarClick(windowId: string) {
|
|
102
|
-
manager.toggleMinimize(windowId);
|
|
103
|
-
// Focus the window element if restored
|
|
104
|
-
const win = manager.getWindow(windowId);
|
|
105
|
-
if (win && !win.minimized && containerEl) {
|
|
106
|
-
setTimeout(() => {
|
|
107
|
-
const el = containerEl?.querySelector<HTMLElement>(`[data-window-id="${windowId}"]`);
|
|
108
|
-
el?.focus();
|
|
109
|
-
}, 0);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
</script>
|
|
113
|
-
|
|
114
|
-
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
115
|
-
<div
|
|
116
|
-
bind:this={containerEl}
|
|
117
|
-
id={managerId}
|
|
118
|
-
class={cn(
|
|
119
|
-
'salmex-wm',
|
|
120
|
-
showDesktopPattern && 'salmex-wm-pattern',
|
|
121
|
-
taskbarPosition === 'top' && 'salmex-wm-taskbar-top',
|
|
122
|
-
className
|
|
123
|
-
)}
|
|
124
|
-
style="height: {height};"
|
|
125
|
-
role="region"
|
|
126
|
-
aria-label="Window manager"
|
|
127
|
-
data-testid={testId}
|
|
128
|
-
onkeydown={handleKeyDown}
|
|
129
|
-
>
|
|
130
|
-
<!-- Window area -->
|
|
131
|
-
<div class="salmex-wm-desktop">
|
|
132
|
-
{#if desktopLabel}
|
|
133
|
-
<span class="salmex-wm-desktop-label" aria-hidden="true">{desktopLabel}</span>
|
|
134
|
-
{/if}
|
|
135
|
-
{#if children}
|
|
136
|
-
{@render children()}
|
|
137
|
-
{/if}
|
|
138
|
-
</div>
|
|
139
|
-
|
|
140
|
-
<!-- Taskbar -->
|
|
141
|
-
{#if showTaskbar}
|
|
142
|
-
<div class="salmex-wm-taskbar" role="toolbar" aria-label="Window taskbar">
|
|
143
|
-
<div class="salmex-wm-taskbar-start">
|
|
144
|
-
<span class="salmex-wm-start-label" aria-hidden="true">Salmex</span>
|
|
145
|
-
</div>
|
|
146
|
-
<div class="salmex-wm-taskbar-items">
|
|
147
|
-
{#each manager.windows as win (win.id)}
|
|
148
|
-
<button
|
|
149
|
-
type="button"
|
|
150
|
-
class={cn(
|
|
151
|
-
'salmex-wm-taskbar-btn',
|
|
152
|
-
win.focused && !win.minimized && 'salmex-wm-taskbar-btn-active',
|
|
153
|
-
win.minimized && 'salmex-wm-taskbar-btn-minimized'
|
|
154
|
-
)}
|
|
155
|
-
onclick={() => handleTaskbarClick(win.id)}
|
|
156
|
-
aria-pressed={win.focused && !win.minimized}
|
|
157
|
-
title={win.title}
|
|
158
|
-
>
|
|
159
|
-
<span class="salmex-wm-taskbar-btn-text">{win.title}</span>
|
|
160
|
-
</button>
|
|
161
|
-
{/each}
|
|
162
|
-
</div>
|
|
163
|
-
<div class="salmex-wm-taskbar-tray" aria-hidden="true">
|
|
164
|
-
<span class="salmex-wm-clock">{new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>
|
|
165
|
-
</div>
|
|
166
|
-
</div>
|
|
167
|
-
{/if}
|
|
168
|
-
</div>
|
|
169
|
-
|
|
170
|
-
<style>
|
|
171
|
-
/* ========================================
|
|
172
|
-
WINDOW MANAGER CONTAINER
|
|
173
|
-
======================================== */
|
|
174
|
-
|
|
175
|
-
.salmex-wm {
|
|
176
|
-
position: relative;
|
|
177
|
-
display: flex;
|
|
178
|
-
flex-direction: column;
|
|
179
|
-
border: 3px solid rgb(var(--salmex-button-dark-edge));
|
|
180
|
-
overflow: hidden;
|
|
181
|
-
background: rgb(var(--salmex-bg-tertiary));
|
|
182
|
-
box-shadow: var(--salmex-shadow-lg);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
.salmex-wm-taskbar-top {
|
|
186
|
-
flex-direction: column-reverse;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/* Desktop background pattern -- Win2K teal with Basquiat texture */
|
|
190
|
-
.salmex-wm-pattern {
|
|
191
|
-
background:
|
|
192
|
-
/* Subtle cross-hatch */
|
|
193
|
-
repeating-linear-gradient(
|
|
194
|
-
45deg,
|
|
195
|
-
transparent,
|
|
196
|
-
transparent 8px,
|
|
197
|
-
rgb(0 0 0 / 0.03) 8px,
|
|
198
|
-
rgb(0 0 0 / 0.03) 9px
|
|
199
|
-
),
|
|
200
|
-
repeating-linear-gradient(
|
|
201
|
-
-45deg,
|
|
202
|
-
transparent,
|
|
203
|
-
transparent 8px,
|
|
204
|
-
rgb(0 0 0 / 0.03) 8px,
|
|
205
|
-
rgb(0 0 0 / 0.03) 9px
|
|
206
|
-
),
|
|
207
|
-
/* Win2K teal base with Basquiat flair */
|
|
208
|
-
linear-gradient(
|
|
209
|
-
135deg,
|
|
210
|
-
rgb(58 110 165),
|
|
211
|
-
rgb(40 90 140)
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
:global([data-theme='dark']) .salmex-wm-pattern {
|
|
216
|
-
background:
|
|
217
|
-
repeating-linear-gradient(
|
|
218
|
-
45deg,
|
|
219
|
-
transparent,
|
|
220
|
-
transparent 8px,
|
|
221
|
-
rgb(255 255 255 / 0.02) 8px,
|
|
222
|
-
rgb(255 255 255 / 0.02) 9px
|
|
223
|
-
),
|
|
224
|
-
repeating-linear-gradient(
|
|
225
|
-
-45deg,
|
|
226
|
-
transparent,
|
|
227
|
-
transparent 8px,
|
|
228
|
-
rgb(255 255 255 / 0.02) 8px,
|
|
229
|
-
rgb(255 255 255 / 0.02) 9px
|
|
230
|
-
),
|
|
231
|
-
linear-gradient(
|
|
232
|
-
135deg,
|
|
233
|
-
rgb(15 15 20),
|
|
234
|
-
rgb(20 18 28)
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/* ========================================
|
|
239
|
-
DESKTOP AREA
|
|
240
|
-
======================================== */
|
|
241
|
-
|
|
242
|
-
.salmex-wm-desktop {
|
|
243
|
-
position: relative;
|
|
244
|
-
flex: 1;
|
|
245
|
-
overflow: hidden;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.salmex-wm-desktop-label {
|
|
249
|
-
position: absolute;
|
|
250
|
-
bottom: var(--salmex-space-3);
|
|
251
|
-
right: var(--salmex-space-4);
|
|
252
|
-
font-family: var(--salmex-font-handwrite);
|
|
253
|
-
font-size: var(--salmex-font-size-lg);
|
|
254
|
-
color: rgb(255 255 255 / 0.25);
|
|
255
|
-
pointer-events: none;
|
|
256
|
-
user-select: none;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
:global([data-theme='dark']) .salmex-wm-desktop-label {
|
|
260
|
-
color: rgb(255 255 255 / 0.1);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/* ========================================
|
|
264
|
-
TASKBAR
|
|
265
|
-
======================================== */
|
|
266
|
-
|
|
267
|
-
.salmex-wm-taskbar {
|
|
268
|
-
display: flex;
|
|
269
|
-
align-items: center;
|
|
270
|
-
gap: 2px;
|
|
271
|
-
padding: 2px var(--salmex-space-1);
|
|
272
|
-
background: rgb(var(--salmex-window-surface));
|
|
273
|
-
border-top: 2px solid rgb(var(--salmex-button-highlight));
|
|
274
|
-
min-height: 36px;
|
|
275
|
-
flex-shrink: 0;
|
|
276
|
-
/* 3D raised taskbar */
|
|
277
|
-
box-shadow:
|
|
278
|
-
inset 0 1px 0 rgb(var(--salmex-button-highlight)),
|
|
279
|
-
inset 0 -1px 0 rgb(var(--salmex-button-shadow));
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
.salmex-wm-taskbar-top .salmex-wm-taskbar {
|
|
283
|
-
border-top: none;
|
|
284
|
-
border-bottom: 2px solid rgb(var(--salmex-button-shadow));
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/* Start button */
|
|
288
|
-
.salmex-wm-taskbar-start {
|
|
289
|
-
display: flex;
|
|
290
|
-
align-items: center;
|
|
291
|
-
padding: 0 var(--salmex-space-2);
|
|
292
|
-
border-right: 1px solid rgb(var(--salmex-button-shadow));
|
|
293
|
-
margin-right: var(--salmex-space-1);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
.salmex-wm-start-label {
|
|
297
|
-
font-family: var(--salmex-font-display);
|
|
298
|
-
font-size: var(--salmex-font-size-xs);
|
|
299
|
-
font-weight: 900;
|
|
300
|
-
text-transform: uppercase;
|
|
301
|
-
letter-spacing: 0.5px;
|
|
302
|
-
color: rgb(var(--salmex-text-primary));
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/* Taskbar items area */
|
|
306
|
-
.salmex-wm-taskbar-items {
|
|
307
|
-
display: flex;
|
|
308
|
-
flex: 1;
|
|
309
|
-
gap: 2px;
|
|
310
|
-
overflow-x: auto;
|
|
311
|
-
min-width: 0;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/* Taskbar button */
|
|
315
|
-
.salmex-wm-taskbar-btn {
|
|
316
|
-
display: flex;
|
|
317
|
-
align-items: center;
|
|
318
|
-
gap: var(--salmex-space-1);
|
|
319
|
-
padding: 2px var(--salmex-space-3);
|
|
320
|
-
min-width: 0;
|
|
321
|
-
max-width: 160px;
|
|
322
|
-
background: rgb(var(--salmex-button-face));
|
|
323
|
-
border: 2px solid rgb(var(--salmex-button-dark-edge));
|
|
324
|
-
cursor: pointer;
|
|
325
|
-
font-family: var(--salmex-font-system);
|
|
326
|
-
font-size: var(--salmex-font-size-xs);
|
|
327
|
-
font-weight: 600;
|
|
328
|
-
color: rgb(var(--salmex-text-primary));
|
|
329
|
-
text-align: left;
|
|
330
|
-
/* Raised 3D */
|
|
331
|
-
box-shadow:
|
|
332
|
-
inset 1px 1px 0 rgb(var(--salmex-button-highlight)),
|
|
333
|
-
inset -1px -1px 0 rgb(var(--salmex-button-shadow));
|
|
334
|
-
transition: all var(--salmex-transition-fast);
|
|
335
|
-
white-space: nowrap;
|
|
336
|
-
overflow: hidden;
|
|
337
|
-
height: 26px;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
.salmex-wm-taskbar-btn:hover {
|
|
341
|
-
background: rgb(var(--salmex-button-light));
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/* Active (focused) — pressed in */
|
|
345
|
-
.salmex-wm-taskbar-btn-active {
|
|
346
|
-
box-shadow:
|
|
347
|
-
inset -1px -1px 0 rgb(var(--salmex-button-highlight)),
|
|
348
|
-
inset 1px 1px 0 rgb(var(--salmex-button-shadow));
|
|
349
|
-
background: rgb(var(--salmex-bg-primary));
|
|
350
|
-
font-weight: 900;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/* Minimized — subtle difference */
|
|
354
|
-
.salmex-wm-taskbar-btn-minimized {
|
|
355
|
-
opacity: 0.75;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
.salmex-wm-taskbar-btn:focus-visible {
|
|
359
|
-
outline: none;
|
|
360
|
-
box-shadow:
|
|
361
|
-
inset 1px 1px 0 rgb(var(--salmex-button-highlight)),
|
|
362
|
-
inset -1px -1px 0 rgb(var(--salmex-button-shadow)),
|
|
363
|
-
0 0 0 2px rgb(var(--salmex-midnight-black)),
|
|
364
|
-
0 0 0 5px rgb(var(--salmex-crown-yellow));
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
:global([data-theme='dark']) .salmex-wm-taskbar-btn:focus-visible {
|
|
368
|
-
box-shadow:
|
|
369
|
-
inset 1px 1px 0 rgb(var(--salmex-button-highlight)),
|
|
370
|
-
inset -1px -1px 0 rgb(var(--salmex-button-shadow)),
|
|
371
|
-
0 0 0 3px rgb(var(--salmex-crown-yellow));
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
.salmex-wm-taskbar-btn-text {
|
|
375
|
-
overflow: hidden;
|
|
376
|
-
text-overflow: ellipsis;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/* System tray */
|
|
380
|
-
.salmex-wm-taskbar-tray {
|
|
381
|
-
display: flex;
|
|
382
|
-
align-items: center;
|
|
383
|
-
gap: var(--salmex-space-2);
|
|
384
|
-
padding: 0 var(--salmex-space-2);
|
|
385
|
-
margin-left: auto;
|
|
386
|
-
border-left: 1px solid rgb(var(--salmex-button-shadow));
|
|
387
|
-
/* Sunken inset */
|
|
388
|
-
box-shadow:
|
|
389
|
-
inset 1px 1px 0 rgb(var(--salmex-button-shadow)),
|
|
390
|
-
inset -1px -1px 0 rgb(var(--salmex-button-highlight));
|
|
391
|
-
height: 22px;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
.salmex-wm-clock {
|
|
395
|
-
font-family: var(--salmex-font-mono);
|
|
396
|
-
font-size: var(--salmex-font-size-xs);
|
|
397
|
-
color: rgb(var(--salmex-text-primary));
|
|
398
|
-
white-space: nowrap;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/* ========================================
|
|
402
|
-
REDUCED MOTION
|
|
403
|
-
======================================== */
|
|
404
|
-
|
|
405
|
-
@media (prefers-reduced-motion: reduce) {
|
|
406
|
-
.salmex-wm-taskbar-btn {
|
|
407
|
-
transition: none;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
</style>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { Snippet } from 'svelte';
|
|
2
|
-
type TaskbarPosition = 'bottom' | 'top';
|
|
3
|
-
interface Props {
|
|
4
|
-
/** Height of the window manager area. */
|
|
5
|
-
height?: string;
|
|
6
|
-
/** Show the taskbar. */
|
|
7
|
-
showTaskbar?: boolean;
|
|
8
|
-
/** Taskbar position. */
|
|
9
|
-
taskbarPosition?: TaskbarPosition;
|
|
10
|
-
/** Show a desktop background pattern. */
|
|
11
|
-
showDesktopPattern?: boolean;
|
|
12
|
-
/** Desktop label in corner. */
|
|
13
|
-
desktopLabel?: string;
|
|
14
|
-
/** Window children (Window components). */
|
|
15
|
-
children?: Snippet;
|
|
16
|
-
/** Additional CSS class. */
|
|
17
|
-
class?: string;
|
|
18
|
-
/** Test ID for automated testing. */
|
|
19
|
-
testId?: string;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* WindowManager
|
|
23
|
-
*
|
|
24
|
-
* Win2K x Basquiat -- Desktop-style container that manages Window components.
|
|
25
|
-
* Provides a bounded area for windows to live in, with a taskbar at the bottom
|
|
26
|
-
* showing all open windows (including minimized). Click-to-focus z-index stacking.
|
|
27
|
-
* Keyboard: F6 cycles windows, Alt+Arrow Up maximizes, Alt+Arrow Down minimizes.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* <WindowManager height="500px">
|
|
31
|
-
* <Window id="notes" title="Notes"><p>Content</p></Window>
|
|
32
|
-
* <Window id="settings" title="Settings"><p>Content</p></Window>
|
|
33
|
-
* </WindowManager>
|
|
34
|
-
*/
|
|
35
|
-
declare const WindowManager: import("svelte").Component<Props, {}, "">;
|
|
36
|
-
type WindowManager = ReturnType<typeof WindowManager>;
|
|
37
|
-
export default WindowManager;
|
|
38
|
-
//# sourceMappingURL=WindowManager.svelte.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WindowManager.svelte.d.ts","sourceRoot":"","sources":["../../../src/windowing/WindowManager/WindowManager.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAOtC,KAAK,eAAe,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExC,UAAU,KAAK;IACd,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,wBAAwB;IACxB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,yCAAyC;IACzC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AA+HD;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/windowing/WindowManager/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default as WindowManager } from './WindowManager.svelte';
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { Window } from './Window/index.js';
|
|
2
|
-
export { WindowManager } from './WindowManager/index.js';
|
|
3
|
-
export { createWindowManager } from './windowStore.svelte.js';
|
|
4
|
-
export type { WindowState, WindowManagerState } from './windowStore.svelte.js';
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/windowing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/windowing/index.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Window Manager state — Svelte 5 runes-based reactive store.
|
|
3
|
-
* Manages window lifecycle: open, focus, minimize, maximize, restore, close.
|
|
4
|
-
* Counter-based z-index stacking; taskbar-aware focus cycling.
|
|
5
|
-
*/
|
|
6
|
-
export interface WindowState {
|
|
7
|
-
id: string;
|
|
8
|
-
title: string;
|
|
9
|
-
minimized: boolean;
|
|
10
|
-
maximized: boolean;
|
|
11
|
-
focused: boolean;
|
|
12
|
-
zIndex: number;
|
|
13
|
-
/** Position before maximize (for restore) */
|
|
14
|
-
savedGeometry: {
|
|
15
|
-
x: number;
|
|
16
|
-
y: number;
|
|
17
|
-
width: number;
|
|
18
|
-
height: number;
|
|
19
|
-
} | null;
|
|
20
|
-
/** Current position */
|
|
21
|
-
x: number;
|
|
22
|
-
y: number;
|
|
23
|
-
width: number;
|
|
24
|
-
height: number;
|
|
25
|
-
}
|
|
26
|
-
export interface WindowManagerState {
|
|
27
|
-
readonly windows: WindowState[];
|
|
28
|
-
register(id: string, title: string, opts?: {
|
|
29
|
-
x?: number;
|
|
30
|
-
y?: number;
|
|
31
|
-
width?: number;
|
|
32
|
-
height?: number;
|
|
33
|
-
}): void;
|
|
34
|
-
unregister(id: string): void;
|
|
35
|
-
focus(id: string): void;
|
|
36
|
-
minimize(id: string): void;
|
|
37
|
-
maximize(id: string, containerWidth: number, containerHeight: number): void;
|
|
38
|
-
restore(id: string): void;
|
|
39
|
-
close(id: string): void;
|
|
40
|
-
toggleMinimize(id: string): void;
|
|
41
|
-
move(id: string, x: number, y: number): void;
|
|
42
|
-
resize(id: string, width: number, height: number): void;
|
|
43
|
-
focusNext(): void;
|
|
44
|
-
focusPrevious(): void;
|
|
45
|
-
getWindow(id: string): WindowState | undefined;
|
|
46
|
-
getFocusedWindow(): WindowState | undefined;
|
|
47
|
-
}
|
|
48
|
-
export declare function createWindowManager(): WindowManagerState;
|
|
49
|
-
//# sourceMappingURL=windowStore.svelte.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"windowStore.svelte.d.ts","sourceRoot":"","sources":["../../src/windowing/windowStore.svelte.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,aAAa,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9E,uBAAuB;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;IAChC,QAAQ,CACP,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAChE,IAAI,CAAC;IACR,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACxD,SAAS,IAAI,IAAI,CAAC;IAClB,aAAa,IAAI,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IAC/C,gBAAgB,IAAI,WAAW,GAAG,SAAS,CAAC;CAC5C;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAqKxD"}
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Window Manager state — Svelte 5 runes-based reactive store.
|
|
3
|
-
* Manages window lifecycle: open, focus, minimize, maximize, restore, close.
|
|
4
|
-
* Counter-based z-index stacking; taskbar-aware focus cycling.
|
|
5
|
-
*/
|
|
6
|
-
export function createWindowManager() {
|
|
7
|
-
const windows = $state([]);
|
|
8
|
-
let nextZ = $state(100);
|
|
9
|
-
function getIdx(id) {
|
|
10
|
-
return windows.findIndex((w) => w.id === id);
|
|
11
|
-
}
|
|
12
|
-
function setAllUnfocused() {
|
|
13
|
-
for (const w of windows) {
|
|
14
|
-
w.focused = false;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function focusNextVisible(excludeId) {
|
|
18
|
-
const visible = windows.filter((w) => !w.minimized && w.id !== excludeId);
|
|
19
|
-
if (visible.length === 0)
|
|
20
|
-
return;
|
|
21
|
-
const top = visible.reduce((a, b) => (a.zIndex > b.zIndex ? a : b));
|
|
22
|
-
setAllUnfocused();
|
|
23
|
-
top.focused = true;
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
get windows() {
|
|
27
|
-
return windows;
|
|
28
|
-
},
|
|
29
|
-
register(id, title, opts) {
|
|
30
|
-
if (getIdx(id) >= 0)
|
|
31
|
-
return;
|
|
32
|
-
nextZ++;
|
|
33
|
-
setAllUnfocused();
|
|
34
|
-
windows.push({
|
|
35
|
-
id,
|
|
36
|
-
title,
|
|
37
|
-
minimized: false,
|
|
38
|
-
maximized: false,
|
|
39
|
-
focused: true,
|
|
40
|
-
zIndex: nextZ,
|
|
41
|
-
savedGeometry: null,
|
|
42
|
-
x: opts?.x ?? 0,
|
|
43
|
-
y: opts?.y ?? 0,
|
|
44
|
-
width: opts?.width ?? 400,
|
|
45
|
-
height: opts?.height ?? 300
|
|
46
|
-
});
|
|
47
|
-
},
|
|
48
|
-
unregister(id) {
|
|
49
|
-
const idx = getIdx(id);
|
|
50
|
-
if (idx < 0)
|
|
51
|
-
return;
|
|
52
|
-
windows.splice(idx, 1);
|
|
53
|
-
focusNextVisible();
|
|
54
|
-
},
|
|
55
|
-
focus(id) {
|
|
56
|
-
const win = windows[getIdx(id)];
|
|
57
|
-
if (!win || win.focused)
|
|
58
|
-
return;
|
|
59
|
-
nextZ++;
|
|
60
|
-
setAllUnfocused();
|
|
61
|
-
win.focused = true;
|
|
62
|
-
win.zIndex = nextZ;
|
|
63
|
-
},
|
|
64
|
-
minimize(id) {
|
|
65
|
-
const win = windows[getIdx(id)];
|
|
66
|
-
if (!win || win.minimized)
|
|
67
|
-
return;
|
|
68
|
-
win.minimized = true;
|
|
69
|
-
win.focused = false;
|
|
70
|
-
focusNextVisible(id);
|
|
71
|
-
},
|
|
72
|
-
maximize(id, containerWidth, containerHeight) {
|
|
73
|
-
const win = windows[getIdx(id)];
|
|
74
|
-
if (!win || win.maximized)
|
|
75
|
-
return;
|
|
76
|
-
win.savedGeometry = { x: win.x, y: win.y, width: win.width, height: win.height };
|
|
77
|
-
win.x = 0;
|
|
78
|
-
win.y = 0;
|
|
79
|
-
win.width = containerWidth;
|
|
80
|
-
win.height = containerHeight;
|
|
81
|
-
win.maximized = true;
|
|
82
|
-
nextZ++;
|
|
83
|
-
setAllUnfocused();
|
|
84
|
-
win.focused = true;
|
|
85
|
-
win.zIndex = nextZ;
|
|
86
|
-
},
|
|
87
|
-
restore(id) {
|
|
88
|
-
const win = windows[getIdx(id)];
|
|
89
|
-
if (!win)
|
|
90
|
-
return;
|
|
91
|
-
if (win.minimized) {
|
|
92
|
-
win.minimized = false;
|
|
93
|
-
nextZ++;
|
|
94
|
-
setAllUnfocused();
|
|
95
|
-
win.focused = true;
|
|
96
|
-
win.zIndex = nextZ;
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (win.maximized && win.savedGeometry) {
|
|
100
|
-
win.x = win.savedGeometry.x;
|
|
101
|
-
win.y = win.savedGeometry.y;
|
|
102
|
-
win.width = win.savedGeometry.width;
|
|
103
|
-
win.height = win.savedGeometry.height;
|
|
104
|
-
win.savedGeometry = null;
|
|
105
|
-
win.maximized = false;
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
close(id) {
|
|
109
|
-
const idx = getIdx(id);
|
|
110
|
-
if (idx < 0)
|
|
111
|
-
return;
|
|
112
|
-
windows.splice(idx, 1);
|
|
113
|
-
focusNextVisible();
|
|
114
|
-
},
|
|
115
|
-
toggleMinimize(id) {
|
|
116
|
-
const win = windows[getIdx(id)];
|
|
117
|
-
if (!win)
|
|
118
|
-
return;
|
|
119
|
-
if (win.minimized) {
|
|
120
|
-
this.restore(id);
|
|
121
|
-
}
|
|
122
|
-
else if (win.focused) {
|
|
123
|
-
this.minimize(id);
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
this.focus(id);
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
move(id, x, y) {
|
|
130
|
-
const win = windows[getIdx(id)];
|
|
131
|
-
if (!win || win.maximized)
|
|
132
|
-
return;
|
|
133
|
-
win.x = x;
|
|
134
|
-
win.y = y;
|
|
135
|
-
},
|
|
136
|
-
resize(id, width, height) {
|
|
137
|
-
const win = windows[getIdx(id)];
|
|
138
|
-
if (!win || win.maximized)
|
|
139
|
-
return;
|
|
140
|
-
win.width = width;
|
|
141
|
-
win.height = height;
|
|
142
|
-
},
|
|
143
|
-
focusNext() {
|
|
144
|
-
const visible = windows.filter((w) => !w.minimized);
|
|
145
|
-
if (visible.length <= 1)
|
|
146
|
-
return;
|
|
147
|
-
const sorted = [...visible].sort((a, b) => a.zIndex - b.zIndex);
|
|
148
|
-
const focusedIdx = sorted.findIndex((w) => w.focused);
|
|
149
|
-
const next = sorted[(focusedIdx + 1) % sorted.length];
|
|
150
|
-
if (next)
|
|
151
|
-
this.focus(next.id);
|
|
152
|
-
},
|
|
153
|
-
focusPrevious() {
|
|
154
|
-
const visible = windows.filter((w) => !w.minimized);
|
|
155
|
-
if (visible.length <= 1)
|
|
156
|
-
return;
|
|
157
|
-
const sorted = [...visible].sort((a, b) => a.zIndex - b.zIndex);
|
|
158
|
-
const focusedIdx = sorted.findIndex((w) => w.focused);
|
|
159
|
-
const prev = sorted[(focusedIdx - 1 + sorted.length) % sorted.length];
|
|
160
|
-
if (prev)
|
|
161
|
-
this.focus(prev.id);
|
|
162
|
-
},
|
|
163
|
-
getWindow(id) {
|
|
164
|
-
return windows[getIdx(id)];
|
|
165
|
-
},
|
|
166
|
-
getFocusedWindow() {
|
|
167
|
-
return windows.find((w) => w.focused);
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
}
|