Primeira versão templates marketing digital
This commit is contained in:
commit
71925b7072
57 changed files with 17072 additions and 0 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
BIN
Template-01/.DS_Store
vendored
Normal file
BIN
Template-01/.DS_Store
vendored
Normal file
Binary file not shown.
20
Template-01/README.md
Normal file
20
Template-01/README.md
Normal 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/19204f35-4c61-4401-a9fe-63973c4f3159
|
||||||
|
|
||||||
|
## 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`
|
||||||
14
Template-01/index.html
Normal file
14
Template-01/index.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><circle cx=%2250%22 cy=%2250%22 r=%2250%22 fill=%22black%22/><text y=%22.9em%22 font-size=%2290%22 text-anchor=%22middle%22 x=%2250%22 fill=%22white%22 font-family=%22sans-serif%22 font-weight=%22bold%22>O</text></svg>" />
|
||||||
|
<title>Onyx Growth | Aceleração Digital</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
6
Template-01/metadata.json
Normal file
6
Template-01/metadata.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"description": "",
|
||||||
|
"requestFramePermissions": [],
|
||||||
|
"majorCapabilities": []
|
||||||
|
}
|
||||||
6369
Template-01/package-lock.json
generated
Normal file
6369
Template-01/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
42
Template-01/package.json
Normal file
42
Template-01/package.json
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"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-markdown": "^10.1.0",
|
||||||
|
"react-router-dom": "^7.15.0",
|
||||||
|
"recharts": "^3.8.1",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
|
"tailwind-merge": "^3.5.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"
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Template-01/src/App.tsx
Normal file
20
Template-01/src/App.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
import Layout from './components/Layout';
|
||||||
|
import ScrollToTop from './components/ScrollToTop';
|
||||||
|
import AnimatedRoutes from './components/AnimatedRoutes';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<Router>
|
||||||
|
<ScrollToTop />
|
||||||
|
<Layout>
|
||||||
|
<AnimatedRoutes />
|
||||||
|
</Layout>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
30
Template-01/src/components/AnimatedRoutes.tsx
Normal file
30
Template-01/src/components/AnimatedRoutes.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Routes, Route, useLocation } from 'react-router-dom';
|
||||||
|
import { AnimatePresence } from 'motion/react';
|
||||||
|
import Home from '../pages/Home';
|
||||||
|
import Services from '../pages/Services';
|
||||||
|
import Cases from '../pages/Cases';
|
||||||
|
import About from '../pages/About';
|
||||||
|
import Blog from '../pages/Blog';
|
||||||
|
import BlogPost from '../pages/BlogPost';
|
||||||
|
import Contact from '../pages/Contact';
|
||||||
|
import NotFound from '../pages/NotFound';
|
||||||
|
import PageTransition from './PageTransition';
|
||||||
|
|
||||||
|
export default function AnimatedRoutes() {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
|
<Routes location={location} key={location.pathname}>
|
||||||
|
<Route path="/" element={<PageTransition><Home /></PageTransition>} />
|
||||||
|
<Route path="/services" element={<PageTransition><Services /></PageTransition>} />
|
||||||
|
<Route path="/cases" element={<PageTransition><Cases /></PageTransition>} />
|
||||||
|
<Route path="/about" element={<PageTransition><About /></PageTransition>} />
|
||||||
|
<Route path="/blog" element={<PageTransition><Blog /></PageTransition>} />
|
||||||
|
<Route path="/blog/:slug" element={<PageTransition><BlogPost /></PageTransition>} />
|
||||||
|
<Route path="/contact" element={<PageTransition><Contact /></PageTransition>} />
|
||||||
|
<Route path="*" element={<PageTransition><NotFound /></PageTransition>} />
|
||||||
|
</Routes>
|
||||||
|
</AnimatePresence>
|
||||||
|
);
|
||||||
|
}
|
||||||
119
Template-01/src/components/Footer.tsx
Normal file
119
Template-01/src/components/Footer.tsx
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ArrowUpRight } from 'lucide-react';
|
||||||
|
|
||||||
|
const footerLinks = {
|
||||||
|
services: [
|
||||||
|
{ name: 'Otimização SEO', path: '/services#seo' },
|
||||||
|
{ name: 'Tráfego Pago', path: '/services#ads' },
|
||||||
|
{ name: 'Design UX/UI', path: '/services#design' },
|
||||||
|
{ name: 'Desenvolvimento Web', path: '/services#web' },
|
||||||
|
],
|
||||||
|
company: [
|
||||||
|
{ name: 'Sobre Nós', path: '/about' },
|
||||||
|
{ name: 'Nossos Trabalhos', path: '/cases' },
|
||||||
|
{ name: 'Blog de Growth', path: '/blog' },
|
||||||
|
{ name: 'Carreiras', path: '#' },
|
||||||
|
],
|
||||||
|
social: [
|
||||||
|
{ name: 'Instagram', path: '#' },
|
||||||
|
{ name: 'LinkedIn', path: '#' },
|
||||||
|
{ name: 'Twitter / X', path: '#' },
|
||||||
|
{ name: 'Dribbble', path: '#' },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="bg-black pt-24 pb-8 border-t border-white/5 relative overflow-hidden">
|
||||||
|
{/* Decorative Blur */}
|
||||||
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-[800px] h-[400px] bg-blue-600/10 rounded-full blur-[120px] pointer-events-none" />
|
||||||
|
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl relative z-10">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-12 gap-12 lg:gap-8 mb-20">
|
||||||
|
|
||||||
|
{/* Brand Col */}
|
||||||
|
<div className="lg:col-span-5 flex flex-col items-start">
|
||||||
|
<Link to="/" className="flex items-center gap-2 mb-6">
|
||||||
|
<div className="w-8 h-8 bg-white rounded-lg flex items-center justify-center">
|
||||||
|
<div className="w-3 h-3 bg-black rounded-sm" />
|
||||||
|
</div>
|
||||||
|
<span className="font-display font-bold text-2xl tracking-tight text-white">
|
||||||
|
Onyx<span className="text-gray-500">.</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
<p className="text-gray-400 text-lg leading-relaxed mb-8 max-w-md">
|
||||||
|
Construímos experiências digitais premiadas e estratégias de crescimento para marcas ambiciosas.
|
||||||
|
</p>
|
||||||
|
<div className="flex bg-white/5 rounded-full p-1 border border-white/10 w-full max-w-md">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Inscreva-se na newsletter"
|
||||||
|
className="bg-transparent border-none text-white px-4 py-2 w-full focus:outline-none placeholder:text-gray-600"
|
||||||
|
id="footer-newsletter-input"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="bg-white text-black px-6 py-2 rounded-full font-medium hover:bg-gray-200 transition-colors shrink-0"
|
||||||
|
id="footer-subscribe-btn"
|
||||||
|
>
|
||||||
|
Assinar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Links Cols */}
|
||||||
|
<div className="lg:col-span-2 lg:col-start-7">
|
||||||
|
<h4 className="text-white font-medium mb-6">Serviços</h4>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{footerLinks.services.map((link) => (
|
||||||
|
<li key={link.name}>
|
||||||
|
<Link to={link.path} className="text-gray-400 hover:text-white transition-colors text-sm flex items-center group">
|
||||||
|
{link.name}
|
||||||
|
<ArrowUpRight className="w-3 h-3 ml-1 opacity-0 -translate-x-2 translate-y-2 group-hover:opacity-100 group-hover:translate-x-0 group-hover:translate-y-0 transition-all duration-300" />
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<h4 className="text-white font-medium mb-6">A Agência</h4>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{footerLinks.company.map((link) => (
|
||||||
|
<li key={link.name}>
|
||||||
|
<Link to={link.path} className="text-gray-400 hover:text-white transition-colors text-sm">
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="lg:col-span-2 space-y-4">
|
||||||
|
<h4 className="text-white font-medium mb-6">Redes</h4>
|
||||||
|
<ul className="space-y-4">
|
||||||
|
{footerLinks.social.map((link) => (
|
||||||
|
<li key={link.name}>
|
||||||
|
<a href={link.path} target="_blank" rel="noopener noreferrer" className="text-gray-400 hover:text-white transition-colors text-sm flex items-center justify-between group">
|
||||||
|
{link.name}
|
||||||
|
<ArrowUpRight className="w-3 h-3 opacity-0 -translate-x-2 translate-y-2 group-hover:opacity-100 group-hover:translate-x-0 group-hover:translate-y-0 transition-all duration-300" />
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bottom */}
|
||||||
|
<div className="pt-8 border-t border-white/10 flex flex-col md:flex-row items-center justify-between gap-4">
|
||||||
|
<p className="text-gray-500 text-sm">
|
||||||
|
© {new Date().getFullYear()} Onyx Digital. Todos os direitos reservados.
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-6 text-sm text-gray-500">
|
||||||
|
<Link to="#" className="hover:text-white transition-colors">Política de Privacidade</Link>
|
||||||
|
<Link to="#" className="hover:text-white transition-colors">Termos de Serviço</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
56
Template-01/src/components/LanguageSelector.tsx
Normal file
56
Template-01/src/components/LanguageSelector.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
|
import { Globe, ChevronDown } from 'lucide-react';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{ code: 'pt', label: 'PT-BR' },
|
||||||
|
{ code: 'en', label: 'ENG' },
|
||||||
|
{ code: 'es', label: 'ESP' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function LanguageSelector() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [selected, setSelected] = useState(languages[0]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
className="flex items-center gap-2 text-sm font-medium text-gray-400 hover:text-white transition-colors px-3 py-2 rounded-full hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<Globe className="w-4 h-4" />
|
||||||
|
{selected.label}
|
||||||
|
<ChevronDown className={cn("w-4 h-4 transition-transform", isOpen && "rotate-180")} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{isOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: 10 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
className="absolute top-full right-0 mt-2 w-32 bg-black/90 backdrop-blur-xl border border-white/10 rounded-[16px] overflow-hidden shadow-2xl z-50 flex flex-col p-1"
|
||||||
|
>
|
||||||
|
{languages.map((lang) => (
|
||||||
|
<button
|
||||||
|
key={lang.code}
|
||||||
|
onClick={() => {
|
||||||
|
setSelected(lang);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"w-full text-left px-4 py-2.5 text-sm transition-colors rounded-[12px]",
|
||||||
|
selected.code === lang.code ? "text-white font-medium bg-white/10" : "text-gray-400 hover:bg-white/5 hover:text-white"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{lang.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
32
Template-01/src/components/Layout.tsx
Normal file
32
Template-01/src/components/Layout.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { AnimatePresence, motion } from 'motion/react';
|
||||||
|
import Navbar from './Navbar';
|
||||||
|
import Footer from './Footer';
|
||||||
|
|
||||||
|
interface LayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Layout({ children }: LayoutProps) {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex flex-col bg-black text-white font-sans selection:bg-blue-500/30">
|
||||||
|
<Navbar />
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
|
<motion.main
|
||||||
|
key={location.pathname}
|
||||||
|
initial={{ opacity: 0, filter: 'blur(10px)', y: 20 }}
|
||||||
|
animate={{ opacity: 1, filter: 'blur(0px)', y: 0 }}
|
||||||
|
exit={{ opacity: 0, filter: 'blur(10px)', y: -20 }}
|
||||||
|
transition={{ duration: 0.5, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="flex-1 flex flex-col relative w-full pt-16"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.main>
|
||||||
|
</AnimatePresence>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
310
Template-01/src/components/Navbar.tsx
Normal file
310
Template-01/src/components/Navbar.tsx
Normal file
|
|
@ -0,0 +1,310 @@
|
||||||
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
|
import { Menu, X, ArrowRight, Search, ChevronRight } from 'lucide-react';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import LanguageSelector from './LanguageSelector';
|
||||||
|
import { articles } from '@/data/articles';
|
||||||
|
|
||||||
|
const navLinks = [
|
||||||
|
{ name: 'Início', path: '/' },
|
||||||
|
{ name: 'Serviços', path: '/services' },
|
||||||
|
{ name: 'Cases', path: '/cases' },
|
||||||
|
{ name: 'Sobre', path: '/about' },
|
||||||
|
{ name: 'Blog', path: '/blog' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Navbar() {
|
||||||
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||||
|
const [searchOpen, setSearchOpen] = useState(false);
|
||||||
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
const location = useLocation();
|
||||||
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
setIsScrolled(window.scrollY > 50);
|
||||||
|
};
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Close menus on route change
|
||||||
|
useEffect(() => {
|
||||||
|
setMobileMenuOpen(false);
|
||||||
|
setSearchOpen(false);
|
||||||
|
setSearchQuery('');
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchOpen) {
|
||||||
|
setTimeout(() => {
|
||||||
|
searchInputRef.current?.focus();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}, [searchOpen]);
|
||||||
|
|
||||||
|
const searchResults = searchQuery.length > 1
|
||||||
|
? articles.filter(a =>
|
||||||
|
a.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
a.excerpt.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
a.category.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
).slice(0, 5)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header
|
||||||
|
className={cn(
|
||||||
|
'fixed inset-x-0 top-0 z-50 transition-all duration-500',
|
||||||
|
isScrolled ? 'py-4' : 'py-6'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex items-center justify-between transition-all duration-500 rounded-2xl px-6 py-4',
|
||||||
|
isScrolled
|
||||||
|
? 'bg-black/40 backdrop-blur-xl border border-white/10 shadow-2xl'
|
||||||
|
: 'bg-transparent border border-transparent'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{/* Logo */}
|
||||||
|
<Link to="/" className="flex items-center gap-2 group">
|
||||||
|
<div className="w-8 h-8 bg-white rounded-lg flex items-center justify-center transition-transform duration-500 group-hover:rotate-12">
|
||||||
|
<div className="w-3 h-3 bg-black rounded-sm" />
|
||||||
|
</div>
|
||||||
|
<span className="font-display font-bold text-xl tracking-tight text-white">
|
||||||
|
Onyx<span className="text-gray-500">.</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop Navigation */}
|
||||||
|
<nav className="hidden md:flex items-center gap-8">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.path}
|
||||||
|
to={link.path}
|
||||||
|
className={cn(
|
||||||
|
'text-sm font-medium transition-colors hover:text-white',
|
||||||
|
location.pathname === link.path ? 'text-white' : 'text-gray-400'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Desktop Action & Mobile Toggle */}
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
onClick={() => setSearchOpen(true)}
|
||||||
|
className="hidden md:flex items-center justify-center text-gray-300 hover:text-white transition-colors w-10 h-10 rounded-full hover:bg-white/10"
|
||||||
|
aria-label="Pesquisar"
|
||||||
|
>
|
||||||
|
<Search className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<LanguageSelector />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="hidden md:flex items-center gap-2 bg-white text-black px-5 py-2.5 rounded-full text-sm font-medium hover:bg-gray-200 transition-colors"
|
||||||
|
id="header-contact-btn"
|
||||||
|
>
|
||||||
|
Iniciar Projeto
|
||||||
|
<ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="md:hidden text-gray-300 hover:text-white transition-colors flex items-center justify-center w-10 h-10"
|
||||||
|
onClick={() => setSearchOpen(true)}
|
||||||
|
aria-label="Pesquisar"
|
||||||
|
>
|
||||||
|
<Search className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="md:hidden text-gray-300 hover:text-white transition-colors flex items-center justify-center w-10 h-10"
|
||||||
|
onClick={() => setMobileMenuOpen(true)}
|
||||||
|
aria-label="Open menu"
|
||||||
|
id="mobile-menu-open"
|
||||||
|
>
|
||||||
|
<Menu strokeWidth={1.5} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* Search Overlay */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{searchOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
className="fixed inset-0 z-[70] bg-black/80 backdrop-blur-sm flex items-start justify-center pt-24 px-4"
|
||||||
|
onClick={() => setSearchOpen(false)}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: -20 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: -20 }}
|
||||||
|
className="w-full max-w-2xl bg-[#0a0a0a] border border-white/10 rounded-2xl shadow-2xl overflow-hidden flex flex-col max-h-[80vh]"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="flex items-center border-b border-white/10 px-4 py-4">
|
||||||
|
<Search className="w-5 h-5 text-gray-400 mr-3" />
|
||||||
|
<input
|
||||||
|
ref={searchInputRef}
|
||||||
|
type="text"
|
||||||
|
placeholder="Pesquisar artigos, cases..."
|
||||||
|
className="flex-1 bg-transparent border-none text-white focus:outline-none text-lg placeholder:text-gray-600"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => setSearchOpen(false)}
|
||||||
|
className="text-gray-500 hover:text-white p-1 rounded-md transition-colors"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{searchQuery.length > 1 && (
|
||||||
|
<div className="overflow-y-auto flex-1 p-2">
|
||||||
|
{searchResults.length > 0 ? (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
{searchResults.map(result => (
|
||||||
|
<Link
|
||||||
|
key={result.id}
|
||||||
|
to={`/blog/${result.slug}`}
|
||||||
|
className="flex items-center gap-4 p-3 rounded-lg hover:bg-white/5 transition-colors group"
|
||||||
|
>
|
||||||
|
<div className="w-12 h-12 bg-white/5 rounded-md overflow-hidden flex-shrink-0">
|
||||||
|
{result.imageUrl ? (
|
||||||
|
<img src={result.imageUrl} alt="" className="w-full h-full object-cover opacity-80" />
|
||||||
|
) : (
|
||||||
|
<div className="w-full h-full flex items-center justify-center bg-blue-500/20 text-blue-400 font-bold text-xs">{result.category.slice(0,3)}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col flex-1 overflow-hidden">
|
||||||
|
<div className="flex items-center justify-between gap-2">
|
||||||
|
<span className="text-white font-medium truncate">{result.title}</span>
|
||||||
|
<span className="text-xs text-blue-400 font-medium px-2 py-0.5 rounded-full bg-blue-400/10 whitespace-nowrap">{result.category}</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-gray-500 truncate">{result.excerpt}</span>
|
||||||
|
</div>
|
||||||
|
<ChevronRight className="w-5 h-5 text-gray-600 group-hover:text-white transition-colors" />
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="py-12 px-4 text-center">
|
||||||
|
<p className="text-gray-400 mb-2">Nenhum resultado encontrado para "{searchQuery}"</p>
|
||||||
|
<button onClick={() => setSearchQuery('')} className="text-blue-400 text-sm hover:underline">Limpar pesquisa</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{searchQuery.length <= 1 && (
|
||||||
|
<div className="py-8 px-6">
|
||||||
|
<h4 className="text-xs font-medium text-gray-500 uppercase tracking-wider mb-4">Sugestões</h4>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{['SEO', 'Growth', 'Ads', 'Design', 'Métricas'].map(term => (
|
||||||
|
<button
|
||||||
|
key={term}
|
||||||
|
onClick={() => setSearchQuery(term)}
|
||||||
|
className="px-3 py-1.5 rounded-full border border-white/10 bg-white/5 text-sm text-gray-300 hover:bg-white/10 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
{term}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
{/* Mobile Menu Overlay */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{mobileMenuOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -20 }}
|
||||||
|
transition={{ duration: 0.3, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="fixed inset-0 z-[60] bg-black/95 backdrop-blur-3xl md:hidden overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col h-full p-6">
|
||||||
|
<div className="flex items-center justify-between mb-12">
|
||||||
|
<Link to="/" className="flex items-center gap-2" onClick={() => setMobileMenuOpen(false)}>
|
||||||
|
<div className="w-8 h-8 bg-white rounded-lg flex items-center justify-center">
|
||||||
|
<div className="w-3 h-3 bg-black rounded-sm" />
|
||||||
|
</div>
|
||||||
|
<span className="font-display font-bold text-xl tracking-tight text-white">
|
||||||
|
Onyx<span className="text-gray-500">.</span>
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
<button
|
||||||
|
onClick={() => setMobileMenuOpen(false)}
|
||||||
|
className="text-gray-400 hover:text-white transition-colors p-2"
|
||||||
|
id="mobile-menu-close"
|
||||||
|
>
|
||||||
|
<X strokeWidth={1.5} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex justify-start px-4 mb-8">
|
||||||
|
<LanguageSelector />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 flex flex-col justify-center gap-8 px-4">
|
||||||
|
{navLinks.map((link, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={link.path}
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: 0.1 + i * 0.05 }}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
to={link.path}
|
||||||
|
className={cn(
|
||||||
|
"text-4xl font-display font-medium tracking-tight",
|
||||||
|
location.pathname === link.path ? "text-white" : "text-gray-500"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.4 }}
|
||||||
|
className="pb-8 px-4"
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="flex w-full items-center justify-center gap-2 bg-white text-black px-6 py-4 rounded-full text-lg font-medium"
|
||||||
|
>
|
||||||
|
Iniciar Projeto
|
||||||
|
<ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
Template-01/src/components/PageTransition.tsx
Normal file
16
Template-01/src/components/PageTransition.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export default function PageTransition({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 15, filter: 'blur(10px)' }}
|
||||||
|
animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}
|
||||||
|
exit={{ opacity: 0, y: -15, filter: 'blur(10px)' }}
|
||||||
|
transition={{ duration: 0.4, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="flex-1 flex flex-col w-full"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
54
Template-01/src/components/SEO.tsx
Normal file
54
Template-01/src/components/SEO.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
|
||||||
|
interface SEOProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
name?: string;
|
||||||
|
type?: string;
|
||||||
|
image?: string;
|
||||||
|
url?: string;
|
||||||
|
schema?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SEO({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
name = 'Onyx Growth',
|
||||||
|
type = 'website',
|
||||||
|
image = 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80', // Default striking image
|
||||||
|
url = 'https://onyx.com.br',
|
||||||
|
schema,
|
||||||
|
}: SEOProps) {
|
||||||
|
// Base site URL (ideally from env or constant)
|
||||||
|
const fullTitle = title.includes(name) ? title : `${title} | ${name}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Helmet>
|
||||||
|
{/* Standard metadata tags */}
|
||||||
|
<title>{fullTitle}</title>
|
||||||
|
<meta name='description' content={description} />
|
||||||
|
|
||||||
|
{/* Open Graph tags for Facebook, LinkedIn etc. shared cards */}
|
||||||
|
<meta property="og:type" content={type} />
|
||||||
|
<meta property="og:title" content={fullTitle} />
|
||||||
|
<meta property="og:description" content={description} />
|
||||||
|
<meta property="og:image" content={image} />
|
||||||
|
<meta property="og:url" content={url} />
|
||||||
|
<meta property="og:site_name" content={name} />
|
||||||
|
|
||||||
|
{/* Twitter tags */}
|
||||||
|
<meta name="twitter:creator" content={name} />
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={fullTitle} />
|
||||||
|
<meta name="twitter:description" content={description} />
|
||||||
|
<meta name="twitter:image" content={image} />
|
||||||
|
|
||||||
|
{/* JSON-LD Schema (Rich Snippets for Google) */}
|
||||||
|
{schema && (
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{JSON.stringify(schema)}
|
||||||
|
</script>
|
||||||
|
)}
|
||||||
|
</Helmet>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
Template-01/src/components/ScrollToTop.tsx
Normal file
16
Template-01/src/components/ScrollToTop.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
export default function ScrollToTop() {
|
||||||
|
const { pathname } = useLocation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
296
Template-01/src/data/articles.ts
Normal file
296
Template-01/src/data/articles.ts
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
export const articles = [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"slug": "guia-seo-2026",
|
||||||
|
"title": "O Guia Definitivo sobre SEO em 2026",
|
||||||
|
"category": "SEO",
|
||||||
|
"readTime": "8 min de leitura",
|
||||||
|
"date": "12 de Maio, 2026",
|
||||||
|
"color": "from-blue-600/30 to-transparent",
|
||||||
|
"featured": true,
|
||||||
|
"author": "Equipe Onyx",
|
||||||
|
"excerpt": "Descubra as táticas secretas e estratégias avançadas de SEO que as maiores empresas do mercado estão utilizando para dominar seus nichos em 2026.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1432821596592-e2c18b78144f?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# O Guia Definitivo sobre SEO em 2026\n\nO mercado mudou drasticamente. O que funcionava no passado em relação a **[SEO](/services)** já não traz os mesmos resultados hoje. Neste artigo, desconstruímos as táticas obsoletas e revelamos frameworks de alto nível.\n\n## Por que você está perdendo ROI?\n\nA maioria das empresas opera com o manual de 2023. Em um cenário impulsionado por inteligência artificial e decisões baseadas em modelagem preditiva, quem não adapta rapidamente a sua estratégia corre um sério risco.\n\n> \"A velocidade de implementação de novas táticas de SEO é hoje a métrica mais importante de uma equipe de growth corporativa.\" — **Marcus Void**, CEO Onyx\n\n### 3 Táticas Imediatas\n\n1. **Rever a Arquitetura de Conversão**: Seu funil atual está vazando capital, principalmente na primeira interação de seu **[Design focado em Conversão](/services)**.\n2. **Implementar Automações Modulares**: Ferramentas engessadas estão matando o seu CAC em **[Performance Ads](/services)**. \n3. **Escalar Conteúdo com Critério**: Mais não significa melhor. Utilize semântica e intenção real de busca, guiando sua operação através de nosso **[Playbook de Growth](/blog)**.\n\n## Próximos Passos\n\nComece rodando uma auditoria técnica profunda. O foco deve ser levantar todos os dados ocultos das últimas campanhas e alinhar à nova visão macro do mercado. Veja os nossos **[Cases de Sucesso](/cases)** abordando reestruturações completas. [Fale com um especialista do nosso time](/contact) se você deseja acelerar esse processo em meses.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"slug": "engenharia-prompt-growth",
|
||||||
|
"title": "Como a Engenharia de Prompt Revolucionou o Growth",
|
||||||
|
"category": "AI",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "10 de Maio, 2026",
|
||||||
|
"color": "from-purple-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Elena Rostova",
|
||||||
|
"excerpt": "Entenda por que saber falar com as máquinas tornou-se a habilidade mais lucrativa para os profissionais de marketing e Growth Hackers modernos.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# A Engenharia de Prompt como Diferencial Competitivo\n\nA inteligência artificial não substituiu estratégias, ela as potencializou. O segredo deixou de ser \"qual IA usar\" para \"como direcionar a IA\". Na Onyx Growth, notamos que clientes que integram prompts avançados em suas operações de **[Ads](/services)** experimentam uma queda de até 40% no CAC.\n\n## Do Zero ao Especialista\n\nUma instrução fraca gera resultados medíocres. Por exemplo, ao gerar copy para tráfego pago, um prompt como \"Escreva um anúncio de sapato\" não serve. O cenário muda quando aplicamos **Frameworks de Conversão**:\n\n> \"Atue como um Copywriter nível AAA de resposta direta. Escreva 3 variações de anúncios para o Facebook Ads focadas em [público-alvo], destacando o [benefício principal] usando o framework PAS (Problem, Agitation, Solution).\"\n\nEste é o padrão ouro na criação de ativos digitais otimizados.\n\n### Acelerando Processos\n\n1. Estruture a voz da marca através de exemplos.\n2. Defina os limites do modelo para evitar alucinações.\n3. Teste A/B as saídas geradas com suas variações manuais.\n\nPara aprofundar, consulte nossos **[Cases de Sucesso](/cases)** de clientes escalando utilizando machine learning e otimização por IA.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"slug": "design-conversivo-psicologia",
|
||||||
|
"title": "Design Conversivo: A Psicologia por Trás das Cores",
|
||||||
|
"category": "Design",
|
||||||
|
"readTime": "7 min de leitura",
|
||||||
|
"date": "08 de Maio, 2026",
|
||||||
|
"color": "from-pink-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Julian Vance",
|
||||||
|
"excerpt": "Muito além da estética: descubra como gatilhos visuais e escolhas cromáticas corretas podem aumentar o seu ticket médio na primeira sessão.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1541462608143-67571c6738dd?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Estética com Propósito Financeiro\n\nO erro número um de **[Design](/services)** B2B e B2C é focar apenas em deixar o site \"bonito\". Design sem um objetivo financeiro é apenas arte. Na Onyx, implementamos Design Conversivo.\n\n## O Que a Ciência Afirma\n\nEstudos indicam que os consumidores julgam um ambiente online em menos de 90 milissegundos. Cores ditam emoções.\n\n- **Azul Escuro**: Confiança, estabilidade (bancos e SaaS B2B usam).\n- **Laranja/Vermelho Pálido**: Urgência contida, chamadas para ação iminentes.\n- **Preto e Dourado/Prata**: Exclusividade, ticket alto, sofisticação.\n\n> \"A função primária do design de interface é remover a fricção cognitiva entre o desejo do usuário e a ação de compra.\" — **Elena Rostova**, Chefe de Design.\n\n## Aplicando na Prática\n\nRevise os botões do seu site. Se o botão de assinatura tem a mesma cor de elementos não clicáveis do site, você está confundindo o cérebro límbico do visitante. O **Ponto Focal** deve guiar a visão imediatamente assim que o site carrega.\n\nDeseja alinhar a sua marca a conceitos avançados de UI/UX? [Fale com a Onyx](/contact).\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"slug": "escalando-campanhas-um-milhao",
|
||||||
|
"title": "Tráfego Pago: Escalando Campanhas de US$ 1 Milhão",
|
||||||
|
"category": "Ads",
|
||||||
|
"readTime": "12 min de leitura",
|
||||||
|
"date": "05 de Maio, 2026",
|
||||||
|
"color": "from-green-600/30 to-transparent",
|
||||||
|
"featured": true,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "Escalar orçamento não é simplesmente aumentar investimento diário. O processo de expansão orçamentária sem perder o ROI é brutalmente técnico.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Como Não Queimar Seu Orçamento \n\nSe você já apertou o botão de aumentar budget de uma campanha validada e viu as métricas desabarem em dois dias, bem vindo ao caos da fase de expansão. Campanhas que rodam estagnadas em orçamentos pequenos não sofrem os mesmos choques de oferta que escalas maciças impõem.\n\n## A Dinâmica de Escala Vertical vs Horizontal\n\nQuando você está buscando escala agressiva via **[Tráfego Pago](/services)**, você se depara com a fadiga criativa. É matemática básica: você entra em leilões mais caros porque esgota o público primário.\n\n### Nossos Pilares de Escala:\n\n1. **Volume Bruto de Criativos**: O segredo não é achar o criativo perfeito, e sim alimentar o algoritmo constantemente.\n2. **Account Consolidation**: Contas com 50 campanhas morrem. Consolidamos o máximo de sinal em 3 a 4 campanhas principais para dar lastro à IA da plataforma.\n3. **Escala Horizontal Geográfica ou de Oferta**: Mantemos o budget vertical controlado enquanto abrimos novas avenidas na horizontal.\n\nMuitas dessas táticas estão fundamentadas nas aplicações reais vistas nos nossos **[Cases de Estudo](/cases)**. Não é sobre gastar mais, é sobre comprar dados de altíssima qualidade de forma progressiva.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"slug": "seo-tecnico-ecommerce",
|
||||||
|
"title": "SEO Técnico para E-commerce: Auditoria Completa",
|
||||||
|
"category": "SEO",
|
||||||
|
"readTime": "9 min de leitura",
|
||||||
|
"date": "03 de Maio, 2026",
|
||||||
|
"color": "from-orange-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Julian Vance",
|
||||||
|
"excerpt": "Lojas virtuais com milhares de URLs param de rankear do dia pra noite. A raiz do problema geralmente é facetas, canonicalização ou crawl budget.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# O Pesadelo das URLs Duplicadas em E-commerce\n\nEstruturas complexas de categoria, juntamente com filtros e parâmetros de ordenação, transformam uma loja pequena de 500 produtos em um monstro com 50.000 URLs rastreáveis. Isso dilui o poder do seu site e esmaga o crawl budget cedido pelo Google.\n\nNossa equipe lidou com a reestruturação de SEO em nosso [Case](/cases) recente focado em e-commerce. O cenário padrão era crítico.\n\n## Os 3 Passos da Limpeza Técnica\n\n1. **Domando Parâmetros Facetados**: Use \\`robots.txt\\` e tags \\`noindex\\` adequadamente para filtros de preço e cor que não possuem volume de busca orgânico.\n2. **Canonical Tags Otimizadas**: Garanta que as variações apontem para a URL principal do produto.\n3. **Renderização de JavaScript**: Muitas lojas em frameworks baseados em JS bloqueiam rastreadores por erro de configuração no SSR (Server-Side Rendering). \n\nOtimizar um E-commerce é um processo contínuo de varredura. Quer entender como estruturar do zero? [Descubra nossos serviços de SEO](/services).\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"slug": "cro-testes-ab",
|
||||||
|
"title": "CRO e Testes A/B: Pequenas Mudanças, Grandes Ganhos",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "5 min de leitura",
|
||||||
|
"date": "01 de Maio, 2026",
|
||||||
|
"color": "from-teal-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Equipe Onyx",
|
||||||
|
"excerpt": "Otimização de Taxa de Conversão pode significar dobrar a lucratividade sem gastar um centavo a mais em anúncios.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1551434678-e076c223a692?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Por que você ignora o CRO?\n\nTodos querem mais tráfego, poucos querem otimizar quem já entra na porta. CRO (Conversion Rate Optimization) é o pilar escondido dos maiores **[Cases](/cases)** no digital.\n\n> \"Aumentar a conversão da sua landing page principal de 2% para 4% reduz o custo por lead pela metade. Imediatamente.\"\n\nO ciclo de testes que executamos em nossos clientes de [Performance Full-Stack](/services):\n- Hipótese baseada em Heatmaps da ferramenta de Analytics.\n- Implementação assíncrona (A/B) de variações no CTA ou Hero Section.\n- Computação de significância estatística de > 95%.\n- Implementação definitiva e reinício do loop.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"slug": "fim-marketing-esperanca",
|
||||||
|
"title": "O Fim do \"Marketing de Esperança\"",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "28 de Abril, 2026",
|
||||||
|
"color": "from-indigo-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "Dados impiedosos precisam guiar sua empresa acima dos achismos criativos e direções emocionais sem lastro analítico.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Não publique e reze. Publique e analise.\n\nA era da intuição acabou. Profissionais que lançam campanhas e esperam pelo melhor estão sendo engolidos por sistemas baseados em dados massivos (Big Data). Nós aplicamos a metodologia de **[Growth Full-Stack](/services)** e não o marketing tradicional.\n\nQualquer decisão, seja a cor de um logo ou a estruturação de uma campanha multicanal, começa e termina nos números. Nossa recomendação principal para quem chega ao **[Onyx Lab](/about)** é instalar uma matriz de Analytics capaz de mapear atribuição multi-touchpoint. Se você não sabe a jornada exata até o fechamento da compra, você não pode escalar.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"slug": "automacao-email-marketing",
|
||||||
|
"title": "Automação de E-mail Marketing: Fluxos que Faturam",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "7 min de leitura",
|
||||||
|
"date": "25 de Abril, 2026",
|
||||||
|
"color": "from-amber-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Equipe Onyx",
|
||||||
|
"excerpt": "Os e-mails ainda são o ativo digital com o maior ROI do ecossistema, contanto que abandonem o caráter de \"boletins informativos chatos\".",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1611162617474-5b21e879e113?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Listas de Email São o Seu Único Tráfego Controlado\n\nGoogle ou Meta podem suspender sua conta amanhã por uma mudança em políticas automáticas de robôs. Ninguém pode retirar a sua lista de e-mails ativamente engajada.\n\nNa nossa vertical de **[Design / Estratégia](/services)**, nós priorizamos táticas que fomentam o owned traffic:\n\n1. Fluxos de Carrinho Abandonado extremistas.\n2. Sequências de Onboarding Educacional de 14 dias (Welcome Series).\n3. Campanhas de Reengajamento focadas (Win-back campaigns).\n\nSe você deseja explorar as estratégias secretas das empresas da Fortune 500, estude nossos **[Cases completos](/cases)** na plataforma. E-mail não morreu, ele evoluiu.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"slug": "time-growth-full-stack",
|
||||||
|
"title": "Como Construir um Time de Growth Full-Stack",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "8 min de leitura",
|
||||||
|
"date": "22 de Abril, 2026",
|
||||||
|
"color": "from-emerald-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "A transição de \"departamento de marketing padrão\" para \"esquadrão de elite focado em receita\". As habilidades não negociáveis.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Silos São o Fim da Empresa\n\nSe o seu cara do SEO não entende de CRO, e sua pessoa de tráfego pago não conversa com Design, você está rasgando dinheiro. A metodologia de **[Growth](/about)** se apoia na multidisciplinaridade, ou os \"Profiles em T\".\n\nProfissionais \"T-shaped\" possuem profundidade enorme em uma disciplina (como Tráfego no Google), mas base razoável na camada horizontal de produto, código, retenção e psicologia de consumo. \n\nVocê não precisa de 5 estagiários e gerentes lentos. Você precisa de 2 operadores plenos que falam de dados cruamente. Se estruturar isso é difícil, você sempre pode terceirizar a execução primária com **[Especialistas de Alta Performance](/services)**.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"slug": "ai-em-campanhas-b2b",
|
||||||
|
"title": "O Impacto da IA em Campanhas B2B",
|
||||||
|
"category": "AI",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "20 de Abril, 2026",
|
||||||
|
"color": "from-cyan-600/30 to-transparent",
|
||||||
|
"featured": true,
|
||||||
|
"author": "Elena Rostova",
|
||||||
|
"excerpt": "Vendas Complexas e Account Based Marketing (ABM) estão vivendo um renascimento graças as inteligências artificiais generativas.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1633356122544-f134324a6cee?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Hiper-Personalização em Massa\n\nA grande dificuldade de vender softwares enterprise (SaaS B2B) é atrair a atenção do gestor sênior (C-level). E-mails frios genéricos (Cold Emails) acabaram. A resposta agora é escalar a hiper-personalização.\n\nUsando IA, a nossa abordagem de **[Growth Focus](/services)** conecta os sinais de engajamento do LinkedIn com a criação instantânea de teses sob medida. É ABM (Account-Based Marketing) executado na velocidade de robôs, mas lido por humanos.\n\nSe quer entender os funis gerados por LLMs em nosso laboratório de vendas, consulte a vitrine de **[Cases](/cases)** exclusivos.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"slug": "web-analytics-2026",
|
||||||
|
"title": "Web Analytics 2026: Dados no Cenário Pós-LGPD",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "7 min de leitura",
|
||||||
|
"date": "17 de Abril, 2026",
|
||||||
|
"color": "from-sky-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Julian Vance",
|
||||||
|
"excerpt": "Adeus aos cookies de terceiros. Como reestruturar sua coleta de métricas (Server-Side Tracking) antes de perder a visão da operação.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# A Cegueira dos Atribuição do Marketing\n\nO bloqueio contínuo do ecossistema Apple e a restrição mundial através de legislações estritas decretaram a morte da pixelagem tradicional. Nossos setups de infraestrutura **[Full-Stack Tech](/services)** implementam Rastreamento Server-Side.\n\n- Vantagens: Aumento expressivo da confiabilidade dos eventos. Menos peso de Javascript no lado do cliente (aumentando a nota de SEO Core Web Vitals).\n- Desvantagens: Complexidade técnica de nuvem que afasta os amadores.\n\nEstar às cegas significa comprar tráfego e culpar a lua pela falta de conversões. Pare de ignorar o rastreamento, ele é a linha de vida da sua equipe de aquisição. Converse conosco sobre como implementar infraestrutura de precisão.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"slug": "copywriting-vs-midia",
|
||||||
|
"title": "Copywriting de Alta Conversão vs Mídia Paga",
|
||||||
|
"category": "Ads",
|
||||||
|
"readTime": "5 min de leitura",
|
||||||
|
"date": "14 de Abril, 2026",
|
||||||
|
"color": "from-rose-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Equipe Onyx",
|
||||||
|
"excerpt": "Batalha dos titãs: descubra a relação íntima entre escrever textos que convertem e as engrenagens ocultas de anúncios otimizados.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1557804506-669a67965ba0?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Uma Parceria Inseparável\n\nNenhum profissional de **[Tráfego de Performance](/services)** salva uma oferta péssima descrita em uma copy medíocre. Um criativo horrível fará o leilão te punir com um CPM caríssimo.\n\nA Copy não é o que você diz sobre seu produto, é sobre a ressonância exata da dor atual do seu cliente sendo apresentada de modo tangível. Utilize estruturas testadas pelo tempo. Se o tráfego não está sendo lucrativo, dê dois passos para trás e reflita primariamente sobre a proposta de valor. \n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"slug": "design-system-b2b",
|
||||||
|
"title": "Design System B2B: Reduzindo Fricção nas Decisões",
|
||||||
|
"category": "Design",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "11 de Abril, 2026",
|
||||||
|
"color": "from-lime-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Elena Rostova",
|
||||||
|
"excerpt": "Padronizar a comunicação visual de produtos complexos resulta em maior escalabilidade e confiança dos decisores em companhias de engenharia.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1541462608143-67571c6738dd?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Componentes Focados em Escalabilidade\n\nA padronização visual poupa semanas dos seus desenvolvedores frontend. Nos relatórios de UI/UX **[da Onyx](/services)**, frequentemente esbarramos em times B2B onde cada página tem 4 tons distintos de azul primário e modais desalinhadas.\n\nA consistência gera credibilidade inconsciente. Empresas de TI precisam exalar rigor técnico. Um Design System com componentes sólidos, grids matematicamente perfeitas (foco em 8px ou 4px), e hierarquia padronizada são obrigatórios.\n\nNão é perda de tempo criar tokens de estilo. É investimento maciço em manutenibilidade.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 14,
|
||||||
|
"slug": "estrategia-omnichannel",
|
||||||
|
"title": "Estratégias Omnichannel que Realmente Funcionam",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "8 min de leitura",
|
||||||
|
"date": "08 de Abril, 2026",
|
||||||
|
"color": "from-zinc-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Equipe Onyx",
|
||||||
|
"excerpt": "Cercar o usuário em todos os pontos focais da rede sem parecer desesperado ou invasivo requer coordenação meticulosa de frequência.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Multi-touchpoint Real\n\nMuitos tentam estar em todas as redes ao mesmo tempo (Tiktok, IG, LinkedIn, Facebook, Pinterest) com o exato mesmo formato. Isso falha miseravelmente.\n\nUma jornada Omnichannel funcional requer entender que um conteúdo do Pinterest e de SEO de Topo de Funil (abordado no setor de **[SEO Técnico](/services)**) tem a missão de iniciar o loop. Em seguida, os retargetings sequenciais no Meta Ads devem aprofundar as objeções, e a conversão final se apóia no e-mail segmentado. Crie tramas narrativas ao invés de repetições cegas da mesma arte.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 15,
|
||||||
|
"slug": "machine-learning-bidding",
|
||||||
|
"title": "Machine Learning em Otimização de Lances de Anúncios",
|
||||||
|
"category": "AI",
|
||||||
|
"readTime": "7 min de leitura",
|
||||||
|
"date": "05 de Abril, 2026",
|
||||||
|
"color": "from-neutral-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "Como as IAs nativas de plataformas (PMax, Advantage+) tiraram os mediocres do jogo e forçaram a criatividade extrema aos especialistas.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# O Algoritmo Venceu os Operadores Manuais\n\nVocê ajusta lances no Google Ads alterando lances de palavras-chave 10 centavos a cada segunda-feira? Acorde: as máquinas fazem milhões de avaliações probabilísticas em milissegundos para prever CTR.\n\nO seu trabalho não é mais ser um calculador de lances de planilhas Excel na **[Mídia de Performance](/services)**. O seu trabalho virou \"Alimentador-Mestre de IAs\". O profissional de Growth hoje projeta conversões offline para nutrir modelos como o Performance Max. Quanto melhor a qualidade do dado injetado (Vendas validadas via CRM, exclusão imediata de SPAMMERS do funnel), melhor o robô te defende. \n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 16,
|
||||||
|
"slug": "content-machine-ai",
|
||||||
|
"title": "Como Escalar Conteúdo com IA Mantendo a Voz da Marca",
|
||||||
|
"category": "AI",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "03 de Abril, 2026",
|
||||||
|
"color": "from-blue-500/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Elena Rostova",
|
||||||
|
"excerpt": "Evite o mar de mesmice que a Inteligência Artificial provocou. O guia tático para acelerar a redação adicionando uma alma inconfundível.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1611162617474-5b21e879e113?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Pare de Postar Robótica\n\nQuando usamos a IA na construção e desenvolvimento da base de Growth (em especial **[Operações Orgânicas](/services)**), exigimos uma estrutura que seja \"Anti-Genérica\". \n\nO framework é simples: a IA cria a espinha dorsal (pontos, argumentos vitais baseados em análise semântica SERP). O humano adiciona as experiências anedóticas, os aprendizados dolorosos, e o tom de voz agressivo/polido da marca.\n\nEsse híbrido Cyborg aumenta em 4x a quantidade da produção [sem perder os resultados documentados em cases](/cases).\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 17,
|
||||||
|
"slug": "auditoria-seo-roi",
|
||||||
|
"title": "Por Que Sua Auditoria de SEO Não Está Gerando ROI",
|
||||||
|
"category": "SEO",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "31 de Março, 2026",
|
||||||
|
"color": "from-orange-500/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Julian Vance",
|
||||||
|
"excerpt": "Milhares de planilhas e auditorias técnicas engavetadas anualmente. Transformando problemas de rasteio em picos de vendas.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Do PDF para a Trincheira\n\nAuditorias de SEO falham porque ninguém prioriza os tickets por impacto. O especialista apresenta 200 mudanças (\"Corrigir faltas de meta description\", \"Tirar H3 do Footer\", \"Otimizar tempo de servidor\").\n\nO time de desenvolvimento foca nos erros fáceis (baixo esforço, baixo impacto) e larga os difíceis (arquitetura complexa, renderização). Consequência: O tráfego não muda 1 mm.\n\nNa auditoria das frentes de **[SEO e Tecnologia](/services)** da Onyx, listamos no topo a alteração que tem potencial de desentupir 20% do faturamento reprimido. Impacto sobre Vaidade.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 18,
|
||||||
|
"slug": "onboarding-ltv-primeiro-mes",
|
||||||
|
"title": "Onboarding de Clientes: O Primeiro Mês Define o LTV",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "7 min de leitura",
|
||||||
|
"date": "28 de Março, 2026",
|
||||||
|
"color": "from-purple-500/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "Reduzir drasticamente o Churn rate começa 5 minutos após o cartão passar. Aprenda táticas de \"Aha-moment\" aplicadas mundialmente.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Tempo para Obter Valor (TTV - Time to Value)\n\nO usuário fechou negócio. A promessa foi gigantesca. Se você deixá-lo vagar por um software engessado ou aguardar resposta manual por dias, o remorso da compra ativou. \n\nNossa visão focada em **[Otimizações Visuais e Fluxos](/services)** enfatiza a compressão de atrito. O primeiro valor \"mágico\" que o cliente extraiu deve chegar na primeira meia hora. Pista em jogos de video game mostram que ganhar as 2 primeiras fases rápido retém jogabilidade em milhões por cento a mais. O seu software deve agir igual. O LTV (Life-Time Value) agradecerá.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 19,
|
||||||
|
"slug": "dark-social-decisoes",
|
||||||
|
"title": "Dark Social: Onde as Decisões Realmente Acontecem",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "5 min de leitura",
|
||||||
|
"date": "25 de Março, 2026",
|
||||||
|
"color": "from-slate-600/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Equipe Onyx",
|
||||||
|
"excerpt": "Analytics e UTMs não pegam o link compartilhado naquele grupo privado do WhatsApp. A verdade oculta sobre conversões indiretas.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1611162617474-5b21e879e113?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Você está Enxergando Metade do Jogo\n\nDark Social representa todas as mensagens DM de Instagram, WhatsApp, Slack interno de empresas. O link vai despido de rastreamento. Quando cai no site e converte, ele recebe marcação de \"Tráfego Direto\". E sua equipe jura que a campanha Display está dando ROI zero.\n\nComo abordar isso? Nas consultorias em parceria aos canais de **[Ads](/services)**, não lutamos com a medição exata algorítmica. Implementamos perguntas em formulários obrigatórios do tipo: \"Como você ouviu falar da nossa empresa pela primeira vez?\". É aí que o campo \"Alguém recomendou no nosso slack\" aparece 15x mais vezes que as planilhas do Facebook reportaram.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 20,
|
||||||
|
"slug": "trafego-pago-crise",
|
||||||
|
"title": "Tráfego Pago em Cenários Adversos e Crises",
|
||||||
|
"category": "Ads",
|
||||||
|
"readTime": "6 min de leitura",
|
||||||
|
"date": "22 de Março, 2026",
|
||||||
|
"color": "from-amber-500/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "Quando a janela fecha e o mercado quebra, concorrentes recuam. O playbook de avanço massivo de capital num momento de medo.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Acumule Market-Share Quando Outros Tremem\n\nVocê está acostumado a dias quentes em um mar calmo. O verdadeiro talento do Growth e da equipe **[de Tráfego](/services)** aparece na instabilidade. Custos de plataforma caem quando o ecossistema reduz leilões devido ao pânico coletivo. É nessa hora que a empresa que detém Caixa se impõe e rouba \"terreno militar\" do concorrente por metade do preço habitual do lead.\n\nComo visualizamos [em grandes reestruturações de cases](/cases), as estratégias adaptativas premiam líderes flexíveis e com visão de longo prazo. Reduza a margem imediata, compre a audiência, engula mercado.\n "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 21,
|
||||||
|
"slug": "futuro-agencias-performance-absoluta",
|
||||||
|
"title": "O Futuro das Agências: Performance Absoluta",
|
||||||
|
"category": "Growth",
|
||||||
|
"readTime": "8 min de leitura",
|
||||||
|
"date": "20 de Março, 2026",
|
||||||
|
"color": "from-indigo-500/30 to-transparent",
|
||||||
|
"featured": false,
|
||||||
|
"author": "Marcus Void",
|
||||||
|
"excerpt": "Adeus às métricas vaidosas (\"curtidas\", \"brand awareness vago\"). O movimento inexorável para parcerias focadas 100% em ROI e crescimento duro.",
|
||||||
|
"imageUrl": "https://images.unsplash.com/photo-1432821596592-e2c18b78144f?auto=format&fit=crop&q=80",
|
||||||
|
"content": "\n# Relatórios Fofos Acabaram\n\nO ecossistema digital mudou do \"fazemos postagens engajadas\" para a sobrevivência fria e metódica dos resultados em caixa. Acreditamos que o **[Onyx Model](/about)** será o escopo mandatório até a década de 2030. Os clientes não pagam por agências; eles compram frentes e divisões terceirizadas especializadas focadas unicamente em **[Growth](/services)**.\n\nEnquanto a mediocridade do setor comemora CPC baixo e leads desqualificados a R$1.00, as operações sólidas cruzam dados da base de CRM para mensurar a taxa de retorno do usuário LTV. \n\nEssa jornada de alto rendimento reflete em números os propósitos maiores da performance sem compromisso. Estude os próximos paradigmas, seja agressivo na retenção do seu conhecimento técnico, e construa barreiras financeiras que a concorrência não tem orçamento contínuo para quebrar.\n "
|
||||||
|
}
|
||||||
|
];
|
||||||
99
Template-01/src/index.css
Normal file
99
Template-01/src/index.css
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Space+Grotesk:wght@500;700&display=swap');
|
||||||
|
@import "tailwindcss";
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-background: #000000;
|
||||||
|
--color-foreground: #ffffff;
|
||||||
|
--color-muted: #8E9299;
|
||||||
|
--color-border: rgba(255, 255, 255, 0.1);
|
||||||
|
--color-accent: #0A66C2;
|
||||||
|
--color-accent-blue: #2563EB;
|
||||||
|
--color-accent-neon: #38bdf8;
|
||||||
|
|
||||||
|
--font-sans: "Inter", system-ui, sans-serif;
|
||||||
|
--font-display: "Plus Jakarta Sans", system-ui, sans-serif;
|
||||||
|
--font-mono: "Space Grotesk", ui-monospace, SFMono-Regular, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--background: 0 0% 0%;
|
||||||
|
--foreground: 0 0% 100%;
|
||||||
|
--muted: 0 0% 64%;
|
||||||
|
--border: 0 0% 15%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #050505; /* Off-black */
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: theme('fontFamily.sans');
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-gradient {
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-image: linear-gradient(to right, #ffffff, #8E9299);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-gradient-blue {
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-image: linear-gradient(135deg, #ffffff 0%, #38bdf8 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-panel {
|
||||||
|
background: rgba(20, 20, 20, 0.4);
|
||||||
|
backdrop-filter: blur(24px);
|
||||||
|
-webkit-backdrop-filter: blur(24px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-panel-glow {
|
||||||
|
background: rgba(20, 20, 20, 0.4);
|
||||||
|
backdrop-filter: blur(24px);
|
||||||
|
-webkit-backdrop-filter: blur(24px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
|
box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.1), 0 0 40px rgba(56, 189, 248, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-lift {
|
||||||
|
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.4s ease;
|
||||||
|
}
|
||||||
|
.hover-lift:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.2), 0 20px 40px rgba(0, 0, 0, 0.4);
|
||||||
|
border-color: rgba(255, 255, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #050505;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #2a2a2a;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #3f3f3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Atmosphere glow overrides */
|
||||||
|
.glow-bg {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(100px);
|
||||||
|
opacity: 0.3;
|
||||||
|
z-index: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
6
Template-01/src/lib/utils.ts
Normal file
6
Template-01/src/lib/utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { clsx, type ClassValue } from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
13
Template-01/src/main.tsx
Normal file
13
Template-01/src/main.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {StrictMode} from 'react';
|
||||||
|
import {createRoot} from 'react-dom/client';
|
||||||
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
import App from './App.tsx';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<StrictMode>
|
||||||
|
<HelmetProvider>
|
||||||
|
<App />
|
||||||
|
</HelmetProvider>
|
||||||
|
</StrictMode>,
|
||||||
|
);
|
||||||
117
Template-01/src/pages/About.tsx
Normal file
117
Template-01/src/pages/About.tsx
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function About() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full pb-32">
|
||||||
|
<SEO
|
||||||
|
title="Sobre a Onyx Growth | O Modelo Anti-Agência"
|
||||||
|
description="Nós acreditamos em performance radical. A Onyx atua como um braço de crescimento que elimina o atrito entre o seu produto e sua audiência, sem enrolação."
|
||||||
|
url="https://onyx.com.br/about"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "AboutPage",
|
||||||
|
"name": "Sobre a Onyx Growth",
|
||||||
|
"description": "A Onyx Growth atua como um braço de crescimento de alta performance em SEO, Ads e Design.",
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Onyx Growth",
|
||||||
|
"foundingDate": "2020",
|
||||||
|
"employee": [
|
||||||
|
{ "@type": "Person", "name": "Marcus Void", "jobTitle": "CEO & Head de Growth" },
|
||||||
|
{ "@type": "Person", "name": "Elena Rostova", "jobTitle": "Diretora Chefe de Design" },
|
||||||
|
{ "@type": "Person", "name": "Julian Vance", "jobTitle": "Diretor de SEO Tech" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<section className="pt-32 pb-20 px-6">
|
||||||
|
<div className="container mx-auto max-w-5xl">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-center mb-24"
|
||||||
|
>
|
||||||
|
<h1 className="text-4xl md:text-6xl lg:text-7xl font-display font-semibold tracking-tighter mb-8 max-w-4xl mx-auto leading-[0.9]">
|
||||||
|
Nós acreditamos em performance <br/> <span className="text-gray-500">radical.</span>
|
||||||
|
</h1>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-16 items-center">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="aspect-[4/5] rounded-[40px] bg-white/5 border border-white/10 relative overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-tr from-blue-900/20 to-transparent" />
|
||||||
|
{/* Fake image representation */}
|
||||||
|
<div className="absolute inset-x-0 bottom-0 h-1/2 bg-gradient-to-t from-black to-transparent" />
|
||||||
|
<div className="absolute bottom-8 left-8">
|
||||||
|
<div className="text-xs uppercase tracking-widest text-gray-400 mb-2">Fundada em 2020</div>
|
||||||
|
<div className="text-2xl font-display font-medium">Remote-first. Impacto Global.</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 20 }}
|
||||||
|
whileInView={{ opacity: 1, x: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
className="flex flex-col gap-8"
|
||||||
|
>
|
||||||
|
<h2 className="text-2xl font-display font-semibold">O Modelo Anti-Agência.</h2>
|
||||||
|
<p className="text-gray-400 text-lg leading-relaxed font-light">
|
||||||
|
A Onyx foi fundada com um propósito único: eliminar o atrito entre produtos excelentes e sua audiência altamente qualificada.
|
||||||
|
</p>
|
||||||
|
<p className="text-gray-400 text-lg leading-relaxed font-light">
|
||||||
|
Agências tradicionais focam em métricas de vaidade — curtidas, impressões e relatórios bonitos. Nós somos um coletivo de profissionais de growth e design focados exclusivamente em lucro, retorno sobre investimento (ROI) e posicionamento estético impecável.
|
||||||
|
</p>
|
||||||
|
<div className="grid grid-cols-2 gap-8 pt-8 border-t border-white/10">
|
||||||
|
<div>
|
||||||
|
<div className="text-3xl font-display font-semibold text-white mb-2">$500M+</div>
|
||||||
|
<div className="text-sm text-gray-500 uppercase tracking-widest">Receita Gerada</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-3xl font-display font-semibold text-white mb-2">35+</div>
|
||||||
|
<div className="text-sm text-gray-500 uppercase tracking-widest">Especialistas Nível Global</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Team Section */}
|
||||||
|
<section className="py-24 px-6 bg-black">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<h2 className="text-3xl md:text-4xl font-display font-semibold mb-16 text-center">Nossos Líderes.</h2>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
|
{[
|
||||||
|
{ name: "Marcus Void", role: "CEO & Head de Growth", img: "bg-blue-900/20" },
|
||||||
|
{ name: "Elena Rostova", role: "Diretora Chefe de Design", img: "bg-purple-900/20" },
|
||||||
|
{ name: "Julian Vance", role: "Diretor de SEO Tech", img: "bg-emerald-900/20" }
|
||||||
|
].map((member, i) => (
|
||||||
|
<div key={member.name} className="flex flex-col">
|
||||||
|
<div className={`w-full aspect-[3/4] rounded-[32px] ${member.img} border border-white/10 mb-6`} />
|
||||||
|
<h3 className="text-2xl font-medium mb-1 text-white">{member.name}</h3>
|
||||||
|
<p className="text-gray-500">{member.role}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="container mx-auto max-w-4xl px-6 text-center mt-20">
|
||||||
|
<div className="glass-panel p-10 md:p-14 rounded-[32px] relative overflow-hidden">
|
||||||
|
<h2 className="text-3xl md:text-4xl font-display font-semibold mb-6">Junte-se à Onyx</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-10 max-w-xl mx-auto">Estamos sempre abertos para talentos raros e profissionais de ponta em Tráfego, SEO e Code.</p>
|
||||||
|
<Link to="#" className="inline-flex items-center gap-2 border border-white/20 text-white px-8 py-4 rounded-full text-lg font-medium hover:bg-white/10 transition-colors">
|
||||||
|
Ver Vagas Abertas <ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
148
Template-01/src/pages/Blog.tsx
Normal file
148
Template-01/src/pages/Blog.tsx
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, Clock, User } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { articles } from '@/data/articles';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function Blog() {
|
||||||
|
const featuredArticle = articles.find(a => a.featured) || articles[0];
|
||||||
|
const recentArticles = articles.filter(a => a.id !== featuredArticle.id).slice(0, 20); // Show rest of them
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full pb-32">
|
||||||
|
<SEO
|
||||||
|
title="O Playbook de Growth | Blog Onyx"
|
||||||
|
description="Nossas anotações, estratégias, táticas e pesquisas. Nós documentamos tudo o que usamos para escalar nossos clientes diariamente em SEO, Design e Ads."
|
||||||
|
url="https://onyx.com.br/blog"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "Blog",
|
||||||
|
"name": "O Playbook de Growth | Blog Onyx",
|
||||||
|
"description": "Nossas anotações, estratégias, táticas e pesquisas. Nós documentamos tudo o que usamos para escalar nossos clientes diariamente em SEO, Design e Ads.",
|
||||||
|
"blogPost": articles.map(article => ({
|
||||||
|
"@type": "BlogPosting",
|
||||||
|
"headline": article.title,
|
||||||
|
"url": `https://onyx.com.br/blog/${article.slug}`,
|
||||||
|
"author": {
|
||||||
|
"@type": "Person",
|
||||||
|
"name": article.author
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<section className="pt-32 pb-20 px-6">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="mb-16 md:mb-24"
|
||||||
|
>
|
||||||
|
<h1 className="text-4xl md:text-6xl lg:text-7xl font-display font-semibold tracking-tighter mb-6">O Playbook de Growth.</h1>
|
||||||
|
<p className="text-xl text-gray-400 font-light max-w-2xl">
|
||||||
|
Nossas anotações, estratégias, táticas e pesquisas. Nós documentamos tudo o que usamos para escalar nossos clientes diariamente.
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Featured Post */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="mb-20"
|
||||||
|
>
|
||||||
|
<Link to={`/blog/${featuredArticle.slug}`} className="group grid grid-cols-1 md:grid-cols-2 gap-8 items-center bg-white/5 border border-white/10 rounded-[40px] p-8 md:p-12 hover:bg-white/10 transition-colors">
|
||||||
|
<div className={`w-full aspect-[4/3] rounded-[24px] bg-gray-900 flex items-center justify-center border border-white/10 relative overflow-hidden`}>
|
||||||
|
{featuredArticle.imageUrl && (
|
||||||
|
<img src={featuredArticle.imageUrl} alt={featuredArticle.title} className="absolute inset-0 w-full h-full object-cover opacity-90 group-hover:scale-105 group-hover:opacity-100 transition-all duration-700" />
|
||||||
|
)}
|
||||||
|
{!featuredArticle.imageUrl && (
|
||||||
|
<div className="text-white/20 font-display font-bold text-6xl group-hover:scale-110 transition-transform">DESTAQUE</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-6">
|
||||||
|
<div className="flex items-center gap-4 text-sm text-gray-400">
|
||||||
|
<span className="text-blue-400 font-medium uppercase tracking-widest">{featuredArticle.category}</span>
|
||||||
|
<div className="w-1 h-1 rounded-full bg-gray-600" />
|
||||||
|
<span className="flex items-center gap-2"><Clock className="w-4 h-4" /> {featuredArticle.readTime}</span>
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl md:text-3xl font-display font-semibold group-hover:text-blue-400 transition-colors leading-tight">
|
||||||
|
{featuredArticle.title}
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-400 text-lg leading-relaxed">
|
||||||
|
{featuredArticle.excerpt}
|
||||||
|
</p>
|
||||||
|
<div className="flex items-center gap-4 mt-4">
|
||||||
|
<div className="w-10 h-10 rounded-full bg-white/10 border border-white/20 flex items-center justify-center">
|
||||||
|
<User className="w-5 h-5 text-gray-300" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="text-sm font-medium text-white">{featuredArticle.author}</span>
|
||||||
|
<span className="text-xs text-gray-500">{featuredArticle.date}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
|
{recentArticles.map((article, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={article.id}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: (index % 3) * 0.1 }}
|
||||||
|
>
|
||||||
|
<Link to={`/blog/${article.slug}`} className="flex flex-col group h-full">
|
||||||
|
<div className={`w-full aspect-[4/3] rounded-[24px] mb-6 overflow-hidden bg-gray-900 border border-white/10 relative`}>
|
||||||
|
{article.imageUrl && (
|
||||||
|
<img src={article.imageUrl} alt={article.title} className="absolute inset-0 w-full h-full object-cover opacity-90 group-hover:opacity-100 group-hover:scale-105 transition-all duration-700" />
|
||||||
|
)}
|
||||||
|
<div className="absolute inset-0 bg-black/10 group-hover:bg-transparent transition-colors" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4 text-xs text-gray-400 mb-4">
|
||||||
|
<span className="text-white font-medium uppercase tracking-widest">{article.category}</span>
|
||||||
|
<div className="w-1 h-1 rounded-full bg-gray-600" />
|
||||||
|
<span>{article.readTime}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 className="text-xl font-display font-semibold mb-3 group-hover:text-blue-400 transition-colors line-clamp-2">
|
||||||
|
{article.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p className="text-gray-400 text-sm leading-relaxed mb-6 line-clamp-3">
|
||||||
|
{article.excerpt}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mt-auto flex items-center text-sm font-medium text-white group-hover:text-blue-400 transition-colors">
|
||||||
|
Ler Artigo <ArrowRight className="w-4 h-4 ml-2 group-hover:translate-x-1 transition-transform" />
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="container mx-auto max-w-4xl px-6 text-center mt-20">
|
||||||
|
<div className="glass-panel p-10 md:p-14 rounded-[32px] relative overflow-hidden">
|
||||||
|
<h2 className="text-3xl md:text-4xl font-display font-semibold mb-6">Não Perca Nada</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-8 max-w-xl mx-auto">Inscreva-se na nossa newsletter semanal de estratégias. Uma análise profunda técnica enviada toda terça-feira.</p>
|
||||||
|
<form className="flex flex-col sm:flex-row gap-4 max-w-md mx-auto" onSubmit={e => e.preventDefault()}>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Seu melhor e-mail"
|
||||||
|
className="flex-1 bg-white/5 border border-white/10 rounded-full px-6 py-4 text-white focus:outline-none focus:border-white transition-colors"
|
||||||
|
/>
|
||||||
|
<button type="submit" className="bg-white text-black px-8 py-4 rounded-full font-medium hover:bg-gray-200 transition-colors">
|
||||||
|
Assinar
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
179
Template-01/src/pages/BlogPost.tsx
Normal file
179
Template-01/src/pages/BlogPost.tsx
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
import { useParams, Link } from 'react-router-dom';
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowLeft, ArrowRight, Clock, User, Share2, Facebook, Twitter, Linkedin } from 'lucide-react';
|
||||||
|
import { articles } from '@/data/articles';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
import remarkGfm from 'remark-gfm';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function BlogPost() {
|
||||||
|
const { slug } = useParams();
|
||||||
|
const article = articles.find(a => a.slug === slug);
|
||||||
|
|
||||||
|
if (!article) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-[70vh] pt-32 px-6">
|
||||||
|
<SEO title="Artigo não encontrado | Onyx Growth" description="Página não encontrada." />
|
||||||
|
<h1 className="text-4xl font-display font-bold mb-4">Artigo não encontrado</h1>
|
||||||
|
<p className="text-gray-400 mb-8">Essa URL pode ter sido alterada ou não existe mais.</p>
|
||||||
|
<Link to="/blog" className="text-blue-400 hover:text-white transition-colors flex items-center gap-2">
|
||||||
|
<ArrowLeft className="w-4 h-4" /> Voltar para o Blog
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle rich tags schema for BlogPosting
|
||||||
|
const articleSchema = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BlogPosting",
|
||||||
|
"mainEntityOfPage": {
|
||||||
|
"@type": "WebPage",
|
||||||
|
"@id": `https://onyx.com.br/blog/${article.slug}`
|
||||||
|
},
|
||||||
|
"headline": article.title,
|
||||||
|
"image": article.imageUrl ? [article.imageUrl] : [],
|
||||||
|
"author": {
|
||||||
|
"@type": "Person",
|
||||||
|
"name": article.author
|
||||||
|
},
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Onyx Growth",
|
||||||
|
"logo": {
|
||||||
|
"@type": "ImageObject",
|
||||||
|
"url": "https://onyx.com.br/icon.png"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Mocking date format since it's just '12 de Maio, 2026' string
|
||||||
|
"datePublished": "2026-05-12",
|
||||||
|
"description": article.excerpt
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className="flex flex-col w-full pb-32">
|
||||||
|
<SEO
|
||||||
|
title={`${article.title} | Blog Onyx`}
|
||||||
|
description={article.excerpt}
|
||||||
|
type="article"
|
||||||
|
image={article.imageUrl}
|
||||||
|
url={`https://onyx.com.br/blog/${article.slug}`}
|
||||||
|
schema={articleSchema}
|
||||||
|
/>
|
||||||
|
{/* Header */}
|
||||||
|
<section className="pt-40 pb-16 px-6 relative">
|
||||||
|
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-purple-600/10 rounded-full blur-[120px] pointer-events-none" />
|
||||||
|
<div className="container mx-auto max-w-4xl relative z-10">
|
||||||
|
<Link to="/blog" className="inline-flex items-center gap-2 text-gray-400 hover:text-white transition-colors mb-12 text-sm font-medium">
|
||||||
|
<ArrowLeft className="w-4 h-4" /> Todos os Artigos
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4 text-sm text-gray-400 mb-6">
|
||||||
|
<span className="text-white font-medium uppercase tracking-widest">{article.category}</span>
|
||||||
|
<div className="w-1 h-1 rounded-full bg-gray-600" />
|
||||||
|
<span className="flex items-center gap-2"><Clock className="w-4 h-4" /> {article.readTime}</span>
|
||||||
|
<div className="w-1 h-1 rounded-full bg-gray-600" />
|
||||||
|
<span>{article.date}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-3xl md:text-5xl font-display font-semibold tracking-tighter mb-8 leading-tight"
|
||||||
|
>
|
||||||
|
{article.title}
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="flex items-center justify-between py-6 border-y border-white/10"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-12 h-12 rounded-full bg-white/10 border border-white/20 flex items-center justify-center">
|
||||||
|
<User className="w-6 h-6 text-gray-300" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="font-medium text-white">{article.author}</span>
|
||||||
|
<span className="text-sm text-gray-500">Especialista Onyx</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<span className="text-sm text-gray-500 font-medium hidden sm:block">Compartilhar:</span>
|
||||||
|
<button className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-gray-400 hover:text-white hover:bg-white/10 transition-colors">
|
||||||
|
<Twitter className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
<button className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-gray-400 hover:text-white hover:bg-white/10 transition-colors">
|
||||||
|
<Linkedin className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
<button className="w-10 h-10 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-gray-400 hover:text-white hover:bg-white/10 transition-colors">
|
||||||
|
<Share2 className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Hero Image */}
|
||||||
|
<section className="px-6 mb-16">
|
||||||
|
<div className="container mx-auto max-w-5xl">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
transition={{ delay: 0.2 }}
|
||||||
|
className={`w-full aspect-[21/9] rounded-[32px] overflow-hidden relative border border-white/10 ${article.color || 'bg-gradient-to-tr from-gray-900 to-zinc-900'}`}
|
||||||
|
>
|
||||||
|
{article.imageUrl && (
|
||||||
|
<img src={article.imageUrl} alt={article.title} className="w-full h-full object-cover opacity-80 mix-blend-overlay" />
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Content */}
|
||||||
|
<section className="px-6">
|
||||||
|
<div className="container mx-auto max-w-3xl">
|
||||||
|
<div className="prose prose-invert prose-lg max-w-none prose-headings:font-display prose-headings:font-semibold prose-a:text-blue-400 hover:prose-a:text-blue-300 prose-img:rounded-2xl prose-img:border prose-img:border-white/10">
|
||||||
|
<ReactMarkdown
|
||||||
|
remarkPlugins={[remarkGfm]}
|
||||||
|
components={{
|
||||||
|
a: ({node, ...props}) => {
|
||||||
|
const isInternal = props.href?.startsWith('/');
|
||||||
|
if (isInternal) {
|
||||||
|
return <Link to={props.href!} className={props.className}>{props.children}</Link>;
|
||||||
|
}
|
||||||
|
return <a target="_blank" rel="noopener noreferrer" {...props} />;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{article.content}
|
||||||
|
</ReactMarkdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Tags */}
|
||||||
|
<div className="flex flex-wrap gap-2 mt-16 pt-8 border-t border-white/10">
|
||||||
|
{['Growth', 'SEO Tático', 'Métricas', 'Performance'].map(tag => (
|
||||||
|
<span key={tag} className="px-4 py-2 rounded-full border border-white/10 bg-white/5 text-sm font-medium text-gray-400">
|
||||||
|
{tag}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Footer CTA */}
|
||||||
|
<section className="container mx-auto max-w-3xl px-6 text-center mt-24">
|
||||||
|
<div className="glass-panel p-10 md:p-14 rounded-[32px] relative overflow-hidden bg-gradient-to-b from-blue-900/20 to-black">
|
||||||
|
<h2 className="text-2xl md:text-4xl font-display font-semibold mb-6">Pronto para aplicar essa estratégia?</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-10 max-w-lg mx-auto">Nós podemos auditar os seus números atuais de forma gratuita e indicar o seu potencial de crescimento escondido para os próximos 6 meses.</p>
|
||||||
|
<Link to="/contact" className="inline-flex items-center gap-2 bg-white text-black px-8 py-4 rounded-full text-lg font-medium hover:bg-gray-200 transition-colors">
|
||||||
|
Falar com o nosso time <ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
);
|
||||||
|
}
|
||||||
292
Template-01/src/pages/Cases.tsx
Normal file
292
Template-01/src/pages/Cases.tsx
Normal file
|
|
@ -0,0 +1,292 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
|
import { ArrowRight, MoveRight } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { AreaChart, Area, BarChart, Bar, LineChart, Line, ResponsiveContainer, Tooltip } from 'recharts';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
const dataSeo = [
|
||||||
|
{ name: 'M1', traffic: 4000 },
|
||||||
|
{ name: 'M2', traffic: 4800 },
|
||||||
|
{ name: 'M3', traffic: 6100 },
|
||||||
|
{ name: 'M4', traffic: 9800 },
|
||||||
|
{ name: 'M5', traffic: 15400 },
|
||||||
|
{ name: 'M6', traffic: 23000 },
|
||||||
|
{ name: 'M7', traffic: 31000 },
|
||||||
|
{ name: 'M8', traffic: 37600 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const dataAds = [
|
||||||
|
{ name: 'Jan', cpa: 120 },
|
||||||
|
{ name: 'Fev', cpa: 110 },
|
||||||
|
{ name: 'Mar', cpa: 85 },
|
||||||
|
{ name: 'Abr', cpa: 70 },
|
||||||
|
{ name: 'Mai', cpa: 52 },
|
||||||
|
{ name: 'Jun', cpa: 45 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const dataGrowth = [
|
||||||
|
{ name: 'Q1', mrr: 20 },
|
||||||
|
{ name: 'Q2', mrr: 45 },
|
||||||
|
{ name: 'Q3', mrr: 85 },
|
||||||
|
{ name: 'Q4', mrr: 150 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const dataBranding = [
|
||||||
|
{ name: 'Antes', ticket: 85 },
|
||||||
|
{ name: 'Depois', ticket: 130 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const cases = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
client: "Nexus FinTech",
|
||||||
|
category: "SEO",
|
||||||
|
title: "Escalando tráfego orgânico em 840% para uma startup Series A.",
|
||||||
|
metrics: [
|
||||||
|
{ label: "Crescimento", value: "+840%" },
|
||||||
|
{ label: "Novos Leads/Mês", value: "1,200+" },
|
||||||
|
{ label: "Período", value: "8 Meses" }
|
||||||
|
],
|
||||||
|
color: "from-blue-600/20 to-transparent",
|
||||||
|
chartColor: "#3b82f6",
|
||||||
|
chart: "seo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
client: "Aura Aesthetics",
|
||||||
|
category: "Tráfego Pago",
|
||||||
|
title: "Redução de CPA em 62% reestruturando todo o funil de reservas.",
|
||||||
|
metrics: [
|
||||||
|
{ label: "Redução de CPA", value: "-62%" },
|
||||||
|
{ label: "Taxa de Conv.", value: "8.4%" },
|
||||||
|
{ label: "ROAS", value: "4.8x" }
|
||||||
|
],
|
||||||
|
color: "from-purple-600/20 to-transparent",
|
||||||
|
chartColor: "#a855f7",
|
||||||
|
chart: "ads"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
client: "Krom SaaS",
|
||||||
|
category: "Growth",
|
||||||
|
title: "De $20k a $150k de MRR através de SEO agressivo B2B.",
|
||||||
|
metrics: [
|
||||||
|
{ label: "Crescimento MRR", value: "7.5x" },
|
||||||
|
{ label: "Posições Top 3", value: "145" },
|
||||||
|
{ label: "Vendas Enterprise", value: "+34" }
|
||||||
|
],
|
||||||
|
color: "from-emerald-600/20 to-transparent",
|
||||||
|
chartColor: "#10b981",
|
||||||
|
chart: "growth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
client: "Nova Retail",
|
||||||
|
category: "Branding",
|
||||||
|
title: "Um rebranding completo que aumentou o ticket médio em R$45.",
|
||||||
|
metrics: [
|
||||||
|
{ label: "Aumento Ticket", value: "+R$45" },
|
||||||
|
{ label: "Bounce Rate", value: "-24%" },
|
||||||
|
{ label: "Faturamento (+)", value: "R$1.2M" }
|
||||||
|
],
|
||||||
|
color: "from-orange-600/20 to-transparent",
|
||||||
|
chartColor: "#f97316",
|
||||||
|
chart: "branding"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const renderChart = (type: string, color: string) => {
|
||||||
|
switch(type) {
|
||||||
|
case 'seo':
|
||||||
|
return (
|
||||||
|
<ResponsiveContainer width="100%" height="100%" minWidth={1} minHeight={1}>
|
||||||
|
<AreaChart data={dataSeo} margin={{ top: 20, right: 0, left: 0, bottom: 0 }}>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="colorSeo" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="5%" stopColor={color} stopOpacity={0.8}/>
|
||||||
|
<stop offset="95%" stopColor={color} stopOpacity={0}/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{ backgroundColor: '#111', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }}
|
||||||
|
itemStyle={{ color: '#fff' }}
|
||||||
|
formatter={(value: number) => [`${value}`, 'Visitas']}
|
||||||
|
/>
|
||||||
|
<Area type="monotone" dataKey="traffic" stroke={color} strokeWidth={3} fillOpacity={1} fill="url(#colorSeo)" />
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
);
|
||||||
|
case 'ads':
|
||||||
|
return (
|
||||||
|
<ResponsiveContainer width="100%" height="100%" minWidth={1} minHeight={1}>
|
||||||
|
<LineChart data={dataAds} margin={{ top: 20, right: 20, left: 20, bottom: 20 }}>
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{ backgroundColor: '#111', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }}
|
||||||
|
itemStyle={{ color: '#fff' }}
|
||||||
|
formatter={(value: number) => [`R$ ${value}`, 'CPA']}
|
||||||
|
/>
|
||||||
|
<Line type="monotone" dataKey="cpa" stroke={color} strokeWidth={4} dot={{ r: 6, fill: '#000', stroke: color, strokeWidth: 2 }} />
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
);
|
||||||
|
case 'growth':
|
||||||
|
return (
|
||||||
|
<ResponsiveContainer width="100%" height="100%" minWidth={1} minHeight={1}>
|
||||||
|
<BarChart data={dataGrowth} margin={{ top: 20, right: 20, left: 20, bottom: 0 }}>
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{ backgroundColor: '#111', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }}
|
||||||
|
cursor={{ fill: 'rgba(255,255,255,0.05)' }}
|
||||||
|
formatter={(value: number) => [`$${value}k`, 'MRR']}
|
||||||
|
/>
|
||||||
|
<Bar dataKey="mrr" fill={color} radius={[6, 6, 0, 0]} />
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
);
|
||||||
|
case 'branding':
|
||||||
|
return (
|
||||||
|
<ResponsiveContainer width="100%" height="100%" minWidth={1} minHeight={1}>
|
||||||
|
<BarChart data={dataBranding} margin={{ top: 40, right: 40, left: 40, bottom: 0 }}>
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{ backgroundColor: '#111', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '8px', color: '#fff' }}
|
||||||
|
cursor={{ fill: 'rgba(255,255,255,0.05)' }}
|
||||||
|
formatter={(value: number) => [`R$ ${value}`, 'Ticket Médio']}
|
||||||
|
/>
|
||||||
|
<Bar dataKey="ticket" fill={color} radius={[6, 6, 0, 0]} maxBarSize={80} />
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Cases() {
|
||||||
|
const [activeTab, setActiveTab] = useState('Todos');
|
||||||
|
const tabs = ['Todos', 'SEO', 'Tráfego Pago', 'Growth', 'Branding'];
|
||||||
|
|
||||||
|
const filteredCases = activeTab === 'Todos'
|
||||||
|
? cases
|
||||||
|
: cases.filter(c => c.category === activeTab);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full pb-32">
|
||||||
|
<SEO
|
||||||
|
title="Cases | Resultados da Onyx Growth"
|
||||||
|
description="Estudos de caso reais de como escalamos a receita de empresas usando táticas de SEO agressivo, Growth Full-Stack e Tráfego Pago de alta conversão."
|
||||||
|
url="https://onyx.com.br/cases"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "CollectionPage",
|
||||||
|
"name": "Cases | Resultados da Onyx Growth",
|
||||||
|
"description": "Estudos de caso reais de como escalamos a receita de empresas usando táticas de SEO agressivo, Growth Full-Stack e Tráfego Pago de alta conversão.",
|
||||||
|
"publisher": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Onyx Growth"
|
||||||
|
},
|
||||||
|
"hasPart": cases.map((c) => ({
|
||||||
|
"@type": "Article",
|
||||||
|
"headline": c.title,
|
||||||
|
"about": {
|
||||||
|
"@type": "Thing",
|
||||||
|
"name": c.client
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<section className="pt-32 pb-20 px-6">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="flex flex-col md:flex-row md:items-end justify-between gap-8 mb-20"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h1 className="text-4xl md:text-6xl lg:text-7xl font-display font-semibold tracking-tighter mb-6">Nosso Trabalho.</h1>
|
||||||
|
<p className="text-xl text-gray-400 max-w-xl font-light">Deixamos os resultados falarem por si. Estudos de caso comprovados para empresas ambiciosas.</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-3">
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<button
|
||||||
|
key={tab}
|
||||||
|
onClick={() => setActiveTab(tab)}
|
||||||
|
className={`px-6 py-2 rounded-full border text-sm font-medium transition-colors ${
|
||||||
|
activeTab === tab
|
||||||
|
? 'bg-white text-black border-white'
|
||||||
|
: 'border-white/10 text-gray-400 hover:text-white hover:border-white/30'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{tab}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div layout className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
|
<AnimatePresence mode="popLayout">
|
||||||
|
{filteredCases.map((project, index) => (
|
||||||
|
<motion.div
|
||||||
|
layout
|
||||||
|
key={project.id}
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95 }}
|
||||||
|
transition={{ duration: 0.4, type: "spring", bounce: 0.2 }}
|
||||||
|
className="group cursor-pointer flex flex-col h-full"
|
||||||
|
>
|
||||||
|
<div className="w-full aspect-[4/3] rounded-[32px] mb-8 overflow-hidden relative border border-white/10 bg-gray-900 flex flex-col">
|
||||||
|
{/* Chart Header Info */}
|
||||||
|
<div className="p-6 md:p-8 flex items-center justify-between z-10 pointer-events-none">
|
||||||
|
<div>
|
||||||
|
<div className="text-sm text-gray-400 mb-1 font-mono uppercase tracking-wider">{project.client}</div>
|
||||||
|
<div className="text-xl font-bold text-white tracking-tight">{project.metrics[0].label}: {project.metrics[0].value}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* The Chart */}
|
||||||
|
<div className="flex-1 w-full relative">
|
||||||
|
<div className="absolute inset-0 p-4 pb-0 pt-20">
|
||||||
|
{renderChart(project.chart, project.chartColor)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="absolute inset-0 bg-black/10 group-hover:bg-transparent transition-colors duration-500 pointer-events-none" />
|
||||||
|
|
||||||
|
<div className="absolute top-6 right-6 w-14 h-14 bg-white rounded-full flex items-center justify-center text-black opacity-0 scale-50 group-hover:opacity-100 group-hover:scale-100 transition-all duration-500 ease-[0.16,1,0.3,1] z-20">
|
||||||
|
<MoveRight className="w-6 h-6 -rotate-45" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 flex flex-col">
|
||||||
|
<div className="flex items-center gap-4 mb-4">
|
||||||
|
<span className="text-white font-medium">{project.client}</span>
|
||||||
|
<div className="w-1 h-1 rounded-full bg-gray-500" />
|
||||||
|
<span className="text-gray-400 text-sm uppercase tracking-wider">{project.category}</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-xl md:text-2xl font-display font-medium mb-8 pr-8 group-hover:text-blue-400 transition-colors">
|
||||||
|
{project.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-3 gap-4 pt-6 border-t border-white/10 mt-auto">
|
||||||
|
{project.metrics.map(metric => (
|
||||||
|
<div key={metric.label}>
|
||||||
|
<div className="text-xl md:text-2xl font-bold text-white mb-1">{metric.value}</div>
|
||||||
|
<div className="text-xs text-gray-500 uppercase tracking-wider leading-tight">{metric.label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</AnimatePresence>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="container mx-auto max-w-4xl px-6 text-center mt-20">
|
||||||
|
<h2 className="text-2xl md:text-4xl font-display font-semibold mb-8">Pronto para ser o nosso próximo case?</h2>
|
||||||
|
<Link to="/contact" className="inline-flex items-center gap-2 bg-white text-black px-8 py-4 rounded-full text-lg font-medium hover:scale-105 transition-transform">
|
||||||
|
Iniciar Projeto <ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
133
Template-01/src/pages/Contact.tsx
Normal file
133
Template-01/src/pages/Contact.tsx
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, Mail, MapPin } from 'lucide-react';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function Contact() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full pb-32">
|
||||||
|
<SEO
|
||||||
|
title="Contato | Bora Escalar com a Onyx"
|
||||||
|
description="Preencha o formulário e marcaremos uma chamada profunda de negócios nas próximas 24 horas. Descubra o verdadeiro potencial do seu produto."
|
||||||
|
url="https://onyx.com.br/contact"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "ContactPage",
|
||||||
|
"name": "Contato | Onyx Growth",
|
||||||
|
"description": "Preencha o formulário e marcaremos uma chamada profunda de negócios nas próximas 24 horas.",
|
||||||
|
"mainEntity": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Onyx Growth",
|
||||||
|
"email": "growth@onyx.agencia",
|
||||||
|
"address": {
|
||||||
|
"@type": "PostalAddress",
|
||||||
|
"streetAddress": "Av. Paulista, 1000 - Bela Vista",
|
||||||
|
"addressLocality": "São Paulo",
|
||||||
|
"addressRegion": "SP",
|
||||||
|
"postalCode": "01310-000",
|
||||||
|
"addressCountry": "BR"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<section className="pt-32 pb-20 px-6 relative overflow-hidden">
|
||||||
|
{/* Glow */}
|
||||||
|
<div className="absolute top-0 right-1/4 w-[500px] h-[500px] bg-blue-600/10 rounded-full blur-[120px] pointer-events-none" />
|
||||||
|
|
||||||
|
<div className="container mx-auto max-w-6xl relative z-10">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="mb-16 md:mb-24"
|
||||||
|
>
|
||||||
|
<h1 className="text-4xl md:text-6xl lg:text-7xl font-display font-semibold tracking-tighter mb-6">Bora Escalar.</h1>
|
||||||
|
<p className="text-xl text-gray-400 font-light max-w-xl">
|
||||||
|
Preencha o formulário abaixo. Se houver um fit estratégico mútou, marcaremos uma chamada profunda de negócios nas próximas 24 horas.
|
||||||
|
</p>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: -20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
>
|
||||||
|
<form className="flex flex-col gap-8" onSubmit={(e) => e.preventDefault()}>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<label className="text-sm font-medium text-gray-400 uppercase tracking-widest">Nome</label>
|
||||||
|
<input type="text" className="bg-transparent border-b border-white/20 pb-4 text-xl focus:outline-none focus:border-white transition-colors text-white" placeholder="João da Silva" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<label className="text-sm font-medium text-gray-400 uppercase tracking-widest">Empresa</label>
|
||||||
|
<input type="text" className="bg-transparent border-b border-white/20 pb-4 text-xl focus:outline-none focus:border-white transition-colors text-white" placeholder="Acme Inc." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<label className="text-sm font-medium text-gray-400 uppercase tracking-widest">E-mail</label>
|
||||||
|
<input type="email" className="bg-transparent border-b border-white/20 pb-4 text-xl focus:outline-none focus:border-white transition-colors text-white" placeholder="joao@acme.com.br" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<label className="text-sm font-medium text-gray-400 uppercase tracking-widest">Faturamento Mensal Atual</label>
|
||||||
|
<select className="bg-transparent border-b border-white/20 pb-4 text-xl focus:outline-none focus:border-white transition-colors text-white appearance-none">
|
||||||
|
<option className="bg-black text-white">< R$ 50k</option>
|
||||||
|
<option className="bg-black text-white">R$ 50k - R$ 250k</option>
|
||||||
|
<option className="bg-black text-white">R$ 250k - R$ 1M</option>
|
||||||
|
<option className="bg-black text-white">R$ 1M+</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
<label className="text-sm font-medium text-gray-400 uppercase tracking-widest">Como podemos ajudar?</label>
|
||||||
|
<textarea rows={3} className="bg-transparent border-b border-white/20 pb-4 text-xl focus:outline-none focus:border-white transition-colors text-white resize-none" placeholder="Precisamos dominar o SEO no nosso nicho e triplicar a conversão..." />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" className="inline-flex items-center justify-center gap-2 bg-white text-black px-8 py-5 rounded-full text-lg font-medium hover:scale-105 transition-transform self-start mt-4">
|
||||||
|
Solicitar Sessão Estratégica
|
||||||
|
<ArrowRight className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, x: 20 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
transition={{ delay: 0.2 }}
|
||||||
|
className="flex flex-col gap-12 lg:pl-16"
|
||||||
|
>
|
||||||
|
<div className="glass-panel p-10 rounded-[32px]">
|
||||||
|
<h3 className="text-2xl font-display font-medium mb-6">Quais os próximos passos?</h3>
|
||||||
|
<ul className="space-y-6">
|
||||||
|
<li className="flex gap-4">
|
||||||
|
<div className="w-8 h-8 rounded-full border border-white/20 flex items-center justify-center shrink-0 font-mono text-sm text-gray-400">01</div>
|
||||||
|
<p className="text-gray-400 leading-relaxed"><span className="text-white font-medium">Descoberta.</span> Nós revisaremos os seus dados para ver entendermos em que momento do jogo vocês estão.</p>
|
||||||
|
</li>
|
||||||
|
<li className="flex gap-4">
|
||||||
|
<div className="w-8 h-8 rounded-full border border-white/20 flex items-center justify-center shrink-0 font-mono text-sm text-gray-400">02</div>
|
||||||
|
<p className="text-gray-400 leading-relaxed"><span className="text-white font-medium">Auditoria Interna.</span> Um membro sênior mapeará todo o território do seu concorrente e a falha do mercado.</p>
|
||||||
|
</li>
|
||||||
|
<li className="flex gap-4">
|
||||||
|
<div className="w-8 h-8 rounded-full border border-white/20 flex items-center justify-center shrink-0 font-mono text-sm text-gray-400">03</div>
|
||||||
|
<p className="text-gray-400 leading-relaxed"><span className="text-white font-medium">Execução Tática.</span> Nós entregaremos a Rota de Fuga. Se ambos quiserem, nós a trilhamos juntos.</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-6">
|
||||||
|
<div className="flex items-center gap-4 text-gray-400">
|
||||||
|
<Mail className="w-6 h-6 text-white" />
|
||||||
|
<span className="text-lg">growth@onyx.agencia</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-4 text-gray-400">
|
||||||
|
<MapPin className="w-6 h-6 text-white" />
|
||||||
|
<span className="text-lg">Av. Paulista, 1000 - Bela Vista<br/>São Paulo, BR 01310</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
264
Template-01/src/pages/Home.tsx
Normal file
264
Template-01/src/pages/Home.tsx
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, BarChart3, Globe, LineChart as LineChartIcon, MoveUpRight, Sparkles, Zap } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { AreaChart, Area, ResponsiveContainer } from 'recharts';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
const mockData = [
|
||||||
|
{ value: 10 }, { value: 15 }, { value: 25 }, { value: 22 },
|
||||||
|
{ value: 35 }, { value: 30 }, { value: 45 }, { value: 55 },
|
||||||
|
{ value: 48 }, { value: 65 }, { value: 85 }, { value: 100 }
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full overflow-hidden">
|
||||||
|
<SEO
|
||||||
|
title="Onyx Growth | Aceleração de Resultados Digitais"
|
||||||
|
description="Nossas estratégias geram milhões para grandes marcas. Soluções agressivas de SEO e Tráfego Pago focadas em ROI e performance sem precedentes."
|
||||||
|
url="https://onyx.com.br"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "ProfessionalService",
|
||||||
|
"name": "Onyx Growth",
|
||||||
|
"url": "https://onyx.com.br",
|
||||||
|
"logo": "https://onyx.com.br/icon.png",
|
||||||
|
"description": "Agência de crescimento digital, especializada em SEO, Design e Ads focados em performance extrema.",
|
||||||
|
"sameAs": [
|
||||||
|
"https://twitter.com/onyxgrowth",
|
||||||
|
"https://linkedin.com/company/onyxgrowth"
|
||||||
|
]
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* HERO SECTION */}
|
||||||
|
<section className="relative min-h-[90vh] flex flex-col items-center justify-center pt-24 pb-12 px-6">
|
||||||
|
{/* Abstract Background Elements */}
|
||||||
|
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div className="absolute top-1/4 left-1/4 w-[500px] h-[500px] bg-blue-600/20 rounded-full blur-[120px] mix-blend-screen opacity-50 animate-pulse" />
|
||||||
|
<div className="absolute bottom-1/4 right-1/4 w-[600px] h-[600px] bg-purple-600/10 rounded-full blur-[150px] mix-blend-screen opacity-50" />
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-[1200px] h-[1px] bg-gradient-to-r from-transparent via-white/10 to-transparent" />
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[1px] h-[800px] bg-gradient-to-b from-transparent via-white/10 to-transparent" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-10 max-w-5xl mx-auto w-full text-center flex flex-col items-center">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-white/10 bg-white/5 backdrop-blur-md mb-8"
|
||||||
|
>
|
||||||
|
<span className="w-2 h-2 rounded-full bg-blue-500 animate-ping" />
|
||||||
|
<span className="text-sm font-medium tracking-wide uppercase text-gray-300">Novo: Growth SEO potencializado por IA</span>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 40 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 1, delay: 0.1, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="text-5xl md:text-7xl lg:text-8xl font-display font-semibold tracking-tighter leading-[0.9] mb-8"
|
||||||
|
>
|
||||||
|
Nós Projetamos o <br/>
|
||||||
|
<span className="text-gradient">Crescimento Digital.</span>
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 1, delay: 0.2, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="text-xl md:text-2xl text-gray-400 max-w-2xl text-center mb-12 leading-relaxed font-light"
|
||||||
|
>
|
||||||
|
A agência de growth premium para marcas ambiciosas. Combinamos SEO de elite, tráfego pago algorítmico e design atraente para escalar a sua receita.
|
||||||
|
</motion.p>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 1, delay: 0.3, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="flex flex-col sm:flex-row items-center gap-6"
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="bg-white text-black px-8 py-4 rounded-full text-lg font-medium hover:scale-105 transition-transform duration-300 flex items-center justify-center gap-2 w-full sm:w-auto"
|
||||||
|
>
|
||||||
|
Iniciar Seu Projeto
|
||||||
|
<ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/cases"
|
||||||
|
className="px-8 py-4 rounded-full text-lg font-medium border border-white/20 hover:bg-white/10 transition-colors duration-300 text-white flex items-center justify-center w-full sm:w-auto"
|
||||||
|
>
|
||||||
|
Ver Nossos Trabalhos
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Floating Metrics / Dashboard Mockup Hint */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 100 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 1.5, delay: 0.5, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="w-full max-w-6xl mx-auto mt-24 relative z-10 perspective-1000"
|
||||||
|
>
|
||||||
|
<div className="relative w-full aspect-[21/9] rounded-2xl sm:rounded-[40px] border border-white/10 bg-black/40 backdrop-blur-2xl overflow-hidden shadow-2xl glass-panel-glow transform rotate-x-12 translate-y-12 scale-95">
|
||||||
|
<div className="absolute top-0 inset-x-0 h-px bg-gradient-to-r from-transparent via-white/30 to-transparent" />
|
||||||
|
{/* Fake dashboard UI inside */}
|
||||||
|
<div className="p-8 h-full flex flex-col gap-6 opacity-60">
|
||||||
|
<div className="flex justify-between items-center border-b border-white/10 pb-6">
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="w-3 h-3 rounded-full bg-red-500/50"/>
|
||||||
|
<div className="w-3 h-3 rounded-full bg-yellow-500/50"/>
|
||||||
|
<div className="w-3 h-3 rounded-full bg-green-500/50"/>
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-xs text-white/50">PERFORMANCE_METRICS_V2.5</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 grid grid-cols-3 gap-6">
|
||||||
|
<div className="rounded-xl border border-white/5 bg-white/5 p-6 flex flex-col justify-between">
|
||||||
|
<span className="text-white/40 font-medium text-sm">Crescimento de Tráfego</span>
|
||||||
|
<span className="text-4xl font-display text-white">+384%</span>
|
||||||
|
</div>
|
||||||
|
<div className="rounded-xl border border-white/5 bg-white/5 p-6 flex flex-col justify-between">
|
||||||
|
<span className="text-white/40 font-medium text-sm">Taxa de Conversão</span>
|
||||||
|
<span className="text-4xl font-display text-white">4.2%</span>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-1 border border-white/5 bg-white/5 rounded-xl overflow-hidden relative">
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-blue-500/10 to-transparent"/>
|
||||||
|
<div className="absolute inset-0 pt-8">
|
||||||
|
<ResponsiveContainer width="100%" height="100%" minWidth={1} minHeight={1}>
|
||||||
|
<AreaChart data={mockData} margin={{ top: 0, right: 0, left: 0, bottom: 0 }}>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="colorValue" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="5%" stopColor="#3b82f6" stopOpacity={0.5}/>
|
||||||
|
<stop offset="95%" stopColor="#3b82f6" stopOpacity={0}/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<Area type="monotone" dataKey="value" stroke="#3b82f6" strokeWidth={2} fillOpacity={1} fill="url(#colorValue)" />
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CLIENT LOGOS */}
|
||||||
|
<section className="py-12 border-y border-white/5 bg-white/[0.02]">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl overflow-hidden">
|
||||||
|
<p className="text-center text-sm font-medium uppercase tracking-widest text-gray-500 mb-8">Confiado por líderes de mercado</p>
|
||||||
|
<div className="flex gap-12 md:gap-24 items-center justify-center flex-wrap opacity-50 grayscale">
|
||||||
|
{/* Fake logos */}
|
||||||
|
<div className="text-2xl font-display font-bold tracking-tighter">VERTEX</div>
|
||||||
|
<div className="text-2xl font-sans font-light tracking-widest">AURA</div>
|
||||||
|
<div className="text-2xl font-mono font-bold italic">NEXUS</div>
|
||||||
|
<div className="text-2xl font-display font-black tracking-tight">KROM</div>
|
||||||
|
<div className="text-2xl font-serif italic">Nova</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* SERVICES PREVIEW */}
|
||||||
|
<section className="py-32 relative">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="flex flex-col md:flex-row justify-between items-end mb-20 gap-8">
|
||||||
|
<div className="max-w-2xl">
|
||||||
|
<h2 className="text-3xl md:text-5xl font-display font-semibold tracking-tighter mb-6">Expertise que gera <span className="text-gray-500">receita.</span></h2>
|
||||||
|
<p className="text-xl text-gray-400 font-light leading-relaxed">
|
||||||
|
Nós não entregamos apenas tráfego. Construímos sistemas imbatíveis desenhados para capturar intenção de compra e converter em caixa.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Link to="/services" className="shrink-0 flex items-center gap-2 hover:text-white text-gray-400 transition-colors pb-2 border-b border-white/20 hover:border-white">
|
||||||
|
Todos os Serviços <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{[
|
||||||
|
{ title: "SEO Técnico", desc: "Domine os resultados de busca com otimização estrutural avançada e aquisição de links de alta autoridade.", icon: <Globe className="w-6 h-6 text-blue-400" /> },
|
||||||
|
{ title: "Performance Ads", desc: "Compra algorítmica de mídia no Google e Meta. ROI máximo através de testes-A/B rigorosos e modelagem de dados.", icon: <LineChartIcon className="w-6 h-6 text-red-400" /> },
|
||||||
|
{ title: "Design focado em Conversão", desc: "Nível UX/UI internacional que gera confiança instantânea e guia os usuários para a conversão.", icon: <Sparkles className="w-6 h-6 text-purple-400" /> }
|
||||||
|
].map((service, i) => (
|
||||||
|
<div key={i} className="group glass-panel p-10 rounded-[32px] hover-lift relative overflow-hidden">
|
||||||
|
<div className="absolute top-0 right-0 p-8 opacity-0 group-hover:opacity-10 transition-opacity duration-500">
|
||||||
|
<MoveUpRight className="w-24 h-24" />
|
||||||
|
</div>
|
||||||
|
<div className="w-14 h-14 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center mb-8 group-hover:scale-110 transition-transform duration-500">
|
||||||
|
{service.icon}
|
||||||
|
</div>
|
||||||
|
<h3 className="text-2xl font-display font-semibold mb-4 text-white group-hover:text-transparent group-hover:bg-clip-text group-hover:bg-gradient-to-r group-hover:from-white group-hover:to-gray-500 transition-all">{service.title}</h3>
|
||||||
|
<p className="text-gray-400 leading-relaxed font-light">{service.desc}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* METRICS / RESULTS BENTO */}
|
||||||
|
<section className="py-24 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 auto-rows-[300px]">
|
||||||
|
<div className="md:col-span-2 md:row-span-2 glass-panel rounded-[32px] p-10 flex flex-col justify-between relative overflow-hidden">
|
||||||
|
<div className="absolute -right-20 -top-20 w-80 h-80 bg-blue-600/20 rounded-full blur-[80px]" />
|
||||||
|
<div>
|
||||||
|
<h3 className="text-3xl font-display font-semibold mb-2">Plano de Crescimento Orgânico</h3>
|
||||||
|
<p className="text-gray-400 max-w-sm">Como escalamos uma startup de FinTech do zero aos 100k acessos mensais em apenas 8 meses.</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-end justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-7xl font-display font-semibold tracking-tighter text-white">+840%</div>
|
||||||
|
<div className="text-sm uppercase tracking-widest text-gray-500 mt-2 font-medium">Aumento de Tráfego</div>
|
||||||
|
</div>
|
||||||
|
<Link to="/cases" className="w-16 h-16 rounded-full bg-white flex items-center justify-center text-black hover:scale-110 transition-transform">
|
||||||
|
<ArrowRight className="w-6 h-6" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="md:col-span-2 glass-panel rounded-[32px] p-10 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div className="text-4xl font-display font-semibold tracking-tighter mb-2"><span className="text-gray-500">R$</span>2.4M</div>
|
||||||
|
<div className="text-sm uppercase tracking-widest text-gray-500 font-medium">Gerados no último trimestre</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-16 h-16 rounded-2xl bg-green-500/10 border border-green-500/20 flex items-center justify-center">
|
||||||
|
<BarChart3 className="w-8 h-8 text-green-400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="md:col-span-1 glass-panel rounded-[32px] p-8 flex flex-col justify-center items-center text-center">
|
||||||
|
<Zap className="w-10 h-10 text-yellow-400 mb-6" />
|
||||||
|
<div className="text-3xl font-display font-semibold mb-2">#1</div>
|
||||||
|
<div className="text-xs uppercase tracking-widest text-gray-500">Agência Rankeada<br/>no Brasil</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="md:col-span-1 glass-panel rounded-[32px] p-8 bg-gradient-to-br from-blue-600/20 to-purple-600/20 border-white/10 flex flex-col justify-end">
|
||||||
|
<div className="text-2xl font-display font-medium mb-4">"A Onyx revolucionou completamente a nossa conversão."</div>
|
||||||
|
<div className="text-sm text-gray-400">— CEO, TechFlow Brasil</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* FINAL CTA */}
|
||||||
|
<section className="py-40 relative">
|
||||||
|
<div className="absolute inset-0 bg-white text-black clip-path-slant z-0" style={{ clipPath: 'polygon(0 10%, 100% 0, 100% 90%, 0 100%)' }}></div>
|
||||||
|
<div className="container mx-auto px-6 max-w-5xl relative z-10 text-center text-black py-20">
|
||||||
|
<h2 className="text-4xl md:text-6xl lg:text-7xl font-display font-bold tracking-tighter mb-8 leading-none">
|
||||||
|
Preparado para liderar <br/> o seu mercado?
|
||||||
|
</h2>
|
||||||
|
<p className="text-xl md:text-2xl text-gray-800 max-w-2xl mx-auto mb-12">
|
||||||
|
Agende uma sessão estratégica para ver exatamente o que precisamos fazer para escalar sua marca. Sem compromissos vazios.
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="inline-flex items-center gap-2 bg-black text-white px-10 py-5 rounded-full text-xl font-medium hover:scale-105 transition-transform"
|
||||||
|
>
|
||||||
|
Obter Proposta Gratuita
|
||||||
|
<ArrowRight className="w-6 h-6" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
Template-01/src/pages/NotFound.tsx
Normal file
34
Template-01/src/pages/NotFound.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ArrowLeft } from 'lucide-react';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-[70vh] px-6 text-center">
|
||||||
|
<SEO
|
||||||
|
title="Página não encontrada | Onyx Growth"
|
||||||
|
description="O caminho que você buscou não existe."
|
||||||
|
url="https://onyx.com.br/404"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebPage",
|
||||||
|
"name": "Página não encontrada | Onyx Growth"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
>
|
||||||
|
<h1 className="text-8xl md:text-[150px] font-display font-bold text-white/5 mb-4 leading-none">404</h1>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-display font-semibold mb-6">Visão bloqueada.</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-10 max-w-md mx-auto">
|
||||||
|
A página que você está tentando acessar foi movida, deletada ou nunca existiu neste sistema de arquitetura.
|
||||||
|
</p>
|
||||||
|
<Link to="/" className="inline-flex items-center gap-2 bg-white text-black px-8 py-4 rounded-full text-lg font-medium hover:bg-gray-200 transition-colors">
|
||||||
|
<ArrowLeft className="w-5 h-5" /> Retornar ao Início
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
145
Template-01/src/pages/Services.tsx
Normal file
145
Template-01/src/pages/Services.tsx
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, BarChart, Code2, Globe, Megaphone, Palette, Search, Sparkles } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{
|
||||||
|
id: "seo",
|
||||||
|
title: "SEO de Elite",
|
||||||
|
description: "Revertemos o algoritmo de busca para dominar palavras-chave de alta intenção de compra. Nós implementamos otimização de cluster, links de altíssima autoridade e arquitetura técnica impecável.",
|
||||||
|
icon: <Search className="w-8 h-8 text-blue-400" />,
|
||||||
|
stats: ["+250% Tráfego Médio", "Risco Zero de Punição"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ads",
|
||||||
|
title: "Tráfego Algotímico",
|
||||||
|
description: "Criativos, copy e modelagem de dados atuando em conjunto no Google e Meta Ads. Não compramos cliques; maximizamos aquisição focados inteiramente em CAC e ROAS.",
|
||||||
|
icon: <BarChart className="w-8 h-8 text-red-400" />,
|
||||||
|
stats: ["CPA Reduzido", "ROAS Acima de 3.5x"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "branding",
|
||||||
|
title: "Branding Premium",
|
||||||
|
description: "Identidades visuais premium que elevam o seu valor percebido, permitindo cobrar tickets cada vez mais altos. Foco extremo na tipografia e mood boards de conversão.",
|
||||||
|
icon: <Palette className="w-8 h-8 text-purple-400" />,
|
||||||
|
stats: ["Design Internacional", "Guias de Marca"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "web",
|
||||||
|
title: "Desenvolvimento Web",
|
||||||
|
description: "Websites desenvolvidos sob demanda (React, Next, Framer) superando o limite do Design System para criar interfaces performáticas, lisas e voltadas a captação.",
|
||||||
|
icon: <Code2 className="w-8 h-8 text-emerald-400" />,
|
||||||
|
stats: ["99+ Google Lighthouse", "Aberturas Instantâneas"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "automation",
|
||||||
|
title: "Automação e IA",
|
||||||
|
description: "Agentes de inteligência artificial que atuam para fechar negociações. Criamos desde o setup das ferramentas base como CRMs, até sistemas neurais avançados.",
|
||||||
|
icon: <Sparkles className="w-8 h-8 text-yellow-400" />,
|
||||||
|
stats: ["Automação 24/7", "Fluxos de Venda Ativos"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "growth",
|
||||||
|
title: "Growth Full-Stack",
|
||||||
|
description: "Nós atuamos como o seu braço de crescimento - C-level fracionado e equipe sênior gerindo de forma holística toda a estruturação de Growth das frentes.",
|
||||||
|
icon: <Globe className="w-8 h-8 text-indigo-400" />,
|
||||||
|
stats: ["Estratégia Completa", "Plano Personalizado"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Services() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full pb-32">
|
||||||
|
<SEO
|
||||||
|
title="Serviços | Onyx Growth"
|
||||||
|
description="Conheça nossas frentes de atuação: SEO de Elite, Tráfego Pago, Design Conversivo, Engenharia Front-end e Growth Full-Stack."
|
||||||
|
url="https://onyx.com.br/services"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "ItemList",
|
||||||
|
"itemListElement": services.map((service, index) => ({
|
||||||
|
"@type": "ListItem",
|
||||||
|
"position": index + 1,
|
||||||
|
"item": {
|
||||||
|
"@type": "Service",
|
||||||
|
"name": service.title,
|
||||||
|
"description": service.description,
|
||||||
|
"provider": {
|
||||||
|
"@type": "Organization",
|
||||||
|
"name": "Onyx Growth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Header */}
|
||||||
|
<section className="pt-32 pb-20 px-6 border-b border-white/5 relative overflow-hidden">
|
||||||
|
<div className="absolute top-0 right-0 w-[600px] h-[600px] bg-blue-600/10 rounded-full blur-[120px] pointer-events-none" />
|
||||||
|
<div className="container mx-auto max-w-5xl text-center relative z-10">
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-4xl md:text-6xl lg:text-7xl font-display font-semibold tracking-tighter mb-8"
|
||||||
|
>
|
||||||
|
Táticas que <br/> <span className="text-gradient">geram faturamento.</span>
|
||||||
|
</motion.h1>
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-xl text-gray-400 max-w-2xl mx-auto font-light leading-relaxed"
|
||||||
|
>
|
||||||
|
Implementamos uma abordagem mecânica no crescimento. Sem métricas de vaidade, apenas aumentos expressivos para o final do mês.
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Services List */}
|
||||||
|
<section className="py-24 px-6 relative z-10">
|
||||||
|
<div className="container mx-auto max-w-6xl">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
|
{services.map((service, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={service.id}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true }}
|
||||||
|
transition={{ delay: index * 0.1 }}
|
||||||
|
id={service.id}
|
||||||
|
className="glass-panel p-10 rounded-[32px] hover-lift flex flex-col h-full"
|
||||||
|
>
|
||||||
|
<div className="w-16 h-16 rounded-2xl bg-white/5 border border-white/10 flex items-center justify-center mb-8">
|
||||||
|
{service.icon}
|
||||||
|
</div>
|
||||||
|
<h2 className="text-2xl font-display font-semibold mb-4">{service.title}</h2>
|
||||||
|
<p className="text-gray-400 leading-relaxed font-light mb-8 flex-1">
|
||||||
|
{service.description}
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-4 pt-6 border-t border-white/10">
|
||||||
|
{service.stats.map(stat => (
|
||||||
|
<div key={stat} className="text-sm font-medium text-white px-4 py-2 bg-white/5 rounded-full border border-white/10">
|
||||||
|
{stat}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<section className="container mx-auto max-w-4xl px-6 text-center mt-12">
|
||||||
|
<div className="glass-panel p-10 md:p-14 rounded-[32px] relative overflow-hidden">
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-b from-blue-600/10 to-transparent pointer-events-none" />
|
||||||
|
<h2 className="text-3xl md:text-4xl font-display font-semibold mb-6">Em dúvida de qual escolher?</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-10 max-w-xl mx-auto">Deixe nossa equipe criar uma rota detalhada para mapear toda falha atual na sua aquisição digital.</p>
|
||||||
|
<Link to="/contact" className="inline-flex items-center gap-2 bg-white text-black px-8 py-4 rounded-full text-lg font-medium hover:bg-gray-200 transition-colors">
|
||||||
|
Solicitar Auditoria <ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
Template-01/tsconfig.json
Normal file
26
Template-01/tsconfig.json
Normal 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": {
|
||||||
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"noEmit": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Template-01/vite.config.ts
Normal file
24
Template-01/vite.config.ts
Normal 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, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
20
Template-02/README.md
Normal file
20
Template-02/README.md
Normal 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/19204f35-4c61-4401-a9fe-63973c4f3159
|
||||||
|
|
||||||
|
## 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`
|
||||||
14
Template-02/index.html
Normal file
14
Template-02/index.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><circle cx=%2250%22 cy=%2250%22 r=%2250%22 fill=%22black%22/><text y=%22.9em%22 font-size=%2290%22 text-anchor=%22middle%22 x=%2250%22 fill=%22white%22 font-family=%22sans-serif%22 font-weight=%22bold%22>O</text></svg>" />
|
||||||
|
<title>Onyx Growth | Aceleração Digital</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
6
Template-02/metadata.json
Normal file
6
Template-02/metadata.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "Agência Onyx",
|
||||||
|
"description": "Agência de Marketing Digital e Growth focada em otimização de faturamento.",
|
||||||
|
"requestFramePermissions": [],
|
||||||
|
"majorCapabilities": []
|
||||||
|
}
|
||||||
6369
Template-02/package-lock.json
generated
Normal file
6369
Template-02/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
42
Template-02/package.json
Normal file
42
Template-02/package.json
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"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",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"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-markdown": "^10.1.0",
|
||||||
|
"react-router-dom": "^7.15.0",
|
||||||
|
"recharts": "^3.8.1",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
|
"tailwind-merge": "^3.5.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"
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Template-02/src/App.tsx
Normal file
18
Template-02/src/App.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
import Layout from './components/Layout';
|
||||||
|
import AnimatedRoutes from './components/AnimatedRoutes';
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
return (
|
||||||
|
<Router>
|
||||||
|
<Layout>
|
||||||
|
<AnimatedRoutes />
|
||||||
|
</Layout>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
30
Template-02/src/components/AnimatedRoutes.tsx
Normal file
30
Template-02/src/components/AnimatedRoutes.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Routes, Route, useLocation } from 'react-router-dom';
|
||||||
|
import { AnimatePresence } from 'motion/react';
|
||||||
|
import Home from '../pages/Home';
|
||||||
|
import Services from '../pages/Services';
|
||||||
|
import Cases from '../pages/Cases';
|
||||||
|
import About from '../pages/About';
|
||||||
|
import Blog from '../pages/Blog';
|
||||||
|
import BlogPost from '../pages/BlogPost';
|
||||||
|
import Contact from '../pages/Contact';
|
||||||
|
import NotFound from '../pages/NotFound';
|
||||||
|
import PageTransition from './PageTransition';
|
||||||
|
|
||||||
|
export default function AnimatedRoutes() {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnimatePresence mode="wait" onExitComplete={() => window.scrollTo(0, 0)}>
|
||||||
|
<Routes location={location} key={location.pathname}>
|
||||||
|
<Route path="/" element={<PageTransition><Home /></PageTransition>} />
|
||||||
|
<Route path="/services" element={<PageTransition><Services /></PageTransition>} />
|
||||||
|
<Route path="/cases" element={<PageTransition><Cases /></PageTransition>} />
|
||||||
|
<Route path="/about" element={<PageTransition><About /></PageTransition>} />
|
||||||
|
<Route path="/blog" element={<PageTransition><Blog /></PageTransition>} />
|
||||||
|
<Route path="/blog/:slug" element={<PageTransition><BlogPost /></PageTransition>} />
|
||||||
|
<Route path="/contact" element={<PageTransition><Contact /></PageTransition>} />
|
||||||
|
<Route path="*" element={<PageTransition><NotFound /></PageTransition>} />
|
||||||
|
</Routes>
|
||||||
|
</AnimatePresence>
|
||||||
|
);
|
||||||
|
}
|
||||||
108
Template-02/src/components/Footer.tsx
Normal file
108
Template-02/src/components/Footer.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
const footerLinks = {
|
||||||
|
systems: [
|
||||||
|
{ name: 'Tráfego Pago Máximo', path: '/services' },
|
||||||
|
{ name: 'SEO & Conteúdo Escalonável', path: '/services' },
|
||||||
|
{ name: 'CRO & Design Orientado', path: '/services' },
|
||||||
|
{ name: 'Engenharia de Vendas', path: '/services' },
|
||||||
|
],
|
||||||
|
nexus: [
|
||||||
|
{ name: 'A Agência', path: '/about' },
|
||||||
|
{ name: 'Nosso Portfólio', path: '/cases' },
|
||||||
|
{ name: 'Blog e Estratégias', path: '/blog' },
|
||||||
|
{ name: 'Fale com Especialista', path: '/contact' },
|
||||||
|
],
|
||||||
|
network: [
|
||||||
|
{ name: 'Instagram', path: '#' },
|
||||||
|
{ name: 'LinkedIn', path: '#' },
|
||||||
|
{ name: 'Podcast', path: '#' },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<footer className="bg-black text-white pt-24 pb-12 border-t border-white/10 relative overflow-hidden">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl relative z-10">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-12 gap-16 lg:gap-8 mb-24">
|
||||||
|
|
||||||
|
{/* Brand Col */}
|
||||||
|
<div className="lg:col-span-5 flex flex-col items-start pr-0 lg:pr-12">
|
||||||
|
<Link to="/" className="mb-8 flex items-center gap-2 group">
|
||||||
|
<span className="font-display font-bold text-2xl tracking-tighter text-white">
|
||||||
|
ONYX
|
||||||
|
</span>
|
||||||
|
<div className="w-1.5 h-1.5 bg-white rounded-full ml-1" />
|
||||||
|
</Link>
|
||||||
|
<p className="font-sans text-gray-500 text-sm leading-relaxed mb-10 max-w-sm">
|
||||||
|
Marketing Digital centrado em engenharia e receita para empresas exigentes e escaláveis.
|
||||||
|
</p>
|
||||||
|
<div className="flex bg-transparent border-b border-white/20 w-full max-w-sm p-1 focus-within:border-white transition-colors">
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
placeholder="Receber nossa Newsletter"
|
||||||
|
className="bg-transparent border-none text-white px-2 py-2 w-full focus:outline-none placeholder:text-gray-700 font-mono text-xs uppercase tracking-widest"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="text-gray-400 hover:text-white px-4 py-2 transition-all flex text-xs font-mono items-center uppercase tracking-widest"
|
||||||
|
>
|
||||||
|
Assinar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Links Cols */}
|
||||||
|
<div className="lg:col-span-2 lg:col-start-7">
|
||||||
|
<h4 className="text-[10px] uppercase tracking-widest text-white/40 font-mono font-bold mb-6">Soluções</h4>
|
||||||
|
<ul className="space-y-4 text-sm font-sans">
|
||||||
|
{footerLinks.systems.map((link) => (
|
||||||
|
<li key={link.name}>
|
||||||
|
<Link to={link.path} className="text-gray-500 hover:text-white transition-colors">
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<h4 className="text-[10px] uppercase tracking-widest text-white/40 font-mono font-bold mb-6">Agência</h4>
|
||||||
|
<ul className="space-y-4 text-sm font-sans">
|
||||||
|
{footerLinks.nexus.map((link) => (
|
||||||
|
<li key={link.name}>
|
||||||
|
<Link to={link.path} className="text-gray-500 hover:text-white transition-colors">
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="lg:col-span-2">
|
||||||
|
<h4 className="text-[10px] uppercase tracking-widest text-white/40 font-mono font-bold mb-6">Social</h4>
|
||||||
|
<ul className="space-y-4 text-sm font-sans">
|
||||||
|
{footerLinks.network.map((link) => (
|
||||||
|
<li key={link.name}>
|
||||||
|
<a href={link.path} target="_blank" rel="noopener noreferrer" className="text-gray-500 hover:text-white transition-colors">
|
||||||
|
{link.name}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bottom */}
|
||||||
|
<div className="pt-8 border-t border-white/10 flex flex-col md:flex-row items-center justify-between gap-6 font-mono text-[10px] text-gray-600 uppercase tracking-widest">
|
||||||
|
<p>
|
||||||
|
COPYRIGHT_ {new Date().getFullYear()} // Nação Onyx
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-6">
|
||||||
|
<Link to="#" className="hover:text-gray-400 transition-colors">Privacidade</Link>
|
||||||
|
<Link to="#" className="hover:text-gray-400 transition-colors">Termos de Uso</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
56
Template-02/src/components/LanguageSelector.tsx
Normal file
56
Template-02/src/components/LanguageSelector.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
|
import { Globe, ChevronDown } from 'lucide-react';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{ code: 'pt', label: 'PT-BR' },
|
||||||
|
{ code: 'en', label: 'ENG' },
|
||||||
|
{ code: 'es', label: 'ESP' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function LanguageSelector() {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [selected, setSelected] = useState(languages[0]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
|
className="flex items-center gap-2 text-sm font-medium text-gray-400 hover:text-white transition-colors px-3 py-2 rounded-full hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<Globe className="w-4 h-4" />
|
||||||
|
{selected.label}
|
||||||
|
<ChevronDown className={cn("w-4 h-4 transition-transform", isOpen && "rotate-180")} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{isOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: 10 }}
|
||||||
|
transition={{ duration: 0.2 }}
|
||||||
|
className="absolute top-full right-0 mt-2 w-32 bg-black/90 backdrop-blur-xl border border-white/10 rounded-[16px] overflow-hidden shadow-2xl z-50 flex flex-col p-1"
|
||||||
|
>
|
||||||
|
{languages.map((lang) => (
|
||||||
|
<button
|
||||||
|
key={lang.code}
|
||||||
|
onClick={() => {
|
||||||
|
setSelected(lang);
|
||||||
|
setIsOpen(false);
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"w-full text-left px-4 py-2.5 text-sm transition-colors rounded-[12px]",
|
||||||
|
selected.code === lang.code ? "text-white font-medium bg-white/10" : "text-gray-400 hover:bg-white/5 hover:text-white"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{lang.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
Template-02/src/components/Layout.tsx
Normal file
19
Template-02/src/components/Layout.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import Navbar from './Navbar';
|
||||||
|
import Footer from './Footer';
|
||||||
|
|
||||||
|
interface LayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Layout({ children }: LayoutProps) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex flex-col bg-black text-white font-sans selection:bg-white selection:text-black">
|
||||||
|
<Navbar />
|
||||||
|
<main className="flex-1 flex flex-col relative w-full pt-16">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
242
Template-02/src/components/Navbar.tsx
Normal file
242
Template-02/src/components/Navbar.tsx
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
|
import { Menu, X, Search, ChevronRight } from 'lucide-react';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { articles } from '@/data/articles';
|
||||||
|
import LanguageSelector from './LanguageSelector';
|
||||||
|
|
||||||
|
const navLinks = [
|
||||||
|
{ name: 'Início', path: '/' },
|
||||||
|
{ name: 'Missão', path: '/about' },
|
||||||
|
{ name: 'Soluções', path: '/services' },
|
||||||
|
{ name: 'Cases', path: '/cases' },
|
||||||
|
{ name: 'Blog', path: '/blog' },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Navbar() {
|
||||||
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||||
|
const [searchOpen, setSearchOpen] = useState(false);
|
||||||
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
const location = useLocation();
|
||||||
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => setIsScrolled(window.scrollY > 10);
|
||||||
|
window.addEventListener('scroll', handleScroll);
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMobileMenuOpen(false);
|
||||||
|
setSearchOpen(false);
|
||||||
|
setSearchQuery('');
|
||||||
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchOpen) setTimeout(() => searchInputRef.current?.focus(), 100);
|
||||||
|
}, [searchOpen]);
|
||||||
|
|
||||||
|
// Prevent scroll when mobile menu is open
|
||||||
|
useEffect(() => {
|
||||||
|
if (mobileMenuOpen || searchOpen) {
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = 'unset';
|
||||||
|
}
|
||||||
|
}, [mobileMenuOpen, searchOpen]);
|
||||||
|
|
||||||
|
const searchResults = searchQuery.length > 1
|
||||||
|
? articles.filter(a =>
|
||||||
|
a.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
a.excerpt.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
a.category.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
).slice(0, 5)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header
|
||||||
|
className={cn(
|
||||||
|
'fixed inset-x-0 top-0 z-50 transition-all duration-300 border-b border-transparent',
|
||||||
|
isScrolled ? 'bg-black/80 backdrop-blur-md border-white/10 py-4' : 'bg-transparent py-4 sm:py-6'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
{/* Logo */}
|
||||||
|
<Link to="/" className="flex items-center gap-2 group">
|
||||||
|
<span className="font-display font-bold text-xl tracking-tighter text-white">
|
||||||
|
ONYX
|
||||||
|
</span>
|
||||||
|
<div className="w-1.5 h-1.5 bg-white rounded-full ml-1" />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* Desktop Nav */}
|
||||||
|
<nav className="hidden md:flex items-center gap-8">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.path}
|
||||||
|
to={link.path}
|
||||||
|
className={cn(
|
||||||
|
'text-[13px] font-mono tracking-wide uppercase transition-colors hover:text-white',
|
||||||
|
location.pathname === link.path ? 'text-white' : 'text-gray-500'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
|
<div className="flex items-center gap-3 sm:gap-4">
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<LanguageSelector />
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setSearchOpen(true)}
|
||||||
|
className="flex items-center justify-center text-gray-500 hover:text-white transition-colors w-10 h-10 rounded-full hover:bg-white/5"
|
||||||
|
>
|
||||||
|
<Search className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="hidden md:flex items-center gap-2 bg-white text-black px-5 py-2.5 rounded-none text-xs font-mono uppercase font-bold hover:bg-gray-200 transition-colors"
|
||||||
|
>
|
||||||
|
Auditoria Gratuita
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="md:hidden text-gray-400 hover:text-white flex items-center justify-center w-10 h-10"
|
||||||
|
onClick={() => setMobileMenuOpen(true)}
|
||||||
|
>
|
||||||
|
<Menu className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* Search Overlay */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{searchOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
className="fixed inset-0 z-[70] bg-black backdrop-blur-md flex items-start justify-center pt-24 px-4"
|
||||||
|
onClick={() => setSearchOpen(false)}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: -20 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: -20 }}
|
||||||
|
className="w-full max-w-2xl bg-black border border-white/10 shadow-2xl overflow-hidden flex flex-col max-h-[80vh]"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="flex items-center border-b border-white/10 px-4 py-4">
|
||||||
|
<Search className="w-5 h-5 text-gray-500 mr-3" />
|
||||||
|
<input
|
||||||
|
ref={searchInputRef}
|
||||||
|
type="text"
|
||||||
|
placeholder="Pesquisar artigos e tópicos..."
|
||||||
|
className="flex-1 bg-transparent border-none text-white focus:outline-none text-base font-mono placeholder:text-gray-700"
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => setSearchOpen(false)}
|
||||||
|
className="text-gray-500 hover:text-white p-2"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{searchQuery.length > 1 && (
|
||||||
|
<div className="overflow-y-auto flex-1 p-2">
|
||||||
|
{searchResults.length > 0 ? (
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
{searchResults.map(result => (
|
||||||
|
<Link
|
||||||
|
key={result.id}
|
||||||
|
to={`/blog/${result.slug}`}
|
||||||
|
className="flex items-center gap-4 p-4 border border-transparent hover:border-white/10 hover:bg-white/5 transition-colors group"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col flex-1 overflow-hidden">
|
||||||
|
<div className="flex items-center justify-between gap-2 mb-1">
|
||||||
|
<span className="font-sans font-medium text-white text-sm truncate">{result.title}</span>
|
||||||
|
<span className="text-[10px] text-gray-400 font-mono tracking-widest uppercase">{result.category}</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-sm text-gray-500 truncate">{result.excerpt}</span>
|
||||||
|
</div>
|
||||||
|
<ChevronRight className="w-4 h-4 text-gray-600 group-hover:text-white transition-colors" />
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="py-12 px-4 text-center border-t border-white/5">
|
||||||
|
<p className="text-gray-600 mb-2 font-mono text-sm uppercase tracking-widest">Aguardando sinais...</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
|
{/* Mobile Menu */}
|
||||||
|
<AnimatePresence>
|
||||||
|
{mobileMenuOpen && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: '-100%' }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: '-100%' }}
|
||||||
|
transition={{ type: 'spring', damping: 25, stiffness: 200 }}
|
||||||
|
className="fixed inset-0 z-[100] bg-black flex flex-col pt-20"
|
||||||
|
>
|
||||||
|
<div className="absolute top-0 inset-x-0 flex items-center justify-between p-4 sm:p-6 border-b border-white/10">
|
||||||
|
<span className="font-display font-bold text-xl tracking-tighter text-white">
|
||||||
|
ONYX
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<LanguageSelector />
|
||||||
|
<button
|
||||||
|
onClick={() => setMobileMenuOpen(false)}
|
||||||
|
className="w-10 h-10 flex items-center justify-center text-white bg-white/5 rounded-full"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex-1 py-12 px-6 flex flex-col justify-center gap-8 overflow-y-auto">
|
||||||
|
<nav className="flex flex-col gap-6">
|
||||||
|
{navLinks.map((link) => (
|
||||||
|
<Link
|
||||||
|
key={link.path}
|
||||||
|
to={link.path}
|
||||||
|
className="text-4xl font-display font-medium text-gray-400 hover:text-white transition-colors"
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div className="mt-12 pt-8 border-t border-white/10">
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="block w-full bg-white text-black px-6 py-4 text-center font-mono uppercase tracking-widest text-sm font-bold"
|
||||||
|
>
|
||||||
|
Solicitar Auditoria
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
16
Template-02/src/components/PageTransition.tsx
Normal file
16
Template-02/src/components/PageTransition.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
export default function PageTransition({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 15, filter: 'blur(10px)' }}
|
||||||
|
animate={{ opacity: 1, y: 0, filter: 'blur(0px)' }}
|
||||||
|
exit={{ opacity: 0, y: -15, filter: 'blur(10px)' }}
|
||||||
|
transition={{ duration: 0.4, ease: [0.16, 1, 0.3, 1] }}
|
||||||
|
className="flex-1 flex flex-col w-full"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
54
Template-02/src/components/SEO.tsx
Normal file
54
Template-02/src/components/SEO.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
|
||||||
|
interface SEOProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
name?: string;
|
||||||
|
type?: string;
|
||||||
|
image?: string;
|
||||||
|
url?: string;
|
||||||
|
schema?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SEO({
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
name = 'Onyx Growth',
|
||||||
|
type = 'website',
|
||||||
|
image = 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80', // Default striking image
|
||||||
|
url = 'https://onyx.com.br',
|
||||||
|
schema,
|
||||||
|
}: SEOProps) {
|
||||||
|
// Base site URL (ideally from env or constant)
|
||||||
|
const fullTitle = title.includes(name) ? title : `${title} | ${name}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Helmet>
|
||||||
|
{/* Standard metadata tags */}
|
||||||
|
<title>{fullTitle}</title>
|
||||||
|
<meta name='description' content={description} />
|
||||||
|
|
||||||
|
{/* Open Graph tags for Facebook, LinkedIn etc. shared cards */}
|
||||||
|
<meta property="og:type" content={type} />
|
||||||
|
<meta property="og:title" content={fullTitle} />
|
||||||
|
<meta property="og:description" content={description} />
|
||||||
|
<meta property="og:image" content={image} />
|
||||||
|
<meta property="og:url" content={url} />
|
||||||
|
<meta property="og:site_name" content={name} />
|
||||||
|
|
||||||
|
{/* Twitter tags */}
|
||||||
|
<meta name="twitter:creator" content={name} />
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={fullTitle} />
|
||||||
|
<meta name="twitter:description" content={description} />
|
||||||
|
<meta name="twitter:image" content={image} />
|
||||||
|
|
||||||
|
{/* JSON-LD Schema (Rich Snippets for Google) */}
|
||||||
|
{schema && (
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{JSON.stringify(schema)}
|
||||||
|
</script>
|
||||||
|
)}
|
||||||
|
</Helmet>
|
||||||
|
);
|
||||||
|
}
|
||||||
86
Template-02/src/data/articles.ts
Normal file
86
Template-02/src/data/articles.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
export const articles = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
slug: "guia-seo-2026",
|
||||||
|
title: "O Guia Definitivo sobre SEO em 2026",
|
||||||
|
category: "SEO",
|
||||||
|
readTime: "8 min de leitura",
|
||||||
|
date: "12 de Maio, 2026",
|
||||||
|
color: "from-blue-600/30 to-transparent",
|
||||||
|
featured: true,
|
||||||
|
author: "Equipe Onyx",
|
||||||
|
excerpt: "Descubra as táticas secretas e estratégias avançadas de SEO que as maiores empresas do mercado estão utilizando para dominar seus nichos em 2026.",
|
||||||
|
imageUrl: "https://images.unsplash.com/photo-1432821596592-e2c18b78144f?auto=format&fit=crop&q=80",
|
||||||
|
content: "\n# O Guia Definitivo sobre SEO em 2026\n\nO mercado mudou drasticamente. O que funcionava no passado em relação a SEO já não traz os mesmos resultados hoje. Neste artigo, desconstruímos as táticas obsoletas e revelamos frameworks de alto nível.\n\n## Por que você está perdendo ROI?\n\nA maioria das empresas opera com o manual de 2023. Em um cenário impulsionado por inteligência artificial e decisões baseadas em modelagem preditiva, quem não adapta rapidamente a sua estratégia corre um sério risco.\n\n> \"A velocidade de implementação de novas táticas de SEO é hoje a métrica mais importante de uma equipe de growth corporativa.\"\n\n### 3 Táticas Imediatas\n\n1. **Rever a Arquitetura de Conversão**: Seu funil atual está vazando capital, principalmente na primeira interação de seu Design focado em Conversão.\n2. **Implementar Automações Modulares**: Ferramentas engessadas estão matando o seu CAC em Performance Ads.\n3. **Escalar Conteúdo com Critério**: Mais não significa melhor. Utilize semântica e intenção real de busca.\n\nComece rodando uma auditoria técnica profunda. O foco deve ser levantar todos os dados ocultos das últimas campanhas e alinhar à nova visão macro do mercado.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
slug: "engenharia-prompt-growth",
|
||||||
|
title: "Como a Engenharia de Prompt Revolucionou o Growth",
|
||||||
|
category: "AI",
|
||||||
|
readTime: "6 min de leitura",
|
||||||
|
date: "10 de Maio, 2026",
|
||||||
|
color: "from-purple-600/30 to-transparent",
|
||||||
|
featured: false,
|
||||||
|
author: "Elena Rostova",
|
||||||
|
excerpt: "Entenda por que saber falar com as máquinas tornou-se a habilidade mais lucrativa para os profissionais de marketing e Growth Hackers modernos.",
|
||||||
|
imageUrl: "https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&q=80",
|
||||||
|
content: "\n# A Engenharia de Prompt como Diferencial Competitivo\n\nA inteligência artificial não substituiu estratégias, ela as potencializou. O segredo deixou de ser \"qual IA usar\" para \"como direcionar a IA\". Notamos que clientes que integram prompts avançados em suas operações de Ads experimentam uma queda de até 40% no CAC.\n\n## Do Zero ao Especialista\n\nUma instrução fraca gera resultados medíocres. Por exemplo, ao gerar copy para tráfego pago, um prompt como \"Escreva um anúncio de sapato\" não serve. O cenário muda quando aplicamos **Frameworks de Conversão**:\n\n> \"Atue como um Copywriter nível AAA de resposta direta. Escreva 3 variações de anúncios para o Facebook Ads focadas em [público-alvo], destacando o [benefício principal] usando o framework PAS (Problem, Agitation, Solution).\"\n\nEste é o padrão ouro na criação de ativos digitais otimizados.\n\n### Acelerando Processos\n\n1. Estruture a voz da marca através de exemplos.\n2. Defina os limites do modelo para evitar alucinações.\n3. Teste A/B as saídas geradas com suas variações manuais.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
slug: "design-conversivo-psicologia",
|
||||||
|
title: "Design Conversivo: A Psicologia por Trás das Cores",
|
||||||
|
category: "Design",
|
||||||
|
readTime: "7 min de leitura",
|
||||||
|
date: "08 de Maio, 2026",
|
||||||
|
color: "from-pink-600/30 to-transparent",
|
||||||
|
featured: false,
|
||||||
|
author: "Julian Vance",
|
||||||
|
excerpt: "Muito além da estética: descubra como gatilhos visuais e escolhas cromáticas corretas podem aumentar o seu ticket médio na primeira sessão.",
|
||||||
|
imageUrl: "https://images.unsplash.com/photo-1541462608143-67571c6738dd?auto=format&fit=crop&q=80",
|
||||||
|
content: "\n# Estética com Propósito Financeiro\n\nO erro número um de Design B2B e B2C é focar apenas em deixar o site \"bonito\". Design sem um objetivo financeiro é apenas arte. Implementamos Design Conversivo.\n\n## O Que a Ciência Afirma\n\nEstudos indicam que os consumidores julgam um ambiente online em menos de 90 milissegundos. Cores ditam emoções.\n\n- **Azul Escuro**: Confiança, estabilidade (bancos e SaaS B2B usam).\n- **Laranja/Vermelho Pálido**: Urgência contida, chamadas para ação iminentes.\n- **Preto e Dourado/Prata**: Exclusividade, ticket alto, sofisticação.\n\n> \"A função primária do design de interface é remover a fricção cognitiva entre o desejo do usuário e a ação de compra.\"\n\n## Aplicando na Prática\n\nRevise os botões do seu site. Se o botão de assinatura tem a mesma cor de elementos não clicáveis do site, você está confundindo o cérebro límbico do visitante. O **Ponto Focal** deve guiar a visão imediatamente assim que o site carrega.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
slug: "escalando-campanhas-um-milhao",
|
||||||
|
title: "Tráfego Pago: Escalando Campanhas de US$ 1 Milhão",
|
||||||
|
category: "Ads",
|
||||||
|
readTime: "12 min de leitura",
|
||||||
|
date: "05 de Maio, 2026",
|
||||||
|
color: "from-green-600/30 to-transparent",
|
||||||
|
featured: true,
|
||||||
|
author: "Marcus Void",
|
||||||
|
excerpt: "Escalar orçamento não é simplesmente aumentar investimento diário. O processo de expansão orçamentária sem perder o ROI é brutalmente técnico.",
|
||||||
|
imageUrl: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80",
|
||||||
|
content: "\n# Como Não Queimar Seu Orçamento \n\nSe você já apertou o botão de aumentar budget de uma campanha validada e viu as métricas desabarem em dois dias, bem vindo ao caos da fase de expansão. Campanhas que rodam estagnadas em orçamentos pequenos não sofrem os mesmos choques de oferta que escalas maciças impõem.\n\n## A Dinâmica de Escala Vertical vs Horizontal\n\nQuando você está buscando escala agressiva via Tráfego Pago, você se depara com a fadiga criativa. É matemática básica: você entra em leilões mais caros porque esgota o público primário.\n\n### Nossos Pilares de Escala:\n\n1. **Volume Bruto de Criativos**: O segredo não é achar o criativo perfeito, e sim alimentar o algoritmo constantemente.\n2. **Account Consolidation**: Contas com 50 campanhas morrem. Consolidamos o máximo de sinal em 3 a 4 campanhas principais para dar lastro à IA da plataforma.\n3. **Escala Horizontal Geográfica ou de Oferta**: Mantemos o budget vertical controlado enquanto abrimos novas avenidas na horizontal.\n\nNão é sobre gastar mais, é sobre comprar dados de altíssima qualidade de forma progressiva.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
slug: "seo-tecnico-ecommerce",
|
||||||
|
title: "SEO Técnico para E-commerce: Auditoria Completa",
|
||||||
|
category: "SEO",
|
||||||
|
readTime: "9 min de leitura",
|
||||||
|
date: "03 de Maio, 2026",
|
||||||
|
color: "from-orange-600/30 to-transparent",
|
||||||
|
featured: false,
|
||||||
|
author: "Julian Vance",
|
||||||
|
excerpt: "Lojas virtuais com milhares de URLs param de rankear do dia pra noite. A raiz do problema geralmente é facetas, canonicalização ou crawl budget.",
|
||||||
|
imageUrl: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80",
|
||||||
|
content: "\n# O Pesadelo das URLs Duplicadas em E-commerce\n\nEstruturas complexas de categoria, juntamente com filtros e parâmetros de ordenação, transformam uma loja pequena de 500 produtos em um monstro com 50.000 URLs rastreáveis. Isso dilui o poder do seu site e esmaga o crawl budget cedido pelo Google.\n\nO cenário padrão em nossos clientes que faturam milhões é quase sempre de estrangulamento técnico.\n\n## Os 3 Passos da Limpeza Técnica\n\n1. **Domando Parâmetros Facetados**: Use estruturação correta e tags `noindex` adequadamente para filtros de preço e cor que não possuem volume de busca orgânico.\n2. **Canonical Tags Otimizadas**: Garanta que as variações apontem para a URL principal do produto.\n3. **Renderização de JavaScript**: Muitas lojas em frameworks blockeiam rastreadores por erro de configuração no SSR (Server-Side Rendering). \n\nOtimizar um E-commerce é um processo contínuo de varredura.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
slug: "cro-testes-ab",
|
||||||
|
title: "CRO e Testes A/B: Pequenas Mudanças, Grandes Ganhos",
|
||||||
|
category: "Growth",
|
||||||
|
readTime: "5 min de leitura",
|
||||||
|
date: "01 de Maio, 2026",
|
||||||
|
color: "from-teal-600/30 to-transparent",
|
||||||
|
featured: true,
|
||||||
|
author: "Equipe Onyx",
|
||||||
|
excerpt: "Otimização de Taxa de Conversão pode significar dobrar a lucratividade sem gastar um centavo a mais em anúncios.",
|
||||||
|
imageUrl: "https://images.unsplash.com/photo-1551434678-e076c223a692?auto=format&fit=crop&q=80",
|
||||||
|
content: "\n# Por que você ignora o CRO?\n\nTodos querem mais tráfego, poucos querem otimizar quem já entra na porta. CRO (Conversion Rate Optimization) é o pilar escondido dos maiores resultados no digital.\n\n> \"Aumentar a conversão da sua landing page principal de 2% para 4% reduz o custo por lead pela metade. Imediatamente.\"\n\nO ciclo de testes que executamos em nossos clientes:\n- Hipótese baseada em Heatmaps da ferramenta de Analytics.\n- Implementação assíncrona (A/B) de variações no CTA ou Hero Section.\n- Computação de significância estatística de > 95%.\n- Implementação definitiva e reinício do loop.\n"
|
||||||
|
}
|
||||||
|
];
|
||||||
71
Template-02/src/index.css
Normal file
71
Template-02/src/index.css
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
|
||||||
|
@import "tailwindcss";
|
||||||
|
@plugin "@tailwindcss/typography";
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-background: #000000;
|
||||||
|
--color-foreground: #ffffff;
|
||||||
|
--color-muted: #888888;
|
||||||
|
--color-border: rgba(255, 255, 255, 0.1);
|
||||||
|
--color-accent: #ffffff;
|
||||||
|
|
||||||
|
--font-sans: "Inter", system-ui, sans-serif;
|
||||||
|
--font-display: "Space Grotesk", sans-serif;
|
||||||
|
--font-mono: "JetBrains Mono", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
color: var(--color-foreground);
|
||||||
|
font-family: theme('fontFamily.sans');
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-gradient {
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-image: linear-gradient(to right, #ffffff, #666666);
|
||||||
|
}
|
||||||
|
|
||||||
|
.glass-panel {
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-lift {
|
||||||
|
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.4s ease, border-color 0.4s ease;
|
||||||
|
}
|
||||||
|
.hover-lift:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
background-color: rgba(255, 255, 255, 0.04);
|
||||||
|
border-color: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: #333333;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #555555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid background utility */
|
||||||
|
.bg-grid-pattern {
|
||||||
|
background-image: linear-gradient(to right, rgba(255,255,255,0.05) 1px, transparent 1px),
|
||||||
|
linear-gradient(to bottom, rgba(255,255,255,0.05) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
}
|
||||||
6
Template-02/src/lib/utils.ts
Normal file
6
Template-02/src/lib/utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { clsx, type ClassValue } from "clsx";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs));
|
||||||
|
}
|
||||||
13
Template-02/src/main.tsx
Normal file
13
Template-02/src/main.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import {StrictMode} from 'react';
|
||||||
|
import {createRoot} from 'react-dom/client';
|
||||||
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
|
import App from './App.tsx';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
createRoot(document.getElementById('root')!).render(
|
||||||
|
<StrictMode>
|
||||||
|
<HelmetProvider>
|
||||||
|
<App />
|
||||||
|
</HelmetProvider>
|
||||||
|
</StrictMode>,
|
||||||
|
);
|
||||||
135
Template-02/src/pages/About.tsx
Normal file
135
Template-02/src/pages/About.tsx
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
const founders = [
|
||||||
|
{
|
||||||
|
name: "Marcus Void",
|
||||||
|
role: "CEO / Head de Estratégia",
|
||||||
|
image: "https://images.unsplash.com/photo-1542744173-8e7e53415bb0?auto=format&fit=crop&q=80",
|
||||||
|
bio: "Estrategista com +10 anos guiando expansão de Startups B2B através de modelagem de CAC e Growth Loops."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Elena Rostova",
|
||||||
|
role: "Diretora de Performance & Tech",
|
||||||
|
image: "https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&q=80",
|
||||||
|
bio: "Pioneira na integração de Server-Side Tracking e arquiteturas maduras de mídia paga para contas globais."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Julian Vance",
|
||||||
|
role: "Líder de Operações Orgânicas",
|
||||||
|
image: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80",
|
||||||
|
bio: "Especialista em SEO Técnico e ranqueamento avançado, alavancando milhões em faturamento orgânico isento de anúncios."
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function About() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full text-white bg-black min-h-screen">
|
||||||
|
<SEO
|
||||||
|
title="O Studio | Agência Onyx"
|
||||||
|
description="Nossas metodologias e cultura de alta performance voltadas para marketing e crescimento."
|
||||||
|
url="https://agencia-onyx.com/about"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* HERO */}
|
||||||
|
<section className="pt-40 pb-20 px-6 relative z-10">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<div className="max-w-4xl">
|
||||||
|
<span className="text-[10px] uppercase font-bold tracking-[0.2em] text-gray-500 mb-6 block font-mono">
|
||||||
|
[03] O STUDIO DE GROWTH
|
||||||
|
</span>
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-5xl sm:text-7xl md:text-8xl font-display font-medium tracking-tighter mb-8 leading-[0.95]"
|
||||||
|
>
|
||||||
|
PRECISÃO <br />
|
||||||
|
<span className="text-gray-500">ALGORÍTMICA.</span>
|
||||||
|
</motion.h1>
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-xl md:text-2xl text-gray-400 max-w-2xl font-sans leading-relaxed"
|
||||||
|
>
|
||||||
|
Uma agência de alta performance para a nova economia. Rejeitamos pacotes padronizados para focar exclusivamente em otimização agressiva de receita.
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* TEXT/ESSAYS */}
|
||||||
|
<section className="py-24 border-t border-white/10 relative z-10 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-5xl">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-16">
|
||||||
|
<div className="prose prose-lg prose-invert prose-p:text-gray-400 prose-p:leading-relaxed font-sans">
|
||||||
|
<h2 className="text-3xl font-display text-white mb-6">Criado pra Escala. Desenhado pra Impacto.</h2>
|
||||||
|
<p>
|
||||||
|
A internet moderna foi invadida por ruído genérico e táticas amadoras de marketing. Acreditamos que velocidade de implementação, rastreamento impecável e mídia focada em lucros são as reais moedas de valor.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
O modelo da Onyx repudia o "marketing de esperança". Nós implantamos operações de funil metódicas, combinando Tráfego Pago impulsionado por máquinas, metodologias rígidas de SEO e laboratórios de CRO (Conversion Rate Optimization).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="border border-white/10 bg-white/5 p-12 flex flex-col justify-center">
|
||||||
|
<p className="text-2xl font-display text-white leading-snug mb-8">
|
||||||
|
"Em uma economia dominada por custo de aquisição (CAC), focar somente em vaidade significa sangrar até o fim."
|
||||||
|
</p>
|
||||||
|
<span className="font-mono text-[10px] uppercase tracking-widest text-gray-500">/// Onyx Board</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* LEADERSHIP */}
|
||||||
|
<section className="py-32 border-t border-white/10 z-10 bg-black relative">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="mb-20">
|
||||||
|
<h2 className="text-4xl md:text-5xl font-display text-white tracking-tighter">DIRETORIA.</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-[1px] bg-white/10 border border-white/10">
|
||||||
|
{founders.map((founder, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={founder.name}
|
||||||
|
initial={{ opacity: 0, y: 30 }}
|
||||||
|
whileInView={{ opacity: 1, y: 0 }}
|
||||||
|
viewport={{ once: true, margin: "-100px" }}
|
||||||
|
transition={{ delay: i * 0.2 }}
|
||||||
|
className="bg-black p-8 hover:bg-white/5 transition-colors group"
|
||||||
|
>
|
||||||
|
<div className="w-full aspect-[4/5] mb-6 bg-white/5 overflow-hidden border border-white/10 relative grayscale group-hover:grayscale-0 transition-all duration-700">
|
||||||
|
<img src={founder.image} alt={founder.name} className="absolute inset-0 w-full h-full object-cover opacity-60 mix-blend-luminosity group-hover:mix-blend-normal group-hover:opacity-100 group-hover:scale-105 transition-all duration-700" />
|
||||||
|
</div>
|
||||||
|
<div className="font-mono text-[10px] uppercase tracking-widest text-gray-400 mb-3 block">{founder.role}</div>
|
||||||
|
<h3 className="text-2xl font-display text-white mb-3">{founder.name}</h3>
|
||||||
|
<p className="text-gray-500 text-sm leading-relaxed font-sans">{founder.bio}</p>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<section className="py-32 border-t border-white/10 relative z-10 text-center bg-black border-b">
|
||||||
|
<div className="container mx-auto px-6 max-w-3xl">
|
||||||
|
<h2 className="text-4xl md:text-5xl font-display font-medium text-white mb-6 tracking-tighter">INICIE O PROJETO</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-10 max-w-xl mx-auto font-sans">Submeta a operação da sua empresa para auditoria direta da nossa inteligência.</p>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="inline-flex items-center justify-center bg-white text-black px-10 py-5 font-mono text-sm uppercase tracking-widest font-bold hover:bg-gray-200 transition-colors"
|
||||||
|
>
|
||||||
|
Falar com Especialistas
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
141
Template-02/src/pages/Blog.tsx
Normal file
141
Template-02/src/pages/Blog.tsx
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ChevronRight, Activity } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { articles } from '@/data/articles';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function Blog() {
|
||||||
|
const featuredArticle = articles.find(a => a.featured) || articles[0];
|
||||||
|
const otherArticles = articles.filter(a => a.id !== featuredArticle.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 pb-24 text-white bg-black">
|
||||||
|
<SEO
|
||||||
|
title="Blog | Agência Onyx"
|
||||||
|
description="Leia nossas reflexões técnicas e estratégias de Marketing Digital."
|
||||||
|
url="https://agencia-onyx.com/blog"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl relative z-10">
|
||||||
|
|
||||||
|
{/* HEADER */}
|
||||||
|
<div className="border-b border-white/10 pb-12 mb-16 flex flex-col md:flex-row justify-between items-start md:items-end gap-12 bg-black/50">
|
||||||
|
<div className="max-w-3xl">
|
||||||
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 border border-white/20 bg-white/5 text-gray-300 text-[10px] font-mono uppercase tracking-widest mb-6">
|
||||||
|
<Activity className="w-3 h-3 animate-pulse text-white" /> Diretório de Estratégias
|
||||||
|
</div>
|
||||||
|
<h1 className="text-5xl md:text-8xl font-display font-medium tracking-tighter mb-6 leading-[0.95]">
|
||||||
|
ONYX <br/> <span className="text-gray-500">LAB.</span>
|
||||||
|
</h1>
|
||||||
|
<p className="font-sans text-xl text-gray-400 leading-relaxed max-w-xl">
|
||||||
|
Táticas algorítmicas documentadas. Relatórios de marketing focados em redução de atrito e aumento de receita.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="hidden md:flex flex-col gap-2 font-mono text-[10px] uppercase tracking-widest text-gray-500 text-right">
|
||||||
|
<span className="text-white">STATUS: ONLINE</span>
|
||||||
|
<span>UPLINK: ATIVO</span>
|
||||||
|
<span>ORDENAÇÃO: MAIS RECENTES</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* FEATURED */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="mb-24 group"
|
||||||
|
>
|
||||||
|
<Link to={`/blog/${featuredArticle.slug}`} className="grid grid-cols-1 lg:grid-cols-12 gap-0 items-center bg-black border border-white/10 transition-colors hover:bg-white/5">
|
||||||
|
<div className="lg:col-span-7 w-full aspect-[4/3] lg:aspect-auto lg:h-[500px] bg-white/5 relative border-b lg:border-b-0 lg:border-r border-white/10 grayscale group-hover:grayscale-0 transition-all duration-700">
|
||||||
|
<img
|
||||||
|
src={featuredArticle.imageUrl}
|
||||||
|
alt={featuredArticle.title}
|
||||||
|
className="absolute inset-0 w-full h-full object-cover opacity-60 group-hover:opacity-100 transition-opacity duration-700 mix-blend-luminosity hover:mix-blend-normal"
|
||||||
|
/>
|
||||||
|
<div className="absolute top-6 left-6 bg-black border border-white/20 px-3 py-1 text-[10px] uppercase font-bold tracking-widest text-white font-mono shadow-[0_0_20px_rgba(255,255,255,0.1)]">
|
||||||
|
ARTIGO PRINCIPAL
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="lg:col-span-5 p-8 lg:p-12 flex flex-col justify-center h-full">
|
||||||
|
<div className="flex items-center gap-3 text-[10px] uppercase tracking-widest text-gray-400 mb-6 font-mono">
|
||||||
|
<span className="text-white border border-white/20 bg-white/5 px-2 py-1">{featuredArticle.category}</span>
|
||||||
|
<span className="border border-white/10 px-2 py-1 text-gray-500">{featuredArticle.date}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="text-3xl lg:text-4xl font-display leading-tight mb-4 text-white">
|
||||||
|
{featuredArticle.title}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p className="font-sans text-gray-400 mb-8 line-clamp-3 leading-relaxed">
|
||||||
|
{featuredArticle.excerpt}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<span className="inline-flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest text-white font-mono mt-auto group-hover:text-gray-300 transition-colors">
|
||||||
|
Acessar Estudo <ChevronRight className="w-4 h-4 ml-1" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
{/* GRID */}
|
||||||
|
<div>
|
||||||
|
<div className="flex justify-between items-end mb-12 border-b border-white/10 pb-4">
|
||||||
|
<h3 className="text-2xl font-display font-medium tracking-tight">Arquivos</h3>
|
||||||
|
<span className="text-[10px] font-mono text-gray-500 uppercase tracking-widest">ORDENAR: DATA</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[1px] bg-white/10 border border-white/10">
|
||||||
|
{otherArticles.map((article, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={article.id}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: (index % 3) * 0.1 }}
|
||||||
|
className="bg-black p-6 group hover:bg-white/5 transition-colors flex flex-col h-full"
|
||||||
|
>
|
||||||
|
<Link to={`/blog/${article.slug}`} className="flex flex-col h-full flex-1">
|
||||||
|
<div className="w-full aspect-[4/3] bg-white/5 mb-6 overflow-hidden relative border border-white/10 grayscale group-hover:grayscale-0 transition-all duration-700">
|
||||||
|
{article.imageUrl && (
|
||||||
|
<img
|
||||||
|
src={article.imageUrl}
|
||||||
|
alt={article.title}
|
||||||
|
className="absolute inset-0 w-full h-full object-cover opacity-50 mix-blend-luminosity group-hover:mix-blend-normal group-hover:opacity-100 group-hover:scale-105 transition-all duration-700"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col flex-1">
|
||||||
|
<div className="flex flex-wrap items-center gap-2 text-[10px] uppercase tracking-widest text-gray-500 font-mono mb-4">
|
||||||
|
<span className="text-white bg-white/5 px-2 py-0.5 border border-white/20">{article.category}</span>
|
||||||
|
<span className="border border-white/10 px-2 py-0.5">{article.date}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 className="text-xl font-display font-medium text-white leading-snug mb-3">
|
||||||
|
{article.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p className="text-sm text-gray-500 mb-6 flex-1 line-clamp-3 font-sans">
|
||||||
|
{article.excerpt}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap items-center justify-between mt-auto pt-4 border-t border-white/10">
|
||||||
|
<span className="text-[10px] uppercase font-mono tracking-widest text-gray-500">Autor: <span className="text-gray-300">{article.author}</span></span>
|
||||||
|
<span className="text-[10px] uppercase font-mono tracking-widest text-white border border-white/20 bg-white/5 px-2 py-0.5">{article.readTime}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
99
Template-02/src/pages/BlogPost.tsx
Normal file
99
Template-02/src/pages/BlogPost.tsx
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowLeft, Clock, Calendar, ChevronRight, Cpu } from 'lucide-react';
|
||||||
|
import { Link, useParams } from 'react-router-dom';
|
||||||
|
import { articles } from '@/data/articles';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
import Markdown from 'react-markdown';
|
||||||
|
|
||||||
|
export default function BlogPost() {
|
||||||
|
const { slug } = useParams();
|
||||||
|
const article = articles.find(a => a.slug === slug) || articles[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen pt-32 pb-24 text-white bg-black">
|
||||||
|
<SEO
|
||||||
|
title={`${article.title} | Agência Onyx`}
|
||||||
|
description={article.excerpt}
|
||||||
|
url={`https://agencia-onyx.com/blog/${article.slug}`}
|
||||||
|
imageUrl={article.imageUrl}
|
||||||
|
type="article"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article className="container mx-auto px-6 max-w-4xl relative z-10">
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/blog"
|
||||||
|
className="inline-flex items-center gap-2 text-[10px] font-mono uppercase tracking-widest text-gray-500 hover:text-white transition-colors mb-16"
|
||||||
|
>
|
||||||
|
<ArrowLeft className="w-4 h-4" />
|
||||||
|
Voltar ao Blog
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{/* HEADER */}
|
||||||
|
<header className="mb-16 border-b border-white/10 pb-16">
|
||||||
|
<div className="flex flex-wrap items-center gap-4 text-[10px] font-bold uppercase tracking-widest font-mono text-gray-500 mb-8">
|
||||||
|
<span className="text-white border border-white/20 bg-white/5 px-3 py-1">{article.category}</span>
|
||||||
|
<span className="flex items-center gap-2 border border-white/10 px-3 py-1 bg-black"><Calendar className="w-3 h-3" /> {article.date}</span>
|
||||||
|
<span className="flex items-center gap-2 border border-white/10 px-3 py-1 bg-black"><Clock className="w-3 h-3" /> {article.readTime}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-4xl md:text-6xl font-display leading-[1.1] text-white mb-8 tracking-tighter"
|
||||||
|
>
|
||||||
|
{article.title}
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ delay: 0.2 }}
|
||||||
|
className="text-[10px] font-mono mt-8 text-gray-500 flex items-center gap-3 uppercase tracking-widest"
|
||||||
|
>
|
||||||
|
<div className="w-8 h-8 border border-white/10 bg-white/5 flex items-center justify-center text-white"><Cpu className="w-4 h-4"/></div>
|
||||||
|
Escrito por: <span className="text-white font-bold">{article.author}</span>
|
||||||
|
</motion.div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* FEATURE IMAGE */}
|
||||||
|
{article.imageUrl && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
|
className="w-full aspect-[21/9] bg-white/5 mb-20 overflow-hidden border border-white/10 relative grayscale"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={article.imageUrl}
|
||||||
|
alt={article.title}
|
||||||
|
className="absolute inset-0 w-full h-full object-cover opacity-60 mix-blend-luminosity"
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* CONTENT */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8, delay: 0.2 }}
|
||||||
|
className="prose prose-lg prose-invert prose-headings:font-display prose-headings:font-medium prose-h1:text-4xl prose-h2:text-3xl prose-h3:text-2xl prose-h1:tracking-tight prose-h2:tracking-tight prose-a:text-white prose-a:underline prose-a:underline-offset-4 prose-p:text-gray-400 prose-p:leading-relaxed prose-p:font-sans prose-blockquote:border-l-2 prose-blockquote:border-white/20 prose-blockquote:bg-white/5 prose-blockquote:px-6 prose-blockquote:py-4 prose-blockquote:font-sans max-w-none"
|
||||||
|
>
|
||||||
|
<div className="text-xl text-gray-300 mb-12 leading-relaxed bg-white/5 p-8 border border-white/10 font-sans tracking-wide relative">
|
||||||
|
<div className="absolute top-0 left-0 w-2 h-full bg-white/20" />
|
||||||
|
<span className="block text-[10px] uppercase font-mono tracking-widest text-gray-500 mb-4">[RESUMO EXECUTIVO]</span>
|
||||||
|
{article.excerpt}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="markdown-body font-sans text-gray-400">
|
||||||
|
<Markdown>{article.content}</Markdown>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
122
Template-02/src/pages/Cases.tsx
Normal file
122
Template-02/src/pages/Cases.tsx
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowUpRight } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
const cases = [
|
||||||
|
{
|
||||||
|
id: "fintech-scale",
|
||||||
|
title: "Escala Brutal de CAC",
|
||||||
|
client: "Fintech B2B",
|
||||||
|
metrics: ["+140% Conversão", "CAC -32%", "Google Ads"],
|
||||||
|
category: "Ads / Landing Pages",
|
||||||
|
image: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ecom-growth",
|
||||||
|
title: "Máquina Geradora de LTV",
|
||||||
|
client: "E-Commerce Global",
|
||||||
|
metrics: ["R$ 15M Recuperados", "SEO Técnico", "CRO Checkout"],
|
||||||
|
category: "SEO / CRO",
|
||||||
|
image: "https://images.unsplash.com/photo-1541462608143-67571c6738dd?auto=format&fit=crop&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "saas-leads",
|
||||||
|
title: "Motor de Geração B2B",
|
||||||
|
client: "SaaS Logístico",
|
||||||
|
metrics: ["15k+ Leads Qualificados", "LinkedIn Ads", "Hubspot CRM"],
|
||||||
|
category: "Growth B2B",
|
||||||
|
image: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ai-support",
|
||||||
|
title: "Automação de Retenção",
|
||||||
|
client: "EduTech App",
|
||||||
|
metrics: ["-40% Churn", "LLM Support", "Automação Make"],
|
||||||
|
category: "Ops / IA",
|
||||||
|
image: "https://images.unsplash.com/photo-1432821596592-e2c18b78144f?auto=format&fit=crop&q=80"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Cases() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full bg-black min-h-screen">
|
||||||
|
<SEO title="Cases | Agência Onyx" description="Operações de marketing implantadas com ROI documentado e trackeado." url="https://agencia-onyx.com/cases" />
|
||||||
|
|
||||||
|
{/* GRID BACKGROUND (Fixed to viewport) */}
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section className="pt-40 pb-20 border-b border-white/10 relative z-10 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="max-w-2xl">
|
||||||
|
<span className="text-[10px] uppercase font-bold tracking-[0.2em] text-gray-500 mb-6 block font-mono">
|
||||||
|
[02] HISTÓRICO VISUAL
|
||||||
|
</span>
|
||||||
|
<h1 className="text-5xl md:text-7xl font-display font-medium text-white tracking-tighter leading-tight mb-8">
|
||||||
|
Operações Reais.
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-gray-400 font-sans">
|
||||||
|
Não vendemos likes. Estas são infraestruturas de aquisição de clientes auditadas através do Google Analytics, Meta e ferramentas de BI rigorosas.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="py-24 relative z-10 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-[1px] bg-white/10 border border-white/10">
|
||||||
|
{cases.map((c, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={c.id}
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.5, delay: i * 0.1 }}
|
||||||
|
className="bg-black p-8 hover:bg-white/5 transition-colors group flex flex-col"
|
||||||
|
>
|
||||||
|
<Link to={`/contact`} className="block w-full aspect-[4/3] bg-white/5 mb-8 border border-white/10 overflow-hidden relative grayscale group-hover:grayscale-0 transition-all duration-700">
|
||||||
|
<img
|
||||||
|
src={c.image}
|
||||||
|
alt={c.title}
|
||||||
|
className="absolute inset-0 w-full h-full object-cover opacity-40 group-hover:opacity-100 group-hover:scale-105 transition-all duration-700 mix-blend-luminosity"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<span className="font-mono text-[10px] text-gray-500 uppercase tracking-widest">{c.category}</span>
|
||||||
|
<ArrowUpRight className="w-5 h-5 text-gray-600 group-hover:text-white transition-colors" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 className="text-3xl font-display text-white mb-2">{c.title}</h2>
|
||||||
|
<p className="text-sm text-gray-500 font-sans mb-8">{c.client}</p>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap gap-2 mt-auto">
|
||||||
|
{c.metrics.map(m => (
|
||||||
|
<span key={m} className="px-2 py-1 border border-white/20 text-[10px] font-mono text-gray-400 uppercase tracking-widest">
|
||||||
|
{m}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<section className="py-32 border-t border-white/10 relative z-10 bg-black text-center border-b">
|
||||||
|
<div className="container mx-auto px-6 max-w-3xl">
|
||||||
|
<h2 className="text-4xl md:text-5xl font-display font-medium text-white mb-6 tracking-tighter">PRECISA DE ROI?</h2>
|
||||||
|
<p className="text-gray-400 mb-10 max-w-xl mx-auto">Feche com os generalistas se você quiser likes. Fale conosco se quiser vendas rastreáveis.</p>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="inline-flex items-center justify-center bg-white text-black px-10 py-5 font-mono text-sm uppercase tracking-widest font-bold hover:bg-gray-200 transition-colors"
|
||||||
|
>
|
||||||
|
Solicitar Proposta
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
106
Template-02/src/pages/Contact.tsx
Normal file
106
Template-02/src/pages/Contact.tsx
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, Activity } from 'lucide-react';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function Contact() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full text-white bg-black min-h-screen">
|
||||||
|
<SEO
|
||||||
|
title="Contato | Agência Onyx"
|
||||||
|
description="Fale diretamente com os nossos estrategistas de Growth e Performance."
|
||||||
|
url="https://agencia-onyx.com/contact"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* HERO & FORM */}
|
||||||
|
<section className="pt-40 pb-32 px-6 relative z-10">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-16 lg:gap-8 items-start">
|
||||||
|
|
||||||
|
{/* Left Content */}
|
||||||
|
<div className="lg:col-span-5 pt-8 sticky top-32">
|
||||||
|
<div className="inline-flex items-center gap-2 px-3 py-1.5 border border-white/20 bg-white/5 text-gray-300 text-[10px] font-mono uppercase tracking-widest mb-6 block">
|
||||||
|
<Activity className="w-3 h-3" /> Acesso ao Time Core
|
||||||
|
</div>
|
||||||
|
<h1 className="text-5xl md:text-7xl font-display font-medium tracking-tighter mb-6 leading-[0.95]">
|
||||||
|
INICIE A <br/> AUDITORIA.
|
||||||
|
</h1>
|
||||||
|
<p className="text-lg text-gray-400 font-sans leading-relaxed mb-12 max-w-md">
|
||||||
|
Integrações de alto impacto demandam planejamento cirúrgico. Preencha o payload para analisarmos o fit técnico inicial da sua operação.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="space-y-4 font-mono text-sm max-w-md">
|
||||||
|
<div className="border border-white/10 p-6 bg-black">
|
||||||
|
<h4 className="text-white font-bold uppercase tracking-widest mb-2 text-[10px]">Headquarters</h4>
|
||||||
|
<p className="text-gray-500 leading-relaxed text-xs uppercase tracking-widest">Onyx Lab Center<br/>São Paulo, SP</p>
|
||||||
|
</div>
|
||||||
|
<div className="border border-white/10 p-6 bg-black">
|
||||||
|
<h4 className="text-white font-bold uppercase tracking-widest mb-2 text-[10px]">E-mail Prioritário</h4>
|
||||||
|
<p className="text-gray-300 hover:text-white cursor-pointer transition-colors text-xs uppercase tracking-widest">hello@agencia-onyx.com</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right Form */}
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.2 }}
|
||||||
|
className="lg:col-span-7 lg:col-start-6 border border-white/10 bg-black p-8 md:p-12"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-8 pb-6 border-b border-white/10">
|
||||||
|
<h3 className="text-2xl font-display font-medium tracking-tight">Parametrização Incial</h3>
|
||||||
|
<span className="text-[10px] font-mono text-gray-500 uppercase tracking-widest">CANAL SEGURO</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form className="space-y-6" onSubmit={(e) => e.preventDefault()}>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div className="space-y-3">
|
||||||
|
<label className="text-gray-400 uppercase tracking-widest text-[10px] font-mono font-bold block">Nome do Responsável</label>
|
||||||
|
<input type="text" className="w-full bg-white/5 border border-white/10 px-4 py-4 text-white focus:outline-none focus:border-white focus:bg-white/10 transition-colors font-sans text-sm" placeholder="Nome Completo" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<label className="text-gray-400 uppercase tracking-widest text-[10px] font-mono font-bold block">E-mail Corporativo</label>
|
||||||
|
<input type="email" className="w-full bg-white/5 border border-white/10 px-4 py-4 text-white focus:outline-none focus:border-white focus:bg-white/10 transition-colors font-sans text-sm" placeholder="voce@empresa.com" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<label className="text-gray-400 uppercase tracking-widest text-[10px] font-mono font-bold block">URL / Site Atual</label>
|
||||||
|
<input type="text" className="w-full bg-white/5 border border-white/10 px-4 py-4 text-white focus:outline-none focus:border-white focus:bg-white/10 transition-colors font-sans text-sm" placeholder="https://..." />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<label className="text-gray-400 uppercase tracking-widest text-[10px] font-mono font-bold block">Plano de Ataque Desejado</label>
|
||||||
|
<div className="relative">
|
||||||
|
<select className="w-full bg-white/5 border border-white/10 px-4 py-4 text-white focus:outline-none focus:border-white focus:bg-white/10 transition-colors font-sans text-sm appearance-none cursor-pointer">
|
||||||
|
<option className="bg-[#0a0a0a]">Auditoria de Tráfego Pago (Ads)</option>
|
||||||
|
<option className="bg-[#0a0a0a]">SEO Técnico & Posicionamento</option>
|
||||||
|
<option className="bg-[#0a0a0a]">CRO & Otimização de Funil UX</option>
|
||||||
|
<option className="bg-[#0a0a0a]">Operação Completa (Growth)</option>
|
||||||
|
</select>
|
||||||
|
<ArrowRight className="w-4 h-4 absolute right-4 top-1/2 -translate-y-1/2 text-gray-500 rotate-90 pointer-events-none" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<label className="text-gray-400 uppercase tracking-widest text-[10px] font-mono font-bold block">Contexto Operacional</label>
|
||||||
|
<textarea rows={4} className="w-full bg-white/5 border border-white/10 px-4 py-4 text-white focus:outline-none focus:border-white focus:bg-white/10 transition-colors font-sans text-sm resize-none" placeholder="Qual o gargalo principal hoje? Falta lead bruto, custo de clique caro, ou taxa de conversão baixa?"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button className="w-full bg-white text-black py-5 uppercase tracking-widest font-mono text-xs font-bold hover:bg-gray-200 transition-colors mt-6">
|
||||||
|
Enviar Dados
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<p className="text-[10px] text-gray-500 font-mono text-center tracking-widest mt-6">Tempo Estimado de Resposta: 24h a 48h</p>
|
||||||
|
</form>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
195
Template-02/src/pages/Home.tsx
Normal file
195
Template-02/src/pages/Home.tsx
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, ChevronRight, Cpu, Network, Shield } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full bg-black min-h-screen text-white font-sans selection:bg-white selection:text-black">
|
||||||
|
<SEO
|
||||||
|
title="Onyx | Marketing Digital e Growth"
|
||||||
|
description="Agência focada em Growth Hacking, Performance Ads e SEO Técnico. Escale suas vendas."
|
||||||
|
url="https://agencia-onyx.com"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* GRID BACKGROUND */}
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-b from-black via-transparent to-black" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* HERO SECTION */}
|
||||||
|
<section className="relative z-10 pt-40 pb-32 min-h-screen flex flex-col justify-center border-b border-white/10">
|
||||||
|
<div className="container mx-auto max-w-7xl px-6">
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 items-end">
|
||||||
|
|
||||||
|
<div className="lg:col-span-8 flex flex-col items-start text-left">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: 10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
className="flex items-center gap-3 px-3 py-1.5 border border-white/20 bg-white/5 text-gray-300 text-[10px] font-mono tracking-widest uppercase mb-12"
|
||||||
|
>
|
||||||
|
<span className="w-1.5 h-1.5 rounded-full bg-white" />
|
||||||
|
Operações 2026 Ativas
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.7, delay: 0.1 }}
|
||||||
|
className="text-6xl sm:text-7xl md:text-8xl lg:text-[100px] font-display font-medium tracking-tighter leading-[0.9] text-white mb-8"
|
||||||
|
>
|
||||||
|
ESCALA <br />
|
||||||
|
<span className="text-gray-500">ABSOLUTA.</span>
|
||||||
|
</motion.h1>
|
||||||
|
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 0.8, delay: 0.3 }}
|
||||||
|
className="text-lg md:text-xl text-gray-400 max-w-xl leading-relaxed"
|
||||||
|
>
|
||||||
|
O fim do marketing de esperança. Construímos infraestruturas de vendas, Growth Hacking e tráfego pago para o 1% do mercado.
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ duration: 1, delay: 0.5 }}
|
||||||
|
className="lg:col-span-4 flex flex-col gap-6"
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="w-full inline-flex items-center justify-between border border-white hover:bg-white hover:text-black transition-colors px-6 py-5"
|
||||||
|
>
|
||||||
|
<span className="font-mono text-sm uppercase tracking-widest font-bold">Solicitar Auditoria</span>
|
||||||
|
<ArrowRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
to="/cases"
|
||||||
|
className="w-full inline-flex items-center justify-between border border-white/10 hover:bg-white/5 transition-colors px-6 py-5 text-gray-400 hover:text-white"
|
||||||
|
>
|
||||||
|
<span className="font-mono text-sm uppercase tracking-widest">Ver Resultados</span>
|
||||||
|
<ChevronRight className="w-5 h-5" />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<div className="mt-8 p-6 border border-white/10 bg-white/5 backdrop-blur-sm hidden sm:block">
|
||||||
|
<div className="flex justify-between items-center mb-4">
|
||||||
|
<span className="font-mono text-[10px] text-gray-500 uppercase tracking-widest">Status do Mercado</span>
|
||||||
|
<span className="font-mono text-[10px] text-white uppercase tracking-widest bg-white/10 px-2 py-0.5">Online</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex justify-between font-mono text-xs">
|
||||||
|
<span className="text-gray-500">Volume de Busca</span>
|
||||||
|
<span className="text-white">Alto</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between font-mono text-xs">
|
||||||
|
<span className="text-gray-500">CAC Médio</span>
|
||||||
|
<span className="text-white">Otimizado</span>
|
||||||
|
</div>
|
||||||
|
<div className="w-full h-1 bg-white/10 mt-4 overflow-hidden">
|
||||||
|
<div className="h-full bg-white w-2/3 animate-[pulse_2s_ease-in-out_infinite]" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CORE MODULES */}
|
||||||
|
<section className="py-32 relative z-10 border-b border-white/10 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="flex flex-col md:flex-row justify-between items-end mb-24 gap-8">
|
||||||
|
<div className="max-w-2xl">
|
||||||
|
<h2 className="text-5xl md:text-6xl font-display font-medium tracking-tighter text-white leading-tight">
|
||||||
|
NOSSOS PILARES.
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<p className="text-gray-400 max-w-sm font-sans text-sm md:text-base">
|
||||||
|
Estratégias rasas não performam mais. Executamos Growth de forma técnica e direcionada a lucros reais.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-[1px] bg-white/10 border border-white/10">
|
||||||
|
{[
|
||||||
|
{ i: <Cpu className="w-6 h-6"/>, t: "Tráfego de Alta Performance", d: "Escala maciça no Google Ads e Meta Ads baseada em algoritmos preditivos e Server-Side Tracking." },
|
||||||
|
{ i: <Network className="w-6 h-6"/>, t: "SEO Técnico Avançado", d: "Dominância nas buscas através de auditorias estruturais profundas e autoridade em clusters." },
|
||||||
|
{ i: <Shield className="w-6 h-6"/>, t: "CRO (Otimização de Conversões)", d: "Design centrado em neurociência para extrair mais vendas do exato mesmo volume de tráfego." }
|
||||||
|
].map((f, i) => (
|
||||||
|
<div key={i} className="bg-black p-10 md:p-12 group hover:bg-white/5 transition-colors duration-500 flex flex-col justify-between h-full min-h-[320px]">
|
||||||
|
<div className="text-white mb-8">
|
||||||
|
{f.i}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-display text-white mb-4 tracking-tight">{f.t}</h3>
|
||||||
|
<p className="text-gray-500 text-sm leading-relaxed">{f.d}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* LOGS */}
|
||||||
|
<section className="py-32 relative z-10 bg-black border-b border-white/10">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="flex justify-between items-end mb-16">
|
||||||
|
<h3 className="text-4xl md:text-5xl font-display tracking-tighter text-white">NOSSOS ARTIGOS.</h3>
|
||||||
|
<Link to="/blog" className="text-xs font-mono uppercase tracking-widest text-white hover:text-gray-400 flex items-center gap-2 transition-colors">
|
||||||
|
Abrir Blog <ArrowRight className="w-4 h-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-[1px] bg-white/10 border border-white/10">
|
||||||
|
<Link to="/blog/escalando-campanhas-um-milhao" className="group bg-black p-8 md:p-12 hover:bg-white/5 transition-colors flex flex-col h-full">
|
||||||
|
<div className="flex items-center gap-4 mb-8">
|
||||||
|
<span className="px-2 py-1 border border-white/20 text-[10px] text-white font-mono uppercase tracking-widest">Ads</span>
|
||||||
|
<span className="text-[10px] text-gray-600 font-mono tracking-widest">LOG.064</span>
|
||||||
|
</div>
|
||||||
|
<h4 className="text-3xl font-display text-white mb-4 tracking-tight group-hover:text-gray-300 transition-colors">Tráfego Pago: Escalando Campanhas de US$ 1 Milhão</h4>
|
||||||
|
<p className="text-gray-500 text-sm mb-12">Escalar orçamento não é simplesmente aumentar investimento diário. O processo de expansão orçamentária sem perder o ROI é brutalmente técnico.</p>
|
||||||
|
|
||||||
|
<div className="mt-auto flex justify-between items-center text-xs font-mono text-gray-500 uppercase tracking-widest">
|
||||||
|
<span>Ler Artigo</span>
|
||||||
|
<ArrowRight className="w-4 h-4 transform group-hover:translate-x-2 transition-transform" />
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link to="/blog/seo-tecnico-ecommerce" className="group bg-black p-8 md:p-12 hover:bg-white/5 transition-colors flex flex-col h-full">
|
||||||
|
<div className="flex items-center gap-4 mb-8">
|
||||||
|
<span className="px-2 py-1 border border-white/20 text-[10px] text-white font-mono uppercase tracking-widest">SEO</span>
|
||||||
|
<span className="text-[10px] text-gray-600 font-mono tracking-widest">LOG.082</span>
|
||||||
|
</div>
|
||||||
|
<h4 className="text-3xl font-display text-white mb-4 tracking-tight group-hover:text-gray-300 transition-colors">SEO Técnico para E-commerce</h4>
|
||||||
|
<p className="text-gray-500 text-sm mb-12">Lojas virtuais com milhares de URLs param de rankear do dia pra noite. A raiz do problema geralmente é facetas, canonicalização ou crawl budget.</p>
|
||||||
|
|
||||||
|
<div className="mt-auto flex justify-between items-center text-xs font-mono text-gray-500 uppercase tracking-widest">
|
||||||
|
<span>Ler Artigo</span>
|
||||||
|
<ArrowRight className="w-4 h-4 transform group-hover:translate-x-2 transition-transform" />
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<section className="py-40 relative z-10 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-4xl text-center">
|
||||||
|
<div className="font-mono text-xs uppercase tracking-widest text-gray-500 mb-6">Fim da Transmissão</div>
|
||||||
|
<h2 className="text-6xl md:text-8xl font-display font-medium tracking-tighter text-white mb-8">PRONTO?</h2>
|
||||||
|
<p className="text-gray-400 mb-12 max-w-xl mx-auto text-lg">Deixe estratégias padrões para trás. Conecte-se com nossa equipe e mapeie sua infraestrutura de crescimento.</p>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="inline-flex items-center justify-center bg-white text-black px-10 py-5 font-mono uppercase tracking-widest text-sm font-bold hover:bg-gray-200 transition-colors"
|
||||||
|
>
|
||||||
|
Iniciar Projeto
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
34
Template-02/src/pages/NotFound.tsx
Normal file
34
Template-02/src/pages/NotFound.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { ArrowLeft } from 'lucide-react';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
export default function NotFound() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-[70vh] px-6 text-center">
|
||||||
|
<SEO
|
||||||
|
title="Página não encontrada | Onyx Growth"
|
||||||
|
description="O caminho que você buscou não existe."
|
||||||
|
url="https://onyx.com.br/404"
|
||||||
|
schema={{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebPage",
|
||||||
|
"name": "Página não encontrada | Onyx Growth"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
>
|
||||||
|
<h1 className="text-8xl md:text-[150px] font-display font-bold text-white/5 mb-4 leading-none">404</h1>
|
||||||
|
<h2 className="text-3xl md:text-5xl font-display font-semibold mb-6">Visão bloqueada.</h2>
|
||||||
|
<p className="text-gray-400 text-lg mb-10 max-w-md mx-auto">
|
||||||
|
A página que você está tentando acessar foi movida, deletada ou nunca existiu neste sistema de arquitetura.
|
||||||
|
</p>
|
||||||
|
<Link to="/" className="inline-flex items-center gap-2 bg-white text-black px-8 py-4 rounded-full text-lg font-medium hover:bg-gray-200 transition-colors">
|
||||||
|
<ArrowLeft className="w-5 h-5" /> Retornar ao Início
|
||||||
|
</Link>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
140
Template-02/src/pages/Services.tsx
Normal file
140
Template-02/src/pages/Services.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { motion } from 'motion/react';
|
||||||
|
import { ArrowRight, BarChart3, Binary, Layout, Cpu, ScanLine, Shield } from 'lucide-react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import SEO from '@/components/SEO';
|
||||||
|
|
||||||
|
const services = [
|
||||||
|
{
|
||||||
|
id: "growth",
|
||||||
|
icon: <BarChart3 className="w-6 h-6" />,
|
||||||
|
title: "Tráfego Pago & Growth",
|
||||||
|
description: "Transformamos o seu orçamento de mídia em um motor previsível de lucro. Executamos modelagem e estruturação brutal no Google e Meta Ads priorizando LTV e menor CAC.",
|
||||||
|
features: ["Machine Learning Bidding", "Server-Side Tracking API", "Teste A/B Contínuo", "Estratégia Cross-Channel"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "seo",
|
||||||
|
icon: <Binary className="w-6 h-6" />,
|
||||||
|
title: "SEO Técnico & Conteúdo",
|
||||||
|
description: "Dominância nas buscas orgânicas não vem de sorte. Aplicamos auditorias profundas para resolver gargalos de indexação e projetamos conteúdo centrado na jornada.",
|
||||||
|
features: ["Auditoria Técnica (Crawl/Index)", "Arquitetura de Silos", "Otimização de Web Vitals", "Link Building Autoridade"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "cro",
|
||||||
|
icon: <Layout className="w-6 h-6" />,
|
||||||
|
title: "CRO & UI de Alta Conversão",
|
||||||
|
description: "Design voltado unicamente para extrair resultados. Desenhamos funis imersivos com estética alinhada a gatilhos neurológicos para conversão instantânea.",
|
||||||
|
features: ["Mapas de Calor e Gravações", "Wireframing Preditivo", "Design Systems Minimalistas", "Otimização de Checkout"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ai-systems",
|
||||||
|
icon: <Cpu className="w-6 h-6" />,
|
||||||
|
title: "Automações e IA (Ops)",
|
||||||
|
description: "Integrações avançadas usando LLMs para automatizar desde qualificação de leads B2B até disparo inteligente de mensagens e recuperação de vendas.",
|
||||||
|
features: ["Qualificadores de Lead (IA)", "Zapier & Make Integations", "Disparos Baseados em Gatilhos", "Infraestrutura de Dados"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Services() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col w-full text-white bg-black">
|
||||||
|
<SEO
|
||||||
|
title="Soluções | Agência Onyx"
|
||||||
|
description="Nossos serviços de Tráfego Pago, SEO e CRO estruturados para alta rentabilidade."
|
||||||
|
url="https://agencia-onyx.com/services"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="fixed inset-0 pointer-events-none z-0">
|
||||||
|
<div className="absolute inset-0 bg-grid-pattern opacity-30" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* HERO */}
|
||||||
|
<section className="pt-40 pb-20 px-6 border-b border-white/10 relative z-10 bg-black">
|
||||||
|
<div className="container mx-auto max-w-7xl">
|
||||||
|
<div className="max-w-4xl">
|
||||||
|
<span className="text-[10px] uppercase font-bold tracking-[0.2em] text-gray-500 mb-6 block font-mono">
|
||||||
|
[01] O ECOSSISTEMA ONYX
|
||||||
|
</span>
|
||||||
|
<motion.h1
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="text-5xl sm:text-7xl md:text-8xl font-display font-medium tracking-tighter mb-8 leading-[0.95]"
|
||||||
|
>
|
||||||
|
SOLUÇÕES DE <br className="hidden md:block"/>
|
||||||
|
<span className="text-gray-500">CRESCIMENTO.</span>
|
||||||
|
</motion.h1>
|
||||||
|
<motion.p
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
className="text-xl md:text-2xl text-gray-400 max-w-2xl leading-relaxed"
|
||||||
|
>
|
||||||
|
Estratégias não funcionam isoladas. Desenhamos a infraestrutura conectada faturando milhões, reduzindo sua operação ao clique.
|
||||||
|
</motion.p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* SERVICES LIST */}
|
||||||
|
<section className="py-24 relative z-10 bg-black">
|
||||||
|
<div className="container mx-auto px-6 max-w-7xl">
|
||||||
|
<div className="grid grid-cols-1 gap-[1px] bg-white/10 border border-white/10">
|
||||||
|
{services.map((service, index) => (
|
||||||
|
<div key={service.id} id={service.id} className="bg-black p-8 md:p-16 grid grid-cols-1 md:grid-cols-12 gap-12 items-start group">
|
||||||
|
|
||||||
|
{/* Left: Icon & Description */}
|
||||||
|
<div className="md:col-span-6 lg:col-span-7 flex flex-col items-start">
|
||||||
|
<div className="w-12 h-12 flex items-center justify-center text-white mb-8 border border-white/20 bg-white/5">
|
||||||
|
{service.icon}
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-display font-medium mb-4 text-white tracking-tight">{service.title}</h2>
|
||||||
|
<p className="text-gray-400 text-lg leading-relaxed mb-8">
|
||||||
|
{service.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="inline-flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest text-white hover:text-gray-300 transition-colors border border-white/20 hover:bg-white/10 px-4 py-2 font-mono"
|
||||||
|
>
|
||||||
|
Iniciar Escopo
|
||||||
|
<ArrowRight className="w-4 h-4 ml-1" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right: Features Array */}
|
||||||
|
<div className="md:col-span-6 lg:col-span-5 bg-white/5 border border-white/10 p-8 h-full flex flex-col">
|
||||||
|
<div className="flex items-center gap-3 mb-6 border-b border-white/10 pb-4">
|
||||||
|
<ScanLine className="w-4 h-4 text-gray-500" />
|
||||||
|
<h4 className="text-[10px] uppercase font-bold tracking-widest text-gray-400 font-mono">Pilares da Solução</h4>
|
||||||
|
</div>
|
||||||
|
<ul className="space-y-6 flex-1">
|
||||||
|
{service.features.map((f, i) => (
|
||||||
|
<li key={i} className="flex items-start gap-4 text-gray-300 font-mono text-xs uppercase tracking-widest leading-snug">
|
||||||
|
<span className="text-gray-500 mt-0.5">0{i+1}_</span>
|
||||||
|
<span>{f}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* CTA */}
|
||||||
|
<section className="py-32 bg-white text-black text-center z-10 relative">
|
||||||
|
<div className="container mx-auto px-6 max-w-4xl">
|
||||||
|
<Shield className="w-12 h-12 mx-auto mb-8 text-black" />
|
||||||
|
<h2 className="text-4xl md:text-5xl font-display font-medium mb-6 tracking-tighter">PRONTO?</h2>
|
||||||
|
<p className="text-lg text-gray-600 mb-10 max-w-2xl mx-auto font-sans">Capacidade de onboarding limitada a fim de preservar o SLA técnico e faturamento da base atual.</p>
|
||||||
|
<Link
|
||||||
|
to="/contact"
|
||||||
|
className="inline-flex items-center justify-center bg-black text-white px-10 py-5 font-mono text-sm uppercase tracking-widest font-bold hover:bg-gray-800 transition-colors"
|
||||||
|
>
|
||||||
|
Solicitar Auditoria
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
Template-02/tsconfig.json
Normal file
26
Template-02/tsconfig.json
Normal 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": {
|
||||||
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"noEmit": true
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Template-02/vite.config.ts
Normal file
24
Template-02/vite.config.ts
Normal 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, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue