554cb99f2c
Add the Umami tracker (cookieless, no consent banner) in the document head, limited to the production hostnames via data-domains so dev traffic doesn't pollute the stats. Pageviews are auto-tracked per page and locale. Custom events on the key funnel: - demo-request (demo form submit, with teamSize) - partner-application (partner form submit, with type) - book-demo (every "Book a demo" CTA click) via data-umami-event - login (clicks through to the app) Also fix the mobile nav menu links, which weren't localized (would drop Danish visitors back to English).
123 lines
4.9 KiB
Vue
123 lines
4.9 KiB
Vue
<script setup lang="ts">
|
|
// Book-a-demo page. Interim: the form composes a prefilled email to
|
|
// info@dezky.eu (zero backend, no US tools). Swap this for the self-built
|
|
// embedded scheduler later — the copy + layout can stay.
|
|
import { ref, computed } from 'vue'
|
|
import { useTheme, useCopy, track } from '~/composables/useLanding'
|
|
|
|
definePageMeta({ layout: 'page' })
|
|
|
|
const t = useTheme()
|
|
const copy = useCopy()
|
|
const c = computed(() => copy.value.pages.demo)
|
|
|
|
const name = ref('')
|
|
const email = ref('')
|
|
const company = ref('')
|
|
const team = ref('')
|
|
const message = ref('')
|
|
|
|
function submit() {
|
|
const d = c.value
|
|
const subject = `Demo request — ${(company.value || name.value).trim()}`
|
|
const body = [
|
|
`${d.nameLabel}: ${name.value}`,
|
|
`${d.emailLabel}: ${email.value}`,
|
|
`${d.companyLabel}: ${company.value}`,
|
|
`${d.teamLabel}: ${team.value}`,
|
|
'',
|
|
message.value,
|
|
].join('\n')
|
|
track('demo-request', { teamSize: team.value })
|
|
window.location.href = `mailto:info@dezky.eu?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`
|
|
}
|
|
|
|
const eyebrow = computed(() => ({
|
|
fontFamily: '\'JetBrains Mono\', monospace', fontSize: '11px', color: t.value.fgDim,
|
|
letterSpacing: '0.12em', textTransform: 'uppercase' as const,
|
|
}))
|
|
const fieldLabel = computed(() => ({
|
|
display: 'block', marginBottom: '8px', fontFamily: '\'JetBrains Mono\', monospace',
|
|
fontSize: '11px', color: t.value.fgMuted, letterSpacing: '0.06em', textTransform: 'uppercase' as const,
|
|
}))
|
|
const inputStyle = computed(() => ({
|
|
width: '100%', padding: '12px 14px', border: `1px solid ${t.value.border}`, borderRadius: '4px',
|
|
background: t.value.bg, color: t.value.fg, fontFamily: '\'Inter\', sans-serif', fontSize: '15px',
|
|
boxSizing: 'border-box' as const,
|
|
}))
|
|
|
|
useHead({ title: () => `${copy.value.pages.demo.label} · dezky` })
|
|
</script>
|
|
|
|
<template>
|
|
<LandingPageHeader :label="c.label" :title="c.title" :intro="c.intro" />
|
|
|
|
<LandingContainer pad="clamp(56px, 8vw, 56px) clamp(20px, 5vw, 64px) clamp(80px, 12vw, 160px)">
|
|
<div class="demo-grid" :style="{ display: 'grid', gap: '48px', alignItems: 'start' }">
|
|
<!-- What to expect -->
|
|
<div>
|
|
<div :style="eyebrow">{{ c.expectHeading }}</div>
|
|
<ul :style="{ listStyle: 'none', margin: '24px 0 0', padding: 0, display: 'flex', flexDirection: 'column', gap: '16px' }">
|
|
<li
|
|
v-for="(e, i) in c.expect" :key="i"
|
|
:style="{ display: 'flex', gap: '12px', fontFamily: '\'Inter\', sans-serif', fontSize: '16px', lineHeight: 1.5, color: t.fg }"
|
|
>
|
|
<span :style="{ color: t.signal, fontWeight: 700, flexShrink: 0 }">✓</span>
|
|
<span>{{ e }}</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- Form -->
|
|
<form
|
|
@submit.prevent="submit"
|
|
:style="{ padding: 'clamp(24px, 4vw, 36px)', border: `1px solid ${t.border}`, borderRadius: '4px', background: t.surface, display: 'flex', flexDirection: 'column', gap: '18px' }"
|
|
>
|
|
<div :style="{ fontFamily: '\'Inter Tight\', sans-serif', fontWeight: 600, fontSize: '20px', color: t.fg, letterSpacing: '-0.015em' }">{{ c.formHeading }}</div>
|
|
|
|
<div>
|
|
<label :style="fieldLabel">{{ c.nameLabel }}</label>
|
|
<input v-model="name" type="text" required :placeholder="c.namePh" :style="inputStyle">
|
|
</div>
|
|
<div>
|
|
<label :style="fieldLabel">{{ c.emailLabel }}</label>
|
|
<input v-model="email" type="email" required :placeholder="c.emailPh" :style="inputStyle">
|
|
</div>
|
|
<div>
|
|
<label :style="fieldLabel">{{ c.companyLabel }}</label>
|
|
<input v-model="company" type="text" required :placeholder="c.companyPh" :style="inputStyle">
|
|
</div>
|
|
<div>
|
|
<label :style="fieldLabel">{{ c.teamLabel }}</label>
|
|
<select v-model="team" :style="{ ...inputStyle, appearance: 'none', cursor: 'pointer' }">
|
|
<option value="" disabled>{{ c.teamPh }}</option>
|
|
<option v-for="s in c.teamSizes" :key="s" :value="s">{{ s }}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label :style="fieldLabel">{{ c.messageLabel }}</label>
|
|
<textarea v-model="message" rows="3" :placeholder="c.messagePh" :style="{ ...inputStyle, resize: 'vertical' }" />
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
:style="{ marginTop: '4px', background: t.signal, color: t.fg, border: 'none', padding: '16px 24px', fontFamily: '\'Inter\', sans-serif', fontSize: '15px', fontWeight: 600, borderRadius: '4px', cursor: 'pointer', letterSpacing: '-0.005em' }"
|
|
>{{ c.submit }} →</button>
|
|
|
|
<p :style="{ margin: 0, fontFamily: '\'Inter\', sans-serif', fontSize: '13px', lineHeight: 1.5, color: t.fgDim }">{{ c.note }}</p>
|
|
</form>
|
|
</div>
|
|
</LandingContainer>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.demo-grid {
|
|
grid-template-columns: 0.85fr 1.15fr;
|
|
}
|
|
@media (max-width: 768px) {
|
|
.demo-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|