@necrolab/dashboard 0.4.221 → 0.5.2

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 (141) hide show
  1. package/.prettierrc +27 -1
  2. package/.vscode/extensions.json +1 -1
  3. package/README.md +64 -2
  4. package/artwork/image.png +0 -0
  5. package/backend/api.js +26 -24
  6. package/backend/auth.js +2 -2
  7. package/backend/batching.js +1 -1
  8. package/backend/endpoints.js +8 -11
  9. package/backend/index.js +2 -2
  10. package/backend/mock-data.js +27 -36
  11. package/backend/mock-src/classes/logger.js +5 -7
  12. package/backend/mock-src/classes/utils.js +3 -2
  13. package/backend/mock-src/ticketmaster.js +4 -4
  14. package/backend/validator.js +2 -2
  15. package/config/configs.json +0 -1
  16. package/dev-server.js +134 -0
  17. package/exit +209 -0
  18. package/index.html +80 -8
  19. package/index.js +1 -1
  20. package/jsconfig.json +16 -0
  21. package/package.json +39 -25
  22. package/postcss.config.js +1 -1
  23. package/postinstall.js +124 -20
  24. package/public/android-chrome-192x192.png +0 -0
  25. package/public/android-chrome-512x512.png +0 -0
  26. package/public/apple-touch-icon.png +0 -0
  27. package/public/favicon-16x16.png +0 -0
  28. package/public/favicon-32x32.png +0 -0
  29. package/public/favicon.ico +0 -0
  30. package/public/img/logo_trans.png +0 -0
  31. package/public/img/necro_logo.png +0 -0
  32. package/public/manifest.json +16 -10
  33. package/public/reconnect-logo.png +0 -0
  34. package/run +176 -9
  35. package/src/App.vue +498 -85
  36. package/src/assets/css/base/reset.scss +43 -0
  37. package/src/assets/css/base/scroll.scss +114 -0
  38. package/src/assets/css/base/typography.scss +37 -0
  39. package/src/assets/css/components/buttons.scss +216 -0
  40. package/src/assets/css/components/forms.scss +221 -0
  41. package/src/assets/css/components/modals.scss +13 -0
  42. package/src/assets/css/components/tables.scss +27 -0
  43. package/src/assets/css/components/toasts.scss +100 -0
  44. package/src/assets/css/main.scss +202 -122
  45. package/src/assets/img/background.svg +2 -2
  46. package/src/assets/img/background.svg.backup +11 -0
  47. package/src/assets/img/logo_trans.png +0 -0
  48. package/src/components/Auth/LoginForm.vue +95 -11
  49. package/src/components/Editors/Account/Account.vue +116 -40
  50. package/src/components/Editors/Account/AccountCreator.vue +88 -39
  51. package/src/components/Editors/Account/AccountView.vue +102 -34
  52. package/src/components/Editors/Account/CreateAccount.vue +80 -32
  53. package/src/components/Editors/Profile/CreateProfile.vue +269 -83
  54. package/src/components/Editors/Profile/Profile.vue +132 -47
  55. package/src/components/Editors/Profile/ProfileCountryChooser.vue +82 -20
  56. package/src/components/Editors/Profile/ProfileView.vue +89 -32
  57. package/src/components/Editors/TagLabel.vue +67 -6
  58. package/src/components/Editors/TagToggle.vue +7 -2
  59. package/src/components/Filter/Filter.vue +288 -71
  60. package/src/components/Filter/FilterPreview.vue +202 -31
  61. package/src/components/Filter/PriceSortToggle.vue +76 -6
  62. package/src/components/Table/Header.vue +1 -1
  63. package/src/components/Table/Row.vue +1 -1
  64. package/src/components/Table/Table.vue +19 -2
  65. package/src/components/Tasks/CheckStock.vue +6 -8
  66. package/src/components/Tasks/Controls/DesktopControls.vue +27 -17
  67. package/src/components/Tasks/Controls/MobileControls.vue +8 -45
  68. package/src/components/Tasks/CreateTaskAXS.vue +80 -72
  69. package/src/components/Tasks/CreateTaskTM.vue +95 -141
  70. package/src/components/Tasks/MassEdit.vue +4 -6
  71. package/src/components/Tasks/QuickSettings.vue +199 -30
  72. package/src/components/Tasks/ScrapeVenue.vue +5 -6
  73. package/src/components/Tasks/Stats.vue +50 -24
  74. package/src/components/Tasks/Task.vue +384 -179
  75. package/src/components/Tasks/TaskLabel.vue +2 -2
  76. package/src/components/Tasks/TaskView.vue +136 -48
  77. package/src/components/Tasks/Utilities.vue +25 -10
  78. package/src/components/Tasks/ViewTask.vue +321 -0
  79. package/src/components/icons/Bag.vue +1 -1
  80. package/src/components/icons/Check.vue +5 -0
  81. package/src/components/icons/Close.vue +21 -0
  82. package/src/components/icons/CloseX.vue +5 -0
  83. package/src/components/icons/Eye.vue +6 -0
  84. package/src/components/icons/Key.vue +21 -0
  85. package/src/components/icons/Loyalty.vue +1 -1
  86. package/src/components/icons/Mail.vue +2 -2
  87. package/src/components/icons/Pencil.vue +21 -0
  88. package/src/components/icons/Play.vue +2 -2
  89. package/src/components/icons/Profile.vue +18 -0
  90. package/src/components/icons/Reload.vue +4 -5
  91. package/src/components/icons/Sandclock.vue +2 -2
  92. package/src/components/icons/Sell.vue +21 -0
  93. package/src/components/icons/Spinner.vue +42 -0
  94. package/src/components/icons/SquareCheck.vue +18 -0
  95. package/src/components/icons/SquareUncheck.vue +18 -0
  96. package/src/components/icons/Stadium.vue +1 -1
  97. package/src/components/icons/Wildcard.vue +18 -0
  98. package/src/components/icons/index.js +26 -1
  99. package/src/components/ui/Modal.vue +107 -13
  100. package/src/components/ui/Navbar.vue +175 -40
  101. package/src/components/ui/ReconnectIndicator.vue +351 -55
  102. package/src/components/ui/Splash.vue +5 -35
  103. package/src/components/ui/controls/CountryChooser.vue +200 -62
  104. package/src/components/ui/controls/atomic/Checkbox.vue +119 -10
  105. package/src/components/ui/controls/atomic/Dropdown.vue +216 -39
  106. package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
  107. package/src/components/ui/controls/atomic/MultiDropdown.vue +300 -37
  108. package/src/components/ui/controls/atomic/Switch.vue +53 -25
  109. package/src/composables/useClickOutside.js +21 -0
  110. package/src/composables/useDropdownPosition.js +174 -0
  111. package/src/libs/Filter.js +60 -24
  112. package/src/registerServiceWorker.js +1 -1
  113. package/src/stores/connection.js +4 -4
  114. package/src/stores/sampleData.js +172 -199
  115. package/src/stores/ui.js +55 -20
  116. package/src/stores/utils.js +30 -4
  117. package/src/types/index.js +41 -0
  118. package/src/utils/debug.js +1 -0
  119. package/src/views/Accounts.vue +116 -50
  120. package/src/views/Console.vue +394 -77
  121. package/src/views/Editor.vue +1176 -123
  122. package/src/views/FilterBuilder.vue +528 -250
  123. package/src/views/Login.vue +75 -14
  124. package/src/views/Profiles.vue +119 -34
  125. package/src/views/Tasks.vue +266 -98
  126. package/static/offline.html +192 -50
  127. package/switch-branch.sh +41 -0
  128. package/tailwind.config.js +119 -27
  129. package/vite.config.js +73 -16
  130. package/workbox-config.cjs +63 -0
  131. package/ICONS.md +0 -21
  132. package/public/img/background.svg +0 -14
  133. package/public/img/logo.png +0 -0
  134. package/public/img/logo_icon.png +0 -0
  135. package/public/img/logo_icon_2.png +0 -0
  136. package/src/assets/css/_input.scss +0 -143
  137. package/src/assets/img/logo.png +0 -0
  138. package/src/assets/img/logo_icon.png +0 -0
  139. package/src/assets/img/logo_icon_2.png +0 -0
  140. package/vue.config.js +0 -32
  141. package/workbox-config.js +0 -7
@@ -4,37 +4,37 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6
6
  <title>Site Offline</title>
7
- <meta name="theme-color" content="rgba(28, 28, 49, 1)" />
7
+ <meta name="theme-color" content="#0f1012" />
8
8
  <style>
9
+ :root {
10
+ --bg-primary: #0f1012;
11
+ --bg-secondary: #1a1b1e;
12
+ --bg-tertiary: #2e2f34;
13
+ --text-primary: #ffffff;
14
+ --text-secondary: #9ca3af;
15
+ --accent: #ef4444;
16
+ --border: #1f2937;
17
+ --glow: rgba(239, 68, 68, 0.15);
18
+ }
19
+
9
20
  body,
10
21
  html {
11
22
  margin: 0;
12
23
  padding: 0;
13
24
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14
- background-color: rgba(28, 28, 49, 1);
15
- color: #fff;
25
+ background-color: var(--bg-primary);
26
+ color: var(--text-primary);
16
27
  height: 100%;
17
- }
18
-
19
- html,
20
- body {
21
- /* Prevent scrolling on both axes */
22
28
  overflow: hidden;
23
29
  position: fixed;
24
30
  width: 100%;
25
31
  height: 100%;
26
-
27
- /* Prevent touch actions except for buttons */
28
32
  touch-action: none;
29
33
  -ms-touch-action: none;
30
-
31
- /* Prevent text selection */
32
34
  -webkit-user-select: none;
33
35
  -moz-user-select: none;
34
36
  -ms-user-select: none;
35
37
  user-select: none;
36
-
37
- /* Prevent pinch zoom */
38
38
  -webkit-touch-callout: none;
39
39
  -webkit-text-size-adjust: none;
40
40
  }
@@ -44,73 +44,220 @@
44
44
  justify-content: center;
45
45
  align-items: center;
46
46
  min-height: 100vh;
47
+ background: radial-gradient(circle at center, var(--bg-secondary) 0%, var(--bg-primary) 100%);
48
+ position: relative;
47
49
  }
50
+
51
+ .container::before {
52
+ content: "";
53
+ position: absolute;
54
+ top: 0;
55
+ left: 0;
56
+ right: 0;
57
+ bottom: 0;
58
+ background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%231a1b1e' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
59
+ opacity: 0.1;
60
+ }
61
+
48
62
  .error-card {
49
- background-color: rgba(39, 39, 67, 0.4);
50
- border-radius: 0.5rem;
51
- padding: 2rem;
52
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
63
+ background-color: var(--bg-secondary);
64
+ border: 1px solid var(--border);
65
+ border-radius: 1rem;
66
+ padding: 2.5rem;
67
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
53
68
  text-align: center;
54
- max-width: 20rem;
69
+ max-width: 24rem;
55
70
  width: 100%;
56
71
  margin: auto;
72
+ animation: slideUp 0.5s ease-out;
73
+ position: relative;
74
+ overflow: hidden;
75
+ backdrop-filter: blur(10px);
57
76
  }
77
+
78
+ .error-card::before {
79
+ content: "";
80
+ position: absolute;
81
+ top: 0;
82
+ left: 0;
83
+ right: 0;
84
+ height: 1px;
85
+ background: linear-gradient(90deg, transparent, var(--accent), transparent);
86
+ opacity: 0.5;
87
+ }
88
+
89
+ .error-card::after {
90
+ content: "";
91
+ position: absolute;
92
+ inset: 0;
93
+ border-radius: 1rem;
94
+ padding: 1px;
95
+ background: linear-gradient(135deg, var(--accent), transparent);
96
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
97
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
98
+ -webkit-mask-composite: xor;
99
+ mask-composite: exclude;
100
+ pointer-events: none;
101
+ }
102
+
58
103
  .icon-wrapper {
59
- background-color: #4a4a61;
60
- width: 4rem;
61
- height: 4rem;
104
+ background-color: var(--bg-tertiary);
105
+ width: 5rem;
106
+ height: 5rem;
62
107
  border-radius: 50%;
63
108
  display: flex;
64
109
  justify-content: center;
65
110
  align-items: center;
66
- margin: 0 auto 1rem;
67
- font-size: 2rem;
68
- color: #ee8282;
111
+ margin: 0 auto 1.5rem;
112
+ font-size: 2.5rem;
113
+ color: var(--accent);
114
+ position: relative;
115
+ animation: pulse 2s infinite;
116
+ box-shadow: 0 0 20px var(--glow);
117
+ }
118
+
119
+ .icon-wrapper::after {
120
+ content: "";
121
+ position: absolute;
122
+ width: 100%;
123
+ height: 100%;
124
+ border-radius: 50%;
125
+ border: 1px solid var(--accent);
126
+ opacity: 0.3;
127
+ animation: ripple 2s infinite;
69
128
  }
129
+
70
130
  h1 {
71
- font-size: 1.5rem;
72
- margin-bottom: 0.5rem;
131
+ font-size: 1.75rem;
132
+ font-weight: 600;
133
+ margin-bottom: 0.75rem;
134
+ background: linear-gradient(90deg, var(--text-primary), var(--text-secondary));
135
+ -webkit-background-clip: text;
136
+ -webkit-text-fill-color: transparent;
137
+ text-shadow: 0 0 20px var(--glow);
73
138
  }
139
+
74
140
  p {
75
- color: rgba(255, 255, 255, 0.7);
76
- margin-bottom: 1.5rem;
141
+ color: var(--text-secondary);
142
+ margin-bottom: 2rem;
143
+ font-size: 1.1rem;
144
+ line-height: 1.5;
77
145
  }
146
+
78
147
  .refresh-button {
79
- background-color: #4a4a61;
80
- color: white;
148
+ background-color: var(--bg-tertiary);
149
+ color: var(--text-primary);
81
150
  border: none;
82
- padding: 0.5rem 1rem;
83
- border-radius: 0.25rem;
151
+ padding: 0.75rem 1.5rem;
152
+ border-radius: 0.5rem;
84
153
  font-size: 1rem;
154
+ font-weight: 500;
85
155
  cursor: pointer;
86
- transition: background-color 0.3s ease;
87
- /* Enable touch actions specifically for the button */
156
+ transition: all 0.3s ease;
88
157
  touch-action: manipulation;
89
158
  -webkit-tap-highlight-color: transparent;
90
- touch-action: auto;
91
- -webkit-touch-callout: none;
92
- cursor: pointer;
159
+ position: relative;
160
+ overflow: hidden;
161
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
162
+ }
163
+
164
+ .refresh-button::before {
165
+ content: "";
166
+ position: absolute;
167
+ top: 0;
168
+ left: 0;
169
+ width: 100%;
170
+ height: 100%;
171
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
172
+ transform: translateX(-100%);
93
173
  }
174
+
94
175
  .refresh-button:hover {
95
- background-color: rgba(255, 255, 255, 0.2);
176
+ background-color: var(--bg-tertiary);
177
+ transform: translateY(-1px);
178
+ box-shadow: 0 0 15px var(--glow);
96
179
  }
180
+
181
+ .refresh-button:hover::before {
182
+ transform: translateX(100%);
183
+ transition: transform 0.6s ease;
184
+ }
185
+
97
186
  .refresh-button:focus {
98
187
  outline: none;
99
- box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
188
+ box-shadow: 0 0 0 3px var(--glow);
100
189
  }
101
- /* Add active state for better touch feedback */
190
+
102
191
  .refresh-button:active {
103
- background-color: rgba(255, 255, 255, 0.3);
104
- transform: scale(0.98);
192
+ transform: translateY(1px);
193
+ background-color: var(--bg-tertiary);
194
+ }
195
+
196
+ @keyframes slideUp {
197
+ from {
198
+ opacity: 0;
199
+ transform: translateY(20px);
200
+ }
201
+ to {
202
+ opacity: 1;
203
+ transform: translateY(0);
204
+ }
205
+ }
206
+
207
+ @keyframes pulse {
208
+ 0% {
209
+ transform: scale(1);
210
+ box-shadow: 0 0 20px var(--glow);
211
+ }
212
+ 50% {
213
+ transform: scale(1.05);
214
+ box-shadow: 0 0 30px var(--glow);
215
+ }
216
+ 100% {
217
+ transform: scale(1);
218
+ box-shadow: 0 0 20px var(--glow);
219
+ }
220
+ }
221
+
222
+ @keyframes ripple {
223
+ 0% {
224
+ transform: scale(1);
225
+ opacity: 0.3;
226
+ }
227
+ 100% {
228
+ transform: scale(1.5);
229
+ opacity: 0;
230
+ }
231
+ }
232
+
233
+ @media (max-width: 640px) {
234
+ .error-card {
235
+ margin: 1rem;
236
+ padding: 1.5rem;
237
+ }
238
+
239
+ .icon-wrapper {
240
+ width: 4rem;
241
+ height: 4rem;
242
+ font-size: 2rem;
243
+ }
244
+
245
+ h1 {
246
+ font-size: 1.5rem;
247
+ }
248
+
249
+ p {
250
+ font-size: 1rem;
251
+ }
105
252
  }
106
253
  </style>
107
254
  </head>
108
255
  <body>
109
256
  <div class="container">
110
257
  <div class="error-card">
111
- <div class="icon-wrapper"><span style="margin-bottom: 0.2rem">&#9888;</span></div>
258
+ <div class="icon-wrapper">⚠️</div>
112
259
  <h1>Site Offline</h1>
113
- <p>We're down. Please try again.</p>
260
+ <p>We're experiencing technical difficulties. Please try again in a moment.</p>
114
261
  <button class="refresh-button" id="refreshButton">Refresh Page</button>
115
262
  </div>
116
263
  </div>
@@ -118,12 +265,10 @@
118
265
  document.addEventListener("DOMContentLoaded", function () {
119
266
  const button = document.getElementById("refreshButton");
120
267
 
121
- // Handle button click/touch
122
268
  button.addEventListener("click", function (e) {
123
269
  window.location.reload();
124
270
  });
125
271
 
126
- // Prevent zoom and scroll on the page but allow button interaction
127
272
  document.addEventListener(
128
273
  "touchstart",
129
274
  function (e) {
@@ -152,12 +297,10 @@
152
297
  { passive: false }
153
298
  );
154
299
 
155
- // Prevent zoom via gesture
156
300
  document.addEventListener("gesturestart", function (e) {
157
301
  e.preventDefault();
158
302
  });
159
303
 
160
- // Prevent zoom via mousewheel/trackpad
161
304
  document.addEventListener(
162
305
  "wheel",
163
306
  function (e) {
@@ -168,7 +311,6 @@
168
311
  { passive: false }
169
312
  );
170
313
 
171
- // Prevent double-tap zoom
172
314
  let lastTap = 0;
173
315
  document.addEventListener("touchend", function (e) {
174
316
  const currentTime = new Date().getTime();
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+
3
+ # USAGE: ./git-force-switch.sh target-branch-name
4
+
5
+ set -e
6
+
7
+ TARGET_BRANCH="$1"
8
+
9
+ if [ -z "$TARGET_BRANCH" ]; then
10
+ echo "❌ Usage: $0 <branch-name>"
11
+ exit 1
12
+ fi
13
+
14
+ echo "🔧 Forcing checkout to '$TARGET_BRANCH'..."
15
+
16
+ # Step 1: Make sure Git respects case differences
17
+ git config core.ignoreCase false
18
+
19
+ # Step 2: Try checkout to see if it fails and capture errors
20
+ ERROR_OUTPUT=$(git checkout "$TARGET_BRANCH" 2>&1) || true
21
+
22
+ # Step 3: Check if it failed due to untracked files
23
+ if echo "$ERROR_OUTPUT" | grep -q "would be overwritten by checkout"; then
24
+ echo "⚠️ Conflicting untracked files detected. Cleaning them up..."
25
+
26
+ # Extract file paths and delete them
27
+ echo "$ERROR_OUTPUT" |
28
+ grep "^\s" |
29
+ sed 's/^[ \t]*//' |
30
+ while read -r FILE; do
31
+ if [ -f "$FILE" ] || [ -d "$FILE" ]; then
32
+ echo "🗑️ Removing $FILE"
33
+ rm -rf "$FILE"
34
+ fi
35
+ done
36
+
37
+ echo "🔁 Retrying checkout..."
38
+ git checkout "$TARGET_BRANCH"
39
+ else
40
+ echo "✅ Switched to $TARGET_BRANCH successfully."
41
+ fi
@@ -1,48 +1,140 @@
1
1
  /** @type {import('tailwindcss').Config} */
2
- module.exports = {
2
+ export default {
3
3
  content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
4
4
  theme: {
5
5
  colors: {
6
- white: "#FFFFFF",
7
- lightgray: "#e5e7eb",
6
+ transparent: "transparent",
7
+ white: "oklch(1 0 0)",
8
+ pure: "oklch(1 0 0)",
9
+ lightgray: "oklch(0.93 0 0)",
8
10
  green: {
9
- 400: "#44b744"
11
+ 300: "oklch(0.75 0.15 145 / <alpha-value>)",
12
+ 400: "oklch(0.68 0.18 145 / <alpha-value>)",
13
+ 500: "oklch(0.60 0.20 145 / <alpha-value>)"
10
14
  },
11
15
  red: {
12
- 400: "#EE8282"
16
+ 300: "oklch(0.68 0.18 25 / <alpha-value>)",
17
+ 400: "oklch(0.62 0.22 25 / <alpha-value>)",
18
+ 500: "oklch(0.58 0.24 25 / <alpha-value>)"
19
+ },
20
+ blue: {
21
+ 300: "oklch(0.68 0.14 250 / <alpha-value>)",
22
+ 400: "oklch(0.60 0.18 250 / <alpha-value>)",
23
+ 500: "oklch(0.54 0.22 250 / <alpha-value>)"
24
+ },
25
+ yellow: {
26
+ 300: "oklch(0.82 0.12 85 / <alpha-value>)",
27
+ 400: "oklch(0.76 0.14 75 / <alpha-value>)",
28
+ 500: "oklch(0.70 0.16 70 / <alpha-value>)"
13
29
  },
14
30
  dark: {
15
- 300: "#1B1C2B",
16
- 400: "#2D2F4A",
17
- 500: "#202036",
18
- 550: "#292a43",
19
- 600: "#25263c"
31
+ 50: "oklch(0.98 0 0 / <alpha-value>)",
32
+ 100: "oklch(0.96 0 0 / <alpha-value>)",
33
+ 200: "oklch(0.93 0 0 / <alpha-value>)",
34
+ 300: "oklch(0.1822 0 0 / <alpha-value>)", // Base background (Supabase dark)
35
+ 400: "oklch(0.2046 0 0 / <alpha-value>)", // Card backgrounds
36
+ 500: "oklch(0.2603 0 0 / <alpha-value>)", // Input backgrounds
37
+ 550: "oklch(0.2809 0 0 / <alpha-value>)", // Subtle elevation
38
+ 600: "oklch(0.2809 0 0 / <alpha-value>)", // Borders
39
+ 650: "oklch(0.3132 0 0 / <alpha-value>)", // Hover states
40
+ 700: "oklch(0.31 0 0 / <alpha-value>)", // Active states
41
+ 750: "oklch(0.33 0 0 / <alpha-value>)", // Selected states
42
+ 800: "oklch(0.08 0 0 / <alpha-value>)", // Deep background
43
+ 850: "oklch(0.06 0 0 / <alpha-value>)", // Deepest background
44
+ 900: "oklch(0.03 0 0 / <alpha-value>)" // Ultra deep
20
45
  },
21
46
  light: {
22
- 300: "#4A4A61",
23
- 400: "#A7A8AF"
47
+ 100: "oklch(0.98 0 0 / <alpha-value>)",
48
+ 200: "oklch(0.92 0 0 / <alpha-value>)",
49
+ 300: "oklch(0.90 0 0 / <alpha-value>)", // Primary text (text-primary)
50
+ 400: "oklch(0.82 0 0 / <alpha-value>)", // Secondary text (text-secondary)
51
+ 500: "oklch(0.65 0 0 / <alpha-value>)", // Muted text (text-muted)
52
+ 600: "oklch(0.50 0 0 / <alpha-value>)", // Disabled text
53
+ 700: "oklch(0.38 0 0 / <alpha-value>)", // Very muted
54
+ 800: "oklch(0.28 0 0 / <alpha-value>)", // Dark muted
55
+ 900: "oklch(0.18 0 0 / <alpha-value>)" // Darkest muted
56
+ },
57
+ gray: {
58
+ 50: "oklch(0.99 0 0 / <alpha-value>)",
59
+ 100: "oklch(0.97 0 0 / <alpha-value>)",
60
+ 200: "oklch(0.93 0 0 / <alpha-value>)",
61
+ 300: "oklch(0.85 0 0 / <alpha-value>)",
62
+ 400: "oklch(0.68 0 0 / <alpha-value>)",
63
+ 500: "oklch(0.52 0 0 / <alpha-value>)",
64
+ 600: "oklch(0.40 0 0 / <alpha-value>)",
65
+ 700: "oklch(0.32 0 0 / <alpha-value>)",
66
+ 800: "oklch(0.22 0 0 / <alpha-value>)",
67
+ 900: "oklch(0.14 0 0 / <alpha-value>)"
24
68
  },
25
- border: "#29293F"
69
+ accent: {
70
+ blue: "oklch(0.56 0.08 264 / <alpha-value>)",
71
+ green: "oklch(0.72 0.15 145 / <alpha-value>)", // Primary accent (#88c999 mint green)
72
+ purple: "oklch(0.65 0.12 305 / <alpha-value>)",
73
+ pink: "oklch(0.62 0.15 350 / <alpha-value>)",
74
+ orange: "oklch(0.70 0.10 55 / <alpha-value>)",
75
+ yellow: "oklch(0.85 0.10 95 / <alpha-value>)"
76
+ },
77
+ border: "oklch(0.26 0 0 / <alpha-value>)"
26
78
  },
27
79
  screens: {
28
- xs: "500px",
29
- sm: "640px",
30
- // => @media (min-width: 640px) { ... }
31
-
32
- md: "768px",
33
- // => @media (min-width: 768px) { ... }
80
+ // Mobile first approach
81
+ xs: "480px", // Small mobile landscape / large mobile portrait
82
+ sm: "640px", // Tablet portrait
83
+ md: "768px", // Tablet landscape / small desktop
84
+ lg: "1024px", // Desktop
85
+ xl: "1280px", // Large desktop
34
86
 
35
- ipadlg: "1000px",
36
- lg: "1030px",
37
- // => @media (min-width: 1024px) { ... }
87
+ // Device-specific breakpoints
88
+ tablet: "768px", // Tablet-specific styling
89
+ desktop: "1024px", // Desktop-specific styling
38
90
 
39
- xl: "1280px",
40
- // => @media (min-width: 1280px) { ... }
41
-
42
- "2xl": "1536px",
43
- // => @media (min-width: 1536px) { ... }
91
+ // Orientation-based breakpoints
44
92
  landscape: {
45
93
  raw: "(orientation: landscape)"
94
+ },
95
+ portrait: {
96
+ raw: "(orientation: portrait)"
97
+ },
98
+
99
+ // Height-based breakpoints for better mobile experience
100
+ "h-sm": {
101
+ raw: "(max-height: 500px)"
102
+ },
103
+ "h-md": {
104
+ raw: "(min-height: 600px)"
105
+ },
106
+ "h-lg": {
107
+ raw: "(min-height: 900px)"
108
+ },
109
+
110
+ // Combined orientation and size breakpoints
111
+ "mobile-landscape": {
112
+ raw: "(max-width: 896px) and (orientation: landscape) and (max-height: 500px)"
113
+ },
114
+ "mobile-portrait": {
115
+ raw: "(max-width: 480px) and (orientation: portrait)"
116
+ },
117
+
118
+ // Touch device detection
119
+ touch: {
120
+ raw: "(hover: none) and (pointer: coarse)"
121
+ },
122
+ "no-touch": {
123
+ raw: "(hover: hover) and (pointer: fine)"
124
+ }
125
+ },
126
+ extend: {
127
+ zIndex: {
128
+ 'dropdown': '100',
129
+ 'dropdown-high': '200',
130
+ 'modal': '1000',
131
+ 'tooltip': '2000',
132
+ 'overlay': '3000',
133
+ 'max': '9999',
134
+ },
135
+ boxShadow: {
136
+ 'card': '0 4px 12px rgba(0, 0, 0, 0.2)',
137
+ 'button': '0 1px 2px rgba(0, 0, 0, 0.2)',
46
138
  }
47
139
  }
48
140
  },
package/vite.config.js CHANGED
@@ -1,39 +1,96 @@
1
1
  import { fileURLToPath, URL } from "node:url";
2
2
  import { defineConfig } from "vite";
3
3
  import vue from "@vitejs/plugin-vue";
4
- import pkg from "./package.json";
4
+ import { readFileSync } from "node:fs";
5
+
6
+ const pkg = JSON.parse(readFileSync("./package.json", "utf-8"));
5
7
 
6
8
  // https://vitejs.dev/config/
7
9
  export default defineConfig({
10
+ cacheDir: './node_modules/.vite',
8
11
  build: {
9
12
  rollupOptions: {
10
- external: []
11
- }
13
+ output: {
14
+ manualChunks: {
15
+ vue: ["vue", "vue-router", "pinia"],
16
+ ui: ["@vueuse/core", "vue-virtual-scroller"],
17
+ utils: ["@msgpack/msgpack", "websocket-heartbeat-js"]
18
+ }
19
+ }
20
+ },
21
+ target: "esnext",
22
+ cssCodeSplit: true,
23
+ sourcemap: false,
24
+ minify: "esbuild",
25
+ emptyOutDir: false
12
26
  },
13
27
  optimizeDeps: {
14
- exclude: ["sharp"] // Exclude 'sharp' from dependency optimization
28
+ include: ["vue", "vue-router", "pinia", "@vueuse/core"],
29
+ exclude: ["sharp"]
15
30
  },
16
31
  define: {
17
- __APP_VERSION__: JSON.stringify(pkg.version) // Inject app version from package.json
32
+ __APP_VERSION__: JSON.stringify(pkg.version),
33
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false
18
34
  },
19
- plugins: [vue()], // Use Vue plugin
35
+ plugins: [
36
+ vue({
37
+ template: {
38
+ compilerOptions: {
39
+ isCustomElement: (tag) => tag.startsWith("necro-")
40
+ }
41
+ }
42
+ })
43
+ ],
20
44
  resolve: {
21
45
  alias: {
22
- "@": fileURLToPath(new URL("./src", import.meta.url)) // Alias for src directory
23
- },
24
- fallback: {
25
- "node-persist": false,
26
- redis: false,
27
- sharp: false,
28
- fs: false,
29
- path: false,
30
- os: false
46
+ "@": fileURLToPath(new URL("./src", import.meta.url))
31
47
  }
32
48
  },
33
49
  css: {
34
50
  preprocessorOptions: {
35
51
  scss: {
36
- api: "modern-compiler" // Use modern SCSS compiler
52
+ api: "modern-compiler",
53
+ silenceDeprecations: ["legacy-js-api"]
54
+ }
55
+ },
56
+ devSourcemap: true
57
+ },
58
+ server: {
59
+ port: 5173,
60
+ strictPort: true,
61
+ host: true,
62
+ cors: true,
63
+ hmr: {
64
+ overlay: false
65
+ },
66
+ // Handle iOS connection resets gracefully
67
+ watch: {
68
+ usePolling: false,
69
+ interval: 1000
70
+ },
71
+ proxy: {
72
+ "/api": {
73
+ target: "http://localhost:8081",
74
+ changeOrigin: true,
75
+ secure: false,
76
+ configure: (proxy) => {
77
+ proxy.on("error", (err, req, res) => {
78
+ res.writeHead(503, {
79
+ "Content-Type": "application/json"
80
+ });
81
+ res.end(JSON.stringify({ error: "Backend starting up, please wait..." }));
82
+ });
83
+ }
84
+ },
85
+ "/ws": {
86
+ target: "ws://localhost:8081",
87
+ ws: true,
88
+ changeOrigin: true,
89
+ configure: (proxy) => {
90
+ proxy.on("error", () => {
91
+ // Silently handle WebSocket connection errors
92
+ });
93
+ }
37
94
  }
38
95
  }
39
96
  }