@necrolab/dashboard 0.5.15 → 0.5.17

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 (137) hide show
  1. package/backend/api.js +2 -3
  2. package/eslint.config.js +46 -0
  3. package/index.html +2 -1
  4. package/package.json +5 -2
  5. package/src/App.vue +70 -566
  6. package/src/assets/css/base/mixins.scss +72 -0
  7. package/src/assets/css/base/reset.scss +0 -2
  8. package/src/assets/css/base/scroll.scss +43 -36
  9. package/src/assets/css/base/typography.scss +9 -10
  10. package/src/assets/css/base/variables.scss +43 -0
  11. package/src/assets/css/components/accessibility.scss +37 -0
  12. package/src/assets/css/components/buttons.scss +61 -74
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +13 -21
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -22
  17. package/src/assets/css/components/tables.scss +5 -7
  18. package/src/assets/css/components/toasts.scss +7 -7
  19. package/src/assets/css/components/utilities.scss +295 -0
  20. package/src/assets/css/main.scss +55 -139
  21. package/src/components/Auth/LoginForm.vue +7 -86
  22. package/src/components/Console/ConsoleToolbar.vue +123 -0
  23. package/src/components/Editors/Account/Account.vue +12 -12
  24. package/src/components/Editors/Account/AccountView.vue +38 -111
  25. package/src/components/Editors/Account/CreateAccount.vue +11 -61
  26. package/src/components/Editors/Account/{AccountCreator.vue → CreateAccountBatch.vue} +28 -59
  27. package/src/components/Editors/AdminFileEditor.vue +179 -0
  28. package/src/components/Editors/Profile/CreateProfile.vue +77 -150
  29. package/src/components/Editors/Profile/Profile.vue +20 -21
  30. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  31. package/src/components/Editors/Profile/ProfileView.vue +41 -116
  32. package/src/components/Editors/ProxyFileEditor.vue +86 -0
  33. package/src/components/Editors/TagLabel.vue +16 -55
  34. package/src/components/Editors/TagToggle.vue +20 -8
  35. package/src/components/Filter/Filter.vue +66 -79
  36. package/src/components/Filter/FilterPreview.vue +153 -135
  37. package/src/components/Filter/PriceSortToggle.vue +36 -43
  38. package/src/components/Table/Header.vue +1 -1
  39. package/src/components/Table/Table.vue +45 -51
  40. package/src/components/Tasks/CheckStock.vue +7 -16
  41. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  42. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  43. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  44. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  45. package/src/components/Tasks/EventDetailRow.vue +21 -0
  46. package/src/components/Tasks/MassEdit.vue +6 -16
  47. package/src/components/Tasks/QuickSettings.vue +140 -216
  48. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  49. package/src/components/Tasks/Stats.vue +20 -39
  50. package/src/components/Tasks/Task.vue +64 -270
  51. package/src/components/Tasks/TaskLabel.vue +9 -3
  52. package/src/components/Tasks/TaskView.vue +45 -64
  53. package/src/components/Tasks/Utilities.vue +10 -44
  54. package/src/components/Tasks/ViewTask.vue +23 -107
  55. package/src/components/icons/Close.vue +2 -8
  56. package/src/components/icons/Gear.vue +8 -8
  57. package/src/components/icons/Hash.vue +5 -0
  58. package/src/components/icons/Key.vue +2 -8
  59. package/src/components/icons/Pencil.vue +2 -8
  60. package/src/components/icons/Profile.vue +2 -8
  61. package/src/components/icons/Sell.vue +2 -8
  62. package/src/components/icons/Spinner.vue +4 -7
  63. package/src/components/icons/Wildcard.vue +2 -8
  64. package/src/components/icons/index.js +3 -5
  65. package/src/components/ui/ActionButtonGroup.vue +113 -52
  66. package/src/components/ui/BalanceIndicator.vue +60 -0
  67. package/src/components/ui/EmptyState.vue +24 -0
  68. package/src/components/ui/EnableDisableToggle.vue +23 -0
  69. package/src/components/ui/FormField.vue +49 -49
  70. package/src/components/ui/IconLabel.vue +23 -0
  71. package/src/components/ui/InfoRow.vue +21 -54
  72. package/src/components/ui/Modal.vue +161 -54
  73. package/src/components/ui/Navbar.vue +63 -44
  74. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  75. package/src/components/ui/ReconnectIndicator.vue +111 -124
  76. package/src/components/ui/SectionCard.vue +6 -14
  77. package/src/components/ui/Splash.vue +2 -10
  78. package/src/components/ui/StatusBadge.vue +26 -28
  79. package/src/components/ui/TaskToggle.vue +54 -0
  80. package/src/components/ui/controls/CountryChooser.vue +29 -66
  81. package/src/components/ui/controls/EyeToggle.vue +1 -1
  82. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  83. package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
  84. package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -120
  85. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  86. package/src/composables/useCodeEditor.js +117 -0
  87. package/src/composables/useColorMapping.js +15 -0
  88. package/src/composables/useCopyToClipboard.js +1 -1
  89. package/src/composables/useDateFormatting.js +21 -0
  90. package/src/composables/useDeviceDetection.js +14 -0
  91. package/src/composables/useDropdownPosition.js +1 -4
  92. package/src/composables/useDynamicTableHeight.js +31 -0
  93. package/src/composables/useEnableDisable.js +6 -0
  94. package/src/composables/useFilterCSS.js +71 -0
  95. package/src/composables/useFormValidation.js +92 -0
  96. package/src/composables/useGetAllTags.js +9 -0
  97. package/src/composables/useIOSViewportHandling.js +76 -0
  98. package/src/composables/useNotchHandling.js +306 -0
  99. package/src/composables/useRowSelection.js +0 -3
  100. package/src/composables/useTableRender.js +23 -0
  101. package/src/composables/useTicketPricing.js +16 -0
  102. package/src/composables/useWindowDimensions.js +21 -0
  103. package/src/composables/useZoomPrevention.js +96 -0
  104. package/src/constants/tableLayout.js +14 -0
  105. package/src/libs/Filter.js +14 -20
  106. package/src/libs/panzoom.js +1 -5
  107. package/src/libs/utils/array.js +58 -0
  108. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  109. package/src/libs/utils/eventUrl.js +40 -0
  110. package/src/libs/utils/string.js +3 -0
  111. package/src/libs/utils/time.js +20 -0
  112. package/src/libs/utils/validation.js +64 -0
  113. package/src/main.js +0 -2
  114. package/src/stores/connection.js +1 -29
  115. package/src/stores/logger.js +6 -12
  116. package/src/stores/sampleData.js +1 -2
  117. package/src/stores/ui.js +80 -71
  118. package/src/utils/tableHelpers.js +1 -0
  119. package/src/views/Accounts.vue +19 -38
  120. package/src/views/Console.vue +74 -253
  121. package/src/views/Editor.vue +47 -1114
  122. package/src/views/FilterBuilder.vue +190 -461
  123. package/src/views/Login.vue +3 -28
  124. package/src/views/Profiles.vue +17 -32
  125. package/src/views/Tasks.vue +51 -38
  126. package/tailwind.config.js +82 -71
  127. package/workbox-config.cjs +47 -5
  128. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
  129. package/exit +0 -209
  130. package/run +0 -177
  131. package/src/assets/css/base/color-fallbacks.scss +0 -10
  132. package/src/assets/img/background.svg.backup +0 -11
  133. package/src/components/icons/SquareCheck.vue +0 -18
  134. package/src/components/icons/SquareUncheck.vue +0 -18
  135. package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
  136. package/switch-branch.sh +0 -41
  137. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -1,70 +1,131 @@
1
1
  <template>
2
- <ul class="mx-auto flex items-center justify-center rounded overflow-visible flex-wrap
3
- bg-dark-400 border-2 border-dark-600 p-[3px] gap-0.5
4
- md:p-0.5 md:gap-px md:rounded-md
5
- lg:p-[3px] lg:gap-0.5 lg:rounded-lg lg:flex-nowrap
6
- max-md:max-w-[44px] max-md:min-h-7 max-md:h-auto max-md:justify-start max-md:mx-0">
2
+ <ul class="action-button-group" :class="{ 'allow-wrap': allowWrap }">
7
3
  <slot />
8
4
  </ul>
9
5
  </template>
10
6
 
11
7
  <script setup>
12
- // Simple wrapper component for action button groups
8
+ defineProps({
9
+ allowWrap: {
10
+ type: Boolean,
11
+ default: false
12
+ }
13
+ });
13
14
  </script>
14
15
 
15
- <style lang="scss" scoped>
16
- ul {
17
- :deep(button) {
18
- @apply relative flex items-center justify-center rounded border-0 outline-0 transition-all duration-150;
19
- @apply bg-transparent text-light-300;
20
- @apply w-7 h-7 rounded-md;
21
-
22
- &:hover {
23
- @apply bg-accent-green/15 text-white;
24
- }
25
-
26
- &:active {
27
- @apply bg-accent-green/25;
28
- }
29
-
30
- // Tablet sizing
31
- @media (min-width: 768px) and (max-width: 1023px) {
32
- @apply w-[26px] h-[26px] rounded;
33
- }
34
-
35
- // Desktop sizing
36
- @media (min-width: 1024px) {
37
- @apply w-7 h-7 rounded-md;
38
- }
39
-
40
- // Mobile sizing
41
- @media (max-width: 640px) {
42
- @apply w-[18px] h-[18px] rounded-xs min-w-[18px] m-px;
43
- }
16
+ <style scoped>
17
+ .action-button-group {
18
+ @apply mx-auto bg-dark-400 border-2 border-dark-550 rounded;
19
+ display: flex;
20
+ flex-wrap: nowrap;
21
+ justify-content: center;
22
+ align-items: center;
23
+ padding: 3px;
24
+ gap: 2px;
25
+ width: fit-content;
26
+ }
27
+
28
+ .action-button-group.allow-wrap {
29
+ flex-wrap: wrap;
30
+ align-items: flex-start;
31
+ }
32
+
33
+ /* Desktop - no wrapping */
34
+ @media (min-width: 1024px) {
35
+ .action-button-group {
36
+ flex-wrap: nowrap;
37
+ padding: 3px;
38
+ gap: 2px;
39
+ border-radius: 0.5rem;
40
+ }
41
+ }
42
+
43
+ /* Tablet - max 3 per row */
44
+ @media (min-width: 768px) and (max-width: 1023px) {
45
+ .action-button-group {
46
+ max-width: 100px;
47
+ padding: 2px;
48
+ gap: 1px;
49
+ border-radius: 0.375rem;
50
+ }
51
+ }
52
+
53
+ /* Mobile - compact layout */
54
+ @media (max-width: 767px) {
55
+ .action-button-group {
56
+ max-width: 100%;
57
+ gap: 3px;
58
+ padding: 3px;
59
+ margin-left: 0;
60
+ margin-right: 0;
61
+ }
62
+
63
+ .action-button-group.allow-wrap {
64
+ justify-content: center;
44
65
  }
66
+ }
45
67
 
46
- :deep(svg),
47
- :deep(img) {
48
- @apply w-4 h-4 relative z-[1];
68
+ /* Button base styling */
69
+ .action-button-group :deep(button) {
70
+ @apply relative flex items-center justify-center border-0 outline-0;
71
+ @apply bg-transparent text-light-300 flex-shrink-0 rounded-md;
72
+ @apply transition-all duration-150;
73
+ width: 28px !important;
74
+ height: 28px !important;
75
+ min-width: 28px !important;
76
+ min-height: 28px !important;
77
+ }
49
78
 
50
- // Tablet sizing
51
- @media (min-width: 768px) and (max-width: 1023px) {
52
- @apply w-3.5 h-3.5;
53
- }
79
+ /* Hover effect */
80
+ .action-button-group :deep(button:hover) {
81
+ background-color: oklch(0.78 0.12 145 / 0.15) !important;
82
+ color: white !important;
83
+ transform: scale(1.03) !important;
84
+ }
54
85
 
55
- // Desktop sizing
56
- @media (min-width: 1024px) {
57
- @apply w-4 h-4;
58
- }
86
+ /* Active effect */
87
+ .action-button-group :deep(button:active) {
88
+ background-color: oklch(0.78 0.12 145 / 0.25) !important;
89
+ transform: scale(0.98) !important;
90
+ }
59
91
 
60
- // Mobile sizing
61
- @media (max-width: 640px) {
62
- @apply w-[12px] h-[12px];
63
- }
92
+ /* Icon sizing */
93
+ .action-button-group :deep(svg),
94
+ .action-button-group :deep(img) {
95
+ width: 16px !important;
96
+ height: 16px !important;
97
+ flex-shrink: 0 !important;
98
+ display: block !important;
99
+ }
100
+
101
+ /* Responsive button sizing */
102
+ @media (min-width: 768px) and (max-width: 1023px) {
103
+ .action-button-group :deep(button) {
104
+ width: 26px !important;
105
+ height: 26px !important;
64
106
  }
65
107
 
66
- :deep(li) {
67
- @apply flex m-0 p-0;
108
+ .action-button-group :deep(svg),
109
+ .action-button-group :deep(img) {
110
+ width: 14px !important;
111
+ height: 14px !important;
68
112
  }
69
113
  }
114
+
115
+ @media (max-width: 767px) {
116
+ .action-button-group :deep(button) {
117
+ width: 22px !important;
118
+ height: 22px !important;
119
+ }
120
+
121
+ .action-button-group :deep(svg),
122
+ .action-button-group :deep(img) {
123
+ width: 12px !important;
124
+ height: 12px !important;
125
+ }
126
+ }
127
+
128
+ .action-button-group li {
129
+ @apply flex m-0 p-0;
130
+ }
70
131
  </style>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <div class="balance-indicator">
3
+ <div v-if="loading" class="flex-gap-1 items-center">
4
+ <svg class="animate-spin h-3 w-3 text-light-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
5
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
6
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
7
+ </svg>
8
+ </div>
9
+ <div v-else-if="error" class="flex-gap-1 items-center" title="Failed to fetch balance">
10
+ <svg class="h-3 w-3 text-red-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
11
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
12
+ </svg>
13
+ </div>
14
+ <div v-else-if="balance !== null && balance !== undefined" class="flex-gap-1 items-center text-green-400" :title="`Balance: ${balance}`">
15
+ <img src="@/assets/img/sell.svg" width="9" class="opacity-60" />
16
+ <span class="text-2xs font-bold tabular-nums">{{ formattedBalance }}</span>
17
+ </div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup>
22
+ import { computed } from "vue";
23
+
24
+ const props = defineProps({
25
+ balance: {
26
+ type: [Number, String, null],
27
+ default: null
28
+ },
29
+ loading: {
30
+ type: Boolean,
31
+ default: false
32
+ },
33
+ error: {
34
+ type: Boolean,
35
+ default: false
36
+ }
37
+ });
38
+
39
+ const formattedBalance = computed(() => {
40
+ if (typeof props.balance === 'number') {
41
+ if (props.balance >= 1000000) {
42
+ return (props.balance / 1000000).toFixed(1) + 'M';
43
+ } else if (props.balance >= 100000) {
44
+ return (props.balance / 1000).toFixed(0) + 'K';
45
+ } else if (props.balance >= 10000) {
46
+ return (props.balance / 1000).toFixed(1) + 'K';
47
+ }
48
+ return props.balance.toLocaleString();
49
+ }
50
+ return String(props.balance);
51
+ });
52
+ </script>
53
+
54
+ <style scoped>
55
+ .balance-indicator {
56
+ @apply absolute right-3 top-1/2 -translate-y-1/2;
57
+ @apply flex items-center justify-center;
58
+ @apply pointer-events-none;
59
+ }
60
+ </style>
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <div class="flex min-h-32 flex-col items-center justify-center bg-dark-400 py-8 text-center text-sm font-medium">
3
+ <component :is="icon" class="empty-state-icon" />
4
+ <p class="text-light-400">{{ message }}</p>
5
+ <p v-if="subtitle" class="mt-1 text-xs text-light-500">{{ subtitle }}</p>
6
+ </div>
7
+ </template>
8
+
9
+ <script setup>
10
+ defineProps({
11
+ icon: {
12
+ type: Object,
13
+ required: true
14
+ },
15
+ message: {
16
+ type: String,
17
+ required: true
18
+ },
19
+ subtitle: {
20
+ type: String,
21
+ default: ''
22
+ }
23
+ });
24
+ </script>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <li v-if="enabled">
3
+ <button @click="$emit('disable')">
4
+ <img class="icon-md" src="/img/controls/disable.svg" />
5
+ </button>
6
+ </li>
7
+ <li v-else>
8
+ <button @click="$emit('enable')">
9
+ <img class="icon-md" src="/img/controls/enable.svg" />
10
+ </button>
11
+ </li>
12
+ </template>
13
+
14
+ <script setup>
15
+ defineProps({
16
+ enabled: {
17
+ type: Boolean,
18
+ required: true
19
+ }
20
+ });
21
+
22
+ defineEmits(["enable", "disable"]);
23
+ </script>
@@ -1,12 +1,13 @@
1
1
  <template>
2
- <div class="input-wrapper" :class="{ 'relative-positioned': zIndex, [`z-${zIndex}`]: zIndex }">
2
+ <div :class="[zIndex && 'relative', getZIndexClass]">
3
3
  <slot name="label">
4
- <label v-if="label" class="label-override mb-2">
4
+ <label v-if="label" class="mb-2 flex items-center gap-2 text-sm font-medium text-white">
5
5
  {{ label }}
6
- <component v-if="icon" :is="icon" />
6
+ <component v-if="icon" :is="icon" class="h-3.5 w-3.5" />
7
7
  </label>
8
8
  </slot>
9
- <div :class="`input-default ${required ? 'required' : ''} ${error ? 'error' : ''}`">
9
+ <!-- For dropdowns, don't wrap in input-default -->
10
+ <div v-if="!noWrapper" :class="['input-default', { 'required': required, 'error border-2 border-error-300': error }]">
10
11
  <slot />
11
12
  <div v-if="incrementer" class="input-incrementer">
12
13
  <button @click="$emit('increment')" type="button">
@@ -17,58 +18,57 @@
17
18
  </button>
18
19
  </div>
19
20
  </div>
21
+ <!-- Direct slot for dropdowns -->
22
+ <slot v-else />
20
23
  </div>
21
24
  </template>
22
25
 
23
26
  <script setup>
24
27
  import { UpIcon, DownIcon } from '@/components/icons';
28
+ import { computed } from 'vue';
25
29
 
26
- defineProps({
27
- label: { type: String, default: '' },
28
- icon: { type: Object, default: null },
29
- required: { type: Boolean, default: false },
30
- error: { type: Boolean, default: false },
31
- incrementer: { type: Boolean, default: false },
32
- zIndex: { type: String, default: '' }
30
+ const props = defineProps({
31
+ label: {
32
+ type: String,
33
+ default: ''
34
+ },
35
+ icon: {
36
+ type: Object,
37
+ default: null
38
+ },
39
+ required: {
40
+ type: Boolean,
41
+ default: false
42
+ },
43
+ error: {
44
+ type: Boolean,
45
+ default: false
46
+ },
47
+ incrementer: {
48
+ type: Boolean,
49
+ default: false
50
+ },
51
+ zIndex: {
52
+ type: String,
53
+ default: '',
54
+ validator: (value) => ['', '0', '1', '2', 'dropdown', 'tooltip'].includes(value)
55
+ },
56
+ noWrapper: {
57
+ type: Boolean,
58
+ default: false
59
+ }
33
60
  });
34
61
 
35
62
  defineEmits(['increment', 'decrement']);
36
- </script>
37
-
38
- <style lang="scss" scoped>
39
- .input-wrapper {
40
- label {
41
- @apply flex items-center;
42
- }
43
- }
44
-
45
- .relative-positioned {
46
- @apply relative;
47
- }
48
-
49
- .z-0 {
50
- z-index: 0;
51
- }
52
-
53
- .z-1 {
54
- z-index: 1;
55
- }
56
63
 
57
- .z-2 {
58
- z-index: 2;
59
- }
60
-
61
- .z-dropdown {
62
- z-index: 100;
63
- }
64
-
65
- .z-tooltip {
66
- z-index: 2000;
67
- }
68
-
69
- .error {
70
- @apply border-2 border-error-300;
71
- }
72
-
73
- // Incrementer styles handled by forms.scss
74
- </style>
64
+ const getZIndexClass = computed(() => {
65
+ const zIndexMap = {
66
+ '0': 'z-0',
67
+ '1': 'z-1',
68
+ '2': 'z-2',
69
+ 'dropdown': 'z-dropdown',
70
+ 'tooltip': 'z-tooltip'
71
+ };
72
+ return zIndexMap[props.zIndex] || '';
73
+ });
74
+ </script>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div class="flex-gap-2 items-center text-xs text-light-100">
3
+ <component :is="icon" :class="iconClass" />
4
+ <span>{{ label }}</span>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup>
9
+ defineProps({
10
+ icon: {
11
+ type: Object,
12
+ required: true
13
+ },
14
+ label: {
15
+ type: String,
16
+ required: true
17
+ },
18
+ iconClass: {
19
+ type: String,
20
+ default: "icon-md text-light-100"
21
+ }
22
+ });
23
+ </script>
@@ -1,21 +1,34 @@
1
1
  <template>
2
2
  <div
3
- class="info-row"
3
+ class="flex items-center gap-3 rounded-lg bg-dark-500 border border-dark-550 px-3 py-2 min-h-10"
4
4
  :class="{ 'items-start': alignStart, [customClass]: customClass }">
5
- <component v-if="icon" :is="icon" class="info-icon" :class="{ 'flex-shrink-0': alignStart }" />
6
- <span v-if="iconText" class="info-icon flex items-center justify-center text-base font-bold" :class="{ 'flex-shrink-0': alignStart }">
5
+ <component
6
+ v-if="icon"
7
+ :is="icon"
8
+ class="icon-md flex-shrink-0 text-light-300"
9
+ :class="{ 'flex-shrink-0': alignStart }" />
10
+ <span
11
+ v-if="iconText"
12
+ class="flex icon-md flex-shrink-0 items-center justify-center text-base font-bold text-light-300"
13
+ :class="{ 'flex-shrink-0': alignStart }">
7
14
  {{ iconText }}
8
15
  </span>
9
- <span class="info-label" :class="{ 'flex-shrink-0': alignStart }">{{ label }}</span>
10
- <span class="info-value" :class="valueClass">
16
+ <span
17
+ class="min-w-25 flex-shrink-0 text-xs font-medium text-light-500 md:min-w-20 md:text-xs+"
18
+ :class="{ 'flex-shrink-0': alignStart }">
19
+ {{ label }}
20
+ </span>
21
+ <span
22
+ class="min-w-0 flex-1 break-words overflow-hidden text-sm text-light-300 md:text-xs+"
23
+ :class="valueClass">
11
24
  <slot>{{ value }}</slot>
12
25
  </span>
13
26
  <button
14
27
  v-if="copyable"
15
28
  @click="handleCopy"
16
- class="copy-button"
17
- :class="{ 'copied': showCopied }">
18
- <component :is="showCopied ? CheckIcon : CopyIcon" class="w-4 h-4" />
29
+ class="ml-2 icon-button bg-transparent text-light-500 transition-standard hover:bg-dark-550 hover:text-light-300"
30
+ :class="{ 'text-accent-green': showCopied }">
31
+ <component :is="showCopied ? CheckIcon : CopyIcon" class="icon-md" />
19
32
  </button>
20
33
  <slot name="action" />
21
34
  </div>
@@ -52,49 +65,3 @@ const handleCopy = () => {
52
65
  };
53
66
  </script>
54
67
 
55
- <style lang="scss" scoped>
56
- .info-row {
57
- @apply flex items-center gap-3 px-3 py-2 rounded-lg;
58
- @apply bg-dark-500 border border-dark-600;
59
- @apply min-h-10;
60
- }
61
-
62
- .info-icon {
63
- @apply w-4 h-4 flex-shrink-0 text-light-300;
64
-
65
- svg {
66
- @apply text-light-300 w-4 h-4;
67
- }
68
- }
69
-
70
- .info-label {
71
- @apply text-xs font-medium flex-shrink-0 text-light-500;
72
- @apply min-w-[100px];
73
-
74
- @media (max-width: 768px) {
75
- @apply min-w-20 text-[11px];
76
- }
77
- }
78
-
79
- .info-value {
80
- @apply text-sm flex-1 text-light-300;
81
- @apply break-words overflow-hidden;
82
- min-width: 0; // Allow flex item to shrink below content size
83
-
84
- @media (max-width: 768px) {
85
- @apply text-[13px];
86
- }
87
- }
88
-
89
- .copy-button {
90
- @apply flex items-center justify-center;
91
- @apply w-8 h-8 rounded transition-all duration-150;
92
- @apply bg-transparent text-light-500 hover:text-light-300 hover:bg-dark-600;
93
- @apply flex-shrink-0;
94
- @apply ml-2; // Ensure spacing from value
95
-
96
- &.copied {
97
- @apply text-accent-green;
98
- }
99
- }
100
- </style>