Elias207 commited on
Commit
7ad82f5
·
verified ·
1 Parent(s): 798a5af

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +268 -204
index.html CHANGED
@@ -9,15 +9,13 @@
9
  :root {
10
  --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
11
  --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
12
- --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
13
- --bg-pattern: linear-gradient(45deg, #1e3c72 0%, #2a5298 50%, #1e3c72 100%);
14
- --text-primary: #ffffff;
15
- --text-secondary: #e2e8f0;
16
  --card-bg: rgba(255, 255, 255, 0.1);
17
- --card-border: rgba(255, 255, 255, 0.2);
18
- --input-bg: rgba(255, 255, 255, 0.15);
19
- --shadow-light: 0 8px 32px rgba(31, 38, 135, 0.37);
20
- --shadow-heavy: 0 15px 35px rgba(31, 38, 135, 0.5);
 
21
  }
22
 
23
  * {
@@ -28,14 +26,14 @@
28
 
29
  body {
30
  font-family: 'Vazirmatn', sans-serif;
31
- background: var(--bg-pattern);
32
- background-attachment: fixed;
33
- min-height: 100vh;
34
  color: var(--text-primary);
 
 
35
  overflow-x: hidden;
36
  }
37
 
38
- /* QR Pattern Background */
39
  body::before {
40
  content: '';
41
  position: fixed;
@@ -43,78 +41,83 @@
43
  left: 0;
44
  width: 100%;
45
  height: 100%;
46
- background-image:
47
- radial-gradient(circle at 25% 25%, rgba(255,255,255,0.05) 2px, transparent 2px),
48
- radial-gradient(circle at 75% 75%, rgba(255,255,255,0.05) 2px, transparent 2px);
49
- background-size: 50px 50px;
50
  z-index: -1;
51
- animation: float 20s ease-in-out infinite;
52
  }
53
 
54
- @keyframes float {
55
- 0%, 100% { transform: translateY(0px) rotate(0deg); }
56
- 50% { transform: translateY(-20px) rotate(1deg); }
 
 
57
  }
58
 
59
- .header {
60
  text-align: center;
61
- padding: 40px 20px;
62
- background: rgba(255, 255, 255, 0.05);
63
- backdrop-filter: blur(20px);
64
  margin-bottom: 40px;
 
65
  }
66
 
67
  .main-title {
68
  font-size: clamp(2rem, 5vw, 3.5rem);
69
  font-weight: 300;
70
  margin-bottom: 10px;
71
- background: linear-gradient(135deg, #ffffff, #a8edea);
72
- -webkit-background-clip: text;
73
- -webkit-text-fill-color: transparent;
74
- background-clip: text;
75
- text-shadow: 0 2px 10px rgba(0,0,0,0.3);
76
  }
77
 
78
- .main-title span {
79
- font-weight: 700;
80
- background: var(--secondary-gradient);
 
 
 
 
 
 
 
 
 
 
 
 
81
  -webkit-background-clip: text;
82
  -webkit-text-fill-color: transparent;
83
  background-clip: text;
 
84
  }
85
 
86
  .subtitle {
87
  font-size: 1.1rem;
88
  color: var(--text-secondary);
89
- opacity: 0.9;
90
  }
91
 
92
- .main-container {
93
- display: grid;
94
- grid-template-columns: 1fr 1fr;
95
  gap: 30px;
96
  max-width: 1200px;
97
  margin: 0 auto;
98
- padding: 0 20px;
99
- }
100
-
101
- @media (max-width: 768px) {
102
- .main-container {
103
- grid-template-columns: 1fr;
104
- gap: 25px;
105
- }
106
  }
107
 
108
  .card {
 
 
 
109
  background: var(--card-bg);
110
  backdrop-filter: blur(20px);
111
- border: 1px solid var(--card-border);
 
112
  border-radius: 20px;
113
  padding: 30px;
114
- box-shadow: var(--shadow-light);
115
- transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
116
  position: relative;
117
  overflow: hidden;
 
118
  }
119
 
120
  .card::before {
@@ -126,12 +129,12 @@
126
  height: 4px;
127
  background: var(--primary-gradient);
128
  transform: scaleX(0);
129
- transition: transform 0.3s ease;
130
  }
131
 
132
  .card:hover {
133
- transform: translateY(-10px);
134
- box-shadow: var(--shadow-heavy);
135
  }
136
 
137
  .card:hover::before {
@@ -139,29 +142,48 @@
139
  }
140
 
141
  .card-header {
142
- display: flex;
143
- align-items: center;
144
- gap: 15px;
145
  margin-bottom: 25px;
146
- padding-bottom: 15px;
147
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
148
  }
149
 
150
  .card-icon {
151
- width: 50px;
152
- height: 50px;
153
- background: var(--primary-gradient);
154
- border-radius: 12px;
155
  display: flex;
156
  align-items: center;
157
  justify-content: center;
158
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  }
160
 
161
  .card-title {
162
- font-size: 1.4rem;
163
  font-weight: 600;
164
- color: var(--text-primary);
 
 
 
 
 
 
165
  }
166
 
167
  .form-group {
@@ -171,7 +193,7 @@
171
  .form-label {
172
  display: block;
173
  margin-bottom: 8px;
174
- font-size: 0.95rem;
175
  color: var(--text-secondary);
176
  font-weight: 500;
177
  }
@@ -179,9 +201,9 @@
179
  .form-input {
180
  width: 100%;
181
  padding: 15px;
182
- background: var(--input-bg);
183
  border: 2px solid transparent;
184
  border-radius: 12px;
 
185
  color: var(--text-primary);
186
  font-size: 1rem;
187
  transition: all 0.3s ease;
@@ -191,12 +213,12 @@
191
  .form-input:focus {
192
  outline: none;
193
  border-color: #667eea;
194
- background: rgba(255, 255, 255, 0.2);
195
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
196
  }
197
 
198
  .form-input::placeholder {
199
- color: rgba(255, 255, 255, 0.6);
200
  }
201
 
202
  .file-input-wrapper {
@@ -208,53 +230,50 @@
208
  display: none;
209
  }
210
 
211
- .file-input-label {
212
  display: flex;
213
  align-items: center;
214
  justify-content: center;
215
- gap: 12px;
216
  padding: 15px;
217
- background: var(--input-bg);
218
  border: 2px dashed rgba(255, 255, 255, 0.3);
219
  border-radius: 12px;
 
220
  transition: all 0.3s ease;
221
- min-height: 60px;
222
  }
223
 
224
- .file-input-label:hover {
225
- border-color: #667eea;
226
- background: rgba(255, 255, 255, 0.2);
 
227
  }
228
 
229
  .file-name {
230
  margin-top: 10px;
231
- padding: 8px 12px;
232
- background: rgba(255, 255, 255, 0.1);
233
- border-radius: 8px;
234
- font-size: 0.9rem;
235
  color: var(--text-secondary);
236
  text-align: center;
237
- min-height: 1.5em;
238
  }
239
 
240
  .btn {
241
  width: 100%;
242
- padding: 16px;
243
- background: var(--primary-gradient);
244
  border: none;
245
  border-radius: 12px;
246
- color: white;
247
  font-size: 1.1rem;
248
  font-weight: 600;
249
  cursor: pointer;
250
- transition: all 0.3s ease;
 
 
251
  display: flex;
252
  align-items: center;
253
  justify-content: center;
254
  gap: 10px;
255
- box-shadow: 0 4px 15px rgba(0,0,0,0.2);
256
- position: relative;
257
- overflow: hidden;
258
  }
259
 
260
  .btn::before {
@@ -264,55 +283,48 @@
264
  left: -100%;
265
  width: 100%;
266
  height: 100%;
267
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
268
  transition: left 0.5s;
269
  }
270
 
271
- .btn:hover:not(:disabled) {
272
- transform: translateY(-2px);
273
- box-shadow: 0 6px 20px rgba(0,0,0,0.3);
274
  }
275
 
276
- .btn:hover:not(:disabled)::before {
277
- left: 100%;
 
278
  }
279
 
280
- .btn:disabled {
281
- background: rgba(255, 255, 255, 0.1);
282
- cursor: not-allowed;
283
- transform: none;
284
  }
285
 
286
- .btn-secondary {
287
- background: var(--success-gradient);
 
 
 
 
 
 
 
288
  }
289
 
290
  .result-container {
291
  margin-top: 20px;
292
  padding: 20px;
293
- background: var(--input-bg);
294
  border-radius: 12px;
 
295
  min-height: 120px;
296
  display: flex;
297
  align-items: center;
298
  justify-content: center;
299
  text-align: center;
300
  position: relative;
301
- backdrop-filter: blur(10px);
302
- }
303
-
304
- .result-container img {
305
- max-width: 100%;
306
- height: auto;
307
- border-radius: 8px;
308
- box-shadow: 0 4px 15px rgba(0,0,0,0.3);
309
- animation: zoomIn 0.5s ease-out;
310
- }
311
-
312
- .result-text {
313
- word-wrap: break-word;
314
- line-height: 1.6;
315
- color: var(--text-primary);
316
  }
317
 
318
  .loader {
@@ -322,6 +334,7 @@
322
  border-top: 4px solid #667eea;
323
  border-radius: 50%;
324
  animation: spin 1s linear infinite;
 
325
  }
326
 
327
  @keyframes spin {
@@ -329,153 +342,164 @@
329
  100% { transform: rotate(360deg); }
330
  }
331
 
 
 
 
 
 
 
 
 
332
  @keyframes zoomIn {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  from {
334
  opacity: 0;
335
- transform: scale(0.5);
336
  }
337
  to {
338
  opacity: 1;
339
- transform: scale(1);
340
  }
341
  }
342
 
343
- .floating-elements {
344
- position: fixed;
345
- top: 0;
346
- left: 0;
347
- width: 100%;
348
- height: 100%;
349
- pointer-events: none;
350
- z-index: -1;
351
- }
352
-
353
- .floating-qr {
354
- position: absolute;
355
- width: 20px;
356
- height: 20px;
357
- background: rgba(255, 255, 255, 0.05);
358
- animation: float-qr 15s infinite linear;
359
  }
360
 
361
- .floating-qr:nth-child(1) { top: 20%; left: 10%; animation-delay: 0s; }
362
- .floating-qr:nth-child(2) { top: 80%; left: 90%; animation-delay: 5s; }
363
- .floating-qr:nth-child(3) { top: 40%; left: 80%; animation-delay: 10s; }
364
-
365
- @keyframes float-qr {
366
- 0% { transform: translateY(0) rotate(0deg); opacity: 0; }
367
- 50% { opacity: 1; }
368
- 100% { transform: translateY(-100vh) rotate(360deg); opacity: 0; }
 
 
 
 
 
 
 
369
  }
370
 
371
- /* Mobile optimizations */
372
  @media (max-width: 480px) {
373
- .header {
374
- padding: 30px 15px;
375
  }
376
 
377
  .card {
378
  padding: 20px;
379
- border-radius: 15px;
380
- }
381
-
382
- .main-container {
383
- padding: 0 15px;
384
  }
385
  }
386
  </style>
387
  </head>
388
  <body>
389
- <div class="floating-elements">
390
- <div class="floating-qr"></div>
391
- <div class="floating-qr"></div>
392
- <div class="floating-qr"></div>
393
- </div>
394
-
395
- <header class="header">
396
- <h1 class="main-title">ابزار مدرن <span>QR Code</span></h1>
397
- <p class="subtitle">ساخت و خواندن کیوآر کد به سادگی</p>
398
  </header>
399
 
400
- <div class="main-container">
401
  <!-- کارت ساخت QR Code -->
402
- <div class="card">
403
  <div class="card-header">
404
  <div class="card-icon">
405
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
406
  <rect x="3" y="3" width="7" height="7"/>
407
  <rect x="14" y="3" width="7" height="7"/>
408
  <rect x="14" y="14" width="7" height="7"/>
409
  <rect x="3" y="14" width="7" height="7"/>
410
- <rect x="5" y="5" width="3" height="3"/>
411
- <rect x="16" y="5" width="3" height="3"/>
412
- <rect x="16" y="16" width="3" height="3"/>
413
- <rect x="5" y="16" width="3" height="3"/>
414
  </svg>
415
  </div>
416
  <h2 class="card-title">ساخت QR Code</h2>
 
417
  </div>
418
 
419
  <div class="form-group">
420
- <label for="text-input" class="form-label">متن یا لینک خود را وارد کنید:</label>
421
- <textarea id="text-input" class="form-input" rows="4" placeholder="مثال: https://google.com یا متن دلخواه">سلام دنیا</textarea>
422
  </div>
423
 
424
- <button id="generate-btn" class="btn">
425
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
426
- <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
 
 
427
  </svg>
428
  <span>ساخت QR Code</span>
429
  </button>
430
 
431
  <div class="result-container">
432
- <div id="generate-loader" class="loader" style="display: none;"></div>
433
- <div id="qr-code-display"></div>
434
  </div>
435
  </div>
436
 
437
  <!-- کارت خواندن QR Code -->
438
- <div class="card">
439
  <div class="card-header">
440
  <div class="card-icon">
441
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
442
  <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
443
  <circle cx="12" cy="12" r="3"/>
444
  </svg>
445
  </div>
446
  <h2 class="card-title">خواندن QR Code</h2>
 
447
  </div>
448
 
449
  <div class="form-group">
450
- <label for="file-input" class="form-label">تصویر QR Code را انتخاب کنید:</label>
451
  <div class="file-input-wrapper">
452
  <input type="file" id="file-input" class="file-input" accept="image/*">
453
- <label for="file-input" class="file-input-label">
454
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
455
  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
456
  <polyline points="17 8 12 3 7 8"/>
457
  <line x1="12" y1="3" x2="12" y2="15"/>
458
  </svg>
459
- <span>انتخاب فایل تصویر</span>
460
  </label>
461
  </div>
462
- <div id="file-name" class="file-name"></div>
463
  </div>
464
 
465
- <button id="read-btn" class="btn btn-secondary">
466
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
467
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
468
- <polyline points="14,2 14,8 20,8"/>
469
- <line x1="16" y1="13" x2="8" y2="13"/>
470
- <line x1="16" y1="17" x2="8" y2="17"/>
471
- <polyline points="10,9 9,9 8,9"/>
472
  </svg>
473
  <span>خواندن QR Code</span>
474
  </button>
475
 
476
  <div class="result-container">
477
- <div id="read-loader" class="loader" style="display: none;"></div>
478
- <div id="decoded-text" class="result-text">نتیجه در اینجا نمایش داده می‌شود</div>
479
  </div>
480
  </div>
481
  </div>
@@ -483,7 +507,7 @@
483
  <script>
484
  const SPACE_URL = "https://cultrix-qrcode-read-generate.hf.space";
485
 
486
- // دریافت عناصر DOM
487
  const generateBtn = document.getElementById('generate-btn');
488
  const readBtn = document.getElementById('read-btn');
489
  const textInput = document.getElementById('text-input');
@@ -497,14 +521,14 @@
497
  // نمایش نام فایل انتخاب شده
498
  fileInput.addEventListener('change', () => {
499
  if (fileInput.files.length > 0) {
500
- fileNameDisplay.textContent = `✓ ${fileInput.files[0].name}`;
501
- fileNameDisplay.style.color = '#4facfe';
502
  } else {
503
  fileNameDisplay.textContent = '';
504
  }
505
  });
506
 
507
- // توابع کمکی
508
  const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
509
 
510
  const listenForData = (sessionHash, onResult, onError) => {
@@ -534,13 +558,11 @@
534
  };
535
  };
536
 
537
- // منطق ساخت QR Code
538
  generateBtn.addEventListener('click', async () => {
539
  const text = textInput.value.trim();
540
  if (!text) {
541
  textInput.focus();
542
- textInput.style.borderColor = '#f5576c';
543
- setTimeout(() => textInput.style.borderColor = 'transparent', 2000);
544
  return;
545
  }
546
 
@@ -565,32 +587,31 @@
565
  if (result && result[0]) {
566
  qrCodeDisplay.innerHTML = result[0];
567
  } else {
568
- qrCodeDisplay.innerHTML = '<p class="result-text">خطا: خروجی معتبر دریافت نشد.</p>';
569
  }
570
  },
571
  (error) => {
572
- qrCodeDisplay.innerHTML = `<p class="result-text">خطا در ساخت: ${error}</p>`;
573
  }
574
  );
575
  } catch (error) {
576
- qrCodeDisplay.innerHTML = `<p class="result-text">خطا: ${error.message}</p>`;
577
  } finally {
578
  generateLoader.style.display = 'none';
579
  generateBtn.disabled = false;
580
  }
581
  });
582
 
583
- // منطق خواندن QR Code
584
  readBtn.addEventListener('click', async () => {
585
  const file = fileInput.files[0];
586
  if (!file) {
587
- fileNameDisplay.textContent = '⚠️ لطفاً یک فایل انتخاب کنید';
588
- fileNameDisplay.style.color = '#f5576c';
589
  return;
590
  }
591
 
592
  readLoader.style.display = 'block';
593
- decodedText.textContent = '';
594
  readBtn.disabled = true;
595
 
596
  try {
@@ -623,19 +644,62 @@
623
  listenForData(
624
  sessionHash,
625
  (result) => {
626
- decodedText.textContent = `📄 متن خوانده شده:\n\n${result[0]}`;
627
  },
628
  (error) => {
629
- decodedText.textContent = `❌ خطا در خواندن: ${error}`;
630
  }
631
  );
632
  } catch (error) {
633
- decodedText.textContent = `❌ خطا: ${error.message}`;
634
  } finally {
635
  readLoader.style.display = 'none';
636
  readBtn.disabled = false;
637
  }
638
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
639
  </script>
640
  </body>
641
  </html>
 
9
  :root {
10
  --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
11
  --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
12
+ --background: linear-gradient(135deg, #1e3c72 0%, #2a5298 50%, #1e3c72 100%);
 
 
 
13
  --card-bg: rgba(255, 255, 255, 0.1);
14
+ --text-primary: #ffffff;
15
+ --text-secondary: #e8eaed;
16
+ --border-color: rgba(255, 255, 255, 0.15);
17
+ --shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
18
+ --glow: 0 0 30px rgba(102, 126, 234, 0.5);
19
  }
20
 
21
  * {
 
26
 
27
  body {
28
  font-family: 'Vazirmatn', sans-serif;
29
+ background: var(--background);
 
 
30
  color: var(--text-primary);
31
+ min-height: 100vh;
32
+ padding: 20px;
33
  overflow-x: hidden;
34
  }
35
 
36
+ /* Background Animations */
37
  body::before {
38
  content: '';
39
  position: fixed;
 
41
  left: 0;
42
  width: 100%;
43
  height: 100%;
44
+ background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="qr" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse"><rect width="8" height="8" fill="rgba(255,255,255,0.03)"/><rect x="12" y="0" width="8" height="8" fill="rgba(255,255,255,0.03)"/><rect x="0" y="12" width="8" height="8" fill="rgba(255,255,255,0.03)"/><rect x="12" y="12" width="8" height="8" fill="rgba(255,255,255,0.03)"/></pattern></defs><rect width="100" height="100" fill="url(%23qr)"/></svg>');
 
 
 
45
  z-index: -1;
46
+ animation: backgroundMove 20s ease-in-out infinite;
47
  }
48
 
49
+ @keyframes backgroundMove {
50
+ 0%, 100% { transform: translate(0, 0) rotate(0deg); }
51
+ 25% { transform: translate(-10px, -10px) rotate(1deg); }
52
+ 50% { transform: translate(10px, -5px) rotate(-1deg); }
53
+ 75% { transform: translate(-5px, 10px) rotate(0.5deg); }
54
  }
55
 
56
+ .main-header {
57
  text-align: center;
 
 
 
58
  margin-bottom: 40px;
59
+ animation: slideDown 1s ease-out;
60
  }
61
 
62
  .main-title {
63
  font-size: clamp(2rem, 5vw, 3.5rem);
64
  font-weight: 300;
65
  margin-bottom: 10px;
66
+ text-shadow: 0 4px 8px rgba(0,0,0,0.5);
67
+ position: relative;
 
 
 
68
  }
69
 
70
+ .main-title::after {
71
+ content: '';
72
+ position: absolute;
73
+ bottom: -10px;
74
+ left: 50%;
75
+ transform: translateX(-50%);
76
+ width: 80px;
77
+ height: 4px;
78
+ background: var(--primary-gradient);
79
+ border-radius: 2px;
80
+ box-shadow: var(--glow);
81
+ }
82
+
83
+ .main-title .highlight {
84
+ background: var(--primary-gradient);
85
  -webkit-background-clip: text;
86
  -webkit-text-fill-color: transparent;
87
  background-clip: text;
88
+ font-weight: 700;
89
  }
90
 
91
  .subtitle {
92
  font-size: 1.1rem;
93
  color: var(--text-secondary);
94
+ opacity: 0.8;
95
  }
96
 
97
+ .app-container {
98
+ display: flex;
 
99
  gap: 30px;
100
  max-width: 1200px;
101
  margin: 0 auto;
102
+ flex-wrap: wrap;
103
+ justify-content: center;
 
 
 
 
 
 
104
  }
105
 
106
  .card {
107
+ flex: 1;
108
+ min-width: 320px;
109
+ max-width: 500px;
110
  background: var(--card-bg);
111
  backdrop-filter: blur(20px);
112
+ -webkit-backdrop-filter: blur(20px);
113
+ border: 1px solid var(--border-color);
114
  border-radius: 20px;
115
  padding: 30px;
116
+ box-shadow: var(--shadow);
117
+ transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
118
  position: relative;
119
  overflow: hidden;
120
+ animation: slideUp 1s ease-out;
121
  }
122
 
123
  .card::before {
 
129
  height: 4px;
130
  background: var(--primary-gradient);
131
  transform: scaleX(0);
132
+ transition: transform 0.4s ease;
133
  }
134
 
135
  .card:hover {
136
+ transform: translateY(-10px) scale(1.02);
137
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
138
  }
139
 
140
  .card:hover::before {
 
142
  }
143
 
144
  .card-header {
145
+ text-align: center;
 
 
146
  margin-bottom: 25px;
147
+ position: relative;
 
148
  }
149
 
150
  .card-icon {
151
+ width: 60px;
152
+ height: 60px;
153
+ margin: 0 auto 15px;
154
+ border-radius: 50%;
155
  display: flex;
156
  align-items: center;
157
  justify-content: center;
158
+ font-size: 24px;
159
+ color: white;
160
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);
161
+ animation: pulse 2s infinite;
162
+ }
163
+
164
+ .generate-card .card-icon {
165
+ background: var(--primary-gradient);
166
+ }
167
+
168
+ .read-card .card-icon {
169
+ background: var(--secondary-gradient);
170
+ }
171
+
172
+ @keyframes pulse {
173
+ 0%, 100% { transform: scale(1); }
174
+ 50% { transform: scale(1.1); }
175
  }
176
 
177
  .card-title {
178
+ font-size: 1.5rem;
179
  font-weight: 600;
180
+ margin-bottom: 8px;
181
+ }
182
+
183
+ .card-subtitle {
184
+ color: var(--text-secondary);
185
+ font-size: 0.9rem;
186
+ opacity: 0.8;
187
  }
188
 
189
  .form-group {
 
193
  .form-label {
194
  display: block;
195
  margin-bottom: 8px;
196
+ font-size: 0.9rem;
197
  color: var(--text-secondary);
198
  font-weight: 500;
199
  }
 
201
  .form-input {
202
  width: 100%;
203
  padding: 15px;
 
204
  border: 2px solid transparent;
205
  border-radius: 12px;
206
+ background: rgba(255, 255, 255, 0.08);
207
  color: var(--text-primary);
208
  font-size: 1rem;
209
  transition: all 0.3s ease;
 
213
  .form-input:focus {
214
  outline: none;
215
  border-color: #667eea;
216
+ background: rgba(255, 255, 255, 0.12);
217
+ box-shadow: 0 0 20px rgba(102, 126, 234, 0.3);
218
  }
219
 
220
  .form-input::placeholder {
221
+ color: rgba(255, 255, 255, 0.5);
222
  }
223
 
224
  .file-input-wrapper {
 
230
  display: none;
231
  }
232
 
233
+ .file-label {
234
  display: flex;
235
  align-items: center;
236
  justify-content: center;
237
+ gap: 10px;
238
  padding: 15px;
 
239
  border: 2px dashed rgba(255, 255, 255, 0.3);
240
  border-radius: 12px;
241
+ background: rgba(255, 255, 255, 0.05);
242
  transition: all 0.3s ease;
243
+ cursor: pointer;
244
  }
245
 
246
+ .file-label:hover {
247
+ border-color: #f5576c;
248
+ background: rgba(245, 87, 108, 0.1);
249
+ transform: scale(1.02);
250
  }
251
 
252
  .file-name {
253
  margin-top: 10px;
254
+ font-size: 0.85rem;
 
 
 
255
  color: var(--text-secondary);
256
  text-align: center;
257
+ min-height: 20px;
258
  }
259
 
260
  .btn {
261
  width: 100%;
262
+ padding: 15px;
 
263
  border: none;
264
  border-radius: 12px;
 
265
  font-size: 1.1rem;
266
  font-weight: 600;
267
  cursor: pointer;
268
+ transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
269
+ position: relative;
270
+ overflow: hidden;
271
  display: flex;
272
  align-items: center;
273
  justify-content: center;
274
  gap: 10px;
275
+ color: white;
276
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
 
277
  }
278
 
279
  .btn::before {
 
283
  left: -100%;
284
  width: 100%;
285
  height: 100%;
286
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
287
  transition: left 0.5s;
288
  }
289
 
290
+ .btn:hover::before {
291
+ left: 100%;
 
292
  }
293
 
294
+ .btn-generate {
295
+ background: var(--primary-gradient);
296
+ box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
297
  }
298
 
299
+ .btn-read {
300
+ background: var(--secondary-gradient);
301
+ box-shadow: 0 8px 20px rgba(245, 87, 108, 0.4);
 
302
  }
303
 
304
+ .btn:hover:not(:disabled) {
305
+ transform: translateY(-3px);
306
+ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.4);
307
+ }
308
+
309
+ .btn:disabled {
310
+ opacity: 0.6;
311
+ cursor: not-allowed;
312
+ transform: none !important;
313
  }
314
 
315
  .result-container {
316
  margin-top: 20px;
317
  padding: 20px;
318
+ background: rgba(255, 255, 255, 0.05);
319
  border-radius: 12px;
320
+ border: 1px solid var(--border-color);
321
  min-height: 120px;
322
  display: flex;
323
  align-items: center;
324
  justify-content: center;
325
  text-align: center;
326
  position: relative;
327
+ overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  }
329
 
330
  .loader {
 
334
  border-top: 4px solid #667eea;
335
  border-radius: 50%;
336
  animation: spin 1s linear infinite;
337
+ display: none;
338
  }
339
 
340
  @keyframes spin {
 
342
  100% { transform: rotate(360deg); }
343
  }
344
 
345
+ .qr-result img {
346
+ max-width: 100%;
347
+ height: auto;
348
+ border-radius: 8px;
349
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
350
+ animation: zoomIn 0.5s ease-out;
351
+ }
352
+
353
  @keyframes zoomIn {
354
+ from {
355
+ opacity: 0;
356
+ transform: scale(0.8);
357
+ }
358
+ to {
359
+ opacity: 1;
360
+ transform: scale(1);
361
+ }
362
+ }
363
+
364
+ .text-result {
365
+ word-wrap: break-word;
366
+ line-height: 1.6;
367
+ font-size: 1rem;
368
+ }
369
+
370
+ /* انیمیشن‌های ورود */
371
+ @keyframes slideDown {
372
  from {
373
  opacity: 0;
374
+ transform: translateY(-50px);
375
  }
376
  to {
377
  opacity: 1;
378
+ transform: translateY(0);
379
  }
380
  }
381
 
382
+ @keyframes slideUp {
383
+ from {
384
+ opacity: 0;
385
+ transform: translateY(50px);
386
+ }
387
+ to {
388
+ opacity: 1;
389
+ transform: translateY(0);
390
+ }
 
 
 
 
 
 
 
391
  }
392
 
393
+ /* Responsive Design */
394
+ @media (max-width: 768px) {
395
+ .app-container {
396
+ flex-direction: column;
397
+ gap: 20px;
398
+ }
399
+
400
+ .card {
401
+ min-width: 100%;
402
+ padding: 25px;
403
+ }
404
+
405
+ body {
406
+ padding: 15px;
407
+ }
408
  }
409
 
 
410
  @media (max-width: 480px) {
411
+ .main-title {
412
+ font-size: 2rem;
413
  }
414
 
415
  .card {
416
  padding: 20px;
 
 
 
 
 
417
  }
418
  }
419
  </style>
420
  </head>
421
  <body>
422
+ <header class="main-header">
423
+ <h1 class="main-title">ابزار مدرن <span class="highlight">QR Code</span></h1>
424
+ <p class="subtitle">ساخت و خواندن کدهای QR به سادگی</p>
 
 
 
 
 
 
425
  </header>
426
 
427
+ <div class="app-container">
428
  <!-- کارت ساخت QR Code -->
429
+ <div class="card generate-card">
430
  <div class="card-header">
431
  <div class="card-icon">
432
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
433
  <rect x="3" y="3" width="7" height="7"/>
434
  <rect x="14" y="3" width="7" height="7"/>
435
  <rect x="14" y="14" width="7" height="7"/>
436
  <rect x="3" y="14" width="7" height="7"/>
 
 
 
 
437
  </svg>
438
  </div>
439
  <h2 class="card-title">ساخت QR Code</h2>
440
+ <p class="card-subtitle">متن خود را به کد QR تبدیل کنید</p>
441
  </div>
442
 
443
  <div class="form-group">
444
+ <label class="form-label" for="text-input">متن یا لینک خود را وارد کنید:</label>
445
+ <textarea id="text-input" class="form-input" rows="4" placeholder="مثال: https://google.com یا سلام دنیا">سلام دنیا</textarea>
446
  </div>
447
 
448
+ <button id="generate-btn" class="btn btn-generate">
449
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
450
+ <path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2v0z"/>
451
+ <path d="M12 8l4 4-4 4"/>
452
+ <path d="M8 12h7"/>
453
  </svg>
454
  <span>ساخت QR Code</span>
455
  </button>
456
 
457
  <div class="result-container">
458
+ <div id="generate-loader" class="loader"></div>
459
+ <div id="qr-code-display" class="qr-result"></div>
460
  </div>
461
  </div>
462
 
463
  <!-- کارت خواندن QR Code -->
464
+ <div class="card read-card">
465
  <div class="card-header">
466
  <div class="card-icon">
467
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
468
  <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
469
  <circle cx="12" cy="12" r="3"/>
470
  </svg>
471
  </div>
472
  <h2 class="card-title">خواندن QR Code</h2>
473
+ <p class="card-subtitle">تصویر QR Code را آپلود کرده و متن آن را بخوانید</p>
474
  </div>
475
 
476
  <div class="form-group">
477
+ <label class="form-label" for="file-input">تصویر QR Code را انتخاب کنید:</label>
478
  <div class="file-input-wrapper">
479
  <input type="file" id="file-input" class="file-input" accept="image/*">
480
+ <label for="file-input" class="file-label">
481
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
482
  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
483
  <polyline points="17 8 12 3 7 8"/>
484
  <line x1="12" y1="3" x2="12" y2="15"/>
485
  </svg>
486
+ <span>انتخاب تصویر</span>
487
  </label>
488
  </div>
489
+ <p id="file-name" class="file-name"></p>
490
  </div>
491
 
492
+ <button id="read-btn" class="btn btn-read">
493
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
494
+ <circle cx="11" cy="11" r="8"/>
495
+ <path d="m21 21-4.35-4.35"/>
 
 
 
496
  </svg>
497
  <span>خواندن QR Code</span>
498
  </button>
499
 
500
  <div class="result-container">
501
+ <div id="read-loader" class="loader"></div>
502
+ <p id="decoded-text" class="text-result">نتیجه در اینجا نمایش داده می‌شود</p>
503
  </div>
504
  </div>
505
  </div>
 
507
  <script>
508
  const SPACE_URL = "https://cultrix-qrcode-read-generate.hf.space";
509
 
510
+ // --- دریافت عناصر DOM ---
511
  const generateBtn = document.getElementById('generate-btn');
512
  const readBtn = document.getElementById('read-btn');
513
  const textInput = document.getElementById('text-input');
 
521
  // نمایش نام فایل انتخاب شده
522
  fileInput.addEventListener('change', () => {
523
  if (fileInput.files.length > 0) {
524
+ fileNameDisplay.textContent = `فایل انتخاب شده: ${fileInput.files[0].name}`;
525
+ fileNameDisplay.style.color = '#4ade80';
526
  } else {
527
  fileNameDisplay.textContent = '';
528
  }
529
  });
530
 
531
+ // --- توابع کمکی ---
532
  const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
533
 
534
  const listenForData = (sessionHash, onResult, onError) => {
 
558
  };
559
  };
560
 
561
+ // --- منطق ساخت QR Code ---
562
  generateBtn.addEventListener('click', async () => {
563
  const text = textInput.value.trim();
564
  if (!text) {
565
  textInput.focus();
 
 
566
  return;
567
  }
568
 
 
587
  if (result && result[0]) {
588
  qrCodeDisplay.innerHTML = result[0];
589
  } else {
590
+ qrCodeDisplay.innerHTML = '<p style="color: #ef4444;">خطا: خروجی معتبر دریافت نشد</p>';
591
  }
592
  },
593
  (error) => {
594
+ qrCodeDisplay.innerHTML = `<p style="color: #ef4444;">خطا در ساخت: ${error}</p>`;
595
  }
596
  );
597
  } catch (error) {
598
+ qrCodeDisplay.innerHTML = `<p style="color: #ef4444;">خطا: ${error.message}</p>`;
599
  } finally {
600
  generateLoader.style.display = 'none';
601
  generateBtn.disabled = false;
602
  }
603
  });
604
 
605
+ // --- منطق خواندن QR Code ---
606
  readBtn.addEventListener('click', async () => {
607
  const file = fileInput.files[0];
608
  if (!file) {
609
+ fileInput.click();
 
610
  return;
611
  }
612
 
613
  readLoader.style.display = 'block';
614
+ decodedText.innerHTML = '';
615
  readBtn.disabled = true;
616
 
617
  try {
 
644
  listenForData(
645
  sessionHash,
646
  (result) => {
647
+ decodedText.innerHTML = `<strong style="color: #4ade80;">متن خوانده شده:</strong><br><br>${result[0]}`;
648
  },
649
  (error) => {
650
+ decodedText.innerHTML = `<p style="color: #ef4444;">خطا در خواندن: ${error}</p>`;
651
  }
652
  );
653
  } catch (error) {
654
+ decodedText.innerHTML = `<p style="color: #ef4444;">خطا: ${error.message}</p>`;
655
  } finally {
656
  readLoader.style.display = 'none';
657
  readBtn.disabled = false;
658
  }
659
  });
660
+
661
+ // اضافه کردن قابلیت drag and drop برای فایل
662
+ const fileLabel = document.querySelector('.file-label');
663
+
664
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
665
+ fileLabel.addEventListener(eventName, preventDefaults, false);
666
+ });
667
+
668
+ function preventDefaults(e) {
669
+ e.preventDefault();
670
+ e.stopPropagation();
671
+ }
672
+
673
+ ['dragenter', 'dragover'].forEach(eventName => {
674
+ fileLabel.addEventListener(eventName, highlight, false);
675
+ });
676
+
677
+ ['dragleave', 'drop'].forEach(eventName => {
678
+ fileLabel.addEventListener(eventName, unhighlight, false);
679
+ });
680
+
681
+ function highlight(e) {
682
+ fileLabel.style.borderColor = '#f5576c';
683
+ fileLabel.style.backgroundColor = 'rgba(245, 87, 108, 0.2)';
684
+ }
685
+
686
+ function unhighlight(e) {
687
+ fileLabel.style.borderColor = 'rgba(255, 255, 255, 0.3)';
688
+ fileLabel.style.backgroundColor = 'rgba(255, 255, 255, 0.05)';
689
+ }
690
+
691
+ fileLabel.addEventListener('drop', handleDrop, false);
692
+
693
+ function handleDrop(e) {
694
+ const dt = e.dataTransfer;
695
+ const files = dt.files;
696
+
697
+ if (files.length > 0) {
698
+ fileInput.files = files;
699
+ fileNameDisplay.textContent = `فایل انتخاب شده: ${files[0].name}`;
700
+ fileNameDisplay.style.color = '#4ade80';
701
+ }
702
+ }
703
  </script>
704
  </body>
705
  </html>