Initial commit

This commit is contained in:
marciobever 2026-05-15 14:38:11 +00:00
commit 7cf05467b4
44 changed files with 13519 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

20
Template-01/README.md Normal file
View file

@ -0,0 +1,20 @@
<div align="center">
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
</div>
# Run and deploy your AI Studio app
This contains everything you need to run your app locally.
View your app in AI Studio: https://ai.studio/apps/3834725f-5856-4096-8bdd-9346114a9c47
## Run Locally
**Prerequisites:** Node.js
1. Install dependencies:
`npm install`
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
3. Run the app:
`npm run dev`

22
Template-01/fix_links.js Normal file
View file

@ -0,0 +1,22 @@
const fs = require('fs');
const file = 'src/data/articles.tsx';
let content = fs.readFileSync(file, 'utf8');
const replacements = [
['<Link to="/">\n análise de valorização do Jardim Europa', '<Link to="/artigo/valorizacao-jardim-europa">\n análise de valorização do Jardim Europa'],
['<Link to="/">novo conceito de luxo vertical', '<Link to="/artigo/novo-luxo-sp">novo conceito de luxo vertical'],
['<Link to="/">\n residência no Jardim Europa', '<Link to="/artigo/residencial-jardim-europa-01">\n residência no Jardim Europa'],
['<Link to="/">leia o guia de aquisição', '<Link to="/artigo/guia-aquisicao-jardim-europa">leia o guia de aquisição'],
['<Link to="/">\n como o retrofit pode impactar esse risco legal', '<Link to="/artigo/importancia-retrofit">\n como o retrofit pode impactar esse risco legal'],
['<Link to="/">casa na Fazenda Boa Vista', '<Link to="/artigo/fazenda-boa-vista">casa na Fazenda Boa Vista'],
['<Link to="/">arquitetura', '<Link to="/artigo/tendencias-arquitetura-2026">arquitetura'],
['<Link to="/">off-market insights', '<Link to="/artigo/mercado-off-market">off-market insights'],
['<Link to="/">importância do retrofit', '<Link to="/artigo/importancia-retrofit">importância do retrofit']
];
for (const [search, replace] of replacements) {
content = content.replace(search, replace);
}
fs.writeFileSync(file, content);
console.log("Done");

50
Template-01/index.html Normal file
View file

@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Google AI Studio App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<!-- Theme Auto-Updater injected by autoblogia -->
<script>
window.addEventListener('message', (event) => {
if (event.data && event.data.type === 'UPDATE_APPEARANCE') {
const { primaryColor, backgroundColor, fontFamily } = event.data.settings;
const root = document.documentElement;
const style = root.style;
if (primaryColor) {
style.setProperty('--primary', primaryColor);
style.setProperty('--color-primary', primaryColor);
style.setProperty('--color-tech-primary', primaryColor);
style.setProperty('--color-seo-primary', primaryColor);
style.setProperty('--color-finance-primary', primaryColor);
style.setProperty('--color-recipe-primary', primaryColor);
style.setProperty('--color-health-primary', primaryColor);
style.setProperty('--color-corporate-primary', primaryColor);
}
if (backgroundColor) {
style.setProperty('--background', backgroundColor);
style.setProperty('--color-bg', backgroundColor);
style.setProperty('--color-tech-surface', backgroundColor);
style.setProperty('--color-seo-surface', backgroundColor);
style.backgroundColor = backgroundColor;
}
if (fontFamily) {
const fontString = '"' + fontFamily + '", sans-serif';
style.setProperty('--font-family', fontString);
style.setProperty('--font-sans', fontString);
style.fontFamily = fontString;
}
}
});
// Ping parent window that we are ready
window.parent.postMessage({ type: 'IFRAME_READY' }, '*');
</script>
</body>
</html>

View file

@ -0,0 +1,6 @@
{
"name": "Rafael Fontes - Corretor de Imobiliária Premium",
"description": "Website premium para corretor de imóveis focado em propriedades de alto padrão e luxo.",
"requestFramePermissions": [],
"majorCapabilities": []
}

4480
Template-01/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

38
Template-01/package.json Normal file
View file

@ -0,0 +1,38 @@
{
"name": "react-example",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --port=3000 --host=0.0.0.0",
"build": "vite build",
"preview": "vite preview",
"clean": "rm -rf dist",
"lint": "tsc --noEmit"
},
"dependencies": {
"@google/genai": "^1.29.0",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.14",
"@vitejs/plugin-react": "^5.0.4",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"lucide-react": "^0.546.0",
"motion": "^12.23.24",
"react": "^19.0.1",
"react-dom": "^19.0.1",
"react-helmet-async": "^3.0.0",
"react-icons": "^5.6.0",
"react-router-dom": "^7.15.0",
"vite": "^6.2.3"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^22.14.0",
"autoprefixer": "^10.4.21",
"tailwindcss": "^4.1.14",
"tsx": "^4.21.0",
"typescript": "~5.8.2",
"vite": "^6.2.3"
}
}

View file

@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://rafaelfontes.com.br/sitemap.xml

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://rafaelfontes.com.br/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://rafaelfontes.com.br/portfolio</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://rafaelfontes.com.br/assessoria</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://rafaelfontes.com.br/insights</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://rafaelfontes.com.br/contato</loc>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
</urlset>

768
Template-01/src/App.tsx Normal file
View file

@ -0,0 +1,768 @@
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "motion/react";
import {
Menu,
X,
ArrowRight,
Instagram,
Linkedin,
MapPin,
ArrowLeft,
MessageCircle,
UserCheck,
Briefcase,
ShieldCheck,
Search,
} from "lucide-react";
import { Routes, Route, Link, useParams, useLocation } from "react-router-dom";
import { Helmet } from "react-helmet-async";
import { articles, ArticleType, Article } from "./data/articles";
import { PortfolioPage } from "./pages/PortfolioPage";
import { AssessoriaPage } from "./pages/AssessoriaPage";
import { InsightsPage } from "./pages/InsightsPage";
import { ContatoPage } from "./pages/ContatoPage";
import { Analytics } from "./components/Analytics";
export default function App() {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isSearchOpen, setIsSearchOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const location = useLocation();
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
useEffect(() => {
window.scrollTo(0, 0);
setIsMobileMenuOpen(false);
setIsSearchOpen(false);
setSearchQuery("");
}, [location.pathname]);
// Filter articles for the homepage feeds
const propertiesAsArticles = articles.filter((a) => a.type === "property");
const marketInsights = articles.filter((a) => a.type === "insight");
const searchResults = articles.filter(a =>
a.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
a.excerpt.toLowerCase().includes(searchQuery.toLowerCase()) ||
(a.details?.location && a.details.location.toLowerCase().includes(searchQuery.toLowerCase()))
);
const isArticleRoute = location.pathname.startsWith('/artigo/');
return (
<div className="min-h-screen bg-zinc-50 text-zinc-900 selection:bg-brand-gold selection:text-white font-sans overflow-x-hidden">
<Analytics />
<Helmet>
<title>Rafael Fontes | Corretor de Imóveis Premium</title>
<meta name="description" content="Rafael Fontes é um corretor de imóveis especializado no mercado premium e de luxo. Acesso exclusivo a propriedades off-market em São Paulo." />
<meta name="keywords" content="corretor de luxo, imóveis premium, são paulo, off-market, mansões, apartamentos alto padrão" />
<meta property="og:title" content="Rafael Fontes | Corretor de Imóveis Premium" />
<meta property="og:description" content="Rafael Fontes é um corretor de imóveis especializado no mercado premium e de luxo. Acesso exclusivo a propriedades off-market em São Paulo." />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Rafael Fontes | Corretor de Imóveis Premium" />
<meta name="twitter:description" content="Rafael Fontes é um corretor de imóveis especializado no mercado premium e de luxo em São Paulo." />
<link rel="canonical" href="https://rafaelfontes.com.br" />
</Helmet>
{/* HEADER */}
<nav
className={`fixed w-full z-50 transition-all duration-500 border-b ${
isScrolled || isArticleRoute
? "bg-zinc-50/95 backdrop-blur-md border-zinc-200 py-4"
: "bg-transparent border-transparent py-8"
}`}
>
<div className="max-w-7xl mx-auto px-6 lg:px-8 flex justify-between items-center">
<div className="flex items-center gap-6">
<Link to="/" className="flex flex-col">
<span className="text-2xl font-serif font-bold tracking-tight text-zinc-900 leading-none">
RAFAEL FONTES
</span>
<span className="text-[10px] uppercase tracking-[0.3em] text-brand-gold font-bold mt-1.5">
Corretor de Imóveis Premium
</span>
</Link>
</div>
{/* Desktop Nav */}
<div className="hidden md:flex items-center gap-8 text-xs uppercase tracking-[0.15em] font-semibold text-zinc-600">
<Link
to="/portfolio"
className="hover:text-brand-gold transition-colors"
>
Portfólio
</Link>
<Link
to="/assessoria"
className="hover:text-brand-gold transition-colors"
>
A Assessoria
</Link>
<Link
to="/insights"
className="hover:text-brand-gold transition-colors"
>
Insights
</Link>
<Link
to="/contato"
className="hover:text-brand-gold transition-colors"
>
Contato
</Link>
<button
onClick={() => setIsSearchOpen(true)}
className="hover:text-brand-gold transition-colors flex items-center justify-center p-2 -mr-2"
aria-label="Buscar"
>
<Search size={18} />
</button>
</div>
<div className="md:hidden flex items-center gap-4">
<button
onClick={() => setIsSearchOpen(true)}
className="text-zinc-900 flex items-center justify-center"
aria-label="Buscar"
>
<Search size={22} />
</button>
<button
className="text-zinc-900"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</div>
{/* Mobile Dropdown */}
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: "auto" }}
exit={{ opacity: 0, height: 0 }}
className="absolute top-full left-0 w-full bg-zinc-50 border-b border-zinc-200 overflow-hidden md:hidden shadow-xl shadow-black/5"
>
<div className="flex flex-col px-6 py-8 gap-6 text-sm uppercase tracking-widest font-semibold text-zinc-600">
<Link
to="/portfolio"
onClick={() => setIsMobileMenuOpen(false)}
>
Portfólio
</Link>
<Link
to="/assessoria"
onClick={() => setIsMobileMenuOpen(false)}
>
A Assessoria
</Link>
<Link to="/insights" onClick={() => setIsMobileMenuOpen(false)}>
Insights
</Link>
<Link to="/contato" onClick={() => setIsMobileMenuOpen(false)}>
Contato
</Link>
</div>
</motion.div>
)}
</AnimatePresence>
</nav>
{/* SEARCH MODAL */}
<AnimatePresence>
{isSearchOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-[100] bg-zinc-50/95 backdrop-blur-xl flex flex-col pt-32 px-6 lg:px-8"
>
<button
onClick={() => setIsSearchOpen(false)}
className="absolute top-8 right-6 lg:right-8 text-zinc-500 hover:text-zinc-900 transition-colors p-2"
aria-label="Agendar"
>
<X size={32} strokeWidth={1} />
</button>
<div className="max-w-4xl w-full mx-auto flex flex-col h-full">
<div className="relative mb-12">
<input
autoFocus
type="text"
placeholder="Busque por bairro, exclusividade ou insights..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-transparent border-b-2 border-zinc-300 text-3xl md:text-5xl font-serif text-zinc-900 pb-4 focus:outline-none focus:border-brand-gold transition-colors placeholder:text-zinc-300"
/>
<Search className="absolute right-0 bottom-6 text-zinc-300" size={32} />
</div>
<div className="flex-1 overflow-y-auto pb-32">
{searchQuery.length > 2 ? (
<div className="space-y-6">
<h3 className="text-xs uppercase tracking-widest text-zinc-400 font-bold mb-8">Resultados ({searchResults.length})</h3>
{searchResults.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{searchResults.map((result) => (
<Link
key={result.id}
to={`/artigo/${result.id}`}
onClick={() => setIsSearchOpen(false)}
className="group block border border-zinc-200 bg-white p-6 hover:border-brand-gold transition-colors"
>
<div className="text-xs font-bold text-brand-gold uppercase tracking-widest mb-3">
{result.type === 'property' ? 'Portfólio' : 'Insight'}
</div>
<h4 className="font-serif text-xl text-zinc-900 mb-2 group-hover:text-brand-gold transition-colors">{result.title}</h4>
<p className="text-sm font-light text-zinc-600 line-clamp-2">{result.excerpt}</p>
</Link>
))}
</div>
) : (
<p className="text-zinc-500 font-light text-lg">Nenhum resultado encontrado para "{searchQuery}". Tente outros termos.</p>
)}
</div>
) : (
<div className="text-zinc-400 font-light text-lg">
Digite pelo menos 3 caracteres para iniciar a busca.
</div>
)}
</div>
</div>
</motion.div>
)}
</AnimatePresence>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/portfolio" element={<PortfolioPage propertiesAsArticles={propertiesAsArticles} />} />
<Route path="/assessoria" element={<AssessoriaPage />} />
<Route path="/insights" element={<InsightsPage marketInsights={marketInsights} />} />
<Route path="/contato" element={<ContatoPage />} />
<Route path="/artigo/:id" element={<ArticleRoute />} />
</Routes>
{/* FOOTER */}
<footer className="bg-white py-8 text-zinc-900 border-t border-zinc-200 text-center text-xs uppercase tracking-widest text-zinc-500 font-bold">
<div className="max-w-7xl mx-auto px-6 lg:px-8 flex flex-col md:flex-row justify-between items-center gap-4">
<p>&copy; {new Date().getFullYear()} RAFAEL FONTES CRECI 123456-F.</p>
<div className="flex gap-8">
<a href="#" className="hover:text-brand-gold transition-colors">
Políticas de Privacidade
</a>
</div>
</div>
</footer>
{/* Floating WhatsApp Button */}
<AnimatePresence>
{(isScrolled || isArticleRoute) && (
<motion.a
initial={{ opacity: 0, scale: 0.8, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8, y: 20 }}
href="https://wa.me/5511999999999"
target="_blank"
rel="noreferrer"
className="fixed bottom-6 right-6 z-50 bg-[#25D366] text-white p-4 rounded-full shadow-[0_4px_14px_rgba(37,211,102,0.4)] hover:bg-[#22bf5b] transition-colors hover:scale-110 active:scale-95 flex items-center justify-center"
aria-label="Falar no WhatsApp"
>
<svg
viewBox="0 0 24 24"
width="28"
height="28"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<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-.51a12.8 12.8 0 0 0-.57-.01c-.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 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-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 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.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 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z" />
</svg>
</motion.a>
)}
</AnimatePresence>
</div>
);
}
function HomePage() {
const location = useLocation();
useEffect(() => {
if (location.hash) {
const element = document.getElementById(location.hash.substring(1));
if (element) {
element.scrollIntoView({ behavior: "smooth" });
}
}
}, [location]);
return (
<>
<Helmet>
<title>Rafael Fontes | Início</title>
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "RealEstateAgent",
"name": "Rafael Fontes",
"image": "https://images.unsplash.com/photo-1560250097-0b93528c311a?q=80&w=1974&auto=format&fit=crop",
"@id": "https://rafaelfontes.com.br",
"url": "https://rafaelfontes.com.br",
"telephone": "+5511999999999",
"address": {
"@type": "PostalAddress",
"streetAddress": "Av. Brigadeiro Faria Lima, 3477",
"addressLocality": "São Paulo",
"addressRegion": "SP",
"postalCode": "04538-133",
"addressCountry": "BR"
},
"priceRange": "$$$$"
})}
</script>
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Como funciona a assessoria para compra de imóveis?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Busca ativa por todo o mercado. Filtro o ruído, faço as inspeções prévias e entrego relatórios analíticos antes da sua visita."
}
},
{
"@type": "Question",
"name": "O que são imóveis off-market?",
"acceptedAnswer": {
"@type": "Answer",
"text": "São propriedades exclusivas que não são anunciadas publicamente, oferecendo maior privacidade e oportunidades únicas para compradores qualificados."
}
},
{
"@type": "Question",
"name": "Qual é a vantagem de contratar um corretor exclusivo para a venda do meu imóvel?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A exclusividade garante um plano de marketing focado, filtro rigoroso de potenciais compradores e proteção contra a desvalorização do ativo por sobreposição de anúncios no mercado."
}
},
{
"@type": "Question",
"name": "Você atua apenas na venda de imóveis prontos ou também em lançamentos?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Atuo em ambos. Para lançamentos, ofereço antecipação de informações e acesso privilegiado a unidades específicas antes da abertura para o mercado em geral."
}
},
{
"@type": "Question",
"name": "Como é garantido o sigilo durante a negociação?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Trabalho com Acordos de Confidencialidade (NDA) quando necessário e filtro estritamente as informações compartilhadas, protegendo a identidade e o patrimônio de ambas as partes."
}
}
]
})}
</script>
</Helmet>
<section className="pt-40 pb-20 md:pt-52 md:pb-32 px-6 min-h-[90vh] flex items-center">
<div className="max-w-7xl mx-auto flex flex-col md:flex-row gap-12 items-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1, ease: "easeOut" }}
className="w-full md:w-1/2 pr-0 md:pr-12"
>
<div className="flex items-center gap-4 mb-8">
<div className="w-12 h-px bg-brand-gold"></div>
<span className="text-xs uppercase tracking-[0.2em] text-brand-gold font-bold">
Apresentação Profissional
</span>
</div>
<h1 className="text-5xl md:text-6xl lg:text-7xl font-serif text-zinc-900 leading-[1.1] mb-8">
Conectando você aos endereços mais cobiçados.
</h1>
<p className="text-lg md:text-xl text-zinc-600 font-light mb-10 leading-relaxed border-l-2 border-zinc-200 pl-6">
Como corretor especialista no segmento premium, faço mais do que
listar imóveis. Eu documento, analiso e apresento as propriedades
mais requintadas do mercado de forma aprofundada e sigilosa.
</p>
<div className="flex flex-wrap items-center gap-4">
<Link
to="/portfolio"
className="bg-zinc-900 hover:bg-brand-gold text-white px-6 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors inline-block text-center"
>
Portfólio
</Link>
<Link
to="/assessoria"
className="border border-zinc-300 text-zinc-900 hover:border-zinc-900 hover:bg-zinc-900 hover:text-white px-6 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors inline-block text-center"
>
A Assessoria
</Link>
<Link
to="/insights"
className="border border-zinc-300 text-zinc-900 hover:border-zinc-900 hover:bg-zinc-900 hover:text-white px-6 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors inline-block text-center"
>
Insights
</Link>
<Link
to="/contato"
className="border border-zinc-300 text-zinc-900 hover:border-zinc-900 hover:bg-zinc-900 hover:text-white px-6 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors inline-block text-center"
>
Contato
</Link>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1, delay: 0.2, ease: "easeOut" }}
className="w-full md:w-1/2 relative"
>
<div className="aspect-[4/5] md:aspect-square overflow-hidden bg-zinc-200 relative">
<img
src="https://images.unsplash.com/photo-1560250097-0b93528c311a?q=80&w=1974&auto=format&fit=crop"
alt="Rafael Fontes - Retrato"
className="w-full h-full object-cover grayscale origin-top"
/>
<div className="absolute inset-0 bg-gradient-to-t from-zinc-900/60 to-transparent flex items-end p-8">
<div>
<p className="text-white font-serif text-2xl">
Rafael Fontes
</p>
<p className="text-zinc-300 text-sm tracking-widest font-light uppercase mt-1">
CRECI 123456-F
</p>
</div>
</div>
</div>
{/* Stamp / Detail */}
<div className="absolute -bottom-6 -left-6 bg-brand-gold text-white p-6 shadow-xl hidden md:block">
<p className="font-serif text-4xl mb-1">15+</p>
<p className="text-xs uppercase tracking-widest font-bold">
Anos de Mercado
</p>
</div>
</motion.div>
</div>
</section>
{/* DIFERENCIAIS SECTION */}
<section className="py-24 bg-zinc-50 border-t border-zinc-200">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="text-center mb-16">
<span className="text-xs uppercase tracking-[0.2em] text-zinc-400 font-bold block mb-4">
Nossos Pilares
</span>
<h2 className="text-4xl md:text-5xl font-serif text-zinc-900 leading-tight">
Diferenciais
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="bg-white p-10 border border-zinc-200 hover:border-brand-gold transition-colors duration-300"
>
<div className="w-12 h-12 bg-zinc-50 flex items-center justify-center rounded-full mb-8 text-brand-gold">
<UserCheck size={20} />
</div>
<h3 className="text-xl font-serif text-zinc-900 mb-4">
Atendimento Personalizado
</h3>
<p className="text-zinc-600 font-light leading-relaxed">
Cada cliente recebe atenção exclusiva. Compreender profundamente suas necessidades, estilo de vida e expectativas é o ponto de partida para qualquer busca ou negociação.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.2 }}
className="bg-white p-10 border border-zinc-200 hover:border-brand-gold transition-colors duration-300"
>
<div className="w-12 h-12 bg-zinc-50 flex items-center justify-center rounded-full mb-8 text-brand-gold">
<Briefcase size={20} />
</div>
<h3 className="text-xl font-serif text-zinc-900 mb-4">
Estratégia de Negociação
</h3>
<p className="text-zinc-600 font-light leading-relaxed">
Abordagem analítica e sigilosa para garantir a melhor composição de valores. Protejo seus interesses com dados de mercado concretos e vasta experiência em transações complexas.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.4 }}
className="bg-white p-10 border border-zinc-200 hover:border-brand-gold transition-colors duration-300"
>
<div className="w-12 h-12 bg-zinc-50 flex items-center justify-center rounded-full mb-8 text-brand-gold">
<ShieldCheck size={20} />
</div>
<h3 className="text-xl font-serif text-zinc-900 mb-4">
Rede Off-Market
</h3>
<p className="text-zinc-600 font-light leading-relaxed">
Acesso privilegiado a propriedades exclusivas que não são anunciadas publicamente, oferecendo um portfólio reservado para compradores qualificados.
</p>
</motion.div>
</div>
</div>
</section>
{/* TESTIMONIALS SECTION (SOCIAL PROOF) */}
<section className="py-24 bg-white border-t border-zinc-200">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="text-center mb-16">
<span className="text-xs uppercase tracking-[0.2em] text-zinc-400 font-bold block mb-4">
Reconhecimento
</span>
<h2 className="text-4xl md:text-5xl font-serif text-zinc-900 leading-tight">
O que dizem nossos clientes
</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<div className="bg-zinc-50 p-10 border border-zinc-200 relative">
<div className="text-brand-gold text-4xl font-serif absolute top-6 left-6 opacity-30">"</div>
<p className="text-zinc-700 font-light leading-relaxed mb-6 relative z-10">
"A abordagem do Rafael foi fundamental para encontrarmos nosso novo lar de forma totalmente sigilosa e assertiva. Ele não apenas nos mostrou imóveis, mas apresentou uma análise completa sobre a valorização da região."
</p>
<div className="font-serif font-medium text-zinc-900">
S.M. Cliente de Compra (Itaim Bibi)
</div>
</div>
<div className="bg-zinc-50 p-10 border border-zinc-200 relative">
<div className="text-brand-gold text-4xl font-serif absolute top-6 left-6 opacity-30">"</div>
<p className="text-zinc-700 font-light leading-relaxed mb-6 relative z-10">
"Confiei a venda do meu apartamento exclusivamente à assessoria dele. O nível de qualificação dos interessados me impressionou, resultando em um fechamento focado apenas no alvo desejado."
</p>
<div className="font-serif font-medium text-zinc-900">
A.C.M Cliente de Venda (Jardins)
</div>
</div>
</div>
</div>
</section>
{/* FAQ SECTION */}
<section className="py-24 bg-zinc-50 border-t border-zinc-200">
<div className="max-w-4xl mx-auto px-6 lg:px-8">
<div className="text-center mb-16">
<span className="text-xs uppercase tracking-[0.2em] text-zinc-400 font-bold block mb-4">
Esclarecimentos
</span>
<h2 className="text-4xl md:text-5xl font-serif text-zinc-900 leading-tight">
Perguntas Frequentes
</h2>
</div>
<div className="space-y-6">
<div className="border border-zinc-200 p-6 bg-white">
<h3 className="font-serif text-xl text-zinc-900 mb-3">Como funciona a assessoria para compra de imóveis?</h3>
<p className="text-zinc-600 font-light">Busca ativa por todo o mercado. Filtro o ruído, faço as inspeções prévias e entrego relatórios analíticos antes da sua visita.</p>
</div>
<div className="border border-zinc-200 p-6 bg-white">
<h3 className="font-serif text-xl text-zinc-900 mb-3">O que são imóveis off-market?</h3>
<p className="text-zinc-600 font-light">São propriedades exclusivas que não são anunciadas publicamente, oferecendo maior privacidade e oportunidades únicas para compradores qualificados.</p>
</div>
<div className="border border-zinc-200 p-6 bg-white">
<h3 className="font-serif text-xl text-zinc-900 mb-3">Qual é a vantagem de contratar um corretor exclusivo para a venda do meu imóvel?</h3>
<p className="text-zinc-600 font-light">A exclusividade garante um plano de marketing focado, filtro rigoroso de potenciais compradores e proteção contra a desvalorização do ativo por sobreposição de anúncios no mercado.</p>
</div>
<div className="border border-zinc-200 p-6 bg-white">
<h3 className="font-serif text-xl text-zinc-900 mb-3">Você atua apenas na venda de imóveis prontos ou também em lançamentos?</h3>
<p className="text-zinc-600 font-light">Atuo em ambos. Para lançamentos, ofereço antecipação de informações e acesso privilegiado a unidades específicas antes da abertura para o mercado em geral.</p>
</div>
<div className="border border-zinc-200 p-6 bg-white">
<h3 className="font-serif text-xl text-zinc-900 mb-3">Como é garantido o sigilo durante a negociação?</h3>
<p className="text-zinc-600 font-light">Trabalho com Acordos de Confidencialidade (NDA) quando necessário e filtro estritamente as informações compartilhadas, protegendo a identidade e o patrimônio de ambas as partes.</p>
</div>
</div>
</div>
</section>
</>
);
}
function ArticleRoute() {
const { id } = useParams();
const article = articles.find((a) => a.id === id);
if (!article) {
return (
<div className="min-h-screen pt-40 pb-24 text-center">
<h1 className="text-4xl font-serif mb-4">Artigo não encontrado</h1>
<Link to="/" className="text-brand-gold hover:underline">Voltar para o início</Link>
</div>
);
}
return <ArticleView article={article} />;
}
function ArticleView({ article }: { article: Article }) {
return (
<>
<Helmet>
<title>{article.title} | Rafael Fontes</title>
<meta name="description" content={article.excerpt} />
{article.type === "property" ? (
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "RealEstateListing",
"name": article.title,
"description": article.excerpt,
"image": article.coverImage,
"offers": {
"@type": "Offer",
"priceCurrency": "BRL",
"price": article.details?.price?.replace(/[^0-9]/g, "") || "0"
}
})}
</script>
) : (
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": article.title,
"description": article.excerpt,
"image": article.coverImage,
"author": {
"@type": "Person",
"name": "Rafael Fontes"
},
"datePublished": "2024-01-01" // Idealmente seria a data do artigo
})}
</script>
)}
</Helmet>
<motion.article
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
className="pt-32 pb-24"
>
<div className="max-w-4xl mx-auto px-6 lg:px-8">
<Link
to="/"
className="inline-flex items-center gap-2 text-xs uppercase tracking-widest font-bold text-zinc-500 hover:text-zinc-900 transition-colors mb-12"
>
<ArrowLeft size={16} />
Voltar
</Link>
<div className="flex items-center gap-4 text-brand-gold text-xs font-bold uppercase tracking-widest mb-6">
<span>{article.category}</span>
<span className="w-4 h-px bg-brand-gold"></span>
<span className="text-zinc-400">{article.date}</span>
</div>
<h1 className="text-4xl md:text-6xl font-serif text-zinc-900 leading-[1.1] mb-8">
{article.title}
</h1>
<p className="text-xl text-zinc-600 font-light leading-relaxed mb-12 border-l-2 border-zinc-200 pl-6">
{article.excerpt}
</p>
</div>
<div className="w-full max-w-6xl mx-auto px-6 lg:px-8 mb-16">
<div className="aspect-[21/9] md:aspect-[21/9] bg-zinc-200 overflow-hidden relative">
<img
src={article.coverImage}
alt={article.title}
className="w-full h-full object-cover"
/>
{article.type === "property" && article.details && (
<div className="absolute bottom-6 right-6 bg-white/90 backdrop-blur px-6 py-4 shadow-xl">
<div className="text-xs uppercase tracking-widest text-zinc-500 font-bold mb-1">
Preço Relacionado
</div>
<div className="font-serif text-2xl text-zinc-900">
{article.details.price}
</div>
</div>
)}
</div>
</div>
<div className="max-w-3xl mx-auto px-6 lg:px-8">
<div className="prose prose-zinc prose-lg font-light leading-loose text-zinc-700">
{article.content}
</div>
<div className="my-16 p-10 bg-zinc-50 border-l-4 border-brand-gold">
<blockquote className="text-2xl font-serif italic text-zinc-900 mb-6 m-0 border-none p-0">
"{article.quote.text}"
</blockquote>
<cite className="text-sm uppercase tracking-widest font-bold text-zinc-500 not-italic">
{article.quote.author}
</cite>
</div>
<div className="text-center pt-16 border-t border-zinc-200 mt-16">
<h3 className="font-serif text-2xl mb-6">
Possui interesse nesta propriedade ou assunto?
</h3>
<a
href="https://wa.me/5511999999999"
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-3 bg-zinc-900 hover:bg-brand-gold text-white px-8 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors"
>
Falar Diretamente no WhatsApp
</a>
</div>
{article.type === "property" && article.details?.location && (
<div className="mt-20 border-t border-zinc-200 pt-16">
<h3 className="font-serif text-2xl mb-2 text-zinc-900">
Localização Regional
</h3>
<p className="text-zinc-500 font-light text-sm mb-8">
Para preservar a segurança e privacidade do proprietário, exibimos apenas a região aproximada da propriedade. A localização exata será divulgada apenas mediante reunião de qualificação.
</p>
<div className="w-full h-80 bg-zinc-200 border border-zinc-200 overflow-hidden relative">
<iframe
src={`https://maps.google.com/maps?q=${encodeURIComponent(article.details.location)}&t=m&z=14&output=embed`}
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen={false}
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title={`Mapa regional para ${article.details.location}`}
className="w-full h-full object-cover mix-blend-luminosity hover:mix-blend-normal opacity-80 hover:opacity-100 transition-all duration-700"
></iframe>
</div>
</div>
)}
</div>
</motion.article>
</>
);
}

View file

@ -0,0 +1,86 @@
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export function Analytics() {
const location = useLocation();
useEffect(() => {
// Inject Google Tag Manager
const gtmId = import.meta.env.VITE_GTM_ID;
if (gtmId) {
const script = document.createElement("script");
script.innerHTML = `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmId}');
`;
document.head.appendChild(script);
const noscript = document.createElement("noscript");
noscript.innerHTML = `<iframe src="https://www.googletagmanager.com/ns.html?id=${gtmId}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`;
document.body.insertBefore(noscript, document.body.firstChild);
}
// Inject Google Analytics (if separate from GTM)
const gaId = import.meta.env.VITE_GA_MEASUREMENT_ID;
if (gaId) {
const scriptGa = document.createElement("script");
scriptGa.async = true;
scriptGa.src = `https://www.googletagmanager.com/gtag/js?id=${gaId}`;
document.head.appendChild(scriptGa);
const scriptInline = document.createElement("script");
scriptInline.innerHTML = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${gaId}');
`;
document.head.appendChild(scriptInline);
}
// Inject Meta/Facebook Pixel
const pixelId = import.meta.env.VITE_FB_PIXEL_ID;
if (pixelId) {
const script = document.createElement("script");
script.innerHTML = `
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '${pixelId}');
fbq('track', 'PageView');
`;
document.head.appendChild(script);
const noscript = document.createElement("noscript");
noscript.innerHTML = `<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=${pixelId}&ev=PageView&noscript=1" />`;
document.body.appendChild(noscript);
}
}, []);
// Track page views on route change
useEffect(() => {
// GA PageView
const gaId = import.meta.env.VITE_GA_MEASUREMENT_ID;
if (gaId && typeof window !== "undefined" && (window as any).gtag) {
(window as any).gtag("config", gaId, {
page_path: location.pathname + location.search,
});
}
// FB Pixel PageView
const pixelId = import.meta.env.VITE_FB_PIXEL_ID;
if (pixelId && typeof window !== "undefined" && (window as any).fbq) {
(window as any).fbq('track', 'PageView');
}
}, [location]);
return null;
}

View file

@ -0,0 +1,652 @@
import React from "react";
import { Link } from "react-router-dom";
export type ArticleType = "property" | "insight";
export interface Article {
id: string;
type: ArticleType;
category: string;
title: string;
excerpt: string;
coverImage: string;
date: string;
content: React.ReactNode;
quote: {
text: string;
author: string;
};
details?: {
price?: string;
specs?: string;
status?: string;
location?: string;
};
}
export const articles: Article[] = [
{
id: "residencial-jardim-europa-01",
type: "property",
category: "Jardim Europa, São Paulo",
title: "Residência de Autor: Modernismo e Privacidade Absoluta",
excerpt:
"Uma análise detalhada desta propriedade singular com 850m² de área construída, integrando living e um jardim projetado por Burle Marx.",
coverImage:
"https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?q=80&w=2075&auto=format&fit=crop",
date: "Maio 2026",
quote: {
text: "A arquitetura não é sobre a construção de paredes, mas sobre a criação de atmosferas.",
author: "Peter Zumthor",
},
details: {
price: "R$ 18.500.000",
specs: "850m² • 4 Suítes • 6 Vagas",
status: "Disponível para Visitação",
location: "Jardim Europa, São Paulo",
},
content: (
<>
<p>
Apresento esta excepcional residência localizada no coração do Jardim
Europa, um dos bairros mais tradicionais e valorizados de São Paulo.
Tive o privilégio de acompanhar a evolução desta propriedade ao longo
dos anos, e seu estado de conservação e design permanecem
irretocáveis.
</p>
<h3>O Espaço e a Luz</h3>
<p>
A planta foi concebida para que a luz natural permeie todos os
ambientes durante o dia. Painéis de vidro piso-teto criam uma
transição fluida entre o interior e o monumental jardim, que abriga
espécies nativas e espelhos d'água.
</p>
<p>
No piso superior, a suíte master atua como um refúgio particular,
contando com dois banheiros independentes, um amplo closet e uma
varanda voltada para o verde. Caso esteja em busca de outras
propriedades na região, você pode conferir nossa{" "}
<Link to="/artigo/valorizacao-jardim-europa">
análise de valorização do Jardim Europa
</Link>
.
</p>
</>
),
},
{
id: "cobertura-itaim-bibi",
type: "property",
category: "Itaim Bibi, São Paulo",
title: "A Perspectiva 360º: Cobertura Duplex no Centro Financeiro",
excerpt:
"Oportunidade raríssima no coração do Itaim. Uma cobertura reformada em 2024, com espaço gourmet completo voltado para o skyline da cidade.",
coverImage:
"https://images.unsplash.com/photo-1600607688969-a5bfcd64bd40?q=80&w=2053&auto=format&fit=crop",
date: "Abril 2026",
quote: {
text: "Viver no topo é ter a cidade como seu quadro em constante mudança.",
author: "Rafael Fontes",
},
details: {
price: "R$ 12.800.000",
specs: "420m² • 3 Suítes • 4 Vagas",
status: "Exclusividade",
location: "Itaim Bibi",
},
content: (
<>
<p>
O Itaim Bibi se consolidou como o epicentro financeiro e de lifestyle
da América Latina. Ter uma cobertura duplex nesta região é um
privilégio destinado a poucos. Este imóvel, em particular, passou por
um retrofit completo estrutural em 2024, assinado por um renomado
escritório de arquitetura brasileiro.
</p>
<h3>Design e Funcionalidade</h3>
<p>
Os acabamentos incluem mármore Travertino Navona e marcenaria Ornare
em todos os ambientes. O destaque definitivo é a área social no
segundo pavimento, equipada com piscina de borda infinita aquecida e
espaço gourmet, perfeito para recepções íntimas com vista para o
parque Ibirapuera.
</p>
<p>
Leia mais sobre o{" "}
<Link to="/artigo/novo-luxo-sp">novo conceito de luxo vertical</Link>.
</p>
</>
),
},
{
id: "fazenda-boa-vista",
type: "property",
category: "Porto Feliz, São Paulo",
title: "Refúgio de Fim de Semana com Arquitetura Vernacular",
excerpt:
"Nesta casa de campo a uma hora de São Paulo, os limites entre o interior e o exterior deixam de existir, cercados por mata nativa e lagos exuberantes.",
coverImage:
"https://images.unsplash.com/photo-1613977257363-707ba9348227?q=80&w=2070&auto=format&fit=crop",
date: "Março 2026",
quote: {
text: "O luxo contemporâneo é o espaço, o silêncio e o tempo.",
author: "Axel Vervoordt",
},
details: {
price: "Consulte o Valor",
specs: "1.200m² • 6 Suítes • 8 Vagas",
status: "Off-Market",
location: "Fazenda Boa Vista",
},
content: (
<>
<p>
Uma imersão completa na natureza sem abrir mão de nenhuma conveniência
urbana. Esta propriedade em um dos condomínios mais exclusivos do país
foi idealizada para ser um santuário familiar.
</p>
<h3>Sustentabilidade e Conforto</h3>
<p>
Com painéis solares, captação de água da chuva e automação residencial
nível 4, a casa opera com altíssima eficiência. O layout privilegia
áreas de convivência generosas, com um deck expansivo que se projeta
em direção à paisagem. Uma verdadeira obra de arte habitável.
</p>
</>
),
},
{
id: "tendencias-arquitetura-2026",
type: "insight",
category: "Tendências",
title: "Tendências de Arquitetura e Interior para 2026",
excerpt:
"A fusão entre tecnologia invisível, materiais orgânicos e a fluidez dos layouts dita as regras das novas residências de luxo.",
coverImage:
"https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?q=80&w=2000&auto=format&fit=crop",
date: "18 Maio, 2026",
quote: {
text: "Onde o design encontra a tecnologia, nasce o conforto invisível.",
author: "Design Studio",
},
content: (
<>
<p>
Este ano consolidou uma mudança silenciosa nas exigências do mercado
premium: a tecnologia não deve mais ser vista no ambiente, mas deve
operar tudo nos bastidores.
</p>
<h3>Acabamentos Orgânicos Naturais</h3>
<p>
Observamos a valorização de imperfeições naturais nas pedras e
madeiras de demolição, trazendo calor e exclusividade a ambientes que
pouco tempo eram pautados pela frieza modernista do vidro e
cimento.
</p>
<p>
Visite nossa{" "}
<Link to="/artigo/residencial-jardim-europa-01">
residência no Jardim Europa
</Link>{" "}
para ver a aplicação prática deste conceito de design.
</p>
</>
),
},
{
id: "mercado-luxo-sp",
type: "insight",
category: "Mercado Financeiro",
title: "Por que São Paulo atrai investidores globais?",
excerpt:
"Dados exclusivos de valorização indicam que a capital paulista se mantém resistente às oscilações internacionais.",
coverImage:
"https://images.unsplash.com/photo-1430285561322-780c604615ce?q=80&w=2070&auto=format&fit=crop",
date: "12 Maio, 2026",
quote: {
text: "O mercado imobiliário paulistano premium é blindado pelas dinâmicas de escassez e exclusividade.",
author: "Financial Times",
},
content: (
<>
<p>
De forma constante, o metro quadrado das coberturas de São Paulo em
regiões prime (Itaim, Vila Nova Conceição) superou a inflação nos
últimos dez anos.
</p>
<h3>Safe Haven</h3>
<p>
Para fundos e family offices, estacionar capital em imóveis icônicos
da cidade provou ser tanto um mecanismo de proteção quanto um
propulsor de ganhos através da hiper-valorização e retrofit.
</p>
</>
),
},
{
id: "guia-aquisicao-jardim-europa",
type: "insight",
category: "Investimentos",
title: "A valorização contínua e as oportunidades no Jardim Europa",
excerpt:
"Como as restrições construtivas garantem o valor do bairro, e por que a paciência é a melhor estratégia de compra.",
coverImage:
"https://images.unsplash.com/photo-1518507727145-cb3e7f01de55?q=80&w=2070&auto=format&fit=crop",
date: "05 Maio, 2026",
quote: {
text: "A ausência de verticalização é o maior luxo contemporâneo de São Paulo.",
author: "Instituto Urbano",
},
content: (
<>
<p>
Diferente de NY ou Londres, as áreas exclusivas de casas em São Paulo
não podem se adensar. O Jardim Europa é tombado, protegendo seus
moradores dos prédios altos. Mas o que isso significa para o
patrimônio?
</p>
<h3>Escassez de Solo e Curva de Apreciação</h3>
<p>
Na prática, quem possui um terreno na região não tem novos
competidores. Recomendamos sempre uma análise minuciosa de diligência
(<Link to="/artigo/guia-aquisicao-jardim-europa">leia o guia de aquisição</Link>) antes
de assinar qualquer compromisso, devido à complexidade da
regularização imobiliária das casas antigas.
</p>
</>
),
},
{
id: "penthouse-cidade-jardim",
type: "property",
category: "Cidade Jardim, São Paulo",
title: "Triplex Suspenso com Vista para a Skyline Paulista",
excerpt:
"Com mais de 1000m², este apartamento evoca a essência de uma mansão suspensa.",
coverImage:
"https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?q=80&w=2000&auto=format&fit=crop",
date: "01 Maio, 2026",
quote: {
text: "A grandiosidade se mede pelo espaço e pela privacidade, a centenas de metros do chão.",
author: "Rafael Fontes",
},
details: {
price: "R$ 35.000.000",
specs: "1050m² • 5 Suítes • 10 Vagas",
status: "Exclusividade",
location: "Cidade Jardim",
},
content: (
<>
<p>
Espaços palacianos. O direito duplo do living cria uma sensação de
imponência. A suíte master ocupa um andar inteiro. Esta é, de fato,
uma joia cobiçada no portfólio.
</p>
</>
),
},
{
id: "guia-aquisicao",
type: "insight",
category: "Guia Jurídico",
title: "Guia de Aquisição: Estruturação jurídica para grandes propriedades",
excerpt:
"Os passos essenciais e diligências que aplico antes de apresentar qualquer imóvel aos meus clientes.",
coverImage:
"https://images.unsplash.com/photo-1450101499163-c8848c66cb85?q=80&w=2070&auto=format&fit=crop",
date: "28 Abril, 2026",
quote: {
text: "A verdadeira segurança em uma negociação imobiliária reside no que não está visível.",
author: "L. Barros, Jurista",
},
content: (
<>
<p>
Em transações de alto valor agregado, as certidões cíveis e criminais
formam apenas 30% da verdadeira análise de risco.
</p>
<p>
Para ler mais, verifique{" "}
<Link to="/artigo/importancia-retrofit">
como o retrofit pode impactar esse risco legal
</Link>
.
</p>
</>
),
},
{
id: "novo-luxo-sp",
type: "insight",
category: "Comportamento",
title: "O Novo Luxo: Espaço vs Localização",
excerpt:
"A mudança de paradigma daqueles que valorizavam endereços cobiçados acima de tudo, em prol do espaço e bem-estar.",
coverImage:
"https://images.unsplash.com/photo-1512917774080-9991f1c4c750?q=80&w=2000&auto=format&fit=crop",
date: "22 Abril, 2026",
quote: {
text: "Não compramos mais endereço, compramos qualidade de vida.",
author: "Exame",
},
content: (
<>
<p>
A pandemia alterou permanentemente o morar premium. O verde deixou de
ser adorno para ser infraestrutura.
</p>
</>
),
},
{
id: "investimento-arte-imoveis",
type: "insight",
category: "Lifestyle",
title: "Investimento em Arte e Alta Decoração de Interiores",
excerpt:
"Como colecionar arte tem sinergia com o mercado de real estate de altíssimo nível.",
coverImage:
"https://images.unsplash.com/photo-1513694203232-719a280e022f?q=80&w=2000&auto=format&fit=crop",
date: "15 Abril, 2026",
quote: {
text: "As paredes são curadoras de nossas almas.",
author: "D. Soares",
},
content: (
<>
<p>
Casas de proporções generosas demandam peças à altura. um
intercâmbio constante entre galerias de arte e imobiliárias premium.
Em minha{" "}
<Link to="/artigo/fazenda-boa-vista">casa na Fazenda Boa Vista</Link>, o
projeto incluiu recuos para esculturas grandes.
</p>
</>
),
},
{
id: "condominio-vila-nova",
type: "property",
category: "Vila Nova Conceição",
title: "Apartamento Neoclássico na Praça Pereira Coutinho",
excerpt:
"Uma joia intocada em um dos logradouros mais valorizados do país.",
coverImage:
"https://images.unsplash.com/photo-1497366216548-37526070297c?q=80&w=2000&auto=format&fit=crop",
date: "10 Abril, 2026",
quote: {
text: "Viver de frente para a praça é prolongar a sala de estar.",
author: "R. Fontes",
},
details: {
price: "R$ 16.000.000",
specs: "300m² • 3 Suítes • 4 Vagas",
status: "Disponível",
location: "Vila Nova Conceição",
},
content: (
<>
<p>
A exclusividade de atravessar a rua e estar no Ibirapuera. Edifício de
assinatura clássica, segurança impecável. Veja as tendências em{" "}
<Link to="/artigo/tendencias-arquitetura-2026">arquitetura</Link> para
atualizar o apartamento se desejar um retrofit.
</p>
</>
),
},
{
id: "casa-alphaville",
type: "property",
category: "Alphaville, São Paulo",
title: "Mansão Monumental no Tamboré",
excerpt:
"Segurança e qualidade de vida com proporções que a capital já não oferece.",
coverImage:
"https://images.unsplash.com/photo-1628611225249-6c4c3af4a80b?q=80&w=2000&auto=format&fit=crop",
date: "03 Abril, 2026",
quote: {
text: "O refúgio perfeito a 30 minutos da Faria Lima.",
author: "Revista Habitar",
},
details: {
price: "R$ 22.000.000",
specs: "1500m² • 6 Suítes • 12 Vagas",
status: "Consulte",
location: "Tamboré Destaque",
},
content: (
<>
<p>
Condomínios de alto luxo em Barueri continuam sua ascensão
impulsionada pelo recuo da modalidade de trabalho híbrido.
</p>
</>
),
},
{
id: "arquitetura-biofilica",
type: "insight",
category: "Design",
title: "Design Biofílico: O que os compradores premium procuram hoje",
excerpt:
"Como a integração com o verde deixou de ser um diferencial e passou a ser exigência.",
coverImage:
"https://images.unsplash.com/photo-1544005313-94ddf0286df2?q=80&w=2000&auto=format&fit=crop",
date: "30 Março, 2026",
quote: {
text: "A natureza não é um lugar para visitar. É a nossa casa.",
author: "Gary Snyder",
},
content: (
<>
<p>
Temos notado o aumento drástico pela procura de incorporações que
possuam mata nativa integrada. O verde é a nova corrente estética.
</p>
</>
),
},
{
id: "sustentabilidade-luxo",
type: "insight",
category: "Visão de Futuro",
title: "Sustentabilidade e Alto Padrão não são mais mutuamente exclusivos",
excerpt: "Certificações EDGE e LEED em residências horizontais.",
coverImage:
"https://images.unsplash.com/photo-1501183638710-841dd1904471?q=80&w=2000&auto=format&fit=crop",
date: "25 Março, 2026",
quote: {
text: "Luxo de verdade é não causar impacto sistêmico.",
author: "ESG Real Estate",
},
content: (
<>
<p>
A preocupação climática levou a uma modernização drástica dos métodos
construtivos e de suprimentos de energia off-grid.
</p>
</>
),
},
{
id: "retorno-casas-vila",
type: "insight",
category: "Urbanismo",
title: "O Retorno e Valorização das Casas de Vila em São Paulo",
excerpt:
"A procura desenfreada por vilas charmosas nos Jardins e Pinheiros.",
coverImage:
"https://images.unsplash.com/photo-1579487785973-74d2ca78ddfc?q=80&w=2000&auto=format&fit=crop",
date: "20 Março, 2026",
quote: {
text: "Há uma poesia irreplicável em pisar na rua de paralelepípedos e abrir um modesto portão para um oasis interno.",
author: "R. Fontes",
},
content: (
<>
<p>
Com as poucas unidades disponíveis no mercado, a precificação bate
recordes históricos. Veja mais em{" "}
<Link to="/artigo/mercado-off-market">off-market insights</Link>.
</p>
</>
),
},
{
id: "mercado-off-market",
type: "insight",
category: "Fundamentos",
title: "Mercado Off-Market: A negociação nas sombras",
excerpt:
"Como operam as chamadas 'Secret Listings' nas camadas mais altas da riqueza paulistana.",
coverImage:
"https://images.unsplash.com/photo-1590856029826-c7a73142bbf1?q=80&w=2000&auto=format&fit=crop",
date: "14 Março, 2026",
quote: {
text: "A discrição é a forma mais elevada de confiança.",
author: "Private Broker",
},
content: (
<>
<p>
Cerca de 40% das transações ultraluxo acontecem sem que a propriedade
seja sequer fotografada profissionalmente e inserida na rede.
</p>
</>
),
},
{
id: "importancia-retrofit",
type: "insight",
category: "Investimentos",
title: "A Importância do Retrofit nos Endereços Icônicos",
excerpt: "Atualizando prédios da década de 70 para compradores atuais.",
coverImage:
"https://images.unsplash.com/photo-1503387762-592deb58ef4e?q=80&w=2000&auto=format&fit=crop",
date: "10 Março, 2026",
quote: {
text: "Preservamos a fachada para atualizar a alma.",
author: "Arquitetura & Urbanismo",
},
content: (
<>
<p>
O retrofit é, hoje, a modalidade de investimento que mais agrega valor
ao metro quadrado defasado de Higienópolis e Jardins.
</p>
</>
),
},
{
id: "casa-pinheiros",
type: "property",
category: "Alto de Pinheiros",
title: "Residência Contemporânea Próxima à Praça Panamericana",
excerpt: "Casa de esquina, com total segurança e vocação receber.",
coverImage:
"https://images.unsplash.com/photo-1512915922686-57c11dde9b6b?q=80&w=2000&auto=format&fit=crop",
date: "05 Março, 2026",
quote: {
text: "Silêncio profundo na metrópole barulhenta.",
author: "Proprietário",
},
details: {
price: "R$ 14.500.000",
specs: "650m² • 4 Suítes • 5 Vagas",
status: "Disponível",
location: "Alto de Pinheiros",
},
content: (
<>
<p>Luz, brisa e segurança. Uma rara oportunidade em Pinheiros.</p>
</>
),
},
{
id: "apartamento-jardins",
type: "property",
category: "Jardins",
title: "Apartamento de Época Totalmente Restaurado",
excerpt: "O charme do piso em taco de peroba e do pé direito de 3.20m.",
coverImage:
"https://images.unsplash.com/photo-1533779283484-8ad4940aa3a8?q=80&w=2000&auto=format&fit=crop",
date: "28 Fevereiro, 2026",
quote: {
text: "O antigo redescoberto.",
author: "Design Team",
},
details: {
price: "R$ 6.800.000",
specs: "280m² • 3 Suítes • 2 Vagas",
status: "Em Negociação",
location: "Jardins",
},
content: (
<>
<p>
Um espetáculo visual de retrofit de ponta, ver mais em{" "}
<Link to="/artigo/importancia-retrofit">importância do retrofit</Link>.
</p>
</>
),
},
{
id: "cobertura-brooklin",
type: "property",
category: "Brooklin",
title: "Penthouse Exclusiva no Novo Polo",
excerpt:
"Condomínio clube moderno com todas as facilidades e uma planta fenomenal.",
coverImage:
"https://images.unsplash.com/photo-1502672260266-1c1e52509def?q=80&w=2000&auto=format&fit=crop",
date: "20 Fevereiro, 2026",
quote: {
text: "O novo centro convergiu para cá.",
author: "Valor Econômico",
},
details: {
price: "R$ 10.500.000",
specs: "380m² • 3 Suítes • 4 Vagas",
status: "Disponível",
location: "Brooklin Novo",
},
content: (
<>
<p>
Uma chance excelente na região com as sedes das maiores empresas do
Brasil.
</p>
</>
),
},
{
id: "fazenda-boa-vista-grama",
type: "property",
category: "Fazenda da Grama",
title: "Casa de Campo Moderna com Vista para o Lago",
excerpt: "Para fugir de São Paulo, no condomínio com praia particular.",
coverImage:
"https://images.unsplash.com/photo-1521579294248-c2bfa12a52ce?q=80&w=2000&auto=format&fit=crop",
date: "15 Fevereiro, 2026",
quote: {
text: "O pé na areia agora é verde e montanhoso.",
author: "Lifestyle Magazine",
},
details: {
price: "R$ 15.000.000",
specs: "800m² • 5 Suítes • 6 Vagas",
status: "Off-Market",
location: "Itupeva",
},
content: (
<>
<p>
Arquitetura em U ao redor de um pátio magnífico e uma piscina espelho
que repousa sobre a visão do lago central.
</p>
</>
),
},
];

20
Template-01/src/index.css Normal file
View file

@ -0,0 +1,20 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@theme {
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-serif: "Playfair Display", ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--color-brand-gold: #cba258;
--color-brand-gold-hover: #b8914b;
--color-brand-dark: #121212;
}
body {
@apply font-sans text-zinc-800 bg-zinc-50;
}
h1, h2, h3, h4, h5, h6 {
@apply font-serif;
}

16
Template-01/src/main.tsx Normal file
View file

@ -0,0 +1,16 @@
import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import App from './App.tsx';
import './index.css';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<HelmetProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</HelmetProvider>
</StrictMode>,
);

View file

@ -0,0 +1,99 @@
import { motion } from "motion/react";
import { Helmet } from "react-helmet-async";
export function AssessoriaPage() {
return (
<>
<Helmet>
<title>A Assessoria | Rafael Fontes | Consultoria Imobiliária Especializada</title>
<meta name="description" content="Proteja seus interesses nas transações imobiliárias mais complexas. Assessoria completa focada em precisão: do representation do vendedor ao buyer's agent." />
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "Service",
"serviceType": "Consultoria Imobiliária",
"provider": {
"@type": "RealEstateAgent",
"name": "Rafael Fontes"
},
"description": "Consultoria imobiliária especializada em transações complexas e mercado de luxo. Representação de proprietários e assessoria na compra (Buyer's Agent)."
})}
</script>
</Helmet>
<div className="pt-32 pb-24 bg-zinc-50 text-zinc-900 min-h-screen flex items-center">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-20 items-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
>
<span className="text-xs uppercase tracking-[0.2em] text-brand-gold font-bold block mb-4">
A Prática
</span>
<h1 className="text-4xl md:text-5xl font-serif leading-tight mb-8">
Consultoria Imobiliária Especializada.
</h1>
<div className="w-16 h-px bg-brand-gold mb-8"></div>
<p className="text-zinc-600 font-light text-lg leading-relaxed mb-8">
Sou contratado para proteger os interesses dos meus clientes nas
transações mais complexas do mercado. Não trabalho com volume,
mas com precisão.
</p>
<ul className="space-y-8 mt-12">
<li className="flex gap-4">
<div className="w-8 h-8 rounded-full border border-brand-gold flex items-center justify-center shrink-0 mt-1">
<span className="text-brand-gold text-xs">01</span>
</div>
<div>
<h4 className="text-xl font-serif mb-2">
Representação de Proprietários
</h4>
<p className="text-zinc-600 font-light">
Estratégias de marketing personalizadas, fotos editoriais
e apresentação focada para compradores qualificados.
</p>
</div>
</li>
<li className="flex gap-4">
<div className="w-8 h-8 rounded-full border border-brand-gold flex items-center justify-center shrink-0 mt-1">
<span className="text-brand-gold text-xs">02</span>
</div>
<div>
<h4 className="text-xl font-serif mb-2">
Assessoria na Compra (Buyer's Agent)
</h4>
<p className="text-zinc-600 font-light">
Busca ativa por todo o mercado. Filtro o ruído, faço as
inspeções prévias e entrego relatórios analíticos antes da
sua visita.
</p>
</div>
</li>
</ul>
</motion.div>
<motion.div
className="grid grid-cols-2 gap-4"
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.8, delay: 0.2 }}
>
<img
src="https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=2070&auto=format&fit=crop"
alt="Jardins"
className="w-full aspect-[3/4] object-cover rounded-sm grayscale-[30%]"
/>
<img
src="https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?q=80&w=2070&auto=format&fit=crop"
alt="Itaim"
className="w-full aspect-[3/4] object-cover rounded-sm grayscale-[30%] translate-y-8"
/>
</motion.div>
</div>
</div>
</div>
</>
);
}

View file

@ -0,0 +1,137 @@
import React, { useState } from "react";
import { motion } from "motion/react";
import { Instagram as InstaIcon, Linkedin as LinkedInIcon } from "lucide-react";
import { Helmet } from "react-helmet-async";
export function ContatoPage() {
const [isSubmitted, setIsSubmitted] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitted(true);
// Here you would typically send data to a backend
setTimeout(() => {
setIsSubmitted(false);
}, 5000);
};
return (
<>
<Helmet>
<title>Contato | Rafael Fontes | Corretor de Luxo</title>
<meta name="description" content="Entre em contato para agendar uma reunião sigilosa. Discutiremos seus objetivos imobiliários no momento atual do mercado." />
</Helmet>
<div className="bg-zinc-50 pt-32 pb-24 text-zinc-900 min-h-screen flex items-center">
<div className="max-w-7xl mx-auto px-6 lg:px-8 w-full">
<motion.div
className="grid grid-cols-1 md:grid-cols-12 gap-16"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
>
<div className="md:col-span-5">
<h1 className="text-4xl lg:text-5xl font-serif leading-tight mb-8">
Pronto para o<br />
próximo passo?
</h1>
<p className="text-zinc-600 font-light text-lg mb-10 max-w-md">
Entre em contato para agendar uma reunião sigilosa. Discutiremos
seus objetivos imobiliários no momento atual do mercado.
</p>
{isSubmitted ? (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="p-6 bg-brand-gold/10 border border-brand-gold/20 text-zinc-900 mb-8"
>
<h3 className="font-serif text-xl mb-2">Mensagem Enviada</h3>
<p className="text-zinc-600 font-light">Obrigado pelo seu contato. Retornarei o mais breve possível com máxima discrição.</p>
</motion.div>
) : (
<form className="space-y-4 max-w-md" onSubmit={handleSubmit}>
<div>
<label htmlFor="name" className="sr-only">Nome Completo</label>
<input required type="text" id="name" placeholder="Nome Completo" className="w-full bg-white border border-zinc-200 text-zinc-900 px-4 py-3 text-sm focus:outline-none focus:border-brand-gold transition-colors placeholder:text-zinc-400" />
</div>
<div>
<label htmlFor="email" className="sr-only">Email</label>
<input required type="email" id="email" placeholder="Endereço de E-mail" className="w-full bg-white border border-zinc-200 text-zinc-900 px-4 py-3 text-sm focus:outline-none focus:border-brand-gold transition-colors placeholder:text-zinc-400" />
</div>
<div>
<label htmlFor="phone" className="sr-only">Telefone / WhatsApp</label>
<input required type="tel" id="phone" placeholder="Telefone / WhatsApp" className="w-full bg-white border border-zinc-200 text-zinc-900 px-4 py-3 text-sm focus:outline-none focus:border-brand-gold transition-colors placeholder:text-zinc-400" />
</div>
<div>
<label htmlFor="message" className="sr-only">Mensagem (opcional)</label>
<textarea id="message" rows={4} placeholder="Sua Mensagem (opcional)" className="w-full bg-white border border-zinc-200 text-zinc-900 px-4 py-3 text-sm focus:outline-none focus:border-brand-gold transition-colors placeholder:text-zinc-400 resize-none"></textarea>
</div>
<button type="submit" className="w-full bg-brand-gold hover:bg-brand-gold-hover text-white px-8 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors mt-2">
Solicitar Contato
</button>
</form>
)}
</div>
<div className="md:col-span-3 md:col-start-7 text-sm font-light">
<h4 className="text-zinc-900 font-bold mb-6 font-serif tracking-wide text-lg">
Contato Rápido
</h4>
<ul className="space-y-4 text-zinc-600">
<li>
<a
href="mailto:rafael@rafaelfontes.com"
className="hover:text-brand-gold transition-colors"
>
rafael@rafaelfontes.com
</a>
</li>
<li>+55 11 99999.9999</li>
<li className="pt-4 flex gap-6">
<a href="#" className="hover:text-brand-gold transition-colors">
<InstaIcon size={20} />
</a>
<a href="#" className="hover:text-brand-gold transition-colors">
<LinkedInIcon size={20} />
</a>
</li>
</ul>
</div>
<div className="md:col-span-3 text-sm font-light">
<h4 className="text-zinc-900 font-bold mb-6 font-serif tracking-wide text-lg">
Localização
</h4>
<ul className="space-y-4 text-zinc-600">
<li>Av. Brigadeiro Faria Lima, 3477</li>
<li>Itaim Bibi</li>
<li>São Paulo - SP</li>
<li>14º Andar (Atendimento com hora marcada)</li>
</ul>
</div>
</motion.div>
{/* MAP SECTION */}
<motion.div
className="mt-20 w-full h-96 bg-zinc-200 border border-zinc-200"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.2 }}
>
<iframe
src="https://maps.google.com/maps?q=Av.%20Brigadeiro%20Faria%20Lima,%203477,%20São%20Paulo&t=m&z=16&output=embed"
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen={false}
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title="Localização do Escritório"
className="w-full h-full object-cover grayscale opacity-80 hover:grayscale-0 hover:opacity-100 transition-all duration-700"
></iframe>
</motion.div>
</div>
</div>
</>
);
}

View file

@ -0,0 +1,65 @@
import { Link } from "react-router-dom";
import { ArrowRight } from "lucide-react";
import { Helmet } from "react-helmet-async";
import { Article } from "../data/articles";
import { motion } from "motion/react";
export function InsightsPage({ marketInsights }: { marketInsights: Article[] }) {
return (
<>
<Helmet>
<title>Insights & Blog | Rafael Fontes</title>
<meta name="description" content="Artigos e análises de mercado sobre o mercado imobiliário premium de São Paulo. Dicas de negócios e inteligência analítica." />
</Helmet>
<div className="pt-32 pb-24 bg-zinc-50 min-h-screen">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
<div>
<span className="text-xs uppercase tracking-[0.2em] text-zinc-400 font-bold block mb-4">
Blog Pessoal
</span>
<h1 className="text-4xl font-serif text-zinc-900 leading-tight">
Artigos & Análises de Mercado
</h1>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-12">
{marketInsights.map((post, index) => (
<motion.div
key={post.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 * index }}
>
<Link
to={`/artigo/${post.id}`}
className="group block"
>
<div className="mb-4">
<span className="text-xs text-zinc-400 uppercase tracking-widest">
{post.date}
</span>
</div>
<h3 className="text-xl font-serif text-zinc-900 mb-4 group-hover:text-brand-gold transition-colors">
{post.title}
</h3>
<p className="text-zinc-600 font-light text-sm leading-relaxed mb-6">
{post.excerpt}
</p>
<span className="flex items-center gap-2 text-xs font-bold uppercase tracking-wider text-brand-gold">
Ler artigo completo{" "}
<ArrowRight
size={14}
className="group-hover:translate-x-1 transition-transform"
/>
</span>
</Link>
</motion.div>
))}
</div>
</div>
</div>
</>
);
}

View file

@ -0,0 +1,146 @@
import { motion } from "motion/react";
import { Link } from "react-router-dom";
import { MapPin, ArrowRight } from "lucide-react";
import { Helmet } from "react-helmet-async";
import { Article } from "../data/articles";
export function PortfolioPage({ propertiesAsArticles }: { propertiesAsArticles: Article[] }) {
return (
<>
<Helmet>
<title>Portfólio de Luxo | Rafael Fontes</title>
<meta name="description" content="Explore propriedades de alto padrão e luxo em São Paulo. Casas e apartamentos em bairros como Itaim Bibi e Jardins, além de opções off-market exclusivas." />
<meta property="og:title" content="Portfólio de Luxo | Rafael Fontes" />
<meta property="og:description" content="Explore propriedades de alto padrão e luxo em São Paulo. Casas e apartamentos em bairros como Itaim Bibi e Jardins." />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Portfólio de Luxo | Rafael Fontes" />
<meta name="twitter:description" content="Explore propriedades de alto padrão e luxo em São Paulo." />
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://rafaelfontes.com.br/"
},{
"@type": "ListItem",
"position": 2,
"name": "Portfólio",
"item": "https://rafaelfontes.com.br/portfolio"
}]
})}
</script>
</Helmet>
<div className="pt-32 pb-24 bg-zinc-50 min-h-screen">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="flex flex-col md:flex-row md:items-end justify-between gap-6 mb-24">
<div className="max-w-2xl">
<span className="text-xs uppercase tracking-[0.2em] text-zinc-400 font-bold block mb-4">
Destaques do Portfólio
</span>
<h1 className="text-4xl md:text-5xl font-serif text-zinc-900 leading-tight">
Apresentação de Imóveis
</h1>
</div>
<p className="text-zinc-500 font-light max-w-sm">
Cada propriedade é tratada como um estudo de caso. Analiso a
arquitetura, a viabilidade e o potencial do ativo antes de
apresentá-lo.
</p>
</div>
<div className="space-y-32">
{propertiesAsArticles.map((property, index) => (
<motion.article
key={property.id}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.8 }}
className={`flex flex-col ${index % 2 !== 0 ? "md:flex-row-reverse" : "md:flex-row"} gap-12 lg:gap-20 items-center group`}
>
{/* Image Side */}
<div className="w-full md:w-3/5">
<Link
to={`/artigo/${property.id}`}
className="block relative aspect-[16/11] overflow-hidden bg-zinc-100"
>
<img
src={property.coverImage}
alt={property.title}
loading={index === 0 ? "eager" : "lazy"}
className="w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-[1.5s] ease-out"
/>
<div className="absolute top-6 left-6 bg-white/90 backdrop-blur px-4 py-2 text-xs font-bold uppercase tracking-wider text-zinc-900">
{property.details?.status || "Exclusividade"}
</div>
</Link>
</div>
{/* Content Side */}
<div className="w-full md:w-2/5 flex flex-col justify-center">
<div className="flex items-center gap-3 text-brand-gold text-sm font-semibold uppercase tracking-wider mb-4">
<MapPin size={16} />
<span>{property.category}</span>
</div>
<Link to={`/artigo/${property.id}`}>
<h3 className="text-3xl lg:text-4xl font-serif text-zinc-900 leading-tight mb-6 hover:text-brand-gold transition-colors">
{property.title}
</h3>
</Link>
<p className="text-zinc-600 font-light leading-relaxed mb-8">
{property.excerpt}
</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-8 py-6 border-y border-zinc-100">
<div>
<span className="block text-xs uppercase tracking-widest text-zinc-400 font-semibold mb-1">
Características
</span>
<span className="text-zinc-900 font-medium">
{property.details?.specs}
</span>
</div>
<div>
<span className="block text-xs uppercase tracking-widest text-zinc-400 font-semibold mb-1">
Preço Solicitado
</span>
<span className="text-zinc-900 font-serif text-xl">
{property.details?.price}
</span>
</div>
</div>
<Link
to={`/artigo/${property.id}`}
className="inline-flex items-center gap-3 text-xs font-bold uppercase tracking-[0.1em] text-zinc-900 group-hover:text-brand-gold transition-colors w-fit"
>
Acessar Dossier Completo{" "}
<ArrowRight
size={16}
className="group-hover:translate-x-1 transition-transform"
/>
</Link>
</div>
</motion.article>
))}
</div>
<div className="mt-24 text-center">
<Link
to="/contato"
className="inline-flex items-center gap-3 border border-zinc-300 px-8 py-4 text-xs font-bold uppercase tracking-[0.1em] text-zinc-900 hover:bg-zinc-900 hover:text-white hover:border-zinc-900 transition-all duration-300"
>
Solicitar Lista Completa (Opções Off-Market)
</Link>
</div>
</div>
</div>
</>
);
}

1
Template-01/src/vite-env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />

26
Template-01/tsconfig.json Normal file
View file

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"module": "ESNext",
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"moduleResolution": "bundler",
"isolatedModules": true,
"moduleDetection": "force",
"allowJs": true,
"jsx": "react-jsx",
"paths": {
"@/*": [
"./*"
]
},
"allowImportingTsExtensions": true,
"noEmit": true
}
}

View file

@ -0,0 +1,24 @@
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import {defineConfig, loadEnv} from 'vite';
export default defineConfig(({mode}) => {
const env = loadEnv(mode, '.', '');
return {
plugins: [react(), tailwindcss()],
define: {
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),
},
resolve: {
alias: {
'@': path.resolve(__dirname, '.'),
},
},
server: {
// HMR is disabled in AI Studio via DISABLE_HMR env var.
// Do not modify—file watching is disabled to prevent flickering during agent edits.
hmr: process.env.DISABLE_HMR !== 'true',
},
};
});

49
Template-02/README.md Normal file
View file

@ -0,0 +1,49 @@
# Helena Fontes - Template Premium para Corretores de Alto Padrão
Este é um template React VIP, projetado para corretores de imóveis, butiques imobiliárias e assessorias que focam no mercado de alto padrão e luxo.
## 🚀 Como Iniciar
1. **Instale as dependências:**
```bash
npm install
```
2. **Rode o servidor de desenvolvimento:**
```bash
npm run dev
```
Acesse em `http://localhost:5173/` (ou a porta informada pelo Vite).
3. **Crie a build para produção:**
```bash
npm run build
```
## 🎨 Customização
### 1. Identidade Visual (Cores e Fontes)
Para alterar a paleta de cores (ex: o tom dourado ou o tom escuro), edite o arquivo `src/index.css`.
As fontes são o **Montserrat** (sem serifa) e **Cormorant Garamond** (serifada) aplicadas via Tailwind. Se desejar alterar as fontes globais, modifique os imports no início do `src/index.css` e as definições variáveis.
### 2. Edição de Dados (Portfólio e Blog)
O template é preenchido através do arquivo **`src/data/articles.ts`**.
Para adicionar ou remover propriedades e artigos de mercado, basta alterar este arquivo. As imagens devem preferencialmente seguir o aspect ratio das fotos atuais (ou utilizar o Unsplash para placeholder).
### 3. Integração de Analytics (Tráfego Pago)
Configure suas tags no arquivo `.env` baseado no `.env.example`:
- `VITE_GTM_ID`: Google Tag Manager
- `VITE_GA_MEASUREMENT_ID`: Google Analytics (G-XXXXXX)
- `VITE_FB_PIXEL_ID`: Pixel do Facebook/Meta
- `VITE_GOOGLE_ADS_ID`: Tag de Conversão Google Ads (AW-XXXXXX)
### 4. Formulário de Contato
A página de contato (`src/pages/ContatoPage.tsx`) possui um design funcional. Para receber os leads diretamente e de forma gratuita em templates estáticos (sem backend), recomendamos trocar o evento onSubmit padrão e integrar plataformas simples como o [Formspree](https://formspree.io/) ou [Netlify Forms](https://docs.netlify.com/forms/setup/).
### 5. Links e Redes Sociais
Lembre-se de atualizar os `href` dos ícones no arquivo `src/App.tsx` (Footer) com os links reais de seu Instagram e LinkedIn.
## 🌐 Deploy
Sendo um aplicativo Vite React App Single Page Application (SPA), o projeto é totalmente otimizado para deploy em plataformas de hospedagem estática gratuitas ou profissionais como **Vercel**, **Netlify**, ou **Cloudflare Pages**.
*Desenvolvido com sofisticação em React, Vite, Framer Motion e Tailwind CSS.*

22
Template-02/fix_links.js Normal file
View file

@ -0,0 +1,22 @@
const fs = require('fs');
const file = 'src/data/articles.tsx';
let content = fs.readFileSync(file, 'utf8');
const replacements = [
['<Link to="/">\n análise de valorização do Jardim Europa', '<Link to="/artigo/valorizacao-jardim-europa">\n análise de valorização do Jardim Europa'],
['<Link to="/">novo conceito de luxo vertical', '<Link to="/artigo/novo-luxo-sp">novo conceito de luxo vertical'],
['<Link to="/">\n residência no Jardim Europa', '<Link to="/artigo/residencial-jardim-europa-01">\n residência no Jardim Europa'],
['<Link to="/">leia o guia de aquisição', '<Link to="/artigo/guia-aquisicao-jardim-europa">leia o guia de aquisição'],
['<Link to="/">\n como o retrofit pode impactar esse risco legal', '<Link to="/artigo/importancia-retrofit">\n como o retrofit pode impactar esse risco legal'],
['<Link to="/">casa na Fazenda Boa Vista', '<Link to="/artigo/fazenda-boa-vista">casa na Fazenda Boa Vista'],
['<Link to="/">arquitetura', '<Link to="/artigo/tendencias-arquitetura-2026">arquitetura'],
['<Link to="/">off-market insights', '<Link to="/artigo/mercado-off-market">off-market insights'],
['<Link to="/">importância do retrofit', '<Link to="/artigo/importancia-retrofit">importância do retrofit']
];
for (const [search, replace] of replacements) {
content = content.replace(search, replace);
}
fs.writeFileSync(file, content);
console.log("Done");

50
Template-02/index.html Normal file
View file

@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Helena Fontes | Corretora de Imóveis Premium</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<!-- Theme Auto-Updater injected by autoblogia -->
<script>
window.addEventListener('message', (event) => {
if (event.data && event.data.type === 'UPDATE_APPEARANCE') {
const { primaryColor, backgroundColor, fontFamily } = event.data.settings;
const root = document.documentElement;
const style = root.style;
if (primaryColor) {
style.setProperty('--primary', primaryColor);
style.setProperty('--color-primary', primaryColor);
style.setProperty('--color-tech-primary', primaryColor);
style.setProperty('--color-seo-primary', primaryColor);
style.setProperty('--color-finance-primary', primaryColor);
style.setProperty('--color-recipe-primary', primaryColor);
style.setProperty('--color-health-primary', primaryColor);
style.setProperty('--color-corporate-primary', primaryColor);
}
if (backgroundColor) {
style.setProperty('--background', backgroundColor);
style.setProperty('--color-bg', backgroundColor);
style.setProperty('--color-tech-surface', backgroundColor);
style.setProperty('--color-seo-surface', backgroundColor);
style.backgroundColor = backgroundColor;
}
if (fontFamily) {
const fontString = '"' + fontFamily + '", sans-serif';
style.setProperty('--font-family', fontString);
style.setProperty('--font-sans', fontString);
style.fontFamily = fontString;
}
}
});
// Ping parent window that we are ready
window.parent.postMessage({ type: 'IFRAME_READY' }, '*');
</script>
</body>
</html>

View file

@ -0,0 +1,6 @@
{
"name": "Rafael Fontes - Corretor de Imobiliária Premium",
"description": "Website premium para corretor de imóveis focado em propriedades de alto padrão e luxo.",
"requestFramePermissions": [],
"majorCapabilities": []
}

4480
Template-02/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

38
Template-02/package.json Normal file
View file

@ -0,0 +1,38 @@
{
"name": "react-example",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --port=3000 --host=0.0.0.0",
"build": "vite build",
"preview": "vite preview",
"clean": "rm -rf dist",
"lint": "tsc --noEmit"
},
"dependencies": {
"@google/genai": "^1.29.0",
"@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.14",
"@vitejs/plugin-react": "^5.0.4",
"dotenv": "^17.2.3",
"express": "^4.21.2",
"lucide-react": "^0.546.0",
"motion": "^12.23.24",
"react": "^19.0.1",
"react-dom": "^19.0.1",
"react-helmet-async": "^3.0.0",
"react-icons": "^5.6.0",
"react-router-dom": "^7.15.0",
"vite": "^6.2.3"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/node": "^22.14.0",
"autoprefixer": "^10.4.21",
"tailwindcss": "^4.1.14",
"tsx": "^4.21.0",
"typescript": "~5.8.2",
"vite": "^6.2.3"
}
}

View file

@ -0,0 +1 @@
/* /index.html 200

View file

@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://helenafontes.com.br/sitemap.xml

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://helenafontes.com.br/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://helenafontes.com.br/portfolio</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://helenafontes.com.br/assessoria</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://helenafontes.com.br/insights</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://helenafontes.com.br/contato</loc>
<changefreq>monthly</changefreq>
<priority>0.6</priority>
</url>
</urlset>

29
Template-02/replace.ts Normal file
View file

@ -0,0 +1,29 @@
import * as fs from 'fs';
import * as path from 'path';
function replaceStone(filePath: string) {
let content = fs.readFileSync(filePath, 'utf8');
let original = content;
content = content.replace(/zinc-/g, "stone-");
if (content !== original) {
fs.writeFileSync(filePath, content, 'utf8');
console.log('Updated stone in ' + filePath);
}
}
function processDirectory(dir: string) {
const files = fs.readdirSync(dir);
for (const file of files) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
processDirectory(fullPath);
} else if (fullPath.endsWith('.tsx') || fullPath.endsWith('.ts')) {
replaceStone(fullPath);
}
}
}
processDirectory('./src');

783
Template-02/src/App.tsx Normal file
View file

@ -0,0 +1,783 @@
import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "motion/react";
import {
Menu,
X,
ArrowRight,
Instagram,
Linkedin,
MapPin,
ArrowLeft,
MessageCircle,
UserCheck,
Briefcase,
ShieldCheck,
Search,
} from "lucide-react";
import { Routes, Route, Link, useParams, useLocation } from "react-router-dom";
import { Helmet } from "react-helmet-async";
import { articles, ArticleType, Article } from "./data/articles";
import { PortfolioPage } from "./pages/PortfolioPage";
import { AssessoriaPage } from "./pages/AssessoriaPage";
import { InsightsPage } from "./pages/InsightsPage";
import { ContatoPage } from "./pages/ContatoPage";
import { NotFoundPage } from "./pages/NotFoundPage";
import { Analytics } from "./components/Analytics";
export default function App() {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isSearchOpen, setIsSearchOpen] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
const location = useLocation();
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
useEffect(() => {
window.scrollTo(0, 0);
setIsMobileMenuOpen(false);
setIsSearchOpen(false);
setSearchQuery("");
}, [location.pathname]);
// Filter articles for the homepage feeds
const propertiesAsArticles = articles.filter((a) => a.type === "property");
const marketInsights = articles.filter((a) => a.type === "insight");
const searchResults = articles.filter(a =>
a.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
a.excerpt.toLowerCase().includes(searchQuery.toLowerCase()) ||
(a.details?.location && a.details.location.toLowerCase().includes(searchQuery.toLowerCase()))
);
const isArticleRoute = location.pathname.startsWith('/artigo/');
return (
<div className="min-h-screen bg-[#FCFAFA] text-brand-dark selection:bg-brand-gold selection:text-white font-sans overflow-x-hidden">
<Analytics />
<Helmet>
<title>Helena Fontes | Corretora de Imóveis Premium</title>
<meta name="description" content="Helena Fontes é uma corretora de imóveis especializada no mercado premium e de luxo. Acesso exclusivo a propriedades off-market em São Paulo." />
<meta name="keywords" content="corretora de luxo, imóveis premium, são paulo, off-market, mansões, apartamentos alto padrão" />
<meta property="og:title" content="Helena Fontes | Corretora de Imóveis Premium" />
<meta property="og:description" content="Helena Fontes é uma corretora de imóveis especializada no mercado premium e de luxo. Acesso exclusivo a propriedades off-market em São Paulo." />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Helena Fontes | Corretora de Imóveis Premium" />
<meta name="twitter:description" content="Helena Fontes é uma corretora de imóveis especializada no mercado premium e de luxo em São Paulo." />
<link rel="canonical" href="https://helenafontes.com.br" />
</Helmet>
{/* HEADER */}
<nav
className={`fixed w-full z-50 transition-all duration-700 ${
isScrolled || isArticleRoute
? "bg-[#FCFAFA]/95 backdrop-blur-md py-4 shadow-sm"
: "bg-transparent py-8"
}`}
>
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="flex items-center justify-between">
{/* Left side: Menu (Mobile) or some links (Desktop) */}
<div className="flex-1 flex items-center justify-start">
<button
className={`md:hidden ${isScrolled || isArticleRoute ? 'text-brand-dark' : 'text-brand-dark'}`}
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? <X size={24} strokeWidth={1} /> : <Menu size={24} strokeWidth={1} />}
</button>
<div className="hidden md:flex items-center gap-8 text-[10px] uppercase tracking-[0.2em] font-semibold text-stone-500">
<Link to="/portfolio" className="hover:text-brand-gold transition-colors">Portfólio</Link>
<Link to="/assessoria" className="hover:text-brand-gold transition-colors">Assessoria</Link>
</div>
</div>
{/* Center: Logo */}
<div className="flex-shrink-0 text-center flex flex-col items-center">
<Link to="/">
<span className={`text-2xl md:text-3xl font-serif tracking-widest leading-none ${isScrolled || isArticleRoute ? 'text-brand-dark' : 'text-brand-dark'}`}>
HELENA FONTES
</span>
</Link>
</div>
{/* Right side: Search & other links */}
<div className="flex-1 flex items-center justify-end gap-6 md:gap-8">
<div className="hidden md:flex items-center gap-8 text-[10px] uppercase tracking-[0.2em] font-semibold text-stone-500">
<Link to="/insights" className="hover:text-brand-gold transition-colors">Insights</Link>
<Link to="/contato" className="hover:text-brand-gold transition-colors">Contato</Link>
</div>
<button
onClick={() => setIsSearchOpen(true)}
className={`hover:text-brand-gold transition-colors flex items-center ${isScrolled || isArticleRoute ? 'text-brand-dark' : 'text-brand-dark'}`}
aria-label="Buscar"
>
<Search size={20} strokeWidth={1.5} />
</button>
</div>
</div>
</div>
{/* Mobile Dropdown */}
<AnimatePresence>
{isMobileMenuOpen && (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
className="absolute top-full left-0 w-full bg-[#FCFAFA] overflow-hidden md:hidden shadow-2xl shadow-black/5 border-t border-stone-100"
>
<div className="flex flex-col px-8 py-10 gap-8 text-xs uppercase tracking-[0.2em] font-medium text-stone-600 text-center">
<Link to="/portfolio" onClick={() => setIsMobileMenuOpen(false)} className="hover:text-brand-gold">Portfólio</Link>
<div className="w-12 h-px bg-stone-200 mx-auto"></div>
<Link to="/assessoria" onClick={() => setIsMobileMenuOpen(false)} className="hover:text-brand-gold">A Assessoria</Link>
<div className="w-12 h-px bg-stone-200 mx-auto"></div>
<Link to="/insights" onClick={() => setIsMobileMenuOpen(false)} className="hover:text-brand-gold">Insights</Link>
<div className="w-12 h-px bg-stone-200 mx-auto"></div>
<Link to="/contato" onClick={() => setIsMobileMenuOpen(false)} className="hover:text-brand-gold">Contato</Link>
</div>
</motion.div>
)}
</AnimatePresence>
</nav>
{/* SEARCH MODAL */}
<AnimatePresence>
{isSearchOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-[100] bg-[#FCFAFA]/95 backdrop-blur-xl flex flex-col pt-32 px-6 lg:px-8"
>
<button
onClick={() => setIsSearchOpen(false)}
className="absolute top-8 right-6 lg:right-8 text-stone-500 hover:text-brand-dark transition-colors p-2"
aria-label="Agendar"
>
<X size={32} strokeWidth={1} />
</button>
<div className="max-w-4xl w-full mx-auto flex flex-col h-full">
<div className="relative mb-12">
<input
autoFocus
type="text"
placeholder="Busque por bairro, exclusividade ou insights..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full bg-transparent border-b-2 border-stone-300 text-3xl md:text-5xl font-serif text-brand-dark pb-4 focus:outline-none focus:border-brand-gold transition-colors placeholder:text-stone-300"
/>
<Search className="absolute right-0 bottom-6 text-stone-300" size={32} />
</div>
<div className="flex-1 overflow-y-auto pb-32">
{searchQuery.length > 2 ? (
<div className="space-y-6">
<h3 className="text-xs uppercase tracking-widest text-stone-400 font-bold mb-8">Resultados ({searchResults.length})</h3>
{searchResults.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
{searchResults.map((result) => (
<Link
key={result.id}
to={`/artigo/${result.id}`}
onClick={() => setIsSearchOpen(false)}
className="group block border border-stone-200 bg-white p-6 hover:border-brand-gold transition-colors"
>
<div className="text-xs font-bold text-brand-gold uppercase tracking-widest mb-3">
{result.type === 'property' ? 'Portfólio' : 'Insight'}
</div>
<h4 className="font-serif text-xl text-brand-dark mb-2 group-hover:text-brand-gold transition-colors">{result.title}</h4>
<p className="text-sm font-light text-stone-600 line-clamp-2">{result.excerpt}</p>
</Link>
))}
</div>
) : (
<p className="text-stone-500 font-light text-lg">Nenhum resultado encontrado para "{searchQuery}". Tente outros termos.</p>
)}
</div>
) : (
<div className="text-stone-400 font-light text-lg">
Digite pelo menos 3 caracteres para iniciar a busca.
</div>
)}
</div>
</div>
</motion.div>
)}
</AnimatePresence>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/portfolio" element={<PortfolioPage propertiesAsArticles={propertiesAsArticles} />} />
<Route path="/assessoria" element={<AssessoriaPage />} />
<Route path="/insights" element={<InsightsPage marketInsights={marketInsights} />} />
<Route path="/contato" element={<ContatoPage />} />
<Route path="/artigo/:id" element={<ArticleRoute />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
{/* FOOTER */}
<footer className="bg-white py-20 text-brand-dark border-t border-stone-100">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="flex flex-col items-center mb-12">
<span className="font-serif text-2xl text-brand-dark italic mb-8">Helena Fontes</span>
<div className="flex gap-8 mb-8 text-stone-400">
<a href="https://instagram.com" target="_blank" rel="noopener noreferrer" className="hover:text-brand-gold transition-colors" aria-label="Instagram">
<Instagram size={18} strokeWidth={1.5} />
</a>
<a href="https://linkedin.com" target="_blank" rel="noopener noreferrer" className="hover:text-brand-gold transition-colors" aria-label="LinkedIn">
<Linkedin size={18} strokeWidth={1.5} />
</a>
</div>
<div className="w-px h-12 bg-brand-gold/30"></div>
</div>
<div className="flex flex-wrap justify-center gap-6 md:gap-12 text-[10px] uppercase tracking-[0.3em] font-bold text-stone-400 mb-12">
<Link to="/portfolio" className="hover:text-brand-gold transition-colors">Portfólio</Link>
<Link to="/assessoria" className="hover:text-brand-gold transition-colors">A Assessoria</Link>
<Link to="/insights" className="hover:text-brand-gold transition-colors">Insights</Link>
<Link to="/contato" className="hover:text-brand-gold transition-colors">Contato</Link>
</div>
<p className="text-center text-[10px] uppercase tracking-[0.2em] text-stone-400 leading-relaxed font-semibold">
&copy; {new Date().getFullYear()} HELENA FONTES CRECI 123456-F. <br className="md:hidden" />
<span className="hidden md:inline"> | </span>CURADORIA IMOBILIÁRIA EXCLUSIVA
</p>
</div>
</footer>
{/* Floating WhatsApp Button */}
<AnimatePresence>
{(isScrolled || isArticleRoute) && (
<motion.a
initial={{ opacity: 0, scale: 0.8, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8, y: 20 }}
href="https://wa.me/5511999999999"
target="_blank"
rel="noreferrer"
className="fixed bottom-6 right-6 z-50 bg-[#25D366] text-white p-4 rounded-full shadow-[0_4px_14px_rgba(37,211,102,0.4)] hover:bg-[#22bf5b] transition-colors hover:scale-110 active:scale-95 flex items-center justify-center"
aria-label="Falar no WhatsApp"
>
<svg
viewBox="0 0 24 24"
width="28"
height="28"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<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-.51a12.8 12.8 0 0 0-.57-.01c-.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 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-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 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.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 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z" />
</svg>
</motion.a>
)}
</AnimatePresence>
</div>
);
}
function HomePage() {
const location = useLocation();
useEffect(() => {
if (location.hash) {
const element = document.getElementById(location.hash.substring(1));
if (element) {
element.scrollIntoView({ behavior: "smooth" });
}
}
}, [location]);
return (
<>
<Helmet>
<title>Helena Fontes | Início</title>
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "RealEstateAgent",
"name": "Helena Fontes",
"image": "https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=1976&auto=format&fit=crop",
"@id": "https://helenafontes.com.br",
"url": "https://helenafontes.com.br",
"telephone": "+5511999999999",
"address": {
"@type": "PostalAddress",
"streetAddress": "Av. Brigadeiro Faria Lima, 3477",
"addressLocality": "São Paulo",
"addressRegion": "SP",
"postalCode": "04538-133",
"addressCountry": "BR"
},
"priceRange": "$$$$"
})}
</script>
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Como funciona a assessoria para compra de imóveis?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Busca ativa por todo o mercado. Filtro o ruído, faço as inspeções prévias e entrego relatórios analíticos antes da sua visita."
}
},
{
"@type": "Question",
"name": "O que são imóveis off-market?",
"acceptedAnswer": {
"@type": "Answer",
"text": "São propriedades exclusivas que não são anunciadas publicamente, oferecendo maior privacidade e oportunidades únicas para compradores qualificados."
}
},
{
"@type": "Question",
"name": "Qual é a vantagem de contratar uma corretora exclusiva para a venda do meu imóvel?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A exclusividade garante um plano de marketing focado, filtro rigoroso de potenciais compradores e proteção contra a desvalorização do ativo por sobreposição de anúncios no mercado."
}
},
{
"@type": "Question",
"name": "Você atua apenas na venda de imóveis prontos ou também em lançamentos?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Atuo em ambos. Para lançamentos, ofereço antecipação de informações e acesso privilegiado a unidades específicas antes da abertura para o mercado em geral."
}
},
{
"@type": "Question",
"name": "Como é garantido o sigilo durante a negociação?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Trabalho com Acordos de Confidencialidade (NDA) quando necessário e filtro estritamente as informações compartilhadas, protegendo a identidade e o patrimônio de ambas as partes."
}
}
]
})}
</script>
</Helmet>
<section className="relative pt-40 pb-20 md:pt-48 md:pb-32 px-6 overflow-hidden bg-[#FCFAFA]">
<div className="max-w-7xl mx-auto w-full flex flex-col-reverse md:flex-row gap-16 md:gap-20 items-center">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 1, delay: 0.2 }}
className="w-full md:w-1/2 flex flex-col text-center md:text-left z-10"
>
<span className="text-brand-gold text-[10px] md:text-xs uppercase tracking-[0.3em] font-bold block mb-4 md:mb-6">
Portfólio Pessoal
</span>
<h1 className="text-5xl md:text-6xl lg:text-7xl font-serif text-brand-dark leading-[1.1] tracking-tight mb-8">
Sua morada, <br className="hidden lg:block"/>
<span className="italic font-light">cuidada em detalhes.</span>
</h1>
<p className="text-stone-500 font-light text-lg max-w-md mx-auto md:mx-0 mb-10 leading-relaxed">
Bem-vinda ao meu espaço. Aqui compartilho minha curadoria pessoal das propriedades mais acolhedoras e exclusivas de São Paulo.
</p>
<div className="flex flex-col sm:flex-row items-center gap-6 justify-center md:justify-start">
<Link
to="/portfolio"
className="inline-flex items-center justify-center min-w-[200px] gap-4 bg-brand-dark hover:bg-brand-gold text-white px-8 py-4 text-[10px] font-bold uppercase tracking-[0.2em] transition-colors w-fit"
>
Conhecer Portfólio
</Link>
<Link
to="/assessoria"
className="inline-flex items-center justify-center min-w-[200px] gap-2 text-brand-dark hover:text-brand-gold text-[10px] font-bold uppercase tracking-[0.2em] transition-colors w-fit border border-brand-dark hover:border-brand-gold px-8 py-4"
>
A Assessoria
</Link>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1.2, delay: 0.3 }}
className="w-full md:w-1/2 relative flex justify-center md:justify-end"
>
<div className="relative w-full max-w-sm lg:max-w-md">
<div className="aspect-[4/5] md:aspect-[3/4] object-cover overflow-hidden rounded-t-full rounded-b-sm bg-stone-100 shadow-xl shadow-stone-200/50">
<img
src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?q=80&w=2070&auto=format&fit=crop"
alt="Interior delicado"
className="w-full h-full object-cover object-center"
/>
</div>
{/* Delicate accents */}
<div className="absolute -top-6 -right-6 w-32 h-32 border border-brand-gold/30 rounded-full -z-10"></div>
<div className="absolute -bottom-8 -left-8 w-40 h-40 bg-[#f4ece8] rounded-full blur-2xl -z-10"></div>
</div>
</motion.div>
</div>
</section>
{/* APRESENTAÇÃO / SOBRE SECTION */}
<section className="py-24 md:py-32 bg-white relative overflow-hidden">
<div className="absolute top-0 right-0 w-1/3 h-full bg-[#FCFAFA] -z-10 mix-blend-multiply"></div>
<div className="max-w-6xl mx-auto px-6 lg:px-8">
<div className="flex flex-col md:flex-row gap-16 lg:gap-24 items-center">
<motion.div
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 1 }}
className="w-full md:w-5/12 relative order-2 md:order-1"
>
<div className="aspect-square rounded-full overflow-hidden border-8 border-white shadow-2xl shadow-stone-200 max-w-sm mx-auto">
<img
src="https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?q=80&w=1976&auto=format&fit=crop"
alt="Helena Fontes - Retrato"
className="w-full h-full object-cover"
/>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 1, delay: 0.2 }}
className="w-full md:w-7/12 order-1 md:order-2 text-center md:text-left"
>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-serif text-brand-dark leading-tight mb-8">
Um olhar refinado para <br className="hidden md:block"/><span className="italic text-brand-gold/80">o seu próximo lar.</span>
</h2>
<div className="space-y-6 text-stone-500 font-light text-lg">
<p>
Olá, sou Helena. Ao longo dos últimos anos, venho me dedicando a entender o que realmente transforma uma propriedade em um refúgio. Mais do que metragens e valores, busco a essência de cada endereço.
</p>
<p>
Trabalho de forma intimista, com um portfólio reduzido e acesso a propriedades exclusivas. Meu papel é guiar você em uma jornada tranquila, transparente e absolutamente inspiradora até a sua nova casa.
</p>
</div>
<div className="mt-10 font-serif italic text-2xl text-brand-dark opacity-80">
Helena Fontes
</div>
</motion.div>
</div>
</div>
</section>
{/* DIFERENCIAIS SECTION (Redesigned) */}
<section className="py-24 md:py-32 bg-[#FCFAFA] relative overflow-hidden">
<div className="absolute top-1/2 left-0 -translate-y-1/2 w-64 h-64 bg-stone-100 rounded-full blur-3xl -z-10"></div>
<div className="max-w-5xl mx-auto px-6 lg:px-8">
<div className="text-center mb-16 md:mb-24">
<h2 className="text-3xl md:text-5xl font-serif text-brand-dark leading-tight">
Elevando o <span className="italic font-light">cuidado,</span> <br/>
<span className="text-stone-400">em cada detalhe.</span>
</h2>
</div>
<div className="space-y-16 lg:space-y-24">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="flex flex-col md:flex-row gap-8 md:gap-16 items-center"
>
<div className="text-brand-gold font-serif italic text-6xl md:text-8xl opacity-30 select-none">I.</div>
<div>
<h3 className="text-2xl font-serif text-brand-dark mb-4">
Discrição e Sutileza
</h3>
<p className="text-stone-500 font-light leading-relaxed max-w-xl">
Cada cliente recebe atenção exclusiva. Compreender profundamente suas necessidades, seus desejos e seu estilo de vida, conduzindo cada visita com absoluta discrição e leveza.
</p>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.2 }}
className="flex flex-col md:flex-row gap-8 md:gap-16 items-center md:pl-20"
>
<div className="text-brand-gold font-serif italic text-6xl md:text-8xl opacity-30 select-none">II.</div>
<div>
<h3 className="text-2xl font-serif text-brand-dark mb-4">
Curadoria Afetiva
</h3>
<p className="text-stone-500 font-light leading-relaxed max-w-xl">
Não mostro dezenas de casas; apresento lares que ressoam com a sua personalidade. Uma seleção criteriosa focada na qualidade de vida e no bom gosto, não no volume.
</p>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.4 }}
className="flex flex-col md:flex-row gap-8 md:gap-16 items-center md:pl-40"
>
<div className="text-brand-gold font-serif italic text-6xl md:text-8xl opacity-30 select-none">III.</div>
<div>
<h3 className="text-2xl font-serif text-brand-dark mb-4">
Rede Off-Market
</h3>
<p className="text-stone-500 font-light leading-relaxed max-w-xl">
Acesso privilegiado a propriedades exclusivas não anunciadas publicamente. Casas e coberturas preservadas para quem valoriza a verdadeira raridade antes que cheguem ao mercado.
</p>
</div>
</motion.div>
</div>
</div>
</section>
{/* TESTIMONIALS SECTION (SOCIAL PROOF) */}
<section className="py-24 lg:py-32 bg-white flex flex-col items-center text-center px-6">
<div className="max-w-4xl mx-auto w-full">
<span className="text-xs uppercase tracking-[0.2em] text-stone-400 font-bold block mb-12">
Reconhecimento
</span>
<div className="relative">
<div className="text-brand-gold/10 text-[120px] font-serif absolute -top-16 left-1/2 -translate-x-1/2 italic leading-none pointer-events-none select-none">"</div>
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="relative z-10"
>
<h2 className="text-2xl md:text-4xl lg:text-5xl font-serif text-brand-dark leading-snug mb-10 text-stone-600 font-light relative z-10 p-8 md:p-12 border border-stone-100 bg-white shadow-2xl shadow-stone-100 rounded-sm">
"A sensibilidade da Helena foi fundamental para encontrarmos nosso novo lar. Ela não apenas nos mostrou imóveis, mas ajudou a vislumbrar o estilo de vida que sonhávamos, com uma paciência e discrição raras no mercado."
<div className="mt-8 font-serif font-medium text-brand-dark tracking-wide text-lg">
<span className="block text-brand-gold text-xs uppercase tracking-widest font-bold mb-2">Cliente Compradora</span>
S.M. Itaim Bibi
</div>
</h2>
</motion.div>
</div>
<div className="mt-12">
<Link to="/assessoria" className="text-[10px] uppercase font-bold tracking-[0.2em] text-brand-dark border-b border-brand-dark hover:border-brand-gold hover:text-brand-gold transition-colors pb-1">
Conhecer a Metodologia
</Link>
</div>
</div>
</section>
{/* FAQ SECTION */}
<section className="py-24 lg:py-32 bg-[#FCFAFA]">
<div className="max-w-5xl mx-auto px-6 lg:px-8">
<div className="text-center mb-16 md:mb-24">
<h2 className="text-3xl md:text-5xl font-serif text-brand-dark leading-tight">
Esclarecimentos <span className="italic text-stone-400">Freqüentes</span>
</h2>
</div>
<div className="space-y-4">
{[
{
q: "Como funciona a assessoria para compra de imóveis?",
a: "Busca ativa por todo o mercado. Filtro o ruído, faço as inspeções prévias e entrego relatórios analíticos antes da sua visita."
},
{
q: "O que são imóveis off-market?",
a: "São propriedades exclusivas que não são anunciadas publicamente, oferecendo maior privacidade e oportunidades únicas para compradores qualificados."
},
{
q: "Qual a vantagem da exclusividade de venda?",
a: "A exclusividade garante um plano de marketing focado, filtro rigoroso e proteção contra a desvalorização do ativo por sobreposição de anúncios no mercado."
},
{
q: "Como é garantido o sigilo da negociação?",
a: "Trabalho com Acordos de Confidencialidade (NDA) quando necessário e filtro estritamente as informações compartilhadas."
}
].map((faq, idx) => (
<div key={idx} className="group border-b border-stone-200 py-8 px-4 hover:bg-white transition-colors cursor-default">
<div className="flex flex-col md:flex-row md:items-baseline gap-4 md:gap-12">
<h3 className="font-serif text-xl tracking-wide text-brand-dark md:w-5/12 shrink-0 group-hover:text-brand-gold transition-colors">
{faq.q}
</h3>
<p className="text-stone-500 font-light md:w-7/12 leading-relaxed">
{faq.a}
</p>
</div>
</div>
))}
</div>
</div>
</section>
</>
);
}
function ArticleRoute() {
const { id } = useParams();
const article = articles.find((a) => a.id === id);
if (!article) {
return (
<div className="min-h-screen pt-40 pb-24 text-center">
<h1 className="text-4xl font-serif mb-4">Artigo não encontrado</h1>
<Link to="/" className="text-brand-gold hover:underline">Voltar para o início</Link>
</div>
);
}
return <ArticleView article={article} />;
}
function ArticleView({ article }: { article: Article }) {
return (
<>
<Helmet>
<title>{article.title} | Helena Fontes</title>
<meta name="description" content={article.excerpt} />
{article.type === "property" ? (
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "RealEstateListing",
"name": article.title,
"description": article.excerpt,
"image": article.coverImage,
"offers": {
"@type": "Offer",
"priceCurrency": "BRL",
"price": article.details?.price?.replace(/[^0-9]/g, "") || "0"
}
})}
</script>
) : (
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": article.title,
"description": article.excerpt,
"image": article.coverImage,
"author": {
"@type": "Person",
"name": "Helena Fontes"
},
"datePublished": "2024-01-01" // Idealmente seria a data do artigo
})}
</script>
)}
</Helmet>
<motion.article
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
className="pt-32 pb-24"
>
<div className="max-w-4xl mx-auto px-6 lg:px-8">
<Link
to="/"
className="inline-flex items-center gap-2 text-xs uppercase tracking-widest font-bold text-stone-500 hover:text-brand-dark transition-colors mb-12"
>
<ArrowLeft size={16} />
Voltar
</Link>
<div className="flex items-center gap-4 text-brand-gold text-[10px] font-bold uppercase tracking-[0.3em] mb-8 justify-center md:justify-start">
<span>{article.category}</span>
<span className="w-4 h-px bg-brand-gold"></span>
<span className="text-stone-400">{article.date}</span>
</div>
<h1 className="text-4xl md:text-5xl lg:text-7xl font-serif text-brand-dark leading-[1.1] mb-12 text-center md:text-left">
{article.title}
</h1>
<p className="text-xl text-stone-500 font-light leading-relaxed mb-16 max-w-2xl px-6 border-l border-brand-gold/50 mx-auto md:mx-0">
{article.excerpt}
</p>
</div>
<div className="w-full max-w-6xl mx-auto px-4 lg:px-8 mb-24">
<div className="aspect-[4/3] md:aspect-[21/9] bg-stone-100 overflow-hidden relative rounded-t-full md:rounded-bl-[200px] md:rounded-tr-[200px]">
<img
src={article.coverImage}
alt={article.title}
className="w-full h-full object-cover"
/>
{article.type === "property" && article.details && (
<div className="absolute bottom-6 right-1/2 translate-x-1/2 md:translate-x-0 md:right-12 bg-white/95 backdrop-blur rounded-sm px-8 py-4 shadow-xl text-center md:text-left">
<div className="text-[10px] uppercase tracking-[0.3em] text-stone-400 font-bold mb-1">
Valor
</div>
<div className="font-serif text-2xl text-brand-dark">
{article.details.price}
</div>
</div>
)}
</div>
</div>
<div className="max-w-3xl mx-auto px-6 lg:px-8">
<div className="prose prose-zinc prose-lg font-light leading-loose text-stone-700">
{article.content}
</div>
<div className="my-24 py-16 px-6 text-center relative max-w-4xl mx-auto">
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-px h-16 bg-brand-gold/30"></div>
<blockquote className="text-3xl md:text-4xl font-serif italic text-stone-500 mb-8 mt-8 leading-relaxed font-light">
"{article.quote.text}"
</blockquote>
<cite className="text-[10px] uppercase tracking-[0.3em] font-bold text-brand-gold not-italic">
{article.quote.author}
</cite>
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-px h-16 bg-brand-gold/30"></div>
</div>
<div className="text-center pt-16 border-t border-stone-200 mt-16">
<h3 className="font-serif text-2xl mb-6">
Possui interesse nesta propriedade ou assunto?
</h3>
<a
href="https://wa.me/5511999999999"
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-3 bg-brand-dark hover:bg-brand-gold text-white px-8 py-4 text-xs font-bold uppercase tracking-[0.1em] transition-colors"
>
Falar Diretamente no WhatsApp
</a>
</div>
{article.type === "property" && article.details?.location && (
<div className="mt-32 pt-24 border-t border-stone-200">
<span className="text-[10px] uppercase tracking-[0.3em] font-bold text-brand-gold block mb-4 text-center">Localização</span>
<h3 className="font-serif text-3xl md:text-5xl mb-6 text-brand-dark text-center">
Território & Contexto
</h3>
<p className="text-stone-500 font-light text-center max-w-xl mx-auto mb-16 leading-relaxed">
Para assegurar a serenidade e máxima privacidade, indicamos apenas a região aproximada. A localização exata deste imóvel será compartilhada de forma estritamente pessoal, mediante uma qualificação delicada.
</p>
<div className="w-full h-96 bg-stone-100 overflow-hidden relative rounded-sm shadow-xl shadow-stone-200/50 border border-white">
<iframe
src={`https://maps.google.com/maps?q=${encodeURIComponent(article.details.location)}&t=m&z=14&output=embed`}
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen={false}
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title={`Mapa regional para ${article.details.location}`}
className="w-full h-full object-cover grayscale opacity-80 hover:grayscale-0 hover:opacity-100 transition-all duration-700"
></iframe>
</div>
</div>
)}
</div>
</motion.article>
</>
);
}

View file

@ -0,0 +1,104 @@
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export function Analytics() {
const location = useLocation();
useEffect(() => {
// Inject Google Tag Manager
const gtmId = import.meta.env.VITE_GTM_ID;
if (gtmId) {
const script = document.createElement("script");
script.innerHTML = `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmId}');
`;
document.head.appendChild(script);
const noscript = document.createElement("noscript");
noscript.innerHTML = `<iframe src="https://www.googletagmanager.com/ns.html?id=${gtmId}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`;
document.body.insertBefore(noscript, document.body.firstChild);
}
// Inject Google Analytics (if separate from GTM)
const gaId = import.meta.env.VITE_GA_MEASUREMENT_ID;
if (gaId) {
const scriptGa = document.createElement("script");
scriptGa.async = true;
scriptGa.src = `https://www.googletagmanager.com/gtag/js?id=${gaId}`;
document.head.appendChild(scriptGa);
const scriptInline = document.createElement("script");
scriptInline.innerHTML = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${gaId}');
`;
document.head.appendChild(scriptInline);
}
// Inject Google Ads (if separate from above GA tag)
const adsId = import.meta.env.VITE_GOOGLE_ADS_ID;
if (adsId && adsId !== gaId) {
const scriptAds = document.createElement("script");
scriptAds.async = true;
scriptAds.src = `https://www.googletagmanager.com/gtag/js?id=${adsId}`;
document.head.appendChild(scriptAds);
const scriptInline = document.createElement("script");
scriptInline.innerHTML = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${adsId}');
`;
document.head.appendChild(scriptInline);
}
// Inject Meta/Facebook Pixel
const pixelId = import.meta.env.VITE_FB_PIXEL_ID;
if (pixelId) {
const script = document.createElement("script");
script.innerHTML = `
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '${pixelId}');
fbq('track', 'PageView');
`;
document.head.appendChild(script);
const noscript = document.createElement("noscript");
noscript.innerHTML = `<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=${pixelId}&ev=PageView&noscript=1" />`;
document.body.appendChild(noscript);
}
}, []);
// Track page views on route change
useEffect(() => {
// GA PageView
const gaId = import.meta.env.VITE_GA_MEASUREMENT_ID;
if (gaId && typeof window !== "undefined" && (window as any).gtag) {
(window as any).gtag("config", gaId, {
page_path: location.pathname + location.search,
});
}
// FB Pixel PageView
const pixelId = import.meta.env.VITE_FB_PIXEL_ID;
if (pixelId && typeof window !== "undefined" && (window as any).fbq) {
(window as any).fbq('track', 'PageView');
}
}, [location]);
return null;
}

View file

@ -0,0 +1,652 @@
import React from "react";
import { Link } from "react-router-dom";
export type ArticleType = "property" | "insight";
export interface Article {
id: string;
type: ArticleType;
category: string;
title: string;
excerpt: string;
coverImage: string;
date: string;
content: React.ReactNode;
quote: {
text: string;
author: string;
};
details?: {
price?: string;
specs?: string;
status?: string;
location?: string;
};
}
export const articles: Article[] = [
{
id: "residencial-jardim-europa-01",
type: "property",
category: "Jardim Europa, São Paulo",
title: "Residência de Autor: Modernismo e Privacidade Absoluta",
excerpt:
"Uma análise detalhada desta propriedade singular com 850m² de área construída, integrando living e um jardim projetado por Burle Marx.",
coverImage:
"https://images.unsplash.com/photo-1600596542815-ffad4c1539a9?q=80&w=2075&auto=format&fit=crop",
date: "Maio 2026",
quote: {
text: "A arquitetura não é sobre a construção de paredes, mas sobre a criação de atmosferas.",
author: "Peter Zumthor",
},
details: {
price: "R$ 18.500.000",
specs: "850m² • 4 Suítes • 6 Vagas",
status: "Disponível para Visitação",
location: "Jardim Europa, São Paulo",
},
content: (
<>
<p>
Apresento esta excepcional residência localizada no coração do Jardim
Europa, um dos bairros mais tradicionais e valorizados de São Paulo.
Tive o privilégio de acompanhar a evolução desta propriedade ao longo
dos anos, e seu estado de conservação e design permanecem
irretocáveis.
</p>
<h3>O Espaço e a Luz</h3>
<p>
A planta foi concebida para que a luz natural permeie todos os
ambientes durante o dia. Painéis de vidro piso-teto criam uma
transição fluida entre o interior e o monumental jardim, que abriga
espécies nativas e espelhos d'água.
</p>
<p>
No piso superior, a suíte master atua como um refúgio particular,
contando com dois banheiros independentes, um amplo closet e uma
varanda voltada para o verde. Caso esteja em busca de outras
propriedades na região, você pode conferir nossa{" "}
<Link to="/artigo/valorizacao-jardim-europa">
análise de valorização do Jardim Europa
</Link>
.
</p>
</>
),
},
{
id: "cobertura-itaim-bibi",
type: "property",
category: "Itaim Bibi, São Paulo",
title: "A Perspectiva 360º: Cobertura Duplex no Centro Financeiro",
excerpt:
"Oportunidade raríssima no coração do Itaim. Uma cobertura reformada em 2024, com espaço gourmet completo voltado para o skyline da cidade.",
coverImage:
"https://images.unsplash.com/photo-1600607688969-a5bfcd64bd40?q=80&w=2053&auto=format&fit=crop",
date: "Abril 2026",
quote: {
text: "Viver no topo é ter a cidade como seu quadro em constante mudança.",
author: "Helena Fontes",
},
details: {
price: "R$ 12.800.000",
specs: "420m² • 3 Suítes • 4 Vagas",
status: "Exclusividade",
location: "Itaim Bibi",
},
content: (
<>
<p>
O Itaim Bibi se consolidou como o epicentro financeiro e de lifestyle
da América Latina. Ter uma cobertura duplex nesta região é um
privilégio destinado a poucos. Este imóvel, em particular, passou por
um retrofit completo estrutural em 2024, assinado por um renomado
escritório de arquitetura brasileiro.
</p>
<h3>Design e Funcionalidade</h3>
<p>
Os acabamentos incluem mármore Travertino Navona e marcenaria Ornare
em todos os ambientes. O destaque definitivo é a área social no
segundo pavimento, equipada com piscina de borda infinita aquecida e
espaço gourmet, perfeito para recepções íntimas com vista para o
parque Ibirapuera.
</p>
<p>
Leia mais sobre o{" "}
<Link to="/artigo/novo-luxo-sp">novo conceito de luxo vertical</Link>.
</p>
</>
),
},
{
id: "fazenda-boa-vista",
type: "property",
category: "Porto Feliz, São Paulo",
title: "Refúgio de Fim de Semana com Arquitetura Vernacular",
excerpt:
"Nesta casa de campo a uma hora de São Paulo, os limites entre o interior e o exterior deixam de existir, cercados por mata nativa e lagos exuberantes.",
coverImage:
"https://images.unsplash.com/photo-1613977257363-707ba9348227?q=80&w=2070&auto=format&fit=crop",
date: "Março 2026",
quote: {
text: "O luxo contemporâneo é o espaço, o silêncio e o tempo.",
author: "Axel Vervoordt",
},
details: {
price: "Consulte o Valor",
specs: "1.200m² • 6 Suítes • 8 Vagas",
status: "Off-Market",
location: "Fazenda Boa Vista",
},
content: (
<>
<p>
Uma imersão completa na natureza sem abrir mão de nenhuma conveniência
urbana. Esta propriedade em um dos condomínios mais exclusivos do país
foi idealizada para ser um santuário familiar.
</p>
<h3>Sustentabilidade e Conforto</h3>
<p>
Com painéis solares, captação de água da chuva e automação residencial
nível 4, a casa opera com altíssima eficiência. O layout privilegia
áreas de convivência generosas, com um deck expansivo que se projeta
em direção à paisagem. Uma verdadeira obra de arte habitável.
</p>
</>
),
},
{
id: "tendencias-arquitetura-2026",
type: "insight",
category: "Tendências",
title: "Tendências de Arquitetura e Interior para 2026",
excerpt:
"A fusão entre tecnologia invisível, materiais orgânicos e a fluidez dos layouts dita as regras das novas residências de luxo.",
coverImage:
"https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?q=80&w=2000&auto=format&fit=crop",
date: "18 Maio, 2026",
quote: {
text: "Onde o design encontra a tecnologia, nasce o conforto invisível.",
author: "Design Studio",
},
content: (
<>
<p>
Este ano consolidou uma mudança silenciosa nas exigências do mercado
premium: a tecnologia não deve mais ser vista no ambiente, mas deve
operar tudo nos bastidores.
</p>
<h3>Acabamentos Orgânicos Naturais</h3>
<p>
Observamos a valorização de imperfeições naturais nas pedras e
madeiras de demolição, trazendo calor e exclusividade a ambientes que
pouco tempo eram pautados pela frieza modernista do vidro e
cimento.
</p>
<p>
Visite nossa{" "}
<Link to="/artigo/residencial-jardim-europa-01">
residência no Jardim Europa
</Link>{" "}
para ver a aplicação prática deste conceito de design.
</p>
</>
),
},
{
id: "mercado-luxo-sp",
type: "insight",
category: "Mercado Financeiro",
title: "Por que São Paulo atrai investidores globais?",
excerpt:
"Dados exclusivos de valorização indicam que a capital paulista se mantém resistente às oscilações internacionais.",
coverImage:
"https://images.unsplash.com/photo-1430285561322-780c604615ce?q=80&w=2070&auto=format&fit=crop",
date: "12 Maio, 2026",
quote: {
text: "O mercado imobiliário paulistano premium é blindado pelas dinâmicas de escassez e exclusividade.",
author: "Financial Times",
},
content: (
<>
<p>
De forma constante, o metro quadrado das coberturas de São Paulo em
regiões prime (Itaim, Vila Nova Conceição) superou a inflação nos
últimos dez anos.
</p>
<h3>Safe Haven</h3>
<p>
Para fundos e family offices, estacionar capital em imóveis icônicos
da cidade provou ser tanto um mecanismo de proteção quanto um
propulsor de ganhos através da hiper-valorização e retrofit.
</p>
</>
),
},
{
id: "guia-aquisicao-jardim-europa",
type: "insight",
category: "Investimentos",
title: "A valorização contínua e as oportunidades no Jardim Europa",
excerpt:
"Como as restrições construtivas garantem o valor do bairro, e por que a paciência é a melhor estratégia de compra.",
coverImage:
"https://images.unsplash.com/photo-1518507727145-cb3e7f01de55?q=80&w=2070&auto=format&fit=crop",
date: "05 Maio, 2026",
quote: {
text: "A ausência de verticalização é o maior luxo contemporâneo de São Paulo.",
author: "Instituto Urbano",
},
content: (
<>
<p>
Diferente de NY ou Londres, as áreas exclusivas de casas em São Paulo
não podem se adensar. O Jardim Europa é tombado, protegendo seus
moradores dos prédios altos. Mas o que isso significa para o
patrimônio?
</p>
<h3>Escassez de Solo e Curva de Apreciação</h3>
<p>
Na prática, quem possui um terreno na região não tem novos
competidores. Recomendamos sempre uma análise minuciosa de diligência
(<Link to="/artigo/guia-aquisicao-jardim-europa">leia o guia de aquisição</Link>) antes
de assinar qualquer compromisso, devido à complexidade da
regularização imobiliária das casas antigas.
</p>
</>
),
},
{
id: "penthouse-cidade-jardim",
type: "property",
category: "Cidade Jardim, São Paulo",
title: "Triplex Suspenso com Vista para a Skyline Paulista",
excerpt:
"Com mais de 1000m², este apartamento evoca a essência de uma mansão suspensa.",
coverImage:
"https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?q=80&w=2000&auto=format&fit=crop",
date: "01 Maio, 2026",
quote: {
text: "A grandiosidade se mede pelo espaço e pela privacidade, a centenas de metros do chão.",
author: "Helena Fontes",
},
details: {
price: "R$ 35.000.000",
specs: "1050m² • 5 Suítes • 10 Vagas",
status: "Exclusividade",
location: "Cidade Jardim",
},
content: (
<>
<p>
Espaços palacianos. O direito duplo do living cria uma sensação de
imponência. A suíte master ocupa um andar inteiro. Esta é, de fato,
uma joia cobiçada no portfólio.
</p>
</>
),
},
{
id: "guia-aquisicao",
type: "insight",
category: "Guia Jurídico",
title: "Guia de Aquisição: Estruturação jurídica para grandes propriedades",
excerpt:
"Os passos essenciais e diligências que aplico antes de apresentar qualquer imóvel aos meus clientes.",
coverImage:
"https://images.unsplash.com/photo-1450101499163-c8848c66cb85?q=80&w=2070&auto=format&fit=crop",
date: "28 Abril, 2026",
quote: {
text: "A verdadeira segurança em uma negociação imobiliária reside no que não está visível.",
author: "L. Barros, Jurista",
},
content: (
<>
<p>
Em transações de alto valor agregado, as certidões cíveis e criminais
formam apenas 30% da verdadeira análise de risco.
</p>
<p>
Para ler mais, verifique{" "}
<Link to="/artigo/importancia-retrofit">
como o retrofit pode impactar esse risco legal
</Link>
.
</p>
</>
),
},
{
id: "novo-luxo-sp",
type: "insight",
category: "Comportamento",
title: "O Novo Luxo: Espaço vs Localização",
excerpt:
"A mudança de paradigma daqueles que valorizavam endereços cobiçados acima de tudo, em prol do espaço e bem-estar.",
coverImage:
"https://images.unsplash.com/photo-1512917774080-9991f1c4c750?q=80&w=2000&auto=format&fit=crop",
date: "22 Abril, 2026",
quote: {
text: "Não compramos mais endereço, compramos qualidade de vida.",
author: "Exame",
},
content: (
<>
<p>
A pandemia alterou permanentemente o morar premium. O verde deixou de
ser adorno para ser infraestrutura.
</p>
</>
),
},
{
id: "investimento-arte-imoveis",
type: "insight",
category: "Lifestyle",
title: "Investimento em Arte e Alta Decoração de Interiores",
excerpt:
"Como colecionar arte tem sinergia com o mercado de real estate de altíssimo nível.",
coverImage:
"https://images.unsplash.com/photo-1513694203232-719a280e022f?q=80&w=2000&auto=format&fit=crop",
date: "15 Abril, 2026",
quote: {
text: "As paredes são curadoras de nossas almas.",
author: "D. Soares",
},
content: (
<>
<p>
Casas de proporções generosas demandam peças à altura. um
intercâmbio constante entre galerias de arte e imobiliárias premium.
Em minha{" "}
<Link to="/artigo/fazenda-boa-vista">casa na Fazenda Boa Vista</Link>, o
projeto incluiu recuos para esculturas grandes.
</p>
</>
),
},
{
id: "condominio-vila-nova",
type: "property",
category: "Vila Nova Conceição",
title: "Apartamento Neoclássico na Praça Pereira Coutinho",
excerpt:
"Uma joia intocada em um dos logradouros mais valorizados do país.",
coverImage:
"https://images.unsplash.com/photo-1497366216548-37526070297c?q=80&w=2000&auto=format&fit=crop",
date: "10 Abril, 2026",
quote: {
text: "Viver de frente para a praça é prolongar a sala de estar.",
author: "R. Fontes",
},
details: {
price: "R$ 16.000.000",
specs: "300m² • 3 Suítes • 4 Vagas",
status: "Disponível",
location: "Vila Nova Conceição",
},
content: (
<>
<p>
A exclusividade de atravessar a rua e estar no Ibirapuera. Edifício de
assinatura clássica, segurança impecável. Veja as tendências em{" "}
<Link to="/artigo/tendencias-arquitetura-2026">arquitetura</Link> para
atualizar o apartamento se desejar um retrofit.
</p>
</>
),
},
{
id: "casa-alphaville",
type: "property",
category: "Alphaville, São Paulo",
title: "Mansão Monumental no Tamboré",
excerpt:
"Segurança e qualidade de vida com proporções que a capital já não oferece.",
coverImage:
"https://images.unsplash.com/photo-1628611225249-6c4c3af4a80b?q=80&w=2000&auto=format&fit=crop",
date: "03 Abril, 2026",
quote: {
text: "O refúgio perfeito a 30 minutos da Faria Lima.",
author: "Revista Habitar",
},
details: {
price: "R$ 22.000.000",
specs: "1500m² • 6 Suítes • 12 Vagas",
status: "Consulte",
location: "Tamboré Destaque",
},
content: (
<>
<p>
Condomínios de alto luxo em Barueri continuam sua ascensão
impulsionada pelo recuo da modalidade de trabalho híbrido.
</p>
</>
),
},
{
id: "arquitetura-biofilica",
type: "insight",
category: "Design",
title: "Design Biofílico: O que os compradores premium procuram hoje",
excerpt:
"Como a integração com o verde deixou de ser um diferencial e passou a ser exigência.",
coverImage:
"https://images.unsplash.com/photo-1544005313-94ddf0286df2?q=80&w=2000&auto=format&fit=crop",
date: "30 Março, 2026",
quote: {
text: "A natureza não é um lugar para visitar. É a nossa casa.",
author: "Gary Snyder",
},
content: (
<>
<p>
Temos notado o aumento drástico pela procura de incorporações que
possuam mata nativa integrada. O verde é a nova corrente estética.
</p>
</>
),
},
{
id: "sustentabilidade-luxo",
type: "insight",
category: "Visão de Futuro",
title: "Sustentabilidade e Alto Padrão não são mais mutuamente exclusivos",
excerpt: "Certificações EDGE e LEED em residências horizontais.",
coverImage:
"https://images.unsplash.com/photo-1501183638710-841dd1904471?q=80&w=2000&auto=format&fit=crop",
date: "25 Março, 2026",
quote: {
text: "Luxo de verdade é não causar impacto sistêmico.",
author: "ESG Real Estate",
},
content: (
<>
<p>
A preocupação climática levou a uma modernização drástica dos métodos
construtivos e de suprimentos de energia off-grid.
</p>
</>
),
},
{
id: "retorno-casas-vila",
type: "insight",
category: "Urbanismo",
title: "O Retorno e Valorização das Casas de Vila em São Paulo",
excerpt:
"A procura desenfreada por vilas charmosas nos Jardins e Pinheiros.",
coverImage:
"https://images.unsplash.com/photo-1579487785973-74d2ca78ddfc?q=80&w=2000&auto=format&fit=crop",
date: "20 Março, 2026",
quote: {
text: "Há uma poesia irreplicável em pisar na rua de paralelepípedos e abrir um modesto portão para um oasis interno.",
author: "R. Fontes",
},
content: (
<>
<p>
Com as poucas unidades disponíveis no mercado, a precificação bate
recordes históricos. Veja mais em{" "}
<Link to="/artigo/mercado-off-market">off-market insights</Link>.
</p>
</>
),
},
{
id: "mercado-off-market",
type: "insight",
category: "Fundamentos",
title: "Mercado Off-Market: A negociação nas sombras",
excerpt:
"Como operam as chamadas 'Secret Listings' nas camadas mais altas da riqueza paulistana.",
coverImage:
"https://images.unsplash.com/photo-1590856029826-c7a73142bbf1?q=80&w=2000&auto=format&fit=crop",
date: "14 Março, 2026",
quote: {
text: "A discrição é a forma mais elevada de confiança.",
author: "Private Broker",
},
content: (
<>
<p>
Cerca de 40% das transações ultraluxo acontecem sem que a propriedade
seja sequer fotografada profissionalmente e inserida na rede.
</p>
</>
),
},
{
id: "importancia-retrofit",
type: "insight",
category: "Investimentos",
title: "A Importância do Retrofit nos Endereços Icônicos",
excerpt: "Atualizando prédios da década de 70 para compradores atuais.",
coverImage:
"https://images.unsplash.com/photo-1503387762-592deb58ef4e?q=80&w=2000&auto=format&fit=crop",
date: "10 Março, 2026",
quote: {
text: "Preservamos a fachada para atualizar a alma.",
author: "Arquitetura & Urbanismo",
},
content: (
<>
<p>
O retrofit é, hoje, a modalidade de investimento que mais agrega valor
ao metro quadrado defasado de Higienópolis e Jardins.
</p>
</>
),
},
{
id: "casa-pinheiros",
type: "property",
category: "Alto de Pinheiros",
title: "Residência Contemporânea Próxima à Praça Panamericana",
excerpt: "Casa de esquina, com total segurança e vocação receber.",
coverImage:
"https://images.unsplash.com/photo-1512915922686-57c11dde9b6b?q=80&w=2000&auto=format&fit=crop",
date: "05 Março, 2026",
quote: {
text: "Silêncio profundo na metrópole barulhenta.",
author: "Proprietário",
},
details: {
price: "R$ 14.500.000",
specs: "650m² • 4 Suítes • 5 Vagas",
status: "Disponível",
location: "Alto de Pinheiros",
},
content: (
<>
<p>Luz, brisa e segurança. Uma rara oportunidade em Pinheiros.</p>
</>
),
},
{
id: "apartamento-jardins",
type: "property",
category: "Jardins",
title: "Apartamento de Época Totalmente Restaurado",
excerpt: "O charme do piso em taco de peroba e do pé direito de 3.20m.",
coverImage:
"https://images.unsplash.com/photo-1533779283484-8ad4940aa3a8?q=80&w=2000&auto=format&fit=crop",
date: "28 Fevereiro, 2026",
quote: {
text: "O antigo redescoberto.",
author: "Design Team",
},
details: {
price: "R$ 6.800.000",
specs: "280m² • 3 Suítes • 2 Vagas",
status: "Em Negociação",
location: "Jardins",
},
content: (
<>
<p>
Um espetáculo visual de retrofit de ponta, ver mais em{" "}
<Link to="/artigo/importancia-retrofit">importância do retrofit</Link>.
</p>
</>
),
},
{
id: "cobertura-brooklin",
type: "property",
category: "Brooklin",
title: "Penthouse Exclusiva no Novo Polo",
excerpt:
"Condomínio clube moderno com todas as facilidades e uma planta fenomenal.",
coverImage:
"https://images.unsplash.com/photo-1502672260266-1c1e52509def?q=80&w=2000&auto=format&fit=crop",
date: "20 Fevereiro, 2026",
quote: {
text: "O novo centro convergiu para cá.",
author: "Valor Econômico",
},
details: {
price: "R$ 10.500.000",
specs: "380m² • 3 Suítes • 4 Vagas",
status: "Disponível",
location: "Brooklin Novo",
},
content: (
<>
<p>
Uma chance excelente na região com as sedes das maiores empresas do
Brasil.
</p>
</>
),
},
{
id: "fazenda-boa-vista-grama",
type: "property",
category: "Fazenda da Grama",
title: "Casa de Campo Moderna com Vista para o Lago",
excerpt: "Para fugir de São Paulo, no condomínio com praia particular.",
coverImage:
"https://images.unsplash.com/photo-1521579294248-c2bfa12a52ce?q=80&w=2000&auto=format&fit=crop",
date: "15 Fevereiro, 2026",
quote: {
text: "O pé na areia agora é verde e montanhoso.",
author: "Lifestyle Magazine",
},
details: {
price: "R$ 15.000.000",
specs: "800m² • 5 Suítes • 6 Vagas",
status: "Off-Market",
location: "Itupeva",
},
content: (
<>
<p>
Arquitetura em U ao redor de um pátio magnífico e uma piscina espelho
que repousa sobre a visão do lago central.
</p>
</>
),
},
];

20
Template-02/src/index.css Normal file
View file

@ -0,0 +1,20 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600&family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap');
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@theme {
--font-sans: "Montserrat", ui-sans-serif, system-ui, sans-serif;
--font-serif: "Cormorant Garamond", ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--color-brand-gold: #C89B85; /* Soft rose gold / blush */
--color-brand-gold-hover: #b58571;
--color-brand-dark: #2a2422; /* Warm espresso / charcoal */
}
body {
@apply font-sans text-brand-dark bg-[#FCFAFA];
}
h1, h2, h3, h4, h5, h6 {
@apply font-serif;
}

16
Template-02/src/main.tsx Normal file
View file

@ -0,0 +1,16 @@
import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import App from './App.tsx';
import './index.css';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<HelmetProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</HelmetProvider>
</StrictMode>,
);

View file

@ -0,0 +1,108 @@
import { motion } from "motion/react";
import { Helmet } from "react-helmet-async";
export function AssessoriaPage() {
return (
<>
<Helmet>
<title>A Assessoria | Helena Fontes | Consultoria Imobiliária Especializada</title>
<meta name="description" content="Proteja seus interesses nas transações imobiliárias mais complexas. Assessoria completa focada em precisão: do representation do vendedor ao buyer's agent." />
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "Service",
"serviceType": "Consultoria Imobiliária",
"provider": {
"@type": "RealEstateAgent",
"name": "Helena Fontes"
},
"description": "Consultoria imobiliária especializada em transações complexas e mercado de luxo. Representação de proprietários e assessoria na compra (Buyer's Agent)."
})}
</script>
</Helmet>
<div className="pt-40 pb-32 bg-[#FCFAFA] text-brand-dark min-h-screen">
<div className="max-w-4xl mx-auto px-6 lg:px-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
className="text-center mb-20"
>
<span className="text-[10px] uppercase tracking-[0.3em] text-brand-gold font-bold block mb-6">
A Prática
</span>
<h1 className="text-4xl md:text-5xl lg:text-7xl font-serif leading-tight mb-8">
A arte do <span className="italic text-stone-400">encontro</span>.
</h1>
<div className="w-px h-16 bg-brand-gold/50 mx-auto my-12"></div>
<p className="text-stone-500 font-light text-lg md:text-xl leading-relaxed max-w-2xl mx-auto">
Meu trabalho transcende a transação. Atuo como uma curadora do seu tempo e
patrimônio, garantindo que o processo de comprar ou vender uma propriedade
seja tão refinado quanto o imóvel em si.
</p>
</motion.div>
<div className="space-y-24 md:space-y-32">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="flex flex-col md:flex-row items-center gap-12 md:gap-20"
>
<div className="w-full md:w-1/2">
<div className="aspect-[4/5] object-cover rounded-t-full bg-stone-100 overflow-hidden shadow-xl shadow-stone-200/50 p-2 border border-white">
<img
src="https://images.unsplash.com/photo-1449844908441-8829872d2607?q=80&w=2070&auto=format&fit=crop"
alt="Detalhe arquitetônico"
className="w-full h-full object-cover rounded-t-full"
/>
</div>
</div>
<div className="w-full md:w-1/2">
<div className="text-brand-gold font-serif italic text-6xl mb-6 opacity-40">I.</div>
<h4 className="text-2xl md:text-3xl font-serif mb-6 text-brand-dark">
Para quem vende
</h4>
<p className="text-stone-500 font-light leading-relaxed text-lg">
Sua propriedade possui uma narrativa única. Desenvolvo estratégias de apresentação
que valorizam não apenas os espaços, mas o estilo de vida que o imóvel proporciona.
O foco é em alcançar as pessoas certas, de forma reservada e altamente direcionada.
</p>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="flex flex-col md:flex-row-reverse items-center gap-12 md:gap-20"
>
<div className="w-full md:w-1/2">
<div className="aspect-[4/5] object-cover rounded-t-full bg-stone-100 overflow-hidden shadow-xl shadow-stone-200/50 p-2 border border-white">
<img
src="https://images.unsplash.com/photo-1600585154340-be6161a56a0c?q=80&w=2070&auto=format&fit=crop"
alt="Ambiente sofisticado"
className="w-full h-full object-cover rounded-t-full"
/>
</div>
</div>
<div className="w-full md:w-1/2 md:text-right">
<div className="text-brand-gold font-serif italic text-6xl mb-6 opacity-40">II.</div>
<h4 className="text-2xl md:text-3xl font-serif mb-6 text-brand-dark">
Para quem busca
</h4>
<p className="text-stone-500 font-light leading-relaxed text-lg">
Como <i>Buyer's Agent</i>, mapeio o mercado (incluindo oportunidades <i>off-market</i>)
para filtrar rigorosamente o que realmente importa. Faço as visitas prévias, economizando
seu tempo e apresentando apenas os imóveis que ressoam com a sua busca.
</p>
</div>
</motion.div>
</div>
</div>
</div>
</>
);
}

View file

@ -0,0 +1,150 @@
import React, { useState } from "react";
import { motion } from "motion/react";
import { Instagram as InstaIcon, Linkedin as LinkedInIcon } from "lucide-react";
import { Helmet } from "react-helmet-async";
export function ContatoPage() {
const [isSubmitted, setIsSubmitted] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitted(true);
// Here you would typically send data to a backend
setTimeout(() => {
setIsSubmitted(false);
}, 5000);
};
return (
<>
<Helmet>
<title>Contato | Helena Fontes | Corretora de Luxo</title>
<meta name="description" content="Entre em contato para agendar uma reunião sigilosa. Discutiremos seus objetivos imobiliários no momento atual do mercado." />
</Helmet>
<div className="bg-[#FCFAFA] pt-40 pb-32 text-brand-dark min-h-screen">
<div className="max-w-4xl mx-auto px-6 lg:px-8 w-full">
<motion.div
className="text-center mb-20"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
>
<span className="text-[10px] uppercase tracking-[0.3em] text-brand-gold font-bold block mb-4">
Atendimento Exclusivo
</span>
<h1 className="text-4xl md:text-5xl lg:text-7xl font-serif leading-tight mb-8">
Um convite para <br className="hidden md:block"/>
<span className="italic text-stone-400">conversarmos.</span>
</h1>
<p className="text-stone-500 font-light text-lg mb-12 max-w-xl mx-auto">
Entre em contato para agendar uma reunião sigilosa. Discutiremos
suas perspectivas no mercado imobiliário com a devida delicadeza
e confidencialidade.
</p>
</motion.div>
<motion.div
className="flex flex-col md:flex-row gap-16 md:gap-24"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.2 }}
>
<div className="w-full md:w-3/5">
{isSubmitted ? (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="p-8 bg-[#f4ece8] text-brand-dark mb-8 rounded-sm"
>
<h3 className="font-serif text-2xl mb-3">Mensagem Recebida</h3>
<p className="text-stone-500 font-light">Obrigada pelo seu contato. Retornarei o mais breve possível com máxima discrição.</p>
</motion.div>
) : (
<form className="space-y-8" onSubmit={handleSubmit}>
<div>
<label htmlFor="name" className="sr-only">Nome Completo</label>
<input required type="text" id="name" placeholder="SEU NOME" className="w-full bg-transparent border-b border-stone-300 text-brand-dark px-2 py-4 text-[10px] tracking-widest uppercase focus:outline-none focus:border-brand-gold transition-colors placeholder:text-stone-400" />
</div>
<div>
<label htmlFor="email" className="sr-only">Email</label>
<input required type="email" id="email" placeholder="ENDEREÇO DE E-MAIL" className="w-full bg-transparent border-b border-stone-300 text-brand-dark px-2 py-4 text-[10px] tracking-widest uppercase focus:outline-none focus:border-brand-gold transition-colors placeholder:text-stone-400" />
</div>
<div>
<label htmlFor="phone" className="sr-only">Telefone / WhatsApp</label>
<input required type="tel" id="phone" placeholder="TELEFONE / WHATSAPP" className="w-full bg-transparent border-b border-stone-300 text-brand-dark px-2 py-4 text-[10px] tracking-widest uppercase focus:outline-none focus:border-brand-gold transition-colors placeholder:text-stone-400" />
</div>
<div>
<label htmlFor="message" className="sr-only">Mensagem (opcional)</label>
<textarea id="message" rows={4} placeholder="COMO POSSO AJUDAR?" className="w-full bg-transparent border-b border-stone-300 text-brand-dark px-2 py-4 text-[10px] tracking-widest uppercase focus:outline-none focus:border-brand-gold transition-colors placeholder:text-stone-400 resize-none"></textarea>
</div>
<button type="submit" className="w-full bg-brand-dark hover:bg-brand-gold text-white px-8 py-5 text-[10px] font-bold uppercase tracking-[0.3em] transition-colors mt-8">
Enviar Mensagem
</button>
</form>
)}
</div>
<div className="w-full md:w-2/5 space-y-16">
<div>
<h4 className="text-[10px] uppercase tracking-[0.3em] text-stone-400 font-bold block mb-6">
Contato Direto
</h4>
<ul className="space-y-4 text-stone-500 font-light text-lg">
<li>
<a
href="mailto:helena@helenafontes.com"
className="hover:text-brand-gold border-b border-stone-300 hover:border-brand-gold pb-1 transition-colors block w-fit"
>
helena@helenafontes.com
</a>
</li>
<li>+55 11 99999.9999</li>
<li className="pt-4 flex gap-6">
<a href="#" className="text-stone-400 hover:text-brand-gold transition-colors">
<InstaIcon size={20} strokeWidth={1.5} />
</a>
<a href="#" className="text-stone-400 hover:text-brand-gold transition-colors">
<LinkedInIcon size={20} strokeWidth={1.5} />
</a>
</li>
</ul>
</div>
<div>
<h4 className="text-[10px] uppercase tracking-[0.3em] text-stone-400 font-bold block mb-6">
O Escritório
</h4>
<ul className="space-y-4 text-stone-500 font-light text-lg">
<li>Av. Brigadeiro Faria Lima, 3477</li>
<li>Itaim Bibi São Paulo, SP</li>
<li className="pt-4 text-stone-400 italic text-sm">Apenas com hora marcada</li>
</ul>
</div>
</div>
</motion.div>
{/* MAP SECTION */}
<motion.div
className="w-full h-80 md:h-96 mt-24 bg-stone-100 border border-white shadow-xl shadow-stone-200/50 rounded-sm overflow-hidden"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.2 }}
>
<iframe
src="https://maps.google.com/maps?q=Av.%20Brigadeiro%20Faria%20Lima,%203477,%20São%20Paulo&t=m&z=16&output=embed&layer=c"
width="100%"
height="100%"
style={{ border: 0 }}
allowFullScreen={false}
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title="Localização do Escritório"
className="w-full h-full object-cover grayscale opacity-80 hover:grayscale-0 hover:opacity-100 transition-all duration-700"
></iframe>
</motion.div>
</div>
</div>
</>
);
}

View file

@ -0,0 +1,66 @@
import { Link } from "react-router-dom";
import { ArrowRight } from "lucide-react";
import { Helmet } from "react-helmet-async";
import { Article } from "../data/articles";
import { motion } from "motion/react";
export function InsightsPage({ marketInsights }: { marketInsights: Article[] }) {
return (
<>
<Helmet>
<title>Insights & Blog | Helena Fontes</title>
<meta name="description" content="Artigos e análises de mercado sobre o mercado imobiliário premium de São Paulo. Dicas de negócios e inteligência analítica." />
</Helmet>
<div className="pt-40 pb-32 bg-[#FCFAFA] min-h-screen">
<div className="max-w-4xl mx-auto px-6 lg:px-8">
<div className="mb-24 text-center md:text-left">
<span className="text-[10px] uppercase tracking-[0.3em] text-stone-400 font-bold block mb-4">
Diário Pessoal
</span>
<h1 className="text-4xl md:text-5xl lg:text-7xl font-serif text-brand-dark leading-tight">
Reflexões e <br className="hidden md:block"/><span className="italic text-stone-400">Inspirações.</span>
</h1>
</div>
<div className="flex flex-col space-y-16 lg:space-y-24">
{marketInsights.map((post, index) => (
<motion.div
key={post.id}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.1 }}
className="border-t border-stone-200 pt-12 md:pt-16"
>
<Link
to={`/artigo/${post.id}`}
className="group block"
>
<div className="flex flex-col md:flex-row md:items-baseline gap-4 md:gap-16 mb-6">
<span className="text-[10px] text-brand-gold uppercase tracking-[0.3em] font-bold w-32 shrink-0">
{post.date}
</span>
<h3 className="text-2xl md:text-4xl font-serif text-brand-dark group-hover:text-stone-500 transition-colors leading-snug">
{post.title}
</h3>
</div>
<div className="flex flex-col md:flex-row gap-4 md:gap-16">
<div className="w-32 shrink-0 hidden md:block"></div>
<div>
<p className="text-stone-500 font-light text-lg leading-relaxed mb-10 max-w-2xl">
{post.excerpt}
</p>
<span className="flex items-center gap-4 text-[10px] font-bold uppercase tracking-[0.3em] text-brand-dark group-hover:text-brand-gold transition-colors w-fit">
<span className="pb-1 border-b border-brand-dark group-hover:border-brand-gold transition-colors">Ler artigo</span>
</span>
</div>
</div>
</Link>
</motion.div>
))}
</div>
</div>
</div>
</>
);
}

View file

@ -0,0 +1,34 @@
import { Link } from "react-router-dom";
import { Helmet } from "react-helmet-async";
import { ArrowLeft } from "lucide-react";
export function NotFoundPage() {
return (
<>
<Helmet>
<title>Página Não Encontrada | Helena Fontes</title>
<meta name="description" content="A página que você está procurando não existe ou foi movida." />
</Helmet>
<div className="min-h-[80vh] flex flex-col items-center justify-center px-6 lg:px-8 text-center pt-32 pb-24">
<span className="text-[10px] uppercase tracking-[0.3em] font-bold text-brand-gold mb-4 block">
Erro 404
</span>
<h1 className="text-4xl md:text-6xl lg:text-8xl font-serif text-brand-dark leading-[1.1] mb-8">
Destino <br className="hidden md:block" />
<span className="italic text-stone-400">indisponível</span>
</h1>
<p className="text-stone-500 font-light max-w-lg mx-auto mb-12">
A página que você procura pode ter sido alterada, retirada do ar para garantir a exclusividade, ou o endereço foi digitado incorretamente.
</p>
<Link
to="/"
className="inline-flex items-center gap-4 bg-brand-dark hover:bg-brand-gold text-white px-8 py-5 text-[10px] font-bold uppercase tracking-[0.3em] transition-colors"
>
<ArrowLeft size={16} />
Retornar à Homepage
</Link>
</div>
</>
);
}

View file

@ -0,0 +1,140 @@
import { motion } from "motion/react";
import { Link } from "react-router-dom";
import { MapPin, ArrowRight } from "lucide-react";
import { Helmet } from "react-helmet-async";
import { Article } from "../data/articles";
export function PortfolioPage({ propertiesAsArticles }: { propertiesAsArticles: Article[] }) {
return (
<>
<Helmet>
<title>Portfólio de Luxo | Helena Fontes</title>
<meta name="description" content="Explore propriedades de alto padrão e luxo em São Paulo. Casas e apartamentos em bairros como Itaim Bibi e Jardins, além de opções off-market exclusivas." />
<meta property="og:title" content="Portfólio de Luxo | Helena Fontes" />
<meta property="og:description" content="Explore propriedades de alto padrão e luxo em São Paulo. Casas e apartamentos em bairros como Itaim Bibi e Jardins." />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Portfólio de Luxo | Helena Fontes" />
<meta name="twitter:description" content="Explore propriedades de alto padrão e luxo em São Paulo." />
<script type="application/ld+json">
{JSON.stringify({
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://helenafontes.com.br/"
},{
"@type": "ListItem",
"position": 2,
"name": "Portfólio",
"item": "https://helenafontes.com.br/portfolio"
}]
})}
</script>
</Helmet>
<div className="pt-40 pb-32 bg-[#FCFAFA] min-h-screen">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="flex flex-col md:flex-row md:items-end justify-between gap-12 mb-32">
<div className="max-w-2xl text-center md:text-left">
<span className="text-[10px] uppercase tracking-[0.3em] text-brand-gold font-bold block mb-4">
Destaques do Portfólio
</span>
<h1 className="text-4xl md:text-5xl lg:text-7xl font-serif text-brand-dark leading-tight">
A curadoria <span className="italic text-stone-400">em foco.</span>
</h1>
</div>
<p className="text-stone-500 font-light text-lg max-w-md text-center md:text-right mt-8 md:mt-0">
Cada propriedade é tratada como uma obra de arte viva. Analiso a
arquitetura e a atmosfera, apresentando apenas espaços que inspiram.
</p>
</div>
<div className="space-y-40">
{propertiesAsArticles.map((property, index) => (
<motion.article
key={property.id}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.8 }}
className={`flex flex-col ${index % 2 !== 0 ? "md:flex-row-reverse" : "md:flex-row"} gap-12 lg:gap-24 items-center group`}
>
{/* Image Side */}
<div className="w-full md:w-3/5">
<Link
to={`/artigo/${property.id}`}
className={`block relative overflow-hidden bg-stone-100 ${index % 2 !== 0 ? "aspect-square rounded-full md:rounded-bl-[200px] md:rounded-tr-[200px] md:rounded-tl-sm md:rounded-br-sm" : "aspect-[4/5] rounded-t-full"}`}
>
<img
src={property.coverImage}
alt={property.title}
loading={index === 0 ? "eager" : "lazy"}
className="w-full h-full object-cover transform group-hover:scale-[1.03] transition-transform duration-[2s] ease-out"
/>
<div className="absolute top-8 left-1/2 -translate-x-1/2 md:translate-x-0 md:left-8 bg-white px-6 py-2 text-[10px] font-bold uppercase tracking-widest text-brand-dark rounded-full shadow-lg">
{property.details?.status || "Exclusividade"}
</div>
</Link>
</div>
{/* Content Side */}
<div className="w-full md:w-2/5 flex flex-col items-center text-center md:text-left md:items-start justify-center">
<div className="flex items-center gap-3 text-brand-gold text-[10px] uppercase tracking-[0.2em] mb-4">
<span>{property.category}</span>
</div>
<Link to={`/artigo/${property.id}`}>
<h3 className="text-3xl lg:text-5xl font-serif text-brand-dark leading-[1.1] mb-6 hover:text-stone-500 transition-colors">
{property.title}
</h3>
</Link>
<p className="text-stone-500 font-light text-lg leading-relaxed mb-10 max-w-md">
{property.excerpt}
</p>
<div className="w-full grid grid-cols-2 gap-8 mb-10 pt-8 border-t border-stone-200">
<div className="text-center md:text-left">
<span className="block text-[10px] uppercase tracking-[0.2em] text-stone-400 mb-2">
Acomodações
</span>
<span className="text-brand-dark font-serif text-xl">
{property.details?.specs}
</span>
</div>
<div className="text-center md:text-right">
<span className="block text-[10px] uppercase tracking-[0.2em] text-stone-400 mb-2">
Valor
</span>
<span className="text-brand-dark font-serif text-xl">
{property.details?.price}
</span>
</div>
</div>
<Link
to={`/artigo/${property.id}`}
className="inline-flex items-center gap-4 text-[10px] font-bold uppercase tracking-[0.3em] text-brand-dark group-hover:text-brand-gold transition-colors"
>
<span className="pb-1 border-b border-brand-dark group-hover:border-brand-gold transition-colors">Examinar</span>
</Link>
</div>
</motion.article>
))}
</div>
<div className="mt-32 text-center border-t border-stone-200 pt-16">
<Link
to="/contato"
className="inline-flex items-center gap-3 bg-brand-dark px-10 py-5 text-[10px] font-bold uppercase tracking-[0.2em] text-white hover:bg-brand-gold transition-colors duration-300"
>
Solicitar Lista Completa (Opções Off-Market)
</Link>
</div>
</div>
</div>
</>
);
}

1
Template-02/src/vite-env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />

26
Template-02/tsconfig.json Normal file
View file

@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ES2022",
"experimentalDecorators": true,
"useDefineForClassFields": false,
"module": "ESNext",
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"skipLibCheck": true,
"moduleResolution": "bundler",
"isolatedModules": true,
"moduleDetection": "force",
"allowJs": true,
"jsx": "react-jsx",
"paths": {
"@/*": [
"./*"
]
},
"allowImportingTsExtensions": true,
"noEmit": true
}
}

View file

@ -0,0 +1,24 @@
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import {defineConfig, loadEnv} from 'vite';
export default defineConfig(({mode}) => {
const env = loadEnv(mode, '.', '');
return {
plugins: [react(), tailwindcss()],
define: {
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY),
},
resolve: {
alias: {
'@': path.resolve(__dirname, '.'),
},
},
server: {
// HMR is disabled in AI Studio via DISABLE_HMR env var.
// Do not modify—file watching is disabled to prevent flickering during agent edits.
hmr: process.env.DISABLE_HMR !== 'true',
},
};
});