@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.
- package/backend/api.js +2 -3
- package/eslint.config.js +46 -0
- package/index.html +2 -1
- package/package.json +5 -2
- package/src/App.vue +70 -566
- package/src/assets/css/base/mixins.scss +72 -0
- package/src/assets/css/base/reset.scss +0 -2
- package/src/assets/css/base/scroll.scss +43 -36
- package/src/assets/css/base/typography.scss +9 -10
- package/src/assets/css/base/variables.scss +43 -0
- package/src/assets/css/components/accessibility.scss +37 -0
- package/src/assets/css/components/buttons.scss +61 -74
- package/src/assets/css/components/forms.scss +31 -32
- package/src/assets/css/components/headers.scss +13 -21
- package/src/assets/css/components/modals.scss +2 -2
- package/src/assets/css/components/search-groups.scss +28 -22
- package/src/assets/css/components/tables.scss +5 -7
- package/src/assets/css/components/toasts.scss +7 -7
- package/src/assets/css/components/utilities.scss +295 -0
- package/src/assets/css/main.scss +55 -139
- package/src/components/Auth/LoginForm.vue +7 -86
- package/src/components/Console/ConsoleToolbar.vue +123 -0
- package/src/components/Editors/Account/Account.vue +12 -12
- package/src/components/Editors/Account/AccountView.vue +38 -111
- package/src/components/Editors/Account/CreateAccount.vue +11 -61
- package/src/components/Editors/Account/{AccountCreator.vue → CreateAccountBatch.vue} +28 -59
- package/src/components/Editors/AdminFileEditor.vue +179 -0
- package/src/components/Editors/Profile/CreateProfile.vue +77 -150
- package/src/components/Editors/Profile/Profile.vue +20 -21
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
- package/src/components/Editors/Profile/ProfileView.vue +41 -116
- package/src/components/Editors/ProxyFileEditor.vue +86 -0
- package/src/components/Editors/TagLabel.vue +16 -55
- package/src/components/Editors/TagToggle.vue +20 -8
- package/src/components/Filter/Filter.vue +66 -79
- package/src/components/Filter/FilterPreview.vue +153 -135
- package/src/components/Filter/PriceSortToggle.vue +36 -43
- package/src/components/Table/Header.vue +1 -1
- package/src/components/Table/Table.vue +45 -51
- package/src/components/Tasks/CheckStock.vue +7 -16
- package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
- package/src/components/Tasks/Controls/MobileControls.vue +5 -20
- package/src/components/Tasks/CreateTaskAXS.vue +20 -118
- package/src/components/Tasks/CreateTaskTM.vue +33 -189
- package/src/components/Tasks/EventDetailRow.vue +21 -0
- package/src/components/Tasks/MassEdit.vue +6 -16
- package/src/components/Tasks/QuickSettings.vue +140 -216
- package/src/components/Tasks/ScrapeVenue.vue +4 -13
- package/src/components/Tasks/Stats.vue +20 -39
- package/src/components/Tasks/Task.vue +64 -270
- package/src/components/Tasks/TaskLabel.vue +9 -3
- package/src/components/Tasks/TaskView.vue +45 -64
- package/src/components/Tasks/Utilities.vue +10 -44
- package/src/components/Tasks/ViewTask.vue +23 -107
- package/src/components/icons/Close.vue +2 -8
- package/src/components/icons/Gear.vue +8 -8
- package/src/components/icons/Hash.vue +5 -0
- package/src/components/icons/Key.vue +2 -8
- package/src/components/icons/Pencil.vue +2 -8
- package/src/components/icons/Profile.vue +2 -8
- package/src/components/icons/Sell.vue +2 -8
- package/src/components/icons/Spinner.vue +4 -7
- package/src/components/icons/Wildcard.vue +2 -8
- package/src/components/icons/index.js +3 -5
- package/src/components/ui/ActionButtonGroup.vue +113 -52
- package/src/components/ui/BalanceIndicator.vue +60 -0
- package/src/components/ui/EmptyState.vue +24 -0
- package/src/components/ui/EnableDisableToggle.vue +23 -0
- package/src/components/ui/FormField.vue +49 -49
- package/src/components/ui/IconLabel.vue +23 -0
- package/src/components/ui/InfoRow.vue +21 -54
- package/src/components/ui/Modal.vue +161 -54
- package/src/components/ui/Navbar.vue +63 -44
- package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
- package/src/components/ui/ReconnectIndicator.vue +111 -124
- package/src/components/ui/SectionCard.vue +6 -14
- package/src/components/ui/Splash.vue +2 -10
- package/src/components/ui/StatusBadge.vue +26 -28
- package/src/components/ui/TaskToggle.vue +54 -0
- package/src/components/ui/controls/CountryChooser.vue +29 -66
- package/src/components/ui/controls/EyeToggle.vue +1 -1
- package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
- package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
- package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -120
- package/src/components/ui/controls/atomic/Switch.vue +21 -84
- package/src/composables/useCodeEditor.js +117 -0
- package/src/composables/useColorMapping.js +15 -0
- package/src/composables/useCopyToClipboard.js +1 -1
- package/src/composables/useDateFormatting.js +21 -0
- package/src/composables/useDeviceDetection.js +14 -0
- package/src/composables/useDropdownPosition.js +1 -4
- package/src/composables/useDynamicTableHeight.js +31 -0
- package/src/composables/useEnableDisable.js +6 -0
- package/src/composables/useFilterCSS.js +71 -0
- package/src/composables/useFormValidation.js +92 -0
- package/src/composables/useGetAllTags.js +9 -0
- package/src/composables/useIOSViewportHandling.js +76 -0
- package/src/composables/useNotchHandling.js +306 -0
- package/src/composables/useRowSelection.js +0 -3
- package/src/composables/useTableRender.js +23 -0
- package/src/composables/useTicketPricing.js +16 -0
- package/src/composables/useWindowDimensions.js +21 -0
- package/src/composables/useZoomPrevention.js +96 -0
- package/src/constants/tableLayout.js +14 -0
- package/src/libs/Filter.js +14 -20
- package/src/libs/panzoom.js +1 -5
- package/src/libs/utils/array.js +58 -0
- package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
- package/src/libs/utils/eventUrl.js +40 -0
- package/src/libs/utils/string.js +3 -0
- package/src/libs/utils/time.js +20 -0
- package/src/libs/utils/validation.js +64 -0
- package/src/main.js +0 -2
- package/src/stores/connection.js +1 -29
- package/src/stores/logger.js +6 -12
- package/src/stores/sampleData.js +1 -2
- package/src/stores/ui.js +80 -71
- package/src/utils/tableHelpers.js +1 -0
- package/src/views/Accounts.vue +19 -38
- package/src/views/Console.vue +74 -253
- package/src/views/Editor.vue +47 -1114
- package/src/views/FilterBuilder.vue +190 -461
- package/src/views/Login.vue +3 -28
- package/src/views/Profiles.vue +17 -32
- package/src/views/Tasks.vue +51 -38
- package/tailwind.config.js +82 -71
- package/workbox-config.cjs +47 -5
- package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
- package/exit +0 -209
- package/run +0 -177
- package/src/assets/css/base/color-fallbacks.scss +0 -10
- package/src/assets/img/background.svg.backup +0 -11
- package/src/components/icons/SquareCheck.vue +0 -18
- package/src/components/icons/SquareUncheck.vue +0 -18
- package/src/components/ui/controls/atomic/LoadingButton.vue +0 -45
- package/switch-branch.sh +0 -41
- /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
package/src/views/Editor.vue
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<!-- Heading -->
|
|
4
3
|
<div class="page-header" style="padding-bottom: 1.25rem;">
|
|
5
4
|
<div class="page-header-card">
|
|
6
5
|
<img src="@/assets/img/pencil.svg" />
|
|
@@ -8,203 +7,46 @@
|
|
|
8
7
|
</div>
|
|
9
8
|
</div>
|
|
10
9
|
|
|
11
|
-
<div class="bg-dark-400 border
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
:includeAdjacentButtons="true"
|
|
25
|
-
rightAmount="right-1" />
|
|
26
|
-
</div>
|
|
27
|
-
<button
|
|
28
|
-
class="refresh-button flex items-center justify-center w-10 h-10 text-white bg-dark-400 rounded-r-lg border-2 border-dark-550 border-l-0"
|
|
29
|
-
@click="loadAvailableFiles()"
|
|
30
|
-
title="Refresh file list">
|
|
31
|
-
<ReloadIcon class="refresh-icon" />
|
|
32
|
-
</button>
|
|
33
|
-
</div>
|
|
34
|
-
<!-- Admin editor buttons moved here -->
|
|
35
|
-
<div v-if="textEditorVisible" class="flex gap-1.5 ml-auto">
|
|
36
|
-
<button
|
|
37
|
-
class="button-default bg-dark-400"
|
|
38
|
-
@click="format()"
|
|
39
|
-
v-if="isJsonFile()"
|
|
40
|
-
title="Format JSON">
|
|
41
|
-
<svg
|
|
42
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
43
|
-
width="16"
|
|
44
|
-
height="16"
|
|
45
|
-
viewBox="0 0 24 24"
|
|
46
|
-
fill="none"
|
|
47
|
-
stroke="currentColor"
|
|
48
|
-
stroke-width="2"
|
|
49
|
-
stroke-linecap="round"
|
|
50
|
-
stroke-linejoin="round">
|
|
51
|
-
<path d="M21 10H7" />
|
|
52
|
-
<path d="M21 6H3" />
|
|
53
|
-
<path d="M21 14H3" />
|
|
54
|
-
<path d="M21 18H7" />
|
|
55
|
-
</svg>
|
|
56
|
-
</button>
|
|
57
|
-
<button class="button-default bg-dark-400" @click="saveAll" title="Save File">
|
|
58
|
-
<svg
|
|
59
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
60
|
-
width="16"
|
|
61
|
-
height="16"
|
|
62
|
-
viewBox="0 0 24 24"
|
|
63
|
-
fill="none"
|
|
64
|
-
stroke="currentColor"
|
|
65
|
-
stroke-width="2"
|
|
66
|
-
stroke-linecap="round"
|
|
67
|
-
stroke-linejoin="round">
|
|
68
|
-
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
|
69
|
-
<polyline points="17 21 17 13 7 13 7 21" />
|
|
70
|
-
<polyline points="7 3 7 8 15 8" />
|
|
71
|
-
</svg>
|
|
72
|
-
</button>
|
|
73
|
-
<button class="button-default bg-dark-400" @click="closeFile" title="Close File">
|
|
74
|
-
<svg
|
|
75
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
76
|
-
width="16"
|
|
77
|
-
height="16"
|
|
78
|
-
viewBox="0 0 24 24"
|
|
79
|
-
fill="none"
|
|
80
|
-
stroke="currentColor"
|
|
81
|
-
stroke-width="2"
|
|
82
|
-
stroke-linecap="round"
|
|
83
|
-
stroke-linejoin="round">
|
|
84
|
-
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
85
|
-
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
86
|
-
</svg>
|
|
87
|
-
</button>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
10
|
+
<div class="bg-dark-400 border-2 rounded-lg shadow-sm p-2" style="border-color: var(--color-border);">
|
|
11
|
+
<AdminFileEditor
|
|
12
|
+
v-if="ui.profile.admin"
|
|
13
|
+
:availableFiles="availableFiles"
|
|
14
|
+
:currentFile="currentFile"
|
|
15
|
+
v-model:content="currentContent"
|
|
16
|
+
:isHidden="!!currentProxyList"
|
|
17
|
+
:logger="ui.logger"
|
|
18
|
+
@load-file="loadFile"
|
|
19
|
+
@refresh-files="loadAvailableFiles"
|
|
20
|
+
@save="saveAll"
|
|
21
|
+
@close="closeFile"
|
|
22
|
+
@format="format" />
|
|
90
23
|
|
|
91
|
-
<transition name="fade">
|
|
92
|
-
<div v-if="textEditorVisible" class="my-3 relative">
|
|
93
|
-
<div class="pb-4">
|
|
94
|
-
<!-- Syntax Highlighting Editor -->
|
|
95
|
-
<div class="editor-container" :class="{ 'has-error': errorMessage }">
|
|
96
|
-
<div class="editor-wrapper">
|
|
97
|
-
<pre ref="codeDisplay" class="language-json code-highlight"></pre>
|
|
98
|
-
<textarea
|
|
99
|
-
ref="codeEditor"
|
|
100
|
-
v-model="currentContent"
|
|
101
|
-
class="code-editor"
|
|
102
|
-
spellcheck="false"
|
|
103
|
-
@scroll="syncScroll"
|
|
104
|
-
@input="highlightCode"
|
|
105
|
-
@keydown.tab.prevent="handleTab"></textarea>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
|
|
110
|
-
<div v-if="errorMessage" class="error-container">
|
|
111
|
-
<div class="error-icon">
|
|
112
|
-
<svg
|
|
113
|
-
width="16"
|
|
114
|
-
height="16"
|
|
115
|
-
viewBox="0 0 24 24"
|
|
116
|
-
fill="none"
|
|
117
|
-
stroke="currentColor"
|
|
118
|
-
stroke-width="2">
|
|
119
|
-
<circle cx="12" cy="12" r="10" />
|
|
120
|
-
<line x1="15" y1="9" x2="9" y2="15" />
|
|
121
|
-
<line x1="9" y1="9" x2="15" y2="15" />
|
|
122
|
-
</svg>
|
|
123
|
-
</div>
|
|
124
|
-
<div class="error-content">
|
|
125
|
-
<div class="error-title">JSON Syntax Error</div>
|
|
126
|
-
<div class="error-text">{{ errorMessage }}</div>
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
129
|
-
</div>
|
|
130
|
-
</transition>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
<!-- Section Divider - Show when both editors are closed -->
|
|
134
24
|
<div v-if="ui.profile.admin && !textEditorVisible && !currentProxyList" class="section-divider" />
|
|
135
25
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
:onClick="loadProxies"
|
|
146
|
-
:options="proxyLists"
|
|
147
|
-
:allowDefault="false"
|
|
148
|
-
:includeAdjacentButtons="true"
|
|
149
|
-
rightAmount="right-1" />
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
<!-- Proxy save button moved here -->
|
|
153
|
-
<div v-if="currentProxyList" class="flex gap-1.5 ml-auto">
|
|
154
|
-
<button class="button-default bg-dark-400" @click="saveProxies" title="Save Proxies">
|
|
155
|
-
<svg
|
|
156
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
157
|
-
width="16"
|
|
158
|
-
height="16"
|
|
159
|
-
viewBox="0 0 24 24"
|
|
160
|
-
fill="none"
|
|
161
|
-
stroke="currentColor"
|
|
162
|
-
stroke-width="2"
|
|
163
|
-
stroke-linecap="round"
|
|
164
|
-
stroke-linejoin="round">
|
|
165
|
-
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
|
166
|
-
<polyline points="17 21 17 13 7 13 7 21" />
|
|
167
|
-
<polyline points="7 3 7 8 15 8" />
|
|
168
|
-
</svg>
|
|
169
|
-
</button>
|
|
170
|
-
<button class="button-default bg-dark-400" @click="closeProxyFile" title="Close File">
|
|
171
|
-
<svg
|
|
172
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
173
|
-
width="16"
|
|
174
|
-
height="16"
|
|
175
|
-
viewBox="0 0 24 24"
|
|
176
|
-
fill="none"
|
|
177
|
-
stroke="currentColor"
|
|
178
|
-
stroke-width="2"
|
|
179
|
-
stroke-linecap="round"
|
|
180
|
-
stroke-linejoin="round">
|
|
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
|
-
</button>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
<!-- Textarea -->
|
|
188
|
-
<transition name="fade">
|
|
189
|
-
<div v-if="currentProxyList" class="relative my-3">
|
|
190
|
-
<div class="pb-4">
|
|
191
|
-
<div class="proxy-editor-container table-component">
|
|
192
|
-
<textarea v-model="proxyContent" class="proxy-editor" spellcheck="false"></textarea>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
</transition>
|
|
197
|
-
</div>
|
|
26
|
+
<ProxyFileEditor
|
|
27
|
+
:proxyLists="proxyLists"
|
|
28
|
+
:currentProxyList="currentProxyList"
|
|
29
|
+
v-model:proxyContent="proxyContent"
|
|
30
|
+
:defaultProxyList="ui.profile.proxyList?.checkout || proxyLists[0]"
|
|
31
|
+
:isHidden="textEditorVisible"
|
|
32
|
+
@load-proxies="loadProxies"
|
|
33
|
+
@save-proxies="saveProxies"
|
|
34
|
+
@close-proxy="closeProxyFile" />
|
|
198
35
|
</div>
|
|
199
36
|
</div>
|
|
200
37
|
</template>
|
|
38
|
+
|
|
201
39
|
<script setup>
|
|
202
|
-
import { ref
|
|
203
|
-
import { DownIcon, ReloadIcon, EditIcon } from "@/components/icons";
|
|
40
|
+
import { ref } from "vue";
|
|
204
41
|
import { useUIStore } from "@/stores/ui";
|
|
205
|
-
import
|
|
206
|
-
import { getProxyLists, getProxyFile } from "@/stores/requests";
|
|
42
|
+
import { getProxyLists, getProxyFile, getQuickConfig, sendQuickConfig } from "@/stores/requests";
|
|
207
43
|
import { DEBUG } from "@/utils/debug";
|
|
44
|
+
import { useCodeEditor } from "@/composables/useCodeEditor";
|
|
45
|
+
import AdminFileEditor from "@/components/Editors/AdminFileEditor.vue";
|
|
46
|
+
import ProxyFileEditor from "@/components/Editors/ProxyFileEditor.vue";
|
|
47
|
+
|
|
48
|
+
const ui = useUIStore();
|
|
49
|
+
const { formatJSON } = useCodeEditor(ui.logger);
|
|
208
50
|
|
|
209
51
|
const loadFromApi = async (path) => {
|
|
210
52
|
const res = await fetch(path);
|
|
@@ -213,158 +55,29 @@ const loadFromApi = async (path) => {
|
|
|
213
55
|
|
|
214
56
|
const availableFiles = ref([]);
|
|
215
57
|
if (DEBUG) availableFiles.value.push("used-codes.json", "proxies.txt", "toMonitor.txt", "test.txt");
|
|
58
|
+
|
|
216
59
|
const currentFile = ref("");
|
|
217
60
|
const textEditorVisible = ref(false);
|
|
218
61
|
const currentContent = ref("");
|
|
219
62
|
const proxyContent = ref("");
|
|
220
63
|
const proxyLists = ref(["loading..."]);
|
|
221
64
|
const currentProxyList = ref("");
|
|
222
|
-
const activeModal = computed(() => ui.activeModal);
|
|
223
|
-
const ui = useUIStore();
|
|
224
|
-
|
|
225
|
-
// References to editor elements
|
|
226
|
-
const codeEditor = ref(null);
|
|
227
|
-
const codeDisplay = ref(null);
|
|
228
65
|
|
|
229
66
|
let previous = {
|
|
230
67
|
proxyContent: { list: ui.profile.proxyList, content: "" },
|
|
231
68
|
currentContent: { file: "", content: "" }
|
|
232
69
|
};
|
|
233
70
|
|
|
234
|
-
const errorMessage = computed(() => {
|
|
235
|
-
if (!currentFile.value.endsWith(".json")) return;
|
|
236
|
-
|
|
237
|
-
let err;
|
|
238
|
-
try {
|
|
239
|
-
JSON.parse(currentContent.value);
|
|
240
|
-
} catch (e) {
|
|
241
|
-
err = e;
|
|
242
|
-
}
|
|
243
|
-
return err?.message;
|
|
244
|
-
});
|
|
245
|
-
|
|
246
71
|
const loadAvailableFiles = async () => (availableFiles.value = await loadFromApi("/api/json-files"));
|
|
247
72
|
|
|
248
73
|
const isJsonFile = () => currentFile.value.endsWith(".json");
|
|
249
74
|
|
|
250
|
-
// Function to highlight code using Prism
|
|
251
|
-
const highlightCode = () => {
|
|
252
|
-
if (!codeDisplay.value || !codeEditor.value) return;
|
|
253
|
-
|
|
254
|
-
// Get the language based on file extension
|
|
255
|
-
let language = "javascript"; // Default language
|
|
256
|
-
|
|
257
|
-
if (currentFile.value) {
|
|
258
|
-
if (currentFile.value.endsWith(".json")) {
|
|
259
|
-
language = "json";
|
|
260
|
-
} else if (currentFile.value.endsWith(".js")) {
|
|
261
|
-
language = "javascript";
|
|
262
|
-
} else if (currentFile.value.endsWith(".txt") || currentFile.value.endsWith(".csv")) {
|
|
263
|
-
language = "text";
|
|
264
|
-
// Plain text doesn't need highlighting
|
|
265
|
-
codeDisplay.value.textContent = currentContent.value || "";
|
|
266
|
-
codeDisplay.value.className = "language-text code-highlight";
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Ensure Prism is available
|
|
272
|
-
if (typeof Prism === "undefined") {
|
|
273
|
-
console.error("Prism is not loaded");
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Use requestAnimationFrame for smoother updates
|
|
278
|
-
requestAnimationFrame(() => {
|
|
279
|
-
try {
|
|
280
|
-
// Update the pre element with highlighted HTML
|
|
281
|
-
const highlighted = Prism.highlight(currentContent.value || "", Prism.languages[language], language);
|
|
282
|
-
codeDisplay.value.innerHTML = highlighted;
|
|
283
|
-
codeDisplay.value.className = `language-${language} code-highlight`;
|
|
284
|
-
} catch (e) {
|
|
285
|
-
console.error("Highlight error:", e);
|
|
286
|
-
// Fallback to plain text if highlighting fails
|
|
287
|
-
codeDisplay.value.textContent = currentContent.value || "";
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Ensure scroll positions are synced after highlighting
|
|
291
|
-
syncScroll();
|
|
292
|
-
});
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
// Function to sync scrolling between textarea and highlighted code
|
|
296
|
-
const syncScroll = () => {
|
|
297
|
-
if (!codeDisplay.value || !codeEditor.value) return;
|
|
298
|
-
|
|
299
|
-
// Synchronize scrolling between the textarea and the highlighted code
|
|
300
|
-
requestAnimationFrame(() => {
|
|
301
|
-
codeDisplay.value.scrollTop = codeEditor.value.scrollTop;
|
|
302
|
-
codeDisplay.value.scrollLeft = codeEditor.value.scrollLeft;
|
|
303
|
-
});
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
// Function to handle tab key press in the editor
|
|
307
|
-
const handleTab = (e) => {
|
|
308
|
-
const textarea = codeEditor.value;
|
|
309
|
-
const start = textarea.selectionStart;
|
|
310
|
-
const end = textarea.selectionEnd;
|
|
311
|
-
|
|
312
|
-
// Insert 4 spaces at cursor position
|
|
313
|
-
const spaces = " ";
|
|
314
|
-
currentContent.value = currentContent.value.substring(0, start) + spaces + currentContent.value.substring(end);
|
|
315
|
-
|
|
316
|
-
// Move cursor position after the inserted tab
|
|
317
|
-
nextTick(() => {
|
|
318
|
-
textarea.selectionStart = textarea.selectionEnd = start + spaces.length;
|
|
319
|
-
highlightCode();
|
|
320
|
-
});
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const format = () => {
|
|
324
|
-
try {
|
|
325
|
-
if (!isJsonFile()) return;
|
|
326
|
-
|
|
327
|
-
const formatted = JSON.stringify(JSON.parse(currentContent.value), null, 4);
|
|
328
|
-
currentContent.value = formatted;
|
|
329
|
-
|
|
330
|
-
// Apply syntax highlighting after formatting
|
|
331
|
-
nextTick(() => {
|
|
332
|
-
highlightCode();
|
|
333
|
-
});
|
|
334
|
-
} catch (e) {
|
|
335
|
-
ui.logger.Error("Could not format JSON", e);
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
|
|
339
|
-
// Watch for content changes to apply syntax highlighting
|
|
340
|
-
watch(currentContent, () => {
|
|
341
|
-
nextTick(() => {
|
|
342
|
-
highlightCode();
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
|
|
346
75
|
const loadFile = async (f) => {
|
|
347
76
|
currentFile.value = f;
|
|
348
77
|
if (DEBUG) {
|
|
349
78
|
textEditorVisible.value = true;
|
|
350
79
|
currentProxyList.value = "";
|
|
351
80
|
currentContent.value = new Array(100).fill(0, 0, 100).join("\n");
|
|
352
|
-
|
|
353
|
-
// Update pre element class based on file type
|
|
354
|
-
if (codeDisplay.value) {
|
|
355
|
-
if (f.endsWith(".json")) {
|
|
356
|
-
codeDisplay.value.className = "language-json";
|
|
357
|
-
} else if (f.endsWith(".js")) {
|
|
358
|
-
codeDisplay.value.className = "language-javascript";
|
|
359
|
-
} else {
|
|
360
|
-
codeDisplay.value.className = "language-text";
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Apply syntax highlighting after content is set
|
|
365
|
-
nextTick(() => {
|
|
366
|
-
highlightCode();
|
|
367
|
-
});
|
|
368
81
|
return;
|
|
369
82
|
}
|
|
370
83
|
|
|
@@ -374,22 +87,6 @@ const loadFile = async (f) => {
|
|
|
374
87
|
currentProxyList.value = "";
|
|
375
88
|
currentContent.value = text;
|
|
376
89
|
previous.currentContent = { file: currentFile.value, content: text };
|
|
377
|
-
|
|
378
|
-
// Update pre element class based on file type
|
|
379
|
-
if (codeDisplay.value) {
|
|
380
|
-
if (f.endsWith(".json")) {
|
|
381
|
-
codeDisplay.value.className = "language-json";
|
|
382
|
-
} else if (f.endsWith(".js")) {
|
|
383
|
-
codeDisplay.value.className = "language-javascript";
|
|
384
|
-
} else {
|
|
385
|
-
codeDisplay.value.className = "language-text";
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Apply syntax highlighting after content is loaded
|
|
390
|
-
nextTick(() => {
|
|
391
|
-
highlightCode();
|
|
392
|
-
});
|
|
393
90
|
};
|
|
394
91
|
|
|
395
92
|
const saveDataToAPI = async (data, endpoint, msg, json = true) => {
|
|
@@ -405,7 +102,7 @@ const saveDataToAPI = async (data, endpoint, msg, json = true) => {
|
|
|
405
102
|
if (json) {
|
|
406
103
|
try {
|
|
407
104
|
j = await res.json();
|
|
408
|
-
} catch
|
|
105
|
+
} catch {
|
|
409
106
|
ui.showError("Error saving proxies");
|
|
410
107
|
return;
|
|
411
108
|
}
|
|
@@ -413,7 +110,7 @@ const saveDataToAPI = async (data, endpoint, msg, json = true) => {
|
|
|
413
110
|
} else {
|
|
414
111
|
try {
|
|
415
112
|
j = await res.text();
|
|
416
|
-
} catch
|
|
113
|
+
} catch {
|
|
417
114
|
ui.showError("Error saving proxies");
|
|
418
115
|
return;
|
|
419
116
|
}
|
|
@@ -434,12 +131,21 @@ const saveFile = async () => {
|
|
|
434
131
|
};
|
|
435
132
|
};
|
|
436
133
|
|
|
134
|
+
const saveQuickConfig = async () => {
|
|
135
|
+
const content = await getQuickConfig();
|
|
136
|
+
await sendQuickConfig(content);
|
|
137
|
+
};
|
|
138
|
+
|
|
437
139
|
const saveAll = async () => {
|
|
438
140
|
if (DEBUG) return;
|
|
439
141
|
if (currentFile.value && currentContent.value) await saveFile();
|
|
440
142
|
await saveQuickConfig();
|
|
441
143
|
};
|
|
442
144
|
|
|
145
|
+
const format = () => {
|
|
146
|
+
formatJSON(ref(currentContent), currentFile.value, () => {});
|
|
147
|
+
};
|
|
148
|
+
|
|
443
149
|
const closeFile = () => {
|
|
444
150
|
currentFile.value = "";
|
|
445
151
|
currentContent.value = "";
|
|
@@ -474,7 +180,6 @@ const loadProxies = async (list) => {
|
|
|
474
180
|
};
|
|
475
181
|
|
|
476
182
|
const saveProxies = async () => {
|
|
477
|
-
// if (!DEBUG) return;
|
|
478
183
|
if (previous.proxyContent.content === proxyContent.value) ui.logger.Info("proxies did not change");
|
|
479
184
|
else {
|
|
480
185
|
await saveDataToAPI(
|
|
@@ -494,790 +199,18 @@ const loadProxyLists = async () => {
|
|
|
494
199
|
else ui.showError("Could not load proxylists");
|
|
495
200
|
};
|
|
496
201
|
|
|
497
|
-
// Initialize syntax highlighting
|
|
498
|
-
onMounted(() => {
|
|
499
|
-
// Apply highlighting when the component is mounted
|
|
500
|
-
nextTick(() => {
|
|
501
|
-
highlightCode();
|
|
502
|
-
|
|
503
|
-
// Ensure scroll synchronization on initial load
|
|
504
|
-
if (codeEditor.value && codeDisplay.value) {
|
|
505
|
-
syncScroll();
|
|
506
|
-
}
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
// iOS-specific editor fixes with cursor tracking
|
|
510
|
-
if (
|
|
511
|
-
/iPad|iPhone|iPod/.test(navigator.platform) ||
|
|
512
|
-
(navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform))
|
|
513
|
-
) {
|
|
514
|
-
const trackCursor = (editor) => {
|
|
515
|
-
const scrollToCursor = () => {
|
|
516
|
-
setTimeout(() => {
|
|
517
|
-
const container = editor.closest(".editor-container") || editor.closest(".proxy-editor-container");
|
|
518
|
-
if (container) {
|
|
519
|
-
// Get cursor position and scroll to it
|
|
520
|
-
const lines = editor.value.substring(0, editor.selectionStart).split("\n");
|
|
521
|
-
const lineHeight = 24; // Approximate line height
|
|
522
|
-
const cursorY = lines.length * lineHeight;
|
|
523
|
-
const containerHeight = container.clientHeight;
|
|
524
|
-
|
|
525
|
-
// Scroll to keep cursor in view
|
|
526
|
-
if (cursorY > container.scrollTop + containerHeight - 60) {
|
|
527
|
-
container.scrollTop = cursorY - containerHeight + 60;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}, 100);
|
|
531
|
-
};
|
|
532
|
-
|
|
533
|
-
editor.addEventListener("focus", scrollToCursor);
|
|
534
|
-
editor.addEventListener("input", scrollToCursor);
|
|
535
|
-
editor.addEventListener("click", scrollToCursor);
|
|
536
|
-
editor.addEventListener("keyup", scrollToCursor);
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
nextTick(() => {
|
|
540
|
-
if (codeEditor.value) {
|
|
541
|
-
trackCursor(codeEditor.value);
|
|
542
|
-
}
|
|
543
|
-
const proxyEditor = document.querySelector(".proxy-editor");
|
|
544
|
-
if (proxyEditor) {
|
|
545
|
-
trackCursor(proxyEditor);
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Watch for editor visibility changes
|
|
551
|
-
watch(textEditorVisible, (newValue) => {
|
|
552
|
-
if (newValue) {
|
|
553
|
-
nextTick(() => {
|
|
554
|
-
highlightCode();
|
|
555
|
-
|
|
556
|
-
// Focus the editor when it becomes visible
|
|
557
|
-
if (codeEditor.value) {
|
|
558
|
-
codeEditor.value.focus();
|
|
559
|
-
}
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
// No cleanup needed - global iOS handling takes care of everything
|
|
566
|
-
|
|
567
202
|
if (ui.profile.admin && !DEBUG) loadAvailableFiles();
|
|
568
203
|
loadProxyLists();
|
|
569
204
|
</script>
|
|
570
|
-
<style lang="scss" scoped>
|
|
571
|
-
/* ==========================================================================
|
|
572
|
-
Z-INDEX MANAGEMENT
|
|
573
|
-
========================================================================== */
|
|
574
|
-
|
|
575
|
-
.z-dropdown-high {
|
|
576
|
-
position: relative;
|
|
577
|
-
z-index: 200;
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
.z-dropdown-high .dropdown-menu,
|
|
581
|
-
.z-dropdown-high .option-list {
|
|
582
|
-
z-index: 250;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
.z-dropdown {
|
|
586
|
-
position: relative;
|
|
587
|
-
z-index: 100;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
.z-dropdown .dropdown-menu,
|
|
591
|
-
.z-dropdown .option-list {
|
|
592
|
-
z-index: 150;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
/* ==========================================================================
|
|
596
|
-
ADMIN EDITOR SECTION CONDITIONAL VISIBILITY
|
|
597
|
-
========================================================================== */
|
|
598
|
-
|
|
599
|
-
/* Hide admin editor when proxy editor is open - ALL SCREEN SIZES */
|
|
600
|
-
.admin-editor-section.landscape-hidden {
|
|
601
|
-
display: none !important;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/* ==========================================================================
|
|
605
|
-
PROXY EDITOR SECTION CONDITIONAL VISIBILITY
|
|
606
|
-
========================================================================== */
|
|
607
|
-
|
|
608
|
-
/* Hide proxy editor when admin editor is open - ALL SCREEN SIZES */
|
|
609
|
-
.proxy-editor-section.landscape-hidden {
|
|
610
|
-
display: none !important;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
/* ==========================================================================
|
|
614
|
-
SECTION HEADERS
|
|
615
|
-
========================================================================== */
|
|
616
|
-
|
|
617
|
-
/* ==========================================================================
|
|
618
|
-
ADMIN FILE DROPDOWN STYLING
|
|
619
|
-
========================================================================== */
|
|
620
|
-
|
|
621
|
-
.admin-file-dropdown {
|
|
622
|
-
height: 2.5rem !important;
|
|
623
|
-
border-top-right-radius: 0 !important;
|
|
624
|
-
border-bottom-right-radius: 0 !important;
|
|
625
|
-
border-top-left-radius: 0.5rem !important;
|
|
626
|
-
border-bottom-left-radius: 0.5rem !important;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
.proxy-file-dropdown {
|
|
630
|
-
height: 2.5rem !important;
|
|
631
|
-
border-radius: 0.5rem !important;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
.refresh-button {
|
|
635
|
-
height: 2.5rem !important;
|
|
636
|
-
transition: all 0.2s ease;
|
|
637
|
-
|
|
638
|
-
&:hover {
|
|
639
|
-
.refresh-icon {
|
|
640
|
-
transform: rotate(180deg);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
.refresh-icon {
|
|
646
|
-
transition: transform 0.5s ease;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/* ==========================================================================
|
|
650
|
-
EDITOR CONTAINERS
|
|
651
|
-
========================================================================== */
|
|
652
|
-
|
|
653
|
-
.editor-container,
|
|
654
|
-
.proxy-editor-container {
|
|
655
|
-
position: relative;
|
|
656
|
-
overflow: hidden;
|
|
657
|
-
height: 400px;
|
|
658
|
-
max-height: 60vh;
|
|
659
|
-
border-radius: 8px;
|
|
660
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
|
661
|
-
background-color: oklch(0.19 0 0);
|
|
662
|
-
transition: height 0.3s ease;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
.proxy-editor-container {
|
|
666
|
-
/* Ensure proxy editor takes full container space */
|
|
667
|
-
display: flex;
|
|
668
|
-
flex-direction: column;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
.proxy-editor-container .pb-4 {
|
|
672
|
-
/* Remove bottom padding to maximize space */
|
|
673
|
-
padding-bottom: 0 !important;
|
|
674
|
-
flex: 1;
|
|
675
|
-
display: flex;
|
|
676
|
-
flex-direction: column;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
.proxy-editor-container .table-component {
|
|
680
|
-
/* Make proxy editor container take full height */
|
|
681
|
-
flex: 1;
|
|
682
|
-
display: flex;
|
|
683
|
-
flex-direction: column;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
.editor-wrapper {
|
|
687
|
-
position: relative;
|
|
688
|
-
width: 100%;
|
|
689
|
-
height: 100%;
|
|
690
|
-
overflow: hidden;
|
|
691
|
-
border-radius: 8px;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
/* ==========================================================================
|
|
695
|
-
EDITOR TEXTAREAS
|
|
696
|
-
========================================================================== */
|
|
697
|
-
|
|
698
|
-
.code-editor,
|
|
699
|
-
.proxy-editor {
|
|
700
|
-
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
701
|
-
font-size: 14px;
|
|
702
|
-
line-height: 1.6;
|
|
703
|
-
tab-size: 4;
|
|
704
|
-
background-color: transparent;
|
|
705
|
-
border: none;
|
|
706
|
-
outline: none;
|
|
707
|
-
resize: none;
|
|
708
|
-
width: 100%;
|
|
709
|
-
height: 100%;
|
|
710
|
-
overflow: auto;
|
|
711
|
-
-webkit-overflow-scrolling: touch;
|
|
712
|
-
padding: 12px;
|
|
713
|
-
margin: 0;
|
|
714
|
-
box-sizing: border-box;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
.code-editor {
|
|
718
|
-
/* Make textarea text transparent so syntax highlighting shows through */
|
|
719
|
-
color: transparent !important;
|
|
720
|
-
z-index: 2;
|
|
721
|
-
position: relative;
|
|
722
|
-
caret-color: #ffffff; /* Keep cursor visible */
|
|
723
|
-
|
|
724
|
-
/* Selection styling */
|
|
725
|
-
&::selection {
|
|
726
|
-
background-color: rgba(255, 255, 255, 0.2);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
.proxy-editor {
|
|
731
|
-
@apply w-full h-full resize-none focus:outline-none;
|
|
732
|
-
color: oklch(0.90 0 0); /* Keep normal text color for proxy editor */
|
|
733
|
-
/* Ensure proxy editor takes full height */
|
|
734
|
-
flex: 1;
|
|
735
|
-
min-height: 100%;
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/* ==========================================================================
|
|
739
|
-
CODE HIGHLIGHTING
|
|
740
|
-
========================================================================== */
|
|
741
|
-
|
|
742
|
-
.code-highlight {
|
|
743
|
-
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
744
|
-
font-size: 14px;
|
|
745
|
-
line-height: 1.6;
|
|
746
|
-
tab-size: 4;
|
|
747
|
-
/* Remove transparent color - let syntax highlighting show */
|
|
748
|
-
color: #f8f8f2 !important;
|
|
749
|
-
background: transparent;
|
|
750
|
-
border: none;
|
|
751
|
-
outline: none;
|
|
752
|
-
resize: none;
|
|
753
|
-
width: 100%;
|
|
754
|
-
height: 100%;
|
|
755
|
-
overflow: hidden;
|
|
756
|
-
white-space: pre;
|
|
757
|
-
pointer-events: none;
|
|
758
|
-
z-index: 1;
|
|
759
|
-
position: absolute;
|
|
760
|
-
top: 0;
|
|
761
|
-
left: 0;
|
|
762
|
-
padding: 12px;
|
|
763
|
-
margin: 0;
|
|
764
|
-
box-sizing: border-box;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/* ==========================================================================
|
|
768
|
-
PRISM.JS SYNTAX HIGHLIGHTING THEME
|
|
769
|
-
========================================================================== */
|
|
770
|
-
|
|
771
|
-
code[class*="language-"],
|
|
772
|
-
pre[class*="language-"] {
|
|
773
|
-
color: #f8f8f2;
|
|
774
|
-
background: none;
|
|
775
|
-
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
|
|
776
|
-
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
|
777
|
-
text-align: left;
|
|
778
|
-
white-space: pre;
|
|
779
|
-
word-spacing: normal;
|
|
780
|
-
word-break: normal;
|
|
781
|
-
word-wrap: normal;
|
|
782
|
-
line-height: 1.5;
|
|
783
|
-
tab-size: 4;
|
|
784
|
-
hyphens: none;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
pre[class*="language-"] {
|
|
788
|
-
padding: 12px;
|
|
789
|
-
margin: 0;
|
|
790
|
-
overflow: auto;
|
|
791
|
-
border-radius: 4px;
|
|
792
|
-
font-family: "Menlo", "Monaco", "Courier New", monospace;
|
|
793
|
-
font-size: 14px;
|
|
794
|
-
line-height: 1.5;
|
|
795
|
-
tab-size: 4;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
:not(pre) > code[class*="language-"],
|
|
799
|
-
pre[class*="language-"] {
|
|
800
|
-
background: oklch(0.19 0 0);
|
|
801
|
-
white-space: pre;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
:not(pre) > code[class*="language-"] {
|
|
805
|
-
padding: 0.1em;
|
|
806
|
-
border-radius: 0.3em;
|
|
807
|
-
white-space: normal;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
.token.comment,
|
|
811
|
-
.token.prolog,
|
|
812
|
-
.token.doctype,
|
|
813
|
-
.token.cdata {
|
|
814
|
-
color: #676f7d;
|
|
815
|
-
font-style: italic;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
.token.punctuation {
|
|
819
|
-
color: #a9b7c6;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
.namespace {
|
|
823
|
-
opacity: 0.8;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
.token.property,
|
|
827
|
-
.token.tag,
|
|
828
|
-
.token.constant,
|
|
829
|
-
.token.symbol,
|
|
830
|
-
.token.deleted {
|
|
831
|
-
color: #e06c75;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
.token.boolean,
|
|
835
|
-
.token.number {
|
|
836
|
-
color: #c792ea;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
.token.selector,
|
|
840
|
-
.token.attr-name,
|
|
841
|
-
.token.string,
|
|
842
|
-
.token.char,
|
|
843
|
-
.token.builtin,
|
|
844
|
-
.token.inserted {
|
|
845
|
-
color: #98c379;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
.token.operator,
|
|
849
|
-
.token.entity,
|
|
850
|
-
.token.url,
|
|
851
|
-
.language-css .token.string,
|
|
852
|
-
.style .token.string {
|
|
853
|
-
color: #89ddff;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
.token.atrule,
|
|
857
|
-
.token.attr-value,
|
|
858
|
-
.token.keyword {
|
|
859
|
-
color: #61afef;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
.token.function,
|
|
863
|
-
.token.class-name {
|
|
864
|
-
color: #ffcb6b;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
.token.regex,
|
|
868
|
-
.token.important,
|
|
869
|
-
.token.variable {
|
|
870
|
-
color: #c5e478;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
.token.important,
|
|
874
|
-
.token.bold {
|
|
875
|
-
font-weight: bold;
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
.token.italic {
|
|
879
|
-
font-style: italic;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
.token.entity {
|
|
883
|
-
cursor: help;
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
.editor-container:hover {
|
|
887
|
-
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
|
888
|
-
transition: box-shadow 0.3s ease;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
/* ==========================================================================
|
|
892
|
-
ERROR MESSAGES
|
|
893
|
-
========================================================================== */
|
|
894
|
-
|
|
895
|
-
.error-container {
|
|
896
|
-
@apply flex items-start gap-3 p-4 bg-red-500/10 border border-red-500/20 rounded-lg mt-4 mb-4;
|
|
897
|
-
|
|
898
|
-
/* Prevent overflow in landscape mode */
|
|
899
|
-
max-width: 100%;
|
|
900
|
-
word-wrap: break-word;
|
|
901
|
-
overflow-wrap: break-word;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
.error-icon {
|
|
905
|
-
@apply flex-shrink-0 text-red-400;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
.error-content {
|
|
909
|
-
@apply flex-1;
|
|
910
|
-
min-width: 0; /* Allow text to shrink */
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
.error-title {
|
|
914
|
-
@apply text-red-400 font-medium text-sm mb-1;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
.error-text {
|
|
918
|
-
@apply text-red-300 text-xs;
|
|
919
|
-
word-break: break-word;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
/* ==========================================================================
|
|
923
|
-
SECTION DIVIDER
|
|
924
|
-
========================================================================== */
|
|
925
205
|
|
|
206
|
+
<style lang="scss" scoped>
|
|
926
207
|
.section-divider {
|
|
927
|
-
|
|
928
|
-
height: 1px;
|
|
929
|
-
width: 100%;
|
|
930
|
-
position: relative;
|
|
931
|
-
|
|
932
|
-
/* Add subtle gradient effect for better visual separation */
|
|
933
|
-
background: linear-gradient(90deg, transparent 0%, oklch(0.26 0 0) 20%, oklch(0.26 0 0) 80%, transparent 100%);
|
|
934
|
-
border: none;
|
|
935
|
-
|
|
936
|
-
/* Add a subtle glow effect */
|
|
937
|
-
box-shadow: 0 0 8px rgba(61, 62, 68, 0.3);
|
|
208
|
+
@apply my-8 h-px w-full bg-dark-550;
|
|
938
209
|
}
|
|
939
210
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
========================================================================== */
|
|
943
|
-
|
|
944
|
-
.flex-responsive-wrap {
|
|
945
|
-
@apply flex flex-wrap items-center gap-4;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
/* ==========================================================================
|
|
950
|
-
MOBILE RESPONSIVE STYLES (max-width: 767px)
|
|
951
|
-
========================================================================== */
|
|
952
|
-
|
|
953
|
-
@media (max-width: 767px) {
|
|
954
|
-
/* Layout adjustments - almost no gap between dropdown and buttons */
|
|
955
|
-
.flex-responsive-wrap {
|
|
956
|
-
@apply flex-col items-stretch !important;
|
|
957
|
-
gap: 0px !important; /* Reduced from 2px to eliminate space between dropdown and buttons */
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
/* Button container - even spacing across full width */
|
|
961
|
-
.flex-responsive-wrap > div:last-child {
|
|
962
|
-
@apply flex justify-center !important;
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
/* Editor container heights - fill available space on mobile */
|
|
966
|
-
.editor-container,
|
|
967
|
-
.proxy-editor-container {
|
|
968
|
-
height: calc(100vh - 380px) !important; /* Fill viewport minus header/controls */
|
|
969
|
-
max-height: 60vh !important; /* Allow more height */
|
|
970
|
-
min-height: 300px !important; /* Ensure minimum usable height */
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
/* Reduce editor height when JSON error is showing in portrait */
|
|
974
|
-
.editor-container.has-error {
|
|
975
|
-
height: calc(100vh - 460px) !important; /* Account for error message */
|
|
976
|
-
max-height: 50vh !important;
|
|
977
|
-
min-height: 250px !important;
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
/* Error message spacing on mobile */
|
|
981
|
-
.error-container {
|
|
982
|
-
margin: 8px 0 !important;
|
|
983
|
-
padding: 8px !important;
|
|
984
|
-
font-size: 11px !important;
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
.error-title {
|
|
988
|
-
font-size: 11px !important;
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
.error-text {
|
|
992
|
-
font-size: 10px !important;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
/* Compact editor controls spacing - no margins */
|
|
996
|
-
.editor-controls-row,
|
|
997
|
-
.proxy-controls-row {
|
|
998
|
-
margin-bottom: 0px !important; /* Eliminated margin completely */
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
/* Compact editor containers - reduced margins for more space */
|
|
1002
|
-
.my-3 {
|
|
1003
|
-
margin: 6px 0 !important; /* Reduced margin between editor and controls */
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
.pb-4 {
|
|
1007
|
-
padding-bottom: 4px !important; /* Reduced padding */
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
/* ==========================================================================
|
|
1012
|
-
TABLET RESPONSIVE STYLES (min-width: 768px)
|
|
1013
|
-
========================================================================== */
|
|
1014
|
-
|
|
1015
|
-
@media (min-width: 768px) {
|
|
1016
|
-
.flex-responsive-wrap {
|
|
1017
|
-
@apply flex-row justify-between items-center !important;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
/* ==========================================================================
|
|
1022
|
-
DESKTOP RESPONSIVE STYLES (min-width: 1024px)
|
|
1023
|
-
========================================================================== */
|
|
1024
|
-
|
|
1025
|
-
@media (min-width: 1024px) {
|
|
1026
|
-
.editor-container,
|
|
1027
|
-
.proxy-editor-container {
|
|
1028
|
-
max-height: 60vh;
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
/* ==========================================================================
|
|
1033
|
-
LARGE DESKTOP RESPONSIVE STYLES (min-width: 1280px)
|
|
1034
|
-
========================================================================== */
|
|
1035
|
-
|
|
1036
|
-
@media (min-width: 1280px) {
|
|
1037
|
-
.editor-container,
|
|
1038
|
-
.proxy-editor-container {
|
|
1039
|
-
max-height: 70vh;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
/* ==========================================================================
|
|
1044
|
-
MOBILE LANDSCAPE MODE (max-height: 500px + landscape)
|
|
1045
|
-
========================================================================== */
|
|
1046
|
-
|
|
1047
|
-
@media (max-height: 500px) and (orientation: landscape) and (min-width: 568px) {
|
|
1048
|
-
/* Truncate card cleanly when admin editor is open */
|
|
1049
|
-
.admin-editor-section:not(.landscape-hidden) + .section-divider + .proxy-editor-section.landscape-hidden {
|
|
211
|
+
.landscape-hidden {
|
|
212
|
+
@media (max-width: 1023px) and (orientation: landscape) {
|
|
1050
213
|
display: none !important;
|
|
1051
214
|
}
|
|
1052
|
-
|
|
1053
|
-
/* Ensure proxy editor takes full space when visible */
|
|
1054
|
-
.proxy-editor-container {
|
|
1055
|
-
height: 130px !important;
|
|
1056
|
-
max-height: 130px !important;
|
|
1057
|
-
min-height: 100px !important;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
.proxy-editor {
|
|
1061
|
-
height: 100% !important;
|
|
1062
|
-
min-height: 100% !important;
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
/* Compact headings */
|
|
1066
|
-
h4 {
|
|
1067
|
-
font-size: 16px !important;
|
|
1068
|
-
margin-bottom: 6px !important;
|
|
1069
|
-
padding-top: 1rem !important;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
h5 {
|
|
1073
|
-
font-size: 14px !important;
|
|
1074
|
-
margin-bottom: 4px !important;
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
/* Section divider */
|
|
1078
|
-
.section-divider {
|
|
1079
|
-
margin: 6px 0 !important;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
/* Editor controls layout */
|
|
1083
|
-
.editor-controls-row,
|
|
1084
|
-
.proxy-controls-row {
|
|
1085
|
-
gap: 6px !important;
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
/* Hide button text to save space in landscape mode */
|
|
1089
|
-
.button-default span {
|
|
1090
|
-
display: none !important;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
/* Compact editor containers - reduced margins for more space */
|
|
1094
|
-
.my-3 {
|
|
1095
|
-
margin: 4px 0 !important; /* Reduced from 6px */
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
.pb-4 {
|
|
1099
|
-
padding-bottom: 2px !important; /* Reduced from 4px */
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
/* Editor container heights - increased to use more available space */
|
|
1103
|
-
.editor-container,
|
|
1104
|
-
.proxy-editor-container {
|
|
1105
|
-
height: 180px !important; /* Increased from 130px */
|
|
1106
|
-
max-height: 180px !important;
|
|
1107
|
-
min-height: 150px !important; /* Increased from 100px */
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
/* Reduce editor height when JSON error is showing */
|
|
1111
|
-
.editor-container.has-error {
|
|
1112
|
-
height: 120px !important; /* Reduced to make room for error message */
|
|
1113
|
-
max-height: 120px !important;
|
|
1114
|
-
min-height: 100px !important;
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
/* Ensure proxy editor takes full space when visible - increased height */
|
|
1118
|
-
.proxy-editor-container {
|
|
1119
|
-
height: 180px !important; /* Increased from 130px */
|
|
1120
|
-
max-height: 180px !important;
|
|
1121
|
-
min-height: 150px !important;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
/* Editor textarea heights - ensure syntax highlighting works */
|
|
1125
|
-
.code-editor,
|
|
1126
|
-
.proxy-editor {
|
|
1127
|
-
font-size: 11px !important;
|
|
1128
|
-
line-height: 1.4 !important;
|
|
1129
|
-
padding: 6px !important;
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
/* Syntax highlighting in landscape mode */
|
|
1133
|
-
.code-highlight {
|
|
1134
|
-
font-size: 11px !important;
|
|
1135
|
-
line-height: 1.4 !important;
|
|
1136
|
-
padding: 6px !important;
|
|
1137
|
-
/* Ensure syntax highlighting is visible in landscape */
|
|
1138
|
-
color: #f8f8f2 !important;
|
|
1139
|
-
opacity: 1 !important;
|
|
1140
|
-
display: block !important;
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
/* Compact error messages */
|
|
1144
|
-
.error-container {
|
|
1145
|
-
margin: 2px 0 !important; /* Reduced from 4px */
|
|
1146
|
-
padding: 4px 6px !important; /* More compact padding */
|
|
1147
|
-
font-size: 9px !important; /* Reduced from 10px */
|
|
1148
|
-
border-radius: 4px !important; /* Smaller border radius */
|
|
1149
|
-
gap: 6px !important; /* Reduced gap */
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
.error-icon {
|
|
1153
|
-
width: 12px !important;
|
|
1154
|
-
height: 12px !important;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
.error-icon svg {
|
|
1158
|
-
width: 12px !important;
|
|
1159
|
-
height: 12px !important;
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
.error-title {
|
|
1163
|
-
font-size: 9px !important; /* Reduced from 10px */
|
|
1164
|
-
margin-bottom: 2px !important;
|
|
1165
|
-
font-weight: 500 !important;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
.error-text {
|
|
1169
|
-
font-size: 8px !important; /* Reduced from 9px */
|
|
1170
|
-
line-height: 1.2 !important;
|
|
1171
|
-
}
|
|
1172
215
|
}
|
|
1173
|
-
|
|
1174
|
-
/* ==========================================================================
|
|
1175
|
-
VERY SHORT LANDSCAPE SCREENS (max-height: 400px + landscape)
|
|
1176
|
-
========================================================================== */
|
|
1177
|
-
|
|
1178
|
-
@media (max-height: 400px) and (orientation: landscape) {
|
|
1179
|
-
.editor-container,
|
|
1180
|
-
.proxy-editor-container {
|
|
1181
|
-
height: 140px !important; /* Increased from 100px */
|
|
1182
|
-
max-height: 140px !important;
|
|
1183
|
-
min-height: 120px !important; /* Increased from 80px */
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
/* Reduce editor height when JSON error is showing in very short landscape */
|
|
1187
|
-
.editor-container.has-error {
|
|
1188
|
-
height: 90px !important; /* Reduced to make room for error message */
|
|
1189
|
-
max-height: 90px !important;
|
|
1190
|
-
min-height: 80px !important;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/* Ensure proxy editor takes full space in very short landscape */
|
|
1194
|
-
.proxy-editor {
|
|
1195
|
-
height: 100% !important;
|
|
1196
|
-
min-height: 100% !important;
|
|
1197
|
-
font-size: 10px !important;
|
|
1198
|
-
line-height: 1.3 !important;
|
|
1199
|
-
padding: 4px !important;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
.code-editor {
|
|
1203
|
-
font-size: 10px !important;
|
|
1204
|
-
line-height: 1.3 !important;
|
|
1205
|
-
padding: 4px !important;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
/* Ensure syntax highlighting works in very short landscape */
|
|
1209
|
-
.code-highlight {
|
|
1210
|
-
font-size: 10px !important;
|
|
1211
|
-
line-height: 1.3 !important;
|
|
1212
|
-
padding: 4px !important;
|
|
1213
|
-
color: #f8f8f2 !important;
|
|
1214
|
-
opacity: 1 !important;
|
|
1215
|
-
display: block !important;
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
/* Ultra-compact error messages for very short landscape */
|
|
1219
|
-
.error-container {
|
|
1220
|
-
margin: 1px 0 !important;
|
|
1221
|
-
padding: 2px 4px !important;
|
|
1222
|
-
font-size: 8px !important;
|
|
1223
|
-
border-radius: 3px !important;
|
|
1224
|
-
gap: 4px !important;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
.error-icon {
|
|
1228
|
-
width: 10px !important;
|
|
1229
|
-
height: 10px !important;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
.error-icon svg {
|
|
1233
|
-
width: 10px !important;
|
|
1234
|
-
height: 10px !important;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
.error-title {
|
|
1238
|
-
font-size: 8px !important;
|
|
1239
|
-
margin-bottom: 1px !important;
|
|
1240
|
-
font-weight: 500 !important;
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
.error-text {
|
|
1244
|
-
font-size: 7px !important;
|
|
1245
|
-
line-height: 1.1 !important;
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
/* ==========================================================================
|
|
1250
|
-
MOBILE & TABLET - COMPACT EDITOR BUTTONS FOR ONE-ROW LAYOUT
|
|
1251
|
-
========================================================================== */
|
|
1252
|
-
|
|
1253
|
-
/* Icon-sized buttons - compact for all screens */
|
|
1254
|
-
.button-default {
|
|
1255
|
-
@apply h-7 w-7 p-0; // 28x28px on desktop/tablet
|
|
1256
|
-
min-width: 28px !important;
|
|
1257
|
-
max-width: 28px !important;
|
|
1258
|
-
width: 28px !important;
|
|
1259
|
-
height: 28px !important;
|
|
1260
|
-
padding: 0 !important;
|
|
1261
|
-
border-radius: 6px;
|
|
1262
|
-
|
|
1263
|
-
svg {
|
|
1264
|
-
@apply w-4 h-4; // 16x16px icons
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
/* Even more compact on mobile */
|
|
1269
|
-
@media (max-width: 640px) {
|
|
1270
|
-
.button-default {
|
|
1271
|
-
@apply h-6 w-6; // 24x24px on mobile
|
|
1272
|
-
min-width: 24px !important;
|
|
1273
|
-
max-width: 24px !important;
|
|
1274
|
-
width: 24px !important;
|
|
1275
|
-
height: 24px !important;
|
|
1276
|
-
|
|
1277
|
-
svg {
|
|
1278
|
-
@apply w-3.5 h-3.5; // 14x14px icons
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
216
|
</style>
|