@necrolab/dashboard 0.4.47 → 0.4.49
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 +2 -1
- package/exit +209 -0
- package/index.html +1 -1
- package/package.json +1 -1
- package/postinstall.js +9 -0
- package/public/manifest.json +8 -3
- package/src/assets/css/_input.scss +104 -111
- package/src/assets/css/_utilities.scss +441 -0
- package/src/assets/css/main.scss +228 -154
- package/src/components/Auth/LoginForm.vue +8 -8
- package/src/components/Editors/Account/Account.vue +156 -146
- package/src/components/Editors/Account/AccountCreator.vue +1 -1
- package/src/components/Editors/Account/AccountView.vue +13 -13
- package/src/components/Editors/Account/CreateAccount.vue +25 -16
- package/src/components/Editors/Profile/CreateProfile.vue +1 -1
- package/src/components/Editors/Profile/Profile.vue +1 -1
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +83 -19
- package/src/components/Editors/Profile/ProfileView.vue +11 -11
- package/src/components/Tasks/CreateTaskAXS.vue +3 -3
- package/src/components/Tasks/CreateTaskTM.vue +7 -35
- package/src/components/Tasks/QuickSettings.vue +112 -9
- package/src/components/Tasks/Stats.vue +29 -25
- package/src/components/Tasks/Task.vue +489 -365
- package/src/components/Tasks/TaskView.vue +21 -23
- package/src/components/icons/Sandclock.vue +2 -2
- package/src/components/icons/Stadium.vue +1 -1
- package/src/components/ui/Modal.vue +37 -35
- package/src/components/ui/controls/CountryChooser.vue +200 -62
- package/src/components/ui/controls/atomic/Dropdown.vue +177 -91
- package/src/components/ui/controls/atomic/MultiDropdown.vue +247 -168
- package/src/composables/useClickOutside.js +21 -0
- package/src/composables/useDropdownPosition.js +174 -0
- package/src/stores/ui.js +5 -4
- package/src/views/Accounts.vue +2 -2
- package/src/views/Console.vue +25 -45
- package/src/views/Editor.vue +1194 -730
- package/src/views/Profiles.vue +2 -2
- package/src/views/Tasks.vue +170 -137
- package/tailwind.config.js +47 -21
package/src/views/Editor.vue
CHANGED
|
@@ -1,202 +1,257 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<!-- Admin editor buttons moved here -->
|
|
32
|
-
<div v-if="textEditorVisible" class="flex flex-wrap gap-2 justify-center lg:justify-end">
|
|
33
|
-
<button class="btn-action flex-shrink-0" @click="format()" v-if="isJsonFile()">
|
|
34
|
-
<svg
|
|
35
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
36
|
-
width="16"
|
|
37
|
-
height="16"
|
|
38
|
-
viewBox="0 0 24 24"
|
|
39
|
-
fill="none"
|
|
40
|
-
stroke="currentColor"
|
|
41
|
-
stroke-width="2"
|
|
42
|
-
stroke-linecap="round"
|
|
43
|
-
stroke-linejoin="round"
|
|
44
|
-
>
|
|
45
|
-
<path d="M21 10H7" />
|
|
46
|
-
<path d="M21 6H3" />
|
|
47
|
-
<path d="M21 14H3" />
|
|
48
|
-
<path d="M21 18H7" />
|
|
49
|
-
</svg>
|
|
50
|
-
<span class="hidden sm:inline">Format</span>
|
|
51
|
-
</button>
|
|
52
|
-
<button class="btn-action flex-shrink-0" @click="saveAll">
|
|
53
|
-
<svg
|
|
54
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
55
|
-
width="16"
|
|
56
|
-
height="16"
|
|
57
|
-
viewBox="0 0 24 24"
|
|
58
|
-
fill="none"
|
|
59
|
-
stroke="currentColor"
|
|
60
|
-
stroke-width="2"
|
|
61
|
-
stroke-linecap="round"
|
|
62
|
-
stroke-linejoin="round"
|
|
63
|
-
>
|
|
64
|
-
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
|
65
|
-
<polyline points="17 21 17 13 7 13 7 21" />
|
|
66
|
-
<polyline points="7 3 7 8 15 8" />
|
|
67
|
-
</svg>
|
|
68
|
-
<span class="hidden sm:inline">Save File</span>
|
|
69
|
-
</button>
|
|
70
|
-
<button class="btn-action flex-shrink-0" @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 class="hidden sm:inline">Close File</span>
|
|
86
|
-
</button>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
2
|
+
<div>
|
|
3
|
+
<!-- Heading -->
|
|
4
|
+
<h4 class="text-white text-xl font-bold mb-5 pt-5 flex gap-2 items-center">
|
|
5
|
+
Editor
|
|
6
|
+
<img src="@/assets/img/pencil.svg" />
|
|
7
|
+
</h4>
|
|
8
|
+
|
|
9
|
+
<div class="card-dark p-2">
|
|
10
|
+
<!-- Admin Editor Section - Hidden when proxy editor is open -->
|
|
11
|
+
<div
|
|
12
|
+
v-if="ui.profile.admin"
|
|
13
|
+
class="admin-editor-section"
|
|
14
|
+
:class="{ 'landscape-hidden': currentProxyList }"
|
|
15
|
+
>
|
|
16
|
+
<h5 class="text-white text-xl font-bold flex gap-x-3 mb-3">Admin Editor</h5>
|
|
17
|
+
<div class="flex-responsive-wrap editor-controls-row">
|
|
18
|
+
<div
|
|
19
|
+
class="w-full lg:w-64 flex flex-shrink-0 dropdown-container z-dropdown-high"
|
|
20
|
+
>
|
|
21
|
+
<div class="relative flex-grow">
|
|
22
|
+
<Dropdown
|
|
23
|
+
class="bg-dark-500 border-2 border-r-0 border-dark-550 admin-file-dropdown w-full"
|
|
24
|
+
default="Select a file"
|
|
25
|
+
:onClick="(f) => loadFile(f)"
|
|
26
|
+
:options="availableFiles"
|
|
27
|
+
:allowDefault="false"
|
|
28
|
+
:includeAdjacentButtons="true"
|
|
29
|
+
rightAmount="right-1"
|
|
30
|
+
/>
|
|
89
31
|
</div>
|
|
32
|
+
<button
|
|
33
|
+
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"
|
|
34
|
+
@click="loadAvailableFiles()"
|
|
35
|
+
title="Refresh file list"
|
|
36
|
+
>
|
|
37
|
+
<ReloadIcon class="refresh-icon" />
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
<!-- Admin editor buttons moved here -->
|
|
41
|
+
<div
|
|
42
|
+
v-if="textEditorVisible"
|
|
43
|
+
class="flex flex-wrap gap-responsive justify-center lg:justify-end editor-buttons-responsive"
|
|
44
|
+
>
|
|
45
|
+
<button
|
|
46
|
+
class="btn-action flex-shrink-0"
|
|
47
|
+
@click="format()"
|
|
48
|
+
v-if="isJsonFile()"
|
|
49
|
+
title="Format JSON"
|
|
50
|
+
>
|
|
51
|
+
<svg
|
|
52
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
53
|
+
width="16"
|
|
54
|
+
height="16"
|
|
55
|
+
viewBox="0 0 24 24"
|
|
56
|
+
fill="none"
|
|
57
|
+
stroke="currentColor"
|
|
58
|
+
stroke-width="2"
|
|
59
|
+
stroke-linecap="round"
|
|
60
|
+
stroke-linejoin="round"
|
|
61
|
+
>
|
|
62
|
+
<path d="M21 10H7" />
|
|
63
|
+
<path d="M21 6H3" />
|
|
64
|
+
<path d="M21 14H3" />
|
|
65
|
+
<path d="M21 18H7" />
|
|
66
|
+
</svg>
|
|
67
|
+
<span class="hidden sm:inline">Format</span>
|
|
68
|
+
</button>
|
|
69
|
+
<button class="btn-action flex-shrink-0" @click="saveAll" title="Save File">
|
|
70
|
+
<svg
|
|
71
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
72
|
+
width="16"
|
|
73
|
+
height="16"
|
|
74
|
+
viewBox="0 0 24 24"
|
|
75
|
+
fill="none"
|
|
76
|
+
stroke="currentColor"
|
|
77
|
+
stroke-width="2"
|
|
78
|
+
stroke-linecap="round"
|
|
79
|
+
stroke-linejoin="round"
|
|
80
|
+
>
|
|
81
|
+
<path
|
|
82
|
+
d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"
|
|
83
|
+
/>
|
|
84
|
+
<polyline points="17 21 17 13 7 13 7 21" />
|
|
85
|
+
<polyline points="7 3 7 8 15 8" />
|
|
86
|
+
</svg>
|
|
87
|
+
<span class="hidden sm:inline">Save File</span>
|
|
88
|
+
</button>
|
|
89
|
+
<button
|
|
90
|
+
class="btn-action flex-shrink-0"
|
|
91
|
+
@click="closeFile"
|
|
92
|
+
title="Close File"
|
|
93
|
+
>
|
|
94
|
+
<svg
|
|
95
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
96
|
+
width="16"
|
|
97
|
+
height="16"
|
|
98
|
+
viewBox="0 0 24 24"
|
|
99
|
+
fill="none"
|
|
100
|
+
stroke="currentColor"
|
|
101
|
+
stroke-width="2"
|
|
102
|
+
stroke-linecap="round"
|
|
103
|
+
stroke-linejoin="round"
|
|
104
|
+
>
|
|
105
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
106
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
107
|
+
</svg>
|
|
108
|
+
<span class="hidden sm:inline">Close File</span>
|
|
109
|
+
</button>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
90
112
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
<div v-if="errorMessage" class="error-container">
|
|
112
|
-
<div class="error-icon">
|
|
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" />
|
|
124
|
-
</svg>
|
|
125
|
-
</div>
|
|
126
|
-
<div class="error-content">
|
|
127
|
-
<div class="error-title">JSON Syntax Error</div>
|
|
128
|
-
<div class="error-text">{{ errorMessage }}</div>
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
</transition>
|
|
133
|
-
<div class="border border-dark-650 my-8" />
|
|
134
|
-
|
|
135
|
-
<h5 class="text-white text-xl font-bold flex gap-x-3 mb-3">Proxy Editor</h5>
|
|
136
|
-
<div class="flex flex-col lg:flex-row lg:justify-between lg:items-center gap-4 proxy-controls-row mb-4">
|
|
137
|
-
<div class="w-full lg:w-64 flex flex-shrink-0 dropdown-container">
|
|
138
|
-
<div class="relative flex-grow">
|
|
139
|
-
<Dropdown
|
|
140
|
-
class="bg-dark-500 border-2 border-dark-550 rounded-lg w-full h-10"
|
|
141
|
-
:default="ui.profile.proxyList?.checkout || proxyLists[0]"
|
|
142
|
-
:onClick="loadProxies"
|
|
143
|
-
:options="proxyLists"
|
|
144
|
-
:allowDefault="false"
|
|
145
|
-
rightAmount="right-1"
|
|
146
|
-
/>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
<!-- Proxy save button moved here -->
|
|
150
|
-
<div v-if="currentProxyList" class="flex flex-wrap gap-2 justify-center lg:justify-end">
|
|
151
|
-
<button class="btn-action flex-shrink-0" @click="saveProxies">
|
|
152
|
-
<svg
|
|
153
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
154
|
-
width="16"
|
|
155
|
-
height="16"
|
|
156
|
-
viewBox="0 0 24 24"
|
|
157
|
-
fill="none"
|
|
158
|
-
stroke="currentColor"
|
|
159
|
-
stroke-width="2"
|
|
160
|
-
stroke-linecap="round"
|
|
161
|
-
stroke-linejoin="round"
|
|
162
|
-
>
|
|
163
|
-
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
|
164
|
-
<polyline points="17 21 17 13 7 13 7 21" />
|
|
165
|
-
<polyline points="7 3 7 8 15 8" />
|
|
166
|
-
</svg>
|
|
167
|
-
<span class="hidden sm:inline">Save Proxies</span>
|
|
168
|
-
</button>
|
|
169
|
-
<button class="btn-action flex-shrink-0" @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 class="hidden sm:inline">Close File</span>
|
|
185
|
-
</button>
|
|
113
|
+
<transition name="fade">
|
|
114
|
+
<div v-if="textEditorVisible" class="my-3 relative">
|
|
115
|
+
<div class="pb-4">
|
|
116
|
+
<!-- Syntax Highlighting Editor -->
|
|
117
|
+
<div
|
|
118
|
+
class="editor-container table-component"
|
|
119
|
+
:class="{ 'has-error': errorMessage }"
|
|
120
|
+
>
|
|
121
|
+
<div class="editor-wrapper">
|
|
122
|
+
<pre ref="codeDisplay" class="language-json code-highlight"></pre>
|
|
123
|
+
<textarea
|
|
124
|
+
ref="codeEditor"
|
|
125
|
+
v-model="currentContent"
|
|
126
|
+
class="code-editor"
|
|
127
|
+
spellcheck="false"
|
|
128
|
+
@scroll="syncScroll"
|
|
129
|
+
@input="highlightCode"
|
|
130
|
+
@keydown.tab.prevent="handleTab"
|
|
131
|
+
></textarea>
|
|
186
132
|
</div>
|
|
133
|
+
</div>
|
|
187
134
|
</div>
|
|
188
|
-
|
|
189
|
-
<
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
135
|
+
|
|
136
|
+
<div v-if="errorMessage" class="error-container">
|
|
137
|
+
<div class="error-icon">
|
|
138
|
+
<svg
|
|
139
|
+
width="16"
|
|
140
|
+
height="16"
|
|
141
|
+
viewBox="0 0 24 24"
|
|
142
|
+
fill="none"
|
|
143
|
+
stroke="currentColor"
|
|
144
|
+
stroke-width="2"
|
|
145
|
+
>
|
|
146
|
+
<circle cx="12" cy="12" r="10" />
|
|
147
|
+
<line x1="15" y1="9" x2="9" y2="15" />
|
|
148
|
+
<line x1="9" y1="9" x2="15" y2="15" />
|
|
149
|
+
</svg>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="error-content">
|
|
152
|
+
<div class="error-title">JSON Syntax Error</div>
|
|
153
|
+
<div class="error-text">{{ errorMessage }}</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</transition>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<!-- Section Divider - Show when both editors are closed -->
|
|
161
|
+
<div
|
|
162
|
+
v-if="ui.profile.admin && !textEditorVisible && !currentProxyList"
|
|
163
|
+
class="section-divider"
|
|
164
|
+
/>
|
|
165
|
+
|
|
166
|
+
<!-- Proxy Editor Section - Hidden when admin editor is open -->
|
|
167
|
+
<div
|
|
168
|
+
class="proxy-editor-section"
|
|
169
|
+
:class="{ 'landscape-hidden': textEditorVisible }"
|
|
170
|
+
>
|
|
171
|
+
<h5 class="text-white text-xl font-bold flex gap-x-3 mb-3">Proxy Editor</h5>
|
|
172
|
+
<div class="flex-responsive-wrap proxy-controls-row mb-1">
|
|
173
|
+
<div class="w-full lg:w-64 flex flex-shrink-0 dropdown-container z-dropdown">
|
|
174
|
+
<div class="relative flex-grow">
|
|
175
|
+
<Dropdown
|
|
176
|
+
class="bg-dark-500 border-2 border-dark-550 proxy-file-dropdown w-full"
|
|
177
|
+
:default="ui.profile.proxyList?.checkout || proxyLists[0]"
|
|
178
|
+
:onClick="loadProxies"
|
|
179
|
+
:options="proxyLists"
|
|
180
|
+
:allowDefault="false"
|
|
181
|
+
:includeAdjacentButtons="true"
|
|
182
|
+
rightAmount="right-1"
|
|
183
|
+
/>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
<!-- Proxy save button moved here -->
|
|
187
|
+
<div
|
|
188
|
+
v-if="currentProxyList"
|
|
189
|
+
class="flex flex-wrap gap-responsive justify-center lg:justify-end editor-buttons-responsive"
|
|
190
|
+
>
|
|
191
|
+
<button
|
|
192
|
+
class="btn-action flex-shrink-0"
|
|
193
|
+
@click="saveProxies"
|
|
194
|
+
title="Save Proxies"
|
|
195
|
+
>
|
|
196
|
+
<svg
|
|
197
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
198
|
+
width="16"
|
|
199
|
+
height="16"
|
|
200
|
+
viewBox="0 0 24 24"
|
|
201
|
+
fill="none"
|
|
202
|
+
stroke="currentColor"
|
|
203
|
+
stroke-width="2"
|
|
204
|
+
stroke-linecap="round"
|
|
205
|
+
stroke-linejoin="round"
|
|
206
|
+
>
|
|
207
|
+
<path
|
|
208
|
+
d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"
|
|
209
|
+
/>
|
|
210
|
+
<polyline points="17 21 17 13 7 13 7 21" />
|
|
211
|
+
<polyline points="7 3 7 8 15 8" />
|
|
212
|
+
</svg>
|
|
213
|
+
<span class="hidden sm:inline">Save Proxies</span>
|
|
214
|
+
</button>
|
|
215
|
+
<button
|
|
216
|
+
class="btn-action flex-shrink-0"
|
|
217
|
+
@click="closeProxyFile"
|
|
218
|
+
title="Close File"
|
|
219
|
+
>
|
|
220
|
+
<svg
|
|
221
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
222
|
+
width="16"
|
|
223
|
+
height="16"
|
|
224
|
+
viewBox="0 0 24 24"
|
|
225
|
+
fill="none"
|
|
226
|
+
stroke="currentColor"
|
|
227
|
+
stroke-width="2"
|
|
228
|
+
stroke-linecap="round"
|
|
229
|
+
stroke-linejoin="round"
|
|
230
|
+
>
|
|
231
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
232
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
233
|
+
</svg>
|
|
234
|
+
<span class="hidden sm:inline">Close File</span>
|
|
235
|
+
</button>
|
|
236
|
+
</div>
|
|
198
237
|
</div>
|
|
238
|
+
<!-- Textarea -->
|
|
239
|
+
<transition name="fade">
|
|
240
|
+
<div v-if="currentProxyList" class="relative my-3">
|
|
241
|
+
<div class="pb-4">
|
|
242
|
+
<div class="proxy-editor-container table-component">
|
|
243
|
+
<textarea
|
|
244
|
+
v-model="proxyContent"
|
|
245
|
+
class="proxy-editor"
|
|
246
|
+
spellcheck="false"
|
|
247
|
+
></textarea>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
</transition>
|
|
252
|
+
</div>
|
|
199
253
|
</div>
|
|
254
|
+
</div>
|
|
200
255
|
</template>
|
|
201
256
|
<script setup>
|
|
202
257
|
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from "vue";
|
|
@@ -207,12 +262,18 @@ import { getProxyLists, getProxyFile } from "@/stores/requests";
|
|
|
207
262
|
import { DEBUG } from "@/utils/debug";
|
|
208
263
|
|
|
209
264
|
const loadFromApi = async (path) => {
|
|
210
|
-
|
|
211
|
-
|
|
265
|
+
const res = await fetch(path);
|
|
266
|
+
return res.json();
|
|
212
267
|
};
|
|
213
268
|
|
|
214
269
|
const availableFiles = ref([]);
|
|
215
|
-
if (DEBUG)
|
|
270
|
+
if (DEBUG)
|
|
271
|
+
availableFiles.value.push(
|
|
272
|
+
"used-codes.json",
|
|
273
|
+
"proxies.txt",
|
|
274
|
+
"toMonitor.txt",
|
|
275
|
+
"test.txt"
|
|
276
|
+
);
|
|
216
277
|
const currentFile = ref("");
|
|
217
278
|
const textEditorVisible = ref(false);
|
|
218
279
|
const currentContent = ref("");
|
|
@@ -227,336 +288,362 @@ const codeEditor = ref(null);
|
|
|
227
288
|
const codeDisplay = ref(null);
|
|
228
289
|
|
|
229
290
|
let previous = {
|
|
230
|
-
|
|
231
|
-
|
|
291
|
+
proxyContent: { list: ui.profile.proxyList, content: "" },
|
|
292
|
+
currentContent: { file: "", content: "" },
|
|
232
293
|
};
|
|
233
294
|
|
|
234
295
|
const errorMessage = computed(() => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
296
|
+
if (!currentFile.value.endsWith(".json")) return;
|
|
297
|
+
|
|
298
|
+
let err;
|
|
299
|
+
try {
|
|
300
|
+
JSON.parse(currentContent.value);
|
|
301
|
+
} catch (e) {
|
|
302
|
+
err = e;
|
|
303
|
+
}
|
|
304
|
+
return err?.message;
|
|
244
305
|
});
|
|
245
306
|
|
|
246
|
-
const loadAvailableFiles = async () =>
|
|
307
|
+
const loadAvailableFiles = async () =>
|
|
308
|
+
(availableFiles.value = await loadFromApi("/api/json-files"));
|
|
247
309
|
|
|
248
310
|
const isJsonFile = () => currentFile.value.endsWith(".json");
|
|
249
311
|
|
|
250
312
|
// Function to highlight code using Prism
|
|
251
313
|
const highlightCode = () => {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
314
|
+
if (!codeDisplay.value || !codeEditor.value) return;
|
|
315
|
+
|
|
316
|
+
// Get the language based on file extension
|
|
317
|
+
let language = "javascript"; // Default language
|
|
318
|
+
|
|
319
|
+
if (currentFile.value) {
|
|
320
|
+
if (currentFile.value.endsWith(".json")) {
|
|
321
|
+
language = "json";
|
|
322
|
+
} else if (currentFile.value.endsWith(".js")) {
|
|
323
|
+
language = "javascript";
|
|
324
|
+
} else if (currentFile.value.endsWith(".txt") || currentFile.value.endsWith(".csv")) {
|
|
325
|
+
language = "text";
|
|
326
|
+
// Plain text doesn't need highlighting
|
|
327
|
+
codeDisplay.value.textContent = currentContent.value || "";
|
|
328
|
+
codeDisplay.value.className = "language-text code-highlight";
|
|
329
|
+
return;
|
|
269
330
|
}
|
|
331
|
+
}
|
|
270
332
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
333
|
+
// Ensure Prism is available
|
|
334
|
+
if (typeof Prism === "undefined") {
|
|
335
|
+
console.error("Prism is not loaded");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
276
338
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
339
|
+
// Use requestAnimationFrame for smoother updates
|
|
340
|
+
requestAnimationFrame(() => {
|
|
341
|
+
try {
|
|
342
|
+
// Update the pre element with highlighted HTML
|
|
343
|
+
const highlighted = Prism.highlight(
|
|
344
|
+
currentContent.value || "",
|
|
345
|
+
Prism.languages[language],
|
|
346
|
+
language
|
|
347
|
+
);
|
|
348
|
+
codeDisplay.value.innerHTML = highlighted;
|
|
349
|
+
codeDisplay.value.className = `language-${language} code-highlight`;
|
|
350
|
+
} catch (e) {
|
|
351
|
+
console.error("Highlight error:", e);
|
|
352
|
+
// Fallback to plain text if highlighting fails
|
|
353
|
+
codeDisplay.value.textContent = currentContent.value || "";
|
|
354
|
+
}
|
|
289
355
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
356
|
+
// Ensure scroll positions are synced after highlighting
|
|
357
|
+
syncScroll();
|
|
358
|
+
});
|
|
293
359
|
};
|
|
294
360
|
|
|
295
361
|
// Function to sync scrolling between textarea and highlighted code
|
|
296
362
|
const syncScroll = () => {
|
|
297
|
-
|
|
363
|
+
if (!codeDisplay.value || !codeEditor.value) return;
|
|
298
364
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
365
|
+
// Synchronize scrolling between the textarea and the highlighted code
|
|
366
|
+
requestAnimationFrame(() => {
|
|
367
|
+
codeDisplay.value.scrollTop = codeEditor.value.scrollTop;
|
|
368
|
+
codeDisplay.value.scrollLeft = codeEditor.value.scrollLeft;
|
|
369
|
+
});
|
|
304
370
|
};
|
|
305
371
|
|
|
306
372
|
// Function to handle tab key press in the editor
|
|
307
373
|
const handleTab = (e) => {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
374
|
+
const textarea = codeEditor.value;
|
|
375
|
+
const start = textarea.selectionStart;
|
|
376
|
+
const end = textarea.selectionEnd;
|
|
377
|
+
|
|
378
|
+
// Insert 4 spaces at cursor position
|
|
379
|
+
const spaces = " ";
|
|
380
|
+
currentContent.value =
|
|
381
|
+
currentContent.value.substring(0, start) +
|
|
382
|
+
spaces +
|
|
383
|
+
currentContent.value.substring(end);
|
|
384
|
+
|
|
385
|
+
// Move cursor position after the inserted tab
|
|
386
|
+
nextTick(() => {
|
|
387
|
+
textarea.selectionStart = textarea.selectionEnd = start + spaces.length;
|
|
388
|
+
highlightCode();
|
|
389
|
+
});
|
|
321
390
|
};
|
|
322
391
|
|
|
323
392
|
const format = () => {
|
|
324
|
-
|
|
325
|
-
|
|
393
|
+
try {
|
|
394
|
+
if (!isJsonFile()) return;
|
|
326
395
|
|
|
327
|
-
|
|
328
|
-
|
|
396
|
+
const formatted = JSON.stringify(JSON.parse(currentContent.value), null, 4);
|
|
397
|
+
currentContent.value = formatted;
|
|
329
398
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
399
|
+
// Apply syntax highlighting after formatting
|
|
400
|
+
nextTick(() => {
|
|
401
|
+
highlightCode();
|
|
402
|
+
});
|
|
403
|
+
} catch (e) {
|
|
404
|
+
ui.logger.Error("Could not format JSON", e);
|
|
405
|
+
}
|
|
337
406
|
};
|
|
338
407
|
|
|
339
408
|
// Watch for content changes to apply syntax highlighting
|
|
340
409
|
watch(currentContent, () => {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
410
|
+
nextTick(() => {
|
|
411
|
+
highlightCode();
|
|
412
|
+
});
|
|
344
413
|
});
|
|
345
414
|
|
|
346
415
|
const loadFile = async (f) => {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
textEditorVisible.value = true;
|
|
350
|
-
currentProxyList.value = "";
|
|
351
|
-
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
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const res = await loadFromApi("/api/json-file?file=" + currentFile.value);
|
|
372
|
-
const text = atob(res.content);
|
|
416
|
+
currentFile.value = f;
|
|
417
|
+
if (DEBUG) {
|
|
373
418
|
textEditorVisible.value = true;
|
|
374
419
|
currentProxyList.value = "";
|
|
375
|
-
currentContent.value =
|
|
376
|
-
previous.currentContent = { file: currentFile.value, content: text };
|
|
420
|
+
currentContent.value = new Array(100).fill(0, 0, 100).join("\n");
|
|
377
421
|
|
|
378
422
|
// Update pre element class based on file type
|
|
379
423
|
if (codeDisplay.value) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
424
|
+
if (f.endsWith(".json")) {
|
|
425
|
+
codeDisplay.value.className = "language-json";
|
|
426
|
+
} else if (f.endsWith(".js")) {
|
|
427
|
+
codeDisplay.value.className = "language-javascript";
|
|
428
|
+
} else {
|
|
429
|
+
codeDisplay.value.className = "language-text";
|
|
430
|
+
}
|
|
387
431
|
}
|
|
388
432
|
|
|
389
|
-
// Apply syntax highlighting after content is
|
|
433
|
+
// Apply syntax highlighting after content is set
|
|
390
434
|
nextTick(() => {
|
|
391
|
-
|
|
435
|
+
highlightCode();
|
|
392
436
|
});
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const res = await loadFromApi("/api/json-file?file=" + currentFile.value);
|
|
441
|
+
const text = atob(res.content);
|
|
442
|
+
textEditorVisible.value = true;
|
|
443
|
+
currentProxyList.value = "";
|
|
444
|
+
currentContent.value = text;
|
|
445
|
+
previous.currentContent = { file: currentFile.value, content: text };
|
|
446
|
+
|
|
447
|
+
// Update pre element class based on file type
|
|
448
|
+
if (codeDisplay.value) {
|
|
449
|
+
if (f.endsWith(".json")) {
|
|
450
|
+
codeDisplay.value.className = "language-json";
|
|
451
|
+
} else if (f.endsWith(".js")) {
|
|
452
|
+
codeDisplay.value.className = "language-javascript";
|
|
453
|
+
} else {
|
|
454
|
+
codeDisplay.value.className = "language-text";
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Apply syntax highlighting after content is loaded
|
|
459
|
+
nextTick(() => {
|
|
460
|
+
highlightCode();
|
|
461
|
+
});
|
|
393
462
|
};
|
|
394
463
|
|
|
395
464
|
const saveDataToAPI = async (data, endpoint, msg, json = true) => {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
465
|
+
if (DEBUG) return;
|
|
466
|
+
const options = {
|
|
467
|
+
method: "POST",
|
|
468
|
+
headers: { "Content-Type": "application/json" },
|
|
469
|
+
body: JSON.stringify({ content: data }),
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
let j;
|
|
473
|
+
const res = await fetch(endpoint, options);
|
|
474
|
+
if (json) {
|
|
475
|
+
try {
|
|
476
|
+
j = await res.json();
|
|
477
|
+
} catch (e) {
|
|
478
|
+
ui.showError("Error saving proxies");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (j?.error) return ui.showError(j.error);
|
|
482
|
+
} else {
|
|
483
|
+
try {
|
|
484
|
+
j = await res.text();
|
|
485
|
+
} catch (e) {
|
|
486
|
+
ui.showError("Error saving proxies");
|
|
487
|
+
return;
|
|
420
488
|
}
|
|
421
|
-
|
|
489
|
+
}
|
|
490
|
+
ui.showSuccess(msg);
|
|
422
491
|
};
|
|
423
492
|
|
|
424
493
|
const saveFile = async () => {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
494
|
+
if (
|
|
495
|
+
btoa(currentContent.value) === previous.currentContent.content &&
|
|
496
|
+
currentFile.value === previous.currentContent.file
|
|
497
|
+
)
|
|
498
|
+
return ui.logger.Info("Content did not change");
|
|
499
|
+
saveDataToAPI(
|
|
500
|
+
btoa(currentContent.value),
|
|
501
|
+
"/api/json-file?file=" + currentFile.value,
|
|
502
|
+
"Successfully saved file"
|
|
503
|
+
);
|
|
504
|
+
previous.currentContent = {
|
|
505
|
+
file: currentFile.value,
|
|
506
|
+
content: btoa(currentContent.value),
|
|
507
|
+
};
|
|
432
508
|
};
|
|
433
509
|
|
|
434
510
|
const saveAll = async () => {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
511
|
+
if (DEBUG) return;
|
|
512
|
+
if (currentFile.value && currentContent.value) await saveFile();
|
|
513
|
+
await saveQuickConfig();
|
|
438
514
|
};
|
|
439
515
|
|
|
440
516
|
const closeFile = () => {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
517
|
+
currentFile.value = "";
|
|
518
|
+
currentContent.value = "";
|
|
519
|
+
textEditorVisible.value = false;
|
|
520
|
+
ui.logger.Info("File closed");
|
|
445
521
|
};
|
|
446
522
|
|
|
447
523
|
const closeProxyFile = () => {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
524
|
+
currentProxyList.value = "";
|
|
525
|
+
proxyContent.value = "";
|
|
526
|
+
ui.logger.Info("Proxy file closed");
|
|
451
527
|
};
|
|
452
528
|
|
|
453
529
|
const loadProxies = async (list) => {
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
ui.logger.Info("Loading proxies: " + list);
|
|
463
|
-
currentProxyList.value = list;
|
|
464
|
-
const file = await getProxyFile(list);
|
|
465
|
-
proxyContent.value = file;
|
|
466
|
-
previous.proxyContent = { content: proxyContent.value };
|
|
467
|
-
textEditorVisible.value = false;
|
|
468
|
-
} catch (ex) {
|
|
469
|
-
ui.logger.Error("Could not load proxies", ex);
|
|
530
|
+
try {
|
|
531
|
+
if (DEBUG) {
|
|
532
|
+
currentProxyList.value = list;
|
|
533
|
+
textEditorVisible.value = false;
|
|
534
|
+
proxyContent.value = new Array(100).fill(0, 0, 100).join("\n");
|
|
535
|
+
return;
|
|
470
536
|
}
|
|
537
|
+
|
|
538
|
+
ui.logger.Info("Loading proxies: " + list);
|
|
539
|
+
currentProxyList.value = list;
|
|
540
|
+
const file = await getProxyFile(list);
|
|
541
|
+
proxyContent.value = file;
|
|
542
|
+
previous.proxyContent = { content: proxyContent.value };
|
|
543
|
+
textEditorVisible.value = false;
|
|
544
|
+
} catch (ex) {
|
|
545
|
+
ui.logger.Error("Could not load proxies", ex);
|
|
546
|
+
}
|
|
471
547
|
};
|
|
472
548
|
|
|
473
549
|
const saveProxies = async () => {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
550
|
+
// if (!DEBUG) return;
|
|
551
|
+
if (previous.proxyContent.content === proxyContent.value)
|
|
552
|
+
ui.logger.Info("proxies did not change");
|
|
553
|
+
else {
|
|
554
|
+
await saveDataToAPI(
|
|
555
|
+
btoa(proxyContent.value),
|
|
556
|
+
"/api/proxies?file=" + currentProxyList.value,
|
|
557
|
+
"Successfully saved proxies",
|
|
558
|
+
false
|
|
559
|
+
);
|
|
560
|
+
previous.proxyContent.content = btoa(proxyContent.value);
|
|
561
|
+
}
|
|
485
562
|
};
|
|
486
563
|
|
|
487
564
|
const loadProxyLists = async () => {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
565
|
+
if (DEBUG)
|
|
566
|
+
return (proxyLists.value = [
|
|
567
|
+
"test-proxies",
|
|
568
|
+
"recaptcha-proxies",
|
|
569
|
+
"checkout-proxies",
|
|
570
|
+
"queue-proxies",
|
|
571
|
+
]);
|
|
572
|
+
const res = await getProxyLists();
|
|
573
|
+
if (Array.isArray(res)) proxyLists.value = res;
|
|
574
|
+
else ui.showError("Could not load proxylists");
|
|
492
575
|
};
|
|
493
576
|
|
|
494
577
|
// Initialize syntax highlighting
|
|
495
578
|
onMounted(() => {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
579
|
+
// Apply highlighting when the component is mounted
|
|
580
|
+
nextTick(() => {
|
|
581
|
+
highlightCode();
|
|
499
582
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
583
|
+
// Ensure scroll synchronization on initial load
|
|
584
|
+
if (codeEditor.value && codeDisplay.value) {
|
|
585
|
+
syncScroll();
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// iOS-specific editor fixes with cursor tracking
|
|
590
|
+
if (
|
|
591
|
+
/iPad|iPhone|iPod/.test(navigator.platform) ||
|
|
592
|
+
(navigator.maxTouchPoints &&
|
|
593
|
+
navigator.maxTouchPoints > 2 &&
|
|
594
|
+
/MacIntel/.test(navigator.platform))
|
|
595
|
+
) {
|
|
596
|
+
const trackCursor = (editor) => {
|
|
597
|
+
const scrollToCursor = () => {
|
|
598
|
+
setTimeout(() => {
|
|
599
|
+
const container =
|
|
600
|
+
editor.closest(".editor-container") ||
|
|
601
|
+
editor.closest(".proxy-editor-container");
|
|
602
|
+
if (container) {
|
|
603
|
+
// Get cursor position and scroll to it
|
|
604
|
+
const lines = editor.value.substring(0, editor.selectionStart).split("\n");
|
|
605
|
+
const lineHeight = 24; // Approximate line height
|
|
606
|
+
const cursorY = lines.length * lineHeight;
|
|
607
|
+
const containerHeight = container.clientHeight;
|
|
608
|
+
|
|
609
|
+
// Scroll to keep cursor in view
|
|
610
|
+
if (cursorY > container.scrollTop + containerHeight - 60) {
|
|
611
|
+
container.scrollTop = cursorY - containerHeight + 60;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}, 100);
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
editor.addEventListener("focus", scrollToCursor);
|
|
618
|
+
editor.addEventListener("input", scrollToCursor);
|
|
619
|
+
editor.addEventListener("click", scrollToCursor);
|
|
620
|
+
editor.addEventListener("keyup", scrollToCursor);
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
nextTick(() => {
|
|
624
|
+
if (codeEditor.value) {
|
|
625
|
+
trackCursor(codeEditor.value);
|
|
626
|
+
}
|
|
627
|
+
const proxyEditor = document.querySelector(".proxy-editor");
|
|
628
|
+
if (proxyEditor) {
|
|
629
|
+
trackCursor(proxyEditor);
|
|
630
|
+
}
|
|
504
631
|
});
|
|
632
|
+
}
|
|
505
633
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
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
|
-
}
|
|
634
|
+
// Watch for editor visibility changes
|
|
635
|
+
watch(textEditorVisible, (newValue) => {
|
|
636
|
+
if (newValue) {
|
|
637
|
+
nextTick(() => {
|
|
638
|
+
highlightCode();
|
|
546
639
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
nextTick(() => {
|
|
551
|
-
highlightCode();
|
|
552
|
-
|
|
553
|
-
// Focus the editor when it becomes visible
|
|
554
|
-
if (codeEditor.value) {
|
|
555
|
-
codeEditor.value.focus();
|
|
556
|
-
}
|
|
557
|
-
});
|
|
640
|
+
// Focus the editor when it becomes visible
|
|
641
|
+
if (codeEditor.value) {
|
|
642
|
+
codeEditor.value.focus();
|
|
558
643
|
}
|
|
559
|
-
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
});
|
|
560
647
|
});
|
|
561
648
|
|
|
562
649
|
// No cleanup needed - global iOS handling takes care of everything
|
|
@@ -565,285 +652,293 @@ if (ui.profile.admin && !DEBUG) loadAvailableFiles();
|
|
|
565
652
|
loadProxyLists();
|
|
566
653
|
</script>
|
|
567
654
|
<style lang="scss" scoped>
|
|
568
|
-
|
|
569
|
-
|
|
655
|
+
/* ==========================================================================
|
|
656
|
+
Z-INDEX MANAGEMENT
|
|
657
|
+
========================================================================== */
|
|
570
658
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
@apply w-full focus:outline-none text-xs text-white;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
$border: 2px;
|
|
659
|
+
.z-dropdown-high {
|
|
660
|
+
position: relative;
|
|
661
|
+
z-index: 200;
|
|
662
|
+
}
|
|
579
663
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
// z-index: -2;
|
|
584
|
-
// margin: -$border;
|
|
585
|
-
// border-radius: inherit;
|
|
586
|
-
// background: radial-gradient(rgba(96, 66, 255, 0.6), rgba(255, 255, 255, 0));
|
|
587
|
-
// }
|
|
664
|
+
.z-dropdown-high .dropdown-menu,
|
|
665
|
+
.z-dropdown-high .option-list {
|
|
666
|
+
z-index: 250;
|
|
588
667
|
}
|
|
589
668
|
|
|
590
|
-
.z-
|
|
591
|
-
|
|
669
|
+
.z-dropdown {
|
|
670
|
+
position: relative;
|
|
671
|
+
z-index: 100;
|
|
592
672
|
}
|
|
593
673
|
|
|
594
|
-
.z-
|
|
595
|
-
|
|
674
|
+
.z-dropdown .dropdown-menu,
|
|
675
|
+
.z-dropdown .option-list {
|
|
676
|
+
z-index: 150;
|
|
596
677
|
}
|
|
597
678
|
|
|
598
|
-
|
|
599
|
-
|
|
679
|
+
/* ==========================================================================
|
|
680
|
+
CARD CONTAINER RESPONSIVENESS
|
|
681
|
+
========================================================================== */
|
|
682
|
+
|
|
683
|
+
.card-dark {
|
|
684
|
+
max-height: calc(100vh - 100px) !important; /* Increased from 120px */
|
|
685
|
+
overflow-y: auto !important;
|
|
686
|
+
-webkit-overflow-scrolling: touch !important;
|
|
687
|
+
margin-bottom: 0.5rem !important; /* Reduced from 1rem */
|
|
688
|
+
/* Reduced bottom padding to minimize empty space */
|
|
689
|
+
padding-bottom: 0.5rem !important; /* Reduced from 1.5rem */
|
|
600
690
|
}
|
|
601
691
|
|
|
602
|
-
|
|
603
|
-
|
|
692
|
+
/* ==========================================================================
|
|
693
|
+
ADMIN EDITOR SECTION CONDITIONAL VISIBILITY
|
|
694
|
+
========================================================================== */
|
|
695
|
+
|
|
696
|
+
.admin-editor-section {
|
|
697
|
+
/* Default: always visible */
|
|
604
698
|
}
|
|
605
699
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
font-weight: 500;
|
|
610
|
-
--tw-text-opacity: 1;
|
|
611
|
-
color: rgb(255 255 255 / 1);
|
|
612
|
-
transition-duration: 150ms;
|
|
700
|
+
/* Hide admin editor when proxy editor is open - ALL SCREEN SIZES */
|
|
701
|
+
.admin-editor-section.landscape-hidden {
|
|
702
|
+
display: none !important;
|
|
613
703
|
}
|
|
614
704
|
|
|
615
|
-
/*
|
|
616
|
-
|
|
705
|
+
/* ==========================================================================
|
|
706
|
+
PROXY EDITOR SECTION CONDITIONAL VISIBILITY
|
|
707
|
+
========================================================================== */
|
|
617
708
|
|
|
618
|
-
.
|
|
619
|
-
|
|
620
|
-
.refresh-icon {
|
|
621
|
-
transform: rotate(180deg);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
709
|
+
.proxy-editor-section {
|
|
710
|
+
/* Default: always visible */
|
|
624
711
|
}
|
|
625
712
|
|
|
626
|
-
|
|
627
|
-
|
|
713
|
+
/* Hide proxy editor when admin editor is open - ALL SCREEN SIZES */
|
|
714
|
+
.proxy-editor-section.landscape-hidden {
|
|
715
|
+
display: none !important;
|
|
628
716
|
}
|
|
629
717
|
|
|
630
|
-
/*
|
|
631
|
-
.
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
border-bottom-right-radius: 0 !important;
|
|
635
|
-
border-top-left-radius: 0.5rem !important; /* lg border radius */
|
|
636
|
-
border-bottom-left-radius: 0.5rem !important; /* lg border radius */
|
|
718
|
+
/* Ensure card has proper bottom margin when sections are hidden */
|
|
719
|
+
.proxy-editor-section.landscape-hidden ~ .card-dark,
|
|
720
|
+
.admin-editor-section.landscape-hidden ~ .card-dark {
|
|
721
|
+
margin-bottom: 1rem !important;
|
|
637
722
|
}
|
|
638
723
|
|
|
639
|
-
/*
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
overflow: visible !important;
|
|
647
|
-
background-color: #2e2f34;
|
|
648
|
-
touch-action: auto !important;
|
|
724
|
+
/* ==========================================================================
|
|
725
|
+
SECTION HEADERS
|
|
726
|
+
========================================================================== */
|
|
727
|
+
|
|
728
|
+
.admin-editor-section h5,
|
|
729
|
+
.proxy-editor-section h5 {
|
|
730
|
+
/* Remove the gradient underline styling */
|
|
649
731
|
}
|
|
650
732
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
733
|
+
/* ==========================================================================
|
|
734
|
+
ADMIN FILE DROPDOWN STYLING
|
|
735
|
+
========================================================================== */
|
|
736
|
+
|
|
737
|
+
.admin-file-dropdown {
|
|
738
|
+
height: 2.5rem !important;
|
|
739
|
+
border-top-right-radius: 0 !important;
|
|
740
|
+
border-bottom-right-radius: 0 !important;
|
|
741
|
+
border-top-left-radius: 0.5rem !important;
|
|
742
|
+
border-bottom-left-radius: 0.5rem !important;
|
|
658
743
|
}
|
|
659
744
|
|
|
660
|
-
.
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
min-height: 300px;
|
|
664
|
-
max-height: 600px;
|
|
665
|
-
background-color: transparent;
|
|
666
|
-
/* Make text completely transparent */
|
|
667
|
-
color: rgba(0, 0, 0, 0);
|
|
668
|
-
caret-color: #e2e8f0;
|
|
669
|
-
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
670
|
-
padding: 12px;
|
|
671
|
-
border: none;
|
|
672
|
-
resize: none;
|
|
673
|
-
font-size: 14px;
|
|
674
|
-
line-height: 1.6;
|
|
675
|
-
tab-size: 4;
|
|
676
|
-
outline: none;
|
|
677
|
-
border: 1px solid #2d2d3b;
|
|
678
|
-
border-radius: 8px;
|
|
679
|
-
z-index: 10;
|
|
680
|
-
position: absolute;
|
|
681
|
-
top: 0;
|
|
682
|
-
left: 0;
|
|
683
|
-
right: 0;
|
|
684
|
-
bottom: 0;
|
|
685
|
-
white-space: pre;
|
|
686
|
-
overflow: auto;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
/* iOS keyboard focus fix and scrolling */
|
|
691
|
-
.code-editor:focus,
|
|
692
|
-
.proxy-editor:focus {
|
|
693
|
-
transform: translateZ(0);
|
|
694
|
-
-webkit-transform: translateZ(0);
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
/* Force textarea scrolling to work */
|
|
698
|
-
.code-editor,
|
|
699
|
-
.proxy-editor {
|
|
700
|
-
overflow: auto !important;
|
|
701
|
-
-webkit-overflow-scrolling: touch !important;
|
|
702
|
-
user-select: text !important;
|
|
703
|
-
-webkit-user-select: text !important;
|
|
704
|
-
touch-action: auto !important;
|
|
705
|
-
overscroll-behavior: auto !important;
|
|
745
|
+
.proxy-file-dropdown {
|
|
746
|
+
height: 2.5rem !important;
|
|
747
|
+
border-radius: 0.5rem !important;
|
|
706
748
|
}
|
|
707
749
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
750
|
+
.refresh-button {
|
|
751
|
+
height: 2.5rem !important;
|
|
752
|
+
transition: all 0.2s ease;
|
|
753
|
+
|
|
754
|
+
&:hover {
|
|
755
|
+
.refresh-icon {
|
|
756
|
+
transform: rotate(180deg);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
715
759
|
}
|
|
716
760
|
|
|
717
|
-
.
|
|
718
|
-
|
|
719
|
-
height: 100%;
|
|
720
|
-
min-height: 300px;
|
|
721
|
-
max-height: 600px;
|
|
722
|
-
overflow: auto;
|
|
723
|
-
white-space: pre;
|
|
724
|
-
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
725
|
-
font-size: 14px;
|
|
726
|
-
line-height: 1.6;
|
|
727
|
-
background-color: transparent !important;
|
|
728
|
-
pointer-events: none;
|
|
729
|
-
z-index: 5;
|
|
730
|
-
position: absolute;
|
|
731
|
-
top: 0;
|
|
732
|
-
left: 0;
|
|
733
|
-
right: 0;
|
|
734
|
-
bottom: 0;
|
|
735
|
-
padding: 12px;
|
|
736
|
-
margin: 0;
|
|
761
|
+
.refresh-icon {
|
|
762
|
+
transition: transform 0.5s ease;
|
|
737
763
|
}
|
|
738
764
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
765
|
+
/* ==========================================================================
|
|
766
|
+
EDITOR CONTAINERS
|
|
767
|
+
========================================================================== */
|
|
768
|
+
|
|
769
|
+
.editor-container,
|
|
770
|
+
.proxy-editor-container {
|
|
771
|
+
position: relative;
|
|
772
|
+
overflow: hidden;
|
|
773
|
+
height: 400px;
|
|
774
|
+
max-height: 60vh;
|
|
775
|
+
border-radius: 8px;
|
|
776
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
|
777
|
+
background-color: #2e2f34;
|
|
778
|
+
transition: height 0.3s ease;
|
|
744
779
|
}
|
|
745
780
|
|
|
746
|
-
/* Proxy editor container */
|
|
747
781
|
.proxy-editor-container {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
max-height: 60vh;
|
|
752
|
-
background-color: #2e2f34;
|
|
753
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
|
782
|
+
/* Ensure proxy editor takes full container space */
|
|
783
|
+
display: flex;
|
|
784
|
+
flex-direction: column;
|
|
754
785
|
}
|
|
755
786
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
787
|
+
.proxy-editor-container .pb-4 {
|
|
788
|
+
/* Remove bottom padding to maximize space */
|
|
789
|
+
padding-bottom: 0 !important;
|
|
790
|
+
flex: 1;
|
|
791
|
+
display: flex;
|
|
792
|
+
flex-direction: column;
|
|
760
793
|
}
|
|
761
794
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
795
|
+
.proxy-editor-container .table-component {
|
|
796
|
+
/* Make proxy editor container take full height */
|
|
797
|
+
flex: 1;
|
|
798
|
+
display: flex;
|
|
799
|
+
flex-direction: column;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.editor-wrapper {
|
|
803
|
+
position: relative;
|
|
804
|
+
width: 100%;
|
|
805
|
+
height: 100%;
|
|
806
|
+
overflow: hidden;
|
|
807
|
+
border-radius: 8px;
|
|
766
808
|
}
|
|
767
809
|
|
|
768
|
-
/*
|
|
810
|
+
/* ==========================================================================
|
|
811
|
+
EDITOR TEXTAREAS
|
|
812
|
+
========================================================================== */
|
|
813
|
+
|
|
814
|
+
.code-editor,
|
|
769
815
|
.proxy-editor {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
816
|
+
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
817
|
+
font-size: 14px;
|
|
818
|
+
line-height: 1.6;
|
|
819
|
+
tab-size: 4;
|
|
820
|
+
background-color: transparent;
|
|
821
|
+
border: none;
|
|
822
|
+
outline: none;
|
|
823
|
+
resize: none;
|
|
824
|
+
width: 100%;
|
|
825
|
+
height: 100%;
|
|
826
|
+
overflow: auto;
|
|
827
|
+
-webkit-overflow-scrolling: touch;
|
|
828
|
+
padding: 12px;
|
|
829
|
+
margin: 0;
|
|
830
|
+
box-sizing: border-box;
|
|
780
831
|
}
|
|
781
832
|
|
|
782
|
-
.
|
|
783
|
-
|
|
833
|
+
.code-editor {
|
|
834
|
+
/* Make textarea text transparent so syntax highlighting shows through */
|
|
835
|
+
color: transparent !important;
|
|
836
|
+
z-index: 2;
|
|
837
|
+
position: relative;
|
|
838
|
+
background-color: transparent;
|
|
839
|
+
caret-color: #ffffff; /* Keep cursor visible */
|
|
840
|
+
|
|
841
|
+
/* Selection styling */
|
|
842
|
+
&::selection {
|
|
843
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
844
|
+
}
|
|
784
845
|
}
|
|
785
846
|
|
|
786
|
-
.proxy-editor
|
|
787
|
-
|
|
788
|
-
|
|
847
|
+
.proxy-editor {
|
|
848
|
+
@apply w-full h-full resize-none focus:outline-none;
|
|
849
|
+
background-color: transparent;
|
|
850
|
+
color: #e2e2e5; /* Keep normal text color for proxy editor */
|
|
851
|
+
/* Ensure proxy editor takes full height */
|
|
852
|
+
flex: 1;
|
|
853
|
+
min-height: 100%;
|
|
789
854
|
}
|
|
790
855
|
|
|
791
|
-
/*
|
|
856
|
+
/* ==========================================================================
|
|
857
|
+
CODE HIGHLIGHTING
|
|
858
|
+
========================================================================== */
|
|
859
|
+
|
|
860
|
+
.code-highlight {
|
|
861
|
+
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
862
|
+
font-size: 14px;
|
|
863
|
+
line-height: 1.6;
|
|
864
|
+
tab-size: 4;
|
|
865
|
+
/* Remove transparent color - let syntax highlighting show */
|
|
866
|
+
color: #f8f8f2 !important;
|
|
867
|
+
background: transparent;
|
|
868
|
+
border: none;
|
|
869
|
+
outline: none;
|
|
870
|
+
resize: none;
|
|
871
|
+
width: 100%;
|
|
872
|
+
height: 100%;
|
|
873
|
+
overflow: hidden;
|
|
874
|
+
white-space: pre;
|
|
875
|
+
pointer-events: none;
|
|
876
|
+
z-index: 1;
|
|
877
|
+
position: absolute;
|
|
878
|
+
top: 0;
|
|
879
|
+
left: 0;
|
|
880
|
+
padding: 12px;
|
|
881
|
+
margin: 0;
|
|
882
|
+
box-sizing: border-box;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
/* ==========================================================================
|
|
886
|
+
PRISM.JS SYNTAX HIGHLIGHTING THEME
|
|
887
|
+
========================================================================== */
|
|
888
|
+
|
|
792
889
|
code[class*="language-"],
|
|
793
890
|
pre[class*="language-"] {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
/* Code blocks */
|
|
891
|
+
color: #f8f8f2;
|
|
892
|
+
background: none;
|
|
893
|
+
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
|
|
894
|
+
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
|
|
895
|
+
text-align: left;
|
|
896
|
+
white-space: pre;
|
|
897
|
+
word-spacing: normal;
|
|
898
|
+
word-break: normal;
|
|
899
|
+
word-wrap: normal;
|
|
900
|
+
line-height: 1.5;
|
|
901
|
+
tab-size: 4;
|
|
902
|
+
hyphens: none;
|
|
903
|
+
}
|
|
904
|
+
|
|
809
905
|
pre[class*="language-"] {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
906
|
+
padding: 12px;
|
|
907
|
+
margin: 0;
|
|
908
|
+
overflow: auto;
|
|
909
|
+
border-radius: 4px;
|
|
910
|
+
font-family: "Menlo", "Monaco", "Courier New", monospace;
|
|
911
|
+
font-size: 14px;
|
|
912
|
+
line-height: 1.5;
|
|
913
|
+
tab-size: 4;
|
|
818
914
|
}
|
|
819
915
|
|
|
820
916
|
:not(pre) > code[class*="language-"],
|
|
821
917
|
pre[class*="language-"] {
|
|
822
|
-
|
|
823
|
-
|
|
918
|
+
background: #2e2f34;
|
|
919
|
+
white-space: pre;
|
|
824
920
|
}
|
|
825
921
|
|
|
826
|
-
/* Inline code */
|
|
827
922
|
:not(pre) > code[class*="language-"] {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
923
|
+
padding: 0.1em;
|
|
924
|
+
border-radius: 0.3em;
|
|
925
|
+
white-space: normal;
|
|
831
926
|
}
|
|
832
927
|
|
|
833
928
|
.token.comment,
|
|
834
929
|
.token.prolog,
|
|
835
930
|
.token.doctype,
|
|
836
931
|
.token.cdata {
|
|
837
|
-
|
|
838
|
-
|
|
932
|
+
color: #676f7d;
|
|
933
|
+
font-style: italic;
|
|
839
934
|
}
|
|
840
935
|
|
|
841
936
|
.token.punctuation {
|
|
842
|
-
|
|
937
|
+
color: #a9b7c6;
|
|
843
938
|
}
|
|
844
939
|
|
|
845
940
|
.namespace {
|
|
846
|
-
|
|
941
|
+
opacity: 0.8;
|
|
847
942
|
}
|
|
848
943
|
|
|
849
944
|
.token.property,
|
|
@@ -851,12 +946,12 @@ pre[class*="language-"] {
|
|
|
851
946
|
.token.constant,
|
|
852
947
|
.token.symbol,
|
|
853
948
|
.token.deleted {
|
|
854
|
-
|
|
949
|
+
color: #e06c75;
|
|
855
950
|
}
|
|
856
951
|
|
|
857
952
|
.token.boolean,
|
|
858
953
|
.token.number {
|
|
859
|
-
|
|
954
|
+
color: #c792ea;
|
|
860
955
|
}
|
|
861
956
|
|
|
862
957
|
.token.selector,
|
|
@@ -865,7 +960,7 @@ pre[class*="language-"] {
|
|
|
865
960
|
.token.char,
|
|
866
961
|
.token.builtin,
|
|
867
962
|
.token.inserted {
|
|
868
|
-
|
|
963
|
+
color: #98c379;
|
|
869
964
|
}
|
|
870
965
|
|
|
871
966
|
.token.operator,
|
|
@@ -873,120 +968,489 @@ pre[class*="language-"] {
|
|
|
873
968
|
.token.url,
|
|
874
969
|
.language-css .token.string,
|
|
875
970
|
.style .token.string {
|
|
876
|
-
|
|
971
|
+
color: #89ddff;
|
|
877
972
|
}
|
|
878
973
|
|
|
879
974
|
.token.atrule,
|
|
880
975
|
.token.attr-value,
|
|
881
976
|
.token.keyword {
|
|
882
|
-
|
|
977
|
+
color: #61afef;
|
|
883
978
|
}
|
|
884
979
|
|
|
885
980
|
.token.function,
|
|
886
981
|
.token.class-name {
|
|
887
|
-
|
|
982
|
+
color: #ffcb6b;
|
|
888
983
|
}
|
|
889
984
|
|
|
890
985
|
.token.regex,
|
|
891
986
|
.token.important,
|
|
892
987
|
.token.variable {
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
/* Add a slight hover effect to the editor for better UX */
|
|
897
|
-
.editor-container:hover {
|
|
898
|
-
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
|
899
|
-
transition: box-shadow 0.3s ease;
|
|
988
|
+
color: #c5e478;
|
|
900
989
|
}
|
|
901
990
|
|
|
902
991
|
.token.important,
|
|
903
992
|
.token.bold {
|
|
904
|
-
|
|
993
|
+
font-weight: bold;
|
|
905
994
|
}
|
|
906
995
|
|
|
907
996
|
.token.italic {
|
|
908
|
-
|
|
997
|
+
font-style: italic;
|
|
909
998
|
}
|
|
910
999
|
|
|
911
1000
|
.token.entity {
|
|
912
|
-
|
|
1001
|
+
cursor: help;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.editor-container:hover {
|
|
1005
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
|
1006
|
+
transition: box-shadow 0.3s ease;
|
|
913
1007
|
}
|
|
914
1008
|
|
|
915
|
-
/*
|
|
1009
|
+
/* ==========================================================================
|
|
1010
|
+
ERROR MESSAGES
|
|
1011
|
+
========================================================================== */
|
|
1012
|
+
|
|
916
1013
|
.error-container {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
border: 1px solid #dc2626;
|
|
924
|
-
background: linear-gradient(135deg, rgba(220, 38, 38, 0.1), rgba(220, 38, 38, 0.05));
|
|
925
|
-
box-shadow: 0 2px 8px rgba(220, 38, 38, 0.15);
|
|
1014
|
+
@apply flex items-start gap-3 p-4 bg-red-500/10 border border-red-500/20 rounded-lg mt-4 mb-4;
|
|
1015
|
+
|
|
1016
|
+
/* Prevent overflow in landscape mode */
|
|
1017
|
+
max-width: 100%;
|
|
1018
|
+
word-wrap: break-word;
|
|
1019
|
+
overflow-wrap: break-word;
|
|
926
1020
|
}
|
|
927
1021
|
|
|
928
1022
|
.error-icon {
|
|
929
|
-
|
|
930
|
-
align-items: center;
|
|
931
|
-
justify-content: center;
|
|
932
|
-
width: 28px;
|
|
933
|
-
height: 28px;
|
|
934
|
-
border-radius: 50%;
|
|
935
|
-
background: rgba(220, 38, 38, 0.2);
|
|
936
|
-
border: 1px solid rgba(220, 38, 38, 0.4);
|
|
937
|
-
color: #ef4444;
|
|
938
|
-
flex-shrink: 0;
|
|
1023
|
+
@apply flex-shrink-0 text-red-400;
|
|
939
1024
|
}
|
|
940
1025
|
|
|
941
1026
|
.error-content {
|
|
942
|
-
|
|
943
|
-
|
|
1027
|
+
@apply flex-1;
|
|
1028
|
+
min-width: 0; /* Allow text to shrink */
|
|
944
1029
|
}
|
|
945
1030
|
|
|
946
1031
|
.error-title {
|
|
947
|
-
|
|
948
|
-
font-size: 14px;
|
|
949
|
-
font-weight: 600;
|
|
950
|
-
margin-bottom: 4px;
|
|
951
|
-
letter-spacing: 0.015em;
|
|
1032
|
+
@apply text-red-400 font-medium text-sm mb-1;
|
|
952
1033
|
}
|
|
953
1034
|
|
|
954
1035
|
.error-text {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
font-family: "JetBrains Mono", "Fira Code", "Menlo", "Monaco", "Courier New", monospace;
|
|
959
|
-
word-break: break-word;
|
|
960
|
-
opacity: 0.9;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
/* iPhone portrait mode spacing fixes */
|
|
964
|
-
@media (max-width: 480px) and (orientation: portrait) {
|
|
965
|
-
.editor-controls-row {
|
|
966
|
-
gap: 0.75rem !important;
|
|
967
|
-
flex-wrap: wrap;
|
|
968
|
-
}
|
|
1036
|
+
@apply text-red-300 text-xs;
|
|
1037
|
+
word-break: break-word;
|
|
1038
|
+
}
|
|
969
1039
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
margin-bottom: 0.5rem;
|
|
974
|
-
}
|
|
1040
|
+
/* ==========================================================================
|
|
1041
|
+
CONSOLE STYLES
|
|
1042
|
+
========================================================================== */
|
|
975
1043
|
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
margin-top: 0.5rem;
|
|
979
|
-
}
|
|
1044
|
+
.console {
|
|
1045
|
+
@apply bg-dark-400 p-7 rounded relative border-dark-550 border-2;
|
|
980
1046
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1047
|
+
textarea {
|
|
1048
|
+
background: transparent;
|
|
1049
|
+
resize: none;
|
|
1050
|
+
height: calc(100vh - 450px);
|
|
1051
|
+
@apply w-full focus:outline-none text-xs text-white;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/* ==========================================================================
|
|
1056
|
+
SECTION DIVIDER
|
|
1057
|
+
========================================================================== */
|
|
1058
|
+
|
|
1059
|
+
.section-divider {
|
|
1060
|
+
margin: 24px 0; /* Balanced margin for better centering */
|
|
1061
|
+
height: 1px;
|
|
1062
|
+
width: 100%;
|
|
1063
|
+
position: relative;
|
|
1064
|
+
|
|
1065
|
+
/* Add subtle gradient effect for better visual separation */
|
|
1066
|
+
background: linear-gradient(
|
|
1067
|
+
90deg,
|
|
1068
|
+
transparent 0%,
|
|
1069
|
+
#3d3e44 20%,
|
|
1070
|
+
#3d3e44 80%,
|
|
1071
|
+
transparent 100%
|
|
1072
|
+
);
|
|
1073
|
+
border: none;
|
|
1074
|
+
|
|
1075
|
+
/* Add a subtle glow effect */
|
|
1076
|
+
box-shadow: 0 0 8px rgba(61, 62, 68, 0.3);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
/* ==========================================================================
|
|
1080
|
+
RESPONSIVE LAYOUT UTILITIES
|
|
1081
|
+
========================================================================== */
|
|
1082
|
+
|
|
1083
|
+
.flex-responsive-wrap {
|
|
1084
|
+
@apply flex flex-wrap items-center gap-4;
|
|
1085
|
+
}
|
|
986
1086
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1087
|
+
/* ==========================================================================
|
|
1088
|
+
MOBILE RESPONSIVE STYLES (max-width: 767px)
|
|
1089
|
+
========================================================================== */
|
|
1090
|
+
|
|
1091
|
+
@media (max-width: 767px) {
|
|
1092
|
+
/* Card container - increased height to use more available space */
|
|
1093
|
+
.card-dark {
|
|
1094
|
+
max-height: calc(100vh - 100px) !important; /* Increased from 120px */
|
|
1095
|
+
overflow-y: auto !important;
|
|
1096
|
+
-webkit-overflow-scrolling: touch !important;
|
|
1097
|
+
margin-bottom: 0.5rem !important; /* Reduced from 1rem */
|
|
1098
|
+
/* Reduced bottom padding to minimize empty space */
|
|
1099
|
+
padding-bottom: 0.5rem !important; /* Reduced from 1.5rem */
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/* Layout adjustments - almost no gap between dropdown and buttons */
|
|
1103
|
+
.flex-responsive-wrap {
|
|
1104
|
+
@apply flex-col items-stretch !important;
|
|
1105
|
+
gap: 0px !important; /* Reduced from 2px to eliminate space between dropdown and buttons */
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/* Button container - even spacing across full width */
|
|
1109
|
+
.flex-responsive-wrap > div:last-child {
|
|
1110
|
+
@apply flex justify-center !important;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/* Smaller buttons on mobile */
|
|
1114
|
+
.btn-action {
|
|
1115
|
+
height: 32px !important;
|
|
1116
|
+
min-height: 32px !important;
|
|
1117
|
+
padding: 0 8px !important;
|
|
1118
|
+
font-size: 12px !important;
|
|
1119
|
+
|
|
1120
|
+
svg {
|
|
1121
|
+
width: 14px !important;
|
|
1122
|
+
height: 14px !important;
|
|
990
1123
|
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/* Editor container heights - reduced for better mobile experience */
|
|
1127
|
+
.editor-container,
|
|
1128
|
+
.proxy-editor-container {
|
|
1129
|
+
height: 200px !important; /* Reduced from 280px for better mobile experience */
|
|
1130
|
+
max-height: 30vh !important; /* Reduced from 35vh */
|
|
1131
|
+
min-height: 180px !important; /* Reduced from 220px */
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/* Reduce editor height when JSON error is showing in portrait */
|
|
1135
|
+
.editor-container.has-error {
|
|
1136
|
+
height: 160px !important; /* Reduced to make room for error message */
|
|
1137
|
+
max-height: 25vh !important;
|
|
1138
|
+
min-height: 140px !important;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
/* Error message spacing on mobile */
|
|
1142
|
+
.error-container {
|
|
1143
|
+
margin: 8px 0 !important;
|
|
1144
|
+
padding: 8px !important;
|
|
1145
|
+
font-size: 11px !important;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
.error-title {
|
|
1149
|
+
font-size: 11px !important;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
.error-text {
|
|
1153
|
+
font-size: 10px !important;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/* Compact editor controls spacing - no margins */
|
|
1157
|
+
.editor-controls-row,
|
|
1158
|
+
.proxy-controls-row {
|
|
1159
|
+
margin-bottom: 0px !important; /* Eliminated margin completely */
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/* Compact editor containers - reduced margins for more space */
|
|
1163
|
+
.my-3 {
|
|
1164
|
+
margin: 6px 0 !important; /* Reduced margin between editor and controls */
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
.pb-4 {
|
|
1168
|
+
padding-bottom: 4px !important; /* Reduced padding */
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/* ==========================================================================
|
|
1173
|
+
TABLET RESPONSIVE STYLES (min-width: 768px)
|
|
1174
|
+
========================================================================== */
|
|
1175
|
+
|
|
1176
|
+
@media (min-width: 768px) {
|
|
1177
|
+
.flex-responsive-wrap {
|
|
1178
|
+
@apply flex-row justify-between items-center !important;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/* ==========================================================================
|
|
1183
|
+
DESKTOP RESPONSIVE STYLES (min-width: 1024px)
|
|
1184
|
+
========================================================================== */
|
|
1185
|
+
|
|
1186
|
+
@media (min-width: 1024px) {
|
|
1187
|
+
.editor-container,
|
|
1188
|
+
.proxy-editor-container {
|
|
1189
|
+
max-height: 60vh;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/* ==========================================================================
|
|
1194
|
+
LARGE DESKTOP RESPONSIVE STYLES (min-width: 1280px)
|
|
1195
|
+
========================================================================== */
|
|
1196
|
+
|
|
1197
|
+
@media (min-width: 1280px) {
|
|
1198
|
+
.editor-container,
|
|
1199
|
+
.proxy-editor-container {
|
|
1200
|
+
max-height: 70vh;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/* ==========================================================================
|
|
1205
|
+
MOBILE LANDSCAPE MODE (max-height: 500px + landscape)
|
|
1206
|
+
========================================================================== */
|
|
1207
|
+
|
|
1208
|
+
@media (max-height: 500px) and (orientation: landscape) and (min-width: 568px) {
|
|
1209
|
+
/* Make card fit in landscape mode with reduced bottom spacing */
|
|
1210
|
+
.card-dark {
|
|
1211
|
+
max-height: calc(100vh - 80px) !important; /* Increased from 60px to 80px */
|
|
1212
|
+
overflow-y: auto !important;
|
|
1213
|
+
-webkit-overflow-scrolling: touch !important;
|
|
1214
|
+
margin-bottom: 0.5rem !important; /* Reduced from 1rem */
|
|
1215
|
+
padding: 8px !important;
|
|
1216
|
+
/* Reduced bottom padding to minimize empty space */
|
|
1217
|
+
padding-bottom: 0.5rem !important; /* Reduced from 1.5rem */
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/* Truncate card cleanly when admin editor is open */
|
|
1221
|
+
.admin-editor-section:not(.landscape-hidden)
|
|
1222
|
+
+ .section-divider
|
|
1223
|
+
+ .proxy-editor-section.landscape-hidden {
|
|
1224
|
+
display: none !important;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/* Ensure proxy editor takes full space when visible */
|
|
1228
|
+
.proxy-editor-container {
|
|
1229
|
+
height: 130px !important;
|
|
1230
|
+
max-height: 130px !important;
|
|
1231
|
+
min-height: 100px !important;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
.proxy-editor {
|
|
1235
|
+
height: 100% !important;
|
|
1236
|
+
min-height: 100% !important;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
/* Compact headings */
|
|
1240
|
+
h4 {
|
|
1241
|
+
font-size: 16px !important;
|
|
1242
|
+
margin-bottom: 6px !important;
|
|
1243
|
+
padding-top: 6px !important;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
h5 {
|
|
1247
|
+
font-size: 14px !important;
|
|
1248
|
+
margin-bottom: 4px !important;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
/* Section divider */
|
|
1252
|
+
.section-divider {
|
|
1253
|
+
margin: 6px 0 !important;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/* Editor controls layout */
|
|
1257
|
+
.editor-controls-row,
|
|
1258
|
+
.proxy-controls-row {
|
|
1259
|
+
gap: 6px !important;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
/* Compact button styling */
|
|
1263
|
+
.btn-action {
|
|
1264
|
+
min-height: 28px !important;
|
|
1265
|
+
height: 28px !important;
|
|
1266
|
+
padding: 0 6px !important;
|
|
1267
|
+
font-size: 11px !important;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/* Hide button text to save space */
|
|
1271
|
+
.btn-action span {
|
|
1272
|
+
display: none !important;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/* Compact editor containers - reduced margins for more space */
|
|
1276
|
+
.my-3 {
|
|
1277
|
+
margin: 4px 0 !important; /* Reduced from 6px */
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
.pb-4 {
|
|
1281
|
+
padding-bottom: 2px !important; /* Reduced from 4px */
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/* Editor container heights - increased to use more available space */
|
|
1285
|
+
.editor-container,
|
|
1286
|
+
.proxy-editor-container {
|
|
1287
|
+
height: 180px !important; /* Increased from 130px */
|
|
1288
|
+
max-height: 180px !important;
|
|
1289
|
+
min-height: 150px !important; /* Increased from 100px */
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
/* Reduce editor height when JSON error is showing */
|
|
1293
|
+
.editor-container.has-error {
|
|
1294
|
+
height: 120px !important; /* Reduced to make room for error message */
|
|
1295
|
+
max-height: 120px !important;
|
|
1296
|
+
min-height: 100px !important;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/* Ensure proxy editor takes full space when visible - increased height */
|
|
1300
|
+
.proxy-editor-container {
|
|
1301
|
+
height: 180px !important; /* Increased from 130px */
|
|
1302
|
+
max-height: 180px !important;
|
|
1303
|
+
min-height: 150px !important;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
/* Editor textarea heights - ensure syntax highlighting works */
|
|
1307
|
+
.code-editor,
|
|
1308
|
+
.proxy-editor {
|
|
1309
|
+
font-size: 11px !important;
|
|
1310
|
+
line-height: 1.4 !important;
|
|
1311
|
+
padding: 6px !important;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/* Syntax highlighting in landscape mode */
|
|
1315
|
+
.code-highlight {
|
|
1316
|
+
font-size: 11px !important;
|
|
1317
|
+
line-height: 1.4 !important;
|
|
1318
|
+
padding: 6px !important;
|
|
1319
|
+
/* Ensure syntax highlighting is visible in landscape */
|
|
1320
|
+
color: #f8f8f2 !important;
|
|
1321
|
+
opacity: 1 !important;
|
|
1322
|
+
display: block !important;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/* Compact error messages */
|
|
1326
|
+
.error-container {
|
|
1327
|
+
margin: 2px 0 !important; /* Reduced from 4px */
|
|
1328
|
+
padding: 4px 6px !important; /* More compact padding */
|
|
1329
|
+
font-size: 9px !important; /* Reduced from 10px */
|
|
1330
|
+
border-radius: 4px !important; /* Smaller border radius */
|
|
1331
|
+
gap: 6px !important; /* Reduced gap */
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
.error-icon {
|
|
1335
|
+
width: 12px !important;
|
|
1336
|
+
height: 12px !important;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
.error-icon svg {
|
|
1340
|
+
width: 12px !important;
|
|
1341
|
+
height: 12px !important;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
.error-title {
|
|
1345
|
+
font-size: 9px !important; /* Reduced from 10px */
|
|
1346
|
+
margin-bottom: 2px !important;
|
|
1347
|
+
font-weight: 500 !important;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
.error-text {
|
|
1351
|
+
font-size: 8px !important; /* Reduced from 9px */
|
|
1352
|
+
line-height: 1.2 !important;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
/* ==========================================================================
|
|
1357
|
+
VERY SHORT LANDSCAPE SCREENS (max-height: 400px + landscape)
|
|
1358
|
+
========================================================================== */
|
|
1359
|
+
|
|
1360
|
+
@media (max-height: 400px) and (orientation: landscape) {
|
|
1361
|
+
.card-dark {
|
|
1362
|
+
max-height: calc(100vh - 70px) !important; /* Increased from 60px */
|
|
1363
|
+
padding: 6px !important;
|
|
1364
|
+
margin-bottom: 0.5rem !important; /* Reduced from 1rem */
|
|
1365
|
+
/* Reduced bottom padding to minimize empty space */
|
|
1366
|
+
padding-bottom: 0.5rem !important; /* Reduced from 1.5rem */
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.editor-container,
|
|
1370
|
+
.proxy-editor-container {
|
|
1371
|
+
height: 140px !important; /* Increased from 100px */
|
|
1372
|
+
max-height: 140px !important;
|
|
1373
|
+
min-height: 120px !important; /* Increased from 80px */
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/* Reduce editor height when JSON error is showing in very short landscape */
|
|
1377
|
+
.editor-container.has-error {
|
|
1378
|
+
height: 90px !important; /* Reduced to make room for error message */
|
|
1379
|
+
max-height: 90px !important;
|
|
1380
|
+
min-height: 80px !important;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/* Ensure proxy editor takes full space in very short landscape */
|
|
1384
|
+
.proxy-editor {
|
|
1385
|
+
height: 100% !important;
|
|
1386
|
+
min-height: 100% !important;
|
|
1387
|
+
font-size: 10px !important;
|
|
1388
|
+
line-height: 1.3 !important;
|
|
1389
|
+
padding: 4px !important;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
.code-editor {
|
|
1393
|
+
font-size: 10px !important;
|
|
1394
|
+
line-height: 1.3 !important;
|
|
1395
|
+
padding: 4px !important;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
/* Ensure syntax highlighting works in very short landscape */
|
|
1399
|
+
.code-highlight {
|
|
1400
|
+
font-size: 10px !important;
|
|
1401
|
+
line-height: 1.3 !important;
|
|
1402
|
+
padding: 4px !important;
|
|
1403
|
+
color: #f8f8f2 !important;
|
|
1404
|
+
opacity: 1 !important;
|
|
1405
|
+
display: block !important;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/* Ultra-compact error messages for very short landscape */
|
|
1409
|
+
.error-container {
|
|
1410
|
+
margin: 1px 0 !important;
|
|
1411
|
+
padding: 2px 4px !important;
|
|
1412
|
+
font-size: 8px !important;
|
|
1413
|
+
border-radius: 3px !important;
|
|
1414
|
+
gap: 4px !important;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
.error-icon {
|
|
1418
|
+
width: 10px !important;
|
|
1419
|
+
height: 10px !important;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
.error-icon svg {
|
|
1423
|
+
width: 10px !important;
|
|
1424
|
+
height: 10px !important;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
.error-title {
|
|
1428
|
+
font-size: 8px !important;
|
|
1429
|
+
margin-bottom: 1px !important;
|
|
1430
|
+
font-weight: 500 !important;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
.error-text {
|
|
1434
|
+
font-size: 7px !important;
|
|
1435
|
+
line-height: 1.1 !important;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
/* Section divider */
|
|
1440
|
+
.section-divider {
|
|
1441
|
+
margin: 12px 0 !important;
|
|
1442
|
+
/* Reduce glow effect in landscape */
|
|
1443
|
+
box-shadow: 0 0 4px rgba(61, 62, 68, 0.2) !important;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
/* Compact section headers in landscape */
|
|
1447
|
+
.admin-editor-section h5,
|
|
1448
|
+
.proxy-editor-section h5 {
|
|
1449
|
+
padding-bottom: 4px !important;
|
|
1450
|
+
|
|
1451
|
+
&::after {
|
|
1452
|
+
width: 30px !important;
|
|
1453
|
+
height: 1px !important;
|
|
1454
|
+
}
|
|
991
1455
|
}
|
|
992
1456
|
</style>
|