@horizon-framework/website-dev-docs 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,190 @@
1
+ # Capabilities — Features Transversais do Frontend
2
+
3
+ > Sistema de funcionalidades reutilizaveis em apps/web/src/capabilities/
4
+
5
+ ---
6
+
7
+ ## Mapa das 11 Capabilities
8
+
9
+ | Capability | Pasta | Funcao |
10
+ |---|---|---|
11
+ | Contacts | `contacts/` | Telefones e emails centralizados |
12
+ | Social | `social/` | Redes sociais (13 plataformas) |
13
+ | Code Snippets | `code-snippets/` | Scripts de marketing (GTM, GA, Facebook Pixel) |
14
+ | MetaTags | `metatags/` | SEO global (title, favicon, OG) |
15
+ | Navigations | `navigations/` | Menus dinamicos (ver NAVEGACAO_DINAMICA.md) |
16
+ | Redirects | `redirects/` | URLs antigas → novas |
17
+ | Sitemap | `sitemap/` | XML dinamico conectado com modulos |
18
+ | Translation | `translation/` | Multilingue (PT, EN, ES) |
19
+ | UTM Tracking | `utm-tracking/` | Captura parametros UTM |
20
+ | Forms | `forms/` | Envio de leads + LGPD |
21
+ | WhatsApp Float | `(em components/)` | Botao flutuante de atendimento |
22
+
23
+ ---
24
+
25
+ ## CONTACTS — Sistema de Contatos
26
+
27
+ **Pasta:** `capabilities/contacts/`
28
+
29
+ Centraliza TODOS os contatos do site (telefones, emails, WhatsApp).
30
+
31
+ **Interface:**
32
+ ```typescript
33
+ interface Contact {
34
+ type: "phone" | "email";
35
+ tags: ContactTag[]; // "whatsapp", "telegram", "mobile", "land"
36
+ value: string; // numero ou email
37
+ label: string; // "WhatsApp Principal"
38
+ }
39
+ ```
40
+
41
+ **Registry:** `CONTACT_TAG_CONFIG` mapeia tags para icones e URLs:
42
+ - whatsapp → `https://wa.me/{numero}`
43
+ - telegram → `https://t.me/{username}`
44
+ - mobile → icone smartphone
45
+ - land → icone phone
46
+
47
+ **Dados:** `data/contacts.data.ts` — contatos base do cliente
48
+ **Converters:** `toNavigationItems(contacts)` → NavigationItem[]
49
+
50
+ **Ao criar site novo:** Editar `data/contacts.data.ts` com contatos do cliente.
51
+
52
+ ---
53
+
54
+ ## SOCIAL — Redes Sociais
55
+
56
+ **Pasta:** `capabilities/social/`
57
+
58
+ 13 plataformas suportadas: Facebook, Instagram, LinkedIn, X, YouTube, TikTok, WhatsApp Business, Telegram, Pinterest, Discord, GitHub, Blog, Other.
59
+
60
+ **Registry:** `SOCIAL_PLATFORMS` com icone, URL pattern, cor, descricao para cada plataforma.
61
+
62
+ **Helpers:**
63
+ - `createSocialFromUsername(platform, username)` → Social
64
+ - `validateSocial(social)` → boolean
65
+ - `toNavigationItems(socials)` → NavigationItem[]
66
+
67
+ **Ao criar site novo:** Editar dados das redes sociais do cliente.
68
+
69
+ ---
70
+
71
+ ## CODE-SNIPPETS — Marketing Scripts
72
+
73
+ **Pasta:** `capabilities/code-snippets/`
74
+
75
+ Arquivo unico `scripts-marketing.tsx` com:
76
+ - Google Tag Manager (GTM)
77
+ - Google Analytics (GA4)
78
+ - Facebook Pixel
79
+ - Eventos de conversao (pagina /obrigado, cliques WhatsApp)
80
+
81
+ **Ao criar site novo:** Trocar IDs de GTM, GA e Facebook Pixel do cliente.
82
+
83
+ ---
84
+
85
+ ## METATAGS — SEO Global
86
+
87
+ **Pasta:** `capabilities/metatags/`
88
+
89
+ Configuracao centralizada em `seo.ts`:
90
+ - Title suffix (nome da imobiliaria)
91
+ - Favicon path
92
+ - OG Image (800x450)
93
+
94
+ **Ao criar site novo:** Trocar nome, favicon e OG image.
95
+
96
+ ---
97
+
98
+ ## REDIRECTS — URLs Antigas
99
+
100
+ **Pasta:** `capabilities/redirects/nextjs/`
101
+
102
+ Gera redirects permanentes para o next.config:
103
+ - Property: `/imovel/{slug}-ref-{id}` → `/imovel/{id}`
104
+ - Genericos: `/venda` → `/imoveis/venda`
105
+ - Search mappings: `/venda/apartamentos` → `/imoveis?filtros`
106
+
107
+ **Exporta:** `generateNextConfigRedirects()` para integrar no next.config.js
108
+
109
+ ---
110
+
111
+ ## SITEMAP — XML Dinamico
112
+
113
+ **Pasta:** `capabilities/sitemap/`
114
+
115
+ Sistema modular: cada modulo implementa `SitemapProvider`.
116
+ - `router.ts` roteia slug para provider correto via MODULES_REGISTRY
117
+ - `config/static-pages.ts` lista paginas estaticas
118
+ - `generators/` gera XML valido + sitemap index
119
+
120
+ **Paginas estaticas incluidas:** /, /sobre, /contato, /localizacao, /termos-uso, /politica-privacidade
121
+
122
+ **Ao criar site novo:** Verificar se paginas estaticas correspondem as existentes.
123
+
124
+ ---
125
+
126
+ ## TRANSLATION — Multilingue
127
+
128
+ **Pasta:** `capabilities/translation/`
129
+
130
+ 3 idiomas: Portugues (pt), Ingles (en), Espanhol (es).
131
+ Usa Google Translate com cookie `googtrans`.
132
+
133
+ **Componentes:** LanguageProvider, LanguageSelector, LanguageSuggestionBanner
134
+ **Hook:** `useForceTranslation`, `useLanguage`
135
+
136
+ ---
137
+
138
+ ## UTM TRACKING — Parametros de Marketing
139
+
140
+ **Pasta:** `capabilities/utm-tracking/`
141
+
142
+ Captura parametros UTM da URL e persiste em localStorage.
143
+ - `extractUTMFromURL()` → UTMParams
144
+ - `saveUTMToStorage()` / `loadUTMFromStorage()`
145
+ - Hook: `useUTMTracking`, `useCurrentUTM`
146
+
147
+ **Tipo:** `UTMParams { source, medium, campaign, term, content }`
148
+
149
+ ---
150
+
151
+ ## FORMS — Envio de Leads
152
+
153
+ **Pasta:** `capabilities/forms/`
154
+
155
+ Sistema centralizado para envio de leads:
156
+ - `sendLead(data)` → envia para AUTOMATIONS
157
+ - `consent.data.ts` → textos LGPD (completo e compacto)
158
+ - Captura meta: page_id, utm_source, utm_campaign
159
+
160
+ **Interface:** `LeadFormData` com campos tipados (text, email, phone, etc.)
161
+
162
+ ---
163
+
164
+ ## WHATSAPP FLUTUANTE
165
+
166
+ **Pasta:** `components/whatsapp-float-button/`
167
+
168
+ Botao circular fixo no canto inferior direito com:
169
+ - Balao de mensagem animado (delay 7s)
170
+ - Avatar do atendente customizavel
171
+ - LocalStorage para lembrar fechamento
172
+ - Link direto: `https://api.whatsapp.com/send/?phone={num}&text={msg}`
173
+
174
+ **Config:** `WhatsAppConfig { phoneNumber, message, showBubble, bubbleMessage, attendantName, attendantAvatar }`
175
+
176
+ **Ao criar site novo:** Configurar numero, mensagem e avatar no WhatsAppProvider.
177
+
178
+ ---
179
+
180
+ ## CHECKLIST — O que trocar ao criar site novo
181
+
182
+ Ao usar template Horizon para novo cliente, trocar em capabilities:
183
+ 1. `contacts/data/contacts.data.ts` — telefones e emails
184
+ 2. `social/data/` — redes sociais
185
+ 3. `code-snippets/scripts-marketing.tsx` — IDs GTM, GA, Facebook
186
+ 4. `metatags/seo.ts` — nome, favicon, OG image
187
+ 5. `redirects/` — URLs especificas do cliente
188
+ 6. `sitemap/config/static-pages.ts` — paginas estaticas
189
+ 7. `WhatsAppProvider` — numero, mensagem, avatar
190
+ 8. `forms/` — verificar destino de leads
@@ -0,0 +1,407 @@
1
+ # Sistema de Componentes Globais
2
+
3
+ Sistema completo de componentes reutilizáveis e utilitários para a aplicação Nova Torres.
4
+
5
+ ## Componentes Implementados
6
+
7
+ ### **1. Sonner Toast** (Já Ativo)
8
+ Sistema de notificações elegante já integrado no layout.
9
+
10
+ **Uso:**
11
+ ```tsx
12
+ import { toast } from "sonner";
13
+
14
+ // Sucesso
15
+ toast.success("Formulário enviado com sucesso!");
16
+
17
+ // Erro
18
+ toast.error("Erro ao processar dados");
19
+
20
+ // Personalizado
21
+ toast("Mensagem", {
22
+ description: "Descrição adicional",
23
+ duration: 5000
24
+ });
25
+ ```
26
+
27
+ ### **2. Global Loading**
28
+ Loading global centralizado com overlay.
29
+
30
+ **Uso:**
31
+ ```tsx
32
+ import { useGlobalLoading } from "@/components/providers/GlobalUIProvider";
33
+
34
+ function MeuComponente() {
35
+ const { showLoading, hideLoading } = useGlobalLoading();
36
+
37
+ const handleSubmit = async () => {
38
+ showLoading();
39
+
40
+ try {
41
+ await minhaFuncaoAsincrona();
42
+ } finally {
43
+ hideLoading();
44
+ }
45
+ };
46
+ }
47
+ ```
48
+
49
+ ### **3. Form Alert Modal** (Sua Ideia Genial!)
50
+ Modal de feedback para formulários com timeout automático.
51
+
52
+ **Uso:**
53
+ ```tsx
54
+ import { useFormAlert } from "@/components/providers/GlobalUIProvider";
55
+
56
+ function MeuFormulario() {
57
+ const { showAlert } = useFormAlert();
58
+
59
+ const handleSubmit = () => {
60
+ // Lógica do formulário...
61
+
62
+ showAlert({
63
+ type: "success", // "success" | "error" | "warning"
64
+ title: "Formulário Enviado!",
65
+ message: "Nossa equipe entrará em contato em breve.",
66
+ timeout: 5000 // auto-fechar em 5s
67
+ });
68
+ };
69
+ }
70
+ ```
71
+
72
+ ### **4. Generic Modal**
73
+ Sistema de modais reutilizáveis com diferentes tipos.
74
+
75
+ **Uso:**
76
+ ```tsx
77
+ import { useModal } from "@/components/providers/GlobalUIProvider";
78
+
79
+ function MeuComponente() {
80
+ const { showModal } = useModal();
81
+
82
+ // Modal customizado
83
+ const openCustomModal = () => {
84
+ showModal({
85
+ type: "dialog",
86
+ title: "Editar Perfil",
87
+ content: <MeuFormulario />,
88
+ size: "lg"
89
+ });
90
+ };
91
+
92
+ // Alert simples
93
+ const openAlert = () => {
94
+ showModal({
95
+ type: "alert",
96
+ title: "Sucesso!",
97
+ description: "Operação realizada com sucesso."
98
+ });
99
+ };
100
+
101
+ // Confirmação
102
+ const openConfirm = () => {
103
+ showModal({
104
+ type: "confirm",
105
+ title: "Confirmar exclusão?",
106
+ description: "Esta ação não pode ser desfeita.",
107
+ variant: "destructive",
108
+ onConfirm: () => console.log("Confirmado"),
109
+ onCancel: () => console.log("Cancelado")
110
+ });
111
+ };
112
+ }
113
+ ```
114
+
115
+ ### **5. Generic Sheet**
116
+ Sidebars/drawers deslizantes para menus e painéis.
117
+
118
+ **Uso:**
119
+ ```tsx
120
+ import { useSheet } from "@/components/providers/GlobalUIProvider";
121
+
122
+ function MeuComponente() {
123
+ const { showSheet } = useSheet();
124
+
125
+ const openMenu = () => {
126
+ showSheet({
127
+ title: "Menu de Navegação",
128
+ side: "left", // "left" | "right" | "top" | "bottom"
129
+ size: "sm", // "sm" | "md" | "lg" | "xl" | "full"
130
+ content: <MenuNavegacao />
131
+ });
132
+ };
133
+
134
+ const openSettings = () => {
135
+ showSheet({
136
+ title: "Configurações",
137
+ side: "right",
138
+ size: "md",
139
+ content: <PainelConfiguracoes />
140
+ });
141
+ };
142
+ }
143
+ ```
144
+
145
+ ### **6. Splash Screen**
146
+ Tela inicial do app com animações elegantes.
147
+
148
+ **Uso:**
149
+ ```tsx
150
+ import { useSplashScreen } from "@/components/providers/GlobalUIProvider";
151
+
152
+ function MeuComponente() {
153
+ const { showSplash, hideSplash } = useSplashScreen();
154
+
155
+ // Mostrar por 3 segundos
156
+ const showWelcome = () => {
157
+ showSplash(3000);
158
+ };
159
+
160
+ // Mostrar até esconder manualmente
161
+ const showPersistent = () => {
162
+ showSplash(0);
163
+ // Depois chamar hideSplash() quando quiser fechar
164
+ };
165
+ }
166
+ ```
167
+
168
+ ### **7. Prose Typography**
169
+ Componente para conteúdo rico em texto (markdown, artigos, docs).
170
+
171
+ **Uso:**
172
+ ```tsx
173
+ import { ProseTypography, ArticleProse, DocsProse } from "@/components/providers/GlobalUIProvider";
174
+
175
+ // Básico
176
+ <ProseTypography size="base" variant="default">
177
+ <div dangerouslySetInnerHTML={{ __html: meuConteudoHTML }} />
178
+ </ProseTypography>
179
+
180
+ // Para artigos
181
+ <ArticleProse
182
+ title="Título do Artigo"
183
+ subtitle="Subtítulo opcional"
184
+ size="lg"
185
+ >
186
+ {meuConteudo}
187
+ </ArticleProse>
188
+
189
+ // Para documentação
190
+ <DocsProse>
191
+ {documentacaoTecnica}
192
+ </DocsProse>
193
+ ```
194
+
195
+ ### **8. Video Player Modal**
196
+ Modal para reprodução de vídeos do YouTube/Vimeo com suporte a navegação.
197
+
198
+ **Localização:** `@/components/ui/horizon-ui/video-player-modal`
199
+
200
+ **Uso Básico:**
201
+ ```tsx
202
+ import { useState } from "react";
203
+ import { VideoPlayerModal } from "@/components/ui/horizon-ui/video-player-modal";
204
+
205
+ function MeuComponente() {
206
+ const [isOpen, setIsOpen] = useState(false);
207
+
208
+ return (
209
+ <>
210
+ <button onClick={() => setIsOpen(true)}>Assistir Vídeo</button>
211
+
212
+ <VideoPlayerModal
213
+ open={isOpen}
214
+ onOpenChange={setIsOpen}
215
+ video={{
216
+ id: "video-1",
217
+ title: "Título do Vídeo",
218
+ url: "https://www.youtube.com/watch?v=VIDEO_ID",
219
+ subtitle: "Descrição opcional",
220
+ }}
221
+ externalLinkText="Assistir no YouTube"
222
+ />
223
+ </>
224
+ );
225
+ }
226
+ ```
227
+
228
+ **Com Navegação (lista de vídeos):**
229
+ ```tsx
230
+ const [currentIndex, setCurrentIndex] = useState(0);
231
+ const videos = [...]; // Lista de vídeos
232
+
233
+ <VideoPlayerModal
234
+ open={isOpen}
235
+ onOpenChange={setIsOpen}
236
+ video={videos[currentIndex]}
237
+ onPrevious={() => setCurrentIndex((i) => (i === 0 ? videos.length - 1 : i - 1))}
238
+ onNext={() => setCurrentIndex((i) => (i + 1) % videos.length)}
239
+ externalLinkText="Assistir no YouTube"
240
+ externalLinkIcon={<Youtube className="size-5" />}
241
+ />
242
+ ```
243
+
244
+ **Props:**
245
+ | Prop | Tipo | Descrição |
246
+ |------|------|-----------|
247
+ | `open` | `boolean` | Controla abertura do modal |
248
+ | `onOpenChange` | `(open: boolean) => void` | Callback de mudança de estado |
249
+ | `video` | `{ id, title, url, subtitle? }` | Dados do vídeo atual |
250
+ | `onPrevious?` | `() => void` | Callback para vídeo anterior |
251
+ | `onNext?` | `() => void` | Callback para próximo vídeo |
252
+ | `showNavigation?` | `boolean` | Mostrar botões prev/next (default: true) |
253
+ | `showExternalLink?` | `boolean` | Mostrar link externo (default: true) |
254
+ | `externalLinkText?` | `string` | Texto do link externo |
255
+ | `externalLinkIcon?` | `ReactNode` | Ícone do link externo |
256
+
257
+ **Suporte automático:**
258
+ - YouTube: `youtube.com/watch?v=`, `youtu.be/`, `youtube.com/shorts/`
259
+ - Vimeo: `vimeo.com/`
260
+ - URLs de embed diretas
261
+
262
+ ## Como Está Configurado
263
+
264
+ O sistema está **100% integrado** no seu `AppProviders.tsx`:
265
+
266
+ ```tsx
267
+ <GlobalUIProvider
268
+ splashScreen={{
269
+ autoShow: false, // Não mostrar automaticamente
270
+ defaultDuration: 2000,
271
+ }}
272
+ >
273
+ {/* Sua aplicação */}
274
+ </GlobalUIProvider>
275
+ ```
276
+
277
+ ## Exemplo Prático: Página de Contato
278
+
279
+ Sua página `/contato` **já está usando** o sistema:
280
+
281
+ 1. **Toast** para feedback (sucesso/erro)
282
+ 2. **Loading** no botão durante envio
283
+ 3. 🆕 **Pode adicionar Form Alert Modal** para feedback mais elegante
284
+
285
+ **Exemplo de melhoria:**
286
+ ```tsx
287
+ // Substitua o toast por Form Alert Modal
288
+ import { useFormAlert } from "@/components/providers/GlobalUIProvider";
289
+
290
+ const { showAlert } = useFormAlert();
291
+
292
+ // Em vez de:
293
+ toast.success("Mensagem enviada com sucesso!");
294
+
295
+ // Use:
296
+ showAlert({
297
+ type: "success",
298
+ title: "Mensagem Enviada!",
299
+ message: "Nossa equipe entrará em contato em breve.",
300
+ timeout: 5000
301
+ });
302
+ ```
303
+
304
+ ## Stories no Storybook
305
+
306
+ Todos os componentes têm stories completos disponíveis em:
307
+
308
+ - `Global/GlobalLoading`
309
+ - `Global/FormAlertModal`
310
+ - `Global/useModal`
311
+ - `Global/useSheet`
312
+ - `Global/SplashScreen`
313
+ - `Global/ProseTypography`
314
+ - `Global/GlobalUIProvider`
315
+ - `HorizonUI/VideoPlayerModal`
316
+
317
+ Execute `pnpm storybook` e navegue para ver exemplos interativos.
318
+
319
+ ## Características Técnicas
320
+
321
+ - **TypeScript completo** - Tipagem forte em todos os hooks
322
+ - **Responsivo** - Funciona em mobile/desktop
323
+ - **Tema adaptativo** - Dark/light mode automático
324
+ - **Animações suaves** - Transições elegantes
325
+ - **Acessibilidade** - Suporte a screen readers
326
+ - **Performance** - Context otimizado, sem re-renders desnecessários
327
+ - **Modular** - Use só o que precisa
328
+ - **Consistente** - Visual uniforme em toda app
329
+
330
+ ## Próximos Passos
331
+
332
+ 1. **Testar** todos os hooks nas páginas existentes
333
+ 2. **Migrar** toasts existentes para Form Alert Modal onde fizer sentido
334
+ 3. **Implementar** splash screen se desejado (`autoShow: true`)
335
+ 4. **Usar** modais e sheets para menus e formulários
336
+ 5. **Aplicar** ProseTypography em conteúdo de blog/docs
337
+
338
+ ## Dicas de Uso
339
+
340
+ ### **Para Formulários:**
341
+ ```tsx
342
+ // Loading + Form Alert = UX perfeito
343
+ const { showLoading, hideLoading } = useGlobalLoading();
344
+ const { showAlert } = useFormAlert();
345
+
346
+ const handleSubmit = async () => {
347
+ showLoading();
348
+
349
+ try {
350
+ await submitForm();
351
+ hideLoading();
352
+
353
+ showAlert({
354
+ type: "success",
355
+ title: "Sucesso!",
356
+ message: "Formulário processado com sucesso."
357
+ });
358
+ } catch (error) {
359
+ hideLoading();
360
+
361
+ showAlert({
362
+ type: "error",
363
+ title: "Erro no Envio",
364
+ message: "Tente novamente em alguns minutos."
365
+ });
366
+ }
367
+ };
368
+ ```
369
+
370
+ ### **Para Navegação:**
371
+ ```tsx
372
+ // Sheet para menu mobile
373
+ const { showSheet } = useSheet();
374
+
375
+ <Button onClick={() => showSheet({
376
+ title: "Menu",
377
+ side: "left",
378
+ size: "sm",
379
+ content: <MobileMenu />
380
+ })}>
381
+ Menu
382
+ </Button>
383
+ ```
384
+
385
+ ### **Para Confirmações:**
386
+ ```tsx
387
+ // Modal de confirmação elegante
388
+ const { showModal } = useModal();
389
+
390
+ const handleDelete = () => {
391
+ showModal({
392
+ type: "confirm",
393
+ title: "Excluir imóvel?",
394
+ description: "Esta ação não poderá ser desfeita.",
395
+ variant: "destructive",
396
+ confirmLabel: "Sim, excluir",
397
+ cancelLabel: "Cancelar",
398
+ onConfirm: () => {
399
+ // Lógica de exclusão
400
+ }
401
+ });
402
+ };
403
+ ```
404
+
405
+ ---
406
+
407
+ **Parabéns!** Seu app agora tem um sistema completo de componentes globais reutilizáveis, elegantes e performáticos. Tudo configurado e pronto para usar!