Elias207 commited on
Commit
7a42222
·
verified ·
1 Parent(s): d5cd931

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +172 -561
index.html CHANGED
@@ -1,561 +1,172 @@
1
- <!DOCTYPE html>
2
- <html lang="fa" dir="rtl">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
- <title>ابزار مدرن QR Code — طراحی جدید</title>
7
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css">
8
-
9
- <style>
10
- :root{
11
- --bg-1:#0f1226;
12
- --bg-2:#1a1f3f;
13
- --bg-3:#0b0f23;
14
- --text:#eaf1ff;
15
- --muted:#b2bdd6;
16
-
17
- --accent-1:#8e44ad;
18
- --accent-2:#3498db;
19
- --accent-3:#00e676;
20
-
21
- --card-bg:rgba(255,255,255,.06);
22
- --card-bg-strong:rgba(255,255,255,.08);
23
- --border:rgba(255,255,255,.14);
24
- --divider:rgba(255,255,255,.08);
25
-
26
- --shadow:0 18px 45px rgba(0,0,0,.35);
27
- --radius:16px;
28
- }
29
-
30
- *{box-sizing:border-box}
31
- html,body{height:100%}
32
- body{
33
- margin:0;
34
- font-family:'Vazirmatn',system-ui,Segoe UI,Roboto,Arial,sans-serif;
35
- color:var(--text);
36
- background:
37
- radial-gradient(1000px 600px at -10% 10%, rgba(124,77,255,.18), transparent 50%),
38
- radial-gradient(800px 500px at 110% 110%, rgba(0,230,118,.12), transparent 50%),
39
- linear-gradient(135deg, var(--bg-2), var(--bg-1) 40%, var(--bg-3));
40
- overflow:hidden; /* اسکرول داخل هر پنل انجام می‌شود */
41
- }
42
-
43
- /* هدر مینیمال */
44
- .topbar{
45
- height:64px;
46
- display:flex;
47
- align-items:center;
48
- justify-content:center;
49
- gap:12px;
50
- padding:0 16px;
51
- position:relative;
52
- z-index:2;
53
- }
54
- .topbar .logo{
55
- inline-size:28px;
56
- block-size:28px;
57
- display:inline-flex;
58
- align-items:center;
59
- justify-content:center;
60
- color:#fff;
61
- background:linear-gradient(135deg, var(--accent-1), var(--accent-2));
62
- border-radius:8px;
63
- box-shadow:0 6px 18px rgba(52,152,219,.35), 0 4px 14px rgba(142,68,173,.25);
64
- }
65
- .topbar h1{
66
- margin:0;
67
- font-size:1.25rem;
68
- font-weight:700;
69
- letter-spacing:.2px;
70
- color:#fff;
71
- }
72
- .topbar span{
73
- font-weight:300;
74
- color:var(--muted);
75
- margin-inline-start:8px;
76
- font-size:.95rem;
77
- }
78
-
79
- /* صفحه دو ستونه همیشه (حتی موبایل) */
80
- .split{
81
- display:grid;
82
- grid-template-columns: 1fr 1fr; /* همیشه کنار هم */
83
- height:calc(100dvh - 64px);
84
- width:100%;
85
- position:relative;
86
- z-index:1;
87
- }
88
- .split::after{ /* خط جداکننده وسط */
89
- content:"";
90
- position:absolute;
91
- inset-block:0;
92
- inset-inline-start:50%;
93
- width:1px;
94
- background:linear-gradient(to bottom, transparent, var(--divider), transparent);
95
- z-index:0;
96
- }
97
-
98
- /* پنل‌ها */
99
- .panel{
100
- position:relative;
101
- padding:20px 16px;
102
- display:flex;
103
- align-items:center;
104
- justify-content:center;
105
- overflow:auto;
106
- isolation:isolate;
107
- }
108
- .panel::before{ /* الگوی نقطه‌ای QR */
109
- content:"";
110
- position:absolute; inset:0;
111
- background-image: radial-gradient(rgba(255,255,255,.09) 1px, transparent 1.2px);
112
- background-size:20px 20px;
113
- opacity:.45;
114
- mask-image:linear-gradient(to bottom, rgba(0,0,0,.25), rgba(0,0,0,.9) 35%, rgba(0,0,0,.5));
115
- pointer-events:none;
116
- z-index:-1;
117
- }
118
-
119
- .panel.generate{
120
- background:linear-gradient(180deg, transparent, rgba(142,68,173,.12));
121
- }
122
- .panel.read{
123
- background:linear-gradient(180deg, transparent, rgba(52,152,219,.12));
124
- }
125
-
126
- /* کارت ابزار داخل هر پنل */
127
- .tool-card{
128
- width:min(540px, 92%);
129
- background:var(--card-bg);
130
- border:1px solid var(--border);
131
- border-radius:var(--radius);
132
- padding:18px;
133
- box-shadow:var(--shadow);
134
- backdrop-filter:blur(10px);
135
- -webkit-backdrop-filter:blur(10px);
136
- display:flex; flex-direction:column; gap:14px;
137
- position:relative;
138
- }
139
-
140
- .tool-card .title{
141
- display:flex; align-items:center; gap:10px;
142
- border-bottom:1px solid var(--divider);
143
- padding-bottom:10px; margin-bottom:6px;
144
- }
145
- .title .badge{
146
- display:inline-flex; align-items:center; justify-content:center;
147
- width:32px; height:32px; border-radius:10px; color:#fff;
148
- box-shadow:0 8px 24px rgba(0,0,0,.25);
149
- }
150
- .generate .title .badge{ background:linear-gradient(135deg, var(--accent-1), var(--accent-2)); }
151
- .read .title .badge{ background:linear-gradient(135deg, var(--accent-2), var(--accent-3)); }
152
-
153
- .title h2{
154
- margin:0; font-size:1.05rem; font-weight:700; color:#fff;
155
- }
156
- .subtitle{
157
- font-size:.9rem; color:var(--muted); margin-top:-4px;
158
- }
159
-
160
- label{
161
- font-size:.88rem; color:#cdd6f7; opacity:.9;
162
- }
163
-
164
- textarea, .input-like{
165
- width:100%;
166
- padding:12px 12px;
167
- border-radius:12px;
168
- border:1px solid var(--border);
169
- background:var(--card-bg-strong);
170
- color:var(--text);
171
- font-size:1rem;
172
- outline:none;
173
- transition:.25s ease;
174
- }
175
- textarea::placeholder{ color:#93a0bf; }
176
- textarea:focus, .input-like:focus-within{
177
- border-color:color-mix(in oklab, var(--accent-2) 55%, white);
178
- box-shadow:0 0 0 6px rgba(52,152,219,.08), 0 6px 24px rgba(52,152,219,.18);
179
- }
180
-
181
- .actions{
182
- display:flex; gap:10px; flex-wrap:wrap; align-items:center;
183
- }
184
- button{
185
- padding:12px 16px;
186
- background:linear-gradient(135deg, var(--accent-1), var(--accent-2));
187
- color:#fff;
188
- border:none; border-radius:12px;
189
- font-weight:700; cursor:pointer;
190
- display:inline-flex; align-items:center; gap:10px;
191
- transition:transform .15s ease, box-shadow .25s ease, filter .25s ease;
192
- box-shadow:0 8px 22px rgba(142,68,173,.25), 0 8px 22px rgba(52,152,219,.22);
193
- }
194
- .read button{ background:linear-gradient(135deg, var(--accent-2), var(--accent-3)); }
195
- button:hover:not(:disabled){ transform:translateY(-2px); filter:saturate(1.1); }
196
- button:disabled{ opacity:.6; cursor:not-allowed; filter:saturate(.8); }
197
-
198
- /* نتیجه‌ها */
199
- .result-box{
200
- margin-top:6px;
201
- padding:16px;
202
- background:rgba(255,255,255,.05);
203
- border:1px solid var(--border);
204
- border-radius:14px;
205
- min-height:120px;
206
- display:flex; align-items:center; justify-content:center;
207
- text-align:center; word-wrap:break-word;
208
- position:relative; overflow:hidden;
209
- }
210
-
211
- /* نمایش QR */
212
- #qr-code-display img{
213
- max-width:100%;
214
- height:auto;
215
- border-radius:10px;
216
- border:2px solid rgba(255,255,255,.9);
217
- box-shadow:0 14px 32px rgba(0,0,0,.35);
218
- animation:fadeIn .45s ease-in-out both;
219
- }
220
- @keyframes fadeIn{
221
- from{opacity:0; transform:scale(.96)}
222
- to{opacity:1; transform:scale(1)}
223
- }
224
-
225
- /* اسپینر */
226
- .loader{
227
- border:3px solid rgba(255,255,255,.26);
228
- border-top:3px solid var(--accent-2);
229
- border-right:3px solid var(--accent-1);
230
- border-radius:50%;
231
- width:28px; height:28px;
232
- animation:spin 1s linear infinite;
233
- display:none;
234
- }
235
- @keyframes spin{ to{ transform:rotate(360deg) } }
236
-
237
- /* Drop Zone برای خواندن QR */
238
- .drop-zone{
239
- width:100%;
240
- background:var(--card-bg-strong);
241
- border:1.5px dashed color-mix(in oklab, var(--accent-2) 65%, #fff 10%);
242
- border-radius:12px;
243
- padding:14px;
244
- display:flex; align-items:center; justify-content:center; gap:10px;
245
- color:#d7e0ff;
246
- cursor:pointer;
247
- transition: border-color .2s ease, box-shadow .25s ease, background .25s ease;
248
- }
249
- .drop-zone:hover{
250
- border-color:color-mix(in oklab, var(--accent-3) 65%, white 10%);
251
- box-shadow:0 0 0 6px rgba(0,230,118,.08), inset 0 0 30px rgba(0,230,118,.06);
252
- background:rgba(0,0,0,.18);
253
- }
254
- .drop-zone.dragging{
255
- border-color:var(--accent-3);
256
- box-shadow:0 0 0 6px rgba(0,230,118,.1), inset 0 0 45px rgba(0,230,118,.08);
257
- background:rgba(0,0,0,.22);
258
- }
259
- .file-name{
260
- margin:0; font-size:.86rem; color:#bdc8ea; opacity:.9;
261
- }
262
- input[type="file"]{ display:none; }
263
-
264
- /* متن خروجی */
265
- #decoded-text{
266
- margin:0; white-space:pre-wrap; line-height:1.6;
267
- }
268
-
269
- /* گوشه‌های اسکنر تزئینی */
270
- .corners{
271
- pointer-events:none;
272
- position:absolute; inset:8px;
273
- display:grid; grid-template-columns: 1fr 1fr;
274
- grid-template-rows: 1fr 1fr;
275
- }
276
- .corner{
277
- width:26px; height:26px; border:2px solid rgba(255,255,255,.85);
278
- border-radius:6px;
279
- }
280
- .corner.tl{ justify-self:start; align-self:start; border-right:none; border-bottom:none; }
281
- .corner.tr{ justify-self:end; align-self:start; border-left:none; border-bottom:none; }
282
- .corner.bl{ justify-self:start; align-self:end; border-right:none; border-top:none; }
283
- .corner.br{ justify-self:end; align-self:end; border-left:none; border-top:none; }
284
-
285
- /* اسکرول‌بار لطیف داخل پنل‌ها */
286
- .panel::-webkit-scrollbar{ width:10px; height:10px; }
287
- .panel::-webkit-scrollbar-thumb{
288
- background:linear-gradient(180deg, rgba(142,68,173,.45), rgba(52,152,219,.45));
289
- border-radius:10px;
290
- }
291
- .panel::-webkit-scrollbar-track{ background:transparent; }
292
-
293
- /* ریزبهینه‌سازی اندازه فونت در خیلی عرض کم */
294
- @media (max-width: 380px){
295
- .title h2{ font-size:1rem }
296
- textarea{ font-size:.95rem }
297
- button{ font-size:.95rem }
298
- }
299
- </style>
300
- </head>
301
- <body>
302
-
303
- <header class="topbar">
304
- <div class="logo" aria-hidden="true">
305
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M3 3h8v8H3zM5 5v4h4V5H5zM13 3h8v8h-8zM15 5v4h4V5h-4zM3 13h8v8H3zM5 15v4h4v-4H5zM13 13h3v3h-3zM17 13h4v4h-4zM13 17h3v4h-3zM17 21v-3h4v3z"/></svg>
306
- </div>
307
- <h1>ابزار مدرن QR Code <span>— ساخت و خواندن کنار هم</span></h1>
308
- </header>
309
-
310
- <main class="split">
311
- <!-- پنل ساخت QR -->
312
- <section class="panel generate">
313
- <div class="tool-card">
314
- <div class="title">
315
- <div class="badge" aria-hidden="true">
316
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 24 24"><path d="M3 3h8v8H3zM5 5v4h4V5H5zM13 3h8v8h-8zM15 5v4h4V5h-4zM3 13h8v8H3zM5 15v4h4v-4H5z"/></svg>
317
- </div>
318
- <div>
319
- <h2>ساخت QR Code از متن</h2>
320
- <div class="subtitle">متن یا لینک خود را بنویسید و یک QR براق تحویل بگیرید ✨</div>
321
- </div>
322
- </div>
323
-
324
- <label for="text-input">متن خود را وارد کنید:</label>
325
- <textarea id="text-input" rows="4" placeholder="مثلا: https://example.com">سلام دنیا</textarea>
326
-
327
- <div class="actions">
328
- <button id="generate-btn" title="ساخت QR Code">
329
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2v0z"/><path d="M12 8l4 4-4 4"/><path d="M8 12h7"/></svg>
330
- <span>ساخت QR Code</span>
331
- </button>
332
- </div>
333
-
334
- <div class="result-box">
335
- <div id="generate-loader" class="loader"></div>
336
- <div id="qr-code-display"></div>
337
- <div class="corners" aria-hidden="true">
338
- <div class="corner tl"></div>
339
- <div class="corner tr"></div>
340
- <div class="corner bl"></div>
341
- <div class="corner br"></div>
342
- </div>
343
- </div>
344
- </div>
345
- </section>
346
-
347
- <!-- پنل خواندن QR -->
348
- <section class="panel read">
349
- <div class="tool-card">
350
- <div class="title">
351
- <div class="badge" aria-hidden="true">
352
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
353
- </div>
354
- <div>
355
- <h2>خواندن متن از QR Code</h2>
356
- <div class="subtitle">تصویر QR را بکشید و رها کنید یا فایل را انتخاب کنید</div>
357
- </div>
358
- </div>
359
-
360
- <label for="file-input">فایل تصویر QR Code را انتخاب کنید:</label>
361
- <div id="drop-zone" class="drop-zone">
362
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
363
- <span>کلیک کنید یا فایل را اینجا رها کنید</span>
364
- <input type="file" id="file-input" accept="image/*" />
365
- </div>
366
- <p id="file-name" class="file-name"></p>
367
-
368
- <div class="actions">
369
- <button id="read-btn" title="خواندن QR Code">
370
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
371
- <span>خواندن QR Code</span>
372
- </button>
373
- </div>
374
-
375
- <div class="result-box">
376
- <div id="read-loader" class="loader"></div>
377
- <p id="decoded-text">نتیجه در اینجا نمایش داده می‌شود.</p>
378
- <div class="corners" aria-hidden="true">
379
- <div class="corner tl"></div>
380
- <div class="corner tr"></div>
381
- <div class="corner bl"></div>
382
- <div class="corner br"></div>
383
- </div>
384
- </div>
385
- </div>
386
- </section>
387
- </main>
388
-
389
- <script>
390
- const SPACE_URL = "https://cultrix-qrcode-read-generate.hf.space";
391
-
392
- // عناصر DOM
393
- const generateBtn = document.getElementById('generate-btn');
394
- const readBtn = document.getElementById('read-btn');
395
- const textInput = document.getElementById('text-input');
396
- const fileInput = document.getElementById('file-input');
397
- const qrCodeDisplay = document.getElementById('qr-code-display');
398
- const decodedText = document.getElementById('decoded-text');
399
- const generateLoader = document.getElementById('generate-loader');
400
- const readLoader = document.getElementById('read-loader');
401
- const fileNameDisplay = document.getElementById('file-name');
402
- const dropZone = document.getElementById('drop-zone');
403
-
404
- // نمایش نام فایل هنگام انتخاب
405
- fileInput.addEventListener('change', () => {
406
- if (fileInput.files.length > 0) {
407
- fileNameDisplay.textContent = `فایل انتخاب شده: ${fileInput.files[0].name}`;
408
- } else {
409
- fileNameDisplay.textContent = '';
410
- }
411
- });
412
-
413
- // Drop Zone رفتار
414
- dropZone.addEventListener('click', () => fileInput.click());
415
- dropZone.addEventListener('dragover', (e) => {
416
- e.preventDefault();
417
- dropZone.classList.add('dragging');
418
- });
419
- dropZone.addEventListener('dragleave', () => {
420
- dropZone.classList.remove('dragging');
421
- });
422
- dropZone.addEventListener('drop', (e) => {
423
- e.preventDefault();
424
- dropZone.classList.remove('dragging');
425
- const file = e.dataTransfer.files?.[0];
426
- if (file) {
427
- const dt = new DataTransfer();
428
- dt.items.add(file);
429
- fileInput.files = dt.files;
430
- fileNameDisplay.textContent = `فایل انتخاب شده: ${file.name}`;
431
- }
432
- });
433
-
434
- // توابع کمکی
435
- const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
436
-
437
- const listenForData = (sessionHash, onResult, onError) => {
438
- const eventSource = new EventSource(`${SPACE_URL}/gradio_api/queue/data?session_hash=${sessionHash}`);
439
-
440
- eventSource.onmessage = (event) => {
441
- try {
442
- const data = JSON.parse(event.data);
443
- if (data.msg === "process_completed") {
444
- eventSource.close();
445
- if (data.output?.error) {
446
- onError(data.output.error);
447
- } else {
448
- onResult(data.output.data);
449
- }
450
- } else if (data.msg === "process_failed") {
451
- eventSource.close();
452
- onError("پردازش با خطا مواجه شد.");
453
- }
454
- } catch (e) {
455
- // در برخی پیام‌های keep-alive داده خالی است
456
- }
457
- };
458
-
459
- eventSource.onerror = (err) => {
460
- console.error("EventSource failed:", err);
461
- eventSource.close();
462
- onError("خطا در ارتباط با سرور.");
463
- };
464
- };
465
-
466
- // ساخت QR
467
- generateBtn.addEventListener('click', async () => {
468
- const text = textInput.value.trim();
469
- if (!text) return alert("لطفاً متنی را وارد کنید.");
470
-
471
- generateLoader.style.display = 'inline-block';
472
- qrCodeDisplay.innerHTML = '';
473
- generateBtn.disabled = true;
474
-
475
- const sessionHash = generateSessionHash();
476
-
477
- try {
478
- const joinResponse = await fetch(`${SPACE_URL}/gradio_api/queue/join`, {
479
- method: 'POST',
480
- headers: { 'Content-Type': 'application/json' },
481
- body: JSON.stringify({ fn_index: 0, data: [text], session_hash: sessionHash })
482
- });
483
-
484
- if (!joinResponse.ok) throw new Error(`خطا در ارسال درخواست: ${joinResponse.statusText}`);
485
-
486
- listenForData(
487
- sessionHash,
488
- (result) => {
489
- if (result && result[0]) {
490
- qrCodeDisplay.innerHTML = result[0];
491
- } else {
492
- qrCodeDisplay.innerText = "خطا: خروجی معتبر دریافت نشد.";
493
- }
494
- },
495
- (error) => {
496
- alert(`خطا در پردازش: ${error}`);
497
- qrCodeDisplay.innerText = "خطا در ساخت تصویر.";
498
- }
499
- );
500
- } catch (error) {
501
- alert(`یک خطا رخ داد: ${error.message}`);
502
- } finally {
503
- generateLoader.style.display = 'none';
504
- generateBtn.disabled = false;
505
- }
506
- });
507
-
508
- // خواندن QR
509
- readBtn.addEventListener('click', async () => {
510
- const file = fileInput.files[0];
511
- if (!file) return alert("لطفاً یک فایل تصویر انتخاب کنید.");
512
-
513
- readLoader.style.display = 'inline-block';
514
- decodedText.innerText = '';
515
- readBtn.disabled = true;
516
-
517
- try {
518
- const formData = new FormData();
519
- formData.append('files', file);
520
-
521
- const uploadResponse = await fetch(`${SPACE_URL}/gradio_api/upload`, { method:'POST', body: formData });
522
- if (!uploadResponse.ok) throw new Error(`خطا در آپلود فایل: ${uploadResponse.statusText}`);
523
-
524
- const uploadResult = await uploadResponse.json();
525
- const serverFilePath = uploadResult[0];
526
-
527
- const fileDataObject = {
528
- path: serverFilePath,
529
- url: `${SPACE_URL}/gradio_api/file=${serverFilePath}`,
530
- orig_name: file.name,
531
- };
532
-
533
- const sessionHash = generateSessionHash();
534
- const joinResponse = await fetch(`${SPACE_URL}/gradio_api/queue/join`, {
535
- method:'POST',
536
- headers:{ 'Content-Type':'application/json' },
537
- body: JSON.stringify({ fn_index: 1, data: [fileDataObject], session_hash: sessionHash })
538
- });
539
- if (!joinResponse.ok) throw new Error(`خطا در ارسال به صف: ${joinResponse.statusText}`);
540
-
541
- listenForData(
542
- sessionHash,
543
- (result) => {
544
- decodedText.innerText = `متن خوانده شده:\n${result?.[0] ?? ''}`;
545
- },
546
- (error) => {
547
- alert(`خطا در پردازش: ${error}`);
548
- decodedText.innerText = "خطا در خواندن کد.";
549
- }
550
- );
551
- } catch (error) {
552
- alert(`یک خطا رخ داد: ${error.message}`);
553
- decodedText.innerText = "نتیجه در اینجا نمایش داده می‌شود.";
554
- } finally {
555
- readLoader.style.display = 'none';
556
- readBtn.disabled = false;
557
- }
558
- });
559
- </script>
560
- </body>
561
- </html>
 
1
+ body {
2
+ font-family: 'Vazirmatn', sans-serif;
3
+ background: linear-gradient(135deg, var(--background-end), var(--background-start));
4
+ color: var(--text-color);
5
+ display: flex;
6
+ justify-content: center;
7
+ align-items: center;
8
+ min-height: 100vh;
9
+ padding: 20px;
10
+ gap: 40px;
11
+ flex-wrap: wrap;
12
+ }
13
+
14
+ .main-title {
15
+ width: 100%;
16
+ text-align: center;
17
+ font-size: 2.5rem;
18
+ font-weight: 300;
19
+ margin-bottom: 20px;
20
+ text-shadow: 0 2px 4px rgba(0,0,0,0.3);
21
+ }
22
+ .main-title span {
23
+ font-weight: 700;
24
+ color: #fff;
25
+ }
26
+
27
+ .container {
28
+ background: var(--container-bg);
29
+ padding: 30px;
30
+ border-radius: 15px;
31
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
32
+ backdrop-filter: blur(10px);
33
+ -webkit-backdrop-filter: blur(10px);
34
+ border: 1px solid var(--border-color);
35
+ width: 100%;
36
+ max-width: 450px;
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: 20px;
40
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
41
+ }
42
+ .container:hover {
43
+ transform: translateY(-5px);
44
+ box-shadow: 0 12px 40px 0 rgba(0, 0, 0, 0.45);
45
+ }
46
+
47
+ h2 {
48
+ text-align: center;
49
+ color: #fff;
50
+ margin-top: 0;
51
+ font-weight: 500;
52
+ border-bottom: 1px solid var(--secondary-color);
53
+ padding-bottom: 15px;
54
+ }
55
+
56
+ label {
57
+ font-size: 0.9rem;
58
+ margin-bottom: -10px;
59
+ color: #bdc3c7;
60
+ }
61
+
62
+ textarea, .file-label {
63
+ width: 100%;
64
+ padding: 12px;
65
+ border-radius: 8px;
66
+ border: 1px solid var(--border-color);
67
+ box-sizing: border-box;
68
+ font-size: 1rem;
69
+ background: var(--input-bg);
70
+ color: var(--text-color);
71
+ transition: border-color 0.3s, box-shadow 0.3s;
72
+ }
73
+ textarea::placeholder {
74
+ color: #95a5a6;
75
+ }
76
+ textarea:focus, .file-label:hover {
77
+ outline: none;
78
+ border-color: var(--secondary-color);
79
+ box-shadow: 0 0 10px rgba(52, 152, 219, 0.5);
80
+ }
81
+
82
+ /* Custom file input */
83
+ .file-wrapper {
84
+ position: relative;
85
+ cursor: pointer;
86
+ }
87
+ input[type="file"] {
88
+ display: none;
89
+ }
90
+ .file-label {
91
+ display: flex;
92
+ justify-content: center;
93
+ align-items: center;
94
+ gap: 10px;
95
+ }
96
+ #file-name {
97
+ margin-top: 10px;
98
+ font-size: 0.85rem;
99
+ color: #bdc3c7;
100
+ text-align: center;
101
+ height: 1.2em;
102
+ }
103
+
104
+ button {
105
+ padding: 14px 20px;
106
+ background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
107
+ color: white;
108
+ border: none;
109
+ border-radius: 8px;
110
+ cursor: pointer;
111
+ font-size: 1.1rem;
112
+ font-weight: 600;
113
+ transition: all 0.3s ease;
114
+ display: flex;
115
+ justify-content: center;
116
+ align-items: center;
117
+ gap: 10px;
118
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
119
+ }
120
+ button:hover:not(:disabled) {
121
+ transform: translateY(-3px);
122
+ box-shadow: 0 6px 20px rgba(0,0,0,0.3);
123
+ }
124
+ button:disabled {
125
+ background: #555;
126
+ cursor: not-allowed;
127
+ opacity: 0.7;
128
+ }
129
+
130
+ .result-box {
131
+ margin-top: 15px;
132
+ padding: 20px;
133
+ background: var(--input-bg);
134
+ border: 1px solid var(--border-color);
135
+ border-radius: 8px;
136
+ min-height: 100px;
137
+ display: flex;
138
+ justify-content: center;
139
+ align-items: center;
140
+ text-align: center;
141
+ word-wrap: break-word;
142
+ color: #ecf0f1;
143
+ font-size: 1rem;
144
+ }
145
+
146
+ #qr-code-display img {
147
+ max-width: 100%;
148
+ height: auto;
149
+ border-radius: 8px;
150
+ border: 2px solid white;
151
+ animation: fadeIn 0.5s ease-in-out;
152
+ }
153
+
154
+ .loader {
155
+ border: 4px solid #555;
156
+ border-top: 4px solid var(--secondary-color);
157
+ border-radius: 50%;
158
+ width: 30px;
159
+ height: 30px;
160
+ animation: spin 1s linear infinite;
161
+ display: none;
162
+ }
163
+
164
+ @keyframes spin {
165
+ 0% { transform: rotate(0deg); }
166
+ 100% { transform: rotate(360deg); }
167
+ }
168
+ @keyframes fadeIn {
169
+ from { opacity: 0; transform: scale(0.9); }
170
+ to { opacity: 1; transform: scale(1); }
171
+ }
172
+ </style>