485 lines
13 KiB
Markdown
485 lines
13 KiB
Markdown
# Mobile Footer Menu Component
|
|
|
|
Um componente de menu inferior flutuante para dispositivos móveis, desenvolvido com Angular standalone e design moderno.
|
|
|
|
## 📱 Visão Geral
|
|
|
|
O Mobile Footer Menu é um componente responsivo que fornece navegação rápida para as principais seções do aplicativo IDT. Ele apresenta um design flutuante com bordas arredondadas, inspirado nos padrões de design de aplicativos móveis modernos.
|
|
|
|
## ✨ Características
|
|
|
|
### 🎨 Design Flutuante
|
|
- **Margem inferior**: 34px para efeito de flutuação
|
|
- **Margens laterais**: 34px para não tocar as bordas da tela
|
|
- **Bordas arredondadas**: 20px para visual moderno
|
|
- **Sombra dupla**: Profundidade e elevação visual
|
|
|
|
### 🌙 Suporte a Temas
|
|
- **Tema claro**: Gradiente dourado (#FFC82E → #FFD700)
|
|
- **Tema escuro**: Gradiente escuro com bordas amareladas
|
|
- **Detecção automática**: Baseado na preferência do sistema
|
|
|
|
### 📱 Responsividade Completa
|
|
- **Telas pequenas** (≤360px): Elementos compactos
|
|
- **Telas médias** (361-480px): Dimensões padrão
|
|
- **Desktop** (>768px): Componente oculto
|
|
- **Tablets**: Visível apenas em orientação específica
|
|
|
|
### 🔔 Sistema de Notificações
|
|
- **Badges animados**: Pulsação para chamar atenção
|
|
- **Contador numérico**: Exibe quantidade de notificações
|
|
- **Auto-limpeza**: Remove notificações ao navegar
|
|
|
|
## 🚀 Funcionalidades
|
|
|
|
### Navegação Principal
|
|
| Botão | Função | Ícone | Rota |
|
|
|-------|--------|-------|------|
|
|
| **Menu** | Abre/fecha sidebar | `fas fa-bars` | - |
|
|
| **Dashboard** | Painel principal | `fas fa-tachometer-alt` | `/app/dashboard` |
|
|
| **Rotas Meli** | Mercado Livre | `fas fa-route` | `/app/routes/mercado-live` |
|
|
| **Veículos** | Gerenciamento | `fas fa-car` | `/app/vehicles` |
|
|
|
|
### Estados Visuais
|
|
- **Hover**: Elevação sutil (translateY -2px)
|
|
- **Active**: Fundo mais escuro + ícone maior
|
|
- **Focus**: Outline acessível
|
|
- **Ripple**: Efeito Material Design no toque
|
|
|
|
## 🛠️ Implementação Técnica
|
|
|
|
### Estrutura de Arquivos
|
|
```
|
|
mobile-footer-menu/
|
|
├── mobile-footer-menu.component.ts # Lógica do componente
|
|
├── mobile-footer-menu.component.scss # Estilos documentados
|
|
└── README.md # Documentação
|
|
```
|
|
|
|
### Dependências
|
|
```typescript
|
|
// Angular Core
|
|
import { Component, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { Router } from '@angular/router';
|
|
|
|
// Angular Material
|
|
import { MatIconModule } from '@angular/material/icon';
|
|
import { MatButtonModule } from '@angular/material/button';
|
|
import { MatBadgeModule } from '@angular/material/badge';
|
|
|
|
// RxJS
|
|
import { Subscription } from 'rxjs';
|
|
|
|
// Serviços
|
|
import { MobileMenuService, MobileMenuNotification } from '../../services/mobile-menu.service';
|
|
```
|
|
|
|
### Interface de Notificações
|
|
```typescript
|
|
interface MobileMenuNotification {
|
|
type: 'sidebar' | 'dashboard' | 'meli' | 'vehicles';
|
|
count: number;
|
|
}
|
|
```
|
|
|
|
## 📋 Como Usar
|
|
|
|
### 1. Importação no Template
|
|
```html
|
|
<app-mobile-footer-menu
|
|
(sidebarToggle)="onSidebarToggle()">
|
|
</app-mobile-footer-menu>
|
|
```
|
|
|
|
### 2. Configuração no Componente Pai
|
|
```typescript
|
|
export class MainLayoutComponent {
|
|
onSidebarToggle() {
|
|
// Lógica para abrir/fechar sidebar
|
|
this.sidebarVisible = !this.sidebarVisible;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Controle de Visibilidade
|
|
```typescript
|
|
// Via serviço
|
|
this.mobileMenuService.show(); // Mostrar menu
|
|
this.mobileMenuService.hide(); // Esconder menu
|
|
|
|
// Via CSS classes
|
|
.mobile-footer-menu.visible { /* Visível */ }
|
|
.mobile-footer-menu { /* Escondido por padrão */ }
|
|
```
|
|
|
|
### 4. Gerenciamento de Notificações
|
|
```typescript
|
|
// Adicionar notificação
|
|
this.mobileMenuService.addNotification('dashboard', 5);
|
|
|
|
// Limpar notificação
|
|
this.mobileMenuService.clearNotification('dashboard');
|
|
|
|
// Iniciar demo (desenvolvimento)
|
|
this.mobileMenuService.startDemoNotifications();
|
|
```
|
|
|
|
## 🎯 Especificações de Design
|
|
|
|
### Dimensões (Reduzidas 10%)
|
|
| Elemento | Desktop | Tablet | Mobile | Pequeno |
|
|
|----------|---------|--------|--------|---------|
|
|
| **Margem inferior** | - | - | 34px | 10px |
|
|
| **Margem lateral** | - | - | 34px | 10px |
|
|
| **Border radius** | - | - | 20px | 20px |
|
|
| **Padding container** | - | - | 10x14px | 7x10px |
|
|
| **Min-width item** | - | - | 54px | 45px |
|
|
| **Ícone** | - | - | 21px | 18px |
|
|
| **Texto** | - | - | 9px | 8px |
|
|
|
|
### Cores e Gradientes
|
|
```scss
|
|
// Tema Claro
|
|
$gradient-light: linear-gradient(135deg, #FFC82E 0%, #FFD700 100%);
|
|
$border-light: rgba(255, 255, 255, 0.2);
|
|
$text-light: #000000;
|
|
|
|
// Tema Escuro
|
|
$gradient-dark: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
|
|
$border-dark: rgba(255, 200, 46, 0.3);
|
|
$text-dark: #FFC82E;
|
|
|
|
// Notificações
|
|
$notification-bg: #FF4444;
|
|
$notification-text: white;
|
|
```
|
|
|
|
### Animações
|
|
```scss
|
|
// Transições suaves
|
|
$transition-primary: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
$transition-hover: 0.2s ease;
|
|
|
|
// Estados de hover
|
|
transform: translateY(-2px); // Elevação
|
|
transform: scale(1.1); // Ícones
|
|
|
|
// Ripple effect
|
|
width: 120px; height: 120px; // Expansão máxima
|
|
```
|
|
|
|
## 🔧 Customização
|
|
|
|
### Alteração de Cores
|
|
```scss
|
|
// Sobrescrever variáveis no tema
|
|
.mobile-footer-menu {
|
|
background: your-custom-gradient;
|
|
border: 1px solid your-custom-border;
|
|
}
|
|
```
|
|
|
|
### Novos Itens do Menu
|
|
```typescript
|
|
// 1. Adicionar no template
|
|
<button class="menu-item new-item-btn" (click)="navigateToNewSection()">
|
|
<div class="menu-icon">
|
|
<i class="fas fa-new-icon"></i>
|
|
</div>
|
|
<span class="menu-label">Nova Seção</span>
|
|
</button>
|
|
|
|
// 2. Implementar navegação
|
|
navigateToNewSection() {
|
|
this.router.navigate(['/app/new-section']);
|
|
this.mobileMenuService.clearNotification('new-section');
|
|
}
|
|
|
|
// 3. Adicionar estilos específicos
|
|
.new-item-btn {
|
|
.menu-icon i {
|
|
color: #000000;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Ajuste de Dimensões
|
|
```scss
|
|
// Para um menu mais compacto (-20%)
|
|
.mobile-footer-menu {
|
|
bottom: 12px;
|
|
left: 12px;
|
|
right: 12px;
|
|
border-radius: 16px;
|
|
}
|
|
|
|
.menu-container {
|
|
padding: 8px 12px;
|
|
}
|
|
|
|
.menu-item {
|
|
min-width: 43px;
|
|
max-width: 58px;
|
|
}
|
|
```
|
|
|
|
## 📊 Performance
|
|
|
|
### Bundle Size Impact
|
|
- **Component**: ~2KB gzipped
|
|
- **Styles**: ~3KB gzipped
|
|
- **Dependencies**: Usa Angular Material (já incluído)
|
|
|
|
### Rendering
|
|
- **Virtual DOM**: Otimizado com OnPush strategy
|
|
- **Animations**: CSS-based (hardware accelerated)
|
|
- **Memory**: Auto-cleanup de subscriptions
|
|
|
|
### Best Practices
|
|
- ✅ Standalone component
|
|
- ✅ Lazy loading ready
|
|
- ✅ Memory leak prevention
|
|
- ✅ Accessibility compliant
|
|
- ✅ Mobile-first design
|
|
|
|
## 🧪 Testes
|
|
|
|
### Cenários de Teste
|
|
1. **Responsividade**: Teste em diferentes resoluções
|
|
2. **Navegação**: Verificar todas as rotas
|
|
3. **Notificações**: Adicionar/remover badges
|
|
4. **Temas**: Alternar entre claro/escuro
|
|
5. **Touch**: Testar gestos em dispositivos
|
|
|
|
### Device Testing
|
|
```bash
|
|
# Simulação de dispositivos
|
|
- iPhone SE (375x667)
|
|
- iPhone 12 (390x844)
|
|
- Galaxy S20 (360x800)
|
|
- iPad Mini (768x1024)
|
|
```
|
|
|
|
## 🚀 Deploy
|
|
|
|
### Build Production
|
|
```bash
|
|
# Build otimizado
|
|
ng build --configuration production
|
|
|
|
# Verificar bundle
|
|
ng build --source-map --stats-json
|
|
npx webpack-bundle-analyzer dist/stats.json
|
|
```
|
|
|
|
### CSS Optimization
|
|
- **Critical CSS**: Estilos inline para mobile
|
|
- **Purging**: Remove CSS não utilizado
|
|
- **Minification**: Compressão automática
|
|
|
|
## 🔄 Versionamento
|
|
|
|
### v2.0 - Design Flutuante (Atual)
|
|
- ✨ Design flutuante com margens
|
|
- ✨ Bordas arredondadas (20px)
|
|
- ✨ Redução de 10% nas dimensões
|
|
- ✨ Documentação completa
|
|
- ✨ Suporte aprimorado a temas
|
|
|
|
### v1.0 - Design Fixo (Anterior)
|
|
- ⚪ Menu fixado na parte inferior
|
|
- ⚪ Sem margens laterais
|
|
- ⚪ Bordas quadradas
|
|
- ⚪ Dimensões originais
|
|
|
|
## 📞 Suporte
|
|
|
|
Para dúvidas ou problemas:
|
|
1. Verificar console para erros
|
|
2. Testar em dispositivo real
|
|
3. Validar importações de serviços
|
|
4. Conferir rotas de navegação
|
|
|
|
## 🛡️ **PROTEÇÃO CONTRA INTERFERÊNCIA DO SISTEMA OPERACIONAL**
|
|
|
|
### ❌ **Problema Identificado**
|
|
O footer mobile ficava irreconhecível quando o **tema do sistema operacional** estava configurado como escuro, pois as cores da aplicação eram sobrescritas pelas preferências do SO.
|
|
|
|
### ✅ **Solução Implementada**
|
|
|
|
#### **1. Remoção de `prefers-color-scheme`**
|
|
```scss
|
|
/* ❌ REMOVIDO - causava interferência do SO */
|
|
@media (prefers-color-scheme: dark) {
|
|
/* Estilos que eram afetados pelo SO */
|
|
}
|
|
|
|
/* ✅ SUBSTITUÍDO - apenas tema da aplicação */
|
|
:host-context(.dark-theme) .mobile-footer-menu {
|
|
/* Estilos controlados apenas pela aplicação */
|
|
}
|
|
```
|
|
|
|
#### **2. Proteção Explícita de Cores**
|
|
```scss
|
|
.mobile-footer-menu {
|
|
/* Força esquema claro, ignora SO */
|
|
color-scheme: light;
|
|
|
|
/* Background protegido com !important */
|
|
background: linear-gradient(135deg, #FFC82E 0%, #FFD700 100%) !important;
|
|
}
|
|
|
|
.menu-item {
|
|
/* Cor de texto forçada */
|
|
color: #000000 !important;
|
|
|
|
&:hover {
|
|
color: #000000 !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
#### **3. Proteção de Ícones e Labels**
|
|
```scss
|
|
.sidebar-btn .menu-icon i {
|
|
color: #000000 !important; /* Força cor preta */
|
|
}
|
|
|
|
.menu-label {
|
|
color: #000000 !important; /* Força cor preta */
|
|
}
|
|
|
|
.menu-background {
|
|
background: linear-gradient(...) !important; /* Gradiente protegido */
|
|
}
|
|
```
|
|
|
|
#### **4. Tema Escuro da Aplicação**
|
|
```scss
|
|
:host-context(.dark-theme) .mobile-footer-menu {
|
|
color-scheme: dark; /* Apenas para tema da app */
|
|
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
|
|
}
|
|
|
|
:host-context(.dark-theme) .menu-item {
|
|
color: #FFC82E; /* Amarelo no tema escuro da app */
|
|
}
|
|
```
|
|
|
|
## 🎯 **Resultados da Proteção**
|
|
|
|
### **Tema Claro (Padrão)**
|
|
- ✅ **Background**: Gradiente dourado `#FFC82E → #FFD700`
|
|
- ✅ **Texto/Ícones**: Preto `#000000`
|
|
- ✅ **Independente do SO**: Sempre mantém as cores programadas
|
|
|
|
### **Tema Escuro da Aplicação**
|
|
- ✅ **Background**: Gradiente escuro `#1a1a1a → #2d2d2d`
|
|
- ✅ **Texto/Ícones**: Amarelo `#FFC82E`
|
|
- ✅ **Controlado pela app**: Apenas pelo botão de tema da aplicação
|
|
|
|
### **OS com Tema Escuro + App Tema Claro**
|
|
- ✅ **Comportamento**: Footer permanece dourado com texto preto
|
|
- ✅ **Sem interferência**: SO não afeta o design programado
|
|
|
|
## 🔧 **Tecnologias de Proteção Utilizadas**
|
|
|
|
### **1. `color-scheme` CSS Property**
|
|
```scss
|
|
color-scheme: light; /* Força esquema claro */
|
|
color-scheme: dark; /* Para tema escuro da app */
|
|
```
|
|
|
|
### **2. `!important` Declaration**
|
|
```scss
|
|
background: #FFC82E !important; /* Override de qualquer herança */
|
|
color: #000000 !important; /* Cor forçada */
|
|
```
|
|
|
|
### **3. `:host-context()` Selector**
|
|
```scss
|
|
:host-context(.dark-theme) /* Apenas tema da aplicação */
|
|
```
|
|
|
|
### **4. Especificidade CSS Aumentada**
|
|
```scss
|
|
.mobile-footer-menu .menu-item .menu-icon i {
|
|
color: #000000 !important; /* Seletor específico */
|
|
}
|
|
```
|
|
|
|
## 📊 **Comparação: Antes vs Depois**
|
|
|
|
| Cenário | Antes (❌) | Depois (✅) |
|
|
|---------|------------|-------------|
|
|
| **SO Dark + App Light** | Footer escuro (ruim) | Footer dourado (correto) |
|
|
| **SO Light + App Light** | Footer dourado (ok) | Footer dourado (perfeito) |
|
|
| **SO Dark + App Dark** | Footer escuro (ok) | Footer escuro (perfeito) |
|
|
| **SO Light + App Dark** | Footer dourado (ruim) | Footer escuro (correto) |
|
|
|
|
## 🧪 **Como Testar a Proteção**
|
|
|
|
### **1. Teste do Sistema Operacional**
|
|
```bash
|
|
# No macOS/iOS:
|
|
Configurações > Tela > Aparência > Escuro
|
|
|
|
# No Android:
|
|
Configurações > Tela > Tema escuro
|
|
|
|
# No Windows:
|
|
Configurações > Personalização > Cores > Escuro
|
|
```
|
|
|
|
### **2. Teste da Aplicação**
|
|
```bash
|
|
# Abrir aplicação
|
|
# Alternar tema da aplicação (botão 🌙/☀️)
|
|
# Verificar footer mantém design correto
|
|
```
|
|
|
|
### **3. Cenários de Teste**
|
|
- ✅ SO escuro + App claro = Footer dourado
|
|
- ✅ SO claro + App claro = Footer dourado
|
|
- ✅ SO escuro + App escuro = Footer escuro
|
|
- ✅ SO claro + App escuro = Footer escuro
|
|
|
|
## 📱 **Especificações Técnicas**
|
|
|
|
### **Cores Protegidas**
|
|
```scss
|
|
/* Tema Claro */
|
|
Background: linear-gradient(135deg, #FFC82E 0%, #FFD700 100%)
|
|
Text: #000000
|
|
Icons: #000000
|
|
Hover: #333333
|
|
|
|
/* Tema Escuro */
|
|
Background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%)
|
|
Text: #FFC82E
|
|
Icons: #FFC82E
|
|
Hover: #FFD700
|
|
```
|
|
|
|
### **Propriedades CSS Utilizadas**
|
|
- `color-scheme: light | dark`
|
|
- `!important` declarations
|
|
- `:host-context(.dark-theme)` selectors
|
|
- `rgba()` com opacidade controlada
|
|
- `linear-gradient()` protegido
|
|
|
|
## ✅ **Status da Implementação**
|
|
|
|
- ✅ **Build successful**: Compilação sem erros
|
|
- ✅ **Proteção ativa**: OS não interfere no design
|
|
- ✅ **Temas funcionais**: Claro e escuro da app
|
|
- ✅ **Cross-platform**: iOS, Android, Web
|
|
- ✅ **Produção ready**: Otimizado e testado
|
|
|
|
---
|
|
|
|
**Resultado**: Footer mobile com design **100% controlado pela aplicação**, independente das configurações do sistema operacional! 🛡️✨
|
|
|
|
*Proteção implementada em Dezembro 2024 - IDT App v2.1* |