@necrolab/dashboard 0.4.38 → 0.4.39
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/.claude/settings.local.json +3 -1
- package/backend/api.js +20 -16
- package/backend/auth.js +2 -2
- package/backend/batching.js +1 -1
- package/backend/endpoints.js +5 -5
- package/backend/index.js +2 -2
- package/backend/mock-data.js +19 -20
- package/backend/mock-src/classes/logger.js +5 -7
- package/backend/mock-src/classes/utils.js +3 -2
- package/backend/mock-src/ticketmaster.js +2 -2
- package/backend/validator.js +2 -2
- package/dev-server.js +49 -0
- package/index.html +1 -1
- package/index.js +1 -1
- package/package.json +6 -5
- package/postcss.config.js +1 -1
- package/postinstall.js +5 -3
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/manifest.json +4 -4
- package/src/App.vue +471 -49
- package/src/assets/css/_input.scss +25 -25
- package/src/assets/css/main.scss +116 -22
- package/src/assets/img/android-chrome-192x192.png +0 -0
- package/src/assets/img/logo_icon-old.png +0 -0
- package/src/assets/img/logo_icon.png +0 -0
- package/src/components/Editors/Account/Account.vue +19 -19
- package/src/components/Editors/Account/AccountCreator.vue +3 -3
- package/src/components/Editors/Account/AccountView.vue +17 -6
- package/src/components/Editors/Profile/Profile.vue +24 -24
- package/src/components/Editors/Profile/ProfileView.vue +22 -9
- package/src/components/Editors/TagLabel.vue +6 -7
- package/src/components/Table/Table.vue +15 -0
- package/src/components/Tasks/Controls/DesktopControls.vue +1 -1
- package/src/components/Tasks/CreateTaskAXS.vue +15 -15
- package/src/components/Tasks/CreateTaskTM.vue +5 -4
- package/src/components/Tasks/Task.vue +23 -35
- package/src/components/Tasks/TaskView.vue +19 -18
- package/src/components/Tasks/Utilities.vue +1 -1
- package/src/components/icons/Mail.vue +2 -2
- package/src/components/ui/Modal.vue +84 -15
- package/src/components/ui/Navbar.vue +118 -39
- package/src/components/ui/controls/atomic/Dropdown.vue +23 -3
- package/src/components/ui/controls/atomic/MultiDropdown.vue +43 -23
- package/src/stores/sampleData.js +5 -4
- package/src/stores/ui.js +3 -3
- package/src/views/Accounts.vue +2 -2
- package/src/views/Console.vue +78 -30
- package/src/views/Editor.vue +175 -24
- package/src/views/FilterBuilder.vue +21 -7
- package/src/views/Profiles.vue +8 -8
- package/src/views/Tasks.vue +51 -2
- package/tailwind.config.js +1 -1
- package/vite.config.js +8 -1
- package/vue.config.js +1 -1
- package/{workbox-config.js → workbox-config.cjs} +1 -4
package/src/views/Console.vue
CHANGED
|
@@ -22,28 +22,20 @@
|
|
|
22
22
|
<div class="flex items-center gap-3">
|
|
23
23
|
<!-- Hide Monitors and Auto buttons only on desktop -->
|
|
24
24
|
<div class="hidden ipadlg:flex items-center gap-3">
|
|
25
|
-
<button
|
|
26
|
-
class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
|
|
27
|
-
>
|
|
25
|
+
<button class="flex rounded gap-3 card-dark px-2 h-10 flex-center">
|
|
28
26
|
<h3 class="text-sm text-white">Hide Monitors</h3>
|
|
29
27
|
<Switch class="scale-75" v-model="filteredLogs" />
|
|
30
28
|
</button>
|
|
31
|
-
<button
|
|
32
|
-
class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
|
|
33
|
-
>
|
|
29
|
+
<button class="flex rounded gap-3 card-dark px-2 h-10 flex-center">
|
|
34
30
|
<h3 class="text-sm text-white">Auto</h3>
|
|
35
31
|
<Switch class="scale-75" v-model="autoscrollToggled" />
|
|
36
32
|
</button>
|
|
37
33
|
</div>
|
|
38
34
|
<!-- Scroll buttons always visible -->
|
|
39
|
-
<button
|
|
40
|
-
class="rounded card-dark w-10 h-10 flex-center"
|
|
41
|
-
>
|
|
35
|
+
<button class="rounded card-dark w-10 h-10 flex-center">
|
|
42
36
|
<UpIcon class="cursor-pointer mx-1 lg:w-4 w-5 h-5" @click="scrollTo('up')" />
|
|
43
37
|
</button>
|
|
44
|
-
<button
|
|
45
|
-
class="rounded card-dark w-10 h-10 flex-center"
|
|
46
|
-
>
|
|
38
|
+
<button class="rounded card-dark w-10 h-10 flex-center">
|
|
47
39
|
<DownIcon class="cursor-pointer ml-1 lg:w-4 w-5 h-5" @click="scrollTo('down')" />
|
|
48
40
|
</button>
|
|
49
41
|
</div>
|
|
@@ -51,28 +43,40 @@
|
|
|
51
43
|
|
|
52
44
|
<Smoothie
|
|
53
45
|
:weight="0.1"
|
|
54
|
-
class="
|
|
46
|
+
class="console overflow-y-auto overflow-x-hidden font-mono text-white scrollable"
|
|
55
47
|
style="min-height: 14rem !important"
|
|
56
48
|
ref="$autoscroll"
|
|
49
|
+
@wheel.stop
|
|
50
|
+
@touchmove.stop
|
|
57
51
|
>
|
|
52
|
+
<div
|
|
53
|
+
v-if="
|
|
54
|
+
(currentTaskLog && currentTaskLog !== ''
|
|
55
|
+
? taskLogMapping[currentTaskLog]
|
|
56
|
+
: logLines.filter((l) => (filteredLogs ? !['-DISCORD'].some((s) => l.includes(s)) : true))
|
|
57
|
+
).length === 0
|
|
58
|
+
"
|
|
59
|
+
class="flex flex-col items-center justify-center h-full empty-state text-center"
|
|
60
|
+
>
|
|
61
|
+
<ConsoleIcon class="w-12 h-12 text-dark-400 mb-3 opacity-50" />
|
|
62
|
+
<p class="text-light-400 text-sm">No logs yet</p>
|
|
63
|
+
<p class="text-light-500 text-xs mt-1">Logs will appear here in real time</p>
|
|
64
|
+
</div>
|
|
58
65
|
<pre
|
|
66
|
+
v-else
|
|
59
67
|
class="hidden-scrollbars"
|
|
60
|
-
v-for="line in currentTaskLog
|
|
68
|
+
v-for="(line, index) in currentTaskLog && currentTaskLog !== ''
|
|
61
69
|
? taskLogMapping[currentTaskLog]
|
|
62
70
|
: logLines.filter((l) => (filteredLogs ? !['-DISCORD'].some((s) => l.includes(s)) : true))"
|
|
63
|
-
v-bind:key="
|
|
71
|
+
v-bind:key="`log-${index}`"
|
|
64
72
|
><code class="md:text-sm lg:text-base" v-html="line"></code></pre>
|
|
65
73
|
</Smoothie>
|
|
66
74
|
<div class="flex ipadlg:hidden justify-between mt-3">
|
|
67
|
-
<button
|
|
68
|
-
class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
|
|
69
|
-
>
|
|
75
|
+
<button class="flex rounded gap-3 card-dark px-2 h-10 flex-center">
|
|
70
76
|
<h3 class="text-sm text-white">Hide Monitors</h3>
|
|
71
77
|
<Switch class="scale-75" v-model="filteredLogs" />
|
|
72
78
|
</button>
|
|
73
|
-
<button
|
|
74
|
-
class="flex rounded gap-3 card-dark px-2 h-10 flex-center"
|
|
75
|
-
>
|
|
79
|
+
<button class="flex rounded gap-3 card-dark px-2 h-10 flex-center">
|
|
76
80
|
<h3 class="text-sm text-white">Auto</h3>
|
|
77
81
|
<Switch class="scale-75" v-model="autoscrollToggled" />
|
|
78
82
|
</button>
|
|
@@ -84,6 +88,39 @@
|
|
|
84
88
|
.console {
|
|
85
89
|
@apply bg-dark-400 lg:p-5 p-2 rounded relative border-dark-550 border-2;
|
|
86
90
|
height: calc(100vh - 16.5rem);
|
|
91
|
+
|
|
92
|
+
// Enable scrollbars for console
|
|
93
|
+
scrollbar-width: thin;
|
|
94
|
+
scrollbar-color: #555 #2e2f34;
|
|
95
|
+
|
|
96
|
+
&::-webkit-scrollbar {
|
|
97
|
+
width: 8px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&::-webkit-scrollbar-track {
|
|
101
|
+
background: #2e2f34;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&::-webkit-scrollbar-thumb {
|
|
105
|
+
background: #555;
|
|
106
|
+
border-radius: 4px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
110
|
+
background: #777;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Empty state styling
|
|
114
|
+
.empty-state {
|
|
115
|
+
min-height: 14rem;
|
|
116
|
+
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// iPhone portrait - disable scroll since everything fits
|
|
120
|
+
@media (max-width: 480px) and (orientation: portrait) {
|
|
121
|
+
height: calc(100vh - 18rem);
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
}
|
|
87
124
|
textarea {
|
|
88
125
|
background: transparent;
|
|
89
126
|
resize: none;
|
|
@@ -97,11 +134,11 @@
|
|
|
97
134
|
.console {
|
|
98
135
|
height: calc(100vh - 20rem);
|
|
99
136
|
@apply p-1 text-xs;
|
|
100
|
-
|
|
137
|
+
|
|
101
138
|
pre {
|
|
102
139
|
line-height: 1.2;
|
|
103
140
|
}
|
|
104
|
-
|
|
141
|
+
|
|
105
142
|
code {
|
|
106
143
|
font-size: 0.7rem !important;
|
|
107
144
|
}
|
|
@@ -151,13 +188,17 @@ const logLines = ref([]);
|
|
|
151
188
|
const ansii = new Filter();
|
|
152
189
|
const autoscrollToggled = ref(true);
|
|
153
190
|
const taskLogMapping = ref({});
|
|
154
|
-
const currentTaskLog = ref(
|
|
191
|
+
const currentTaskLog = ref("");
|
|
155
192
|
const filteredLogs = ref(true);
|
|
156
193
|
|
|
157
194
|
const path = "/api/updates?type=console";
|
|
158
195
|
const url = (window.location.protocol === "http:" ? "ws://" : "wss://") + window.location.host + path;
|
|
159
196
|
const scrollTo = (dir) => {
|
|
160
197
|
try {
|
|
198
|
+
if (!$autoscroll.value?.el) {
|
|
199
|
+
if (DEBUG) console.log("Autoscroll element not ready");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
161
202
|
if (dir === "up") $autoscroll.value.el.scrollTop = 0;
|
|
162
203
|
else $autoscroll.value.el.scrollTop = parseInt($autoscroll.value.el.children[1].style.height);
|
|
163
204
|
} catch (e) {
|
|
@@ -166,7 +207,7 @@ const scrollTo = (dir) => {
|
|
|
166
207
|
};
|
|
167
208
|
|
|
168
209
|
const addAnsiToOutput = (a) => {
|
|
169
|
-
const html = ansii.toHtml(a
|
|
210
|
+
const html = ansii.toHtml(a?.log || a);
|
|
170
211
|
logLines.value.push(html);
|
|
171
212
|
if (autoscrollToggled.value)
|
|
172
213
|
nextTick().then(() => {
|
|
@@ -206,11 +247,18 @@ const makeTaskLogMapping = (lines) => {
|
|
|
206
247
|
|
|
207
248
|
window.startDebugConsoleMessages = () => {
|
|
208
249
|
setInterval(() => {
|
|
209
|
-
const
|
|
210
|
-
Math.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
250
|
+
const log = {
|
|
251
|
+
log: `\u001b[96m[12:16:02.273]\u001b[00m \u001b[96m[TASK-${Math.round(
|
|
252
|
+
Math.random() * 10
|
|
253
|
+
)}]\u001b[00m TEST TEST TEST Needs To Queue: false - Queue up: false`,
|
|
254
|
+
metadata: {
|
|
255
|
+
taskId: Math.round(Math.random() * 10),
|
|
256
|
+
siteId: "TM_US",
|
|
257
|
+
global: false
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
addAnsiToOutput(log);
|
|
261
|
+
makeTaskLogMapping([log]);
|
|
214
262
|
}, 500);
|
|
215
263
|
};
|
|
216
264
|
|
package/src/views/Editor.vue
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<!-- Heading -->
|
|
4
|
-
<GearIcon class="w-5 cursor-pointer" @click="ui.toggleModal('quick-settings')" />
|
|
5
4
|
<h4 class="text-white text-xl font-bold mb-5 pt-5 flex gap-2 items-center">
|
|
6
5
|
Editor <img src="@/assets/img/pencil.svg" />
|
|
7
6
|
</h4>
|
|
@@ -9,8 +8,8 @@
|
|
|
9
8
|
<div class="card-dark p-2">
|
|
10
9
|
<div v-if="ui.profile.admin">
|
|
11
10
|
<h5 class="text-white text-xl font-bold flex gap-x-3 mb-3">Admin Editor</h5>
|
|
12
|
-
<div class="flex justify-between items-center">
|
|
13
|
-
<div class="w-64 flex">
|
|
11
|
+
<div class="flex justify-between items-center gap-4 editor-controls-row">
|
|
12
|
+
<div class="w-64 flex flex-shrink-0 dropdown-container">
|
|
14
13
|
<div class="relative flex-grow">
|
|
15
14
|
<Dropdown
|
|
16
15
|
class="bg-dark-500 border-2 border-r-0 border-dark-550 admin-file-dropdown w-full"
|
|
@@ -30,7 +29,7 @@
|
|
|
30
29
|
</button>
|
|
31
30
|
</div>
|
|
32
31
|
<!-- Admin editor buttons moved here -->
|
|
33
|
-
<div v-if="textEditorVisible" class="flex gap-x-2
|
|
32
|
+
<div v-if="textEditorVisible" class="flex gap-x-2 flex-shrink-0">
|
|
34
33
|
<button class="btn-action" @click="format()" v-if="isJsonFile()">
|
|
35
34
|
<svg
|
|
36
35
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -68,6 +67,23 @@
|
|
|
68
67
|
</svg>
|
|
69
68
|
<span>Save File</span>
|
|
70
69
|
</button>
|
|
70
|
+
<button class="btn-action" @click="closeFile">
|
|
71
|
+
<svg
|
|
72
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
73
|
+
width="16"
|
|
74
|
+
height="16"
|
|
75
|
+
viewBox="0 0 24 24"
|
|
76
|
+
fill="none"
|
|
77
|
+
stroke="currentColor"
|
|
78
|
+
stroke-width="2"
|
|
79
|
+
stroke-linecap="round"
|
|
80
|
+
stroke-linejoin="round"
|
|
81
|
+
>
|
|
82
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
83
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
84
|
+
</svg>
|
|
85
|
+
<span>Close File</span>
|
|
86
|
+
</button>
|
|
71
87
|
</div>
|
|
72
88
|
</div>
|
|
73
89
|
</div>
|
|
@@ -76,7 +92,7 @@
|
|
|
76
92
|
<div v-if="textEditorVisible" class="my-3 relative">
|
|
77
93
|
<div class="pb-4">
|
|
78
94
|
<!-- Syntax Highlighting Editor -->
|
|
79
|
-
<div class="editor-container">
|
|
95
|
+
<div class="editor-container table-component">
|
|
80
96
|
<div class="editor-wrapper">
|
|
81
97
|
<pre ref="codeDisplay" class="language-json code-highlight"></pre>
|
|
82
98
|
<textarea
|
|
@@ -94,10 +110,17 @@
|
|
|
94
110
|
|
|
95
111
|
<div v-if="errorMessage" class="error-container">
|
|
96
112
|
<div class="error-icon">
|
|
97
|
-
<svg
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
<svg
|
|
114
|
+
width="16"
|
|
115
|
+
height="16"
|
|
116
|
+
viewBox="0 0 24 24"
|
|
117
|
+
fill="none"
|
|
118
|
+
stroke="currentColor"
|
|
119
|
+
stroke-width="2"
|
|
120
|
+
>
|
|
121
|
+
<circle cx="12" cy="12" r="10" />
|
|
122
|
+
<line x1="15" y1="9" x2="9" y2="15" />
|
|
123
|
+
<line x1="9" y1="9" x2="15" y2="15" />
|
|
101
124
|
</svg>
|
|
102
125
|
</div>
|
|
103
126
|
<div class="error-content">
|
|
@@ -110,9 +133,9 @@
|
|
|
110
133
|
<div class="border border-dark-650 my-8" />
|
|
111
134
|
|
|
112
135
|
<h5 class="text-white text-xl font-bold flex gap-x-3 mb-3">Proxy Editor</h5>
|
|
113
|
-
<div class="flex justify-between items-center
|
|
114
|
-
<div class="w-64">
|
|
115
|
-
<div class="relative">
|
|
136
|
+
<div class="flex justify-between items-center gap-4 proxy-controls-row mb-4">
|
|
137
|
+
<div class="w-64 flex flex-shrink-0 dropdown-container">
|
|
138
|
+
<div class="relative flex-grow">
|
|
116
139
|
<Dropdown
|
|
117
140
|
class="bg-dark-500 border-2 border-dark-550 rounded-lg w-full h-10"
|
|
118
141
|
:default="ui.profile.proxyList?.checkout || proxyLists[0]"
|
|
@@ -124,7 +147,7 @@
|
|
|
124
147
|
</div>
|
|
125
148
|
</div>
|
|
126
149
|
<!-- Proxy save button moved here -->
|
|
127
|
-
<div v-if="currentProxyList"
|
|
150
|
+
<div v-if="currentProxyList" class="flex gap-x-2 flex-shrink-0">
|
|
128
151
|
<button class="btn-action h-12" @click="saveProxies">
|
|
129
152
|
<svg
|
|
130
153
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -143,28 +166,40 @@
|
|
|
143
166
|
</svg>
|
|
144
167
|
<span>Save Proxies</span>
|
|
145
168
|
</button>
|
|
169
|
+
<button class="btn-action h-12" @click="closeProxyFile">
|
|
170
|
+
<svg
|
|
171
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
172
|
+
width="16"
|
|
173
|
+
height="16"
|
|
174
|
+
viewBox="0 0 24 24"
|
|
175
|
+
fill="none"
|
|
176
|
+
stroke="currentColor"
|
|
177
|
+
stroke-width="2"
|
|
178
|
+
stroke-linecap="round"
|
|
179
|
+
stroke-linejoin="round"
|
|
180
|
+
>
|
|
181
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
182
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
183
|
+
</svg>
|
|
184
|
+
<span>Close File</span>
|
|
185
|
+
</button>
|
|
146
186
|
</div>
|
|
147
187
|
</div>
|
|
148
188
|
<!-- Textarea -->
|
|
149
189
|
<transition name="fade">
|
|
150
190
|
<div v-if="currentProxyList" class="relative my-3">
|
|
151
191
|
<div class="pb-4">
|
|
152
|
-
<div class="proxy-editor-container">
|
|
153
|
-
<textarea
|
|
154
|
-
v-model="proxyContent"
|
|
155
|
-
class="proxy-editor"
|
|
156
|
-
spellcheck="false"
|
|
157
|
-
></textarea>
|
|
192
|
+
<div class="proxy-editor-container table-component">
|
|
193
|
+
<textarea v-model="proxyContent" class="proxy-editor" spellcheck="false"></textarea>
|
|
158
194
|
</div>
|
|
159
195
|
</div>
|
|
160
196
|
</div>
|
|
161
197
|
</transition>
|
|
162
198
|
</div>
|
|
163
|
-
<QuickSettings v-if="activeModal === 'quick-settings'" />
|
|
164
199
|
</div>
|
|
165
200
|
</template>
|
|
166
201
|
<script setup>
|
|
167
|
-
import { ref, computed, watch, onMounted, nextTick } from "vue";
|
|
202
|
+
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from "vue";
|
|
168
203
|
import { DownIcon, ReloadIcon, EditIcon } from "@/components/icons";
|
|
169
204
|
import { useUIStore } from "@/stores/ui";
|
|
170
205
|
import Dropdown from "@/components/ui/controls/atomic/Dropdown.vue";
|
|
@@ -402,6 +437,19 @@ const saveAll = async () => {
|
|
|
402
437
|
await saveQuickConfig();
|
|
403
438
|
};
|
|
404
439
|
|
|
440
|
+
const closeFile = () => {
|
|
441
|
+
currentFile.value = "";
|
|
442
|
+
currentContent.value = "";
|
|
443
|
+
textEditorVisible.value = false;
|
|
444
|
+
ui.logger.Info("File closed");
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
const closeProxyFile = () => {
|
|
448
|
+
currentProxyList.value = "";
|
|
449
|
+
proxyContent.value = "";
|
|
450
|
+
ui.logger.Info("Proxy file closed");
|
|
451
|
+
};
|
|
452
|
+
|
|
405
453
|
const loadProxies = async (list) => {
|
|
406
454
|
try {
|
|
407
455
|
if (DEBUG) {
|
|
@@ -455,6 +503,47 @@ onMounted(() => {
|
|
|
455
503
|
}
|
|
456
504
|
});
|
|
457
505
|
|
|
506
|
+
// iOS-specific editor fixes with cursor tracking
|
|
507
|
+
if (
|
|
508
|
+
/iPad|iPhone|iPod/.test(navigator.platform) ||
|
|
509
|
+
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform))
|
|
510
|
+
) {
|
|
511
|
+
const trackCursor = (editor) => {
|
|
512
|
+
const scrollToCursor = () => {
|
|
513
|
+
setTimeout(() => {
|
|
514
|
+
const container = editor.closest(".editor-container") || editor.closest(".proxy-editor-container");
|
|
515
|
+
if (container) {
|
|
516
|
+
// Get cursor position and scroll to it
|
|
517
|
+
const lines = editor.value.substring(0, editor.selectionStart).split("\n");
|
|
518
|
+
const lineHeight = 24; // Approximate line height
|
|
519
|
+
const cursorY = lines.length * lineHeight;
|
|
520
|
+
const containerHeight = container.clientHeight;
|
|
521
|
+
|
|
522
|
+
// Scroll to keep cursor in view
|
|
523
|
+
if (cursorY > container.scrollTop + containerHeight - 60) {
|
|
524
|
+
container.scrollTop = cursorY - containerHeight + 60;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}, 100);
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
editor.addEventListener("focus", scrollToCursor);
|
|
531
|
+
editor.addEventListener("input", scrollToCursor);
|
|
532
|
+
editor.addEventListener("click", scrollToCursor);
|
|
533
|
+
editor.addEventListener("keyup", scrollToCursor);
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
nextTick(() => {
|
|
537
|
+
if (codeEditor.value) {
|
|
538
|
+
trackCursor(codeEditor.value);
|
|
539
|
+
}
|
|
540
|
+
const proxyEditor = document.querySelector(".proxy-editor");
|
|
541
|
+
if (proxyEditor) {
|
|
542
|
+
trackCursor(proxyEditor);
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
458
547
|
// Watch for editor visibility changes
|
|
459
548
|
watch(textEditorVisible, (newValue) => {
|
|
460
549
|
if (newValue) {
|
|
@@ -470,6 +559,8 @@ onMounted(() => {
|
|
|
470
559
|
});
|
|
471
560
|
});
|
|
472
561
|
|
|
562
|
+
// No cleanup needed - global iOS handling takes care of everything
|
|
563
|
+
|
|
473
564
|
if (ui.profile.admin && !DEBUG) loadAvailableFiles();
|
|
474
565
|
loadProxyLists();
|
|
475
566
|
</script>
|
|
@@ -552,8 +643,9 @@ loadProxyLists();
|
|
|
552
643
|
max-height: 600px;
|
|
553
644
|
border-radius: 8px;
|
|
554
645
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
|
555
|
-
overflow:
|
|
646
|
+
overflow: visible !important;
|
|
556
647
|
background-color: #2e2f34;
|
|
648
|
+
touch-action: auto !important;
|
|
557
649
|
}
|
|
558
650
|
|
|
559
651
|
.editor-wrapper {
|
|
@@ -562,6 +654,7 @@ loadProxyLists();
|
|
|
562
654
|
height: 100%;
|
|
563
655
|
min-height: 300px;
|
|
564
656
|
max-height: 600px;
|
|
657
|
+
overflow: visible !important; /* ALLOW SCROLLING */
|
|
565
658
|
}
|
|
566
659
|
|
|
567
660
|
.code-editor {
|
|
@@ -598,6 +691,33 @@ loadProxyLists();
|
|
|
598
691
|
background: rgba(98, 114, 164, 0.4);
|
|
599
692
|
}
|
|
600
693
|
|
|
694
|
+
/* iOS keyboard focus fix and scrolling */
|
|
695
|
+
.code-editor:focus,
|
|
696
|
+
.proxy-editor:focus {
|
|
697
|
+
transform: translateZ(0);
|
|
698
|
+
-webkit-transform: translateZ(0);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/* Force textarea scrolling to work */
|
|
702
|
+
.code-editor,
|
|
703
|
+
.proxy-editor {
|
|
704
|
+
overflow: auto !important;
|
|
705
|
+
-webkit-overflow-scrolling: touch !important;
|
|
706
|
+
user-select: text !important;
|
|
707
|
+
-webkit-user-select: text !important;
|
|
708
|
+
touch-action: auto !important;
|
|
709
|
+
overscroll-behavior: auto !important;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/* Additional override for any global styles */
|
|
713
|
+
textarea.code-editor,
|
|
714
|
+
textarea.proxy-editor {
|
|
715
|
+
overflow: auto !important;
|
|
716
|
+
-webkit-overflow-scrolling: touch !important;
|
|
717
|
+
touch-action: auto !important;
|
|
718
|
+
overscroll-behavior: auto !important;
|
|
719
|
+
}
|
|
720
|
+
|
|
601
721
|
.code-highlight {
|
|
602
722
|
width: 100%;
|
|
603
723
|
height: 100%;
|
|
@@ -629,7 +749,8 @@ loadProxyLists();
|
|
|
629
749
|
|
|
630
750
|
/* Proxy editor container */
|
|
631
751
|
.proxy-editor-container {
|
|
632
|
-
@apply w-full
|
|
752
|
+
@apply w-full rounded-lg border border-dark-600;
|
|
753
|
+
overflow: visible !important; /* ALLOW SCROLLING */
|
|
633
754
|
height: 400px;
|
|
634
755
|
max-height: 60vh;
|
|
635
756
|
background-color: #2e2f34;
|
|
@@ -668,7 +789,7 @@ loadProxyLists();
|
|
|
668
789
|
|
|
669
790
|
.proxy-editor-container:focus-within {
|
|
670
791
|
border-color: #5d7cc0;
|
|
671
|
-
box-shadow: 0 0 0 2px rgba(
|
|
792
|
+
box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.4);
|
|
672
793
|
}
|
|
673
794
|
|
|
674
795
|
/* Prism.js dark theme */
|
|
@@ -842,4 +963,34 @@ pre[class*="language-"] {
|
|
|
842
963
|
word-break: break-word;
|
|
843
964
|
opacity: 0.9;
|
|
844
965
|
}
|
|
966
|
+
|
|
967
|
+
/* iPhone portrait mode spacing fixes */
|
|
968
|
+
@media (max-width: 480px) and (orientation: portrait) {
|
|
969
|
+
.editor-controls-row {
|
|
970
|
+
gap: 0.75rem !important;
|
|
971
|
+
flex-wrap: wrap;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.dropdown-container {
|
|
975
|
+
width: 100% !important;
|
|
976
|
+
max-width: 16rem;
|
|
977
|
+
margin-bottom: 0.5rem;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
.editor-controls-row > div:last-child {
|
|
981
|
+
margin-right: auto;
|
|
982
|
+
margin-top: 0.5rem;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/* Proxy editor responsive layout */
|
|
986
|
+
.proxy-controls-row {
|
|
987
|
+
gap: 0.75rem !important;
|
|
988
|
+
flex-wrap: wrap;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
.proxy-controls-row > div:last-child {
|
|
992
|
+
margin-right: auto;
|
|
993
|
+
margin-top: 0.5rem;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
845
996
|
</style>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="filter-builder-container w-full min-h-0 flex flex-col overflow-hidden">
|
|
3
3
|
<!-- Heading -->
|
|
4
|
-
<div class="flex-between pt-4 pb-1
|
|
4
|
+
<div class="flex-between pt-4 pb-1 mt-1">
|
|
5
5
|
<div class="flex-center gap-4">
|
|
6
6
|
<FilterIcon class="cursor-pointer smooth-hover text-white" />
|
|
7
7
|
<h4 class="text-heading">Filter creator</h4>
|
|
@@ -47,9 +47,22 @@
|
|
|
47
47
|
v-else
|
|
48
48
|
class="h-full flex items-center justify-center p-2 rounded shadow border-2 border-dark-550 svg-container"
|
|
49
49
|
>
|
|
50
|
-
<div class="text-center
|
|
51
|
-
<
|
|
52
|
-
|
|
50
|
+
<div class="text-center">
|
|
51
|
+
<svg
|
|
52
|
+
class="w-12 h-12 mb-3 mx-auto opacity-50"
|
|
53
|
+
viewBox="0 0 19 19"
|
|
54
|
+
fill="none"
|
|
55
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
56
|
+
>
|
|
57
|
+
<path
|
|
58
|
+
d="M2.37499 5.54165V2.37498L5.54166 3.95831L2.37499 5.54165ZM14.25 5.54165V2.37498L17.4167 3.95831L14.25 5.54165ZM8.70833 4.74998V1.58331L11.875 3.16665L8.70833 4.74998ZM8.70833 17.4166C7.70555 17.3903 6.77218 17.3079 5.9082 17.1696C5.0437 17.0308 4.29162 16.8559 3.65195 16.6448C3.01176 16.4337 2.50694 16.1896 2.13749 15.9125C1.76805 15.6354 1.58333 15.3451 1.58333 15.0416V7.91665C1.58333 7.58678 1.79127 7.27988 2.20716 6.99594C2.62252 6.71252 3.18645 6.46183 3.89895 6.24385C4.61145 6.02641 5.4493 5.85488 6.4125 5.72927C7.37569 5.60419 8.40486 5.54165 9.49999 5.54165C10.5951 5.54165 11.6243 5.60419 12.5875 5.72927C13.5507 5.85488 14.3885 6.02641 15.101 6.24385C15.8135 6.46183 16.3775 6.71252 16.7928 6.99594C17.2087 7.27988 17.4167 7.58678 17.4167 7.91665V15.0416C17.4167 15.3451 17.2319 15.6354 16.8625 15.9125C16.493 16.1896 15.9885 16.4337 15.3488 16.6448C14.7086 16.8559 13.9565 17.0308 13.0926 17.1696C12.2281 17.3079 11.2944 17.3903 10.2917 17.4166V14.25H8.70833V17.4166ZM9.49999 8.70831C10.7799 8.70831 11.885 8.63231 12.8155 8.48031C13.7454 8.32884 14.4875 8.15415 15.0417 7.95623C15.0417 7.89026 14.5403 7.73509 13.5375 7.49073C12.5347 7.2469 11.1889 7.12498 9.49999 7.12498C7.81111 7.12498 6.46527 7.2469 5.46249 7.49073C4.45972 7.73509 3.95833 7.89026 3.95833 7.95623C4.51249 8.15415 5.25481 8.32884 6.18529 8.48031C7.11523 8.63231 8.22013 8.70831 9.49999 8.70831ZM7.12499 15.7146V12.6666H11.875V15.7146C12.9305 15.609 13.7948 15.4538 14.4677 15.2491C15.1406 15.0448 15.5958 14.8635 15.8333 14.7052V9.34165C15.1076 9.63192 14.1972 9.86283 13.1021 10.0344C12.0069 10.2059 10.8062 10.2916 9.49999 10.2916C8.19374 10.2916 6.99305 10.2059 5.89791 10.0344C4.80277 9.86283 3.89236 9.63192 3.16666 9.34165V14.7052C3.40416 14.8635 3.85937 15.0448 4.53229 15.2491C5.2052 15.4538 6.06944 15.609 7.12499 15.7146Z"
|
|
59
|
+
fill="#F5F5F5"
|
|
60
|
+
/>
|
|
61
|
+
</svg>
|
|
62
|
+
<p class="text-light-400 text-sm">No Map</p>
|
|
63
|
+
<p class="text-light-500 text-xs">
|
|
64
|
+
Enter an event ID and click "Load" to display the venue map
|
|
65
|
+
</p>
|
|
53
66
|
</div>
|
|
54
67
|
</div>
|
|
55
68
|
</div>
|
|
@@ -83,13 +96,13 @@
|
|
|
83
96
|
<div class="flex items-center gap-2">
|
|
84
97
|
<span class="text-base">Filters</span>
|
|
85
98
|
<span class="text-base text-light-300">{{ filterBuilder.filters.length }}</span>
|
|
99
|
+
</div>
|
|
100
|
+
<div class="flex gap-2 items-center">
|
|
86
101
|
<PriceSortToggle
|
|
87
102
|
class="w-14 smooth-hover"
|
|
88
103
|
:options="['All', 'WL', 'BL']"
|
|
89
104
|
@change="(e) => (shownFilters = e)"
|
|
90
105
|
/>
|
|
91
|
-
</div>
|
|
92
|
-
<div class="flex gap-2 items-center">
|
|
93
106
|
<button class="header-btn save-btn" @click="saveFilter">
|
|
94
107
|
<EditIcon class="w-4 h-4" />
|
|
95
108
|
<span class="lg:block hidden">Save</span>
|
|
@@ -167,7 +180,7 @@
|
|
|
167
180
|
</div>
|
|
168
181
|
</div>
|
|
169
182
|
|
|
170
|
-
<transition-group name="fade"
|
|
183
|
+
<transition-group name="fade">
|
|
171
184
|
<FilterPreview v-if="activeModal === 'preview-filter'" :filter="filterBuilder" />
|
|
172
185
|
</transition-group>
|
|
173
186
|
</div>
|
|
@@ -562,6 +575,7 @@ const updateShownVenue = async () => {
|
|
|
562
575
|
|
|
563
576
|
const loadFilter = async () => {
|
|
564
577
|
try {
|
|
578
|
+
if (!eventId.value) return;
|
|
565
579
|
const res = await fetch(`/api/filter/load?eventId=${eventId.value}`);
|
|
566
580
|
const data = await res.json();
|
|
567
581
|
if (eventId.value) ui.showSuccess("Loaded filter data");
|
package/src/views/Profiles.vue
CHANGED
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
</button>
|
|
24
24
|
</li>
|
|
25
25
|
<li>
|
|
26
|
-
<button
|
|
27
|
-
:disabled="ui.disabledButtons['add-profiles']"
|
|
28
|
-
@click="disable"
|
|
26
|
+
<button
|
|
27
|
+
:disabled="ui.disabledButtons['add-profiles']"
|
|
28
|
+
@click="disable"
|
|
29
29
|
class="smooth-hover text-red-400"
|
|
30
30
|
>
|
|
31
31
|
<CloseXIcon />
|
|
32
32
|
</button>
|
|
33
33
|
</li>
|
|
34
34
|
<li>
|
|
35
|
-
<button
|
|
36
|
-
:disabled="ui.disabledButtons['add-profiles']"
|
|
37
|
-
@click="enable"
|
|
35
|
+
<button
|
|
36
|
+
:disabled="ui.disabledButtons['add-profiles']"
|
|
37
|
+
@click="enable"
|
|
38
38
|
class="smooth-hover text-green-400"
|
|
39
39
|
>
|
|
40
40
|
<CheckIcon />
|
|
@@ -112,10 +112,10 @@
|
|
|
112
112
|
</div>
|
|
113
113
|
|
|
114
114
|
<!-- Tasks (Table) -->
|
|
115
|
-
<ProfileView :
|
|
115
|
+
<ProfileView :profiles="processedTasks" />
|
|
116
116
|
|
|
117
117
|
<!-- Modal -->
|
|
118
|
-
<transition-group name="fade"
|
|
118
|
+
<transition-group name="fade">
|
|
119
119
|
<CreateProfile v-if="activeModal === 'create-profile'" />
|
|
120
120
|
</transition-group>
|
|
121
121
|
</div>
|