- Vite + Vue 3 + TypeScript + Tailwind CSS v4 scaffold - lucide-vue-next icons, Inter font, design tokens - AppNavbar: sticky, scroll shadow, mobile hamburger - AppFooter: dark navy, 3 link columns, copyright bar - HeroSection: pill badge, H1, CTAs, trust row, screenshot - PrivacyBanner: dark, 3 stat icons (Server/Shield/WifiOff) - SeeItLiveSection: gate kiosk screenshot showcase - FeaturesSection: 6-card grid with Lucide icons - ScreenshotsSection: Student Directory + Reports.jpg cards - HowItWorksSection: 3 steps + billing card - SupportSection: 5 support cards + quote card - ContactSection: form with Formspree, validation, success state - v-reveal directive: Intersection Observer scroll animations - SEO meta tags + Open Graph + Twitter Card - vercel.json SPA rewrite rule - Build: 100KB JS / 19KB CSS, 0 errors
147 lines
5.4 KiB
Vue
147 lines
5.4 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
|
|
const form = ref({
|
|
school: '',
|
|
contact: '',
|
|
phone: '',
|
|
})
|
|
|
|
const submitted = ref(false)
|
|
const submitting = ref(false)
|
|
const error = ref('')
|
|
|
|
const bulletPoints = [
|
|
'✓ Free consultation call with our team',
|
|
'✓ Custom quote based on your school size',
|
|
'✓ Demo of the live system before you commit',
|
|
]
|
|
|
|
// Replace with your actual Formspree form ID: https://formspree.io
|
|
const FORMSPREE_URL = 'https://formspree.io/f/YOUR_FORM_ID'
|
|
|
|
async function handleSubmit() {
|
|
error.value = ''
|
|
if (!form.value.school || !form.value.contact || !form.value.phone) {
|
|
error.value = 'Please fill in all fields before submitting.'
|
|
return
|
|
}
|
|
submitting.value = true
|
|
try {
|
|
const res = await fetch(FORMSPREE_URL, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
body: JSON.stringify({
|
|
school: form.value.school,
|
|
contact: form.value.contact,
|
|
phone: form.value.phone,
|
|
}),
|
|
})
|
|
if (res.ok) {
|
|
submitted.value = true
|
|
} else {
|
|
error.value = 'Something went wrong. Please try again or email us directly.'
|
|
}
|
|
} catch {
|
|
error.value = 'Network error. Please check your connection and try again.'
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<section id="contact" class="bg-[#0F172A]">
|
|
<div class="page-container flex flex-col lg:flex-row items-start lg:items-center gap-16 xl:gap-20 py-20">
|
|
|
|
<!-- Left: Copy -->
|
|
<div v-reveal class="flex-1 flex flex-col gap-5 min-w-0">
|
|
<span class="text-[#60A5FA] font-semibold text-[11px] tracking-[2px] uppercase">
|
|
Get in Touch
|
|
</span>
|
|
<h2 class="text-white font-bold text-[clamp(28px,3vw,40px)] leading-[1.15] max-w-[520px]">
|
|
Ready to bring TapTrack<br class="hidden sm:block" /> to your school?
|
|
</h2>
|
|
<p class="text-[#94A3B8] text-[16px] leading-[1.65] max-w-[520px]">
|
|
Tell us about your school and we'll get back to you with a tailored proposal — including implementation scope, NFC hardware, and SMS credit packages that fit your needs.
|
|
</p>
|
|
<div class="flex flex-col gap-2.5 mt-1">
|
|
<span
|
|
v-for="point in bulletPoints"
|
|
:key="point"
|
|
class="text-[#CBD5E1] text-[14px]"
|
|
>
|
|
{{ point }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right: Form card -->
|
|
<div v-reveal="{ delay: 150 }" class="w-full lg:w-[480px] shrink-0">
|
|
<div class="bg-[#1E293B] rounded-2xl p-8 lg:p-9 flex flex-col gap-5">
|
|
|
|
<div>
|
|
<h3 class="text-white font-bold text-xl">Request a Demo</h3>
|
|
<p class="text-[#64748B] text-[13px] mt-1">Fill this out and we'll reach you within 24 hours.</p>
|
|
</div>
|
|
|
|
<!-- Success state -->
|
|
<div v-if="submitted" class="flex flex-col items-center gap-3 py-6 text-center">
|
|
<div class="w-12 h-12 rounded-full bg-[#059669] flex items-center justify-center">
|
|
<span class="text-white font-bold text-xl">✓</span>
|
|
</div>
|
|
<p class="text-white font-semibold text-base">Request sent!</p>
|
|
<p class="text-[#94A3B8] text-sm">We'll get back to you within 24 hours.</p>
|
|
</div>
|
|
|
|
<!-- Form -->
|
|
<form v-else class="flex flex-col gap-4" @submit.prevent="handleSubmit">
|
|
|
|
<div class="flex flex-col gap-1.5">
|
|
<label class="text-[#CBD5E1] font-medium text-[13px]">School Name</label>
|
|
<input
|
|
v-model="form.school"
|
|
type="text"
|
|
placeholder="e.g. San Pedro Elementary School"
|
|
class="w-full h-[42px] bg-[#0F172A] border border-[#334155] rounded-lg px-3 text-[13px] text-white placeholder:text-[#475569] focus:outline-none focus:border-[#1D4ED8] transition-colors"
|
|
/>
|
|
</div>
|
|
|
|
<div class="flex flex-col gap-1.5">
|
|
<label class="text-[#CBD5E1] font-medium text-[13px]">Contact Person</label>
|
|
<input
|
|
v-model="form.contact"
|
|
type="text"
|
|
placeholder="Principal / Administrator name"
|
|
class="w-full h-[42px] bg-[#0F172A] border border-[#334155] rounded-lg px-3 text-[13px] text-white placeholder:text-[#475569] focus:outline-none focus:border-[#1D4ED8] transition-colors"
|
|
/>
|
|
</div>
|
|
|
|
<div class="flex flex-col gap-1.5">
|
|
<label class="text-[#CBD5E1] font-medium text-[13px]">Phone / Email</label>
|
|
<input
|
|
v-model="form.phone"
|
|
type="text"
|
|
placeholder="+63 9XX XXX XXXX or email@school.edu.ph"
|
|
class="w-full h-[42px] bg-[#0F172A] border border-[#334155] rounded-lg px-3 text-[13px] text-white placeholder:text-[#475569] focus:outline-none focus:border-[#1D4ED8] transition-colors"
|
|
/>
|
|
</div>
|
|
|
|
<p v-if="error" class="text-red-400 text-[13px]">{{ error }}</p>
|
|
|
|
<button
|
|
type="submit"
|
|
:disabled="submitting"
|
|
class="w-full bg-[#1D4ED8] hover:bg-[#1A43C0] disabled:opacity-60 text-white font-semibold text-[15px] py-[13px] rounded-lg transition-colors duration-150 mt-1 cursor-pointer"
|
|
>
|
|
{{ submitting ? 'Sending…' : 'Send Request' }}
|
|
</button>
|
|
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
</template>
|