Pular para o conteúdo principal

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-bgbg-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"):

  1. Criar o componente em app/layouts/variants/header/HeaderCustom.tsx
  2. Adicionar a chave "header-custom" em app/types/layout.ts (HeaderVariantKey)
  3. Registrar em app/layouts/layout-registry.ts
  4. 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.ts exporta legacyHomeRows / legacyCasinoRows / legacyCasinoLiveRows — consumido quando CASSINO_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ífica
  • games — 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 em routes.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çãoPor que evitar
Modificar @cactus-agents/* diretamenteSão pacotes npm — alterações locais serão perdidas no pnpm update
Alterar routes.tsApenas importa buildRoutes() do config — edite o config ao invés
Alterar root.tsx sem necessidadeHTML shell e providers globais — mudanças aqui podem quebrar atualizações futuras do template
dica

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.