att layout

This commit is contained in:
eycksilva 2026-01-21 12:33:57 -03:00
parent 6a9bbd84cd
commit d916bee429
23 changed files with 717 additions and 298 deletions

View file

@ -0,0 +1,201 @@
# Melhorias de Responsividade e Internacionalização
## ✅ Concluído
### 1. Sistema de Idiomas
- ✅ Sistema de i18n já implementado com 3 idiomas (pt-BR, en, es)
- ✅ LanguageSwitcher component criado e funcional
- ✅ Traduções adicionadas para navegação mobile:
- `nav.language`: "Idioma" / "Language" / "Idioma"
- `nav.registerUser`: "Cadastrar Usuário" / "Register User" / "Registrar Usuario"
- `nav.registerCompany`: "Cadastrar Empresa" / "Register Company" / "Registrar Empresa"
### 2. Navbar Responsivo
- ✅ Menu mobile já implementado com Sheet component
- ✅ LanguageSwitcher adicionado no desktop
- ⚠️ **PENDENTE**: Adicionar LanguageSwitcher no menu mobile
## 📋 Próximos Passos
### 1. Completar Traduções nos Arquivos de Idioma
#### en.json (Inglês)
Adicionar na seção "nav" (linha 18-24):
```json
"nav": {
"jobs": "Jobs",
"about": "About",
"contact": "Contact",
"login": "Login",
"register": "Register",
"language": "Language",
"registerUser": "Register User",
"registerCompany": "Register Company"
},
```
#### es.json (Espanhol)
Adicionar na seção "nav":
```json
"nav": {
"jobs": "Empleos",
"about": "Acerca de",
"contact": "Contacto",
"login": "Iniciar sesión",
"register": "Registrarse",
"language": "Idioma",
"registerUser": "Registrar Usuario",
"registerCompany": "Registrar Empresa"
},
```
### 2. Atualizar Navbar para Mobile
Arquivo: `e:\gohorse\gohorsejobs\frontend\src\components\navbar.tsx`
Adicionar após a linha 110 (dentro do SheetContent):
```tsx
{/* Language Switcher in Mobile */}
<div className="flex items-center justify-between px-2 py-2 bg-muted rounded-lg">
<span className="text-sm font-medium">{t('nav.language')}</span>
<LanguageSwitcher />
</div>
```
E atualizar os links de registro no mobile (linhas 139-144):
```tsx
<Link href="/register/user" onClick={() => setIsOpen(false)}>
<Button variant="outline" className="w-full justify-start gap-2">
<UserPlus className="w-4 h-4" />
{t('nav.registerUser')}
</Button>
</Link>
<Link href="/register" onClick={() => setIsOpen(false)}>
<Button className="w-full justify-start gap-2">
<Building2 className="w-4 h-4" />
{t('nav.registerCompany')}
</Button>
</Link>
```
### 3. Verificar Responsividade em Todas as Páginas
Testar as seguintes páginas em diferentes tamanhos de tela:
- ✅ `/` - Home
- ✅ `/jobs` - Lista de vagas
- ✅ `/blog` - Blog
- ✅ `/companies` - Empresas
- ⚠️ `/jobs/[id]` - Detalhes da vaga
- ⚠️ `/jobs/[id]/apply` - Formulário de candidatura
- ⚠️ `/blog/[slug]` - Artigo do blog
- ⚠️ `/register/user` - Cadastro de usuário
- ⚠️ `/register` - Cadastro de empresa
- ⚠️ `/publicar-vaga` - Publicar vaga
- ⚠️ `/dashboard/*` - Todas as páginas do dashboard
### 4. Melhorias de Responsividade Específicas
#### Breakpoints Padrão do Tailwind:
- `sm`: 640px
- `md`: 768px
- `lg`: 1024px
- `xl`: 1280px
- `2xl`: 1536px
#### Checklist de Responsividade:
- [ ] Textos legíveis em mobile (min 14px)
- [ ] Botões com tamanho adequado para toque (min 44x44px)
- [ ] Espaçamento adequado entre elementos
- [ ] Imagens responsivas com `object-fit`
- [ ] Tabelas com scroll horizontal em mobile
- [ ] Formulários com campos empilhados em mobile
- [ ] Navegação mobile funcional
- [ ] Modais e dialogs responsivos
## 🎨 Padrões de Responsividade
### Containers
```tsx
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
```
### Grid Responsivo
```tsx
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
```
### Texto Responsivo
```tsx
<h1 className="text-2xl md:text-3xl lg:text-4xl font-bold">
```
### Padding/Margin Responsivo
```tsx
<div className="py-8 md:py-12 lg:py-16">
```
### Flex Responsivo
```tsx
<div className="flex flex-col md:flex-row gap-4">
```
## 🌐 Uso do Sistema de Idiomas
### Em Componentes
```tsx
import { useTranslation } from "@/lib/i18n";
export function MyComponent() {
const { t, locale, setLocale } = useTranslation();
return (
<div>
<h1>{t('page.title')}</h1>
<p>{t('page.description', { name: 'João' })}</p>
</div>
);
}
```
### Trocar Idioma
```tsx
setLocale('pt-BR'); // ou 'en' ou 'es'
```
## 📱 Testes de Responsividade
### Dispositivos para Testar:
1. **Mobile**: 375x667 (iPhone SE)
2. **Mobile**: 390x844 (iPhone 12 Pro)
3. **Tablet**: 768x1024 (iPad)
4. **Desktop**: 1280x720
5. **Desktop**: 1920x1080
### Ferramentas:
- Chrome DevTools (F12 → Toggle Device Toolbar)
- Firefox Responsive Design Mode
- Testes em dispositivos reais
## 🚀 Comandos Úteis
```bash
# Rodar em desenvolvimento
npm run dev
# Build para produção
npm run build
# Verificar erros de lint
npm run lint
# Corrigir erros de lint
npm run lint:fix
```
## 📝 Notas
- O sistema de cores já está padronizado para `#F0932B`
- O Edge Runtime foi removido de todos os arquivos problemáticos
- O projeto usa Next.js 14 com App Router
- Tailwind CSS é usado para estilização
- shadcn/ui é usado para componentes

BIN
frontend/public/111.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
frontend/public/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
frontend/public/18.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

View file

@ -68,7 +68,7 @@ export default function AboutPage() {
</p>
</div>
<div className="relative">
<div className="relative h-96 rounded-2xl overflow-hidden shadow-2xl bg-[#f0932b]">
<div className="relative h-96 rounded-2xl overflow-hidden shadow-2xl bg-[#F0932B]">
<Image
src="/1.png"
alt="GoHorse Jobs Team"
@ -93,7 +93,7 @@ export default function AboutPage() {
<div className="max-w-6xl mx-auto">
<div className="grid lg:grid-cols-2 gap-16 items-center">
<div className="order-2 lg:order-1">
<div className="relative h-96 rounded-2xl overflow-hidden shadow-xl bg-[#f0932b]">
<div className="relative h-96 rounded-2xl overflow-hidden shadow-xl bg-[#F0932B]">
<Image
src="/2.png"
alt="O que fazemos"
@ -215,7 +215,7 @@ export default function AboutPage() {
</section>
{/* CTA Section */}
<section className="relative py-20 md:py-28 bg-[#f0932b] overflow-hidden">
<section className="relative py-20 md:py-28 bg-[#F0932B] overflow-hidden">
<Image
src="/4.png"
alt="Background"

View file

@ -1,8 +1,5 @@
import { NextResponse } from 'next/server';
export const runtime = 'edge';
/**
* Runtime Configuration API
*

View file

@ -294,7 +294,7 @@ export default function BlogPostPage() {
{/* Article Header */}
<article className="py-12">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto">
<div className="max-w-4xl mx-auto flex flex-col items-start text-left">
{/* Back Button */}
<Link
href="/blog"
@ -311,10 +311,16 @@ export default function BlogPostPage() {
</span>
</div>
{/* Title */}
{/* Title, Subtitle e Botão alinhados à esquerda */}
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-6 leading-tight">
{post.title}
</h1>
<p className="mb-8 text-lg text-gray-700">
Conectamos você com as melhores empresas e techs.
</p>
<button className="bg-[#f0932b] text-white font-bold px-8 py-4 rounded mt-4">
Buscar Vagas
</button>
{/* Meta Info */}
<div className="flex flex-wrap items-center gap-6 text-gray-600 mb-8 pb-8 border-b border-gray-200">

View file

@ -171,7 +171,7 @@ export default function BlogPage() {
const filteredPosts = blogPosts.filter(post => {
const matchesSearch = post.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
post.excerpt.toLowerCase().includes(searchTerm.toLowerCase())
post.excerpt.toLowerCase().includes(searchTerm.toLowerCase())
const matchesCategory = selectedCategory === "Todas" || post.category === selectedCategory
return matchesSearch && matchesCategory
@ -186,7 +186,7 @@ export default function BlogPage() {
<main className="flex-1">
{/* Hero Section */}
<section className="relative bg-[#f0932b] py-16 md:py-24 overflow-hidden">
<section className="relative bg-[#F0932B] py-16 md:py-24 overflow-hidden">
<div className="absolute inset-0 opacity-10">
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_30%_50%,rgba(255,255,255,0.2)_0%,transparent_50%)]"></div>
</div>
@ -209,7 +209,7 @@ export default function BlogPage() {
placeholder="Buscar artigos..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-14 pr-4 py-3 rounded-full text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#f0932b] text-lg bg-white"
className="w-full pl-14 pr-4 py-3 rounded-full text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#F0932B] text-lg bg-white"
/>
</div>
</div>
@ -225,11 +225,10 @@ export default function BlogPage() {
<button
key={category}
onClick={() => setSelectedCategory(category)}
className={`px-5 py-2 rounded-full font-medium whitespace-nowrap transition-all ${
selectedCategory === category
? 'bg-[#f0932b] text-white shadow-md'
className={`px-5 py-2 rounded-full font-medium whitespace-nowrap transition-all ${selectedCategory === category
? 'bg-[#F0932B] text-white shadow-md'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
}`}
>
{category}
</button>
@ -243,7 +242,7 @@ export default function BlogPage() {
<section className="py-12 bg-gradient-to-b from-orange-50 to-white">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center gap-3 mb-8">
<TrendingUp className="w-7 h-7 text-[#f0932b]" />
<TrendingUp className="w-7 h-7 text-[#F0932B]" />
<h2 className="text-3xl font-bold text-gray-900">Artigos em Destaque</h2>
</div>
@ -252,7 +251,7 @@ export default function BlogPage() {
<Link
key={post.id}
href={`/blog/${post.slug}`}
className="group bg-white rounded-2xl overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 border-2 border-[#f0932b]/20"
className="group bg-white rounded-2xl overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 border-2 border-[#F0932B]/20"
>
<div className="relative h-56 overflow-hidden">
<Image
@ -262,18 +261,18 @@ export default function BlogPage() {
className="object-cover group-hover:scale-110 transition-transform duration-300"
/>
<div className="absolute top-4 left-4">
<span className="bg-[#f0932b] text-white px-3 py-1 rounded-full text-xs font-semibold">
<span className="bg-[#F0932B] text-white px-3 py-1 rounded-full text-xs font-semibold">
Destaque
</span>
</div>
</div>
<div className="p-6">
<div className="flex items-center gap-2 mb-3">
<span className="bg-[#f0932b]/10 text-[#f0932b] px-3 py-1 rounded-full text-xs font-semibold">
<span className="bg-[#F0932B]/10 text-[#F0932B] px-3 py-1 rounded-full text-xs font-semibold">
{post.category}
</span>
</div>
<h3 className="text-xl font-bold text-gray-900 mb-3 group-hover:text-[#f0932b] transition-colors line-clamp-2">
<h3 className="text-xl font-bold text-gray-900 mb-3 group-hover:text-[#F0932B] transition-colors line-clamp-2">
{post.title}
</h3>
<p className="text-gray-600 mb-4 line-clamp-2">
@ -307,7 +306,7 @@ export default function BlogPage() {
{selectedCategory === "Todas" ? "Todos os Artigos" : `Categoria: ${selectedCategory}`}
</h2>
<p className="text-gray-600">
<span className="font-semibold text-[#f0932b]">{filteredPosts.length}</span> artigos encontrados
<span className="font-semibold text-[#F0932B]">{filteredPosts.length}</span> artigos encontrados
</p>
</div>
@ -316,7 +315,7 @@ export default function BlogPage() {
<Link
key={post.id}
href={`/blog/${post.slug}`}
className="group bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-xl transition-all duration-300 border border-gray-200 hover:border-[#f0932b]"
className="group bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-xl transition-all duration-300 border border-gray-200 hover:border-[#F0932B]"
>
<div className="relative h-48 overflow-hidden">
<Image
@ -332,7 +331,7 @@ export default function BlogPage() {
{post.category}
</span>
</div>
<h3 className="text-lg font-bold text-gray-900 mb-2 group-hover:text-[#f0932b] transition-colors line-clamp-2">
<h3 className="text-lg font-bold text-gray-900 mb-2 group-hover:text-[#F0932B] transition-colors line-clamp-2">
{post.title}
</h3>
<p className="text-gray-600 text-sm mb-4 line-clamp-3">
@ -343,7 +342,7 @@ export default function BlogPage() {
<Clock className="w-3 h-3" />
<span>{post.readTime}</span>
</div>
<div className="flex items-center gap-1 text-[#f0932b] font-semibold text-sm">
<div className="flex items-center gap-1 text-[#F0932B] font-semibold text-sm">
<span>Ler mais</span>
<ArrowRight className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
</div>
@ -364,7 +363,7 @@ export default function BlogPage() {
</section>
{/* Newsletter CTA */}
<section className="bg-gradient-to-br from-[#f0932b] to-[#e67e22] py-16">
<section className="bg-gradient-to-br from-[#F0932B] to-[#d97d1a] py-16">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center text-white">
<Lightbulb className="w-16 h-16 mx-auto mb-6" />
@ -380,7 +379,7 @@ export default function BlogPage() {
placeholder="Seu melhor e-mail"
className="flex-1 px-6 py-4 rounded-full bg-white text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-white"
/>
<button className="bg-white text-[#f0932b] hover:bg-gray-100 font-bold px-8 py-4 rounded-full transition-colors whitespace-nowrap">
<button className="bg-white text-[#F0932B] hover:bg-gray-100 font-bold px-8 py-4 rounded-full transition-colors whitespace-nowrap">
Assinar Newsletter
</button>
</div>

View file

@ -170,7 +170,7 @@ export default function CompaniesPage() {
<main className="flex-1">
{/* Hero Section */}
<section className="relative bg-[#f0932b] py-20 md:py-28 overflow-hidden">
<section className="relative bg-[#F0932B] py-20 md:py-28 overflow-hidden">
<div className="absolute inset-0 opacity-10">
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_30%_50%,rgba(255,255,255,0.2)_0%,transparent_50%)]"></div>
</div>
@ -193,7 +193,7 @@ export default function CompaniesPage() {
placeholder="Buscar empresas por nome ou setor..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-14 pr-4 py-3 rounded-full text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#f0932b] text-lg bg-white"
className="w-full pl-14 pr-4 py-3 rounded-full text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#F0932B] text-lg bg-white"
/>
</div>
@ -214,7 +214,7 @@ export default function CompaniesPage() {
<select
value={selectedIndustry}
onChange={(e) => setSelectedIndustry(e.target.value)}
className="px-4 py-2 rounded-full border border-gray-300 focus:outline-none focus:ring-2 focus:ring-[#f0932b] bg-white"
className="px-4 py-2 rounded-full border border-gray-300 focus:outline-none focus:ring-2 focus:ring-[#F0932B] bg-white"
>
{industries.map(industry => (
<option key={industry} value={industry}>{industry}</option>
@ -224,7 +224,7 @@ export default function CompaniesPage() {
<select
value={selectedSize}
onChange={(e) => setSelectedSize(e.target.value)}
className="px-4 py-2 rounded-full border border-gray-300 focus:outline-none focus:ring-2 focus:ring-[#f0932b] bg-white"
className="px-4 py-2 rounded-full border border-gray-300 focus:outline-none focus:ring-2 focus:ring-[#F0932B] bg-white"
>
{companySizes.map(size => (
<option key={size} value={size}>{size}</option>
@ -232,7 +232,7 @@ export default function CompaniesPage() {
</select>
<div className="ml-auto text-sm text-gray-600">
<span className="font-semibold text-[#f0932b]">{filteredCompanies.length}</span> empresas encontradas
<span className="font-semibold text-[#F0932B]">{filteredCompanies.length}</span> empresas encontradas
</div>
</div>
</div>
@ -243,7 +243,7 @@ export default function CompaniesPage() {
<section className="py-16 bg-gradient-to-b from-orange-50 to-white">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center gap-3 mb-8">
<Star className="w-6 h-6 text-[#f0932b]" />
<Star className="w-6 h-6 text-[#F0932B]" />
<h2 className="text-3xl font-bold text-gray-900">Empresas em Destaque</h2>
</div>
@ -251,11 +251,11 @@ export default function CompaniesPage() {
{featuredCompanies.map((company) => (
<div
key={company.id}
className="bg-white rounded-2xl p-6 shadow-lg hover:shadow-xl transition-all duration-300 border-2 border-[#f0932b]/20"
className="bg-white rounded-2xl p-6 shadow-lg hover:shadow-xl transition-all duration-300 border-2 border-[#F0932B]/20"
>
<div className="flex items-start gap-4 mb-4">
<div className="w-16 h-16 rounded-xl bg-[#f0932b]/10 flex items-center justify-center flex-shrink-0">
<Building2 className="w-8 h-8 text-[#f0932b]" />
<div className="w-16 h-16 rounded-xl bg-[#F0932B]/10 flex items-center justify-center flex-shrink-0">
<Building2 className="w-8 h-8 text-[#F0932B]" />
</div>
<div className="flex-1">
<div className="flex items-start justify-between mb-2">
@ -275,7 +275,7 @@ export default function CompaniesPage() {
{company.employees}
</span>
</div>
<span className="inline-block bg-[#f0932b]/10 text-[#f0932b] px-3 py-1 rounded-full text-xs font-semibold">
<span className="inline-block bg-[#F0932B]/10 text-[#F0932B] px-3 py-1 rounded-full text-xs font-semibold">
{company.industry}
</span>
</div>
@ -292,13 +292,13 @@ export default function CompaniesPage() {
</div>
<div className="flex items-center justify-between pt-4 border-t border-gray-100">
<div className="flex items-center gap-2 text-[#f0932b] font-semibold">
<div className="flex items-center gap-2 text-[#F0932B] font-semibold">
<Briefcase className="w-5 h-5" />
<span>{company.openJobs} vagas abertas</span>
</div>
<Link
href={`/companies/${company.id}`}
className="text-[#f0932b] hover:underline font-semibold"
className="text-[#F0932B] hover:underline font-semibold"
>
Ver perfil
</Link>
@ -319,11 +319,11 @@ export default function CompaniesPage() {
{filteredCompanies.map((company) => (
<div
key={company.id}
className="bg-white rounded-2xl p-6 shadow-md hover:shadow-xl transition-all duration-300 border border-gray-200 hover:border-[#f0932b]"
className="bg-white rounded-2xl p-6 shadow-md hover:shadow-xl transition-all duration-300 border border-gray-200 hover:border-[#F0932B]"
>
<div className="flex items-start justify-between mb-4">
<div className="w-14 h-14 rounded-lg bg-gray-100 flex items-center justify-center">
<Building2 className="w-7 h-7 text-[#f0932b]" />
<Building2 className="w-7 h-7 text-[#F0932B]" />
</div>
{company.featured && (
<span className="bg-yellow-100 text-yellow-700 text-xs font-semibold px-2 py-1 rounded-full">
@ -335,7 +335,7 @@ export default function CompaniesPage() {
<h3 className="text-xl font-bold text-gray-900 mb-2">{company.name}</h3>
<div className="flex items-center gap-2 mb-3">
<span className="bg-[#f0932b]/10 text-[#f0932b] px-3 py-1 rounded-full text-xs font-semibold">
<span className="bg-[#F0932B]/10 text-[#F0932B] px-3 py-1 rounded-full text-xs font-semibold">
{company.industry}
</span>
<div className="flex items-center gap-1">
@ -358,12 +358,12 @@ export default function CompaniesPage() {
</div>
<div className="pt-4 border-t border-gray-100 flex items-center justify-between">
<span className="text-[#f0932b] font-semibold text-sm">
<span className="text-[#F0932B] font-semibold text-sm">
{company.openJobs} vagas
</span>
<Link
href={`/companies/${company.id}`}
className="text-gray-600 hover:text-[#f0932b] font-semibold text-sm transition-colors"
className="text-gray-600 hover:text-[#F0932B] font-semibold text-sm transition-colors"
>
Ver mais
</Link>

View file

@ -5,9 +5,6 @@ import { useRouter, useParams } from "next/navigation";
import { toast } from "sonner";
import { emailTemplatesApi, EmailTemplate } from "@/lib/api";
export const runtime = 'edge';
export default function EditEmailTemplatePage() {
const router = useRouter();
const params = useParams();

View file

@ -12,9 +12,6 @@ import { toast } from "sonner"
import { Send, ArrowLeft } from "lucide-react"
import { formatDistanceToNow } from "date-fns"
export const runtime = 'edge';
export default function TicketDetailsPage() {
const params = useParams()
const router = useRouter()

View file

@ -27,9 +27,6 @@ import {
DialogTitle,
} from "@/components/ui/dialog"
export const runtime = 'edge';
export default function AdminTicketDetailsPage() {
const params = useParams()
const router = useRouter()

View file

@ -57,7 +57,7 @@ body {
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.705 0.188 57.5); /* #f0932b Orange */
--primary: oklch(0.705 0.188 57.5); /* #F0932B Orange */
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
@ -91,7 +91,7 @@ body {
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.705 0.188 57.5); /* #f0932b Orange */
--primary: oklch(0.705 0.188 57.5); /* #F0932B Orange */
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);

View file

@ -49,11 +49,6 @@ import { useTranslation } from "@/lib/i18n";
import { getCurrentUser } from "@/lib/auth";
export const runtime = 'edge';
export default function JobApplicationPage({
params,
}: {

View file

@ -37,9 +37,6 @@ import Link from "next/link";
import { motion } from "framer-motion";
import { useTranslation } from "@/lib/i18n";
export const runtime = 'edge';
export default function JobDetailPage({
params,
}: {

View file

@ -151,13 +151,17 @@ function JobsContent() {
return (
<>
{/* Hero Section */}
<section className="bg-gradient-to-br from-primary/10 via-primary/5 to-transparent py-12 md:py-16">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto text-center">
<section className="relative bg-[#F0932B] py-12 md:py-16 overflow-hidden">
<div className="absolute inset-0 opacity-10">
<div className="absolute top-0 left-0 w-full h-full bg-[radial-gradient(circle_at_30%_50%,rgba(255,255,255,0.2)_0%,transparent_50%)]"></div>
</div>
<div className="container mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div className="max-w-3xl mx-auto text-center text-white">
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="text-4xl md:text-5xl font-bold text-foreground mb-4 text-balance"
className="text-4xl md:text-5xl font-bold mb-4 text-balance"
>
{t('jobs.title')}
</motion.h1>
@ -165,7 +169,7 @@ function JobsContent() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="text-lg text-muted-foreground text-pretty"
className="text-lg opacity-95 text-pretty"
>
{loading ? t('jobs.loading') : t('jobs.subtitle', { count: totalJobs })}
</motion.p>
@ -174,7 +178,7 @@ function JobsContent() {
</section>
{/* Search and Filters Section */}
<section className="py-8 border-b bg-background/50">
<section className="py-8 border-b bg-white">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-5xl mx-auto space-y-4">
{/* Main Search Bar */}
@ -203,12 +207,12 @@ function JobsContent() {
<Button
variant="outline"
onClick={() => setShowFilters(!showFilters)}
className="h-12 gap-2"
className="h-12 gap-2 hover:bg-[#F0932B]/10 hover:text-[#F0932B] hover:border-[#F0932B]"
>
<SlidersHorizontal className="h-4 w-4" />
{t('jobs.filters.toggle')}
{hasActiveFilters && (
<Badge variant="secondary" className="ml-1 px-1 py-0 text-xs">
<Badge variant="secondary" className="ml-1 px-1 py-0 text-xs bg-[#F0932B] text-white">
!
</Badge>
)}
@ -290,7 +294,7 @@ function JobsContent() {
<Button
variant="outline"
onClick={clearFilters}
className="gap-2"
className="gap-2 hover:bg-red-50 hover:text-red-600 hover:border-red-300"
>
<X className="h-4 w-4" />
{t('jobs.reset')}
@ -316,7 +320,7 @@ function JobsContent() {
<div className="flex items-center gap-2 flex-wrap">
<span className="hidden sm:inline">Active filters:</span>
{searchTerm && (
<Badge variant="secondary" className="gap-1">
<Badge variant="secondary" className="gap-1 bg-[#F0932B]/10 text-[#F0932B] border-[#F0932B]/20">
"{searchTerm}"
<button onClick={() => setSearchTerm("")} className="ml-1">
<X className="h-3 w-3" />
@ -324,7 +328,7 @@ function JobsContent() {
</Badge>
)}
{locationFilter && (
<Badge variant="secondary" className="gap-1">
<Badge variant="secondary" className="gap-1 bg-[#F0932B]/10 text-[#F0932B] border-[#F0932B]/20">
{locationFilter}
<button onClick={() => setLocationFilter("")} className="ml-1">
<X className="h-3 w-3" />
@ -332,7 +336,7 @@ function JobsContent() {
</Badge>
)}
{typeFilter !== "all" && (
<Badge variant="secondary" className="gap-1">
<Badge variant="secondary" className="gap-1 bg-[#F0932B]/10 text-[#F0932B] border-[#F0932B]/20">
{typeFilter}
<button onClick={() => setTypeFilter("all")} className="ml-1">
<X className="h-3 w-3" />
@ -340,7 +344,7 @@ function JobsContent() {
</Badge>
)}
{workModeFilter !== "all" && (
<Badge variant="secondary" className="gap-1">
<Badge variant="secondary" className="gap-1 bg-[#F0932B]/10 text-[#F0932B] border-[#F0932B]/20">
{workModeFilter === "remote" ? t("workMode.remote") :
workModeFilter === "hybrid" ? t("workMode.hybrid") :
workModeFilter === "onsite" ? t("workMode.onsite") : workModeFilter}
@ -357,7 +361,7 @@ function JobsContent() {
</section>
{/* Jobs Grid */}
<section className="py-12">
<section className="py-12 bg-white">
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-5xl mx-auto">
{error && (
@ -394,6 +398,7 @@ function JobsContent() {
variant="outline"
onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
disabled={currentPage === 1}
className="hover:bg-[#F0932B]/10 hover:text-[#F0932B] hover:border-[#F0932B]"
>
{t('jobs.pagination.previous')}
</Button>
@ -404,6 +409,7 @@ function JobsContent() {
variant="outline"
onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
disabled={currentPage === totalPages}
className="hover:bg-[#F0932B]/10 hover:text-[#F0932B] hover:border-[#F0932B]"
>
{t('jobs.pagination.next')}
</Button>
@ -425,7 +431,7 @@ function JobsContent() {
<Button
variant="outline"
onClick={clearFilters}
className="gap-2"
className="gap-2 hover:bg-[#F0932B]/10 hover:text-[#F0932B] hover:border-[#F0932B]"
>
<X className="h-4 w-4" />
{t('jobs.resetFilters')}

View file

@ -7,7 +7,7 @@ import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { mockJobs, mockTestimonials } from "@/lib/mock-data"
import { FileText, CheckCircle, ArrowRight, Building2, Users, ChevronLeft, ChevronRight } from "lucide-react"
import { FileText, CheckCircle, ArrowRight, Building2, Users, ChevronLeft, ChevronRight, Eye } from "lucide-react"
import Link from "next/link"
import { motion } from "framer-motion"
import Image from "next/image"
@ -24,6 +24,22 @@ export default function HomePage() {
const [loading, setLoading] = useState(true)
const [featuredIndex, setFeaturedIndex] = useState(0)
const [moreJobsIndex, setMoreJobsIndex] = useState(0)
const [openFilters, setOpenFilters] = useState({
contractType: false,
workMode: false,
location: false,
salary: false
})
const toggleFilter = (filterName: keyof typeof openFilters) => {
setOpenFilters(prev => ({
contractType: false,
workMode: false,
location: false,
salary: false,
[filterName]: !prev[filterName]
}))
}
useEffect(() => {
async function fetchFeaturedJobs() {
@ -114,15 +130,15 @@ export default function HomePage() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-4xl sm:text-5xl lg:text-5xl font-bold mb-4 text-white"
className="text-5xl sm:text-6xl lg:text-6xl font-bold mb-6 text-white leading-tight"
>
{t('home.hero.title')}<br/>{t('home.hero.titleLine2')}
{t('home.hero.title')}<br />{t('home.hero.titleLine2')}
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 }}
className="text-base mb-8 leading-relaxed text-white"
className="text-2xl mb-10 leading-relaxed text-white"
>
{t('home.hero.subtitle')}
</motion.p>
@ -133,7 +149,7 @@ export default function HomePage() {
className="flex gap-4"
>
<Link href="/jobs">
<Button size="lg" className="bg-primary hover:bg-primary/90 text-white hover:shadow-lg font-semibold px-8 py-3 text-base rounded-lg transition-all duration-200 border-0">
<Button size="lg" className="bg-primary hover:bg-primary/90 text-white hover:shadow-lg font-bold px-10 py-6 text-lg rounded-lg transition-all duration-200 border-0">
{t('home.hero.cta')}
</Button>
</Link>
@ -147,7 +163,7 @@ export default function HomePage() {
<section className="bg-white py-16">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-8xl">
<div className="mb-8">
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-3 mb-6">
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-0 mb-6">
<div className="flex-1 relative">
<svg className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
@ -155,74 +171,270 @@ export default function HomePage() {
<input
type="text"
placeholder={t('home.search.placeholder')}
className="w-full h-14 pl-12 pr-4 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent text-base bg-white shadow-sm"
className="w-full h-14 pl-12 pr-4 border border-gray-300 rounded-l-lg rounded-r-none focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent text-base bg-white shadow-sm"
/>
</div>
<Button className="bg-primary hover:bg-primary/90 text-white h-14 px-10 rounded-lg font-semibold flex items-center justify-center gap-2 shadow-md hover:shadow-lg transition-all">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
<Button className="bg-primary hover:bg-primary/90 text-white h-14 px-16 rounded-r-lg rounded-l-none font-semibold flex items-center justify-center gap-3 shadow-md hover:shadow-lg transition-all -ml-px min-w-[220px] text-2xl">
<FilterIcon />
{t('home.search.filter')}
</Button>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="bg-white border-2 border-gray-200 rounded-xl p-5 shadow-sm hover:border-primary/30 transition-colors">
<div className="flex items-center justify-between w-full mb-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 items-start">
<div className="bg-white border-2 border-gray-200 rounded-xl shadow-sm hover:border-primary/30 transition-colors relative">
<button
onClick={() => toggleFilter('contractType')}
className="flex items-center justify-between w-full p-5"
>
<span className="text-base font-bold text-gray-900">{t('home.search.contractType')}</span>
</div>
<div className="space-y-3">
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.pj')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.clt')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.freelancer')}</span>
</label>
</div>
<svg
className={`w-5 h-5 text-gray-600 transition-transform ${openFilters.contractType ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openFilters.contractType && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className="absolute top-full left-0 right-0 mt-2 bg-white border-2 border-gray-200 rounded-xl shadow-lg z-50 space-y-3 px-5 py-5"
>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.pj')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.clt')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.freelancer')}</span>
</label>
</motion.div>
)}
</div>
<div className="bg-white border-2 border-gray-200 rounded-xl p-5 shadow-sm hover:border-primary/30 transition-colors">
<div className="flex items-center justify-between w-full mb-4">
<div className="bg-white border-2 border-gray-200 rounded-xl shadow-sm hover:border-primary/30 transition-colors relative">
<button
onClick={() => toggleFilter('workMode')}
className="flex items-center justify-between w-full p-5"
>
<span className="text-base font-bold text-gray-900">{t('home.search.workMode')}</span>
</div>
<div className="space-y-3">
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.homeOffice')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.presencial')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.hybrid')}</span>
</label>
</div>
<svg
className={`w-5 h-5 text-gray-600 transition-transform ${openFilters.workMode ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openFilters.workMode && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className="absolute top-full left-0 right-0 mt-2 bg-white border-2 border-gray-200 rounded-xl shadow-lg z-50 space-y-3 px-5 py-5"
>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.homeOffice')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.presencial')}</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>{t('home.search.hybrid')}</span>
</label>
</motion.div>
)}
</div>
<div className="bg-white border-2 border-gray-200 rounded-xl p-5 shadow-sm hover:border-primary/30 transition-colors">
<div className="flex items-center justify-between w-full mb-4">
<div className="bg-white border-2 border-gray-200 rounded-xl shadow-sm hover:border-primary/30 transition-colors relative">
<button
onClick={() => toggleFilter('location')}
className="flex items-center justify-between w-full p-5"
>
<span className="text-base font-bold text-gray-900">{t('home.search.location')}</span>
</div>
<select className="w-full px-4 py-2.5 text-sm text-gray-700 bg-gray-50 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
<option>{t('home.search.select')}</option>
</select>
<svg
className={`w-5 h-5 text-gray-600 transition-transform ${openFilters.location ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openFilters.location && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className="absolute top-full left-0 right-0 mt-2 bg-white border-2 border-gray-200 rounded-xl shadow-lg z-50 space-y-3 max-h-64 overflow-y-auto px-5 py-5 scrollbar-hide"
>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Acre, AC</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Alagoas, AL</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Amapá, AP</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Amazonas, AM</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Bahia, BA</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Ceará, CE</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Distrito Federal, DF</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Espírito Santo, ES</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Goiás, GO</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Maranhão, MA</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Mato Grosso, MT</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Mato Grosso do Sul, MS</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Minas Gerais, MG</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Pará, PA</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Paraíba, PB</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Paraná, PR</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Pernambuco, PE</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Piauí, PI</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Rio de Janeiro, RJ</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Rio Grande do Norte, RN</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Rio Grande do Sul, RS</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Rondônia, RO</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Roraima, RR</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Santa Catarina, SC</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>São Paulo, SP</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Sergipe, SE</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Tocantins, TO</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Remoto</span>
</label>
</motion.div>
)}
</div>
<div className="bg-white border-2 border-gray-200 rounded-xl p-5 shadow-sm hover:border-primary/30 transition-colors">
<div className="flex items-center justify-between w-full mb-4">
<div className="bg-white border-2 border-gray-200 rounded-xl shadow-sm hover:border-primary/30 transition-colors relative">
<button
onClick={() => toggleFilter('salary')}
className="flex items-center justify-between w-full p-5"
>
<span className="text-base font-bold text-gray-900">{t('home.search.salary')}</span>
</div>
<select className="w-full px-4 py-2.5 text-sm text-gray-700 bg-gray-50 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
<option>{t('home.search.select')}</option>
</select>
<svg
className={`w-5 h-5 text-gray-600 transition-transform ${openFilters.salary ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openFilters.salary && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
className="absolute top-full left-0 right-0 mt-2 bg-white border-2 border-gray-200 rounded-xl shadow-lg z-50 space-y-3 px-5 py-5"
>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Até R$ 3.000</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>R$ 3.000 - R$ 6.000</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>R$ 6.000 - R$ 10.000</span>
</label>
<label className="flex items-center text-sm text-gray-700 cursor-pointer hover:text-gray-900 transition-colors">
<input type="checkbox" className="w-4 h-4 text-primary border-gray-300 rounded focus:ring-primary mr-3" />
<span>Acima de R$ 10.000</span>
</label>
</motion.div>
)}
</div>
</div>
</div>
@ -233,85 +445,82 @@ export default function HomePage() {
<section className="bg-white py-12">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-8xl">
<div className="flex justify-between items-center mb-8">
<h2 className="text-2xl font-bold text-gray-900">{t('home.featuredJobs.title')}</h2>
<div className="flex gap-2">
<Button
variant="outline"
size="icon"
onClick={() => setFeaturedIndex(Math.max(0, featuredIndex - 8))}
disabled={featuredIndex === 0}
className="h-10 w-10"
>
<ChevronLeft className="h-5 w-5" />
</Button>
<Button
variant="outline"
size="icon"
onClick={() => {
const jobs = featuredJobs.length >= 16 ? featuredJobs.slice(0, 16) : mockJobs.slice(0, 16)
setFeaturedIndex(Math.min(jobs.length - 8, featuredIndex + 8))
}}
disabled={featuredIndex >= ((featuredJobs.length >= 16 ? featuredJobs.slice(0, 16) : mockJobs.slice(0, 16)).length - 8)}
className="h-10 w-10"
>
<ChevronRight className="h-5 w-5" />
</Button>
</div>
<h2 className="text-3xl font-bold text-gray-900">Vagas em Destaque</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{(featuredJobs.length >= 16 ? featuredJobs.slice(0, 16) : mockJobs.slice(0, 16))
.slice(featuredIndex, featuredIndex + 8)
{(featuredJobs.length >= 4 ? featuredJobs.slice(0, 4) : mockJobs.slice(0, 4))
.map((job, index) => {
const dates = ['02/06', '05/06', '08/06', '11/06', '14/06', '17/06', '19/06', '20/06'];
const randomDate = dates[(featuredIndex + index) % dates.length];
const dates = ['02/06', '05/06', '08/06', '11/06'];
const randomDate = dates[index % dates.length];
const levels = ['Pleno', 'Júnior', 'Sênior', 'Pleno'];
const level = levels[index % levels.length];
const statusLabels = ['Remoto', 'Híbrido', 'Presencial', 'Remoto'];
const statusLabel = statusLabels[index % statusLabels.length];
return (
<motion.div
key={job.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<Card className="hover:shadow-xl transition-shadow border border-gray-200 rounded-2xl overflow-hidden bg-white h-full flex flex-col">
{/* Ícone no topo */}
<div className="p-6 pb-4">
<div className="w-14 h-14 bg-gray-100 rounded-xl flex items-center justify-center mb-4">
<Building2 className="w-7 h-7 text-gray-900" />
</div>
{/* Título */}
<h3 className="font-bold text-lg mb-3 text-gray-900 line-clamp-2 min-h-[3.5rem]">{job.title}</h3>
{/* Tags */}
<div className="flex flex-wrap gap-2 mb-3">
<span className="text-xs px-3 py-1 bg-blue-50 text-blue-700 rounded-md border border-blue-200">
{job.company}
</span>
<span className="text-xs px-3 py-1 bg-blue-50 text-blue-700 rounded-md border border-blue-200">
{job.location}
<motion.div
key={job.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<Card className="hover:shadow-lg transition-all border border-gray-200 rounded-2xl overflow-hidden bg-white h-full flex flex-col">
{/* Header com logo, nome da empresa, seta e badge */}
<div className="flex items-center justify-between p-4 border-b border-gray-100">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-gray-100 rounded-lg flex items-center justify-center flex-shrink-0">
<Building2 className="w-5 h-5 text-gray-700" />
</div>
<span className="text-sm font-medium text-gray-900 truncate">{job.company}</span>
<svg className="w-4 h-4 text-gray-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
<span className="text-xs px-3 py-1 bg-gray-900 text-white rounded-full font-medium flex-shrink-0">
{statusLabel}
</span>
</div>
{/* Data */}
<div className="flex items-center gap-1.5 text-gray-500 mb-4">
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span className="text-xs">{randomDate}</span>
{/* Background Image */}
<div className="relative h-32 bg-gradient-to-br from-blue-50 to-purple-50 flex items-center justify-center overflow-hidden">
<Image
src="/111.png"
alt="Background"
fill
className="object-cover"
quality={100}
/>
</div>
</div>
{/* Botão */}
<div className="px-6 pb-6 mt-auto">
<Link href={`/jobs/${job.id}`}>
<Button size="lg" className="w-full bg-primary hover:bg-primary/90 text-white rounded-lg font-semibold shadow-lg">
{t('home.featuredJobs.apply')}
</Button>
</Link>
</div>
</Card>
</motion.div>
)})}
<CardContent className="p-5 flex flex-col flex-1">
{/* Título da vaga */}
<h3 className="font-bold text-lg text-gray-900 mb-2 line-clamp-2">{job.title}</h3>
{/* Info do nível */}
<div className="mb-4 pb-4 border-b border-gray-200">
<p className="text-sm text-gray-500">{level} · {job.location}</p>
</div>
{/* Botões */}
<div className="mt-auto flex gap-2">
<Button
variant="outline"
className="flex-1 border-gray-300 text-gray-700 hover:bg-gray-50 rounded-lg font-medium h-9 text-sm flex items-center justify-center gap-2"
>
<Eye className="w-4 h-4" />
Ver Vaga
</Button>
<Link href={`/jobs/${job.id}`} className="flex-1">
<Button className="w-full bg-gray-900 hover:bg-gray-800 text-white rounded-lg font-medium h-9 text-sm">
Aplicar agora
</Button>
</Link>
</div>
</CardContent>
</Card>
</motion.div>
)
})}
</div>
</div>
</section>
@ -319,14 +528,16 @@ export default function HomePage() {
{/* More Jobs Section */}
<section className="bg-white py-12">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-8xl">
<div className="flex justify-between items-center mb-6">
<h2 className="text-2xl font-bold text-gray-900">{t('home.moreJobs.title')}</h2>
<div className="flex justify-between items-center mb-8">
<h2 className="text-3xl font-bold text-gray-900">{t('home.moreJobs.title')}</h2>
<Link href="/jobs">
<Button className="bg-primary hover:bg-primary/90 text-white rounded-md px-6 py-2">{t('home.moreJobs.viewAll')}</Button>
<Button className="bg-primary hover:bg-primary/90 text-white rounded-lg px-10 py-4 font-bold text-lg min-w-[220px]">
{t('home.moreJobs.viewAll')}
</Button>
</Link>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{mockJobs.slice(0, 8)
.map((job, index) => {
const colors = [
@ -338,57 +549,47 @@ export default function HomePage() {
const icon = icons[index % icons.length];
return (
<motion.div
key={job.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<Card className="hover:shadow-lg transition-all border border-gray-200 bg-white rounded-xl overflow-hidden group cursor-pointer h-full">
<CardContent className="p-5">
{/* Cabeçalho com logo e seta */}
<div className="flex items-start justify-between mb-4">
<div className="flex items-start gap-3 flex-1">
<div className={`w-12 h-12 ${bgColor} rounded-full flex items-center justify-center text-white text-xl flex-shrink-0`}>
{icon}
</div>
<div className="flex-1 min-w-0">
<h3 className="font-bold text-base text-gray-900 line-clamp-1 mb-1">{job.title}</h3>
<p className="text-sm text-gray-600 line-clamp-1">{job.company}</p>
<motion.div
key={job.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
<Card className="hover:shadow-lg transition-all border border-gray-200 bg-white rounded-xl overflow-hidden group cursor-pointer h-full">
<CardContent className="p-5">
{/* Cabeçalho com logo e seta */}
<div className="flex items-start justify-between mb-4">
<div className="flex items-start gap-3 flex-1">
<div className={`w-12 h-12 ${bgColor} rounded-full flex items-center justify-center text-white text-xl flex-shrink-0`}>
{icon}
</div>
<div className="flex-1 min-w-0">
<h3 className="font-bold text-base text-gray-900 line-clamp-1 mb-1">{job.title}</h3>
<p className="text-sm text-gray-600 line-clamp-1">{job.company}</p>
</div>
</div>
<ChevronRight className="w-5 h-5 text-gray-400 group-hover:text-gray-600 transition-colors flex-shrink-0 ml-2" />
</div>
<ChevronRight className="w-5 h-5 text-gray-400 group-hover:text-gray-600 transition-colors flex-shrink-0 ml-2" />
</div>
{/* Tags */}
<div className="mb-4">
<div className="flex flex-wrap gap-1.5">
<span className="text-xs px-2 py-0.5 bg-gray-100 text-gray-700 rounded">
{job.location}
</span>
<span className="text-xs px-2 py-0.5 bg-gray-100 text-gray-700 rounded">
{job.type}
</span>
{/* Rodapé com botões */}
<div className="flex items-center gap-2 pt-3 border-t border-gray-100">
<button className="flex-1 flex items-center justify-center gap-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors h-9 px-3">
<svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
</svg>
<span className="text-xs font-medium text-gray-700">Favoritar</span>
</button>
<Link href={`/jobs/${job.id}`} className="flex-1">
<Button size="sm" className="w-full bg-primary hover:bg-primary/90 text-white rounded-md font-medium text-xs h-9">
Aplicar agora
</Button>
</Link>
</div>
</div>
{/* Rodapé com botões */}
<div className="flex items-center gap-2 pt-3 border-t border-gray-100">
<Link href={`/jobs/${job.id}`} className="flex-1">
<Button size="sm" className="w-full bg-primary hover:bg-primary/90 text-white rounded-md font-medium text-xs h-8">
Aplicar agora
</Button>
</Link>
<button className="w-8 h-8 flex items-center justify-center border border-gray-300 rounded-md hover:bg-gray-50 transition-colors">
<svg className="w-4 h-4 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z" />
</svg>
</button>
</div>
</CardContent>
</Card>
</motion.div>
)})}
</CardContent>
</Card>
</motion.div>
)
})}
</div>
</div>
</section>
@ -399,27 +600,30 @@ export default function HomePage() {
<div className="bg-primary rounded-2xl overflow-hidden shadow-lg relative">
<div className="absolute inset-0 z-0">
<Image
src="/12.png"
src="/18.png"
alt="Background"
fill
className="object-cover object-right"
quality={100}
priority
/>
</div>
<div className="grid lg:grid-cols-2 gap-8 items-center p-8 lg:p-12 relative z-10">
{/* Text Content */}
<div className="text-white">
<div className="flex items-center gap-2 mb-6">
<Users className="w-6 h-6" />
<span className="font-medium text-sm">{t('home.cta.badge')}</span>
<div className="w-8 h-8 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-white font-bold text-lg">$</span>
</div>
<span className="font-medium text-base">{t('home.cta.badge')}</span>
</div>
<h2 className="text-3xl lg:text-4xl font-bold mb-4 leading-tight">
<h2 className="text-3xl lg:text-4xl font-bold mb-4 leading-tight whitespace-nowrap">
{t('home.cta.title')}
</h2>
<p className="mb-6 text-white/90 text-sm">
<p className="mb-6 text-white/90 text-lg">
{t('home.cta.subtitle')}
</p>
<Button size="lg" className="bg-white text-primary hover:bg-white/90 font-semibold px-8 rounded-md">
<Button size="lg" className="bg-white text-primary hover:bg-white/90 font-bold px-12 py-7 text-xl rounded-lg">
{t('home.cta.button')}
</Button>
</div>
@ -433,3 +637,13 @@ export default function HomePage() {
</div>
)
}
function FilterIcon() {
return (
<svg width="44" height="44" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="w-11 h-11">
<rect x="4" y="7" width="16" height="3" rx="1.5" fill="white" />
<rect x="7" y="12" width="10" height="3" rx="1.5" fill="white" />
<rect x="10" y="17" width="4" height="3" rx="1.5" fill="white" />
</svg>
);
}

View file

@ -43,7 +43,7 @@ export default function PublicarVagaPage() {
<main className="flex-1 flex">
{/* Left Side - Brand Section */}
<div className="hidden lg:flex lg:w-2/5 bg-[#f0932b] relative overflow-hidden">
<div className="hidden lg:flex lg:w-2/5 bg-[#F0932B] relative overflow-hidden">
<Image
src="/6.png"
alt="Background"
@ -326,7 +326,7 @@ export default function PublicarVagaPage() {
<div className="pt-4">
<button
type="submit"
className="w-full bg-[#f0932b] hover:bg-[#e8871e] text-white font-bold py-4 rounded-full text-lg transition-colors shadow-lg hover:shadow-xl"
className="w-full bg-[#F0932B] hover:bg-[#d97d1a] text-white font-bold py-4 rounded-full text-lg transition-colors shadow-lg hover:shadow-xl"
>
ANUNCIAR VAGA GRÁTIS
</button>

View file

@ -329,7 +329,7 @@ export default function RegisterUserPage() {
<Button
type="submit"
className="w-full h-11 cursor-pointer bg-[#f0932b] hover:bg-[#e8871e]"
className="w-full h-11 cursor-pointer bg-[#F0932B] hover:bg-[#d97d1a]"
disabled={loading}
>
{loading ? "Criando conta..." : "Criar Conta"}

View file

@ -12,14 +12,16 @@ export function Footer() {
<div className="container mx-auto px-4 sm:px-6 lg:px-8 max-w-8xl">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
<div>
<h3 className="font-bold mb-4 text-gray-900">Informações</h3>
<h3 className="font-bold mb-4 text-gray-900 text-lg">Informações</h3>
<ul className="space-y-3">
<li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/about" className="text-sm text-gray-600 hover:text-primary transition-colors">
Sobre nós
</Link>
</li>
<li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/contact" className="text-sm text-gray-600 hover:text-primary transition-colors">
Contato
</Link>
@ -28,14 +30,16 @@ export function Footer() {
</div>
<div>
<h3 className="font-bold mb-4 text-gray-900">Para Candidatos</h3>
<h3 className="font-bold mb-4 text-gray-900 text-lg">Para Candidatos</h3>
<ul className="space-y-3">
<li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/jobs" className="text-sm text-gray-600 hover:text-primary transition-colors">
Buscar Vagas
</Link>
</li>
<li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/register/user" className="text-sm text-gray-600 hover:text-primary transition-colors">
Criar Conta
</Link>
@ -44,9 +48,10 @@ export function Footer() {
</div>
<div>
<h3 className="font-bold mb-4 text-gray-900">Para Empresas</h3>
<h3 className="font-bold mb-4 text-gray-900 text-lg">Para Empresas</h3>
<ul className="space-y-3">
<li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/publicar-vaga" className="text-sm text-gray-600 hover:text-primary transition-colors">
Publicar Vaga
</Link>
@ -55,7 +60,7 @@ export function Footer() {
</div>
<div>
<h3 className="font-bold mb-4 text-gray-900">Redes Sociais</h3>
<h3 className="font-bold mb-4 text-gray-900 text-lg">Redes Sociais</h3>
<div className="flex gap-3">
<a href="#" className="w-10 h-10 rounded-lg border-2 border-gray-300 hover:bg-gray-50 text-[#1F2F40] flex items-center justify-center transition-colors">
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">

View file

@ -20,7 +20,10 @@
"about": "About",
"contact": "Contact",
"login": "Login",
"register": "Register"
"register": "Register",
"language": "Language",
"registerUser": "Register User",
"registerCompany": "Register Company"
},
"about": {
"hero": {

View file

@ -20,7 +20,10 @@
"about": "Sobre",
"contact": "Contacto",
"login": "Ingresar",
"register": "Registrarse"
"register": "Registrarse",
"language": "Idioma",
"registerUser": "Registrar Usuario",
"registerCompany": "Registrar Empresa"
},
"about": {
"hero": {

View file

@ -53,7 +53,10 @@
"about": "Sobre",
"contact": "Contato",
"login": "Entrar",
"register": "Cadastrar"
"register": "Cadastrar",
"language": "Idioma",
"registerUser": "Cadastrar Usuário",
"registerCompany": "Cadastrar Empresa"
},
"about": {
"hero": {
@ -145,11 +148,10 @@
},
"home": {
"hero": {
"title": "Encontre o emprego certo, de forma simples",
"subtitle": "Conectamos candidatos e empresas de forma rápida e direta",
"searchJobs": "Procurar vagas",
"imCompany": "Sou empresa",
"postJob": "Postar vaga"
"title": "Encontre a Vaga de TI",
"titleLine2": "dos Seus Sonhos",
"subtitle": "Conectamos você com as melhores empresas e techs.",
"cta": "Buscar Vagas"
},
"featured": {
"title": "Vagas em Destaque",
@ -1226,7 +1228,7 @@
},
"home": {
"hero": {
"title": "Encontre a Vaga de TI.",
"title": "Encontre a Vaga de TI",
"titleLine2": "dos Seus Sonhos.",
"subtitle": "Conectamos você com as melhores empresas e techs.",
"cta": "Buscar Vagas"