@akinon/ui-shell-dev 1.1.0 → 1.2.0

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 (40) hide show
  1. package/dist/akinon-favicon.png +0 -0
  2. package/dist/akinon-logo.png +0 -0
  3. package/dist/akinon-logo.svg +10 -0
  4. package/dist/assets/index-BFs1gfY5.css +1 -0
  5. package/dist/assets/index-Dk6Gr15i.js +408 -0
  6. package/dist/assets/jost-cyrillic-wght-normal-B0_vFdaS.woff2 +0 -0
  7. package/dist/assets/jost-latin-ext-wght-normal-B4kqP43q.woff2 +0 -0
  8. package/dist/assets/jost-latin-wght-normal-CfFW3YMY.woff2 +0 -0
  9. package/dist/index.html +2 -2
  10. package/dist/logo.png +0 -0
  11. package/dist/symbol.png +0 -0
  12. package/package.json +7 -3
  13. package/public/akinon-favicon.png +0 -0
  14. package/public/akinon-logo.png +0 -0
  15. package/public/akinon-logo.svg +10 -0
  16. package/public/logo.png +0 -0
  17. package/public/symbol.png +0 -0
  18. package/src/components/AppLayout.tsx +8 -26
  19. package/src/components/Header.tsx +20 -11
  20. package/src/components/Navigation.tsx +37 -64
  21. package/src/components/PageContent.tsx +9 -0
  22. package/src/components/PageHeading.tsx +61 -0
  23. package/src/components/PluginTestPage.scss +26 -0
  24. package/src/components/PluginTestPage.tsx +89 -207
  25. package/src/components/WelcomePage.tsx +72 -69
  26. package/src/components/layout.scss +26 -24
  27. package/src/global.scss +33 -0
  28. package/src/main.tsx +8 -2
  29. package/src/pages/Dashboard.tsx +25 -0
  30. package/src/pages/External.tsx +15 -0
  31. package/src/pages/PluginTest.tsx +7 -0
  32. package/src/pages/pages.scss +9 -0
  33. package/src/providers.tsx +108 -0
  34. package/src/routes.tsx +44 -0
  35. package/src/server/dev-server.mjs +18 -15
  36. package/src/shell-app.tsx +12 -3
  37. package/src/utils/navigation.tsx +65 -0
  38. package/dist/assets/index-cI-pE1VB.js +0 -387
  39. package/dist/assets/index-tRJwBFdH.css +0 -1
  40. package/src/components/AppRouter.tsx +0 -41
@@ -0,0 +1,108 @@
1
+ import type { ApplicationActions, RegisteredApp } from '@akinon/app-shell';
2
+ import { AppShellProvider, type ShellNavigation } from '@akinon/app-shell';
3
+ import { notification } from '@akinon/ui-react';
4
+ import React from 'react';
5
+ import { useNavigate, useSearchParams } from 'react-router-dom';
6
+
7
+ import type { ShellConfig } from './types';
8
+
9
+ interface ProvidersProps {
10
+ config: ShellConfig;
11
+ children: React.ReactNode;
12
+ }
13
+
14
+ export const Providers: React.FC<ProvidersProps> = ({ config, children }) => {
15
+ const [api, contextHolder] = notification.useNotification();
16
+ const [searchParams] = useSearchParams();
17
+ const navigate = useNavigate();
18
+
19
+ // Convert shell config to apps format for AppShellProvider
20
+ const apps: RegisteredApp[] = [
21
+ {
22
+ id: 1,
23
+ url: config.plugin.url,
24
+ slug: config.plugin.name.toLowerCase().replace(/\s+/g, '-'),
25
+ path: '', // Empty path for development like playground
26
+ type: config.plugin.type === 'fullpage' ? 'full_page' : 'plugin',
27
+ name: config.plugin.name
28
+ }
29
+ ];
30
+
31
+ const navigation: ShellNavigation = {
32
+ navigate: ({ id, path, external }: any) => {
33
+ const app = apps.find(app => app.id === id);
34
+ if (!app) return;
35
+
36
+ const uri = external ? path : `/external/${app.slug}${path || ''}`;
37
+ navigate(uri);
38
+ }
39
+ };
40
+
41
+ const data = {
42
+ lng: 'en',
43
+ username: 'Developer',
44
+ searchParams: Object.fromEntries([...searchParams])
45
+ };
46
+
47
+ const defaultActions = {
48
+ showModalDialog: () => {
49
+ // Implementation for showing a modal dialog
50
+ },
51
+ showToast: (
52
+ content: string,
53
+ type: 'success' | 'error' | 'info' | 'warning' | 'loading' | 'destroy'
54
+ ) => {
55
+ if (type === 'loading' || type === 'destroy') {
56
+ return;
57
+ }
58
+ api[type]({
59
+ message: content,
60
+ placement: 'top'
61
+ });
62
+ },
63
+ showErrorMessage: (title: string, content: string) => {
64
+ api.error({
65
+ message: title,
66
+ description: content,
67
+ placement: 'top'
68
+ });
69
+ },
70
+ showRichModal: () => {
71
+ // Rich modal implementation
72
+ }
73
+ };
74
+
75
+ const customActions = {
76
+ reloadPage: () => window.location.reload(),
77
+ logMessage: (newItem: Object) => {
78
+ try {
79
+ const prevItems = JSON.parse(
80
+ localStorage.getItem('logMessages') || '[]'
81
+ );
82
+ localStorage.setItem(
83
+ 'logMessages',
84
+ JSON.stringify([...prevItems, newItem])
85
+ );
86
+ } catch {}
87
+ }
88
+ };
89
+
90
+ const actions: ApplicationActions = {
91
+ ...defaultActions,
92
+ actions: {
93
+ ...customActions
94
+ }
95
+ };
96
+
97
+ return (
98
+ <AppShellProvider
99
+ apps={apps}
100
+ navigation={navigation}
101
+ data={data}
102
+ actions={actions}
103
+ >
104
+ {children}
105
+ {contextHolder}
106
+ </AppShellProvider>
107
+ );
108
+ };
package/src/routes.tsx ADDED
@@ -0,0 +1,44 @@
1
+ import { useAppShell } from '@akinon/app-shell';
2
+ import React from 'react';
3
+ import { Route, Routes as ReactRouterRoutes } from 'react-router-dom';
4
+
5
+ import { PageDashboard } from './pages/Dashboard';
6
+ import { PageExternal } from './pages/External';
7
+ import { PagePluginTest } from './pages/PluginTest';
8
+
9
+ export const Routes = () => {
10
+ const { apps, configs } = useAppShell();
11
+ const fullpageApps = apps.filter(app => app.type === 'full_page');
12
+
13
+ return (
14
+ <ReactRouterRoutes>
15
+ {fullpageApps.map(app => (
16
+ <Route key={app.id} path={`/external/${app.slug}`}>
17
+ <Route index element={<PageExternal id={app.id} path={app.path} />} />
18
+
19
+ {(configs.get(app.id) as any)?.menu?.map((sub: any) => {
20
+ return (
21
+ sub.path !== '/' && (
22
+ <Route
23
+ key={sub.path}
24
+ path={`/external/${app.slug}${sub.path}`}
25
+ element={
26
+ <PageExternal
27
+ id={app.id}
28
+ path={
29
+ app.subSlug ? `${app.subSlug}${sub.path}` : sub.path
30
+ }
31
+ />
32
+ }
33
+ />
34
+ )
35
+ );
36
+ })}
37
+ </Route>
38
+ ))}
39
+
40
+ <Route path="/plugin-test" element={<PagePluginTest />} />
41
+ <Route path="/" element={<PageDashboard />} />
42
+ </ReactRouterRoutes>
43
+ );
44
+ };
@@ -35,12 +35,13 @@ export class ShellDevServer {
35
35
  async start() {
36
36
  try {
37
37
  console.log('🔧 Starting shell server initialization...');
38
-
38
+
39
39
  const shellRoot = path.resolve(__dirname, '../..');
40
40
  const distPath = path.resolve(shellRoot, 'dist');
41
41
  // Only use production mode if explicitly set via env var
42
- const isProduction = process.env.NODE_ENV === 'production' && fs.existsSync(distPath);
43
-
42
+ const isProduction =
43
+ process.env.NODE_ENV === 'production' && fs.existsSync(distPath);
44
+
44
45
  console.log(`📁 Shell root: ${shellRoot}`);
45
46
  console.log(`🏭 Production mode: ${isProduction}`);
46
47
 
@@ -50,14 +51,14 @@ export class ShellDevServer {
50
51
  if (isProduction) {
51
52
  // Production: serve built assets
52
53
  this.app.use('/assets', express.static(path.join(distPath, 'assets')));
53
-
54
+
54
55
  this.app.get('*', (req, res, next) => {
55
56
  if (req.path.startsWith('/api')) {
56
57
  return next();
57
58
  }
58
59
 
59
60
  console.log(`📄 Serving production HTML for: ${req.url}`);
60
-
61
+
61
62
  let template = fs.readFileSync(
62
63
  path.resolve(distPath, 'index.html'),
63
64
  'utf-8'
@@ -85,20 +86,18 @@ export class ShellDevServer {
85
86
 
86
87
  console.log('✅ Vite server created successfully');
87
88
 
88
- // Use Vite middleware for assets and HMR
89
- this.app.use(this.viteServer.middlewares);
90
-
91
- console.log('✅ Vite middleware configured');
92
-
93
- // Serve the shell app (only for HTML requests)
89
+ // Serve the shell app (only for HTML requests) - MUST be before Vite middleware
94
90
  this.app.get('*', async (req, res, next) => {
95
- if (req.path.startsWith('/api') || req.path.startsWith('/src') || req.path.includes('.')) {
91
+ if (
92
+ req.path.startsWith('/api') ||
93
+ req.path.startsWith('/src') ||
94
+ req.path.startsWith('/@') ||
95
+ req.path.includes('.')
96
+ ) {
96
97
  return next();
97
98
  }
98
99
 
99
100
  try {
100
- console.log(`📄 Serving development HTML for: ${req.url}`);
101
-
102
101
  let template = fs.readFileSync(
103
102
  path.resolve(__dirname, '../../index.html'),
104
103
  'utf-8'
@@ -115,7 +114,6 @@ export class ShellDevServer {
115
114
  `<script>window.__SHELL_CONFIG__ = ${JSON.stringify(this.config)};</script>`
116
115
  );
117
116
 
118
- console.log(`✅ HTML processed successfully for ${req.url}`);
119
117
  res.status(200).set({ 'Content-Type': 'text/html' }).end(template);
120
118
  } catch (error) {
121
119
  console.error(`❌ Error serving ${req.url}:`, error);
@@ -123,6 +121,11 @@ export class ShellDevServer {
123
121
  next(error);
124
122
  }
125
123
  });
124
+
125
+ // Use Vite middleware for assets and HMR - MUST be after our route handler
126
+ this.app.use(this.viteServer.middlewares);
127
+
128
+ console.log('✅ Vite middleware configured');
126
129
  }
127
130
 
128
131
  // Start server
package/src/shell-app.tsx CHANGED
@@ -1,7 +1,10 @@
1
1
  import { AkinonUiProvider } from '@akinon/ui-react';
2
2
  import React from 'react';
3
+ import { BrowserRouter } from 'react-router-dom';
3
4
 
4
5
  import { AppLayout } from './components/AppLayout';
6
+ import { Providers } from './providers';
7
+ import { Routes } from './routes';
5
8
  import type { ShellConfig } from './types';
6
9
 
7
10
  interface ShellAppProps {
@@ -10,8 +13,14 @@ interface ShellAppProps {
10
13
 
11
14
  export const ShellApp: React.FC<ShellAppProps> = ({ config }) => {
12
15
  return (
13
- <AkinonUiProvider>
14
- <AppLayout config={config} />
15
- </AkinonUiProvider>
16
+ <BrowserRouter>
17
+ <AkinonUiProvider>
18
+ <Providers config={config}>
19
+ <AppLayout>
20
+ <Routes />
21
+ </AppLayout>
22
+ </Providers>
23
+ </AkinonUiProvider>
24
+ </BrowserRouter>
16
25
  );
17
26
  };
@@ -0,0 +1,65 @@
1
+ import type { RegisteredApp } from '@akinon/app-shell';
2
+ import type { TMenuItemType } from '@akinon/ui-react';
3
+
4
+ const STATIC_NAVIGATION_ITEMS: TMenuItemType[] = [
5
+ {
6
+ key: '/',
7
+ label: 'Welcome',
8
+ icon: 'dashboard'
9
+ },
10
+ {
11
+ key: '/placeholder-1',
12
+ label: 'Settings',
13
+ icon: 'ayarlar',
14
+ disabled: true
15
+ },
16
+ {
17
+ key: '/placeholder-2',
18
+ label: 'Help & Support',
19
+ icon: 'bilgilendirme_servis',
20
+ disabled: true
21
+ }
22
+ ];
23
+
24
+ const PLUGIN_NAVIGATION_ITEMS: TMenuItemType[] = [
25
+ {
26
+ key: '/plugin-test',
27
+ label: 'Plugin Test',
28
+ icon: 'box'
29
+ }
30
+ ];
31
+
32
+ export const getStaticNavigationItems = () => {
33
+ return STATIC_NAVIGATION_ITEMS;
34
+ };
35
+
36
+ export const getFullpageNavigationItems = (
37
+ apps: RegisteredApp[],
38
+ configs: Map<number, any>
39
+ ): TMenuItemType[] => {
40
+ return apps
41
+ .filter(app => app.type === 'full_page')
42
+ .map((app): TMenuItemType => {
43
+ return {
44
+ key: `/external/${app.slug}`,
45
+ label: app.name,
46
+ icon: 'stoklistesi',
47
+ children: configs
48
+ .get(app.id)
49
+ ?.menu?.map((sub: any): TMenuItemType | false => {
50
+ if (sub?.child) return false;
51
+
52
+ return {
53
+ key: `/external/${app.slug}${sub.path}`,
54
+ label: sub.label,
55
+ icon: 'eksi'
56
+ };
57
+ })
58
+ .filter(Boolean)
59
+ };
60
+ });
61
+ };
62
+
63
+ export const getPluginNavigationItems = () => {
64
+ return PLUGIN_NAVIGATION_ITEMS;
65
+ };