Znfeoqm commited on
Commit
2d454cc
·
verified ·
1 Parent(s): c1dd5df

Update src/App.jsx

Browse files
Files changed (1) hide show
  1. src/App.jsx +103 -214
src/App.jsx CHANGED
@@ -27,21 +27,21 @@ const QRGeneratorTab = ({
27
  isSuggestingIdeas, suggestIdeas, downloadQrCode, qrCanvasRef,
28
  isInputFocused, setIsInputFocused, currentThemeClasses,
29
  qrStyles, selectedStyleIndex, setSelectedStyleIndex, styleCanvasRefs, drawQrCode,
30
- suggestedIdeaList, showSuggestedIdeas, setShowSuggestedIdeas,
31
- downloadFormat, setDownloadFormat, qrResolution, setQrResolution
32
  }) => {
33
  // Effect to generate QR code on the main canvas (Generator Tab)
34
  useEffect(() => {
35
- // Use a higher resolution for the preview canvas for better quality
36
- drawQrCode(qrCanvasRef.current, content, qrColor, errorLevel, 512, '#000000');
37
  }, [content, qrColor, errorLevel, drawQrCode, qrCanvasRef]);
38
 
39
  // Effect to generate QR codes for style previews (Style Selection Panel)
40
  useEffect(() => {
41
  qrStyles.forEach((style, index) => {
42
  const canvas = styleCanvasRefs.current[index];
43
- // Use black background for style previews as well
44
- drawQrCode(canvas, "Sample", style.fg, 'H', 80, '#000000');
45
  });
46
  }, [qrStyles, drawQrCode, styleCanvasRefs]);
47
 
@@ -78,7 +78,7 @@ const QRGeneratorTab = ({
78
  ) : (
79
  <i className="fas fa-lightbulb mr-2"></i>
80
  )}
81
- 💡 {isSuggestingIdeas ? 'Loading Ideas...' : 'Suggest Ideas'}
82
  </button>
83
  <button
84
  className={`w-full sm:w-1/2 py-3 px-6 rounded-xl font-bold text-lg bg-gradient-to-r ${currentThemeClasses.secondaryAccent} text-white shadow-lg ${currentThemeClasses.buttonGlow} transform hover:-translate-y-1 transition-all duration-300 ease-in-out flex items-center justify-center`}
@@ -88,35 +88,19 @@ const QRGeneratorTab = ({
88
  </button>
89
  </div>
90
 
91
- {/* Display suggested ideas as clickable buttons */}
92
- {suggestedIdeaList.length > 0 && (
93
  <div className={`mt-4 p-4 rounded-xl border ${currentThemeClasses.glassBorder} ${currentThemeClasses.glassBg} shadow-inner transition-all duration-300 overflow-hidden`}>
94
  <div className="flex justify-between items-center cursor-pointer" onClick={() => setShowSuggestedIdeas(!showSuggestedIdeas)}>
95
- <label className={`font-semibold ${currentThemeClasses.labelColor} font-inter`}>Suggested QR Ideas:</label>
96
  <i className={`fas ${showSuggestedIdeas ? 'fa-chevron-up' : 'fa-chevron-down'} transition-transform duration-300`}></i>
97
  </div>
98
  <div className={`overflow-hidden transition-all duration-500 ease-in-out ${showSuggestedIdeas ? 'max-h-96 opacity-100 mt-2' : 'max-h-0 opacity-0'}`}>
99
- <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2 mt-2">
100
- {suggestedIdeaList.map((idea, index) => (
101
- <button
102
- key={index}
103
- className={`flex items-center p-2 rounded-lg text-sm transition-all duration-200 ease-in-out
104
- ${currentThemeClasses.inputBg} ${currentThemeClasses.text} hover:bg-blue-500/20 hover:scale-[1.02]`}
105
- onClick={() => {
106
- setContent(idea.text);
107
- setShowSuggestedIdeas(false); // Hide suggestions after selection
108
- }}
109
- >
110
- <span className="mr-2">{idea.emoji}</span>
111
- {idea.text}
112
- </button>
113
- ))}
114
- </div>
115
  </div>
116
  </div>
117
  )}
118
 
119
-
120
  <label className={`mt-4 mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>Error Correction Level:</label>
121
  <select
122
  className={`w-full p-3 rounded-xl border ${currentThemeClasses.inputBorder} ${currentThemeClasses.inputBg} ${currentThemeClasses.text} focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none transition-all duration-300 font-inter`}
@@ -137,41 +121,24 @@ const QRGeneratorTab = ({
137
  onChange={(e) => setQrColor(e.target.value)}
138
  />
139
 
140
- {/* New: Download Format and Resolution Selection */}
141
- <div className="flex flex-col sm:flex-row space-y-4 sm:space-y-0 sm:space-x-4 mt-4">
142
- <div className="w-full sm:w-1/2">
143
- <label className={`mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter block`}>Download Format:</label>
144
- <select
145
- className={`w-full p-3 rounded-xl border ${currentThemeClasses.inputBorder} ${currentThemeClasses.inputBg} ${currentThemeClasses.text} focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none transition-all duration-300 font-inter`}
146
- value={downloadFormat}
147
- onChange={(e) => setDownloadFormat(e.target.value)}
148
- >
149
- <option value="png">PNG (High Resolution)</option>
150
- <option value="svg">SVG (Vector)</option>
151
- </select>
152
- </div>
153
- {downloadFormat === 'png' && (
154
- <div className="w-full sm:w-1/2">
155
- <label className={`mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter block`}>PNG Resolution:</label>
156
- <select
157
- className={`w-full p-3 rounded-xl border ${currentThemeClasses.inputBorder} ${currentThemeClasses.inputBg} ${currentThemeClasses.text} focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none transition-all duration-300 font-inter`}
158
- value={qrResolution}
159
- onChange={(e) => setQrResolution(parseInt(e.target.value))}
160
- >
161
- <option value={1024}>1024x1024</option>
162
- <option value={2048}>2048x2048</option>
163
- <option value={4096}>4096x4096</option>
164
- </select>
165
- </div>
166
- )}
167
- </div>
168
-
169
 
170
  <label className={`mt-6 mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>QR Preview:</label>
171
  <div
172
  className={`relative flex justify-center items-center w-full min-h-[300px] rounded-2xl border-2 ${currentThemeClasses.qrPreviewBorder} ${currentThemeClasses.qrPreviewBg} p-4 shadow-inner overflow-hidden transform transition-all duration-300 hover:scale-[1.01] hover:-translate-y-1 ${currentThemeClasses.glow}`}
173
  >
174
- <canvas ref={qrCanvasRef} width="512" height="512" className={`rounded-lg shadow-xl ${content ? '' : 'hidden'}`}></canvas>
175
  {!content && (
176
  <p className={`${currentThemeClasses.labelColor} text-lg font-inter absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2`}>Enter content to see QR preview</p>
177
  )}
@@ -209,7 +176,7 @@ const QRGeneratorTab = ({
209
  // --- QRDecoderTab Component ---
210
  const QRDecoderTab = ({
211
  decodedContent, setDecodedContent,
212
- isSummarizing, summarizeXml, showAlert, decodeQrCode,
213
  currentThemeClasses
214
  }) => {
215
  return (
@@ -245,7 +212,7 @@ const QRDecoderTab = ({
245
 
246
  <button
247
  className={`mt-4 w-full py-3 px-6 rounded-xl font-bold text-lg bg-gradient-to-r ${currentThemeClasses.secondaryAccent} text-white shadow-lg ${currentThemeClasses.buttonGlow} transform hover:-translate-y-1 transition-all duration-300 ease-in-out flex items-center justify-center`}
248
- onClick={summarizeXml}
249
  disabled={isSummarizing || !decodedContent.trim() || decodedContent === 'No QR code detected.'}
250
  >
251
  {isSummarizing ? (
@@ -253,7 +220,7 @@ const QRDecoderTab = ({
253
  ) : (
254
  <i className="fas fa-file-alt mr-2"></i>
255
  )}
256
- 📝 {isSummarizing ? 'Summarizing XML...' : 'Summarize XML'}
257
  </button>
258
  </div>
259
  </div>
@@ -295,55 +262,38 @@ const App = () => {
295
  const [activeTab, setActiveTab] = useState('generator');
296
  const [content, setContent] = useState('');
297
  const [errorLevel, setErrorLevel] = useState('L');
298
- const [qrColor, setQrColor] = useState('#00FFCC'); // Default to a vibrant neon cyan
299
  const [decodedContent, setDecodedContent] = useState('');
300
  const [selectedStyleIndex, setSelectedStyleIndex] = useState(0);
301
- const [currentTheme, setCurrentTheme] = useState('dark'); // Initial state, will be updated by useEffect
302
  const [isSummarizing, setIsSummarizing] = useState(false);
303
- const [allAvailableIdeas, setAllAvailableIdeas] = useState([]); // Stores all ideas from the text file
304
- const [suggestedIdeaList, setSuggestedIdeaList] = useState([]); // Stores the randomly selected subset
305
  const [isSuggestingIdeas, setIsSuggestingIdeas] = useState(false);
306
  const [showSuggestedIdeas, setShowSuggestedIdeas] = useState(false);
307
  const [alertMessage, setAlertMessage] = useState(null);
308
  const [isInputFocused, setIsInputFocused] = useState(false);
309
- const [downloadFormat, setDownloadFormat] = useState('png'); // Default download format
310
- const [qrResolution, setQrResolution] = useState(2048); // Default high resolution for PNG
311
 
312
  const qrCanvasRef = useRef(null);
313
- // styleCanvasRefs is for the QR style previews, not dependent on the number of suggested ideas
314
- const styleCanvasRefs = useRef(Array(12).fill(null));
315
-
316
- // Detect user's preferred color scheme and set initial theme
317
- useEffect(() => {
318
- const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
319
- setCurrentTheme(prefersDarkMode ? 'dark' : 'light');
320
-
321
- // Listen for changes in the user's preferred color scheme
322
- const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
323
- const handleChange = (e) => {
324
- setCurrentTheme(e.matches ? 'dark' : 'light');
325
- };
326
- mediaQuery.addEventListener('change', handleChange);
327
- return () => mediaQuery.removeEventListener('change', handleChange);
328
- }, []);
329
 
330
- // Define QR code styles (updated with more neon colors)
331
  const qrStyles = [
332
- { name: "Neon Cyan", fg: "#00FFCC" },
333
- { name: "Neon Green", fg: "#00FF00" },
334
- { name: "Neon Magenta", fg: "#FF00FF" },
335
- { name: "Electric Blue", fg: "#00BFFF" },
336
- { name: "Laser Red", fg: "#FF3333" },
337
- { name: "Vivid Yellow", fg: "#FFFF00" },
338
- { name: "Deep Purple", fg: "#8A2BE2" },
339
- { name: "Aqua", fg: "#00FFFF" },
340
- { name: "Lime", fg: "#32CD32" },
341
- { name: "Fuchsia", fg: "#FF00FF" },
342
- { name: "Orange Glow", fg: "#FFA500" },
343
- { name: "White Glow", fg: "#FFFFFF" }, // A white glow on black background
344
  ];
345
 
346
- // Define themes
347
  const themes = {
348
  dark: {
349
  bg: 'bg-gradient-to-br from-[#0A0A0A] via-[#1A0A2A] to-[#0A0A0A] animate-gradient-shift',
@@ -509,7 +459,7 @@ const App = () => {
509
  };
510
 
511
  // Callback to generate QR code on a given canvas
512
- const drawQrCode = useCallback((canvas, text, color, errorLevel, size = 256, bg = '#FFFFFF') => {
513
  if (!canvas) {
514
  console.warn("Canvas element is null, cannot draw QR code.");
515
  return;
@@ -532,8 +482,8 @@ const App = () => {
532
  errorCorrectionLevel: errorLevel,
533
  width: size,
534
  color: {
535
- dark: color, // QR code dots color
536
- light: bg // QR code background color
537
  }
538
  }, function (error) {
539
  if (error) console.error("QR Code drawing error:", error);
@@ -541,69 +491,31 @@ const App = () => {
541
  }
542
  }, []);
543
 
544
- // Function to download the generated QR code (now supports PNG and SVG)
545
- const downloadQrCode = async () => {
546
  if (content.trim() === '') {
547
  showAlert('Please enter content to generate QR code.');
548
  return;
549
  }
550
 
551
- if (downloadFormat === 'png') {
552
- const canvas = document.createElement('canvas'); // Create an off-screen canvas for high-res
553
- await new Promise(resolve => {
554
- QRCode.toCanvas(canvas, content, {
555
- errorCorrectionLevel: errorLevel,
556
- width: qrResolution, // Use selected resolution
557
- color: {
558
- dark: qrColor,
559
- light: '#000000' // Black background for downloaded PNG
560
- }
561
- }, function (error) {
562
- if (error) {
563
- console.error("QR Code PNG drawing error:", error);
564
- showAlert("Failed to generate high-resolution PNG. Try again.");
565
- }
566
- resolve();
567
- });
568
- });
569
 
570
- const pngUrl = canvas.toDataURL("image/png");
571
- const downloadLink = document.createElement('a');
572
- downloadLink.href = pngUrl;
573
- downloadLink.download = `qrcode_${qrResolution}px.png`;
574
- document.body.appendChild(downloadLink);
575
- downloadLink.click();
576
- document.body.removeChild(downloadLink);
577
- showAlert(`QR Code downloaded as PNG (${qrResolution}x${qrResolution}px)!`);
578
-
579
- } else if (downloadFormat === 'svg') {
580
- try {
581
- const svgString = await QRCode.toString(content, {
582
- errorCorrectionLevel: errorLevel,
583
- type: 'svg',
584
- width: qrResolution, // Reusing qrResolution for SVG viewBox consistency
585
- color: {
586
- dark: qrColor,
587
- light: '#000000' // Black background for SVG
588
- }
589
- });
590
-
591
- const blob = new Blob([svgString], { type: 'image/svg+xml' });
592
- const url = URL.createObjectURL(blob);
593
- const downloadLink = document.createElement('a');
594
- downloadLink.href = url;
595
- downloadLink.download = `qrcode.svg`;
596
- document.body.appendChild(downloadLink);
597
- downloadLink.click();
598
- document.body.removeChild(downloadLink);
599
- URL.revokeObjectURL(url); // Clean up the URL object
600
- showAlert('QR Code downloaded as SVG!');
601
-
602
- } catch (error) {
603
- console.error("QR Code SVG generation error:", error);
604
- showAlert("Failed to generate SVG. Please try again.");
605
- }
606
- }
607
  };
608
 
609
  // Function to decode QR code from an uploaded image
@@ -626,8 +538,8 @@ const App = () => {
626
  if (jsQR) {
627
  let code = jsQR(imageData.data, imageData.width, imageData.height);
628
 
629
- // Attempt inversion if initial scan fails
630
  if (!code) {
 
631
  for (let i = 0; i < imageData.data.length; i += 4) {
632
  imageData.data[i] = 255 - imageData.data[i];
633
  imageData.data[i + 1] = 255 - imageData.data[i + 1];
@@ -638,16 +550,16 @@ const App = () => {
638
 
639
  if (code) {
640
  setDecodedContent(code.data);
641
- setSuggestedIdeaList([]); // Clear previous suggestions when new QR is decoded
642
  setShowSuggestedIdeas(false);
643
  } else {
644
  setDecodedContent('No QR code detected.');
645
- setSuggestedIdeaList([]);
646
  setShowSuggestedIdeas(false);
647
  }
648
  } else {
649
  showAlert('QR decoder library (jsQR) not loaded. Please try again or check internet connection.');
650
- setSuggestedIdeaList([]);
651
  setShowSuggestedIdeas(false);
652
  }
653
  };
@@ -656,8 +568,8 @@ const App = () => {
656
  reader.readAsDataURL(file);
657
  };
658
 
659
- // Function to summarize XML content using Gemini API
660
- const summarizeXml = async () => {
661
  if (!decodedContent.trim() || decodedContent === 'No QR code detected.') {
662
  showAlert('Please decode a QR code first to summarize its content.');
663
  return;
@@ -666,94 +578,72 @@ const App = () => {
666
  setIsSummarizing(true);
667
  try {
668
  let chatHistory = [];
669
- // Updated prompt to specifically convert XML to plain text
670
- const prompt = `Convert the following XML content into concise, human-readable plain text. Extract key information and present it clearly. If the content is not XML, summarize it as plain text. XML/Text to process: "${decodedContent}"`;
671
  chatHistory.push({ role: "user", parts: [{ text: prompt }] });
672
  const payload = { contents: chatHistory };
673
  const apiKey = ""; // Canvas will provide this at runtime
674
  const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`;
675
 
676
- console.log("Attempting to summarize XML content...");
677
  const response = await fetch(apiUrl, {
678
  method: 'POST',
679
  headers: { 'Content-Type': 'application/json' },
680
  body: JSON.stringify(payload)
681
  });
682
 
683
- console.log("Summarize XML API Response Status:", response.status, response.statusText);
684
- if (!response.ok) {
685
- const errorData = await response.text();
686
- console.error("Summarize XML API Error Response:", errorData);
687
- showAlert(`Failed to summarize XML: ${response.statusText}. Please try again.`);
688
- return;
689
- }
690
-
691
  const result = await response.json();
692
- console.log("Summarize XML API Result:", result);
693
 
694
  if (result.candidates && result.candidates.length > 0 &&
695
  result.candidates[0].content && result.candidates[0].content.parts &&
696
  result.candidates[0].content.parts.length > 0) {
697
  const text = result.candidates[0].content.parts[0].text;
698
  setContent(text); // Update the generator's input field with summarized content
699
- showAlert('Content summarized (XML converted) and moved to QR Generator tab!');
700
  } else {
701
- console.error("Gemini API response structure unexpected for summarizeXml:", result);
702
- showAlert("Failed to summarize XML. Unexpected API response. Please try again.");
703
  }
704
  } catch (error) {
705
- console.error("Error summarizing XML content:", error);
706
- showAlert("An error occurred while summarizing XML content. Please check your network connection.");
707
  } finally {
708
  setIsSummarizing(false);
709
  }
710
  };
711
 
712
- // Function to fetch and set random suggested ideas from a text file
713
  const suggestIdeas = async () => {
714
  setIsSuggestingIdeas(true);
715
- setSuggestedIdeaList([]); // Clear previous ideas
716
- setShowSuggestedIdeas(true); // Show the ideas panel
717
 
718
  try {
719
- if (allAvailableIdeas.length === 0) {
720
- console.log("Fetching suggestedIdeas.txt...");
721
- const response = await fetch('/suggestedIdeas.txt'); // Path to the text file
722
- if (!response.ok) {
723
- throw new Error(`HTTP error! status: ${response.status}`);
724
- }
725
- const text = await response.text();
726
- const parsedIdeas = text.split('\n').filter(line => line.trim() !== '').map(line => {
727
- const firstSpaceIndex = line.indexOf(' ');
728
- if (firstSpaceIndex > -1) {
729
- return {
730
- emoji: line.substring(0, firstSpaceIndex).trim(),
731
- text: line.substring(firstSpaceIndex + 1).trim()
732
- };
733
- }
734
- return { emoji: '', text: line.trim() }; // Fallback if no space found
735
- });
736
- setAllAvailableIdeas(parsedIdeas);
737
- console.log("All ideas loaded:", parsedIdeas.length);
738
  }
 
739
 
740
- // Select a random subset of ideas
741
- const numIdeasToShow = 15; // You can adjust this number
742
- const shuffled = [...allAvailableIdeas].sort(() => 0.5 - Math.random());
743
- const selectedIdeas = shuffled.slice(0, numIdeasToShow);
744
- setSuggestedIdeaList(selectedIdeas);
745
- console.log("Random ideas selected:", selectedIdeas);
746
 
 
 
 
 
 
 
 
 
 
747
  } catch (error) {
748
  console.error("Error fetching or parsing suggested ideas:", error);
749
- showAlert("Could not load suggested ideas. Please check the 'suggestedIdeas.txt' file and try again.");
750
- setSuggestedIdeaList([]); // Clear ideas on error
751
  } finally {
752
  setIsSuggestingIdeas(false);
753
  }
754
  };
755
 
756
-
757
  return (
758
  <div className={`min-h-screen font-inter antialiased ${currentThemeClasses.bg} ${currentThemeClasses.text} transition-all duration-500 ease-in-out`}>
759
  <div className="container mx-auto p-4 max-w-7xl">
@@ -800,15 +690,14 @@ const App = () => {
800
  qrStyles={qrStyles} selectedStyleIndex={selectedStyleIndex}
801
  setSelectedStyleIndex={setSelectedStyleIndex} styleCanvasRefs={styleCanvasRefs}
802
  drawQrCode={drawQrCode}
803
- suggestedIdeaList={suggestedIdeaList} showSuggestedIdeas={showSuggestedIdeas} setShowSuggestedIdeas={setShowSuggestedIdeas}
804
- downloadFormat={downloadFormat} setDownloadFormat={setDownloadFormat}
805
- qrResolution={qrResolution} setQrResolution={setQrResolution}
806
  />
807
  )}
808
  {activeTab === 'decoder' && (
809
  <QRDecoderTab
810
  decodedContent={decodedContent} setDecodedContent={setDecodedContent}
811
- isSummarizing={isSummarizing} summarizeXml={summarizeXml}
812
  showAlert={showAlert} decodeQrCode={decodeQrCode}
813
  currentThemeClasses={currentThemeClasses}
814
  />
 
27
  isSuggestingIdeas, suggestIdeas, downloadQrCode, qrCanvasRef,
28
  isInputFocused, setIsInputFocused, currentThemeClasses,
29
  qrStyles, selectedStyleIndex, setSelectedStyleIndex, styleCanvasRefs, drawQrCode,
30
+ suggestedIdeas, showSuggestedIdeas, setShowSuggestedIdeas,
31
+ downloadResolution, setDownloadResolution // New prop for download resolution
32
  }) => {
33
  // Effect to generate QR code on the main canvas (Generator Tab)
34
  useEffect(() => {
35
+ // Preview canvas is always 256x256
36
+ drawQrCode(qrCanvasRef.current, content, qrColor, errorLevel, 256);
37
  }, [content, qrColor, errorLevel, drawQrCode, qrCanvasRef]);
38
 
39
  // Effect to generate QR codes for style previews (Style Selection Panel)
40
  useEffect(() => {
41
  qrStyles.forEach((style, index) => {
42
  const canvas = styleCanvasRefs.current[index];
43
+ // Use a generic sample for style previews, not actual content
44
+ drawQrCode(canvas, "Sample", style.fg, 'H', 80);
45
  });
46
  }, [qrStyles, drawQrCode, styleCanvasRefs]);
47
 
 
78
  ) : (
79
  <i className="fas fa-lightbulb mr-2"></i>
80
  )}
81
+ 💡 {isSuggestingIdeas ? 'Suggesting Idea...' : 'Suggest Idea'}
82
  </button>
83
  <button
84
  className={`w-full sm:w-1/2 py-3 px-6 rounded-xl font-bold text-lg bg-gradient-to-r ${currentThemeClasses.secondaryAccent} text-white shadow-lg ${currentThemeClasses.buttonGlow} transform hover:-translate-y-1 transition-all duration-300 ease-in-out flex items-center justify-center`}
 
88
  </button>
89
  </div>
90
 
91
+ {/* Suggested Ideas Panel */}
92
+ {showSuggestedIdeas && suggestedIdeas && (
93
  <div className={`mt-4 p-4 rounded-xl border ${currentThemeClasses.glassBorder} ${currentThemeClasses.glassBg} shadow-inner transition-all duration-300 overflow-hidden`}>
94
  <div className="flex justify-between items-center cursor-pointer" onClick={() => setShowSuggestedIdeas(!showSuggestedIdeas)}>
95
+ <label className={`font-semibold ${currentThemeClasses.labelColor} font-inter`}>Suggested QR Idea:</label>
96
  <i className={`fas ${showSuggestedIdeas ? 'fa-chevron-up' : 'fa-chevron-down'} transition-transform duration-300`}></i>
97
  </div>
98
  <div className={`overflow-hidden transition-all duration-500 ease-in-out ${showSuggestedIdeas ? 'max-h-96 opacity-100 mt-2' : 'max-h-0 opacity-0'}`}>
99
+ <p className={`${currentThemeClasses.text} whitespace-pre-wrap text-sm font-inter`}>{suggestedIdeas}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  </div>
101
  </div>
102
  )}
103
 
 
104
  <label className={`mt-4 mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>Error Correction Level:</label>
105
  <select
106
  className={`w-full p-3 rounded-xl border ${currentThemeClasses.inputBorder} ${currentThemeClasses.inputBg} ${currentThemeClasses.text} focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none transition-all duration-300 font-inter`}
 
121
  onChange={(e) => setQrColor(e.target.value)}
122
  />
123
 
124
+ {/* New: Download Resolution Selector */}
125
+ <label className={`mt-4 mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>Download Resolution:</label>
126
+ <select
127
+ className={`w-full p-3 rounded-xl border ${currentThemeClasses.inputBorder} ${currentThemeClasses.inputBg} ${currentThemeClasses.text} focus:outline-none focus:ring-2 focus:ring-blue-500 appearance-none transition-all duration-300 font-inter`}
128
+ value={downloadResolution}
129
+ onChange={(e) => setDownloadResolution(Number(e.target.value))}
130
+ >
131
+ <option value={256}>256x256 (Preview Size)</option>
132
+ <option value={512}>512x512 (Medium)</option>
133
+ <option value={1024}>1024x1024 (High)</option>
134
+ <option value={2048}>2048x2048 (Very High)</option>
135
+ </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  <label className={`mt-6 mb-2 font-semibold ${currentThemeClasses.labelColor} font-inter`}>QR Preview:</label>
138
  <div
139
  className={`relative flex justify-center items-center w-full min-h-[300px] rounded-2xl border-2 ${currentThemeClasses.qrPreviewBorder} ${currentThemeClasses.qrPreviewBg} p-4 shadow-inner overflow-hidden transform transition-all duration-300 hover:scale-[1.01] hover:-translate-y-1 ${currentThemeClasses.glow}`}
140
  >
141
+ <canvas ref={qrCanvasRef} width="256" height="256" className={`rounded-lg shadow-xl ${content ? '' : 'hidden'}`}></canvas>
142
  {!content && (
143
  <p className={`${currentThemeClasses.labelColor} text-lg font-inter absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2`}>Enter content to see QR preview</p>
144
  )}
 
176
  // --- QRDecoderTab Component ---
177
  const QRDecoderTab = ({
178
  decodedContent, setDecodedContent,
179
+ isSummarizing, summarizeContent, showAlert, decodeQrCode,
180
  currentThemeClasses
181
  }) => {
182
  return (
 
212
 
213
  <button
214
  className={`mt-4 w-full py-3 px-6 rounded-xl font-bold text-lg bg-gradient-to-r ${currentThemeClasses.secondaryAccent} text-white shadow-lg ${currentThemeClasses.buttonGlow} transform hover:-translate-y-1 transition-all duration-300 ease-in-out flex items-center justify-center`}
215
+ onClick={summarizeContent}
216
  disabled={isSummarizing || !decodedContent.trim() || decodedContent === 'No QR code detected.'}
217
  >
218
  {isSummarizing ? (
 
220
  ) : (
221
  <i className="fas fa-file-alt mr-2"></i>
222
  )}
223
+ 📝 {isSummarizing ? 'Summarizing Content...' : 'Summarize Content'}
224
  </button>
225
  </div>
226
  </div>
 
262
  const [activeTab, setActiveTab] = useState('generator');
263
  const [content, setContent] = useState('');
264
  const [errorLevel, setErrorLevel] = useState('L');
265
+ const [qrColor, setQrColor] = useState('#000000');
266
  const [decodedContent, setDecodedContent] = useState('');
267
  const [selectedStyleIndex, setSelectedStyleIndex] = useState(0);
268
+ const [currentTheme, setCurrentTheme] = useState('dark');
269
  const [isSummarizing, setIsSummarizing] = useState(false);
270
+ const [suggestedIdeas, setSuggestedIdeas] = useState('');
 
271
  const [isSuggestingIdeas, setIsSuggestingIdeas] = useState(false);
272
  const [showSuggestedIdeas, setShowSuggestedIdeas] = useState(false);
273
  const [alertMessage, setAlertMessage] = useState(null);
274
  const [isInputFocused, setIsInputFocused] = useState(false);
275
+ const [downloadResolution, setDownloadResolution] = useState(512); // New state for download resolution
 
276
 
277
  const qrCanvasRef = useRef(null);
278
+ const styleCanvasRefs = useRef(Array(12).fill(null));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
 
280
+ // Define QR code styles (remains in App as it's static data used by QRGeneratorTab)
281
  const qrStyles = [
282
+ { name: "Classic", fg: "#000000" },
283
+ { name: "Blue", fg: "#0033CC" },
284
+ { name: "Red", fg: "#CC3300" },
285
+ { name: "Green", fg: "#006600" },
286
+ { name: "Pink", fg: "#FF0099" },
287
+ { name: "Teal", fg: "#008080" },
288
+ { name: "Indigo", fg: "#4B0082" },
289
+ { name: "Orange", fg: "#FF6600" },
290
+ { name: "Gray", "fg": "#333333" },
291
+ { name: "Crimson", "fg": "#DC143C" },
292
+ { name: "Gold", "fg": "#FFD700" },
293
+ { name: "Turquoise", "fg": "#40E0D0" },
294
  ];
295
 
296
+ // Define themes (remains in App)
297
  const themes = {
298
  dark: {
299
  bg: 'bg-gradient-to-br from-[#0A0A0A] via-[#1A0A2A] to-[#0A0A0A] animate-gradient-shift',
 
459
  };
460
 
461
  // Callback to generate QR code on a given canvas
462
+ const drawQrCode = useCallback((canvas, text, color, errorLevel, size = 256) => {
463
  if (!canvas) {
464
  console.warn("Canvas element is null, cannot draw QR code.");
465
  return;
 
482
  errorCorrectionLevel: errorLevel,
483
  width: size,
484
  color: {
485
+ dark: color,
486
+ light: '#FFFFFF'
487
  }
488
  }, function (error) {
489
  if (error) console.error("QR Code drawing error:", error);
 
491
  }
492
  }, []);
493
 
494
+ // Function to download the generated QR code
495
+ const downloadQrCode = () => {
496
  if (content.trim() === '') {
497
  showAlert('Please enter content to generate QR code.');
498
  return;
499
  }
500
 
501
+ // Create a temporary canvas for high-resolution download
502
+ const tempCanvas = document.createElement('canvas');
503
+ tempCanvas.width = downloadResolution;
504
+ tempCanvas.height = downloadResolution;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505
 
506
+ // Draw the QR code onto the temporary canvas at the selected resolution
507
+ drawQrCode(tempCanvas, content, qrColor, errorLevel, downloadResolution);
508
+
509
+ // Get the data URL from the temporary canvas
510
+ const pngUrl = tempCanvas.toDataURL("image/png");
511
+ const downloadLink = document.createElement('a');
512
+ downloadLink.href = pngUrl;
513
+ downloadLink.download = `qrcode_${downloadResolution}x${downloadResolution}.png`;
514
+ document.body.appendChild(downloadLink);
515
+ downloadLink.click();
516
+ document.body.removeChild(downloadLink);
517
+
518
+ showAlert(`QR Code saved as ${downloadResolution}x${downloadResolution} PNG!`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
519
  };
520
 
521
  // Function to decode QR code from an uploaded image
 
538
  if (jsQR) {
539
  let code = jsQR(imageData.data, imageData.width, imageData.height);
540
 
 
541
  if (!code) {
542
+ // Attempt to invert colors and try again
543
  for (let i = 0; i < imageData.data.length; i += 4) {
544
  imageData.data[i] = 255 - imageData.data[i];
545
  imageData.data[i + 1] = 255 - imageData.data[i + 1];
 
550
 
551
  if (code) {
552
  setDecodedContent(code.data);
553
+ setSuggestedIdeas(''); // Clear previous suggestions when new QR is decoded
554
  setShowSuggestedIdeas(false);
555
  } else {
556
  setDecodedContent('No QR code detected.');
557
+ setSuggestedIdeas('');
558
  setShowSuggestedIdeas(false);
559
  }
560
  } else {
561
  showAlert('QR decoder library (jsQR) not loaded. Please try again or check internet connection.');
562
+ setSuggestedIdeas('');
563
  setShowSuggestedIdeas(false);
564
  }
565
  };
 
568
  reader.readAsDataURL(file);
569
  };
570
 
571
+ // Function to summarize content using Gemini API
572
+ const summarizeContent = async () => {
573
  if (!decodedContent.trim() || decodedContent === 'No QR code detected.') {
574
  showAlert('Please decode a QR code first to summarize its content.');
575
  return;
 
578
  setIsSummarizing(true);
579
  try {
580
  let chatHistory = [];
581
+ // Prompt to handle various content types for summarization
582
+ const prompt = `Summarize the following text concisely. If the text appears to be in XML, JSON, or another large structured format, extract the key information and present it as plain text. If it's a very long plain text, provide a brief summary. Text to summarize: "${decodedContent}"`;
583
  chatHistory.push({ role: "user", parts: [{ text: prompt }] });
584
  const payload = { contents: chatHistory };
585
  const apiKey = ""; // Canvas will provide this at runtime
586
  const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`;
587
 
 
588
  const response = await fetch(apiUrl, {
589
  method: 'POST',
590
  headers: { 'Content-Type': 'application/json' },
591
  body: JSON.stringify(payload)
592
  });
593
 
 
 
 
 
 
 
 
 
594
  const result = await response.json();
 
595
 
596
  if (result.candidates && result.candidates.length > 0 &&
597
  result.candidates[0].content && result.candidates[0].content.parts &&
598
  result.candidates[0].content.parts.length > 0) {
599
  const text = result.candidates[0].content.parts[0].text;
600
  setContent(text); // Update the generator's input field with summarized content
601
+ showAlert('Content summarized and moved to QR Generator tab!');
602
  } else {
603
+ showAlert("Failed to summarize content. Please try again.");
 
604
  }
605
  } catch (error) {
606
+ console.error("Error summarizing content:", error);
607
+ showAlert("An error occurred while summarizing content.");
608
  } finally {
609
  setIsSummarizing(false);
610
  }
611
  };
612
 
613
+ // Function to suggest ideas for QR code generation from suggestedIdeas.txt
614
  const suggestIdeas = async () => {
615
  setIsSuggestingIdeas(true);
616
+ setSuggestedIdeas('Fetching ideas...');
617
+ setShowSuggestedIdeas(true); // Always show the ideas panel when fetching
618
 
619
  try {
620
+ // Fetch content from the suggestedIdeas.txt file
621
+ const response = await fetch('suggestedIdeas.txt');
622
+ if (!response.ok) {
623
+ throw new Error(`HTTP error! status: ${response.status}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
  }
625
+ const text = await response.text();
626
 
627
+ // Split the text into individual ideas, assuming each idea is on a new line
628
+ const ideasArray = text.split('\n').map(line => line.trim()).filter(line => line.length > 0);
 
 
 
 
629
 
630
+ if (ideasArray.length > 0) {
631
+ // Select a random idea
632
+ const randomIndex = Math.floor(Math.random() * ideasArray.length);
633
+ const randomIdea = ideasArray[randomIndex];
634
+ setSuggestedIdeas(randomIdea); // Display the randomly selected idea
635
+ setContent(randomIdea); // Set the QR content to the suggested idea
636
+ } else {
637
+ setSuggestedIdeas("No ideas found in suggestedIdeas.txt.");
638
+ }
639
  } catch (error) {
640
  console.error("Error fetching or parsing suggested ideas:", error);
641
+ setSuggestedIdeas("An error occurred while fetching ideas.");
 
642
  } finally {
643
  setIsSuggestingIdeas(false);
644
  }
645
  };
646
 
 
647
  return (
648
  <div className={`min-h-screen font-inter antialiased ${currentThemeClasses.bg} ${currentThemeClasses.text} transition-all duration-500 ease-in-out`}>
649
  <div className="container mx-auto p-4 max-w-7xl">
 
690
  qrStyles={qrStyles} selectedStyleIndex={selectedStyleIndex}
691
  setSelectedStyleIndex={setSelectedStyleIndex} styleCanvasRefs={styleCanvasRefs}
692
  drawQrCode={drawQrCode}
693
+ suggestedIdeas={suggestedIdeas} showSuggestedIdeas={showSuggestedIdeas} setShowSuggestedIdeas={setShowSuggestedIdeas}
694
+ downloadResolution={downloadResolution} setDownloadResolution={setDownloadResolution} // Pass new prop
 
695
  />
696
  )}
697
  {activeTab === 'decoder' && (
698
  <QRDecoderTab
699
  decodedContent={decodedContent} setDecodedContent={setDecodedContent}
700
+ isSummarizing={isSummarizing} summarizeContent={summarizeContent}
701
  showAlert={showAlert} decodeQrCode={decodeQrCode}
702
  currentThemeClasses={currentThemeClasses}
703
  />