@rendra-ui/web 2.3.0 → 2.4.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/README.md +83 -60
- package/bin/rendra.mjs +19 -7
- package/dist/base.css +1 -1
- package/dist/{button-DWhICtIG.js → button-C6rjowQi.js} +4 -4
- package/dist/{button-DWhICtIG.js.map → button-C6rjowQi.js.map} +1 -1
- package/dist/chart.js +5 -5
- package/dist/cli/auditar.js +66 -16
- package/dist/cli/auditar.js.map +1 -1
- package/dist/cli/codigos.js +2 -2
- package/dist/cli/executar-auditar.js +634 -0
- package/dist/cli/executar-auditar.js.map +1 -0
- package/dist/cli/help.js +7 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/trocar.js +2 -2
- package/dist/cli/typescript-loader.js +1 -1
- package/dist/{cn-DDZQKUVV.js → cn-DXDpTGsu.js} +2 -2
- package/dist/{cn-DDZQKUVV.js.map → cn-DXDpTGsu.js.map} +1 -1
- package/dist/{components-Cq_PmN4y.js → components-hp7iWioq.js} +21 -4
- package/dist/components-hp7iWioq.js.map +1 -0
- package/dist/components.css +107 -1
- package/dist/document-viewer.js +4 -4
- package/dist/{empty-state-C491qfzf.js → empty-state-CdaDLcsB.js} +50 -30
- package/dist/empty-state-CdaDLcsB.js.map +1 -0
- package/dist/index.js +120 -63
- package/dist/index.js.map +1 -1
- package/dist/{rendra-provider-BRtk5Qa1.js → rendra-provider-7jUgUHzR.js} +2 -2
- package/dist/{rendra-provider-BRtk5Qa1.js.map → rendra-provider-7jUgUHzR.js.map} +1 -1
- package/dist/rich-text-editor.js +3 -3
- package/dist/router-bridge.js +2 -2
- package/dist/tokens.css +11 -1
- package/dist/{tooltip-DsNlnBSY.js → tooltip-bdmbX6vC.js} +3 -3
- package/dist/{tooltip-DsNlnBSY.js.map → tooltip-bdmbX6vC.js.map} +1 -1
- package/dist/types/components/app-shell/app-shell.d.ts +22 -2
- package/dist/types/components/app-shell/shell-context.d.ts +7 -1
- package/dist/types/components/app-shell/types.d.ts +23 -0
- package/dist/types/components/layout/page-header.d.ts +17 -1
- package/dist/types/components/ui/brand-feedback-icon.d.ts +20 -3
- package/dist/types/components/ui/button-group.d.ts +8 -1
- package/dist/types/components/ui/empty-state.d.ts +4 -0
- package/dist/types/components/ui/error-page.d.ts +6 -1
- package/dist/types/components/ui/modal.d.ts +4 -0
- package/dist/types/components/ui/wizard.d.ts +14 -1
- package/dist/types/lib/initials.d.ts +2 -0
- package/dist/{use-breakpoint-C3ivDt2R.js → use-breakpoint-Dyp-0E_c.js} +2 -2
- package/dist/{use-breakpoint-C3ivDt2R.js.map → use-breakpoint-Dyp-0E_c.js.map} +1 -1
- package/dist/widget-grid.js +2 -2
- package/package.json +2 -1
- package/dist/components-Cq_PmN4y.js.map +0 -1
- package/dist/empty-state-C491qfzf.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/*! Rendra Design System v2.
|
|
2
|
-
import { t as cn } from "./cn-
|
|
1
|
+
/*! Rendra Design System v2.4.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
|
|
2
|
+
import { t as cn } from "./cn-DXDpTGsu.js";
|
|
3
|
+
import { CircleCheck, CircleX, Info, TriangleAlert } from "lucide-react";
|
|
3
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
import { createContext, useContext } from "react";
|
|
5
6
|
import { cva } from "class-variance-authority";
|
|
@@ -14,27 +15,39 @@ function useBrand() {
|
|
|
14
15
|
}
|
|
15
16
|
//#endregion
|
|
16
17
|
//#region src/components/ui/brand-feedback-icon.tsx
|
|
18
|
+
var sizes = {
|
|
19
|
+
sm: "size-icon-sm",
|
|
20
|
+
md: "size-icon-md",
|
|
21
|
+
lg: "size-icon-lg",
|
|
22
|
+
xl: "size-12",
|
|
23
|
+
"2xl": "size-16"
|
|
24
|
+
};
|
|
17
25
|
var iconVariants = cva("relative inline-flex shrink-0", {
|
|
18
|
-
variants: {
|
|
19
|
-
|
|
20
|
-
success: "text-success",
|
|
21
|
-
error: "text-destructive",
|
|
22
|
-
warning: "text-warning",
|
|
23
|
-
info: "text-info"
|
|
24
|
-
},
|
|
25
|
-
size: {
|
|
26
|
-
sm: "size-icon-sm",
|
|
27
|
-
md: "size-icon-md",
|
|
28
|
-
lg: "size-icon-lg",
|
|
29
|
-
xl: "size-12",
|
|
30
|
-
"2xl": "size-16"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
defaultVariants: {
|
|
34
|
-
type: "info",
|
|
35
|
-
size: "md"
|
|
36
|
-
}
|
|
26
|
+
variants: { size: sizes },
|
|
27
|
+
defaultVariants: { size: "md" }
|
|
37
28
|
});
|
|
29
|
+
/** Cor do estado (tinge o símbolo e, em statusBadge, o ícone ao lado). */
|
|
30
|
+
var stateText = {
|
|
31
|
+
success: "text-success",
|
|
32
|
+
error: "text-destructive",
|
|
33
|
+
warning: "text-warning",
|
|
34
|
+
info: "text-info"
|
|
35
|
+
};
|
|
36
|
+
/** Ícone Lucide do selo ao lado do símbolo (statusBadge). */
|
|
37
|
+
var badgeIcons = {
|
|
38
|
+
success: CircleCheck,
|
|
39
|
+
error: CircleX,
|
|
40
|
+
warning: TriangleAlert,
|
|
41
|
+
info: Info
|
|
42
|
+
};
|
|
43
|
+
/** Tamanho do ícone ao lado, proporcional ao do símbolo. */
|
|
44
|
+
var badgeIconSize = {
|
|
45
|
+
sm: "size-3",
|
|
46
|
+
md: "size-icon-sm",
|
|
47
|
+
lg: "size-icon-md",
|
|
48
|
+
xl: "size-icon-lg",
|
|
49
|
+
"2xl": "size-icon-lg"
|
|
50
|
+
};
|
|
38
51
|
var badgeTone = {
|
|
39
52
|
success: "bg-success text-success-foreground",
|
|
40
53
|
error: "bg-destructive text-destructive-foreground",
|
|
@@ -100,7 +113,7 @@ function StatusGlyph({ type, animated, ...props }) {
|
|
|
100
113
|
* semântica, com um selo de status para que o significado não dependa só da cor.
|
|
101
114
|
* Cada tipo pode ser substituído por um SVG próprio em brand.config.ts (feedbackIcons).
|
|
102
115
|
*/
|
|
103
|
-
function BrandFeedbackIcon({ type, size, label, animated = false, className }) {
|
|
116
|
+
function BrandFeedbackIcon({ type, size, label, animated = false, symbolTone = "state", statusBadge = false, animation = "pop", className }) {
|
|
104
117
|
const { brand } = useBrand();
|
|
105
118
|
const Custom = brand.feedbackIcons?.[type];
|
|
106
119
|
const Symbol = brand.symbol;
|
|
@@ -108,19 +121,26 @@ function BrandFeedbackIcon({ type, size, label, animated = false, className }) {
|
|
|
108
121
|
role: "img",
|
|
109
122
|
"aria-label": label
|
|
110
123
|
} : { "aria-hidden": true };
|
|
124
|
+
const encaixe = animation === "encaixe";
|
|
125
|
+
const rootTone = symbolTone === "state" ? stateText[type] : void 0;
|
|
126
|
+
const symbolTonal = symbolTone === "brand" && "text-primary-text";
|
|
127
|
+
const symbolAnim = animated && (encaixe ? "animate-encaixe" : "animate-pop");
|
|
128
|
+
const badgeAnim = animated && (encaixe ? "animate-encaixe" : "animate-pop anim-delay-1");
|
|
129
|
+
const BadgeIcon = badgeIcons[type];
|
|
130
|
+
const sideBadge = statusBadge && !Custom;
|
|
111
131
|
return /* @__PURE__ */ jsx("span", {
|
|
112
132
|
"data-slot": "feedback-icon",
|
|
113
133
|
"data-rendra": "BFI-001",
|
|
114
|
-
className: cn(iconVariants({
|
|
115
|
-
type,
|
|
116
|
-
size
|
|
117
|
-
}), animated && type === "error" && "animate-shake", className),
|
|
134
|
+
className: cn(sideBadge ? "relative inline-flex shrink-0 items-center gap-1" : iconVariants({ size }), rootTone, animated && !encaixe && type === "error" && "animate-shake", className),
|
|
118
135
|
...a11y,
|
|
119
|
-
children: Custom ? /* @__PURE__ */ jsx(Custom, { className: cn("size-full",
|
|
120
|
-
|
|
136
|
+
children: Custom ? /* @__PURE__ */ jsx(Custom, { className: cn("size-full", symbolTonal, symbolAnim) }) : sideBadge ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Symbol, { className: cn(sizes[size ?? "md"], symbolTonal, symbolAnim) }), /* @__PURE__ */ jsx(BadgeIcon, {
|
|
137
|
+
"aria-hidden": true,
|
|
138
|
+
className: cn("shrink-0", badgeIconSize[size ?? "md"], stateText[type], badgeAnim)
|
|
139
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Symbol, { className: cn("size-full mask-status-cutout", symbolTonal, symbolAnim) }), /* @__PURE__ */ jsx("span", {
|
|
140
|
+
className: cn("absolute right-0 bottom-0 flex size-1/2 items-center justify-center rounded-full", badgeTone[type], badgeAnim),
|
|
121
141
|
children: /* @__PURE__ */ jsx(StatusGlyph, {
|
|
122
142
|
type,
|
|
123
|
-
animated,
|
|
143
|
+
animated: animated && !encaixe,
|
|
124
144
|
className: "size-full"
|
|
125
145
|
})
|
|
126
146
|
})] })
|
|
@@ -165,4 +185,4 @@ function EmptyState({ title, description, type = "info", actions, size = "defaul
|
|
|
165
185
|
//#endregion
|
|
166
186
|
export { BrandContext as a, useBrand as i, BrandFeedbackIcon as n, feedbackLabels as r, EmptyState as t };
|
|
167
187
|
|
|
168
|
-
//# sourceMappingURL=empty-state-
|
|
188
|
+
//# sourceMappingURL=empty-state-CdaDLcsB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-state-CdaDLcsB.js","names":[],"sources":["../src/brand/brand-context.ts","../src/brand/use-brand.ts","../src/components/ui/brand-feedback-icon.tsx","../src/components/ui/empty-state.tsx"],"sourcesContent":["import { createContext } from 'react'\nimport type { Shape } from '@/lib/shape'\nimport type { BrandConfig, PaletteConfig } from './types'\n\nexport type ColorMode = 'light' | 'dark' | 'system'\n\nexport interface BrandContextValue {\n brand: BrandConfig\n brands: BrandConfig[]\n setBrandId: (id: string) => void\n mode: ColorMode\n resolvedMode: 'light' | 'dark'\n setMode: (mode: ColorMode) => void\n /** Formato do template ativo (fixo por template). */\n shape: Shape\n /** Paleta de cores em uso (por padrão, a do próprio modelo). */\n palette: PaletteConfig\n palettes: PaletteConfig[]\n /** Usa a paleta de outro template; null volta às cores do próprio modelo. */\n setPaletteId: (id: string | null) => void\n /** Logotipo adequado para a sidebar com a paleta atual. */\n sidebarLogoVariant: 'light' | 'dark'\n}\n\nexport const BrandContext = createContext<BrandContextValue | null>(null)\n","import { useContext } from 'react'\nimport { BrandContext } from './brand-context'\n\nexport function useBrand() {\n const ctx = useContext(BrandContext)\n if (!ctx) throw new Error('useBrand precisa estar dentro de <BrandProvider>.')\n return ctx\n}\n","import { cva, type VariantProps } from 'class-variance-authority'\nimport { CircleCheck, CircleX, Info, TriangleAlert, type LucideIcon } from 'lucide-react'\nimport type { SVGProps } from 'react'\nimport { useBrand } from '@/brand/use-brand'\nimport type { FeedbackType } from '@/brand/types'\nimport { cn } from '@/lib/cn'\n\nconst sizes = {\n sm: 'size-icon-sm',\n md: 'size-icon-md',\n lg: 'size-icon-lg',\n xl: 'size-12',\n '2xl': 'size-16',\n} as const\n\nconst iconVariants = cva('relative inline-flex shrink-0', {\n variants: { size: sizes },\n defaultVariants: { size: 'md' },\n})\n\n/** Cor do estado (tinge o símbolo e, em statusBadge, o ícone ao lado). */\nconst stateText: Record<FeedbackType, string> = {\n success: 'text-success',\n error: 'text-destructive',\n warning: 'text-warning',\n info: 'text-info',\n}\n\n/** Ícone Lucide do selo ao lado do símbolo (statusBadge). */\nconst badgeIcons: Record<FeedbackType, LucideIcon> = {\n success: CircleCheck,\n error: CircleX,\n warning: TriangleAlert,\n info: Info,\n}\n\n/** Tamanho do ícone ao lado, proporcional ao do símbolo. */\nconst badgeIconSize: Record<keyof typeof sizes, string> = {\n sm: 'size-3',\n md: 'size-icon-sm',\n lg: 'size-icon-md',\n xl: 'size-icon-lg',\n '2xl': 'size-icon-lg',\n}\n\nconst badgeTone: Record<FeedbackType, string> = {\n success: 'bg-success text-success-foreground',\n error: 'bg-destructive text-destructive-foreground',\n warning: 'bg-warning text-warning-foreground',\n info: 'bg-info text-info-foreground',\n}\n\nexport const feedbackLabels: Record<FeedbackType, string> = {\n success: 'Sucesso',\n error: 'Erro',\n warning: 'Atenção',\n info: 'Informação',\n}\n\n/** Glifos universais de status desenhados em traço, herdando currentColor. */\nfunction StatusGlyph({\n type,\n animated,\n ...props\n}: { type: FeedbackType; animated?: boolean } & SVGProps<SVGSVGElement>) {\n // pathLength=1 normaliza o traço: o desenho anima de 1 a 0 em qualquer glifo.\n const draw = animated\n ? ({ pathLength: 1, strokeDasharray: 1, className: 'animate-draw' } as const)\n : {}\n const common = {\n viewBox: '0 0 12 12',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 2,\n strokeLinecap: 'round' as const,\n strokeLinejoin: 'round' as const,\n 'aria-hidden': true,\n ...props,\n }\n switch (type) {\n case 'success':\n return (\n <svg {...common}>\n <path d=\"M3 6.2 5.1 8.2 9 4\" {...draw} />\n </svg>\n )\n case 'error':\n return (\n <svg {...common}>\n <path d=\"M4 4l4 4M8 4 4 8\" {...draw} />\n </svg>\n )\n case 'warning':\n return (\n <svg {...common}>\n <path d=\"M6 3.2v3.3M6 8.8v0\" {...draw} />\n </svg>\n )\n case 'info':\n return (\n <svg {...common}>\n <path d=\"M6 3.2v0M6 5.5v3.3\" {...draw} />\n </svg>\n )\n }\n}\n\nexport interface BrandFeedbackIconProps extends VariantProps<typeof iconVariants> {\n type: FeedbackType\n /** Texto para leitores de tela. Sem ele o ícone é decorativo (o texto ao lado informa). */\n label?: string\n /**\n * Anima a entrada: o símbolo entra com mola e o glifo se desenha (check se formando,\n * X se riscando). O erro treme ao final. Respeita reduzir movimento.\n * Troque a key do componente para repetir a animação.\n */\n animated?: boolean\n /**\n * Cor do símbolo. `state` (padrão): a cor do estado (verde, vermelho, amarelo, azul).\n * `brand`: a cor primária da marca (`text-primary-text`); o selo de estado mantém a cor do\n * estado, para o significado não depender só da cor.\n */\n symbolTone?: 'state' | 'brand'\n /**\n * `false` (padrão): selo de estado sobreposto ao símbolo. `true`: o ícone do estado\n * (Lucide, na cor do estado) fica ao lado do símbolo, no lugar do selo sobreposto. Com um\n * SVG próprio em `brand.feedbackIcons[type]`, o SVG vence e nenhum selo é desenhado.\n */\n statusBadge?: boolean\n /**\n * Só vale com `animated`. `pop` (padrão): entra com mola, o glifo se desenha e o erro\n * treme. `encaixe`: entra em 240 ms, curva de saída suave, sem quique, sem desenho e sem\n * tremor. Com \"reduzir movimento\" do sistema, nenhuma animação roda.\n */\n animation?: 'pop' | 'encaixe'\n className?: string\n}\n\n/**\n * Ícone de feedback da marca: o símbolo da marca em currentColor, tingido pela cor\n * semântica, com um selo de status para que o significado não dependa só da cor.\n * Cada tipo pode ser substituído por um SVG próprio em brand.config.ts (feedbackIcons).\n */\nexport function BrandFeedbackIcon({\n type,\n size,\n label,\n animated = false,\n symbolTone = 'state',\n statusBadge = false,\n animation = 'pop',\n className,\n}: BrandFeedbackIconProps) {\n const { brand } = useBrand()\n const Custom = brand.feedbackIcons?.[type]\n const Symbol = brand.symbol\n const a11y = label\n ? ({ role: 'img', 'aria-label': label } as const)\n : ({ 'aria-hidden': true } as const)\n const encaixe = animation === 'encaixe'\n // Com `symbolTone=\"state\"` o texto do estado fica na raiz (como sempre); com `brand` sai da raiz.\n const rootTone = symbolTone === 'state' ? stateText[type] : undefined\n const symbolTonal = symbolTone === 'brand' && 'text-primary-text'\n const symbolAnim = animated && (encaixe ? 'animate-encaixe' : 'animate-pop')\n const badgeAnim = animated && (encaixe ? 'animate-encaixe' : 'animate-pop anim-delay-1')\n const BadgeIcon = badgeIcons[type]\n const sideBadge = statusBadge && !Custom\n\n return (\n <span\n data-slot=\"feedback-icon\"\n data-rendra=\"BFI-001\"\n className={cn(\n sideBadge ? 'relative inline-flex shrink-0 items-center gap-1' : iconVariants({ size }),\n rootTone,\n animated && !encaixe && type === 'error' && 'animate-shake',\n className,\n )}\n {...a11y}\n >\n {Custom ? (\n <Custom className={cn('size-full', symbolTonal, symbolAnim)} />\n ) : sideBadge ? (\n <>\n <Symbol className={cn(sizes[size ?? 'md'], symbolTonal, symbolAnim)} />\n <BadgeIcon\n aria-hidden\n className={cn('shrink-0', badgeIconSize[size ?? 'md'], stateText[type], badgeAnim)}\n />\n </>\n ) : (\n <>\n <Symbol className={cn('size-full mask-status-cutout', symbolTonal, symbolAnim)} />\n <span\n className={cn(\n 'absolute right-0 bottom-0 flex size-1/2 items-center justify-center rounded-full',\n badgeTone[type],\n badgeAnim,\n )}\n >\n <StatusGlyph type={type} animated={animated && !encaixe} className=\"size-full\" />\n </span>\n </>\n )}\n </span>\n )\n}\n","import type { ReactNode } from 'react'\nimport type { FeedbackType } from '@/brand/types'\nimport { BrandFeedbackIcon } from '@/components/ui/brand-feedback-icon'\nimport { cn } from '@/lib/cn'\n\nexport interface EmptyStateProps {\n title: string\n description?: ReactNode\n /** Tipo do ícone de feedback da marca. info para \"sem dados\", error para falha. */\n type?: FeedbackType\n /** Ações: no máximo uma principal e uma secundária. */\n actions?: ReactNode\n /** compact: dentro de tabela ou card pequeno. */\n size?: 'default' | 'compact'\n /**\n * Classes extras, que vencem as do componente. Para zerar o respiro vertical (por exemplo,\n * dentro de um card que já tem o seu) use `className=\"py-0 md:py-0\"`.\n */\n className?: string\n}\n\n/** Estado vazio (e de erro) com o ícone de feedback da marca. */\nexport function EmptyState({\n title,\n description,\n type = 'info',\n actions,\n size = 'default',\n className,\n}: EmptyStateProps) {\n return (\n <div\n data-rendra=\"VAZ-001\"\n className={cn(\n 'flex flex-col items-center justify-center gap-4 text-center',\n size === 'compact' ? 'px-4 py-8' : 'px-4 py-12 md:py-16',\n className,\n )}\n >\n <span className=\"relative flex items-center justify-center\">\n <span aria-hidden className=\"absolute size-16 rounded-full bg-gradient-soft\" />\n <BrandFeedbackIcon\n type={type}\n size={size === 'compact' ? 'xl' : '2xl'}\n className=\"relative\"\n />\n </span>\n <div className=\"flex w-full flex-col gap-1\">\n <p className=\"text-base font-semibold\">{title}</p>\n {description && <p className=\"text-sm text-muted-foreground\">{description}</p>}\n </div>\n {actions && <div className=\"flex flex-wrap justify-center gap-3\">{actions}</div>}\n </div>\n )\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/*! Rendra Design System v2.
|
|
2
|
-
import { t as cn } from "./cn-
|
|
3
|
-
import { a as catalogByComponent, c as findComponentsWithoutDefault, d as findPresetCollisions, f as getCatalogEntry, i as assertCatalogIntegrity, l as findDuplicateCodes, n as CATALOG_EXCLUDED_FILES, o as filesMissingCatalogEntry, p as resolveCatalogCode, r as COMPONENT_CODE_PATTERN, s as findComponentsWithMultipleDefaults, t as CATALOG, u as findInvalidFormatCodes } from "./components-
|
|
4
|
-
import { i as usePrefersReducedMotion, n as buttonVariants, r as Spinner, t as Button } from "./button-
|
|
5
|
-
import { a as DropdownMenuContent, c as DropdownMenuLabel, d as DropdownMenuSeparator, f as DropdownMenuSub, h as DropdownMenuTrigger, i as DropdownMenuCheckboxItem, l as DropdownMenuRadioGroup, m as DropdownMenuSubTrigger, n as TooltipProvider, o as DropdownMenuGroup, p as DropdownMenuSubContent, r as DropdownMenu, s as DropdownMenuItem, t as Tooltip, u as DropdownMenuRadioItem } from "./tooltip-
|
|
6
|
-
import { a as BrandContext, i as useBrand, n as BrandFeedbackIcon, r as feedbackLabels, t as EmptyState } from "./empty-state-
|
|
7
|
-
import { a as useRendraNavigate, i as useRendraLink, n as useCurrentPath, r as useRendraBreadcrumbs, t as RendraProvider } from "./rendra-provider-
|
|
8
|
-
import { n as useBreakpoint, t as breakpoints } from "./use-breakpoint-
|
|
1
|
+
/*! Rendra Design System v2.4.0 | MIT | © 2026 Bruno Magalhaes | brunomagalhaes.me */
|
|
2
|
+
import { t as cn } from "./cn-DXDpTGsu.js";
|
|
3
|
+
import { a as catalogByComponent, c as findComponentsWithoutDefault, d as findPresetCollisions, f as getCatalogEntry, i as assertCatalogIntegrity, l as findDuplicateCodes, n as CATALOG_EXCLUDED_FILES, o as filesMissingCatalogEntry, p as resolveCatalogCode, r as COMPONENT_CODE_PATTERN, s as findComponentsWithMultipleDefaults, t as CATALOG, u as findInvalidFormatCodes } from "./components-hp7iWioq.js";
|
|
4
|
+
import { i as usePrefersReducedMotion, n as buttonVariants, r as Spinner, t as Button } from "./button-C6rjowQi.js";
|
|
5
|
+
import { a as DropdownMenuContent, c as DropdownMenuLabel, d as DropdownMenuSeparator, f as DropdownMenuSub, h as DropdownMenuTrigger, i as DropdownMenuCheckboxItem, l as DropdownMenuRadioGroup, m as DropdownMenuSubTrigger, n as TooltipProvider, o as DropdownMenuGroup, p as DropdownMenuSubContent, r as DropdownMenu, s as DropdownMenuItem, t as Tooltip, u as DropdownMenuRadioItem } from "./tooltip-bdmbX6vC.js";
|
|
6
|
+
import { a as BrandContext, i as useBrand, n as BrandFeedbackIcon, r as feedbackLabels, t as EmptyState } from "./empty-state-CdaDLcsB.js";
|
|
7
|
+
import { a as useRendraNavigate, i as useRendraLink, n as useCurrentPath, r as useRendraBreadcrumbs, t as RendraProvider } from "./rendra-provider-7jUgUHzR.js";
|
|
8
|
+
import { n as useBreakpoint, t as breakpoints } from "./use-breakpoint-Dyp-0E_c.js";
|
|
9
9
|
import { ArrowDown, ArrowDownRight, ArrowLeft, ArrowRight, ArrowRightLeft, ArrowUp, ArrowUpRight, Bell, Bot, CalendarDays, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, Clock, Columns3, Download, EllipsisVertical, Eye, EyeOff, FileText, Film, Filter, Globe, GripVertical, Home, ImageIcon, ImagePlus, Info, LayoutTemplate, LogOut, Mail, MapPin, Menu, MessageCircle, MessagesSquare, Mic, Minus, Monitor, Moon, MoreHorizontal, Palette, PanelLeft, Paperclip, Pause, Pencil, Phone, Play, Plus, Reply, RotateCw, Search, Send, SkipForward, Smartphone, Smile, Star, Sun, Trash2, TriangleAlert, UploadCloud, User, VideoIcon, X, XCircle, Zap } from "lucide-react";
|
|
10
10
|
import { Accordion as Accordion$1, Avatar as Avatar$1, Checkbox as Checkbox$1, Collapsible, ContextMenu, Dialog, Label as Label$1, NavigationMenu, Popover as Popover$1, Progress as Progress$1, RadioGroup as RadioGroup$1, Slider as Slider$1, Slot, Switch as Switch$1, Tabs as Tabs$1, VisuallyHidden } from "radix-ui";
|
|
11
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -182,6 +182,13 @@ function Alert({ type, title, description, action, onDismiss, animated = false,
|
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
//#endregion
|
|
185
|
+
//#region src/lib/initials.ts
|
|
186
|
+
/** Iniciais de um nome: primeira letra do primeiro e do último nome, em maiúsculas. */
|
|
187
|
+
function initials(name) {
|
|
188
|
+
const parts = name.trim().split(/\s+/);
|
|
189
|
+
return ((parts[0]?.charAt(0) ?? "") + (parts.length > 1 ? parts[parts.length - 1]?.charAt(0) ?? "" : "")).toUpperCase();
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
185
192
|
//#region src/components/ui/avatar.tsx
|
|
186
193
|
var avatarVariants = cva("relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-avatar bg-primary-soft font-medium text-primary-soft-foreground select-none", {
|
|
187
194
|
variants: { size: {
|
|
@@ -191,10 +198,6 @@ var avatarVariants = cva("relative inline-flex shrink-0 items-center justify-cen
|
|
|
191
198
|
} },
|
|
192
199
|
defaultVariants: { size: "md" }
|
|
193
200
|
});
|
|
194
|
-
function initials(name) {
|
|
195
|
-
const parts = name.trim().split(/\s+/);
|
|
196
|
-
return ((parts[0]?.charAt(0) ?? "") + (parts.length > 1 ? parts[parts.length - 1]?.charAt(0) ?? "" : "")).toUpperCase();
|
|
197
|
-
}
|
|
198
201
|
function Avatar({ name, src, size, className }) {
|
|
199
202
|
return /* @__PURE__ */ jsxs(Avatar$1.Root, {
|
|
200
203
|
"data-rendra": "AVT-001",
|
|
@@ -362,13 +365,17 @@ function BrandLogo({ on = "surface", symbolOnly, size = "md", className }) {
|
|
|
362
365
|
}),
|
|
363
366
|
!symbolOnly && /* @__PURE__ */ jsxs("span", {
|
|
364
367
|
className: "truncate text-lg leading-none tracking-tight",
|
|
365
|
-
children: [
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx("span", {
|
|
370
|
+
className: cn("font-semibold", strong),
|
|
371
|
+
children: first
|
|
372
|
+
}),
|
|
373
|
+
rest.length > 0 && " ",
|
|
374
|
+
rest.length > 0 && /* @__PURE__ */ jsx("span", {
|
|
375
|
+
className: cn("font-normal", soft),
|
|
376
|
+
children: rest.join(" ")
|
|
377
|
+
})
|
|
378
|
+
]
|
|
372
379
|
}),
|
|
373
380
|
symbolOnly && /* @__PURE__ */ jsx("span", {
|
|
374
381
|
className: "sr-only",
|
|
@@ -468,11 +475,11 @@ function Breadcrumb({ items, variant = "responsive", className }) {
|
|
|
468
475
|
* ButtonGroup único: agrupa botões de ação (children) ou funciona como controle
|
|
469
476
|
* segmentado de escolha única (options + value).
|
|
470
477
|
*/
|
|
471
|
-
function ButtonGroup({ children, options, value, onChange, size = "md", fullWidth, className, ...aria }) {
|
|
478
|
+
function ButtonGroup({ children, options, value, onChange, size = "md", fullWidth, orientation = "horizontal", className, ...aria }) {
|
|
472
479
|
if (options) return /* @__PURE__ */ jsx("div", {
|
|
473
480
|
role: "radiogroup",
|
|
474
481
|
"aria-label": aria["aria-label"],
|
|
475
|
-
"data-rendra": "
|
|
482
|
+
"data-rendra": resolveCatalogCode("ButtonGroup", { orientation: "horizontal" }),
|
|
476
483
|
className: cn("inline-flex max-w-full flex-wrap gap-1 rounded-control border bg-muted p-1", fullWidth && "flex w-full", className),
|
|
477
484
|
children: options.map((o) => {
|
|
478
485
|
const active = o.value === value;
|
|
@@ -487,18 +494,34 @@ function ButtonGroup({ children, options, value, onChange, size = "md", fullWidt
|
|
|
487
494
|
}, o.value);
|
|
488
495
|
})
|
|
489
496
|
});
|
|
497
|
+
const vertical = orientation === "vertical";
|
|
498
|
+
const responsive = orientation === "responsive";
|
|
490
499
|
return /* @__PURE__ */ jsx("div", {
|
|
491
500
|
role: "group",
|
|
492
501
|
"aria-label": aria["aria-label"],
|
|
493
|
-
"data-rendra": "
|
|
494
|
-
className: cn("inline-flex max-w-full", "[&>*]:rounded-none [&>*]:shadow-none [&>*:first-child]:rounded-l-control [&>*:
|
|
502
|
+
"data-rendra": resolveCatalogCode("ButtonGroup", { orientation }),
|
|
503
|
+
className: cn("inline-flex max-w-full", "[&>*]:rounded-none [&>*]:shadow-none [&>*:focus-visible]:z-10", orientation === "horizontal" && "[&>*:first-child]:rounded-l-control [&>*:last-child]:rounded-r-control [&>*:not(:first-child)]:-ml-px", vertical && "flex-col [&>*]:w-full [&>*:first-child]:rounded-t-control [&>*:last-child]:rounded-b-control [&>*:not(:first-child)]:-mt-px", responsive && "flex-col md:flex-row [&>*]:w-full md:[&>*]:w-auto [&>*:first-child]:rounded-t-control md:[&>*:first-child]:rounded-l-control md:[&>*:first-child]:rounded-tr-none [&>*:last-child]:rounded-b-control md:[&>*:last-child]:rounded-r-control md:[&>*:last-child]:rounded-bl-none [&>*:not(:first-child)]:-mt-px md:[&>*:not(:first-child)]:mt-0 md:[&>*:not(:first-child)]:-ml-px", fullWidth && (vertical ? "flex w-full" : "flex w-full [&>*]:flex-1"), className),
|
|
495
504
|
children
|
|
496
505
|
});
|
|
497
506
|
}
|
|
498
507
|
//#endregion
|
|
499
508
|
//#region src/components/ui/overlay-shell.tsx
|
|
500
509
|
function OverlayShell({ title, description, icon, children, footer, hideHeader, onRequestClose, bodyClassName }) {
|
|
510
|
+
const closeButton = /* @__PURE__ */ jsx("button", {
|
|
511
|
+
type: "button",
|
|
512
|
+
onClick: onRequestClose,
|
|
513
|
+
"aria-label": "Fechar",
|
|
514
|
+
className: cn("-mt-1 -mr-2 flex size-touch shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors hover:bg-accent hover:text-foreground md:size-control-md", hideHeader && "pointer-events-auto m-0 cursor-default opacity-0 focus-visible:cursor-pointer focus-visible:opacity-100"),
|
|
515
|
+
children: /* @__PURE__ */ jsx(X, {
|
|
516
|
+
className: "size-icon-md",
|
|
517
|
+
"aria-hidden": true
|
|
518
|
+
})
|
|
519
|
+
});
|
|
501
520
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
521
|
+
hideHeader && /* @__PURE__ */ jsx("div", {
|
|
522
|
+
className: "pointer-events-none absolute inset-x-0 top-0 z-10 flex justify-end px-2 pt-safe md:px-4 md:pt-4",
|
|
523
|
+
children: closeButton
|
|
524
|
+
}),
|
|
502
525
|
/* @__PURE__ */ jsxs("header", {
|
|
503
526
|
className: cn("flex shrink-0 items-start gap-3 border-b px-4 pt-safe pb-4 md:px-6 md:pt-6", hideHeader && "sr-only"),
|
|
504
527
|
children: [
|
|
@@ -520,16 +543,7 @@ function OverlayShell({ title, description, icon, children, footer, hideHeader,
|
|
|
520
543
|
children: title
|
|
521
544
|
})]
|
|
522
545
|
}),
|
|
523
|
-
|
|
524
|
-
type: "button",
|
|
525
|
-
onClick: onRequestClose,
|
|
526
|
-
"aria-label": "Fechar",
|
|
527
|
-
className: "-mt-1 -mr-2 flex size-touch shrink-0 cursor-pointer items-center justify-center rounded-item text-muted-foreground transition-colors hover:bg-accent hover:text-foreground md:size-control-md",
|
|
528
|
-
children: /* @__PURE__ */ jsx(X, {
|
|
529
|
-
className: "size-icon-md",
|
|
530
|
-
"aria-hidden": true
|
|
531
|
-
})
|
|
532
|
-
})
|
|
546
|
+
!hideHeader && closeButton
|
|
533
547
|
]
|
|
534
548
|
}),
|
|
535
549
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -554,7 +568,7 @@ var feedback = {
|
|
|
554
568
|
destructive: "error",
|
|
555
569
|
info: "info"
|
|
556
570
|
};
|
|
557
|
-
function Modal({ open, onOpenChange, title, description, type = "confirm", size = "sm", children, confirmLabel = type === "destructive" ? "Excluir" : type === "info" ? "Entendi" : "Confirmar", cancelLabel
|
|
571
|
+
function Modal({ open, onOpenChange, title, description, type = "confirm", size = "sm", children, confirmLabel = type === "destructive" ? "Excluir" : type === "info" ? "Entendi" : "Confirmar", cancelLabel, onConfirm, formId, loading }) {
|
|
558
572
|
const [busy, setBusy] = useState(false);
|
|
559
573
|
const close = () => onOpenChange(false);
|
|
560
574
|
const confirm = async () => {
|
|
@@ -590,8 +604,8 @@ function Modal({ open, onOpenChange, title, description, type = "confirm", size
|
|
|
590
604
|
form: isForm ? formId : void 0,
|
|
591
605
|
onClick: isForm && formId ? void 0 : confirm
|
|
592
606
|
},
|
|
593
|
-
cancel: type === "info" ? void 0 : {
|
|
594
|
-
label: cancelLabel,
|
|
607
|
+
cancel: type === "info" && cancelLabel === void 0 ? void 0 : {
|
|
608
|
+
label: cancelLabel ?? "Cancelar",
|
|
595
609
|
onClick: close
|
|
596
610
|
}
|
|
597
611
|
}),
|
|
@@ -4017,10 +4031,11 @@ var content = {
|
|
|
4017
4031
|
* Tela de erro única (404 e 500), com o ícone de feedback da marca animado.
|
|
4018
4032
|
* Ações seguem a regra 30/70: secundária à esquerda, principal à direita.
|
|
4019
4033
|
*/
|
|
4020
|
-
function ErrorPage({ code, title, description, fullScreen = false }) {
|
|
4034
|
+
function ErrorPage({ code, title, description, fullScreen = false, back = true }) {
|
|
4021
4035
|
const Link = useRendraLink();
|
|
4022
4036
|
const { goBack } = useRendraNavigate();
|
|
4023
4037
|
const c = content[code];
|
|
4038
|
+
const principal = back ? "col-span-7" : "col-span-10";
|
|
4024
4039
|
return /* @__PURE__ */ jsx("div", {
|
|
4025
4040
|
"data-rendra": "ERRO-001",
|
|
4026
4041
|
className: cn("flex w-full items-center justify-center px-4 py-12", fullScreen ? "min-h-dvh" : "min-h-full"),
|
|
@@ -4058,7 +4073,7 @@ function ErrorPage({ code, title, description, fullScreen = false }) {
|
|
|
4058
4073
|
}),
|
|
4059
4074
|
/* @__PURE__ */ jsxs("div", {
|
|
4060
4075
|
className: "grid w-full grid-cols-10 gap-3",
|
|
4061
|
-
children: [/* @__PURE__ */ jsx(Button, {
|
|
4076
|
+
children: [back && /* @__PURE__ */ jsx(Button, {
|
|
4062
4077
|
variant: "outline",
|
|
4063
4078
|
icon: /* @__PURE__ */ jsx(ArrowLeft, {}),
|
|
4064
4079
|
className: "col-span-3",
|
|
@@ -4070,12 +4085,12 @@ function ErrorPage({ code, title, description, fullScreen = false }) {
|
|
|
4070
4085
|
})
|
|
4071
4086
|
}), code === 500 ? /* @__PURE__ */ jsx(Button, {
|
|
4072
4087
|
icon: /* @__PURE__ */ jsx(RotateCw, {}),
|
|
4073
|
-
className:
|
|
4088
|
+
className: principal,
|
|
4074
4089
|
onClick: () => location.reload(),
|
|
4075
4090
|
children: "Tentar de novo"
|
|
4076
4091
|
}) : /* @__PURE__ */ jsx(Button, {
|
|
4077
4092
|
asChild: true,
|
|
4078
|
-
className:
|
|
4093
|
+
className: principal,
|
|
4079
4094
|
children: /* @__PURE__ */ jsxs(Link, {
|
|
4080
4095
|
to: "/",
|
|
4081
4096
|
children: [/* @__PURE__ */ jsx(Home, { "aria-hidden": true }), "Ir para o painel"]
|
|
@@ -8329,7 +8344,7 @@ function Stepper({ steps, current, errors = [], orientation = "horizontal", onSt
|
|
|
8329
8344
|
});
|
|
8330
8345
|
}
|
|
8331
8346
|
/** Cadastro em etapas, com validação por etapa e rodapé Voltar / Avançar. */
|
|
8332
|
-
function Wizard({ steps, children, onValidateStep, onFinish, onCancel, finishLabel = "Concluir", orientation = "horizontal", stickyFooter = false }) {
|
|
8347
|
+
function Wizard({ steps, children, onValidateStep, onFinish, onCancel, cancelLabel = "Cancelar", backLabel = "Voltar", nextLabel = "Avançar", finishLabel = "Concluir", onSkip, skipLabel = "Pular", orientation = "horizontal", stickyFooter = false }) {
|
|
8333
8348
|
const [current, setCurrent] = useState(0);
|
|
8334
8349
|
const [errors, setErrors] = useState([]);
|
|
8335
8350
|
const [busy, setBusy] = useState(false);
|
|
@@ -8348,6 +8363,11 @@ function Wizard({ steps, children, onValidateStep, onFinish, onCancel, finishLab
|
|
|
8348
8363
|
setBusy(false);
|
|
8349
8364
|
}
|
|
8350
8365
|
};
|
|
8366
|
+
const skip = () => {
|
|
8367
|
+
setErrors((e) => e.filter((x) => x !== current));
|
|
8368
|
+
setCurrent((c) => c + 1);
|
|
8369
|
+
onSkip?.();
|
|
8370
|
+
};
|
|
8351
8371
|
const body = /* @__PURE__ */ jsx("div", {
|
|
8352
8372
|
className: "flex min-w-0 flex-col gap-6",
|
|
8353
8373
|
children: children[current]
|
|
@@ -8367,15 +8387,19 @@ function Wizard({ steps, children, onValidateStep, onFinish, onCancel, finishLab
|
|
|
8367
8387
|
children: [body, /* @__PURE__ */ jsx(ActionBar, {
|
|
8368
8388
|
sticky: stickyFooter,
|
|
8369
8389
|
cancel: current > 0 ? {
|
|
8370
|
-
label:
|
|
8390
|
+
label: backLabel,
|
|
8371
8391
|
icon: /* @__PURE__ */ jsx(ArrowLeft, {}),
|
|
8372
8392
|
onClick: () => setCurrent((c) => c - 1)
|
|
8373
8393
|
} : onCancel ? {
|
|
8374
|
-
label:
|
|
8394
|
+
label: cancelLabel,
|
|
8375
8395
|
onClick: onCancel
|
|
8376
8396
|
} : void 0,
|
|
8397
|
+
secondary: onSkip && !last ? [{
|
|
8398
|
+
label: skipLabel,
|
|
8399
|
+
onClick: skip
|
|
8400
|
+
}] : void 0,
|
|
8377
8401
|
primary: {
|
|
8378
|
-
label: last ? finishLabel :
|
|
8402
|
+
label: last ? finishLabel : nextLabel,
|
|
8379
8403
|
icon: last ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(ArrowRight, {}),
|
|
8380
8404
|
onClick: next,
|
|
8381
8405
|
loading: busy,
|
|
@@ -8548,7 +8572,7 @@ function Section({ title, description, actions, level = 2, gap = "4", className,
|
|
|
8548
8572
|
* O título fica no header (com a trilha); aqui ele só é lido por leitores de tela,
|
|
8549
8573
|
* para que cada página tenha um único título principal (h1).
|
|
8550
8574
|
*/
|
|
8551
|
-
function PageHeader({ title, showTitle = false, description, help, breadcrumb, actions, children, className }) {
|
|
8575
|
+
function PageHeader({ title, showTitle = false, description, help, breadcrumb, actions, bodyTitle = false, titleSpace = "reserve", children, className }) {
|
|
8552
8576
|
const shell = useContext(ShellContext);
|
|
8553
8577
|
const setPageHelp = shell?.setPageHelp;
|
|
8554
8578
|
useEffect(() => {
|
|
@@ -8557,18 +8581,24 @@ function PageHeader({ title, showTitle = false, description, help, breadcrumb, a
|
|
|
8557
8581
|
return () => setPageHelp(null);
|
|
8558
8582
|
}, [help, setPageHelp]);
|
|
8559
8583
|
const inlineHelp = help && !shell;
|
|
8584
|
+
const visible = showTitle || bodyTitle || description || actions || breadcrumb || children || inlineHelp;
|
|
8585
|
+
const collapseTitle = titleSpace === "none" && !showTitle && !bodyTitle && !inlineHelp && !description;
|
|
8586
|
+
const titleClass = showTitle || inlineHelp ? "text-2xl md:text-3xl" : bodyTitle ? "text-base md:sr-only" : "sr-only";
|
|
8560
8587
|
return /* @__PURE__ */ jsxs("header", {
|
|
8561
|
-
className: cn("-mb-2 flex min-w-0 flex-col gap-4 md:-mb-4", !
|
|
8588
|
+
className: cn("-mb-2 flex min-w-0 flex-col gap-4 md:-mb-4", !visible && "sr-only", className),
|
|
8562
8589
|
children: [
|
|
8563
8590
|
breadcrumb && /* @__PURE__ */ jsx(Breadcrumb, { items: breadcrumb }),
|
|
8564
8591
|
/* @__PURE__ */ jsxs("div", {
|
|
8565
8592
|
className: "flex min-w-0 flex-col gap-4 md:flex-row md:items-center md:justify-between md:gap-6",
|
|
8566
|
-
children: [/* @__PURE__ */
|
|
8593
|
+
children: [collapseTitle ? /* @__PURE__ */ jsx("h1", {
|
|
8594
|
+
className: "sr-only",
|
|
8595
|
+
children: title
|
|
8596
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
8567
8597
|
className: "flex min-w-0 flex-col gap-1",
|
|
8568
8598
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
8569
8599
|
className: "flex min-w-0 items-center gap-1",
|
|
8570
8600
|
children: [/* @__PURE__ */ jsx("h1", {
|
|
8571
|
-
className:
|
|
8601
|
+
className: titleClass,
|
|
8572
8602
|
children: title
|
|
8573
8603
|
}), inlineHelp && /* @__PURE__ */ jsx(InfoHint, {
|
|
8574
8604
|
title: typeof title === "string" ? title : "Sobre esta tela",
|
|
@@ -9025,14 +9055,18 @@ function LayoutItems() {
|
|
|
9025
9055
|
}
|
|
9026
9056
|
function UserMenu() {
|
|
9027
9057
|
const Link = useRendraLink();
|
|
9028
|
-
const { user, userMenuItems, onLogout } = useShell();
|
|
9058
|
+
const { user, userMenuItems, onLogout, userMenu, workspaces } = useShell();
|
|
9029
9059
|
const { brand, brands, setBrandId, palette, palettes, setPaletteId } = useBrand();
|
|
9060
|
+
const showTheme = userMenu?.theme !== false;
|
|
9061
|
+
const showTemplate = userMenu?.template !== false;
|
|
9062
|
+
const showLayout = userMenu?.layout !== false;
|
|
9063
|
+
const showPreferences = showTheme || showTemplate || showLayout;
|
|
9030
9064
|
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
9031
9065
|
asChild: true,
|
|
9032
9066
|
children: /* @__PURE__ */ jsx(Button, {
|
|
9033
9067
|
variant: "ghost",
|
|
9034
9068
|
iconOnly: true,
|
|
9035
|
-
"aria-label":
|
|
9069
|
+
"aria-label": `${initials(user.name)}, menu de ${user.name}`,
|
|
9036
9070
|
children: /* @__PURE__ */ jsx(Avatar, {
|
|
9037
9071
|
name: user.name,
|
|
9038
9072
|
src: user.avatarUrl
|
|
@@ -9051,6 +9085,18 @@ function UserMenu() {
|
|
|
9051
9085
|
children: user.email
|
|
9052
9086
|
})]
|
|
9053
9087
|
}),
|
|
9088
|
+
workspaces && workspaces.items.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9089
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9090
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: workspaces.label ?? "Espaço" }),
|
|
9091
|
+
/* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
|
|
9092
|
+
value: workspaces.activeId,
|
|
9093
|
+
onValueChange: workspaces.onSelect,
|
|
9094
|
+
children: workspaces.items.map((w) => /* @__PURE__ */ jsx(DropdownMenuRadioItem, {
|
|
9095
|
+
value: w.id,
|
|
9096
|
+
children: w.label
|
|
9097
|
+
}, w.id))
|
|
9098
|
+
})
|
|
9099
|
+
] }),
|
|
9054
9100
|
userMenuItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(DropdownMenuSeparator, {}), userMenuItems.map((item) => {
|
|
9055
9101
|
const Icon = item.icon;
|
|
9056
9102
|
return item.to ? /* @__PURE__ */ jsx(DropdownMenuItem, {
|
|
@@ -9064,9 +9110,9 @@ function UserMenu() {
|
|
|
9064
9110
|
children: [Icon && /* @__PURE__ */ jsx(Icon, { "aria-hidden": true }), item.label]
|
|
9065
9111
|
}, item.label);
|
|
9066
9112
|
})] }),
|
|
9067
|
-
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9068
|
-
/* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Sun, { "aria-hidden": true }), "Tema"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(ModeItems, {}) })] }),
|
|
9069
|
-
/* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Palette, { "aria-hidden": true }), "Template"] }), /* @__PURE__ */ jsxs(DropdownMenuSubContent, { children: [
|
|
9113
|
+
showPreferences && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9114
|
+
showTheme && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Sun, { "aria-hidden": true }), "Tema"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(ModeItems, {}) })] }),
|
|
9115
|
+
showTemplate && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(Palette, { "aria-hidden": true }), "Template"] }), /* @__PURE__ */ jsxs(DropdownMenuSubContent, { children: [
|
|
9070
9116
|
/* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Modelo" }),
|
|
9071
9117
|
/* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
|
|
9072
9118
|
value: brand.id,
|
|
@@ -9096,7 +9142,7 @@ function UserMenu() {
|
|
|
9096
9142
|
}, b.id))
|
|
9097
9143
|
})
|
|
9098
9144
|
] })] }),
|
|
9099
|
-
/* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(LayoutTemplate, { "aria-hidden": true }), "Layout"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(LayoutItems, {}) })] }),
|
|
9145
|
+
showLayout && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [/* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [/* @__PURE__ */ jsx(LayoutTemplate, { "aria-hidden": true }), "Layout"] }), /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: /* @__PURE__ */ jsx(LayoutItems, {}) })] }),
|
|
9100
9146
|
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
9101
9147
|
/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
9102
9148
|
destructive: true,
|
|
@@ -9217,7 +9263,7 @@ function TopNav() {
|
|
|
9217
9263
|
});
|
|
9218
9264
|
}
|
|
9219
9265
|
function Header() {
|
|
9220
|
-
const { layout, setLayout, setMobileNavOpen, setSearchOpen, pageHelp, homeLabel, notifications } = useShell();
|
|
9266
|
+
const { layout, setLayout, setMobileNavOpen, setSearchOpen, pageHelp, homeLabel, notifications, headerLogo } = useShell();
|
|
9221
9267
|
const { brand, resolvedMode } = useBrand();
|
|
9222
9268
|
const Link = useRendraLink();
|
|
9223
9269
|
const crumbs = useRendraBreadcrumbs();
|
|
@@ -9229,12 +9275,16 @@ function Header() {
|
|
|
9229
9275
|
const topbar = layout.navigation === "topbar";
|
|
9230
9276
|
const hasParent = Boolean(crumbs.length >= 2 && crumbs[crumbs.length - 2]?.to);
|
|
9231
9277
|
const menuInFooter = layout.bottomNav || hasParent;
|
|
9232
|
-
const pageTitle = /* @__PURE__ */ jsxs("
|
|
9233
|
-
|
|
9278
|
+
const pageTitle = /* @__PURE__ */ jsxs(Fragment, { children: [headerLogo && /* @__PURE__ */ jsx("span", {
|
|
9279
|
+
"aria-hidden": true,
|
|
9280
|
+
className: "flex min-w-0 flex-1 items-center md:hidden",
|
|
9281
|
+
children: headerLogo
|
|
9282
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
9283
|
+
className: cn("flex min-w-0 flex-1 flex-col justify-center", headerLogo && "max-md:flex-none"),
|
|
9234
9284
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
9235
9285
|
className: "flex min-w-0 items-center gap-1",
|
|
9236
9286
|
children: [/* @__PURE__ */ jsx("p", {
|
|
9237
|
-
className: "truncate text-sm leading-tight font-semibold md:text-base",
|
|
9287
|
+
className: cn("truncate text-sm leading-tight font-semibold md:text-base", headerLogo && "max-md:sr-only"),
|
|
9238
9288
|
children: crumbs[crumbs.length - 1]?.label ?? brand.productName
|
|
9239
9289
|
}), pageHelp && /* @__PURE__ */ jsx(InfoHint, {
|
|
9240
9290
|
title: crumbs[crumbs.length - 1]?.label ?? brand.productName,
|
|
@@ -9243,9 +9293,10 @@ function Header() {
|
|
|
9243
9293
|
})]
|
|
9244
9294
|
}), /* @__PURE__ */ jsx(Breadcrumb, {
|
|
9245
9295
|
items: trail,
|
|
9246
|
-
variant: "trail"
|
|
9296
|
+
variant: "trail",
|
|
9297
|
+
className: cn(headerLogo && "max-md:hidden")
|
|
9247
9298
|
})]
|
|
9248
|
-
});
|
|
9299
|
+
})] });
|
|
9249
9300
|
const collapsed = layout.sidebar === "collapsed";
|
|
9250
9301
|
return /* @__PURE__ */ jsxs("header", {
|
|
9251
9302
|
className: "relative z-30 flex h-header shrink-0 items-center gap-1 border-b bg-card px-2 md:gap-2 md:px-4",
|
|
@@ -9809,7 +9860,7 @@ function BottomNav({ onMenu }) {
|
|
|
9809
9860
|
* Título da aba e meta description (SEO) não são responsabilidade do AppShell: o
|
|
9810
9861
|
* boilerplate (src/app/app-layout.tsx) aplica isso com useRouteMeta, que lê @/config/seo.
|
|
9811
9862
|
*/
|
|
9812
|
-
function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenuItems = [], onLogout, homeLabel = "Início", quickActions = [], notifications, userConfigurable = true, children }) {
|
|
9863
|
+
function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenuItems = [], onLogout, homeLabel = "Início", quickActions = [], notifications, userMenu, workspaces, headerLogo, userConfigurable = true, children }) {
|
|
9813
9864
|
const [userLayout, setUserLayout] = useState(() => userConfigurable ? readUserLayout() : {});
|
|
9814
9865
|
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
|
9815
9866
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
@@ -9872,7 +9923,10 @@ function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenu
|
|
|
9872
9923
|
onLogout,
|
|
9873
9924
|
homeLabel,
|
|
9874
9925
|
quickActions,
|
|
9875
|
-
notifications
|
|
9926
|
+
notifications,
|
|
9927
|
+
userMenu,
|
|
9928
|
+
workspaces,
|
|
9929
|
+
headerLogo
|
|
9876
9930
|
};
|
|
9877
9931
|
}, [
|
|
9878
9932
|
layout,
|
|
@@ -9889,7 +9943,10 @@ function AppShell({ navigation, layout: layoutProp, user = defaultUser, userMenu
|
|
|
9889
9943
|
onLogout,
|
|
9890
9944
|
homeLabel,
|
|
9891
9945
|
quickActions,
|
|
9892
|
-
notifications
|
|
9946
|
+
notifications,
|
|
9947
|
+
userMenu,
|
|
9948
|
+
workspaces,
|
|
9949
|
+
headerLogo
|
|
9893
9950
|
]);
|
|
9894
9951
|
return /* @__PURE__ */ jsx(ShellContext.Provider, {
|
|
9895
9952
|
value,
|