← back to Resize It

web-interface.html

326 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spoonflower Image Resizer</title>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gradient-to-br from-purple-600 to-indigo-800 min-h-screen flex items-center justify-center p-6">
    <div class="bg-white rounded-2xl shadow-2xl p-8 max-w-2xl w-full">
        <!-- Header -->
        <div class="text-center mb-8">
            <h1 class="text-4xl font-bold text-gray-800 mb-2">🎨 Spoonflower Resizer</h1>
            <p class="text-gray-600">Resize designs to 24" width at 150 DPI</p>
        </div>

        <!-- Drop Zone -->
        <div id="dropZone" class="border-4 border-dashed border-purple-300 rounded-xl p-12 text-center bg-purple-50 hover:bg-purple-100 transition-colors cursor-pointer mb-6">
            <p class="text-purple-600 text-lg font-semibold mb-2">📁 Drop image file here</p>
            <p class="text-gray-500 text-sm">or click to browse</p>
            <input type="file" id="fileInput" accept="image/*" class="hidden">
        </div>

        <!-- OR Divider -->
        <div class="flex items-center my-6">
            <div class="flex-1 border-t border-gray-300"></div>
            <span class="px-4 text-gray-500 text-sm">OR</span>
            <div class="flex-1 border-t border-gray-300"></div>
        </div>

        <!-- Spoonflower URL Input -->
        <div class="mb-6">
            <label class="block text-sm font-medium text-gray-700 mb-2">Spoonflower Design URL</label>
            <input
                type="text"
                id="urlInput"
                placeholder="https://www.spoonflower.com/artists/designs/12345-design-name"
                class="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-purple-500 transition-colors"
            >
        </div>

        <!-- Action Buttons -->
        <div class="grid grid-cols-2 gap-4 mb-6">
            <button
                id="resizeBtn"
                class="bg-gradient-to-r from-purple-600 to-indigo-600 text-white font-semibold py-3 px-6 rounded-lg hover:shadow-lg transform hover:-translate-y-0.5 transition-all disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
            >
                🔧 Resize and Download
            </button>
            <button
                id="goToSpoonBtn"
                class="bg-gradient-to-r from-green-500 to-emerald-600 text-white font-semibold py-3 px-6 rounded-lg hover:shadow-lg transform hover:-translate-y-0.5 transition-all disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
                disabled
            >
                🌐 Go To Spoon Page
            </button>
        </div>

        <!-- Spoonflower Link Field (appears after resize) -->
        <div id="spoonLinkContainer" class="hidden mb-6 p-4 bg-green-50 border-2 border-green-300 rounded-lg">
            <label class="block text-sm font-medium text-green-800 mb-2">✅ Design Link Ready</label>
            <div class="flex gap-2">
                <input
                    type="text"
                    id="spoonLink"
                    readonly
                    class="flex-1 px-4 py-2 bg-white border border-green-300 rounded-lg text-gray-700"
                >
                <button
                    id="openNewTabBtn"
                    class="px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors font-semibold"
                >
                    🔗 Open New Tab
                </button>
            </div>
        </div>

        <!-- Status Messages -->
        <div id="status" class="hidden p-4 rounded-lg mb-6"></div>

        <!-- Results Panel -->
        <div id="resultsPanel" class="hidden mt-6 p-6 bg-gray-50 rounded-xl border border-gray-200">
            <h3 class="text-lg font-bold text-gray-800 mb-4">📊 Resize Results</h3>
            <div id="resultsContent"></div>
        </div>

        <!-- Preview -->
        <div id="preview" class="mt-6"></div>
    </div>

    <script>
        const dropZone = document.getElementById('dropZone');
        const fileInput = document.getElementById('fileInput');
        const urlInput = document.getElementById('urlInput');
        const resizeBtn = document.getElementById('resizeBtn');
        const goToSpoonBtn = document.getElementById('goToSpoonBtn');
        const spoonLinkContainer = document.getElementById('spoonLinkContainer');
        const spoonLink = document.getElementById('spoonLink');
        const openNewTabBtn = document.getElementById('openNewTabBtn');
        const status = document.getElementById('status');
        const resultsPanel = document.getElementById('resultsPanel');
        const resultsContent = document.getElementById('resultsContent');
        const preview = document.getElementById('preview');

        let selectedFile = null;
        let currentSpoonflowerUrl = null;
        let resizedImageUrl = null;

        // Drop zone handlers
        dropZone.addEventListener('click', () => fileInput.click());

        dropZone.addEventListener('dragover', (e) => {
            e.preventDefault();
            dropZone.classList.add('border-purple-500', 'bg-purple-200');
        });

        dropZone.addEventListener('dragleave', () => {
            dropZone.classList.remove('border-purple-500', 'bg-purple-200');
        });

        dropZone.addEventListener('drop', (e) => {
            e.preventDefault();
            dropZone.classList.remove('border-purple-500', 'bg-purple-200');

            const files = e.dataTransfer.files;
            if (files.length > 0) {
                handleFile(files[0]);
            }
        });

        fileInput.addEventListener('change', (e) => {
            if (e.target.files.length > 0) {
                handleFile(e.target.files[0]);
            }
        });

        function handleFile(file) {
            if (!file.type.startsWith('image/')) {
                showStatus('error', 'Please select an image file');
                return;
            }

            selectedFile = file;
            dropZone.innerHTML = `
                <p class="text-green-600 text-lg font-semibold mb-2">✅ ${file.name}</p>
                <p class="text-gray-500 text-sm">Click to change</p>
            `;
            showStatus('success', `Selected: ${file.name} (${(file.size / 1024 / 1024).toFixed(2)} MB)`);

            // Show preview
            const reader = new FileReader();
            reader.onload = (e) => {
                preview.innerHTML = `<img src="${e.target.result}" alt="Preview" class="max-w-full rounded-lg shadow-lg mx-auto">`;
            };
            reader.readAsDataURL(file);
        }

        // Resize and Download button
        resizeBtn.addEventListener('click', async () => {
            const url = urlInput.value.trim();

            if (!selectedFile && !url) {
                showStatus('error', 'Please select a file or enter a Spoonflower URL');
                return;
            }

            resizeBtn.disabled = true;
            showStatus('info', '⏳ Processing...');

            try {
                let result;
                if (selectedFile) {
                    result = await processLocalFile(selectedFile);
                } else if (url) {
                    result = await processSpoonflowerURL(url);
                }

                // Show results
                displayResults(result);

                // If Spoonflower URL was provided, use it
                if (url && url.includes('spoonflower.com')) {
                    currentSpoonflowerUrl = url;
                    goToSpoonBtn.disabled = false;
                    spoonLink.value = url;
                    spoonLinkContainer.classList.remove('hidden');

                    showStatus('success', '✅ Image resized successfully! Opening Spoonflower page...');

                    // Auto-open Spoonflower page after 1 second
                    setTimeout(() => {
                        window.open(url, '_blank');
                    }, 1000);
                } else {
                    // No URL provided - ask for it
                    showStatus('success', '✅ Image resized successfully!');

                    // Prompt for Spoonflower URL
                    setTimeout(() => {
                        const spoonUrl = prompt('Enter the Spoonflower design URL to open:');
                        if (spoonUrl && spoonUrl.includes('spoonflower.com')) {
                            currentSpoonflowerUrl = spoonUrl;
                            goToSpoonBtn.disabled = false;
                            spoonLink.value = spoonUrl;
                            spoonLinkContainer.classList.remove('hidden');
                            urlInput.value = spoonUrl;

                            showStatus('success', '✅ Opening Spoonflower design page...');
                            window.open(spoonUrl, '_blank');
                        }
                    }, 500);
                }

            } catch (error) {
                showStatus('error', error.message);
            } finally {
                resizeBtn.disabled = false;
            }
        });

        // Go To Spoon Page button
        goToSpoonBtn.addEventListener('click', () => {
            if (currentSpoonflowerUrl) {
                window.open(currentSpoonflowerUrl, '_blank');
                showStatus('success', '🌐 Opened Spoonflower design page in new tab');
            }
        });

        // Open New Tab button
        openNewTabBtn.addEventListener('click', () => {
            const url = spoonLink.value;
            if (url) {
                window.open(url, '_blank');
                showStatus('success', '🌐 Opened Spoonflower design in new tab');
            }
        });

        async function processLocalFile(file) {
            const formData = new FormData();
            formData.append('file', file);

            const response = await fetch('/api/resize', {
                method: 'POST',
                body: formData
            });

            if (!response.ok) {
                throw new Error('Failed to process image');
            }

            return await response.json();
        }

        async function processSpoonflowerURL(url) {
            const response = await fetch('/api/spoonflower', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ url })
            });

            if (!response.ok) {
                const error = await response.json();
                throw new Error(error.message || 'Failed to process Spoonflower URL');
            }

            return await response.json();
        }

        function displayResults(result) {
            resultsPanel.classList.remove('hidden');

            const warningHtml = result.warning ? `
                <div class="bg-yellow-50 border-l-4 border-yellow-400 p-3 mt-3">
                    <p class="text-yellow-800 text-sm">⚠️ ${result.warning}</p>
                </div>
            ` : '';

            resultsContent.innerHTML = `
                <div class="grid grid-cols-2 gap-4 mb-4">
                    <div>
                        <p class="text-sm text-gray-600">Original Size</p>
                        <p class="font-semibold text-gray-800">${result.original.width} × ${result.original.height} px</p>
                    </div>
                    <div>
                        <p class="text-sm text-gray-600">Resized Size</p>
                        <p class="font-semibold text-gray-800">${result.resized.width} × ${result.resized.height} px</p>
                    </div>
                    <div>
                        <p class="text-sm text-gray-600">Physical Size</p>
                        <p class="font-semibold text-gray-800">24" × ${result.resized.heightInches}" @ 150 DPI</p>
                    </div>
                    <div>
                        <p class="text-sm text-gray-600">Scale Factor</p>
                        <p class="font-semibold text-gray-800">${result.scaleFactor}x</p>
                    </div>
                </div>

                ${warningHtml}

                <a href="${result.downloadUrl}" download
                   class="mt-4 block w-full bg-blue-600 text-white text-center font-semibold py-3 px-6 rounded-lg hover:bg-blue-700 transition-colors">
                    💾 Download Resized Image
                </a>
            `;

            resizedImageUrl = result.downloadUrl;
        }

        function showStatus(type, message) {
            status.classList.remove('hidden');

            const colors = {
                success: 'bg-green-100 border-green-400 text-green-800',
                error: 'bg-red-100 border-red-400 text-red-800',
                info: 'bg-blue-100 border-blue-400 text-blue-800'
            };

            status.className = `p-4 rounded-lg mb-6 border-l-4 ${colors[type]}`;
            status.textContent = message;
        }
    </script>
</body>
</html>