Znfeoqm commited on
Commit
e04348c
·
verified ·
1 Parent(s): c0eaec6

Update src/App.jsx

Browse files
Files changed (1) hide show
  1. src/App.jsx +165 -9
src/App.jsx CHANGED
@@ -31,7 +31,7 @@ const QRGeneratorTab = ({
31
  // Effect to generate QR code on the main canvas (Generator Tab)
32
  useEffect(() => {
33
  drawQrCode(qrCanvasRef.current, content, qrColor, errorLevel);
34
- }, [content, qrColor, errorLevel, drawQrCode, qrCanvasRef]); // Added qrCanvasRef to dependencies
35
 
36
  // Effect to generate QR codes for style previews (Style Selection Panel)
37
  useEffect(() => {
@@ -39,7 +39,7 @@ const QRGeneratorTab = ({
39
  const canvas = styleCanvasRefs.current[index];
40
  drawQrCode(canvas, "Sample", style.fg, 'H', 80);
41
  });
42
- }, [qrStyles, drawQrCode, styleCanvasRefs]); // Added styleCanvasRefs to dependencies
43
 
44
  return (
45
  <div className="flex flex-col lg:flex-row p-4 md:p-6 space-y-6 lg:space-y-0 lg:space-x-6 h-full">
@@ -47,8 +47,15 @@ const QRGeneratorTab = ({
47
  <div className={`flex flex-col w-full lg:w-3/4 p-6 rounded-2xl border ${currentThemeClasses.glassBorder} ${currentThemeClasses.glassBg} shadow-2xl ${currentThemeClasses.shadow} transform transition-all duration-500 ease-in-out`}>
48
  <label className={`mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>Enter Content:</label>
49
  <textarea
50
- className={`w-full p-3 rounded-xl border ${currentThemeClasses.inputBorder} ${currentThemeClasses.inputBg} ${currentThemeClasses.text} focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all duration-300 font-inter
51
- ${isInputFocused ? 'ring-2 ring-blue-500 shadow-md shadow-blue-500/50' : ''}`}
 
 
 
 
 
 
 
52
  rows="6"
53
  placeholder="Enter text or URL..."
54
  value={content}
@@ -335,7 +342,7 @@ const App = () => {
335
  cardBorder: 'border-green-900/15',
336
  qrPreviewBorder: 'border-green-500/50',
337
  qrPreviewBg: 'bg-gradient-to-br from-green-900/30 to-green-800/30 backdrop-blur-md',
338
- headerGlow: 'animate-quantum-flux'
339
  },
340
  'ocean-blue': {
341
  bg: 'bg-gradient-to-br from-[#001A33] via-[#003366] to-[#002A5A] animate-gradient-shift',
@@ -357,7 +364,7 @@ const App = () => {
357
  cardBorder: 'border-blue-900/15',
358
  qrPreviewBorder: 'border-blue-600/50',
359
  qrPreviewBg: 'bg-gradient-to-br from-blue-950/30 to-blue-900/30 backdrop-blur-md',
360
- headerGlow: 'animate-quantum-flux'
361
  },
362
  'warm-grey': {
363
  bg: 'bg-gradient-to-br from-[#202020] via-[#404040] to-[#303030] animate-gradient-shift',
@@ -379,7 +386,7 @@ const App = () => {
379
  cardBorder: 'border-gray-700/15',
380
  qrPreviewBorder: 'border-gray-500/50',
381
  qrPreviewBg: 'bg-gradient-to-br from-gray-800/30 to-gray-700/30 backdrop-blur-md',
382
- headerGlow: 'animate-quantum-flux'
383
  },
384
  'deep-purple': {
385
  bg: 'bg-gradient-to-br from-[#100830] via-[#201040] to-[#180C38] animate-gradient-shift',
@@ -401,7 +408,7 @@ const App = () => {
401
  cardBorder: 'border-purple-900/15',
402
  qrPreviewBorder: 'border-purple-600/50',
403
  qrPreviewBg: 'bg-gradient-to-br from-purple-950/30 to-purple-900/30 backdrop-blur-md',
404
- headerGlow: 'animate-quantum-flux'
405
  },
406
  'sunrise-orange': {
407
  bg: 'bg-gradient-to-br from-[#A0300A] via-[#D0501A] to-[#B84012] animate-gradient-shift',
@@ -423,7 +430,7 @@ const App = () => {
423
  cardBorder: 'border-orange-800/15',
424
  qrPreviewBorder: 'border-orange-600/50',
425
  qrPreviewBg: 'bg-gradient-to-br from-orange-900/30 to-orange-800/30 backdrop-blur-md',
426
- headerGlow: 'animate-quantum-flux'
427
  },
428
  };
429
 
@@ -467,6 +474,155 @@ const App = () => {
467
  }
468
  }, []);
469
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  return (
471
  <div className={`min-h-screen font-inter antialiased ${currentThemeClasses.bg} ${currentThemeClasses.text} transition-all duration-500 ease-in-out`}>
472
  <div className="container mx-auto p-4 max-w-7xl">
 
31
  // Effect to generate QR code on the main canvas (Generator Tab)
32
  useEffect(() => {
33
  drawQrCode(qrCanvasRef.current, content, qrColor, errorLevel);
34
+ }, [content, qrColor, errorLevel, drawQrCode, qrCanvasRef]);
35
 
36
  // Effect to generate QR codes for style previews (Style Selection Panel)
37
  useEffect(() => {
 
39
  const canvas = styleCanvasRefs.current[index];
40
  drawQrCode(canvas, "Sample", style.fg, 'H', 80);
41
  });
42
+ }, [qrStyles, drawQrCode, styleCanvasRefs]);
43
 
44
  return (
45
  <div className="flex flex-col lg:flex-row p-4 md:p-6 space-y-6 lg:space-y-0 lg:space-x-6 h-full">
 
47
  <div className={`flex flex-col w-full lg:w-3/4 p-6 rounded-2xl border ${currentThemeClasses.glassBorder} ${currentThemeClasses.glassBg} shadow-2xl ${currentThemeClasses.shadow} transform transition-all duration-500 ease-in-out`}>
48
  <label className={`mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>Enter Content:</label>
49
  <textarea
50
+ // CRITICAL FIX: Using string concatenation for className to avoid parser issues
51
+ className={
52
+ "w-full p-3 rounded-xl border " +
53
+ currentThemeClasses.inputBorder + " " +
54
+ currentThemeClasses.inputBg + " " +
55
+ currentThemeClasses.text + " " +
56
+ "focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all duration-300 font-inter " +
57
+ (isInputFocused ? 'ring-2 ring-blue-500 shadow-md shadow-blue-500/50' : '')
58
+ }
59
  rows="6"
60
  placeholder="Enter text or URL..."
61
  value={content}
 
342
  cardBorder: 'border-green-900/15',
343
  qrPreviewBorder: 'border-green-500/50',
344
  qrPreviewBg: 'bg-gradient-to-br from-green-900/30 to-green-800/30 backdrop-blur-md',
345
+ headerGlow: 'animate-quantum-flux'
346
  },
347
  'ocean-blue': {
348
  bg: 'bg-gradient-to-br from-[#001A33] via-[#003366] to-[#002A5A] animate-gradient-shift',
 
364
  cardBorder: 'border-blue-900/15',
365
  qrPreviewBorder: 'border-blue-600/50',
366
  qrPreviewBg: 'bg-gradient-to-br from-blue-950/30 to-blue-900/30 backdrop-blur-md',
367
+ headerGlow: 'animate-quantum-flux'
368
  },
369
  'warm-grey': {
370
  bg: 'bg-gradient-to-br from-[#202020] via-[#404040] to-[#303030] animate-gradient-shift',
 
386
  cardBorder: 'border-gray-700/15',
387
  qrPreviewBorder: 'border-gray-500/50',
388
  qrPreviewBg: 'bg-gradient-to-br from-gray-800/30 to-gray-700/30 backdrop-blur-md',
389
+ headerGlow: 'animate-quantum-flux'
390
  },
391
  'deep-purple': {
392
  bg: 'bg-gradient-to-br from-[#100830] via-[#201040] to-[#180C38] animate-gradient-shift',
 
408
  cardBorder: 'border-purple-900/15',
409
  qrPreviewBorder: 'border-purple-600/50',
410
  qrPreviewBg: 'bg-gradient-to-br from-purple-950/30 to-purple-900/30 backdrop-blur-md',
411
+ headerGlow: 'animate-quantum-flux'
412
  },
413
  'sunrise-orange': {
414
  bg: 'bg-gradient-to-br from-[#A0300A] via-[#D0501A] to-[#B84012] animate-gradient-shift',
 
430
  cardBorder: 'border-orange-800/15',
431
  qrPreviewBorder: 'border-orange-600/50',
432
  qrPreviewBg: 'bg-gradient-to-br from-orange-900/30 to-orange-800/30 backdrop-blur-md',
433
+ headerGlow: 'animate-quantum-flux'
434
  },
435
  };
436
 
 
474
  }
475
  }, []);
476
 
477
+ // Function to download the generated QR code (remains in App, passed to generator)
478
+ const downloadQrCode = () => {
479
+ if (content.trim() === '') {
480
+ showAlert('Please enter content to generate QR code.');
481
+ return;
482
+ }
483
+ const canvas = qrCanvasRef.current;
484
+ if (canvas) {
485
+ const pngUrl = canvas.toDataURL("image/png");
486
+ const downloadLink = document.createElement('a');
487
+ downloadLink.href = pngUrl;
488
+ downloadLink.download = 'qrcode.png';
489
+ document.body.appendChild(downloadLink);
490
+ downloadLink.click();
491
+ document.body.removeChild(downloadLink);
492
+ }
493
+ };
494
+
495
+ // Function to decode QR code from an uploaded image (remains in App, passed to decoder)
496
+ const decodeQrCode = (event) => {
497
+ const file = event.target.files[0];
498
+ if (!file) return;
499
+
500
+ const reader = new FileReader();
501
+ reader.onload = (e) => {
502
+ const img = new Image();
503
+ img.onload = () => {
504
+ const canvas = document.createElement('canvas');
505
+ const context = canvas.getContext('2d');
506
+ canvas.width = img.width;
507
+ canvas.height = img.height;
508
+ context.drawImage(img, 0, 0, img.width, img.height);
509
+
510
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
511
+
512
+ if (jsQR) {
513
+ let code = jsQR(imageData.data, imageData.width, imageData.height);
514
+
515
+ if (!code) {
516
+ for (let i = 0; i < imageData.data.length; i += 4) {
517
+ imageData.data[i] = 255 - imageData.data[i];
518
+ imageData.data[i + 1] = 255 - imageData.data[i + 1];
519
+ imageData.data[i + 2] = 255 - imageData.data[i + 2];
520
+ }
521
+ code = jsQR(imageData.data, imageData.width, imageData.height);
522
+ }
523
+
524
+ if (code) {
525
+ setDecodedContent(code.data);
526
+ setSuggestedActions('');
527
+ setShowSuggestedActions(false);
528
+ } else {
529
+ setDecodedContent('No QR code detected.');
530
+ setSuggestedActions('');
531
+ setShowSuggestedActions(false);
532
+ }
533
+ } else {
534
+ showAlert('QR decoder library (jsQR) not loaded. Please try again or check internet connection.');
535
+ setSuggestedActions('');
536
+ setShowSuggestedActions(false);
537
+ }
538
+ };
539
+ img.src = e.target.result;
540
+ };
541
+ reader.readAsDataURL(file);
542
+ };
543
+
544
+ // Function to summarize content using Gemini API (remains in App, passed to generator)
545
+ const summarizeContent = async () => {
546
+ if (!content.trim()) {
547
+ showAlert('Please enter content to summarize.');
548
+ return;
549
+ }
550
+
551
+ setIsSummarizing(true);
552
+ try {
553
+ let chatHistory = [];
554
+ const prompt = `Summarize the following text concisely: ${content}`;
555
+ chatHistory.push({ role: "user", parts: [{ text: prompt }] });
556
+ const payload = { contents: chatHistory };
557
+ const apiKey = ""; // Canvas will provide this at runtime
558
+ const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`;
559
+
560
+ const response = await fetch(apiUrl, {
561
+ method: 'POST',
562
+ headers: { 'Content-Type': 'application/json' },
563
+ body: JSON.stringify(payload)
564
+ });
565
+
566
+ const result = await response.json();
567
+
568
+ if (result.candidates && result.candidates.length > 0 &&
569
+ result.candidates[0].content && result.candidates[0].content.parts &&
570
+ result.candidates[0].content.parts.length > 0) {
571
+ const text = result.candidates[0].content.parts[0].text;
572
+ setContent(text);
573
+ } else {
574
+ showAlert("Failed to summarize content. Please try again.");
575
+ }
576
+ } catch (error) {
577
+ console.error("Error summarizing content:", error);
578
+ showAlert("An error occurred while summarizing content.");
579
+ } finally {
580
+ setIsSummarizing(false);
581
+ }
582
+ };
583
+
584
+ // Function to suggest actions based on decoded content using Gemini API (remains in App, passed to decoder)
585
+ const suggestActions = async () => {
586
+ if (!decodedContent.trim() || decodedContent === 'No QR code detected.') {
587
+ showAlert('Please decode a QR code first to suggest actions.');
588
+ return;
589
+ }
590
+
591
+ setIsSuggestingActions(true);
592
+ setSuggestedActions('Thinking...');
593
+ setShowSuggestedActions(true);
594
+ try {
595
+ let chatHistory = [];
596
+ const prompt = `Given the following text from a QR code, suggest relevant actions a user might take. Format the suggestions as a bulleted list. Text: "${decodedContent}"`;
597
+ chatHistory.push({ role: "user", parts: [{ text: prompt }] });
598
+ const payload = { contents: chatHistory };
599
+ const apiKey = ""; // Canvas will provide this at runtime
600
+ const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`;
601
+
602
+ const response = await fetch(apiUrl, {
603
+ method: 'POST',
604
+ headers: { 'Content-Type': 'application/json' },
605
+ body: JSON.stringify(payload)
606
+ });
607
+
608
+ const result = await response.json();
609
+
610
+ if (result.candidates && result.candidates.length > 0 &&
611
+ result.candidates[0].content && result.candidates[0].content.parts &&
612
+ result.candidates[0].content.parts.length > 0) {
613
+ const text = result.candidates[0].content.parts[0].text;
614
+ setSuggestedActions(text);
615
+ } else {
616
+ setSuggestedActions("Could not suggest actions. Please try again.");
617
+ }
618
+ } catch (error) {
619
+ console.error("Error suggesting actions:", error);
620
+ setSuggestedActions("An error occurred while suggesting actions.");
621
+ } finally {
622
+ setIsSuggestingActions(false);
623
+ }
624
+ };
625
+
626
  return (
627
  <div className={`min-h-screen font-inter antialiased ${currentThemeClasses.bg} ${currentThemeClasses.text} transition-all duration-500 ease-in-out`}>
628
  <div className="container mx-auto p-4 max-w-7xl">