queen-mq 0.1.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 (90) hide show
  1. package/API.md +1116 -0
  2. package/CACHE.md +519 -0
  3. package/DASHBOARD-V3.md +478 -0
  4. package/DASHBOARD.md +382 -0
  5. package/MOD_QUEUE.md +453 -0
  6. package/PARTITION_LOCKING_DESIGN.md +989 -0
  7. package/PLAN.md +707 -0
  8. package/QUERY_ANALSYS.md +72 -0
  9. package/QUEUE_BUS.md +334 -0
  10. package/README.md +1495 -0
  11. package/V2-PLAN.md +236 -0
  12. package/assets/dashboard.png +0 -0
  13. package/dashboard/.vscode/extensions.json +3 -0
  14. package/dashboard/README.md +5 -0
  15. package/dashboard/index.html +14 -0
  16. package/dashboard/package-lock.json +1458 -0
  17. package/dashboard/package.json +25 -0
  18. package/dashboard/public/vite.svg +1 -0
  19. package/dashboard/src/App.vue +29 -0
  20. package/dashboard/src/assets/styles/main.css +908 -0
  21. package/dashboard/src/assets/vue.svg +1 -0
  22. package/dashboard/src/components/cards/MetricCard.vue +298 -0
  23. package/dashboard/src/components/charts/QueueDepthChart.vue +276 -0
  24. package/dashboard/src/components/charts/QueueLagChart.vue +436 -0
  25. package/dashboard/src/components/charts/ThroughputChart.vue +302 -0
  26. package/dashboard/src/components/common/ActivityFeed.vue +251 -0
  27. package/dashboard/src/components/layout/AppHeader.vue +208 -0
  28. package/dashboard/src/components/layout/AppLayout.vue +88 -0
  29. package/dashboard/src/components/layout/AppSidebar.vue +261 -0
  30. package/dashboard/src/main.js +44 -0
  31. package/dashboard/src/router.js +54 -0
  32. package/dashboard/src/services/api.js +187 -0
  33. package/dashboard/src/services/websocket.js +167 -0
  34. package/dashboard/src/utils/constants.js +56 -0
  35. package/dashboard/src/utils/helpers.js +118 -0
  36. package/dashboard/src/views/Analytics.vue +912 -0
  37. package/dashboard/src/views/Dashboard.vue +906 -0
  38. package/dashboard/src/views/Messages.vue +437 -0
  39. package/dashboard/src/views/QueueDetail.vue +501 -0
  40. package/dashboard/src/views/Queues.vue +333 -0
  41. package/dashboard/vite.config.js +30 -0
  42. package/debug-namespace.js +110 -0
  43. package/docs/long-polling.md +159 -0
  44. package/docs/multi-server-cache-solutions.md +185 -0
  45. package/docs/performance-tuning.md +222 -0
  46. package/examples/bus-mode.js +239 -0
  47. package/examples/continuous-consumer-optimized.js +215 -0
  48. package/examples/continuous-consumer.js +159 -0
  49. package/examples/continuous-producer.js +343 -0
  50. package/examples/mixed-mode.js +277 -0
  51. package/examples/multi-server-test.js +305 -0
  52. package/examples/single.js +64 -0
  53. package/examples/smartchat-dealyed.js +42 -0
  54. package/examples/smartchat.js +52 -0
  55. package/examples/test-cache-invalidation.js +119 -0
  56. package/examples/test-cache-multi-server.js +245 -0
  57. package/examples/test-minimal-client.js +112 -0
  58. package/examples/test-queue-creation-policy.js +137 -0
  59. package/init-db.js +20 -0
  60. package/package.json +36 -0
  61. package/src/client/client.js +291 -0
  62. package/src/client/index.js +6 -0
  63. package/src/client/queenClient.js +513 -0
  64. package/src/client/utils/http.js +172 -0
  65. package/src/client/utils/loadBalancer.js +152 -0
  66. package/src/client/utils/retry.js +35 -0
  67. package/src/config.js +215 -0
  68. package/src/database/connection.js +103 -0
  69. package/src/database/poolManager.js +192 -0
  70. package/src/database/schema-v2.sql +214 -0
  71. package/src/managers/eventManager.js +59 -0
  72. package/src/managers/queueManagerOptimized.js +1512 -0
  73. package/src/managers/resourceCache.js +96 -0
  74. package/src/managers/systemEventManager.js +127 -0
  75. package/src/routes/ack.js +26 -0
  76. package/src/routes/analytics.js +812 -0
  77. package/src/routes/configure.js +46 -0
  78. package/src/routes/messages.js +298 -0
  79. package/src/routes/pop.js +85 -0
  80. package/src/routes/push.js +28 -0
  81. package/src/routes/resources.js +296 -0
  82. package/src/server.js +1286 -0
  83. package/src/services/encryptionService.js +82 -0
  84. package/src/services/evictionService.js +131 -0
  85. package/src/services/retentionService.js +129 -0
  86. package/src/services/startupSync.js +35 -0
  87. package/src/test/test.js +4521 -0
  88. package/src/utils/logger.js +44 -0
  89. package/src/utils/uuid.js +5 -0
  90. package/src/websocket/wsServer.js +221 -0
@@ -0,0 +1,908 @@
1
+ /* Queen Dashboard V3 - Dark Theme with Rose Primary */
2
+
3
+ /* ============================================
4
+ Dark Mode Color System - Aura Theme
5
+ ============================================ */
6
+ :root.dark {
7
+ /* Surface Colors - Dark Mode (Stone) */
8
+ --surface-0: #0c0a09; /* Darkest background - stone-950 */
9
+ --surface-50: #1c1917; /* Card backgrounds - stone-900 */
10
+ --surface-100: #292524; /* Elevated surfaces - stone-800 */
11
+ --surface-200: #44403c; /* Borders, dividers - stone-700 */
12
+ --surface-300: #57534e; /* Disabled text - stone-600 */
13
+ --surface-400: #78716c; /* Muted text - stone-500 */
14
+ --surface-500: #a8a29e; /* Regular text - stone-400 */
15
+ --surface-600: #d6d3d1; /* Emphasized text - stone-300 */
16
+ --surface-700: #e7e5e4; /* Bright text - stone-200 */
17
+ --surface-800: #f5f5f4; /* Brightest text - stone-100 */
18
+ --surface-900: #fafaf9; /* Pure white - stone-50 */
19
+
20
+ /* Rose/Pink Primary Colors */
21
+ --primary-50: #fdf2f8;
22
+ --primary-100: #fce7f3;
23
+ --primary-200: #fbcfe8;
24
+ --primary-300: #f9a8d4;
25
+ --primary-400: #f472b6;
26
+ --primary-500: #ec4899; /* Main rose */
27
+ --primary-600: #db2777;
28
+ --primary-700: #be185d;
29
+ --primary-800: #9f1239;
30
+ --primary-900: #881337;
31
+
32
+ /* Gradient Definitions */
33
+ --gradient-primary: linear-gradient(135deg, #ec4899 0%, #db2777 100%);
34
+ --gradient-chart: linear-gradient(180deg, rgba(236, 72, 153, 0.4) 0%, rgba(236, 72, 153, 0.1) 100%);
35
+ --gradient-glow: radial-gradient(circle at center, rgba(236, 72, 153, 0.2), transparent);
36
+
37
+ /* Status Colors */
38
+ --success-color: #10b981;
39
+ --warning-color: #f59e0b;
40
+ --danger-color: #ef4444;
41
+ --info-color: #06b6d4;
42
+
43
+ /* Semantic Colors */
44
+ --text-color: var(--surface-600);
45
+ --text-secondary: var(--surface-500);
46
+ --text-muted: var(--surface-400);
47
+ --bg-primary: var(--surface-0);
48
+ --bg-secondary: var(--surface-50);
49
+ --border-color: rgba(255, 255, 255, 0.05);
50
+
51
+ /* Spacing */
52
+ --spacing-xs: 0.25rem;
53
+ --spacing-sm: 0.5rem;
54
+ --spacing-md: 1rem;
55
+ --spacing-lg: 1.5rem;
56
+ --spacing-xl: 2rem;
57
+ --spacing-2xl: 3rem;
58
+
59
+ /* Border Radius */
60
+ --radius-sm: 0.25rem;
61
+ --radius-md: 0.375rem;
62
+ --radius-lg: 0.5rem;
63
+ --radius-xl: 0.75rem;
64
+ --radius-2xl: 1rem;
65
+ --radius-full: 9999px;
66
+
67
+ /* Shadows - Dark Mode */
68
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
69
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
70
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
71
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.6);
72
+ --shadow-glow: 0 0 20px rgba(236, 72, 153, 0.3);
73
+
74
+ /* Transitions */
75
+ --transition-fast: 150ms ease;
76
+ --transition-base: 250ms ease;
77
+ --transition-slow: 350ms ease;
78
+ }
79
+
80
+ /* ============================================
81
+ Base Styles
82
+ ============================================ */
83
+ * {
84
+ margin: 0;
85
+ padding: 0;
86
+ box-sizing: border-box;
87
+ }
88
+
89
+ html {
90
+ font-size: 14px;
91
+ }
92
+
93
+ body {
94
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
95
+ background: #0c0a09;
96
+ color: var(--text-color);
97
+ line-height: 1.6;
98
+ min-height: 100vh;
99
+ -webkit-font-smoothing: antialiased;
100
+ -moz-osx-font-smoothing: grayscale;
101
+ transition: background-color var(--transition-base), color var(--transition-base);
102
+ }
103
+
104
+ .dark body {
105
+ background: #0c0a09;
106
+ }
107
+
108
+ #app {
109
+ min-height: 100vh;
110
+ display: flex;
111
+ flex-direction: column;
112
+ background: #0c0a09;
113
+ }
114
+
115
+ /* ============================================
116
+ Typography
117
+ ============================================ */
118
+ h1, h2, h3, h4, h5, h6 {
119
+ font-weight: 600;
120
+ line-height: 1.3;
121
+ color: var(--surface-700);
122
+ }
123
+
124
+ h1 { font-size: 1.875rem; }
125
+ h2 { font-size: 1.5rem; }
126
+ h3 { font-size: 1.25rem; }
127
+ h4 { font-size: 1.125rem; }
128
+ h5 { font-size: 1rem; }
129
+ h6 { font-size: 0.875rem; }
130
+
131
+ p {
132
+ color: var(--text-secondary);
133
+ }
134
+
135
+ /* ============================================
136
+ Cards - Dark Theme V3
137
+ ============================================ */
138
+ .card-v3 {
139
+ background: transparent;
140
+ border: 1px solid rgba(255, 255, 255, 0.1);
141
+ border-radius: 16px;
142
+ padding: 1.5rem;
143
+ position: relative;
144
+ overflow: hidden;
145
+ transition: all var(--transition-base);
146
+ }
147
+
148
+ .card-v3::before {
149
+ content: '';
150
+ position: absolute;
151
+ top: 0;
152
+ left: 0;
153
+ right: 0;
154
+ height: 1px;
155
+ background: linear-gradient(90deg,
156
+ transparent,
157
+ rgba(236, 72, 153, 0.5),
158
+ transparent
159
+ );
160
+ }
161
+
162
+ .card-v3:hover {
163
+ transform: translateY(-2px);
164
+ box-shadow: var(--shadow-glow);
165
+ border-color: rgba(236, 72, 153, 0.2);
166
+ }
167
+
168
+ /* ============================================
169
+ Metric Cards - V3 Design
170
+ ============================================ */
171
+ .metric-card-v3 {
172
+ background: transparent;
173
+ border: 1px solid rgba(255, 255, 255, 0.08);
174
+ border-radius: 12px;
175
+ padding: 1.25rem;
176
+ display: flex;
177
+ align-items: flex-start;
178
+ gap: 1rem;
179
+ position: relative;
180
+ overflow: hidden;
181
+ transition: all var(--transition-base);
182
+ }
183
+
184
+ .metric-card-v3:hover {
185
+ border-color: rgba(236, 72, 153, 0.15);
186
+ }
187
+
188
+ .metric-icon-wrapper {
189
+ width: 48px;
190
+ height: 48px;
191
+ border-radius: 12px;
192
+ background: var(--gradient-primary);
193
+ display: flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ flex-shrink: 0;
197
+ }
198
+
199
+ .metric-icon-wrapper i {
200
+ font-size: 1.25rem;
201
+ color: white;
202
+ }
203
+
204
+ .metric-content {
205
+ flex: 1;
206
+ min-width: 0;
207
+ }
208
+
209
+ .metric-label {
210
+ font-size: 0.75rem;
211
+ color: var(--surface-400);
212
+ text-transform: uppercase;
213
+ letter-spacing: 0.05em;
214
+ margin-bottom: 0.25rem;
215
+ }
216
+
217
+ .metric-value {
218
+ font-size: 1.75rem;
219
+ font-weight: 700;
220
+ color: var(--surface-700);
221
+ line-height: 1;
222
+ margin-bottom: 0.5rem;
223
+ }
224
+
225
+ .metric-change {
226
+ display: inline-flex;
227
+ align-items: center;
228
+ gap: 0.25rem;
229
+ font-size: 0.875rem;
230
+ font-weight: 500;
231
+ }
232
+
233
+ .metric-change.positive {
234
+ color: var(--success-color);
235
+ }
236
+
237
+ .metric-change.negative {
238
+ color: var(--danger-color);
239
+ }
240
+
241
+ .metric-sparkline {
242
+ position: absolute;
243
+ right: 1rem;
244
+ bottom: 1rem;
245
+ width: 80px;
246
+ height: 30px;
247
+ opacity: 0.5;
248
+ }
249
+
250
+ /* ============================================
251
+ Buttons - Dark Theme
252
+ ============================================ */
253
+ .btn-primary {
254
+ background: var(--gradient-primary);
255
+ border: none;
256
+ color: white;
257
+ padding: 0.625rem 1.25rem;
258
+ border-radius: 8px;
259
+ font-weight: 500;
260
+ box-shadow: 0 4px 14px rgba(236, 72, 153, 0.3);
261
+ cursor: pointer;
262
+ transition: all var(--transition-base);
263
+ }
264
+
265
+ .btn-primary:hover {
266
+ transform: translateY(-1px);
267
+ box-shadow: 0 6px 20px rgba(236, 72, 153, 0.4);
268
+ }
269
+
270
+ .btn-secondary {
271
+ background: rgba(255, 255, 255, 0.05);
272
+ border: 1px solid rgba(255, 255, 255, 0.1);
273
+ color: var(--surface-500);
274
+ padding: 0.625rem 1.25rem;
275
+ border-radius: 8px;
276
+ font-weight: 500;
277
+ cursor: pointer;
278
+ transition: all var(--transition-base);
279
+ }
280
+
281
+ .btn-secondary:hover {
282
+ background: rgba(255, 255, 255, 0.08);
283
+ border-color: rgba(255, 255, 255, 0.2);
284
+ color: var(--surface-600);
285
+ }
286
+
287
+ /* ============================================
288
+ Input Fields - Dark Theme
289
+ ============================================ */
290
+ .input-v3 {
291
+ background: rgba(0, 0, 0, 0.3);
292
+ border: 1px solid rgba(255, 255, 255, 0.1);
293
+ border-radius: 8px;
294
+ color: var(--surface-600);
295
+ padding: 0.625rem 1rem;
296
+ font-size: 0.875rem;
297
+ width: 100%;
298
+ transition: all var(--transition-base);
299
+ }
300
+
301
+ .input-v3:focus {
302
+ outline: none;
303
+ border-color: var(--primary-500);
304
+ box-shadow: 0 0 0 3px rgba(236, 72, 153, 0.1);
305
+ background: rgba(0, 0, 0, 0.5);
306
+ }
307
+
308
+ .input-v3::placeholder {
309
+ color: var(--surface-300);
310
+ }
311
+
312
+ /* ============================================
313
+ Tables - Dark Theme
314
+ ============================================ */
315
+ .dark-table-v3 {
316
+ background: transparent;
317
+ border-radius: 12px;
318
+ overflow: hidden;
319
+ border: none;
320
+ }
321
+
322
+ .dark-table-v3 thead {
323
+ background: var(--surface-0);
324
+ }
325
+
326
+ .dark-table-v3 th {
327
+ color: var(--surface-400);
328
+ font-weight: 600;
329
+ font-size: 0.75rem;
330
+ text-transform: uppercase;
331
+ letter-spacing: 0.05em;
332
+ padding: 1rem;
333
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
334
+ }
335
+
336
+ .dark-table-v3 td {
337
+ color: var(--surface-600);
338
+ padding: 0.875rem 1rem;
339
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
340
+ }
341
+
342
+ .dark-table-v3 tbody tr {
343
+ transition: all var(--transition-fast);
344
+ }
345
+
346
+ .dark-table-v3 tbody tr:hover {
347
+ background: rgba(236, 72, 153, 0.05);
348
+ }
349
+
350
+ /* ============================================
351
+ Queue Distribution Card
352
+ ============================================ */
353
+ .distribution-card {
354
+ background: transparent;
355
+ border: 1px solid rgba(255, 255, 255, 0.1);
356
+ border-radius: 16px;
357
+ padding: 1.5rem;
358
+ }
359
+
360
+ .distribution-header {
361
+ display: flex;
362
+ justify-content: space-between;
363
+ align-items: center;
364
+ margin-bottom: 1.5rem;
365
+ }
366
+
367
+ .distribution-header h3 {
368
+ font-size: 1.125rem;
369
+ color: var(--surface-700);
370
+ }
371
+
372
+ .distribution-bar {
373
+ display: flex;
374
+ height: 40px;
375
+ border-radius: 8px;
376
+ overflow: hidden;
377
+ margin-bottom: 1.5rem;
378
+ background: var(--surface-0);
379
+ }
380
+
381
+ .distribution-bar .segment {
382
+ transition: all var(--transition-base);
383
+ position: relative;
384
+ }
385
+
386
+ .distribution-bar .segment:hover {
387
+ filter: brightness(1.2);
388
+ }
389
+
390
+ .distribution-legend {
391
+ display: grid;
392
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
393
+ gap: 0.75rem;
394
+ }
395
+
396
+ .legend-item {
397
+ display: flex;
398
+ align-items: center;
399
+ gap: 0.5rem;
400
+ font-size: 0.875rem;
401
+ color: var(--surface-500);
402
+ }
403
+
404
+ .legend-item .dot {
405
+ width: 8px;
406
+ height: 8px;
407
+ border-radius: 50%;
408
+ flex-shrink: 0;
409
+ }
410
+
411
+ /* ============================================
412
+ Status Colors - Dark Theme
413
+ ============================================ */
414
+ .status-pending {
415
+ color: var(--warning-color);
416
+ background-color: rgba(245, 158, 11, 0.15);
417
+ padding: 0.25rem 0.75rem;
418
+ border-radius: var(--radius-full);
419
+ font-size: 0.75rem;
420
+ font-weight: 600;
421
+ }
422
+
423
+ .status-processing {
424
+ color: var(--info-color);
425
+ background-color: rgba(6, 182, 212, 0.15);
426
+ padding: 0.25rem 0.75rem;
427
+ border-radius: var(--radius-full);
428
+ font-size: 0.75rem;
429
+ font-weight: 600;
430
+ }
431
+
432
+ .status-completed {
433
+ color: var(--success-color);
434
+ background-color: rgba(16, 185, 129, 0.15);
435
+ padding: 0.25rem 0.75rem;
436
+ border-radius: var(--radius-full);
437
+ font-size: 0.75rem;
438
+ font-weight: 600;
439
+ }
440
+
441
+ .status-failed {
442
+ color: var(--danger-color);
443
+ background-color: rgba(239, 68, 68, 0.15);
444
+ padding: 0.25rem 0.75rem;
445
+ border-radius: var(--radius-full);
446
+ font-size: 0.75rem;
447
+ font-weight: 600;
448
+ }
449
+
450
+ .status-dead_letter {
451
+ color: var(--surface-400);
452
+ background-color: rgba(148, 163, 184, 0.15);
453
+ padding: 0.25rem 0.75rem;
454
+ border-radius: var(--radius-full);
455
+ font-size: 0.75rem;
456
+ font-weight: 600;
457
+ }
458
+
459
+ /* ============================================
460
+ Animations
461
+ ============================================ */
462
+ @keyframes fadeIn {
463
+ from {
464
+ opacity: 0;
465
+ transform: translateY(10px);
466
+ }
467
+ to {
468
+ opacity: 1;
469
+ transform: translateY(0);
470
+ }
471
+ }
472
+
473
+ @keyframes slideIn {
474
+ from {
475
+ opacity: 0;
476
+ transform: translateX(-10px);
477
+ }
478
+ to {
479
+ opacity: 1;
480
+ transform: translateX(0);
481
+ }
482
+ }
483
+
484
+ @keyframes pulse {
485
+ 0%, 100% {
486
+ opacity: 1;
487
+ }
488
+ 50% {
489
+ opacity: 0.5;
490
+ }
491
+ }
492
+
493
+ @keyframes spin {
494
+ from {
495
+ transform: rotate(0deg);
496
+ }
497
+ to {
498
+ transform: rotate(360deg);
499
+ }
500
+ }
501
+
502
+ @keyframes shimmer {
503
+ 0% {
504
+ background-position: -200% center;
505
+ }
506
+ 100% {
507
+ background-position: 200% center;
508
+ }
509
+ }
510
+
511
+ @keyframes glow {
512
+ 0%, 100% {
513
+ box-shadow: 0 0 5px rgba(236, 72, 153, 0.5);
514
+ }
515
+ 50% {
516
+ box-shadow: 0 0 20px rgba(236, 72, 153, 0.8);
517
+ }
518
+ }
519
+
520
+ .fade-in {
521
+ animation: fadeIn 0.3s ease;
522
+ }
523
+
524
+ .slide-in {
525
+ animation: slideIn 0.3s ease;
526
+ }
527
+
528
+ .pulse {
529
+ animation: pulse 2s ease infinite;
530
+ }
531
+
532
+ .spin {
533
+ animation: spin 1s linear infinite;
534
+ }
535
+
536
+ .glow {
537
+ animation: glow 2s ease infinite;
538
+ }
539
+
540
+ /* ============================================
541
+ Loading States
542
+ ============================================ */
543
+ .skeleton {
544
+ background: linear-gradient(
545
+ 90deg,
546
+ var(--surface-100) 25%,
547
+ var(--surface-200) 50%,
548
+ var(--surface-100) 75%
549
+ );
550
+ background-size: 200% 100%;
551
+ animation: shimmer 1.5s infinite;
552
+ border-radius: var(--radius-md);
553
+ }
554
+
555
+ /* ============================================
556
+ Utility Classes
557
+ ============================================ */
558
+ .container {
559
+ max-width: 1400px;
560
+ margin: 0 auto;
561
+ padding: 0 var(--spacing-lg);
562
+ }
563
+
564
+ .flex {
565
+ display: flex;
566
+ }
567
+
568
+ .flex-center {
569
+ display: flex;
570
+ align-items: center;
571
+ justify-content: center;
572
+ }
573
+
574
+ .flex-between {
575
+ display: flex;
576
+ align-items: center;
577
+ justify-content: space-between;
578
+ }
579
+
580
+ .grid {
581
+ display: grid;
582
+ }
583
+
584
+ .gap-sm { gap: var(--spacing-sm); }
585
+ .gap-md { gap: var(--spacing-md); }
586
+ .gap-lg { gap: var(--spacing-lg); }
587
+ .gap-xl { gap: var(--spacing-xl); }
588
+
589
+ /* ============================================
590
+ Layout Grids
591
+ ============================================ */
592
+ .dashboard-grid {
593
+ display: grid;
594
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
595
+ gap: var(--spacing-lg);
596
+ }
597
+
598
+ .analytics-grid {
599
+ display: grid;
600
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
601
+ gap: var(--spacing-lg);
602
+ }
603
+
604
+ /* ============================================
605
+ Scrollbar Styling - Dark Theme
606
+ ============================================ */
607
+ ::-webkit-scrollbar {
608
+ width: 8px;
609
+ height: 8px;
610
+ }
611
+
612
+ ::-webkit-scrollbar-track {
613
+ background: var(--surface-100);
614
+ border-radius: var(--radius-full);
615
+ }
616
+
617
+ ::-webkit-scrollbar-thumb {
618
+ background: var(--surface-200);
619
+ border-radius: var(--radius-full);
620
+ transition: background var(--transition-fast);
621
+ }
622
+
623
+ ::-webkit-scrollbar-thumb:hover {
624
+ background: var(--surface-300);
625
+ }
626
+
627
+ /* ============================================
628
+ PrimeVue Dark Theme Overrides
629
+ ============================================ */
630
+ .p-component {
631
+ font-family: inherit;
632
+ font-size: 0.875rem;
633
+ }
634
+
635
+ .p-button {
636
+ transition: all var(--transition-base);
637
+ border-radius: var(--radius-md);
638
+ font-weight: 500;
639
+ font-size: 0.875rem;
640
+ padding: 0.5rem 1rem;
641
+ }
642
+
643
+ .p-button:hover {
644
+ transform: translateY(-1px);
645
+ box-shadow: 0 4px 12px rgba(236, 72, 153, 0.3);
646
+ }
647
+
648
+ .p-button-primary {
649
+ background: var(--gradient-primary);
650
+ border: none;
651
+ }
652
+
653
+ .p-button-primary:hover {
654
+ box-shadow: 0 6px 20px rgba(236, 72, 153, 0.4);
655
+ }
656
+
657
+ .p-datatable {
658
+ background: var(--surface-50);
659
+ border-radius: 12px;
660
+ overflow: hidden;
661
+ border: 1px solid rgba(255, 255, 255, 0.05);
662
+ font-size: 0.875rem;
663
+ }
664
+
665
+ .p-datatable .p-datatable-thead > tr > th {
666
+ background: var(--surface-0);
667
+ color: var(--surface-400);
668
+ font-weight: 600;
669
+ font-size: 0.75rem;
670
+ text-transform: uppercase;
671
+ letter-spacing: 0.05em;
672
+ padding: 1rem;
673
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
674
+ }
675
+
676
+ .p-datatable .p-datatable-tbody > tr {
677
+ transition: background-color var(--transition-fast);
678
+ }
679
+
680
+ .p-datatable .p-datatable-tbody > tr:hover {
681
+ background-color: rgba(236, 72, 153, 0.05) !important;
682
+ }
683
+
684
+ .p-datatable .p-datatable-tbody > tr > td {
685
+ padding: 0.875rem 1rem;
686
+ font-size: 0.875rem;
687
+ color: var(--surface-600);
688
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
689
+ }
690
+
691
+ .p-card {
692
+ background: var(--surface-50);
693
+ box-shadow: none;
694
+ border: 1px solid rgba(255, 255, 255, 0.05);
695
+ border-radius: 12px;
696
+ }
697
+
698
+ .p-card:hover {
699
+ box-shadow: var(--shadow-glow);
700
+ border-color: rgba(236, 72, 153, 0.2);
701
+ }
702
+
703
+ .p-tag {
704
+ border-radius: var(--radius-full);
705
+ font-weight: 600;
706
+ padding: 0.25rem 0.75rem;
707
+ font-size: 0.75rem;
708
+ }
709
+
710
+ .p-badge {
711
+ border-radius: var(--radius-md);
712
+ font-weight: 600;
713
+ font-size: 0.75rem;
714
+ }
715
+
716
+ /* Chart container styling */
717
+ .chart-container {
718
+ background: transparent;
719
+ border: 1px solid rgba(255, 255, 255, 0.1);
720
+ border-radius: 16px;
721
+ padding: 1.5rem;
722
+ }
723
+
724
+ .chart-header {
725
+ display: flex;
726
+ justify-content: space-between;
727
+ align-items: center;
728
+ margin-bottom: 1.5rem;
729
+ }
730
+
731
+ .chart-title {
732
+ font-size: 1.125rem;
733
+ font-weight: 600;
734
+ color: var(--surface-700);
735
+ }
736
+
737
+ /* ============================================
738
+ Connection Status
739
+ ============================================ */
740
+ .connection-status {
741
+ display: inline-flex;
742
+ align-items: center;
743
+ gap: var(--spacing-xs);
744
+ padding: var(--spacing-xs) var(--spacing-sm);
745
+ border-radius: var(--radius-full);
746
+ font-size: 0.875rem;
747
+ font-weight: 500;
748
+ }
749
+
750
+ .connection-status.connected {
751
+ background: rgba(16, 185, 129, 0.15);
752
+ color: var(--success-color);
753
+ }
754
+
755
+ .connection-status.disconnected {
756
+ background: rgba(239, 68, 68, 0.15);
757
+ color: var(--danger-color);
758
+ }
759
+
760
+ .connection-status .indicator {
761
+ width: 8px;
762
+ height: 8px;
763
+ border-radius: 50%;
764
+ background: currentColor;
765
+ }
766
+
767
+ .connection-status.connected .indicator {
768
+ animation: pulse 2s infinite;
769
+ }
770
+
771
+ /* ============================================
772
+ Responsive Design
773
+ ============================================ */
774
+ @media (max-width: 1024px) {
775
+ .dashboard-grid {
776
+ grid-template-columns: repeat(2, 1fr);
777
+ }
778
+
779
+ .analytics-grid {
780
+ grid-template-columns: 1fr;
781
+ }
782
+ }
783
+
784
+ @media (max-width: 768px) {
785
+ html {
786
+ font-size: 13px;
787
+ }
788
+
789
+ .container {
790
+ padding: 0 0.75rem;
791
+ }
792
+
793
+ .dashboard-grid {
794
+ grid-template-columns: 1fr;
795
+ gap: 0.75rem;
796
+ }
797
+
798
+ .analytics-grid {
799
+ grid-template-columns: 1fr;
800
+ }
801
+
802
+ .card-v3,
803
+ .metric-card-v3 {
804
+ padding: 1rem;
805
+ border-radius: var(--radius-lg);
806
+ }
807
+
808
+ .hide-mobile {
809
+ display: none !important;
810
+ }
811
+ }
812
+
813
+ @media (max-width: 480px) {
814
+ html {
815
+ font-size: 12px;
816
+ }
817
+
818
+ .dashboard-grid {
819
+ gap: 0.5rem;
820
+ }
821
+
822
+ .card-v3,
823
+ .metric-card-v3 {
824
+ padding: 0.875rem;
825
+ }
826
+ }
827
+
828
+ @media (min-width: 769px) {
829
+ .hide-desktop {
830
+ display: none !important;
831
+ }
832
+ }
833
+
834
+ /* ============================================
835
+ Activity Feed Styles
836
+ ============================================ */
837
+ .activity-feed {
838
+ background: transparent;
839
+ border: 1px solid rgba(255, 255, 255, 0.1);
840
+ border-radius: 16px;
841
+ padding: 1.5rem;
842
+ max-height: 400px;
843
+ overflow-y: auto;
844
+ }
845
+
846
+ .activity-item {
847
+ display: flex;
848
+ gap: 1rem;
849
+ padding: 0.875rem;
850
+ border-radius: 8px;
851
+ margin-bottom: 0.5rem;
852
+ background: var(--surface-0);
853
+ border: 1px solid rgba(255, 255, 255, 0.03);
854
+ transition: all var(--transition-fast);
855
+ }
856
+
857
+ .activity-item:hover {
858
+ background: rgba(236, 72, 153, 0.05);
859
+ border-color: rgba(236, 72, 153, 0.1);
860
+ }
861
+
862
+ .activity-icon {
863
+ width: 36px;
864
+ height: 36px;
865
+ border-radius: 8px;
866
+ display: flex;
867
+ align-items: center;
868
+ justify-content: center;
869
+ flex-shrink: 0;
870
+ }
871
+
872
+ .activity-icon.push {
873
+ background: rgba(16, 185, 129, 0.15);
874
+ color: var(--success-color);
875
+ }
876
+
877
+ .activity-icon.pop {
878
+ background: rgba(6, 182, 212, 0.15);
879
+ color: var(--info-color);
880
+ }
881
+
882
+ .activity-icon.ack {
883
+ background: rgba(236, 72, 153, 0.15);
884
+ color: var(--primary-500);
885
+ }
886
+
887
+ .activity-content {
888
+ flex: 1;
889
+ min-width: 0;
890
+ }
891
+
892
+ .activity-title {
893
+ font-size: 0.875rem;
894
+ font-weight: 500;
895
+ color: var(--surface-600);
896
+ margin-bottom: 0.125rem;
897
+ }
898
+
899
+ .activity-description {
900
+ font-size: 0.75rem;
901
+ color: var(--surface-400);
902
+ }
903
+
904
+ .activity-time {
905
+ font-size: 0.75rem;
906
+ color: var(--surface-300);
907
+ margin-left: auto;
908
+ }