qrcodedemo/src/components/TextAreaComponent.jsx
Michael Mainguy 874f3c4412 Add standalone bundle for qrCodeUtils with all dependencies
- Created vite.standalone.config.js for optimized bundle building
- Added build scripts for standalone bundle generation
- Generated three formats: IIFE (28KB), UMD (28KB), ES Module (61KB)
- Includes all dependencies: qrcode and imagetracer
- Added comprehensive documentation and examples
- Created build script with detailed bundle information
- Added terser for minification optimization
- Fixed package.json dependencies and scripts
2025-08-01 17:17:36 -05:00

270 lines
7.7 KiB
JavaScript

import React, { useState, useEffect, useRef } from 'react'
import {
generateQRCode,
generateSVGQRCode,
addImageToQRCode,
addImageToSVG,
generateCompleteSVGQRCode,
downloadSVG,
fileToDataURL,
validateImageFile
} from '../utils/qrCodeUtils'
const TextAreaComponent = () => {
const [text, setText] = useState('')
const [qrCodeUrl, setQrCodeUrl] = useState('')
const [customImage, setCustomImage] = useState(null)
const [customImageUrl, setCustomImageUrl] = useState('')
const [imageSize, setImageSize] = useState(25) // Size as percentage of QR code
const [foregroundColor, setForegroundColor] = useState('#0000ff') // QR code foreground color
const [backgroundColor, setBackgroundColor] = useState('#FFFFFF') // QR code background color
const canvasRef = useRef(null)
// Generate QR code when text, custom image, image size, or colors change
useEffect(() => {
if (text.trim()) {
generateQRCodeLocal(text)
} else {
setQrCodeUrl('')
}
}, [text, customImage, imageSize, foregroundColor, backgroundColor])
const generateQRCodeLocal = async (inputText) => {
try {
// Generate QR code as data URL using utility function
const url = await generateQRCode(inputText, foregroundColor, backgroundColor)
if (customImage) {
// Create QR code with custom image overlay
const qrWithImage = await addImageToQRCode(url, customImageUrl, imageSize)
setQrCodeUrl(qrWithImage)
} else {
setQrCodeUrl(url)
}
} catch (error) {
console.error('Error generating QR code:', error)
setQrCodeUrl('')
}
}
const generateSVGQRCodeLocal = async (inputText) => {
try {
console.log('Base SVG generated, length:', inputText.length)
if (customImage) {
console.log('Custom image detected, adding to SVG...')
// Add custom image to SVG using utility function
const svgWithImage = await addImageToSVG(inputText, customImageUrl, imageSize)
console.log('SVG with image generated, length:', svgWithImage.length)
return svgWithImage
} else {
console.log('No custom image, returning base SVG')
return inputText
}
} catch (error) {
console.error('Error generating SVG QR code:', error)
return null
}
}
const exportAsSVG = async () => {
if (!text.trim()) {
alert('Please enter some text to generate a QR code')
return
}
// Generate base SVG QR code using utility function
const baseSvg = await generateSVGQRCode(text, foregroundColor, backgroundColor)
if (!baseSvg) {
alert('Error generating QR code')
return
}
// Add custom image if present
const svgContent = await generateSVGQRCodeLocal(baseSvg)
if (svgContent) {
// Debug: Log the SVG content to see what's being generated
console.log('Generated SVG content:', svgContent)
// Use utility function to download SVG
downloadSVG(svgContent, 'qrcode.svg')
}
}
const handleImageUpload = async (event) => {
const file = event.target.files[0]
if (file) {
// Validate file using utility function
const validation = validateImageFile(file)
if (!validation.success) {
alert(validation.error)
return
}
try {
// Convert file to data URL using utility function
const dataUrl = await fileToDataURL(file)
setCustomImage(file)
setCustomImageUrl(dataUrl)
} catch (error) {
console.error('Error processing image file:', error)
alert('Error processing image file')
}
}
}
const removeCustomImage = () => {
setCustomImage(null)
setCustomImageUrl('')
}
const handleTextChange = (e) => {
setText(e.target.value)
}
const handleClear = () => {
setText('')
}
return (
<div className="textarea-container">
<label htmlFor="text-input" className="textarea-label">
Enter text to generate QR code:
</label>
<textarea
id="text-input"
value={text}
onChange={handleTextChange}
placeholder="Enter your text here..."
className="textarea-input"
rows={6}
cols={50}
/>
<div className="color-controls">
<div className="color-input-group">
<label htmlFor="foreground-color" className="color-label">
QR Code Color:
</label>
<input
id="foreground-color"
type="color"
value={foregroundColor}
onChange={(e) => setForegroundColor(e.target.value)}
className="color-input"
/>
<span className="color-value">{foregroundColor}</span>
</div>
<div className="color-input-group">
<label htmlFor="background-color" className="color-label">
Background Color:
</label>
<input
id="background-color"
type="color"
value={backgroundColor}
onChange={(e) => setBackgroundColor(e.target.value)}
className="color-input"
/>
<span className="color-value">{backgroundColor}</span>
</div>
</div>
<div className="image-upload-section">
<label htmlFor="image-upload" className="image-upload-label">
Add custom image or SVG to QR code center:
</label>
<div className="image-upload-controls">
<input
id="image-upload"
type="file"
accept="image/*,.svg"
onChange={handleImageUpload}
className="image-upload-input"
/>
{customImage && (
<button
onClick={removeCustomImage}
className="remove-image-button"
>
Remove Image
</button>
)}
</div>
{customImage && (
<div className="image-preview">
<img
src={customImageUrl}
alt="Custom image preview"
className="preview-image"
/>
<span className="image-name">{customImage.name}</span>
</div>
)}
{customImage && (
<div className="image-size-control">
<label htmlFor="image-size" className="size-label">
Image Size: {imageSize}%
</label>
<input
id="image-size"
type="range"
min="10"
max="40"
value={imageSize}
onChange={(e) => setImageSize(parseInt(e.target.value))}
className="size-slider"
/>
<div className="size-labels">
<span>Small</span>
<span>Large</span>
</div>
</div>
)}
</div>
<div className="textarea-actions">
<button
onClick={handleClear}
className="clear-button"
disabled={!text}
>
Clear
</button>
<span className="character-count">
Characters: {text.length}
</span>
</div>
{qrCodeUrl && (
<div className="qr-code-container">
<h3>QR Code {customImage && '(with custom image)'}</h3>
<img
src={qrCodeUrl}
alt="QR Code"
className="qr-code-image"
/>
<div className="qr-code-actions">
<button
onClick={exportAsSVG}
className="export-svg-button"
>
Export as SVG
</button>
</div>
<p className="qr-code-info">
Scan this QR code with any QR code reader app
</p>
</div>
)}
</div>
)
}
export default TextAreaComponent