feat: Implement initial portfolio website structure with core components and a new post creator tool.
This commit is contained in:
1 parent
036363b521
commit
aa07d6faeb
15 files changed
+1337
-1855
No files matched your search
+98
-198
@@ -1,223 +1,123 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Send, User, Mail, MessageSquare, Sparkles } from "lucide-react";
|
||||
import { ShimmerButton as MagicShimmerButton } from "@/components/magicui/shimmer-button";
|
||||
import Squares from "@/components/Squares";
|
||||
import type React from "react";
|
||||
import { useState } from "react";
|
||||
import { Section } from "./Section";
|
||||
|
||||
// --- CONFIGURAÇÃO DE ENGENHARIA ---
|
||||
// Substitua pelo seu número real: CódigoPaís + DDD + Número (sem espaços ou símbolos)
|
||||
const WHATSAPP_NUMBER = "5547992742365";
|
||||
|
||||
interface FormData {
|
||||
name: string;
|
||||
email: string;
|
||||
subject: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper Component: Resolve o erro de tipagem TS2322 (IntrinsicAttributes)
|
||||
* Estendemos a interface para aceitar propriedades de estilo customizadas.
|
||||
*/
|
||||
interface ExtendedShimmerProps extends React.ComponentProps<typeof MagicShimmerButton> {
|
||||
shimmerColor?: string;
|
||||
shimmerSize?: string;
|
||||
type?: "button" | "submit" | "reset";
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const CustomShimmerButton = ({
|
||||
children,
|
||||
className,
|
||||
shimmerColor = "#3b82f6",
|
||||
shimmerSize = "0.1em",
|
||||
...props
|
||||
}: ExtendedShimmerProps) => {
|
||||
return (
|
||||
<MagicShimmerButton
|
||||
{...props}
|
||||
className={className}
|
||||
// @ts-ignore - Ignora restrição de tipos da lib original se necessário
|
||||
shimmerColor={shimmerColor}
|
||||
shimmerSize={shimmerSize}
|
||||
>
|
||||
{children}
|
||||
</MagicShimmerButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Contact() {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
email: "",
|
||||
subject: "full-stack",
|
||||
message: "",
|
||||
});
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 800));
|
||||
|
||||
// Definimos os emojis via Unicode Escape para máxima compatibilidade
|
||||
const icons = {
|
||||
rocket: "\u{1F680}",
|
||||
person: "\u{1F464}",
|
||||
email: "\u{1F4E7}",
|
||||
tools: "\u{1F6E0}",
|
||||
chat: "\u{1F4AC}"
|
||||
};
|
||||
|
||||
const messageTemplate = `*NOVA SOLICITAÇÃO DE PROJETO*
|
||||
|
||||
*Origem:* Portfólio Profissional
|
||||
*Prioridade:* Alta (Lead Qualificado)
|
||||
|
||||
---
|
||||
*CLIENTE:* ${formData.name}
|
||||
*EMAIL:* ${formData.email}
|
||||
*ÁREA:* ${formData.subject.toUpperCase()}
|
||||
|
||||
*DESCRIÇÃO:*
|
||||
"${formData.message}"
|
||||
---
|
||||
_Mensagem gerada via Evandro.dev | Garuva, SC_`;
|
||||
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 encodedMessage = encodeURIComponent(messageTemplate);
|
||||
const whatsappUrl = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodedMessage}`;
|
||||
|
||||
window.open(whatsappUrl, "_blank", "noopener,noreferrer");
|
||||
setIsSubmitting(false);
|
||||
};
|
||||
|
||||
const inputStyles =
|
||||
"w-full bg-black/40 border border-white/5 rounded-xl px-4 py-3 text-slate-200 placeholder:text-slate-600 focus:border-blue-500/50 focus:ring-2 focus:ring-blue-500/10 focus:bg-black/60 outline-none transition-all duration-300 font-mono text-sm backdrop-blur-sm group-hover:border-white/10";
|
||||
const labelStyles =
|
||||
"text-[10px] font-bold text-slate-500 uppercase tracking-widest mb-2 flex items-center gap-2 transition-colors group-hover:text-slate-400";
|
||||
|
||||
return (
|
||||
<section id="contact" className="w-full py-24 relative">
|
||||
|
||||
|
||||
<div className="w-full max-w-4xl mx-auto px-6 relative z-10">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
className="relative bg-zinc-900/40 backdrop-blur-xl border border-white/10 rounded-3xl p-8 md:p-12 shadow-2xl overflow-hidden"
|
||||
>
|
||||
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-blue-500/0 via-blue-500/50 to-blue-500/0" />
|
||||
|
||||
<div className="mb-10 text-center space-y-2">
|
||||
<h2 className="text-3xl md:text-4xl font-bold bg-clip-text text-transparent bg-gradient-to-b from-white to-white/60">
|
||||
Vamos Construir o Futuro
|
||||
</h2>
|
||||
<p className="text-slate-400 text-sm md:text-base max-w-lg mx-auto">
|
||||
Descreva seu desafio técnico. Retorno com uma arquitetura sólida em até 24h.
|
||||
</p>
|
||||
<Section
|
||||
id="contact"
|
||||
eyebrow="CONTACT_PROTOCOL.init"
|
||||
title="Vamos discutir o próximo sistema"
|
||||
description="Descreva o contexto, o gargalo ou o produto. O contato abre direto no WhatsApp com briefing estruturado."
|
||||
dark
|
||||
>
|
||||
<div className="ds-grid-2">
|
||||
<div className="ds-card">
|
||||
<div className="ds-kicker">Response SLA</div>
|
||||
<h3 className="ds-card-title">Retorno inicial em até 24h</h3>
|
||||
<p className="ds-copy">
|
||||
Ideal para discovery técnico, revisão de arquitetura, rescue de
|
||||
projeto, otimização de performance ou construção de produto do
|
||||
zero.
|
||||
</p>
|
||||
<div className="mt-sp-6 space-y-sp-4 text-[12px] leading-7 text-[rgba(255,255,255,.7)]">
|
||||
<div>WhatsApp: +55 47 99274-2365</div>
|
||||
<div>E-mail: evandrofonsecajunior@gmail.com</div>
|
||||
<div>Base: Garuva, Santa Catarina · atuação remota</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-8 relative">
|
||||
<div className="grid md:grid-cols-2 gap-8">
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<User className="w-3 h-3 text-blue-500" /> NOME COMPLETO
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
placeholder="Ex: Alan Turing"
|
||||
className={inputStyles}
|
||||
value={formData.name}
|
||||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<Mail className="w-3 h-3 text-blue-500" /> E-MAIL CORPORATIVO
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
type="email"
|
||||
placeholder="[email protected]"
|
||||
className={inputStyles}
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<Sparkles className="w-3 h-3 text-blue-500" /> TIPO DE PROJETO
|
||||
</label>
|
||||
<div className="relative">
|
||||
<select
|
||||
className={`${inputStyles} appearance-none cursor-pointer`}
|
||||
value={formData.subject}
|
||||
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
|
||||
>
|
||||
<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 className="absolute right-4 top-1/2 -translate-y-1/2 pointer-events-none text-slate-500">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3 group">
|
||||
<label className={labelStyles}>
|
||||
<MessageSquare className="w-3 h-3 text-blue-500" /> DETALHES DO PROJETO
|
||||
</label>
|
||||
<textarea
|
||||
required
|
||||
rows={5}
|
||||
placeholder="Descreva os requisitos técnicos e objetivos do sistema..."
|
||||
className={`${inputStyles} resize-none`}
|
||||
value={formData.message}
|
||||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<motion.div whileHover={{ scale: 1.01 }} whileTap={{ scale: 0.99 }} className="pt-6">
|
||||
<CustomShimmerButton
|
||||
type="submit"
|
||||
className="w-full h-14 rounded-xl shadow-lg shadow-blue-500/20"
|
||||
shimmerColor="#60a5fa"
|
||||
shimmerSize="0.1em"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
<div className="flex flex-row items-center justify-center gap-3 w-full h-full">
|
||||
{isSubmitting ? (
|
||||
<div className="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||||
) : (
|
||||
<>
|
||||
<span className="text-white font-bold tracking-widest uppercase text-xs md:text-sm">
|
||||
Iniciar Protocolo de Contato
|
||||
</span>
|
||||
<Send className="w-4 h-4 text-white" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CustomShimmerButton>
|
||||
</motion.div>
|
||||
|
||||
<footer className="pt-2">
|
||||
<p className="text-[10px] text-center text-slate-600 font-mono uppercase tracking-widest opacity-60">
|
||||
Secured by End-to-End Encryption
|
||||
</p>
|
||||
</footer>
|
||||
</form>
|
||||
</motion.div>
|
||||
<form onSubmit={handleSubmit} className="ds-card space-y-sp-5">
|
||||
<div>
|
||||
<label htmlFor="contact-name" className="ds-kicker block">
|
||||
Nome completo
|
||||
</label>
|
||||
<input
|
||||
id="contact-name"
|
||||
required
|
||||
type="text"
|
||||
value={formData.name}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, name: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-email" className="ds-kicker block">
|
||||
E-mail corporativo
|
||||
</label>
|
||||
<input
|
||||
id="contact-email"
|
||||
required
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, email: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="contact-subject" className="ds-kicker block">
|
||||
Tipo de projeto
|
||||
</label>
|
||||
<select
|
||||
id="contact-subject"
|
||||
value={formData.subject}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, subject: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
>
|
||||
<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="ds-kicker block">
|
||||
Detalhes do projeto
|
||||
</label>
|
||||
<textarea
|
||||
id="contact-message"
|
||||
required
|
||||
rows={6}
|
||||
value={formData.message}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, message: e.target.value })
|
||||
}
|
||||
className="mt-sp-2 w-full resize-none border border-[rgba(255,255,255,.12)] bg-[rgba(255,255,255,.03)] px-sp-4 py-[14px] text-[12px] text-white outline-none transition-colors focus:border-slash"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" className="ds-link ds-link-accent border-0">
|
||||
Iniciar protocolo de contato
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user