fix: privacy 404 + enhanced playground controls
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 9m7s

BUG-010: Add 301 redirects for clean URLs (/privacy → /privacy.html etc.)
and fix inconsistent href links across legal pages.

FEATURE: Enhanced playground with fullPage, quality, deviceScale,
waitUntil, and waitForSelector controls for better API evaluation.
This commit is contained in:
SnapAPI Agent 2026-02-22 08:52:32 +00:00
parent d20fbbfe2e
commit db1fa8d506
6 changed files with 79 additions and 22 deletions

View file

@ -162,9 +162,9 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
</div>
<div class="footer-col">
<h5>Legal</h5>
<a href="/impressum">Impressum</a>
<a href="/privacy">Privacy Policy</a>
<a href="/terms">Terms of Service</a>
<a href="/impressum.html">Impressum</a>
<a href="/privacy.html">Privacy Policy</a>
<a href="/terms.html">Terms of Service</a>
</div>
</div>
<div class="footer-bottom">

View file

@ -302,13 +302,19 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
<label>URL to capture</label>
<input type="url" id="pg-url" value="https://example.com" placeholder="https://example.com">
</div>
<div>
<label>Format</label>
<select id="pg-format">
<option value="png">PNG</option>
<option value="jpeg">JPEG</option>
<option value="webp">WebP</option>
</select>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div>
<label>Format</label>
<select id="pg-format">
<option value="png">PNG</option>
<option value="jpeg">JPEG</option>
<option value="webp">WebP</option>
</select>
</div>
<div>
<label>Quality</label>
<input type="number" id="pg-quality" value="80" min="1" max="100" title="JPEG/WebP quality (1-100). Ignored for PNG.">
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div>
@ -320,6 +326,34 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
<input type="number" id="pg-height" value="800" min="200" max="1080">
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div>
<label>Device Scale</label>
<select id="pg-scale">
<option value="1">1x</option>
<option value="2">2x (Retina)</option>
<option value="3">3x</option>
</select>
</div>
<div>
<label>Wait Until</label>
<select id="pg-waituntil">
<option value="domcontentloaded">DOM Ready</option>
<option value="load">Page Load</option>
<option value="networkidle0">Network Idle</option>
<option value="networkidle2">Network Idle 2</option>
</select>
</div>
</div>
<div>
<label style="display:flex;align-items:center;gap:8px;cursor:pointer;text-transform:none;letter-spacing:0;font-size:.9rem">
<input type="checkbox" id="pg-fullpage" style="width:auto;padding:0;accent-color:var(--primary)"> Capture full page
</label>
</div>
<div>
<label>Wait for Selector <span style="font-weight:400;text-transform:none;letter-spacing:0">(optional)</span></label>
<input type="text" id="pg-selector" placeholder="#content, .loaded, img" title="CSS selector to wait for before capturing">
</div>
<button class="btn btn-primary" onclick="runPlayground()" id="pg-btn" style="margin-top:auto">
Take Screenshot →
</button>
@ -632,8 +666,13 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
async function runPlayground(){
var url=document.getElementById('pg-url').value;
var format=document.getElementById('pg-format').value;
var quality=parseInt(document.getElementById('pg-quality').value)||80;
var width=parseInt(document.getElementById('pg-width').value)||1280;
var height=parseInt(document.getElementById('pg-height').value)||800;
var fullPage=document.getElementById('pg-fullpage').checked;
var deviceScale=parseInt(document.getElementById('pg-scale').value)||1;
var waitUntil=document.getElementById('pg-waituntil').value;
var waitForSelector=document.getElementById('pg-selector').value.trim()||undefined;
if(!url){alert('Please enter a URL');return}
var btn=document.getElementById('pg-btn');
@ -646,11 +685,14 @@ async function runPlayground(){
placeholder.style.display='none';result.style.display='none';error.style.display='none';
loading.style.display='flex';
var body={url:url,format:format,width:width,height:height,fullPage:fullPage,quality:quality,deviceScale:deviceScale,waitUntil:waitUntil};
if(waitForSelector)body.waitForSelector=waitForSelector;
try{
var r=await fetch('/v1/playground',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({url:url,format:format,width:width,height:height})
body:JSON.stringify(body)
});
if(!r.ok){var d=await r.json().catch(function(){return{}});throw new Error(d.error||'HTTP '+r.status)}
var blob=await r.blob();

View file

@ -298,9 +298,9 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
</div>
<div class="footer-col">
<h5>Legal</h5>
<a href="/impressum">Impressum</a>
<a href="/privacy">Privacy Policy</a>
<a href="/terms">Terms of Service</a>
<a href="/impressum.html">Impressum</a>
<a href="/privacy.html">Privacy Policy</a>
<a href="/terms.html">Terms of Service</a>
</div>
</div>
<div class="footer-bottom">

View file

@ -236,7 +236,7 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
<h2>6. Data & Privacy</h2>
<ul>
<li>Your privacy is governed by our <a href="/privacy">Privacy Policy</a></li>
<li>Your privacy is governed by our <a href="/privacy.html">Privacy Policy</a></li>
<li>All data processing occurs within the European Union</li>
<li>Screenshots are generated and returned immediately (not stored)</li>
<li>API usage logs retained for billing and security purposes</li>
@ -379,9 +379,9 @@ footer{border-top:1px solid var(--border);padding:48px 24px 32px;background:var(
</div>
<div class="footer-col">
<h5>Legal</h5>
<a href="/impressum">Impressum</a>
<a href="/privacy">Privacy Policy</a>
<a href="/terms">Terms of Service</a>
<a href="/impressum.html">Impressum</a>
<a href="/privacy.html">Privacy Policy</a>
<a href="/terms.html">Terms of Service</a>
</div>
</div>
<div class="footer-bottom">