Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Thinkly Labs SEO</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| background: #0a0a0a; | |
| color: #ffffff; | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
| min-height: 100vh; | |
| background-image: radial-gradient(circle at 20% 20%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), | |
| radial-gradient(circle at 80% 80%, rgba(255, 119, 198, 0.3) 0%, transparent 50%); | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 40px 20px; | |
| } | |
| .header { | |
| text-align: center; | |
| margin-bottom: 60px; | |
| } | |
| .logo { | |
| font-size: 48px; | |
| font-weight: 700; | |
| margin-bottom: 10px; | |
| z-index: 10; | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 12px; | |
| } | |
| .logo-icon { | |
| background: rgba(255, 255, 255, 0.1); | |
| border-radius: 12px; | |
| padding: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| backdrop-filter: blur(5px); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| } | |
| .logo-svg { | |
| width: 32px; | |
| height: 32px; | |
| filter: brightness(0) invert(1); | |
| } | |
| .logo-text { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| } | |
| .subtitle { | |
| font-size: 18px; | |
| color: #888; | |
| margin-bottom: 40px; | |
| } | |
| .main-card { | |
| background: rgba(255, 255, 255, 0.02); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 16px; | |
| padding: 40px; | |
| backdrop-filter: blur(10px); | |
| margin-bottom: 40px; | |
| } | |
| .form-group { | |
| margin-bottom: 24px; | |
| } | |
| .form-label { | |
| display: block; | |
| margin-bottom: 8px; | |
| font-weight: 600; | |
| color: #fff; | |
| } | |
| .form-input { | |
| width: 100%; | |
| padding: 16px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| border-radius: 8px; | |
| color: #fff; | |
| font-size: 16px; | |
| transition: all 0.3s ease; | |
| } | |
| .form-input:focus { | |
| outline: none; | |
| border-color: #374151; | |
| background: rgba(255, 255, 255, 0.15); | |
| } | |
| .form-input:not(:placeholder-shown) { | |
| background: rgba(255, 255, 255, 0.15); | |
| } | |
| .form-input::placeholder { | |
| color: #666; | |
| } | |
| .textarea { | |
| min-height: 120px; | |
| resize: vertical; | |
| font-family: inherit; | |
| } | |
| .generate-btn { | |
| width: 100%; | |
| padding: 18px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| border-radius: 12px; | |
| color: white; | |
| font-size: 18px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| margin-top: 20px; | |
| backdrop-filter: blur(10px); | |
| box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); | |
| } | |
| .generate-btn:hover { | |
| transform: translateY(-2px); | |
| background: rgba(255, 255, 255, 0.15); | |
| border-color: rgba(255, 255, 255, 0.3); | |
| box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4); | |
| } | |
| .generate-btn:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| transform: none; | |
| } | |
| .options-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
| gap: 24px; | |
| margin-bottom: 40px; | |
| } | |
| .option-card { | |
| background: transparent; | |
| border: none; | |
| border-radius: 12px; | |
| padding: 24px; | |
| text-align: center; | |
| cursor: default; | |
| } | |
| .option-icon { | |
| font-size: 32px; | |
| margin-bottom: 12px; | |
| display: block; | |
| } | |
| .option-title { | |
| font-size: 16px; | |
| font-weight: 500; | |
| margin-bottom: 6px; | |
| color: #fff; | |
| } | |
| .option-desc { | |
| color: #aaa; | |
| font-size: 13px; | |
| line-height: 1.4; | |
| } | |
| .loading-overlay { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.8); | |
| z-index: 1000; | |
| justify-content: center; | |
| align-items: center; | |
| flex-direction: column; | |
| } | |
| .loading-spinner { | |
| width: 60px; | |
| height: 60px; | |
| border: 3px solid rgba(255, 255, 255, 0.3); | |
| border-top: 3px solid #667eea; | |
| border-radius: 50%; | |
| animation: spin 1s linear infinite; | |
| margin-bottom: 20px; | |
| } | |
| .loading-text { | |
| color: #fff; | |
| font-size: 18px; | |
| margin-bottom: 10px; | |
| } | |
| .loading-subtext { | |
| color: #888; | |
| font-size: 14px; | |
| } | |
| @keyframes spin { | |
| 0% { | |
| transform: rotate(0deg); | |
| } | |
| 100% { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| .error-message { | |
| background: rgba(220, 38, 38, 0.1); | |
| border: 1px solid rgba(220, 38, 38, 0.3); | |
| border-radius: 8px; | |
| padding: 16px; | |
| color: #fca5a5; | |
| margin-top: 16px; | |
| display: none; | |
| } | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 20px 16px; | |
| } | |
| .main-card { | |
| padding: 24px; | |
| } | |
| .logo { | |
| font-size: 36px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1 class="logo"> | |
| <span class="logo-icon"> | |
| <img src="/static/logo.svg" alt="Thinkly Logo" class="logo-svg"> | |
| </span> | |
| <span class="logo-text">Thinkly Labs SEO</span> | |
| </h1> | |
| <p class="subtitle">Professional SEO Analysis & Reporting</p> | |
| </div> | |
| <div class="options-grid"> | |
| <div class="option-card"> | |
| <span class="option-icon">β‘</span> | |
| <div class="option-title">Technical SEO</div> | |
| <div class="option-desc">PageSpeed insights, Core Web Vitals</div> | |
| </div> | |
| <div class="option-card"> | |
| <span class="option-icon">π</span> | |
| <div class="option-title">Content Audit</div> | |
| <div class="option-desc">Metadata analysis, content quality</div> | |
| </div> | |
| <div class="option-card"> | |
| <span class="option-icon">π</span> | |
| <div class="option-title">Competitor Analysis</div> | |
| <div class="option-desc">Performance benchmarking</div> | |
| </div> | |
| <div class="option-card"> | |
| <span class="option-icon">π</span> | |
| <div class="option-title">Professional Reports</div> | |
| <div class="option-desc">HTML & PDF export</div> | |
| </div> | |
| </div> | |
| <div class="main-card"> | |
| <form id="seoForm"> | |
| <div class="form-group"> | |
| <label class="form-label" for="url">Website URL</label> | |
| <input type="url" id="url" name="url" class="form-input" placeholder="https://example.com" required> | |
| </div> | |
| <div class="form-group"> | |
| <label class="form-label" for="competitors">Competitor URLs (Optional)</label> | |
| <textarea id="competitors" name="competitors" class="form-input textarea" | |
| placeholder="https://competitor1.com https://competitor2.com One URL per line"></textarea> | |
| </div> | |
| <button type="submit" class="generate-btn" id="generateBtn"> | |
| Generate SEO Report | |
| </button> | |
| <div class="error-message" id="errorMessage"></div> | |
| </form> | |
| </div> | |
| </div> | |
| <div class="loading-overlay" id="loadingOverlay"> | |
| <div class="loading-spinner"></div> | |
| <div class="loading-text" id="loadingText">Generating SEO report...</div> | |
| <div class="loading-subtext" id="loadingSubtext">This may take a few minutes</div> | |
| </div> | |
| <script> | |
| document.getElementById('seoForm').addEventListener('submit', async function (e) { | |
| e.preventDefault(); | |
| const url = document.getElementById('url').value.trim(); | |
| const competitors = document.getElementById('competitors').value | |
| .split('\n') | |
| .map(c => c.trim()) | |
| .filter(c => c); | |
| const loadingOverlay = document.getElementById('loadingOverlay'); | |
| const errorMessage = document.getElementById('errorMessage'); | |
| const loadingText = document.getElementById('loadingText'); | |
| const loadingSubtext = document.getElementById('loadingSubtext'); | |
| errorMessage.style.display = 'none'; | |
| loadingOverlay.style.display = 'flex'; | |
| const loadingMessages = [ | |
| { text: 'Analyzing technical SEO...', subtext: 'Checking PageSpeed insights' }, | |
| { text: 'Performing content audit...', subtext: 'Crawling website content' }, | |
| { text: 'Analyzing competitors...', subtext: 'Comparing performance metrics' }, | |
| { text: 'Generating professional report...', subtext: 'Creating charts and visualizations' } | |
| ]; | |
| let messageIndex = 0; | |
| const messageInterval = setInterval(() => { | |
| if (messageIndex < loadingMessages.length) { | |
| loadingText.textContent = loadingMessages[messageIndex].text; | |
| loadingSubtext.textContent = loadingMessages[messageIndex].subtext; | |
| messageIndex++; | |
| } | |
| }, 3000); | |
| try { | |
| const response = await fetch('/generate', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| url: url, | |
| competitors: competitors | |
| }) | |
| }); | |
| const data = await response.json(); | |
| clearInterval(messageInterval); | |
| loadingOverlay.style.display = 'none'; | |
| if (data.success) { | |
| window.location.href = data.redirect_url; | |
| } else { | |
| errorMessage.textContent = data.error; | |
| errorMessage.style.display = 'block'; | |
| } | |
| } catch (error) { | |
| clearInterval(messageInterval); | |
| loadingOverlay.style.display = 'none'; | |
| errorMessage.textContent = 'Network error. Please try again.'; | |
| errorMessage.style.display = 'block'; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |