← BackVDesing — Code to Reality
estado: código fuente
page.tsx
types.ts
globals.css
1'use client'
3import { useState, useEffect,
4 useRef, useCallback } from 'react'
5import { useRouter } from 'next/navigation'
6import Image from 'next/image'
7import Link from 'next/link'
8import { track } from '@vercel/analytics'
10// ── Types ─────────────────────────────────────────
11type Plan = {
12 id: 'basic' | 'pro' | 'custom'
13 name: string
14 price: number
15 features: readonly string[]
16 popular?: boolean
17}
19interface QuoteState {
20 plan: Plan | null
21 addons: string[]
22 total: number
23 sent: boolean
24}
26// ── Config ────────────────────────────────────────
27const WA_NUMBER = '17879449031'
28const DEADLINE = new Date('2026-05-23T23:59:59')
29const SITE_URL = 'https://vdesing.pages.dev'
31const PLANS: Plan[] = [
32 { id: 'basic', name: 'Básico', price: 680,
33 features: ['Landing page','Hosting','WhatsApp','SSL'] },
34 { id: 'pro', name: 'Pro', price: 1280, popular: true,
35 features: ['3 páginas','Logo','Video 60s','SEO'] },
36]
38// ── Utils ─────────────────────────────────────────
39function buildWAMessage(state: QuoteState): string {
40 if (!state.plan) return ''
41 const lines = [
42 `Plan: ${state.plan.name} ($${state.plan.price})`,
43 ]
44 if (state.addons.length > 0)
45 lines.push(`Extras: ${state.addons.join(", ")}`)
46 lines.push(`Total estimado: $${state.total}`)
47 return encodeURIComponent(lines.join("\n"))
48}
50// ── Custom Hooks ───────────────────────────────────
51function useScrollNav() {
52 const [scrolled, setScrolled] = useState(false)
53 useEffect(() => {
54 const fn = () => setScrolled(window.scrollY > 60)
55 window.addEventListener('scroll', fn, { passive: true })
56 return () => window.removeEventListener('scroll', fn)
57 }, [])
58 return scrolled
59}
61function useCountdown(deadline: Date) {
62 const [left, setLeft] = useState({ d:0,h:0,m:0,s:0 })
63 useEffect(() => {
64 const tick = () => {
65 const diff = Math.max(0, deadline.getTime()-Date.now())
66 setLeft({ d: Math.floor(diff/86400000),
67 h: Math.floor(diff%86400000/3600000),
68 m: Math.floor(diff%3600000/60000),
69 s: Math.floor(diff%60000/1000) })
70 }
71 tick()
72 const id = setInterval(tick, 1000)
73 return () => clearInterval(id)
74 }, [deadline])
75 return left
76}
78// ── Component ──────────────────────────────// +$200
79export default function VDesingPage() {
80 const scrolled = useScrollNav()
81 const countdown = useCountdown(DEADLINE)
82 const router = useRouter()
83 const heroRef = useRef<HTMLElement>(null)
84 const [state, setState] = useState<QuoteState>({
85 plan: null, addons: [], total: 0, sent: false
86 })
87 const [lang, setLang] = useState<"es"|"en">("es")
89 const selectPlan = useCallback((plan: Plan) => {
90 setState(p => ({ ...p, plan, total: plan.price }))
91 track("plan_selected", { plan: plan.id })
92 }, [])
94 return (
95 <main className="bg-[#08080d] min-h-screen text-white">
97 {/* ── Nav ──────────────────── */}// +$150
98 <nav className={`fixed top-0 w-full z-50
99 backdrop-blur transition-all duration-300
100 border-b border-white/5
101 ${scrolled ? "bg-[#08080d]/90" : ""}`}>
102 <Link href="/">
103 VDesing<span>— 3D Webs PR</span>
104 </Link>
105 <a href={`https://wa.me/${WA_NUMBER}`}
106 className="bg-[#39FF8B] text-black ...">
107 {lang === "es" ? "Cotizar →" : "Get a Quote →"}
108 </a>
109 </nav>
111 {/* ── Hero ──────────────────── */}// +$180
112 <section ref={heroRef} className="hero pt-36 ...">
113 <h1 className="font-serif
114 text-[clamp(2rem,5vw,4rem)]
115 leading-[1.1] tracking-[-0.02em]">
116 Tu negocio en una{" "}
117 <em className="text-[#39FF8B] italic">
118 web profesional
119 </em>{" "}que vende
120 </h1>
121 <p className="text-white/55 max-w-md ...">
122 Diseño, desarrollo, logo, video — un techo.
123 </p>
124 <a href="#paquetes" className="cta-btn ...">
125 VER PAQUETES ↓
126 </a>
127 </section>
129 {/* ── Pricing ─────────────────── */}// +$150
130 <section id="paquetes" className="...">
131 {PLANS.map(plan => (
132 <div key={plan.id}
133 onClick={() => selectPlan(plan)}
134 className={plan.popular ? "featured" : ""}>
135 <span>{plan.name}</span>
136 <span>${plan.price.toLocaleString()}</span>
137 <ul>
138 {plan.features.map(f => (
139 <li key={f}>✓ {f}</li>
140 ))}
141 </ul>
142 </div>
143 ))}
144 </section>
146 </main>
147 )
148}
1export type Locale = 'es' | 'en'
2export type ServiceId = 'basic'|'pro'|'custom'
4export interface SiteConfig {
5 name: string
6 domain: string
7 phone: string
8 waLink: string
9}
11export type NavLink = {
12 href: string
13 label: Record<Locale, string>
14 icon?: string
15}
17export interface Project {
18 slug: string
19 title: string
20 tags: string[]
21 cover: string
22 url?: string
23}
1/* ── Design tokens ─────────────── */
2:root {
3 --bg: oklch(8% 0.01 280);
4 --surface: oklch(12% 0.02 280);
5 --accent: #39FF8B;
6 --purple: #A855F7;
7 --ink: oklch(96% 0.005 280);
8 --muted: oklch(96% 0.005 280 / 0.45);
9 --mono: 'JetBrains Mono', monospace;
10}
12@layer base {
13 body { background: var(--bg); color: var(--ink) }
14 h1, h2, h3 { font-family: 'Fraunces', serif }
15}
17.cta-btn {
18 background: var(--accent);
19 padding: 12px 28px;
20 border-radius: var(--radius);
21 box-shadow: 0 0 24px #39FF8B44;
22}
▋
localhost:3000/servicios/3d
VDesing — 3D Webs PRCOTIZAR →+$150
Puerto Rico · Latam · Desde $100/mes
Tu negocio en una web profesional que vende
Diseño, desarrollo, logo, video — todo bajo un mismo techo.
+$180VER PAQUETES ↓
Paquetes — pago único+$150
Básico
$680
✓Landing page
✓Hosting incluido
✓WhatsApp + SSL
✓Entrega 5-7 días
Más popular
Pro
$1,280
✓3 páginas
✓Logo incluido
✓Video promo 60s
✓SEO + WhatsApp
Cotización en vivo
Arquitectura + lógica$200
Nav + sistema de diseño$150
Hero + animaciones$180
Pricing + SEO + deploy$150
Total estimado$0
Bajá y mirá cómo el código se vuelve web ↓