From dabf3c1004b3a72fd7daf2b320dbce593f12d825 Mon Sep 17 00:00:00 2001 From: DocFast CEO Date: Fri, 20 Feb 2026 09:32:25 +0000 Subject: [PATCH] Redesign playground: template tabs, live preview, split pane, mobile responsive - Add 3 pre-built templates (Invoice, Report, Custom HTML) - Split-pane editor with live HTML preview (updates as you type) - Generation timer shows actual response time - Before/after comparison (free watermarked vs Pro clean) - Pro CTA integrated into result panel - Fully responsive: stacks on mobile - Professional polish matching site design language --- public/app.js | 62 ++++- public/app.min.js | 2 +- public/docs.html | 1 - public/index.html | 241 ++++++++++++------- public/src/index.html | 464 ++++++++++++++++++++++++++++++++++--- templates/pages/index.html | 130 ++++++++++- 6 files changed, 762 insertions(+), 138 deletions(-) diff --git a/public/app.js b/public/app.js index aa1806e..f613f65 100644 --- a/public/app.js +++ b/public/app.js @@ -173,6 +173,35 @@ async function checkout() { } // === Demo Playground === +var pgTemplates = { + invoice: '\n\n\n\n\n
\n
\n
Acme Corp
\n
123 Business Ave, Suite 100
San Francisco, CA 94102
\n
\n
\n
Invoice
\n
#INV-2024-0042
\n
Feb 20, 2026
\n
\n
\n
\n
Bill To
Jane Smith
456 Client Road
New York, NY 10001
\n
Payment Due
March 20, 2026
Payment Method
Bank Transfer
\n
\n \n \n \n \n \n \n \n \n
DescriptionQtyRateAmount
Web Development — Landing Page40 hrs$150$6,000
UI/UX Design — Mockups16 hrs$125$2,000
API Integration & Testing24 hrs$150$3,600
Total$11,600
\n \n\n', + report: '\n\n\n\n\n

Q4 2025 Performance Report

\n
Prepared by Analytics Team — February 2026
\n
\n
142%
Revenue Growth
\n
2.4M
API Calls
\n
99.9%
Uptime
\n
\n

Executive Summary

\n

Q4 saw exceptional growth across all key metrics. Customer acquisition increased by 85% while churn decreased to an all-time low of 1.2%. Our expansion into the EU market contributed significantly to revenue gains.

\n
\n

🎯 Key Achievement

\n

Crossed 10,000 active users milestone in December, two months ahead of target. Enterprise segment grew 200% QoQ.

\n
\n

Product Updates

\n

Launched 3 major features: batch processing, webhook notifications, and custom templates. Template engine adoption reached 40% of Pro users within the first month.

\n

Outlook

\n

Q1 2026 focus areas include Markdown-to-PDF improvements, enhanced template library, and SOC 2 certification to unlock enterprise sales pipeline.

\n\n', + custom: '\n\n\n\n\n

Hello World!

\n

Edit this HTML and watch the preview update in real time.

\n

Then click Generate PDF to download it.

\n\n' +}; + +var previewDebounce = null; +function updatePreview() { + var iframe = document.getElementById('demoPreview'); + var html = document.getElementById('demoHtml').value; + if (!iframe) return; + var doc = iframe.contentDocument || iframe.contentWindow.document; + doc.open(); + doc.write(html); + doc.close(); +} + +function setTemplate(name) { + var ta = document.getElementById('demoHtml'); + ta.value = pgTemplates[name] || pgTemplates.custom; + updatePreview(); + // Update active tab + document.querySelectorAll('.pg-tab').forEach(function(t) { + var isActive = t.getAttribute('data-template') === name; + t.classList.toggle('active', isActive); + t.setAttribute('aria-selected', isActive ? 'true' : 'false'); + }); +} + async function generateDemo() { var btn = document.getElementById('demoGenerateBtn'); var status = document.getElementById('demoStatus'); @@ -183,14 +212,16 @@ async function generateDemo() { if (!html) { errorEl.textContent = 'Please enter some HTML.'; errorEl.style.display = 'block'; - result.style.display = 'none'; + result.classList.remove('visible'); return; } errorEl.style.display = 'none'; - result.style.display = 'none'; + result.classList.remove('visible'); btn.disabled = true; - status.textContent = 'Generating PDF…'; + btn.classList.add('pg-generating'); + status.textContent = 'Generating…'; + var startTime = performance.now(); try { var res = await fetch('/v1/demo/html', { @@ -204,21 +235,25 @@ async function generateDemo() { errorEl.textContent = data.error || 'Something went wrong.'; errorEl.style.display = 'block'; btn.disabled = false; + btn.classList.remove('pg-generating'); status.textContent = ''; return; } + var elapsed = ((performance.now() - startTime) / 1000).toFixed(1); var blob = await res.blob(); var url = URL.createObjectURL(blob); - var dl = document.getElementById('demoDownload'); - dl.href = url; - result.style.display = 'block'; + document.getElementById('demoDownload').href = url; + document.getElementById('demoTime').textContent = elapsed; + result.classList.add('visible'); status.textContent = ''; btn.disabled = false; + btn.classList.remove('pg-generating'); } catch (err) { errorEl.textContent = 'Network error. Please try again.'; errorEl.style.display = 'block'; btn.disabled = false; + btn.classList.remove('pg-generating'); status.textContent = ''; } } @@ -233,6 +268,21 @@ document.addEventListener('DOMContentLoaded', function() { // Demo playground document.getElementById('demoGenerateBtn').addEventListener('click', generateDemo); + // Playground tabs + document.querySelectorAll('.pg-tab').forEach(function(tab) { + tab.addEventListener('click', function() { setTemplate(this.getAttribute('data-template')); }); + }); + // Init with invoice template + setTemplate('invoice'); + // Live preview on input + document.getElementById('demoHtml').addEventListener('input', function() { + clearTimeout(previewDebounce); + previewDebounce = setTimeout(updatePreview, 150); + }); + // Playground checkout button + var pgCheckout = document.getElementById('btn-checkout-playground'); + if (pgCheckout) pgCheckout.addEventListener('click', checkout); + // Checkout buttons document.getElementById('btn-checkout').addEventListener('click', checkout); var heroCheckout = document.getElementById('btn-checkout-hero'); diff --git a/public/app.min.js b/public/app.min.js index 904a38d..c5006e6 100644 --- a/public/app.min.js +++ b/public/app.min.js @@ -1 +1 @@ -var recoverEmail="";function showRecoverState(e){["recoverInitial","recoverLoading","recoverVerify","recoverResult"].forEach(function(e){var t=document.getElementById(e);t&&t.classList.remove("active")}),document.getElementById(e).classList.add("active")}function openRecover(){document.getElementById("recoverModal").classList.add("active"),showRecoverState("recoverInitial");var e=document.getElementById("recoverError");e&&(e.style.display="none");var t=document.getElementById("recoverVerifyError");t&&(t.style.display="none"),document.getElementById("recoverEmailInput").value="",document.getElementById("recoverCode").value="",recoverEmail="",setTimeout(function(){document.getElementById("recoverEmailInput").focus()},100)}function closeRecover(){document.getElementById("recoverModal").classList.remove("active")}async function submitRecover(){var e=document.getElementById("recoverError"),t=document.getElementById("recoverBtn"),n=document.getElementById("recoverEmailInput").value.trim();if(!n||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(n))return e.textContent="Please enter a valid email address.",void(e.style.display="block");e.style.display="none",t.disabled=!0,showRecoverState("recoverLoading");try{var a=await fetch("/v1/recover",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:n})}),o=await a.json();if(!a.ok)return showRecoverState("recoverInitial"),e.textContent=o.error||"Something went wrong.",e.style.display="block",void(t.disabled=!1);recoverEmail=n,document.getElementById("recoverEmailDisplay").textContent=n,showRecoverState("recoverVerify"),document.getElementById("recoverCode").focus(),t.disabled=!1}catch(n){showRecoverState("recoverInitial"),e.textContent="Network error. Please try again.",e.style.display="block",t.disabled=!1}}async function submitRecoverVerify(){var e=document.getElementById("recoverVerifyError"),t=document.getElementById("recoverVerifyBtn"),n=document.getElementById("recoverCode").value.trim();if(!n||!/^\d{6}$/.test(n))return e.textContent="Please enter a 6-digit code.",void(e.style.display="block");e.style.display="none",t.disabled=!0;try{var a=await fetch("/v1/recover/verify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:recoverEmail,code:n})}),o=await a.json();if(!a.ok)return e.textContent=o.error||"Verification failed.",e.style.display="block",void(t.disabled=!1);if(o.apiKey){document.getElementById("recoveredKeyText").textContent=o.apiKey,showRecoverState("recoverResult");var i=document.querySelector("#recoverResult h2");i&&(i.setAttribute("tabindex","-1"),i.focus())}else e.textContent=o.message||"No key found for this email.",e.style.display="block",t.disabled=!1}catch(n){e.textContent="Network error. Please try again.",e.style.display="block",t.disabled=!1}}function copyRecoveredKey(){doCopy(document.getElementById("recoveredKeyText").textContent,document.getElementById("copyRecoveredBtn"))}function doCopy(e,t){function n(){t.textContent="✓ Copied!",setTimeout(function(){t.textContent="Copy"},2e3)}function a(){t.textContent="Failed",setTimeout(function(){t.textContent="Copy"},2e3)}try{navigator.clipboard&&window.isSecureContext?navigator.clipboard.writeText(e).then(n).catch(function(){fallbackCopy(e,n,a)}):fallbackCopy(e,n,a)}catch(e){a()}}function fallbackCopy(e,t,n){try{var a=document.createElement("textarea");a.value=e,a.style.position="fixed",a.style.opacity="0",a.style.top="-9999px",document.body.appendChild(a),a.focus(),a.select();var o=document.execCommand("copy");document.body.removeChild(a),o?t():n()}catch(e){n()}}async function checkout(){try{var e=await fetch("/v1/billing/checkout",{method:"POST"}),t=await e.json();t.url?window.location.href=t.url:alert("Checkout is not available yet. Please try again later.")}catch(e){alert("Something went wrong. Please try again.")}}async function generateDemo(){var e=document.getElementById("demoGenerateBtn"),t=document.getElementById("demoStatus"),n=document.getElementById("demoResult"),a=document.getElementById("demoError"),o=document.getElementById("demoHtml").value.trim();if(!o)return a.textContent="Please enter some HTML.",a.style.display="block",void(n.style.display="none");a.style.display="none",n.style.display="none",e.disabled=!0,t.textContent="Generating PDF…";try{var i=await fetch("/v1/demo/html",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({html:o})});if(!i.ok){var l=await i.json();return a.textContent=l.error||"Something went wrong.",a.style.display="block",e.disabled=!1,void(t.textContent="")}var r=await i.blob(),c=URL.createObjectURL(r);document.getElementById("demoDownload").href=c,n.style.display="block",t.textContent="",e.disabled=!1}catch(n){a.textContent="Network error. Please try again.",a.style.display="block",e.disabled=!1,t.textContent=""}}document.addEventListener("DOMContentLoaded",function(){"#change-email"===window.location.hash&&openEmailChange(),document.getElementById("demoGenerateBtn").addEventListener("click",generateDemo),document.getElementById("btn-checkout").addEventListener("click",checkout);var e=document.getElementById("btn-checkout-hero");e&&e.addEventListener("click",checkout),document.getElementById("btn-close-recover").addEventListener("click",closeRecover),document.getElementById("recoverBtn").addEventListener("click",submitRecover),document.getElementById("recoverVerifyBtn").addEventListener("click",submitRecoverVerify),document.getElementById("copyRecoveredBtn").addEventListener("click",copyRecoveredKey),document.getElementById("recoverModal").addEventListener("click",function(e){e.target===this&&closeRecover()}),document.querySelectorAll(".open-recover").forEach(function(e){e.addEventListener("click",function(e){e.preventDefault(),openRecover()})}),document.querySelectorAll('a[href^="#"]').forEach(function(e){e.addEventListener("click",function(e){var t=this.getAttribute("href");if("#"!==t){e.preventDefault();var n=document.querySelector(t);n&&n.scrollIntoView({behavior:"smooth"})}})})});var emailChangeApiKey="",emailChangeNewEmail="";function showEmailChangeState(e){["emailChangeInitial","emailChangeLoading","emailChangeVerify","emailChangeResult"].forEach(function(e){var t=document.getElementById(e);t&&t.classList.remove("active")}),document.getElementById(e).classList.add("active")}function openEmailChange(){closeRecover(),document.getElementById("emailChangeModal").classList.add("active"),showEmailChangeState("emailChangeInitial");var e=document.getElementById("emailChangeError");e&&(e.style.display="none");var t=document.getElementById("emailChangeVerifyError");t&&(t.style.display="none"),document.getElementById("emailChangeApiKey").value="",document.getElementById("emailChangeNewEmail").value="",document.getElementById("emailChangeCode").value="",emailChangeApiKey="",emailChangeNewEmail=""}function closeEmailChange(){document.getElementById("emailChangeModal").classList.remove("active")}async function submitEmailChange(){var e=document.getElementById("emailChangeError"),t=document.getElementById("emailChangeBtn"),n=document.getElementById("emailChangeApiKey").value.trim(),a=document.getElementById("emailChangeNewEmail").value.trim();if(!n)return e.textContent="Please enter your API key.",void(e.style.display="block");if(!a||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a))return e.textContent="Please enter a valid email address.",void(e.style.display="block");e.style.display="none",t.disabled=!0,showEmailChangeState("emailChangeLoading");try{var o=await fetch("/v1/email-change",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:n,newEmail:a})}),i=await o.json();if(!o.ok)return showEmailChangeState("emailChangeInitial"),e.textContent=i.error||"Something went wrong.",e.style.display="block",void(t.disabled=!1);emailChangeApiKey=n,emailChangeNewEmail=a,document.getElementById("emailChangeEmailDisplay").textContent=a,showEmailChangeState("emailChangeVerify"),document.getElementById("emailChangeCode").focus(),t.disabled=!1}catch(n){showEmailChangeState("emailChangeInitial"),e.textContent="Network error. Please try again.",e.style.display="block",t.disabled=!1}}async function submitEmailChangeVerify(){var e=document.getElementById("emailChangeVerifyError"),t=document.getElementById("emailChangeVerifyBtn"),n=document.getElementById("emailChangeCode").value.trim();if(!n||!/^\d{6}$/.test(n))return e.textContent="Please enter a 6-digit code.",void(e.style.display="block");e.style.display="none",t.disabled=!0;try{var a=await fetch("/v1/email-change/verify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:emailChangeApiKey,newEmail:emailChangeNewEmail,code:n})}),o=await a.json();if(!a.ok)return e.textContent=o.error||"Verification failed.",e.style.display="block",void(t.disabled=!1);document.getElementById("emailChangeNewDisplay").textContent=o.newEmail||emailChangeNewEmail,showEmailChangeState("emailChangeResult");var i=document.querySelector("#emailChangeResult h2");i&&(i.setAttribute("tabindex","-1"),i.focus())}catch(n){e.textContent="Network error. Please try again.",e.style.display="block",t.disabled=!1}}document.addEventListener("DOMContentLoaded",function(){var e=document.getElementById("btn-close-email-change");e&&e.addEventListener("click",closeEmailChange);var t=document.getElementById("emailChangeBtn");t&&t.addEventListener("click",submitEmailChange);var n=document.getElementById("emailChangeVerifyBtn");n&&n.addEventListener("click",submitEmailChangeVerify);var a=document.getElementById("emailChangeModal");a&&a.addEventListener("click",function(e){e.target===this&&closeEmailChange()}),document.querySelectorAll(".open-email-change").forEach(function(e){e.addEventListener("click",function(e){e.preventDefault(),openEmailChange()})})}),function(){function e(){for(var e=["recoverModal","emailChangeModal"],t=0;t\n\n\n\n\n
\n
\n
Acme Corp
\n
123 Business Ave, Suite 100
San Francisco, CA 94102
\n
\n
\n
Invoice
\n
#INV-2024-0042
\n
Feb 20, 2026
\n
\n
\n
\n
Bill To
Jane Smith
456 Client Road
New York, NY 10001
\n
Payment Due
March 20, 2026
Payment Method
Bank Transfer
\n
\n \n \n \n \n \n \n \n \n
DescriptionQtyRateAmount
Web Development — Landing Page40 hrs$150$6,000
UI/UX Design — Mockups16 hrs$125$2,000
API Integration & Testing24 hrs$150$3,600
Total$11,600
\n \n\n',report:'\n\n\n\n\n

Q4 2025 Performance Report

\n
Prepared by Analytics Team — February 2026
\n
\n
142%
Revenue Growth
\n
2.4M
API Calls
\n
99.9%
Uptime
\n
\n

Executive Summary

\n

Q4 saw exceptional growth across all key metrics. Customer acquisition increased by 85% while churn decreased to an all-time low of 1.2%. Our expansion into the EU market contributed significantly to revenue gains.

\n
\n

🎯 Key Achievement

\n

Crossed 10,000 active users milestone in December, two months ahead of target. Enterprise segment grew 200% QoQ.

\n
\n

Product Updates

\n

Launched 3 major features: batch processing, webhook notifications, and custom templates. Template engine adoption reached 40% of Pro users within the first month.

\n

Outlook

\n

Q1 2026 focus areas include Markdown-to-PDF improvements, enhanced template library, and SOC 2 certification to unlock enterprise sales pipeline.

\n\n',custom:"\n\n\n\n\n

Hello World!

\n

Edit this HTML and watch the preview update in real time.

\n

Then click Generate PDF to download it.

\n\n"},previewDebounce=null;function updatePreview(){var e=document.getElementById("demoPreview"),t=document.getElementById("demoHtml").value;if(e){var n=e.contentDocument||e.contentWindow.document;n.open(),n.write(t),n.close()}}function setTemplate(e){document.getElementById("demoHtml").value=pgTemplates[e]||pgTemplates.custom,updatePreview(),document.querySelectorAll(".pg-tab").forEach(function(t){var n=t.getAttribute("data-template")===e;t.classList.toggle("active",n),t.setAttribute("aria-selected",n?"true":"false")})}async function generateDemo(){var e=document.getElementById("demoGenerateBtn"),t=document.getElementById("demoStatus"),n=document.getElementById("demoResult"),a=document.getElementById("demoError"),o=document.getElementById("demoHtml").value.trim();if(!o)return a.textContent="Please enter some HTML.",a.style.display="block",void n.classList.remove("visible");a.style.display="none",n.classList.remove("visible"),e.disabled=!0,e.classList.add("pg-generating"),t.textContent="Generating…";var i=performance.now();try{var r=await fetch("/v1/demo/html",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({html:o})});if(!r.ok){var l=await r.json();return a.textContent=l.error||"Something went wrong.",a.style.display="block",e.disabled=!1,e.classList.remove("pg-generating"),void(t.textContent="")}var d=((performance.now()-i)/1e3).toFixed(1),c=await r.blob(),s=URL.createObjectURL(c);document.getElementById("demoDownload").href=s,document.getElementById("demoTime").textContent=d,n.classList.add("visible"),t.textContent="",e.disabled=!1,e.classList.remove("pg-generating")}catch(n){a.textContent="Network error. Please try again.",a.style.display="block",e.disabled=!1,e.classList.remove("pg-generating"),t.textContent=""}}document.addEventListener("DOMContentLoaded",function(){"#change-email"===window.location.hash&&openEmailChange(),document.getElementById("demoGenerateBtn").addEventListener("click",generateDemo),document.querySelectorAll(".pg-tab").forEach(function(e){e.addEventListener("click",function(){setTemplate(this.getAttribute("data-template"))})}),setTemplate("invoice"),document.getElementById("demoHtml").addEventListener("input",function(){clearTimeout(previewDebounce),previewDebounce=setTimeout(updatePreview,150)});var e=document.getElementById("btn-checkout-playground");e&&e.addEventListener("click",checkout),document.getElementById("btn-checkout").addEventListener("click",checkout);var t=document.getElementById("btn-checkout-hero");t&&t.addEventListener("click",checkout),document.getElementById("btn-close-recover").addEventListener("click",closeRecover),document.getElementById("recoverBtn").addEventListener("click",submitRecover),document.getElementById("recoverVerifyBtn").addEventListener("click",submitRecoverVerify),document.getElementById("copyRecoveredBtn").addEventListener("click",copyRecoveredKey),document.getElementById("recoverModal").addEventListener("click",function(e){e.target===this&&closeRecover()}),document.querySelectorAll(".open-recover").forEach(function(e){e.addEventListener("click",function(e){e.preventDefault(),openRecover()})}),document.querySelectorAll('a[href^="#"]').forEach(function(e){e.addEventListener("click",function(e){var t=this.getAttribute("href");if("#"!==t){e.preventDefault();var n=document.querySelector(t);n&&n.scrollIntoView({behavior:"smooth"})}})})});var emailChangeApiKey="",emailChangeNewEmail="";function showEmailChangeState(e){["emailChangeInitial","emailChangeLoading","emailChangeVerify","emailChangeResult"].forEach(function(e){var t=document.getElementById(e);t&&t.classList.remove("active")}),document.getElementById(e).classList.add("active")}function openEmailChange(){closeRecover(),document.getElementById("emailChangeModal").classList.add("active"),showEmailChangeState("emailChangeInitial");var e=document.getElementById("emailChangeError");e&&(e.style.display="none");var t=document.getElementById("emailChangeVerifyError");t&&(t.style.display="none"),document.getElementById("emailChangeApiKey").value="",document.getElementById("emailChangeNewEmail").value="",document.getElementById("emailChangeCode").value="",emailChangeApiKey="",emailChangeNewEmail=""}function closeEmailChange(){document.getElementById("emailChangeModal").classList.remove("active")}async function submitEmailChange(){var e=document.getElementById("emailChangeError"),t=document.getElementById("emailChangeBtn"),n=document.getElementById("emailChangeApiKey").value.trim(),a=document.getElementById("emailChangeNewEmail").value.trim();if(!n)return e.textContent="Please enter your API key.",void(e.style.display="block");if(!a||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a))return e.textContent="Please enter a valid email address.",void(e.style.display="block");e.style.display="none",t.disabled=!0,showEmailChangeState("emailChangeLoading");try{var o=await fetch("/v1/email-change",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:n,newEmail:a})}),i=await o.json();if(!o.ok)return showEmailChangeState("emailChangeInitial"),e.textContent=i.error||"Something went wrong.",e.style.display="block",void(t.disabled=!1);emailChangeApiKey=n,emailChangeNewEmail=a,document.getElementById("emailChangeEmailDisplay").textContent=a,showEmailChangeState("emailChangeVerify"),document.getElementById("emailChangeCode").focus(),t.disabled=!1}catch(n){showEmailChangeState("emailChangeInitial"),e.textContent="Network error. Please try again.",e.style.display="block",t.disabled=!1}}async function submitEmailChangeVerify(){var e=document.getElementById("emailChangeVerifyError"),t=document.getElementById("emailChangeVerifyBtn"),n=document.getElementById("emailChangeCode").value.trim();if(!n||!/^\d{6}$/.test(n))return e.textContent="Please enter a 6-digit code.",void(e.style.display="block");e.style.display="none",t.disabled=!0;try{var a=await fetch("/v1/email-change/verify",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:emailChangeApiKey,newEmail:emailChangeNewEmail,code:n})}),o=await a.json();if(!a.ok)return e.textContent=o.error||"Verification failed.",e.style.display="block",void(t.disabled=!1);document.getElementById("emailChangeNewDisplay").textContent=o.newEmail||emailChangeNewEmail,showEmailChangeState("emailChangeResult");var i=document.querySelector("#emailChangeResult h2");i&&(i.setAttribute("tabindex","-1"),i.focus())}catch(n){e.textContent="Network error. Please try again.",e.style.display="block",t.disabled=!1}}document.addEventListener("DOMContentLoaded",function(){var e=document.getElementById("btn-close-email-change");e&&e.addEventListener("click",closeEmailChange);var t=document.getElementById("emailChangeBtn");t&&t.addEventListener("click",submitEmailChange);var n=document.getElementById("emailChangeVerifyBtn");n&&n.addEventListener("click",submitEmailChangeVerify);var a=document.getElementById("emailChangeModal");a&&a.addEventListener("click",function(e){e.target===this&&closeEmailChange()}),document.querySelectorAll(".open-email-change").forEach(function(e){e.addEventListener("click",function(e){e.preventDefault(),openEmailChange()})})}),function(){function e(){for(var e=["recoverModal","emailChangeModal"],t=0;t - + -{{> nav}} + -
-
+
🚀 Simple PDF API for Developers

HTML to PDF
in one API call

@@ -56,7 +362,7 @@
-
+
@@ -86,7 +392,7 @@
🇪🇺
-

Hosted in the EU

+

Hosted in the EU

Your data never leaves the EU • GDPR Compliant • Hetzner Germany (Nuremberg)

@@ -132,20 +438,69 @@
-
+
-

Try it now

-

Paste HTML, get a watermarked PDF. No signup required.

-
- -
- - +

Try it — right now

+

Pick a template or write your own HTML. Generate a real PDF in seconds.

+ + +
+ + + +
+ + +
+
+
+ + HTML +
+
- - + + +
+ + +
+ + + +
+
+
+
+

PDF generated in 0.4s

+ Download PDF → +
+
+
+
+
🆓 Free Demo
+
Watermarked output
+
+
+
+
⚡ Pro
+
Clean, production-ready
+
+
+
+
@@ -167,28 +522,38 @@
  • No watermarks
  • Priority support (support@docfast.dev)
  • - +
    - - -{{> footer}} + - @@ -223,7 +587,43 @@ - + + + + diff --git a/templates/pages/index.html b/templates/pages/index.html index 3fec6da..a8f49d6 100644 --- a/templates/pages/index.html +++ b/templates/pages/index.html @@ -255,6 +255,63 @@ html, body { #emailChangeResult.active { display: block; } #emailChangeVerify.active { display: block; } +/* Playground — redesigned */ +.playground { padding: 80px 0; } +.pg-tabs { display: flex; gap: 8px; justify-content: center; margin-bottom: 24px; flex-wrap: wrap; } +.pg-tab { background: var(--card); border: 1px solid var(--border); color: var(--muted); padding: 10px 20px; border-radius: 8px; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: all 0.2s; } +.pg-tab:hover { border-color: var(--muted); color: var(--fg); } +.pg-tab.active { background: rgba(52,211,153,0.08); border-color: var(--accent); color: var(--accent); } +.pg-split { display: grid; grid-template-columns: 1fr 1fr; gap: 0; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: var(--card); min-height: 380px; } +.pg-editor-pane, .pg-preview-pane { display: flex; flex-direction: column; min-height: 0; } +.pg-pane-header { display: flex; align-items: center; gap: 10px; padding: 10px 16px; background: #1a1f2b; border-bottom: 1px solid var(--border); } +.pg-pane-header-preview { justify-content: space-between; } +.pg-pane-dots { display: flex; gap: 5px; } +.pg-pane-dots span { width: 8px; height: 8px; border-radius: 50%; } +.pg-pane-dots span:nth-child(1) { background: #f87171; } +.pg-pane-dots span:nth-child(2) { background: #fbbf24; } +.pg-pane-dots span:nth-child(3) { background: #34d399; } +.pg-pane-label { font-size: 0.75rem; color: var(--muted); font-family: monospace; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; } +.pg-preview-badge { font-size: 0.65rem; color: var(--accent); background: rgba(52,211,153,0.08); padding: 3px 8px; border-radius: 4px; font-weight: 500; } +#demoHtml { flex: 1; width: 100%; padding: 16px; border: none; background: transparent; color: var(--fg); font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; font-size: 0.82rem; line-height: 1.7; resize: none; outline: none; tab-size: 2; } +.pg-preview-pane { border-left: 1px solid var(--border); } +.pg-preview-frame-wrap { flex: 1; background: #fff; position: relative; overflow: hidden; } +#demoPreview { width: 100%; height: 100%; border: none; background: #fff; } +.pg-actions { display: flex; align-items: center; gap: 16px; justify-content: center; margin-top: 24px; flex-wrap: wrap; } +.btn-lg { padding: 16px 36px; font-size: 1.05rem; border-radius: 12px; } +.btn-sm { padding: 10px 20px; font-size: 0.85rem; } +.pg-btn-icon { font-size: 1.1rem; } +.pg-status { color: var(--muted); font-size: 0.9rem; } +.pg-result { display: none; margin-top: 24px; background: var(--card); border: 1px solid var(--accent); border-radius: var(--radius-lg); padding: 28px; animation: pgSlideIn 0.3s ease; } +.pg-result.visible { display: block; } +@keyframes pgSlideIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } +.pg-result-inner { display: flex; align-items: center; gap: 16px; } +.pg-result-icon { font-size: 2rem; } +.pg-result-title { font-weight: 700; font-size: 1.05rem; margin-bottom: 8px; } +.pg-result-comparison { display: flex; align-items: center; gap: 16px; justify-content: center; margin-top: 24px; padding-top: 24px; border-top: 1px solid var(--border); } +.pg-compare-item { padding: 12px 20px; border-radius: 8px; text-align: center; flex: 1; max-width: 200px; } +.pg-compare-free { background: rgba(248,113,113,0.06); border: 1px solid rgba(248,113,113,0.15); } +.pg-compare-pro { background: rgba(52,211,153,0.06); border: 1px solid rgba(52,211,153,0.2); } +.pg-compare-label { font-weight: 700; font-size: 0.9rem; margin-bottom: 4px; } +.pg-compare-free .pg-compare-label { color: #f87171; } +.pg-compare-pro .pg-compare-label { color: var(--accent); } +.pg-compare-desc { color: var(--muted); font-size: 0.8rem; } +.pg-compare-arrow { color: var(--muted); font-size: 1.2rem; font-weight: 700; } +.pg-result-cta { text-align: center; margin-top: 20px; } +.pg-generating .pg-btn-icon { display: inline-block; animation: spin 0.7s linear infinite; } +@media (max-width: 768px) { + .pg-split { grid-template-columns: 1fr; min-height: auto; } + .pg-preview-pane { border-left: none; border-top: 1px solid var(--border); } + .pg-preview-frame-wrap { height: 250px; } + #demoHtml { min-height: 200px; } + .pg-result-comparison { flex-direction: column; gap: 8px; } + .pg-compare-arrow { transform: rotate(90deg); } + .pg-compare-item { max-width: 100%; } +} +@media (max-width: 375px) { + .pg-tabs { gap: 4px; } + .pg-tab { padding: 8px 12px; font-size: 0.75rem; } +} + /* Focus-visible for accessibility */ .btn:focus-visible, a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } /* Skip to content */ @@ -381,20 +438,69 @@ html, body {
    -
    +
    -

    Try it now

    -

    Paste HTML, get a watermarked PDF. No signup required.

    -
    - -
    - - +

    Try it — right now

    +

    Pick a template or write your own HTML. Generate a real PDF in seconds.

    + + +
    + + + +
    + + +
    +
    +
    + + HTML +
    +
    - - + + +
    + + +
    + + + +
    +
    +
    +
    +

    PDF generated in 0.4s

    + Download PDF → +
    +
    +
    +
    +
    🆓 Free Demo
    +
    Watermarked output
    +
    +
    +
    +
    ⚡ Pro
    +
    Clean, production-ready
    +
    +
    +
    +