Layout
O layout do front-web-base é baseado em um sistema de composição de variantes. Cada brand escolhe quais componentes de slot (header, sidebar, footer, etc.) quer usar via app/config/layout/composition.ts, sem precisar reescrever o DefaultLayout.tsx.
Sistema de Composição
Camadas
| Camada | Arquivo | Responsabilidade |
|---|---|---|
| Config brand-editável | app/config/layout/composition.ts | Define slots e estrutura para a brand |
| Defaults + helper | app/layouts/layout.defaults.ts | Valores default do base + defineLayoutConfig() (deep merge) |
| Catálogo central | app/layouts/layout-registry.ts | Mapa string key → componente |
| Variantes | app/layouts/variants/<slot>/ | Componentes de variante reutilizáveis |
| Tipos | app/types/layout.ts | LayoutConfig, ColumnLayout, *VariantKey |
Estrutura do LayoutConfig
// app/types/layout.ts
export type ColumnLayout = "left-main" | "left-main-right";
export type HeaderVariantKey = "header-default" | "header-vera";
export type SidebarVariantKey = "sidebar-narrow" | "sidebar-wide";
export type RightPanelVariantKey = "right-panel-winners";
export type FooterVariantKey = "footer-default";
export interface LayoutConfig {
structure: {
columns: ColumnLayout;
};
slots: {
header: HeaderVariantKey;
sidebar: SidebarVariantKey;
rightPanel?: RightPanelVariantKey;
footer: FooterVariantKey;
};
componentVariants?: {
// variantes de sub-componentes (ex: bannerHeight)
[key: string]: string;
};
}
Provider Chain
Os providers são aninhados nesta ordem (dentro do DefaultLayout.tsx):
EnvProvider → BrandProvider → CountryProvider → TranslationProvider
Após os providers, três initializers executam side-effects:
| Initializer | Função |
|---|---|
AuthInitializer | Restaura sessão, refresh token, polling de profile |
WalletInitializer | Carrega saldo e configura polling |
SmarticoInitializer | Inicializa SDK Smartico (gamificação) se smarticoHash existir |
Estrutura visual (layout padrão)
┌────────────────────────────────────────────────────────────┐
│ Header (h-14, bg-header-bg) │
│ [☰ mobile] [Logo] [Casino|Sports] [🔍 Ctrl+K] [Auth] │
├──────────────┬─────────────────────────────────────────────┤
│ Sidebar │ main (flex-1, overflow-y-auto) │
│ 280px exp. │ │
│ 70px col. │ {children} │
│ │ │
│ Promo │ <Suspense> │
│ Casino │ <LazyFooter /> │
│ Sports │ </Suspense> │
│ Extras │ │
├──────────────┴─────────────────────────────────────────────┤
│ MobileBottomNav (mobile only) │
└────────────────────────────────────────────────────────────┘
Variantes disponíveis
Header
| Chave | Componente | Descrição |
|---|---|---|
header-default | HeaderDefault.tsx | Header padrão com logo, tabs casino/sports, search, auth |
header-vera | HeaderVera.tsx | Placeholder para vera-bet (smoke test) |
Sidebar
| Chave | Componente | Descrição |
|---|---|---|
sidebar-narrow | SidebarNarrow.tsx | Sidebar colapsável 280px/70px (padrão) |
sidebar-wide | SidebarWide.tsx | Sidebar larga (para layouts com mais espaço) |
Footer
| Chave | Componente | Descrição |
|---|---|---|
footer-default | FooterDefault.tsx | Footer padrão com sponsors, links, badges, legal |
Right Panel (opcional)
| Chave | Componente | Descrição |
|---|---|---|
right-panel-winners | RightPanelWinners.tsx | Coluna direita com lista de vencedores |
Widgets opcionais
Além dos slots estruturais, o template tem widgets opcionais que cada brand liga/desliga via app/config/widgets/<nome>.ts. Cada widget mora em app/widgets/<nome>/ e segue o pattern { variant: VariantKey | null, items: Item[] }.
| Widget | Config | Componente | Função |
|---|---|---|---|
| Sidebar Buttons | widgets/sidebar-buttons.ts | app/widgets/sidebar-buttons/ | CTAs no rail da sidebar (referral, tournaments, missions, etc.) — 3 visual variants (colored, gradient, grid) + 8 catalog intents typed + custom items + specials (sponsor-cta) |
| Topbar Notifications | widgets/topbar-notifications.ts | app/widgets/topbar-notifications/ | Barra rotativa no topo (download app, telegram, push) |
| Bottom Notifications | widgets/bottom-notifications.ts | app/widgets/bottom-notifications/ | CTA flutuante mobile no fundo da tela |
| Campaign Widget | widgets/campaign-widget.ts | app/widgets/campaign-widget/ | Presentinho flutuante de campanha sazonal |
| Home Leagues | widgets/home-leagues.ts | app/widgets/home-leagues/ | Row de ligas esportivas curadas na home |
Sidebar Buttons — exemplo de uso
Brand controla cada item via gradient/color/lucide-icon/image. Cores se ajustam ao tema da brand automaticamente quando não há override:
// overrides/<brand>/app/config/widgets/sidebar-buttons.ts
import { Trophy, Target, Users } from "lucide-react";
import type { SidebarButtonsConfig } from "~/types/sidebar-buttons";
export const sidebarButtonsConfig: SidebarButtonsConfig = {
variant: "gradient",
items: [
{
intent: "referral",
iconType: "lucide",
icon: Users,
// Brand-primary green com fade-out alpha (a1cd3d f2 → a1cd3d 36).
gradient: ["#a1cd3df2", "#a1cd3d36"],
},
{ intent: "tournaments", iconType: "lucide", icon: Trophy },
{ intent: "missions", iconType: "lucide", icon: Target },
],
};
Detalhes completos em Layout Composition — Widgets.
Lazy Modals
Modais carregados sob demanda (code-split) — montados pelo DefaultLayout.tsx:
| Modal | Trigger |
|---|---|
LazyValidationBlockerOverlay | Usuário sem validação completa tenta ação protegida |
LazyAuthModals | Login, registro, esqueci senha |
LazyValidationStepsModal | Steps de validação (email, SMS, docs, endereço) |
LazyPasswordValidationModal | Confirmação de senha para ações sensíveis |
LazyKycModal | Verificação KYC |
LazyPaymentModals | Depósito, saque, PIX |
SearchKeyboardShortcut | Ctrl/Cmd+K abre busca |
BackToTop
Botão flutuante que aparece após scroll. Usa contentRef para rolar o main de volta ao topo.
MobileBottomNav
Barra de navegação fixa no rodapé em mobile. Mostra ícones para Home, Casino, Sports, Depositar, Perfil.
layout.config.ts (fork override)
O arquivo app/config/layout/composition.ts é o ponto de entrada brand-editável para o sistema de composição. O helper defineLayoutConfig faz deep merge com os defaults do base — o brand só precisa especificar o que muda.
// app/config/layout/composition.ts (base — layout padrão)
import { defineLayoutConfig } from "~/layouts/layout.defaults";
export const layoutConfig = defineLayoutConfig({});
// overrides/vera-bet/app/config/layout/composition.ts (exemplo de brand)
import { defineLayoutConfig } from "~/layouts/layout.defaults";
export const layoutConfig = defineLayoutConfig({
structure: { columns: "left-main-right" },
slots: {
header: "header-vera",
sidebar: "sidebar-wide",
rightPanel: "right-panel-winners",
},
});
Para criar uma variante completamente custom:
- Criar componente em
app/layouts/variants/<slot>/<NomeVariante>.tsx - Adicionar a chave em
app/types/layout.ts(ex:"header-custom"noHeaderVariantKey) - Registrar em
app/layouts/layout-registry.ts - Usar a nova chave no
layout.config.tsdo fork
Veja a documentação completa do sistema de composição em Layout Composition System.