@ramme-io/create-app 1.2.1 → 1.2.5

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 (102) hide show
  1. package/package.json +9 -15
  2. package/template/package.json +41 -0
  3. package/template/pkg.json +9 -7
  4. package/template/src/App.tsx +72 -31
  5. package/template/src/components/AIChatWidget.tsx +2 -2
  6. package/template/src/components/AppHeader.tsx +12 -12
  7. package/template/src/components/AutoForm.tsx +13 -0
  8. package/template/src/{pages/styleguide → components}/NotFound.tsx +1 -1
  9. package/template/src/components/PageTitleUpdater.tsx +2 -2
  10. package/template/src/components/ProtectedRoute.tsx +18 -1
  11. package/template/src/components/ScrollToTop.tsx +19 -0
  12. package/template/src/components/dashboard/ChartLine.tsx +28 -0
  13. package/template/src/components/dashboard/StatCard.tsx +61 -0
  14. package/template/src/config/app.manifest.ts +3 -1
  15. package/template/src/config/component-registry.tsx +69 -0
  16. package/template/src/config/navigation.ts +1 -1
  17. package/template/src/data/mock-charts.ts +32 -28
  18. package/template/src/{components → engine/renderers}/DynamicBlock.tsx +28 -8
  19. package/template/src/engine/renderers/DynamicPage.tsx +150 -0
  20. package/template/src/engine/runtime/ManifestContext.tsx +79 -0
  21. package/template/src/{contexts → engine/runtime}/MqttContext.tsx +23 -14
  22. package/template/src/{contexts → engine/runtime}/SitemapContext.tsx +1 -1
  23. package/template/src/engine/runtime/data-seeder.ts +47 -0
  24. package/template/src/{hooks → engine/runtime}/useAction.ts +11 -14
  25. package/template/src/{hooks → engine/runtime}/useCrudLocalStorage.ts +27 -8
  26. package/template/src/{hooks → engine/runtime}/useDataQuery.ts +15 -1
  27. package/template/src/engine/runtime/useDynamicSitemap.tsx +43 -0
  28. package/template/src/engine/runtime/useJustInTimeSeeder.ts +76 -0
  29. package/template/src/engine/runtime/useLiveBridge.ts +44 -0
  30. package/template/src/engine/runtime/useSignal.ts +40 -0
  31. package/template/src/{generated/hooks.ts → engine/runtime/useSignalStore.ts} +35 -8
  32. package/template/src/engine/runtime/useWorkflowEngine.ts +89 -0
  33. package/template/src/{core → engine/types}/manifest-types.ts +35 -3
  34. package/template/src/{types → engine/validation}/schema.ts +17 -0
  35. package/template/src/{pages → features/ai/pages}/AiChat.tsx +1 -1
  36. package/template/src/features/auth/AuthContext.tsx +118 -0
  37. package/template/src/features/auth/pages/AuthLayout.tsx +55 -0
  38. package/template/src/features/auth/pages/LoginPage.tsx +106 -0
  39. package/template/src/features/auth/pages/SignupPage.tsx +96 -0
  40. package/template/src/{blocks → features/datagrid}/SmartTable.tsx +41 -25
  41. package/template/src/features/developer/GhostOverlay.tsx +114 -0
  42. package/template/src/{pages → features/onboarding/pages}/Welcome.tsx +0 -1
  43. package/template/src/features/overview/index.ts +1 -0
  44. package/template/src/features/overview/pages/OverviewPage.tsx +127 -0
  45. package/template/src/{pages → features/playground/pages}/AccountingLedgerPage.tsx +1 -1
  46. package/template/src/{pages/prototypes → features/playground/pages}/ItemSelectorPage.tsx +1 -1
  47. package/template/src/{pages/settings → features/settings/pages}/BillingPage.tsx +1 -1
  48. package/template/src/features/settings/pages/ProfilePage.tsx +153 -0
  49. package/template/src/{pages/settings → features/settings/pages}/TeamPage.tsx +1 -1
  50. package/template/src/features/styleguide/Styleguide.tsx +75 -0
  51. package/template/src/features/users/components/UserDrawer.tsx +138 -0
  52. package/template/src/features/users/index.ts +2 -0
  53. package/template/src/features/users/pages/UsersPage.tsx +151 -0
  54. package/template/src/features/visualizations/SmartChart.tsx +178 -0
  55. package/template/src/index.css +1 -1
  56. package/template/src/main.tsx +27 -15
  57. package/template/src/templates/dashboard/DashboardLayout.tsx +77 -107
  58. package/template/src/templates/dashboard/dashboard.sitemap.ts +19 -22
  59. package/template/src/templates/docs/DocsLayout.tsx +49 -38
  60. package/template/src/templates/docs/docs.sitemap.ts +22 -34
  61. package/template/src/templates/settings/SettingsLayout.tsx +83 -143
  62. package/template/src/templates/settings/settings.sitemap.ts +6 -6
  63. package/template/tailwind.config.cjs +10 -9
  64. package/template/vite.config.ts +0 -11
  65. package/template/src/adaptors/.gitkeep +0 -0
  66. package/template/src/components/LocalSideNav.tsx +0 -120
  67. package/template/src/components/PageWithSideNav.tsx +0 -69
  68. package/template/src/components/dev/GhostOverlay.tsx +0 -68
  69. package/template/src/config/dashboard.layout.ts +0 -110
  70. package/template/src/contexts/AuthContext.tsx +0 -64
  71. package/template/src/core/component-registry.tsx +0 -56
  72. package/template/src/core/data-seeder.ts +0 -35
  73. package/template/src/data/mockUsers.ts +0 -18
  74. package/template/src/hooks/useSignal.ts +0 -83
  75. package/template/src/hooks/useWorkflowEngine.ts +0 -123
  76. package/template/src/layouts/DataLayout.tsx +0 -37
  77. package/template/src/layouts/SideNavLayout.tsx +0 -28
  78. package/template/src/pages/Dashboard.tsx +0 -60
  79. package/template/src/pages/DataGridPage.tsx +0 -184
  80. package/template/src/pages/DynamicPage.tsx +0 -95
  81. package/template/src/pages/LoginPage.tsx +0 -58
  82. package/template/src/pages/settings/ProfilePage.tsx +0 -10
  83. package/template/src/pages/styleguide/Styleguide.tsx +0 -40
  84. package/template/src/templates/docs/pages/Introduction.tsx +0 -13
  85. package/template/src/types/signal.ts +0 -23
  86. /package/template/src/{core → engine/renderers}/route-generator.tsx +0 -0
  87. /package/template/src/{core → engine/types}/sitemap-entry.ts +0 -0
  88. /package/template/src/{pages → features}/GenericContentPage.tsx +0 -0
  89. /package/template/src/{hooks → features/assistant}/useMockChat.ts +0 -0
  90. /package/template/src/{hooks → features/developer}/useDevTools.ts +0 -0
  91. /package/template/src/{pages → features}/styleguide/sections/charts/ChartsSection.tsx +0 -0
  92. /package/template/src/{pages → features}/styleguide/sections/colors/ColorsSection.tsx +0 -0
  93. /package/template/src/{pages → features}/styleguide/sections/elements/ElementsSection.tsx +0 -0
  94. /package/template/src/{pages → features}/styleguide/sections/feedback/FeedbackSection.tsx +0 -0
  95. /package/template/src/{pages → features}/styleguide/sections/forms/FormsSection.tsx +0 -0
  96. /package/template/src/{pages → features}/styleguide/sections/icons/IconsSection.tsx +0 -0
  97. /package/template/src/{pages → features}/styleguide/sections/layout/LayoutSection.tsx +0 -0
  98. /package/template/src/{pages → features}/styleguide/sections/navigation/NavigationSection.tsx +0 -0
  99. /package/template/src/{pages → features}/styleguide/sections/tables/TablesSection.tsx +0 -0
  100. /package/template/src/{pages → features}/styleguide/sections/templates/TemplatesSection.tsx +0 -0
  101. /package/template/src/{pages → features}/styleguide/sections/theming/ThemingSection.tsx +0 -0
  102. /package/template/src/{pages → features}/styleguide/sections/utilities/UtilitiesSection.tsx +0 -0
@@ -0,0 +1,178 @@
1
+ import React, { useMemo } from 'react';
2
+ import {
3
+ BarChart, Bar, LineChart, Line, AreaChart, Area, PieChart, Pie, Cell,
4
+ XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend
5
+ } from 'recharts';
6
+ import { Card } from '@ramme-io/ui';
7
+ import { BarChart3, Bug } from 'lucide-react';
8
+
9
+ interface SmartChartProps {
10
+ rowData?: any[];
11
+ chartType?: 'bar' | 'line' | 'area' | 'pie';
12
+ xAxis?: string;
13
+ yAxis?: string;
14
+ aggregation?: string;
15
+ title?: string;
16
+ className?: string;
17
+ }
18
+
19
+ const COLORS = ['#0ea5e9', '#22c55e', '#eab308', '#ef4444', '#8b5cf6'];
20
+
21
+ export const SmartChart: React.FC<SmartChartProps> = ({
22
+ rowData = [], chartType = 'bar', xAxis, yAxis, aggregation = 'none', title, className
23
+ }) => {
24
+
25
+ // 1. DATA PROCESSING ENGINE
26
+ const processedData = useMemo(() => {
27
+ if (!rowData || rowData.length === 0) return [];
28
+
29
+ // Fallback: If no xAxis provided, try to find a string key, else use 'id'
30
+ const activeX = xAxis || Object.keys(rowData[0]).find(k => typeof rowData[0][k] === 'string') || 'id';
31
+
32
+ // Normalize mode
33
+ const mode = aggregation?.toLowerCase() || 'none';
34
+
35
+ // SCENARIO A: COUNT
36
+ if (mode === 'count') {
37
+ const counts: Record<string, number> = {};
38
+ rowData.forEach(row => {
39
+ const rawVal = row[activeX];
40
+ // Handle Booleans (true/false) explicitly
41
+ const key = String(rawVal !== undefined && rawVal !== null ? rawVal : 'Unknown');
42
+ counts[key] = (counts[key] || 0) + 1;
43
+ });
44
+ return Object.entries(counts).map(([name, value]) => ({ name, value }));
45
+ }
46
+
47
+ // SCENARIO B: SUM
48
+ if (mode === 'sum' && yAxis) {
49
+ const sums: Record<string, number> = {};
50
+ rowData.forEach(row => {
51
+ const key = String(row[activeX] ?? 'Unknown');
52
+ const val = Number(row[yAxis]) || 0;
53
+ sums[key] = (sums[key] || 0) + val;
54
+ });
55
+ return Object.entries(sums).map(([name, value]) => ({ name, value }));
56
+ }
57
+
58
+ // SCENARIO C: RAW
59
+ return rowData.map(row => ({
60
+ name: String(row[activeX] ?? ''),
61
+ value: yAxis ? Number(row[yAxis]) : 0
62
+ }));
63
+
64
+ }, [rowData, xAxis, yAxis, aggregation]);
65
+
66
+ // 2. RENDERERS
67
+ const renderChart = () => {
68
+ // If no data to render, show placeholder
69
+ if (processedData.length === 0) {
70
+ return (
71
+ <div className="flex flex-col items-center justify-center h-full text-muted-foreground opacity-50">
72
+ <BarChart3 size={32} />
73
+ <span className="text-xs mt-2">No Data Available</span>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ const type = chartType?.toLowerCase() || 'bar';
79
+ switch (type) {
80
+ case 'pie':
81
+ return (
82
+ <PieChart>
83
+ <Pie data={processedData} cx="50%" cy="50%" innerRadius={60} outerRadius={80} paddingAngle={5} dataKey="value">
84
+ {processedData.map((_, index) => <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />)}
85
+ </Pie>
86
+ <Tooltip />
87
+ <Legend verticalAlign="bottom" height={36}/>
88
+ </PieChart>
89
+ );
90
+ case 'line':
91
+ return (
92
+ <LineChart data={processedData}>
93
+ <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
94
+ <XAxis dataKey="name" fontSize={12} tickLine={false} axisLine={false} />
95
+ <YAxis fontSize={12} tickLine={false} axisLine={false} />
96
+ <Tooltip />
97
+ <Line type="monotone" dataKey="value" stroke="#0ea5e9" strokeWidth={3} dot={{r:4}} />
98
+ </LineChart>
99
+ );
100
+ case 'area':
101
+ return (
102
+ <AreaChart data={processedData}>
103
+ <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
104
+ <XAxis dataKey="name" fontSize={12} tickLine={false} axisLine={false} />
105
+ <YAxis fontSize={12} tickLine={false} axisLine={false} />
106
+ <Tooltip />
107
+ <Area type="monotone" dataKey="value" stroke="#0ea5e9" fill="#0ea5e9" fillOpacity={0.2} />
108
+ </AreaChart>
109
+ );
110
+ case 'bar': default:
111
+ return (
112
+ <BarChart data={processedData}>
113
+ <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
114
+ <XAxis dataKey="name" fontSize={12} tickLine={false} axisLine={false} />
115
+ <YAxis fontSize={12} tickLine={false} axisLine={false} />
116
+ <Tooltip cursor={{ fill: '#f1f5f9' }} />
117
+ <Bar dataKey="value" fill="#0ea5e9" radius={[4, 4, 0, 0]} />
118
+ </BarChart>
119
+ );
120
+ }
121
+ };
122
+
123
+ return (
124
+ <Card className={`p-4 flex flex-col h-full bg-white border border-border shadow-sm ${className}`}>
125
+ {/* Title Header */}
126
+ <div className="flex items-center justify-between mb-4">
127
+ <div className="flex flex-col">
128
+ {title && <h3 className="text-sm font-bold text-foreground uppercase tracking-wider">{title}</h3>}
129
+ {/* Subtitle with Aggregation info */}
130
+ {aggregation && aggregation !== 'none' && (
131
+ <span className="text-[10px] text-muted-foreground font-mono">
132
+ BY {aggregation.toUpperCase()} ({xAxis})
133
+ </span>
134
+ )}
135
+ </div>
136
+ </div>
137
+
138
+ {/* Chart Canvas */}
139
+ <div className="flex-1 w-full min-h-[200px]">
140
+ <ResponsiveContainer width="100%" height="100%">{renderChart()}</ResponsiveContainer>
141
+ </div>
142
+
143
+ {/* ✅ DEBUG CONSOLE (Collapsible) */}
144
+ <div className="mt-4 border-t border-border pt-2">
145
+ <details className="text-[10px] text-muted-foreground group">
146
+ <summary className="cursor-pointer hover:text-primary flex items-center gap-2 select-none font-mono">
147
+ <Bug size={12} />
148
+ <span>Debug Configuration</span>
149
+ <span className="ml-auto opacity-50">{rowData?.length || 0} Rows</span>
150
+ </summary>
151
+ <div className="mt-2 p-3 bg-slate-950 text-green-400 rounded-md font-mono overflow-x-auto text-[10px] leading-relaxed shadow-inner">
152
+ <div className="mb-2 pb-2 border-b border-white/10">
153
+ <span className="text-white font-bold block mb-1">INCOMING PROPS:</span>
154
+ <div>chartType: <span className="text-yellow-300">"{chartType}"</span></div>
155
+ <div>aggregation: <span className="text-yellow-300">"{aggregation}"</span></div>
156
+ <div>xAxis (Key): <span className="text-yellow-300">"{xAxis}"</span></div>
157
+ <div>yAxis (Val): <span className="text-yellow-300">"{yAxis}"</span></div>
158
+ </div>
159
+
160
+ <div className="mb-2 pb-2 border-b border-white/10">
161
+ <span className="text-white font-bold block mb-1">DATA SNAPSHOT (Row 0):</span>
162
+ {rowData && rowData.length > 0 ? (
163
+ <pre>{JSON.stringify(rowData[0], null, 2)}</pre>
164
+ ) : (
165
+ <span className="text-red-400">No Data Rows Received</span>
166
+ )}
167
+ </div>
168
+
169
+ <div>
170
+ <span className="text-white font-bold block mb-1">PROCESSED OUTPUT (Top 3):</span>
171
+ <pre>{JSON.stringify(processedData.slice(0, 3), null, 2)}</pre>
172
+ </div>
173
+ </div>
174
+ </details>
175
+ </div>
176
+ </Card>
177
+ );
178
+ };
@@ -1,4 +1,4 @@
1
- @import '@ramme-io/ui/style.css';
1
+
2
2
 
3
3
  @tailwind base;
4
4
  @tailwind components;
@@ -3,26 +3,38 @@ import ReactDOM from 'react-dom/client';
3
3
  import { BrowserRouter } from 'react-router-dom';
4
4
  import App from './App.tsx';
5
5
  import { ThemeProvider, ToastProvider } from '@ramme-io/ui';
6
- import { AuthProvider } from './contexts/AuthContext';
7
- import { MqttProvider } from './contexts/MqttContext';
8
- import '@ramme-io/ui/style.css';
6
+ import { AuthProvider } from './features/auth/AuthContext.tsx';
7
+ import { MqttProvider } from './engine/runtime/MqttContext';
8
+ import "@ramme-io/ui/index.css";
9
9
  import './index.css';
10
10
 
11
- // This import activates all AG Grid Enterprise features
11
+ // 1. Data Seeder (Critical for Auth)
12
+ import { initializeDataLake } from './engine/runtime/data-seeder';
13
+
14
+ // 2. Manifest Provider (Critical for Builder Preview)
15
+ import { ManifestProvider } from './engine/runtime/ManifestContext';
16
+
17
+ // 3. AG Grid Enterprise
12
18
  import 'ag-grid-enterprise';
13
19
 
20
+ // Initialize mock data immediately on boot
21
+ initializeDataLake();
22
+
14
23
  ReactDOM.createRoot(document.getElementById('root')!).render(
15
24
  <React.StrictMode>
16
- <BrowserRouter>
17
- <ThemeProvider>
18
- <ToastProvider>
19
- <AuthProvider>
20
- <MqttProvider>
21
- <App />
22
- </MqttProvider>
23
- </AuthProvider>
24
- </ToastProvider>
25
- </ThemeProvider>
26
- </BrowserRouter>
25
+ {/* 🛡️ KEEPS THE BRIDGE ALIVE: Wraps the entire app */}
26
+ <ManifestProvider>
27
+ <BrowserRouter>
28
+ <ThemeProvider>
29
+ <ToastProvider>
30
+ <AuthProvider>
31
+ <MqttProvider>
32
+ <App />
33
+ </MqttProvider>
34
+ </AuthProvider>
35
+ </ToastProvider>
36
+ </ThemeProvider>
37
+ </BrowserRouter>
38
+ </ManifestProvider>
27
39
  </React.StrictMode>,
28
40
  );
@@ -1,127 +1,97 @@
1
- import React, { useState } from 'react'; // <-- Added useState
2
- import { Outlet, NavLink } from 'react-router-dom';
1
+ import React, { useState, useMemo } from 'react';
2
+ import { Outlet, useNavigate, useLocation } from 'react-router-dom';
3
3
  import {
4
4
  Sidebar,
5
- SidebarProvider,
6
- SidebarHeader,
7
- SidebarContent,
8
- SidebarFooter,
9
- SidebarMenu,
10
- SidebarMenuItem,
11
- useSidebar,
12
- Button,
13
- Icon,
14
- ChatFAB, // <-- NEW: Import FAB
15
- } from '@ramme-io/ui';
5
+ type SidebarItem,
6
+ ChatFAB,
7
+ type IconName,
8
+ } from '@ramme-io/ui';
9
+
16
10
  import { dashboardSitemap } from './dashboard.sitemap';
17
- import { SitemapProvider } from '../../contexts/SitemapContext';
11
+ import { SitemapProvider } from '../../engine/runtime/SitemapContext';
18
12
  import PageTitleUpdater from '../../components/PageTitleUpdater';
19
13
  import AppHeader from '../../components/AppHeader';
20
- import { AIChatWidget } from '../../components/AIChatWidget'; // <-- NEW: Import Widget
21
- import { useWorkflowEngine } from '../../hooks/useWorkflowEngine';
22
-
23
- // NavLink wrapper - Correct
24
- const SidebarNavLink = React.forwardRef<HTMLAnchorElement, any>(
25
- ({ end, href, ...props }, ref) => {
26
- return <NavLink ref={ref} to={href || ''} {...props} end={end} />;
27
- },
28
- );
29
- SidebarNavLink.displayName = 'SidebarNavLink';
14
+ import { AIChatWidget } from '../../components/AIChatWidget';
15
+ import { useWorkflowEngine } from '../../engine/runtime/useWorkflowEngine';
30
16
 
31
- // Sidebar Content Component
32
- const AppSidebarContent: React.FC = () => {
33
- const { isOpen, toggle } = useSidebar();
34
- return (
35
- <>
36
- <SidebarHeader>
37
- <div className="flex items-center justify-end w-full h-full">
38
- <Button
39
- variant="ghost"
40
- size="icon"
41
- onClick={toggle}
42
- className="hidden md:flex mr-1"
43
- >
44
- <Icon name={isOpen ? 'panel-left-close' : 'panel-left-open'} />
45
- </Button>
46
- </div>
47
- </SidebarHeader>
17
+ // 1. IMPORT THE HOOK
18
+ import { useDynamicSitemap } from '../../engine/runtime/useDynamicSitemap';
48
19
 
49
- <SidebarContent>
50
- <SidebarMenu>
51
- {dashboardSitemap.map((item) => (
52
- <React.Fragment key={item.id}>
53
- <SidebarMenuItem
54
- as={SidebarNavLink}
55
- href={item.path ? `/dashboard/${item.path}` : '/dashboard'}
56
- end
57
- icon={item.icon ? <Icon name={item.icon} /> : undefined}
58
- tooltip={item.title}
59
- >
60
- {item.title}
61
- </SidebarMenuItem>
62
- {item.children &&
63
- isOpen &&
64
- item.children.map((child) => (
65
- <SidebarMenuItem
66
- key={child.id}
67
- as={SidebarNavLink}
68
- href={`/dashboard/${item.path}/${child.path}`}
69
- end
70
- icon={child.icon ? <Icon name={child.icon} /> : undefined}
71
- tooltip={child.title}
72
- className="pl-10"
73
- >
74
- {child.title}
75
- </SidebarMenuItem>
76
- ))}
77
- </React.Fragment>
78
- ))}
79
- </SidebarMenu>
80
- </SidebarContent>
81
-
82
- <SidebarFooter />
83
- </>
84
- );
85
- };
86
-
87
- // Main Layout Component
88
20
  const DashboardLayout: React.FC = () => {
89
- // 1. STATE: Track if the chat window is open
21
+ const navigate = useNavigate();
22
+ const location = useLocation();
90
23
  const [isChatOpen, setIsChatOpen] = useState(false);
24
+
91
25
  useWorkflowEngine();
92
26
 
27
+ // ✅ 2. GET LIVE DATA (Merges Static + Builder Data)
28
+ const liveSitemap = useDynamicSitemap(dashboardSitemap);
29
+
30
+ // ✅ 3. BUILD SIDEBAR FROM LIVE DATA
31
+ const sidebarItems: SidebarItem[] = useMemo(() => {
32
+ // We map over 'liveSitemap' instead of 'dashboardSitemap'
33
+ return liveSitemap.map((route) => ({
34
+ id: route.id,
35
+ label: route.title,
36
+ icon: route.icon as IconName,
37
+ // Handle the path logic safely
38
+ href: route.path.startsWith('/') ? route.path : `/dashboard/${route.path}`,
39
+ }));
40
+ }, [liveSitemap]); // Re-run whenever the Builder sends an update
41
+
42
+ // 4. Determine Active Item
43
+ const activeItemId = useMemo(() => {
44
+ const active = sidebarItems.find(item =>
45
+ item.href !== '/dashboard' && location.pathname.startsWith(item.href!)
46
+ );
47
+ return active?.id || sidebarItems[0]?.id;
48
+ }, [location.pathname, sidebarItems]);
49
+
93
50
  return (
94
- <SitemapProvider value={dashboardSitemap}>
51
+ // ✅ 5. PASS LIVE SITEMAP TO CONTEXT (For Breadcrumbs/Titles)
52
+ <SitemapProvider value={liveSitemap}>
95
53
  <PageTitleUpdater />
96
- <SidebarProvider>
97
- <div className="flex h-screen bg-background text-foreground relative">
98
- <Sidebar>
99
- <AppSidebarContent />
100
- </Sidebar>
101
- <div className="flex flex-col flex-1 overflow-hidden">
102
- <AppHeader />
103
- <main className="flex-1 overflow-y-auto p-8">
104
- <Outlet />
105
- </main>
106
- </div>
54
+
55
+ <div className="flex h-screen bg-background text-foreground relative">
56
+
57
+ <Sidebar
58
+ className="relative border-border"
59
+ items={sidebarItems} // Now contains your new page!
60
+ activeItemId={activeItemId}
61
+ onNavigate={(item) => {
62
+ if (item.href) navigate(item.href);
63
+ }}
64
+ user={{
65
+ name: "Demo User",
66
+ email: "user@example.com",
67
+ avatarUrl: "https://i.pravatar.cc/150?u=ramme"
68
+ }}
69
+ logo={
70
+ <div className="flex items-center gap-2 px-2 font-bold text-xl tracking-tight">
71
+ <span className="text-primary">Ramme</span>App
72
+ </div>
73
+ }
74
+ />
107
75
 
108
- {/* --- AI COPILOT SECTION --- */}
109
-
110
- {/* 2. The Widget: Only renders when open */}
111
- {isChatOpen && (
112
- <AIChatWidget onClose={() => setIsChatOpen(false)} />
113
- )}
76
+ <div className="flex flex-col flex-1 overflow-hidden">
77
+ <AppHeader />
78
+ <main className="flex-1 overflow-y-auto p-8 bg-muted/20">
79
+ <Outlet />
80
+ </main>
81
+ </div>
114
82
 
115
- {/* 3. The Button: Fixed to bottom-right */}
116
- <div className="fixed bottom-6 right-6 z-50">
117
- <ChatFAB
118
- onClick={() => setIsChatOpen(!isChatOpen)}
119
- tooltipContent={isChatOpen ? "Close Assistant" : "Open Bodewell AI"}
120
- />
121
- </div>
83
+ {isChatOpen && (
84
+ <AIChatWidget onClose={() => setIsChatOpen(false)} />
85
+ )}
122
86
 
87
+ <div className="fixed bottom-6 right-6 z-50">
88
+ <ChatFAB
89
+ onClick={() => setIsChatOpen(!isChatOpen)}
90
+ tooltipContent={isChatOpen ? "Close Assistant" : "Open Bodewell AI"}
91
+ />
123
92
  </div>
124
- </SidebarProvider>
93
+
94
+ </div>
125
95
  </SitemapProvider>
126
96
  );
127
97
  };
@@ -1,11 +1,16 @@
1
- import { type SitemapEntry } from '../../core/sitemap-entry';
1
+ import { type SitemapEntry } from '../../engine/types/sitemap-entry';
2
2
  import { appManifest } from '../../config/app.manifest';
3
- import Dashboard from '../../pages/Dashboard';
4
- import AiChat from '../../pages/AiChat';
5
- import Welcome from '../../pages/Welcome'; // ✅ Import the new page
3
+
4
+ // Existing pages (Legacy location)
5
+ import Welcome from '../../features/onboarding/pages/Welcome';
6
+ import { OverviewPage } from '../../features/overview';
7
+ import AiChat from '../../features/ai/pages/AiChat';
8
+
9
+ // ✅ NEW: Import from the Feature Domain (Clean API)
10
+ import { UsersPage } from '../../features/users';
6
11
 
7
12
  export const dashboardSitemap: SitemapEntry[] = [
8
- // 1. The New Landing Page
13
+ // 1. The New Landing Page
9
14
  {
10
15
  id: 'welcome',
11
16
  path: 'welcome',
@@ -13,24 +18,16 @@ export const dashboardSitemap: SitemapEntry[] = [
13
18
  icon: 'rocket',
14
19
  component: Welcome,
15
20
  },
16
- ];
17
21
 
18
- // A. Dynamic Pages from Manifest
19
- if (appManifest.pages) {
20
- appManifest.pages.forEach(page => {
21
- const isDashboard = page.slug === 'dashboard';
22
-
23
- dashboardSitemap.push({
24
- id: page.id,
25
- title: page.title,
26
- // ✅ FIX: Map the main dashboard to 'app' instead of root ''
27
- // This prevents conflict with the layout root
28
- path: isDashboard ? 'app' : page.slug,
29
- icon: isDashboard ? 'layout-dashboard' : 'file-text',
30
- component: Dashboard,
31
- });
32
- });
33
- }
22
+ // 3. The User Management Module
23
+ {
24
+ id: 'users',
25
+ path: 'users',
26
+ title: 'Users',
27
+ icon: 'users',
28
+ component: UsersPage,
29
+ }
30
+ ];
34
31
 
35
32
  // B. Dynamic Modules
36
33
  if (appManifest.modules?.includes('ai-chat')) {
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { Outlet, NavLink } from 'react-router-dom';
3
3
  import { docsSitemap } from './docs.sitemap';
4
- import { SitemapProvider } from '../../contexts/SitemapContext';
4
+ import { SitemapProvider } from '../../engine/runtime/SitemapContext';
5
5
  import AppHeader from '../../components/AppHeader';
6
6
  import AppFooter from '../../components/AppFooter';
7
7
  import { Icon } from '@ramme-io/ui';
@@ -9,44 +9,55 @@ import PageTitleUpdater from '../../components/PageTitleUpdater';
9
9
 
10
10
  const DocsLayout: React.FC = () => {
11
11
  return (
12
- // Add a wrapper div with the correct theme classes
13
- <div className="bg-background text-foreground">
14
- <div className="flex flex-col min-h-screen">
15
- <AppHeader />
16
- <main className="flex-grow">
17
- <div className="bg-background border-b border-border sticky top-16 z-30">
18
- <nav className="container mx-auto px-4">
19
- <ul className="flex items-center gap-4 h-12">
20
- {docsSitemap.map((item) => (
21
- <li key={item.id}>
22
- <NavLink
23
- to={item.path || ''}
24
- end={!item.children || item.children.length === 0}
25
- className={({ isActive }) =>
26
- `flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md transition-colors ${
27
- isActive
28
- ? 'bg-primary text-primary-foreground'
29
- : 'text-muted-foreground hover:bg-muted'
30
- }`
31
- }
32
- >
33
- {item.icon && <Icon name={item.icon} className="h-4 w-4" />}
34
- <span>{item.title}</span>
35
- </NavLink>
36
- </li>
37
- ))}
38
- </ul>
39
- </nav>
40
- </div>
41
- <div className="container mx-auto p-4 md:p-8">
42
- <SitemapProvider value={docsSitemap}>
43
- <PageTitleUpdater />
12
+ <div className="bg-background text-foreground min-h-screen flex flex-col font-sans">
13
+ <AppHeader />
14
+
15
+ <main className="flex-grow flex flex-col">
16
+ {/* --- TOP NAVIGATION BAR --- */}
17
+ <div className="bg-card border-b border-border sticky top-16 z-30 w-full">
18
+ <nav className="w-full px-6">
19
+ <ul className="flex items-center gap-6 h-12">
20
+ {docsSitemap.map((item) => (
21
+ <li key={item.id}>
22
+ <NavLink
23
+ to={item.path || ''}
24
+ end={!item.children || item.children.length === 0}
25
+ className={({ isActive }) =>
26
+ `flex items-center gap-2 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
27
+ isActive
28
+ ? 'bg-primary/10 text-primary'
29
+ : 'text-muted-foreground hover:text-foreground hover:bg-muted/50'
30
+ }`
31
+ }
32
+ >
33
+ {item.icon && <Icon name={item.icon} className="h-4 w-4" />}
34
+ <span>{item.title}</span>
35
+ </NavLink>
36
+ </li>
37
+ ))}
38
+ </ul>
39
+ </nav>
40
+ </div>
41
+
42
+ {/* --- MAIN CONTENT WRAPPER --- */}
43
+ <div className="w-full flex-1 flex flex-col">
44
+ <SitemapProvider value={docsSitemap}>
45
+ <PageTitleUpdater />
46
+
47
+ {/* Page Content */}
48
+ <div className="flex-1">
44
49
  <Outlet />
45
- </SitemapProvider>
46
- </div>
47
- </main>
48
- <AppFooter />
49
- </div>
50
+ </div>
51
+
52
+ {/* Footer - Now part of the content flow */}
53
+ <div className="border-t border-border mt-auto w-full bg-background">
54
+ <div className="max-w-7xl mx-auto px-6">
55
+ <AppFooter />
56
+ </div>
57
+ </div>
58
+ </SitemapProvider>
59
+ </div>
60
+ </main>
50
61
  </div>
51
62
  );
52
63
  };