@necrolab/dashboard 0.4.50 → 0.4.52

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/src/App.vue CHANGED
@@ -9,27 +9,23 @@
9
9
  :style="{
10
10
  'margin-top': maxPull() + 'px',
11
11
  transform: `rotate(${ui.pullChange}deg)`
12
- }"
13
- >
12
+ }">
14
13
  <div
15
14
  class="refresh-icon p-2 rounded-full mx-auto duration-200"
16
15
  :class="{
17
16
  'opacity-100': ui.pullChange > 250,
18
17
  'opacity-0': ui.pullChange < 250
19
- }"
20
- >
18
+ }">
21
19
  <svg
22
20
  xmlns="http://www.w3.org/2000/svg"
23
21
  fill="none"
24
22
  viewBox="0 0 24 24"
25
23
  class="stroke-2 w-4 stroke-dark-400"
26
- :class="{ 'opacity-0': ui.pullChange == 0 }"
27
- >
24
+ :class="{ 'opacity-0': ui.pullChange == 0 }">
28
25
  <path
29
26
  strokeLinecap="round"
30
27
  strokeLinejoin="round"
31
- d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
32
- />
28
+ d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
33
29
  </svg>
34
30
  </div>
35
31
  </div>
@@ -38,8 +34,7 @@
38
34
  :class="{
39
35
  'opacity-100': ui.pullChange > 250,
40
36
  'opacity-0': ui.pullChange < 250
41
- }"
42
- >
37
+ }">
43
38
  Release to refresh
44
39
  </h2>
45
40
  </div>
@@ -58,8 +53,7 @@
58
53
  :class="[
59
54
  'component-container pb-2 mt-0 lg:mt-4 ios-wrapper',
60
55
  { 'w-full': landscapeIos }
61
- ]"
62
- />
56
+ ]" />
63
57
  </transition>
64
58
  </router-view>
65
59
  </div>
@@ -94,10 +88,27 @@ function isIpadOS() {
94
88
  return navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform);
95
89
  }
96
90
 
97
- window.matchMedia("(orientation: portrait)").addEventListener("change", (e) => {
98
- if (!e.matches && isIOS() && !isIpadOS()) landscapeIos.value = true;
99
- else landscapeIos.value = false;
100
- });
91
+ // Handle orientation changes for iOS devices
92
+ const handleOrientationChange = () => {
93
+ if (isIOS()) {
94
+ if (isIpadOS()) {
95
+ // For iPad, we want to allow proper viewport resizing
96
+ landscapeIos.value = window.matchMedia("(orientation: landscape)").matches;
97
+ document.documentElement.style.setProperty("width", "100%", "important");
98
+ document.body.style.setProperty("width", "100%", "important");
99
+ } else {
100
+ // For iPhone, maintain the current behavior
101
+ landscapeIos.value = window.matchMedia("(orientation: landscape)").matches;
102
+ }
103
+ }
104
+ };
105
+
106
+ // Initial orientation check
107
+ handleOrientationChange();
108
+
109
+ // Listen for orientation changes
110
+ window.matchMedia("(orientation: portrait)").addEventListener("change", handleOrientationChange);
111
+ window.matchMedia("(orientation: landscape)").addEventListener("change", handleOrientationChange);
101
112
 
102
113
  if (!window.location.href.includes(":5173")) ui.startSpinner("Loading...");
103
114
 
@@ -109,7 +120,7 @@ onMounted(() => {
109
120
  setTimeout(handleNotch, 50);
110
121
  setTimeout(handleNotch, 150);
111
122
  setTimeout(handleNotch, 300);
112
-
123
+
113
124
  // Set up a recurring check for the first few seconds
114
125
  let attempts = 0;
115
126
  const recurringCheck = setInterval(() => {
@@ -149,64 +160,30 @@ document.addEventListener("keydown", function (event) {
149
160
  }
150
161
  });
151
162
  // Nuclear iOS keyboard prevention - lock everything down
152
- let isIOSDevice = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform));
163
+ let isIOSDevice =
164
+ /iPad|iPhone|iPod/.test(navigator.platform) ||
165
+ (navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform));
153
166
 
154
167
  if (isIOSDevice) {
155
- const originalViewportHeight = window.innerHeight;
156
- const originalScrollY = window.scrollY || 0;
157
-
158
- // Nuclear viewport lock
159
- const lockViewport = () => {
160
- document.documentElement.style.setProperty('height', `${originalViewportHeight}px`, 'important');
161
- document.documentElement.style.setProperty('width', '100vw', 'important');
162
- document.documentElement.style.setProperty('position', 'fixed', 'important');
163
- document.documentElement.style.setProperty('top', `${-originalScrollY}px`, 'important');
164
- document.documentElement.style.setProperty('left', '0px', 'important');
165
- document.documentElement.style.setProperty('overflow', 'hidden', 'important');
166
-
167
- document.body.style.setProperty('height', `${originalViewportHeight}px`, 'important');
168
- document.body.style.setProperty('width', '100vw', 'important');
169
- document.body.style.setProperty('position', 'fixed', 'important');
170
- document.body.style.setProperty('top', '0px', 'important');
171
- document.body.style.setProperty('left', '0px', 'important');
172
- document.body.style.setProperty('overflow', 'hidden', 'important');
173
-
174
- const app = document.getElementById('app');
175
- if (app) {
176
- app.style.setProperty('height', `${originalViewportHeight}px`, 'important');
177
- app.style.setProperty('width', '100vw', 'important');
178
- app.style.setProperty('overflow', 'hidden', 'important');
168
+ const handleViewportResize = () => {
169
+ if (isIpadOS()) {
170
+ // For iPad, allow natural viewport behavior
171
+ return;
179
172
  }
173
+
174
+ // For iPhone, maintain viewport stability
175
+ const vh = window.innerHeight * 0.01;
176
+ document.documentElement.style.setProperty("--vh", `${vh}px`);
180
177
  };
181
-
182
- // Lock immediately
183
- lockViewport();
184
-
185
- // Prevent ALL viewport events
186
- window.addEventListener('resize', (e) => {
187
- e.preventDefault();
188
- e.stopPropagation();
189
- lockViewport();
190
- return false;
191
- }, { passive: false, capture: true });
192
-
178
+
179
+ // Initial setup
180
+ handleViewportResize();
181
+
182
+ // Listen for viewport changes
183
+ window.addEventListener("resize", handleViewportResize);
193
184
  if (window.visualViewport) {
194
- window.visualViewport.addEventListener('resize', (e) => {
195
- e.preventDefault();
196
- e.stopPropagation();
197
- lockViewport();
198
- return false;
199
- }, { passive: false });
185
+ window.visualViewport.addEventListener("resize", handleViewportResize);
200
186
  }
201
-
202
- // Override window.innerHeight
203
- Object.defineProperty(window, 'innerHeight', {
204
- get: () => originalViewportHeight,
205
- configurable: false
206
- });
207
-
208
- // Continuous enforcement
209
- setInterval(lockViewport, 200);
210
187
  }
211
188
 
212
189
  // Precise mouse wheel control - only allow scrolling within specific scrollable elements
@@ -214,22 +191,22 @@ window.addEventListener(
214
191
  "mousewheel",
215
192
  function (event) {
216
193
  // Check if we're on a scrollable textarea
217
- const isScrollableTextarea = event.target.tagName === 'TEXTAREA' &&
218
- (event.target.classList.contains('code-editor') ||
219
- event.target.classList.contains('proxy-editor'));
220
-
194
+ const isScrollableTextarea =
195
+ event.target.tagName === "TEXTAREA" &&
196
+ (event.target.classList.contains("code-editor") || event.target.classList.contains("proxy-editor"));
197
+
221
198
  // Check if we're in a table but only allow scrolling on actual scrollable content
222
- const isInTable = event.target.closest('.table-component');
223
- const isScrollableTableContent = isInTable && (
224
- event.target.closest('.grid') || // Table rows
225
- event.target.closest('.table-row') ||
226
- (event.target.closest('.table-component') && !event.target.closest('.table-header'))
227
- );
228
-
199
+ const isInTable = event.target.closest(".table-component");
200
+ const isScrollableTableContent =
201
+ isInTable &&
202
+ (event.target.closest(".grid") || // Table rows
203
+ event.target.closest(".table-row") ||
204
+ (event.target.closest(".table-component") && !event.target.closest(".table-header")));
205
+
229
206
  // Allow scrolling in navbar and modals
230
- const isInNavbar = event.target.closest('.navbar') || event.target.closest('.mobile-menu');
207
+ const isInNavbar = event.target.closest(".navbar") || event.target.closest(".mobile-menu");
231
208
  const isInModal = event.target.closest('[role="dialog"]');
232
-
209
+
233
210
  // Only allow these specific cases
234
211
  if (isScrollableTextarea || isScrollableTableContent || isInNavbar || isInModal) {
235
212
  // Stop propagation to prevent page scroll
@@ -238,7 +215,7 @@ window.addEventListener(
238
215
  }
239
216
  return;
240
217
  }
241
-
218
+
242
219
  event.preventDefault();
243
220
  },
244
221
  { passive: false }
@@ -248,27 +225,27 @@ window.addEventListener(
248
225
  "DOMMouseScroll",
249
226
  function (event) {
250
227
  // Use same logic as mousewheel
251
- const isScrollableTextarea = event.target.tagName === 'TEXTAREA' &&
252
- (event.target.classList.contains('code-editor') ||
253
- event.target.classList.contains('proxy-editor'));
254
-
255
- const isInTable = event.target.closest('.table-component');
256
- const isScrollableTableContent = isInTable && (
257
- event.target.closest('.grid') ||
258
- event.target.closest('.table-row') ||
259
- (event.target.closest('.table-component') && !event.target.closest('.table-header'))
260
- );
261
-
262
- const isInNavbar = event.target.closest('.navbar') || event.target.closest('.mobile-menu');
228
+ const isScrollableTextarea =
229
+ event.target.tagName === "TEXTAREA" &&
230
+ (event.target.classList.contains("code-editor") || event.target.classList.contains("proxy-editor"));
231
+
232
+ const isInTable = event.target.closest(".table-component");
233
+ const isScrollableTableContent =
234
+ isInTable &&
235
+ (event.target.closest(".grid") ||
236
+ event.target.closest(".table-row") ||
237
+ (event.target.closest(".table-component") && !event.target.closest(".table-header")));
238
+
239
+ const isInNavbar = event.target.closest(".navbar") || event.target.closest(".mobile-menu");
263
240
  const isInModal = event.target.closest('[role="dialog"]');
264
-
241
+
265
242
  if (isScrollableTextarea || isScrollableTableContent || isInNavbar || isInModal) {
266
243
  if (isScrollableTableContent || isScrollableTextarea) {
267
244
  event.stopPropagation();
268
245
  }
269
246
  return;
270
247
  }
271
-
248
+
272
249
  event.preventDefault();
273
250
  },
274
251
  { passive: false }
@@ -278,27 +255,27 @@ window.addEventListener(
278
255
  "wheel",
279
256
  function (event) {
280
257
  // Use same logic as mousewheel
281
- const isScrollableTextarea = event.target.tagName === 'TEXTAREA' &&
282
- (event.target.classList.contains('code-editor') ||
283
- event.target.classList.contains('proxy-editor'));
284
-
285
- const isInTable = event.target.closest('.table-component');
286
- const isScrollableTableContent = isInTable && (
287
- event.target.closest('.grid') ||
288
- event.target.closest('.table-row') ||
289
- (event.target.closest('.table-component') && !event.target.closest('.table-header'))
290
- );
291
-
292
- const isInNavbar = event.target.closest('.navbar') || event.target.closest('.mobile-menu');
258
+ const isScrollableTextarea =
259
+ event.target.tagName === "TEXTAREA" &&
260
+ (event.target.classList.contains("code-editor") || event.target.classList.contains("proxy-editor"));
261
+
262
+ const isInTable = event.target.closest(".table-component");
263
+ const isScrollableTableContent =
264
+ isInTable &&
265
+ (event.target.closest(".grid") ||
266
+ event.target.closest(".table-row") ||
267
+ (event.target.closest(".table-component") && !event.target.closest(".table-header")));
268
+
269
+ const isInNavbar = event.target.closest(".navbar") || event.target.closest(".mobile-menu");
293
270
  const isInModal = event.target.closest('[role="dialog"]');
294
-
271
+
295
272
  if (isScrollableTextarea || isScrollableTableContent || isInNavbar || isInModal) {
296
273
  if (isScrollableTableContent || isScrollableTextarea) {
297
274
  event.stopPropagation();
298
275
  }
299
276
  return;
300
277
  }
301
-
278
+
302
279
  event.preventDefault();
303
280
  },
304
281
  { passive: false }
@@ -317,22 +294,22 @@ window.addEventListener(
317
294
  "touchmove",
318
295
  function (event) {
319
296
  // Check if we're touching a scrollable element directly
320
- const isScrollableTextarea = event.target.tagName === 'TEXTAREA' &&
321
- (event.target.classList.contains('code-editor') ||
322
- event.target.classList.contains('proxy-editor'));
323
-
297
+ const isScrollableTextarea =
298
+ event.target.tagName === "TEXTAREA" &&
299
+ (event.target.classList.contains("code-editor") || event.target.classList.contains("proxy-editor"));
300
+
324
301
  // Check if we're in a table but only allow scrolling on actual scrollable content
325
- const isInTable = event.target.closest('.table-component');
326
- const isScrollableTableContent = isInTable && (
327
- event.target.closest('.grid') || // Table rows
328
- event.target.closest('.table-row') ||
329
- (event.target.closest('.table-component') && !event.target.closest('.table-header'))
330
- );
331
-
302
+ const isInTable = event.target.closest(".table-component");
303
+ const isScrollableTableContent =
304
+ isInTable &&
305
+ (event.target.closest(".grid") || // Table rows
306
+ event.target.closest(".table-row") ||
307
+ (event.target.closest(".table-component") && !event.target.closest(".table-header")));
308
+
332
309
  // Allow scrolling in navbar and modals (they handle their own boundaries)
333
- const isInNavbar = event.target.closest('.navbar') || event.target.closest('.mobile-menu');
310
+ const isInNavbar = event.target.closest(".navbar") || event.target.closest(".mobile-menu");
334
311
  const isInModal = event.target.closest('[role="dialog"]');
335
-
312
+
336
313
  // Only allow these specific cases
337
314
  if (isScrollableTextarea || isScrollableTableContent || isInNavbar || isInModal) {
338
315
  // For table content, ensure we stop propagation to prevent page scroll
@@ -341,7 +318,7 @@ window.addEventListener(
341
318
  }
342
319
  return;
343
320
  }
344
-
321
+
345
322
  // Prevent everything else
346
323
  event.preventDefault();
347
324
  },
@@ -358,22 +335,22 @@ let pendingUpdate = false;
358
335
  function isLandscapeMode() {
359
336
  // Check orientation first
360
337
  let orientationLandscape = false;
361
-
362
- if (typeof window.orientation !== 'undefined') {
338
+
339
+ if (typeof window.orientation !== "undefined") {
363
340
  orientationLandscape = Math.abs(window.orientation) === 90;
364
- } else if (screen.orientation && typeof screen.orientation.angle !== 'undefined') {
341
+ } else if (screen.orientation && typeof screen.orientation.angle !== "undefined") {
365
342
  orientationLandscape = Math.abs(screen.orientation.angle) === 90;
366
343
  }
367
-
344
+
368
345
  // Always also check dimensions as backup
369
346
  const dimensionLandscape = window.innerWidth > window.innerHeight;
370
- const hasStrongLandscapeRatio = (window.innerWidth / window.innerHeight) > 1.5;
371
-
347
+ const hasStrongLandscapeRatio = window.innerWidth / window.innerHeight > 1.5;
348
+
372
349
  // For iPhones, if dimensions clearly indicate landscape, trust that
373
350
  if (isIOS() && !isIpadOS() && dimensionLandscape && hasStrongLandscapeRatio) {
374
351
  return true;
375
352
  }
376
-
353
+
377
354
  // Otherwise use orientation if available, fallback to dimensions
378
355
  return orientationLandscape || (dimensionLandscape && hasStrongLandscapeRatio);
379
356
  }
@@ -381,46 +358,48 @@ function isLandscapeMode() {
381
358
  function hasDeviceNotch() {
382
359
  // Only check for notch on actual devices that might have one
383
360
  if (!isIOS() || isIpadOS()) return false;
384
-
385
- return CSS.supports("padding-left: env(safe-area-inset-left)") &&
386
- CSS.supports("padding-right: env(safe-area-inset-right)");
361
+
362
+ return (
363
+ CSS.supports("padding-left: env(safe-area-inset-left)") &&
364
+ CSS.supports("padding-right: env(safe-area-inset-right)")
365
+ );
387
366
  }
388
367
 
389
368
  function handleNotch(force = false) {
390
369
  // Simple debouncing
391
370
  if (isNotchBusy && !force) return;
392
-
371
+
393
372
  try {
394
373
  // Only for iPhone (not iPad)
395
374
  if (!isIOS() || isIpadOS()) return;
396
-
375
+
397
376
  const wrappers = document.querySelectorAll(".ios-wrapper");
398
377
  if (wrappers.length === 0) {
399
378
  setTimeout(() => handleNotch(force), 100);
400
379
  return;
401
380
  }
402
-
381
+
403
382
  const isLandscape = isLandscapeMode();
404
383
  const hasNotch = hasDeviceNotch();
405
-
384
+
406
385
  // Get orientation
407
386
  let orientation = window.orientation;
408
- if (typeof orientation === 'undefined' && screen.orientation) {
387
+ if (typeof orientation === "undefined" && screen.orientation) {
409
388
  orientation = screen.orientation.angle;
410
389
  }
411
-
390
+
412
391
  // Create state signature to prevent redundant updates
413
392
  const currentState = `${isLandscape}-${hasNotch}-${orientation}-${window.innerWidth}x${window.innerHeight}`;
414
393
  if (lastNotchState === currentState && !force) {
415
394
  return;
416
395
  }
417
396
  lastNotchState = currentState;
418
-
397
+
419
398
  isNotchBusy = true;
420
-
399
+
421
400
  // Debug info
422
- if (window.location.href.includes('localhost') || window.location.href.includes('5173')) {
423
- console.log('🔥 Notch Debug:', {
401
+ if (window.location.href.includes("localhost") || window.location.href.includes("5173")) {
402
+ console.log("🔥 Notch Debug:", {
424
403
  isLandscape,
425
404
  hasNotch,
426
405
  orientation,
@@ -428,34 +407,34 @@ function handleNotch(force = false) {
428
407
  state: currentState
429
408
  });
430
409
  }
431
-
410
+
432
411
  if (hasNotch && isLandscape) {
433
412
  // Test actual safe area values to determine notch side
434
- const testDiv = document.createElement('div');
435
- testDiv.style.position = 'fixed';
436
- testDiv.style.top = '0';
437
- testDiv.style.left = '0';
438
- testDiv.style.visibility = 'hidden';
439
- testDiv.style.paddingLeft = 'env(safe-area-inset-left)';
440
- testDiv.style.paddingRight = 'env(safe-area-inset-right)';
413
+ const testDiv = document.createElement("div");
414
+ testDiv.style.position = "fixed";
415
+ testDiv.style.top = "0";
416
+ testDiv.style.left = "0";
417
+ testDiv.style.visibility = "hidden";
418
+ testDiv.style.paddingLeft = "env(safe-area-inset-left)";
419
+ testDiv.style.paddingRight = "env(safe-area-inset-right)";
441
420
  document.body.appendChild(testDiv);
442
-
421
+
443
422
  const computedStyle = getComputedStyle(testDiv);
444
423
  const leftInset = parseFloat(computedStyle.paddingLeft) || 0;
445
424
  const rightInset = parseFloat(computedStyle.paddingRight) || 0;
446
-
425
+
447
426
  document.body.removeChild(testDiv);
448
-
449
- console.log('🔍 Safe area insets:', { leftInset, rightInset });
450
-
427
+
428
+ console.log("🔍 Safe area insets:", { leftInset, rightInset });
429
+
451
430
  // Apply styles instantly - NO ANIMATION
452
- wrappers.forEach(wrapper => {
431
+ wrappers.forEach((wrapper) => {
453
432
  if (leftInset > 0) {
454
433
  // Notch on left
455
434
  wrapper.style.paddingLeft = "env(safe-area-inset-left)";
456
435
  wrapper.style.paddingRight = "0.5rem";
457
436
  } else if (rightInset > 0) {
458
- // Notch on right
437
+ // Notch on right
459
438
  wrapper.style.paddingLeft = "0.5rem";
460
439
  wrapper.style.paddingRight = "env(safe-area-inset-right)";
461
440
  } else {
@@ -466,21 +445,25 @@ function handleNotch(force = false) {
466
445
  });
467
446
  } else {
468
447
  // Portrait or no notch
469
- const padding = window.innerWidth > 1280 ? "2.5rem" :
470
- window.innerWidth > 1030 ? "1.5rem" :
471
- window.innerWidth > 768 ? "0.5rem" : "0.5rem";
472
-
448
+ const padding =
449
+ window.innerWidth > 1280
450
+ ? "2.5rem"
451
+ : window.innerWidth > 1030
452
+ ? "1.5rem"
453
+ : window.innerWidth > 768
454
+ ? "0.5rem"
455
+ : "0.5rem";
456
+
473
457
  // Apply styles instantly - NO ANIMATION
474
- wrappers.forEach(wrapper => {
458
+ wrappers.forEach((wrapper) => {
475
459
  wrapper.style.paddingLeft = padding;
476
460
  wrapper.style.paddingRight = padding;
477
461
  });
478
462
  }
479
-
463
+
480
464
  isNotchBusy = false;
481
-
482
465
  } catch (error) {
483
- console.warn('Notch error:', error);
466
+ console.warn("Notch error:", error);
484
467
  isNotchBusy = false;
485
468
  }
486
469
  }
@@ -491,10 +474,10 @@ function triggerNotch() {
491
474
  }
492
475
 
493
476
  // Event listeners
494
- window.addEventListener('orientationchange', triggerNotch);
495
- window.addEventListener('resize', triggerNotch);
477
+ window.addEventListener("orientationchange", triggerNotch);
478
+ window.addEventListener("resize", triggerNotch);
496
479
  if (screen.orientation) {
497
- screen.orientation.addEventListener('change', triggerNotch);
480
+ screen.orientation.addEventListener("change", triggerNotch);
498
481
  }
499
482
 
500
483
  // Aggressive initial setup to handle all scenarios
@@ -509,43 +492,42 @@ function initNotchHandling() {
509
492
  }
510
493
 
511
494
  // Multiple initialization points
512
- if (document.readyState === 'loading') {
513
- document.addEventListener('DOMContentLoaded', initNotchHandling);
495
+ if (document.readyState === "loading") {
496
+ document.addEventListener("DOMContentLoaded", initNotchHandling);
514
497
  } else {
515
498
  initNotchHandling();
516
499
  }
517
500
 
518
- window.addEventListener('load', initNotchHandling);
501
+ window.addEventListener("load", initNotchHandling);
519
502
 
520
503
  // Also run when page becomes visible (handles app switching)
521
- document.addEventListener('visibilitychange', () => {
504
+ document.addEventListener("visibilitychange", () => {
522
505
  if (!document.hidden) {
523
506
  setTimeout(handleNotch, 100);
524
507
  }
525
508
  });
526
509
 
527
510
  // Run on focus (when returning to app)
528
- window.addEventListener('focus', () => {
511
+ window.addEventListener("focus", () => {
529
512
  setTimeout(handleNotch, 100);
530
513
  });
531
514
 
532
515
  // Watch for ios-wrapper elements appearing in DOM
533
516
  const observer = new MutationObserver((mutations) => {
534
517
  let shouldTrigger = false;
535
-
518
+
536
519
  mutations.forEach((mutation) => {
537
- if (mutation.type === 'childList') {
520
+ if (mutation.type === "childList") {
538
521
  mutation.addedNodes.forEach((node) => {
539
522
  if (node.nodeType === Node.ELEMENT_NODE) {
540
- if (node.classList?.contains('ios-wrapper') ||
541
- node.querySelector?.('.ios-wrapper')) {
523
+ if (node.classList?.contains("ios-wrapper") || node.querySelector?.(".ios-wrapper")) {
542
524
  shouldTrigger = true;
543
525
  }
544
526
  }
545
527
  });
546
528
  }
547
529
  });
548
-
530
+
549
531
  if (shouldTrigger) {
550
532
  setTimeout(() => handleNotch(true), 10);
551
533
  setTimeout(() => handleNotch(true), 100);
@@ -554,15 +536,15 @@ const observer = new MutationObserver((mutations) => {
554
536
 
555
537
  // Start observing
556
538
  if (document.body) {
557
- observer.observe(document.body, {
558
- childList: true,
559
- subtree: true
539
+ observer.observe(document.body, {
540
+ childList: true,
541
+ subtree: true
560
542
  });
561
543
  } else {
562
- document.addEventListener('DOMContentLoaded', () => {
563
- observer.observe(document.body, {
564
- childList: true,
565
- subtree: true
544
+ document.addEventListener("DOMContentLoaded", () => {
545
+ observer.observe(document.body, {
546
+ childList: true,
547
+ subtree: true
566
548
  });
567
549
  });
568
550
  }
@@ -571,17 +553,17 @@ if (document.body) {
571
553
  const originalPushState = history.pushState;
572
554
  const originalReplaceState = history.replaceState;
573
555
 
574
- history.pushState = function(...args) {
556
+ history.pushState = function (...args) {
575
557
  originalPushState.apply(this, args);
576
558
  triggerNotch();
577
559
  };
578
560
 
579
- history.replaceState = function(...args) {
561
+ history.replaceState = function (...args) {
580
562
  originalReplaceState.apply(this, args);
581
563
  triggerNotch();
582
564
  };
583
565
 
584
- window.addEventListener('popstate', triggerNotch);
566
+ window.addEventListener("popstate", triggerNotch);
585
567
 
586
568
  // Expose for manual triggering
587
569
  window.simulateRotate = handleNotch;
@@ -645,7 +627,7 @@ watch(
645
627
  // Immediate triggers
646
628
  handleNotch();
647
629
  triggerNotch();
648
-
630
+
649
631
  // Staggered attempts
650
632
  setTimeout(handleNotch, 10);
651
633
  setTimeout(handleNotch, 50);
@@ -658,10 +640,10 @@ watch(
658
640
  watch(
659
641
  () => router.currentRoute.value.path,
660
642
  () => {
661
- // Immediate triggers
643
+ // Immediate triggers
662
644
  handleNotch();
663
645
  triggerNotch();
664
-
646
+
665
647
  // Staggered attempts
666
648
  setTimeout(handleNotch, 25);
667
649
  setTimeout(handleNotch, 100);
@@ -672,7 +654,8 @@ const layout = computed(() => router.currentRoute.value.meta.layout);
672
654
  </script>
673
655
  <style lang="scss">
674
656
  // Ultra bulletproof scroll prevention
675
- html, body {
657
+ html,
658
+ body {
676
659
  overflow: hidden !important;
677
660
  overscroll-behavior: none !important;
678
661
  width: 100% !important;