Last active
December 31, 2025 00:47
-
-
Save shauryashah94/55e12fb8de6348c08bd20425ea7e617e to your computer and use it in GitHub Desktop.
caulking-selector.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Caulking & Sealant Selector - The Caulking Store</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); | |
| * { | |
| font-family: 'Inter', sans-serif; | |
| } | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); | |
| } | |
| .primary-gradient { | |
| background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); | |
| } | |
| .secondary-gradient { | |
| background: linear-gradient(135deg, #10b981 0%, #047857 100%); | |
| } | |
| .card-hover { | |
| transition: all 0.3s ease; | |
| } | |
| .card-hover:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); | |
| } | |
| .option-selected { | |
| border-color: #3b82f6; | |
| background-color: #eff6ff; | |
| } | |
| .option-icon { | |
| width: 50px; | |
| height: 50px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| border-radius: 12px; | |
| font-size: 24px; | |
| } | |
| .progress-dot { | |
| width: 12px; | |
| height: 12px; | |
| border-radius: 50%; | |
| background-color: #cbd5e1; | |
| } | |
| .progress-dot.active { | |
| background-color: #3b82f6; | |
| } | |
| .progress-dot.completed { | |
| background-color: #10b981; | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.5s ease-in-out; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .tag { | |
| display: inline-block; | |
| padding: 4px 12px; | |
| border-radius: 20px; | |
| font-size: 12px; | |
| font-weight: 600; | |
| margin-right: 6px; | |
| margin-bottom: 6px; | |
| } | |
| .slide-in-right { | |
| animation: slideInRight 0.5s ease-out; | |
| } | |
| @keyframes slideInRight { | |
| from { transform: translateX(20px); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| .pulse { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); } | |
| 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); } | |
| } | |
| .scrollbar-custom { | |
| scrollbar-width: thin; | |
| scrollbar-color: #cbd5e1 transparent; | |
| } | |
| .scrollbar-custom::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .scrollbar-custom::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| .scrollbar-custom::-webkit-scrollbar-thumb { | |
| background-color: #cbd5e1; | |
| border-radius: 20px; | |
| } | |
| </style> | |
| </head> | |
| <body class="gradient-bg min-h-screen"> | |
| <!-- Header --> | |
| <header class="primary-gradient text-white shadow-lg"> | |
| <div class="container mx-auto px-4 py-6"> | |
| <div class="flex flex-col md:flex-row justify-between items-center"> | |
| <div class="flex items-center mb-4 md:mb-0"> | |
| <div class="bg-white p-2 rounded-lg mr-4"> | |
| <i class="fas fa-tools text-blue-600 text-2xl"></i> | |
| </div> | |
| <div> | |
| <h1 class="text-2xl md:text-3xl font-bold">Caulking & Sealant Finder</h1> | |
| <p class="text-blue-100">Find the perfect product for your project</p> | |
| </div> | |
| </div> | |
| <div class="text-center md:text-right"> | |
| <p class="text-lg font-semibold">Powered by</p> | |
| <p class="text-xl font-bold text-white">The Caulking Store</p> | |
| <a href="https://thecaulkingstore.com" target="_blank" class="text-blue-100 hover:text-white underline text-sm">thecaulkingstore.com</a> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main App Container --> | |
| <main class="container mx-auto px-4 py-8"> | |
| <!-- Progress Bar --> | |
| <div class="mb-10 max-w-4xl mx-auto"> | |
| <div class="flex justify-between mb-4"> | |
| <div class="text-center"> | |
| <div class="progress-dot completed mx-auto mb-2"></div> | |
| <span class="text-sm font-medium text-gray-700">Application</span> | |
| </div> | |
| <div class="flex-1 mt-1 mx-2"> | |
| <div class="h-1 bg-gray-200 rounded-full overflow-hidden"> | |
| <div id="progress-bar" class="h-full secondary-gradient transition-all duration-500" style="width: 25%"></div> | |
| </div> | |
| </div> | |
| <div class="text-center"> | |
| <div class="progress-dot active mx-auto mb-2"></div> | |
| <span class="text-sm font-medium text-gray-700">Location</span> | |
| </div> | |
| <div class="flex-1 mt-1 mx-2"> | |
| <div class="h-1 bg-gray-200 rounded-full"></div> | |
| </div> | |
| <div class="text-center"> | |
| <div class="progress-dot mx-auto mb-2"></div> | |
| <span class="text-sm font-medium text-gray-700">Material</span> | |
| </div> | |
| <div class="flex-1 mt-1 mx-2"> | |
| <div class="h-1 bg-gray-200 rounded-full"></div> | |
| </div> | |
| <div class="text-center"> | |
| <div class="progress-dot mx-auto mb-2"></div> | |
| <span class="text-sm font-medium text-gray-700">Results</span> | |
| </div> | |
| </div> | |
| <div class="text-center mt-2"> | |
| <span id="step-indicator" class="font-bold text-blue-600">Step 1 of 4: Choose Application Type</span> | |
| </div> | |
| </div> | |
| <!-- App Content --> | |
| <div id="app-content" class="max-w-6xl mx-auto"> | |
| <!-- Question Container --> | |
| <div id="question-container" class="fade-in"> | |
| <!-- Question will be loaded here by JavaScript --> | |
| </div> | |
| <!-- Results Container (Hidden Initially) --> | |
| <div id="results-container" class="hidden"> | |
| <!-- Results will be loaded here by JavaScript --> | |
| </div> | |
| <!-- Your Selections Summary --> | |
| <div id="selections-summary" class="mt-8 bg-white rounded-xl shadow-lg p-6 max-w-4xl mx-auto hidden"> | |
| <h3 class="text-xl font-bold text-gray-800 mb-4">Your Project Details</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <p class="text-sm text-gray-500">Application</p> | |
| <p id="summary-application" class="font-semibold text-gray-800">-</p> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <p class="text-sm text-gray-500">Location</p> | |
| <p id="summary-location" class="font-semibold text-gray-800">-</p> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <p class="text-sm text-gray-500">Material</p> | |
| <p id="summary-material" class="font-semibold text-gray-800">-</p> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-lg"> | |
| <p class="text-sm text-gray-500">Movement</p> | |
| <p id="summary-movement" class="font-semibold text-gray-800">-</p> | |
| </div> | |
| </div> | |
| <div class="mt-4 flex justify-end"> | |
| <button id="restart-btn" class="px-6 py-2 bg-gray-200 text-gray-800 rounded-lg font-medium hover:bg-gray-300 transition-colors"> | |
| <i class="fas fa-redo-alt mr-2"></i>Start Over | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="bg-gray-900 text-white mt-16 py-8"> | |
| <div class="container mx-auto px-4"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
| <div> | |
| <h3 class="text-xl font-bold mb-4">Need Help?</h3> | |
| <p class="text-gray-300 mb-4">Our experts are ready to assist you with your project.</p> | |
| <a href="tel:416-860-8308" class="inline-flex items-center text-blue-300 hover:text-white"> | |
| <i class="fas fa-phone mr-2"></i> (416) 860-8308 | |
| </a> | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold mb-4">Contact Us</h3> | |
| <p class="text-gray-300 mb-2"> | |
| <i class="fas fa-envelope mr-2"></i> [email protected] | |
| </p> | |
| <p class="text-gray-300"> | |
| <i class="fas fa-globe mr-2"></i> thecaulkingstore.com | |
| </p> | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold mb-4">About This Tool</h3> | |
| <p class="text-gray-300 text-sm"> | |
| This tool helps you find the right caulking and sealants based on products available at The Caulking Store. Recommendations are based on product specifications and intended applications. | |
| </p> | |
| </div> | |
| </div> | |
| <div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-400 text-sm"> | |
| <p>© 2023 The Caulking Store. This is a product selection tool for informational purposes.</p> | |
| </div> | |
| </div> | |
| </footer> | |
| <!-- JavaScript --> | |
| <script> | |
| // Product database based on The Caulking Store products | |
| const products = [ | |
| { | |
| id: 1, | |
| name: "Tremco Dymonic FC", | |
| type: "Polyurethane Sealant", | |
| category: "polyurethane", | |
| application: ["exterior", "interior"], | |
| location: ["control joints", "expansion joints", "perimeter seals"], | |
| material: ["concrete", "metal", "masonry", "wood"], | |
| movement: "High (±50%)", | |
| features: ["UV resistant", "weatherproof", "paintable", "non-sag"], | |
| colors: ["White", "Gray", "Black", "Aluminum", "Limestone"], | |
| description: "High-performance polyurethane sealant for demanding applications with extreme movement", | |
| bestFor: "Expansion joints, plaza decks, parking structures", | |
| image: "polyurethane" | |
| }, | |
| { | |
| id: 2, | |
| name: "Tremco Spectrem 1", | |
| type: "Structural Silicone", | |
| category: "silicone", | |
| application: ["exterior"], | |
| location: ["curtain wall", "structural glazing", "glass"], | |
| material: ["glass", "metal", "granite"], | |
| movement: "High (±50%)", | |
| features: ["structural strength", "UV resistant", "weatherproof", "clear"], | |
| colors: ["Clear", "Black", "Gray", "White"], | |
| description: "High-strength structural silicone for glass and metal curtain wall systems", | |
| bestFor: "Structural glazing, curtain wall, glass-to-glass applications", | |
| image: "silicone" | |
| }, | |
| { | |
| id: 3, | |
| name: "Tremco Spectrem 2", | |
| type: "Silicone Sealant", | |
| category: "silicone", | |
| application: ["exterior", "interior"], | |
| location: ["windows", "doors", "perimeter seals"], | |
| material: ["glass", "metal", "masonry", "wood"], | |
| movement: "Medium (±25%)", | |
| features: ["weatherproof", "UV resistant", "mold resistant", "paintable"], | |
| colors: ["Clear", "White", "Gray", "Black", "Brown"], | |
| description: "Versatile silicone sealant for general purpose sealing applications", | |
| bestFor: "Window and door perimeters, general caulking", | |
| image: "silicone" | |
| }, | |
| { | |
| id: 4, | |
| name: "Tremco 830 Elastomeric", | |
| type: "Acrylic Latex", | |
| category: "acrylic", | |
| application: ["interior", "exterior"], | |
| location: ["trim", "molding", "cracks", "gaps"], | |
| material: ["drywall", "wood", "plaster", "painted surfaces"], | |
| movement: "Low (±12.5%)", | |
| features: ["paintable", "water clean-up", "low odor", "fast drying"], | |
| colors: ["White", "Clear"], | |
| description: "High-quality acrylic latex caulk for interior and exterior trim work", | |
| bestFor: "Trim, molding, baseboards, interior cracks", | |
| image: "acrylic" | |
| }, | |
| { | |
| id: 5, | |
| name: "Tremco ExoAir 440", | |
| type: "Air Barrier Sealant", | |
| category: "specialty", | |
| application: ["exterior"], | |
| location: ["air barriers", "weather barriers", "sheathing"], | |
| material: ["OSB", "plywood", "concrete", "metal"], | |
| movement: "High (±50%)", | |
| features: ["air barrier", "water resistant", "UV resistant", "compatible with membranes"], | |
| colors: ["Gray"], | |
| description: "High-performance sealant for air barrier systems and weather sealing", | |
| bestFor: "Air barrier systems, sheathing seams, weather barriers", | |
| image: "specialty" | |
| }, | |
| { | |
| id: 6, | |
| name: "Tremco FyreSeal", | |
| type: "Firestop Sealant", | |
| category: "firestop", | |
| application: ["firestop"], | |
| location: ["penetrations", "joints", "gaps"], | |
| material: ["concrete", "drywall", "metal", "pipe"], | |
| movement: "Low (±12.5%)", | |
| features: ["fire rated", "smoke seal", "intumescent", "UL classified"], | |
| colors: ["Red", "Gray"], | |
| description: "Intumescent firestop sealant for through-penetrations and joints", | |
| bestFor: "Fire-rated walls, pipe penetrations, electrical penetrations", | |
| image: "firestop" | |
| }, | |
| { | |
| id: 7, | |
| name: "Pecora 890", | |
| type: "Polyurethane Sealant", | |
| category: "polyurethane", | |
| application: ["exterior"], | |
| location: ["concrete joints", "expansion joints", "pavement"], | |
| material: ["concrete", "asphalt", "metal"], | |
| movement: "High (±50%)", | |
| features: ["traffic durable", "fuel resistant", "chemical resistant", "flexible"], | |
| colors: ["Gray", "Black"], | |
| description: "Heavy-duty polyurethane sealant for demanding pavement applications", | |
| bestFor: "Airport runways, bridge decks, industrial floors", | |
| image: "polyurethane" | |
| }, | |
| { | |
| id: 8, | |
| name: "Tremco Vulkem 116", | |
| type: "Polyurethane Sealant", | |
| category: "polyurethane", | |
| application: ["exterior"], | |
| location: ["expansion joints", "precast panels", "perimeter seals"], | |
| material: ["concrete", "metal", "glass", "masonry"], | |
| movement: "High (±50%)", | |
| features: ["self-leveling", "gun grade", "toolable", "weatherproof"], | |
| colors: ["Gray", "Black", "White", "Terracotta"], | |
| description: "Premium polyurethane sealant for horizontal and vertical applications", | |
| bestFor: "Horizontal expansion joints, precast panels, vertical joints", | |
| image: "polyurethane" | |
| }, | |
| { | |
| id: 9, | |
| name: "Tremsil 600", | |
| type: "Neutral Silicone", | |
| category: "silicone", | |
| application: ["interior"], | |
| location: ["kitchen", "bathroom", "wet areas"], | |
| material: ["tile", "porcelain", "fiberglass", "acrylic"], | |
| movement: "Medium (±25%)", | |
| features: ["mold resistant", "mildew resistant", "waterproof", "flexible"], | |
| colors: ["Clear", "White"], | |
| description: "Neutral cure silicone sealant for kitchen and bathroom applications", | |
| bestFor: "Bathtubs, showers, sinks, kitchen backsplashes", | |
| image: "silicone" | |
| }, | |
| { | |
| id: 10, | |
| name: "OSI Quad Max", | |
| type: "Advanced Polymer", | |
| category: "hybrid", | |
| application: ["exterior", "interior"], | |
| location: ["windows", "doors", "siding", "trim"], | |
| material: ["vinyl", "wood", "metal", "fiberglass"], | |
| movement: "High (±50%)", | |
| features: ["paintable", "stainable", "flexible", "adheres to most surfaces"], | |
| colors: ["White", "Clear", "Brown", "Gray"], | |
| description: "Advanced polymer sealant with superior adhesion and flexibility", | |
| bestFor: "Windows, doors, siding, trim, multi-surface applications", | |
| image: "hybrid" | |
| } | |
| ]; | |
| // User selections | |
| const userSelections = { | |
| application: null, | |
| location: null, | |
| material: null, | |
| movement: null | |
| }; | |
| // Current step | |
| let currentStep = 1; | |
| // Questions data | |
| const questions = { | |
| 1: { | |
| title: "What type of application?", | |
| subtitle: "Choose where the sealant will be used", | |
| options: [ | |
| { | |
| id: "exterior", | |
| name: "Exterior", | |
| description: "Outdoor applications exposed to weather", | |
| icon: "fas fa-sun", | |
| color: "bg-yellow-100 text-yellow-800" | |
| }, | |
| { | |
| id: "interior", | |
| name: "Interior", | |
| description: "Indoor applications protected from weather", | |
| icon: "fas fa-home", | |
| color: "bg-blue-100 text-blue-800" | |
| }, | |
| { | |
| id: "firestop", | |
| name: "Firestop", | |
| description: "Fire-rated sealing for penetrations and joints", | |
| icon: "fas fa-fire", | |
| color: "bg-red-100 text-red-800" | |
| }, | |
| { | |
| id: "wet-area", | |
| name: "Wet Area", | |
| description: "Kitchens, bathrooms, and other wet locations", | |
| icon: "fas fa-tint", | |
| color: "bg-cyan-100 text-cyan-800" | |
| } | |
| ] | |
| }, | |
| 2: { | |
| title: "Where will it be applied?", | |
| subtitle: "Select the specific location", | |
| options: { | |
| exterior: [ | |
| { id: "windows-doors", name: "Windows & Doors", icon: "fas fa-window-maximize" }, | |
| { id: "siding-trim", name: "Siding & Trim", icon: "fas fa-border-all" }, | |
| { id: "expansion-joints", name: "Expansion Joints", icon: "fas fa-expand-alt" }, | |
| { id: "roof-flashing", name: "Roof & Flashing", icon: "fas fa-roofing" }, | |
| { id: "concrete-joints", name: "Concrete Joints", icon: "fas fa-road" }, | |
| { id: "curtain-wall", name: "Curtain Wall", icon: "fas fa-building" } | |
| ], | |
| interior: [ | |
| { id: "trim-molding", name: "Trim & Molding", icon: "fas fa-ruler-combined" }, | |
| { id: "drywall-cracks", name: "Drywall Cracks", icon: "fas fa-crop-alt" }, | |
| { id: "baseboards", name: "Baseboards", icon: "fas fa-border-style" }, | |
| { id: "ceilings", name: "Ceilings", icon: "fas fa-border-top" }, | |
| { id: "corners", name: "Corners", icon: "fas fa-vector-square" } | |
| ], | |
| firestop: [ | |
| { id: "pipe-penetrations", name: "Pipe Penetrations", icon: "fas fa-wrench" }, | |
| { id: "electrical-penetrations", name: "Electrical Penetrations", icon: "fas fa-plug" }, | |
| { id: "fire-rated-joints", name: "Fire-Rated Joints", icon: "fas fa-fire-extinguisher" }, | |
| { id: "duct-penetrations", name: "Duct Penetrations", icon: "fas fa-wind" } | |
| ], | |
| "wet-area": [ | |
| { id: "bathtub-shower", name: "Bathtub & Shower", icon: "fas fa-bath" }, | |
| { id: "kitchen-sink", name: "Kitchen Sink", icon: "fas fa-sink" }, | |
| { id: "backsplash", name: "Backsplash", icon: "fas fa-utensils" }, | |
| { id: "vanity-counter", name: "Vanity & Counter", icon: "fas fa-toilet" } | |
| ] | |
| } | |
| }, | |
| 3: { | |
| title: "What material are you sealing?", | |
| subtitle: "Choose the primary surface material", | |
| options: [ | |
| { id: "concrete", name: "Concrete / Masonry", icon: "fas fa-gopuram", color: "bg-gray-100" }, | |
| { id: "wood", name: "Wood", icon: "fas fa-tree", color: "bg-amber-100" }, | |
| { id: "metal", name: "Metal / Aluminum", icon: "fas fa-cog", color: "bg-gray-200" }, | |
| { id: "glass", name: "Glass", icon: "fas fa-wine-glass-alt", color: "bg-blue-50" }, | |
| { id: "drywall", name: "Drywall / Plaster", icon: "fas fa-th", color: "bg-white" }, | |
| { id: "tile", name: "Tile / Ceramic", icon: "fas fa-border-style", color: "bg-red-50" }, | |
| { id: "vinyl", name: "Vinyl / PVC", icon: "fas fa-cube", color: "bg-purple-50" }, | |
| { id: "plastic", name: "Plastic / Fiberglass", icon: "fas fa-industry", color: "bg-cyan-50" } | |
| ] | |
| } | |
| }; | |
| // Initialize the app | |
| document.addEventListener('DOMContentLoaded', function() { | |
| loadStep(currentStep); | |
| // Add restart button event listener | |
| document.getElementById('restart-btn').addEventListener('click', restartApp); | |
| }); | |
| // Load a step based on the step number | |
| function loadStep(step) { | |
| const container = document.getElementById('question-container'); | |
| const progressBar = document.getElementById('progress-bar'); | |
| const stepIndicator = document.getElementById('step-indicator'); | |
| // Update progress bar | |
| progressBar.style.width = `${(step / 4) * 100}%`; | |
| // Update progress dots | |
| updateProgressDots(step); | |
| if (step <= 3) { | |
| // Show question container, hide results | |
| container.classList.remove('hidden'); | |
| document.getElementById('results-container').classList.add('hidden'); | |
| document.getElementById('selections-summary').classList.add('hidden'); | |
| let html = ''; | |
| if (step === 1) { | |
| stepIndicator.textContent = "Step 1 of 4: Choose Application Type"; | |
| html = renderQuestion(questions[1]); | |
| } | |
| else if (step === 2) { | |
| stepIndicator.textContent = "Step 2 of 4: Select Location"; | |
| if (userSelections.application) { | |
| html = renderQuestion(questions[2], userSelections.application); | |
| } else { | |
| // If no application selected, go back to step 1 | |
| currentStep = 1; | |
| loadStep(1); | |
| return; | |
| } | |
| } | |
| else if (step === 3) { | |
| stepIndicator.textContent = "Step 3 of 4: Choose Material"; | |
| html = renderQuestion(questions[3]); | |
| } | |
| container.innerHTML = html; | |
| container.classList.remove('fade-in'); | |
| void container.offsetWidth; // Trigger reflow | |
| container.classList.add('fade-in'); | |
| // Add event listeners to options | |
| setTimeout(() => { | |
| const optionButtons = document.querySelectorAll('.option-btn'); | |
| optionButtons.forEach(button => { | |
| button.addEventListener('click', function() { | |
| const value = this.getAttribute('data-value'); | |
| handleOptionSelection(step, value); | |
| }); | |
| }); | |
| }, 100); | |
| } | |
| else if (step === 4) { | |
| // Show results | |
| stepIndicator.textContent = "Step 4 of 4: View Recommendations"; | |
| showResults(); | |
| } | |
| } | |
| // Render a question | |
| function renderQuestion(question, filter = null) { | |
| let options = question.options; | |
| // If this is step 2, filter options based on application | |
| if (currentStep === 2 && filter) { | |
| options = question.options[filter]; | |
| } | |
| let html = ` | |
| <div class="bg-white rounded-2xl shadow-xl p-8 card-hover"> | |
| <div class="text-center mb-10"> | |
| <h2 class="text-3xl md:text-4xl font-bold text-gray-800 mb-3">${question.title}</h2> | |
| <p class="text-gray-600 text-lg max-w-2xl mx-auto">${question.subtitle}</p> | |
| </div> | |
| <div class="grid grid-cols-1 ${options.length > 4 ? 'md:grid-cols-2' : 'md:grid-cols-2 lg:grid-cols-4'} gap-6"> | |
| `; | |
| options.forEach(option => { | |
| const isSelected = ( | |
| (currentStep === 1 && userSelections.application === option.id) || | |
| (currentStep === 2 && userSelections.location === option.id) || | |
| (currentStep === 3 && userSelections.material === option.id) | |
| ); | |
| html += ` | |
| <button class="option-btn w-full h-full p-6 rounded-xl border-2 text-left transition-all duration-300 card-hover ${isSelected ? 'option-selected border-blue-500 shadow-md' : 'border-gray-200 hover:border-blue-300'}" | |
| data-value="${option.id}"> | |
| <div class="flex flex-col items-center text-center"> | |
| <div class="option-icon ${option.color || 'bg-blue-100 text-blue-600'} mb-4"> | |
| <i class="${option.icon}"></i> | |
| </div> | |
| <h3 class="text-xl font-bold text-gray-800 mb-2">${option.name}</h3> | |
| ${option.description ? `<p class="text-gray-600 text-sm mb-4">${option.description}</p>` : ''} | |
| ${isSelected ? ` | |
| <div class="mt-2 text-blue-600"> | |
| <i class="fas fa-check-circle"></i> Selected | |
| </div> | |
| ` : ''} | |
| </div> | |
| </button> | |
| `; | |
| }); | |
| html += ` | |
| </div> | |
| <div class="flex justify-between mt-10 pt-6 border-t border-gray-100"> | |
| ${currentStep > 1 ? ` | |
| <button id="back-btn" class="px-8 py-3 bg-gray-100 text-gray-800 rounded-lg font-semibold hover:bg-gray-200 transition-colors"> | |
| <i class="fas fa-arrow-left mr-2"></i> Back | |
| </button> | |
| ` : '<div></div>'} | |
| ${currentStep < 3 ? ` | |
| <button id="next-btn" class="px-8 py-3 bg-gray-200 text-gray-800 rounded-lg font-semibold hover:bg-gray-300 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" | |
| ${!hasSelectionForCurrentStep() ? 'disabled' : ''}> | |
| Continue <i class="fas fa-arrow-right ml-2"></i> | |
| </button> | |
| ` : ` | |
| <button id="find-results-btn" class="px-8 py-3 primary-gradient text-white rounded-lg font-semibold hover:opacity-90 transition-all shadow-lg hover:shadow-xl ${!hasSelectionForCurrentStep() ? 'disabled:opacity-50 disabled:cursor-not-allowed' : ''}" | |
| ${!hasSelectionForCurrentStep() ? 'disabled' : ''}> | |
| Find Recommendations <i class="fas fa-search ml-2"></i> | |
| </button> | |
| `} | |
| </div> | |
| </div> | |
| `; | |
| return html; | |
| } | |
| // Handle option selection | |
| function handleOptionSelection(step, value) { | |
| if (step === 1) { | |
| userSelections.application = value; | |
| } else if (step === 2) { | |
| userSelections.location = value; | |
| } else if (step === 3) { | |
| userSelections.material = value; | |
| } | |
| // Update the UI | |
| loadStep(currentStep); | |
| // Enable the next button if selection is made | |
| if (hasSelectionForCurrentStep()) { | |
| const nextButton = document.getElementById('next-btn') || document.getElementById('find-results-btn'); | |
| if (nextButton) { | |
| nextButton.disabled = false; | |
| nextButton.classList.remove('disabled:opacity-50', 'disabled:cursor-not-allowed'); | |
| } | |
| } | |
| // Add event listeners for navigation buttons | |
| setTimeout(() => { | |
| const backButton = document.getElementById('back-btn'); | |
| if (backButton) { | |
| backButton.addEventListener('click', goBack); | |
| } | |
| const nextButton = document.getElementById('next-btn'); | |
| if (nextButton) { | |
| nextButton.addEventListener('click', goNext); | |
| } | |
| const findResultsButton = document.getElementById('find-results-btn'); | |
| if (findResultsButton) { | |
| findResultsButton.addEventListener('click', goNext); | |
| } | |
| }, 100); | |
| } | |
| // Check if user has made a selection for current step | |
| function hasSelectionForCurrentStep() { | |
| if (currentStep === 1) { | |
| return userSelections.application !== null; | |
| } else if (currentStep === 2) { | |
| return userSelections.location !== null; | |
| } else if (currentStep === 3) { | |
| return userSelections.material !== null; | |
| } | |
| return false; | |
| } | |
| // Go to next step | |
| function goNext() { | |
| if (currentStep < 4) { | |
| currentStep++; | |
| loadStep(currentStep); | |
| } | |
| } | |
| // Go back to previous step | |
| function goBack() { | |
| if (currentStep > 1) { | |
| currentStep--; | |
| loadStep(currentStep); | |
| } | |
| } | |
| // Update progress dots | |
| function updateProgressDots(current) { | |
| const dots = document.querySelectorAll('.progress-dot'); | |
| dots.forEach((dot, index) => { | |
| dot.classList.remove('active', 'completed'); | |
| if (index + 1 < current) { | |
| dot.classList.add('completed'); | |
| } else if (index + 1 === current) { | |
| dot.classList.add('active'); | |
| } | |
| }); | |
| } | |
| // Show results based on user selections | |
| function showResults() { | |
| const questionContainer = document.getElementById('question-container'); | |
| const resultsContainer = document.getElementById('results-container'); | |
| const summaryContainer = document.getElementById('selections-summary'); | |
| // Hide question container, show results and summary | |
| questionContainer.classList.add('hidden'); | |
| resultsContainer.classList.remove('hidden'); | |
| summaryContainer.classList.remove('hidden'); | |
| // Update summary | |
| updateSummary(); | |
| // Find matching products | |
| const matches = findMatchingProducts(); | |
| // Render results | |
| let html = ` | |
| <div class="bg-white rounded-2xl shadow-xl p-8 mb-8"> | |
| <div class="text-center mb-8"> | |
| <h2 class="text-3xl md:text-4xl font-bold text-gray-800 mb-3">Recommended Products</h2> | |
| <p class="text-gray-600 text-lg max-w-3xl mx-auto">Based on your project requirements, here are the best products for your needs</p> | |
| </div> | |
| ${matches.length === 0 ? ` | |
| <div class="bg-yellow-50 border-l-4 border-yellow-400 p-6 rounded-r-lg mb-8"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-exclamation-triangle text-yellow-400 text-2xl"></i> | |
| </div> | |
| <div class="ml-4"> | |
| <h3 class="text-lg font-bold text-yellow-800">No perfect matches found</h3> | |
| <p class="text-yellow-700 mt-2">We couldn't find products that match all your criteria. Try adjusting your selections or contact our experts for personalized recommendations.</p> | |
| <button class="mt-4 px-6 py-2 bg-yellow-100 text-yellow-800 rounded-lg font-medium hover:bg-yellow-200 transition-colors" onclick="restartApp()"> | |
| Try Different Options | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ` : ''} | |
| <div class="space-y-8"> | |
| `; | |
| // Sort matches by relevance (more matches = higher relevance) | |
| matches.sort((a, b) => b.matchScore - a.matchScore); | |
| // Show top 6 matches | |
| const topMatches = matches.slice(0, 6); | |
| topMatches.forEach((match, index) => { | |
| const product = match.product; | |
| const matchPercentage = Math.min(100, Math.round((match.matchScore / 4) * 100)); | |
| html += ` | |
| <div class="border border-gray-200 rounded-2xl overflow-hidden slide-in-right" style="animation-delay: ${index * 0.1}s"> | |
| ${index === 0 ? ` | |
| <div class="bg-gradient-to-r from-green-500 to-green-600 text-white p-3 text-center font-bold"> | |
| <i class="fas fa-crown mr-2"></i> Best Match (${matchPercentage}% Match) | |
| </div> | |
| ` : index === 1 ? ` | |
| <div class="bg-gradient-to-r from-blue-500 to-blue-600 text-white p-3 text-center font-bold"> | |
| <i class="fas fa-medal mr-2"></i> Excellent Match (${matchPercentage}% Match) | |
| </div> | |
| ` : ` | |
| <div class="bg-gradient-to-r from-gray-600 to-gray-700 text-white p-3 text-center font-bold"> | |
| Good Match (${matchPercentage}% Match) | |
| </div> | |
| `} | |
| <div class="p-6"> | |
| <div class="flex flex-col lg:flex-row lg:items-start gap-6"> | |
| <div class="lg:w-1/4"> | |
| <div class="bg-gradient-to-br from-gray-100 to-gray-200 rounded-xl p-6 h-full flex flex-col items-center justify-center"> | |
| <div class="text-5xl mb-4 text-gray-700"> | |
| ${getProductIcon(product.category)} | |
| </div> | |
| <h3 class="text-xl font-bold text-gray-800 text-center mb-2">${product.type}</h3> | |
| <div class="text-center"> | |
| <span class="tag ${getCategoryColor(product.category)}">${product.category}</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="lg:w-3/4"> | |
| <div class="flex flex-col md:flex-row md:items-start md:justify-between mb-4"> | |
| <div> | |
| <h3 class="text-2xl font-bold text-gray-800 mb-2">${product.name}</h3> | |
| <p class="text-gray-700 text-lg mb-4">${product.description}</p> | |
| </div> | |
| <div class="flex-shrink-0 mt-4 md:mt-0"> | |
| <div class="bg-blue-50 p-4 rounded-xl border border-blue-200"> | |
| <div class="text-3xl font-bold text-blue-700 text-center">${matchPercentage}%</div> | |
| <div class="text-sm text-blue-600 text-center font-medium">Match Score</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <h4 class="font-bold text-gray-800 mb-3 flex items-center"> | |
| <i class="fas fa-bullseye mr-2 text-blue-600"></i> Best For: | |
| </h4> | |
| <p class="text-gray-700">${product.bestFor}</p> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6"> | |
| <div> | |
| <h4 class="font-bold text-gray-800 mb-3 flex items-center"> | |
| <i class="fas fa-check-circle mr-2 text-green-600"></i> Key Features: | |
| </h4> | |
| <div class="flex flex-wrap gap-2"> | |
| ${product.features.slice(0, 4).map(feature => ` | |
| <span class="tag bg-green-100 text-green-800">${feature}</span> | |
| `).join('')} | |
| </div> | |
| </div> | |
| <div> | |
| <h4 class="font-bold text-gray-800 mb-3 flex items-center"> | |
| <i class="fas fa-palette mr-2 text-purple-600"></i> Available Colors: | |
| </h4> | |
| <div class="flex flex-wrap gap-2"> | |
| ${product.colors.slice(0, 3).map(color => ` | |
| <span class="tag bg-purple-100 text-purple-800">${color}</span> | |
| `).join('')} | |
| ${product.colors.length > 3 ? `<span class="tag bg-gray-100 text-gray-800">+${product.colors.length - 3} more</span>` : ''} | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 pt-4 border-t border-gray-200"> | |
| <div class="text-sm text-gray-600"> | |
| <div class="flex items-center"> | |
| <i class="fas fa-arrows-alt-h mr-2"></i> | |
| <span>Movement Capacity: <strong>${product.movement}</strong></span> | |
| </div> | |
| </div> | |
| <div class="flex gap-3"> | |
| <button class="px-5 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors" onclick="showProductDetails(${product.id})"> | |
| <i class="fas fa-info-circle mr-2"></i> Details | |
| </button> | |
| <a href="https://thecaulkingstore.com/search?q=${encodeURIComponent(product.name)}" target="_blank" class="px-5 py-2 primary-gradient text-white rounded-lg font-medium hover:opacity-90 transition-all shadow-md"> | |
| <i class="fas fa-shopping-cart mr-2"></i> View Product | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| html += ` | |
| </div> | |
| <div class="mt-12 bg-gradient-to-r from-blue-50 to-indigo-50 border border-blue-200 rounded-2xl p-8"> | |
| <div class="text-center mb-6"> | |
| <h3 class="text-2xl font-bold text-gray-800 mb-3">Need Professional Advice?</h3> | |
| <p class="text-gray-700 max-w-2xl mx-auto">Our caulking experts are available to help you choose the right product for your specific project.</p> | |
| </div> | |
| <div class="flex flex-col md:flex-row justify-center items-center gap-6"> | |
| <a href="tel:416-860-8308" class="flex items-center px-6 py-3 bg-white text-blue-600 rounded-xl font-bold hover:bg-blue-50 transition-all border-2 border-blue-200 shadow-md"> | |
| <i class="fas fa-phone mr-3 text-xl"></i> | |
| <div> | |
| <div class="text-sm">Call Us</div> | |
| <div class="text-lg">(416) 860-8308</div> | |
| </div> | |
| </a> | |
| <a href="mailto:[email protected]" class="flex items-center px-6 py-3 bg-white text-blue-600 rounded-xl font-bold hover:bg-blue-50 transition-all border-2 border-blue-200 shadow-md"> | |
| <i class="fas fa-envelope mr-3 text-xl"></i> | |
| <div> | |
| <div class="text-sm">Email Us</div> | |
| <div class="text-lg">[email protected]</div> | |
| </div> | |
| </a> | |
| <a href="https://thecaulkingstore.com" target="_blank" class="flex items-center px-6 py-3 primary-gradient text-white rounded-xl font-bold hover:opacity-90 transition-all shadow-lg"> | |
| <i class="fas fa-external-link-alt mr-3 text-xl"></i> | |
| <div> | |
| <div class="text-sm">Visit</div> | |
| <div class="text-lg">The Caulking Store</div> | |
| </div> | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| resultsContainer.innerHTML = html; | |
| resultsContainer.classList.remove('fade-in'); | |
| void resultsContainer.offsetWidth; // Trigger reflow | |
| resultsContainer.classList.add('fade-in'); | |
| } | |
| // Find products that match user selections | |
| function findMatchingProducts() { | |
| const matches = []; | |
| products.forEach(product => { | |
| let matchScore = 0; | |
| let matchReasons = []; | |
| // Check application match | |
| if (product.application.includes(userSelections.application)) { | |
| matchScore += 1; | |
| matchReasons.push(`✓ Suitable for ${userSelections.application} applications`); | |
| } | |
| // Check location match (simplified - checking if any location matches) | |
| let locationMatch = false; | |
| for (const loc of product.location) { | |
| if (loc.toLowerCase().includes(userSelections.location)) { | |
| locationMatch = true; | |
| break; | |
| } | |
| } | |
| if (locationMatch) { | |
| matchScore += 1; | |
| matchReasons.push(`✓ Can be used for ${userSelections.location}`); | |
| } | |
| // Check material match | |
| if (product.material.includes(userSelections.material)) { | |
| matchScore += 1; | |
| matchReasons.push(`✓ Compatible with ${userSelections.material}`); | |
| } | |
| // Add to matches if at least one criteria matches | |
| if (matchScore > 0) { | |
| matches.push({ | |
| product, | |
| matchScore, | |
| matchReasons | |
| }); | |
| } | |
| }); | |
| return matches; | |
| } | |
| // Update the summary with user selections | |
| function updateSummary() { | |
| const applicationMap = { | |
| 'exterior': 'Exterior', | |
| 'interior': 'Interior', | |
| 'firestop': 'Firestop', | |
| 'wet-area': 'Wet Area' | |
| }; | |
| const locationMap = { | |
| 'windows-doors': 'Windows & Doors', | |
| 'siding-trim': 'Siding & Trim', | |
| 'expansion-joints': 'Expansion Joints', | |
| 'roof-flashing': 'Roof & Flashing', | |
| 'concrete-joints': 'Concrete Joints', | |
| 'curtain-wall': 'Curtain Wall', | |
| 'trim-molding': 'Trim & Molding', | |
| 'drywall-cracks': 'Drywall Cracks', | |
| 'baseboards': 'Baseboards', | |
| 'ceilings': 'Ceilings', | |
| 'corners': 'Corners', | |
| 'pipe-penetrations': 'Pipe Penetrations', | |
| 'electrical-penetrations': 'Electrical Penetrations', | |
| 'fire-rated-joints': 'Fire-Rated Joints', | |
| 'duct-penetrations': 'Duct Penetrations', | |
| 'bathtub-shower': 'Bathtub & Shower', | |
| 'kitchen-sink': 'Kitchen Sink', | |
| 'backsplash': 'Backsplash', | |
| 'vanity-counter': 'Vanity & Counter' | |
| }; | |
| const materialMap = { | |
| 'concrete': 'Concrete / Masonry', | |
| 'wood': 'Wood', | |
| 'metal': 'Metal / Aluminum', | |
| 'glass': 'Glass', | |
| 'drywall': 'Drywall / Plaster', | |
| 'tile': 'Tile / Ceramic', | |
| 'vinyl': 'Vinyl / PVC', | |
| 'plastic': 'Plastic / Fiberglass' | |
| }; | |
| document.getElementById('summary-application').textContent = | |
| applicationMap[userSelections.application] || '-'; | |
| document.getElementById('summary-location').textContent = | |
| locationMap[userSelections.location] || '-'; | |
| document.getElementById('summary-material').textContent = | |
| materialMap[userSelections.material] || '-'; | |
| document.getElementById('summary-movement').textContent = 'All types'; | |
| } | |
| // Get product icon based on category | |
| function getProductIcon(category) { | |
| const icons = { | |
| 'polyurethane': 'fas fa-expand-alt', | |
| 'silicone': 'fas fa-droplet', | |
| 'acrylic': 'fas fa-paint-roller', | |
| 'firestop': 'fas fa-fire', | |
| 'specialty': 'fas fa-star', | |
| 'hybrid': 'fas fa-blend' | |
| }; | |
| return icons[category] || 'fas fa-box'; | |
| } | |
| // Get category color class | |
| function getCategoryColor(category) { | |
| const colors = { | |
| 'polyurethane': 'bg-blue-100 text-blue-800', | |
| 'silicone': 'bg-purple-100 text-purple-800', | |
| 'acrylic': 'bg-green-100 text-green-800', | |
| 'firestop': 'bg-red-100 text-red-800', | |
| 'specialty': 'bg-yellow-100 text-yellow-800', | |
| 'hybrid': 'bg-indigo-100 text-indigo-800' | |
| }; | |
| return colors[category] || 'bg-gray-100 text-gray-800'; | |
| } | |
| // Show product details modal | |
| function showProductDetails(productId) { | |
| const product = products.find(p => p.id === productId); | |
| if (!product) return; | |
| // Create modal | |
| const modalHtml = ` | |
| <div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50"> | |
| <div class="bg-white rounded-2xl max-w-4xl w-full max-h-[90vh] overflow-y-auto"> | |
| <div class="p-6 border-b border-gray-200 flex justify-between items-center"> | |
| <h3 class="text-2xl font-bold text-gray-800">${product.name}</h3> | |
| <button onclick="closeModal()" class="text-gray-500 hover:text-gray-700 text-2xl"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="p-6"> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> | |
| <div> | |
| <div class="mb-6"> | |
| <h4 class="text-lg font-bold text-gray-800 mb-2">Product Description</h4> | |
| <p class="text-gray-700">${product.description}</p> | |
| </div> | |
| <div class="mb-6"> | |
| <h4 class="text-lg font-bold text-gray-800 mb-2">Best For</h4> | |
| <p class="text-gray-700">${product.bestFor}</p> | |
| </div> | |
| <div class="mb-6"> | |
| <h4 class="text-lg font-bold text-gray-800 mb-3">Key Features</h4> | |
| <div class="space-y-2"> | |
| ${product.features.map(feature => ` | |
| <div class="flex items-start"> | |
| <i class="fas fa-check text-green-500 mt-1 mr-3"></i> | |
| <span class="text-gray-700">${feature}</span> | |
| </div> | |
| `).join('')} | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="mb-6"> | |
| <h4 class="text-lg font-bold text-gray-800 mb-3">Technical Specifications</h4> | |
| <div class="space-y-4"> | |
| <div class="flex justify-between border-b border-gray-100 pb-2"> | |
| <span class="text-gray-600">Type</span> | |
| <span class="font-medium">${product.type}</span> | |
| </div> | |
| <div class="flex justify-between border-b border-gray-100 pb-2"> | |
| <span class="text-gray-600">Movement Capacity</span> | |
| <span class="font-medium">${product.movement}</span> | |
| </div> | |
| <div class="flex justify-between border-b border-gray-100 pb-2"> | |
| <span class="text-gray-600">Applications</span> | |
| <span class="font-medium">${product.application.join(', ')}</span> | |
| </div> | |
| <div class="flex justify-between border-b border-gray-100 pb-2"> | |
| <span class="text-gray-600">Compatible Materials</span> | |
| <span class="font-medium">${product.material.join(', ')}</span> | |
| </div> | |
| <div class="flex justify-between border-b border-gray-100 pb-2"> | |
| <span class="text-gray-600">Available Colors</span> | |
| <span class="font-medium">${product.colors.join(', ')}</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-blue-50 rounded-xl p-5 border border-blue-200"> | |
| <h4 class="text-lg font-bold text-gray-800 mb-3">Purchase Options</h4> | |
| <p class="text-gray-700 mb-4">This product is available at The Caulking Store in various sizes and formulations.</p> | |
| <div class="flex flex-col sm:flex-row gap-3"> | |
| <a href="https://thecaulkingstore.com/search?q=${encodeURIComponent(product.name)}" target="_blank" class="flex-1 px-5 py-3 primary-gradient text-white rounded-lg font-bold text-center hover:opacity-90 transition-all"> | |
| <i class="fas fa-external-link-alt mr-2"></i> View on Website | |
| </a> | |
| <a href="tel:416-860-8308" class="flex-1 px-5 py-3 bg-white text-blue-600 rounded-lg font-bold text-center hover:bg-blue-50 transition-all border-2 border-blue-200"> | |
| <i class="fas fa-phone mr-2"></i> Call to Order | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| const modalContainer = document.createElement('div'); | |
| modalContainer.innerHTML = modalHtml; | |
| document.body.appendChild(modalContainer); | |
| } | |
| // Close modal | |
| function closeModal() { | |
| const modal = document.querySelector('.fixed.inset-0.bg-black'); | |
| if (modal) { | |
| modal.remove(); | |
| } | |
| } | |
| // Restart the app | |
| function restartApp() { | |
| // Reset selections | |
| userSelections.application = null; | |
| userSelections.location = null; | |
| userSelections.material = null; | |
| userSelections.movement = null; | |
| // Reset to step 1 | |
| currentStep = 1; | |
| // Reload the app | |
| loadStep(currentStep); | |
| } | |
| // Make functions available globally for HTML event handlers | |
| window.showProductDetails = showProductDetails; | |
| window.closeModal = closeModal; | |
| window.restartApp = restartApp; | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment