@necrolab/dashboard 0.5.16 → 0.5.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.
Files changed (66) hide show
  1. package/package.json +1 -1
  2. package/src/App.vue +14 -480
  3. package/src/assets/css/components/buttons.scss +12 -68
  4. package/src/assets/css/components/headers.scss +1 -1
  5. package/src/assets/css/components/utilities.scss +91 -16
  6. package/src/assets/css/main.scss +22 -95
  7. package/src/components/Auth/LoginForm.vue +2 -2
  8. package/src/components/Console/ConsoleToolbar.vue +123 -0
  9. package/src/components/Editors/Account/Account.vue +4 -2
  10. package/src/components/Editors/Account/AccountView.vue +12 -37
  11. package/src/components/Editors/Account/CreateAccount.vue +3 -11
  12. package/src/components/Editors/AdminFileEditor.vue +421 -0
  13. package/src/components/Editors/Profile/CreateProfile.vue +4 -20
  14. package/src/components/Editors/Profile/Profile.vue +5 -4
  15. package/src/components/Editors/Profile/ProfileView.vue +13 -38
  16. package/src/components/Editors/ProxyFileEditor.vue +178 -0
  17. package/src/components/Filter/Filter.vue +6 -6
  18. package/src/components/Filter/FilterPreview.vue +4 -12
  19. package/src/components/Filter/PriceSortToggle.vue +1 -1
  20. package/src/components/Tasks/QuickSettings.vue +5 -5
  21. package/src/components/Tasks/Stats.vue +1 -1
  22. package/src/components/Tasks/Task.vue +5 -8
  23. package/src/components/Tasks/TaskView.vue +2 -1
  24. package/src/components/Tasks/ViewTask.vue +2 -2
  25. package/src/components/icons/index.js +0 -4
  26. package/src/components/ui/ActionButtonGroup.vue +2 -2
  27. package/src/components/ui/BalanceIndicator.vue +3 -3
  28. package/src/components/ui/EnableDisableToggle.vue +2 -2
  29. package/src/components/ui/FormField.vue +2 -2
  30. package/src/components/ui/IconLabel.vue +2 -2
  31. package/src/components/ui/InfoRow.vue +4 -4
  32. package/src/components/ui/Modal.vue +83 -9
  33. package/src/components/ui/Navbar.vue +3 -3
  34. package/src/components/ui/ReadonlyFieldsSection.vue +1 -1
  35. package/src/components/ui/StatusBadge.vue +1 -1
  36. package/src/components/ui/controls/CountryChooser.vue +5 -5
  37. package/src/components/ui/controls/atomic/MultiDropdown.vue +1 -1
  38. package/src/composables/useCodeEditor.js +117 -0
  39. package/src/composables/useDropdownPosition.js +0 -2
  40. package/src/composables/useEnableDisable.js +6 -0
  41. package/src/composables/useFilterCSS.js +71 -0
  42. package/src/composables/useFormValidation.js +92 -0
  43. package/src/composables/useGetAllTags.js +9 -0
  44. package/src/composables/useIOSViewportHandling.js +76 -0
  45. package/src/composables/useNotchHandling.js +306 -0
  46. package/src/composables/useTableRender.js +23 -0
  47. package/src/composables/useZoomPrevention.js +96 -0
  48. package/src/constants/tableLayout.js +14 -0
  49. package/src/libs/utils/array.js +1 -3
  50. package/src/libs/utils/dataGeneration.js +1 -1
  51. package/src/libs/utils/string.js +1 -26
  52. package/src/libs/utils/validation.js +2 -26
  53. package/src/stores/connection.js +0 -25
  54. package/src/stores/ui.js +21 -35
  55. package/src/utils/tableHelpers.js +1 -0
  56. package/src/views/Accounts.vue +9 -17
  57. package/src/views/Console.vue +15 -92
  58. package/src/views/Editor.vue +39 -938
  59. package/src/views/FilterBuilder.vue +9 -97
  60. package/src/views/Profiles.vue +9 -17
  61. package/src/views/Tasks.vue +4 -4
  62. package/src/assets/img/background.svg.backup +0 -11
  63. package/src/components/icons/SquareCheck.vue +0 -12
  64. package/src/components/icons/SquareUncheck.vue +0 -12
  65. package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
  66. /package/src/components/Editors/Account/{AccountCreator.vue → CreateAccountBatch.vue} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@necrolab/dashboard",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "rm -rf dist && vite build && npx workbox-cli generateSW workbox-config.cjs",
package/src/App.vue CHANGED
@@ -36,101 +36,31 @@
36
36
 
37
37
  <script setup>
38
38
  import { storeToRefs } from "pinia";
39
- import { ref, computed, watch, onMounted } from "vue";
39
+ import { ref, computed } from "vue";
40
40
  import { useRouter } from "vue-router";
41
41
  import Navbar from "@/components/ui/Navbar.vue";
42
42
  import { useUIStore } from "@/stores/ui";
43
43
  import Splash from "@/components/ui/Splash.vue";
44
44
  import ReconnectIndicator from "@/components/ui/ReconnectIndicator.vue";
45
- import { DEBUG } from "@/utils/debug";
46
- import { useDeviceDetection } from "@/composables/useDeviceDetection";
45
+ import { useZoomPrevention } from "@/composables/useZoomPrevention";
46
+ import { useIOSViewportHandling } from "@/composables/useIOSViewportHandling";
47
+ import { useNotchHandling } from "@/composables/useNotchHandling";
47
48
 
48
49
  const ui = useUIStore();
49
50
  const { showSpinner: spinner } = storeToRefs(ui);
50
51
  const router = useRouter();
51
52
  const isLoading = ref(false);
52
- const showLandscapeLock = ref(false);
53
53
 
54
- const { isIOS, isIpadOS } = useDeviceDetection();
54
+ // Initialize zoom prevention (all browsers)
55
+ const { KEY_CODES } = useZoomPrevention();
55
56
 
56
- // Prevent pinch-to-zoom gestures
57
- document.addEventListener('touchstart', (e) => {
58
- if (e.touches.length > 1) {
59
- e.preventDefault();
60
- }
61
- }, { passive: false });
62
-
63
- document.addEventListener('touchmove', (e) => {
64
- if (e.touches.length > 1) {
65
- e.preventDefault();
66
- }
67
- }, { passive: false });
68
-
69
- document.addEventListener('gesturestart', (e) => {
70
- e.preventDefault();
71
- }, { passive: false });
72
-
73
- document.addEventListener('gesturechange', (e) => {
74
- e.preventDefault();
75
- }, { passive: false });
76
-
77
- document.addEventListener('gestureend', (e) => {
78
- e.preventDefault();
79
- }, { passive: false });
80
-
81
- // Prevent double-tap zoom
82
- let lastTouchEnd = 0;
83
- document.addEventListener('touchend', (e) => {
84
- const now = Date.now();
85
- if (now - lastTouchEnd <= 300) {
86
- e.preventDefault();
87
- }
88
- lastTouchEnd = now;
89
- }, { passive: false });
90
-
91
- if (!window.location.href.includes(":5173")) ui.startSpinner("Loading...");
92
-
93
- // Handle iPhone landscape lock
94
- function updateLandscapeLock() {
95
- if (isIOS() && !isIpadOS()) {
96
- showLandscapeLock.value = isLandscapeMode();
97
- }
98
- }
57
+ // Initialize iOS viewport handling
58
+ useIOSViewportHandling();
99
59
 
100
- // Update on orientation/resize
101
- window.addEventListener("orientationchange", updateLandscapeLock);
102
- window.addEventListener("resize", updateLandscapeLock);
103
- updateLandscapeLock();
104
-
105
- // Ensure notch handling runs when Vue app mounts
106
- onMounted(() => {
107
- // Optimized: Single debounced handler instead of multiple setTimeouts
108
- let attempts = 0;
109
- const maxAttempts = 5;
110
- const delays = [0, 50, 150, 300, 500];
111
-
112
- const scheduleNextAttempt = (index) => {
113
- if (index >= maxAttempts) return;
114
- setTimeout(() => {
115
- handleNotch();
116
- scheduleNextAttempt(index + 1);
117
- }, delays[index]);
118
- };
119
-
120
- scheduleNextAttempt(0);
121
- });
122
-
123
- // Keyboard key codes
124
- const KEY_CODES = {
125
- ESCAPE: 27,
126
- EQUAL: 61,
127
- NUMPAD_PLUS: 107,
128
- FIREFOX_MINUS: 173,
129
- NUMPAD_MINUS: 109,
130
- CHROME_EQUAL: 187,
131
- MINUS: 189
132
- };
60
+ // Initialize notch handling (iPhone-specific)
61
+ const { showLandscapeLock } = useNotchHandling(ui.logger);
133
62
 
63
+ // ESC key handling for modals
134
64
  document.onkeydown = function (evt) {
135
65
  evt = evt || window.event;
136
66
  let isEscape = false;
@@ -144,408 +74,12 @@ document.onkeydown = function (evt) {
144
74
  }
145
75
  };
146
76
 
147
- // Prevent ALL keyboard zoom combinations
148
- document.addEventListener("keydown", function (event) {
149
- // Prevent Ctrl/Cmd + Plus/Minus/0 (various keycodes for different browsers)
150
- if (
151
- (event.ctrlKey || event.metaKey) &&
152
- (event.which === KEY_CODES.EQUAL ||
153
- event.which === KEY_CODES.NUMPAD_PLUS ||
154
- event.which === KEY_CODES.FIREFOX_MINUS ||
155
- event.which === KEY_CODES.NUMPAD_MINUS ||
156
- event.which === KEY_CODES.CHROME_EQUAL ||
157
- event.which === KEY_CODES.MINUS ||
158
- event.keyCode === KEY_CODES.EQUAL ||
159
- event.keyCode === KEY_CODES.NUMPAD_PLUS ||
160
- event.keyCode === KEY_CODES.FIREFOX_MINUS ||
161
- event.keyCode === KEY_CODES.NUMPAD_MINUS ||
162
- event.keyCode === KEY_CODES.CHROME_EQUAL ||
163
- event.keyCode === KEY_CODES.MINUS ||
164
- event.key === '+' ||
165
- event.key === '-' ||
166
- event.key === '=' ||
167
- event.key === '0')
168
- ) {
169
- event.preventDefault();
170
- }
171
- }, { passive: false });
172
-
173
- // Prevent Ctrl/Cmd + Mouse wheel zoom (desktop)
174
- document.addEventListener("wheel", function (event) {
175
- if (event.ctrlKey || event.metaKey) {
176
- event.preventDefault();
177
- }
178
- }, { passive: false });
179
-
180
- // Also block mousewheel for older browsers
181
- document.addEventListener("mousewheel", function (event) {
182
- if (event.ctrlKey || event.metaKey) {
183
- event.preventDefault();
184
- }
185
- }, { passive: false });
186
-
187
- // Block DOMMouseScroll for Firefox
188
- document.addEventListener("DOMMouseScroll", function (event) {
189
- if (event.ctrlKey || event.metaKey) {
190
- event.preventDefault();
191
- }
192
- }, { passive: false });
193
- // Nuclear iOS keyboard prevention - lock everything down
194
- let isIOSDevice =
195
- /iPad|iPhone|iPod/.test(navigator.platform) ||
196
- (navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform));
197
-
198
- if (isIOSDevice) {
199
- const handleViewportResize = () => {
200
- if (isIpadOS()) {
201
- // For iPad, allow natural viewport behavior
202
- return;
203
- }
204
-
205
- // For iPhone, maintain viewport stability
206
- const vh = window.innerHeight * 0.01;
207
- document.documentElement.style.setProperty("--vh", `${vh}px`);
208
- };
209
-
210
- // Initial setup
211
- handleViewportResize();
212
-
213
- // Listen for viewport changes
214
- window.addEventListener("resize", handleViewportResize);
215
- if (window.visualViewport) {
216
- window.visualViewport.addEventListener("resize", handleViewportResize);
217
- }
218
- }
219
-
220
- // Simplified scroll control - let scrollable elements handle their own scrolling
221
- // Page scroll is already prevented by overflow: hidden on html/body
222
-
223
-
224
-
225
- // Precise scroll control - only allow scrolling within specific scrollable elements
226
- window.addEventListener(
227
- "touchmove",
228
- function (event) {
229
- // Check if we're touching a scrollable element directly
230
- const isScrollableTextarea =
231
- event.target.tagName === "TEXTAREA" &&
232
- (event.target.classList.contains("code-editor") || event.target.classList.contains("proxy-editor"));
233
-
234
- // Check if we're in a scrollable container
235
- const isInScrollableContainer =
236
- event.target.closest(".stop-pan") ||
237
- event.target.closest(".overflow-y-auto") ||
238
- event.target.closest(".vue-recycle-scroller") ||
239
- event.target.closest(".scroller") ||
240
- event.target.closest(".scrollable");
241
-
242
- // Check if we're in a table but only allow scrolling on actual scrollable content
243
- const isInTable = event.target.closest(".table-component");
244
- const isScrollableTableContent =
245
- isInTable &&
246
- (event.target.closest(".grid") || // Table rows
247
- event.target.closest(".table-row") ||
248
- isInScrollableContainer ||
249
- (event.target.closest(".table-component") && !event.target.closest(".table-header")));
250
-
251
- // Allow scrolling in navbar and modals (they handle their own boundaries)
252
- const isInNavbar = event.target.closest(".navbar") || event.target.closest(".mobile-menu");
253
- const isInModal = event.target.closest('[role="dialog"]');
254
-
255
- // Only allow these specific cases
256
- if (isScrollableTextarea || isScrollableTableContent || isInScrollableContainer || isInNavbar || isInModal) {
257
- // For table content, ensure we stop propagation to prevent page scroll
258
- if (isScrollableTableContent || isScrollableTextarea || isInScrollableContainer) {
259
- event.stopPropagation();
260
- }
261
- return;
262
- }
263
-
264
- // Prevent everything else
265
- event.preventDefault();
266
- },
267
- { passive: false }
268
- );
269
-
270
- let notchTimeout;
271
- let isNotchBusy = false;
272
- let lastNotchState = null;
273
-
274
- function isLandscapeMode() {
275
- // Check orientation first
276
- let orientationLandscape = false;
277
-
278
- if (typeof window.orientation !== "undefined") {
279
- orientationLandscape = Math.abs(window.orientation) === 90;
280
- } else if (screen.orientation && typeof screen.orientation.angle !== "undefined") {
281
- orientationLandscape = Math.abs(screen.orientation.angle) === 90;
282
- }
283
-
284
- // Always also check dimensions as backup
285
- const dimensionLandscape = window.innerWidth > window.innerHeight;
286
- const hasStrongLandscapeRatio = window.innerWidth / window.innerHeight > 1.5;
287
-
288
- // For iPhones, if dimensions clearly indicate landscape, trust that
289
- if (isIOS() && !isIpadOS() && dimensionLandscape && hasStrongLandscapeRatio) {
290
- return true;
291
- }
292
-
293
- // Otherwise use orientation if available, fallback to dimensions
294
- return orientationLandscape || (dimensionLandscape && hasStrongLandscapeRatio);
295
- }
296
-
297
- function hasDeviceNotch() {
298
- // Only check for notch on actual devices that might have one
299
- if (!isIOS() || isIpadOS()) return false;
300
-
301
- return (
302
- CSS.supports("padding-left: env(safe-area-inset-left)") &&
303
- CSS.supports("padding-right: env(safe-area-inset-right)")
304
- );
305
- }
306
-
307
- function handleNotch(force = false) {
308
- // Simple debouncing
309
- if (isNotchBusy && !force) return;
310
-
311
- try {
312
- // Only for iPhone (not iPad)
313
- if (!isIOS() || isIpadOS()) return;
314
-
315
- const wrappers = document.querySelectorAll(".ios-wrapper");
316
- if (wrappers.length === 0) {
317
- setTimeout(() => handleNotch(force), 100);
318
- return;
319
- }
320
-
321
- const isLandscape = isLandscapeMode();
322
- const hasNotch = hasDeviceNotch();
323
-
324
- // Get orientation
325
- let orientation = window.orientation;
326
- if (typeof orientation === "undefined" && screen.orientation) {
327
- orientation = screen.orientation.angle;
328
- }
329
-
330
- // Create state signature to prevent redundant updates
331
- const currentState = `${isLandscape}-${hasNotch}-${orientation}-${window.innerWidth}x${window.innerHeight}`;
332
- if (lastNotchState === currentState && !force) {
333
- return;
334
- }
335
- lastNotchState = currentState;
336
-
337
- isNotchBusy = true;
338
-
339
- if (DEBUG) {
340
- ui.logger.Debug("🔥 Notch Debug:", {
341
- isLandscape,
342
- hasNotch,
343
- orientation,
344
- dimensions: `${window.innerWidth}x${window.innerHeight}`,
345
- state: currentState
346
- });
347
- }
348
-
349
- if (hasNotch && isLandscape) {
350
- // Test actual safe area values to determine notch side
351
- const testDiv = document.createElement("div");
352
- testDiv.style.position = "fixed";
353
- testDiv.style.top = "0";
354
- testDiv.style.left = "0";
355
- testDiv.style.visibility = "hidden";
356
- testDiv.style.paddingLeft = "env(safe-area-inset-left)";
357
- testDiv.style.paddingRight = "env(safe-area-inset-right)";
358
- document.body.appendChild(testDiv);
359
-
360
- const computedStyle = getComputedStyle(testDiv);
361
- const leftInset = parseFloat(computedStyle.paddingLeft) || 0;
362
- const rightInset = parseFloat(computedStyle.paddingRight) || 0;
363
-
364
- document.body.removeChild(testDiv);
365
-
366
- if (DEBUG) ui.logger.Debug("🔍 Safe area insets:", { leftInset, rightInset });
367
-
368
- // Apply styles instantly - NO ANIMATION
369
- wrappers.forEach((wrapper) => {
370
- if (leftInset > 0) {
371
- // Notch on left
372
- wrapper.style.paddingLeft = "env(safe-area-inset-left)";
373
- wrapper.style.paddingRight = "0.5rem";
374
- } else if (rightInset > 0) {
375
- // Notch on right
376
- wrapper.style.paddingLeft = "0.5rem";
377
- wrapper.style.paddingRight = "env(safe-area-inset-right)";
378
- } else {
379
- // Fallback - no detectable notch
380
- wrapper.style.paddingLeft = "0.5rem";
381
- wrapper.style.paddingRight = "0.5rem";
382
- }
383
- });
384
- } else {
385
- // Portrait or no notch - Responsive padding constants
386
- const RESPONSIVE_PADDING = {
387
- XL: { minWidth: 1280, padding: "2.5rem" },
388
- LG: { minWidth: 1030, padding: "1.5rem" },
389
- MD: { minWidth: 768, padding: "0.5rem" },
390
- DEFAULT: { padding: "0.5rem" }
391
- };
392
-
393
- const padding =
394
- window.innerWidth > RESPONSIVE_PADDING.XL.minWidth
395
- ? RESPONSIVE_PADDING.XL.padding
396
- : window.innerWidth > RESPONSIVE_PADDING.LG.minWidth
397
- ? RESPONSIVE_PADDING.LG.padding
398
- : window.innerWidth > RESPONSIVE_PADDING.MD.minWidth
399
- ? RESPONSIVE_PADDING.MD.padding
400
- : RESPONSIVE_PADDING.DEFAULT.padding;
401
-
402
- // Apply styles instantly - NO ANIMATION
403
- wrappers.forEach((wrapper) => {
404
- wrapper.style.paddingLeft = padding;
405
- wrapper.style.paddingRight = padding;
406
- });
407
- }
408
-
409
- isNotchBusy = false;
410
- } catch (error) {
411
- if (DEBUG) ui.logger.Yellow("Notch error:", error);
412
- isNotchBusy = false;
413
- }
414
- }
415
-
416
- function triggerNotch() {
417
- clearTimeout(notchTimeout);
418
- notchTimeout = setTimeout(handleNotch, 50);
419
- }
420
-
421
- // Event listeners
422
- window.addEventListener("orientationchange", triggerNotch);
423
- window.addEventListener("resize", triggerNotch);
424
- if (screen.orientation) {
425
- screen.orientation.addEventListener("change", triggerNotch);
426
- }
427
-
428
- // Aggressive initial setup to handle all scenarios
429
- function initNotchHandling() {
430
- handleNotch(true); // Force first execution
431
- setTimeout(() => handleNotch(true), 50);
432
- setTimeout(() => handleNotch(true), 150);
433
- setTimeout(() => handleNotch(true), 300);
434
- setTimeout(() => handleNotch(true), 500);
435
- setTimeout(() => handleNotch(true), 1000);
436
- setTimeout(() => handleNotch(true), 2000); // Extra long delay for slow loads
437
- }
438
-
439
- // Multiple initialization points
440
- if (document.readyState === "loading") {
441
- document.addEventListener("DOMContentLoaded", initNotchHandling);
442
- } else {
443
- initNotchHandling();
444
- }
445
-
446
- window.addEventListener("load", initNotchHandling);
447
-
448
- // Also run when page becomes visible (handles app switching)
449
- document.addEventListener("visibilitychange", () => {
450
- if (!document.hidden) {
451
- setTimeout(handleNotch, 100);
452
- }
453
- });
454
-
455
- // Run on focus (when returning to app)
456
- window.addEventListener("focus", () => {
457
- setTimeout(handleNotch, 100);
458
- });
459
-
460
- // Watch for ios-wrapper elements appearing in DOM
461
- const observer = new MutationObserver((mutations) => {
462
- let shouldTrigger = false;
463
-
464
- mutations.forEach((mutation) => {
465
- if (mutation.type === "childList") {
466
- mutation.addedNodes.forEach((node) => {
467
- if (node.nodeType === Node.ELEMENT_NODE) {
468
- if (node.classList?.contains("ios-wrapper") || node.querySelector?.(".ios-wrapper")) {
469
- shouldTrigger = true;
470
- }
471
- }
472
- });
473
- }
474
- });
475
-
476
- if (shouldTrigger) {
477
- setTimeout(() => handleNotch(true), 10);
478
- setTimeout(() => handleNotch(true), 100);
479
- }
480
- });
481
-
482
- // Start observing
483
- if (document.body) {
484
- observer.observe(document.body, {
485
- childList: true,
486
- subtree: true
487
- });
488
- } else {
489
- document.addEventListener("DOMContentLoaded", () => {
490
- observer.observe(document.body, {
491
- childList: true,
492
- subtree: true
493
- });
494
- });
495
- }
496
-
497
- // Navigation handling
498
- const originalPushState = history.pushState;
499
- const originalReplaceState = history.replaceState;
500
-
501
- history.pushState = function (...args) {
502
- originalPushState.apply(this, args);
503
- triggerNotch();
504
- };
505
-
506
- history.replaceState = function (...args) {
507
- originalReplaceState.apply(this, args);
508
- triggerNotch();
509
- };
510
-
511
- window.addEventListener("popstate", triggerNotch);
512
-
513
- // Expose for manual triggering
514
- window.simulateRotate = handleNotch;
515
-
516
- // Pull-to-refresh removed per user request
517
- // Vue router integration - aggressive triggering on route changes
518
- watch(
519
- () => router.currentRoute.value.name,
520
- () => {
521
- // Immediate triggers
522
- handleNotch();
523
- triggerNotch();
524
-
525
- // Staggered attempts
526
- setTimeout(handleNotch, 10);
527
- setTimeout(handleNotch, 50);
528
- setTimeout(handleNotch, 150);
529
- setTimeout(handleNotch, 300);
530
- setTimeout(handleNotch, 500);
531
- }
532
- );
533
-
534
- watch(
535
- () => router.currentRoute.value.path,
536
- () => {
537
- // Immediate triggers
538
- handleNotch();
539
- triggerNotch();
77
+ // Start spinner unless in development
78
+ if (!window.location.href.includes(":5173")) ui.startSpinner("Loading...");
540
79
 
541
- // Staggered attempts
542
- setTimeout(handleNotch, 25);
543
- setTimeout(handleNotch, 100);
544
- setTimeout(handleNotch, 250);
545
- }
546
- );
547
80
  const layout = computed(() => router.currentRoute.value.meta.layout);
548
81
  </script>
82
+
549
83
  <style lang="scss">
550
84
  /* iPhone Landscape Lock Overlay */
551
85
  .iphone-landscape-lock {
@@ -5,10 +5,8 @@
5
5
  @use "../base/mixins" as *;
6
6
 
7
7
  .btn-primary {
8
- @apply font-medium transition-all duration-150;
9
- @apply bg-accent-green text-white;
10
- @apply px-4 py-2 rounded-md;
11
- @apply shadow-sm border-2 border-accent-green;
8
+ @apply font-medium bg-accent-green text-white px-4 py-2 rounded-md shadow-sm border-2 border-accent-green;
9
+ @include transition-standard;
12
10
 
13
11
  &:hover {
14
12
  @apply bg-green-400 border-green-400;
@@ -20,58 +18,10 @@
20
18
  }
21
19
  }
22
20
 
23
- .btn-secondary {
24
- @apply font-medium transition-all duration-150;
25
- @apply bg-transparent text-accent-green;
26
- @apply px-4 py-2 rounded-md;
27
- @apply border-2 border-accent-green;
28
-
29
- &:hover {
30
- @apply bg-accent-green text-white border-accent-green;
31
- }
32
-
33
- &:active {
34
- @apply bg-green-400 border-accent-green;
35
- @include focus-ring-accent;
36
- }
37
- }
38
-
39
- .btn-ghost {
40
- @apply font-medium transition-all duration-150;
41
- @apply bg-transparent text-light-400;
42
- @apply px-4 py-2 rounded-md;
43
- @apply border-none;
44
-
45
- &:hover {
46
- @apply bg-dark-450 text-light-300;
47
- }
48
-
49
- &:active {
50
- @apply bg-dark-350;
51
- }
52
- }
53
-
54
- .btn-danger,
55
- .btn-destructive {
56
- @apply font-medium transition-all duration-150;
57
- @apply bg-error-500 text-white;
58
- @apply px-4 py-2 rounded-md;
59
- @apply shadow-sm border-none;
60
-
61
- &:hover {
62
- @apply bg-error-400;
63
- }
64
-
65
- &:active {
66
- @apply bg-red-500;
67
- }
68
- }
69
21
 
70
22
  .btn-icon {
71
- @apply flex items-center justify-center transition-all duration-150;
72
- @apply p-1 rounded-md;
73
- @apply bg-transparent text-light-400;
74
- @apply border-none;
23
+ @apply flex items-center justify-center p-1 rounded-md bg-transparent text-light-400 border-none;
24
+ @include transition-standard;
75
25
 
76
26
  &:hover {
77
27
  @apply bg-dark-450 text-white;
@@ -83,11 +33,8 @@
83
33
  }
84
34
 
85
35
  .btn-action {
86
- @apply font-medium flex items-center justify-center gap-x-2 transition-all duration-150;
87
- @apply bg-transparent text-accent-green;
88
- @apply px-4 h-10 rounded-md;
89
- @apply border-2 border-accent-green;
90
- @apply text-xs;
36
+ @apply font-medium flex items-center justify-center gap-x-2 bg-transparent text-accent-green px-4 h-10 rounded-md border-2 border-accent-green text-xs;
37
+ @include transition-standard;
91
38
 
92
39
  &:hover {
93
40
  @apply bg-accent-green text-white border-accent-green;
@@ -100,8 +47,8 @@
100
47
  }
101
48
 
102
49
  .button-default {
103
- @apply font-medium transition-all duration-150 flex items-center justify-center gap-x-2;
104
- @apply h-14 rounded-lg text-white border-2 border-dark-550 text-sm px-6 w-48;
50
+ @apply font-medium flex items-center justify-center gap-x-2 h-14 rounded-lg text-white border-2 border-dark-550 text-sm px-6 w-48;
51
+ @include transition-standard;
105
52
 
106
53
  svg {
107
54
  @apply w-4 h-4 flex-shrink-0;
@@ -146,10 +93,8 @@
146
93
  }
147
94
 
148
95
  .login-btn {
149
- @apply flex items-center justify-center gap-2;
150
- @apply h-12 rounded-lg font-semibold tracking-wider uppercase;
151
- @apply bg-accent-green border-2 border-accent-green text-white;
152
- @apply transition-all duration-150;
96
+ @apply flex items-center justify-center gap-2 h-12 rounded-lg font-semibold tracking-wider uppercase bg-accent-green border-2 border-accent-green text-white;
97
+ @include transition-standard;
153
98
  font-size: theme('fontSize.base-');
154
99
 
155
100
  &:hover:enabled {
@@ -198,9 +143,8 @@
198
143
  ========================================================================== */
199
144
 
200
145
  .btn-modal {
201
- @apply h-10 rounded-md text-xs flex items-center justify-center;
202
- @apply font-medium px-4;
203
- @apply hover:border-dark-700 transition-all duration-150 btn-focus-ring;
146
+ @apply h-10 rounded-md text-xs flex items-center justify-center font-medium px-4 hover:border-dark-700 btn-focus-ring;
147
+ @include transition-standard;
204
148
  @include dark-button-base;
205
149
  @include scale-hover;
206
150
  }
@@ -77,7 +77,7 @@
77
77
  padding-top: 1rem;
78
78
 
79
79
  .page-header-card {
80
- gap: 2.5;
80
+ gap: 0.625rem;
81
81
  padding: 0.5rem 0.875rem;
82
82
 
83
83
  svg, img {