SEO & accessibility: OG tags, robots.txt, sitemap, OG image, aria labels, focus trap, keyboard nav
Some checks failed
Deploy to Production / Deploy to Server (push) Has been cancelled

This commit is contained in:
OpenClaw 2026-02-16 08:27:25 +00:00
parent ed273430c7
commit 4833edf44c
6 changed files with 88 additions and 16 deletions

View file

@ -477,3 +477,39 @@ document.addEventListener('DOMContentLoaded', function() {
el.addEventListener('click', function(e) { e.preventDefault(); openEmailChange(); });
});
});
// === Accessibility: Escape key closes modals, focus trapping ===
(function() {
function getActiveModal() {
var modals = ['signupModal', 'recoverModal', 'emailChangeModal'];
for (var i = 0; i < modals.length; i++) {
var m = document.getElementById(modals[i]);
if (m && m.classList.contains('active')) return m;
}
return null;
}
function closeActiveModal() {
var m = getActiveModal();
if (!m) return;
m.classList.remove('active');
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeActiveModal();
// Focus trap inside active modal
if (e.key === 'Tab') {
var modal = getActiveModal();
if (!modal) return;
var focusable = modal.querySelectorAll('button:not([disabled]), input:not([disabled]), a[href], [tabindex]:not([tabindex="-1"])');
if (focusable.length === 0) return;
var first = focusable[0], last = focusable[focusable.length - 1];
if (e.shiftKey) {
if (document.activeElement === first) { e.preventDefault(); last.focus(); }
} else {
if (document.activeElement === last) { e.preventDefault(); first.focus(); }
}
}
});
})();

View file

@ -5,6 +5,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DocFast — HTML & Markdown to PDF API</title>
<meta name="description" content="Convert HTML and Markdown to beautiful PDFs with a simple API call. Built-in invoice templates. Fast, reliable, developer-friendly.">
<meta property="og:title" content="DocFast — HTML & Markdown to PDF API">
<meta property="og:description" content="Convert HTML and Markdown to beautiful PDFs with a simple API call. Fast, reliable, developer-friendly.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://docfast.dev">
<meta property="og:image" content="https://docfast.dev/og-image.png">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="DocFast — HTML & Markdown to PDF API">
<meta name="twitter:description" content="Convert HTML and Markdown to beautiful PDFs with a simple API call.">
<link rel="canonical" href="https://docfast.dev">
<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>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
@ -231,6 +240,9 @@ html, body {
#emailChangeLoading.active { display: flex; flex-direction: column; align-items: center; padding: 40px 0; text-align: center; }
#emailChangeResult.active { display: block; }
#emailChangeVerify.active { display: block; }
/* Focus-visible for accessibility */
.btn:focus-visible, a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@ -238,7 +250,7 @@ html, body {
</head>
<body>
<nav>
<nav aria-label="Main navigation">
<div class="container">
<div class="logo">⚡ Doc<span>Fast</span></div>
<div class="nav-links">
@ -249,7 +261,7 @@ html, body {
</div>
</nav>
<section class="hero">
<main class="hero" role="main">
<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>
@ -262,7 +274,7 @@ html, body {
<div class="code-section">
<div class="code-header">
<div class="code-dots"><span></span><span></span><span></span></div>
<div class="code-dots" aria-hidden="true"><span></span><span></span><span></span></div>
<span class="code-label">terminal</span>
</div>
<div class="code-block">
@ -275,7 +287,7 @@ html, body {
</div>
</div>
</div>
</section>
</main>
<section class="trust">
<div class="container">
@ -306,32 +318,32 @@ html, body {
<p class="section-sub">A complete PDF generation API. No SDKs, no dependencies, no setup.</p>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon"></div>
<div class="feature-icon" aria-hidden="true"></div>
<h3>Sub-second Speed</h3>
<p>Persistent browser pool — no cold starts. Your PDFs are ready before your spinner shows.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎨</div>
<div class="feature-icon" aria-hidden="true">🎨</div>
<h3>Pixel-perfect Output</h3>
<p>Full CSS support including flexbox, grid, and custom fonts. Your brand, your PDFs.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📄</div>
<div class="feature-icon" aria-hidden="true">📄</div>
<h3>Built-in Templates</h3>
<p>Invoice and receipt templates out of the box. Pass JSON data, get beautiful PDFs.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔧</div>
<div class="feature-icon" aria-hidden="true">🔧</div>
<h3>Dead-simple API</h3>
<p>REST API. JSON in, PDF out. Works with curl, Python, Node, Go — anything with HTTP.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📐</div>
<div class="feature-icon" aria-hidden="true">📐</div>
<h3>Fully Configurable</h3>
<p>A4, Letter, custom sizes. Portrait or landscape. Headers, footers, and margins.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔒</div>
<div class="feature-icon" aria-hidden="true">🔒</div>
<h3>Secure by Default</h3>
<p>HTTPS only. Rate limiting. No data stored. PDFs stream directly — nothing touches disk.</p>
</div>
@ -372,7 +384,7 @@ html, body {
</div>
</section>
<footer>
<footer aria-label="Footer">
<div class="container">
<div class="footer-left">© 2026 DocFast. Fast PDF generation for developers.</div>
<div class="footer-links">
@ -384,7 +396,7 @@ html, body {
</footer>
<!-- Signup Modal -->
<div class="modal-overlay" id="signupModal">
<div class="modal-overlay" id="signupModal" role="dialog" aria-label="Sign up for API key">
<div class="modal">
<button class="close" id="btn-close-signup">&times;</button>
@ -411,7 +423,7 @@ html, body {
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">Code expires in 15 minutes</p>
</div>
<div id="signupResult">
<div id="signupResult" aria-live="polite">
<h2>🚀 Your API key is ready!</h2>
<div class="warning-box">
<span class="icon">⚠️</span>
@ -428,7 +440,7 @@ html, body {
<!-- Recovery Modal -->
<div class="modal-overlay" id="recoverModal">
<div class="modal-overlay" id="recoverModal" role="dialog" aria-label="Recover API key">
<div class="modal">
<button class="close" id="btn-close-recover">&times;</button>
@ -455,7 +467,7 @@ html, body {
<p style="margin-top:16px;color:var(--muted);font-size:0.8rem;text-align:center;">Code expires in 15 minutes</p>
</div>
<div id="recoverResult">
<div id="recoverResult" aria-live="polite">
<h2>🔑 Your API key</h2>
<div class="warning-box">
<span class="icon">⚠️</span>
@ -472,7 +484,7 @@ html, body {
<!-- Email Change Modal -->
<div class="modal-overlay" id="emailChangeModal">
<div class="modal-overlay" id="emailChangeModal" role="dialog" aria-label="Change email">
<div class="modal">
<button class="close" id="btn-close-email-change">&times;</button>

BIN
public/og-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

13
public/og-image.svg Normal file
View file

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
<rect width="1200" height="630" fill="#0b0d11"/>
<rect x="0" y="0" width="1200" height="630" fill="url(#glow)" opacity="0.3"/>
<defs>
<radialGradient id="glow" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#34d399" stop-opacity="0.2"/>
<stop offset="100%" stop-color="#0b0d11" stop-opacity="0"/>
</radialGradient>
</defs>
<text x="600" y="270" text-anchor="middle" font-family="Inter, -apple-system, sans-serif" font-size="80" font-weight="800" fill="#e4e7ed">⚡ Doc<tspan fill="#34d399">Fast</tspan></text>
<text x="600" y="370" text-anchor="middle" font-family="Inter, -apple-system, sans-serif" font-size="36" font-weight="400" fill="#7a8194">HTML &amp; Markdown to PDF API</text>
<rect x="400" y="420" width="400" height="4" rx="2" fill="#34d399" opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 910 B

6
public/robots.txt Normal file
View file

@ -0,0 +1,6 @@
User-agent: *
Allow: /
Disallow: /v1/
Disallow: /api
Disallow: /health
Sitemap: https://docfast.dev/sitemap.xml

5
public/sitemap.xml Normal file
View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemapns.org/schemas/sitemap/0.9">
<url><loc>https://docfast.dev/</loc><changefreq>weekly</changefreq><priority>1.0</priority></url>
<url><loc>https://docfast.dev/docs</loc><changefreq>weekly</changefreq><priority>0.8</priority></url>
</urlset>