fix: SEO + accessibility + consistency fixes (BUG-056,062,063,064,065,066,067,068)
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 11m8s

This commit is contained in:
OpenClaw Deployer 2026-02-19 08:39:56 +00:00
parent c6af7cd864
commit fb05989b3b
3 changed files with 28 additions and 19 deletions

View file

@ -304,6 +304,11 @@ async function checkout() {
}
document.addEventListener('DOMContentLoaded', function() {
// BUG-068: Open change email modal if navigated via #change-email hash
if (window.location.hash === '#change-email') {
openEmailChange();
}
document.getElementById('btn-signup').addEventListener('click', openSignup);
document.getElementById('btn-signup-2').addEventListener('click', openSignup);
document.getElementById('btn-checkout').addEventListener('click', checkout);

View file

@ -14,6 +14,7 @@
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="DocFast API Documentation">
<meta name="twitter:description" content="Convert HTML and Markdown to PDF with a simple REST API call.">
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<link rel="stylesheet" href="/swagger-ui/swagger-ui.css">
<style>

View file

@ -16,7 +16,7 @@
<meta name="twitter:image" content="https://docfast.dev/og-image.png">
<link rel="canonical" href="https://docfast.dev">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"SoftwareApplication","name":"DocFast","url":"https://docfast.dev","applicationCategory":"DeveloperApplication","operatingSystem":"Web","description":"Convert HTML and Markdown to beautiful PDFs with a simple API call. Fast, reliable, developer-friendly.","offers":[{"@type":"Offer","price":"0","priceCurrency":"EUR","name":"Free","description":"100 PDFs/month"},{"@type":"Offer","price":"9","priceCurrency":"EUR","name":"Pro","description":"5,000 PDFs per month","billingIncrement":"P1M"}]}
{"@context":"https://schema.org","@type":"SoftwareApplication","name":"DocFast","url":"https://docfast.dev","applicationCategory":"DeveloperApplication","operatingSystem":"Web","description":"Convert HTML and Markdown to beautiful PDFs with a simple API call. Fast, reliable, developer-friendly.","offers":[{"@type":"Offer","price":"0","priceCurrency":"EUR","name":"Free","description":"100 PDFs/month"},{"@type":"Offer","price":"9","priceCurrency":"EUR","name":"Pro","description":"5,000 PDFs/month","billingIncrement":"P1M"}]}
</script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
<style>
@ -113,7 +113,7 @@ section { position: relative; }
.eu-badge { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 32px; max-width: 600px; margin: 0 auto; display: flex; align-items: center; gap: 20px; transition: border-color 0.2s, transform 0.2s; }
.eu-badge:hover { border-color: rgba(52,211,153,0.3); transform: translateY(-2px); }
.eu-icon { font-size: 3rem; flex-shrink: 0; }
.eu-content h3 { font-size: 1.4rem; font-weight: 700; margin-bottom: 8px; color: var(--fg); }
.eu-content h2 { font-size: 1.4rem; font-weight: 700; margin-bottom: 8px; color: var(--fg); }
.eu-content p { color: var(--muted); font-size: 0.95rem; line-height: 1.6; margin: 0; }
@media (max-width: 640px) {
.eu-badge { flex-direction: column; text-align: center; gap: 16px; padding: 24px; }
@ -270,7 +270,7 @@ html, body {
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body>
<a href="#main" class="skip-link">Skip to content</a>
<a href="#main-content" class="skip-link">Skip to main content</a>
<nav aria-label="Main navigation">
<div class="container">
@ -283,7 +283,8 @@ html, body {
</div>
</nav>
<main class="hero" role="main" id="main">
<main role="main" id="main-content">
<section class="hero">
<div class="container">
<div class="badge">🚀 Simple PDF API for Developers</div>
<h1>HTML to <span class="gradient">PDF</span><br>in one API call</h1>
@ -309,7 +310,7 @@ html, body {
</div>
</div>
</div>
</main>
</section>
<section class="trust">
<div class="container">
@ -339,7 +340,7 @@ html, body {
<div class="eu-badge">
<div class="eu-icon">🇪🇺</div>
<div class="eu-content">
<h3>Hosted in the EU</h3>
<h2>Hosted in the EU</h2>
<p>Your data never leaves the EU • GDPR Compliant • Hetzner Germany (Nuremberg)</p>
</div>
</div>
@ -418,6 +419,8 @@ html, body {
</div>
</section>
</main>
<footer aria-label="Footer">
<div class="container">
<div class="footer-left">© 2026 DocFast. Fast PDF generation for developers.</div>
@ -434,15 +437,15 @@ html, body {
</footer>
<!-- Signup Modal -->
<div class="modal-overlay" id="signupModal" role="dialog" aria-label="Sign up for API key">
<div class="modal-overlay" id="signupModal" role="dialog" aria-modal="true" aria-label="Sign up for API key">
<div class="modal">
<button class="close" id="btn-close-signup">&times;</button>
<button class="close" id="btn-close-signup" aria-label="Close dialog">&times;</button>
<div id="signupInitial" class="active">
<h2>Get your free API key</h2>
<p>Enter your email to get started. No credit card required.</p>
<div class="signup-error" id="signupError"></div>
<input type="email" id="signupEmail" placeholder="your.email@example.com" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:16px;" required>
<input type="email" id="signupEmail" aria-label="Email address" placeholder="your.email@example.com" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:16px;" required>
<button class="btn btn-primary" style="width:100%" id="signupBtn">Generate API Key →</button>
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">100 free PDFs/month • All endpoints included<br><a href="#" class="open-recover" style="color:var(--muted)">Lost your API key? Recover it →</a></p>
</div>
@ -456,7 +459,7 @@ html, body {
<h2>Enter verification code</h2>
<p>We sent a 6-digit code to <strong id="verifyEmailDisplay"></strong></p>
<div class="signup-error" id="verifyError"></div>
<input type="text" id="verifyCode" placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" style="width:100%;padding:14px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:1.4rem;letter-spacing:0.3em;text-align:center;margin-bottom:16px;font-family:monospace;" required>
<input type="text" id="verifyCode" aria-label="Verification code" placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" style="width:100%;padding:14px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:1.4rem;letter-spacing:0.3em;text-align:center;margin-bottom:16px;font-family:monospace;" required>
<button class="btn btn-primary" style="width:100%" id="verifyBtn">Verify →</button>
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">Code expires in 15 minutes</p>
</div>
@ -478,15 +481,15 @@ html, body {
<!-- Recovery Modal -->
<div class="modal-overlay" id="recoverModal" role="dialog" aria-label="Recover API key">
<div class="modal-overlay" id="recoverModal" role="dialog" aria-modal="true" aria-label="Recover API key">
<div class="modal">
<button class="close" id="btn-close-recover">&times;</button>
<button class="close" id="btn-close-recover" aria-label="Close dialog">&times;</button>
<div id="recoverInitial" class="active">
<h2>Recover your API key</h2>
<p>Enter the email you signed up with. We'll send a verification code.</p>
<div class="signup-error" id="recoverError"></div>
<input type="email" id="recoverEmailInput" placeholder="your.email@example.com" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:16px;" required>
<input type="email" id="recoverEmailInput" aria-label="Email address" placeholder="your.email@example.com" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:16px;" required>
<button class="btn btn-primary" style="width:100%" id="recoverBtn">Send Verification Code →</button>
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">Your key will be shown here after verification — never sent via email</p>
</div>
@ -500,7 +503,7 @@ html, body {
<h2>Enter verification code</h2>
<p>We sent a 6-digit code to <strong id="recoverEmailDisplay"></strong></p>
<div class="signup-error" id="recoverVerifyError"></div>
<input type="text" id="recoverCode" placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" style="width:100%;padding:14px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:1.4rem;letter-spacing:0.3em;text-align:center;margin-bottom:16px;font-family:monospace;" required>
<input type="text" id="recoverCode" aria-label="Verification code" placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" style="width:100%;padding:14px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:1.4rem;letter-spacing:0.3em;text-align:center;margin-bottom:16px;font-family:monospace;" required>
<button class="btn btn-primary" style="width:100%" id="recoverVerifyBtn">Verify →</button>
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">Code expires in 15 minutes</p>
</div>
@ -522,16 +525,16 @@ html, body {
<!-- Email Change Modal -->
<div class="modal-overlay" id="emailChangeModal" role="dialog" aria-label="Change email">
<div class="modal-overlay" id="emailChangeModal" role="dialog" aria-modal="true" aria-label="Change email">
<div class="modal">
<button class="close" id="btn-close-email-change">&times;</button>
<button class="close" id="btn-close-email-change" aria-label="Close dialog">&times;</button>
<div id="emailChangeInitial" class="active">
<h2>Change your email</h2>
<p>Enter your API key and new email address.</p>
<div class="signup-error" id="emailChangeError"></div>
<input type="text" id="emailChangeApiKey" placeholder="Your API key (df_free_... or df_pro_...)" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:12px;font-family:monospace;" required>
<input type="email" id="emailChangeNewEmail" placeholder="new.email@example.com" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:16px;" required>
<input type="text" id="emailChangeApiKey" aria-label="API key" placeholder="Your API key (df_free_... or df_pro_...)" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:12px;font-family:monospace;" required>
<input type="email" id="emailChangeNewEmail" aria-label="New email address" placeholder="new.email@example.com" style="width:100%;padding:12px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:0.9rem;margin-bottom:16px;" required>
<button class="btn btn-primary" style="width:100%" id="emailChangeBtn">Send Verification Code →</button>
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">A verification code will be sent to your new email</p>
</div>
@ -545,7 +548,7 @@ html, body {
<h2>Enter verification code</h2>
<p>We sent a 6-digit code to <strong id="emailChangeEmailDisplay"></strong></p>
<div class="signup-error" id="emailChangeVerifyError"></div>
<input type="text" id="emailChangeCode" placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" style="width:100%;padding:14px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:1.4rem;letter-spacing:0.3em;text-align:center;margin-bottom:16px;font-family:monospace;" required>
<input type="text" id="emailChangeCode" aria-label="Verification code" placeholder="123456" maxlength="6" pattern="[0-9]{6}" inputmode="numeric" style="width:100%;padding:14px;border:1px solid var(--border);background:var(--bg);color:var(--fg);border-radius:8px;font-size:1.4rem;letter-spacing:0.3em;text-align:center;margin-bottom:16px;font-family:monospace;" required>
<button class="btn btn-primary" style="width:100%" id="emailChangeVerifyBtn">Verify →</button>
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">Code expires in 15 minutes</p>
</div>