polish: fix padding and spacing across all sections to match Pencil design

- FeatureCard: px-7 pt-8 pb-8 (design: padding [32,28]), h-full for equal heights
- HeroSection: py-20 on mobile, gap-20 between columns, screenshot 380px
- PrivacyBanner: py-14, gap-20, stat items min-w-[100px]
- SeeItLiveSection: py-24, max-w-[640px] header, block img
- FeaturesSection: gap-[72px] section, flex wrapper for equal-height cards
- ScreenshotsSection: lg:h-[340px] images, px-6 py-5 info, gap-2
- HowItWorksSection: gap-20 columns, gap-10 steps, divide-y billing items, p-10 card
- SupportSection: py-24, gap-16, flex wrappers for equal-height cards
- ContactSection: py-20, gap-20, p-9 form card, gap-5 fields
- AppFooter: pt-14 pb-7, border-b [#1E293B], pt-5 bottom bar
This commit is contained in:
kevin-asprec
2026-03-17 04:31:21 +08:00
parent 2340ae58c6
commit 6199f78cfb
11 changed files with 139 additions and 136 deletions

View File

@@ -1327,7 +1327,7 @@
"fill": {
"type": "image",
"enabled": true,
"url": "public/screenshots/rj2JV.png",
"url": "Reports.jpg",
"mode": "fill"
},
"cornerRadius": [

View File

@@ -1,16 +1,15 @@
<script setup lang="ts">
// Design: padding [56, 100, 28, 100], footerTop gap 64, fBrand width 260, fDiv #1E293B
const productLinks = [
{ label: 'Features', href: '#features' },
{ label: 'How It Works', href: '#how-it-works' },
{ label: 'Services', href: '#support' },
]
const companyLinks = [
{ label: 'About Us', href: '#' },
{ label: 'Contact', href: '#contact' },
{ label: 'Blog', href: '#' },
]
const legalLinks = [
{ label: 'Privacy Policy', href: '#' },
{ label: 'Terms of Service', href: '#' },
@@ -18,20 +17,22 @@ const legalLinks = [
</script>
<template>
<footer class="bg-[#020617] text-white">
<div class="page-container py-14 pb-7">
<footer class="bg-[#020617]">
<div class="page-container pt-14 pb-7">
<!-- Top row: brand + nav columns -->
<div class="flex flex-col md:flex-row gap-12 md:gap-16 pb-10 border-b border-[#1E293B]">
<!-- Top row: fBrand 260 + spacer + 3 nav columns, gap 64 -->
<div class="flex flex-col md:flex-row gap-16 pb-10 border-b border-[#1E293B]">
<!-- Brand column -->
<!-- Brand column: gap 14, width 260 -->
<div class="flex flex-col gap-3.5 w-full md:w-[260px] shrink-0">
<!-- Logo row: gap 8 -->
<div class="flex items-center gap-2">
<div class="w-7 h-7 rounded-[6px] bg-[#1D4ED8] flex items-center justify-center shrink-0">
<span class="text-white font-bold text-sm leading-none">T</span>
</div>
<span class="text-white font-bold text-base">TapTrack</span>
</div>
<!-- Tagline: 13px, lineHeight 1.65, max-w 220 -->
<p class="text-[#475569] text-[13px] leading-[1.65] max-w-[220px]">
On-premises NFC attendance for Philippine schools. Student data stays where it belongs with you.
</p>
@@ -40,10 +41,9 @@ const legalLinks = [
<!-- Spacer -->
<div class="hidden md:block flex-1" />
<!-- Nav columns -->
<!-- Nav columns: gap 64 between columns, gap 12 inside each -->
<div class="grid grid-cols-2 sm:grid-cols-3 gap-8 md:gap-16">
<!-- Product -->
<div class="flex flex-col gap-3">
<span class="text-[#D1D5DB] font-semibold text-[13px]">Product</span>
<a
@@ -56,7 +56,6 @@ const legalLinks = [
</a>
</div>
<!-- Company -->
<div class="flex flex-col gap-3">
<span class="text-[#D1D5DB] font-semibold text-[13px]">Company</span>
<a
@@ -69,7 +68,6 @@ const legalLinks = [
</a>
</div>
<!-- Legal -->
<div class="flex flex-col gap-3">
<span class="text-[#D1D5DB] font-semibold text-[13px]">Legal</span>
<a
@@ -81,10 +79,11 @@ const legalLinks = [
{{ link.label }}
</a>
</div>
</div>
</div>
<!-- Bottom bar -->
<!-- Bottom bar: padding [20, 0, 0, 0] -->
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 pt-5">
<p class="text-[#374151] text-xs">
© 2025 TapTrack. All rights reserved. Built in the Philippines.

View File

@@ -1,12 +1,8 @@
<script setup lang="ts">
import { ref } from 'vue'
const form = ref({
school: '',
contact: '',
phone: '',
})
// Design: padding [80, 100], gap 80, alignItems center
const form = ref({ school: '', contact: '', phone: '' })
const submitted = ref(false)
const submitting = ref(false)
const error = ref('')
@@ -17,7 +13,6 @@ const bulletPoints = [
'✓ 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() {
@@ -31,11 +26,7 @@ async function handleSubmit() {
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,
}),
body: JSON.stringify({ school: form.value.school, contact: form.value.contact, phone: form.value.phone }),
})
if (res.ok) {
submitted.value = true
@@ -52,9 +43,9 @@ async function handleSubmit() {
<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">
<div class="page-container flex flex-col lg:flex-row items-start lg:items-center gap-20 py-20">
<!-- Left: Copy -->
<!-- Left: gap 20 -->
<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
@@ -65,6 +56,7 @@ async function handleSubmit() {
<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>
<!-- Bullet points: gap 10 -->
<div class="flex flex-col gap-2.5 mt-1">
<span
v-for="point in bulletPoints"
@@ -76,17 +68,17 @@ async function handleSubmit() {
</div>
</div>
<!-- Right: Form card -->
<!-- Right: Form card, width 480, padding 36, gap 20, cornerRadius 16, fill #1E293B -->
<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 class="bg-[#1E293B] rounded-2xl p-9 flex flex-col gap-5">
<div>
<div class="flex flex-col gap-1">
<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>
<p class="text-[#64748B] text-[13px]">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 v-if="submitted" class="flex flex-col items-center gap-3 py-8 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>
@@ -94,7 +86,7 @@ async function handleSubmit() {
<p class="text-[#94A3B8] text-sm">We'll get back to you within 24 hours.</p>
</div>
<!-- Form -->
<!-- Form: gap 16 between fields -->
<form v-else class="flex flex-col gap-4" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-1.5">
@@ -127,8 +119,9 @@ async function handleSubmit() {
/>
</div>
<p v-if="error" class="text-red-400 text-[13px]">{{ error }}</p>
<p v-if="error" class="text-red-400 text-[13px] -mt-1">{{ error }}</p>
<!-- Submit button: padding [13, 0], width fill -->
<button
type="submit"
:disabled="submitting"

View File

@@ -11,19 +11,18 @@ defineProps<{
</script>
<template>
<div class="flex flex-col gap-3.5 bg-[#F8FAFC] border border-[#E2E8F0] rounded-[14px] p-7 pt-8">
<!-- Icon box -->
<!-- Design: cornerRadius 14, padding [32, 28], gap 14 -->
<div class="flex flex-col gap-3.5 bg-[#F8FAFC] border border-[#E2E8F0] rounded-2xl px-7 pt-8 pb-8 h-full">
<!-- Icon box: 44×44, cornerRadius 10 -->
<div
class="w-11 h-11 rounded-[10px] flex items-center justify-center shrink-0"
:style="{ backgroundColor: iconBg }"
>
<component :is="icon" :size="22" :stroke-width="1.75" :style="{ color: iconColor }" />
</div>
<!-- Title -->
<!-- Title: 16px semibold -->
<h3 class="text-[#0F172A] font-semibold text-base leading-snug">{{ title }}</h3>
<!-- Description -->
<!-- Description: 13px, lineHeight 1.65 -->
<p class="text-[#64748B] text-[13px] leading-[1.65]">{{ description }}</p>
</div>
</template>

View File

@@ -15,87 +15,86 @@ const features = [
iconColor: '#1D4ED8',
iconBg: '#EFF6FF',
title: 'NFC Tap-In Attendance',
description:
'Students tap their NFC ID card on the reader. Attendance is recorded instantly — no queuing, no manual entry, no errors.',
description: 'Students tap their NFC ID card on the reader. Attendance is recorded instantly — no queuing, no manual entry, no errors.',
},
{
icon: MessageSquare,
iconColor: '#059669',
iconBg: '#ECFDF5',
title: 'Instant Parent SMS Alerts',
description:
'Parents receive an automatic SMS the moment their child arrives or is marked absent. No app required on their end.',
description: 'Parents receive an automatic SMS the moment their child arrives or is marked absent. No app required on their end.',
},
{
icon: LayoutDashboard,
iconColor: '#CA8A04',
iconBg: '#FEF9C3',
title: 'Live Attendance Dashboard',
description:
'Principals and advisers see real-time attendance, late counts, and absent students — all from a single screen.',
description: 'Principals and advisers see real-time attendance, late counts, and absent students — all from a single screen.',
},
{
icon: BookOpen,
iconColor: '#7C3AED',
iconBg: '#F3E8FF',
title: 'Automated Attendance Reports',
description:
'Monthly attendance summaries are generated and sent automatically to administrators — with per-student and per-class breakdowns.',
description: 'Monthly attendance summaries are generated and sent automatically to administrators — with per-student and per-class breakdowns.',
},
{
icon: Users,
iconColor: '#E11D48',
iconBg: '#FFF1F2',
title: 'Student & Section Management',
description:
"Manage your full student roster, assign sections and advisers, and link each student to their parent's contact number.",
description: "Manage your full student roster, assign sections and advisers, and link each student to their parent's contact number.",
},
{
icon: Activity,
iconColor: '#0284C7',
iconBg: '#E0F2FE',
title: 'SMS Credit Monitoring',
description:
'Track your prepaid SMS credit balance in real time. Low-credit alerts let you top up before you run out — no interruptions to parent notifications.',
description: 'Track your prepaid SMS credit balance in real time. Low-credit alerts let you top up before you run out — no interruptions to parent notifications.',
},
]
</script>
<template>
<!-- Design: padding [96, 100], gap 72 between header and grid -->
<section id="features" class="bg-white">
<div class="page-container flex flex-col gap-[72px] py-24">
<!-- Section header -->
<div v-reveal class="flex flex-col items-center gap-2.5">
<!-- Header: gap 10, alignItems center -->
<div v-reveal class="flex flex-col items-center gap-2.5 text-center">
<span class="text-[#1D4ED8] font-semibold text-[11px] tracking-[2px] uppercase">
What TapTrack Does
</span>
<h2 class="text-[#0F172A] font-bold text-[clamp(28px,3vw,40px)] leading-[1.15] text-center max-w-[560px]">
<h2 class="text-[#0F172A] font-bold text-[clamp(28px,3vw,40px)] leading-[1.15] max-w-[560px]">
Every feature your school<br class="hidden sm:block" /> actually needs.
</h2>
<p class="text-[#64748B] text-[17px] leading-[1.6] text-center max-w-[560px]">
<p class="text-[#64748B] text-[17px] leading-[1.6] max-w-[560px]">
Designed around the real workflow of Filipino schools from homeroom attendance to parent communication.
</p>
</div>
<!-- Cards grid: 2 rows × 3 cols -->
<!-- 2 rows × 3 cols, gap 24 between cards, gap 24 between rows -->
<div class="flex flex-col gap-6">
<!-- Row 1 -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="(feature, i) in features.slice(0, 3)"
:key="feature.title"
v-for="(f, i) in features.slice(0, 3)"
:key="f.title"
v-reveal="{ delay: i * 80 }"
class="flex"
>
<FeatureCard v-bind="feature" />
<FeatureCard v-bind="f" />
</div>
</div>
<!-- Row 2 -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="(feature, i) in features.slice(3)"
:key="feature.title"
v-for="(f, i) in features.slice(3)"
:key="f.title"
v-reveal="{ delay: i * 80 }"
class="flex"
>
<FeatureCard v-bind="feature" />
<FeatureCard v-bind="f" />
</div>
</div>
</div>

View File

@@ -3,29 +3,30 @@
</script>
<template>
<section class="bg-[#F8FAFF] min-h-[640px] flex items-center">
<div class="page-container w-full flex flex-col lg:flex-row items-center gap-16 xl:gap-20 py-16 lg:py-0">
<!-- Design: height 640, padding [0, 100], gap 80 between columns -->
<section class="bg-[#F8FAFF]">
<div class="page-container w-full flex flex-col lg:flex-row items-center gap-20 min-h-[640px] py-20 lg:py-16">
<!-- Left Column -->
<div v-reveal class="flex-1 flex flex-col gap-7 min-w-0">
<!-- Pill badge -->
<!-- Pill badge: fill #EFF6FF, cornerRadius 20, padding [5,12], gap 6 -->
<div class="inline-flex items-center gap-1.5 bg-[#EFF6FF] rounded-full px-3 py-[5px] w-fit">
<span class="w-1.5 h-1.5 rounded-full bg-[#1D4ED8] shrink-0"></span>
<span class="text-[#1D4ED8] font-semibold text-xs">Built for Philippine Schools</span>
<span class="text-[#1D4ED8] font-semibold text-xs leading-none">Built for Philippine Schools</span>
</div>
<!-- H1 -->
<!-- H1: 58px bold, lineHeight 1.1 -->
<h1 class="text-[#0F172A] font-bold text-[clamp(38px,4.5vw,58px)] leading-[1.1] max-w-[560px]">
Attendance That<br>Runs Itself.
</h1>
<!-- Subtitle -->
<!-- Subtitle: 17px, lineHeight 1.7 -->
<p class="text-[#475569] text-[17px] leading-[1.7] max-w-[520px]">
TapTrack is an on-premises NFC attendance system students tap their ID card, parents get an SMS, and your records are updated automatically. No manual registers. No paper trails.
</p>
<!-- CTA Buttons -->
<!-- CTA Buttons: gap 12, padding [13, 26] -->
<div class="flex flex-wrap items-center gap-3">
<a
href="#contact"
@@ -41,18 +42,18 @@
</a>
</div>
<!-- Trust row -->
<!-- Trust row: gap 20 -->
<div class="flex flex-wrap items-center gap-5">
<span class="text-[#64748B] text-[13px]">&nbsp; Student data stays on your servers</span>
<span class="text-[#64748B] text-[13px]">&nbsp; No cloud lock-in</span>
</div>
</div>
<!-- Right Column -->
<!-- Right Column: width 580, gap 16 -->
<div v-reveal="{ delay: 150 }" class="w-full lg:w-[580px] shrink-0 flex flex-col gap-4 items-center">
<!-- Screenshot frame -->
<div class="w-full max-w-[580px] h-[300px] sm:h-[380px] rounded-2xl overflow-hidden border-2 border-[#E2E8F0] shadow-xl">
<!-- Screenshot: 580×380, cornerRadius 16, border 2px -->
<div class="w-full max-w-[580px] h-[320px] sm:h-[380px] rounded-2xl overflow-hidden border-2 border-[#E2E8F0] shadow-xl">
<img
src="/screenshots/58IBI.png"
alt="TapTrack live attendance dashboard"
@@ -60,7 +61,7 @@
/>
</div>
<!-- Caption -->
<!-- Caption: 12px, textAlign center -->
<p class="text-[#94A3B8] text-xs text-center max-w-[520px] leading-relaxed">
Live dashboard running on your school's own server data never leaves your premises.
</p>

View File

@@ -1,24 +1,22 @@
<script setup lang="ts">
import { Wrench, Zap, CircleCheck } from 'lucide-vue-next'
// Design: padding [96, 100], gap 80, layout horizontal
const steps = [
{
num: '1',
title: "We install TapTrack on your school's hardware",
description:
'Our team sets up the on-premises software and NFC reader. You pay a one-time implementation fee and you own the setup.',
description: 'Our team sets up the on-premises software and NFC reader. You pay a one-time implementation fee and you own the setup.',
},
{
num: '2',
title: 'We enrol your students and train your staff',
description:
'We import your student list, assign NFC ID cards, add parent numbers, and run a full walkthrough with your administrators.',
description: 'We import your student list, assign NFC ID cards, add parent numbers, and run a full walkthrough with your administrators.',
},
{
num: '3',
title: 'Top up SMS credits monthly as needed',
description:
'No recurring subscription. You purchase prepaid SMS credits when you need them. The system keeps sending alerts as long as your credits last.',
description: 'No recurring subscription. You purchase prepaid SMS credits when you need them. The system keeps sending alerts as long as your credits last.',
},
]
@@ -42,10 +40,12 @@ const billingItems = [
<template>
<section id="how-it-works" class="bg-[#F8FAFF]">
<div class="page-container flex flex-col lg:flex-row gap-16 xl:gap-20 py-24">
<div class="page-container flex flex-col lg:flex-row gap-20 py-24">
<!-- Left: Steps -->
<!-- Left column: gap 40 -->
<div v-reveal class="flex-1 flex flex-col gap-10 min-w-0">
<!-- Header: gap 10 -->
<div class="flex flex-col gap-2.5">
<span class="text-[#1D4ED8] font-semibold text-[11px] tracking-[2px] uppercase">
How It Works
@@ -58,16 +58,19 @@ const billingItems = [
</p>
</div>
<div class="flex flex-col gap-8">
<!-- Steps: gap 40, each step gap 20 -->
<div class="flex flex-col gap-10">
<div
v-for="(step, i) in steps"
:key="step.num"
v-reveal="{ delay: i * 100 }"
class="flex items-start gap-5"
>
<!-- Number bubble: 36×36, cornerRadius 18 -->
<div class="w-9 h-9 rounded-full bg-[#1D4ED8] flex items-center justify-center shrink-0 mt-0.5">
<span class="text-white font-bold text-[15px] leading-none">{{ step.num }}</span>
</div>
<!-- Step content: gap 6 -->
<div class="flex flex-col gap-1.5 min-w-0">
<h3 class="text-[#0F172A] font-semibold text-[15px] leading-snug">{{ step.title }}</h3>
<p class="text-[#64748B] text-[13px] leading-[1.6]">{{ step.description }}</p>
@@ -76,20 +79,22 @@ const billingItems = [
</div>
</div>
<!-- Right: Billing card -->
<!-- Right: Billing card, width 460, padding 40, gap 24, cornerRadius 20 -->
<div v-reveal="{ delay: 150 }" class="w-full lg:w-[460px] shrink-0">
<div class="bg-white border border-[#E2E8F0] rounded-[20px] p-8 lg:p-10 flex flex-col gap-6">
<h3 class="text-[#0F172A] font-bold text-xl">How billing works</h3>
<p class="text-[#64748B] text-[14px] leading-[1.6]">
Transparent, no surprises. You only pay for what you actually use.
</p>
<div class="bg-white border border-[#E2E8F0] rounded-[20px] p-10 flex flex-col gap-6 h-full">
<div class="flex flex-col gap-2">
<h3 class="text-[#0F172A] font-bold text-xl">How billing works</h3>
<p class="text-[#64748B] text-[14px] leading-[1.6]">
Transparent, no surprises. You only pay for what you actually use.
</p>
</div>
<div class="flex flex-col">
<!-- Billing items -->
<div class="flex flex-col divide-y divide-[#F1F5F9]">
<div
v-for="(item, i) in billingItems"
v-for="item in billingItems"
:key="item.title"
class="flex items-start gap-3.5 py-4"
:class="i === 0 ? 'border-b border-[#F1F5F9]' : ''"
class="flex items-start gap-3.5 py-4 first:pt-0 last:pb-0"
>
<div
class="w-9 h-9 rounded-lg flex items-center justify-center shrink-0"
@@ -97,13 +102,14 @@ const billingItems = [
>
<component :is="item.icon" :size="18" :stroke-width="1.75" :style="{ color: item.iconColor }" />
</div>
<div class="flex flex-col gap-0.5 min-w-0">
<div class="flex flex-col gap-1 min-w-0">
<span class="text-[#0F172A] font-semibold text-[14px]">{{ item.title }}</span>
<span class="text-[#64748B] text-[13px] leading-[1.5]">{{ item.description }}</span>
</div>
</div>
</div>
<!-- Note: fill #F0FDF4, cornerRadius 8, padding [12,14], gap 10 -->
<div class="flex items-start gap-2.5 bg-[#F0FDF4] rounded-lg px-3.5 py-3">
<CircleCheck :size="16" :stroke-width="2" class="text-[#16A34A] shrink-0 mt-0.5" />
<p class="text-[#15803D] text-[13px] leading-[1.5]">

View File

@@ -9,31 +9,35 @@ const stats = [
</script>
<template>
<!-- Design: padding [56, 100], gap 80, alignItems center -->
<section class="bg-[#0F172A]">
<div class="page-container flex flex-col lg:flex-row items-start lg:items-center gap-12 lg:gap-20 py-14">
<div class="page-container flex flex-col lg:flex-row items-start lg:items-center gap-20 py-14">
<!-- Left: Text content -->
<!-- Left: gap 12 -->
<div v-reveal class="flex-1 flex flex-col gap-3 min-w-0">
<!-- Label: fill #1E3A5F, cornerRadius 4, padding [4,10] -->
<div class="w-fit bg-[#1E3A5F] rounded px-[10px] py-1">
<span class="text-[#60A5FA] font-semibold text-[11px] tracking-[1px] uppercase">
Data Privacy
</span>
</div>
<!-- Title: 28px bold, lineHeight 1.2, max-w 500 -->
<h2 class="text-white font-bold text-[28px] leading-[1.2] max-w-[500px]">
Student data never leaves your school.
</h2>
<!-- Sub: 15px, lineHeight 1.6, max-w 500 -->
<p class="text-[#94A3B8] text-[15px] leading-[1.6] max-w-[500px]">
TapTrack runs entirely on your own server. No student records, attendance logs, or personal data are ever uploaded to a third-party cloud.
</p>
</div>
<!-- Right: Stat items -->
<!-- Right: gap 40, stat items centered -->
<div class="flex flex-row flex-wrap gap-10 shrink-0">
<div
v-for="(stat, i) in stats"
:key="stat.label"
v-reveal="{ delay: i * 100 }"
class="flex flex-col items-center gap-1.5 min-w-[90px]"
class="flex flex-col items-center gap-1.5 min-w-[100px]"
>
<component :is="stat.icon" class="text-[#60A5FA]" :size="28" :stroke-width="1.75" />
<span class="text-white font-semibold text-[13px]">{{ stat.label }}</span>

View File

@@ -1,18 +1,17 @@
<script setup lang="ts">
// Design: padding [96, 100], gap 56, screenshot cards cornerRadius 14, border #E2E8F0
const cards = [
{
img: '/screenshots/4frZA.png',
alt: 'TapTrack Student Directory screen',
title: 'Student Directory',
description:
'Manage your full roster — NFC ID assignments, parent numbers, section placement, and enrolment status all in one place.',
description: 'Manage your full roster — NFC ID assignments, parent numbers, section placement, and enrolment status all in one place.',
},
{
img: '/screenshots/Reports.jpg',
alt: 'TapTrack Reports & Analytics screen',
title: 'Reports & Analytics',
description:
'Generate attendance summaries by class, date range, and section. Export to PDF or Excel for DepEd compliance and parent meetings.',
description: 'Generate attendance summaries by class, date range, and section. Export to PDF or Excel for DepEd compliance and parent meetings.',
},
]
</script>
@@ -22,19 +21,19 @@ const cards = [
<div class="page-container flex flex-col gap-14 py-24">
<!-- Header -->
<div v-reveal class="flex flex-col items-center gap-2.5">
<div v-reveal class="flex flex-col items-center gap-2.5 text-center">
<span class="text-[#1D4ED8] font-semibold text-[11px] tracking-[2px] uppercase">
Inside TapTrack
</span>
<h2 class="text-[#0F172A] font-bold text-[clamp(26px,3vw,38px)] leading-[1.15] text-center max-w-[600px]">
<h2 class="text-[#0F172A] font-bold text-[clamp(26px,3vw,38px)] leading-[1.15] max-w-[600px]">
A system built for how your school actually works.
</h2>
<p class="text-[#64748B] text-[16px] leading-[1.6] text-center max-w-[580px]">
<p class="text-[#64748B] text-[16px] leading-[1.6] max-w-[580px]">
Every screen is purpose-built for school administrators, advisers, and principals not generic enterprise software.
</p>
</div>
<!-- Screenshot cards grid -->
<!-- 2-col card grid, gap 28 -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-7">
<div
v-for="(card, i) in cards"
@@ -42,14 +41,16 @@ const cards = [
v-reveal="{ delay: i * 120 }"
class="flex flex-col rounded-[14px] border border-[#E2E8F0] overflow-hidden"
>
<div class="h-[240px] sm:h-[300px] lg:h-[340px] overflow-hidden">
<!-- Image: height 340, object-top -->
<div class="h-[260px] sm:h-[320px] lg:h-[340px] overflow-hidden">
<img
:src="card.img"
:alt="card.alt"
class="w-full h-full object-cover object-top"
class="w-full h-full object-cover object-top block"
/>
</div>
<div class="flex flex-col gap-1.5 px-6 py-5">
<!-- Info: padding [20, 24], gap 6 -->
<div class="flex flex-col gap-2 px-6 py-5">
<h3 class="text-[#0F172A] font-semibold text-base">{{ card.title }}</h3>
<p class="text-[#64748B] text-[13px] leading-[1.6]">{{ card.description }}</p>
</div>

View File

@@ -1,34 +1,37 @@
<script setup lang="ts">
// Gate View kiosk screenshot section
// Design: padding [96, 100], gap 40, layout vertical, alignItems center
</script>
<template>
<section class="bg-[#F8FAFF]">
<div class="page-container flex flex-col items-center gap-10 py-24">
<!-- Header -->
<div v-reveal class="flex flex-col items-center gap-2.5 w-full">
<!-- Header: gap 10, alignItems center, width fill -->
<div v-reveal class="flex flex-col items-center gap-2.5 w-full max-w-[640px]">
<!-- Label: 11px semibold, tracking 2px -->
<span class="text-[#1D4ED8] font-semibold text-[11px] tracking-[2px] uppercase">
The System in Action
</span>
<h2 class="text-[#0F172A] font-bold text-[clamp(28px,3vw,38px)] leading-[1.15] text-center max-w-[600px]">
<!-- Title: 38px bold, lineHeight 1.15, textAlign center, width 600 -->
<h2 class="text-[#0F172A] font-bold text-[clamp(28px,3vw,38px)] leading-[1.15] text-center">
The gate display students see every morning.
</h2>
<p class="text-[#64748B] text-[16px] leading-[1.6] text-center max-w-[600px]">
<!-- Sub: 16px, lineHeight 1.6, textAlign center, width 600 -->
<p class="text-[#64748B] text-[16px] leading-[1.6] text-center">
A full-screen kiosk view runs at your school gate students tap their NFC ID card and instantly see their name, section, and status confirmed.
</p>
</div>
<!-- Gate View Screenshot -->
<!-- Gate screenshot: width 960, height 540, cornerRadius 16, border #E2E8F0 -->
<div v-reveal="{ delay: 100 }" class="w-full max-w-[960px] rounded-2xl overflow-hidden border border-[#E2E8F0] shadow-lg">
<img
src="/screenshots/gE861.png"
alt="TapTrack gate kiosk display"
class="w-full h-auto object-cover"
class="w-full h-auto block"
/>
</div>
<!-- Caption -->
<!-- Caption: 13px, textAlign center, width 700 -->
<p v-reveal="{ delay: 150 }" class="text-[#94A3B8] text-[13px] text-center max-w-[700px] leading-relaxed">
Full-screen gate display running on a monitor at your school entrance. No login required for students just tap and go.
</p>

View File

@@ -8,46 +8,42 @@ import {
} from 'lucide-vue-next'
import FeatureCard from './FeatureCard.vue'
// Design: padding [96, 100], gap 64, card padding [36, 28]
const supportCards = [
{
icon: Headphones,
iconColor: '#1D4ED8',
iconBg: '#EFF6FF',
title: 'Dedicated Support Channel',
description:
'Get direct access to our technical team via chat or phone. No ticket queues, no bots — real people who know your setup.',
description: 'Get direct access to our technical team via chat or phone. No ticket queues, no bots — real people who know your setup.',
},
{
icon: Settings,
iconColor: '#CA8A04',
iconBg: '#FEF9C3',
title: 'System Updates & Maintenance',
description:
'We push updates to fix bugs and add improvements. Your system stays current without you having to do anything.',
description: 'We push updates to fix bugs and add improvements. Your system stays current without you having to do anything.',
},
{
icon: GraduationCap,
iconColor: '#059669',
iconBg: '#ECFDF5',
title: 'Staff Re-training Assistance',
description:
"New school year, new staff? We'll get your team up to speed. Re-training sessions available on request.",
description: "New school year, new staff? We'll get your team up to speed. Re-training sessions available on request.",
},
{
icon: Monitor,
iconColor: '#7C3AED',
iconBg: '#F3E8FF',
title: 'Remote Troubleshooting',
description:
'Most issues can be resolved remotely. Our team can connect to your system and fix problems without an on-site visit.',
description: 'Most issues can be resolved remotely. Our team can connect to your system and fix problems without an on-site visit.',
},
{
icon: DatabaseBackup,
iconColor: '#E11D48',
iconBg: '#FFF1F2',
title: 'Data Backup Assistance',
description:
'We help you set up regular attendance data backups so your records are always safe, even if hardware fails.',
description: 'We help you set up regular attendance data backups so your records are always safe, even if hardware fails.',
},
]
</script>
@@ -57,42 +53,44 @@ const supportCards = [
<div class="page-container flex flex-col gap-16 py-24">
<!-- Header -->
<div v-reveal class="flex flex-col items-center gap-2.5">
<div v-reveal class="flex flex-col items-center gap-2.5 text-center">
<span class="text-[#1D4ED8] font-semibold text-[11px] tracking-[2px] uppercase">
After-Sales Support
</span>
<h2 class="text-[#0F172A] font-bold text-[clamp(28px,3vw,38px)] leading-[1.15] text-center max-w-[560px]">
<h2 class="text-[#0F172A] font-bold text-[clamp(28px,3vw,38px)] leading-[1.15] max-w-[560px]">
We don't just install and leave.
</h2>
<p class="text-[#64748B] text-[17px] leading-[1.6] text-center max-w-[560px]">
<p class="text-[#64748B] text-[17px] leading-[1.6] max-w-[560px]">
Our team stays with you long after go-live. If something breaks or your staff needs help, we're one message away.
</p>
</div>
<!-- Row 1: 3 cards -->
<!-- Row 1: 3 cards, gap 24 -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="(card, i) in supportCards.slice(0, 3)"
:key="card.title"
v-reveal="{ delay: i * 80 }"
class="flex"
>
<FeatureCard v-bind="card" />
</div>
</div>
<!-- Row 2: 2 cards + quote card -->
<!-- Row 2: 2 support cards + quote card -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div
v-for="(card, i) in supportCards.slice(3)"
:key="card.title"
v-reveal="{ delay: i * 80 }"
class="flex"
>
<FeatureCard v-bind="card" />
</div>
<!-- Quote card -->
<div v-reveal="{ delay: 160 }" class="flex flex-col gap-4 bg-[#EFF6FF] border border-[#BFDBFE] rounded-[14px] p-7 pt-9">
<p class="text-[#1E3A5F] font-medium text-base leading-[1.65]">
<!-- Quote card: fill #EFF6FF, border #BFDBFE, padding [36, 28], gap 16 -->
<div v-reveal="{ delay: 160 }" class="flex flex-col gap-4 bg-[#EFF6FF] border border-[#BFDBFE] rounded-2xl px-7 pt-9 pb-8">
<p class="text-[#1E3A5F] font-medium text-base leading-[1.65] flex-1">
"Think of us as your school's IT partner for attendance — not just a vendor who sold you something."
</p>
<div class="flex items-center gap-2.5">