@snksergio/design-system 0.61.0 → 0.63.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.
- package/dist-lib/ai/blocos/chart/budget-breakdown.tsx +174 -0
- package/dist-lib/ai/blocos/indice.md +43 -0
- package/dist-lib/ai/blocos/paneldetail/detalhe-com-tabela.tsx +450 -0
- package/dist-lib/ai/blocos/paneldetail/detalhe-de-tarefa-com-abas.tsx +570 -0
- package/dist-lib/ai/blocos/paneldetail/detalhe-do-registro.tsx +555 -0
- package/dist-lib/ai/componentes/AlertModal.md +47 -0
- package/dist-lib/ai/componentes/AppShell.md +117 -0
- package/dist-lib/ai/componentes/Breadcrumb.md +187 -0
- package/dist-lib/ai/componentes/Button.md +116 -0
- package/dist-lib/ai/componentes/ButtonGroup.md +162 -0
- package/dist-lib/ai/componentes/CardCheckbox.md +99 -0
- package/dist-lib/ai/componentes/CardOption.md +133 -0
- package/dist-lib/ai/componentes/Chart.md +93 -0
- package/dist-lib/ai/componentes/Chip.md +68 -0
- package/dist-lib/ai/componentes/ChoroplethMap.md +118 -0
- package/dist-lib/ai/componentes/ColorPicker.md +70 -0
- package/dist-lib/ai/componentes/Combobox.md +51 -0
- package/dist-lib/ai/componentes/ConversationListItem.md +90 -0
- package/dist-lib/ai/componentes/DataList.md +111 -0
- package/dist-lib/ai/componentes/DataTable.md +867 -0
- package/dist-lib/ai/componentes/DatePicker.md +84 -0
- package/dist-lib/ai/componentes/DateSeparatorChip.md +59 -0
- package/dist-lib/ai/componentes/EmptyState.md +72 -0
- package/dist-lib/ai/componentes/FileUploadField.md +95 -0
- package/dist-lib/ai/componentes/FloatingPanel.md +118 -0
- package/dist-lib/ai/componentes/FooterTable.md +62 -0
- package/dist-lib/ai/componentes/FormField.md +110 -0
- package/dist-lib/ai/componentes/Gantt.md +552 -0
- package/dist-lib/ai/componentes/Header.md +98 -0
- package/dist-lib/ai/componentes/Icon.md +65 -0
- package/dist-lib/ai/componentes/Kanban.md +343 -0
- package/dist-lib/ai/componentes/Kpi.md +103 -0
- package/dist-lib/ai/componentes/List.md +61 -0
- package/dist-lib/ai/componentes/MarkdownText.md +59 -0
- package/dist-lib/ai/componentes/MenuSidebar.md +128 -0
- package/dist-lib/ai/componentes/MessageAck.md +53 -0
- package/dist-lib/ai/componentes/MessageBubble.md +115 -0
- package/dist-lib/ai/componentes/MessageComposer.md +80 -0
- package/dist-lib/ai/componentes/MessageVariablesPicker.md +104 -0
- package/dist-lib/ai/componentes/Modal.md +88 -0
- package/dist-lib/ai/componentes/MonthYearPicker.md +49 -0
- package/dist-lib/ai/componentes/PageHeader.md +129 -0
- package/dist-lib/ai/componentes/Panel.md +84 -0
- package/dist-lib/ai/componentes/Scheduler.md +421 -0
- package/dist-lib/ai/componentes/ScreenLoader.md +60 -0
- package/dist-lib/ai/componentes/SingleMenuSidebar.md +171 -0
- package/dist-lib/ai/componentes/Spinner.md +52 -0
- package/dist-lib/ai/componentes/Table.md +192 -0
- package/dist-lib/ai/componentes/TableToolbar.md +87 -0
- package/dist-lib/ai/componentes/TabsNavigation.md +152 -0
- package/dist-lib/ai/componentes/Toast.md +49 -0
- package/dist-lib/ai/componentes/_primitivos.md +74 -0
- package/dist-lib/ai/componentes/avatar-ig.md +181 -0
- package/dist-lib/ai/componentes/indice.json +49 -0
- package/dist-lib/ai/exemplos/app-shell/app-shell-example.tsx +140 -0
- package/dist-lib/ai/exemplos/app-shell/index.ts +3 -0
- package/dist-lib/ai/exemplos/app-shell/nav-data.ts +97 -0
- package/dist-lib/ai/exemplos/app-shell/routes.tsx +75 -0
- package/dist-lib/ai/exemplos/chat/chat-screen.tsx +152 -0
- package/dist-lib/ai/exemplos/chat/chat-v2-mocks.ts +171 -0
- package/dist-lib/ai/exemplos/chat/chat-v2.styles.ts +23 -0
- package/dist-lib/ai/exemplos/chat/chat-v2.types.ts +81 -0
- package/dist-lib/ai/exemplos/chat/components/ChannelDot/channel-dot.tsx +28 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/conversation-actions-menu.tsx +83 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/index.ts +4 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.styles.ts +22 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.tsx +203 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.types.ts +10 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationColumn/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.styles.ts +55 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.tsx +52 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.types.ts +7 -0
- package/dist-lib/ai/exemplos/chat/components/ConversationListItem/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/DateSeparator/date-separator.tsx +18 -0
- package/dist-lib/ai/exemplos/chat/components/DetailField/detail-field.tsx +23 -0
- package/dist-lib/ai/exemplos/chat/components/DetailSection/detail-section.tsx +41 -0
- package/dist-lib/ai/exemplos/chat/components/DetailSection/index.ts +1 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.styles.ts +30 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.tsx +142 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.types.ts +16 -0
- package/dist-lib/ai/exemplos/chat/components/DetailsColumn/index.ts +5 -0
- package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.styles.ts +37 -0
- package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.tsx +45 -0
- package/dist-lib/ai/exemplos/chat/components/FilterRow/index.ts +1 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.styles.ts +27 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.tsx +66 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.types.ts +13 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-rail.tsx +38 -0
- package/dist-lib/ai/exemplos/chat/components/FiltersColumn/index.ts +6 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.styles.ts +37 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.tsx +29 -0
- package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.types.ts +5 -0
- package/dist-lib/ai/exemplos/chat/components/PersonAvatar/index.ts +5 -0
- package/dist-lib/ai/exemplos/chat/components/PersonAvatar/person-avatar.tsx +31 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/index.ts +2 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.styles.ts +19 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.tsx +140 -0
- package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.types.ts +13 -0
- package/dist-lib/ai/exemplos/chat/components/RailItem/index.ts +1 -0
- package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.styles.ts +30 -0
- package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.tsx +42 -0
- package/dist-lib/ai/exemplos/chat/hooks/use-resizable.ts +98 -0
- package/dist-lib/ai/exemplos/chat/index.ts +1 -0
- package/dist-lib/ai/exemplos/clientes/_table-data.ts +59 -0
- package/dist-lib/ai/exemplos/clientes/clientes-screen.tsx +505 -0
- package/dist-lib/ai/exemplos/clientes/clientes-showcase-mocks.ts +117 -0
- package/dist-lib/ai/exemplos/clientes/clientes-showcase.styles.ts +13 -0
- package/dist-lib/ai/exemplos/clientes/clientes-showcase.types.ts +16 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.styles.ts +28 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.tsx +303 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.types.ts +14 -0
- package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/index.ts +2 -0
- package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/index.ts +2 -0
- package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
- package/dist-lib/ai/exemplos/clientes/index.ts +1 -0
- package/dist-lib/ai/exemplos/dashboard/dashboard-brazil-map.ts +33 -0
- package/dist-lib/ai/exemplos/dashboard/dashboard-screen.tsx +1110 -0
- package/dist-lib/ai/exemplos/dashboard/index.ts +1 -0
- package/dist-lib/ai/exemplos/edit-page/components/StepNav.tsx +81 -0
- package/dist-lib/ai/exemplos/edit-page/components/section-card.tsx +85 -0
- package/dist-lib/ai/exemplos/edit-page/edit-page-screen.tsx +234 -0
- package/dist-lib/ai/exemplos/edit-page/index.ts +1 -0
- package/dist-lib/ai/exemplos/finance/_table-data.ts +57 -0
- package/dist-lib/ai/exemplos/finance/clientes-financeiro-mocks.ts +227 -0
- package/dist-lib/ai/exemplos/finance/clientes-financeiro.types.ts +75 -0
- package/dist-lib/ai/exemplos/finance/clientes-showcase-mocks.ts +117 -0
- package/dist-lib/ai/exemplos/finance/clientes-showcase.styles.ts +13 -0
- package/dist-lib/ai/exemplos/finance/clientes-showcase.types.ts +16 -0
- package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/editar-finance-drawer.tsx +241 -0
- package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/index.ts +5 -0
- package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/extrato-expansion.tsx +172 -0
- package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/index.ts +1 -0
- package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/finance-detail-panel.tsx +241 -0
- package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/index.ts +2 -0
- package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/index.ts +2 -0
- package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
- package/dist-lib/ai/exemplos/finance/components/SacarDialog/index.ts +2 -0
- package/dist-lib/ai/exemplos/finance/components/SacarDialog/sacar-dialog.tsx +346 -0
- package/dist-lib/ai/exemplos/finance/finance-screen.tsx +821 -0
- package/dist-lib/ai/exemplos/finance/index.ts +1 -0
- package/dist-lib/ai/exemplos/gantt/_gantt-data.tsx +402 -0
- package/dist-lib/ai/exemplos/gantt/gantt-screen.tsx +512 -0
- package/dist-lib/ai/exemplos/gantt/index.ts +1 -0
- package/dist-lib/ai/exemplos/login/index.ts +1 -0
- package/dist-lib/ai/exemplos/login/login-screen.tsx +246 -0
- package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/consultor-detail-panel.tsx +158 -0
- package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/index.ts +2 -0
- package/dist-lib/ai/exemplos/mapa-rede/index.ts +1 -0
- package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede-mocks.ts +655 -0
- package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede.types.ts +53 -0
- package/dist-lib/ai/exemplos/mapa-rede/mapa-rede-screen.tsx +227 -0
- package/dist-lib/ai/exemplos/order-detail/components/ActivityTab.tsx +77 -0
- package/dist-lib/ai/exemplos/order-detail/components/AttachmentsTab.tsx +45 -0
- package/dist-lib/ai/exemplos/order-detail/components/CommentsTab.tsx +111 -0
- package/dist-lib/ai/exemplos/order-detail/components/DetailsTab.tsx +189 -0
- package/dist-lib/ai/exemplos/order-detail/components/OverviewTab.tsx +200 -0
- package/dist-lib/ai/exemplos/order-detail/components/section-card.tsx +85 -0
- package/dist-lib/ai/exemplos/order-detail/index.ts +1 -0
- package/dist-lib/ai/exemplos/order-detail/order-detail-screen.tsx +119 -0
- package/dist-lib/ai/exemplos/order-detail/order-mocks.ts +186 -0
- package/dist-lib/ai/exemplos/order-detail/order.types.ts +118 -0
- package/dist-lib/ai/global/componentes.md +217 -0
- package/dist-lib/ai/global/composicao.md +182 -0
- package/dist-lib/ai/indice.json +192 -0
- package/dist-lib/ai/lint/ds-lint-patterns.mjs +115 -0
- package/dist-lib/ai/manifest.json +42 -0
- package/dist-lib/ai/regras/design.md +88 -0
- package/dist-lib/ai/regras/temas.md +192 -0
- package/dist-lib/ai/regras-por-componente.json +103 -0
- package/dist-lib/ai/roteiros/app-builder/roteiro.md +155 -0
- package/dist-lib/ai/roteiros/auth-builder/roteiro.md +42 -0
- package/dist-lib/ai/roteiros/cards/roteiro.md +34 -0
- package/dist-lib/ai/roteiros/charts/roteiro.md +32 -0
- package/dist-lib/ai/roteiros/chat/roteiro.md +31 -0
- package/dist-lib/ai/roteiros/crud-builder/blueprint.md +63 -0
- package/dist-lib/ai/roteiros/crud-builder/entrevista.md +139 -0
- package/dist-lib/ai/roteiros/crud-builder/geracao.md +113 -0
- package/dist-lib/ai/roteiros/crud-builder/roteiro.md +89 -0
- package/dist-lib/ai/roteiros/dashboard-builder/blueprint.md +47 -0
- package/dist-lib/ai/roteiros/dashboard-builder/entrevista.md +62 -0
- package/dist-lib/ai/roteiros/dashboard-builder/geracao.md +88 -0
- package/dist-lib/ai/roteiros/dashboard-builder/roteiro.md +88 -0
- package/dist-lib/ai/roteiros/drawers/roteiro.md +41 -0
- package/dist-lib/ai/roteiros/list-builder/blueprint.md +94 -0
- package/dist-lib/ai/roteiros/list-builder/entrevista.md +188 -0
- package/dist-lib/ai/roteiros/list-builder/geracao.md +63 -0
- package/dist-lib/ai/roteiros/list-builder/roteiro.md +91 -0
- package/dist-lib/ai/roteiros/module-replicator/roteiro.md +56 -0
- package/dist-lib/ai/roteiros/page-detail/roteiro.md +32 -0
- package/dist-lib/ai/roteiros/page-edit/roteiro.md +31 -0
- package/dist-lib/ai/roteiros/screen-composer/roteiro.md +95 -0
- package/package.json +4 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
{
|
|
2
|
+
"rotas": [
|
|
3
|
+
{
|
|
4
|
+
"sinais": [
|
|
5
|
+
"tabela",
|
|
6
|
+
"grade",
|
|
7
|
+
"grid de dados",
|
|
8
|
+
"crud",
|
|
9
|
+
"datatable",
|
|
10
|
+
"planilha",
|
|
11
|
+
"colunas"
|
|
12
|
+
],
|
|
13
|
+
"rota": "skill `crud-builder` (`/ds-create-crud`) — entrevista guiada",
|
|
14
|
+
"roteiro": "crud-builder"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"sinais": [
|
|
18
|
+
"kanban",
|
|
19
|
+
"board",
|
|
20
|
+
"funil",
|
|
21
|
+
"pipeline de vendas",
|
|
22
|
+
"quadro por status/etapa"
|
|
23
|
+
],
|
|
24
|
+
"rota": "skill `crud-builder` (`/ds-create-crud`) — kanban é `viewMode` do DataTable; ref. `example-finance` (kanban por situação)",
|
|
25
|
+
"roteiro": "crud-builder"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"sinais": [
|
|
29
|
+
"tabela e lista no mesmo lugar",
|
|
30
|
+
"alternar tabela/lista",
|
|
31
|
+
"toggle de visão tabela↔lista"
|
|
32
|
+
],
|
|
33
|
+
"rota": "skill `crud-builder` (`/ds-create-crud`) — é `viewMode:\"list\"` + `listConfig` do DataTable (não DataList paralelo)",
|
|
34
|
+
"roteiro": "crud-builder"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"sinais": [
|
|
38
|
+
"lista de cards",
|
|
39
|
+
"árvore",
|
|
40
|
+
"hierarquia",
|
|
41
|
+
"rede/organograma",
|
|
42
|
+
"níveis",
|
|
43
|
+
"treeview",
|
|
44
|
+
"feed de cards"
|
|
45
|
+
],
|
|
46
|
+
"rota": "skill `list-builder` (`/ds-create-list`) — entrevista guiada",
|
|
47
|
+
"roteiro": "list-builder"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"sinais": [
|
|
51
|
+
"lista",
|
|
52
|
+
"listagem de x"
|
|
53
|
+
],
|
|
54
|
+
"rota": "PERGUNTE \"grade de colunas ou cards?\" → `crud-builder` ou `list-builder` (ou front-door `/ds-create-screen`)"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"sinais": [
|
|
58
|
+
"formulário",
|
|
59
|
+
"cadastro",
|
|
60
|
+
"tela de edição",
|
|
61
|
+
"editar x",
|
|
62
|
+
"novo x",
|
|
63
|
+
"multi-step"
|
|
64
|
+
],
|
|
65
|
+
"rota": "skill `page-edit` → `example-edit-page`",
|
|
66
|
+
"roteiro": "page-edit"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"sinais": [
|
|
70
|
+
"detalhe",
|
|
71
|
+
"detalhamento",
|
|
72
|
+
"ficha",
|
|
73
|
+
"página de x com abas",
|
|
74
|
+
"visão geral do pedido"
|
|
75
|
+
],
|
|
76
|
+
"rota": "skill `page-detail` → `example-order-detail`",
|
|
77
|
+
"roteiro": "page-detail"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"sinais": [
|
|
81
|
+
"login",
|
|
82
|
+
"entrar",
|
|
83
|
+
"acesso",
|
|
84
|
+
"autenticação",
|
|
85
|
+
"sign in",
|
|
86
|
+
"esqueci a senha",
|
|
87
|
+
"tela de login"
|
|
88
|
+
],
|
|
89
|
+
"rota": "skill `auth-builder` (`/ds-create-login`) → `example-login` (fullscreen, painel por tokens)",
|
|
90
|
+
"roteiro": "auth-builder"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"sinais": [
|
|
94
|
+
"dashboard",
|
|
95
|
+
"painel",
|
|
96
|
+
"visão geral",
|
|
97
|
+
"indicadores"
|
|
98
|
+
],
|
|
99
|
+
"rota": "skill `dashboard-builder` (`/ds-create-dashboard`) — entrevista → gate → geração ancorada no `example-dashboard`",
|
|
100
|
+
"roteiro": "dashboard-builder"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"sinais": [
|
|
104
|
+
"tabela + detalhe ao lado",
|
|
105
|
+
"clicar abre o detalhe",
|
|
106
|
+
"filtro no topo que muda tudo"
|
|
107
|
+
],
|
|
108
|
+
"rota": "skill `screen-composer` — master-detail / cross-filter; monta as peças pelos builders + cabeia o estado compartilhado (a receita está na própria skill)",
|
|
109
|
+
"roteiro": "screen-composer"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"sinais": [
|
|
113
|
+
"gráfico",
|
|
114
|
+
"chart",
|
|
115
|
+
"barras/linha/área/pizza"
|
|
116
|
+
],
|
|
117
|
+
"rota": "skill `charts` → `Chart/USAGE.md` + `example-dashboard`",
|
|
118
|
+
"roteiro": "charts"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"sinais": [
|
|
122
|
+
"financeiro",
|
|
123
|
+
"extrato",
|
|
124
|
+
"saldo",
|
|
125
|
+
"transações"
|
|
126
|
+
],
|
|
127
|
+
"rota": "`example-finance` (puxar + adaptar)"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"sinais": [
|
|
131
|
+
"chat",
|
|
132
|
+
"inbox",
|
|
133
|
+
"conversas",
|
|
134
|
+
"atendimento"
|
|
135
|
+
],
|
|
136
|
+
"rota": "skill `chat` → `example-chat`",
|
|
137
|
+
"roteiro": "chat"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"sinais": [
|
|
141
|
+
"drawer/painel de criar/editar/ver detalhe"
|
|
142
|
+
],
|
|
143
|
+
"rota": "skill `drawers` → drawers do `example-finance`",
|
|
144
|
+
"roteiro": "drawers"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"sinais": [
|
|
148
|
+
"cards",
|
|
149
|
+
"blocos",
|
|
150
|
+
"painéis soltos",
|
|
151
|
+
"seções"
|
|
152
|
+
],
|
|
153
|
+
"rota": "skill `cards` → `Card`/`Panel` + showcase",
|
|
154
|
+
"roteiro": "cards"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"sinais": [
|
|
158
|
+
"igual ao exemplo de <x>",
|
|
159
|
+
"estrutura do <x>"
|
|
160
|
+
],
|
|
161
|
+
"rota": "puxar `example-<X>` e adaptar"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"sinais": [
|
|
165
|
+
"esqueleto do app",
|
|
166
|
+
"estrutura/base do app",
|
|
167
|
+
"shell + navegação + rotas",
|
|
168
|
+
"montar o app do zero"
|
|
169
|
+
],
|
|
170
|
+
"rota": "skill `app-builder` (`/ds-create-app`) → `example-app-shell` (AppShell + nav-data + mapa de rotas declarativo)",
|
|
171
|
+
"roteiro": "app-builder"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"sinais": [
|
|
175
|
+
"replica o módulo x igual ao y",
|
|
176
|
+
"mesma estrutura pra outro segmento/vertical",
|
|
177
|
+
"clonar telas"
|
|
178
|
+
],
|
|
179
|
+
"rota": "skill `module-replicator` (`/ds-replicate-module`) — avalia copiar × parametrizar; troca dados/rótulos, mantém estrutura",
|
|
180
|
+
"roteiro": "module-replicator"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"sinais": [
|
|
184
|
+
"que componente uso pra x",
|
|
185
|
+
"tem componente de y?",
|
|
186
|
+
"quais opções pra abas / filtro / data",
|
|
187
|
+
"o que o ds tem pra formulário"
|
|
188
|
+
],
|
|
189
|
+
"rota": "rule `.claude/rules/ds-components.md` — vocabulário dos componentes por tarefa, com o critério de escolha. Não é pedido de tela: responda pela rule, não abra builder"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ds-lint-patterns — FONTE ÚNICA dos anti-patterns de estilo do DS.
|
|
3
|
+
*
|
|
4
|
+
* Consumido por DOIS clientes (nunca duplique a tabela):
|
|
5
|
+
* - .claude/hooks/ds-lint-styles.sh → aviso local, nunca bloqueia
|
|
6
|
+
* - scripts/lint-styles.mjs --ratchet → check de CI, bloqueia violação nova
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ E por um TERCEIRO, fora deste repo: este arquivo é foundational
|
|
9
|
+
* (`foundational-pairs.mjs`) e é copiado inteiro para
|
|
10
|
+
* `cli/templates/default/_claude/hooks/`, que o ds:link projeta no projeto do
|
|
11
|
+
* consumidor. Lá, `.ai/` e os caminhos internos do DS NÃO EXISTEM — os que
|
|
12
|
+
* aparecem nos comentários abaixo só resolvem aqui. Por isso nenhuma `msg`
|
|
13
|
+
* cita caminho: mensagem de lint tem que se bastar onde for lida.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ Só entram aqui regras erradas INDEPENDENTE DE CONTEXTO (valor divergente
|
|
16
|
+
* do token, classe que não existe). Regras que exigem contexto cross-elemento
|
|
17
|
+
* ou julgamento de intenção — L-004 (afordância de foco pode estar no wrapper)
|
|
18
|
+
* e L-007 (escolha de preset tipográfico) — pertencem ao revisor semântico,
|
|
19
|
+
* NÃO a este arquivo. Ver `.ai/specs/pipeline-governance-ci.md` §1.1.
|
|
20
|
+
*
|
|
21
|
+
* Buracos de cobertura conhecidos (não fechados nesta rodada — cada um exige
|
|
22
|
+
* medição/decisão de política própria; ver it.todo no teste):
|
|
23
|
+
* - `space-x-N` / `space-y-N` (utility legado, sem token DS direto) e
|
|
24
|
+
* `w-N`/`h-N` isolados fora das famílias `h|min-h|size` acima.
|
|
25
|
+
* - **Template literals**: o delimitador cobre aspas simples e duplas, mas
|
|
26
|
+
* NÃO crase — `` `flex gap-4` `` passa limpo (forma diferente, não
|
|
27
|
+
* coberta nesta rodada).
|
|
28
|
+
* - **Números fora do que foi medido no baseline**: as alternações listam
|
|
29
|
+
* só os valores encontrados na varredura de 2026-07-29, não a escala
|
|
30
|
+
* Tailwind inteira — `w-10`, `p-9`, `gap-11`, `h-20` passam limpo hoje.
|
|
31
|
+
* Ampliar a faixa numérica exige nova medição própria, fora desta correção.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
export const DS_LINT_PATTERNS = [
|
|
35
|
+
{
|
|
36
|
+
id: "L-001",
|
|
37
|
+
re: /ring-ring-[a-z-]+\/[0-9]+/,
|
|
38
|
+
msg: "ring-ring-*/N — o token de ring já tem alpha embutido. Remova o /N.",
|
|
39
|
+
},
|
|
40
|
+
// `0` fora da alternação de propósito: não existe token DS pra zero
|
|
41
|
+
// (p-0/gap-0 são resets legítimos, comuns com `!` sobre base do shadcn).
|
|
42
|
+
{
|
|
43
|
+
id: "L-002",
|
|
44
|
+
re: /['"][^'"]*\bgap(-[xy])?-(1|2|3|4|5|6|7|8|9|10|12|14|16|20|24)\b[^'"]*['"]/,
|
|
45
|
+
msg: "gap-N literal → use gap-gp-{2xs,xs,sm,md,lg,xl,2xl}.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "L-002",
|
|
49
|
+
re: /['"][^'"]*\b(px|py|pt|pb|pl|pr|p)-(1|2|3|4|5|6|7|8|10|12|16)\b[^'"]*['"]/,
|
|
50
|
+
msg: "pad/space literal → use p-sp-* (space) ou px-pad-* (pad).",
|
|
51
|
+
},
|
|
52
|
+
// ⚠️ Esta msg NÃO aponta pra arquivo, e é de propósito. Ela terminava com
|
|
53
|
+
// "ver .ai/context/tokens/sizing-shape-elevation.md" — caminho que existe aqui
|
|
54
|
+
// e que o CONSUMIDOR nunca recebe: este módulo é foundational (ver
|
|
55
|
+
// foundational-pairs.mjs) e roda também no `.claude/` projetado pelo ds:link,
|
|
56
|
+
// onde `.ai/` não existe. Mensagem que manda ler o inalcançável faz a pessoa
|
|
57
|
+
// parar de investigar achando que a resposta está em outro lugar (L-060).
|
|
58
|
+
// A regra aqui é: msg de lint se basta ou não cita caminho.
|
|
59
|
+
{
|
|
60
|
+
id: "L-002",
|
|
61
|
+
re: /['"][^'"]*\b(h|min-h|size)-(7|8|9|10|11|12|13|14|16)\b[^'"]*['"]/,
|
|
62
|
+
msg: "height/size fixo → use min-h-form-* (h-9=form-md, h-10=form-lg, h-11=form-xl). Se for quadrado, size-comp-*. Se for maior (~h-12 a h-16, 48-64px), não é form — use token de layout (ex.: h-layout-navbar).",
|
|
63
|
+
},
|
|
64
|
+
// `none` e `full` fora da alternação: são numericamente IDÊNTICOS ao token DS
|
|
65
|
+
// (--radius-radius-full: 9999px, --radius-radius-none: 0px) → não podem ser
|
|
66
|
+
// defeito. Já sm..3xl DIVERGEM (nativo lg=0.5rem vs DS 0.625rem) → defeito
|
|
67
|
+
// real. Side variants (rounded-t-lg) carregam o mesmo valor divergente.
|
|
68
|
+
{
|
|
69
|
+
id: "L-002",
|
|
70
|
+
re: /['"][^'"]*\brounded(-(t|b|l|r|tl|tr|bl|br|s|e|ss|se|es|ee))?-(sm|md|lg|xl|2xl|3xl)\b[^'"]*['"]/,
|
|
71
|
+
msg: "rounded-N nativo tem VALOR DIFERENTE do token DS (nativo lg=0.5rem vs DS 0.625rem) → use rounded-radius-*.",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "L-002",
|
|
75
|
+
re: /['"][^'"]*\bshadow-(2xs|xs|sm|md|lg|xl|2xl)\b[^'"]*['"]/,
|
|
76
|
+
msg: "shadow-N nativo → use shadow-sh-*.",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "L-003",
|
|
80
|
+
re: /['"][^'"]*\bring-3\b[^'"]*['"]/,
|
|
81
|
+
msg: "ring-3 não existe no Tailwind (vira no-op silencioso) → use ring-4.",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "L-005",
|
|
85
|
+
re: /['"][^'"]*\bbg-input\/[0-9]+[^'"]*['"]/,
|
|
86
|
+
msg: "bg-input/N é var do shadcn → use o token DS bg-bg-surface (ou bg-bg-muted).",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "IMPORT",
|
|
90
|
+
re: /from\s+['"]tailwind-variants['"]/,
|
|
91
|
+
msg: 'import errado: use `import { tv } from "@/utils/tv"` — o wrapper do DS carrega o twMergeConfig da L-016.',
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
/** Linha de comentário não é código — citar uma classe proibida ao explicar a
|
|
96
|
+
* regra não pode reprovar o CI. Cobre `//`, `/*`, ` *` e o comentário JSX
|
|
97
|
+
* `{/* ... *\/}`, que entrou no escopo junto com o `.tsx`. */
|
|
98
|
+
const isComment = (text) => /^\s*(\/\/|\/\*|\*|\{\s*\/\*)/.test(text);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Roda todos os patterns contra uma lista de linhas.
|
|
102
|
+
* @param {Array<{n: number, text: string}>} lines
|
|
103
|
+
* @returns {Array<{id: string, msg: string, n: number, text: string}>}
|
|
104
|
+
*/
|
|
105
|
+
export function scanLines(lines) {
|
|
106
|
+
const out = [];
|
|
107
|
+
for (const { n, text } of lines) {
|
|
108
|
+
if (isComment(text)) continue;
|
|
109
|
+
for (const p of DS_LINT_PATTERNS) {
|
|
110
|
+
// `re` sem flag /g → .test() não mantém lastIndex, seguro reusar.
|
|
111
|
+
if (p.re.test(text)) out.push({ id: p.id, msg: p.msg, n, text });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pacote": "@snksergio/design-system",
|
|
3
|
+
"versao": "0.63.0",
|
|
4
|
+
"commit": "d9db4cd",
|
|
5
|
+
"gerado": "2026-09-15",
|
|
6
|
+
"conteudo": {
|
|
7
|
+
"roteiros": [
|
|
8
|
+
"app-builder",
|
|
9
|
+
"auth-builder",
|
|
10
|
+
"cards",
|
|
11
|
+
"charts",
|
|
12
|
+
"chat",
|
|
13
|
+
"crud-builder",
|
|
14
|
+
"dashboard-builder",
|
|
15
|
+
"drawers",
|
|
16
|
+
"list-builder",
|
|
17
|
+
"module-replicator",
|
|
18
|
+
"page-detail",
|
|
19
|
+
"page-edit",
|
|
20
|
+
"screen-composer"
|
|
21
|
+
],
|
|
22
|
+
"exemplos": [
|
|
23
|
+
"app-shell",
|
|
24
|
+
"chat",
|
|
25
|
+
"clientes",
|
|
26
|
+
"dashboard",
|
|
27
|
+
"edit-page",
|
|
28
|
+
"finance",
|
|
29
|
+
"gantt",
|
|
30
|
+
"login",
|
|
31
|
+
"mapa-rede",
|
|
32
|
+
"order-detail"
|
|
33
|
+
],
|
|
34
|
+
"componentes": 47,
|
|
35
|
+
"componentesComRegra": 19,
|
|
36
|
+
"rotas": 19,
|
|
37
|
+
"rotasComRoteiro": 15,
|
|
38
|
+
"arquivosDeExemplo": 108,
|
|
39
|
+
"arquivosDeBloco": 4,
|
|
40
|
+
"residuoClaudeCode": 42
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
|
|
2
|
+
# Regras de design iGreen (auto-carregadas)
|
|
3
|
+
|
|
4
|
+
Ao gerar ou editar QUALQUER UI neste projeto, aplique sem ser pedido. Detalhe e
|
|
5
|
+
contexto em `DESIGN.md` (raiz). API de cada componente em
|
|
6
|
+
`src/components/ui/<Nome>/USAGE.md`.
|
|
7
|
+
|
|
8
|
+
> **Modo submódulo.** Se existe `.claude/ds-config.json` com `"mode": "submodule"`, três
|
|
9
|
+
> coisas mudam nesta regra: (1) `DESIGN.md` e os `USAGE.md` ficam em `<dsPath>/` e
|
|
10
|
+
> `<dsPath>/src/components/ui/<Nome>/`, não na sua raiz; (2) **não** existe `igreen:add`,
|
|
11
|
+
> manifesto nem hook de proteção — os componentes estão no disco e você importa pelo
|
|
12
|
+
> `importBase`; (3) a regra de **não editar o tema/fundação** continua valendo, só que por
|
|
13
|
+
> disciplina, não por bloqueio: o que você editar no submódulo some no próximo `git pull`.
|
|
14
|
+
|
|
15
|
+
## Composição de tela
|
|
16
|
+
- Wrapper de página: `flex flex-col h-full min-h-0 gap-gp-2xl`.
|
|
17
|
+
- **16px (`gap-gp-2xl`) entre o `PageHeader` e o próximo bloco** — nunca grudado.
|
|
18
|
+
- Conteúdo que precisa preencher (tabela): `className="flex-1 min-h-0"` + pai com altura.
|
|
19
|
+
- Forms: `<FormField>` (nunca `<label>` cru) + `gap-form-gap` (20px) entre campos.
|
|
20
|
+
- Card: densidade pela prop `size` do `<Card>` — `sm` 16 · **`md` 20 (default)** · `lg` 24 (tokens `p-pad-card-sm/md/lg`; `base` é alias depreciado de `md`); entre cards `gap-gp-md`/`gap-gp-lg`.
|
|
21
|
+
|
|
22
|
+
## Tokens (classe DS antes de Tailwind literal)
|
|
23
|
+
```
|
|
24
|
+
gap-4 → gap-gp-md p-4 → p-sp-md/p-pad-2xl rounded-lg → rounded-radius-lg
|
|
25
|
+
shadow-md → shadow-sh-md h-9/h-10 → min-h-form-md/lg size-5 → size-icon-md
|
|
26
|
+
```
|
|
27
|
+
- **Prefira o token de COMPONENTE ao genérico**: altura `min-h-form-*` (não `h-9/10`), gap de form `gap-form-gap`, ícone `size-icon-*` (não `size-5`), padding de card `p-pad-card-*`, gutter `px-pad-page-*`, chrome `h-layout-*`, largura `max-w-*`. Genérico (`gap-gp-*`/`p-sp-*`/`px-pad-*`) só como fallback. Cheat-sheet completo em `DESIGN.md` ("Tokens de componente").
|
|
28
|
+
- Foco: `focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-{color}` (ring já tem alpha — nunca `/30`, nunca `ring-3`).
|
|
29
|
+
- Cor só por token semântico (`bg-bg-brand`, `text-fg-default`...). Zero hex em className. Destrutivo na API = `color="critical"`.
|
|
30
|
+
|
|
31
|
+
- ⚠️ **`max-w-container-*` NÃO existe** — `container` é o único namespace que não dobra o
|
|
32
|
+
prefixo. `max-w-md` já é os **768px do DS** (não os 448px do Tailwind); use `max-w-lg`,
|
|
33
|
+
`max-w-drawer-md`, `max-w-modal-sm`. A forma com `container` não emite CSS e some em silêncio.
|
|
34
|
+
- ⚠️ **`bg-bg-scrollbar-thumb` / `-hover` são de uso interno** dos `@utility scrollbar-*`
|
|
35
|
+
(alpha neutro, pra barra ter contraste próprio). Não use como fundo de elemento.
|
|
36
|
+
|
|
37
|
+
## Tipografia
|
|
38
|
+
- Default interativo: `text-body-sm` (13/500). **7 papéis**: display/heading/title/body/caption/**stat**/code.
|
|
39
|
+
- **Número de KPI/métrica = `text-stat-{sm,md,lg,xl}`** (20/24/30/34px) + `tabular-nums`. Nunca `text-[Npx]` na unha, nunca `display-*`/`heading-*` pra valor de indicador.
|
|
40
|
+
- **Código / identificador / valor técnico = `text-code-{sm,md}`** (13/14px, Geist Mono) — chave de env, ID, hash, slug, path. Nunca `font-mono text-body-*` + `tracking-*` na unha: `code` é 1 dos 7 papéis e existe pra isto.
|
|
41
|
+
- Override de peso via `font-bold/semibold/medium/normal`. Nunca `text-xs font-semibold` avulso → use preset.
|
|
42
|
+
|
|
43
|
+
## ⛔ O tema já traz o runtime — não redeclare
|
|
44
|
+
O `tailwind-theme.css` importado no seu CSS de entrada **não é só CSS vars**. Ele traz
|
|
45
|
+
`@font-face` do Geist, `--font-sans`/`--font-mono`, `@custom-variant dark`, regras de
|
|
46
|
+
`html`/`body`/`button` e as utilities `outline-float` e `scrollbar-thin`/`scrollbar-default`.
|
|
47
|
+
|
|
48
|
+
**Não redeclare nenhuma delas** no seu CSS: classe comum vence `@utility`, e a **segunda**
|
|
49
|
+
declaração de `@custom-variant` vence a primeira — você acaba com um comportamento no seu
|
|
50
|
+
projeto e outro no resto do sistema, sem erro nenhum. Os `.woff2` do Geist, sim, são seus
|
|
51
|
+
(o `@font-face` aponta pra `/fonts/`, raiz do site).
|
|
52
|
+
|
|
53
|
+
## 🖼️ Trabalhando a partir de print / Figma / tela existente
|
|
54
|
+
A referência decide **conteúdo**; o DS decide **pele e comportamento**.
|
|
55
|
+
- **Dela**: copy, labels, nomenclatura, ordem dos campos. Copie e não "melhore" sem pedir — o jargão é do domínio do usuário.
|
|
56
|
+
- **Do DS, sempre**: fonte/família, tamanho, peso, tracking, cor, espaçamento, radius, sombra, foco e **comportamento de componente**. Preset existe → use o preset; compor na unha porque "ficou igual ao print" é drift.
|
|
57
|
+
- **Cor**: a referência escolhe o CONJUNTO (print escuro → `dark`; outra marca → `data-theme`), **nunca** o valor. Não derive hex do pixel.
|
|
58
|
+
- **Chrome (rail/menu/header) na referência = shell no escopo.** Print de app + pedido de "uma tela" é `shell + tela`. Não vai entregar o shell? Avise em linha destacada **antes** de gerar.
|
|
59
|
+
|
|
60
|
+
## Antes de criar
|
|
61
|
+
- Existe exemplo/skill pra isso? (tabela→`/ds-create-crud`; ver `DESIGN.md` mapa de intenção). Puxe e adapte em vez de escrever do zero.
|
|
62
|
+
- Leu o `USAGE.md` do componente? Não invente prop/variante.
|
|
63
|
+
- `npx tsc --noEmit` limpo antes de entregar.
|
|
64
|
+
|
|
65
|
+
## ⛔ Arquivos protegidos — NÃO editar (integridade do DS)
|
|
66
|
+
- **NUNCA edite** o tema/tokens (`src/styles/theme/**`) nem a fundação (`src/lib/utils.ts` = cn, `src/utils/tv.ts` = tv, `src/lib/lucide-types.ts`). São a base visual gerada pelo DS — editar quebra o sistema todo e some no próximo update.
|
|
67
|
+
|
|
68
|
+
> **O que de fato te impede, por canal:**
|
|
69
|
+
>
|
|
70
|
+
> | canal | trava |
|
|
71
|
+
> |---|---|
|
|
72
|
+
> | copy-in / scaffold | ✅ hook `protect-ds.mjs` **bloqueia** (`Edit`/`Write`/`MultiEdit`) e **avisa** em `Bash` que escreve nesses paths |
|
|
73
|
+
> | **submódulo** | ✅ **desde o CLI 0.24.0** — o `ds-link` projeta o hook, e ele reconhece o layout de submódulo (bloqueia `<dsPath>/src/styles/theme/**` e `<dsPath>/tokens/**`, sem confundir com o **seu** `src/`). ⚠️ **1 passo manual:** hook só roda se estiver no seu `.claude/settings.json`, e o `ds-link` não escreve nesse arquivo (é seu) — ele **imprime o bloco pronto** e repete o aviso até você colar |
|
|
74
|
+
> | npm install | ❌ nenhuma — o código vive em `node_modules` |
|
|
75
|
+
>
|
|
76
|
+
> ⚠️ **Até o CLI 0.25.1 esta tabela dizia "❌ nenhuma" no submódulo**, justificando com *"o
|
|
77
|
+
> `ds-link` não projeta `hooks/`"*. Era verdade até a 0.23.x e **deixou de ser na 0.24.0** —
|
|
78
|
+
> eu mudei o mecanismo e atualizei a `ds-channels.md`, mas não procurei as outras superfícies
|
|
79
|
+
> que descreviam a mesma coisa. Se você leu a versão anterior e concluiu que no submódulo não
|
|
80
|
+
> há rede de segurança: há, e vale colar o bloco.
|
|
81
|
+
- **Não edite o `.styles.ts`/internals de um componente do DS** pra "ajustar visual" de uma tela. Isso vira edição local (drift) e diverge do padrão. **Customize na COMPOSIÇÃO**: escolha variantes/props do componente + classes DS na SUA tela.
|
|
82
|
+
- Quer outra cor/tom? Use o **token/variante semântico** que já existe (`color="..."`, `bg-bg-*`). Não invente hex nem reescreva o token.
|
|
83
|
+
- Pra evoluir o tema de fato → re-sincronize com o DS (`npm run igreen:add -- theme`), não edite à mão.
|
|
84
|
+
|
|
85
|
+
## Puxar componentes/exemplos (manifesto)
|
|
86
|
+
- **SEMPRE** `npm run igreen:add -- <item> [<item> ...]` — o wrapper instala E registra no `.igreen-ds/manifest.json` (baseline pro `igreen:drift`/`igreen:update`).
|
|
87
|
+
- **NUNCA** `npx shadcn add @igreen/...` cru: o componente instala mas fica **fora do manifesto** (o `igreen:drift` acusa "não gerenciado"). Se acontecer, recupere rodando `npm run igreen:add -- <os mesmos itens>` (idempotente; re-baseline sem sobrescrever edição).
|
|
88
|
+
- Commite o `.igreen-ds/manifest.json`.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
|
|
2
|
+
# Temas de marca (iGreen DS)
|
|
3
|
+
|
|
4
|
+
O DS tem 5 marcas. Cada marca não-default é um **overlay de cor** escopado em
|
|
5
|
+
`[data-theme="<id>"]` que sobrescreve **só o que difere** do tema-base — 87 vars em `blue` e
|
|
6
|
+
`green`, 125 em `vibrant`, 166 em `pay`, contra ~350 do base.
|
|
7
|
+
|
|
8
|
+
| id | marca | arquivo |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `default` | iGreen (verde padrão) | — **é** o tema-base, não tem overlay |
|
|
11
|
+
| `blue` | Azul | `brand-blue.css` |
|
|
12
|
+
| `green` | Verde (grass) | `brand-green.css` |
|
|
13
|
+
| `pay` | iGreen Pay | `brand-pay.css` |
|
|
14
|
+
| `vibrant` | iGreen Vibrant (verde fluorescente) | `brand-vibrant.css` |
|
|
15
|
+
|
|
16
|
+
## ⛔ Antes de mexer: 2 fatos que causam 90% dos erros
|
|
17
|
+
|
|
18
|
+
1. **Importar o CSS não ativa nada.** O overlay é escopado — sem
|
|
19
|
+
`data-theme="<id>"` no `<html>`, nenhuma regra casa e nada muda. Não existe erro:
|
|
20
|
+
falha em silêncio.
|
|
21
|
+
2. **Ordem de import importa.** O overlay tem que vir **depois** do `tailwind-theme.css`.
|
|
22
|
+
Antes, o tema-base ganha por ordem de fonte.
|
|
23
|
+
|
|
24
|
+
Marca e claro/escuro são **eixos independentes**: `data-theme` no `<html>` + classe
|
|
25
|
+
`.dark`. Combinam livremente.
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<html data-theme="vibrant" class="dark"> <!-- vibrant, escuro -->
|
|
29
|
+
<html data-theme="vibrant"> <!-- vibrant, claro -->
|
|
30
|
+
<html> <!-- default (sem atributo) -->
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Trocar o tema — identifique o modo PRIMEIRO
|
|
34
|
+
|
|
35
|
+
Existe `.claude/ds-config.json` com `"mode": "submodule"`?
|
|
36
|
+
|
|
37
|
+
### Modo SUBMÓDULO
|
|
38
|
+
|
|
39
|
+
O **CSS** já está no disco. Importe (ajuste o caminho pro `dsPath` do `ds-config.json`):
|
|
40
|
+
|
|
41
|
+
```css
|
|
42
|
+
@import "tailwindcss";
|
|
43
|
+
@import "../design-system/src/styles/theme/tailwind-theme.css";
|
|
44
|
+
@import "../design-system/src/styles/theme/brand-vibrant.css";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Não rode `igreen:add` — em modo submódulo ele não se aplica. Tema novo chega com
|
|
48
|
+
`git pull` no submódulo. **Não** precisa de `@source`: o submódulo fica dentro da raiz do
|
|
49
|
+
projeto e o Tailwind v4 já escaneia daí.
|
|
50
|
+
|
|
51
|
+
⚠️ **Duas coisas NÃO vêm com o submódulo**, e a segunda falha em silêncio:
|
|
52
|
+
|
|
53
|
+
1. **As dependências.** O submódulo entrega código-fonte, não pacote — `npm i` das libs que os
|
|
54
|
+
componentes importam. O mínimo pra `Button` + `Modal`:
|
|
55
|
+
`tailwind-variants tailwind-merge clsx lucide-react @radix-ui/react-dialog @radix-ui/react-slot`.
|
|
56
|
+
O build quebra alto (`failed to resolve …`), então é fácil de achar.
|
|
57
|
+
2. **Os arquivos da fonte Geist.** O `@font-face` viaja no tema, mas aponta pra `/fonts/*.woff2`
|
|
58
|
+
— raiz do **site**, não do submódulo. Copie:
|
|
59
|
+
`mkdir -p public/fonts && cp design-system/public/fonts/*.woff2 public/fonts/`.
|
|
60
|
+
Sem isso **não há erro**: o `font-family` segue dizendo `Geist`, o navegador recebe o
|
|
61
|
+
`index.html` no lugar do arquivo, e os 27 presets caem em system-ui. Confira com
|
|
62
|
+
`document.fonts.check("16px Geist")` — tem que ser `true`.
|
|
63
|
+
|
|
64
|
+
### Modo COPY-IN (scaffold do CLI)
|
|
65
|
+
|
|
66
|
+
Cada tema é item do registry. Traga com o mesmo comando dos componentes:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm run igreen:add -- theme-vibrant # copia src/styles/theme/brand-vibrant.css
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Depois importe:
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
@import "./styles/theme/tailwind-theme.css";
|
|
76
|
+
@import "./styles/theme/brand-vibrant.css";
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
⚠️ O scaffold **apaga** os overlays não escolhidos no prompt "Tema de cor?". Se o arquivo
|
|
80
|
+
não está em `src/styles/theme/`, é porque outro tema foi escolhido na criação — traga com
|
|
81
|
+
o `igreen:add` acima.
|
|
82
|
+
|
|
83
|
+
### Consumindo o DS por `npm install`
|
|
84
|
+
|
|
85
|
+
⚠️ **A diretiva `@source` é OBRIGATÓRIA e é o erro nº 1 deste canal.** O Tailwind v4 **não
|
|
86
|
+
escaneia `node_modules`** — sem ela **nenhuma** classe do DS é gerada e os componentes
|
|
87
|
+
renderizam **sem estilo nenhum**, sem erro no console e sem build quebrado. Fácil concluir
|
|
88
|
+
que "o pacote está quebrado".
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
@import "tailwindcss";
|
|
92
|
+
|
|
93
|
+
/* Sem esta linha, zero classes do DS. Tem que cobrir `dist-lib/**`, não só o
|
|
94
|
+
index.mjs — as classes dos componentes flutuantes vivem nos *chunks*. */
|
|
95
|
+
@source "../node_modules/@snksergio/design-system/dist-lib/**/*.mjs";
|
|
96
|
+
|
|
97
|
+
@import "@snksergio/design-system/theme.css"; /* obrigatório */
|
|
98
|
+
@import "@snksergio/design-system/theme/brand-vibrant.css"; /* a marca */
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Ajuste o caminho do `@source` à profundidade do seu CSS de entrada (de `src/index.css`, a
|
|
102
|
+
raiz do projeto é `../`).
|
|
103
|
+
|
|
104
|
+
**Copie as fontes Geist** — o `@font-face` viaja no tema, mas aponta pra `/fonts/*.woff2`,
|
|
105
|
+
raiz do **site**:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
mkdir -p public/fonts
|
|
109
|
+
cp node_modules/@snksergio/design-system/dist-lib/fonts/*.woff2 public/fonts/
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
⚠️ Sem isso **não há erro**: o `font-family` segue dizendo `Geist`, o navegador recebe o
|
|
113
|
+
`index.html` no lugar do arquivo e os 27 presets caem em system-ui. Confira com
|
|
114
|
+
`document.fonts.check("16px Geist")` — tem que ser `true`.
|
|
115
|
+
|
|
116
|
+
Requer `@snksergio/design-system` **≥ 0.31.1** (antes disso o pacote levava só o tema-base);
|
|
117
|
+
as fontes só são publicadas a partir da **0.35.0**.
|
|
118
|
+
|
|
119
|
+
## Trocar em runtime (seletor de marca)
|
|
120
|
+
|
|
121
|
+
### Consumindo por `npm install` → use o hook `useBrand` (≥ 0.33.0)
|
|
122
|
+
|
|
123
|
+
Ele já resolve persistência, sincronia entre abas e a regra de que `default` significa
|
|
124
|
+
**remover** o atributo (o tema-base não tem overlay).
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { useBrand } from "@snksergio/design-system";
|
|
128
|
+
|
|
129
|
+
// Passe SÓ as marcas cujo overlay você importou no CSS.
|
|
130
|
+
const MINHAS_MARCAS = [
|
|
131
|
+
{ id: "default", label: "iGreen", swatch: "oklch(0.5248 0.1415 150.9)" },
|
|
132
|
+
{ id: "vibrant", label: "iGreen Vibrant", swatch: "#0fff00" },
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
function SeletorDeMarca() {
|
|
136
|
+
const { brand, brands, current, setBrand } = useBrand({ brands: MINHAS_MARCAS });
|
|
137
|
+
return (
|
|
138
|
+
<select value={brand} onChange={(e) => setBrand(e.target.value)} aria-label="Marca">
|
|
139
|
+
{brands.map((b) => (
|
|
140
|
+
<option key={b.id} value={b.id}>{b.label}</option>
|
|
141
|
+
))}
|
|
142
|
+
</select>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
⚠️ **O catálogo é o ponto todo.** Sem o argumento, `useBrand` usa as 5 marcas do DS — e o
|
|
148
|
+
seletor listaria temas cujo CSS não está no seu bundle. `data-theme` com id sem overlay é
|
|
149
|
+
**no-op silencioso**: a opção aparece, o usuário clica, nada acontece, e não há erro.
|
|
150
|
+
Declare só o que você importou. `current` devolve a entrada ativa (label + swatch) pronta,
|
|
151
|
+
sem `find()`.
|
|
152
|
+
|
|
153
|
+
Valor persistido fora do catálogo cai na primeira entrada — então um `localStorage` com
|
|
154
|
+
`"pay"` de outro app não deixa este num tema órfão.
|
|
155
|
+
|
|
156
|
+
### Copy-in / submódulo, ou sem o pacote npm
|
|
157
|
+
|
|
158
|
+
Escreve/remove o atributo na mão. `default` remove:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
function aplicarMarca(id: string) {
|
|
162
|
+
const root = document.documentElement;
|
|
163
|
+
if (id === "default") root.removeAttribute("data-theme");
|
|
164
|
+
else root.setAttribute("data-theme", id);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Mesma armadilha: só funciona pras marcas cujo CSS **está no bundle**. Se o app oferece N
|
|
169
|
+
marcas ao usuário, importe os N overlays — e valide o id contra a lista que você importou,
|
|
170
|
+
não contra as 5 do DS.
|
|
171
|
+
|
|
172
|
+
## Criar um tema novo
|
|
173
|
+
|
|
174
|
+
Marca muda **somente cor**. Spacing, sizing, radius, elevation e tipografia vêm sempre da
|
|
175
|
+
`default` — não há como uma marca alterá-los, por design. Se o pedido envolve mudar
|
|
176
|
+
espaçamento ou fonte "só nesta marca", **não é tema** — é outra coisa, pergunte.
|
|
177
|
+
|
|
178
|
+
Criar marca é trabalho no **repo do DS**, não aqui: 3 arquivos em `tokens/brands/<id>/`
|
|
179
|
+
(palette + color-light + color-dark, mesmo contrato de nomes da default) e
|
|
180
|
+
`npm run tokens:brand:<id>`. Neste projeto você **consome** o resultado. Se o usuário
|
|
181
|
+
quer uma marca que não existe, o caminho é abrir a demanda no DS — não improvisar CSS
|
|
182
|
+
sobrescrevendo tokens aqui (isso quebra o `protect-ds` e sai do sistema).
|
|
183
|
+
|
|
184
|
+
## Nunca faça
|
|
185
|
+
|
|
186
|
+
- Sobrescrever CSS var de tema na unha (`--color-bg-brand: ...`) pra "simular" uma marca.
|
|
187
|
+
Use overlay; var solta divergem do dark, dos status e do resto do sistema.
|
|
188
|
+
- Duplicar o overlay dentro do projeto pra editar cor. Ele é gerado; edição some no
|
|
189
|
+
próximo update.
|
|
190
|
+
- Aplicar `data-theme` num wrapper interno em vez do `<html>`. Os dois blocos do overlay
|
|
191
|
+
(`[data-theme="x"]:not(.dark)` e `.dark[data-theme="x"]`) assumem marca e modo no MESMO
|
|
192
|
+
elemento — em elementos diferentes o light vaza pro dark.
|