Pontos de Customização Rápida
O template prepara 3 arquivos como pontos de customização fácil. Eles são os primeiros que um fork vai querer alterar, mas o cliente não está limitado a eles — pode modificar qualquer arquivo do projeto.
Estrutura app/config/ em subpastas semânticas
app/config/ foi reorganizado em 14 subpastas por domínio. Imports usam path completo (~/config/<dir>/X), sem suffix .config. Brand override espelha o mesmo path:
app/config/
├── theme/ colors, sizes
├── layout/ composition (slots), header, sidebar, sidebar-sports, bottomnav, menu, user-tabs
├── widgets/ sidebar-buttons, topbar-notifications, bottom-notifications, campaign-widget, home-leagues
├── sections/ home-rows.{legacy,new,custom}, casino-rows.{...}, casino-live-rows.{...}
├── catalog/ categories.custom, categories.personalize, game-thumbs, smart-related
├── routes/ paths, legacy-redirects, lp-redirects, lps
├── analytics/ analytics, schema, mixpanel, hotjar, pendo, appsflyer
├── features/ features, configcat
├── scripts/ scripts, images, games (Softswiss inject)
├── legal/ licenses, pages, html/{privacy,terms,...}
├── seo/ seo, page-descriptions.server, games-seo.server, sports-seo
├── payments/ deposit
├── gamification/ gamification, gamification.server
├── sports/ sports
├── referral/ v1, v2
└── content/ faq.server, game-details.server
1. theme/colors.ts
Define os tokens de cor do tema da brand. Todo fork vai querer personalizar este arquivo.
// app/config/theme/colors.ts (ou overrides/<brand>/app/config/theme/colors.ts)
export const themeColors = {
primary: "#ff6b00",
"bg-primary": "#1a0a00",
sidebar: {
bg: "#1f1200",
"button-bg": "#3a1f5e",
icon: "#ffffff",
"cta-bg": "#ff6b00",
"cta-text": "#ffffff",
// ...
},
// ... demais tokens
};
Os tokens viram Tailwind utility classes automaticamente: sidebar.button-bg → bg-sidebar-button-bg, text-sidebar-button-bg, border-sidebar-button-bg, from-sidebar-button-bg, etc. Componentes usam essas classes pra ficarem brand-aware sem hardcoding.
2. routes/paths.ts
Customiza URL paths por brand (ex: /casino → /cassino):
// overrides/<brand-key>/app/config/routes/paths.ts
import type { RoutePathMap } from "~/types/routes";
export const routePaths: RoutePathMap = {
casino: "/cassino",
"casino.play": "/cassino/jogar/:provider/:game",
// ... todas as outras chaves obrigatórias
};
:::caution Registro de rotas não é overrideable
O registro de rotas (app/router/routes.ts) não é overrideable via Vite plugin — é um arquivo do fork. Para adicionar novas páginas, edite app/router/routes.ts diretamente. Para customizar URL paths das páginas existentes, use o override de routes/paths.ts.
:::
3. layout/composition.ts
Define a composição de layout — quais variantes de header, sidebar, footer e outros slots usar. O helper defineLayoutConfig faz deep merge com os defaults do base.
// overrides/<brand-key>/app/config/layout/composition.ts
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 nova (ex: "header-custom"):
- Criar o componente em
app/layouts/variants/header/HeaderCustom.tsx - Adicionar a chave
"header-custom"emapp/types/layout.ts(HeaderVariantKey) - Registrar em
app/layouts/layout-registry.ts - Usar a nova chave no override de
composition.ts
Veja a documentação completa em Layout Composition System.
4. widgets/sidebar-buttons.ts (e demais widgets)
Widgets opcionais embebidos (sidebar-buttons, topbar-notifications, bottom-notifications, campaign-widget, home-leagues) têm cada um seu próprio config file que a brand pode redeclarar. Pattern recorrente: { variant: VariantKey | null, items: Item[] }.
Exemplo — sidebar-buttons com gradient horizontal customizado per-item:
// 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,
gradient: ["#a1cd3df2", "#a1cd3d36"], // accent → fade pro sidebar bg
},
{ intent: "tournaments", iconType: "lucide", icon: Trophy },
{ intent: "missions", iconType: "lucide", icon: Target },
],
};
3 variants visuais (colored / gradient / grid), 8 catalog intents typed, custom items pra one-offs, special items pra UI dedicada (sponsor-cta). Cada brand escolhe a paleta sem mexer em código. Detalhes em Layout Composition — Widgets.
Brand overrides (overrides/<brand-key>/app/)
Cada brand pode sobrescrever arquivos espelhando a estrutura de app/ em overrides/<brand-key>/app/. O brandOverridesPlugin do Vite resolve qualquer import ~/xxx olhando primeiro em overrides/<brand-key>/app/xxx; se o arquivo existir lá, ele é usado. Caso contrário, cai no base em app/xxx. Não há whitelist — qualquer arquivo sob ~/ é potencialmente overridável.
Override = file replacement, não deep-merge. Se brand sobrescreve widgets/sidebar-buttons.ts, redeclara o config inteiro. Não há merge campo-a-campo.
Na prática, os alvos mais comuns por domínio (lista viva — conferir app/config/ pra estado atual):
# Visual / layout
theme/colors.ts theme/sizes.ts
layout/composition.ts layout/header.ts layout/sidebar.ts
layout/sidebar-sports.ts layout/bottomnav.ts layout/menu.ts
layout/user-tabs.ts
# Widgets opcionais
widgets/sidebar-buttons.ts widgets/topbar-notifications.ts
widgets/bottom-notifications.ts widgets/campaign-widget.ts widgets/home-leagues.ts
# Rotas
routes/paths.ts routes/legacy-redirects.ts
routes/lp-redirects.ts routes/lps.ts
# Catálogo de jogos / categorias
catalog/categories.custom.ts catalog/categories.personalize.ts
catalog/game-thumbs.ts catalog/smart-related.ts
# Seções de página
sections/home-rows.{legacy,new,custom}.ts
sections/casino-rows.{legacy,new,custom}.ts
sections/casino-live-rows.{legacy,new,custom}.ts
# Conteúdo / features / SEO
features/features.ts features/configcat.ts
analytics/{analytics,schema,mixpanel,hotjar,pendo,appsflyer}.ts
legal/licenses.ts legal/pages.ts legal/html/*.ts
seo/seo.ts seo/page-descriptions.server.ts
seo/games-seo.server.ts seo/sports-seo.ts
payments/deposit.ts gamification/gamification.ts
sports/sports.ts scripts/{scripts,images,games}.ts
referral/v1.ts referral/v2.ts
content/faq.server.ts content/game-details.server.ts
Casino rows — override por brand
Com o enum CASSINO_MODE (ver env-vars e games.md), brands que rodam CASSINO_MODE=legacy declaram as rows da home/hub/live no arquivo X.legacy.ts (onde X ∈ {home-rows, casino-rows, casino-live-rows}). Em CASSINO_MODE=api_new o BFF é a fonte das rows — brands nesse modo não precisam override.
X.legacy.tsexportalegacyHomeRows/legacyCasinoRows/legacyCasinoLiveRows— consumido quandoCASSINO_MODE=legacy.
categories.personalize.config.ts é um overlay opcional que aplica orderBy + displayPriority em slugs do BFF (modos legacy e api_new). Sem entry, a categoria segue o comportamento nativo do BFF.
game-details.server.ts (SEO e descriptions de jogos)
O arquivo game-details.server.ts centraliza metadados SEO e descriptions de jogos. É server-only — nunca entra no bundle client.
Estrutura:
defaults— templates aplicados a todos os jogos sem entry específicagames— overrides por jogo (campos omitidos herdam do defaults)
Template tags disponíveis: {game_name}, {game_provider}, {game_rtp}, {brand_name}.
// overrides/casateste-com/app/config/content/game-details.server.ts
export interface GameDetailEntry {
meta_title?: string;
meta_description?: string;
front_description?: string;
}
export interface GameDetailsConfig {
defaults: Required<GameDetailEntry>;
games: Record<string, Partial<GameDetailEntry>>;
}
export const gameDetails: GameDetailsConfig = {
defaults: {
meta_title: "{game_name} - Jogar no CasaTeste | {brand_name}",
meta_description: "{game_name} é um jogo disponível no {brand_name}...",
front_description: "<strong>{game_name}</strong> é um jogo disponível no <strong>{brand_name}</strong>...",
},
games: {
"pgsoft/fortune-tiger": {
meta_title: "Fortune Tiger 🐯 - Exclusivo CasaTeste",
// meta_description e front_description herdam do defaults
},
},
};
routes.paths.ts (Route Registry)
O arquivo routes.paths.ts permite que brands customizem todos os URL paths de páginas sem tocar em componentes ou no route tree. O override deve exportar um objeto routePaths completo implementando RoutePathMap:
// overrides/state77-com/app/config/routes/paths.ts
import type { RoutePathMap } from "~/types/routes";
export const routePaths: RoutePathMap = {
casino: "/casino",
"casino.play": "/casino/juego/:provider/:game",
sports: "/deportes",
// ... todas as outras chaves obrigatórias
};
Apenas os segmentos estáticos devem ser alterados — placeholders de parâmetros (:slug, :provider, etc.) devem permanecer iguais. Veja a documentação completa em app/types/routes.ts.
:::warning Regra arquitetural
app/config deve conter somente configuração estática de brand (dados que mudam por fork/marca). Hooks, parsers, helpers de phone mask e lógica de negócio não devem ficar em app/config. Dados globais (catálogo de países, DDI, currency-country) vêm do SDK @cactus-agents/*.
:::
Além dos config files
O cliente pode ir muito além desses 3 arquivos:
- Criar componentes próprios em
app/components/ - Adicionar páginas em
app/routes/(e registrá-las emroutes.config.ts) - Criar hooks em
app/hooks/ - Adicionar stores em
app/store/ - Customizar serviços em
app/services/ - Redesenhar o layout inteiro — criar um novo layout em
app/layouts/ - Adicionar bibliotecas — instalar o que precisar via pnpm
O que evitar
| Ação | Por que evitar |
|---|---|
Modificar @cactus-agents/* diretamente | São pacotes npm — alterações locais serão perdidas no pnpm update |
Alterar routes.ts | Apenas importa buildRoutes() do config — edite o config ao invés |
Alterar root.tsx sem necessidade | HTML shell e providers globais — mudanças aqui podem quebrar atualizações futuras do template |
Se precisar de algo que o @cactus-agents/* não suporta, entre em contato com o time Cactus. Podemos adicionar ao SDK para que todos os clientes se beneficiem.