comparison mrjunejune/test/snapshots/tools_file_converter.snapshot @ 94:092afa595764

[MrJuneJune] Added Integration tests.
author June Park <parkjune1995@gmail.com>
date Fri, 02 Jan 2026 18:13:32 -0800
parents
children 1c446ab6f945
comparison
equal deleted inserted replaced
93:be91a73d801a 94:092afa595764
1 HTTP/1.1 200 OK
2 Content-Type: text/html
3 Content-Length: 7742
4 Connection: close
5
6 <!DOCTYPE html>
7 <html lang="en">
8 <head>
9 <meta charset="UTF-8">
10 <meta name="viewport" content="width=device-width, initial-scale=1.0">
11 <title>File Format Converter</title>
12 <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
13
14 <link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font" crossorigin>
15 <link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
16
17 <link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin>
18 <link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin>
19
20 <link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin>
21 <link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
22 <link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
23
24 <link rel="preload" href="/base.css" as="style" />
25 <link rel="stylesheet" href="/base.css" />
26
27
28 <style>
29 .container {
30 max-width: 800px;
31 margin: 2rem auto;
32 padding: 2rem;
33 }
34
35 .converter-section {
36 border-radius: 8px;
37 border: 2px solid var(--lightgray);
38 padding: 2rem;
39 margin-bottom: 2rem;
40 }
41
42 .converter-section h2 {
43 margin-top: 0;
44 color: var(--black);
45 }
46
47 .file-input-wrapper {
48 margin: 1rem 0;
49 }
50
51 .file-input-wrapper label {
52 display: block;
53 margin-bottom: 0.5rem;
54 font-weight: 600;
55 }
56
57 input[type="file"] {
58 width: 50%;
59 padding: 0.5rem;
60 border: 2px dashed #ccc;
61 border-radius: 4px;
62 background: white;
63 }
64
65 button {
66 background: var(--purple);
67 font-family: "More Thin", sans-serif;
68 color: var(--gray-gradient);
69 border: none;
70 padding: 0.75rem 1.5rem;
71 border-radius: 4px;
72 cursor: pointer;
73 font-size: 1rem;
74 margin-top: 1rem;
75 }
76
77 button:hover {
78 background: var(--orange);
79 }
80
81 button:disabled {
82 background: var(--gray);
83 cursor: not-allowed;
84 }
85
86 .result {
87 margin-top: 1rem;
88 padding: 1rem;
89 background: white;
90 border-radius: 4px;
91 display: none;
92 }
93
94 .result.show {
95 display: block;
96 }
97
98 .result.success {
99 border-left: 4px solid var(--blue);
100 }
101
102 .result.error {
103 border-left: 4px solid var(--red);
104 }
105
106 .download-link {
107 display: inline-block;
108 margin-top: 0.5rem;
109 color: var(--awesome);
110 text-decoration: none;
111 }
112
113 .download-link:hover {
114 text-decoration: underline;
115 }
116
117 .loading {
118 display: none;
119 margin-top: 1rem;
120 }
121
122 .loading.show {
123 display: block;
124 }
125 </style>
126 </head>
127 <body>
128 <style>
129 :root {
130 --header-background: var(--white);
131 --header-color: rgb(var(--black));
132 --link-hover-accent: var(--awesome);
133 }
134
135 /* Fixed icon in top left corner */
136 #themeToggle {
137 position: fixed;
138 top: 20px;
139 left: 20px;
140 background: var(--header-background);
141 display: flex;
142 align-items: center;
143 border-radius: 50%;
144 cursor: pointer;
145 z-index: 1000;
146 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
147 transition: transform 0.2s ease;
148 }
149
150 #themeToggle:hover {
151 transform: scale(1.05);
152 }
153
154 /* Professional header */
155 header {
156 margin: auto;
157 padding: 1.5em 1em;
158 font-family: "More", sans-serif;
159 box-shadow: 0 2px 8px rgba(var(--black), 5%);
160 width: 720px;
161 max-width: calc(100% - 2em);
162 text-align: center;
163 }
164
165 header h1 {
166 margin: 0;
167 font-size: 1.8em;
168 font-weight: 700;
169 letter-spacing: -0.5px;
170 }
171
172 header h1 a {
173 text-decoration: none;
174 color: var(--header-color);
175 }
176
177 header h1 a::before {
178 display: none;
179 }
180
181 /* Mobile responsiveness */
182 @media (max-width: 720px) {
183 #themeToggle {
184 top: 15px;
185 left: 15px;
186 }
187
188 header {
189 padding: 1em;
190 }
191
192 header h1 {
193 font-size: 1.5em;
194 }
195 }
196
197 @media (max-width: 480px) {
198 #themeToggle {
199 top: 10px;
200 left: 10px;
201 }
202
203 #themeToggle img {
204 height: 40px;
205 width: 40px;
206 }
207
208 header h1 {
209 font-size: 1.3em;
210 }
211 }
212
213 #logo {
214 width: 300px;
215 }
216
217 /* 1. DEFINE THE DEFAULTS (Light Mode) */
218 :root {
219 --logo-invert: invert(0);
220 --epi-grayscale: grayscale(0) brightness(1);
221 }
222
223 /* 2. MANUAL DARK OVERRIDE */
224 html.dark {
225 --logo-invert: invert(1);
226 --epi-grayscale: grayscale(1);
227 }
228
229 /* 3. MANUAL LIGHT OVERRIDE */
230 html.light-mode {
231 --logo-invert: invert(0);
232 --epi-grayscale: brightness(2.9) grayscale(1);
233 }
234
235 /* 4. SYSTEM PREFERENCE */
236 @media (prefers-color-scheme: dark) {
237 :root:not(.light-mode) {
238 --logo-invert: invert(1);
239 }
240 }
241
242 /* 5. APPLY TO ELEMENTS */
243 #logo {
244 -webkit-filter: var(--logo-invert);
245 filter: var(--logo-invert);
246 transition: filter 0.3s ease;
247 }
248
249 .epi-logo {
250 -webkit-filter: var(--epi-grayscale);
251 filter: var(--epi-grayscale);
252 transition: filter 0.3s ease;
253 }
254 </style>
255
256 <div id="themeToggle">
257 <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
258 </div>
259
260 <header>
261 <h1><a href="/">MrJuneJune</a></h1>
262 </header>
263 <script src="/index.js"></script>
264
265
266
267 <div class="container">
268 <h1>File Format Converter</h1>
269 <p>Convert your images and videos to different formats using FFmpeg</p>
270
271 <div class="converter-section">
272 <h2>Image to WebP Converter</h2>
273 <p>Upload an image file (PNG, JPG, GIF, etc.) to convert it to WebP format</p>
274
275 <div class="file-input-wrapper">
276 <label for="imageInput">Choose an image file:</label>
277 <input type="file" id="imageInput" accept="image/*">
278 </div>
279
280 <button id="convertImageBtn" onclick="convertImageToWebP()">Convert to WebP</button>
281
282 <div class="loading" id="imageLoading">Converting... Please wait.</div>
283
284 <div class="result" id="imageResult">
285 <p id="imageMessage"></p>
286 <a id="imageDownload" class="download-link" style="display: none;">Download WebP Image</a>
287 </div>
288 </div>
289
290 <div class="converter-section">
291 <h2>Video to MP4 Converter</h2>
292 <p>Upload a video file (AVI, MOV, MKV, etc.) to convert it to MP4 format</p>
293
294 <div class="file-input-wrapper">
295 <label for="videoInput">Choose a video file:</label>
296 <input type="file" id="videoInput" accept="video/*">
297 </div>
298
299 <button id="convertVideoBtn" onclick="convertVideoToMP4()">Convert to MP4</button>
300
301 <div class="loading" id="videoLoading">Converting... Please wait.</div>
302
303 <div class="result" id="videoResult">
304 <p id="videoMessage"></p>
305 <a id="videoDownload" class="download-link" style="display: none;">Download MP4 Video</a>
306 </div>
307 </div>
308 <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
309 <small>&copy; 2026 June Park</small>
310 </div>
311
312 </div>
313 <script src="/tools/file_converter/index.js"></script>
314 </body>
315 </html>