@alliance-droid/status-feedback-system 1.2.0 → 1.3.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.
@@ -92,6 +92,35 @@
92
92
  let screenshotData = $state<string | null>(null);
93
93
  let capturingScreenshot = $state(false);
94
94
 
95
+ // Drag state
96
+ let isDragging = $state(false);
97
+ let dragOffsetX = 0;
98
+ let dragOffsetY = 0;
99
+ let modalX = $state(0);
100
+ let modalY = $state(0);
101
+ let modalPositioned = $state(false);
102
+
103
+ function handleDragStart(e: MouseEvent) {
104
+ isDragging = true;
105
+ const modalEl = (e.currentTarget as HTMLElement).closest('.sf-modal') as HTMLElement;
106
+ if (!modalEl) return;
107
+ const rect = modalEl.getBoundingClientRect();
108
+ dragOffsetX = e.clientX - rect.left;
109
+ dragOffsetY = e.clientY - rect.top;
110
+ e.preventDefault();
111
+ }
112
+
113
+ function handleDragMove(e: MouseEvent) {
114
+ if (!isDragging) return;
115
+ modalX = e.clientX - dragOffsetX;
116
+ modalY = e.clientY - dragOffsetY;
117
+ modalPositioned = true;
118
+ }
119
+
120
+ function handleDragEnd() {
121
+ isDragging = false;
122
+ }
123
+
95
124
  // Console error capture
96
125
  let consoleErrors: string[] = [];
97
126
  let originalConsoleError: typeof console.error;
@@ -118,6 +147,9 @@
118
147
  document.addEventListener('click', closeMenu);
119
148
  // Escape closes everything
120
149
  document.addEventListener('keydown', handleKeydown);
150
+ // Drag listeners (on document so drag continues outside modal)
151
+ document.addEventListener('mousemove', handleDragMove);
152
+ document.addEventListener('mouseup', handleDragEnd);
121
153
 
122
154
  // Onboarding toast
123
155
  if (showOnboarding && !localStorage.getItem(ONBOARDING_KEY)) {
@@ -133,6 +165,8 @@
133
165
  document.removeEventListener('contextmenu', handleContextMenu);
134
166
  document.removeEventListener('click', closeMenu);
135
167
  document.removeEventListener('keydown', handleKeydown);
168
+ document.removeEventListener('mousemove', handleDragMove);
169
+ document.removeEventListener('mouseup', handleDragEnd);
136
170
  });
137
171
 
138
172
  function handleContextMenu(e: MouseEvent) {
@@ -218,6 +252,10 @@
218
252
  submitResult = null;
219
253
  menuOpen = false;
220
254
  formOpen = true;
255
+ // Reset drag position (center on screen)
256
+ modalPositioned = false;
257
+ modalX = 0;
258
+ modalY = 0;
221
259
 
222
260
  // Auto-capture screenshot for bugs
223
261
  if (type === 'bug') {
@@ -334,34 +372,43 @@
334
372
 
335
373
  <!-- Form modal -->
336
374
  {#if formOpen}
337
- <!-- svelte-ignore a11y_no_static_element_interactions — modal backdrop needs mousedown for click-outside-to-close -->
338
- <div class="fixed inset-0 z-[99998] flex items-center justify-center bg-black/50" onmousedown={(e) => { if (e.target === e.currentTarget) formOpen = false; }}>
339
- <!-- svelte-ignore a11y_no_static_element_interactions — prevents modal close when clicking inside form -->
340
- <div class="w-full max-w-lg mx-4" onmousedown={(e) => e.stopPropagation()}>
341
- <Card variant="elevated" padding="none">
342
- <!-- Header -->
343
- <div class="flex items-center justify-between px-5 py-4 border-b border-border">
344
- <div class="flex items-center gap-2">
345
- {#if formType === 'bug'}
346
- <i class="fa-solid fa-bug text-red-400"></i>
347
- <h3 class="text-base font-semibold">Report Bug</h3>
348
- {:else}
349
- <i class="fa-solid fa-lightbulb text-amber-400"></i>
350
- <h3 class="text-base font-semibold">Request Feature</h3>
351
- {/if}
352
- <Badge variant="neutral" size="sm">{getEnvironmentName()}</Badge>
353
- </div>
354
- <button
355
- class="text-foreground-tertiary hover:text-foreground transition-colors bg-transparent border-none cursor-pointer text-lg"
356
- onclick={() => (formOpen = false)}
357
- aria-label="Close feedback form"
358
- >
359
- <i class="fa-solid fa-xmark"></i>
360
- </button>
375
+ <!-- No backdrop — modal floats freely over the page -->
376
+ <div
377
+ class="sf-modal fixed z-[99998] w-full max-w-lg flex flex-col"
378
+ style={modalPositioned
379
+ ? `left: ${modalX}px; top: ${modalY}px;`
380
+ : 'left: 50%; top: 50%; transform: translate(-50%, -50%);'
381
+ }
382
+ >
383
+ <Card variant="elevated" padding="none" class="flex flex-col max-h-[calc(100vh-2rem)] overflow-hidden">
384
+ <!-- Header (fixed) -->
385
+ <!-- svelte-ignore a11y_no_static_element_interactions — drag handle needs mousedown -->
386
+ <div
387
+ class="flex items-center justify-between px-5 py-4 border-b border-border shrink-0 select-none"
388
+ style="cursor: {isDragging ? 'grabbing' : 'grab'};"
389
+ onmousedown={handleDragStart}
390
+ >
391
+ <div class="flex items-center gap-2">
392
+ {#if formType === 'bug'}
393
+ <i class="fa-solid fa-bug text-red-400"></i>
394
+ <h3 class="text-base font-semibold">Report Bug</h3>
395
+ {:else}
396
+ <i class="fa-solid fa-lightbulb text-amber-400"></i>
397
+ <h3 class="text-base font-semibold">Request Feature</h3>
398
+ {/if}
399
+ <Badge variant="neutral" size="sm">{getEnvironmentName()}</Badge>
361
400
  </div>
401
+ <button
402
+ class="text-foreground-tertiary hover:text-foreground transition-colors bg-transparent border-none cursor-pointer text-lg"
403
+ onclick={() => (formOpen = false)}
404
+ aria-label="Close feedback form"
405
+ >
406
+ <i class="fa-solid fa-xmark"></i>
407
+ </button>
408
+ </div>
362
409
 
363
- <!-- Body -->
364
- <div class="p-5 space-y-4">
410
+ <!-- Body (scrollable) -->
411
+ <div class="p-5 space-y-4 overflow-y-auto">
365
412
  {#if submitResult === 'success'}
366
413
  <div class="text-center py-6">
367
414
  <i class="fa-solid fa-check-circle text-3xl text-green-400"></i>
@@ -451,24 +498,27 @@
451
498
  </p>
452
499
  {/if}
453
500
 
454
- <div class="flex justify-end gap-2 pt-1">
455
- <Button variant="neutral" style="outline" onclick={() => (formOpen = false)}>
456
- Cancel
457
- </Button>
458
- <Button
459
- variant={formType === 'bug' ? 'danger' : 'primary'}
460
- disabled={submitting || !formMessage.trim()}
461
- loading={submitting}
462
- onclick={handleSubmit}
463
- >
464
- {formType === 'bug' ? 'Report Bug' : 'Submit Request'}
465
- </Button>
466
- </div>
467
- {/if}
501
+ {/if}
468
502
  </div>
503
+
504
+ <!-- Footer (fixed) -->
505
+ {#if submitResult !== 'success'}
506
+ <div class="flex justify-end gap-2 px-5 py-4 border-t border-border shrink-0">
507
+ <Button variant="neutral" style="outline" onclick={() => (formOpen = false)}>
508
+ Cancel
509
+ </Button>
510
+ <Button
511
+ variant={formType === 'bug' ? 'danger' : 'primary'}
512
+ disabled={submitting || !formMessage.trim()}
513
+ loading={submitting}
514
+ onclick={handleSubmit}
515
+ >
516
+ {formType === 'bug' ? 'Report Bug' : 'Submit Request'}
517
+ </Button>
518
+ </div>
519
+ {/if}
469
520
  </Card>
470
521
  </div>
471
- </div>
472
522
  {/if}
473
523
 
474
524
  <!-- Onboarding toast -->
@@ -560,4 +610,9 @@
560
610
  .sf-toast-close:hover {
561
611
  color: #e2e8f0;
562
612
  }
613
+
614
+ /* Floating modal shadow — no backdrop so needs strong depth cue */
615
+ .sf-modal :global(.card) {
616
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05);
617
+ }
563
618
  </style>
@@ -241,16 +241,16 @@
241
241
  <main class="flex-1 min-w-0">
242
242
  <div class="flex items-start justify-between mb-4">
243
243
  <div>
244
- <h2 class="text-xl font-bold flex items-center gap-2">
245
- {#if activeCategory}
244
+ {#if activeCategory}
245
+ <h2 class="text-xl font-bold flex items-center gap-2">
246
246
  <i class={getCategoryIcon(activeCategory)}></i>
247
247
  {getCategoryLabel(activeCategory)}
248
- {:else}
249
- {title}
248
+ </h2>
249
+ {#if getCategoryDescription(activeCategory)}
250
+ <p class="text-sm text-foreground-secondary mt-1">{getCategoryDescription(activeCategory)}</p>
250
251
  {/if}
251
- </h2>
252
- {#if activeCategory && getCategoryDescription(activeCategory)}
253
- <p class="text-sm text-foreground-secondary mt-1">{getCategoryDescription(activeCategory)}</p>
252
+ {:else if title}
253
+ <h2 class="text-xl font-bold">{title}</h2>
254
254
  {/if}
255
255
  </div>
256
256
  {#if showSubmit}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alliance-droid/status-feedback-system",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "description": "Drop-in system status pages and user feedback forms for SvelteKit apps",
6
6
  "svelte": "./dist/index.js",