deepspace 0.26.0 → 0.26.1

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 (52) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/{chunk-LPXWXF6R.js → chunk-YBXIUDZJ.js} +2 -2
  3. package/dist/{chunk-LPXWXF6R.js.map → chunk-YBXIUDZJ.js.map} +1 -1
  4. package/dist/cli.js +80 -45
  5. package/dist/cli.js.map +1 -1
  6. package/dist/documentation-client-core.js +1 -1
  7. package/dist/documentation-default-renderer.cjs +1 -1
  8. package/dist/documentation-react.js +1 -1
  9. package/dist/documentation-runtime.js +1 -1
  10. package/dist/documentation-server-core.js +1 -1
  11. package/dist/documentation.js +1 -1
  12. package/dist/documentation.js.map +1 -1
  13. package/dist/index.d.ts +26 -434
  14. package/dist/index.js +99 -864
  15. package/dist/index.js.map +1 -1
  16. package/dist/schema.d.ts +4 -41
  17. package/dist/schema.js +2 -242
  18. package/dist/schema.js.map +1 -1
  19. package/dist/server.d.ts +6 -162
  20. package/dist/server.js +13 -281
  21. package/dist/server.js.map +1 -1
  22. package/dist/worker.d.ts +4 -160
  23. package/dist/worker.js +15 -281
  24. package/dist/worker.js.map +1 -1
  25. package/features/messaging/feature.json +3 -43
  26. package/features/messaging/src/ChatPage.tsx +12 -16
  27. package/features/messaging/src/components/chat/ChatHeader.tsx +5 -13
  28. package/features/messaging/src/components/chat/MessageItem.tsx +7 -9
  29. package/features/messaging/src/components/chat/MessageList.tsx +57 -40
  30. package/features/messaging/src/components/chat/ThreadPanel.tsx +25 -11
  31. package/features/messaging/src/components/chat/UserProfilePopover.tsx +10 -29
  32. package/features/messaging/src/hooks/useChatChannel.ts +18 -23
  33. package/features/messaging/src/messaging-schema.ts +0 -2
  34. package/features/search-bar/feature.json +9 -20
  35. package/features/search-bar/src/InlineSearch.tsx +101 -0
  36. package/features/search-bar/src/__tests__/search-model.test.tsx +38 -0
  37. package/features/search-bar/src/search-model.ts +2 -149
  38. package/package.json +1 -1
  39. package/features/messaging/src/ChatMultiPage.tsx +0 -298
  40. package/features/messaging/src/components/chat-multi/AddMemberModal.tsx +0 -188
  41. package/features/messaging/src/components/chat-multi/BrowseGroupsModal.tsx +0 -163
  42. package/features/messaging/src/components/chat-multi/ChannelListItem.tsx +0 -147
  43. package/features/messaging/src/components/chat-multi/ChannelSettingsPanel.tsx +0 -344
  44. package/features/messaging/src/components/chat-multi/ChannelSidebar.tsx +0 -460
  45. package/features/messaging/src/components/chat-multi/CreateGroupModal.tsx +0 -190
  46. package/features/messaging/src/components/chat-multi/InvitationList.tsx +0 -149
  47. package/features/messaging/src/components/chat-multi/NewMessageModal.tsx +0 -159
  48. package/features/messaging/src/hooks/useMultiChannel.ts +0 -142
  49. package/features/search-bar/src/SearchOverlay.tsx +0 -566
  50. package/features/search-bar/src/__tests__/search-model.test.ts +0 -40
  51. package/features/sidebar/feature.json +0 -19
  52. package/features/sidebar/src/AppSidebar.tsx +0 -558
@@ -1,558 +0,0 @@
1
- /**
2
- * AppSidebar -- collapsible left navigation sidebar.
3
- *
4
- * Features:
5
- * - Collapsed (52px): icon-only with right-side tooltips
6
- * - Expanded (240px): icons + labels + user chip
7
- * - Mobile (<=768px): overlay drawer with backdrop
8
- * - Collapse state persisted to localStorage
9
- * - Role-based nav filtering via useUser()
10
- * - Active state via react-router-dom useLocation
11
- */
12
-
13
- import { useState, useEffect, useCallback, type ReactNode } from 'react'
14
- import { useLocation, Link } from 'react-router-dom'
15
- import { PanelLeft, Zap, Menu } from 'lucide-react'
16
- import { useUser } from 'deepspace'
17
- import { ROLES, ROLE_CONFIG, type Role } from 'deepspace'
18
-
19
- // ============================================================================
20
- // CSS injection
21
- // ============================================================================
22
-
23
- const SIDEBAR_CSS = `@layer base {
24
- .app-shell {
25
- height: 100%;
26
- display: flex;
27
- overflow: hidden;
28
- background: color-mix(in srgb, var(--color-card) 40%, var(--color-background));
29
- padding: 8px 8px 8px 0;
30
- }
31
- .app-content {
32
- flex: 1;
33
- min-width: 0;
34
- height: 100%;
35
- display: flex;
36
- flex-direction: column;
37
- overflow: hidden;
38
- background: var(--color-background);
39
- border-radius: 12px;
40
- border: 1px solid var(--color-border);
41
- }
42
- .sidebar {
43
- height: 100%;
44
- display: flex;
45
- flex-direction: column;
46
- overflow: hidden;
47
- flex-shrink: 0;
48
- transition: width 200ms cubic-bezier(0.16, 1, 0.3, 1);
49
- }
50
- .sidebar.collapsed { overflow: visible; }
51
- .sidebar-logo-row {
52
- display: flex;
53
- align-items: center;
54
- height: 52px;
55
- padding: 0 8px;
56
- flex-shrink: 0;
57
- }
58
- .sidebar-logo-btn {
59
- width: 36px;
60
- height: 36px;
61
- display: flex;
62
- align-items: center;
63
- justify-content: center;
64
- flex-shrink: 0;
65
- border: none;
66
- background: none;
67
- border-radius: 8px;
68
- cursor: pointer;
69
- padding: 0;
70
- color: var(--color-primary);
71
- transition: background 0.15s, color 0.15s;
72
- }
73
- .sidebar-logo-btn:hover {
74
- background: color-mix(in srgb, var(--color-muted) 60%, transparent);
75
- color: var(--color-foreground);
76
- }
77
- .sidebar-logo-text {
78
- font-size: 15px;
79
- font-weight: 700;
80
- color: var(--color-foreground);
81
- letter-spacing: -0.3px;
82
- white-space: nowrap;
83
- margin-left: 4px;
84
- opacity: 1;
85
- transition: opacity 150ms ease;
86
- }
87
- .sidebar-collapse-btn {
88
- margin-left: auto;
89
- width: 28px;
90
- height: 28px;
91
- display: flex;
92
- align-items: center;
93
- justify-content: center;
94
- border: none;
95
- background: none;
96
- border-radius: 6px;
97
- color: var(--color-muted-foreground);
98
- cursor: pointer;
99
- flex-shrink: 0;
100
- transition: color 0.15s, background 0.15s;
101
- }
102
- .sidebar-collapse-btn:hover {
103
- color: var(--color-foreground);
104
- background: color-mix(in srgb, var(--color-muted) 60%, transparent);
105
- }
106
- .sidebar-nav-section {
107
- display: flex;
108
- flex-direction: column;
109
- padding: 8px 8px;
110
- gap: 2px;
111
- flex-shrink: 0;
112
- }
113
- .sidebar-nav-item {
114
- display: flex;
115
- align-items: center;
116
- height: 36px;
117
- padding: 0;
118
- border: none;
119
- background: none;
120
- border-radius: 8px;
121
- color: var(--color-muted-foreground);
122
- font-size: 13px;
123
- font-weight: 500;
124
- cursor: pointer;
125
- text-decoration: none;
126
- transition: background 0.15s, color 0.15s;
127
- white-space: nowrap;
128
- font-family: inherit;
129
- overflow: hidden;
130
- }
131
- .sidebar-nav-item:hover {
132
- background: color-mix(in srgb, var(--color-muted) 60%, transparent);
133
- color: var(--color-foreground);
134
- }
135
- .sidebar-nav-item.active {
136
- background: color-mix(in srgb, var(--color-primary) 15%, transparent);
137
- color: var(--color-primary);
138
- font-weight: 600;
139
- }
140
- .sidebar-nav-icon {
141
- width: 36px;
142
- height: 36px;
143
- display: flex;
144
- align-items: center;
145
- justify-content: center;
146
- flex-shrink: 0;
147
- }
148
- .sidebar-nav-label {
149
- margin-left: 4px;
150
- opacity: 1;
151
- transition: opacity 150ms ease;
152
- }
153
- .sidebar-user-section {
154
- margin-top: auto;
155
- padding: 8px 8px;
156
- flex-shrink: 0;
157
- border-top: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
158
- }
159
- .sidebar-user-chip {
160
- display: flex;
161
- align-items: center;
162
- gap: 8px;
163
- padding: 6px 8px;
164
- border-radius: 8px;
165
- overflow: hidden;
166
- transition: background 0.15s;
167
- }
168
- .sidebar-user-avatar {
169
- width: 28px;
170
- height: 28px;
171
- border-radius: 50%;
172
- flex-shrink: 0;
173
- object-fit: cover;
174
- }
175
- .sidebar-user-avatar-fallback {
176
- width: 28px;
177
- height: 28px;
178
- border-radius: 50%;
179
- flex-shrink: 0;
180
- display: flex;
181
- align-items: center;
182
- justify-content: center;
183
- font-size: 11px;
184
- font-weight: 600;
185
- background: color-mix(in srgb, var(--color-muted) 60%, transparent);
186
- color: var(--color-muted-foreground);
187
- }
188
- .sidebar-user-info {
189
- display: flex;
190
- flex-direction: column;
191
- min-width: 0;
192
- opacity: 1;
193
- transition: opacity 150ms ease;
194
- }
195
- .sidebar-user-name {
196
- font-size: 13px;
197
- font-weight: 500;
198
- color: var(--color-foreground);
199
- white-space: nowrap;
200
- overflow: hidden;
201
- text-overflow: ellipsis;
202
- }
203
- .sidebar-user-role {
204
- font-size: 11px;
205
- color: var(--color-muted-foreground);
206
- text-transform: capitalize;
207
- }
208
- .sidebar.collapsed .sidebar-logo-text,
209
- .sidebar.collapsed .sidebar-collapse-btn,
210
- .sidebar.collapsed .sidebar-nav-label { opacity: 0; pointer-events: none; }
211
- .sidebar.collapsed .sidebar-user-info { opacity: 0; pointer-events: none; }
212
- .sidebar.collapsed .sidebar-user-chip { padding: 0; justify-content: center; }
213
- .sidebar.collapsed .sidebar-nav-section { overflow: visible; }
214
- .sidebar.collapsed .sidebar-nav-item { overflow: visible; }
215
- .sidebar-tooltip-right { position: relative; }
216
- .sidebar-tooltip-right::before,
217
- .sidebar-tooltip-right::after {
218
- position: absolute;
219
- opacity: 0;
220
- visibility: hidden;
221
- pointer-events: none;
222
- transition: opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease;
223
- z-index: 10100;
224
- }
225
- .sidebar-tooltip-right::before {
226
- content: '';
227
- top: 50%;
228
- left: 100%;
229
- transform: translateY(-50%) translateX(-2px);
230
- border: 6px solid transparent;
231
- border-right-color: var(--color-card);
232
- }
233
- .sidebar-tooltip-right::after {
234
- content: attr(data-tooltip);
235
- top: 50%;
236
- left: calc(100% + 10px);
237
- transform: translateY(-50%) translateX(-4px);
238
- padding: 6px 10px;
239
- background: var(--color-card);
240
- color: var(--color-foreground);
241
- font-size: 12px;
242
- font-weight: 500;
243
- white-space: nowrap;
244
- border-radius: 6px;
245
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
246
- border: 1px solid var(--color-border);
247
- }
248
- .sidebar-tooltip-right:hover::before,
249
- .sidebar-tooltip-right:hover::after {
250
- opacity: 1;
251
- visibility: visible;
252
- transform: translateY(-50%) translateX(0);
253
- }
254
- .sidebar-mobile-header { display: none; }
255
- .sidebar-mobile-backdrop { display: none; }
256
- }
257
- @media (max-width: 768px) {
258
- .app-shell { padding: 0; }
259
- .app-content { border-radius: 0; border: none; }
260
- .sidebar-mobile-header {
261
- display: flex;
262
- align-items: center;
263
- height: 48px;
264
- padding: 0 12px;
265
- gap: 12px;
266
- flex-shrink: 0;
267
- background: color-mix(in srgb, var(--color-card) 40%, var(--color-background));
268
- border-bottom: 1px solid var(--color-border);
269
- }
270
- .sidebar-mobile-hamburger {
271
- width: 36px;
272
- height: 36px;
273
- display: flex;
274
- align-items: center;
275
- justify-content: center;
276
- border: none;
277
- background: none;
278
- border-radius: 8px;
279
- color: var(--color-muted-foreground);
280
- cursor: pointer;
281
- padding: 0;
282
- flex-shrink: 0;
283
- transition: color 0.15s, background 0.15s;
284
- }
285
- .sidebar-mobile-hamburger:hover {
286
- color: var(--color-foreground);
287
- background: var(--color-muted);
288
- }
289
- .sidebar-mobile-title {
290
- font-size: 15px;
291
- font-weight: 600;
292
- color: var(--color-foreground);
293
- }
294
- .sidebar-mobile-backdrop {
295
- display: block;
296
- position: fixed;
297
- inset: 0;
298
- z-index: 998;
299
- background: rgba(0, 0, 0, 0.4);
300
- animation: sidebarBackdropFadeIn 0.2s ease;
301
- }
302
- .sidebar {
303
- position: fixed;
304
- top: 0;
305
- left: 0;
306
- bottom: 0;
307
- z-index: 999;
308
- width: 260px !important;
309
- background: color-mix(in srgb, var(--color-card) 40%, var(--color-background));
310
- transform: translateX(-100%);
311
- transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
312
- box-shadow: none;
313
- }
314
- .sidebar.mobile-open {
315
- transform: translateX(0);
316
- box-shadow: 4px 0 24px rgba(0, 0, 0, 0.15);
317
- }
318
- .sidebar.collapsed { width: 260px !important; }
319
- .sidebar.collapsed .sidebar-logo-text,
320
- .sidebar.collapsed .sidebar-nav-label { opacity: 1; pointer-events: auto; }
321
- .sidebar.collapsed .sidebar-user-info { opacity: 1; pointer-events: auto; }
322
- .sidebar-collapse-btn { display: none; }
323
- }
324
- @keyframes sidebarBackdropFadeIn {
325
- from { opacity: 0; }
326
- to { opacity: 1; }
327
- }`
328
-
329
- let sidebarCssInjected = false
330
-
331
- function useSidebarCSS() {
332
- useEffect(() => {
333
- if (sidebarCssInjected) return
334
- sidebarCssInjected = true
335
- const style = document.createElement('style')
336
- style.textContent = SIDEBAR_CSS
337
- document.head.appendChild(style)
338
- return () => {
339
- document.head.removeChild(style)
340
- sidebarCssInjected = false
341
- }
342
- }, [])
343
- }
344
-
345
- // ============================================================================
346
- // Types
347
- // ============================================================================
348
-
349
- export interface SidebarNavItem {
350
- path: string
351
- label: string
352
- icon: ReactNode
353
- roles: Role[]
354
- }
355
-
356
- interface AppSidebarProps {
357
- appName: string
358
- navItems: SidebarNavItem[]
359
- isMobileOpen: boolean
360
- onMobileClose: () => void
361
- /** When set and sidebar is expanded, the logo links to this path. */
362
- logoHref?: string
363
- }
364
-
365
- // ============================================================================
366
- // localStorage helpers
367
- // ============================================================================
368
-
369
- const STORAGE_KEY = 'app-sidebar-collapsed'
370
-
371
- function readCollapsed(): boolean {
372
- try {
373
- return localStorage.getItem(STORAGE_KEY) === 'true'
374
- } catch {
375
- return false
376
- }
377
- }
378
-
379
- function writeCollapsed(value: boolean): void {
380
- try {
381
- localStorage.setItem(STORAGE_KEY, String(value))
382
- } catch { /* storage unavailable (private mode/quota): non-critical */ }
383
- }
384
-
385
- // ============================================================================
386
- // Mobile header
387
- // ============================================================================
388
-
389
- interface MobileHeaderProps {
390
- appName: string
391
- onOpenMenu: () => void
392
- }
393
-
394
- export function SidebarMobileHeader({ appName, onOpenMenu }: MobileHeaderProps) {
395
- useSidebarCSS()
396
-
397
- return (
398
- <div className="sidebar-mobile-header">
399
- <button
400
- type="button"
401
- className="sidebar-mobile-hamburger"
402
- onClick={onOpenMenu}
403
- aria-label="Open menu"
404
- >
405
- <Menu size={18} />
406
- </button>
407
- <span className="sidebar-mobile-title">{appName}</span>
408
- </div>
409
- )
410
- }
411
-
412
- // ============================================================================
413
- // AppSidebar
414
- // ============================================================================
415
-
416
- export function AppSidebar({ appName, navItems, isMobileOpen, onMobileClose, logoHref }: AppSidebarProps) {
417
- useSidebarCSS()
418
-
419
- const location = useLocation()
420
- const { user } = useUser()
421
- const isAdmin = user?.role === 'admin'
422
-
423
- const [isCollapsed, setIsCollapsed] = useState(readCollapsed)
424
- const [logoHovered, setLogoHovered] = useState(false)
425
-
426
- const sidebarWidth = isCollapsed ? 52 : 240
427
-
428
- const userRole = (user?.role ?? ROLES.VIEWER) as Role
429
- const roleConfig = ROLE_CONFIG[userRole] ?? ROLE_CONFIG[ROLES.VIEWER]
430
-
431
- const visibleNavItems = isAdmin
432
- ? navItems
433
- : navItems.filter(item => item.roles.includes(userRole))
434
-
435
- const toggleCollapsed = useCallback(() => {
436
- setIsCollapsed(prev => {
437
- const next = !prev
438
- writeCollapsed(next)
439
- return next
440
- })
441
- }, [])
442
-
443
- // Close mobile drawer on route change
444
- useEffect(() => {
445
- onMobileClose()
446
- }, [location.pathname, onMobileClose])
447
-
448
- const handleLogoClick = () => {
449
- if (isMobileOpen) {
450
- onMobileClose()
451
- } else if (isCollapsed) {
452
- toggleCollapsed()
453
- }
454
- }
455
-
456
- const showTooltip = isCollapsed && !isMobileOpen
457
-
458
- const sidebarClasses = [
459
- 'sidebar',
460
- isCollapsed ? 'collapsed' : '',
461
- isMobileOpen ? 'mobile-open' : '',
462
- ].filter(Boolean).join(' ')
463
-
464
- return (
465
- <>
466
- {isMobileOpen && (
467
- <div className="sidebar-mobile-backdrop" onClick={onMobileClose} />
468
- )}
469
-
470
- <nav
471
- className={sidebarClasses}
472
- style={{ width: sidebarWidth }}
473
- >
474
- {/* Logo row */}
475
- <div className="sidebar-logo-row">
476
- {isCollapsed && !isMobileOpen ? (
477
- <button
478
- type="button"
479
- className={`sidebar-logo-btn ${showTooltip ? 'sidebar-tooltip-right' : ''}`}
480
- onClick={handleLogoClick}
481
- data-tooltip={showTooltip ? 'Open Sidebar' : undefined}
482
- onMouseEnter={() => setLogoHovered(true)}
483
- onMouseLeave={() => setLogoHovered(false)}
484
- >
485
- {showTooltip && logoHovered ? (
486
- <PanelLeft size={18} />
487
- ) : (
488
- <Zap size={18} />
489
- )}
490
- </button>
491
- ) : logoHref ? (
492
- <Link to={logoHref} className="sidebar-logo-btn">
493
- <Zap size={18} />
494
- </Link>
495
- ) : (
496
- <button type="button" className="sidebar-logo-btn" onClick={handleLogoClick}>
497
- <Zap size={18} />
498
- </button>
499
- )}
500
- {logoHref && !isCollapsed ? (
501
- <Link to={logoHref} className="sidebar-logo-text">{appName}</Link>
502
- ) : (
503
- <span className="sidebar-logo-text">{appName}</span>
504
- )}
505
- <button
506
- type="button"
507
- className="sidebar-collapse-btn"
508
- onClick={toggleCollapsed}
509
- title="Collapse sidebar"
510
- >
511
- <PanelLeft size={16} />
512
- </button>
513
- </div>
514
-
515
- {/* Navigation items */}
516
- <div className="sidebar-nav-section">
517
- {visibleNavItems.map(item => {
518
- const isActive = location.pathname === item.path
519
- return (
520
- <Link
521
- key={item.path}
522
- to={item.path}
523
- className={`sidebar-nav-item ${isActive ? 'active' : ''} ${showTooltip ? 'sidebar-tooltip-right' : ''}`}
524
- data-tooltip={showTooltip ? item.label : undefined}
525
- >
526
- <span className="sidebar-nav-icon">{item.icon}</span>
527
- <span className="sidebar-nav-label">{item.label}</span>
528
- </Link>
529
- )
530
- })}
531
- </div>
532
-
533
- {/* User chip pinned to bottom */}
534
- {user && (
535
- <div className="sidebar-user-section">
536
- <div className="sidebar-user-chip">
537
- {user.imageUrl ? (
538
- <img
539
- src={user.imageUrl}
540
- alt=""
541
- className="sidebar-user-avatar"
542
- />
543
- ) : (
544
- <div className="sidebar-user-avatar-fallback">
545
- {user.name?.[0]?.toUpperCase() ?? '?'}
546
- </div>
547
- )}
548
- <div className="sidebar-user-info">
549
- <span className="sidebar-user-name">{user.name}</span>
550
- <span className="sidebar-user-role">{roleConfig.title}</span>
551
- </div>
552
- </div>
553
- </div>
554
- )}
555
- </nav>
556
- </>
557
- )
558
- }