ywana-core8 0.2.16 → 0.2.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ywana-core8",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "ywana-core8",
5
5
  "homepage": "https://ywana.github.io/workspace",
6
6
  "author": "Ernesto Roldan Garcia",
@@ -1,5 +1,505 @@
1
1
  import React, { useState } from 'react'
2
2
  import { Desktop } from './desktop.js'
3
+ import {
4
+ useWindowDialogs,
5
+ useWindowNotifications,
6
+ useWindowTooltips,
7
+ useWindowContextMenus,
8
+ useWindowOverlays
9
+ } from './window.js'
10
+
11
+ // Demo components for showcasing WindowInstanceContext features
12
+
13
+ /**
14
+ * Settings App - Demonstrates dialogs and notifications
15
+ */
16
+ const SettingsApp = () => {
17
+ const { showDialog } = useWindowDialogs()
18
+ const { showNotification } = useWindowNotifications()
19
+
20
+ const handleSaveSettings = () => {
21
+ showDialog({
22
+ title: 'Confirm Settings',
23
+ content: (
24
+ <div style={{ padding: '20px' }}>
25
+ <p>Are you sure you want to save these settings?</p>
26
+ <p>This will apply changes to your system configuration.</p>
27
+ </div>
28
+ ),
29
+ actions: (
30
+ <div style={{ display: 'flex', gap: '8px' }}>
31
+ <button
32
+ style={{
33
+ padding: '8px 16px',
34
+ background: '#007bff',
35
+ color: 'white',
36
+ border: 'none',
37
+ borderRadius: '4px',
38
+ cursor: 'pointer'
39
+ }}
40
+ onClick={() => {
41
+ showNotification({
42
+ type: 'success',
43
+ title: 'Settings Saved!',
44
+ message: 'Your configuration has been updated successfully.',
45
+ icon: '✅',
46
+ duration: 3000
47
+ })
48
+ }}
49
+ >
50
+ Save
51
+ </button>
52
+ <button
53
+ style={{
54
+ padding: '8px 16px',
55
+ background: '#6c757d',
56
+ color: 'white',
57
+ border: 'none',
58
+ borderRadius: '4px',
59
+ cursor: 'pointer'
60
+ }}
61
+ >
62
+ Cancel
63
+ </button>
64
+ </div>
65
+ )
66
+ })
67
+ }
68
+
69
+ const handleResetSettings = () => {
70
+ showNotification({
71
+ type: 'warning',
72
+ title: 'Reset Warning',
73
+ message: 'This will restore all settings to default values.',
74
+ icon: '⚠️',
75
+ duration: 4000
76
+ })
77
+ }
78
+
79
+ return (
80
+ <div style={{ padding: '20px' }}>
81
+ <h2>⚙️ System Settings</h2>
82
+ <p>Configure your system preferences</p>
83
+
84
+ <div style={{
85
+ background: '#f8f9fa',
86
+ padding: '16px',
87
+ borderRadius: '8px',
88
+ margin: '20px 0',
89
+ border: '1px solid #dee2e6'
90
+ }}>
91
+ <h3>Display Settings</h3>
92
+ <label style={{ display: 'block', margin: '8px 0' }}>
93
+ <input type="checkbox" defaultChecked /> Enable dark mode
94
+ </label>
95
+ <label style={{ display: 'block', margin: '8px 0' }}>
96
+ <input type="checkbox" /> Show desktop icons
97
+ </label>
98
+ <label style={{ display: 'block', margin: '8px 0' }}>
99
+ Resolution:
100
+ <select style={{ marginLeft: '8px', padding: '4px' }}>
101
+ <option>1920x1080</option>
102
+ <option>1366x768</option>
103
+ <option>1280x720</option>
104
+ </select>
105
+ </label>
106
+ </div>
107
+
108
+ <div style={{ display: 'flex', gap: '12px', marginTop: '20px' }}>
109
+ <button
110
+ onClick={handleSaveSettings}
111
+ style={{
112
+ padding: '10px 20px',
113
+ background: '#28a745',
114
+ color: 'white',
115
+ border: 'none',
116
+ borderRadius: '6px',
117
+ cursor: 'pointer'
118
+ }}
119
+ >
120
+ Save Settings
121
+ </button>
122
+ <button
123
+ onClick={handleResetSettings}
124
+ style={{
125
+ padding: '10px 20px',
126
+ background: '#dc3545',
127
+ color: 'white',
128
+ border: 'none',
129
+ borderRadius: '6px',
130
+ cursor: 'pointer'
131
+ }}
132
+ >
133
+ Reset to Default
134
+ </button>
135
+ </div>
136
+ </div>
137
+ )
138
+ }
139
+
140
+ /**
141
+ * Text Editor App - Demonstrates context menus and tooltips
142
+ */
143
+ const TextEditorApp = () => {
144
+ const { showContextMenu } = useWindowContextMenus()
145
+ const { showTooltip, hideTooltip } = useWindowTooltips()
146
+ const { showNotification } = useWindowNotifications()
147
+ const [content, setContent] = useState('Welcome to the Text Editor!\n\nRight-click for context menu.\nHover buttons for tooltips.')
148
+
149
+ const handleContextMenu = (e) => {
150
+ e.preventDefault()
151
+ const rect = e.target.getBoundingClientRect()
152
+ const windowBounds = e.target.closest('.window').getBoundingClientRect()
153
+
154
+ showContextMenu({
155
+ x: e.clientX - windowBounds.left,
156
+ y: e.clientY - windowBounds.top,
157
+ items: [
158
+ {
159
+ label: 'Cut',
160
+ icon: '✂️',
161
+ shortcut: 'Ctrl+X',
162
+ onClick: () => showNotification({ type: 'info', message: 'Cut selected text', duration: 2000 })
163
+ },
164
+ {
165
+ label: 'Copy',
166
+ icon: '📋',
167
+ shortcut: 'Ctrl+C',
168
+ onClick: () => showNotification({ type: 'info', message: 'Copied to clipboard', duration: 2000 })
169
+ },
170
+ {
171
+ label: 'Paste',
172
+ icon: '📄',
173
+ shortcut: 'Ctrl+V',
174
+ onClick: () => showNotification({ type: 'info', message: 'Pasted from clipboard', duration: 2000 })
175
+ },
176
+ {
177
+ label: 'Select All',
178
+ icon: '🔘',
179
+ shortcut: 'Ctrl+A',
180
+ onClick: () => showNotification({ type: 'info', message: 'Selected all text', duration: 2000 })
181
+ }
182
+ ]
183
+ })
184
+ }
185
+
186
+ const handleTooltip = (e, text) => {
187
+ const rect = e.target.getBoundingClientRect()
188
+ const windowBounds = e.target.closest('.window').getBoundingClientRect()
189
+
190
+ const tooltipId = showTooltip({
191
+ text,
192
+ x: rect.left - windowBounds.left + rect.width / 2,
193
+ y: rect.top - windowBounds.top - 10,
194
+ position: 'top'
195
+ })
196
+
197
+ setTimeout(() => hideTooltip(tooltipId), 2000)
198
+ }
199
+
200
+ return (
201
+ <div style={{ padding: '16px', height: '100%', display: 'flex', flexDirection: 'column' }}>
202
+ <div style={{ display: 'flex', gap: '8px', marginBottom: '12px', padding: '8px', background: '#f8f9fa', borderRadius: '4px' }}>
203
+ <button
204
+ onMouseEnter={(e) => handleTooltip(e, 'Create a new document')}
205
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
206
+ >
207
+ 📄 New
208
+ </button>
209
+ <button
210
+ onMouseEnter={(e) => handleTooltip(e, 'Open an existing document')}
211
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
212
+ >
213
+ 📁 Open
214
+ </button>
215
+ <button
216
+ onMouseEnter={(e) => handleTooltip(e, 'Save current document')}
217
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
218
+ >
219
+ 💾 Save
220
+ </button>
221
+ <button
222
+ onMouseEnter={(e) => handleTooltip(e, 'Undo last action')}
223
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
224
+ >
225
+ ↶ Undo
226
+ </button>
227
+ <button
228
+ onMouseEnter={(e) => handleTooltip(e, 'Redo last undone action')}
229
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
230
+ >
231
+ ↷ Redo
232
+ </button>
233
+ </div>
234
+
235
+ <textarea
236
+ value={content}
237
+ onChange={(e) => setContent(e.target.value)}
238
+ onContextMenu={handleContextMenu}
239
+ style={{
240
+ flex: 1,
241
+ border: '1px solid #ccc',
242
+ borderRadius: '4px',
243
+ padding: '12px',
244
+ fontFamily: 'monospace',
245
+ fontSize: '14px',
246
+ resize: 'none',
247
+ outline: 'none'
248
+ }}
249
+ placeholder="Start typing your document..."
250
+ />
251
+
252
+ <div style={{
253
+ marginTop: '8px',
254
+ padding: '8px',
255
+ background: '#f8f9fa',
256
+ borderRadius: '4px',
257
+ fontSize: '12px',
258
+ color: '#666',
259
+ display: 'flex',
260
+ justifyContent: 'space-between'
261
+ }}>
262
+ <span>Lines: {content.split('\n').length}</span>
263
+ <span>Characters: {content.length}</span>
264
+ <span>Words: {content.split(/\s+/).filter(w => w.length > 0).length}</span>
265
+ </div>
266
+ </div>
267
+ )
268
+ }
269
+
270
+ /**
271
+ * File Explorer App - Demonstrates overlays and all features combined
272
+ */
273
+ const FileExplorerApp = () => {
274
+ const { showOverlay, hideOverlay } = useWindowOverlays()
275
+ const { showDialog } = useWindowDialogs()
276
+ const { showNotification } = useWindowNotifications()
277
+ const { showContextMenu } = useWindowContextMenus()
278
+
279
+ const handleFileOperation = (operation) => {
280
+ const overlayId = showOverlay({
281
+ content: (
282
+ <div style={{ padding: '40px', textAlign: 'center', minWidth: '300px' }}>
283
+ <h3>Processing...</h3>
284
+ <div style={{
285
+ width: '40px',
286
+ height: '40px',
287
+ border: '4px solid #f3f3f3',
288
+ borderTop: '4px solid #007bff',
289
+ borderRadius: '50%',
290
+ animation: 'spin 1s linear infinite',
291
+ margin: '20px auto'
292
+ }}></div>
293
+ <p>{operation} files...</p>
294
+ <style jsx>{`
295
+ @keyframes spin {
296
+ 0% { transform: rotate(0deg); }
297
+ 100% { transform: rotate(360deg); }
298
+ }
299
+ `}</style>
300
+ </div>
301
+ ),
302
+ closeOnBackdrop: false,
303
+ showCloseButton: false
304
+ })
305
+
306
+ // Simulate file operation
307
+ setTimeout(() => {
308
+ hideOverlay(overlayId)
309
+ showNotification({
310
+ type: 'success',
311
+ title: 'Operation Complete',
312
+ message: `${operation} completed successfully!`,
313
+ icon: '✅',
314
+ duration: 3000
315
+ })
316
+ }, 2000)
317
+ }
318
+
319
+ const handleDeleteFile = (fileName) => {
320
+ showDialog({
321
+ title: 'Delete File',
322
+ content: (
323
+ <div style={{ padding: '20px' }}>
324
+ <p>Are you sure you want to delete <strong>{fileName}</strong>?</p>
325
+ <p style={{ color: '#dc3545', fontSize: '14px' }}>This action cannot be undone.</p>
326
+ </div>
327
+ ),
328
+ actions: (
329
+ <div style={{ display: 'flex', gap: '8px' }}>
330
+ <button
331
+ style={{
332
+ padding: '8px 16px',
333
+ background: '#dc3545',
334
+ color: 'white',
335
+ border: 'none',
336
+ borderRadius: '4px',
337
+ cursor: 'pointer'
338
+ }}
339
+ onClick={() => handleFileOperation('Deleting')}
340
+ >
341
+ Delete
342
+ </button>
343
+ <button
344
+ style={{
345
+ padding: '8px 16px',
346
+ background: '#6c757d',
347
+ color: 'white',
348
+ border: 'none',
349
+ borderRadius: '4px',
350
+ cursor: 'pointer'
351
+ }}
352
+ >
353
+ Cancel
354
+ </button>
355
+ </div>
356
+ )
357
+ })
358
+ }
359
+
360
+ const handleFileContextMenu = (e, fileName) => {
361
+ e.preventDefault()
362
+ const windowBounds = e.target.closest('.window').getBoundingClientRect()
363
+
364
+ showContextMenu({
365
+ x: e.clientX - windowBounds.left,
366
+ y: e.clientY - windowBounds.top,
367
+ items: [
368
+ {
369
+ label: 'Open',
370
+ icon: '📂',
371
+ onClick: () => showNotification({ type: 'info', message: `Opening ${fileName}`, duration: 2000 })
372
+ },
373
+ {
374
+ label: 'Copy',
375
+ icon: '📋',
376
+ shortcut: 'Ctrl+C',
377
+ onClick: () => handleFileOperation('Copying')
378
+ },
379
+ {
380
+ label: 'Cut',
381
+ icon: '✂️',
382
+ shortcut: 'Ctrl+X',
383
+ onClick: () => handleFileOperation('Moving')
384
+ },
385
+ {
386
+ label: 'Delete',
387
+ icon: '🗑️',
388
+ shortcut: 'Del',
389
+ onClick: () => handleDeleteFile(fileName)
390
+ },
391
+ {
392
+ label: 'Properties',
393
+ icon: '📋',
394
+ onClick: () => showDialog({
395
+ title: `Properties - ${fileName}`,
396
+ content: (
397
+ <div style={{ padding: '20px' }}>
398
+ <h4>{fileName}</h4>
399
+ <p><strong>Type:</strong> Document</p>
400
+ <p><strong>Size:</strong> 1.2 MB</p>
401
+ <p><strong>Created:</strong> Today, 10:30 AM</p>
402
+ <p><strong>Modified:</strong> Today, 2:15 PM</p>
403
+ </div>
404
+ )
405
+ })
406
+ }
407
+ ]
408
+ })
409
+ }
410
+
411
+ const files = [
412
+ { name: 'Document.txt', icon: '📄', type: 'Text Document' },
413
+ { name: 'Image.jpg', icon: '🖼️', type: 'JPEG Image' },
414
+ { name: 'Presentation.pptx', icon: '📊', type: 'PowerPoint' },
415
+ { name: 'Spreadsheet.xlsx', icon: '📈', type: 'Excel File' },
416
+ { name: 'Video.mp4', icon: '🎬', type: 'Video File' },
417
+ { name: 'Archive.zip', icon: '📦', type: 'Compressed File' }
418
+ ]
419
+
420
+ return (
421
+ <div style={{ padding: '16px', height: '100%', display: 'flex', flexDirection: 'column' }}>
422
+ <div style={{ display: 'flex', gap: '8px', marginBottom: '16px', padding: '8px', background: '#f8f9fa', borderRadius: '4px' }}>
423
+ <button
424
+ onClick={() => handleFileOperation('Creating new folder')}
425
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
426
+ >
427
+ 📁 New Folder
428
+ </button>
429
+ <button
430
+ onClick={() => handleFileOperation('Uploading')}
431
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
432
+ >
433
+ 📤 Upload
434
+ </button>
435
+ <button
436
+ onClick={() => handleFileOperation('Refreshing')}
437
+ style={{ padding: '6px 12px', border: '1px solid #ccc', borderRadius: '4px', cursor: 'pointer' }}
438
+ >
439
+ 🔄 Refresh
440
+ </button>
441
+ </div>
442
+
443
+ <div style={{
444
+ flex: 1,
445
+ border: '1px solid #dee2e6',
446
+ borderRadius: '4px',
447
+ background: 'white',
448
+ overflow: 'auto'
449
+ }}>
450
+ <div style={{
451
+ display: 'grid',
452
+ gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',
453
+ gap: '16px',
454
+ padding: '16px'
455
+ }}>
456
+ {files.map((file, index) => (
457
+ <div
458
+ key={index}
459
+ onContextMenu={(e) => handleFileContextMenu(e, file.name)}
460
+ onDoubleClick={() => showNotification({
461
+ type: 'info',
462
+ message: `Opening ${file.name}`,
463
+ duration: 2000
464
+ })}
465
+ style={{
466
+ display: 'flex',
467
+ flexDirection: 'column',
468
+ alignItems: 'center',
469
+ padding: '12px',
470
+ borderRadius: '8px',
471
+ cursor: 'pointer',
472
+ transition: 'background-color 0.2s',
473
+ ':hover': { background: '#f8f9fa' }
474
+ }}
475
+ onMouseEnter={(e) => e.target.style.background = '#f8f9fa'}
476
+ onMouseLeave={(e) => e.target.style.background = 'transparent'}
477
+ >
478
+ <div style={{ fontSize: '32px', marginBottom: '8px' }}>{file.icon}</div>
479
+ <div style={{ fontSize: '12px', textAlign: 'center', wordBreak: 'break-word' }}>
480
+ {file.name}
481
+ </div>
482
+ <div style={{ fontSize: '10px', color: '#666', textAlign: 'center' }}>
483
+ {file.type}
484
+ </div>
485
+ </div>
486
+ ))}
487
+ </div>
488
+ </div>
489
+
490
+ <div style={{
491
+ marginTop: '8px',
492
+ padding: '8px',
493
+ background: '#f8f9fa',
494
+ borderRadius: '4px',
495
+ fontSize: '12px',
496
+ color: '#666'
497
+ }}>
498
+ {files.length} items • Right-click for context menu • Double-click to open
499
+ </div>
500
+ </div>
501
+ )
502
+ }
3
503
 
4
504
  // Complete desktop configuration
5
505
  const desktopConfig = {
@@ -16,20 +516,20 @@ const desktopConfig = {
16
516
  {
17
517
  id: 'file-explorer',
18
518
  name: 'File Explorer',
19
- description: 'Browse and manage files',
519
+ description: 'Browse and manage files - Showcases overlays, dialogs, context menus',
20
520
  icon: '📁',
21
521
  category: 'System',
22
- component: null,
23
- size: { width: 600, height: 400 }
522
+ component: <FileExplorerApp />,
523
+ size: { width: 600, height: 450 }
24
524
  },
25
525
  {
26
526
  id: 'text-editor',
27
527
  name: 'Text Editor',
28
- description: 'Edit text files',
528
+ description: 'Edit text files - Showcases context menus and tooltips',
29
529
  icon: '📝',
30
530
  category: 'Productivity',
31
- component: null,
32
- size: { width: 500, height: 350 }
531
+ component: <TextEditorApp />,
532
+ size: { width: 550, height: 400 }
33
533
  },
34
534
  {
35
535
  id: 'calculator',
@@ -43,11 +543,11 @@ const desktopConfig = {
43
543
  {
44
544
  id: 'settings',
45
545
  name: 'Settings',
46
- description: 'System configuration',
546
+ description: 'System configuration - Showcases dialogs and notifications',
47
547
  icon: '⚙️',
48
548
  category: 'System',
49
- component: null,
50
- size: { width: 450, height: 300 }
549
+ component: <SettingsApp />,
550
+ size: { width: 480, height: 350 }
51
551
  },
52
552
  {
53
553
  id: 'browser',
@@ -55,7 +555,7 @@ const desktopConfig = {
55
555
  description: 'Browse the internet',
56
556
  icon: '🌐',
57
557
  category: 'Internet',
58
- component: null,
558
+ content: null,
59
559
  size: { width: 800, height: 500 }
60
560
  },
61
561
  {
@@ -64,7 +564,7 @@ const desktopConfig = {
64
564
  description: 'Command line interface',
65
565
  icon: '💻',
66
566
  category: 'Development',
67
- component: null,
567
+ content: null,
68
568
  size: { width: 700, height: 400 }
69
569
  },
70
570
  {
@@ -73,7 +573,7 @@ const desktopConfig = {
73
573
  description: 'View and edit images',
74
574
  icon: '🖼️',
75
575
  category: 'Media',
76
- component: null,
576
+ content: null,
77
577
  size: { width: 600, height: 500 }
78
578
  },
79
579
  {
@@ -82,7 +582,7 @@ const desktopConfig = {
82
582
  description: 'Play audio files',
83
583
  icon: '🎵',
84
584
  category: 'Media',
85
- component: null,
585
+ content: null,
86
586
  size: { width: 400, height: 300 }
87
587
  }
88
588
  ]
@@ -166,7 +666,15 @@ export const CompleteDesktop = () => {
166
666
  <li><strong>Responsive:</strong> Windows stay within workspace bounds</li>
167
667
  </ul>
168
668
 
169
- <h4>🎨 Current Theme: <span style={{color: '#2196f3'}}>{theme}</span></h4>
669
+ <h4>� New WindowInstanceContext Features:</h4>
670
+ <ul>
671
+ <li><strong>Settings App:</strong> Dialogs and notifications</li>
672
+ <li><strong>Text Editor:</strong> Context menus (right-click) and tooltips (hover buttons)</li>
673
+ <li><strong>File Explorer:</strong> All features combined - overlays, dialogs, context menus</li>
674
+ <li><strong>Contained Elements:</strong> All floating elements stay within window boundaries</li>
675
+ </ul>
676
+
677
+ <h4>�🎨 Current Theme: <span style={{color: '#2196f3'}}>{theme}</span></h4>
170
678
  <p><em>Change theme using the selector in top-right corner</em></p>
171
679
  </div>
172
680
  </div>