@snksergio/design-system 0.62.0 → 0.64.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/DataTable.md +2 -1
- package/dist-lib/ai/componentes/TableToolbar.md +1 -1
- 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/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 +7 -0
- package/dist-lib/ai/indice.json +30 -15
- package/dist-lib/ai/manifest.json +32 -6
- 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 +146 -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/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 +193 -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/dist-lib/chunks/{panel-B-liPlxr.mjs → panel-CN0ChoHM.mjs} +5 -2
- package/dist-lib/chunks/{panel-B-liPlxr.mjs.map → panel-CN0ChoHM.mjs.map} +1 -1
- package/dist-lib/chunks/{panel-DoNbjeqX.cjs → panel-Cpq1xHck.cjs} +5 -2
- package/dist-lib/chunks/{panel-DoNbjeqX.cjs.map → panel-Cpq1xHck.cjs.map} +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/index.mjs +2 -2
- package/dist-lib/preview/clientes.cjs +1 -1
- package/dist-lib/preview/clientes.mjs +1 -1
- package/dist-lib/src/components/ui/DataTable/data-table.d.ts.map +1 -1
- package/dist-lib/src/components/ui/DataTable/data-table.types.d.ts +20 -2
- package/dist-lib/src/components/ui/DataTable/data-table.types.d.ts.map +1 -1
- package/package.json +1 -1
- /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/blueprint.md +0 -0
- /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/entrevista.md +0 -0
- /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/geracao.md +0 -0
- /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/roteiro.md +0 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Calendar,
|
|
4
|
+
Check,
|
|
5
|
+
CircleDot,
|
|
6
|
+
Clock,
|
|
7
|
+
Download,
|
|
8
|
+
FileText,
|
|
9
|
+
Flag,
|
|
10
|
+
Link2,
|
|
11
|
+
Paperclip,
|
|
12
|
+
Pencil,
|
|
13
|
+
Plus,
|
|
14
|
+
SendHorizontal,
|
|
15
|
+
Tag,
|
|
16
|
+
Users,
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import type { LucideIcon } from "@/lib/lucide-types";
|
|
19
|
+
// Import por ARQUIVO, não pelo barrel `@/components/shadcn` — o barrel não é distribuído por
|
|
20
|
+
// nenhum item do registry, então um bloco que o importasse chegaria no consumidor de copy-in
|
|
21
|
+
// com import que não resolve (L-037, gate `registry-imports`).
|
|
22
|
+
import { Input } from "@/components/shadcn/input";
|
|
23
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/shadcn/tabs";
|
|
24
|
+
import { Avatar } from "@/components/ui/avatar-ig";
|
|
25
|
+
import { Button } from "@/components/ui/Button";
|
|
26
|
+
import { Chip } from "@/components/ui/Chip";
|
|
27
|
+
import { FloatingPanel } from "@/components/ui/FloatingPanel";
|
|
28
|
+
|
|
29
|
+
export const BLOCK = {
|
|
30
|
+
id: "dsgreen-paneldetail-2",
|
|
31
|
+
nome: "Detalhe de tarefa com abas",
|
|
32
|
+
descricao:
|
|
33
|
+
"Painel de detalhe de uma TAREFA: contexto (projeto/coluna) no header, título grande no corpo, propriedades em lista plana com ícone à esquerda e valor à direita, descrição, e abas pros conteúdos que crescem — subtarefas, anexos, comentários e atividade.",
|
|
34
|
+
usa: [
|
|
35
|
+
"FloatingPanel (side=\"right\", size=\"lg\", titleSlot + headerActions + maximizable + resizable; body PADDED, sem Section)",
|
|
36
|
+
"Tabs (fullWidth, variante default) + TabsContent",
|
|
37
|
+
"Avatar (pilha com sobreposição) · Chip (soft) · Input · Button",
|
|
38
|
+
],
|
|
39
|
+
} as const;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* dsgreen-paneldetail-2 — detalhe de TAREFA, com abas.
|
|
43
|
+
*
|
|
44
|
+
* ## Por que existe, tendo o `dsgreen-paneldetail-1`
|
|
45
|
+
*
|
|
46
|
+
* Os dois são painel de detalhe e param aí a semelhança. O que muda é **o que o registro é**:
|
|
47
|
+
*
|
|
48
|
+
* | | `-1` registro (cliente, pedido) | `-2` tarefa (esta) |
|
|
49
|
+
* |---|---|---|
|
|
50
|
+
* | identidade | nome curto → cabe no header | título é uma FRASE → vai no corpo, grande; o header leva o **contexto** (projeto / coluna) |
|
|
51
|
+
* | dados | 20+ campos, agrupáveis por assunto | ~6 propriedades, e nenhuma agrupável |
|
|
52
|
+
* | estrutura | `FloatingPanelSection` colapsável | **lista plana** com ícone à esquerda |
|
|
53
|
+
* | abas | ⛔ não — o colapso já esconde | ✅ **sim** — ver abaixo |
|
|
54
|
+
*
|
|
55
|
+
* ## Aqui aba está certa, e no `-1` estava errada
|
|
56
|
+
*
|
|
57
|
+
* A regra não é "aba é ruim". É: **aba serve pra tipo de conteúdo, não pra mais campos.**
|
|
58
|
+
*
|
|
59
|
+
* No `-1` as abas escondiam seções de campos — e um corpo que já é pilha de seções
|
|
60
|
+
* colapsáveis já tem mecanismo de esconder; os dois juntos fazem o usuário procurar o dado em
|
|
61
|
+
* dois lugares.
|
|
62
|
+
*
|
|
63
|
+
* Aqui cada aba é uma **natureza diferente**: subtarefa é checklist, anexo é arquivo,
|
|
64
|
+
* comentário é conversa, atividade é log. Nenhuma é campo, nenhuma cabe na lista de
|
|
65
|
+
* propriedades, e todas **crescem sem limite** — 40 comentários não podem empurrar o próximo
|
|
66
|
+
* dado 40 linhas pra baixo. É exatamente o caso pra aba.
|
|
67
|
+
*
|
|
68
|
+
* ## O body é PADDED aqui — o oposto do `-1`
|
|
69
|
+
*
|
|
70
|
+
* ⚠️ Não copie o `bodyPadded={false}` do `-1`. Lá ele é obrigatório porque as
|
|
71
|
+
* `FloatingPanelSection` trazem padding próprio e divisória de ponta a ponta. **Aqui não há
|
|
72
|
+
* Section nenhuma**, então o default (`bodyPadded` = true, gutter de 18px) é o certo, e some a
|
|
73
|
+
* necessidade de qualquer margem negativa. Ligar `false` aqui colaria todo o conteúdo na borda.
|
|
74
|
+
*
|
|
75
|
+
* ## A lista de propriedades: por que grid e não `justify-between`
|
|
76
|
+
*
|
|
77
|
+
* `grid-cols-[132px_1fr]` alinha os valores numa **coluna única**, que é o que dá a leitura de
|
|
78
|
+
* ficha. Com `justify-between` cada valor encostaria na borda direita numa distância diferente
|
|
79
|
+
* (depende do tamanho do label), e a coluna desapareceria.
|
|
80
|
+
*
|
|
81
|
+
* Também não é `FloatingPanelField`: ele é `label ... valor` **sem ícone** e com o valor
|
|
82
|
+
* alinhado à direita. Aqui o ícone à esquerda do label é parte do desenho — ele é o que
|
|
83
|
+
* permite varrer a lista por tipo de propriedade sem ler.
|
|
84
|
+
*
|
|
85
|
+
* ## Regras do DS que este bloco carrega (e que copiar sem elas quebra)
|
|
86
|
+
*
|
|
87
|
+
* - **Aba dentro de painel vem `fullWidth`, na variante default (`segmented`).** Regra
|
|
88
|
+
* declarada no `USAGE.md` do `FloatingPanel`: em 560px o `line` vira um trilho curto que lê
|
|
89
|
+
* como fragmento. Com 4 abas o `fullWidth` dá ~130px cada — cabe.
|
|
90
|
+
* - **Ação de ícone é `variant="soft"` + `aria-label`.** O maximize e o close que o
|
|
91
|
+
* componente renderiza são `soft`+`secondary`; `ghost` no meio da fileira fica sem container
|
|
92
|
+
* e lê como desabilitada. E botão de ícone sem `aria-label` é anunciado só como "button".
|
|
93
|
+
* - **Status/prioridade/tag são `Chip`**, nunca `<span>` estilizado — o Chip já resolve tom,
|
|
94
|
+
* contraste e altura de linha.
|
|
95
|
+
* - **Data com `tabular-nums`**, senão os dígitos dançam entre as linhas da lista.
|
|
96
|
+
* - **Pilha de avatares:** `-ml-sp-sm` (6px, token) + `ring-2 ring-bg-surface` pra separar um
|
|
97
|
+
* do outro. O DS **não tem** `AvatarGroup` — se passar a ter, troque por ele.
|
|
98
|
+
* - **Subtarefa concluída = disco CHEIO**, feito com `<span bg-bg-success>` + `<Check>`, não
|
|
99
|
+
* com o `CircleCheck` do lucide: ele desenha o círculo com `stroke="currentColor"`, e no
|
|
100
|
+
* dark o traço (preto, porque `fg-on-success` inverte) fica por cima do preenchimento e come
|
|
101
|
+
* ~2px de verde de cada lado. Medido no `-1`, mesma solução aqui.
|
|
102
|
+
*
|
|
103
|
+
* ## Cuidado ao adaptar
|
|
104
|
+
*
|
|
105
|
+
* - **O botão daqui é do EXEMPLO.** No board real quem abre o painel é o card clicado:
|
|
106
|
+
* `open={!!tarefaSelecionada}`.
|
|
107
|
+
* - **Contagem na aba** (`Comentários 3`) só quando o número informa. "Atividade 47" não
|
|
108
|
+
* ajuda ninguém a decidir se clica.
|
|
109
|
+
* - **O campo de mensagem aqui é `Input` + botão.** O DS tem um `MessageComposer` bem mais
|
|
110
|
+
* completo (anexo, menção, template), mas ele **não está no registry** — um bloco que o
|
|
111
|
+
* importasse não resolveria no consumidor de copy-in. Se ele entrar no registry, troque.
|
|
112
|
+
* - **Não empilhe as 4 abas em telas estreitas.** Em mobile o `FloatingPanel` vira sheet e 4
|
|
113
|
+
* triggers de ~80px ficam ilegíveis: ali o certo é reduzir pra 2 (Comentários + resto num
|
|
114
|
+
* menu) ou virar tela própria.
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
/** Fixture do bloco. Fica aqui de propósito: bloco é auto-contido, então quem copia vê a
|
|
118
|
+
* forma do dado esperado sem inferir do render. */
|
|
119
|
+
const TAREFA = {
|
|
120
|
+
contexto: "Projeto UI/UX",
|
|
121
|
+
coluna: "Em revisão",
|
|
122
|
+
titulo: "Redesenhar o painel de analytics do dashboard",
|
|
123
|
+
descricao:
|
|
124
|
+
"Revisar a hierarquia dos KPIs e trocar os quatro cards do topo por uma faixa única. O gráfico de barras precisa caber ao lado do ranking sem quebrar em 1280px.",
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const PROPRIEDADES: {
|
|
128
|
+
icone: LucideIcon;
|
|
129
|
+
label: string;
|
|
130
|
+
valor: React.ReactNode;
|
|
131
|
+
}[] = [
|
|
132
|
+
{
|
|
133
|
+
icone: CircleDot,
|
|
134
|
+
label: "Status",
|
|
135
|
+
valor: (
|
|
136
|
+
<Chip color="info" variant="soft" size="sm">
|
|
137
|
+
Em revisão
|
|
138
|
+
</Chip>
|
|
139
|
+
),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
icone: Flag,
|
|
143
|
+
label: "Prioridade",
|
|
144
|
+
valor: (
|
|
145
|
+
<Chip color="warning" variant="soft" size="sm">
|
|
146
|
+
Alta
|
|
147
|
+
</Chip>
|
|
148
|
+
),
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
icone: Calendar,
|
|
152
|
+
label: "Prazo",
|
|
153
|
+
valor: <span className="tabular-nums">3 out 2026 — 12 out 2026</span>,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
icone: Tag,
|
|
157
|
+
label: "Tags",
|
|
158
|
+
valor: (
|
|
159
|
+
<span className="flex flex-wrap items-center gap-gp-sm">
|
|
160
|
+
{["Dashboard", "Analytics", "Frontend"].map((t) => (
|
|
161
|
+
<Chip key={t} color="neutral" variant="soft" size="sm">
|
|
162
|
+
{t}
|
|
163
|
+
</Chip>
|
|
164
|
+
))}
|
|
165
|
+
</span>
|
|
166
|
+
),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
icone: Users,
|
|
170
|
+
label: "Responsáveis",
|
|
171
|
+
valor: (
|
|
172
|
+
/* Pilha com sobreposição: `-ml-sp-sm` (6px, token) no 2º em diante + `ring` da cor da
|
|
173
|
+
superfície, que é o que separa um avatar do outro. Sem AvatarGroup no DS. */
|
|
174
|
+
<span className="flex items-center">
|
|
175
|
+
{[
|
|
176
|
+
{ ini: "MD", hex: "#2563EB" },
|
|
177
|
+
{ ini: "AC", hex: "#CC092F" },
|
|
178
|
+
{ ini: "JS", hex: "#7C3AED" },
|
|
179
|
+
].map((p, i) => (
|
|
180
|
+
<Avatar
|
|
181
|
+
key={p.ini}
|
|
182
|
+
size="sm"
|
|
183
|
+
colorHex={p.hex}
|
|
184
|
+
aria-label={p.ini}
|
|
185
|
+
className={i > 0 ? "-ml-sp-sm ring-2 ring-bg-surface" : "ring-2 ring-bg-surface"}
|
|
186
|
+
>
|
|
187
|
+
{p.ini}
|
|
188
|
+
</Avatar>
|
|
189
|
+
))}
|
|
190
|
+
</span>
|
|
191
|
+
),
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
icone: Clock,
|
|
195
|
+
label: "Criada em",
|
|
196
|
+
valor: <span className="tabular-nums">20 set 2026, 10:35</span>,
|
|
197
|
+
},
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
const SUBTAREFAS = [
|
|
201
|
+
{ label: "Levantar os KPIs que o time realmente usa", feita: true },
|
|
202
|
+
{ label: "Definir a faixa única no lugar dos 4 cards", feita: true },
|
|
203
|
+
{ label: "Validar o gráfico ao lado do ranking em 1280px", feita: false },
|
|
204
|
+
{ label: "Revisar com o time de dados", feita: false },
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
const ANEXOS = [
|
|
208
|
+
{ nome: "Briefing do redesign.pdf", tamanho: "1,5 MB", quando: "24 set 2026" },
|
|
209
|
+
{ nome: "Medições de 1280px.png", tamanho: "820 KB", quando: "26 set 2026" },
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
const COMENTARIOS = [
|
|
213
|
+
{
|
|
214
|
+
autor: "Terry James",
|
|
215
|
+
iniciais: "TJ",
|
|
216
|
+
hex: "#2563EB",
|
|
217
|
+
quando: "sex, 14:20",
|
|
218
|
+
texto:
|
|
219
|
+
"A faixa única resolve a hierarquia, mas o ranking fica sem respiro em 1280px. Consegue medir antes de fechar?",
|
|
220
|
+
reacoes: "2",
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
autor: "Aline Castro",
|
|
224
|
+
iniciais: "AC",
|
|
225
|
+
hex: "#CC092F",
|
|
226
|
+
quando: "sex, 15:02",
|
|
227
|
+
texto: "Medido: 148px pro ranking. Cabe, mas com o título em duas linhas.",
|
|
228
|
+
reacoes: null,
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
/** Log agrupado por DIA. O agrupamento é do dado, não do render: quem monta a lista já sabe
|
|
233
|
+
* a que dia cada evento pertence, e derivar isso no componente esconderia a regra de fuso. */
|
|
234
|
+
const ATIVIDADE = [
|
|
235
|
+
{
|
|
236
|
+
dia: "Hoje",
|
|
237
|
+
eventos: [
|
|
238
|
+
{ autor: "Talan Korsgaard", iniciais: "TK", hex: "#7C3AED", texto: "mudou o status de Em progresso para Em revisão", quando: "10:45" },
|
|
239
|
+
{ autor: "Davis Donin", iniciais: "DD", hex: "#0891B2", texto: "anexou Medições de 1280px.png", quando: "10:20" },
|
|
240
|
+
{ autor: "Aline Castro", iniciais: "AC", hex: "#CC092F", texto: "concluiu a subtarefa Definir a faixa única", quando: "09:58" },
|
|
241
|
+
],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
dia: "Ontem",
|
|
245
|
+
eventos: [
|
|
246
|
+
{ autor: "Terry James", iniciais: "TJ", hex: "#2563EB", texto: "comentou sobre o respiro do ranking em 1280px", quando: "14:20" },
|
|
247
|
+
{ autor: "Aline Castro", iniciais: "AC", hex: "#CC092F", texto: "adicionou a tag Analytics", quando: "11:07" },
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
dia: "24 set 2026",
|
|
252
|
+
eventos: [
|
|
253
|
+
{ autor: "Davis Donin", iniciais: "DD", hex: "#0891B2", texto: "anexou Briefing do redesign.pdf", quando: "16:32" },
|
|
254
|
+
{ autor: "Talan Korsgaard", iniciais: "TK", hex: "#7C3AED", texto: "definiu o prazo para 12 out 2026", quando: "16:10" },
|
|
255
|
+
{ autor: "Talan Korsgaard", iniciais: "TK", hex: "#7C3AED", texto: "criou a tarefa", quando: "16:04" },
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
/** Linha da lista de propriedades: ícone à esquerda, label, e o valor na coluna da direita. */
|
|
261
|
+
function Propriedade({
|
|
262
|
+
icone: Icone,
|
|
263
|
+
label,
|
|
264
|
+
valor,
|
|
265
|
+
}: {
|
|
266
|
+
icone: LucideIcon;
|
|
267
|
+
label: string;
|
|
268
|
+
valor: React.ReactNode;
|
|
269
|
+
}) {
|
|
270
|
+
return (
|
|
271
|
+
<>
|
|
272
|
+
{/* `min-h-form-md` (36px) nas DUAS células. Sem isso a linha tem altura do conteúdo, e
|
|
273
|
+
medido dá 30px na de texto puro contra 36px na que tem `Chip` — a lista fica com
|
|
274
|
+
ritmo irregular. 36 é o piso natural: é a altura que o Chip já impõe, então nada
|
|
275
|
+
cresce, só as menores igualam. */}
|
|
276
|
+
<div className="flex min-h-form-md items-center gap-gp-md text-body-sm text-fg-muted">
|
|
277
|
+
<Icone className="size-icon-sm shrink-0 text-fg-subtle" aria-hidden="true" />
|
|
278
|
+
<span className="truncate">{label}</span>
|
|
279
|
+
</div>
|
|
280
|
+
<div className="flex min-h-form-md min-w-0 items-center text-body-sm text-fg-default">
|
|
281
|
+
{valor}
|
|
282
|
+
</div>
|
|
283
|
+
</>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function DetalheDeTarefaComAbas() {
|
|
288
|
+
const [aberto, setAberto] = useState(false);
|
|
289
|
+
const [aba, setAba] = useState("subtarefas");
|
|
290
|
+
const feitas = SUBTAREFAS.filter((s) => s.feita).length;
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<>
|
|
294
|
+
{/* No board real este botão não existe: quem abre o painel é o card clicado. */}
|
|
295
|
+
<Button variant="outline" color="secondary" onClick={() => setAberto(true)}>
|
|
296
|
+
Abrir detalhe da tarefa
|
|
297
|
+
</Button>
|
|
298
|
+
|
|
299
|
+
<FloatingPanel
|
|
300
|
+
open={aberto}
|
|
301
|
+
onOpenChange={setAberto}
|
|
302
|
+
side="right"
|
|
303
|
+
size="lg"
|
|
304
|
+
resizable
|
|
305
|
+
maximizable
|
|
306
|
+
resizableStorageKey="dsgreen-paneldetail-2.width"
|
|
307
|
+
/* Header leva o CONTEXTO, não a identidade: título de tarefa é uma frase e não cabe
|
|
308
|
+
numa linha de header. Quem identifica aqui é "onde a tarefa está". */
|
|
309
|
+
titleSlot={
|
|
310
|
+
<div className="flex min-w-0 items-center gap-gp-sm text-body-sm text-fg-muted">
|
|
311
|
+
<span className="truncate">{TAREFA.contexto}</span>
|
|
312
|
+
<span className="opacity-50">/</span>
|
|
313
|
+
<span className="truncate font-medium text-fg-default">{TAREFA.coluna}</span>
|
|
314
|
+
</div>
|
|
315
|
+
}
|
|
316
|
+
headerActions={
|
|
317
|
+
<>
|
|
318
|
+
<Button variant="soft" color="secondary" size="icon-sm" aria-label="Editar tarefa">
|
|
319
|
+
<Pencil />
|
|
320
|
+
</Button>
|
|
321
|
+
<Button variant="soft" color="secondary" size="icon-sm" aria-label="Copiar link">
|
|
322
|
+
<Link2 />
|
|
323
|
+
</Button>
|
|
324
|
+
</>
|
|
325
|
+
}
|
|
326
|
+
footer={
|
|
327
|
+
<>
|
|
328
|
+
<Button
|
|
329
|
+
variant="outline"
|
|
330
|
+
color="secondary"
|
|
331
|
+
size="sm"
|
|
332
|
+
onClick={() => setAberto(false)}
|
|
333
|
+
>
|
|
334
|
+
Fechar
|
|
335
|
+
</Button>
|
|
336
|
+
<Button variant="filled" size="sm" iconLeft={<Check />}>
|
|
337
|
+
Concluir tarefa
|
|
338
|
+
</Button>
|
|
339
|
+
</>
|
|
340
|
+
}
|
|
341
|
+
>
|
|
342
|
+
{/* ⚠️ Este wrapper de gap é OBRIGATÓRIO, e não é preferência: o body do
|
|
343
|
+
`FloatingPanel` **não tem gap entre filhos** (`row-gap: normal`, medido) — só
|
|
344
|
+
padding. Sem ele, título, lista, descrição e abas ficam com **0px** entre si, todos
|
|
345
|
+
colados. Não confunda com o `PanelBody` do `Panel`, que tem `gap-gp-3xl` embutido:
|
|
346
|
+
é a diferença que fez a 1ª versão deste bloco sair grudada. */}
|
|
347
|
+
<div className="flex flex-col gap-gp-2xl">
|
|
348
|
+
{/* Título no CORPO, grande. `text-balance` evita a última linha órfã de uma palavra. */}
|
|
349
|
+
<h2 className="text-title-lg text-balance text-fg-default">{TAREFA.titulo}</h2>
|
|
350
|
+
|
|
351
|
+
{/* Lista plana de propriedades. O grid alinha todos os valores numa coluna só — é
|
|
352
|
+
isso que dá leitura de ficha; `justify-between` desalinharia por tamanho de
|
|
353
|
+
label. */}
|
|
354
|
+
<div className="grid grid-cols-[132px_1fr] items-center gap-x-gp-md">
|
|
355
|
+
{PROPRIEDADES.map((p) => (
|
|
356
|
+
<Propriedade key={p.label} {...p} />
|
|
357
|
+
))}
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
{/* `bg-bg-surface`, não `bg-bg-subtle`: medido no dark, o subtle dá
|
|
361
|
+
`oklch(1 0 0 / 0.01)` — 1% de branco sobre o painel, invisível. O surface é
|
|
362
|
+
superfície de verdade e destaca o bloco de texto do resto da ficha. */}
|
|
363
|
+
<div className="flex flex-col gap-gp-md rounded-radius-lg border border-border-default bg-bg-surface p-pad-2xl">
|
|
364
|
+
<span className="text-body-xs font-semibold text-fg-muted">Descrição</span>
|
|
365
|
+
<p className="text-body-sm text-fg-default">{TAREFA.descricao}</p>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
{/* Abas: cada uma é uma NATUREZA de conteúdo que cresce sem limite — não são campos.
|
|
370
|
+
É a diferença que justifica aba aqui e a proíbe no `dsgreen-paneldetail-1`. */}
|
|
371
|
+
<Tabs value={aba} onValueChange={setAba} fullWidth className="mt-gp-2xl">
|
|
372
|
+
<TabsList>
|
|
373
|
+
<TabsTrigger value="subtarefas">Subtarefas</TabsTrigger>
|
|
374
|
+
<TabsTrigger value="anexos">Anexos</TabsTrigger>
|
|
375
|
+
<TabsTrigger value="comentarios">Comentários</TabsTrigger>
|
|
376
|
+
<TabsTrigger value="atividade">Atividade</TabsTrigger>
|
|
377
|
+
</TabsList>
|
|
378
|
+
|
|
379
|
+
<TabsContent value="subtarefas" className="flex flex-col gap-gp-lg pt-pad-xl">
|
|
380
|
+
<div className="flex items-center justify-between text-body-xs text-fg-muted">
|
|
381
|
+
<span className="font-semibold text-fg-default">Progresso</span>
|
|
382
|
+
<span className="tabular-nums">
|
|
383
|
+
{feitas}/{SUBTAREFAS.length}
|
|
384
|
+
</span>
|
|
385
|
+
</div>
|
|
386
|
+
{/* Timeline: a linha vertical liga um marcador ao próximo. Ela é um `<span>` que
|
|
387
|
+
cresce (`flex-1`) numa coluna ao lado do marcador — NÃO um `before:` com
|
|
388
|
+
`left-[7px]`, que seria valor na unha e desalinharia se o marcador mudar de
|
|
389
|
+
tamanho. O `gap-0` no `<ul>` é o que mantém a linha contínua; o respiro entre
|
|
390
|
+
itens vem do `pb` do texto. */}
|
|
391
|
+
<ul className="flex flex-col gap-0">
|
|
392
|
+
{SUBTAREFAS.map((s, i) => {
|
|
393
|
+
const ultima = i === SUBTAREFAS.length - 1;
|
|
394
|
+
return (
|
|
395
|
+
<li key={s.label} className="flex gap-gp-md text-body-sm">
|
|
396
|
+
<div className="flex flex-col items-center">
|
|
397
|
+
{s.feita ? (
|
|
398
|
+
/* Disco CHEIO: `<span>` + `<Check>`, não o `CircleCheck` do lucide — o
|
|
399
|
+
stroke dele fica por cima do fill e come o disco no dark. */
|
|
400
|
+
<span
|
|
401
|
+
className="grid size-icon-sm shrink-0 place-items-center rounded-radius-full bg-bg-success text-fg-on-success"
|
|
402
|
+
aria-hidden="true"
|
|
403
|
+
>
|
|
404
|
+
<Check className="size-icon-2xs" strokeWidth={3} />
|
|
405
|
+
</span>
|
|
406
|
+
) : (
|
|
407
|
+
<span
|
|
408
|
+
className="size-icon-sm shrink-0 rounded-radius-full border border-border-input"
|
|
409
|
+
aria-hidden="true"
|
|
410
|
+
/>
|
|
411
|
+
)}
|
|
412
|
+
{!ultima && (
|
|
413
|
+
<span
|
|
414
|
+
className="mt-gp-2xs w-px flex-1 bg-border-default"
|
|
415
|
+
aria-hidden="true"
|
|
416
|
+
/>
|
|
417
|
+
)}
|
|
418
|
+
</div>
|
|
419
|
+
<span
|
|
420
|
+
className={`${ultima ? "" : "pb-pad-xl"} ${
|
|
421
|
+
s.feita ? "text-fg-muted line-through" : "text-fg-default"
|
|
422
|
+
}`}
|
|
423
|
+
>
|
|
424
|
+
{s.label}
|
|
425
|
+
</span>
|
|
426
|
+
</li>
|
|
427
|
+
);
|
|
428
|
+
})}
|
|
429
|
+
</ul>
|
|
430
|
+
</TabsContent>
|
|
431
|
+
|
|
432
|
+
<TabsContent value="anexos" className="flex flex-col gap-gp-md pt-pad-xl">
|
|
433
|
+
{ANEXOS.map((a) => (
|
|
434
|
+
<div
|
|
435
|
+
key={a.nome}
|
|
436
|
+
className="flex items-center gap-gp-md rounded-radius-lg border border-border-default bg-bg-surface p-pad-xl"
|
|
437
|
+
>
|
|
438
|
+
<FileText className="size-icon-md shrink-0 text-fg-subtle" aria-hidden="true" />
|
|
439
|
+
<div className="flex min-w-0 flex-1 flex-col">
|
|
440
|
+
<span className="truncate text-body-sm text-fg-default">{a.nome}</span>
|
|
441
|
+
{/* Tamanho e data na MESMA linha secundária, separados por `·`. Duas linhas
|
|
442
|
+
aqui esticariam a altura do anexo sem ganhar leitura — os dois são
|
|
443
|
+
metadado do mesmo arquivo. */}
|
|
444
|
+
<span className="text-caption-sm tabular-nums text-fg-muted">
|
|
445
|
+
{a.tamanho} · {a.quando}
|
|
446
|
+
</span>
|
|
447
|
+
</div>
|
|
448
|
+
<Button
|
|
449
|
+
variant="ghost"
|
|
450
|
+
color="secondary"
|
|
451
|
+
size="icon-sm"
|
|
452
|
+
aria-label={`Baixar ${a.nome}`}
|
|
453
|
+
>
|
|
454
|
+
<Download />
|
|
455
|
+
</Button>
|
|
456
|
+
</div>
|
|
457
|
+
))}
|
|
458
|
+
<Button variant="outline" color="secondary" size="sm" iconLeft={<Plus />}>
|
|
459
|
+
Anexar arquivo
|
|
460
|
+
</Button>
|
|
461
|
+
</TabsContent>
|
|
462
|
+
|
|
463
|
+
<TabsContent value="comentarios" className="flex flex-col gap-gp-2xl pt-pad-xl">
|
|
464
|
+
<ul className="flex flex-col gap-gp-2xl">
|
|
465
|
+
{COMENTARIOS.map((c) => (
|
|
466
|
+
<li key={c.quando} className="flex gap-gp-md">
|
|
467
|
+
<Avatar
|
|
468
|
+
size="md"
|
|
469
|
+
colorHex={c.hex}
|
|
470
|
+
className="shrink-0"
|
|
471
|
+
aria-label={c.autor}
|
|
472
|
+
>
|
|
473
|
+
{c.iniciais}
|
|
474
|
+
</Avatar>
|
|
475
|
+
<div className="flex min-w-0 flex-col gap-gp-2xs">
|
|
476
|
+
<span className="flex flex-wrap items-baseline gap-gp-sm">
|
|
477
|
+
<span className="text-body-sm font-semibold text-fg-default">
|
|
478
|
+
{c.autor}
|
|
479
|
+
</span>
|
|
480
|
+
<span className="text-caption-sm tabular-nums text-fg-muted">
|
|
481
|
+
{c.quando}
|
|
482
|
+
</span>
|
|
483
|
+
</span>
|
|
484
|
+
<p className="text-body-sm text-fg-default">{c.texto}</p>
|
|
485
|
+
{c.reacoes && (
|
|
486
|
+
<span className="mt-gp-2xs w-fit">
|
|
487
|
+
<Chip color="neutral" variant="soft" size="sm">
|
|
488
|
+
👍 {c.reacoes}
|
|
489
|
+
</Chip>
|
|
490
|
+
</span>
|
|
491
|
+
)}
|
|
492
|
+
</div>
|
|
493
|
+
</li>
|
|
494
|
+
))}
|
|
495
|
+
</ul>
|
|
496
|
+
{/* Campo de mensagem: `Input` + botão de enviar. O `MessageComposer` do DS é mais
|
|
497
|
+
completo mas NÃO está no registry — ver "Cuidado ao adaptar". */}
|
|
498
|
+
<div className="flex items-center gap-gp-md">
|
|
499
|
+
<Input placeholder="Escreva um comentário…" aria-label="Novo comentário" />
|
|
500
|
+
<Button
|
|
501
|
+
variant="soft"
|
|
502
|
+
color="secondary"
|
|
503
|
+
size="icon-sm"
|
|
504
|
+
aria-label="Anexar ao comentário"
|
|
505
|
+
>
|
|
506
|
+
<Paperclip />
|
|
507
|
+
</Button>
|
|
508
|
+
<Button variant="filled" size="icon-sm" aria-label="Enviar comentário">
|
|
509
|
+
<SendHorizontal />
|
|
510
|
+
</Button>
|
|
511
|
+
</div>
|
|
512
|
+
</TabsContent>
|
|
513
|
+
|
|
514
|
+
<TabsContent value="atividade" className="flex flex-col gap-gp-2xl pt-pad-xl">
|
|
515
|
+
{ATIVIDADE.map((grupo) => (
|
|
516
|
+
<div key={grupo.dia} className="flex flex-col gap-gp-md">
|
|
517
|
+
{/* Separador de dia no padrão de conversa: fio · badge · fio. Centralizado
|
|
518
|
+
porque ele divide o fluxo, não rotula o item de baixo — encostado à
|
|
519
|
+
esquerda ele leria como título do primeiro evento.
|
|
520
|
+
|
|
521
|
+
O dia é um `Chip`, não texto solto: com 3 grupos na mesma rolagem, texto
|
|
522
|
+
fino do mesmo tamanho do resto some no meio do log. O badge dá o degrau
|
|
523
|
+
visual que separa bloco de bloco.
|
|
524
|
+
|
|
525
|
+
⚠️ Os fios são `aria-hidden`, o Chip NÃO. A 1ª versão tinha `aria-hidden`
|
|
526
|
+
no container inteiro e escondia a data — e é ela que agrupa o log: sem
|
|
527
|
+
ela, no leitor de tela os 8 eventos viram uma lista corrida sem dia. */}
|
|
528
|
+
<div className="flex items-center gap-gp-md">
|
|
529
|
+
<span className="h-px flex-1 bg-border-subtle" aria-hidden="true" />
|
|
530
|
+
<Chip color="neutral" variant="soft" size="sm">
|
|
531
|
+
{grupo.dia}
|
|
532
|
+
</Chip>
|
|
533
|
+
<span className="h-px flex-1 bg-border-subtle" aria-hidden="true" />
|
|
534
|
+
</div>
|
|
535
|
+
|
|
536
|
+
<ul className="flex flex-col">
|
|
537
|
+
{grupo.eventos.map((a) => (
|
|
538
|
+
<li
|
|
539
|
+
key={a.autor + a.quando}
|
|
540
|
+
/* Divisória por evento: log é lista de linhas parecidas, e sem
|
|
541
|
+
separação elas viram parágrafo corrido. A última do grupo não leva,
|
|
542
|
+
porque o separador de dia já fecha o bloco. */
|
|
543
|
+
className="flex items-start gap-gp-md border-b border-border-subtle py-pad-lg first:pt-0 last:border-b-0 last:pb-0"
|
|
544
|
+
>
|
|
545
|
+
<Avatar
|
|
546
|
+
size="sm"
|
|
547
|
+
colorHex={a.hex}
|
|
548
|
+
className="shrink-0"
|
|
549
|
+
aria-label={a.autor}
|
|
550
|
+
>
|
|
551
|
+
{a.iniciais}
|
|
552
|
+
</Avatar>
|
|
553
|
+
<p className="min-w-0 flex-1 text-body-sm text-fg-muted">
|
|
554
|
+
<span className="font-semibold text-fg-default">{a.autor}</span>{" "}
|
|
555
|
+
{a.texto}
|
|
556
|
+
</p>
|
|
557
|
+
<span className="shrink-0 text-caption-sm tabular-nums text-fg-muted">
|
|
558
|
+
{a.quando}
|
|
559
|
+
</span>
|
|
560
|
+
</li>
|
|
561
|
+
))}
|
|
562
|
+
</ul>
|
|
563
|
+
</div>
|
|
564
|
+
))}
|
|
565
|
+
</TabsContent>
|
|
566
|
+
</Tabs>
|
|
567
|
+
</FloatingPanel>
|
|
568
|
+
</>
|
|
569
|
+
);
|
|
570
|
+
}
|