portapack 0.3.2 → 0.4.0
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/CHANGELOG.md +14 -0
- package/README.md +5 -39
- package/desktop/README.md +112 -0
- package/desktop/app.go +61 -0
- package/desktop/frontend/README.md +8 -0
- package/desktop/frontend/index.html +13 -0
- package/desktop/frontend/package-lock.json +873 -0
- package/desktop/frontend/package.json +18 -0
- package/desktop/frontend/src/App.vue +805 -0
- package/desktop/frontend/src/assets/fonts/OFL.txt +93 -0
- package/desktop/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 +0 -0
- package/desktop/frontend/src/main.js +5 -0
- package/desktop/frontend/src/style.css +26 -0
- package/desktop/frontend/vite.config.js +7 -0
- package/desktop/go.mod +38 -0
- package/desktop/go.sum +79 -0
- package/desktop/main.go +36 -0
- package/desktop/wails.json +14 -0
- package/dist/cli/cli-entry.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/docs/.vitepress/config.ts +2 -0
- package/docs/architecture.md +186 -0
- package/docs/getting-started.md +1 -2
- package/docs/roadmap.md +233 -0
- package/examples/main.ts +0 -22
- package/package.json +1 -1
- package/src/core/bundler.ts +0 -2
- package/src/core/extractor.ts +0 -5
- package/tsup.config.ts +0 -1
@@ -0,0 +1,805 @@
|
|
1
|
+
<script setup>
|
2
|
+
import { ref, onMounted, watch } from 'vue';
|
3
|
+
import {RunPortapack} from "../wailsjs/go/main/App"
|
4
|
+
|
5
|
+
// State for CLI options
|
6
|
+
const inputPath = ref('');
|
7
|
+
const outputPath = ref('');
|
8
|
+
const minifyAll = ref(false);
|
9
|
+
const noMinifyHtml = ref(false);
|
10
|
+
const noMinifyCss = ref(false);
|
11
|
+
const noMinifyJs = ref(false);
|
12
|
+
const embedAssets = ref(false);
|
13
|
+
const recursive = ref(false);
|
14
|
+
const maxDepth = ref('');
|
15
|
+
const baseUrl = ref('');
|
16
|
+
const dryRun = ref(false);
|
17
|
+
const verbose = ref(false);
|
18
|
+
const logLevel = ref('info'); // Default log level
|
19
|
+
const commandOutput = ref('');
|
20
|
+
const isProcessing = ref(false); // To indicate when the command is running
|
21
|
+
|
22
|
+
// Theme state
|
23
|
+
const isDarkMode = ref(true); // Default to dark mode
|
24
|
+
const mascotPath = ref('https://res.cloudinary.com/dwaypfftw/image/upload/v1744373244/portapack-transparent_qlyfpm.png');
|
25
|
+
|
26
|
+
// Toggle light/dark mode
|
27
|
+
const toggleTheme = () => {
|
28
|
+
isDarkMode.value = !isDarkMode.value;
|
29
|
+
document.documentElement.setAttribute('data-theme', isDarkMode.value ? 'dark' : 'light');
|
30
|
+
};
|
31
|
+
|
32
|
+
// Watchers for minification logic
|
33
|
+
// When minifyAll is true, individual no-minify options should be disabled but not set to true
|
34
|
+
// When minifyAll is false, individual no-minify options are enabled
|
35
|
+
watch(minifyAll, (newVal) => {
|
36
|
+
if (newVal) {
|
37
|
+
noMinifyHtml.value = false;
|
38
|
+
noMinifyCss.value = false;
|
39
|
+
noMinifyJs.value = false;
|
40
|
+
}
|
41
|
+
});
|
42
|
+
|
43
|
+
// Build and execute the portapack command
|
44
|
+
const executePortapack = async () => {
|
45
|
+
isProcessing.value = true;
|
46
|
+
commandOutput.value = 'Running portapack command...';
|
47
|
+
|
48
|
+
try {
|
49
|
+
// Construct command arguments
|
50
|
+
let args = [];
|
51
|
+
if (inputPath.value) {
|
52
|
+
args.push(inputPath.value);
|
53
|
+
}
|
54
|
+
if (outputPath.value) {
|
55
|
+
args.push('-o', outputPath.value);
|
56
|
+
}
|
57
|
+
if (minifyAll.value) {
|
58
|
+
args.push('-m');
|
59
|
+
} else {
|
60
|
+
// Only add individual no-minify if minifyAll is false
|
61
|
+
if (noMinifyHtml.value) args.push('--no-minify-html');
|
62
|
+
if (noMinifyCss.value) args.push('--no-minify-css');
|
63
|
+
if (noMinifyJs.value) args.push('--no-minify-js');
|
64
|
+
}
|
65
|
+
if (embedAssets.value) {
|
66
|
+
args.push('-e');
|
67
|
+
} else {
|
68
|
+
args.push('--no-embed-assets');
|
69
|
+
}
|
70
|
+
if (recursive.value) {
|
71
|
+
args.push('-r');
|
72
|
+
if (maxDepth.value) args.push(maxDepth.value);
|
73
|
+
}
|
74
|
+
if (baseUrl.value) {
|
75
|
+
args.push('-b', baseUrl.value);
|
76
|
+
}
|
77
|
+
if (dryRun.value) {
|
78
|
+
args.push('-d');
|
79
|
+
}
|
80
|
+
if (verbose.value) {
|
81
|
+
args.push('-v');
|
82
|
+
}
|
83
|
+
if (logLevel.value && logLevel.value !== 'info') { // 'info' is default, no need to explicitly add
|
84
|
+
args.push('--log-level', logLevel.value);
|
85
|
+
}
|
86
|
+
|
87
|
+
console.log("Executing with arguments:", args);
|
88
|
+
|
89
|
+
// Call Go backend to execute the command
|
90
|
+
const result = await RunPortapack(args); // This method will be implemented in app.go
|
91
|
+
commandOutput.value = result;
|
92
|
+
} catch (error) {
|
93
|
+
commandOutput.value = `Error: ${error.message || error}`;
|
94
|
+
console.error("Portapack command failed:", error);
|
95
|
+
} finally {
|
96
|
+
isProcessing.value = false;
|
97
|
+
}
|
98
|
+
};
|
99
|
+
|
100
|
+
const resetOptions = () => {
|
101
|
+
inputPath.value = '';
|
102
|
+
outputPath.value = '';
|
103
|
+
minifyAll.value = false;
|
104
|
+
noMinifyHtml.value = false;
|
105
|
+
noMinifyCss.value = false;
|
106
|
+
noMinifyJs.value = false;
|
107
|
+
embedAssets.value = false;
|
108
|
+
recursive.value = false;
|
109
|
+
maxDepth.value = '';
|
110
|
+
baseUrl.value = '';
|
111
|
+
dryRun.value = false;
|
112
|
+
verbose.value = false;
|
113
|
+
logLevel.value = 'info';
|
114
|
+
commandOutput.value = '';
|
115
|
+
};
|
116
|
+
|
117
|
+
onMounted(() => {
|
118
|
+
// Set initial theme based on default
|
119
|
+
document.documentElement.setAttribute('data-theme', isDarkMode.value ? 'dark' : 'light');
|
120
|
+
});
|
121
|
+
</script>
|
122
|
+
|
123
|
+
<template>
|
124
|
+
<div class="container" :class="{ 'dark-mode': isDarkMode, 'light-mode': !isDarkMode }">
|
125
|
+
<header class="app-header">
|
126
|
+
<img :src="mascotPath" alt="Portapack Mascot" class="mascot" />
|
127
|
+
<h1>Portapack CLI UI</h1>
|
128
|
+
<button @click="toggleTheme" class="theme-toggle">
|
129
|
+
<span v-if="isDarkMode">☀️ Light Mode</span>
|
130
|
+
<span v-else>🌙 Dark Mode</span>
|
131
|
+
</button>
|
132
|
+
</header>
|
133
|
+
|
134
|
+
<main class="main-content">
|
135
|
+
<section class="input-section card">
|
136
|
+
<h2>Input & Output</h2>
|
137
|
+
<div class="form-group">
|
138
|
+
<label for="inputPath">Input HTML File or URL:</label>
|
139
|
+
<div class="input-wrapper">
|
140
|
+
<input id="inputPath" v-model="inputPath" placeholder="e.g., index.html or https://example.com" />
|
141
|
+
<div class="input-icon">📁</div>
|
142
|
+
</div>
|
143
|
+
</div>
|
144
|
+
<div class="form-group">
|
145
|
+
<label for="outputPath">Output File Path (-o, --output):</label>
|
146
|
+
<div class="input-wrapper">
|
147
|
+
<input id="outputPath" v-model="outputPath" placeholder="e.g., output.html" />
|
148
|
+
<div class="input-icon">💾</div>
|
149
|
+
</div>
|
150
|
+
</div>
|
151
|
+
</section>
|
152
|
+
|
153
|
+
<section class="options-section">
|
154
|
+
<div class="card">
|
155
|
+
<h2>Minification Options</h2>
|
156
|
+
<div class="form-group checkbox-group">
|
157
|
+
<label class="checkbox-container">
|
158
|
+
<input type="checkbox" id="minifyAll" v-model="minifyAll" />
|
159
|
+
<span class="checkmark"></span>
|
160
|
+
Enable All Minification (-m, --minify)
|
161
|
+
</label>
|
162
|
+
</div>
|
163
|
+
<div class="form-group checkbox-group">
|
164
|
+
<label class="checkbox-container" :class="{ disabled: minifyAll }">
|
165
|
+
<input type="checkbox" id="noMinifyHtml" v-model="noMinifyHtml" :disabled="minifyAll" />
|
166
|
+
<span class="checkmark"></span>
|
167
|
+
Disable HTML Minification (--no-minify-html)
|
168
|
+
</label>
|
169
|
+
</div>
|
170
|
+
<div class="form-group checkbox-group">
|
171
|
+
<label class="checkbox-container" :class="{ disabled: minifyAll }">
|
172
|
+
<input type="checkbox" id="noMinifyCss" v-model="noMinifyCss" :disabled="minifyAll" />
|
173
|
+
<span class="checkmark"></span>
|
174
|
+
Disable CSS Minification (--no-minify-css)
|
175
|
+
</label>
|
176
|
+
</div>
|
177
|
+
<div class="form-group checkbox-group">
|
178
|
+
<label class="checkbox-container" :class="{ disabled: minifyAll }">
|
179
|
+
<input type="checkbox" id="noMinifyJs" v-model="noMinifyJs" :disabled="minifyAll" />
|
180
|
+
<span class="checkmark"></span>
|
181
|
+
Disable JavaScript Minification (--no-minify-js)
|
182
|
+
</label>
|
183
|
+
</div>
|
184
|
+
</div>
|
185
|
+
|
186
|
+
<div class="card">
|
187
|
+
<h2>Asset Handling</h2>
|
188
|
+
<div class="form-group checkbox-group">
|
189
|
+
<label class="checkbox-container">
|
190
|
+
<input type="checkbox" id="embedAssets" v-model="embedAssets" />
|
191
|
+
<span class="checkmark"></span>
|
192
|
+
Embed Assets as Data URIs (-e, --embed-assets)
|
193
|
+
</label>
|
194
|
+
</div>
|
195
|
+
</div>
|
196
|
+
|
197
|
+
<div class="card">
|
198
|
+
<h2>Recursive Crawling</h2>
|
199
|
+
<div class="form-group checkbox-group">
|
200
|
+
<label class="checkbox-container">
|
201
|
+
<input type="checkbox" id="recursive" v-model="recursive" />
|
202
|
+
<span class="checkmark"></span>
|
203
|
+
Recursively Crawl Site (-r, --recursive)
|
204
|
+
</label>
|
205
|
+
</div>
|
206
|
+
<div class="form-group" v-if="recursive">
|
207
|
+
<label for="maxDepth">Max Depth (optional, for -r):</label>
|
208
|
+
<div class="input-wrapper">
|
209
|
+
<input type="number" id="maxDepth" v-model="maxDepth" placeholder="e.g., 2" min="0" />
|
210
|
+
<div class="input-icon">🔢</div>
|
211
|
+
</div>
|
212
|
+
</div>
|
213
|
+
</div>
|
214
|
+
</section>
|
215
|
+
|
216
|
+
<section class="advanced-options card">
|
217
|
+
<h2>Advanced Options</h2>
|
218
|
+
<div class="form-group">
|
219
|
+
<label for="baseUrl">Base URL for Relative Links (-b, --base-url):</label>
|
220
|
+
<div class="input-wrapper">
|
221
|
+
<input id="baseUrl" v-model="baseUrl" placeholder="e.g., http://localhost:8080" />
|
222
|
+
<div class="input-icon">🌐</div>
|
223
|
+
</div>
|
224
|
+
</div>
|
225
|
+
<div class="form-group checkbox-group">
|
226
|
+
<label class="checkbox-container">
|
227
|
+
<input type="checkbox" id="dryRun" v-model="dryRun" />
|
228
|
+
<span class="checkmark"></span>
|
229
|
+
Dry Run (-d, --dry-run)
|
230
|
+
</label>
|
231
|
+
</div>
|
232
|
+
<div class="form-group checkbox-group">
|
233
|
+
<label class="checkbox-container">
|
234
|
+
<input type="checkbox" id="verbose" v-model="verbose" />
|
235
|
+
<span class="checkmark"></span>
|
236
|
+
Enable Verbose Logging (-v, --verbose)
|
237
|
+
</label>
|
238
|
+
</div>
|
239
|
+
<div class="form-group">
|
240
|
+
<label for="logLevel">Log Level (--log-level):</label>
|
241
|
+
<div class="select-wrapper">
|
242
|
+
<select id="logLevel" v-model="logLevel">
|
243
|
+
<option value="debug">debug</option>
|
244
|
+
<option value="info">info</option>
|
245
|
+
<option value="warn">warn</option>
|
246
|
+
<option value="error">error</option>
|
247
|
+
<option value="silent">silent</option>
|
248
|
+
<option value="none">none</option>
|
249
|
+
</select>
|
250
|
+
<div class="select-arrow">▼</div>
|
251
|
+
</div>
|
252
|
+
</div>
|
253
|
+
</section>
|
254
|
+
|
255
|
+
<div class="actions">
|
256
|
+
<button @click="executePortapack" :disabled="isProcessing" class="primary-button">
|
257
|
+
{{ isProcessing ? 'Bundling...' : '📦 Bundle!' }}
|
258
|
+
</button>
|
259
|
+
<button @click="resetOptions" :disabled="isProcessing" class="secondary-button">Reset Options</button>
|
260
|
+
</div>
|
261
|
+
|
262
|
+
<section class="output-log card">
|
263
|
+
<h2>Command Output</h2>
|
264
|
+
<pre>{{ commandOutput }}</pre>
|
265
|
+
</section>
|
266
|
+
</main>
|
267
|
+
</div>
|
268
|
+
</template>
|
269
|
+
|
270
|
+
<style>
|
271
|
+
/* Base styles from style.css and additional for App.vue */
|
272
|
+
html {
|
273
|
+
background-color: rgba(27, 38, 54, 1); /* Base dark background */
|
274
|
+
text-align: center;
|
275
|
+
}
|
276
|
+
|
277
|
+
body {
|
278
|
+
margin: 0;
|
279
|
+
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
280
|
+
}
|
281
|
+
|
282
|
+
@font-face {
|
283
|
+
font-family: "Nunito";
|
284
|
+
font-style: normal;
|
285
|
+
font-weight: 400;
|
286
|
+
src: local(""), url("./assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
|
287
|
+
}
|
288
|
+
|
289
|
+
#app {
|
290
|
+
height: 100vh;
|
291
|
+
text-align: center;
|
292
|
+
}
|
293
|
+
|
294
|
+
/* Light/Dark Mode variables */
|
295
|
+
:root {
|
296
|
+
/* Dark mode colors */
|
297
|
+
--bg-dark: rgba(27, 38, 54, 1);
|
298
|
+
--text-dark: #ffffff;
|
299
|
+
--card-bg-dark: rgba(35, 49, 70, 0.8);
|
300
|
+
--border-dark: rgba(50, 70, 90, 0.7);
|
301
|
+
--input-bg-dark: #2c3e50;
|
302
|
+
--input-border-dark: #4a6572;
|
303
|
+
--input-focus-dark: #5dade2;
|
304
|
+
--checkbox-bg-dark: #34495e;
|
305
|
+
--checkbox-checked-dark: #3498db;
|
306
|
+
|
307
|
+
/* Light mode colors */
|
308
|
+
--bg-light: linear-gradient(135deg, #ffd89b 0%, #19547b 100%);
|
309
|
+
--text-light: #2c3e50;
|
310
|
+
--card-bg-light: rgba(255, 255, 255, 0.95);
|
311
|
+
--border-light: #e0e6ed;
|
312
|
+
--input-bg-light: #ffffff;
|
313
|
+
--input-border-light: #d1d9e6;
|
314
|
+
--input-focus-light: #f39c12;
|
315
|
+
--checkbox-bg-light: #f8f9fa;
|
316
|
+
--checkbox-checked-light: #f39c12;
|
317
|
+
|
318
|
+
/* Button colors */
|
319
|
+
--btn-primary-dark: linear-gradient(135deg, #4CAF50, #45a049);
|
320
|
+
--btn-primary-light: linear-gradient(135deg, #667eea, #764ba2);
|
321
|
+
--btn-secondary-dark: linear-gradient(135deg, #6c757d, #5a6268);
|
322
|
+
--btn-secondary-light: linear-gradient(135deg, #a8a8a8, #8d8d8d);
|
323
|
+
}
|
324
|
+
|
325
|
+
/* Theme application */
|
326
|
+
html[data-theme='dark'] {
|
327
|
+
background: var(--bg-dark);
|
328
|
+
color: var(--text-dark);
|
329
|
+
}
|
330
|
+
|
331
|
+
html[data-theme='light'] {
|
332
|
+
background: var(--bg-light);
|
333
|
+
color: var(--text-light);
|
334
|
+
}
|
335
|
+
|
336
|
+
/* General Layout */
|
337
|
+
.container {
|
338
|
+
display: flex;
|
339
|
+
flex-direction: column;
|
340
|
+
align-items: center;
|
341
|
+
min-height: 100vh;
|
342
|
+
padding: 20px;
|
343
|
+
box-sizing: border-box;
|
344
|
+
}
|
345
|
+
|
346
|
+
.dark-mode {
|
347
|
+
color: var(--text-dark);
|
348
|
+
}
|
349
|
+
|
350
|
+
.light-mode {
|
351
|
+
color: var(--text-light);
|
352
|
+
}
|
353
|
+
|
354
|
+
.app-header {
|
355
|
+
display: flex;
|
356
|
+
align-items: center;
|
357
|
+
justify-content: center;
|
358
|
+
width: 100%;
|
359
|
+
max-width: 800px;
|
360
|
+
margin-bottom: 30px;
|
361
|
+
gap: 20px;
|
362
|
+
position: relative;
|
363
|
+
}
|
364
|
+
|
365
|
+
.mascot {
|
366
|
+
width: 80px;
|
367
|
+
height: auto;
|
368
|
+
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
|
369
|
+
}
|
370
|
+
|
371
|
+
h1 {
|
372
|
+
font-size: 2.5em;
|
373
|
+
margin: 0;
|
374
|
+
font-weight: 700;
|
375
|
+
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
376
|
+
}
|
377
|
+
|
378
|
+
.light-mode h1 {
|
379
|
+
color: var(--text-light);
|
380
|
+
text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8);
|
381
|
+
}
|
382
|
+
|
383
|
+
.theme-toggle {
|
384
|
+
position: absolute;
|
385
|
+
right: 0;
|
386
|
+
padding: 12px 20px;
|
387
|
+
border-radius: 25px;
|
388
|
+
cursor: pointer;
|
389
|
+
border: none;
|
390
|
+
font-weight: 600;
|
391
|
+
transition: all 0.3s ease;
|
392
|
+
display: flex;
|
393
|
+
align-items: center;
|
394
|
+
gap: 8px;
|
395
|
+
font-size: 0.9em;
|
396
|
+
backdrop-filter: blur(10px);
|
397
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
398
|
+
}
|
399
|
+
|
400
|
+
.dark-mode .theme-toggle {
|
401
|
+
background: rgba(255, 255, 255, 0.1);
|
402
|
+
color: white;
|
403
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
404
|
+
}
|
405
|
+
|
406
|
+
.light-mode .theme-toggle {
|
407
|
+
background: rgba(255, 255, 255, 0.9);
|
408
|
+
color: var(--text-light);
|
409
|
+
border: 1px solid rgba(255, 255, 255, 0.3);
|
410
|
+
}
|
411
|
+
|
412
|
+
.theme-toggle:hover {
|
413
|
+
transform: translateY(-2px);
|
414
|
+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
|
415
|
+
}
|
416
|
+
|
417
|
+
.main-content {
|
418
|
+
display: flex;
|
419
|
+
flex-direction: column;
|
420
|
+
gap: 20px;
|
421
|
+
width: 100%;
|
422
|
+
max-width: 800px;
|
423
|
+
}
|
424
|
+
|
425
|
+
.card {
|
426
|
+
backdrop-filter: blur(10px);
|
427
|
+
border-radius: 15px;
|
428
|
+
padding: 25px;
|
429
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
430
|
+
text-align: left;
|
431
|
+
transition: all 0.3s ease;
|
432
|
+
border: 1px solid transparent;
|
433
|
+
}
|
434
|
+
|
435
|
+
.dark-mode .card {
|
436
|
+
background: var(--card-bg-dark);
|
437
|
+
border-color: var(--border-dark);
|
438
|
+
}
|
439
|
+
|
440
|
+
.light-mode .card {
|
441
|
+
background: var(--card-bg-light);
|
442
|
+
border-color: var(--border-light);
|
443
|
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
444
|
+
}
|
445
|
+
|
446
|
+
.card:hover {
|
447
|
+
transform: translateY(-2px);
|
448
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
|
449
|
+
}
|
450
|
+
|
451
|
+
.light-mode .card:hover {
|
452
|
+
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
|
453
|
+
}
|
454
|
+
|
455
|
+
.options-section {
|
456
|
+
display: grid;
|
457
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
458
|
+
gap: 20px;
|
459
|
+
}
|
460
|
+
|
461
|
+
h2 {
|
462
|
+
margin-top: 0;
|
463
|
+
border-bottom: 2px solid;
|
464
|
+
padding-bottom: 12px;
|
465
|
+
margin-bottom: 25px;
|
466
|
+
font-size: 1.4em;
|
467
|
+
font-weight: 600;
|
468
|
+
}
|
469
|
+
|
470
|
+
.dark-mode h2 {
|
471
|
+
color: var(--text-dark);
|
472
|
+
border-color: var(--border-dark);
|
473
|
+
}
|
474
|
+
|
475
|
+
.light-mode h2 {
|
476
|
+
color: var(--text-light);
|
477
|
+
border-color: var(--border-light);
|
478
|
+
}
|
479
|
+
|
480
|
+
.form-group {
|
481
|
+
margin-bottom: 20px;
|
482
|
+
}
|
483
|
+
|
484
|
+
.form-group label {
|
485
|
+
display: block;
|
486
|
+
margin-bottom: 8px;
|
487
|
+
font-weight: 600;
|
488
|
+
font-size: 0.95em;
|
489
|
+
}
|
490
|
+
|
491
|
+
.dark-mode .form-group label {
|
492
|
+
color: var(--text-dark);
|
493
|
+
}
|
494
|
+
|
495
|
+
.light-mode .form-group label {
|
496
|
+
color: var(--text-light);
|
497
|
+
}
|
498
|
+
|
499
|
+
/* Enhanced Input Styles */
|
500
|
+
.input-wrapper {
|
501
|
+
position: relative;
|
502
|
+
display: flex;
|
503
|
+
align-items: center;
|
504
|
+
}
|
505
|
+
|
506
|
+
.input-wrapper input {
|
507
|
+
width: 100%;
|
508
|
+
padding: 15px 50px 15px 15px;
|
509
|
+
border-radius: 10px;
|
510
|
+
border: 2px solid;
|
511
|
+
font-size: 1em;
|
512
|
+
transition: all 0.3s ease;
|
513
|
+
box-sizing: border-box;
|
514
|
+
font-family: inherit;
|
515
|
+
}
|
516
|
+
|
517
|
+
.dark-mode .input-wrapper input {
|
518
|
+
background: var(--input-bg-dark);
|
519
|
+
border-color: var(--input-border-dark);
|
520
|
+
color: var(--text-dark);
|
521
|
+
}
|
522
|
+
|
523
|
+
.light-mode .input-wrapper input {
|
524
|
+
background: var(--input-bg-light);
|
525
|
+
border-color: var(--input-border-light);
|
526
|
+
color: var(--text-light);
|
527
|
+
}
|
528
|
+
|
529
|
+
.input-wrapper input:focus {
|
530
|
+
outline: none;
|
531
|
+
transform: translateY(-1px);
|
532
|
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
533
|
+
}
|
534
|
+
|
535
|
+
.dark-mode .input-wrapper input:focus {
|
536
|
+
border-color: var(--input-focus-dark);
|
537
|
+
box-shadow: 0 0 0 3px rgba(93, 173, 226, 0.2);
|
538
|
+
}
|
539
|
+
|
540
|
+
.light-mode .input-wrapper input:focus {
|
541
|
+
border-color: var(--input-focus-light);
|
542
|
+
box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.2);
|
543
|
+
}
|
544
|
+
|
545
|
+
.input-icon {
|
546
|
+
position: absolute;
|
547
|
+
right: 15px;
|
548
|
+
font-size: 1.2em;
|
549
|
+
opacity: 0.6;
|
550
|
+
pointer-events: none;
|
551
|
+
}
|
552
|
+
|
553
|
+
/* Enhanced Select Styles */
|
554
|
+
.select-wrapper {
|
555
|
+
position: relative;
|
556
|
+
display: flex;
|
557
|
+
align-items: center;
|
558
|
+
}
|
559
|
+
|
560
|
+
.select-wrapper select {
|
561
|
+
width: 100%;
|
562
|
+
padding: 15px 40px 15px 15px;
|
563
|
+
border-radius: 10px;
|
564
|
+
border: 2px solid;
|
565
|
+
font-size: 1em;
|
566
|
+
transition: all 0.3s ease;
|
567
|
+
box-sizing: border-box;
|
568
|
+
appearance: none;
|
569
|
+
cursor: pointer;
|
570
|
+
font-family: inherit;
|
571
|
+
}
|
572
|
+
|
573
|
+
.dark-mode .select-wrapper select {
|
574
|
+
background: var(--input-bg-dark);
|
575
|
+
border-color: var(--input-border-dark);
|
576
|
+
color: var(--text-dark);
|
577
|
+
}
|
578
|
+
|
579
|
+
.light-mode .select-wrapper select {
|
580
|
+
background: var(--input-bg-light);
|
581
|
+
border-color: var(--input-border-light);
|
582
|
+
color: var(--text-light);
|
583
|
+
}
|
584
|
+
|
585
|
+
.select-wrapper select:focus {
|
586
|
+
outline: none;
|
587
|
+
transform: translateY(-1px);
|
588
|
+
}
|
589
|
+
|
590
|
+
.dark-mode .select-wrapper select:focus {
|
591
|
+
border-color: var(--input-focus-dark);
|
592
|
+
box-shadow: 0 0 0 3px rgba(93, 173, 226, 0.2);
|
593
|
+
}
|
594
|
+
|
595
|
+
.light-mode .select-wrapper select:focus {
|
596
|
+
border-color: var(--input-focus-light);
|
597
|
+
box-shadow: 0 0 0 3px rgba(243, 156, 18, 0.2);
|
598
|
+
}
|
599
|
+
|
600
|
+
.select-arrow {
|
601
|
+
position: absolute;
|
602
|
+
right: 15px;
|
603
|
+
font-size: 0.8em;
|
604
|
+
opacity: 0.6;
|
605
|
+
pointer-events: none;
|
606
|
+
transition: transform 0.3s ease;
|
607
|
+
}
|
608
|
+
|
609
|
+
.select-wrapper:hover .select-arrow {
|
610
|
+
transform: translateY(-1px);
|
611
|
+
}
|
612
|
+
|
613
|
+
/* Enhanced Checkbox Styles */
|
614
|
+
.checkbox-container {
|
615
|
+
display: flex;
|
616
|
+
align-items: center;
|
617
|
+
cursor: pointer;
|
618
|
+
margin-bottom: 12px;
|
619
|
+
padding: 10px;
|
620
|
+
border-radius: 8px;
|
621
|
+
transition: all 0.3s ease;
|
622
|
+
font-weight: 500;
|
623
|
+
}
|
624
|
+
|
625
|
+
.checkbox-container:hover {
|
626
|
+
background: rgba(255, 255, 255, 0.05);
|
627
|
+
}
|
628
|
+
|
629
|
+
.light-mode .checkbox-container:hover {
|
630
|
+
background: rgba(0, 0, 0, 0.03);
|
631
|
+
}
|
632
|
+
|
633
|
+
.checkbox-container.disabled {
|
634
|
+
opacity: 0.5;
|
635
|
+
cursor: not-allowed;
|
636
|
+
}
|
637
|
+
|
638
|
+
.checkbox-container input[type="checkbox"] {
|
639
|
+
position: absolute;
|
640
|
+
opacity: 0;
|
641
|
+
cursor: pointer;
|
642
|
+
}
|
643
|
+
|
644
|
+
.checkmark {
|
645
|
+
height: 20px;
|
646
|
+
width: 20px;
|
647
|
+
border-radius: 4px;
|
648
|
+
border: 2px solid;
|
649
|
+
margin-right: 12px;
|
650
|
+
position: relative;
|
651
|
+
transition: all 0.3s ease;
|
652
|
+
flex-shrink: 0;
|
653
|
+
}
|
654
|
+
|
655
|
+
.dark-mode .checkmark {
|
656
|
+
background: var(--checkbox-bg-dark);
|
657
|
+
border-color: var(--input-border-dark);
|
658
|
+
}
|
659
|
+
|
660
|
+
.light-mode .checkmark {
|
661
|
+
background: var(--checkbox-bg-light);
|
662
|
+
border-color: var(--input-border-light);
|
663
|
+
}
|
664
|
+
|
665
|
+
.checkbox-container input:checked ~ .checkmark {
|
666
|
+
transform: scale(1.1);
|
667
|
+
}
|
668
|
+
|
669
|
+
.dark-mode .checkbox-container input:checked ~ .checkmark {
|
670
|
+
background: var(--checkbox-checked-dark);
|
671
|
+
border-color: var(--checkbox-checked-dark);
|
672
|
+
}
|
673
|
+
|
674
|
+
.light-mode .checkbox-container input:checked ~ .checkmark {
|
675
|
+
background: var(--checkbox-checked-light);
|
676
|
+
border-color: var(--checkbox-checked-light);
|
677
|
+
}
|
678
|
+
|
679
|
+
.checkmark:after {
|
680
|
+
content: "";
|
681
|
+
position: absolute;
|
682
|
+
display: none;
|
683
|
+
left: 6px;
|
684
|
+
top: 2px;
|
685
|
+
width: 6px;
|
686
|
+
height: 10px;
|
687
|
+
border: solid white;
|
688
|
+
border-width: 0 2px 2px 0;
|
689
|
+
transform: rotate(45deg);
|
690
|
+
}
|
691
|
+
|
692
|
+
.checkbox-container input:checked ~ .checkmark:after {
|
693
|
+
display: block;
|
694
|
+
}
|
695
|
+
|
696
|
+
.checkbox-group {
|
697
|
+
display: block;
|
698
|
+
margin-bottom: 0;
|
699
|
+
}
|
700
|
+
|
701
|
+
.actions {
|
702
|
+
display: flex;
|
703
|
+
justify-content: center;
|
704
|
+
gap: 20px;
|
705
|
+
margin-top: 30px;
|
706
|
+
}
|
707
|
+
|
708
|
+
button {
|
709
|
+
padding: 15px 30px;
|
710
|
+
border: none;
|
711
|
+
border-radius: 12px;
|
712
|
+
font-size: 1.1em;
|
713
|
+
font-weight: 600;
|
714
|
+
cursor: pointer;
|
715
|
+
transition: all 0.3s ease;
|
716
|
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
717
|
+
backdrop-filter: blur(10px);
|
718
|
+
}
|
719
|
+
|
720
|
+
button.primary-button {
|
721
|
+
background: var(--btn-primary-dark);
|
722
|
+
color: white;
|
723
|
+
}
|
724
|
+
|
725
|
+
.light-mode button.primary-button {
|
726
|
+
background: var(--btn-primary-light);
|
727
|
+
}
|
728
|
+
|
729
|
+
button.primary-button:hover:not(:disabled) {
|
730
|
+
transform: translateY(-3px);
|
731
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
|
732
|
+
}
|
733
|
+
|
734
|
+
button.secondary-button {
|
735
|
+
background: var(--btn-secondary-dark);
|
736
|
+
color: white;
|
737
|
+
}
|
738
|
+
|
739
|
+
.light-mode button.secondary-button {
|
740
|
+
background: var(--btn-secondary-light);
|
741
|
+
}
|
742
|
+
|
743
|
+
button.secondary-button:hover:not(:disabled) {
|
744
|
+
transform: translateY(-3px);
|
745
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
|
746
|
+
}
|
747
|
+
|
748
|
+
button:disabled {
|
749
|
+
opacity: 0.6;
|
750
|
+
cursor: not-allowed;
|
751
|
+
transform: none !important;
|
752
|
+
}
|
753
|
+
|
754
|
+
.output-log pre {
|
755
|
+
padding: 20px;
|
756
|
+
border-radius: 10px;
|
757
|
+
max-height: 300px;
|
758
|
+
overflow-y: auto;
|
759
|
+
white-space: pre-wrap;
|
760
|
+
word-wrap: break-word;
|
761
|
+
font-family: 'Fira Code', 'Courier New', Courier, monospace;
|
762
|
+
font-size: 0.9em;
|
763
|
+
border: 2px solid;
|
764
|
+
margin: 0;
|
765
|
+
line-height: 1.5;
|
766
|
+
}
|
767
|
+
|
768
|
+
.dark-mode .output-log pre {
|
769
|
+
background: rgba(0, 0, 0, 0.5);
|
770
|
+
color: #eee;
|
771
|
+
border-color: var(--border-dark);
|
772
|
+
}
|
773
|
+
|
774
|
+
.light-mode .output-log pre {
|
775
|
+
background: rgba(248, 249, 250, 0.9);
|
776
|
+
color: var(--text-light);
|
777
|
+
border-color: var(--border-light);
|
778
|
+
}
|
779
|
+
|
780
|
+
/* Responsive Design */
|
781
|
+
@media (max-width: 768px) {
|
782
|
+
.app-header {
|
783
|
+
flex-direction: column;
|
784
|
+
gap: 15px;
|
785
|
+
}
|
786
|
+
|
787
|
+
.theme-toggle {
|
788
|
+
position: static;
|
789
|
+
}
|
790
|
+
|
791
|
+
.options-section {
|
792
|
+
grid-template-columns: 1fr;
|
793
|
+
}
|
794
|
+
|
795
|
+
.actions {
|
796
|
+
flex-direction: column;
|
797
|
+
align-items: center;
|
798
|
+
}
|
799
|
+
|
800
|
+
button {
|
801
|
+
width: 100%;
|
802
|
+
max-width: 300px;
|
803
|
+
}
|
804
|
+
}
|
805
|
+
</style>
|