@vadimcomanescu/nadicode-design-system 2.0.9 → 4.0.1
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/.agents/skills/seed/SKILL.md +24 -14
- package/.agents/skills/seed/contract.md +19 -6
- package/.agents/skills/seed/recipes/agency-home.md +5 -5
- package/.agents/skills/seed/recipes/auth.md +3 -3
- package/.agents/skills/seed/recipes/blog-content.md +2 -2
- package/.agents/skills/seed/recipes/company-about.md +3 -3
- package/.agents/skills/seed/recipes/company-contact.md +3 -3
- package/.agents/skills/seed/recipes/digital-workers.md +3 -3
- package/.agents/skills/seed/recipes/marketing-landing.md +8 -8
- package/.agents/skills/seed/recipes/marketing-shell.md +4 -4
- package/.agents/skills/seed/recipes/navigation-shell.md +3 -2
- package/.agents/skills/seed/recipes/pricing.md +4 -4
- package/.agents/skills/seed/recipes/service-detail.md +3 -3
- package/.agents/skills/seed/references/blocks.md +5 -5
- package/.agents/skills/seed/references/components.md +2 -2
- package/.agents/skills/seed/references/nextjs.md +2 -2
- package/README.md +3 -3
- package/contracts/consumer-intent-map.json +1 -2
- package/contracts/release-governance-baseline.json +3 -37
- package/dist/catalog/catalog.d.ts +2220 -0
- package/dist/catalog/catalog.js +1913 -0
- package/dist/catalog/components.d.ts +201 -0
- package/dist/catalog/components.js +407 -0
- package/dist/catalog/types.d.ts +4 -0
- package/dist/catalog/types.js +1 -0
- package/dist/chunk-224KPIOG.js +60 -0
- package/dist/chunk-25BOZMXA.js +169 -0
- package/dist/chunk-32OLQ7FC.js +130 -0
- package/dist/chunk-3JJBJ4VR.js +47 -0
- package/dist/chunk-3U56FXYC.js +30 -0
- package/dist/chunk-4MWKE6F5.js +86 -0
- package/dist/chunk-6HGSU24S.js +94 -0
- package/dist/chunk-7IADIXDV.js +168 -0
- package/dist/chunk-7NS3VFD7.js +86 -0
- package/dist/chunk-ALA6OM7K.js +134 -0
- package/dist/chunk-AN5TW4AL.js +50 -0
- package/dist/chunk-AWZFQQGN.js +167 -0
- package/dist/chunk-BRCBJ3S4.js +42 -0
- package/dist/chunk-BRICSLHJ.js +30 -0
- package/dist/chunk-BYEHHZZN.js +115 -0
- package/dist/chunk-C33GUEDY.js +149 -0
- package/dist/chunk-CUDMDYKE.js +150 -0
- package/dist/chunk-CVTMWSNS.js +145 -0
- package/dist/chunk-DEZXWNYF.js +165 -0
- package/dist/chunk-DNJEVMDY.js +40 -0
- package/dist/chunk-DNJOBML6.js +66 -0
- package/dist/chunk-FTGFOK6T.js +69 -0
- package/dist/{chunk-7A2RXKGH.js → chunk-GJ557DGH.js} +1 -1
- package/dist/chunk-HFBJ6L6O.js +104 -0
- package/dist/chunk-HPTHS7SX.js +52 -0
- package/dist/chunk-K4U67BVG.js +175 -0
- package/dist/chunk-KNR3WB5C.js +147 -0
- package/dist/chunk-KQ7ZC6EM.js +66 -0
- package/dist/chunk-LGW7FVG5.js +83 -0
- package/dist/chunk-LK2L3C7D.js +72 -0
- package/dist/chunk-LP6ZZYOQ.js +36 -0
- package/dist/chunk-LV4P7WVM.js +54 -0
- package/dist/chunk-MGSGCARB.js +164 -0
- package/dist/chunk-N3YFYMNZ.js +73 -0
- package/dist/{chunk-DSMGCFMJ.js → chunk-POFFOUQW.js} +2 -5
- package/dist/chunk-Q5IYBNA7.js +56 -0
- package/dist/chunk-QJCE7NZF.js +85 -0
- package/dist/chunk-QW5II6YK.js +96 -0
- package/dist/chunk-RMGDDOCD.js +138 -0
- package/dist/chunk-RNCX4JIE.js +70 -0
- package/dist/chunk-RWCL5OPX.js +112 -0
- package/dist/chunk-S5OY2B63.js +28 -0
- package/dist/chunk-SIQNG72C.js +257 -0
- package/dist/chunk-SP7NIZFP.js +117 -0
- package/dist/chunk-SWRJWMGG.js +30 -0
- package/dist/chunk-TCQIJ3DO.js +85 -0
- package/dist/chunk-TPJ6JJ2F.js +290 -0
- package/dist/chunk-UR43ANYS.js +159 -0
- package/dist/chunk-VRGPG2YN.js +79 -0
- package/dist/chunk-WSBLCWY7.js +126 -0
- package/dist/chunk-XKKFSFYO.js +93 -0
- package/dist/chunk-XO7TBM47.js +32 -0
- package/dist/chunk-YDYDGG5K.js +132 -0
- package/dist/chunk-YMJOUYMT.js +171 -0
- package/dist/chunk-Z2WION42.js +32 -0
- package/dist/chunk-ZFKSVEYW.js +35 -0
- package/dist/components/blocks/AgentProfileGridBlock.js +8 -86
- package/dist/components/blocks/AgentRunOverviewBlock.js +8 -147
- package/dist/components/blocks/AgentWorkbenchBlock.js +15 -257
- package/dist/components/blocks/AudioVisualizerBlock.js +2 -50
- package/dist/components/blocks/AuthLayout.js +9 -73
- package/dist/components/blocks/BannerBlock.js +8 -66
- package/dist/components/blocks/BarChartBlock.js +5 -47
- package/dist/components/blocks/ChartBlock.js +7 -54
- package/dist/components/blocks/ChartCollectionBlock.js +11 -171
- package/dist/components/blocks/ChatLayout.js +12 -126
- package/dist/components/blocks/CreateBlock.js +9 -104
- package/dist/components/blocks/DataGridBlock.js +9 -117
- package/dist/components/blocks/DirectoryBlock.js +12 -85
- package/dist/components/blocks/FeatureGridBlock.js +6 -56
- package/dist/components/blocks/GalleryBlock.js +6 -69
- package/dist/components/blocks/HeroBlock.js +2 -2
- package/dist/components/blocks/HeroSectionBlock.js +10 -134
- package/dist/components/blocks/IntegrationsBlock.js +13 -94
- package/dist/components/blocks/InteractiveAreaChartBlock.js +5 -290
- package/dist/components/blocks/KanbanDemoBlock.js +8 -145
- package/dist/components/blocks/LogoCloud.js +4 -35
- package/dist/components/blocks/NavUser.js +5 -85
- package/dist/components/blocks/NotFoundBlock.js +8 -32
- package/dist/components/blocks/OnboardingBlock.js +7 -66
- package/dist/components/blocks/SettingsLayout.js +13 -86
- package/dist/components/blocks/SignUpBlock.js +8 -168
- package/dist/components/blocks/SolutionShowcaseBlock.js +11 -112
- package/dist/components/blocks/StatsBlock.js +6 -60
- package/dist/components/blocks/UsageDonutBlock.js +5 -79
- package/dist/components/blocks/WizardBlock.js +12 -93
- package/dist/components/blocks/user/InviteUserModal.js +10 -132
- package/dist/components/page-kits/AccountLockedPageKit.js +3 -40
- package/dist/components/page-kits/AgentsChatPageKit.js +11 -159
- package/dist/components/page-kits/AnalyticsPageKit.js +12 -150
- package/dist/components/page-kits/BlogContentPageKit.js +12 -167
- package/dist/components/page-kits/CheckoutPageKit.js +9 -83
- package/dist/components/page-kits/CompanySuitePageKit.js +9 -96
- package/dist/components/page-kits/DashboardPageKit.js +11 -149
- package/dist/components/page-kits/ErrorPageKit.js +5 -52
- package/dist/components/page-kits/KanbanBoardPageKit.js +7 -169
- package/dist/components/page-kits/LandingPageKit.js +12 -73
- package/dist/components/page-kits/LoginPageKit.js +3 -32
- package/dist/components/page-kits/OnboardingPageKit.js +6 -115
- package/dist/components/page-kits/PricingPageKit.js +12 -138
- package/dist/components/page-kits/ProfileSettingsPageKit.js +10 -164
- package/dist/components/page-kits/RecoveryPageKit.js +3 -42
- package/dist/components/page-kits/ResetPageKit.js +3 -36
- package/dist/components/page-kits/ServiceSuitePageKit.js +11 -176
- package/dist/components/page-kits/SignupPageKit.js +3 -30
- package/dist/components/page-kits/SuccessPageKit.js +4 -30
- package/dist/components/page-kits/TeamSettingsPageKit.js +9 -165
- package/dist/components/page-kits/TwoFactorPageKit.js +4 -28
- package/dist/components/page-kits/VerifyEmailPageKit.js +4 -30
- package/dist/components/page-kits/VoiceAgentsPageKit.js +13 -130
- package/dist/components/ui/AvatarUpload.js +1 -1
- package/dist/components/ui/CheckoutForm.js +5 -70
- package/dist/components/ui/MouseEffect.js +1 -1
- package/eslint-rules/nadicode/config.js +2 -0
- package/eslint-rules/nadicode/data/catalog-names.json +93 -0
- package/eslint-rules/nadicode/index.js +4 -0
- package/eslint-rules/nadicode/rules/__tests__/require-catalog-component.test.js +77 -0
- package/eslint-rules/nadicode/rules/__tests__/require-catalog-import.test.js +111 -0
- package/eslint-rules/nadicode/rules/require-catalog-component.js +79 -0
- package/eslint-rules/nadicode/rules/require-catalog-import.js +59 -0
- package/package.json +15 -358
- package/contracts/block-props-schemas.json +0 -2186
- package/contracts/component-props-schemas.json +0 -8322
- package/contracts/consumer-contract.json +0 -178
- package/contracts/page-kit-props-schemas.json +0 -1894
- package/contracts/public-surface-registry.json +0 -5822
- package/contracts/public-surface-registry.schema.json +0 -219
- package/contracts/spec-manifest.json +0 -46
- package/dist/catalog.json +0 -5221
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LoginBlock } from './chunk-RGE5OQMZ.js';
|
|
2
|
+
import { cn } from './chunk-QYZT24TS.js';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
function SignupPageKit({
|
|
6
|
+
action,
|
|
7
|
+
googleAction,
|
|
8
|
+
error,
|
|
9
|
+
showSocial = true,
|
|
10
|
+
labels,
|
|
11
|
+
signInHref,
|
|
12
|
+
className,
|
|
13
|
+
cardClassName
|
|
14
|
+
}) {
|
|
15
|
+
return /* @__PURE__ */ jsx("section", { className: cn("min-h-dvh w-full bg-background px-4 py-12 md:px-8 md:py-20", className), children: /* @__PURE__ */ jsx("div", { className: "mx-auto flex w-full max-w-5xl items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
16
|
+
LoginBlock,
|
|
17
|
+
{
|
|
18
|
+
className: cn("w-full", cardClassName),
|
|
19
|
+
type: "signup",
|
|
20
|
+
action,
|
|
21
|
+
googleAction,
|
|
22
|
+
error,
|
|
23
|
+
showSocial,
|
|
24
|
+
labels,
|
|
25
|
+
signInHref
|
|
26
|
+
}
|
|
27
|
+
) }) });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { SignupPageKit };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { CrudFormPageKit } from './chunk-KWILREVQ.js';
|
|
2
|
+
import { Typography } from './chunk-N53OMWW2.js';
|
|
3
|
+
import { Heading } from './chunk-WI547C47.js';
|
|
4
|
+
import { Card, CardHeader, CardTitle, CardContent } from './chunk-AH6YSYYT.js';
|
|
5
|
+
import { Button } from './chunk-7KIDDF3I.js';
|
|
6
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
function mapState(state) {
|
|
9
|
+
switch (state) {
|
|
10
|
+
case "validation-error":
|
|
11
|
+
return "validation-error";
|
|
12
|
+
case "saving":
|
|
13
|
+
return "submitting";
|
|
14
|
+
case "active-step":
|
|
15
|
+
return "dirty";
|
|
16
|
+
case "complete":
|
|
17
|
+
return "saved";
|
|
18
|
+
default:
|
|
19
|
+
return "pristine";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function OnboardingPageKit({
|
|
23
|
+
shell,
|
|
24
|
+
steps,
|
|
25
|
+
activeStepIndex,
|
|
26
|
+
state = "default",
|
|
27
|
+
validationMessage,
|
|
28
|
+
onStepChange,
|
|
29
|
+
onComplete,
|
|
30
|
+
canSkipOptionalStep = false,
|
|
31
|
+
onBack,
|
|
32
|
+
onContinueFromComplete,
|
|
33
|
+
completeTitle = "Onboarding complete",
|
|
34
|
+
completeDescription = "Your workspace is ready. Continue to your dashboard.",
|
|
35
|
+
className
|
|
36
|
+
}) {
|
|
37
|
+
const hasSteps = steps.length > 0;
|
|
38
|
+
const boundedStepIndex = hasSteps ? Math.min(Math.max(activeStepIndex, 0), steps.length - 1) : 0;
|
|
39
|
+
const currentStep = hasSteps ? steps[boundedStepIndex] : null;
|
|
40
|
+
const isLastStep = hasSteps ? boundedStepIndex === steps.length - 1 : true;
|
|
41
|
+
if (state === "complete") {
|
|
42
|
+
return /* @__PURE__ */ jsx(
|
|
43
|
+
CrudFormPageKit,
|
|
44
|
+
{
|
|
45
|
+
shell,
|
|
46
|
+
title: "Onboarding",
|
|
47
|
+
description: "Complete state",
|
|
48
|
+
state: "saved",
|
|
49
|
+
sections: [
|
|
50
|
+
{
|
|
51
|
+
id: "complete",
|
|
52
|
+
title: completeTitle,
|
|
53
|
+
content: /* @__PURE__ */ jsxs(Card, { children: [
|
|
54
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: completeTitle }) }),
|
|
55
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-3", children: [
|
|
56
|
+
/* @__PURE__ */ jsx(Typography, { variant: "muted", children: completeDescription }),
|
|
57
|
+
onContinueFromComplete ? /* @__PURE__ */ jsx(Button, { onClick: onContinueFromComplete, children: "Continue" }) : null
|
|
58
|
+
] })
|
|
59
|
+
] })
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
className
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const title = currentStep ? `Onboarding \xB7 ${currentStep.title}` : "Onboarding";
|
|
67
|
+
const description = hasSteps ? `Step ${boundedStepIndex + 1} of ${steps.length}` : "Configure your workspace in a guided flow.";
|
|
68
|
+
return /* @__PURE__ */ jsx(
|
|
69
|
+
CrudFormPageKit,
|
|
70
|
+
{
|
|
71
|
+
shell,
|
|
72
|
+
title,
|
|
73
|
+
description,
|
|
74
|
+
state: mapState(state),
|
|
75
|
+
validationMessage,
|
|
76
|
+
sections: [
|
|
77
|
+
{
|
|
78
|
+
id: currentStep?.id ?? "no-steps",
|
|
79
|
+
title: currentStep?.title ?? "No steps configured",
|
|
80
|
+
description: currentStep?.description,
|
|
81
|
+
optional: currentStep?.optional,
|
|
82
|
+
content: currentStep ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
83
|
+
/* @__PURE__ */ jsx(Heading, { level: 4, children: currentStep.title }),
|
|
84
|
+
currentStep.description ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: currentStep.description }) : null,
|
|
85
|
+
/* @__PURE__ */ jsx("div", { children: currentStep.content })
|
|
86
|
+
] }) : /* @__PURE__ */ jsx(Typography, { variant: "muted", children: "Provide at least one onboarding step." })
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
actions: {
|
|
90
|
+
secondary: onBack ? {
|
|
91
|
+
label: "Back",
|
|
92
|
+
onAction: onBack,
|
|
93
|
+
disabled: boundedStepIndex === 0
|
|
94
|
+
} : void 0,
|
|
95
|
+
tertiary: canSkipOptionalStep && currentStep?.optional ? {
|
|
96
|
+
label: "Skip optional step",
|
|
97
|
+
onAction: () => onComplete?.()
|
|
98
|
+
} : void 0,
|
|
99
|
+
primary: {
|
|
100
|
+
label: isLastStep ? "Complete" : "Next",
|
|
101
|
+
onAction: () => {
|
|
102
|
+
if (!hasSteps || isLastStep) {
|
|
103
|
+
onComplete?.();
|
|
104
|
+
} else {
|
|
105
|
+
onStepChange?.(boundedStepIndex + 1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
className
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { OnboardingPageKit };
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { NavigationShellPageKit } from './chunk-ZKLB5N3Q.js';
|
|
2
|
+
import { ActivityFeedBlock } from './chunk-ZM2NODUK.js';
|
|
3
|
+
import { Typography } from './chunk-N53OMWW2.js';
|
|
4
|
+
import { MetricCard } from './chunk-BRXNGF5W.js';
|
|
5
|
+
import { Heading } from './chunk-WI547C47.js';
|
|
6
|
+
import { DataFreshness } from './chunk-WST5NLLC.js';
|
|
7
|
+
import { ChartCard } from './chunk-HJZRSPWB.js';
|
|
8
|
+
import { Empty, EmptyTitle, EmptyDescription } from './chunk-55HD4L6G.js';
|
|
9
|
+
import { Card, CardHeader, CardTitle, CardContent } from './chunk-AH6YSYYT.js';
|
|
10
|
+
import { cn } from './chunk-QYZT24TS.js';
|
|
11
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
12
|
+
|
|
13
|
+
var EMPTY_KPIS = [];
|
|
14
|
+
var EMPTY_CHART_REGIONS = [];
|
|
15
|
+
var EMPTY_ACTIVITY_ITEMS = [];
|
|
16
|
+
function deriveRegionState(state, data) {
|
|
17
|
+
if (state) {
|
|
18
|
+
return state;
|
|
19
|
+
}
|
|
20
|
+
if (!data || data.length === 0) {
|
|
21
|
+
return "empty";
|
|
22
|
+
}
|
|
23
|
+
return "has-data";
|
|
24
|
+
}
|
|
25
|
+
function renderChartRegion(region) {
|
|
26
|
+
const state = deriveRegionState(region.state, region.data);
|
|
27
|
+
const isPartialDataState = state === "partial-data";
|
|
28
|
+
if (state === "error") {
|
|
29
|
+
return /* @__PURE__ */ jsxs(Card, { className: region.className, children: [
|
|
30
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: region.title }) }),
|
|
31
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
|
|
32
|
+
"div",
|
|
33
|
+
{
|
|
34
|
+
role: "alert",
|
|
35
|
+
className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
|
|
36
|
+
children: region.errorMessage ?? "Chart region is unavailable."
|
|
37
|
+
}
|
|
38
|
+
) })
|
|
39
|
+
] }, region.id);
|
|
40
|
+
}
|
|
41
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", region.className), children: [
|
|
42
|
+
isPartialDataState ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Some chart points are still loading, available data remains visible." }) : null,
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
ChartCard,
|
|
45
|
+
{
|
|
46
|
+
title: region.title,
|
|
47
|
+
description: region.description,
|
|
48
|
+
chart: region.chart,
|
|
49
|
+
data: state === "empty" ? [] : region.data,
|
|
50
|
+
loading: state === "loading",
|
|
51
|
+
emptyTitle: region.emptyTitle ?? "No chart data",
|
|
52
|
+
emptyDescription: region.emptyDescription ?? "This chart will populate once data is available."
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
] }, region.id);
|
|
56
|
+
}
|
|
57
|
+
function DashboardPageKit({
|
|
58
|
+
shell,
|
|
59
|
+
title = "Dashboard overview",
|
|
60
|
+
description = "Track KPI performance, chart health, and recent activity from one route-level contract.",
|
|
61
|
+
kpis = EMPTY_KPIS,
|
|
62
|
+
kpiState,
|
|
63
|
+
chartRegions = EMPTY_CHART_REGIONS,
|
|
64
|
+
activityRegion,
|
|
65
|
+
lastUpdated,
|
|
66
|
+
className
|
|
67
|
+
}) {
|
|
68
|
+
const freshnessTimestamp = lastUpdated ?? /* @__PURE__ */ new Date();
|
|
69
|
+
const resolvedKpiState = deriveRegionState(kpiState, kpis);
|
|
70
|
+
const resolvedActivityState = deriveRegionState(activityRegion?.state, activityRegion?.items ?? EMPTY_ACTIVITY_ITEMS);
|
|
71
|
+
const hasLoadingCharts = chartRegions.some((region) => deriveRegionState(region.state, region.data) === "loading");
|
|
72
|
+
const loadingKpis = Array.from({ length: Math.max(kpis.length, 4) }, (_, index) => /* @__PURE__ */ jsx(
|
|
73
|
+
MetricCard,
|
|
74
|
+
{
|
|
75
|
+
label: `Loading metric ${index + 1}`,
|
|
76
|
+
value: 0,
|
|
77
|
+
loading: true
|
|
78
|
+
},
|
|
79
|
+
`loading-kpi-${index}`
|
|
80
|
+
));
|
|
81
|
+
return /* @__PURE__ */ jsx(NavigationShellPageKit, { ...shell, children: /* @__PURE__ */ jsxs("section", { className: cn("space-y-6", className), children: [
|
|
82
|
+
/* @__PURE__ */ jsxs("header", { className: "flex flex-wrap items-center gap-3", children: [
|
|
83
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
|
|
84
|
+
/* @__PURE__ */ jsx(Heading, { level: 3, children: title }),
|
|
85
|
+
/* @__PURE__ */ jsx(Typography, { variant: "muted", children: description })
|
|
86
|
+
] }),
|
|
87
|
+
/* @__PURE__ */ jsx(DataFreshness, { lastUpdated: freshnessTimestamp, isLive: true })
|
|
88
|
+
] }),
|
|
89
|
+
/* @__PURE__ */ jsxs("section", { "aria-label": "Dashboard KPI region", className: "space-y-3", children: [
|
|
90
|
+
resolvedKpiState === "loading" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
91
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Loading KPI metrics" }),
|
|
92
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4", children: loadingKpis })
|
|
93
|
+
] }) : null,
|
|
94
|
+
resolvedKpiState === "error" ? /* @__PURE__ */ jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
role: "alert",
|
|
98
|
+
className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
|
|
99
|
+
children: "KPI metrics are currently unavailable."
|
|
100
|
+
}
|
|
101
|
+
) : null,
|
|
102
|
+
resolvedKpiState === "empty" ? /* @__PURE__ */ jsxs(Empty, { children: [
|
|
103
|
+
/* @__PURE__ */ jsx(EmptyTitle, { children: "No KPI data" }),
|
|
104
|
+
/* @__PURE__ */ jsx(EmptyDescription, { children: "Connect your data source to populate KPI cards." })
|
|
105
|
+
] }) : null,
|
|
106
|
+
resolvedKpiState === "partial-data" ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Some KPI metrics are temporarily unavailable." }) : null,
|
|
107
|
+
resolvedKpiState === "has-data" || resolvedKpiState === "partial-data" ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4", children: kpis.map((kpi) => /* @__PURE__ */ jsx(
|
|
108
|
+
MetricCard,
|
|
109
|
+
{
|
|
110
|
+
...kpi
|
|
111
|
+
},
|
|
112
|
+
`${kpi.label}-${String(kpi.value)}`
|
|
113
|
+
)) }) : null
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsxs("section", { "aria-label": "Dashboard chart regions", className: "grid gap-4 xl:grid-cols-2", children: [
|
|
116
|
+
hasLoadingCharts ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary xl:col-span-2", children: "Loading chart data" }) : null,
|
|
117
|
+
chartRegions.map((region) => renderChartRegion(region))
|
|
118
|
+
] }),
|
|
119
|
+
/* @__PURE__ */ jsxs("section", { "aria-label": "Dashboard activity region", children: [
|
|
120
|
+
resolvedActivityState === "loading" ? /* @__PURE__ */ jsxs(Card, { children: [
|
|
121
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: activityRegion?.title ?? "Recent activity" }) }),
|
|
122
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Loading activity feed" }) })
|
|
123
|
+
] }) : null,
|
|
124
|
+
resolvedActivityState === "error" ? /* @__PURE__ */ jsx(
|
|
125
|
+
"div",
|
|
126
|
+
{
|
|
127
|
+
role: "alert",
|
|
128
|
+
className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
|
|
129
|
+
children: activityRegion?.errorMessage ?? "Activity feed is unavailable."
|
|
130
|
+
}
|
|
131
|
+
) : null,
|
|
132
|
+
resolvedActivityState === "empty" ? /* @__PURE__ */ jsxs(Empty, { children: [
|
|
133
|
+
/* @__PURE__ */ jsx(EmptyTitle, { children: activityRegion?.emptyTitle ?? "No activity yet" }),
|
|
134
|
+
/* @__PURE__ */ jsx(EmptyDescription, { children: activityRegion?.emptyDescription ?? "Recent updates will appear once your team starts making changes." })
|
|
135
|
+
] }) : null,
|
|
136
|
+
resolvedActivityState === "partial-data" ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Recent activity is partially available while remaining events sync." }) : null,
|
|
137
|
+
resolvedActivityState === "has-data" || resolvedActivityState === "partial-data" ? /* @__PURE__ */ jsx(
|
|
138
|
+
ActivityFeedBlock,
|
|
139
|
+
{
|
|
140
|
+
title: activityRegion?.title ?? "Recent activity",
|
|
141
|
+
activities: activityRegion?.items,
|
|
142
|
+
className: "py-4 md:py-6"
|
|
143
|
+
}
|
|
144
|
+
) : null
|
|
145
|
+
] })
|
|
146
|
+
] }) });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export { DashboardPageKit };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { NavigationShellPageKit } from './chunk-ZKLB5N3Q.js';
|
|
2
|
+
import { Typography } from './chunk-N53OMWW2.js';
|
|
3
|
+
import { NativeSelect } from './chunk-UGV45DH3.js';
|
|
4
|
+
import { Heading } from './chunk-WI547C47.js';
|
|
5
|
+
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from './chunk-PXDHNGTG.js';
|
|
6
|
+
import { ChartCard } from './chunk-HJZRSPWB.js';
|
|
7
|
+
import { Empty, EmptyTitle, EmptyDescription } from './chunk-55HD4L6G.js';
|
|
8
|
+
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from './chunk-AH6YSYYT.js';
|
|
9
|
+
import { Button } from './chunk-7KIDDF3I.js';
|
|
10
|
+
import { Badge } from './chunk-S4JAHKOP.js';
|
|
11
|
+
import { cn } from './chunk-QYZT24TS.js';
|
|
12
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
13
|
+
|
|
14
|
+
function deriveState(state, data) {
|
|
15
|
+
if (state) {
|
|
16
|
+
return state;
|
|
17
|
+
}
|
|
18
|
+
if (!data || data.length === 0) {
|
|
19
|
+
return "empty";
|
|
20
|
+
}
|
|
21
|
+
return "has-data";
|
|
22
|
+
}
|
|
23
|
+
function renderGridRegion(region) {
|
|
24
|
+
const state = deriveState(region.state, region.rows);
|
|
25
|
+
const isFilteredState = state === "filtered";
|
|
26
|
+
const isPartialDataState = state === "partial-data";
|
|
27
|
+
if (state === "loading") {
|
|
28
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
29
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: region.title }) }),
|
|
30
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Loading analytics table" }) })
|
|
31
|
+
] }, region.id);
|
|
32
|
+
}
|
|
33
|
+
if (state === "error") {
|
|
34
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
35
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: region.title }) }),
|
|
36
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
|
|
37
|
+
"div",
|
|
38
|
+
{
|
|
39
|
+
role: "alert",
|
|
40
|
+
className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
|
|
41
|
+
children: region.errorMessage ?? "Analytics table is unavailable."
|
|
42
|
+
}
|
|
43
|
+
) })
|
|
44
|
+
] }, region.id);
|
|
45
|
+
}
|
|
46
|
+
if (state === "empty" || isFilteredState) {
|
|
47
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
48
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
49
|
+
/* @__PURE__ */ jsx(CardTitle, { children: region.title }),
|
|
50
|
+
region.description ? /* @__PURE__ */ jsx(CardDescription, { children: region.description }) : null
|
|
51
|
+
] }),
|
|
52
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Empty, { children: [
|
|
53
|
+
/* @__PURE__ */ jsx(EmptyTitle, { children: region.emptyTitle ?? (isFilteredState ? "No rows for selected filters" : "No matching rows") }),
|
|
54
|
+
/* @__PURE__ */ jsx(EmptyDescription, { children: region.emptyDescription ?? (isFilteredState ? "Broaden filters or date range to restore table results." : "Adjust filters or date range to load analytics records.") })
|
|
55
|
+
] }) })
|
|
56
|
+
] }, region.id);
|
|
57
|
+
}
|
|
58
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
59
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
60
|
+
/* @__PURE__ */ jsx(CardTitle, { children: region.title }),
|
|
61
|
+
region.description ? /* @__PURE__ */ jsx(CardDescription, { children: region.description }) : null
|
|
62
|
+
] }),
|
|
63
|
+
/* @__PURE__ */ jsxs(CardContent, { children: [
|
|
64
|
+
isPartialDataState ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "mb-3 text-text-secondary", children: "Showing available rows while some analytics dimensions are still syncing." }) : null,
|
|
65
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
66
|
+
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: region.columns.map((column) => /* @__PURE__ */ jsx(TableHead, { children: column }, `${region.id}-${column}`)) }) }),
|
|
67
|
+
/* @__PURE__ */ jsx(TableBody, { children: region.rows.map((row, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: region.columns.map((column) => /* @__PURE__ */ jsx(TableCell, { children: row[column] ?? "-" }, `${region.id}-row-${rowIndex}-${column}`)) }, `${region.id}-row-${rowIndex}`)) })
|
|
68
|
+
] }) })
|
|
69
|
+
] })
|
|
70
|
+
] }, region.id);
|
|
71
|
+
}
|
|
72
|
+
function AnalyticsPageKit({
|
|
73
|
+
shell,
|
|
74
|
+
title = "Analytics reporting",
|
|
75
|
+
description = "Coordinate filters, chart surfaces, and tabular analysis from one stable page-kit contract.",
|
|
76
|
+
filters,
|
|
77
|
+
chartRegions,
|
|
78
|
+
gridRegions,
|
|
79
|
+
comparisonLabel,
|
|
80
|
+
onResetFilters,
|
|
81
|
+
className
|
|
82
|
+
}) {
|
|
83
|
+
return /* @__PURE__ */ jsx(NavigationShellPageKit, { ...shell, children: /* @__PURE__ */ jsxs("section", { className: cn("space-y-6", className), children: [
|
|
84
|
+
/* @__PURE__ */ jsxs("header", { className: "space-y-2", children: [
|
|
85
|
+
/* @__PURE__ */ jsx(Heading, { level: 3, children: title }),
|
|
86
|
+
/* @__PURE__ */ jsx(Typography, { variant: "muted", children: description })
|
|
87
|
+
] }),
|
|
88
|
+
/* @__PURE__ */ jsx(
|
|
89
|
+
"section",
|
|
90
|
+
{
|
|
91
|
+
"aria-label": "Analytics filters",
|
|
92
|
+
className: "rounded-lg border border-border/70 bg-surface/60 p-4",
|
|
93
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-4", children: [
|
|
94
|
+
filters.map((filter) => /* @__PURE__ */ jsxs("div", { className: "min-w-[180px] flex-1 space-y-2", children: [
|
|
95
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `analytics-filter-${filter.id}`, className: "text-sm font-medium text-text-primary", children: filter.label }),
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
NativeSelect,
|
|
98
|
+
{
|
|
99
|
+
id: `analytics-filter-${filter.id}`,
|
|
100
|
+
"aria-label": filter.label,
|
|
101
|
+
value: filter.value,
|
|
102
|
+
onChange: (event) => filter.onChange?.(event.target.value),
|
|
103
|
+
children: filter.options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, `${filter.id}-${option.value}`))
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
] }, filter.id)),
|
|
107
|
+
comparisonLabel ? /* @__PURE__ */ jsx(Badge, { variant: "outline", children: comparisonLabel }) : null,
|
|
108
|
+
onResetFilters ? /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: onResetFilters, children: "Reset filters" }) : null
|
|
109
|
+
] })
|
|
110
|
+
}
|
|
111
|
+
),
|
|
112
|
+
/* @__PURE__ */ jsx("section", { className: "grid gap-4 xl:grid-cols-2", children: chartRegions.map((region) => {
|
|
113
|
+
const state = deriveState(region.state, region.data);
|
|
114
|
+
const isFilteredState = state === "filtered";
|
|
115
|
+
const isPartialDataState = state === "partial-data";
|
|
116
|
+
if (state === "error") {
|
|
117
|
+
return /* @__PURE__ */ jsxs(Card, { className: region.className, children: [
|
|
118
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { children: region.title }) }),
|
|
119
|
+
/* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
role: "alert",
|
|
123
|
+
className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
|
|
124
|
+
children: region.errorMessage ?? "Analytics chart is unavailable."
|
|
125
|
+
}
|
|
126
|
+
) })
|
|
127
|
+
] }, region.id);
|
|
128
|
+
}
|
|
129
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
130
|
+
isPartialDataState ? /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-text-secondary", children: "Showing available chart data while some series are still syncing." }) : null,
|
|
131
|
+
/* @__PURE__ */ jsx(
|
|
132
|
+
ChartCard,
|
|
133
|
+
{
|
|
134
|
+
className: region.className,
|
|
135
|
+
title: region.title,
|
|
136
|
+
description: region.description,
|
|
137
|
+
chart: region.chart,
|
|
138
|
+
data: state === "empty" || isFilteredState ? [] : region.data,
|
|
139
|
+
loading: state === "loading",
|
|
140
|
+
emptyTitle: region.emptyTitle ?? (isFilteredState ? "No chart points for selected filters" : "No chart points"),
|
|
141
|
+
emptyDescription: region.emptyDescription ?? "Try adjusting filters to broaden the results."
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
] }, region.id);
|
|
145
|
+
}) }),
|
|
146
|
+
/* @__PURE__ */ jsx("section", { className: "grid gap-4 xl:grid-cols-2", children: gridRegions.map((region) => renderGridRegion(region)) })
|
|
147
|
+
] }) });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { AnalyticsPageKit };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { Typography } from './chunk-N53OMWW2.js';
|
|
2
|
+
import { Heading } from './chunk-WI547C47.js';
|
|
3
|
+
import { KanbanBoard, KanbanColumn, KanbanColumnHeader, KanbanItem, KanbanHandle } from './chunk-TYP2MR3Q.js';
|
|
4
|
+
import { Empty, EmptyDescription } from './chunk-55HD4L6G.js';
|
|
5
|
+
import { Avatar, AvatarFallback } from './chunk-NAAU5IWU.js';
|
|
6
|
+
import { Badge } from './chunk-S4JAHKOP.js';
|
|
7
|
+
import { cn } from './chunk-QYZT24TS.js';
|
|
8
|
+
import { useState } from 'react';
|
|
9
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
10
|
+
|
|
11
|
+
var PRIORITY_STYLES = {
|
|
12
|
+
low: { dot: "bg-success", badge: "bg-success/10 text-success" },
|
|
13
|
+
medium: { dot: "bg-warning", badge: "bg-warning/10 text-warning" },
|
|
14
|
+
high: { dot: "bg-destructive", badge: "bg-destructive/10 text-destructive" },
|
|
15
|
+
critical: { dot: "bg-destructive", badge: "bg-destructive/20 text-destructive" }
|
|
16
|
+
};
|
|
17
|
+
var COLUMN_META = {
|
|
18
|
+
backlog: { label: "Backlog", color: "bg-text-tertiary" },
|
|
19
|
+
todo: { label: "To Do", color: "bg-accent" },
|
|
20
|
+
"in-progress": { label: "In Progress", color: "bg-warning" },
|
|
21
|
+
review: { label: "Review", color: "bg-info" },
|
|
22
|
+
done: { label: "Done", color: "bg-success" }
|
|
23
|
+
};
|
|
24
|
+
var INITIAL_COLUMNS = [
|
|
25
|
+
{
|
|
26
|
+
id: "backlog",
|
|
27
|
+
items: [
|
|
28
|
+
{ id: "t1", title: "Design token audit", description: "Review all semantic tokens for contrast compliance", priority: "medium", assignee: "AK", tags: ["tokens", "a11y"] },
|
|
29
|
+
{ id: "t2", title: "Update changelog", description: "Document v2.0 breaking changes", priority: "low", assignee: "VM", tags: ["docs"] },
|
|
30
|
+
{ id: "t3", title: "Virtualized list primitive", description: "Research windowing for large data tables", priority: "low", assignee: "JR", tags: ["perf", "research"] }
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "todo",
|
|
35
|
+
items: [
|
|
36
|
+
{ id: "t4", title: "Date range picker a11y", description: "Fix keyboard navigation between months", priority: "high", assignee: "AK", tags: ["a11y", "datepicker"] },
|
|
37
|
+
{ id: "t5", title: "Carousel keyboard nav", description: "Arrow keys should cycle through slides", priority: "high", assignee: "VM", tags: ["a11y", "carousel"] }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "in-progress",
|
|
42
|
+
items: [
|
|
43
|
+
{ id: "t6", title: "Kanban board primitive", description: "dnd-kit compound component with glass styling", priority: "critical", assignee: "VM", tags: ["dnd", "new"] },
|
|
44
|
+
{ id: "t7", title: "Bloom theme spring tuning", description: "Adjust bloom spring presets for more playful overshoot", priority: "medium", assignee: "JR", tags: ["motion", "bloom"] }
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "review",
|
|
49
|
+
items: [
|
|
50
|
+
{ id: "t8", title: "Form wizard validation", description: "Zod schema per step with async validation support", priority: "high", assignee: "AK", tags: ["forms", "zod"] }
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "done",
|
|
55
|
+
items: [
|
|
56
|
+
{ id: "t9", title: "Dark mode polish", description: "Fix washed-out glass panels in dark mode", priority: "medium", assignee: "VM", tags: ["theme", "glass"] },
|
|
57
|
+
{ id: "t10", title: "Icon animation system", description: "77 animated icons with imperative handles", priority: "low", assignee: "JR", tags: ["icons", "motion"] }
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
function TaskCard({ task, compact = false }) {
|
|
62
|
+
const ps = PRIORITY_STYLES[task.priority];
|
|
63
|
+
const content = /* @__PURE__ */ jsxs("div", { className: cn("min-w-0 flex-1 space-y-2", compact && "w-[260px] p-3"), children: [
|
|
64
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
65
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-text-primary leading-snug", children: task.title }),
|
|
66
|
+
!compact && /* @__PURE__ */ jsx("div", { className: cn("mt-0.5 h-2 w-2 shrink-0 rounded-full", ps.dot) })
|
|
67
|
+
] }),
|
|
68
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary line-clamp-2", children: task.description }),
|
|
69
|
+
!compact && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: task.tags.map((tag) => /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "rounded bg-surface-secondary px-1.5 text-[10px] font-medium text-text-tertiary", children: tag }, tag)) }),
|
|
70
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pt-1", children: [
|
|
71
|
+
/* @__PURE__ */ jsx(Badge, { variant: "outline", className: cn("rounded px-1.5 text-[10px] uppercase tracking-wider", ps.badge), children: task.priority }),
|
|
72
|
+
!compact && /* @__PURE__ */ jsx(Avatar, { className: "h-5 w-5 text-[10px]", children: /* @__PURE__ */ jsx(AvatarFallback, { children: task.assignee }) })
|
|
73
|
+
] })
|
|
74
|
+
] });
|
|
75
|
+
if (compact) return content;
|
|
76
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
77
|
+
/* @__PURE__ */ jsx(KanbanHandle, { "aria-label": `Move ${task.title}` }),
|
|
78
|
+
content
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
var getTaskId = (task) => task.id;
|
|
82
|
+
var getTaskLabel = (task) => task.title;
|
|
83
|
+
var renderOverlay = (task) => /* @__PURE__ */ jsx(TaskCard, { task, compact: true });
|
|
84
|
+
function KanbanDemoBlock({ className }) {
|
|
85
|
+
const [columns, setColumns] = useState(INITIAL_COLUMNS);
|
|
86
|
+
const [moveLog, setMoveLog] = useState([]);
|
|
87
|
+
function handleMove(next, meta) {
|
|
88
|
+
setColumns([...next]);
|
|
89
|
+
const entry = `${meta.item.title}: ${meta.fromColumnId} \u2192 ${meta.toColumnId} (pos ${meta.toIndex})`;
|
|
90
|
+
setMoveLog((prev) => [entry, ...prev].slice(0, 10));
|
|
91
|
+
}
|
|
92
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-6", className), children: [
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
94
|
+
/* @__PURE__ */ jsx(Heading, { level: 1, size: "display", children: "Kanban Board" }),
|
|
95
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", className: "mt-1 text-text-secondary", children: "Drag tasks between columns. Uses handle-only drag with keyboard support." })
|
|
96
|
+
] }),
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
KanbanBoard,
|
|
99
|
+
{
|
|
100
|
+
value: columns,
|
|
101
|
+
onValueChange: handleMove,
|
|
102
|
+
getItemId: getTaskId,
|
|
103
|
+
getItemLabel: getTaskLabel,
|
|
104
|
+
renderOverlay,
|
|
105
|
+
className: "pb-4",
|
|
106
|
+
children: columns.map((col) => {
|
|
107
|
+
const colMeta = COLUMN_META[col.id] ?? { label: col.id, color: "bg-accent" };
|
|
108
|
+
return /* @__PURE__ */ jsxs(
|
|
109
|
+
KanbanColumn,
|
|
110
|
+
{
|
|
111
|
+
id: col.id,
|
|
112
|
+
items: col.items,
|
|
113
|
+
"aria-label": colMeta.label,
|
|
114
|
+
className: "w-[280px] shrink-0",
|
|
115
|
+
children: [
|
|
116
|
+
/* @__PURE__ */ jsxs(KanbanColumnHeader, { children: [
|
|
117
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
118
|
+
/* @__PURE__ */ jsx("div", { className: cn("h-2 w-2 rounded-full", colMeta.color) }),
|
|
119
|
+
/* @__PURE__ */ jsx("span", { children: colMeta.label })
|
|
120
|
+
] }),
|
|
121
|
+
/* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-xs tabular-nums", children: col.items.length })
|
|
122
|
+
] }),
|
|
123
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: col.items.map((task) => /* @__PURE__ */ jsx(KanbanItem, { value: task, children: /* @__PURE__ */ jsx(TaskCard, { task }) }, task.id)) }),
|
|
124
|
+
col.items.length === 0 && /* @__PURE__ */ jsx(Empty, { className: "h-24 p-4", children: /* @__PURE__ */ jsx(EmptyDescription, { className: "text-xs", children: "Drop tasks here" }) })
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
col.id
|
|
128
|
+
);
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
),
|
|
132
|
+
moveLog.length > 0 && /* @__PURE__ */ jsxs("div", { className: "glass-panel rounded-lg p-4", children: [
|
|
133
|
+
/* @__PURE__ */ jsx(Heading, { level: 4, size: "title", className: "mb-2", children: "Move Log" }),
|
|
134
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1 font-mono text-xs text-text-secondary", children: moveLog.map((entry, i) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
135
|
+
/* @__PURE__ */ jsxs("span", { className: "text-text-tertiary", children: [
|
|
136
|
+
moveLog.length - i,
|
|
137
|
+
"."
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ jsx("span", { children: entry })
|
|
140
|
+
] }, i)) })
|
|
141
|
+
] })
|
|
142
|
+
] });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export { KanbanDemoBlock };
|