Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const redirects = {
'/page': '/',
'/wtd': '/',
'/hn': '/',
'/meet': '/demo',
'/site': '/demo',
'/site/demo': '/demo',
'/video-demo': '/demo',
Expand Down
28 changes: 28 additions & 0 deletions public/assets/helm.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/assets/vitess-stacked.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/shared/TopHeader.astro
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const { activeSection = getActiveSection(Astro.url.pathname), showNavTools = fal
{showNavTools ? <div class="pl-site-search sl-flex print:hidden"><slot name="nav-tools" /></div> : null}
<div class="pl-site-cta-row">
<a class="pl-site-cta pl-site-cta-secondary" href="https://accounts.gopromptless.ai/sign-up" data-track-action="sign_up" data-track-funnel="conversion" data-track-location="nav">Sign up</a>
<a class="pl-site-cta" href="/meet" data-track-action="book_demo" data-track-funnel="conversion" data-track-location="nav">Book demo</a>
<a class="pl-site-cta" href="/demo" data-track-action="book_demo" data-track-funnel="conversion" data-track-location="nav">Book demo</a>
</div>
</div>

Expand Down
4 changes: 3 additions & 1 deletion src/components/site/BlogRequestDemo.astro
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,14 @@

if (!res.ok) throw new Error('Submission failed');

try { sessionStorage.setItem('pl_demo_email', email); } catch {}

window.posthog?.capture('blog_demo_requested', {
location: 'blog',
$set: { email },
});

window.location.assign('https://promptless.ai/meet');
window.location.assign('https://promptless.ai/demo');
} catch {
setStatus('Something went wrong. Please try again.', 'error');
submitBtn.disabled = false;
Expand Down
175 changes: 175 additions & 0 deletions src/components/site/DemoBooking.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
---

<!--
Email-gated Cal.com booking widget.

The Cal.com embed is always loaded (hidden via display:none) so it's ready
instantly when revealed. If the visitor already provided their email (stored
in sessionStorage by the homepage hero or blog CTA), we show it immediately
with the email prefilled. Otherwise we show a small email form first.

No-JS fallback: the email gate and Cal.com embed both require JavaScript.
We show a plain link to the Cal.com booking page via <noscript>. Users who
submitted their email on the homepage via the native form POST will be asked
for their email again on Cal.com — there is no way to pass it without JS.
-->

<div id="demo-booking">
<div id="demo-email-gate" class="demo-email-gate">
<form id="demo-email-form" class="pl-site-form-row">
<label class="sr-only" for="demo-gate-email">Work email</label>
<input
id="demo-gate-email"
type="email"
name="email"
placeholder="Work email"
required
/>
<button type="submit">Continue to booking</button>
</form>
</div>

<div id="demo-calendar" class="pl-site-meet-calendar" style="display:none;">
<div class="pl-site-meet-calendar-mount" id="cal-inline-demo-booking"></div>
</div>

<noscript>
<p>
<a href="https://app.cal.com/team/promptless/15m-discovery-call">
Book a 15-minute demo &rarr;
</a>
</p>
</noscript>
</div>

<script is:inline>
(() => {
var EMAIL_KEY = 'pl_demo_email';
var gate = document.getElementById('demo-email-gate');
var calendar = document.getElementById('demo-calendar');
var form = document.getElementById('demo-email-form');
var namespace = 'demo-booking';
var elementSelector = '#cal-inline-demo-booking';

function getStoredEmail() {
try { return sessionStorage.getItem(EMAIL_KEY); } catch { return null; }
}

function storeEmail(email) {
try { sessionStorage.setItem(EMAIL_KEY, email); } catch {}
}

// Load Cal.com embed immediately (hidden) so it's prewarmed
function bootCal() {
var mountEl = document.querySelector(elementSelector);
if (!mountEl || mountEl.dataset.calMounted === 'true') return;

(function (C, A, L) {
var p = function (a, ar) { a.q.push(ar); };
var d = C.document;
C.Cal = C.Cal || function () {
var cal = C.Cal;
var ar = arguments;
if (!cal.loaded) {
cal.ns = {};
cal.q = cal.q || [];
d.head.appendChild(d.createElement('script')).src = A;
cal.loaded = true;
}
if (ar[0] === L) {
var api = function () { p(api, arguments); };
var ns = ar[1];
api.q = api.q || [];
if (typeof ns === 'string') {
cal.ns[ns] = cal.ns[ns] || api;
p(cal.ns[ns], ar);
p(cal, ['initNamespace', ns]);
} else { p(cal, ar); }
return;
}
p(cal, ar);
};
})(window, 'https://app.cal.com/embed/embed.js', 'init');

var calLink = 'team/promptless/15m-discovery-call';
var storedEmail = getStoredEmail();
if (storedEmail) {
calLink += '?email=' + encodeURIComponent(storedEmail);
}

window.Cal('init', namespace, { origin: 'https://app.cal.com' });
window.Cal.ns[namespace]('inline', {
elementOrSelector: elementSelector,
config: { layout: 'month_view', useSlotsViewOnSmallScreen: 'true' },
calLink: calLink,
});
window.Cal.ns[namespace]('ui', {
hideEventTypeDetails: false,
layout: 'month_view',
});

mountEl.dataset.calMounted = 'true';
}

function showCal() {
if (calendar) calendar.style.display = '';
if (gate) gate.style.display = 'none';
}

// Query param overrides:
// ?demo=reset — clear stored email, show the gate
// ?demo=cal — skip the gate, show Cal.com
var params = new URLSearchParams(window.location.search);
var demoParam = params.get('demo');
if (demoParam === 'reset') {
try { sessionStorage.removeItem(EMAIL_KEY); } catch {}
}

// Always boot Cal.com embed on page load (stays hidden until revealed)
bootCal();

var storedEmail = demoParam === 'reset' ? null : getStoredEmail();
if (storedEmail || demoParam === 'cal') {
showCal();
return;
}

if (form) {
form.addEventListener('submit', function (e) {
e.preventDefault();
var input = form.querySelector('input[name="email"]');
var email = input && input.value ? input.value.trim() : '';
if (!email) return;

storeEmail(email);

// Submit to Formspark so the lead is captured
try {
fetch('https://submit-form.com/roBOd2Oxb', {
method: 'POST',
body: new URLSearchParams({ email }).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json',
},
});
} catch (_) {}

if (window.posthog) {
window.posthog.capture('demo_requested', {
location: 'demo_page',
$set: { email: email },
});
}

showCal();
});
}

document.addEventListener('astro:page-load', function () {
bootCal();
if (getStoredEmail()) showCal();
});
})();
</script>
11 changes: 7 additions & 4 deletions src/components/site/Hero.astro
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ const {
class="pl-site-form-row"
action="https://submit-form.com/roBOd2Oxb"
method="post"
data-redirect="/meet"
data-redirect="/demo"
>
<label class="sr-only" for="work-email">Work email</label>
<input id="work-email" type="email" name="email" placeholder="Work email" required />
<input type="hidden" name="_redirect" value="/meet" />
<input type="hidden" name="_redirect" value="/demo" />
<button type="submit" name="submit" data-track-action="book_demo" data-track-funnel="conversion" data-track-location="hero">Book demo</button>
</form>

Expand All @@ -54,7 +54,7 @@ const {
const redirectInput = form.querySelector('input[name="_redirect"]');

if (redirectInput instanceof HTMLInputElement) {
redirectInput.value = `${window.location.origin}/meet`;
redirectInput.value = `${window.location.origin}/demo`;
}

form.addEventListener('submit', async (event) => {
Expand All @@ -72,6 +72,9 @@ const {
}

const email = (form.querySelector('input[name="email"]') as HTMLInputElement)?.value?.trim();
if (email) {
try { sessionStorage.setItem('pl_demo_email', email); } catch {}
}
(window as any).posthog?.capture('demo_requested', {
location: 'hero',
...(email ? { $set: { email } } : {}),
Expand Down Expand Up @@ -102,7 +105,7 @@ const {
throw new Error(`Formspark submission failed with status ${response.status}`);
}

const redirectTo = form.dataset.redirect || '/meet';
const redirectTo = form.dataset.redirect || '/demo';
window.location.assign(redirectTo);
} catch (_error) {
// Fallback to native form post if fetch fails (e.g. CORS/network).
Expand Down
104 changes: 104 additions & 0 deletions src/components/site/SocialProofLinks.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
const links = [
{
href: 'https://github.com/vitessio/website/commits/',
logo: '/assets/vitess-stacked.png',
name: 'vitessio/website',
desc: 'View commits on GitHub',
},
{
href: 'https://github.com/helm/helm-www/commits/main/',
logo: '/assets/helm.svg',
name: 'helm/helm-www',
desc: 'View commits on GitHub',
},
];
---

<div class="pl-proof-grid">
{links.map((l) => (
<a class="pl-proof-card" href={l.href} target="_blank" rel="noopener" data-track-action="view_commits" data-track-funnel="evaluation" data-track-location="demo_social_proof">
<img src={l.logo} alt="" class="pl-proof-logo" />
<span class="pl-proof-content">
<span class="pl-proof-name">{l.name}</span>
<span class="pl-proof-desc">{l.desc}</span>
</span>
<span class="pl-proof-arrow">&rarr;</span>
</a>
))}
</div>

<style>
.pl-proof-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.9rem;
margin: 1.25rem 0;
}

@media (max-width: 580px) {
.pl-proof-grid {
grid-template-columns: 1fr;
}
}

.pl-proof-card {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 0.72rem;
border: 1px solid #e4e9f3;
border-radius: 0.8rem;
background: #ffffff;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
padding: 0.95rem;
color: #1f2937;
text-decoration: none;
transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease;
}

.pl-proof-card:hover {
border-color: #bfd1ff;
box-shadow: 0 8px 20px rgba(37, 99, 235, 0.1);
transform: translateY(-1px);
text-decoration: none;
color: #1f2937;
}

.pl-proof-logo {
flex-shrink: 0;
width: 44px;
height: 44px;
object-fit: contain;
border-radius: 0 !important;
}

.pl-proof-content {
display: grid;
gap: 0.1rem;
min-width: 0;
}

.pl-proof-name {
font-size: 0.95rem;
font-weight: 650;
color: #111827;
line-height: 1.3;
}

.pl-proof-desc {
font-size: 0.82rem;
color: #596275;
line-height: 1.35;
}

.pl-proof-arrow {
color: #9aa3b6;
font-size: 1.05rem;
transition: color 140ms;
}

.pl-proof-card:hover .pl-proof-arrow {
color: #2f56df;
}
</style>
2 changes: 1 addition & 1 deletion src/components/site/VideoEmbed.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
} = Astro.props;
---

<section id="overview">
<section id="video">
<div class="pl-site-video-embed">
<iframe
src={src}
Expand Down
Loading
Loading