@ramme-io/create-app 1.2.2 → 1.2.6

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 (27) hide show
  1. package/package.json +9 -14
  2. package/template/package.json +5 -3
  3. package/template/pkg.json +11 -7
  4. package/template/src/App.tsx +11 -1
  5. package/template/src/components/AppHeader.tsx +10 -10
  6. package/template/src/components/dashboard/ChartLine.tsx +28 -0
  7. package/template/src/components/dashboard/StatCard.tsx +61 -0
  8. package/template/src/config/component-registry.tsx +57 -44
  9. package/template/src/engine/renderers/DynamicBlock.tsx +1 -1
  10. package/template/src/engine/renderers/DynamicPage.tsx +134 -98
  11. package/template/src/engine/runtime/ManifestContext.tsx +79 -0
  12. package/template/src/engine/runtime/MqttContext.tsx +16 -21
  13. package/template/src/engine/runtime/data-seeder.ts +9 -7
  14. package/template/src/engine/runtime/useAction.ts +7 -21
  15. package/template/src/engine/runtime/useDynamicSitemap.tsx +43 -0
  16. package/template/src/engine/runtime/useJustInTimeSeeder.ts +76 -0
  17. package/template/src/engine/runtime/useLiveBridge.ts +44 -0
  18. package/template/src/engine/runtime/useSignal.ts +10 -21
  19. package/template/src/engine/runtime/useWorkflowEngine.ts +23 -78
  20. package/template/src/features/datagrid/SmartTable.tsx +38 -20
  21. package/template/src/features/developer/GhostOverlay.tsx +67 -21
  22. package/template/src/features/visualizations/SmartChart.tsx +178 -0
  23. package/template/src/main.tsx +25 -13
  24. package/template/src/templates/dashboard/DashboardLayout.tsx +19 -18
  25. package/template/src/templates/dashboard/dashboard.sitemap.ts +1 -8
  26. package/template/tailwind.config.cjs +10 -9
  27. package/template/vite.config.ts +0 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramme-io/create-app",
3
- "version": "1.2.2",
3
+ "version": "1.2.6",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-ramme-app": "./index.js"
@@ -9,14 +9,6 @@
9
9
  "index.js",
10
10
  "template"
11
11
  ],
12
- "scripts": {
13
- "dev": "cd template && vite",
14
- "build": "cd template && tsc && vite build",
15
- "preview": "cd template && vite preview",
16
- "pack-tarball": "npm pack",
17
- "bundle:ai": "repomix --ignore '**/*.lock,**/dist/**,**/template/dist/**,**/template/node_modules/**' --output 'ramme-starter-context.txt'",
18
- "zip:builder": "cd template && zip -r ../base.zip . -x \"node_modules/*\" \"dist/*\" \".DS_Store\" && mv ../base.zip ../../ramme-app-builder/public/base.zip && echo '✅ base.zip updated in Builder!'"
19
- },
20
12
  "dependencies": {
21
13
  "ag-grid-community": "^34.1.2",
22
14
  "ag-grid-enterprise": "^34.1.2",
@@ -39,9 +31,12 @@
39
31
  "typescript": "^5.2.2",
40
32
  "vite": "^5.2.0"
41
33
  },
42
- "pnpm": {
43
- "overrides": {
44
- "react-router-dom": "6.30.1"
45
- }
34
+ "scripts": {
35
+ "dev": "cd template && vite",
36
+ "build": "cd template && tsc && vite build",
37
+ "preview": "cd template && vite preview",
38
+ "pack-tarball": "npm pack",
39
+ "bundle:ai": "repomix --ignore '**/*.lock,**/dist/**,**/template/dist/**,**/template/node_modules/**' --output 'ramme-starter-context.txt'",
40
+ "zip:builder": "cd template && zip -r ../base.zip . -x \"node_modules/*\" \"dist/*\" \".DS_Store\" && mv ../base.zip ../../ramme-app-builder/public/base.zip && echo '✅ base.zip updated in Builder!'"
46
41
  }
47
- }
42
+ }
@@ -10,19 +10,20 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@ai-sdk/google": "^0.0.10",
13
- "@ramme-io/ui": "^1.2.2",
14
- "@types/uuid": "^10.0.0",
13
+ "@ramme-io/ui": "^1.2.3",
15
14
  "ag-grid-community": "^31.3.1",
16
15
  "ag-grid-enterprise": "^31.3.1",
17
16
  "ag-grid-react": "^31.3.1",
18
17
  "ai": "^3.0.0",
19
18
  "framer-motion": "^11.0.0",
20
19
  "fs-extra": "^11.2.0",
20
+ "lucide-react": "^0.454.0",
21
21
  "mqtt": "^5.3.5",
22
22
  "react": "^18.2.0",
23
23
  "react-dom": "^18.2.0",
24
24
  "react-resizable-panels": "^2.0.9",
25
25
  "react-router-dom": "^6.22.0",
26
+ "recharts": "^2.12.7",
26
27
  "uuid": "^13.0.0",
27
28
  "zod": "^3.22.0",
28
29
  "zustand": "^4.5.7"
@@ -31,6 +32,7 @@
31
32
  "@types/node": "^20.11.0",
32
33
  "@types/react": "^18.2.0",
33
34
  "@types/react-dom": "^18.2.0",
35
+ "@types/uuid": "^10.0.0",
34
36
  "@vitejs/plugin-react": "^4.2.0",
35
37
  "autoprefixer": "^10.4.19",
36
38
  "postcss": "^8.4.38",
@@ -38,4 +40,4 @@
38
40
  "typescript": "^5.2.0",
39
41
  "vite": "^5.2.0"
40
42
  }
41
- }
43
+ }
package/template/pkg.json CHANGED
@@ -9,26 +9,30 @@
9
9
  "preview": "vite preview"
10
10
  },
11
11
  "dependencies": {
12
- "@ramme-io/ui": "^1.2.2",
13
- "mqtt": "^5.3.5",
14
- "zustand": "^4.5.0",
12
+ "@ai-sdk/google": "^0.0.10",
13
+ "@ramme-io/ui": "^1.2.3",
15
14
  "ag-grid-community": "^31.3.1",
16
15
  "ag-grid-enterprise": "^31.3.1",
17
16
  "ag-grid-react": "^31.3.1",
17
+ "ai": "^3.0.0",
18
18
  "framer-motion": "^11.0.0",
19
19
  "fs-extra": "^11.2.0",
20
+ "lucide-react": "^0.454.0",
21
+ "mqtt": "^5.3.5",
20
22
  "react": "^18.2.0",
21
23
  "react-dom": "^18.2.0",
22
- "react-router-dom": "^6.22.0",
23
24
  "react-resizable-panels": "^2.0.9",
24
- "ai": "^3.0.0",
25
- "@ai-sdk/google": "^0.0.10",
26
- "zod": "^3.22.0"
25
+ "react-router-dom": "^6.22.0",
26
+ "recharts": "^2.12.7",
27
+ "uuid": "^13.0.0",
28
+ "zod": "^3.22.0",
29
+ "zustand": "^4.5.7"
27
30
  },
28
31
  "devDependencies": {
29
32
  "@types/node": "^20.11.0",
30
33
  "@types/react": "^18.2.0",
31
34
  "@types/react-dom": "^18.2.0",
35
+ "@types/uuid": "^10.0.0",
32
36
  "@vitejs/plugin-react": "^4.2.0",
33
37
  "autoprefixer": "^10.4.19",
34
38
  "postcss": "^8.4.38",
@@ -5,6 +5,7 @@ import { ThemeProvider } from '@ramme-io/ui';
5
5
  import { AuthProvider } from './features/auth/AuthContext';
6
6
  import { MqttProvider } from './engine/runtime/MqttContext';
7
7
 
8
+
8
9
  // --- 1. IMPORT AUTH CLUSTER ---
9
10
  import { AuthLayout } from './features/auth/pages/AuthLayout';
10
11
  import LoginPage from './features/auth/pages/LoginPage';
@@ -13,6 +14,7 @@ import SignupPage from './features/auth/pages/SignupPage';
13
14
  // --- 2. IMPORT TEMPLATES ---
14
15
  import DashboardLayout from './templates/dashboard/DashboardLayout';
15
16
  import { dashboardSitemap } from './templates/dashboard/dashboard.sitemap';
17
+ import { useDynamicSitemap } from './engine/runtime/useDynamicSitemap';
16
18
  import DocsLayout from './templates/docs/DocsLayout';
17
19
  import { docsSitemap } from './templates/docs/docs.sitemap';
18
20
  import SettingsLayout from './templates/settings/SettingsLayout';
@@ -28,6 +30,7 @@ import { initializeDataLake } from './engine/runtime/data-seeder';
28
30
  import ScrollToTop from './components/ScrollToTop';
29
31
  import HashLinkScroll from './components/HashLinkScroll';
30
32
 
33
+
31
34
  function App() {
32
35
 
33
36
  // Trigger data seeding on mount
@@ -35,8 +38,14 @@ function App() {
35
38
  initializeDataLake();
36
39
  }, []);
37
40
 
41
+ const liveDashboardRoutes = useDynamicSitemap(dashboardSitemap);
42
+
43
+ console.log("🗺️ ROUTER MAP:", liveDashboardRoutes.map(r => ({ path: r.path, id: r.id })));
44
+
45
+
38
46
  return (
39
47
  <ThemeProvider>
48
+
40
49
  <AuthProvider>
41
50
  <MqttProvider>
42
51
  <ScrollToTop />
@@ -60,7 +69,7 @@ function App() {
60
69
  {/* Dashboard Template */}
61
70
  <Route path="/dashboard/*" element={<DashboardLayout />}>
62
71
  <Route index element={<Navigate to="welcome" replace />} />
63
- {generateRoutes(dashboardSitemap)}
72
+ {generateRoutes(liveDashboardRoutes)}
64
73
  </Route>
65
74
 
66
75
  {/* Docs Template */}
@@ -79,6 +88,7 @@ function App() {
79
88
  </Routes>
80
89
  </MqttProvider>
81
90
  </AuthProvider>
91
+
82
92
  </ThemeProvider>
83
93
  );
84
94
  }
@@ -4,9 +4,9 @@
4
4
  * @description This is the global application header.
5
5
  *
6
6
  * @developer_notes
7
- * STRATEGIC REFACTOR (10/21/2025):
8
- * 1. Updated logo to include both the `orange.png` image and "Ramme" text.
9
- * 2. Kept all A.D.A.P.T. manifest, asChild, and z-index fixes.
7
+ * STRATEGIC REFACTOR:
8
+ * 1. Cleaned up Ghost Bridge telemetry for production feel.
9
+ * 2. Kept all A.D.A.P.T. navigation and z-index fixes.
10
10
  */
11
11
  import React from 'react';
12
12
  import { Link } from 'react-router-dom';
@@ -25,7 +25,7 @@ import { useAuth } from '../features/auth/AuthContext';
25
25
  import { appManifest } from '../config/navigation';
26
26
  import type { ManifestLink } from '../engine/types/manifest-types';
27
27
  import TemplateSwitcher from './TemplateSwitcher';
28
- import rammeLogo from '../assets/orange.png'; // <-- 1. IMPORT THE LOGO
28
+ import rammeLogo from '../assets/orange.png';
29
29
 
30
30
  const AppHeader: React.FC = () => {
31
31
  const { theme, availableThemes, setTheme } = useTheme();
@@ -47,13 +47,13 @@ const AppHeader: React.FC = () => {
47
47
  // Z-INDEX FIX: Set to z-50 to render above the z-40 sidebar.
48
48
  <header className="flex items-center justify-between p-4 bg-card border-b border-border shadow-sm sticky top-0 z-50">
49
49
 
50
- {/* --- 2. UPDATED LOGO BLOCK --- */}
51
- {/* Logo - links to dashboard home */}
50
+ {/* --- 1. LOGO BLOCK --- */}
52
51
  <Link to="/dashboard" className="flex items-center gap-2">
53
52
  <img src={rammeLogo} alt="Ramme Logo" className="h-8 w-auto" />
54
53
  <h1 className="text-2xl font-bold text-text">Ramme</h1>
55
54
  </Link>
56
55
 
56
+ {/* --- 2. USER ACTIONS --- */}
57
57
  <div className="flex items-center gap-4">
58
58
  <TemplateSwitcher />
59
59
  {user && (
@@ -64,14 +64,14 @@ const AppHeader: React.FC = () => {
64
64
  </button>
65
65
  }
66
66
  >
67
- {/* 1. User Info (Static) */}
67
+ {/* User Info */}
68
68
  <div className="p-2 text-sm text-muted-foreground">
69
69
  <p className="font-semibold text-text">{user.name}</p>
70
70
  <p>{user.email}</p>
71
71
  </div>
72
72
  <MenuDivider />
73
73
 
74
- {/* 2. Designer-Controlled Nav Links */}
74
+ {/* Navigation Links */}
75
75
  {userNavLinks.map((link: ManifestLink) => (
76
76
  <MenuItem
77
77
  key={link.id}
@@ -83,7 +83,7 @@ const AppHeader: React.FC = () => {
83
83
  ))}
84
84
  <MenuDivider />
85
85
 
86
- {/* 3. App-Specific: Theme Switcher */}
86
+ {/* Theme Switcher */}
87
87
  <div className="p-2 text-sm text-muted-foreground">
88
88
  <p>
89
89
  Active Theme:{' '}
@@ -100,7 +100,7 @@ const AppHeader: React.FC = () => {
100
100
  ))}
101
101
  <MenuDivider />
102
102
 
103
- {/* 4. App-Specific: Actions */}
103
+ {/* Actions */}
104
104
  <MenuItem onClick={handleResetData} icon={<Icon name="refresh-cw" />}>
105
105
  Reset Data
106
106
  </MenuItem>
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { Card } from '@ramme-io/ui';
3
+
4
+ export const ChartLine: React.FC<{ title: string; description?: string }> = ({ title, description }) => {
5
+ return (
6
+ <Card className="p-6 h-full min-h-[300px] flex flex-col">
7
+ <div className="mb-6">
8
+ <h3 className="font-semibold text-lg">{title}</h3>
9
+ {description && <p className="text-sm text-muted-foreground">{description}</p>}
10
+ </div>
11
+
12
+ {/* Visual Mockup of a Chart */}
13
+ <div className="flex-1 flex items-end justify-between gap-2 px-2 pb-2 mt-4 border-b border-l border-border/50">
14
+ {[40, 70, 45, 90, 65, 85, 55, 95, 75, 60, 90, 100].map((h, i) => (
15
+ <div key={i} className="w-full flex flex-col items-center gap-2 group">
16
+ <div
17
+ className="w-full bg-primary/20 group-hover:bg-primary/80 transition-all rounded-t-sm"
18
+ style={{ height: `${h}%` }}
19
+ />
20
+ </div>
21
+ ))}
22
+ </div>
23
+ <div className="flex justify-between mt-2 text-xs text-muted-foreground px-2">
24
+ <span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span>
25
+ </div>
26
+ </Card>
27
+ );
28
+ };
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import { Card } from '@ramme-io/ui';
3
+ import { ArrowUpRight, ArrowDownRight, Activity, Users, DollarSign, CreditCard } from 'lucide-react';
4
+
5
+ interface StatCardProps {
6
+ title: string;
7
+ value: string | number;
8
+ trend?: string;
9
+ status?: 'positive' | 'negative' | 'neutral' | 'offline';
10
+ }
11
+
12
+ export const StatCard: React.FC<StatCardProps> = ({
13
+ title,
14
+ value,
15
+ trend,
16
+ status = 'neutral'
17
+ }) => {
18
+ const statusColors = {
19
+ positive: 'text-green-600 bg-green-100',
20
+ negative: 'text-red-600 bg-red-100',
21
+ neutral: 'text-blue-600 bg-blue-100',
22
+ offline: 'text-gray-400 bg-gray-100',
23
+ };
24
+
25
+ const getIcon = () => {
26
+ switch(title?.toLowerCase()) {
27
+ case 'active users': return <Users size={20} />;
28
+ case 'revenue': return <DollarSign size={20} />;
29
+ case 'sales': return <CreditCard size={20} />;
30
+ default: return <Activity size={20} />;
31
+ }
32
+ };
33
+
34
+ return (
35
+ <Card className="p-6 flex flex-col justify-between h-full border-border/60 hover:shadow-md transition-all">
36
+ <div className="flex justify-between items-start mb-4">
37
+ <div>
38
+ <p className="text-sm font-medium text-muted-foreground">{title}</p>
39
+ <h3 className="text-2xl font-bold mt-1 tracking-tight">{value || '--'}</h3>
40
+ </div>
41
+ <div className={`p-2 rounded-lg ${statusColors[status] || statusColors.neutral}`}>
42
+ {getIcon()}
43
+ </div>
44
+ </div>
45
+
46
+ {trend && (
47
+ <div className="flex items-center gap-1 text-xs font-medium">
48
+ {trend.startsWith('+') ? (
49
+ <ArrowUpRight size={14} className="text-green-600" />
50
+ ) : (
51
+ <ArrowDownRight size={14} className="text-red-600" />
52
+ )}
53
+ <span className={trend.startsWith('+') ? 'text-green-600' : 'text-red-600'}>
54
+ {trend}
55
+ </span>
56
+ <span className="text-muted-foreground ml-1">from last month</span>
57
+ </div>
58
+ )}
59
+ </Card>
60
+ );
61
+ };
@@ -1,56 +1,69 @@
1
1
  import React from 'react';
2
- import {
3
- DeviceCard,
4
- StatCard,
5
- BarChart,
6
- LineChart,
7
- PieChart,
8
- DataTable,
9
- Card,
10
- Alert,
11
- EmptyState,
12
- ToggleSwitch
13
- } from '@ramme-io/ui';
14
-
15
- // ✅ IMPORT YOUR CUSTOM COMPONENT
2
+ // ✅ 1. Import the Master Registry from the UI Library (Tier 1: Atoms)
3
+ // This instantly pulls in Button, Card, Inputs, Layouts, Navigation, etc.
4
+ import { AUTO_REGISTRY } from '@ramme-io/ui';
5
+
6
+ // ✅ 2. Import Local "Smart Blocks" (Tier 2: Logic)
7
+ // These exist only in the App (Starter), not the UI library.
16
8
  import { SmartTable } from '../features/datagrid/SmartTable';
9
+ import { SmartChart } from '../features/visualizations/SmartChart';
17
10
 
11
+ // ✅ 3. MERGE EVERYTHING
18
12
  export const COMPONENT_REGISTRY: Record<string, React.FC<any>> = {
19
- // IoT Primitives
20
- DeviceCard,
21
-
22
- // Data Display
23
- StatCard,
24
- BarChart,
25
- LineChart,
26
- PieChart,
27
-
28
- // Tables
29
- DataTable, // The raw grid
30
-
31
- // ✅ FIX: Map "SmartTable" to the actual SmartTable component
32
- // (Previously it was aliased to DataTable, which broke the UI)
33
- SmartTable: SmartTable,
34
-
35
- // Layout & Feedback
36
- Card,
37
- Alert,
38
- EmptyState,
39
-
40
- // Forms/Controls
41
- ToggleSwitch
13
+ // A. The Entire UI Library (~50+ components)
14
+ ...AUTO_REGISTRY,
15
+
16
+ // B. The Smart Blocks (Data-Connected)
17
+ SmartTable,
18
+ SmartChart,
19
+
20
+ // C. Legacy Aliases (For older AI prompts/manifests)
21
+ 'smart_table': SmartTable,
22
+ 'smart_chart': SmartChart,
23
+ 'stat_card': AUTO_REGISTRY['StatCard'],
24
+ 'chart_line': AUTO_REGISTRY['LineChart'],
25
+ 'chart_bar': AUTO_REGISTRY['BarChart'],
26
+ 'chart_pie': AUTO_REGISTRY['PieChart'],
42
27
  };
43
28
 
29
+ // --- COMPONENT RESOLVER ENGINE ---
44
30
  export const getComponent = (name: string) => {
45
- const Component = COMPONENT_REGISTRY[name];
31
+ // 1. Normalize the key to handle case-insensitivity and snake_case
32
+ // e.g. "page_header" -> "PageHeader", "button" -> "Button"
33
+ const normalizedName = name.replace(/_/g, '').toLowerCase();
46
34
 
35
+ // 2. Lookup Strategy
36
+ // We check the exact name, then the lowercase version, then the normalized version
37
+ const Component =
38
+ COMPONENT_REGISTRY[name] ||
39
+ COMPONENT_MAP_LOWER[name.toLowerCase()] ||
40
+ COMPONENT_MAP_NORMALIZED[normalizedName];
41
+
42
+ // 3. Safety Net (Ghost Placeholder)
47
43
  if (!Component) {
48
- console.warn(`[Registry] Unknown component type: "${name}"`);
49
- return () => (
50
- <Alert variant="danger" title="Unknown Component">
51
- The system tried to render <code>{name}</code> but it was not found in the registry.
52
- </Alert>
44
+ console.warn(`[Registry] Unknown component: "${name}"`);
45
+
46
+ return ({ ...props }) => (
47
+ <div className="p-4 border-2 border-dashed border-red-200 bg-red-50 rounded-lg flex flex-col items-center justify-center text-red-400 min-h-[100px] h-full w-full animate-in fade-in">
48
+ <span className="text-xs font-mono font-bold uppercase tracking-wider">{name}</span>
49
+ <span className="text-[10px] mt-1 opacity-75">Component Missing</span>
50
+ {/* Hidden debug data for developers */}
51
+ <div className="hidden">{JSON.stringify(props)}</div>
52
+ </div>
53
53
  );
54
54
  }
55
55
  return Component;
56
- };
56
+ };
57
+
58
+ // --- OPTIMIZATION: PRE-CALCULATED LOOKUP MAPS ---
59
+ // We generate these once on startup so we don't map/reduce on every render.
60
+
61
+ const COMPONENT_MAP_LOWER = Object.keys(COMPONENT_REGISTRY).reduce((acc, key) => {
62
+ acc[key.toLowerCase()] = COMPONENT_REGISTRY[key];
63
+ return acc;
64
+ }, {} as Record<string, React.FC<any>>);
65
+
66
+ const COMPONENT_MAP_NORMALIZED = Object.keys(COMPONENT_REGISTRY).reduce((acc, key) => {
67
+ acc[key.replace(/_/g, '').toLowerCase()] = COMPONENT_REGISTRY[key];
68
+ return acc;
69
+ }, {} as Record<string, React.FC<any>>);
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { getComponent } from '../../config/component-registry';
3
3
  // @ts-ignore
4
- import { useGeneratedSignals } from '../generated/hooks';
4
+ import { useGeneratedSignals } from '../runtime/useSignalStore';
5
5
  import { getMockData } from '../../data/mockData';
6
6
 
7
7
  /**