pswex-design-system 7.0.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,628 @@
1
+ # Componentes
2
+
3
+ 36 no total, todos em `window.PSWEX`.
4
+ O tipo completo de cada um está em `componentes/tipos/<Nome>.d.ts`.
5
+
6
+ ### Fundamentos
7
+
8
+ #### EscalaTipografica
9
+
10
+ Gilroy em cinco pesos, escala em clamp, sem breakpoint.
11
+
12
+ | Prop | Tipo | Obrigatória | O que faz |
13
+ |---|---|---|---|
14
+ | `className` | `string` | não | |
15
+
16
+ ```jsx
17
+ <EscalaTipografica />
18
+ ```
19
+
20
+ #### Icone
21
+
22
+ Catálogo de 72 ícones de traço: um para cada um dos 14 serviços, um para cada uma das 12 campanhas, e 20 de interface. Os que terminam em `-compact` são a versão simplificada, para 20px ou menos.
23
+
24
+ | Prop | Tipo | Obrigatória | O que faz |
25
+ |---|---|---|---|
26
+ | `nome` | um dos 72 nomes do catálogo, lista na seção Ícones | sim | Nome do ícone no catálogo. O sufixo `-compact` é a versão simplificada, para 20px ou menos. |
27
+ | `tamanho` | `number` | não | Lado do quadrado, em px. O traço não engrossa junto, por isso 24 é o tamanho de desenho. |
28
+ | `titulo` | `string` | não | Rótulo para leitor de tela. Sem ele o ícone é tratado como decoração. |
29
+ | `className` | `string` | não | |
30
+ | `id` | `string` | não | |
31
+ | `style` | `React.CSSProperties` | não | |
32
+
33
+ ```jsx
34
+ <Icone nome="agentes-ia" tamanho={26} />
35
+ <Icone nome="whatsapp-chat" tamanho={18} titulo="Falar no WhatsApp" />
36
+ ```
37
+
38
+ #### PaletaMarca
39
+
40
+ As dez cores da identidade, iguais nos dois temas.
41
+
42
+ | Prop | Tipo | Obrigatória | O que faz |
43
+ |---|---|---|---|
44
+ | `className` | `string` | não | |
45
+
46
+ ```jsx
47
+ <PaletaMarca />
48
+ ```
49
+
50
+ #### PaletaSemantica
51
+
52
+ Os tokens de papel na tela, que invertem no tema escuro.
53
+
54
+ | Prop | Tipo | Obrigatória | O que faz |
55
+ |---|---|---|---|
56
+ | `className` | `string` | não | |
57
+
58
+ ```jsx
59
+ <PaletaSemantica />
60
+ ```
61
+
62
+ ### Componentes
63
+
64
+ #### Btn
65
+
66
+ Botão pílula em três variantes.
67
+
68
+ | Prop | Tipo | Obrigatória | O que faz |
69
+ |---|---|---|---|
70
+ | `variante` | `"cta" \| "red" \| "ghost"` | não | `cta` é o lime, usado para conversão e só uma vez por tela. `red` é o vermelho da marca. `ghost` é contorno, para ação secundária. |
71
+ | `href` | `string` | não | Destino do link. O componente renderiza um `<a>`, então href é o que torna o botão clicável. |
72
+ | `target` | `string` | não | |
73
+ | `rel` | `string` | não | |
74
+ | `children` | `React.ReactNode` | não | |
75
+ | `className` | `string` | não | |
76
+ | `id` | `string` | não | |
77
+ | `style` | `React.CSSProperties` | não | |
78
+
79
+ ```jsx
80
+ <Btn variante="cta" href="#contato">Falar no WhatsApp</Btn>
81
+ <Btn variante="ghost" href="/projetos">Ver projetos</Btn>
82
+ ```
83
+
84
+ #### Card
85
+
86
+ Card de conteúdo com eyebrow, título, apoio e link.
87
+
88
+ | Prop | Tipo | Obrigatória | O que faz |
89
+ |---|---|---|---|
90
+ | `icone` | um dos 72 nomes do catálogo, lista na seção Ícones | não | Ícone do catálogo, acima do eyebrow. É o que tira o card de ser só texto. Ver Icone para a lista. |
91
+ | `eyebrow` | `React.ReactNode` | não | |
92
+ | `titulo` | `React.ReactNode` | sim | |
93
+ | `texto` | `React.ReactNode` | não | Texto de apoio do card. |
94
+ | `href` | `string` | não | Quando existe, o card inteiro vira link e ganha o hover de elevação. |
95
+ | `linkTexto` | `React.ReactNode` | não | Rótulo do link de texto no pé do card. |
96
+ | `className` | `string` | não | |
97
+
98
+ ```jsx
99
+ <Card
100
+ eyebrow="Serviço"
101
+ titulo="Agentes de IA"
102
+ texto="Atendimento que responde na hora e não deixa lead esfriar."
103
+ href="/agentes-de-ia"
104
+ linkTexto="Ver como funciona"
105
+ />
106
+ ```
107
+
108
+ #### Cards
109
+
110
+ Grade fluida de cards, 2, 3 ou 4 colunas.
111
+
112
+ | Prop | Tipo | Obrigatória | O que faz |
113
+ |---|---|---|---|
114
+ | `colunas` | `2 \| 3 \| 4` | não | Número de colunas alvo. A grade é fluida e quebra sozinha no mobile. |
115
+ | `children` | `React.ReactNode` | não | |
116
+ | `className` | `string` | não | |
117
+ | `id` | `string` | não | |
118
+ | `style` | `React.CSSProperties` | não | |
119
+
120
+ ```jsx
121
+ <Cards colunas={3}>
122
+ <Card titulo="Sites" texto="Página que carrega rápido e converte." />
123
+ </Cards>
124
+ ```
125
+
126
+ #### Caso
127
+
128
+ Card de caso com tag de categoria.
129
+
130
+ | Prop | Tipo | Obrigatória | O que faz |
131
+ |---|---|---|---|
132
+ | `icone` | um dos 72 nomes do catálogo, lista na seção Ícones | não | Ícone do catálogo, acima da tag. Ver Icone para a lista. |
133
+ | `tag` | `React.ReactNode` | não | Rótulo do setor ou do tipo de trabalho. |
134
+ | `titulo` | `React.ReactNode` | sim | |
135
+ | `texto` | `React.ReactNode` | não | |
136
+ | `className` | `string` | não | |
137
+
138
+ ```jsx
139
+ <Caso tag="Autoescola" titulo="Clube Líder" texto="O que era feito à mão virou fila automática." />
140
+ ```
141
+
142
+ #### Eyebrow
143
+
144
+ Rótulo curto em caixa alta acima do título.
145
+
146
+ | Prop | Tipo | Obrigatória | O que faz |
147
+ |---|---|---|---|
148
+ | `children` | `React.ReactNode` | não | |
149
+ | `className` | `string` | não | |
150
+ | `id` | `string` | não | |
151
+ | `style` | `React.CSSProperties` | não | |
152
+
153
+ ```jsx
154
+ <Eyebrow>Belo Horizonte</Eyebrow>
155
+ ```
156
+
157
+ #### Faq
158
+
159
+ Item de FAQ em details.
160
+
161
+ | Prop | Tipo | Obrigatória | O que faz |
162
+ |---|---|---|---|
163
+ | `pergunta` | `React.ReactNode` | sim | |
164
+ | `children` | `React.ReactNode` | não | |
165
+ | `aberto` | `boolean` | não | Deixa o item aberto no primeiro render. |
166
+ | `className` | `string` | não | |
167
+
168
+ ```jsx
169
+ <Faq pergunta="Em quanto tempo fica pronto?">Depende do escopo. A proposta traz o prazo fechado.</Faq>
170
+ ```
171
+
172
+ #### Field
173
+
174
+ Campo de formulário com label, controle e linha de erro.
175
+
176
+ | Prop | Tipo | Obrigatória | O que faz |
177
+ |---|---|---|---|
178
+ | `label` | `React.ReactNode` | sim | Texto da label. |
179
+ | `nota` | `React.ReactNode` | não | Complemento da label, em peso leve. Serve para "opcional". |
180
+ | `nome` | `string` | sim | `id` e `name` do controle. |
181
+ | `tipo` | `unknown` | não | |
182
+ | `placeholder` | `string` | não | |
183
+ | `erro` | `React.ReactNode` | não | Mensagem de erro abaixo do campo. |
184
+ | `className` | `string` | não | |
185
+
186
+ ```jsx
187
+ <Field nome="whatsapp" label="WhatsApp" tipo="tel" placeholder="(31) 99999-9999" />
188
+ ```
189
+
190
+ #### Lead
191
+
192
+ Parágrafo de abertura, maior que o corpo.
193
+
194
+ | Prop | Tipo | Obrigatória | O que faz |
195
+ |---|---|---|---|
196
+ | `children` | `React.ReactNode` | não | |
197
+ | `className` | `string` | não | |
198
+ | `id` | `string` | não | |
199
+ | `style` | `React.CSSProperties` | não | |
200
+
201
+ ```jsx
202
+ <Lead>Seu time faz o trabalho. O processo faz o trabalho voltar.</Lead>
203
+ ```
204
+
205
+ #### PillList
206
+
207
+ Pílulas de navegação secundária.
208
+
209
+ | Prop | Tipo | Obrigatória | O que faz |
210
+ |---|---|---|---|
211
+ | `itens` | `{ rotulo: React.ReactNode; href: string; }[]` | sim | Cada item vira uma pílula clicável. |
212
+ | `className` | `string` | não | |
213
+
214
+ ```jsx
215
+ <PillList itens={[{rotulo:'Sites', href:'/sites'}, {rotulo:'Lojas virtuais', href:'/lojas'}]} />
216
+ ```
217
+
218
+ #### Quote
219
+
220
+ Depoimento com régua vermelha e atribuição.
221
+
222
+ | Prop | Tipo | Obrigatória | O que faz |
223
+ |---|---|---|---|
224
+ | `children` | `React.ReactNode` | não | A citação. |
225
+ | `autor` | `React.ReactNode` | não | Quem falou, e de onde. |
226
+ | `className` | `string` | não | |
227
+
228
+ ```jsx
229
+ <Quote autor="Michele, clínica">
230
+ Resolveu a agenda que vivia dando choque de horário.
231
+ </Quote>
232
+ ```
233
+
234
+ #### Quotes
235
+
236
+ Grade fluida de depoimentos.
237
+
238
+ | Prop | Tipo | Obrigatória | O que faz |
239
+ |---|---|---|---|
240
+ | `children` | `React.ReactNode` | não | |
241
+ | `className` | `string` | não | |
242
+ | `id` | `string` | não | |
243
+ | `style` | `React.CSSProperties` | não | |
244
+
245
+ ```jsx
246
+ <Quotes><Quote autor="Bruno, climatização">Chegou lead no mesmo dia.</Quote></Quotes>
247
+ ```
248
+
249
+ #### Ratingbar
250
+
251
+ Faixa fina logo abaixo do hero, no navy mais escuro, com frases curtas de contexto.
252
+
253
+ | Prop | Tipo | Obrigatória | O que faz |
254
+ |---|---|---|---|
255
+ | `estrelas` | `React.ReactNode` | não | Estrelas em texto. Vazio por padrão: nota de avaliação só entra com fonte conferida. |
256
+ | `destaque` | `React.ReactNode` | não | Trecho em negrito logo depois das estrelas. |
257
+ | `itens` | `React.ReactNode[]` | não | Frases curtas ao lado, separadas pelo próprio flex. |
258
+ | `className` | `string` | não | |
259
+
260
+ ```jsx
261
+ <Ratingbar itens={["Mais de 10 anos fazendo tecnologia que vende", "Belo Horizonte, atendendo o Brasil inteiro"]} />
262
+ ```
263
+
264
+ #### Reveal
265
+
266
+ Envelope de entrada: o conteúdo sobe 14px e aparece quando ganha a classe `in`.
267
+
268
+ | Prop | Tipo | Obrigatória | O que faz |
269
+ |---|---|---|---|
270
+ | `visivel` | `boolean` | não | `true` já entra visível, que é o que o script do site faz ao cruzar a viewport. |
271
+ | `children` | `React.ReactNode` | não | |
272
+ | `className` | `string` | não | |
273
+ | `id` | `string` | não | |
274
+ | `style` | `React.CSSProperties` | não | |
275
+
276
+ ```jsx
277
+ <Reveal visivel>
278
+ <SecHead titulo="Onde a gente já entregou" />
279
+ </Reveal>
280
+ ```
281
+
282
+ #### Row2
283
+
284
+ Duas colunas dentro do formulário.
285
+
286
+ | Prop | Tipo | Obrigatória | O que faz |
287
+ |---|---|---|---|
288
+ | `children` | `React.ReactNode` | não | |
289
+ | `className` | `string` | não | |
290
+ | `id` | `string` | não | |
291
+ | `style` | `React.CSSProperties` | não | |
292
+
293
+ ```jsx
294
+ <Row2><Field nome="nome" label="Nome" /><Field nome="email" label="E-mail" tipo="email" /></Row2>
295
+ ```
296
+
297
+ #### SecHead
298
+
299
+ Eyebrow, h2 e apoio, o cabeçalho de toda seção.
300
+
301
+ | Prop | Tipo | Obrigatória | O que faz |
302
+ |---|---|---|---|
303
+ | `eyebrow` | `React.ReactNode` | não | Rótulo em caixa alta acima do título. |
304
+ | `titulo` | `React.ReactNode` | sim | Título da seção, sai como h2. |
305
+ | `apoio` | `React.ReactNode` | não | Linha de apoio abaixo do título. |
306
+ | `className` | `string` | não | |
307
+
308
+ ```jsx
309
+ <SecHead
310
+ eyebrow="Projetos"
311
+ titulo="Onde a gente já entregou"
312
+ apoio="Cliente com nome, setor e o que foi feito."
313
+ />
314
+ ```
315
+
316
+ #### Selos
317
+
318
+ Pílulas de contorno para credencial e localização.
319
+
320
+ | Prop | Tipo | Obrigatória | O que faz |
321
+ |---|---|---|---|
322
+ | `itens` | `React.ReactNode[]` | sim | Credencial, localização, CNPJ, o que for verificável. |
323
+ | `className` | `string` | não | |
324
+
325
+ ```jsx
326
+ <Selos itens={['Belo Horizonte', 'CNPJ 28.477.119/0001-79', 'Google Ads AI']} />
327
+ ```
328
+
329
+ #### SkipLink
330
+
331
+ Atalho de teclado para pular a navegação e cair no conteúdo.
332
+
333
+ | Prop | Tipo | Obrigatória | O que faz |
334
+ |---|---|---|---|
335
+ | `children` | `React.ReactNode` | não | |
336
+ | `className` | `string` | não | |
337
+ | `id` | `string` | não | |
338
+ | `style` | `React.CSSProperties` | não | |
339
+
340
+ ```jsx
341
+ <SkipLink href="#conteudo">Ir para o conteúdo</SkipLink>
342
+ ```
343
+
344
+ #### StepsList
345
+
346
+ Método numerado, com a numeração vinda do CSS.
347
+
348
+ | Prop | Tipo | Obrigatória | O que faz |
349
+ |---|---|---|---|
350
+ | `passos` | `PassoProps[]` | sim | |
351
+ | `className` | `string` | não | |
352
+
353
+ ```jsx
354
+ <StepsList passos={[
355
+ {titulo:'Elimina', texto:'O que não precisa existir sai.'},
356
+ {titulo:'Simplifica', texto:'O que sobra fica com menos passo.'},
357
+ ]} />
358
+ ```
359
+
360
+ #### Ticks
361
+
362
+ Lista de checagem com marcador redondo.
363
+
364
+ | Prop | Tipo | Obrigatória | O que faz |
365
+ |---|---|---|---|
366
+ | `itens` | `React.ReactNode[]` | sim | Itens da lista. |
367
+ | `positivo` | `boolean` | não | `false` troca o marcador para o X em fundo rosa claro. |
368
+ | `className` | `string` | não | |
369
+
370
+ ```jsx
371
+ <Ticks itens={['Hospedagem inclusa', 'Open Graph em todas as páginas']} />
372
+ ```
373
+
374
+ #### TxtLink
375
+
376
+ Link de texto com sublinhado no hover.
377
+
378
+ | Prop | Tipo | Obrigatória | O que faz |
379
+ |---|---|---|---|
380
+ | `href` | `string` | não | Destino do link. O componente renderiza um `<a>`. |
381
+ | `target` | `string` | não | |
382
+ | `rel` | `string` | não | |
383
+ | `children` | `React.ReactNode` | não | |
384
+ | `className` | `string` | não | |
385
+ | `id` | `string` | não | |
386
+ | `style` | `React.CSSProperties` | não | |
387
+
388
+ ```jsx
389
+ <TxtLink href="/servicos">Ver todos os serviços</TxtLink>
390
+ ```
391
+
392
+ #### Vid
393
+
394
+ Depoimento em vídeo em proporção 16 por 10, com o nome de quem fala sobreposto embaixo.
395
+
396
+ | Prop | Tipo | Obrigatória | O que faz |
397
+ |---|---|---|---|
398
+ | `src` | `string` | não | |
399
+ | `placeholder` | `React.ReactNode` | não | Texto mostrado no lugar do player enquanto não existe arquivo de vídeo. |
400
+ | `poster` | `string` | não | Imagem que aparece antes do play. |
401
+ | `legenda` | `React.ReactNode` | não | Nome e contexto de quem fala, sobre um véu escuro no rodapé. |
402
+ | `className` | `string` | não | |
403
+
404
+ ```jsx
405
+ <Vid src="/depoimentos/bruno.mp4" poster="/depoimentos/bruno.jpg" legenda="Bruno, Climatização" />
406
+ ```
407
+
408
+ ### Blocos
409
+
410
+ #### Footer
411
+
412
+ Rodapé no navy mais escuro. Coluna da marca com descrição e selos, mais até três colunas de navegação, e a linha legal no pé.
413
+
414
+ | Prop | Tipo | Obrigatória | O que faz |
415
+ |---|---|---|---|
416
+ | `logo` | `React.ReactNode` | não | |
417
+ | `descricao` | `React.ReactNode` | não | Parágrafo de posicionamento embaixo do logo. |
418
+ | `selos` | `React.ReactNode` | não | Selos da primeira coluna. Um `Selos` cabe aqui. |
419
+ | `colunas` | `FooterColuna[]` | não | |
420
+ | `legal` | `React.ReactNode[]` | não | Linha final: razão social, CNPJ, endereço, telefone. |
421
+ | `className` | `string` | não | |
422
+
423
+ ```jsx
424
+ <Footer
425
+ logo={<img src="/logo-branco.png" alt="PSWEX" height={28} />}
426
+ descricao="Nós fazemos seu negócio dar certo."
427
+ selos={<Selos itens={["Meta Tech Provider", "Google Ads AI"]} />}
428
+ colunas={[{ titulo: "Serviços", links: [{ href: "/sites", label: "Criação de sites" }] }]}
429
+ legal={["PSWEX Tecnologia", "CNPJ 28.477.119/0001-79", "(31) 99922-9792"]}
430
+ />
431
+ ```
432
+
433
+ #### Hero
434
+
435
+ Dobra de abertura em navy com foto de fundo.
436
+
437
+ | Prop | Tipo | Obrigatória | O que faz |
438
+ |---|---|---|---|
439
+ | `eyebrow` | `React.ReactNode` | não | |
440
+ | `titulo` | `React.ReactNode` | sim | |
441
+ | `apoio` | `React.ReactNode` | não | |
442
+ | `acoes` | `React.ReactNode` | não | Botões da dobra. Um cta e um ghost é o padrão da casa. |
443
+ | `nota` | `React.ReactNode` | não | Linha pequena abaixo dos botões. |
444
+ | `lado` | `React.ReactNode` | não | Coluna da direita: imagem, vídeo, o que a página pedir. |
445
+ | `fundo` | `"foto" \| "grad" \| "grad-azul" \| "grad-vermelho"` | não | `foto` é o webp de fundo. `grad` é a arte vetorial, que troca sozinha de arquivo em 1400px e em 980px. `grad-azul` e `gr |
446
+ | `className` | `string` | não | |
447
+
448
+ ```jsx
449
+ <Hero
450
+ eyebrow="Belo Horizonte, 10 anos"
451
+ titulo="Nós fazemos seu negócio dar certo"
452
+ apoio="Seu time faz o trabalho. O processo faz o trabalho voltar. E você paga pelas duas vezes."
453
+ acoes={<><Btn variante="cta" href="#contato">Falar no WhatsApp</Btn><Btn variante="ghost" href="/projetos">Ver projetos</Btn></>}
454
+ nota="Resposta no mesmo dia útil."
455
+ />
456
+ ```
457
+
458
+ #### LeadForm
459
+
460
+ Formulário de captura em card branco.
461
+
462
+ | Prop | Tipo | Obrigatória | O que faz |
463
+ |---|---|---|---|
464
+ | `children` | `React.ReactNode` | não | |
465
+ | `botao` | `React.ReactNode` | não | Texto do botão de envio. |
466
+ | `nota` | `React.ReactNode` | não | Linha de privacidade abaixo do botão. |
467
+ | `className` | `string` | não | |
468
+
469
+ ```jsx
470
+ <LeadForm botao="Quero falar com a PSWEX" nota="Seus dados ficam com a PSWEX.">
471
+ <Row2><Field nome="nome" label="Nome" /><Field nome="tel" label="WhatsApp" tipo="tel" /></Row2>
472
+ <Field nome="empresa" label="Empresa" nota="opcional" />
473
+ </LeadForm>
474
+ ```
475
+
476
+ #### PhoneMock
477
+
478
+ Aparelho desenhado em CSS com uma conversa dentro. É a coluna direita do hero da home.
479
+
480
+ | Prop | Tipo | Obrigatória | O que faz |
481
+ |---|---|---|---|
482
+ | `mensagens` | `PhoneMensagem[]` | sim | |
483
+ | `passos` | `React.ReactNode[]` | não | Pílulas que entram animadas ao lado do aparelho. Abaixo de 1100px empilham. |
484
+ | `className` | `string` | não | |
485
+
486
+ ```jsx
487
+ <PhoneMock
488
+ mensagens={[
489
+ { texto: "Vocês fazem orçamento de quanto?" },
490
+ { texto: "Depende do que você precisa.", de: "voce" },
491
+ ]}
492
+ passos={["Entender o que trava", "Escolher por onde começar"]}
493
+ />
494
+ ```
495
+
496
+ #### Secao
497
+
498
+ Seção com padding vertical da escala e Shell embutido.
499
+
500
+ | Prop | Tipo | Obrigatória | O que faz |
501
+ |---|---|---|---|
502
+ | `fundo` | um dos 10 nomes do catálogo, lista na seção Ícones | não | Fundo da seção. `dark` é o navy da marca. `grad` é a arte vetorial da casa, azul de um lado e vermelho do outro, com a p |
503
+ | `children` | `React.ReactNode` | não | |
504
+ | `className` | `string` | não | |
505
+ | `id` | `string` | não | |
506
+ | `style` | `React.CSSProperties` | não | |
507
+
508
+ ```jsx
509
+ <Secao fundo="dark">
510
+ <SecHead eyebrow="Método" titulo="Elimina, simplifica, automatiza" />
511
+ <StepsList passos={[{titulo:'Elimina', texto:'O que não precisa existir sai.'}]} />
512
+ </Secao>
513
+ ```
514
+
515
+ #### Servicos
516
+
517
+ Grade de serviço com ícone. É o atalho para não montar `Cards` cheio de `Card` na mão em toda página.
518
+
519
+ | Prop | Tipo | Obrigatória | O que faz |
520
+ |---|---|---|---|
521
+ | `itens` | um dos 72 nomes do catálogo, lista na seção Ícones | sim | Um item por card. O ícone é obrigatório, que é o ponto do bloco. |
522
+ | `titulo` | `React.ReactNode` | sim | |
523
+ | `texto` | `React.ReactNode` | não | |
524
+ | `href` | `string` | não | Quando existe, o card vira link e ganha o rótulo "Ver" no pé. |
525
+ | `colunas` | `2 \| 3 \| 4` | não | |
526
+ | `className` | `string` | não | |
527
+
528
+ ```jsx
529
+ <Servicos
530
+ colunas={3}
531
+ itens={[
532
+ { icone: 'criacao-de-sites', titulo: 'Sites', texto: 'Carrega rápido e tem para onde ir.', href: '/sites' },
533
+ { icone: 'agentes-ia', titulo: 'Agentes de IA', texto: 'Responde na hora e qualifica.', href: '/ia' },
534
+ ]}
535
+ />
536
+ ```
537
+
538
+ #### Shell
539
+
540
+ Container de 1200px com respiro lateral.
541
+
542
+ | Prop | Tipo | Obrigatória | O que faz |
543
+ |---|---|---|---|
544
+ | `children` | `React.ReactNode` | não | |
545
+ | `className` | `string` | não | |
546
+ | `id` | `string` | não | |
547
+ | `style` | `React.CSSProperties` | não | |
548
+
549
+ ```jsx
550
+ <Shell>
551
+ <SecHead titulo="Serviços" />
552
+ </Shell>
553
+ ```
554
+
555
+ #### Split
556
+
557
+ Duas colunas dentro de uma `section`, que viram uma só abaixo de 900px.
558
+
559
+ | Prop | Tipo | Obrigatória | O que faz |
560
+ |---|---|---|---|
561
+ | `proporcao` | `"a" \| "b" \| "c"` | não | `a` dá mais espaço à esquerda, `b` divide igual, `c` divide igual e centraliza na vertical. |
562
+ | `children` | `React.ReactNode` | não | |
563
+ | `className` | `string` | não | |
564
+ | `id` | `string` | não | |
565
+ | `style` | `React.CSSProperties` | não | |
566
+
567
+ ```jsx
568
+ <section>
569
+ <Split proporcao="a">
570
+ <div><SecHead titulo="O que você recebe." /></div>
571
+ <div><StepsList passos={[{ titulo: "Entender" }]} /></div>
572
+ </Split>
573
+ </section>
574
+ ```
575
+
576
+ #### Topbar
577
+
578
+ Cabeçalho fixo em navy translúcido. Logo à esquerda, navegação no meio, botão de conversão à direita.
579
+
580
+ | Prop | Tipo | Obrigatória | O que faz |
581
+ |---|---|---|---|
582
+ | `logo` | `React.ReactNode` | não | Logo da marca. Imagem de 30px de altura sobre o navy. |
583
+ | `href` | `string` | não | |
584
+ | `links` | `TopbarLink[]` | não | |
585
+ | `acao` | `React.ReactNode` | não | Botão da direita. Um `Btn` com variante `cta` é o padrão. |
586
+ | `className` | `string` | não | |
587
+
588
+ ```jsx
589
+ <Topbar
590
+ logo={<img src="/logo-branco.png" alt="PSWEX" height={30} />}
591
+ href="/"
592
+ links={[{ href: "/servicos", label: "Serviços" }, { href: "/cases", label: "Projetos", atual: true }]}
593
+ acao={<Btn variante="cta" href="/avaliacao">Falar com a gente</Btn>}
594
+ />
595
+ ```
596
+
597
+ #### Wall
598
+
599
+ Parede de logos de cliente em grade automática.
600
+
601
+ | Prop | Tipo | Obrigatória | O que faz |
602
+ |---|---|---|---|
603
+ | `titulo` | `React.ReactNode` | não | Rótulo centralizado acima da grade. |
604
+ | `logos` | `WallLogo[]` | sim | |
605
+ | `className` | `string` | não | |
606
+
607
+ ```jsx
608
+ <Wall titulo="Quem já confiou" logos={[{ src: "/logos/unimed.png", alt: "Unimed, cliente PSWEX" }]} />
609
+ ```
610
+
611
+ #### WhatsAppModal
612
+
613
+ Pede nome e número antes de abrir a conversa no WhatsApp. É o que separa um clique anônimo de um lead com nome.
614
+
615
+ | Prop | Tipo | Obrigatória | O que faz |
616
+ |---|---|---|---|
617
+ | `aberto` | `boolean` | não | `false` mantém o `hidden`, que é como o modal nasce antes do clique. |
618
+ | `eyebrow` | `React.ReactNode` | não | |
619
+ | `titulo` | `React.ReactNode` | não | |
620
+ | `apoio` | `React.ReactNode` | não | |
621
+ | `botao` | `React.ReactNode` | não | |
622
+ | `nota` | `React.ReactNode` | não | Linha de privacidade centralizada abaixo do botão. |
623
+ | `className` | `string` | não | |
624
+ | `style` | `React.CSSProperties` | não | Escape para ancorar o modal dentro de um container, em vez de cobrir a tela. |
625
+
626
+ ```jsx
627
+ <WhatsAppModal aberto />
628
+ ```