@ramme-io/create-app 1.2.1 → 1.2.2
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 +1 -2
- package/template/package.json +41 -0
- package/template/pkg.json +1 -1
- package/template/src/App.tsx +62 -31
- package/template/src/components/AIChatWidget.tsx +2 -2
- package/template/src/components/AppHeader.tsx +2 -2
- 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/config/app.manifest.ts +3 -1
- package/template/src/{core → config}/component-registry.tsx +1 -1
- 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 +27 -7
- package/template/src/{pages → engine/renderers}/DynamicPage.tsx +23 -4
- package/template/src/{contexts → engine/runtime}/MqttContext.tsx +25 -11
- package/template/src/{contexts → engine/runtime}/SitemapContext.tsx +1 -1
- package/template/src/{core → engine/runtime}/data-seeder.ts +15 -5
- package/template/src/{hooks → engine/runtime}/useAction.ts +19 -8
- 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/useSignal.ts +51 -0
- package/template/src/{generated/hooks.ts → engine/runtime/useSignalStore.ts} +35 -8
- package/template/src/{hooks → engine/runtime}/useWorkflowEngine.ts +34 -13
- 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 +4 -6
- 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/index.css +1 -1
- package/template/src/main.tsx +3 -3
- package/template/src/templates/dashboard/DashboardLayout.tsx +75 -106
- package/template/src/templates/dashboard/dashboard.sitemap.ts +26 -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/vite.config.ts +12 -9
- 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/config/dashboard.layout.ts +0 -110
- package/template/src/contexts/AuthContext.tsx +0 -64
- package/template/src/data/mockUsers.ts +0 -18
- package/template/src/hooks/useSignal.ts +0 -83
- 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/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/{components/dev → features/developer}/GhostOverlay.tsx +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,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 '../../
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
</
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
};
|
|
@@ -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
|
},
|
package/template/vite.config.ts
CHANGED
|
@@ -2,22 +2,25 @@ 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: {
|
|
9
8
|
alias: {
|
|
10
9
|
'@': path.resolve(__dirname, './src'),
|
|
10
|
+
|
|
11
|
+
// ✅ FIX: Go up 2 levels to find the sibling 'ramme-ui' folder
|
|
12
|
+
'@ramme-io/ui': path.resolve(__dirname, '../../ramme-ui/src'),
|
|
11
13
|
},
|
|
12
14
|
},
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
// ✅ CRITICAL: Allow Vite to serve files outside the current project folder
|
|
16
|
+
server: {
|
|
17
|
+
fs: {
|
|
18
|
+
allow: [
|
|
19
|
+
// Allow serving files from the project root
|
|
20
|
+
'.',
|
|
21
|
+
// Allow serving files from the sibling UI library
|
|
22
|
+
'../../ramme-ui',
|
|
23
|
+
],
|
|
21
24
|
},
|
|
22
25
|
},
|
|
23
26
|
});
|
|
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;
|