Estado do disco em 14/10/2026, sem filtrar. Inclui as copias .sync-conflict-* do Syncthing de 07/10 e os 15 arquivos que o Syncthing apagou; todo esse conteudo ja existia em outros commits. So havia fora do Git: AGENTS.md, CLAUDE.md e a alteracao em data/project-health.json.
This commit is contained in:
1 parent
b2f3899dc2
commit
dfcadc71fa
77 files changed
+6944
-2419
No files matched your search
+202
-223
@@ -1,252 +1,231 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowUpRight, Mail, MapPin } from "lucide-react";
|
||||
import type { FormEvent } from "react";
|
||||
import { motion, type Variants } from "motion/react";
|
||||
import type React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { trackWhatsAppOpen } from "@/lib/analytics";
|
||||
import { useReducedMotion } from "@/app/hooks/useReducedMotion";
|
||||
import { buildWhatsAppUrl, getWhatsAppDisplayNumber } from "@/lib/whatsapp";
|
||||
import WhatsAppLink from "./WhatsAppLink";
|
||||
|
||||
// WhatsApp brand silhouette from Simple Icons (simple-icons/simple-icons).
|
||||
function WhatsAppMark({ className }: { className: string }) {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className={className}
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
>
|
||||
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
import { DrawLine } from "./animations/DrawLine";
|
||||
import MagneticButton from "./cinematic/MagneticButton";
|
||||
import { Section } from "./Section";
|
||||
|
||||
export default function Contact() {
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
const [whatsAppDisplay, setWhatsAppDisplay] = useState("WhatsApp");
|
||||
|
||||
useEffect(() => {
|
||||
setWhatsAppDisplay(getWhatsAppDisplayNumber());
|
||||
}, []);
|
||||
|
||||
const fieldClassName =
|
||||
"mt-sp-2 w-full min-w-0 rounded-lg border border-white/15 bg-black/25 px-sp-4 py-sp-3 font-display text-base leading-6 text-white placeholder:text-white/40 focus-visible:border-[var(--slash)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--slash)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--ink)]";
|
||||
const labelClassName = "block font-display text-sm font-medium text-white/85";
|
||||
"mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.06)] px-sp-4 py-[14px] text-[13px] leading-6 text-white outline-none transition-[border-color,box-shadow] focus-visible:border-[var(--slash)] focus-visible:ring-2 focus-visible:ring-[rgba(204,255,0,0.34)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--ink)]";
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
subject: "Sistemas web sob medida",
|
||||
subject: "full-stack",
|
||||
message: "",
|
||||
});
|
||||
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (!e.currentTarget.reportValidity()) return;
|
||||
const messageTemplate = `Olá, Evandro! Quero conversar sobre um projeto.\n\nNome: ${formData.name}\nE-mail: ${formData.email}\nTipo de projeto: ${formData.subject}\n\nContexto, objetivo e prazo:\n${formData.message}\n\nContato iniciado pelo site evandro.dev.br.`;
|
||||
window.open(
|
||||
buildWhatsAppUrl(messageTemplate),
|
||||
"_blank",
|
||||
"noopener,noreferrer",
|
||||
);
|
||||
trackWhatsAppOpen({ service: "Contato", placement: "contact_form" });
|
||||
|
||||
const messageTemplate = `*NOVA SOLICITACAO DE PROJETO*\n\n*Origem:* Portfolio Profissional\n*Prioridade:* Alta\n\n---\n*CLIENTE:* ${formData.name}\n*EMAIL:* ${formData.email}\n*AREA:* ${formData.subject.toUpperCase()}\n\n*DESCRICAO:*\n"${formData.message}"\n---\n_Mensagem gerada via Evandro.dev | Garuva, SC_`;
|
||||
|
||||
const whatsappUrl = buildWhatsAppUrl(messageTemplate);
|
||||
|
||||
window.open(whatsappUrl, "_blank", "noopener,noreferrer");
|
||||
};
|
||||
|
||||
const gridVariants: Variants = {
|
||||
hidden: {},
|
||||
visible: {
|
||||
transition: {
|
||||
delayChildren: 0.05,
|
||||
staggerChildren: 0.08,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const cardVariants: Variants = {
|
||||
hidden: shouldReduceMotion
|
||||
? { opacity: 0 }
|
||||
: { opacity: 0, y: 18, clipPath: "inset(100% 0 0 0)" },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
clipPath: "inset(0% 0 0 0)",
|
||||
transition: shouldReduceMotion
|
||||
? { duration: 0.25 }
|
||||
: { duration: 0.75, ease: [0.16, 1, 0.3, 1] },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
<Section
|
||||
id="contact"
|
||||
aria-labelledby="contact-title"
|
||||
className="ds-section ds-section-dark"
|
||||
eyebrow="Contact"
|
||||
title="Consultoria técnica para software, arquitetura e integrações críticas"
|
||||
description="Fale comigo se você precisa de engenharia de software, consultoria técnica, arquitetura de software ou apoio em projetos com Next.js, Tauri, Rust e IoT."
|
||||
dark
|
||||
disableChildrenAnimation
|
||||
>
|
||||
<div className="ds-section-shell grid items-start gap-sp-10 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:gap-sp-16">
|
||||
<div className="min-w-0">
|
||||
<p className="ds-eyebrow">Contato</p>
|
||||
<h2
|
||||
id="contact-title"
|
||||
className="ds-section-title mt-sp-4 max-w-[19ch] text-balance"
|
||||
>
|
||||
Vamos conversar sobre o que sua empresa precisa.
|
||||
</h2>
|
||||
<p className="mt-sp-5 max-w-[44ch] font-display text-base leading-8 text-white/70">
|
||||
Conte o que você quer resolver. Pode ser um projeto novo, uma
|
||||
melhoria ou uma integração. Não precisa chegar com a solução
|
||||
definida.
|
||||
</p>
|
||||
<div className="mt-sp-8 border-l-2 border-[var(--slash)] pl-sp-5">
|
||||
<h3 className="font-display text-lg font-semibold text-white">
|
||||
Você fala direto com quem desenvolve.
|
||||
</h3>
|
||||
<p className="mt-sp-2 max-w-[44ch] font-display text-sm leading-7 text-white/65">
|
||||
Sou Evandro. A primeira conversa é para entender sua necessidade;
|
||||
escopo, prazo e proposta vêm depois.
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-sp-8 divide-y divide-white/10 border-y border-white/10">
|
||||
<WhatsAppLink
|
||||
service="Contato"
|
||||
placement="contact_direct"
|
||||
className="group flex min-h-20 items-center gap-sp-4 rounded-sm py-sp-5 text-white no-underline"
|
||||
>
|
||||
<span className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-[#25d366]/10 text-[#25d366]">
|
||||
<WhatsAppMark className="h-6 w-6" />
|
||||
</span>
|
||||
<span className="min-w-0 flex-1 font-display">
|
||||
<span className="block text-sm font-semibold text-white group-hover:text-[#25d366]">
|
||||
Prefere conversar direto?
|
||||
</span>
|
||||
<span className="mt-1 block text-sm text-white/65">
|
||||
WhatsApp · {whatsAppDisplay}
|
||||
</span>
|
||||
</span>
|
||||
<ArrowUpRight
|
||||
className="h-5 w-5 shrink-0 text-white/50 group-hover:text-[#25d366]"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</WhatsAppLink>
|
||||
<a
|
||||
href="mailto:[email protected]"
|
||||
className="group flex min-h-16 items-center gap-sp-4 rounded-sm py-sp-5 text-white/65 no-underline hover:text-white focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[var(--slash)]"
|
||||
>
|
||||
<Mail className="h-5 w-5 shrink-0" aria-hidden="true" />
|
||||
<span className="min-w-0 break-all font-display text-sm">
|
||||
evandrofonsecajunior@gmail.com
|
||||
</span>
|
||||
<ArrowUpRight
|
||||
className="ml-auto h-4 w-4 shrink-0"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<p className="mt-sp-5 flex items-start gap-sp-3 font-display text-sm leading-6 text-white/55">
|
||||
<MapPin className="mt-0.5 h-4 w-4 shrink-0" aria-hidden="true" />
|
||||
Garuva, Santa Catarina. Atendimento remoto em todo o Brasil.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
aria-labelledby="contact-form-title"
|
||||
className="min-w-0 rounded-2xl border border-white/12 bg-white/[0.035] p-sp-5 sm:p-sp-8"
|
||||
<motion.div
|
||||
className="ds-grid-2"
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, amount: 0.2 }}
|
||||
variants={gridVariants}
|
||||
>
|
||||
<motion.div
|
||||
className="ds-card"
|
||||
variants={cardVariants}
|
||||
whileHover={
|
||||
shouldReduceMotion
|
||||
? undefined
|
||||
: {
|
||||
y: -4,
|
||||
boxShadow: "0 20px 42px rgba(0, 0, 0, 0.4)",
|
||||
}
|
||||
}
|
||||
whileTap={shouldReduceMotion ? undefined : { scale: 0.995 }}
|
||||
transition={{ type: "spring", stiffness: 180, damping: 18 }}
|
||||
>
|
||||
<div className="mb-sp-6 flex items-start gap-sp-4 border-b border-white/10 pb-sp-6">
|
||||
<span className="flex h-12 w-12 shrink-0 items-center justify-center rounded-xl bg-[#25d366] text-[#071b10]">
|
||||
<WhatsAppMark className="h-7 w-7" />
|
||||
</span>
|
||||
<div>
|
||||
<h3
|
||||
id="contact-form-title"
|
||||
className="font-display text-xl font-semibold leading-7 text-white"
|
||||
>
|
||||
Prepare sua mensagem
|
||||
</h3>
|
||||
<p className="mt-1 font-display text-sm leading-6 text-white/65">
|
||||
Você revisa no WhatsApp antes de enviar.
|
||||
</p>
|
||||
</div>
|
||||
<div className="ds-kicker" data-reel="left">
|
||||
Availability
|
||||
</div>
|
||||
<div className="space-y-sp-5">
|
||||
<div className="grid gap-sp-5 xl:grid-cols-2">
|
||||
<div>
|
||||
<label htmlFor="contact-name" className={labelClassName}>
|
||||
Nome completo
|
||||
</label>
|
||||
<input
|
||||
id="contact-name"
|
||||
name="name"
|
||||
required
|
||||
type="text"
|
||||
autoComplete="name"
|
||||
placeholder="Como posso te chamar?"
|
||||
value={formData.name}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, name: e.target.value })
|
||||
}
|
||||
className={fieldClassName}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-email" className={labelClassName}>
|
||||
E-mail
|
||||
</label>
|
||||
<input
|
||||
id="contact-email"
|
||||
name="email"
|
||||
required
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
placeholder="[email protected]"
|
||||
value={formData.email}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, email: e.target.value })
|
||||
}
|
||||
className={fieldClassName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-subject" className={labelClassName}>
|
||||
Tipo de projeto
|
||||
</label>
|
||||
<select
|
||||
id="contact-subject"
|
||||
name="subject"
|
||||
value={formData.subject}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, subject: e.target.value })
|
||||
}
|
||||
className={`${fieldClassName} [color-scheme:dark]`}
|
||||
>
|
||||
<option value="Sistemas web sob medida">
|
||||
Sistemas web sob medida
|
||||
</option>
|
||||
<option value="Aplicativos">Aplicativos</option>
|
||||
<option value="Integrações e automações">
|
||||
Integrações e automações
|
||||
</option>
|
||||
<option value="Evolução de um sistema existente">
|
||||
Evolução de um sistema existente
|
||||
</option>
|
||||
<option value="Ainda preciso definir">
|
||||
Ainda preciso definir
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-message" className={labelClassName}>
|
||||
Contexto do projeto
|
||||
</label>
|
||||
<textarea
|
||||
id="contact-message"
|
||||
name="message"
|
||||
required
|
||||
rows={4}
|
||||
autoComplete="off"
|
||||
placeholder="O que você precisa resolver? Qual resultado espera e existe um prazo?"
|
||||
aria-describedby="contact-privacy-note"
|
||||
value={formData.message}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, message: e.target.value })
|
||||
}
|
||||
className={`${fieldClassName} min-h-32 resize-y`}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="flex min-h-14 w-full items-center justify-center gap-sp-3 rounded-lg bg-[#25d366] px-sp-4 py-sp-4 font-display text-base font-semibold leading-6 text-[#071b10] transition-colors hover:bg-[#54e58b] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-[#25d366] motion-reduce:transition-none"
|
||||
>
|
||||
<WhatsAppMark className="h-6 w-6 shrink-0" />
|
||||
Continuar no WhatsApp
|
||||
<ArrowUpRight className="h-5 w-5 shrink-0" aria-hidden="true" />
|
||||
</button>
|
||||
<p
|
||||
id="contact-privacy-note"
|
||||
className="font-display text-xs leading-6 text-white/55"
|
||||
>
|
||||
Nada é enviado automaticamente. O WhatsApp abre com a mensagem
|
||||
para você revisar. Não inclua senhas nem dados pessoais de
|
||||
clientes.
|
||||
</p>
|
||||
<DrawLine delay={0.04} />
|
||||
<h3 className="ds-card-title" data-reel="top">
|
||||
Resposta inicial em ate 24h
|
||||
</h3>
|
||||
<p className="ds-copy" data-reel="right">
|
||||
Ideal para discovery tecnico, revisao de arquitetura, rescue de
|
||||
projeto, performance ou construcao de produto com ownership real.
|
||||
</p>
|
||||
<div
|
||||
className="mt-sp-6 space-y-sp-4 text-[13px] leading-7 text-[rgba(255,255,255,.85)]"
|
||||
data-reel-stagger="bottom"
|
||||
>
|
||||
<div>WhatsApp: {whatsAppDisplay}</div>
|
||||
<div>E-mail: evandrofonsecajunior@gmail.com</div>
|
||||
<div>Base: Garuva, Santa Catarina | atuacao remota</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<div
|
||||
className="mt-sp-6 border-t border-[rgba(255,255,255,.08)] pt-sp-4 text-[12px] leading-6 text-[rgba(255,255,255,.75)]"
|
||||
data-reel="fade"
|
||||
>
|
||||
Envie contexto, prazo e objetivo. Eu cuido de transformar isso em
|
||||
conversa tecnica objetiva.
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
<motion.form
|
||||
onSubmit={handleSubmit}
|
||||
className="ds-card space-y-sp-5"
|
||||
variants={cardVariants}
|
||||
whileHover={
|
||||
shouldReduceMotion
|
||||
? undefined
|
||||
: {
|
||||
y: -4,
|
||||
boxShadow: "0 20px 42px rgba(0, 0, 0, 0.4)",
|
||||
}
|
||||
}
|
||||
transition={{ type: "spring", stiffness: 180, damping: 18 }}
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="contact-name"
|
||||
className="block text-[12px] font-medium text-[rgba(255,255,255,.85)]"
|
||||
>
|
||||
Nome completo
|
||||
</label>
|
||||
<input
|
||||
id="contact-name"
|
||||
name="name"
|
||||
required
|
||||
type="text"
|
||||
autoComplete="name"
|
||||
value={formData.name}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, name: e.target.value })
|
||||
}
|
||||
className={fieldClassName}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="contact-email"
|
||||
className="block text-[12px] font-medium text-[rgba(255,255,255,.85)]"
|
||||
>
|
||||
E-mail
|
||||
</label>
|
||||
<input
|
||||
id="contact-email"
|
||||
name="email"
|
||||
required
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
value={formData.email}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, email: e.target.value })
|
||||
}
|
||||
className={fieldClassName}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="contact-subject"
|
||||
className="block text-[12px] font-medium text-[rgba(255,255,255,.85)]"
|
||||
>
|
||||
Tipo de projeto
|
||||
</label>
|
||||
<select
|
||||
id="contact-subject"
|
||||
name="subject"
|
||||
value={formData.subject}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, subject: e.target.value })
|
||||
}
|
||||
className={fieldClassName}
|
||||
style={{ color: "#fff", backgroundColor: "#1a1a1a" }}
|
||||
>
|
||||
<option value="full-stack">Desenvolvimento Full-Stack</option>
|
||||
<option value="cloud">Cloud & Infrastructure</option>
|
||||
<option value="iot">Internet of Things (IoT)</option>
|
||||
<option value="consultancy">Consultoria Técnica Sênior</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="contact-message"
|
||||
className="block text-[12px] font-medium text-[rgba(255,255,255,.85)]"
|
||||
>
|
||||
Contexto do projeto
|
||||
</label>
|
||||
<textarea
|
||||
id="contact-message"
|
||||
name="message"
|
||||
required
|
||||
rows={6}
|
||||
autoComplete="off"
|
||||
value={formData.message}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, message: e.target.value })
|
||||
}
|
||||
className={`${fieldClassName} resize-none`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<MagneticButton
|
||||
as="button"
|
||||
type="submit"
|
||||
className="ds-link ds-link-accent min-h-12 border-0"
|
||||
strength={0.2}
|
||||
>
|
||||
Enviar briefing pelo WhatsApp
|
||||
</MagneticButton>
|
||||
</motion.form>
|
||||
</motion.div>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user