@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,246 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { Eye, EyeOff, LifeBuoy, Hexagon, ShieldCheck, Zap } from "lucide-react";
|
|
4
|
+
import { Button } from "@/components/ui/Button";
|
|
5
|
+
import { FormFieldInput, FormFieldCheckbox } from "@/components/ui/FormField";
|
|
6
|
+
import { SidebarBrandIcon } from "@/components/ui/MenuSidebar";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* LoginScreen — tela de login split (form à esquerda, painel à direita).
|
|
10
|
+
* Self-contained e configurável por props:
|
|
11
|
+
*
|
|
12
|
+
* - `logo` — marca no topo do form (default: logo iGreen; passe o do seu app).
|
|
13
|
+
* - `rightVariant` — painel direito: "text" (marca 100% por tokens, sem asset) ·
|
|
14
|
+
* "image" (só a imagem) · "image-text" (imagem + headline sobreposta).
|
|
15
|
+
* **Default "image"** — sem `image`, cai no painel de texto (nunca quebra).
|
|
16
|
+
* - `image` — URL da imagem (variants image/-text e do fundo `ambient`).
|
|
17
|
+
* - `ambient` — fundo ambiente: a imagem borrada/escurecida atrás do card (destaque).
|
|
18
|
+
* - `panelTitle` / `panelSubtitle` — copy do painel (text e image-text).
|
|
19
|
+
*
|
|
20
|
+
* Mockado: `onSubmit` só previne o default — o consumidor pluga a auth real.
|
|
21
|
+
*/
|
|
22
|
+
export interface LoginScreenProps {
|
|
23
|
+
logo?: ReactNode;
|
|
24
|
+
rightVariant?: "text" | "image" | "image-text";
|
|
25
|
+
image?: string;
|
|
26
|
+
ambient?: boolean;
|
|
27
|
+
panelTitle?: string;
|
|
28
|
+
panelSubtitle?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const SELLING_POINTS = [
|
|
32
|
+
{ icon: Zap, label: "Acompanhe seus resultados em tempo real" },
|
|
33
|
+
{ icon: ShieldCheck, label: "Acesso seguro à sua conta" },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export function LoginScreen({
|
|
37
|
+
logo = <SidebarBrandIcon size={24} />,
|
|
38
|
+
rightVariant = "image",
|
|
39
|
+
image,
|
|
40
|
+
ambient = false,
|
|
41
|
+
panelTitle = "Tudo o que você precisa, num só lugar.",
|
|
42
|
+
panelSubtitle = "Gerencie seus dados, acompanhe resultados e cresça com a sua equipe.",
|
|
43
|
+
}: LoginScreenProps = {}) {
|
|
44
|
+
const [email, setEmail] = useState("");
|
|
45
|
+
const [senha, setSenha] = useState("");
|
|
46
|
+
const [showSenha, setShowSenha] = useState(false);
|
|
47
|
+
const [manter, setManter] = useState(true);
|
|
48
|
+
|
|
49
|
+
const entrar = (e: React.FormEvent) => {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
// Mock: plugue a autenticação real do seu app aqui.
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Sem imagem, os variants de imagem caem no painel de marca (nunca quebra).
|
|
55
|
+
const variant = rightVariant !== "text" && !image ? "text" : rightVariant;
|
|
56
|
+
const hasAmbient = ambient && !!image;
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div className="relative flex min-h-screen flex-col items-center justify-center gap-gp-2xl overflow-hidden bg-bg-canvas p-pad-2xl">
|
|
60
|
+
{/* Fundo ambiente: a imagem borrada + escurecida atrás de tudo. */}
|
|
61
|
+
{hasAmbient && (
|
|
62
|
+
<>
|
|
63
|
+
<img
|
|
64
|
+
src={image}
|
|
65
|
+
aria-hidden
|
|
66
|
+
alt=""
|
|
67
|
+
className="pointer-events-none absolute inset-0 size-full scale-110 object-cover opacity-20 blur-[60px] saturate-150"
|
|
68
|
+
/>
|
|
69
|
+
<div
|
|
70
|
+
aria-hidden
|
|
71
|
+
className="pointer-events-none absolute inset-0 bg-bg-canvas/85"
|
|
72
|
+
/>
|
|
73
|
+
</>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
<div className="relative z-10 grid w-full max-w-[1000px] overflow-hidden rounded-radius-2xl border border-border-subtle shadow-sh-lg lg:min-h-[620px] lg:grid-cols-2">
|
|
77
|
+
{/* ── Esquerda: formulário ── */}
|
|
78
|
+
<div className="flex flex-col justify-center gap-gp-3xl bg-bg-surface p-pad-4xl lg:px-[40px] lg:py-pad-6xl">
|
|
79
|
+
<div className="mb-gp-md flex flex-col items-center gap-gp-lg text-center">
|
|
80
|
+
<span className="grid size-[48px] place-items-center rounded-radius-2xl bg-bg-brand text-fg-on-brand shadow-sh-sm">
|
|
81
|
+
{logo}
|
|
82
|
+
</span>
|
|
83
|
+
<div className="flex flex-col gap-gp-2xs">
|
|
84
|
+
<h1 className="text-heading-xs font-bold text-fg-default">
|
|
85
|
+
Bem-vindo de volta
|
|
86
|
+
</h1>
|
|
87
|
+
<p className="mx-auto max-w-[300px] text-body-md text-fg-muted">
|
|
88
|
+
Adicione suas credenciais abaixo para acessar sua conta.
|
|
89
|
+
</p>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<form className="flex flex-col gap-form-gap" onSubmit={entrar}>
|
|
94
|
+
<FormFieldInput
|
|
95
|
+
label="Email"
|
|
96
|
+
type="email"
|
|
97
|
+
autoComplete="email"
|
|
98
|
+
placeholder="voce@email.com"
|
|
99
|
+
helperText="Use o email cadastrado na sua conta."
|
|
100
|
+
className="min-h-form-xl"
|
|
101
|
+
value={email}
|
|
102
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
103
|
+
/>
|
|
104
|
+
|
|
105
|
+
<FormFieldInput
|
|
106
|
+
label="Senha"
|
|
107
|
+
type={showSenha ? "text" : "password"}
|
|
108
|
+
autoComplete="current-password"
|
|
109
|
+
placeholder="Sua senha"
|
|
110
|
+
className="min-h-form-xl"
|
|
111
|
+
value={senha}
|
|
112
|
+
onChange={(e) => setSenha(e.target.value)}
|
|
113
|
+
endAddon={
|
|
114
|
+
<button
|
|
115
|
+
type="button"
|
|
116
|
+
aria-label={showSenha ? "Ocultar senha" : "Mostrar senha"}
|
|
117
|
+
onClick={() => setShowSenha((s) => !s)}
|
|
118
|
+
className="grid place-items-center rounded-radius-sm text-fg-muted transition-colors hover:text-fg-default focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand [&>svg]:size-icon-sm"
|
|
119
|
+
>
|
|
120
|
+
{showSenha ? <EyeOff /> : <Eye />}
|
|
121
|
+
</button>
|
|
122
|
+
}
|
|
123
|
+
/>
|
|
124
|
+
|
|
125
|
+
<div className="flex items-center justify-between gap-gp-md">
|
|
126
|
+
<FormFieldCheckbox
|
|
127
|
+
label="Manter conectado"
|
|
128
|
+
checked={manter}
|
|
129
|
+
onCheckedChange={(v) => setManter(v === true)}
|
|
130
|
+
/>
|
|
131
|
+
<button
|
|
132
|
+
type="button"
|
|
133
|
+
className="shrink-0 whitespace-nowrap rounded-radius-sm text-body-sm font-medium text-fg-brand transition-colors hover:underline focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand"
|
|
134
|
+
>
|
|
135
|
+
Esqueceu a senha?
|
|
136
|
+
</button>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<Button
|
|
140
|
+
type="submit"
|
|
141
|
+
color="primary"
|
|
142
|
+
variant="filled"
|
|
143
|
+
size="lg"
|
|
144
|
+
className="w-full min-h-form-xl"
|
|
145
|
+
>
|
|
146
|
+
Entrar
|
|
147
|
+
</Button>
|
|
148
|
+
</form>
|
|
149
|
+
|
|
150
|
+
<p className="mt-gp-md flex flex-wrap items-center justify-center gap-gp-xs text-body-sm text-fg-muted [&>svg]:size-icon-sm [&>svg]:text-fg-subtle">
|
|
151
|
+
<LifeBuoy />
|
|
152
|
+
Precisa de ajuda para acessar?{" "}
|
|
153
|
+
<a
|
|
154
|
+
href="#"
|
|
155
|
+
className="rounded-radius-sm font-medium text-fg-brand transition-colors hover:underline focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-brand"
|
|
156
|
+
>
|
|
157
|
+
Fale com o suporte
|
|
158
|
+
</a>
|
|
159
|
+
</p>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
{/* ── Direita: painel (some no mobile) ── */}
|
|
163
|
+
<div className="relative hidden overflow-hidden bg-bg-brand lg:block">
|
|
164
|
+
{variant === "text" && (
|
|
165
|
+
<BrandPanel title={panelTitle} subtitle={panelSubtitle} />
|
|
166
|
+
)}
|
|
167
|
+
|
|
168
|
+
{variant === "image" && (
|
|
169
|
+
<img
|
|
170
|
+
src={image}
|
|
171
|
+
alt=""
|
|
172
|
+
aria-hidden
|
|
173
|
+
className="absolute inset-0 h-full w-full object-cover"
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
176
|
+
|
|
177
|
+
{variant === "image-text" && (
|
|
178
|
+
<>
|
|
179
|
+
<img
|
|
180
|
+
src={image}
|
|
181
|
+
alt=""
|
|
182
|
+
aria-hidden
|
|
183
|
+
className="absolute inset-0 h-full w-full object-cover"
|
|
184
|
+
/>
|
|
185
|
+
{/* Overlay escuro pra legibilidade do texto sobre a foto (exceção: texto sobre imagem). */}
|
|
186
|
+
<div
|
|
187
|
+
aria-hidden
|
|
188
|
+
className="absolute inset-0 bg-gradient-to-t from-black/75 via-black/25 to-transparent"
|
|
189
|
+
/>
|
|
190
|
+
<div className="absolute inset-x-0 bottom-0 flex flex-col gap-gp-md p-pad-6xl text-white">
|
|
191
|
+
<h2 className="text-heading-sm font-semibold leading-tight">
|
|
192
|
+
{panelTitle}
|
|
193
|
+
</h2>
|
|
194
|
+
<p className="max-w-[360px] text-body-md text-white/85">
|
|
195
|
+
{panelSubtitle}
|
|
196
|
+
</p>
|
|
197
|
+
</div>
|
|
198
|
+
</>
|
|
199
|
+
)}
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<p className="relative z-10 text-center text-caption-sm text-fg-subtle">
|
|
204
|
+
Ao continuar, você concorda com os Termos de Uso e a Política de
|
|
205
|
+
Privacidade.
|
|
206
|
+
</p>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Painel de marca 100% por tokens (variant "text") — sem asset externo. */
|
|
212
|
+
function BrandPanel({ title, subtitle }: { title: string; subtitle: string }) {
|
|
213
|
+
return (
|
|
214
|
+
<div className="flex h-full flex-col justify-between">
|
|
215
|
+
<div
|
|
216
|
+
aria-hidden
|
|
217
|
+
className="pointer-events-none absolute inset-0 opacity-[0.14] [background:radial-gradient(circle_at_18%_18%,var(--color-fg-on-brand)_0,transparent_42%),radial-gradient(circle_at_88%_8%,var(--color-fg-on-brand)_0,transparent_32%)]"
|
|
218
|
+
/>
|
|
219
|
+
<div
|
|
220
|
+
aria-hidden
|
|
221
|
+
className="pointer-events-none absolute inset-0 bg-gradient-to-br from-transparent via-transparent to-fg-default/25"
|
|
222
|
+
/>
|
|
223
|
+
<div className="relative z-10 flex flex-col gap-gp-lg p-pad-6xl text-fg-on-brand">
|
|
224
|
+
<span className="grid size-[44px] place-items-center rounded-radius-xl bg-fg-on-brand/15 [&>svg]:size-icon-md">
|
|
225
|
+
<Hexagon strokeWidth={1.8} />
|
|
226
|
+
</span>
|
|
227
|
+
<div className="flex flex-col gap-gp-md">
|
|
228
|
+
<h2 className="text-heading-sm font-semibold leading-tight">{title}</h2>
|
|
229
|
+
<p className="max-w-[340px] text-body-md text-fg-on-brand/80">{subtitle}</p>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
<ul className="relative z-10 flex flex-col gap-gp-lg p-pad-6xl text-fg-on-brand">
|
|
233
|
+
{SELLING_POINTS.map(({ icon: Icon, label }) => (
|
|
234
|
+
<li key={label} className="flex items-center gap-gp-md">
|
|
235
|
+
<span className="grid size-comp-lg shrink-0 place-items-center rounded-radius-full bg-fg-on-brand/15 [&>svg]:size-icon-sm">
|
|
236
|
+
<Icon strokeWidth={1.8} />
|
|
237
|
+
</span>
|
|
238
|
+
<span className="text-body-md text-fg-on-brand/90">{label}</span>
|
|
239
|
+
</li>
|
|
240
|
+
))}
|
|
241
|
+
</ul>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export default LoginScreen;
|
package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/consultor-detail-panel.tsx
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { Pencil, UserMinus } from "lucide-react";
|
|
2
|
+
import {
|
|
3
|
+
FloatingPanel,
|
|
4
|
+
FloatingPanelSection,
|
|
5
|
+
FloatingPanelField,
|
|
6
|
+
} from "@/components/ui/FloatingPanel";
|
|
7
|
+
import { Avatar } from "@/components/ui/avatar-ig";
|
|
8
|
+
import { Button } from "@/components/ui/Button/button";
|
|
9
|
+
import { Chip } from "@/components/ui/Chip";
|
|
10
|
+
import {
|
|
11
|
+
GRADUACAO,
|
|
12
|
+
REGIAO,
|
|
13
|
+
formatLongDate,
|
|
14
|
+
formatNum,
|
|
15
|
+
initials,
|
|
16
|
+
levelOf,
|
|
17
|
+
subtreeLabel,
|
|
18
|
+
} from "../../mapa-de-rede-mocks";
|
|
19
|
+
import type { Consultor } from "../../mapa-de-rede.types";
|
|
20
|
+
|
|
21
|
+
export type ConsultorDetailPanelProps = {
|
|
22
|
+
consultor: Consultor | null;
|
|
23
|
+
onClose: () => void;
|
|
24
|
+
onEdit?: (c: Consultor) => void;
|
|
25
|
+
onRemove?: (c: Consultor) => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function ConsultorDetailPanel({
|
|
29
|
+
consultor,
|
|
30
|
+
onClose,
|
|
31
|
+
onEdit,
|
|
32
|
+
onRemove,
|
|
33
|
+
}: ConsultorDetailPanelProps) {
|
|
34
|
+
if (!consultor) return null;
|
|
35
|
+
|
|
36
|
+
const grad = GRADUACAO[consultor.graduacao];
|
|
37
|
+
const diretos = consultor.children?.length ?? 0;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<FloatingPanel
|
|
41
|
+
open={consultor !== null}
|
|
42
|
+
onOpenChange={(open) => {
|
|
43
|
+
if (!open) onClose();
|
|
44
|
+
}}
|
|
45
|
+
side="right"
|
|
46
|
+
size="md"
|
|
47
|
+
resizable
|
|
48
|
+
maximizable
|
|
49
|
+
bodyPadded={false}
|
|
50
|
+
resizableStorageKey="mapa-de-rede.detail-panel.width"
|
|
51
|
+
titleSlot={
|
|
52
|
+
<div className="flex min-w-0 items-center gap-gp-md">
|
|
53
|
+
<Avatar
|
|
54
|
+
size="md"
|
|
55
|
+
colorHex={consultor.avatarColor}
|
|
56
|
+
className="shrink-0 text-caption-md font-bold"
|
|
57
|
+
>
|
|
58
|
+
{initials(consultor.name)}
|
|
59
|
+
</Avatar>
|
|
60
|
+
<div className="flex min-w-0 flex-col gap-gp-2xs">
|
|
61
|
+
<span className="truncate text-body-md font-semibold text-fg-default">
|
|
62
|
+
{consultor.name}
|
|
63
|
+
</span>
|
|
64
|
+
<span className="flex flex-wrap items-center gap-gp-sm">
|
|
65
|
+
<Chip color="neutral" variant="soft" size="sm" shape="pill">
|
|
66
|
+
{levelOf(consultor.id)}
|
|
67
|
+
</Chip>
|
|
68
|
+
<Chip color={grad.color} variant="soft" size="sm" shape="pill">
|
|
69
|
+
{grad.label}
|
|
70
|
+
</Chip>
|
|
71
|
+
{consultor.pro && (
|
|
72
|
+
<Chip color="success" variant="soft" size="sm" shape="pill">
|
|
73
|
+
PRO
|
|
74
|
+
</Chip>
|
|
75
|
+
)}
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
}
|
|
80
|
+
footer={
|
|
81
|
+
<div className="flex items-center gap-gp-md">
|
|
82
|
+
<Button
|
|
83
|
+
variant="outline"
|
|
84
|
+
color="secondary"
|
|
85
|
+
size="md"
|
|
86
|
+
iconLeft={<Pencil />}
|
|
87
|
+
className="flex-1"
|
|
88
|
+
onClick={() => onEdit?.(consultor)}
|
|
89
|
+
>
|
|
90
|
+
Editar
|
|
91
|
+
</Button>
|
|
92
|
+
<Button
|
|
93
|
+
variant="outline"
|
|
94
|
+
color="critical"
|
|
95
|
+
size="icon-md"
|
|
96
|
+
aria-label="Remover da rede"
|
|
97
|
+
onClick={() => onRemove?.(consultor)}
|
|
98
|
+
>
|
|
99
|
+
<UserMinus />
|
|
100
|
+
</Button>
|
|
101
|
+
</div>
|
|
102
|
+
}
|
|
103
|
+
>
|
|
104
|
+
<FloatingPanelSection title="Desempenho próprio">
|
|
105
|
+
<FloatingPanelField
|
|
106
|
+
label="GP próprio"
|
|
107
|
+
value={formatNum(consultor.gpProprio)}
|
|
108
|
+
/>
|
|
109
|
+
<FloatingPanelField
|
|
110
|
+
label="Clientes diretos"
|
|
111
|
+
value={formatNum(consultor.clientes)}
|
|
112
|
+
/>
|
|
113
|
+
<FloatingPanelField
|
|
114
|
+
label="Descendentes diretos"
|
|
115
|
+
value={formatNum(diretos)}
|
|
116
|
+
/>
|
|
117
|
+
</FloatingPanelSection>
|
|
118
|
+
|
|
119
|
+
<FloatingPanelSection title="Subárvore (agregado)">
|
|
120
|
+
{consultor.subtree ? (
|
|
121
|
+
<>
|
|
122
|
+
<FloatingPanelField
|
|
123
|
+
label="Consultores"
|
|
124
|
+
value={formatNum(consultor.subtree.consultores)}
|
|
125
|
+
/>
|
|
126
|
+
<FloatingPanelField
|
|
127
|
+
label="GP da rede"
|
|
128
|
+
value={formatNum(consultor.subtree.gp)}
|
|
129
|
+
/>
|
|
130
|
+
<FloatingPanelField
|
|
131
|
+
label="Clientes da rede"
|
|
132
|
+
value={formatNum(consultor.subtree.clientes)}
|
|
133
|
+
/>
|
|
134
|
+
</>
|
|
135
|
+
) : (
|
|
136
|
+
<p className="px-pad-xl py-pad-md text-body-sm text-fg-muted">
|
|
137
|
+
{subtreeLabel(consultor)}
|
|
138
|
+
</p>
|
|
139
|
+
)}
|
|
140
|
+
</FloatingPanelSection>
|
|
141
|
+
|
|
142
|
+
<FloatingPanelSection title="Contato & atuação">
|
|
143
|
+
<FloatingPanelField label="Email" value={consultor.email} />
|
|
144
|
+
<FloatingPanelField label="Telefone" value={consultor.phone} />
|
|
145
|
+
<FloatingPanelField label="Localização" value={consultor.location} />
|
|
146
|
+
<FloatingPanelField label="Região" value={REGIAO[consultor.regiao]} />
|
|
147
|
+
<FloatingPanelField
|
|
148
|
+
label="Consultor desde"
|
|
149
|
+
value={formatLongDate(consultor.since)}
|
|
150
|
+
/>
|
|
151
|
+
<FloatingPanelField
|
|
152
|
+
label="Última atividade"
|
|
153
|
+
value={consultor.lastActive}
|
|
154
|
+
/>
|
|
155
|
+
</FloatingPanelSection>
|
|
156
|
+
</FloatingPanel>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MapaDeRedeScreen, default } from "./mapa-rede-screen";
|