forked from git.gladyson/openmonetis
chore: adicionar configuração de dependências no pnpm-workspace
Adiciona a configuração 'onlyBuiltDependencies' no arquivo pnpm-workspace.yaml, especificando as dependências que devem ser construídas: esbuild, sharp e unrs-resolver. Essa mudança visa otimizar o gerenciamento de dependências no projeto.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,6 +22,7 @@ next-env.d.ts
|
|||||||
/build
|
/build
|
||||||
/dist
|
/dist
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
.pnpm-store
|
||||||
|
|
||||||
# === Testing ===
|
# === Testing ===
|
||||||
/coverage
|
/coverage
|
||||||
|
|||||||
314
README.md
314
README.md
@@ -1,6 +1,8 @@
|
|||||||
# OpenSheets
|
# OpenSheets
|
||||||
|
|
||||||
> Uma aplicação moderna e completa construída com **Next.js 16**, **Better Auth**, **Drizzle ORM**, **PostgreSQL** e **shadcn/ui**.
|
> Projeto pessoal de gestão financeira. Self-hosted, manual e open source.
|
||||||
|
|
||||||
|
> **⚠️ Não há versão online hospedada.** Você precisa clonar o repositório e rodar localmente ou no seu próprio servidor.
|
||||||
|
|
||||||
[](https://nextjs.org/)
|
[](https://nextjs.org/)
|
||||||
[](https://www.typescriptlang.org/)
|
[](https://www.typescriptlang.org/)
|
||||||
@@ -23,23 +25,78 @@
|
|||||||
- [Configuração de Variáveis de Ambiente](#-configuração-de-variáveis-de-ambiente)
|
- [Configuração de Variáveis de Ambiente](#-configuração-de-variáveis-de-ambiente)
|
||||||
- [Banco de Dados](#-banco-de-dados)
|
- [Banco de Dados](#-banco-de-dados)
|
||||||
- [Arquitetura](#-arquitetura)
|
- [Arquitetura](#-arquitetura)
|
||||||
- [Troubleshooting](#-troubleshooting)
|
|
||||||
- [Contribuindo](#-contribuindo)
|
- [Contribuindo](#-contribuindo)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Sobre o Projeto
|
## 🎯 Sobre o Projeto
|
||||||
|
|
||||||
**OpenSheets** é uma aplicação full-stack moderna projetada para controle de finanças pessoais. Construída com as melhores práticas de desenvolvimento e ferramentas de ponta, oferece uma base sólida e escalável para gestão financeira completa.
|
**OpenSheets** é um projeto pessoal de gestão financeira que criei para organizar minhas próprias finanças. Cansei de usar planilhas desorganizadas e aplicativos que não fazem exatamente o que preciso, então decidi construir algo do jeito que funciona pra mim.
|
||||||
|
|
||||||
### Por que usar o OpenSheets?
|
A ideia é simples: ter um lugar onde consigo ver todas as minhas contas, cartões, gastos e receitas de forma clara. Se isso for útil pra você também, fique à vontade para usar e contribuir.
|
||||||
|
|
||||||
- ✅ **Pronto para Produção** - Docker, health checks, migrations automáticas
|
### ⚠️ Avisos importantes
|
||||||
- ✅ **TypeScript First** - Type safety em toda a aplicação
|
|
||||||
- ✅ **Autenticação Completa** - Better Auth com OAuth, email magic links
|
**1. Não há versão hospedada online**
|
||||||
- ✅ **ORM Moderno** - Drizzle com Drizzle Studio integrado
|
|
||||||
- ✅ **UI Components** - shadcn/ui com design system completo
|
Este projeto é self-hosted. Você precisa rodar no seu próprio computador ou servidor. Não existe uma versão pública online onde você pode simplesmente criar uma conta.
|
||||||
- ✅ **Developer Experience** - Hot reload, Turbopack, ESLint configurado
|
|
||||||
|
**2. Não há Open Finance**
|
||||||
|
|
||||||
|
Você precisa registrar manualmente suas transações. Se você procura algo que sincroniza automaticamente com seu banco, este projeto não é pra você.
|
||||||
|
|
||||||
|
**3. Requer disciplina**
|
||||||
|
|
||||||
|
O OpenSheets funciona melhor para quem:
|
||||||
|
|
||||||
|
- Tem disciplina de registrar os gastos regularmente
|
||||||
|
- Quer controle total sobre seus dados
|
||||||
|
- Gosta de entender exatamente onde o dinheiro está indo
|
||||||
|
- Sabe rodar projetos localmente ou tem vontade de aprender
|
||||||
|
|
||||||
|
Se você não se importa em dedicar alguns minutos por dia (ou semana) para manter tudo atualizado, vai funcionar bem. Caso contrário, provavelmente vai abandonar depois de uma semana.
|
||||||
|
|
||||||
|
### O que tem aqui
|
||||||
|
|
||||||
|
💰 **Controle de contas e transações**
|
||||||
|
|
||||||
|
- Registre suas contas bancárias, cartões e dinheiro em espécie
|
||||||
|
- Adicione receitas, despesas e transferências entre contas
|
||||||
|
- Organize tudo por categorias (moradia, alimentação, transporte, etc.)
|
||||||
|
- Veja o saldo atual de cada conta
|
||||||
|
|
||||||
|
📊 **Relatórios e gráficos**
|
||||||
|
|
||||||
|
- Dashboard com resumo mensal das suas finanças
|
||||||
|
- Gráficos de evolução do patrimônio
|
||||||
|
- Comparação de gastos por categoria
|
||||||
|
- Entenda pra onde seu dinheiro está indo
|
||||||
|
|
||||||
|
💳 **Faturas de cartão de crédito**
|
||||||
|
|
||||||
|
- Cadastre seus cartões e acompanhe as faturas
|
||||||
|
- Veja o que ainda não foi fechado na fatura atual
|
||||||
|
- Controle de limites e vencimentos
|
||||||
|
|
||||||
|
🎯 **Orçamentos**
|
||||||
|
|
||||||
|
- Defina quanto quer gastar por categoria no mês
|
||||||
|
- Acompanhe se está dentro do planejado
|
||||||
|
|
||||||
|
### Stack técnica
|
||||||
|
|
||||||
|
Construído com tecnologias modernas que facilitam o desenvolvimento:
|
||||||
|
|
||||||
|
- **Next.js 16** com App Router e Turbopack
|
||||||
|
- **TypeScript** em tudo
|
||||||
|
- **PostgreSQL 18** como banco de dados
|
||||||
|
- **Drizzle ORM** para trabalhar com o banco
|
||||||
|
- **Better Auth** para login (email + OAuth)
|
||||||
|
- **shadcn/ui** para os componentes da interface
|
||||||
|
- **Docker** para facilitar deploy e desenvolvimento
|
||||||
|
- **Tailwind CSS** para estilização
|
||||||
|
|
||||||
|
O projeto é open source, seus dados ficam no seu controle (pode rodar localmente ou no seu próprio servidor), e você pode customizar o que quiser.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -727,242 +784,6 @@ opensheets/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🆘 Troubleshooting
|
|
||||||
|
|
||||||
### Erro: "DATABASE_URL env variable is not set"
|
|
||||||
|
|
||||||
**Causa:** Arquivo `.env` não existe ou `DATABASE_URL` não configurado
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
# Edite .env e configure DATABASE_URL
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Container do app não conecta ao banco
|
|
||||||
|
|
||||||
**Causa:** `DATABASE_URL` usa `localhost` em vez de `db`
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
Para Docker, use o **nome do serviço**:
|
|
||||||
|
|
||||||
```env
|
|
||||||
# ❌ Errado (localhost não funciona dentro do container)
|
|
||||||
DATABASE_URL=postgresql://opensheets:senha@localhost:5432/opensheets_db
|
|
||||||
|
|
||||||
# ✅ Correto (usa nome do serviço Docker)
|
|
||||||
DATABASE_URL=postgresql://opensheets:senha@db:5432/opensheets_db
|
|
||||||
```
|
|
||||||
|
|
||||||
Para desenvolvimento local (sem Docker app):
|
|
||||||
|
|
||||||
```env
|
|
||||||
# ✅ Correto (app roda local, banco em Docker)
|
|
||||||
DATABASE_URL=postgresql://opensheets:senha@localhost:5432/opensheets_db
|
|
||||||
```
|
|
||||||
|
|
||||||
**Verifique o status do banco:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
docker compose logs db
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Porta 3000 ou 5432 já está em uso
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
Edite o `.env`:
|
|
||||||
|
|
||||||
```env
|
|
||||||
APP_PORT=3001
|
|
||||||
DB_PORT=5433
|
|
||||||
```
|
|
||||||
|
|
||||||
Ou pare o processo que está usando:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Descobrir quem usa a porta
|
|
||||||
lsof -i :3000
|
|
||||||
lsof -i :5432
|
|
||||||
|
|
||||||
# Matar processo
|
|
||||||
kill -9 <PID>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Migrations não rodam
|
|
||||||
|
|
||||||
**Com Docker:**
|
|
||||||
|
|
||||||
Migrations rodam automaticamente no startup. Veja logs:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm docker:logs:app
|
|
||||||
```
|
|
||||||
|
|
||||||
Se falharem, rode manualmente:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose exec app pnpm db:push
|
|
||||||
```
|
|
||||||
|
|
||||||
**Sem Docker:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm db:push
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Erro: "server.js not found"
|
|
||||||
|
|
||||||
**Causa:** Next.js não gerou standalone build
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
1. Verifique `next.config.ts`:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const nextConfig: NextConfig = {
|
|
||||||
output: "standalone", // ← Deve estar presente
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Rebuild:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose down
|
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Erro ao atualizar PostgreSQL 16 → 18
|
|
||||||
|
|
||||||
**Causa:** Volumes antigos são incompatíveis
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# ⚠️ ATENÇÃO: Isso apaga dados do banco local!
|
|
||||||
docker compose down -v
|
|
||||||
|
|
||||||
# Suba novamente com PostgreSQL 18
|
|
||||||
docker compose up --build
|
|
||||||
```
|
|
||||||
|
|
||||||
**Para preservar dados:**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Backup
|
|
||||||
docker compose exec db pg_dumpall -U opensheets > backup.sql
|
|
||||||
|
|
||||||
# 2. Limpa volumes
|
|
||||||
docker compose down -v
|
|
||||||
|
|
||||||
# 3. Sobe PG 18
|
|
||||||
docker compose up -d db
|
|
||||||
|
|
||||||
# 4. Aguarda (15s)
|
|
||||||
sleep 15
|
|
||||||
|
|
||||||
# 5. Restaura
|
|
||||||
docker compose exec -T db psql -U opensheets -d opensheets_db < backup.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Drizzle Studio não abre
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
1. Verifique se o banco está rodando:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose ps
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Teste conexão:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
psql $DATABASE_URL
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Abra Drizzle Studio:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pnpm db:studio
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Build do Docker muito lento
|
|
||||||
|
|
||||||
**Causa:** Cache não está sendo aproveitado
|
|
||||||
|
|
||||||
**Solução:**
|
|
||||||
|
|
||||||
1. Use BuildKit:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export DOCKER_BUILDKIT=1
|
|
||||||
docker compose build
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Limpe cache antigo:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker builder prune
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Multi-stage build já otimiza camadas
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### "Permission denied" ao rodar Docker
|
|
||||||
|
|
||||||
**Causa:** Usuário não está no grupo docker
|
|
||||||
|
|
||||||
**Solução (Linux):**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo usermod -aG docker $USER
|
|
||||||
newgrp docker
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solução (Mac/Windows):**
|
|
||||||
|
|
||||||
- Docker Desktop deve estar rodando
|
|
||||||
- Verifique configurações de permissão
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Limpar tudo e começar do zero
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Para containers e remove volumes
|
|
||||||
docker compose down -v
|
|
||||||
|
|
||||||
# Remove images não usadas
|
|
||||||
docker system prune -a
|
|
||||||
|
|
||||||
# Remove TUDO do Docker (cuidado!)
|
|
||||||
docker system prune -a --volumes
|
|
||||||
|
|
||||||
# Rebuild do zero
|
|
||||||
pnpm docker:up
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🤝 Contribuindo
|
## 🤝 Contribuindo
|
||||||
|
|
||||||
Contribuições são muito bem-vindas!
|
Contribuições são muito bem-vindas!
|
||||||
@@ -991,7 +812,6 @@ Contribuições são muito bem-vindas!
|
|||||||
### Padrões
|
### Padrões
|
||||||
|
|
||||||
- Use **TypeScript**
|
- Use **TypeScript**
|
||||||
- Siga o **ESLint** configurado
|
|
||||||
- Documente **features novas**
|
- Documente **features novas**
|
||||||
- Use **commits semânticos** (feat, fix, docs, etc)
|
- Use **commits semânticos** (feat, fix, docs, etc)
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ import {
|
|||||||
RiBankCardLine,
|
RiBankCardLine,
|
||||||
RiBarChartBoxLine,
|
RiBarChartBoxLine,
|
||||||
RiCalendarLine,
|
RiCalendarLine,
|
||||||
|
RiCodeSSlashLine,
|
||||||
|
RiDatabase2Line,
|
||||||
RiDeviceLine,
|
RiDeviceLine,
|
||||||
RiEyeOffLine,
|
RiGithubFill,
|
||||||
RiLineChartLine,
|
RiLineChartLine,
|
||||||
RiLockLine,
|
RiLockLine,
|
||||||
RiMoneyDollarCircleLine,
|
RiMoneyDollarCircleLine,
|
||||||
RiNotificationLine,
|
|
||||||
RiPieChartLine,
|
RiPieChartLine,
|
||||||
RiShieldCheckLine,
|
RiShieldCheckLine,
|
||||||
RiTimeLine,
|
RiTimeLine,
|
||||||
@@ -33,6 +34,29 @@ export default async function Page() {
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Logo />
|
<Logo />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Center Navigation Links */}
|
||||||
|
<nav className="hidden md:flex items-center gap-6 absolute left-1/2 transform -translate-x-1/2">
|
||||||
|
<a
|
||||||
|
href="#funcionalidades"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Funcionalidades
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="#stack"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Stack
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="#como-usar"
|
||||||
|
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Como usar
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<nav className="flex items-center gap-2 md:gap-4">
|
<nav className="flex items-center gap-2 md:gap-4">
|
||||||
<AnimatedThemeToggler />
|
<AnimatedThemeToggler />
|
||||||
{session?.user ? (
|
{session?.user ? (
|
||||||
@@ -50,7 +74,7 @@ export default async function Page() {
|
|||||||
</Link>
|
</Link>
|
||||||
<Link href="/signup">
|
<Link href="/signup">
|
||||||
<Button size="sm" className="gap-2">
|
<Button size="sm" className="gap-2">
|
||||||
Começar Grátis
|
Começar
|
||||||
<RiArrowRightSLine size={16} />
|
<RiArrowRightSLine size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -64,77 +88,90 @@ export default async function Page() {
|
|||||||
<section className="relative py-16 md:py-24 lg:py-32">
|
<section className="relative py-16 md:py-24 lg:py-32">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="mx-auto flex max-w-5xl flex-col items-center text-center gap-6">
|
<div className="mx-auto flex max-w-5xl flex-col items-center text-center gap-6">
|
||||||
<Badge variant="secondary" className="mb-2">
|
<Badge variant="primary" className="mb-2">
|
||||||
<RiLineChartLine size={14} className="mr-1" />
|
<RiGithubFill size={14} className="mr-1" />
|
||||||
Controle Financeiro Inteligente
|
Projeto Open Source
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
||||||
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight">
|
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight">
|
||||||
Gerencie suas finanças
|
Suas finanças,
|
||||||
<span className="text-primary"> com simplicidade</span>
|
<span className="text-primary"> do seu jeito</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="text-lg md:text-xl text-muted-foreground max-w-2xl">
|
<p className="text-lg md:text-xl text-muted-foreground max-w-2xl">
|
||||||
Organize seus gastos, acompanhe receitas, gerencie cartões de
|
Um projeto pessoal de gestão financeira. Self-hosted, sem Open
|
||||||
crédito e tome decisões financeiras mais inteligentes. Tudo em um
|
Finance, sem sincronização automática. Rode no seu computador ou
|
||||||
só lugar.
|
servidor e tenha controle total sobre suas finanças.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className="rounded-lg border bg-muted/30 p-4 max-w-2xl">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
<span className="font-semibold text-foreground">
|
||||||
|
⚠️ Aviso importante:
|
||||||
|
</span>{" "}
|
||||||
|
Este sistema requer disciplina. Você precisa registrar
|
||||||
|
manualmente cada transação. Se prefere algo automático, este
|
||||||
|
projeto não é pra você.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-4 mt-4">
|
<div className="flex flex-col sm:flex-row gap-4 mt-4">
|
||||||
<Link href="/signup">
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets-app"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<Button size="lg" className="gap-2 w-full sm:w-auto">
|
<Button size="lg" className="gap-2 w-full sm:w-auto">
|
||||||
Começar Gratuitamente
|
<RiGithubFill size={18} />
|
||||||
<RiArrowRightSLine size={18} />
|
Baixar no GitHub
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/login">
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets-app#readme"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full sm:w-auto"
|
className="w-full sm:w-auto gap-2"
|
||||||
>
|
>
|
||||||
Fazer Login
|
Ver Documentação
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-8 flex flex-wrap items-center justify-center gap-6 text-sm text-muted-foreground">
|
<div className="mt-8 flex flex-wrap items-center justify-center gap-6 text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<RiShieldCheckLine size={18} className="text-primary" />
|
<RiLockLine size={18} className="text-primary" />
|
||||||
Dados Seguros
|
Seus dados, seu servidor
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<RiEyeOffLine size={18} className="text-primary" />
|
<RiGithubFill size={18} className="text-primary" />
|
||||||
Modo Privacidade
|
100% Open Source
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<RiDeviceLine size={18} className="text-primary" />
|
|
||||||
100% Responsivo
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Features Section */}
|
{/* What's Here Section */}
|
||||||
<section className="py-16 md:py-24 bg-muted/30">
|
<section id="funcionalidades" className="py-16 md:py-24 bg-muted/30">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="mx-auto max-w-5xl">
|
<div className="mx-auto max-w-5xl">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<Badge variant="secondary" className="mb-4">
|
<Badge variant="primary" className="mb-4">
|
||||||
Funcionalidades
|
O que tem aqui
|
||||||
</Badge>
|
</Badge>
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
||||||
Tudo que você precisa para gerenciar suas finanças
|
Funcionalidades que importam
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
|
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
|
||||||
Ferramentas poderosas e intuitivas para controle financeiro
|
Ferramentas simples para organizar suas contas, cartões, gastos
|
||||||
completo
|
e receitas
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||||
<Card className="border-2 hover:border-primary/50 transition-colors">
|
<Card className="border-[1.5px] hover:border-primary/50 transition-colors">
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||||
@@ -142,18 +179,38 @@ export default async function Page() {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-lg mb-2">
|
<h3 className="font-semibold text-lg mb-2">
|
||||||
Lançamentos
|
Contas e transações
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Registre receitas e despesas com categorização
|
Registre suas contas bancárias, cartões e dinheiro.
|
||||||
automática e controle detalhado de pagadores e contas.
|
Adicione receitas, despesas e transferências. Organize
|
||||||
|
por categorias.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="border-2 hover:border-primary/50 transition-colors">
|
<Card className="border-[1.5px] hover:border-primary/50 transition-colors">
|
||||||
|
<CardContent className="pt-6">
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||||
|
<RiBarChartBoxLine size={24} className="text-primary" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-lg mb-2">
|
||||||
|
Relatórios e gráficos
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Dashboard com resumo mensal. Gráficos de evolução do
|
||||||
|
patrimônio. Entenda pra onde seu dinheiro está indo.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px] hover:border-primary/50 transition-colors">
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||||
@@ -161,35 +218,38 @@ export default async function Page() {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-lg mb-2">
|
<h3 className="font-semibold text-lg mb-2">
|
||||||
Cartões de Crédito
|
Faturas de cartão
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Gerencie múltiplos cartões, acompanhe faturas, limites e
|
Cadastre seus cartões e acompanhe as faturas. Veja o que
|
||||||
nunca perca o controle dos gastos.
|
ainda não foi fechado. Controle limites e vencimentos.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="border-2 hover:border-primary/50 transition-colors">
|
<Card className="border-[1.5px] hover:border-primary/50 transition-colors">
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||||
<RiPieChartLine size={24} className="text-primary" />
|
<RiPieChartLine size={24} className="text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-lg mb-2">Categorias</h3>
|
<h3 className="font-semibold text-lg mb-2">
|
||||||
|
Categorias personalizadas
|
||||||
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Organize suas transações em categorias personalizadas e
|
Crie e organize suas próprias categorias. Moradia,
|
||||||
visualize onde seu dinheiro está indo.
|
alimentação, transporte, ou o que fizer sentido pra
|
||||||
|
você.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="border-2 hover:border-primary/50 transition-colors">
|
<Card className="border-[1.5px] hover:border-primary/50 transition-colors">
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||||
@@ -201,41 +261,26 @@ export default async function Page() {
|
|||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-lg mb-2">Orçamentos</h3>
|
<h3 className="font-semibold text-lg mb-2">Orçamentos</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Defina limites de gastos por categoria e receba alertas
|
Defina quanto quer gastar por categoria no mês.
|
||||||
para manter suas finanças no caminho certo.
|
Acompanhe se está dentro do planejado.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="border-2 hover:border-primary/50 transition-colors">
|
<Card className="border-[1.5px] hover:border-primary/50 transition-colors">
|
||||||
<CardContent className="pt-6">
|
|
||||||
<div className="flex flex-col gap-4">
|
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
|
||||||
<RiBarChartBoxLine size={24} className="text-primary" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold text-lg mb-2">Insights</h3>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
Análise detalhada de padrões de gastos com gráficos e
|
|
||||||
relatórios para decisões mais inteligentes.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card className="border-2 hover:border-primary/50 transition-colors">
|
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
|
||||||
<RiCalendarLine size={24} className="text-primary" />
|
<RiCalendarLine size={24} className="text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-lg mb-2">Calendário</h3>
|
<h3 className="font-semibold text-lg mb-2">
|
||||||
|
Calendário financeiro
|
||||||
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Visualize suas transações em calendário mensal e nunca
|
Visualize suas transações em calendário mensal. Nunca
|
||||||
perca prazos importantes.
|
perca prazos importantes.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -247,167 +292,343 @@ export default async function Page() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Benefits Section */}
|
{/* Tech Stack Section */}
|
||||||
<section className="py-16 md:py-24">
|
<section id="stack" className="py-16 md:py-24">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="mx-auto max-w-5xl">
|
<div className="mx-auto max-w-5xl">
|
||||||
<div className="grid gap-12 lg:grid-cols-2 items-center">
|
<div className="text-center mb-12">
|
||||||
<div>
|
<Badge variant="primary" className="mb-4">
|
||||||
<Badge variant="secondary" className="mb-4">
|
Stack técnica
|
||||||
Vantagens
|
</Badge>
|
||||||
</Badge>
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-6">
|
Construído com tecnologias modernas
|
||||||
Controle financeiro descomplicado
|
</h2>
|
||||||
</h2>
|
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
|
||||||
<div className="space-y-6">
|
Open source, self-hosted e fácil de customizar
|
||||||
<div className="flex gap-4">
|
</p>
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
</div>
|
||||||
<RiShieldCheckLine size={20} className="text-primary" />
|
|
||||||
</div>
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<RiCodeSSlashLine
|
||||||
|
size={32}
|
||||||
|
className="text-primary shrink-0"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-1">
|
<h3 className="font-semibold text-lg mb-2">Frontend</h3>
|
||||||
Segurança em Primeiro Lugar
|
<p className="text-sm text-muted-foreground mb-3">
|
||||||
</h3>
|
Next.js 16, TypeScript, Tailwind CSS, shadcn/ui
|
||||||
<p className="text-sm text-muted-foreground">
|
</p>
|
||||||
Seus dados financeiros são criptografados e armazenados
|
<p className="text-xs text-muted-foreground">
|
||||||
com os mais altos padrões de segurança.
|
Interface moderna e responsiva com React 19 e App Router
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<RiDatabase2Line
|
||||||
|
size={32}
|
||||||
|
className="text-primary shrink-0"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-lg mb-2">Backend</h3>
|
||||||
|
<p className="text-sm text-muted-foreground mb-3">
|
||||||
|
PostgreSQL 18, Drizzle ORM, Better Auth
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Banco relacional robusto com type-safe ORM
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<RiShieldCheckLine
|
||||||
|
size={32}
|
||||||
|
className="text-primary shrink-0"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-lg mb-2">Segurança</h3>
|
||||||
|
<p className="text-sm text-muted-foreground mb-3">
|
||||||
|
Better Auth com OAuth (Google) e autenticação por email
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Sessões seguras e proteção de rotas por middleware
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<RiDeviceLine size={32} className="text-primary shrink-0" />
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold text-lg mb-2">Deploy</h3>
|
||||||
|
<p className="text-sm text-muted-foreground mb-3">
|
||||||
|
Docker com multi-stage build, health checks e volumes
|
||||||
|
persistentes
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Fácil de rodar localmente ou em qualquer servidor
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Seus dados ficam no seu controle. Pode rodar localmente ou no
|
||||||
|
seu próprio servidor.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* How to run Section */}
|
||||||
|
<section id="como-usar" className="py-16 md:py-24">
|
||||||
|
<div className="container">
|
||||||
|
<div className="mx-auto max-w-3xl">
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<Badge variant="primary" className="mb-4">
|
||||||
|
Como usar
|
||||||
|
</Badge>
|
||||||
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
||||||
|
Rode no seu computador
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-muted-foreground">
|
||||||
|
Não há versão hospedada online. Você precisa rodar localmente.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-2">
|
||||||
|
Clone o repositório
|
||||||
|
</h3>
|
||||||
|
<code className="text-sm bg-muted px-2 py-1 rounded">
|
||||||
|
git clone
|
||||||
|
https://github.com/felipegcoutinho/opensheets-app.git
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold">
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-2">
|
||||||
|
Configure as variáveis de ambiente
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Copie o{" "}
|
||||||
|
<code className="bg-muted px-1 rounded">
|
||||||
|
.env.example
|
||||||
|
</code>{" "}
|
||||||
|
para <code className="bg-muted px-1 rounded">.env</code>{" "}
|
||||||
|
e configure o banco de dados
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold">
|
||||||
|
3
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-2">
|
||||||
|
Suba o banco via Docker
|
||||||
|
</h3>
|
||||||
|
<code className="text-sm bg-muted px-2 py-1 rounded">
|
||||||
|
docker compose up db -d
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground font-bold">
|
||||||
|
4
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-2">
|
||||||
|
Rode a aplicação localmente
|
||||||
|
</h3>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<code className="block text-sm bg-muted px-2 py-1 rounded">
|
||||||
|
pnpm install
|
||||||
|
</code>
|
||||||
|
<code className="block text-sm bg-muted px-2 py-1 rounded">
|
||||||
|
pnpm db:push
|
||||||
|
</code>
|
||||||
|
<code className="block text-sm bg-muted px-2 py-1 rounded">
|
||||||
|
pnpm dev
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 text-center">
|
||||||
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets-app#-início-rápido"
|
||||||
|
target="_blank"
|
||||||
|
className="text-sm text-primary hover:underline"
|
||||||
|
>
|
||||||
|
Ver documentação completa →
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Who is this for Section */}
|
||||||
|
<section className="py-16 md:py-24 bg-muted/30">
|
||||||
|
<div className="container">
|
||||||
|
<div className="mx-auto max-w-3xl">
|
||||||
|
<div className="text-center mb-12">
|
||||||
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
||||||
|
Para quem funciona?
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-muted-foreground">
|
||||||
|
O OpenSheets funciona melhor se você:
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
||||||
<RiTimeLine size={20} className="text-primary" />
|
<RiTimeLine size={20} className="text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-1">Economize Tempo</h3>
|
<h3 className="font-semibold mb-1">
|
||||||
|
Tem disciplina de registrar gastos
|
||||||
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Interface intuitiva que permite registrar transações em
|
Não se importa em dedicar alguns minutos por dia ou
|
||||||
segundos e acompanhar tudo de forma visual.
|
semana para manter tudo atualizado
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
||||||
<RiNotificationLine size={20} className="text-primary" />
|
<RiLockLine size={20} className="text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-1">
|
<h3 className="font-semibold mb-1">
|
||||||
Alertas Inteligentes
|
Quer controle total sobre seus dados
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Receba notificações sobre vencimentos, limites de
|
Prefere hospedar seus próprios dados ao invés de
|
||||||
orçamento e padrões incomuns de gastos.
|
depender de serviços terceiros
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card className="border-[1.5px]">
|
||||||
|
<CardContent>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10">
|
||||||
<RiEyeOffLine size={20} className="text-primary" />
|
<RiLineChartLine size={20} className="text-primary" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold mb-1">Modo Privacidade</h3>
|
<h3 className="font-semibold mb-1">
|
||||||
|
Gosta de entender exatamente onde o dinheiro vai
|
||||||
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Oculte valores sensíveis com um clique para visualizar
|
Quer visualizar padrões de gastos e tomar decisões
|
||||||
suas finanças em qualquer lugar com discrição.
|
informadas
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CardContent>
|
||||||
</div>
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="mt-8 rounded-lg border bg-background p-6 text-center">
|
||||||
<Card className="border-2">
|
<p className="text-sm text-muted-foreground">
|
||||||
<CardContent className="pt-6">
|
Se você não se encaixa nisso, provavelmente vai abandonar depois
|
||||||
<div className="flex items-start gap-4">
|
de uma semana. E tudo bem! Existem outras ferramentas com
|
||||||
<RiLineChartLine
|
sincronização automática que podem funcionar melhor pra você.
|
||||||
size={32}
|
</p>
|
||||||
className="text-primary shrink-0"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold text-lg mb-2">
|
|
||||||
Visualização Clara
|
|
||||||
</h3>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
Gráficos interativos e dashboards personalizáveis
|
|
||||||
mostram sua situação financeira de forma clara e
|
|
||||||
objetiva.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card className="border-2">
|
|
||||||
<CardContent className="pt-6">
|
|
||||||
<div className="flex items-start gap-4">
|
|
||||||
<RiDeviceLine
|
|
||||||
size={32}
|
|
||||||
className="text-primary shrink-0"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold text-lg mb-2">
|
|
||||||
Acesso em Qualquer Lugar
|
|
||||||
</h3>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
Design responsivo que funciona perfeitamente em
|
|
||||||
desktop, tablet e smartphone. Suas finanças sempre à
|
|
||||||
mão.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card className="border-2">
|
|
||||||
<CardContent className="pt-6">
|
|
||||||
<div className="flex items-start gap-4">
|
|
||||||
<RiLockLine size={32} className="text-primary shrink-0" />
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold text-lg mb-2">
|
|
||||||
Privacidade Garantida
|
|
||||||
</h3>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
Seus dados são seus. Sem compartilhamento com
|
|
||||||
terceiros, sem anúncios, sem surpresas.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* CTA Section */}
|
{/* CTA Section */}
|
||||||
<section className="py-16 md:py-24 bg-muted/30">
|
<section className="py-16 md:py-24">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="mx-auto max-w-3xl text-center">
|
<div className="mx-auto max-w-3xl text-center">
|
||||||
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
<h2 className="text-3xl md:text-4xl font-bold tracking-tight mb-4">
|
||||||
Pronto para transformar suas finanças?
|
Pronto para testar?
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-muted-foreground mb-8">
|
<p className="text-lg text-muted-foreground mb-8">
|
||||||
Comece agora mesmo a organizar seu dinheiro de forma inteligente.
|
Clone o repositório, rode localmente e veja se faz sentido pra
|
||||||
É grátis e leva menos de um minuto.
|
você. É open source e gratuito.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||||
<Link href="/signup">
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets-app"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<Button size="lg" className="gap-2 w-full sm:w-auto">
|
<Button size="lg" className="gap-2 w-full sm:w-auto">
|
||||||
Criar Conta Gratuita
|
<RiGithubFill size={18} />
|
||||||
<RiArrowRightSLine size={18} />
|
Baixar Projeto
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/login">
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets-app#-início-rápido"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full sm:w-auto"
|
className="w-full sm:w-auto gap-2"
|
||||||
>
|
>
|
||||||
Já tenho conta
|
Como Instalar
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -418,113 +639,70 @@ export default async function Page() {
|
|||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="border-t py-12 mt-auto">
|
<footer className="border-t py-12 mt-auto">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-4">
|
<div className="mx-auto max-w-5xl">
|
||||||
<div>
|
<div className="grid gap-8 md:grid-cols-3">
|
||||||
<Logo />
|
<div>
|
||||||
<p className="text-sm text-muted-foreground mt-4">
|
<Logo />
|
||||||
Gerencie suas finanças pessoais com simplicidade e segurança.
|
<p className="text-sm text-muted-foreground mt-4">
|
||||||
|
Projeto pessoal de gestão financeira. Open source e
|
||||||
|
self-hosted.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-4">Projeto</h3>
|
||||||
|
<ul className="space-y-3 text-sm text-muted-foreground">
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets"
|
||||||
|
target="_blank"
|
||||||
|
className="hover:text-foreground transition-colors flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<RiGithubFill size={16} />
|
||||||
|
GitHub
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets#readme"
|
||||||
|
target="_blank"
|
||||||
|
className="hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Documentação
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Link
|
||||||
|
href="https://github.com/felipegcoutinho/opensheets/issues"
|
||||||
|
target="_blank"
|
||||||
|
className="hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Reportar Bug
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="font-semibold mb-4">Stack</h3>
|
||||||
|
<ul className="space-y-3 text-sm text-muted-foreground">
|
||||||
|
<li>Next.js 16 + TypeScript</li>
|
||||||
|
<li>PostgreSQL 18 + Drizzle ORM</li>
|
||||||
|
<li>Better Auth + shadcn/ui</li>
|
||||||
|
<li>Docker + Docker Compose</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="border-t mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-muted-foreground">
|
||||||
|
<p>
|
||||||
|
© {new Date().getFullYear()} OpenSheets. Projeto open source sob
|
||||||
|
licença MIT.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
<div className="flex items-center gap-2">
|
||||||
|
<RiShieldCheckLine size={16} className="text-primary" />
|
||||||
<div>
|
<span>Seus dados, seu servidor</span>
|
||||||
<h3 className="font-semibold mb-4">Produto</h3>
|
</div>
|
||||||
<ul className="space-y-3 text-sm text-muted-foreground">
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Funcionalidades
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Preços
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Segurança
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold mb-4">Recursos</h3>
|
|
||||||
<ul className="space-y-3 text-sm text-muted-foreground">
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Blog
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Ajuda
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Tutoriais
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h3 className="font-semibold mb-4">Legal</h3>
|
|
||||||
<ul className="space-y-3 text-sm text-muted-foreground">
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Privacidade
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Termos de Uso
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<Link
|
|
||||||
href="/login"
|
|
||||||
className="hover:text-foreground transition-colors"
|
|
||||||
>
|
|
||||||
Cookies
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="border-t mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-muted-foreground">
|
|
||||||
<p>
|
|
||||||
© {new Date().getFullYear()} OpenSheets. Todos os direitos
|
|
||||||
reservados.
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<RiShieldCheckLine size={16} className="text-primary" />
|
|
||||||
<span>Seus dados são protegidos e criptografados</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -178,6 +178,11 @@
|
|||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
scroll-padding-top: 80px; /* Offset para o header sticky */
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Toaster } from "@/components/ui/sonner";
|
|||||||
import { main_font } from "@/public/fonts/font_index";
|
import { main_font } from "@/public/fonts/font_index";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
|
import { Analytics } from "@vercel/analytics/next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "OpenSheets",
|
title: "OpenSheets",
|
||||||
@@ -17,13 +18,6 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<head>
|
|
||||||
<script
|
|
||||||
defer
|
|
||||||
src="https://umami.felipecoutinho.com/script.js"
|
|
||||||
data-website-id="42f8519e-de88-467e-8969-d13a76211e43"
|
|
||||||
></script>
|
|
||||||
</head>
|
|
||||||
<body
|
<body
|
||||||
className={`${main_font.className} antialiased`}
|
className={`${main_font.className} antialiased`}
|
||||||
suppressHydrationWarning
|
suppressHydrationWarning
|
||||||
@@ -34,6 +28,7 @@ export default function RootLayout({
|
|||||||
<Toaster position="top-right" />
|
<Toaster position="top-right" />
|
||||||
</PrivacyProvider>
|
</PrivacyProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
<Analytics />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
<div
|
<div
|
||||||
data-slot="card"
|
data-slot="card"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-card text-card-foreground flex flex-col gap-6 border drop-shadow-xs py-6 rounded-md hover:border-primary/50 transition-colors",
|
"bg-card text-card-foreground flex flex-col gap-6 border-[1.5px] drop-shadow-xs py-6 rounded-md hover:border-primary/50 transition-colors",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"db:push": "drizzle-kit push",
|
"db:push": "drizzle-kit push",
|
||||||
"db:studio": "drizzle-kit studio",
|
"db:studio": "drizzle-kit studio",
|
||||||
"docker:up": "docker compose up --build",
|
"docker:up": "docker compose up --build",
|
||||||
"docker:up:detached": "docker compose up --build -d",
|
"docker:up:db": "docker compose up -d db",
|
||||||
|
"docker:up:d": "docker compose up --build -d",
|
||||||
"docker:down": "docker compose down",
|
"docker:down": "docker compose down",
|
||||||
"docker:down:volumes": "docker compose down -v",
|
"docker:down:volumes": "docker compose down -v",
|
||||||
"docker:logs": "docker compose logs -f",
|
"docker:logs": "docker compose logs -f",
|
||||||
@@ -27,10 +28,6 @@
|
|||||||
"@ai-sdk/anthropic": "^2.0.44",
|
"@ai-sdk/anthropic": "^2.0.44",
|
||||||
"@ai-sdk/google": "^2.0.31",
|
"@ai-sdk/google": "^2.0.31",
|
||||||
"@ai-sdk/openai": "^2.0.66",
|
"@ai-sdk/openai": "^2.0.66",
|
||||||
"@dnd-kit/core": "6.3.1",
|
|
||||||
"@dnd-kit/modifiers": "9.0.0",
|
|
||||||
"@dnd-kit/sortable": "10.0.0",
|
|
||||||
"@dnd-kit/utilities": "3.2.2",
|
|
||||||
"@openrouter/ai-sdk-provider": "^1.2.2",
|
"@openrouter/ai-sdk-provider": "^1.2.2",
|
||||||
"@radix-ui/react-alert-dialog": "1.1.15",
|
"@radix-ui/react-alert-dialog": "1.1.15",
|
||||||
"@radix-ui/react-avatar": "1.1.11",
|
"@radix-ui/react-avatar": "1.1.11",
|
||||||
@@ -53,6 +50,7 @@
|
|||||||
"@radix-ui/react-tooltip": "1.2.8",
|
"@radix-ui/react-tooltip": "1.2.8",
|
||||||
"@remixicon/react": "4.7.0",
|
"@remixicon/react": "4.7.0",
|
||||||
"@tanstack/react-table": "8.21.3",
|
"@tanstack/react-table": "8.21.3",
|
||||||
|
"@vercel/analytics": "^1.5.0",
|
||||||
"ai": "^5.0.93",
|
"ai": "^5.0.93",
|
||||||
"better-auth": "1.3.34",
|
"better-auth": "1.3.34",
|
||||||
"class-variance-authority": "0.7.1",
|
"class-variance-authority": "0.7.1",
|
||||||
@@ -80,6 +78,7 @@
|
|||||||
"@types/node": "24.10.1",
|
"@types/node": "24.10.1",
|
||||||
"@types/react": "19.2.4",
|
"@types/react": "19.2.4",
|
||||||
"@types/react-dom": "19.2.3",
|
"@types/react-dom": "19.2.3",
|
||||||
|
"depcheck": "^1.4.7",
|
||||||
"drizzle-kit": "0.31.7",
|
"drizzle-kit": "0.31.7",
|
||||||
"eslint": "9.39.1",
|
"eslint": "9.39.1",
|
||||||
"eslint-config-next": "16.0.3",
|
"eslint-config-next": "16.0.3",
|
||||||
|
|||||||
564
pnpm-lock.yaml
generated
564
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
onlyBuiltDependencies:
|
||||||
|
- esbuild
|
||||||
|
- sharp
|
||||||
|
- unrs-resolver
|
||||||
Reference in New Issue
Block a user