@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.
- package/package.json +9 -15
- package/template/package.json +41 -0
- package/template/pkg.json +9 -7
- package/template/src/App.tsx +72 -31
- package/template/src/components/AIChatWidget.tsx +2 -2
- package/template/src/components/AppHeader.tsx +12 -12
- package/template/src/components/AutoForm.tsx +13 -0
- package/template/src/{pages/styleguide → components}/NotFound.tsx +1 -1
- package/template/src/components/PageTitleUpdater.tsx +2 -2
- package/template/src/components/ProtectedRoute.tsx +18 -1
- package/template/src/components/ScrollToTop.tsx +19 -0
- package/template/src/components/dashboard/ChartLine.tsx +28 -0
- package/template/src/components/dashboard/StatCard.tsx +61 -0
- package/template/src/config/app.manifest.ts +3 -1
- package/template/src/config/component-registry.tsx +69 -0
- package/template/src/config/navigation.ts +1 -1
- package/template/src/data/mock-charts.ts +32 -28
- package/template/src/{components → engine/renderers}/DynamicBlock.tsx +28 -8
- package/template/src/engine/renderers/DynamicPage.tsx +150 -0
- package/template/src/engine/runtime/ManifestContext.tsx +79 -0
- package/template/src/{contexts → engine/runtime}/MqttContext.tsx +23 -14
- package/template/src/{contexts → engine/runtime}/SitemapContext.tsx +1 -1
- package/template/src/engine/runtime/data-seeder.ts +47 -0
- package/template/src/{hooks → engine/runtime}/useAction.ts +11 -14
- package/template/src/{hooks → engine/runtime}/useCrudLocalStorage.ts +27 -8
- package/template/src/{hooks → engine/runtime}/useDataQuery.ts +15 -1
- package/template/src/engine/runtime/useDynamicSitemap.tsx +43 -0
- package/template/src/engine/runtime/useJustInTimeSeeder.ts +76 -0
- package/template/src/engine/runtime/useLiveBridge.ts +44 -0
- package/template/src/engine/runtime/useSignal.ts +40 -0
- package/template/src/{generated/hooks.ts → engine/runtime/useSignalStore.ts} +35 -8
- package/template/src/engine/runtime/useWorkflowEngine.ts +89 -0
- package/template/src/{core → engine/types}/manifest-types.ts +35 -3
- package/template/src/{types → engine/validation}/schema.ts +17 -0
- package/template/src/{pages → features/ai/pages}/AiChat.tsx +1 -1
- package/template/src/features/auth/AuthContext.tsx +118 -0
- package/template/src/features/auth/pages/AuthLayout.tsx +55 -0
- package/template/src/features/auth/pages/LoginPage.tsx +106 -0
- package/template/src/features/auth/pages/SignupPage.tsx +96 -0
- package/template/src/{blocks → features/datagrid}/SmartTable.tsx +41 -25
- package/template/src/features/developer/GhostOverlay.tsx +114 -0
- package/template/src/{pages → features/onboarding/pages}/Welcome.tsx +0 -1
- package/template/src/features/overview/index.ts +1 -0
- package/template/src/features/overview/pages/OverviewPage.tsx +127 -0
- package/template/src/{pages → features/playground/pages}/AccountingLedgerPage.tsx +1 -1
- package/template/src/{pages/prototypes → features/playground/pages}/ItemSelectorPage.tsx +1 -1
- package/template/src/{pages/settings → features/settings/pages}/BillingPage.tsx +1 -1
- package/template/src/features/settings/pages/ProfilePage.tsx +153 -0
- package/template/src/{pages/settings → features/settings/pages}/TeamPage.tsx +1 -1
- package/template/src/features/styleguide/Styleguide.tsx +75 -0
- package/template/src/features/users/components/UserDrawer.tsx +138 -0
- package/template/src/features/users/index.ts +2 -0
- package/template/src/features/users/pages/UsersPage.tsx +151 -0
- package/template/src/features/visualizations/SmartChart.tsx +178 -0
- package/template/src/index.css +1 -1
- package/template/src/main.tsx +27 -15
- package/template/src/templates/dashboard/DashboardLayout.tsx +77 -107
- package/template/src/templates/dashboard/dashboard.sitemap.ts +19 -22
- package/template/src/templates/docs/DocsLayout.tsx +49 -38
- package/template/src/templates/docs/docs.sitemap.ts +22 -34
- package/template/src/templates/settings/SettingsLayout.tsx +83 -143
- package/template/src/templates/settings/settings.sitemap.ts +6 -6
- package/template/tailwind.config.cjs +10 -9
- package/template/vite.config.ts +0 -11
- package/template/src/adaptors/.gitkeep +0 -0
- package/template/src/components/LocalSideNav.tsx +0 -120
- package/template/src/components/PageWithSideNav.tsx +0 -69
- package/template/src/components/dev/GhostOverlay.tsx +0 -68
- package/template/src/config/dashboard.layout.ts +0 -110
- package/template/src/contexts/AuthContext.tsx +0 -64
- package/template/src/core/component-registry.tsx +0 -56
- package/template/src/core/data-seeder.ts +0 -35
- package/template/src/data/mockUsers.ts +0 -18
- package/template/src/hooks/useSignal.ts +0 -83
- package/template/src/hooks/useWorkflowEngine.ts +0 -123
- package/template/src/layouts/DataLayout.tsx +0 -37
- package/template/src/layouts/SideNavLayout.tsx +0 -28
- package/template/src/pages/Dashboard.tsx +0 -60
- package/template/src/pages/DataGridPage.tsx +0 -184
- package/template/src/pages/DynamicPage.tsx +0 -95
- package/template/src/pages/LoginPage.tsx +0 -58
- package/template/src/pages/settings/ProfilePage.tsx +0 -10
- package/template/src/pages/styleguide/Styleguide.tsx +0 -40
- package/template/src/templates/docs/pages/Introduction.tsx +0 -13
- package/template/src/types/signal.ts +0 -23
- /package/template/src/{core → engine/renderers}/route-generator.tsx +0 -0
- /package/template/src/{core → engine/types}/sitemap-entry.ts +0 -0
- /package/template/src/{pages → features}/GenericContentPage.tsx +0 -0
- /package/template/src/{hooks → features/assistant}/useMockChat.ts +0 -0
- /package/template/src/{hooks → features/developer}/useDevTools.ts +0 -0
- /package/template/src/{pages → features}/styleguide/sections/charts/ChartsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/colors/ColorsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/elements/ElementsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/feedback/FeedbackSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/forms/FormsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/icons/IconsSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/layout/LayoutSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/navigation/NavigationSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/tables/TablesSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/templates/TemplatesSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/theming/ThemingSection.tsx +0 -0
- /package/template/src/{pages → features}/styleguide/sections/utilities/UtilitiesSection.tsx +0 -0
|
@@ -1,34 +1,33 @@
|
|
|
1
|
-
import { type SitemapEntry } from '../../
|
|
1
|
+
import { type SitemapEntry } from '../../engine/types/sitemap-entry';
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import AccountingLedgerPage from '../../pages/AccountingLedgerPage';
|
|
8
|
-
import Styleguide from '../../pages/styleguide/Styleguide';
|
|
9
|
-
import DataLayout from '../../layouts/DataLayout';
|
|
3
|
+
// --- PAGE IMPORTS ---
|
|
4
|
+
// ✅ Corrected: Kept named import for OverviewPage based on your index.ts export
|
|
5
|
+
import { OverviewPage } from '../../features/overview';
|
|
6
|
+
import AiChat from '../../features/ai/pages/AiChat';
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
8
|
+
import Styleguide from '../../features/styleguide/Styleguide';
|
|
9
|
+
|
|
10
|
+
// --- SECTION IMPORTS ---
|
|
11
|
+
import TemplatesSection from '../../features/styleguide/sections/templates/TemplatesSection';
|
|
12
|
+
import LayoutSection from '../../features/styleguide/sections/layout/LayoutSection';
|
|
13
|
+
import ThemingSection from '../../features/styleguide/sections/theming/ThemingSection';
|
|
14
|
+
import NavigationSection from '../../features/styleguide/sections/navigation/NavigationSection';
|
|
15
|
+
import TablesSection from '../../features/styleguide/sections/tables/TablesSection';
|
|
16
|
+
import ChartsSection from '../../features/styleguide/sections/charts/ChartsSection';
|
|
17
|
+
import ElementsSection from '../../features/styleguide/sections/elements/ElementsSection';
|
|
18
|
+
import FormsSection from '../../features/styleguide/sections/forms/FormsSection';
|
|
19
|
+
import FeedbackSection from '../../features/styleguide/sections/feedback/FeedbackSection';
|
|
20
|
+
import UtilitiesSection from '../../features/styleguide/sections/utilities/UtilitiesSection';
|
|
21
|
+
import ColorsSection from '../../features/styleguide/sections/colors/ColorsSection';
|
|
22
|
+
import IconsSection from '../../features/styleguide/sections/icons/IconsSection';
|
|
24
23
|
|
|
25
24
|
export const docsSitemap: SitemapEntry[] = [
|
|
26
25
|
{
|
|
27
26
|
id: 'dashboard',
|
|
28
|
-
path: '', // Index route
|
|
27
|
+
path: '', // Index route
|
|
29
28
|
title: 'Dashboard',
|
|
30
29
|
icon: 'home',
|
|
31
|
-
component:
|
|
30
|
+
component: OverviewPage,
|
|
32
31
|
},
|
|
33
32
|
{
|
|
34
33
|
id: 'ai-chat',
|
|
@@ -37,17 +36,6 @@ export const docsSitemap: SitemapEntry[] = [
|
|
|
37
36
|
icon: 'bot',
|
|
38
37
|
component: AiChat,
|
|
39
38
|
},
|
|
40
|
-
{
|
|
41
|
-
id: 'data',
|
|
42
|
-
path: 'data',
|
|
43
|
-
title: 'Data',
|
|
44
|
-
icon: 'database',
|
|
45
|
-
component: DataLayout,
|
|
46
|
-
children: [
|
|
47
|
-
{ id: 'grid', path: 'grid', title: 'Data Grid', component: DataGridPage, icon: 'table' },
|
|
48
|
-
{ id: 'ledger', path: 'ledger', title: 'Ledger', component: AccountingLedgerPage, icon: 'book-open' },
|
|
49
|
-
],
|
|
50
|
-
},
|
|
51
39
|
{
|
|
52
40
|
id: 'styleguide',
|
|
53
41
|
path: 'styleguide',
|
|
@@ -1,170 +1,110 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @repository ramme-app-starter
|
|
4
|
-
* @description
|
|
5
|
-
* Sidebar-Only layout. Moved TemplateSwitcher to SidebarContent.
|
|
6
|
-
* Includes all previous fixes (href, icons, conditional branding, providers, etc.).
|
|
7
|
-
* Confirmed handleResetData is included.
|
|
8
|
-
*/
|
|
9
|
-
import React from 'react';
|
|
10
|
-
import { Outlet, NavLink, Link } from 'react-router-dom';
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
|
11
3
|
import {
|
|
12
4
|
Sidebar,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
SidebarContent,
|
|
16
|
-
SidebarFooter,
|
|
17
|
-
SidebarMenu,
|
|
18
|
-
SidebarMenuItem,
|
|
19
|
-
useSidebar,
|
|
20
|
-
Button,
|
|
21
|
-
Icon,
|
|
22
|
-
Avatar,
|
|
23
|
-
Menu,
|
|
24
|
-
MenuItem,
|
|
25
|
-
MenuDivider,
|
|
26
|
-
useTheme,
|
|
27
|
-
type ThemeName,
|
|
5
|
+
type SidebarItem,
|
|
6
|
+
type IconName,
|
|
28
7
|
} from '@ramme-io/ui';
|
|
29
8
|
import { settingsSitemap } from './settings.sitemap';
|
|
30
9
|
import rammeLogo from '../../assets/orange.png';
|
|
31
|
-
import { useAuth } from '../../
|
|
32
|
-
import {
|
|
33
|
-
import type { ManifestLink } from '../../core/manifest-types';
|
|
34
|
-
import { SitemapProvider } from '../../contexts/SitemapContext';
|
|
10
|
+
import { useAuth } from '../../features/auth/AuthContext';
|
|
11
|
+
import { SitemapProvider } from '../../engine/runtime/SitemapContext';
|
|
35
12
|
import PageTitleUpdater from '../../components/PageTitleUpdater';
|
|
36
|
-
// --- Import TemplateSwitcher ---
|
|
37
13
|
import TemplateSwitcher from '../../components/TemplateSwitcher';
|
|
38
14
|
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
return <NavLink ref={ref} to={href || ''} {...props} end={end} />;
|
|
43
|
-
},
|
|
44
|
-
);
|
|
45
|
-
SidebarNavLink.displayName = 'SidebarNavLink';
|
|
46
|
-
|
|
47
|
-
// Sidebar Content Component
|
|
48
|
-
const AppSidebarContent: React.FC = () => {
|
|
49
|
-
const { isOpen, toggle } = useSidebar();
|
|
50
|
-
const { theme, availableThemes, setTheme } = useTheme();
|
|
15
|
+
const SettingsLayout: React.FC = () => {
|
|
16
|
+
const navigate = useNavigate();
|
|
17
|
+
const location = useLocation();
|
|
51
18
|
const { user, logout } = useAuth();
|
|
52
|
-
const userNavLinks = appManifest.userMenu;
|
|
53
19
|
|
|
54
|
-
// ---
|
|
20
|
+
// --- Actions ---
|
|
55
21
|
const handleResetData = () => {
|
|
56
|
-
if (
|
|
57
|
-
window.confirm(
|
|
58
|
-
'Are you sure you want to reset all user data? This cannot be undone.',
|
|
59
|
-
)
|
|
60
|
-
) {
|
|
22
|
+
if (window.confirm('Are you sure you want to reset all user data? This cannot be undone.')) {
|
|
61
23
|
localStorage.removeItem('users');
|
|
62
24
|
window.location.reload();
|
|
63
25
|
}
|
|
64
26
|
};
|
|
65
27
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<img src={rammeLogo} alt="Ramme Logo" className="h-7 w-auto" />
|
|
78
|
-
<span className="text-xl font-bold text-text">Ramme</span>
|
|
79
|
-
</Link>
|
|
80
|
-
|
|
81
|
-
{/* TemplateSwitcher REMOVED from here */}
|
|
28
|
+
// --- Data Mapping ---
|
|
29
|
+
// We combine the Sitemap navigation with the System Actions (Reset/Logout)
|
|
30
|
+
// so they all live harmoniously in the new "Zero Jank" sidebar list.
|
|
31
|
+
const sidebarItems: SidebarItem[] = useMemo(() => {
|
|
32
|
+
// 1. Navigation Items
|
|
33
|
+
const navItems: SidebarItem[] = settingsSitemap.map((item) => ({
|
|
34
|
+
id: item.id,
|
|
35
|
+
label: item.title,
|
|
36
|
+
icon: (item.icon as IconName) || 'settings',
|
|
37
|
+
href: item.path ? `/settings/${item.path}` : '/settings',
|
|
38
|
+
}));
|
|
82
39
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
40
|
+
// 2. System Actions (Appended to bottom)
|
|
41
|
+
const actionItems: SidebarItem[] = [
|
|
42
|
+
{
|
|
43
|
+
id: 'action-reset',
|
|
44
|
+
label: 'Reset Data',
|
|
45
|
+
icon: 'refresh-cw' as IconName,
|
|
46
|
+
onClick: handleResetData,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'action-logout',
|
|
50
|
+
label: 'Logout',
|
|
51
|
+
icon: 'log-out' as IconName,
|
|
52
|
+
onClick: logout,
|
|
53
|
+
}
|
|
54
|
+
];
|
|
93
55
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
{/* Only visible when sidebar is open */}
|
|
97
|
-
<div className={`mb-4 transition-opacity duration-200 ${!isOpen ? 'opacity-0 hidden' : 'opacity-100'}`}>
|
|
98
|
-
<TemplateSwitcher />
|
|
99
|
-
</div>
|
|
56
|
+
return [...navItems, ...actionItems];
|
|
57
|
+
}, [logout]);
|
|
100
58
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
tooltip={item.title}
|
|
109
|
-
>
|
|
110
|
-
{item.title}
|
|
111
|
-
</SidebarMenuItem>
|
|
112
|
-
))}
|
|
113
|
-
</SidebarMenu>
|
|
114
|
-
</SidebarContent>
|
|
59
|
+
// Determine active item (only for nav items, actions don't stay active)
|
|
60
|
+
const activeItemId = useMemo(() => {
|
|
61
|
+
const active = sidebarItems.find(item =>
|
|
62
|
+
item.href && item.href !== '/settings' && location.pathname.startsWith(item.href)
|
|
63
|
+
);
|
|
64
|
+
return active?.id || (location.pathname === '/settings' ? sidebarItems[0]?.id : undefined);
|
|
65
|
+
}, [location.pathname, sidebarItems]);
|
|
115
66
|
|
|
116
|
-
<SidebarFooter>
|
|
117
|
-
{user && (
|
|
118
|
-
<Menu position="top-right" trigger={
|
|
119
|
-
<button className="flex items-center gap-3 w-full text-left rounded-md p-2 hover:bg-muted focus:outline-none focus:ring-2 focus:ring-primary">
|
|
120
|
-
<Avatar name={user.name} size="sm" />
|
|
121
|
-
<div className={`flex-1 transition-opacity duration-200 ${!isOpen ? 'opacity-0 hidden' : 'opacity-100'}`}>
|
|
122
|
-
<p className="font-semibold text-sm text-text">{user.name}</p>
|
|
123
|
-
<p className="text-xs text-muted-foreground">{user.email}</p>
|
|
124
|
-
</div>
|
|
125
|
-
</button>
|
|
126
|
-
}>
|
|
127
|
-
{/* User Menu Content */}
|
|
128
|
-
{userNavLinks.map((link: ManifestLink) => (
|
|
129
|
-
<MenuItem key={link.id} asChild icon={link.icon ? <Icon name={link.icon} /> : undefined}>
|
|
130
|
-
<Link to={link.path}>{link.title}</Link>
|
|
131
|
-
</MenuItem>
|
|
132
|
-
))}
|
|
133
|
-
<MenuDivider />
|
|
134
|
-
{availableThemes.map((themeName: string) => (
|
|
135
|
-
<MenuItem key={themeName} onClick={() => setTheme(themeName as ThemeName)}>
|
|
136
|
-
{themeName.charAt(0).toUpperCase() + themeName.slice(1)}
|
|
137
|
-
</MenuItem>
|
|
138
|
-
))}
|
|
139
|
-
<MenuDivider />
|
|
140
|
-
{/* Calls handleResetData */}
|
|
141
|
-
<MenuItem onClick={handleResetData} icon={<Icon name="refresh-cw" />}> Reset Data </MenuItem>
|
|
142
|
-
{/* Calls logout */}
|
|
143
|
-
<MenuItem onClick={logout} icon={<Icon name="log-out" />}> Logout </MenuItem>
|
|
144
|
-
</Menu>
|
|
145
|
-
)}
|
|
146
|
-
</SidebarFooter>
|
|
147
|
-
</>
|
|
148
|
-
);
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
// Main layout component
|
|
152
|
-
const SettingsLayout: React.FC = () => {
|
|
153
67
|
return (
|
|
154
68
|
<SitemapProvider value={settingsSitemap}>
|
|
155
69
|
<PageTitleUpdater />
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
70
|
+
|
|
71
|
+
<div className="flex h-screen bg-background text-foreground">
|
|
72
|
+
<Sidebar
|
|
73
|
+
className="relative border-border"
|
|
74
|
+
items={sidebarItems}
|
|
75
|
+
activeItemId={activeItemId}
|
|
76
|
+
// Handle both Navigation (href) and Actions (onClick)
|
|
77
|
+
onNavigate={(item) => {
|
|
78
|
+
if (item.href) {
|
|
79
|
+
navigate(item.href);
|
|
80
|
+
}
|
|
81
|
+
// item.onClick is handled automatically by the Sidebar component if present
|
|
82
|
+
}}
|
|
83
|
+
user={user ? {
|
|
84
|
+
name: user.name,
|
|
85
|
+
email: user.email,
|
|
86
|
+
avatarUrl: undefined // Add avatar URL if available in user object
|
|
87
|
+
} : undefined}
|
|
88
|
+
logo={
|
|
89
|
+
<div className="flex items-center gap-2 px-2">
|
|
90
|
+
<img src={rammeLogo} alt="Ramme" className="h-7 w-auto" />
|
|
91
|
+
<span className="text-xl font-bold">Ramme</span>
|
|
92
|
+
</div>
|
|
93
|
+
}
|
|
94
|
+
// Inject the TemplateSwitcher into the footer slot (above the user profile)
|
|
95
|
+
footerSlot={
|
|
96
|
+
<div className="mb-2">
|
|
97
|
+
<TemplateSwitcher />
|
|
98
|
+
</div>
|
|
99
|
+
}
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
<div className="flex flex-col flex-1 overflow-hidden">
|
|
103
|
+
<main className="flex-1 overflow-y-auto p-8 bg-muted/20">
|
|
104
|
+
<Outlet />
|
|
105
|
+
</main>
|
|
166
106
|
</div>
|
|
167
|
-
</
|
|
107
|
+
</div>
|
|
168
108
|
</SitemapProvider>
|
|
169
109
|
);
|
|
170
110
|
};
|
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
* Defines the Information Architecture (IA) for the "Settings" layout.
|
|
6
6
|
* Imports components from the /pages/settings/ directory.
|
|
7
7
|
*/
|
|
8
|
-
import type { SitemapEntry } from '../../
|
|
8
|
+
import type { SitemapEntry } from '../../engine/types/sitemap-entry';
|
|
9
9
|
|
|
10
10
|
// --- 1. Import from the new /pages/settings/ directory ---
|
|
11
|
-
import ProfilePage from '../../
|
|
12
|
-
import BillingPage from '../../
|
|
13
|
-
import TeamPage from '../../
|
|
11
|
+
import ProfilePage from '../../features/settings/pages/ProfilePage';
|
|
12
|
+
import BillingPage from '../../features/settings/pages/BillingPage';
|
|
13
|
+
import TeamPage from '../../features/settings/pages/TeamPage';
|
|
14
14
|
|
|
15
15
|
// --- 2. Export with the correct name ---
|
|
16
16
|
export const settingsSitemap: SitemapEntry[] = [
|
|
17
17
|
{
|
|
18
|
-
id: '
|
|
18
|
+
id: 'profile',
|
|
19
19
|
path: 'profile',
|
|
20
|
-
title: 'Profile',
|
|
20
|
+
title: 'My Profile',
|
|
21
21
|
icon: 'user',
|
|
22
22
|
component: ProfilePage,
|
|
23
23
|
},
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
|
|
3
|
-
// This finds the absolute path to the @ramme-io/ui package's directory
|
|
4
|
-
const rammeUiPath = path.dirname(require.resolve('@ramme-io/ui/package.json'));
|
|
5
|
-
|
|
6
1
|
/** @type {import('tailwindcss').Config} */
|
|
7
2
|
module.exports = {
|
|
8
3
|
presets: [
|
|
9
|
-
//
|
|
10
|
-
require(
|
|
4
|
+
// ✅ STANDARD: Directly require the preset from the package
|
|
5
|
+
require('@ramme-io/ui/tailwind.preset.js')
|
|
11
6
|
],
|
|
12
7
|
content: [
|
|
13
8
|
"./index.html",
|
|
14
9
|
"./src/**/*.{js,ts,jsx,tsx}",
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
|
|
11
|
+
// ✅ STANDARD: Point directly to node_modules relative to this config file
|
|
12
|
+
// This is the industry standard way (like how Flowbite or Shadcn work)
|
|
13
|
+
"./node_modules/@ramme-io/ui/dist/**/*.{js,ts,jsx,tsx}"
|
|
17
14
|
],
|
|
15
|
+
theme: {
|
|
16
|
+
extend: {},
|
|
17
|
+
},
|
|
18
|
+
plugins: [],
|
|
18
19
|
}
|
package/template/vite.config.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { defineConfig } from 'vite';
|
|
|
2
2
|
import react from '@vitejs/plugin-react';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
|
-
// https://vitejs.dev/config/
|
|
6
5
|
export default defineConfig({
|
|
7
6
|
plugins: [react()],
|
|
8
7
|
resolve: {
|
|
@@ -10,14 +9,4 @@ export default defineConfig({
|
|
|
10
9
|
'@': path.resolve(__dirname, './src'),
|
|
11
10
|
},
|
|
12
11
|
},
|
|
13
|
-
// ADD THIS SECTION to ensure the linked dependency is correctly
|
|
14
|
-
// processed and watched for changes by the Vite dev server.
|
|
15
|
-
optimizeDeps: {
|
|
16
|
-
include: ['@ramme-io/ui'],
|
|
17
|
-
},
|
|
18
|
-
build: {
|
|
19
|
-
commonjsOptions: {
|
|
20
|
-
include: [/@ramme\/ui/, /node_modules/],
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
12
|
});
|
|
File without changes
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { NavLink, useLocation } from 'react-router-dom';
|
|
3
|
-
import { Icon, type IconName } from '@ramme-io/ui';
|
|
4
|
-
import { motion, AnimatePresence } from 'framer-motion';
|
|
5
|
-
|
|
6
|
-
export interface NavItem {
|
|
7
|
-
label: string;
|
|
8
|
-
href: string;
|
|
9
|
-
icon?: IconName;
|
|
10
|
-
children?: NavItem[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface LocalSideNavProps {
|
|
14
|
-
navItems: NavItem[];
|
|
15
|
-
className?: string;
|
|
16
|
-
onLinkClick?: () => void; // 1. Add the optional prop
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const LocalSideNav: React.FC<LocalSideNavProps> = ({ navItems, className, onLinkClick }) => { // 2. Destructure prop
|
|
20
|
-
const location = useLocation();
|
|
21
|
-
const [expandedItems, setExpandedItems] = useState<Record<string, boolean>>({});
|
|
22
|
-
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const currentParent = navItems.find(item =>
|
|
25
|
-
item.children?.some(child => location.pathname === child.href)
|
|
26
|
-
);
|
|
27
|
-
if (currentParent) {
|
|
28
|
-
setExpandedItems(prev => ({ ...prev, [currentParent.href]: true }));
|
|
29
|
-
}
|
|
30
|
-
}, [location.pathname, navItems]);
|
|
31
|
-
|
|
32
|
-
const handleToggle = (href: string) => {
|
|
33
|
-
setExpandedItems(prev => ({ ...prev, [href]: !prev[href] }));
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const childNavLinkClasses = ({ isActive }: { isActive: boolean }) =>
|
|
37
|
-
`flex items-center gap-2 text-sm transition-colors duration-200 py-1 ${
|
|
38
|
-
isActive
|
|
39
|
-
? 'text-primary font-medium'
|
|
40
|
-
: 'text-muted-foreground hover:text-text'
|
|
41
|
-
}`;
|
|
42
|
-
|
|
43
|
-
const renderNavLinks = (items: NavItem[]) => {
|
|
44
|
-
return items.map(item => {
|
|
45
|
-
const isExpanded = !!expandedItems[item.href];
|
|
46
|
-
|
|
47
|
-
if (item.children) {
|
|
48
|
-
return (
|
|
49
|
-
//Section link
|
|
50
|
-
<li key={item.href}>
|
|
51
|
-
<button
|
|
52
|
-
onClick={() => handleToggle(item.href)}
|
|
53
|
-
className="flex w-full items-center justify-between gap-2 py-1 font-normal text-text transition-colors duration-200 hover:text-primary"
|
|
54
|
-
>
|
|
55
|
-
<span className="flex items-center gap-2">
|
|
56
|
-
{item.icon && <Icon name={item.icon} className="h-4 w-4" />}
|
|
57
|
-
<span className="text-md">{item.label}</span>
|
|
58
|
-
</span>
|
|
59
|
-
<Icon
|
|
60
|
-
name="chevron-right"
|
|
61
|
-
className={`h-4 w-4 transition-transform duration-200 ${isExpanded ? 'rotate-90' : ''}`}
|
|
62
|
-
/>
|
|
63
|
-
</button>
|
|
64
|
-
<AnimatePresence initial={false}>
|
|
65
|
-
{isExpanded && (
|
|
66
|
-
<motion.ul
|
|
67
|
-
key="content"
|
|
68
|
-
initial="collapsed"
|
|
69
|
-
animate="open"
|
|
70
|
-
exit="collapsed"
|
|
71
|
-
variants={{
|
|
72
|
-
open: { opacity: 1, height: 'auto' },
|
|
73
|
-
collapsed: { opacity: 0, height: 0 },
|
|
74
|
-
}}
|
|
75
|
-
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
|
76
|
-
className="space-y-1 overflow-hidden border-l border-border pl-5 mt-1 ml-1"
|
|
77
|
-
>
|
|
78
|
-
{item.children.map(child => (
|
|
79
|
-
<li key={child.href}>
|
|
80
|
-
<NavLink
|
|
81
|
-
to={child.href}
|
|
82
|
-
className={childNavLinkClasses}
|
|
83
|
-
onClick={onLinkClick} // 3. Add onClick to child NavLink
|
|
84
|
-
>
|
|
85
|
-
{child.label}
|
|
86
|
-
</NavLink>
|
|
87
|
-
</li>
|
|
88
|
-
))}
|
|
89
|
-
</motion.ul>
|
|
90
|
-
)}
|
|
91
|
-
</AnimatePresence>
|
|
92
|
-
</li>
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<li key={item.href}>
|
|
98
|
-
<NavLink
|
|
99
|
-
to={item.href}
|
|
100
|
-
className="flex items-center gap-2 py-1 text-lg font-semibold"
|
|
101
|
-
onClick={onLinkClick} // 3. Add onClick to top-level NavLink
|
|
102
|
-
>
|
|
103
|
-
{item.icon && <Icon name={item.icon} className="h-4 w-4" />}
|
|
104
|
-
{item.label}
|
|
105
|
-
</NavLink>
|
|
106
|
-
</li>
|
|
107
|
-
);
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
return (
|
|
112
|
-
<nav className={`w-full ${className || ''}`}>
|
|
113
|
-
<ul className="space-y-1">
|
|
114
|
-
{renderNavLinks(navItems)}
|
|
115
|
-
</ul>
|
|
116
|
-
</nav>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
export default LocalSideNav;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Button, Drawer, Icon } from '@ramme-io/ui';
|
|
3
|
-
import LocalSideNav from './LocalSideNav';
|
|
4
|
-
import type { NavItem } from './LocalSideNav';
|
|
5
|
-
|
|
6
|
-
interface PageWithSideNavProps {
|
|
7
|
-
navItems: NavItem[];
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
sideNavHeader?: React.ReactNode;
|
|
10
|
-
contentWidth?: 'fixed' | 'full';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const PageWithSideNav: React.FC<PageWithSideNavProps> = ({
|
|
14
|
-
navItems,
|
|
15
|
-
children,
|
|
16
|
-
sideNavHeader,
|
|
17
|
-
contentWidth = 'fixed',
|
|
18
|
-
}) => {
|
|
19
|
-
const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);
|
|
20
|
-
|
|
21
|
-
const contentContainerClass = contentWidth === 'fixed'
|
|
22
|
-
? 'max-w-7xl mx-auto'
|
|
23
|
-
: '';
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<div className="flex flex-col md:flex-row h-full">
|
|
27
|
-
{/* --- Mobile Header --- */}
|
|
28
|
-
<div className="md:hidden p-4 bg-card border-b border-border flex items-center justify-between sticky top-[65px] z-10">
|
|
29
|
-
{sideNavHeader}
|
|
30
|
-
<Button onClick={() => setIsMobileNavOpen(true)} variant="ghost" size="icon">
|
|
31
|
-
<Icon name="panel-left" />
|
|
32
|
-
</Button>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
{/* --- Desktop Sidebar --- */}
|
|
36
|
-
<aside className="hidden md:flex flex-col w-64 border-r border-border p-4 sticky top-[65px] h-[calc(100vh-65px)]">
|
|
37
|
-
{sideNavHeader}
|
|
38
|
-
<LocalSideNav navItems={navItems} className="mt-1" />
|
|
39
|
-
</aside>
|
|
40
|
-
|
|
41
|
-
{/* --- Mobile Drawer --- */}
|
|
42
|
-
<Drawer
|
|
43
|
-
isOpen={isMobileNavOpen}
|
|
44
|
-
onClose={() => setIsMobileNavOpen(false)}
|
|
45
|
-
position="left"
|
|
46
|
-
>
|
|
47
|
-
<div className="p-4">
|
|
48
|
-
<Button
|
|
49
|
-
onClick={() => setIsMobileNavOpen(false)}
|
|
50
|
-
variant="ghost"
|
|
51
|
-
size="icon"
|
|
52
|
-
className="absolute top-4 right-4"
|
|
53
|
-
>
|
|
54
|
-
<Icon name="x" />
|
|
55
|
-
</Button>
|
|
56
|
-
<div className="mt-2">{sideNavHeader}</div>
|
|
57
|
-
<LocalSideNav navItems={navItems} onLinkClick={() => setIsMobileNavOpen(false)} />
|
|
58
|
-
</div>
|
|
59
|
-
</Drawer>
|
|
60
|
-
|
|
61
|
-
{/* --- Main Content --- */}
|
|
62
|
-
<main className="flex-1 p-6 overflow-y-auto">
|
|
63
|
-
<div className={contentContainerClass}>
|
|
64
|
-
{children}
|
|
65
|
-
</div>
|
|
66
|
-
</main>
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
69
|
-
};
|