258 lines
14 KiB
HTML
258 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Plausible Link & QR Code Generator</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/qr-code-styling@1.5.0/lib/qr-code-styling.js"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
font-family: 'Inter', sans-serif;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-slate-100 flex items-center justify-center min-h-screen p-4">
|
|
|
|
<div class="bg-white p-8 rounded-2xl shadow-lg max-w-2xl w-full">
|
|
<!-- Header -->
|
|
<div class="text-center mb-8">
|
|
<h1 class="text-3xl font-bold text-slate-800">Marketing Link & QR Code Generator</h1>
|
|
<p class="text-slate-500 mt-2">Create special links for your business cards and flyers to see how many visitors they bring to our website!</p>
|
|
</div>
|
|
|
|
<!-- Form -->
|
|
<form id="link-form" class="space-y-6">
|
|
<div>
|
|
<label for="base-url" class="block text-sm font-medium text-slate-700 mb-1">Our Website URL</label>
|
|
<input type="text" id="base-url" value="https://beachpartyballoons.com" class="block w-full px-3 py-2 bg-slate-50 border border-slate-300 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500" readonly>
|
|
<p class="text-xs text-slate-400 mt-1">This is locked to our main website.</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="campaign" class="block text-sm font-medium text-slate-700 mb-1">What is this link for?</label>
|
|
<input type="text" id="campaign" placeholder="e.g., Business Card, Holiday Flyer, Craft Fair Poster" required class="block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
<p class="text-xs text-slate-400 mt-1">This helps us group our marketing efforts.</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="source" class="block text-sm font-medium text-slate-700 mb-1">Where will you put this link/QR code?</label>
|
|
<input type="text" id="source" placeholder="e.g., Milford Office Flyer, Wedding Expo Handout" required class="block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
<p class="text-xs text-slate-400 mt-1">Be specific so we know exactly what worked!</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="employee-name" class="block text-sm font-medium text-slate-700 mb-1">Your Name (Optional, for Business Cards)</label>
|
|
<input type="text" id="employee-name" placeholder="e.g., Jane Doe" class="block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
<p class="text-xs text-slate-400 mt-1">This lets us see who's driving the most traffic!</p>
|
|
</div>
|
|
|
|
<!-- New Customization Section -->
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700 mb-2">QR Code Style (Optional)</label>
|
|
<div class="p-4 border rounded-lg bg-slate-50 space-y-4">
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="dots-style" class="block text-xs font-medium text-slate-600 mb-1">Dot Style</label>
|
|
<select id="dots-style" class="block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm">
|
|
<option value="square">Square</option>
|
|
<option value="dots">Dots</option>
|
|
<option value="rounded">Rounded</option>
|
|
<option value="extra-rounded">Extra Rounded</option>
|
|
<option value="classy">Classy</option>
|
|
<option value="classy-rounded">Classy Rounded</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="color-dots" class="block text-xs font-medium text-slate-600 mb-1">Dot Color</label>
|
|
<input type="color" id="color-dots" value="#00A99D" class="w-full h-10 p-1 bg-white border border-slate-300 rounded-md cursor-pointer">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 pt-4 border-t">
|
|
<div>
|
|
<label for="corner-square-style" class="block text-xs font-medium text-slate-600 mb-1">Corner Square Style</label>
|
|
<select id="corner-square-style" class="block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm">
|
|
<option value="square">Square</option>
|
|
<option value="dot">Dot</option>
|
|
<option value="extra-rounded">Extra Rounded</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="color-corner-square" class="block text-xs font-medium text-slate-600 mb-1">Corner Square Color</label>
|
|
<input type="color" id="color-corner-square" value="#009FDD" class="w-full h-10 p-1 bg-white border border-slate-300 rounded-md cursor-pointer">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="corner-dot-style" class="block text-xs font-medium text-slate-600 mb-1">Inner Corner Style</label>
|
|
<select id="corner-dot-style" class="block w-full px-3 py-2 bg-white border border-slate-300 rounded-md shadow-sm">
|
|
<option value="square">Square</option>
|
|
<option value="dot">Dot</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label for="color-corner-dot" class="block text-xs font-medium text-slate-600 mb-1">Inner Corner Color</label>
|
|
<input type="color" id="color-corner-dot" value="#98C73D" class="w-full h-10 p-1 bg-white border border-slate-300 rounded-md cursor-pointer">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pt-4 border-t">
|
|
<label for="color-light" class="block text-xs font-medium text-slate-600 mb-1">Background Color</label>
|
|
<input type="color" id="color-light" value="#ffffff" class="w-full h-10 p-1 bg-white border border-slate-300 rounded-md cursor-pointer">
|
|
</div>
|
|
</div>
|
|
<p class="text-xs text-slate-400 mt-2"><strong>Tip:</strong> Keep a high contrast between the code and background for best scanning results.</p>
|
|
</div>
|
|
|
|
|
|
<button type="submit" class="w-full bg-blue-600 text-white font-bold py-3 px-4 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition-colors duration-300">
|
|
Generate Link & QR Code
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Output Section -->
|
|
<div id="output-section" class="mt-8 pt-6 border-t border-slate-200 hidden">
|
|
<h2 class="text-2xl font-bold text-slate-800 text-center mb-6">Your Marketing Assets are Ready!</h2>
|
|
|
|
<div class="grid md:grid-cols-2 gap-8 items-center">
|
|
<!-- Left Side: Link Info -->
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3 class="font-semibold text-slate-700 mb-2">1. Your Trackable Link</h3>
|
|
<div class="flex items-center space-x-2">
|
|
<input id="generated-link" type="text" class="w-full px-3 py-2 bg-slate-100 border border-slate-300 rounded-md text-sm" readonly>
|
|
<button id="copy-button" class="bg-slate-200 hover:bg-slate-300 text-slate-700 font-medium py-2 px-4 rounded-md transition-colors">Copy</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-semibold text-slate-700 mb-2">2. Download Your QR Code</h3>
|
|
<p class="text-sm text-slate-500 mb-3">Add this image to your flyer or business card. When someone scans it, we can track their visit.</p>
|
|
<button id="download-button" class="w-full text-center bg-green-600 text-white font-bold py-2 px-4 rounded-lg hover:bg-green-700 transition-colors">Download QR Code (.png)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Side: QR Code Image -->
|
|
<div class="flex justify-center items-center p-4 bg-slate-50 rounded-lg border">
|
|
<div id="qrcode-container"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Footer -->
|
|
<div class="text-center mt-8">
|
|
<p class="text-sm text-slate-500"><strong>Why do we do this?</strong> These special links help us understand which of our marketing ideas are the most effective at bringing new customers to our website. Thanks for helping out!</p>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const form = document.getElementById('link-form');
|
|
const outputSection = document.getElementById('output-section');
|
|
const generatedLinkInput = document.getElementById('generated-link');
|
|
const qrcodeContainer = document.getElementById('qrcode-container');
|
|
const copyButton = document.getElementById('copy-button');
|
|
const downloadButton = document.getElementById('download-button');
|
|
let qrCodeInstance = null;
|
|
|
|
// Helper function to format text for URLs (e.g., "Business Card" -> "business_card")
|
|
const slugify = (text) => text.toString().toLowerCase().trim()
|
|
.replace(/\s+/g, '_') // Replace spaces with _
|
|
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
|
|
.replace(/\-\-+/g, '_'); // Replace multiple - with single _
|
|
|
|
form.addEventListener('submit', (e) => {
|
|
e.preventDefault();
|
|
|
|
const baseURL = document.getElementById('base-url').value;
|
|
const campaign = document.getElementById('campaign').value;
|
|
const source = document.getElementById('source').value;
|
|
const employeeName = document.getElementById('employee-name').value;
|
|
|
|
// Get new style values
|
|
const dotsStyle = document.getElementById('dots-style').value;
|
|
const cornerSquareStyle = document.getElementById('corner-square-style').value;
|
|
const cornerDotStyle = document.getElementById('corner-dot-style').value;
|
|
const colorDots = document.getElementById('color-dots').value;
|
|
const colorCornerSquare = document.getElementById('color-corner-square').value;
|
|
const colorCornerDot = document.getElementById('color-corner-dot').value;
|
|
const colorLight = document.getElementById('color-light').value;
|
|
|
|
|
|
// Build the URL with UTM parameters
|
|
const url = new URL(baseURL);
|
|
url.searchParams.set('utm_campaign', slugify(campaign));
|
|
url.searchParams.set('utm_source', slugify(source));
|
|
url.searchParams.set('utm_medium', 'print'); // Hardcoded as this tool is for physical media
|
|
|
|
if (employeeName) {
|
|
url.searchParams.set('utm_content', slugify(employeeName));
|
|
}
|
|
|
|
const finalURL = url.toString();
|
|
generatedLinkInput.value = finalURL;
|
|
|
|
const qrOptions = {
|
|
width: 200,
|
|
height: 200,
|
|
type: 'svg',
|
|
data: finalURL,
|
|
dotsOptions: {
|
|
color: colorDots,
|
|
type: dotsStyle
|
|
},
|
|
backgroundOptions: {
|
|
color: colorLight,
|
|
},
|
|
cornersSquareOptions: {
|
|
color: colorCornerSquare,
|
|
type: cornerSquareStyle
|
|
},
|
|
cornersDotOptions: {
|
|
color: colorCornerDot,
|
|
type: cornerDotStyle
|
|
}
|
|
};
|
|
|
|
if (qrCodeInstance) {
|
|
qrCodeInstance.update(qrOptions);
|
|
} else {
|
|
qrCodeInstance = new QRCodeStyling(qrOptions);
|
|
qrcodeContainer.innerHTML = '';
|
|
qrCodeInstance.append(qrcodeContainer);
|
|
}
|
|
|
|
outputSection.classList.remove('hidden');
|
|
});
|
|
|
|
downloadButton.addEventListener('click', () => {
|
|
if (!qrCodeInstance) return;
|
|
const campaign = document.getElementById('campaign').value;
|
|
const source = document.getElementById('source').value;
|
|
const downloadFileName = `qr_${slugify(campaign)}_${slugify(source)}`;
|
|
qrCodeInstance.download({ name: downloadFileName, extension: "png" });
|
|
});
|
|
|
|
copyButton.addEventListener('click', () => {
|
|
generatedLinkInput.select();
|
|
try {
|
|
// Use the newer clipboard API if available
|
|
navigator.clipboard.writeText(generatedLinkInput.value);
|
|
copyButton.textContent = 'Copied!';
|
|
setTimeout(() => { copyButton.textContent = 'Copy'; }, 2000);
|
|
} catch (err) {
|
|
// Fallback for older browsers
|
|
document.execCommand('copy');
|
|
copyButton.textContent = 'Copied!';
|
|
setTimeout(() => { copyButton.textContent = 'Copy'; }, 2000);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|
|
|
|
|
|
|