treesap 0.1.13 → 0.2.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.
Files changed (147) hide show
  1. package/README.md +31 -192
  2. package/dist/app.d.ts +28 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +184 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/context.d.ts +36 -0
  7. package/dist/context.d.ts.map +1 -0
  8. package/dist/context.js +95 -0
  9. package/dist/context.js.map +1 -0
  10. package/dist/index.d.ts +5 -7
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +5 -9
  13. package/dist/index.js.map +1 -1
  14. package/dist/middleware/cors.d.ts +11 -0
  15. package/dist/middleware/cors.d.ts.map +1 -0
  16. package/dist/middleware/cors.js +34 -0
  17. package/dist/middleware/cors.js.map +1 -0
  18. package/dist/middleware/serve-static.d.ts +6 -0
  19. package/dist/middleware/serve-static.d.ts.map +1 -0
  20. package/dist/middleware/serve-static.js +68 -0
  21. package/dist/middleware/serve-static.js.map +1 -0
  22. package/dist/node.d.ts +8 -0
  23. package/dist/node.d.ts.map +1 -0
  24. package/dist/node.js +52 -0
  25. package/dist/node.js.map +1 -0
  26. package/dist/path.d.ts +10 -0
  27. package/dist/path.d.ts.map +1 -0
  28. package/dist/path.js +45 -0
  29. package/dist/path.js.map +1 -0
  30. package/dist/vite.d.ts +31 -0
  31. package/dist/vite.d.ts.map +1 -0
  32. package/dist/vite.js +278 -0
  33. package/dist/vite.js.map +1 -0
  34. package/package.json +33 -40
  35. package/dist/cli.d.ts +0 -3
  36. package/dist/cli.d.ts.map +0 -1
  37. package/dist/cli.js +0 -137
  38. package/dist/cli.js.map +0 -1
  39. package/dist/components/BaseHead.d.ts +0 -5
  40. package/dist/components/BaseHead.d.ts.map +0 -1
  41. package/dist/components/BaseHead.js +0 -161
  42. package/dist/components/BaseHead.js.map +0 -1
  43. package/dist/components/ChatInput.d.ts +0 -7
  44. package/dist/components/ChatInput.d.ts.map +0 -1
  45. package/dist/components/ChatInput.js +0 -11
  46. package/dist/components/ChatInput.js.map +0 -1
  47. package/dist/components/Sidebar.d.ts +0 -8
  48. package/dist/components/Sidebar.d.ts.map +0 -1
  49. package/dist/components/Sidebar.js +0 -7
  50. package/dist/components/Sidebar.js.map +0 -1
  51. package/dist/components/SimpleLivePreview.d.ts +0 -7
  52. package/dist/components/SimpleLivePreview.d.ts.map +0 -1
  53. package/dist/components/SimpleLivePreview.js +0 -7
  54. package/dist/components/SimpleLivePreview.js.map +0 -1
  55. package/dist/components/Terminal.d.ts +0 -7
  56. package/dist/components/Terminal.d.ts.map +0 -1
  57. package/dist/components/Terminal.js +0 -14
  58. package/dist/components/Terminal.js.map +0 -1
  59. package/dist/components/VoiceRecorder.d.ts +0 -4
  60. package/dist/components/VoiceRecorder.d.ts.map +0 -1
  61. package/dist/components/VoiceRecorder.js +0 -5
  62. package/dist/components/VoiceRecorder.js.map +0 -1
  63. package/dist/components/icons/GeminiLogo.d.ts +0 -7
  64. package/dist/components/icons/GeminiLogo.d.ts.map +0 -1
  65. package/dist/components/icons/GeminiLogo.js +0 -5
  66. package/dist/components/icons/GeminiLogo.js.map +0 -1
  67. package/dist/components/icons/OllamaLogo.d.ts +0 -2
  68. package/dist/components/icons/OllamaLogo.d.ts.map +0 -1
  69. package/dist/components/icons/OllamaLogo.js +0 -5
  70. package/dist/components/icons/OllamaLogo.js.map +0 -1
  71. package/dist/layouts/Layout.d.ts +0 -9
  72. package/dist/layouts/Layout.d.ts.map +0 -1
  73. package/dist/layouts/Layout.js +0 -9
  74. package/dist/layouts/Layout.js.map +0 -1
  75. package/dist/layouts/NotFoundLayout.d.ts +0 -2
  76. package/dist/layouts/NotFoundLayout.d.ts.map +0 -1
  77. package/dist/layouts/NotFoundLayout.js +0 -6
  78. package/dist/layouts/NotFoundLayout.js.map +0 -1
  79. package/dist/pages/Code.d.ts +0 -7
  80. package/dist/pages/Code.d.ts.map +0 -1
  81. package/dist/pages/Code.js +0 -8
  82. package/dist/pages/Code.js.map +0 -1
  83. package/dist/pages/Home.d.ts +0 -7
  84. package/dist/pages/Home.d.ts.map +0 -1
  85. package/dist/pages/Home.js +0 -8
  86. package/dist/pages/Home.js.map +0 -1
  87. package/dist/pages/Welcome.d.ts +0 -2
  88. package/dist/pages/Welcome.d.ts.map +0 -1
  89. package/dist/pages/Welcome.js +0 -6
  90. package/dist/pages/Welcome.js.map +0 -1
  91. package/dist/server.d.ts +0 -11
  92. package/dist/server.d.ts.map +0 -1
  93. package/dist/server.js +0 -434
  94. package/dist/server.js.map +0 -1
  95. package/dist/services/dev-server.d.ts +0 -29
  96. package/dist/services/dev-server.d.ts.map +0 -1
  97. package/dist/services/dev-server.js +0 -201
  98. package/dist/services/dev-server.js.map +0 -1
  99. package/dist/services/terminal.d.ts +0 -46
  100. package/dist/services/terminal.d.ts.map +0 -1
  101. package/dist/services/terminal.js +0 -264
  102. package/dist/services/terminal.js.map +0 -1
  103. package/dist/services/websocket.d.ts +0 -48
  104. package/dist/services/websocket.d.ts.map +0 -1
  105. package/dist/services/websocket.js +0 -332
  106. package/dist/services/websocket.js.map +0 -1
  107. package/dist/static/components/ChatInput.js +0 -237
  108. package/dist/static/components/Sidebar.js +0 -225
  109. package/dist/static/components/SimpleLivePreview.js +0 -305
  110. package/dist/static/components/Terminal.js +0 -461
  111. package/dist/static/components/TerminalTabs.js +0 -383
  112. package/dist/static/favicon.svg +0 -14
  113. package/dist/static/signals/LivePreviewSignal.js +0 -71
  114. package/dist/static/signals/SidebarSignal.js +0 -123
  115. package/dist/static/signals/TerminalSignal.js +0 -273
  116. package/dist/static/styles/main.css +0 -1761
  117. package/src/cli.ts +0 -155
  118. package/src/components/BaseHead.ts +0 -164
  119. package/src/components/ChatInput.tsx +0 -56
  120. package/src/components/Sidebar.tsx +0 -99
  121. package/src/components/SimpleLivePreview.tsx +0 -40
  122. package/src/components/Terminal.tsx +0 -40
  123. package/src/components/VoiceRecorder.tsx +0 -33
  124. package/src/components/icons/GeminiLogo.tsx +0 -10
  125. package/src/components/icons/OllamaLogo.tsx +0 -5
  126. package/src/index.tsx +0 -12
  127. package/src/layouts/Layout.tsx +0 -41
  128. package/src/layouts/NotFoundLayout.tsx +0 -15
  129. package/src/pages/Code.tsx +0 -34
  130. package/src/pages/Welcome.tsx +0 -56
  131. package/src/server.tsx +0 -519
  132. package/src/services/dev-server.ts +0 -234
  133. package/src/services/terminal.ts +0 -325
  134. package/src/services/websocket.ts +0 -405
  135. package/src/static/components/ChatInput.js +0 -237
  136. package/src/static/components/Sidebar.js +0 -225
  137. package/src/static/components/SimpleLivePreview.js +0 -305
  138. package/src/static/components/Terminal.js +0 -461
  139. package/src/static/components/TerminalTabs.js +0 -383
  140. package/src/static/favicon.svg +0 -14
  141. package/src/static/signals/LivePreviewSignal.js +0 -71
  142. package/src/static/signals/SidebarSignal.js +0 -123
  143. package/src/static/signals/TerminalSignal.js +0 -273
  144. package/src/static/styles/main.css +0 -1761
  145. package/src/styles/input.css +0 -3
  146. package/tailwind.config.ts +0 -22
  147. package/tsconfig.json +0 -37
@@ -1,383 +0,0 @@
1
- // Terminal tabs management
2
- import { terminalStore } from '/signals/TerminalSignal.js';
3
-
4
- class TerminalTabManager {
5
- constructor() {
6
- this.maxTerminals = 3;
7
- this.activeTerminalIndex = 1;
8
-
9
- this.init();
10
- }
11
-
12
- init() {
13
- console.log('TerminalTabManager initialized');
14
-
15
- // Set up event listeners
16
- this.setupEventListeners();
17
-
18
- // Subscribe to terminal store changes
19
- this.subscribeToStore();
20
-
21
- // Initialize first terminal
22
- this.showTerminal(1);
23
-
24
- // Update button visibility
25
- this.updateAddButtonVisibility();
26
- this.updateCloseButtonsVisibility();
27
- }
28
-
29
- setupEventListeners() {
30
- // Terminal tab click handlers
31
- for (let i = 1; i <= this.maxTerminals; i++) {
32
- const tabBtn = document.getElementById(`terminal-tab-${i}`);
33
- if (tabBtn) {
34
- tabBtn.addEventListener('click', (e) => {
35
- // Prevent event bubbling to close button
36
- if (!e.target.closest('.terminal-close-btn')) {
37
- this.switchToTerminal(i);
38
- }
39
- });
40
- }
41
-
42
- // Close button handlers
43
- const closeBtns = document.querySelectorAll(`[data-terminal-index="${i}"].terminal-close-btn`);
44
- closeBtns.forEach(btn => {
45
- btn.addEventListener('click', async (e) => {
46
- e.stopPropagation();
47
- await this.closeTerminal(i);
48
- });
49
- });
50
- }
51
-
52
- // Add terminal button
53
- const addBtn = document.getElementById('add-terminal-btn');
54
- if (addBtn) {
55
- addBtn.addEventListener('click', () => {
56
- this.addTerminal();
57
- });
58
- }
59
-
60
- // Keyboard shortcuts
61
- document.addEventListener('keydown', (e) => {
62
- // Ctrl+Shift+` to create new terminal
63
- if (e.ctrlKey && e.shiftKey && e.code === 'Backquote') {
64
- e.preventDefault();
65
- this.addTerminal();
66
- }
67
-
68
- // Ctrl+Shift+W to close current terminal
69
- if (e.ctrlKey && e.shiftKey && e.key === 'W') {
70
- e.preventDefault();
71
- this.closeTerminal(this.activeTerminalIndex);
72
- }
73
- });
74
-
75
- // Window resize handler to fit terminals
76
- window.addEventListener('resize', () => {
77
- // Resize the currently active terminal
78
- setTimeout(() => {
79
- if (window.terminalManagers) {
80
- const activeManager = window.terminalManagers.get(`terminal-${this.activeTerminalIndex}`);
81
- if (activeManager && activeManager.terminal) {
82
- activeManager.fitTerminal();
83
- console.log(`Resized active terminal-${this.activeTerminalIndex} due to window resize`);
84
- }
85
- }
86
- }, 100);
87
- });
88
- }
89
-
90
- subscribeToStore() {
91
- // Watch for active terminal changes in the store
92
- terminalStore.activeTerminalId.subscribe((terminalId) => {
93
- if (terminalId) {
94
- const match = terminalId.match(/terminal-(\d+)/);
95
- if (match) {
96
- const index = parseInt(match[1]);
97
- this.updateActiveTabVisual(index);
98
- }
99
- }
100
- });
101
- }
102
-
103
- switchToTerminal(index) {
104
- if (index < 1 || index > this.maxTerminals) return;
105
-
106
- console.log(`Switching to terminal ${index}`);
107
-
108
- // Update store
109
- terminalStore.setActiveTerminal(`terminal-${index}`);
110
-
111
- // Show the terminal
112
- this.showTerminal(index);
113
-
114
- // Update active index
115
- this.activeTerminalIndex = index;
116
- }
117
-
118
- showTerminal(index) {
119
- // Hide all terminal containers
120
- for (let i = 1; i <= this.maxTerminals; i++) {
121
- const container = document.getElementById(`terminal-container-${i}`);
122
- if (container) {
123
- container.style.display = 'none';
124
- }
125
- }
126
-
127
- // Show the active terminal container
128
- const activeContainer = document.getElementById(`terminal-container-${index}`);
129
- if (activeContainer) {
130
- activeContainer.style.display = 'block';
131
- }
132
-
133
- // Update tab visuals
134
- this.updateActiveTabVisual(index);
135
-
136
- // Focus and resize the terminal
137
- setTimeout(() => {
138
- const terminalElement = document.getElementById(`terminal-${index}-xterm`);
139
- if (terminalElement && window.terminalManagers) {
140
- const manager = window.terminalManagers.get(`terminal-${index}`);
141
- if (manager && manager.terminal) {
142
- // Fit the terminal to its container
143
- manager.fitTerminal();
144
- // Focus the terminal
145
- manager.terminal.focus();
146
- console.log(`Focused and resized terminal-${index}`);
147
- } else {
148
- console.warn(`Terminal manager not found for terminal-${index}`);
149
- }
150
- }
151
- }, 150);
152
- }
153
-
154
- updateActiveTabVisual(activeIndex) {
155
- for (let i = 1; i <= this.maxTerminals; i++) {
156
- const tab = document.getElementById(`terminal-tab-${i}`);
157
- if (tab) {
158
- if (i === activeIndex) {
159
- // Active tab styling
160
- tab.className = 'terminal-tab flex items-center px-3 py-1 text-sm text-white bg-[#1e1e1e] border-t-2 border-[#0e639c] rounded-t-sm hover:bg-[#2d2d30] transition-colors';
161
- } else {
162
- // Inactive tab styling
163
- tab.className = 'terminal-tab flex items-center px-3 py-1 text-sm text-[#cccccc] hover:text-white hover:bg-[#2d2d30] transition-colors rounded-t-sm';
164
- }
165
- }
166
- }
167
- }
168
-
169
- addTerminal() {
170
- // Find the next available terminal slot
171
- for (let i = 2; i <= this.maxTerminals; i++) {
172
- const tab = document.getElementById(`terminal-tab-${i}`);
173
- const container = document.getElementById(`terminal-container-${i}`);
174
-
175
- if (tab && container && tab.style.display === 'none') {
176
- console.log(`Adding terminal ${i}`);
177
-
178
- // Show the tab
179
- tab.style.display = 'flex';
180
-
181
- // Add to store
182
- terminalStore.addTerminal(i);
183
-
184
- // Show the container temporarily to allow terminal initialization
185
- container.style.display = 'block';
186
-
187
- // Initialize the terminal by triggering the terminal manager to look for new terminals
188
- setTimeout(() => {
189
- if (window.initializeTerminals) {
190
- window.initializeTerminals();
191
- }
192
-
193
- // Switch to the new terminal after initialization (this will handle hiding/showing properly)
194
- setTimeout(() => {
195
- this.switchToTerminal(i);
196
-
197
- // Force a resize after switching
198
- setTimeout(() => {
199
- if (window.terminalManagers) {
200
- const manager = window.terminalManagers.get(`terminal-${i}`);
201
- if (manager && manager.terminal) {
202
- manager.fitTerminal();
203
- console.log(`Force-resized new terminal-${i}`);
204
- }
205
- }
206
- }, 100);
207
- }, 200);
208
- }, 100);
209
-
210
- // Update add button visibility
211
- this.updateAddButtonVisibility();
212
-
213
- // Show close button for new terminal (except terminal 1)
214
- this.updateCloseButtonsVisibility();
215
-
216
- return;
217
- }
218
- }
219
-
220
- console.log('Maximum number of terminals reached');
221
- }
222
-
223
- async closeTerminal(index) {
224
- if (index === 1) {
225
- console.log('Cannot close terminal 1');
226
- return; // Can't close the first terminal
227
- }
228
-
229
- console.log(`Closing terminal ${index}`);
230
-
231
- const tab = document.getElementById(`terminal-tab-${index}`);
232
- const container = document.getElementById(`terminal-container-${index}`);
233
-
234
- if (tab && container) {
235
- // Destroy server-side terminal session
236
- const terminal = terminalStore.getTerminalByIndex(index);
237
- if (terminal && terminal.sessionId) {
238
- try {
239
- const response = await fetch(`/terminal/session/${terminal.sessionId}`, {
240
- method: 'DELETE'
241
- });
242
-
243
- if (response.ok) {
244
- console.log(`Terminal session ${terminal.sessionId} destroyed on server`);
245
- } else {
246
- console.warn(`Failed to destroy terminal session ${terminal.sessionId} on server:`, await response.text());
247
- }
248
- } catch (error) {
249
- console.error(`Error destroying terminal session ${terminal.sessionId}:`, error);
250
- }
251
- } else {
252
- console.warn(`No terminal found with index ${index} to destroy session`);
253
- }
254
-
255
- // Destroy the terminal manager instance
256
- if (window.terminalManagers) {
257
- const manager = window.terminalManagers.get(`terminal-${index}`);
258
- if (manager) {
259
- await manager.destroy();
260
- window.terminalManagers.delete(`terminal-${index}`);
261
- console.log(`Terminal manager for terminal-${index} destroyed`);
262
- }
263
- }
264
-
265
- // Hide the tab and container
266
- tab.style.display = 'none';
267
- container.style.display = 'none';
268
-
269
- // Remove from store
270
- terminalStore.removeTerminal(`terminal-${index}`);
271
-
272
- // If we're closing the active terminal, switch to another one
273
- if (this.activeTerminalIndex === index) {
274
- // Find the next available terminal
275
- for (let i = 1; i <= this.maxTerminals; i++) {
276
- const nextTab = document.getElementById(`terminal-tab-${i}`);
277
- if (nextTab && nextTab.style.display !== 'none') {
278
- this.switchToTerminal(i);
279
- break;
280
- }
281
- }
282
- }
283
-
284
- // Update add button visibility
285
- this.updateAddButtonVisibility();
286
-
287
- // Update close button visibility
288
- this.updateCloseButtonsVisibility();
289
- }
290
- }
291
-
292
- updateAddButtonVisibility() {
293
- const addBtn = document.getElementById('add-terminal-btn');
294
- if (!addBtn) return;
295
-
296
- // Count visible terminals
297
- let visibleCount = 0;
298
- for (let i = 1; i <= this.maxTerminals; i++) {
299
- const tab = document.getElementById(`terminal-tab-${i}`);
300
- if (tab && tab.style.display !== 'none') {
301
- visibleCount++;
302
- }
303
- }
304
-
305
- // Hide add button if we have max terminals
306
- addBtn.style.display = visibleCount >= this.maxTerminals ? 'none' : 'flex';
307
- }
308
-
309
- updateCloseButtonsVisibility() {
310
- // Count visible terminals
311
- let visibleCount = 0;
312
- for (let i = 1; i <= this.maxTerminals; i++) {
313
- const tab = document.getElementById(`terminal-tab-${i}`);
314
- if (tab && tab.style.display !== 'none') {
315
- visibleCount++;
316
- }
317
- }
318
-
319
- // Show/hide close buttons - never show on terminal 1, only show on others if more than 1 terminal
320
- for (let i = 1; i <= this.maxTerminals; i++) {
321
- const closeBtns = document.querySelectorAll(`[data-terminal-index="${i}"].terminal-close-btn`);
322
- closeBtns.forEach(btn => {
323
- if (i === 1) {
324
- // Never show close button on Terminal 1
325
- btn.style.display = 'none';
326
- } else {
327
- // Show close button on other terminals only if there are multiple terminals
328
- const tab = document.getElementById(`terminal-tab-${i}`);
329
- if (tab && tab.style.display !== 'none' && visibleCount > 1) {
330
- btn.style.display = 'inline-flex';
331
- } else {
332
- btn.style.display = 'none';
333
- }
334
- }
335
- });
336
- }
337
- }
338
-
339
- // Get current state
340
- getState() {
341
- const visibleTerminals = [];
342
- for (let i = 1; i <= this.maxTerminals; i++) {
343
- const tab = document.getElementById(`terminal-tab-${i}`);
344
- if (tab && tab.style.display !== 'none') {
345
- visibleTerminals.push(i);
346
- }
347
- }
348
-
349
- return {
350
- visibleTerminals,
351
- activeTerminalIndex: this.activeTerminalIndex,
352
- maxTerminals: this.maxTerminals
353
- };
354
- }
355
- }
356
-
357
- // Auto-initialize when script loads
358
- let terminalTabManager;
359
-
360
- function initializeTerminalTabs() {
361
- // Wait for DOM elements to be ready
362
- const terminalTab1 = document.getElementById('terminal-tab-1');
363
- if (terminalTab1) {
364
- console.log('Initializing TerminalTabManager...');
365
- terminalTabManager = new TerminalTabManager();
366
- } else {
367
- console.log('Terminal tabs not found, retrying...');
368
- setTimeout(initializeTerminalTabs, 100);
369
- }
370
- }
371
-
372
- // Initialize
373
- if (document.readyState === 'loading') {
374
- document.addEventListener('DOMContentLoaded', initializeTerminalTabs);
375
- } else {
376
- initializeTerminalTabs();
377
- }
378
-
379
- // Make available globally
380
- window.terminalTabManager = terminalTabManager;
381
- window.TerminalTabManager = TerminalTabManager;
382
-
383
- export default TerminalTabManager;
@@ -1,14 +0,0 @@
1
- <svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <style>
3
- path {
4
- fill: black;
5
- }
6
- @media (prefers-color-scheme: dark) {
7
- path {
8
- fill: white;
9
- }
10
- }
11
- </style>
12
- <path d="M236.752 231.541L133.378 335.909C129.158 340.169 124.236 342.21 118.61 342.033C112.984 341.855 108.062 339.637 103.842 335.377C99.9747 331.117 97.953 326.147 97.7771 320.467C97.6013 314.787 99.6231 309.817 103.842 305.557L243.081 164.98C245.19 162.85 247.476 161.342 249.937 160.454C252.398 159.567 255.035 159.123 257.848 159.123C260.661 159.123 263.298 159.567 265.76 160.454C268.221 161.342 270.506 162.85 272.616 164.98L411.854 305.557C415.722 309.462 417.656 314.343 417.656 320.201C417.656 326.058 415.722 331.117 411.854 335.377C407.635 339.637 402.624 341.767 396.823 341.767C391.021 341.767 386.011 339.637 381.791 335.377L278.945 231.541V469.564C278.945 475.599 276.923 480.657 272.88 484.74C268.836 488.822 263.826 490.863 257.848 490.863C251.871 490.863 246.86 488.822 242.817 484.74C238.773 480.657 236.752 475.599 236.752 469.564V231.541Z" fill="currentColor"/>
13
- <path fill-rule="evenodd" clip-rule="evenodd" d="M258 62.2033L388.126 192.329C394.96 199.163 406.04 199.163 412.874 192.329C419.709 185.495 419.709 174.414 412.874 167.58L277.445 32.1512C266.706 21.4118 249.294 21.4118 238.555 32.1512L103.126 167.58C96.2915 174.414 96.2915 185.495 103.126 192.329C109.96 199.163 121.04 199.163 127.874 192.329L258 62.2033Z" fill="currentColor"/>
14
- </svg>
@@ -1,71 +0,0 @@
1
- import { signal, computed } from 'https://esm.sh/@preact/signals@1.2.2';
2
-
3
- // Live Preview state management
4
- class LivePreviewStore {
5
- constructor() {
6
- // Core state signals
7
- this.refreshTrigger = signal(0);
8
- this.previewPort = signal(5173); // Default port
9
- this.currentUrl = signal('http://localhost:5173');
10
- this.isMobileView = signal(false);
11
- this.isLoading = signal(false);
12
-
13
- // Computed values
14
- this.shouldRefresh = computed(() => this.refreshTrigger.value);
15
- this.baseUrl = computed(() => `http://localhost:${this.previewPort.value}`);
16
- }
17
-
18
- // Actions for managing preview state
19
- refresh() {
20
- this.refreshTrigger.value = this.refreshTrigger.value + 1;
21
- }
22
-
23
- setPreviewPort(port) {
24
- this.previewPort.value = port;
25
- // Update currentUrl to use new port if it was using the old port
26
- const currentUrlValue = this.currentUrl.value;
27
- const oldPort = currentUrlValue.match(/:(\d+)/)?.[1];
28
- if (oldPort) {
29
- this.currentUrl.value = currentUrlValue.replace(`:${oldPort}`, `:${port}`);
30
- } else {
31
- this.currentUrl.value = `http://localhost:${port}`;
32
- }
33
- }
34
-
35
- setUrl(url) {
36
- this.currentUrl.value = url;
37
- this.refresh(); // Auto-refresh when URL changes
38
- }
39
-
40
- toggleMobileView() {
41
- this.isMobileView.value = !this.isMobileView.value;
42
- }
43
-
44
- setLoading(isLoading) {
45
- this.isLoading.value = isLoading;
46
- }
47
-
48
- // Debug helpers
49
- getState() {
50
- return {
51
- refreshTrigger: this.refreshTrigger.value,
52
- previewPort: this.previewPort.value,
53
- currentUrl: this.currentUrl.value,
54
- isMobileView: this.isMobileView.value,
55
- isLoading: this.isLoading.value,
56
- baseUrl: this.baseUrl.value
57
- };
58
- }
59
-
60
- logState() {
61
- console.log('Live Preview State:', this.getState());
62
- }
63
- }
64
-
65
- // Create and export singleton instance
66
- export const livePreviewStore = new LivePreviewStore();
67
-
68
- // Make it available globally for debugging
69
- if (typeof window !== 'undefined') {
70
- window.livePreviewStore = livePreviewStore;
71
- }
@@ -1,123 +0,0 @@
1
- import { signal, computed } from 'https://esm.sh/@preact/signals@1.2.2';
2
-
3
- // Sidebar state management
4
- class SidebarStore {
5
- constructor() {
6
- // Core state signals
7
- this.isOpen = signal(true); // Default to open on desktop
8
- this.isMobile = signal(false); // Track if we're in mobile viewport
9
- this.mobileBreakpoint = signal(768); // Breakpoint for mobile/desktop detection
10
-
11
- // Computed values
12
- this.shouldShowBackdrop = computed(() => this.isMobile.value && this.isOpen.value);
13
- this.shouldShowMobileToggle = computed(() => this.isMobile.value && !this.isOpen.value);
14
- this.shouldShowFloatingButton = computed(() => !this.isMobile.value && !this.isOpen.value);
15
-
16
- // Initialize mobile detection
17
- this.initializeMobileDetection();
18
- }
19
-
20
- // Initialize mobile detection and set initial state
21
- initializeMobileDetection() {
22
- if (typeof window !== 'undefined') {
23
- this.updateMobileState();
24
-
25
- // Listen for window resize
26
- window.addEventListener('resize', () => {
27
- this.updateMobileState();
28
- });
29
- }
30
- }
31
-
32
- // Update mobile state based on window width
33
- updateMobileState() {
34
- if (typeof window === 'undefined') return;
35
-
36
- const wasMobile = this.isMobile.value;
37
- const nowMobile = window.innerWidth < this.mobileBreakpoint.value;
38
-
39
- this.isMobile.value = nowMobile;
40
-
41
- // Handle initial state or breakpoint transitions
42
- if (wasMobile === undefined) {
43
- // First time: desktop shows sidebar, mobile hides it
44
- this.isOpen.value = !nowMobile;
45
- } else if (wasMobile !== nowMobile) {
46
- // Breakpoint changed
47
- if (wasMobile && !nowMobile) {
48
- // Mobile to desktop: show sidebar
49
- this.isOpen.value = true;
50
- } else if (!wasMobile && nowMobile) {
51
- // Desktop to mobile: hide sidebar
52
- this.isOpen.value = false;
53
- }
54
- }
55
- }
56
-
57
- // Actions for managing sidebar state
58
- toggle() {
59
- this.isOpen.value = !this.isOpen.value;
60
- console.log(`Sidebar toggled: ${this.isOpen.value ? 'open' : 'closed'}`);
61
- }
62
-
63
- open() {
64
- this.isOpen.value = true;
65
- console.log('Sidebar opened');
66
- }
67
-
68
- close() {
69
- this.isOpen.value = false;
70
- console.log('Sidebar closed');
71
- }
72
-
73
- // Set mobile breakpoint
74
- setMobileBreakpoint(breakpoint) {
75
- this.mobileBreakpoint.value = breakpoint;
76
- this.updateMobileState();
77
- }
78
-
79
- // Get current state (useful for components that need to read state once)
80
- getState() {
81
- return {
82
- isOpen: this.isOpen.value,
83
- isMobile: this.isMobile.value,
84
- mobileBreakpoint: this.mobileBreakpoint.value,
85
- shouldShowBackdrop: this.shouldShowBackdrop.value,
86
- shouldShowMobileToggle: this.shouldShowMobileToggle.value,
87
- shouldShowFloatingButton: this.shouldShowFloatingButton.value
88
- };
89
- }
90
-
91
- // Debug helpers
92
- logState() {
93
- console.log('Sidebar Store State:', this.getState());
94
- }
95
-
96
- // Subscribe to state changes (for components that need to react to changes)
97
- onStateChange(callback) {
98
- // Create an effect that runs when any sidebar state changes
99
- const unsubscribe = () => {
100
- // This is a simple implementation - in a full app you might want more granular subscriptions
101
- const state = this.getState();
102
- callback(state);
103
- };
104
-
105
- // Subscribe to all relevant signals
106
- this.isOpen.subscribe(unsubscribe);
107
- this.isMobile.subscribe(unsubscribe);
108
-
109
- // Return unsubscribe function
110
- return () => {
111
- // Note: Preact signals don't have a direct unsubscribe method
112
- // In a production app, you'd want to implement proper cleanup
113
- };
114
- }
115
- }
116
-
117
- // Create and export singleton instance
118
- export const sidebarStore = new SidebarStore();
119
-
120
- // Make it available globally for debugging
121
- if (typeof window !== 'undefined') {
122
- window.sidebarStore = sidebarStore;
123
- }