@contractspec/example.saas-boilerplate 3.7.7 → 3.8.4

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.
Files changed (52) hide show
  1. package/.turbo/turbo-build.log +36 -24
  2. package/CHANGELOG.md +72 -0
  3. package/README.md +1 -0
  4. package/dist/browser/index.js +371 -92
  5. package/dist/browser/saas-boilerplate.feature.js +208 -0
  6. package/dist/browser/ui/SaasDashboard.js +311 -60
  7. package/dist/browser/ui/SaasDashboard.visualizations.js +249 -0
  8. package/dist/browser/ui/index.js +362 -92
  9. package/dist/browser/ui/renderers/index.js +229 -3
  10. package/dist/browser/ui/renderers/project-list.markdown.js +229 -3
  11. package/dist/browser/visualizations/catalog.js +155 -0
  12. package/dist/browser/visualizations/index.js +217 -0
  13. package/dist/browser/visualizations/selectors.js +210 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +371 -92
  16. package/dist/node/index.js +371 -92
  17. package/dist/node/saas-boilerplate.feature.js +208 -0
  18. package/dist/node/ui/SaasDashboard.js +311 -60
  19. package/dist/node/ui/SaasDashboard.visualizations.js +249 -0
  20. package/dist/node/ui/index.js +362 -92
  21. package/dist/node/ui/renderers/index.js +229 -3
  22. package/dist/node/ui/renderers/project-list.markdown.js +229 -3
  23. package/dist/node/visualizations/catalog.js +155 -0
  24. package/dist/node/visualizations/index.js +217 -0
  25. package/dist/node/visualizations/selectors.js +210 -0
  26. package/dist/saas-boilerplate.feature.js +208 -0
  27. package/dist/ui/SaasDashboard.js +311 -60
  28. package/dist/ui/SaasDashboard.visualizations.d.ts +5 -0
  29. package/dist/ui/SaasDashboard.visualizations.js +250 -0
  30. package/dist/ui/index.js +362 -92
  31. package/dist/ui/renderers/index.js +229 -3
  32. package/dist/ui/renderers/project-list.markdown.d.ts +1 -1
  33. package/dist/ui/renderers/project-list.markdown.js +229 -3
  34. package/dist/ui/renderers/project-list.renderer.d.ts +1 -1
  35. package/dist/visualizations/catalog.d.ts +11 -0
  36. package/dist/visualizations/catalog.js +156 -0
  37. package/dist/visualizations/index.d.ts +2 -0
  38. package/dist/visualizations/index.js +218 -0
  39. package/dist/visualizations/selectors.d.ts +8 -0
  40. package/dist/visualizations/selectors.js +211 -0
  41. package/dist/visualizations/selectors.test.d.ts +1 -0
  42. package/package.json +70 -13
  43. package/src/index.ts +1 -0
  44. package/src/saas-boilerplate.feature.ts +3 -0
  45. package/src/ui/SaasDashboard.tsx +8 -0
  46. package/src/ui/SaasDashboard.visualizations.tsx +41 -0
  47. package/src/ui/renderers/project-list.markdown.ts +39 -15
  48. package/src/ui/renderers/project-list.renderer.tsx +1 -1
  49. package/src/visualizations/catalog.ts +153 -0
  50. package/src/visualizations/index.ts +2 -0
  51. package/src/visualizations/selectors.test.ts +25 -0
  52. package/src/visualizations/selectors.ts +85 -0
package/dist/ui/index.js CHANGED
@@ -345,6 +345,213 @@ function createSaasHandlers(db) {
345
345
  getSubscription
346
346
  };
347
347
  }
348
+ // src/visualizations/catalog.ts
349
+ import {
350
+ defineVisualization,
351
+ VisualizationRegistry
352
+ } from "@contractspec/lib.contracts-spec/visualizations";
353
+ var PROJECT_LIST_REF = {
354
+ key: "saas.project.list",
355
+ version: "1.0.0"
356
+ };
357
+ var META = {
358
+ version: "1.0.0",
359
+ domain: "saas",
360
+ stability: "experimental",
361
+ owners: ["@example.saas-boilerplate"],
362
+ tags: ["saas", "visualization", "projects"]
363
+ };
364
+ var SaasProjectUsageVisualization = defineVisualization({
365
+ meta: {
366
+ ...META,
367
+ key: "saas-boilerplate.visualization.project-usage",
368
+ title: "Project Capacity",
369
+ description: "Current project count against the current plan limit.",
370
+ goal: "Show usage against the active plan allowance.",
371
+ context: "SaaS account overview."
372
+ },
373
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
374
+ visualization: {
375
+ kind: "metric",
376
+ measure: "totalProjects",
377
+ comparisonMeasure: "projectLimit",
378
+ measures: [
379
+ {
380
+ key: "totalProjects",
381
+ label: "Projects",
382
+ dataPath: "totalProjects",
383
+ format: "number"
384
+ },
385
+ {
386
+ key: "projectLimit",
387
+ label: "Plan Limit",
388
+ dataPath: "projectLimit",
389
+ format: "number"
390
+ }
391
+ ],
392
+ table: { caption: "Current project count and plan limit." }
393
+ }
394
+ });
395
+ var SaasProjectStatusVisualization = defineVisualization({
396
+ meta: {
397
+ ...META,
398
+ key: "saas-boilerplate.visualization.project-status",
399
+ title: "Project Status",
400
+ description: "Distribution of project states.",
401
+ goal: "Show the mix of active, draft, and archived projects.",
402
+ context: "Project portfolio overview."
403
+ },
404
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
405
+ visualization: {
406
+ kind: "pie",
407
+ nameDimension: "status",
408
+ valueMeasure: "projects",
409
+ dimensions: [
410
+ { key: "status", label: "Status", dataPath: "status", type: "category" }
411
+ ],
412
+ measures: [
413
+ {
414
+ key: "projects",
415
+ label: "Projects",
416
+ dataPath: "projects",
417
+ format: "number"
418
+ }
419
+ ],
420
+ table: { caption: "Project counts by status." }
421
+ }
422
+ });
423
+ var SaasProjectTierVisualization = defineVisualization({
424
+ meta: {
425
+ ...META,
426
+ key: "saas-boilerplate.visualization.project-tiers",
427
+ title: "Tier Comparison",
428
+ description: "Distribution of projects across tiers.",
429
+ goal: "Compare how the current portfolio is distributed by tier.",
430
+ context: "Plan and packaging overview."
431
+ },
432
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
433
+ visualization: {
434
+ kind: "cartesian",
435
+ variant: "bar",
436
+ xDimension: "tier",
437
+ yMeasures: ["projects"],
438
+ dimensions: [
439
+ { key: "tier", label: "Tier", dataPath: "tier", type: "category" }
440
+ ],
441
+ measures: [
442
+ {
443
+ key: "projects",
444
+ label: "Projects",
445
+ dataPath: "projects",
446
+ format: "number",
447
+ color: "#1d4ed8"
448
+ }
449
+ ],
450
+ table: { caption: "Project counts by tier." }
451
+ }
452
+ });
453
+ var SaasProjectActivityVisualization = defineVisualization({
454
+ meta: {
455
+ ...META,
456
+ key: "saas-boilerplate.visualization.project-activity",
457
+ title: "Recent Project Activity",
458
+ description: "Daily project creation activity.",
459
+ goal: "Show recent project activity over time.",
460
+ context: "Project portfolio trend view."
461
+ },
462
+ source: { primary: PROJECT_LIST_REF, resultPath: "data" },
463
+ visualization: {
464
+ kind: "cartesian",
465
+ variant: "line",
466
+ xDimension: "day",
467
+ yMeasures: ["projects"],
468
+ dimensions: [{ key: "day", label: "Day", dataPath: "day", type: "time" }],
469
+ measures: [
470
+ {
471
+ key: "projects",
472
+ label: "Projects",
473
+ dataPath: "projects",
474
+ format: "number",
475
+ color: "#0f766e"
476
+ }
477
+ ],
478
+ table: { caption: "Daily project creation counts." }
479
+ }
480
+ });
481
+ var SaasVisualizationSpecs = [
482
+ SaasProjectUsageVisualization,
483
+ SaasProjectStatusVisualization,
484
+ SaasProjectTierVisualization,
485
+ SaasProjectActivityVisualization
486
+ ];
487
+ var SaasVisualizationRegistry = new VisualizationRegistry([
488
+ ...SaasVisualizationSpecs
489
+ ]);
490
+ var SaasVisualizationRefs = SaasVisualizationSpecs.map((spec) => ({
491
+ key: spec.meta.key,
492
+ version: spec.meta.version
493
+ }));
494
+
495
+ // src/visualizations/selectors.ts
496
+ function toDayKey(value) {
497
+ const date = value instanceof Date ? value : new Date(value);
498
+ return date.toISOString().slice(0, 10);
499
+ }
500
+ function createSaasVisualizationItems(projects, projectLimit = 10) {
501
+ const statusCounts = new Map;
502
+ const tierCounts = new Map;
503
+ const activityCounts = new Map;
504
+ for (const project of projects) {
505
+ statusCounts.set(project.status, (statusCounts.get(project.status) ?? 0) + 1);
506
+ tierCounts.set(project.tier, (tierCounts.get(project.tier) ?? 0) + 1);
507
+ const day = toDayKey(project.createdAt);
508
+ activityCounts.set(day, (activityCounts.get(day) ?? 0) + 1);
509
+ }
510
+ return [
511
+ {
512
+ key: "saas-capacity",
513
+ spec: SaasProjectUsageVisualization,
514
+ data: { data: [{ totalProjects: projects.length, projectLimit }] },
515
+ title: "Project Capacity",
516
+ description: "Current project count compared to the active limit.",
517
+ height: 220
518
+ },
519
+ {
520
+ key: "saas-status",
521
+ spec: SaasProjectStatusVisualization,
522
+ data: {
523
+ data: Array.from(statusCounts.entries()).map(([status, count]) => ({
524
+ status,
525
+ projects: count
526
+ }))
527
+ },
528
+ title: "Project Status",
529
+ description: "Status mix across the current project portfolio.",
530
+ height: 260
531
+ },
532
+ {
533
+ key: "saas-tier",
534
+ spec: SaasProjectTierVisualization,
535
+ data: {
536
+ data: Array.from(tierCounts.entries()).map(([tier, count]) => ({
537
+ tier,
538
+ projects: count
539
+ }))
540
+ },
541
+ title: "Tier Comparison",
542
+ description: "How projects are distributed across tiers."
543
+ },
544
+ {
545
+ key: "saas-activity",
546
+ spec: SaasProjectActivityVisualization,
547
+ data: {
548
+ data: Array.from(activityCounts.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([day, count]) => ({ day, projects: count }))
549
+ },
550
+ title: "Recent Project Activity",
551
+ description: "Daily project creation activity."
552
+ }
553
+ ];
554
+ }
348
555
  // src/ui/hooks/useProjectList.ts
349
556
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
350
557
  import { useCallback, useEffect, useMemo, useState } from "react";
@@ -1041,6 +1248,18 @@ var saasOverlays = [
1041
1248
  saasDemoOverlay
1042
1249
  ];
1043
1250
  // src/ui/renderers/project-list.markdown.ts
1251
+ var PROJECT_TIERS = [
1252
+ "FREE",
1253
+ "PRO",
1254
+ "ENTERPRISE"
1255
+ ];
1256
+ function toVisualizationProject(project, index) {
1257
+ return {
1258
+ status: project.status === "DELETED" ? "ARCHIVED" : project.status,
1259
+ tier: PROJECT_TIERS[index % PROJECT_TIERS.length] ?? "FREE",
1260
+ createdAt: project.createdAt
1261
+ };
1262
+ }
1044
1263
  var projectListMarkdownRenderer = {
1045
1264
  target: "markdown",
1046
1265
  render: async (desc, _ctx) => {
@@ -1051,7 +1270,7 @@ var projectListMarkdownRenderer = {
1051
1270
  limit: 20,
1052
1271
  offset: 0
1053
1272
  });
1054
- const items = data.projects ?? data.items ?? [];
1273
+ const items = data.projects ?? [];
1055
1274
  const lines = [
1056
1275
  "# Projects",
1057
1276
  "",
@@ -1088,6 +1307,7 @@ var saasDashboardMarkdownRenderer = {
1088
1307
  const projects = projectsData.projects ?? [];
1089
1308
  const activeProjects = projects.filter((p) => p.status === "ACTIVE").length;
1090
1309
  const archivedProjects = projects.filter((p) => p.status === "ARCHIVED").length;
1310
+ const visualizations = createSaasVisualizationItems(projects.map(toVisualizationProject), 10);
1091
1311
  const lines = [
1092
1312
  "# SaaS Dashboard",
1093
1313
  "",
@@ -1102,10 +1322,16 @@ var saasDashboardMarkdownRenderer = {
1102
1322
  `| Archived Projects | ${archivedProjects} |`,
1103
1323
  `| Subscription Plan | ${subscription.planName} |`,
1104
1324
  `| Subscription Status | ${subscription.status} |`,
1105
- "",
1106
- "## Projects",
1107
1325
  ""
1108
1326
  ];
1327
+ lines.push("## Visualization Overview");
1328
+ lines.push("");
1329
+ for (const item of visualizations) {
1330
+ lines.push(`- **${item.title}** via \`${item.spec.meta.key}\``);
1331
+ }
1332
+ lines.push("");
1333
+ lines.push("## Projects");
1334
+ lines.push("");
1109
1335
  if (projects.length === 0) {
1110
1336
  lines.push("_No projects yet._");
1111
1337
  } else {
@@ -1299,6 +1525,46 @@ var projectListReactRenderer = {
1299
1525
  return /* @__PURE__ */ jsxDEV4(SaasProjectList, {}, undefined, false, undefined, this);
1300
1526
  }
1301
1527
  };
1528
+ // src/ui/SaasDashboard.visualizations.tsx
1529
+ import {
1530
+ VisualizationCard,
1531
+ VisualizationGrid
1532
+ } from "@contractspec/lib.design-system";
1533
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1534
+ "use client";
1535
+ function SaasVisualizationOverview({
1536
+ projects,
1537
+ projectLimit
1538
+ }) {
1539
+ const items = createSaasVisualizationItems(projects, projectLimit);
1540
+ return /* @__PURE__ */ jsxDEV5("section", {
1541
+ className: "space-y-3",
1542
+ children: [
1543
+ /* @__PURE__ */ jsxDEV5("div", {
1544
+ children: [
1545
+ /* @__PURE__ */ jsxDEV5("h3", {
1546
+ className: "font-semibold text-lg",
1547
+ children: "Portfolio Visualizations"
1548
+ }, undefined, false, undefined, this),
1549
+ /* @__PURE__ */ jsxDEV5("p", {
1550
+ className: "text-muted-foreground text-sm",
1551
+ children: "Contract-backed charts for project mix, capacity, and activity."
1552
+ }, undefined, false, undefined, this)
1553
+ ]
1554
+ }, undefined, true, undefined, this),
1555
+ /* @__PURE__ */ jsxDEV5(VisualizationGrid, {
1556
+ children: items.map((item) => /* @__PURE__ */ jsxDEV5(VisualizationCard, {
1557
+ data: item.data,
1558
+ description: item.description,
1559
+ height: item.height,
1560
+ spec: item.spec,
1561
+ title: item.title
1562
+ }, item.key, false, undefined, this))
1563
+ }, undefined, false, undefined, this)
1564
+ ]
1565
+ }, undefined, true, undefined, this);
1566
+ }
1567
+
1302
1568
  // src/ui/SaasDashboard.tsx
1303
1569
  import {
1304
1570
  Button as Button4,
@@ -1311,7 +1577,7 @@ import {
1311
1577
  StatusChip as StatusChip2
1312
1578
  } from "@contractspec/lib.design-system";
1313
1579
  import { useCallback as useCallback3, useState as useState5 } from "react";
1314
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1580
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1315
1581
  "use client";
1316
1582
  function getStatusTone2(status) {
1317
1583
  switch (status) {
@@ -1346,32 +1612,32 @@ function SaasDashboard() {
1346
1612
  { id: "settings", label: "Settings", icon: "\u2699\uFE0F" }
1347
1613
  ];
1348
1614
  if (loading && !data) {
1349
- return /* @__PURE__ */ jsxDEV5(LoaderBlock2, {
1615
+ return /* @__PURE__ */ jsxDEV6(LoaderBlock2, {
1350
1616
  label: "Loading dashboard..."
1351
1617
  }, undefined, false, undefined, this);
1352
1618
  }
1353
1619
  if (error) {
1354
- return /* @__PURE__ */ jsxDEV5(ErrorState2, {
1620
+ return /* @__PURE__ */ jsxDEV6(ErrorState2, {
1355
1621
  title: "Failed to load dashboard",
1356
1622
  description: error.message,
1357
1623
  onRetry: refetch,
1358
1624
  retryLabel: "Retry"
1359
1625
  }, undefined, false, undefined, this);
1360
1626
  }
1361
- return /* @__PURE__ */ jsxDEV5("div", {
1627
+ return /* @__PURE__ */ jsxDEV6("div", {
1362
1628
  className: "space-y-6",
1363
1629
  children: [
1364
- /* @__PURE__ */ jsxDEV5("div", {
1630
+ /* @__PURE__ */ jsxDEV6("div", {
1365
1631
  className: "flex items-center justify-between",
1366
1632
  children: [
1367
- /* @__PURE__ */ jsxDEV5("h2", {
1633
+ /* @__PURE__ */ jsxDEV6("h2", {
1368
1634
  className: "font-bold text-2xl",
1369
1635
  children: "SaaS Dashboard"
1370
1636
  }, undefined, false, undefined, this),
1371
- activeTab === "projects" && /* @__PURE__ */ jsxDEV5(Button4, {
1637
+ activeTab === "projects" && /* @__PURE__ */ jsxDEV6(Button4, {
1372
1638
  onPress: () => setIsCreateModalOpen(true),
1373
1639
  children: [
1374
- /* @__PURE__ */ jsxDEV5("span", {
1640
+ /* @__PURE__ */ jsxDEV6("span", {
1375
1641
  className: "mr-2",
1376
1642
  children: "+"
1377
1643
  }, undefined, false, undefined, this),
@@ -1380,59 +1646,63 @@ function SaasDashboard() {
1380
1646
  }, undefined, true, undefined, this)
1381
1647
  ]
1382
1648
  }, undefined, true, undefined, this),
1383
- stats && subscription && /* @__PURE__ */ jsxDEV5(StatCardGroup2, {
1649
+ stats && subscription && /* @__PURE__ */ jsxDEV6(StatCardGroup2, {
1384
1650
  children: [
1385
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1651
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1386
1652
  label: "Projects",
1387
1653
  value: stats.total.toString()
1388
1654
  }, undefined, false, undefined, this),
1389
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1655
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1390
1656
  label: "Active",
1391
1657
  value: stats.activeCount.toString()
1392
1658
  }, undefined, false, undefined, this),
1393
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1659
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1394
1660
  label: "Draft",
1395
1661
  value: stats.draftCount.toString()
1396
1662
  }, undefined, false, undefined, this),
1397
- /* @__PURE__ */ jsxDEV5(StatCard2, {
1663
+ /* @__PURE__ */ jsxDEV6(StatCard2, {
1398
1664
  label: "Plan",
1399
1665
  value: subscription.plan,
1400
1666
  hint: subscription.status
1401
1667
  }, undefined, false, undefined, this)
1402
1668
  ]
1403
1669
  }, undefined, true, undefined, this),
1404
- /* @__PURE__ */ jsxDEV5("nav", {
1670
+ data && stats && /* @__PURE__ */ jsxDEV6(SaasVisualizationOverview, {
1671
+ projectLimit: stats.projectLimit,
1672
+ projects: data.items
1673
+ }, undefined, false, undefined, this),
1674
+ /* @__PURE__ */ jsxDEV6("nav", {
1405
1675
  className: "flex gap-1 rounded-lg bg-muted p-1",
1406
1676
  role: "tablist",
1407
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV5("button", {
1677
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV6("button", {
1408
1678
  type: "button",
1409
1679
  role: "tab",
1410
1680
  "aria-selected": activeTab === tab.id,
1411
1681
  onClick: () => setActiveTab(tab.id),
1412
1682
  className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
1413
1683
  children: [
1414
- /* @__PURE__ */ jsxDEV5("span", {
1684
+ /* @__PURE__ */ jsxDEV6("span", {
1415
1685
  children: tab.icon
1416
1686
  }, undefined, false, undefined, this),
1417
1687
  tab.label
1418
1688
  ]
1419
1689
  }, tab.id, true, undefined, this))
1420
1690
  }, undefined, false, undefined, this),
1421
- /* @__PURE__ */ jsxDEV5("div", {
1691
+ /* @__PURE__ */ jsxDEV6("div", {
1422
1692
  className: "min-h-[400px]",
1423
1693
  role: "tabpanel",
1424
1694
  children: [
1425
- activeTab === "projects" && /* @__PURE__ */ jsxDEV5(ProjectsTab, {
1695
+ activeTab === "projects" && /* @__PURE__ */ jsxDEV6(ProjectsTab, {
1426
1696
  data,
1427
1697
  onProjectClick: handleProjectClick
1428
1698
  }, undefined, false, undefined, this),
1429
- activeTab === "billing" && /* @__PURE__ */ jsxDEV5(BillingTab, {
1699
+ activeTab === "billing" && /* @__PURE__ */ jsxDEV6(BillingTab, {
1430
1700
  subscription
1431
1701
  }, undefined, false, undefined, this),
1432
- activeTab === "settings" && /* @__PURE__ */ jsxDEV5(SettingsTab, {}, undefined, false, undefined, this)
1702
+ activeTab === "settings" && /* @__PURE__ */ jsxDEV6(SettingsTab, {}, undefined, false, undefined, this)
1433
1703
  ]
1434
1704
  }, undefined, true, undefined, this),
1435
- /* @__PURE__ */ jsxDEV5(CreateProjectModal, {
1705
+ /* @__PURE__ */ jsxDEV6(CreateProjectModal, {
1436
1706
  isOpen: isCreateModalOpen,
1437
1707
  onClose: () => setIsCreateModalOpen(false),
1438
1708
  onSubmit: async (input) => {
@@ -1440,7 +1710,7 @@ function SaasDashboard() {
1440
1710
  },
1441
1711
  isLoading: mutations.createState.loading
1442
1712
  }, undefined, false, undefined, this),
1443
- /* @__PURE__ */ jsxDEV5(ProjectActionsModal, {
1713
+ /* @__PURE__ */ jsxDEV6(ProjectActionsModal, {
1444
1714
  isOpen: isProjectActionsOpen,
1445
1715
  project: selectedProject,
1446
1716
  onClose: () => {
@@ -1466,34 +1736,34 @@ function SaasDashboard() {
1466
1736
  }
1467
1737
  function ProjectsTab({ data, onProjectClick }) {
1468
1738
  if (!data?.items.length) {
1469
- return /* @__PURE__ */ jsxDEV5(EmptyState2, {
1739
+ return /* @__PURE__ */ jsxDEV6(EmptyState2, {
1470
1740
  title: "No projects yet",
1471
1741
  description: "Create your first project to get started."
1472
1742
  }, undefined, false, undefined, this);
1473
1743
  }
1474
- return /* @__PURE__ */ jsxDEV5("div", {
1744
+ return /* @__PURE__ */ jsxDEV6("div", {
1475
1745
  className: "space-y-4",
1476
- children: /* @__PURE__ */ jsxDEV5("div", {
1746
+ children: /* @__PURE__ */ jsxDEV6("div", {
1477
1747
  className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3",
1478
- children: data.items.map((project) => /* @__PURE__ */ jsxDEV5(EntityCard2, {
1748
+ children: data.items.map((project) => /* @__PURE__ */ jsxDEV6(EntityCard2, {
1479
1749
  cardTitle: project.name,
1480
1750
  cardSubtitle: project.tier,
1481
- meta: /* @__PURE__ */ jsxDEV5("p", {
1751
+ meta: /* @__PURE__ */ jsxDEV6("p", {
1482
1752
  className: "text-muted-foreground text-sm",
1483
1753
  children: project.description
1484
1754
  }, undefined, false, undefined, this),
1485
- chips: /* @__PURE__ */ jsxDEV5(StatusChip2, {
1755
+ chips: /* @__PURE__ */ jsxDEV6(StatusChip2, {
1486
1756
  tone: getStatusTone2(project.status),
1487
1757
  label: project.status
1488
1758
  }, undefined, false, undefined, this),
1489
- footer: /* @__PURE__ */ jsxDEV5("div", {
1759
+ footer: /* @__PURE__ */ jsxDEV6("div", {
1490
1760
  className: "flex w-full items-center justify-between",
1491
1761
  children: [
1492
- /* @__PURE__ */ jsxDEV5("span", {
1762
+ /* @__PURE__ */ jsxDEV6("span", {
1493
1763
  className: "text-muted-foreground text-xs",
1494
1764
  children: project.updatedAt.toLocaleDateString()
1495
1765
  }, undefined, false, undefined, this),
1496
- /* @__PURE__ */ jsxDEV5(Button4, {
1766
+ /* @__PURE__ */ jsxDEV6(Button4, {
1497
1767
  variant: "ghost",
1498
1768
  size: "sm",
1499
1769
  onPress: () => onProjectClick?.(project),
@@ -1508,25 +1778,25 @@ function ProjectsTab({ data, onProjectClick }) {
1508
1778
  function BillingTab({ subscription }) {
1509
1779
  if (!subscription)
1510
1780
  return null;
1511
- return /* @__PURE__ */ jsxDEV5("div", {
1781
+ return /* @__PURE__ */ jsxDEV6("div", {
1512
1782
  className: "space-y-6",
1513
1783
  children: [
1514
- /* @__PURE__ */ jsxDEV5("div", {
1784
+ /* @__PURE__ */ jsxDEV6("div", {
1515
1785
  className: "rounded-xl border border-border bg-card p-6",
1516
1786
  children: [
1517
- /* @__PURE__ */ jsxDEV5("div", {
1787
+ /* @__PURE__ */ jsxDEV6("div", {
1518
1788
  className: "flex items-start justify-between",
1519
1789
  children: [
1520
- /* @__PURE__ */ jsxDEV5("div", {
1790
+ /* @__PURE__ */ jsxDEV6("div", {
1521
1791
  children: [
1522
- /* @__PURE__ */ jsxDEV5("h3", {
1792
+ /* @__PURE__ */ jsxDEV6("h3", {
1523
1793
  className: "font-semibold text-lg",
1524
1794
  children: [
1525
1795
  subscription.plan,
1526
1796
  " Plan"
1527
1797
  ]
1528
1798
  }, undefined, true, undefined, this),
1529
- /* @__PURE__ */ jsxDEV5("p", {
1799
+ /* @__PURE__ */ jsxDEV6("p", {
1530
1800
  className: "text-muted-foreground text-sm",
1531
1801
  children: [
1532
1802
  "Current period:",
@@ -1537,7 +1807,7 @@ function BillingTab({ subscription }) {
1537
1807
  subscription.currentPeriodEnd.toLocaleDateString()
1538
1808
  ]
1539
1809
  }, undefined, true, undefined, this),
1540
- /* @__PURE__ */ jsxDEV5("p", {
1810
+ /* @__PURE__ */ jsxDEV6("p", {
1541
1811
  className: "text-muted-foreground text-sm",
1542
1812
  children: [
1543
1813
  "Billing cycle: ",
@@ -1546,21 +1816,21 @@ function BillingTab({ subscription }) {
1546
1816
  }, undefined, true, undefined, this)
1547
1817
  ]
1548
1818
  }, undefined, true, undefined, this),
1549
- /* @__PURE__ */ jsxDEV5(StatusChip2, {
1819
+ /* @__PURE__ */ jsxDEV6(StatusChip2, {
1550
1820
  tone: "success",
1551
1821
  label: subscription.status
1552
1822
  }, undefined, false, undefined, this)
1553
1823
  ]
1554
1824
  }, undefined, true, undefined, this),
1555
- /* @__PURE__ */ jsxDEV5("div", {
1825
+ /* @__PURE__ */ jsxDEV6("div", {
1556
1826
  className: "mt-4 flex gap-3",
1557
1827
  children: [
1558
- /* @__PURE__ */ jsxDEV5(Button4, {
1828
+ /* @__PURE__ */ jsxDEV6(Button4, {
1559
1829
  variant: "outline",
1560
1830
  onPress: () => alert("Upgrade clicked!"),
1561
1831
  children: "Upgrade Plan"
1562
1832
  }, undefined, false, undefined, this),
1563
- /* @__PURE__ */ jsxDEV5(Button4, {
1833
+ /* @__PURE__ */ jsxDEV6(Button4, {
1564
1834
  variant: "ghost",
1565
1835
  onPress: () => alert("Manage Billing clicked!"),
1566
1836
  children: "Manage Billing"
@@ -1569,9 +1839,9 @@ function BillingTab({ subscription }) {
1569
1839
  }, undefined, true, undefined, this)
1570
1840
  ]
1571
1841
  }, undefined, true, undefined, this),
1572
- subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV5("div", {
1842
+ subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsxDEV6("div", {
1573
1843
  className: "rounded-xl border border-border bg-destructive/10 p-4 text-destructive",
1574
- children: /* @__PURE__ */ jsxDEV5("p", {
1844
+ children: /* @__PURE__ */ jsxDEV6("p", {
1575
1845
  className: "font-medium text-sm",
1576
1846
  children: "\u26A0\uFE0F Your subscription will be cancelled at the end of the current period."
1577
1847
  }, undefined, false, undefined, this)
@@ -1580,26 +1850,26 @@ function BillingTab({ subscription }) {
1580
1850
  }, undefined, true, undefined, this);
1581
1851
  }
1582
1852
  function SettingsTab() {
1583
- return /* @__PURE__ */ jsxDEV5("div", {
1853
+ return /* @__PURE__ */ jsxDEV6("div", {
1584
1854
  className: "space-y-6",
1585
- children: /* @__PURE__ */ jsxDEV5("div", {
1855
+ children: /* @__PURE__ */ jsxDEV6("div", {
1586
1856
  className: "rounded-xl border border-border bg-card p-6",
1587
1857
  children: [
1588
- /* @__PURE__ */ jsxDEV5("h3", {
1858
+ /* @__PURE__ */ jsxDEV6("h3", {
1589
1859
  className: "mb-4 font-semibold text-lg",
1590
1860
  children: "Organization Settings"
1591
1861
  }, undefined, false, undefined, this),
1592
- /* @__PURE__ */ jsxDEV5("div", {
1862
+ /* @__PURE__ */ jsxDEV6("div", {
1593
1863
  className: "space-y-4",
1594
1864
  children: [
1595
- /* @__PURE__ */ jsxDEV5("div", {
1865
+ /* @__PURE__ */ jsxDEV6("div", {
1596
1866
  children: [
1597
- /* @__PURE__ */ jsxDEV5("label", {
1867
+ /* @__PURE__ */ jsxDEV6("label", {
1598
1868
  htmlFor: "org-name",
1599
1869
  className: "font-medium text-sm",
1600
1870
  children: "Organization Name"
1601
1871
  }, undefined, false, undefined, this),
1602
- /* @__PURE__ */ jsxDEV5("input", {
1872
+ /* @__PURE__ */ jsxDEV6("input", {
1603
1873
  id: "org-name",
1604
1874
  type: "text",
1605
1875
  defaultValue: "Demo Organization",
@@ -1607,36 +1877,36 @@ function SettingsTab() {
1607
1877
  }, undefined, false, undefined, this)
1608
1878
  ]
1609
1879
  }, undefined, true, undefined, this),
1610
- /* @__PURE__ */ jsxDEV5("div", {
1880
+ /* @__PURE__ */ jsxDEV6("div", {
1611
1881
  children: [
1612
- /* @__PURE__ */ jsxDEV5("label", {
1882
+ /* @__PURE__ */ jsxDEV6("label", {
1613
1883
  htmlFor: "timezone",
1614
1884
  className: "font-medium text-sm",
1615
1885
  children: "Default Timezone"
1616
1886
  }, undefined, false, undefined, this),
1617
- /* @__PURE__ */ jsxDEV5("select", {
1887
+ /* @__PURE__ */ jsxDEV6("select", {
1618
1888
  id: "timezone",
1619
1889
  className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
1620
1890
  children: [
1621
- /* @__PURE__ */ jsxDEV5("option", {
1891
+ /* @__PURE__ */ jsxDEV6("option", {
1622
1892
  children: "UTC"
1623
1893
  }, undefined, false, undefined, this),
1624
- /* @__PURE__ */ jsxDEV5("option", {
1894
+ /* @__PURE__ */ jsxDEV6("option", {
1625
1895
  children: "America/New_York"
1626
1896
  }, undefined, false, undefined, this),
1627
- /* @__PURE__ */ jsxDEV5("option", {
1897
+ /* @__PURE__ */ jsxDEV6("option", {
1628
1898
  children: "Europe/London"
1629
1899
  }, undefined, false, undefined, this),
1630
- /* @__PURE__ */ jsxDEV5("option", {
1900
+ /* @__PURE__ */ jsxDEV6("option", {
1631
1901
  children: "Asia/Tokyo"
1632
1902
  }, undefined, false, undefined, this)
1633
1903
  ]
1634
1904
  }, undefined, true, undefined, this)
1635
1905
  ]
1636
1906
  }, undefined, true, undefined, this),
1637
- /* @__PURE__ */ jsxDEV5("div", {
1907
+ /* @__PURE__ */ jsxDEV6("div", {
1638
1908
  className: "pt-2",
1639
- children: /* @__PURE__ */ jsxDEV5(Button4, {
1909
+ children: /* @__PURE__ */ jsxDEV6(Button4, {
1640
1910
  onPress: () => alert("Settings saved!"),
1641
1911
  children: "Save Settings"
1642
1912
  }, undefined, false, undefined, this)
@@ -1651,32 +1921,32 @@ function SettingsTab() {
1651
1921
  // src/ui/SaasSettingsPanel.tsx
1652
1922
  import { Button as Button5 } from "@contractspec/lib.design-system";
1653
1923
  import { useState as useState6 } from "react";
1654
- import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
1924
+ import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
1655
1925
  "use client";
1656
1926
  function SaasSettingsPanel() {
1657
1927
  const [orgName, setOrgName] = useState6("Demo Organization");
1658
1928
  const [timezone, setTimezone] = useState6("UTC");
1659
- return /* @__PURE__ */ jsxDEV6("div", {
1929
+ return /* @__PURE__ */ jsxDEV7("div", {
1660
1930
  className: "space-y-6",
1661
1931
  children: [
1662
- /* @__PURE__ */ jsxDEV6("div", {
1932
+ /* @__PURE__ */ jsxDEV7("div", {
1663
1933
  className: "rounded-xl border border-border bg-card p-6",
1664
1934
  children: [
1665
- /* @__PURE__ */ jsxDEV6("h3", {
1935
+ /* @__PURE__ */ jsxDEV7("h3", {
1666
1936
  className: "mb-4 font-semibold text-lg",
1667
1937
  children: "Organization Settings"
1668
1938
  }, undefined, false, undefined, this),
1669
- /* @__PURE__ */ jsxDEV6("div", {
1939
+ /* @__PURE__ */ jsxDEV7("div", {
1670
1940
  className: "space-y-4",
1671
1941
  children: [
1672
- /* @__PURE__ */ jsxDEV6("div", {
1942
+ /* @__PURE__ */ jsxDEV7("div", {
1673
1943
  children: [
1674
- /* @__PURE__ */ jsxDEV6("label", {
1944
+ /* @__PURE__ */ jsxDEV7("label", {
1675
1945
  htmlFor: "setting-org-name",
1676
1946
  className: "block font-medium text-sm",
1677
1947
  children: "Organization Name"
1678
1948
  }, undefined, false, undefined, this),
1679
- /* @__PURE__ */ jsxDEV6("input", {
1949
+ /* @__PURE__ */ jsxDEV7("input", {
1680
1950
  id: "setting-org-name",
1681
1951
  type: "text",
1682
1952
  value: orgName,
@@ -1685,32 +1955,32 @@ function SaasSettingsPanel() {
1685
1955
  }, undefined, false, undefined, this)
1686
1956
  ]
1687
1957
  }, undefined, true, undefined, this),
1688
- /* @__PURE__ */ jsxDEV6("div", {
1958
+ /* @__PURE__ */ jsxDEV7("div", {
1689
1959
  children: [
1690
- /* @__PURE__ */ jsxDEV6("label", {
1960
+ /* @__PURE__ */ jsxDEV7("label", {
1691
1961
  htmlFor: "setting-timezone",
1692
1962
  className: "block font-medium text-sm",
1693
1963
  children: "Default Timezone"
1694
1964
  }, undefined, false, undefined, this),
1695
- /* @__PURE__ */ jsxDEV6("select", {
1965
+ /* @__PURE__ */ jsxDEV7("select", {
1696
1966
  id: "setting-timezone",
1697
1967
  value: timezone,
1698
1968
  onChange: (e) => setTimezone(e.target.value),
1699
1969
  className: "mt-1 block w-full rounded-md border border-input bg-background px-3 py-2",
1700
1970
  children: [
1701
- /* @__PURE__ */ jsxDEV6("option", {
1971
+ /* @__PURE__ */ jsxDEV7("option", {
1702
1972
  value: "UTC",
1703
1973
  children: "UTC"
1704
1974
  }, undefined, false, undefined, this),
1705
- /* @__PURE__ */ jsxDEV6("option", {
1975
+ /* @__PURE__ */ jsxDEV7("option", {
1706
1976
  value: "America/New_York",
1707
1977
  children: "America/New_York"
1708
1978
  }, undefined, false, undefined, this),
1709
- /* @__PURE__ */ jsxDEV6("option", {
1979
+ /* @__PURE__ */ jsxDEV7("option", {
1710
1980
  value: "Europe/London",
1711
1981
  children: "Europe/London"
1712
1982
  }, undefined, false, undefined, this),
1713
- /* @__PURE__ */ jsxDEV6("option", {
1983
+ /* @__PURE__ */ jsxDEV7("option", {
1714
1984
  value: "Asia/Tokyo",
1715
1985
  children: "Asia/Tokyo"
1716
1986
  }, undefined, false, undefined, this)
@@ -1720,37 +1990,37 @@ function SaasSettingsPanel() {
1720
1990
  }, undefined, true, undefined, this)
1721
1991
  ]
1722
1992
  }, undefined, true, undefined, this),
1723
- /* @__PURE__ */ jsxDEV6("div", {
1993
+ /* @__PURE__ */ jsxDEV7("div", {
1724
1994
  className: "mt-6",
1725
- children: /* @__PURE__ */ jsxDEV6(Button5, {
1995
+ children: /* @__PURE__ */ jsxDEV7(Button5, {
1726
1996
  variant: "default",
1727
1997
  children: "Save Changes"
1728
1998
  }, undefined, false, undefined, this)
1729
1999
  }, undefined, false, undefined, this)
1730
2000
  ]
1731
2001
  }, undefined, true, undefined, this),
1732
- /* @__PURE__ */ jsxDEV6("div", {
2002
+ /* @__PURE__ */ jsxDEV7("div", {
1733
2003
  className: "rounded-xl border border-border bg-card p-6",
1734
2004
  children: [
1735
- /* @__PURE__ */ jsxDEV6("h3", {
2005
+ /* @__PURE__ */ jsxDEV7("h3", {
1736
2006
  className: "mb-4 font-semibold text-lg",
1737
2007
  children: "Notifications"
1738
2008
  }, undefined, false, undefined, this),
1739
- /* @__PURE__ */ jsxDEV6("div", {
2009
+ /* @__PURE__ */ jsxDEV7("div", {
1740
2010
  className: "space-y-3",
1741
2011
  children: [
1742
2012
  { label: "Email notifications", defaultChecked: true },
1743
2013
  { label: "Usage alerts", defaultChecked: true },
1744
2014
  { label: "Weekly digest", defaultChecked: false }
1745
- ].map((item) => /* @__PURE__ */ jsxDEV6("label", {
2015
+ ].map((item) => /* @__PURE__ */ jsxDEV7("label", {
1746
2016
  className: "flex items-center gap-3",
1747
2017
  children: [
1748
- /* @__PURE__ */ jsxDEV6("input", {
2018
+ /* @__PURE__ */ jsxDEV7("input", {
1749
2019
  type: "checkbox",
1750
2020
  defaultChecked: item.defaultChecked,
1751
2021
  className: "h-4 w-4 rounded border-input"
1752
2022
  }, undefined, false, undefined, this),
1753
- /* @__PURE__ */ jsxDEV6("span", {
2023
+ /* @__PURE__ */ jsxDEV7("span", {
1754
2024
  className: "text-sm",
1755
2025
  children: item.label
1756
2026
  }, undefined, false, undefined, this)
@@ -1759,26 +2029,26 @@ function SaasSettingsPanel() {
1759
2029
  }, undefined, false, undefined, this)
1760
2030
  ]
1761
2031
  }, undefined, true, undefined, this),
1762
- /* @__PURE__ */ jsxDEV6("div", {
2032
+ /* @__PURE__ */ jsxDEV7("div", {
1763
2033
  className: "rounded-xl border border-red-200 bg-red-50 p-6 dark:border-red-900 dark:bg-red-950/20",
1764
2034
  children: [
1765
- /* @__PURE__ */ jsxDEV6("h3", {
2035
+ /* @__PURE__ */ jsxDEV7("h3", {
1766
2036
  className: "mb-2 font-semibold text-lg text-red-700 dark:text-red-400",
1767
2037
  children: "Danger Zone"
1768
2038
  }, undefined, false, undefined, this),
1769
- /* @__PURE__ */ jsxDEV6("p", {
2039
+ /* @__PURE__ */ jsxDEV7("p", {
1770
2040
  className: "mb-4 text-red-600 text-sm dark:text-red-300",
1771
2041
  children: "These actions are irreversible. Please proceed with caution."
1772
2042
  }, undefined, false, undefined, this),
1773
- /* @__PURE__ */ jsxDEV6("div", {
2043
+ /* @__PURE__ */ jsxDEV7("div", {
1774
2044
  className: "flex gap-3",
1775
2045
  children: [
1776
- /* @__PURE__ */ jsxDEV6(Button5, {
2046
+ /* @__PURE__ */ jsxDEV7(Button5, {
1777
2047
  variant: "secondary",
1778
2048
  size: "sm",
1779
2049
  children: "Export Data"
1780
2050
  }, undefined, false, undefined, this),
1781
- /* @__PURE__ */ jsxDEV6(Button5, {
2051
+ /* @__PURE__ */ jsxDEV7(Button5, {
1782
2052
  variant: "secondary",
1783
2053
  size: "sm",
1784
2054
  children: "Delete Organization"