@nocobase/plugin-mobile-client 0.10.0-alpha.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.
Files changed (183) hide show
  1. package/client.d.ts +4 -0
  2. package/client.js +30 -0
  3. package/docs/en-US/index.md +7 -0
  4. package/docs/en-US/installation.md +13 -0
  5. package/docs/en-US/tabs.json +14 -0
  6. package/docs/en-US/usage.md +1 -0
  7. package/docs/zh-CN/index.md +7 -0
  8. package/docs/zh-CN/installation.md +13 -0
  9. package/docs/zh-CN/tabs.json +14 -0
  10. package/docs/zh-CN/usage.md +2 -0
  11. package/lib/client/configuration/App.d.ts +2 -0
  12. package/lib/client/configuration/App.js +40 -0
  13. package/lib/client/configuration/Interface.d.ts +2 -0
  14. package/lib/client/configuration/Interface.js +20 -0
  15. package/lib/client/configuration/index.d.ts +2 -0
  16. package/lib/client/configuration/index.js +27 -0
  17. package/lib/client/core/bridge/index.d.ts +2 -0
  18. package/lib/client/core/bridge/index.js +17 -0
  19. package/lib/client/core/bridge/injects.d.ts +13 -0
  20. package/lib/client/core/bridge/injects.js +13 -0
  21. package/lib/client/core/bridge/native-call.d.ts +1 -0
  22. package/lib/client/core/bridge/native-call.js +24 -0
  23. package/lib/client/core/index.d.ts +3 -0
  24. package/lib/client/core/index.js +46 -0
  25. package/lib/client/core/schema/common/index.d.ts +1 -0
  26. package/lib/client/core/schema/common/index.js +16 -0
  27. package/lib/client/core/schema/common/page.d.ts +16 -0
  28. package/lib/client/core/schema/common/page.js +23 -0
  29. package/lib/client/core/schema/components/container/Container.Designer.d.ts +2 -0
  30. package/lib/client/core/schema/components/container/Container.Designer.js +138 -0
  31. package/lib/client/core/schema/components/container/Container.d.ts +5 -0
  32. package/lib/client/core/schema/components/container/Container.js +150 -0
  33. package/lib/client/core/schema/components/container/index.d.ts +1 -0
  34. package/lib/client/core/schema/components/container/index.js +16 -0
  35. package/lib/client/core/schema/components/header/Header.Designer.d.ts +2 -0
  36. package/lib/client/core/schema/components/header/Header.Designer.js +72 -0
  37. package/lib/client/core/schema/components/header/Header.d.ts +10 -0
  38. package/lib/client/core/schema/components/header/Header.js +85 -0
  39. package/lib/client/core/schema/components/header/index.d.ts +1 -0
  40. package/lib/client/core/schema/components/header/index.js +16 -0
  41. package/lib/client/core/schema/components/index.d.ts +6 -0
  42. package/lib/client/core/schema/components/index.js +71 -0
  43. package/lib/client/core/schema/components/menu/Menu.Designer.d.ts +2 -0
  44. package/lib/client/core/schema/components/menu/Menu.Designer.js +81 -0
  45. package/lib/client/core/schema/components/menu/Menu.Item.d.ts +6 -0
  46. package/lib/client/core/schema/components/menu/Menu.Item.js +129 -0
  47. package/lib/client/core/schema/components/menu/Menu.d.ts +7 -0
  48. package/lib/client/core/schema/components/menu/Menu.js +88 -0
  49. package/lib/client/core/schema/components/menu/MenuBlockInitializer.d.ts +2 -0
  50. package/lib/client/core/schema/components/menu/MenuBlockInitializer.js +51 -0
  51. package/lib/client/core/schema/components/menu/index.d.ts +2 -0
  52. package/lib/client/core/schema/components/menu/index.js +27 -0
  53. package/lib/client/core/schema/components/menu/schema.d.ts +17 -0
  54. package/lib/client/core/schema/components/menu/schema.js +24 -0
  55. package/lib/client/core/schema/components/page/Page.Designer.d.ts +2 -0
  56. package/lib/client/core/schema/components/page/Page.Designer.js +160 -0
  57. package/lib/client/core/schema/components/page/Page.d.ts +5 -0
  58. package/lib/client/core/schema/components/page/Page.js +157 -0
  59. package/lib/client/core/schema/components/page/index.d.ts +1 -0
  60. package/lib/client/core/schema/components/page/index.js +16 -0
  61. package/lib/client/core/schema/components/settings/Settings.Designer.d.ts +2 -0
  62. package/lib/client/core/schema/components/settings/Settings.Designer.js +37 -0
  63. package/lib/client/core/schema/components/settings/Settings.d.ts +6 -0
  64. package/lib/client/core/schema/components/settings/Settings.js +43 -0
  65. package/lib/client/core/schema/components/settings/SettingsBlockInitializer.d.ts +2 -0
  66. package/lib/client/core/schema/components/settings/SettingsBlockInitializer.js +51 -0
  67. package/lib/client/core/schema/components/settings/index.d.ts +2 -0
  68. package/lib/client/core/schema/components/settings/index.js +27 -0
  69. package/lib/client/core/schema/components/tab-bar/TabBar.Item.d.ts +6 -0
  70. package/lib/client/core/schema/components/tab-bar/TabBar.Item.js +80 -0
  71. package/lib/client/core/schema/components/tab-bar/TabBar.d.ts +6 -0
  72. package/lib/client/core/schema/components/tab-bar/TabBar.js +138 -0
  73. package/lib/client/core/schema/components/tab-bar/index.d.ts +1 -0
  74. package/lib/client/core/schema/components/tab-bar/index.js +16 -0
  75. package/lib/client/core/schema/components/tab-bar/schema.d.ts +18 -0
  76. package/lib/client/core/schema/components/tab-bar/schema.js +25 -0
  77. package/lib/client/core/schema/helpers/index.d.ts +67 -0
  78. package/lib/client/core/schema/helpers/index.js +49 -0
  79. package/lib/client/core/schema/hooks/index.d.ts +1 -0
  80. package/lib/client/core/schema/hooks/index.js +16 -0
  81. package/lib/client/core/schema/hooks/useSchemaPatch.d.ts +3 -0
  82. package/lib/client/core/schema/hooks/useSchemaPatch.js +61 -0
  83. package/lib/client/core/schema/index.d.ts +3 -0
  84. package/lib/client/core/schema/index.js +38 -0
  85. package/lib/client/core/schema/initializers/BlockInitializers.d.ts +147 -0
  86. package/lib/client/core/schema/initializers/BlockInitializers.js +79 -0
  87. package/lib/client/core/schema/initializers/index.d.ts +1 -0
  88. package/lib/client/core/schema/initializers/index.js +16 -0
  89. package/lib/client/core/schema/scopes/grid-card.d.ts +15 -0
  90. package/lib/client/core/schema/scopes/grid-card.js +45 -0
  91. package/lib/client/core/schema/scopes/index.d.ts +1 -0
  92. package/lib/client/core/schema/scopes/index.js +16 -0
  93. package/lib/client/devices/iOS6.d.ts +5 -0
  94. package/lib/client/devices/iOS6.js +32 -0
  95. package/lib/client/devices/index.d.ts +2 -0
  96. package/lib/client/devices/index.js +43 -0
  97. package/lib/client/index.d.ts +3 -0
  98. package/lib/client/index.js +47 -0
  99. package/lib/client/locale/en-US.d.ts +2 -0
  100. package/lib/client/locale/en-US.js +9 -0
  101. package/lib/client/locale/index.d.ts +4 -0
  102. package/lib/client/locale/index.js +43 -0
  103. package/lib/client/locale/zh-CN.d.ts +32 -0
  104. package/lib/client/locale/zh-CN.js +39 -0
  105. package/lib/client/router/Application.d.ts +3 -0
  106. package/lib/client/router/Application.js +129 -0
  107. package/lib/client/router/InterfaceProvider.d.ts +4 -0
  108. package/lib/client/router/InterfaceProvider.js +29 -0
  109. package/lib/client/router/InterfaceRouter.d.ts +6 -0
  110. package/lib/client/router/InterfaceRouter.js +58 -0
  111. package/lib/client/router/RouteSwitchProvider.d.ts +2 -0
  112. package/lib/client/router/RouteSwitchProvider.js +59 -0
  113. package/lib/client/router/index.d.ts +2 -0
  114. package/lib/client/router/index.js +27 -0
  115. package/lib/index.d.ts +1 -0
  116. package/lib/index.js +13 -0
  117. package/lib/server/index.d.ts +1 -0
  118. package/lib/server/index.js +13 -0
  119. package/lib/server/plugin.d.ts +10 -0
  120. package/lib/server/plugin.js +57 -0
  121. package/lib/server/routes.d.ts +34 -0
  122. package/lib/server/routes.js +41 -0
  123. package/package.json +28 -0
  124. package/server.d.ts +4 -0
  125. package/server.js +30 -0
  126. package/src/client/configuration/App.tsx +23 -0
  127. package/src/client/configuration/Interface.tsx +11 -0
  128. package/src/client/configuration/index.ts +2 -0
  129. package/src/client/core/bridge/index.ts +2 -0
  130. package/src/client/core/bridge/injects.ts +14 -0
  131. package/src/client/core/bridge/native-call.ts +23 -0
  132. package/src/client/core/index.tsx +45 -0
  133. package/src/client/core/schema/common/index.ts +1 -0
  134. package/src/client/core/schema/common/page.ts +16 -0
  135. package/src/client/core/schema/components/container/Container.Designer.tsx +88 -0
  136. package/src/client/core/schema/components/container/Container.tsx +135 -0
  137. package/src/client/core/schema/components/container/index.ts +1 -0
  138. package/src/client/core/schema/components/header/Header.Designer.tsx +39 -0
  139. package/src/client/core/schema/components/header/Header.tsx +49 -0
  140. package/src/client/core/schema/components/header/index.ts +1 -0
  141. package/src/client/core/schema/components/index.ts +6 -0
  142. package/src/client/core/schema/components/menu/Menu.Designer.tsx +46 -0
  143. package/src/client/core/schema/components/menu/Menu.Item.tsx +97 -0
  144. package/src/client/core/schema/components/menu/Menu.tsx +82 -0
  145. package/src/client/core/schema/components/menu/MenuBlockInitializer.tsx +20 -0
  146. package/src/client/core/schema/components/menu/index.ts +2 -0
  147. package/src/client/core/schema/components/menu/schema.ts +17 -0
  148. package/src/client/core/schema/components/page/Page.Designer.tsx +106 -0
  149. package/src/client/core/schema/components/page/Page.tsx +132 -0
  150. package/src/client/core/schema/components/page/index.ts +1 -0
  151. package/src/client/core/schema/components/settings/Settings.Designer.tsx +22 -0
  152. package/src/client/core/schema/components/settings/Settings.tsx +25 -0
  153. package/src/client/core/schema/components/settings/SettingsBlockInitializer.tsx +20 -0
  154. package/src/client/core/schema/components/settings/index.ts +2 -0
  155. package/src/client/core/schema/components/tab-bar/TabBar.Item.tsx +67 -0
  156. package/src/client/core/schema/components/tab-bar/TabBar.tsx +108 -0
  157. package/src/client/core/schema/components/tab-bar/index.ts +1 -0
  158. package/src/client/core/schema/components/tab-bar/schema.ts +18 -0
  159. package/src/client/core/schema/helpers/index.ts +38 -0
  160. package/src/client/core/schema/hooks/index.ts +1 -0
  161. package/src/client/core/schema/hooks/useSchemaPatch.ts +24 -0
  162. package/src/client/core/schema/index.ts +3 -0
  163. package/src/client/core/schema/initializers/BlockInitializers.ts +81 -0
  164. package/src/client/core/schema/initializers/index.ts +1 -0
  165. package/src/client/core/schema/scopes/grid-card.ts +35 -0
  166. package/src/client/core/schema/scopes/index.ts +1 -0
  167. package/src/client/devices/iOS6.tsx +24 -0
  168. package/src/client/devices/index.tsx +27 -0
  169. package/src/client/index.tsx +33 -0
  170. package/src/client/locale/en-US.ts +5 -0
  171. package/src/client/locale/index.ts +23 -0
  172. package/src/client/locale/zh-CN.ts +33 -0
  173. package/src/client/router/Application.tsx +114 -0
  174. package/src/client/router/InterfaceProvider.tsx +11 -0
  175. package/src/client/router/InterfaceRouter.tsx +48 -0
  176. package/src/client/router/RouteSwitchProvider.tsx +31 -0
  177. package/src/client/router/index.ts +2 -0
  178. package/src/index.ts +1 -0
  179. package/src/server/collections/.gitkeep +0 -0
  180. package/src/server/index.ts +1 -0
  181. package/src/server/plugin.ts +25 -0
  182. package/src/server/routes.ts +38 -0
  183. package/types.d.ts +0 -0
@@ -0,0 +1,23 @@
1
+ import { invoke } from './injects';
2
+
3
+ /**
4
+ * App 右滑返回
5
+ * @param cb 回调函数,返回 true 表示 web 自己消费,false表示 app 消费
6
+ */
7
+
8
+ const JSBridgeFunction = {
9
+ /**
10
+ * @description JSBridge injects
11
+ */
12
+ onBackPressed: () => {
13
+ if (history.length === 1) {
14
+ invoke({ action: 'moveTaskToBack' });
15
+ } else {
16
+ history.back();
17
+ }
18
+ },
19
+ };
20
+
21
+ Object.keys(JSBridgeFunction).forEach((key) => {
22
+ window[key] = JSBridgeFunction[key];
23
+ });
@@ -0,0 +1,45 @@
1
+ import { SchemaComponentOptions, SchemaInitializerProvider } from '@nocobase/client';
2
+ import React from 'react';
3
+ import {
4
+ MBlockInitializers,
5
+ MMenuBlockInitializer,
6
+ MMenu,
7
+ MContainer,
8
+ MTabBar,
9
+ MPage,
10
+ MHeader,
11
+ MSettingsBlockInitializer,
12
+ MSettings,
13
+ useGridCardBlockItemProps,
14
+ useGridCardBlockProps,
15
+ } from './schema';
16
+ import './bridge';
17
+
18
+ export const MobileCore: React.FC = (props) => {
19
+ return (
20
+ <SchemaInitializerProvider
21
+ initializers={{
22
+ MBlockInitializers,
23
+ }}
24
+ >
25
+ <SchemaComponentOptions
26
+ components={{
27
+ MMenuBlockInitializer,
28
+ MSettingsBlockInitializer,
29
+ MContainer,
30
+ MMenu,
31
+ MTabBar,
32
+ MPage,
33
+ MHeader,
34
+ MSettings,
35
+ }}
36
+ scope={{
37
+ useGridCardBlockItemProps,
38
+ useGridCardBlockProps,
39
+ }}
40
+ >
41
+ {props.children}
42
+ </SchemaComponentOptions>
43
+ </SchemaInitializerProvider>
44
+ );
45
+ };
@@ -0,0 +1 @@
1
+ export * from './page';
@@ -0,0 +1,16 @@
1
+ export const PageSchema = {
2
+ type: 'void',
3
+ 'x-component': 'MPage',
4
+ 'x-designer': 'MPage.Designer',
5
+ 'x-component-props': {},
6
+ properties: {
7
+ grid: {
8
+ type: 'void',
9
+ 'x-component': 'Grid',
10
+ 'x-initializer': 'MBlockInitializers',
11
+ 'x-component-props': {
12
+ showDivider: false,
13
+ },
14
+ },
15
+ },
16
+ };
@@ -0,0 +1,88 @@
1
+ import { SchemaSettings, useDesignable } from '@nocobase/client';
2
+ import React from 'react';
3
+ import { generateNTemplate, useTranslation } from '../../../../locale';
4
+ import { Schema, useField, useFieldSchema } from '@formily/react';
5
+ import { uid } from '@formily/shared';
6
+ import { useNavigate } from 'react-router-dom';
7
+ import { findSchema } from '../../helpers';
8
+ import { Button } from 'antd';
9
+ import { MenuOutlined } from '@ant-design/icons';
10
+ import { PageSchema } from '../../common';
11
+
12
+ export const ContainerDesigner = () => {
13
+ const { t } = useTranslation();
14
+ const fieldSchema = useFieldSchema();
15
+ const { dn } = useDesignable();
16
+ const tabBarSchema = fieldSchema.reduceProperties(
17
+ (schema, next) => schema || (next['x-component'] === 'MTabBar' && next),
18
+ ) as Schema;
19
+
20
+ const navigate = useNavigate();
21
+
22
+ const field = useField();
23
+ const schemaSettingsProps = {
24
+ dn,
25
+ field,
26
+ fieldSchema,
27
+ };
28
+ return (
29
+ <SchemaSettings
30
+ title={
31
+ <Button
32
+ style={{
33
+ borderColor: 'rgb(241, 139, 98)',
34
+ color: 'rgb(241, 139, 98)',
35
+ }}
36
+ icon={<MenuOutlined />}
37
+ type="dashed"
38
+ >
39
+ {t('App level Configuration')}
40
+ </Button>
41
+ }
42
+ {...schemaSettingsProps}
43
+ >
44
+ <SchemaSettings.SwitchItem
45
+ checked={!!tabBarSchema}
46
+ title={t('Enable TabBar')}
47
+ onChange={async (v) => {
48
+ if (v) {
49
+ const pageSchema = findSchema(fieldSchema, 'MPage');
50
+ if (!pageSchema) return;
51
+ await dn.remove(pageSchema);
52
+ await dn.insertBeforeEnd({
53
+ type: 'void',
54
+ 'x-component': 'MTabBar',
55
+ 'x-component-props': {},
56
+ name: 'tabBar',
57
+ properties: {
58
+ [uid()]: {
59
+ type: 'void',
60
+ 'x-component': 'MTabBar.Item',
61
+ 'x-designer': 'MTabBar.Item.Designer',
62
+ 'x-component-props': {
63
+ icon: 'HomeOutlined',
64
+ title: generateNTemplate('Untitled'),
65
+ },
66
+ properties: {
67
+ page: pageSchema.toJSON(),
68
+ },
69
+ },
70
+ },
71
+ });
72
+ } else {
73
+ const tabBarSchemaFirstKey = Object.keys(tabBarSchema.properties || {})?.[0];
74
+ const pageSchema = tabBarSchemaFirstKey
75
+ ? findSchema(tabBarSchema.properties[tabBarSchemaFirstKey], 'MPage')
76
+ : null;
77
+ await dn.remove(tabBarSchema);
78
+ await dn.insertBeforeEnd(pageSchema || PageSchema, {
79
+ onSuccess() {
80
+ navigate('../');
81
+ },
82
+ });
83
+ }
84
+ }}
85
+ />
86
+ </SchemaSettings>
87
+ );
88
+ };
@@ -0,0 +1,135 @@
1
+ import { css, cx } from '@emotion/css';
2
+ import { useFieldSchema } from '@formily/react';
3
+ import { RouteSwitch, SchemaComponent, SortableItem, useDesigner } from '@nocobase/client';
4
+ import React, { useMemo } from 'react';
5
+ import { Navigate, RouteProps, useLocation, useParams } from 'react-router-dom';
6
+ import { ContainerDesigner } from './Container.Designer';
7
+
8
+ const findGrid = (schema, uid) => {
9
+ return schema.reduceProperties((final, next) => {
10
+ if (final) return final;
11
+ if (next['x-component'] === 'MTabBar') {
12
+ return findGrid(next, uid);
13
+ }
14
+ if (next['x-component'] === 'MTabBar.Item' && uid === next['x-uid']) {
15
+ return next;
16
+ }
17
+ });
18
+ };
19
+
20
+ const TabContentComponent = () => {
21
+ const { name } = useParams<{ name: string }>();
22
+ const fieldSchema = useFieldSchema();
23
+ if (!name) return <></>;
24
+ const gridSchema = findGrid(fieldSchema.properties['tabBar'], name.replace('tab_', ''));
25
+ if (!gridSchema) {
26
+ return <Navigate replace to="../" />;
27
+ }
28
+ return <SchemaComponent schema={gridSchema} />;
29
+ };
30
+
31
+ const InternalContainer: React.FC = (props) => {
32
+ const Designer = useDesigner();
33
+ const fieldSchema = useFieldSchema();
34
+ const params = useParams<{ name: string }>();
35
+ const location = useLocation();
36
+ const tabBarSchema = fieldSchema?.properties?.['tabBar'];
37
+ const tabBarCurrentFirstKey = tabBarSchema?.properties ? Object.keys(tabBarSchema.properties)[0] : null;
38
+ let redirectToUid = null;
39
+ if (tabBarCurrentFirstKey) {
40
+ redirectToUid = tabBarSchema?.properties[tabBarCurrentFirstKey]?.['x-uid'];
41
+ }
42
+
43
+ const tabRoutes = useMemo<RouteProps[]>(() => {
44
+ if (!redirectToUid) {
45
+ return [];
46
+ }
47
+ const locationPath = location.pathname.endsWith('/') ? location.pathname.slice(0, -1) : location.pathname;
48
+
49
+ return [
50
+ !params.name
51
+ ? {
52
+ type: 'redirect',
53
+ to: `${locationPath}/tab_${redirectToUid}`,
54
+ from: location.pathname,
55
+ }
56
+ : null,
57
+ {
58
+ type: 'route',
59
+ path: location.pathname,
60
+ component: TabContentComponent,
61
+ },
62
+ ].filter(Boolean) as any[];
63
+ }, [redirectToUid, params.name, location.pathname]);
64
+
65
+ return (
66
+ <SortableItem
67
+ eid="nb-mobile-scroll-wrapper"
68
+ className={cx(
69
+ 'nb-mobile-container',
70
+ css`
71
+ & > .general-schema-designer > .general-schema-designer-icons {
72
+ right: unset;
73
+ left: 2px;
74
+ }
75
+ background: #f0f2f5;
76
+ display: flex;
77
+ flex-direction: column;
78
+ width: 100%;
79
+ height: 100%;
80
+ overflow-y: scroll;
81
+ position: initial !important;
82
+ `,
83
+ )}
84
+ >
85
+ <Designer></Designer>
86
+ <div
87
+ style={{
88
+ paddingBottom: tabRoutes.length ? '50px' : '0px',
89
+ }}
90
+ className={cx('nb-mobile-container-content')}
91
+ >
92
+ {tabRoutes.length ? (
93
+ <RouteSwitch routes={tabRoutes as any} />
94
+ ) : (
95
+ <SchemaComponent
96
+ filterProperties={(schema) => {
97
+ return schema['x-component'] !== 'MTabBar';
98
+ }}
99
+ schema={fieldSchema}
100
+ />
101
+ )}
102
+ </div>
103
+ <div
104
+ className={cx(
105
+ 'nb-mobile-container-tab-bar',
106
+ css`
107
+ & > .general-schema-designer {
108
+ --nb-designer-top: 20px;
109
+ }
110
+ position: absolute;
111
+ background: #ffffff;
112
+ width: 100%;
113
+ bottom: 0;
114
+ left: 0;
115
+ z-index: 1000;
116
+ `,
117
+ )}
118
+ >
119
+ <SchemaComponent
120
+ onlyRenderProperties
121
+ filterProperties={(schema) => {
122
+ return schema['x-component'] === 'MTabBar';
123
+ }}
124
+ schema={fieldSchema}
125
+ ></SchemaComponent>
126
+ </div>
127
+ </SortableItem>
128
+ );
129
+ };
130
+
131
+ export const MContainer = InternalContainer as unknown as typeof InternalContainer & {
132
+ Designer: typeof ContainerDesigner;
133
+ };
134
+ MContainer.Designer = ContainerDesigner;
135
+ MContainer.displayName = 'MContainer';
@@ -0,0 +1 @@
1
+ export * from './Container';
@@ -0,0 +1,39 @@
1
+ import { Schema, useField, useFieldSchema } from '@formily/react';
2
+ import { GeneralSchemaDesigner, SchemaSettings, useDesignable } from '@nocobase/client';
3
+ import React from 'react';
4
+ import { Switch } from '@formily/antd';
5
+ import { useTranslation } from '../../../../locale';
6
+ import { useSchemaPatch } from '../../hooks';
7
+
8
+ export const HeaderDesigner = () => {
9
+ const field = useField();
10
+ const { onUpdateComponentProps } = useSchemaPatch();
11
+ const { t } = useTranslation();
12
+ return (
13
+ <GeneralSchemaDesigner draggable={false}>
14
+ <SchemaSettings.ModalItem
15
+ title={t('Edit info')}
16
+ components={{ Switch }}
17
+ initialValues={field.componentProps}
18
+ schema={{
19
+ properties: {
20
+ title: {
21
+ type: 'string',
22
+ title: t('Title'),
23
+ required: true,
24
+ 'x-component': 'Input',
25
+ 'x-decorator': 'FormItem',
26
+ },
27
+ showBack: {
28
+ type: 'boolean',
29
+ title: t('Display back button'),
30
+ 'x-component': 'Switch',
31
+ 'x-decorator': 'FormItem',
32
+ },
33
+ },
34
+ }}
35
+ onSubmit={onUpdateComponentProps}
36
+ />
37
+ </GeneralSchemaDesigner>
38
+ );
39
+ };
@@ -0,0 +1,49 @@
1
+ import { css, cx } from '@emotion/css';
2
+ import { SortableItem, useCompile, useDesigner } from '@nocobase/client';
3
+ import { NavBar, NavBarProps } from 'antd-mobile';
4
+ import React, { useEffect } from 'react';
5
+ import { useNavigate } from 'react-router-dom';
6
+ import { HeaderDesigner } from './Header.Designer';
7
+ import { useField } from '@formily/react';
8
+ import { generateNTemplate } from '../../../../locale';
9
+
10
+ export interface HeaderProps extends NavBarProps {
11
+ title?: string;
12
+ showBack?: boolean;
13
+ }
14
+ const InternalHeader = (props: HeaderProps) => {
15
+ const field = useField();
16
+ const { title = generateNTemplate('Untitled'), showBack = false } = { ...props, ...field?.componentProps };
17
+ const Designer = useDesigner();
18
+ const compile = useCompile();
19
+ const compiledTitle = compile(title);
20
+ const navigate = useNavigate();
21
+
22
+ useEffect(() => {
23
+ // sync title
24
+ document.title = `${compiledTitle} - NocoBase`;
25
+ }, [compiledTitle]);
26
+
27
+ return (
28
+ <SortableItem
29
+ className={cx(
30
+ 'nb-mobile-header',
31
+ css`
32
+ width: 100%;
33
+ background: #fff;
34
+ `,
35
+ )}
36
+ >
37
+ <NavBar backArrow={showBack} onBack={() => navigate(-1)}>
38
+ {compiledTitle}
39
+ </NavBar>
40
+ <Designer />
41
+ </SortableItem>
42
+ );
43
+ };
44
+
45
+ export const MHeader = InternalHeader as unknown as typeof InternalHeader & {
46
+ Designer: typeof HeaderDesigner;
47
+ };
48
+
49
+ MHeader.Designer = HeaderDesigner;
@@ -0,0 +1 @@
1
+ export * from './Header';
@@ -0,0 +1,6 @@
1
+ export * from './menu';
2
+ export * from './container';
3
+ export * from './tab-bar';
4
+ export * from './page';
5
+ export * from './header';
6
+ export * from './settings';
@@ -0,0 +1,46 @@
1
+ import { GeneralSchemaDesigner, SchemaSettings, useDesignable } from '@nocobase/client';
2
+ import { MenuOutlined } from '@ant-design/icons';
3
+ import React from 'react';
4
+ import { useTranslation } from '../../../../locale';
5
+ import { Button } from 'antd';
6
+ import { useFieldSchema, useField } from '@formily/react';
7
+
8
+ export const MenuDesigner: React.FC = (props) => {
9
+ const { t } = useTranslation();
10
+ const fieldSchema = useFieldSchema();
11
+ const { dn } = useDesignable();
12
+ const field = useField();
13
+ const schemaSettingsProps = {
14
+ dn,
15
+ field,
16
+ fieldSchema,
17
+ };
18
+ return (
19
+ <SchemaSettings
20
+ title={
21
+ <Button
22
+ style={{
23
+ borderColor: 'rgb(241, 139, 98)',
24
+ color: 'rgb(241, 139, 98)',
25
+ }}
26
+ icon={<MenuOutlined />}
27
+ type="dashed"
28
+ >
29
+ {t('Menu configuration')}
30
+ </Button>
31
+ }
32
+ {...schemaSettingsProps}
33
+ >
34
+ <SchemaSettings.Remove
35
+ key="remove"
36
+ removeParentsIfNoChildren
37
+ confirm={{
38
+ title: t('Delete menu block'),
39
+ }}
40
+ breakRemoveOn={{
41
+ 'x-component': 'Grid',
42
+ }}
43
+ />
44
+ </SchemaSettings>
45
+ );
46
+ };
@@ -0,0 +1,97 @@
1
+ import { css, cx } from '@emotion/css';
2
+ import { useField, useFieldSchema } from '@formily/react';
3
+ import { GeneralSchemaDesigner, Icon, SchemaSettings, SortableItem, useCompile, useDesigner } from '@nocobase/client';
4
+ import { List, ListItemProps } from 'antd-mobile';
5
+ import React from 'react';
6
+ import { useLocation, useNavigate, useParams } from 'react-router-dom';
7
+ import { useTranslation } from '../../../../locale';
8
+ import { useSchemaPatch } from '../../hooks';
9
+
10
+ interface MMenuItemProps extends ListItemProps {
11
+ name: string;
12
+ icon: string;
13
+ }
14
+
15
+ const InternalMenuItem: React.FC<MMenuItemProps> = (props) => {
16
+ const { icon, name } = props;
17
+ const Designer = useDesigner();
18
+ const navigate = useNavigate();
19
+ const location = useLocation();
20
+ const fieldSchema = useFieldSchema();
21
+ const compile = useCompile();
22
+ const params = useParams<{ name: string }>();
23
+
24
+ const onToPage = () => {
25
+ const locationPath = location.pathname.endsWith('/') ? location.pathname.slice(0, -1) : location.pathname;
26
+ navigate(params.name ? `/mobile/${fieldSchema['x-uid']}` : `${locationPath}/${fieldSchema['x-uid']}`);
27
+ };
28
+ return (
29
+ <SortableItem
30
+ className={cx(
31
+ 'nb-mobile-menu-item',
32
+ css`
33
+ width: 100%;
34
+ background: var(--adm-color-background);
35
+ > .adm-list-item {
36
+ background: inherit;
37
+ }
38
+ `,
39
+ )}
40
+ >
41
+ <List.Item arrow clickable {...props} prefix={<Icon type={icon} />} onClick={onToPage}>
42
+ {compile(name)}
43
+ </List.Item>
44
+ <Designer></Designer>
45
+ </SortableItem>
46
+ );
47
+ };
48
+
49
+ const MenuItemDesigner: React.FC = () => {
50
+ const { t } = useTranslation();
51
+ const { onUpdateComponentProps } = useSchemaPatch();
52
+ const field = useField();
53
+
54
+ return (
55
+ <GeneralSchemaDesigner>
56
+ <SchemaSettings.ModalItem
57
+ title={t('Edit menu info')}
58
+ initialValues={field.componentProps}
59
+ schema={{
60
+ properties: {
61
+ name: {
62
+ type: 'string',
63
+ title: t('Menu name'),
64
+ required: true,
65
+ 'x-component': 'Input',
66
+ 'x-decorator': 'FormItem',
67
+ },
68
+ icon: {
69
+ required: true,
70
+ 'x-decorator': 'FormItem',
71
+ 'x-component': 'IconPicker',
72
+ title: t('Icon'),
73
+ 'x-component-props': {},
74
+ },
75
+ },
76
+ }}
77
+ onSubmit={onUpdateComponentProps}
78
+ />
79
+ <SchemaSettings.Remove
80
+ key="remove"
81
+ removeParentsIfNoChildren
82
+ confirm={{
83
+ title: t('Delete menu item?'),
84
+ }}
85
+ breakRemoveOn={{
86
+ 'x-component': 'MMenu',
87
+ }}
88
+ />
89
+ </GeneralSchemaDesigner>
90
+ );
91
+ };
92
+
93
+ export const MenuItem = InternalMenuItem as typeof InternalMenuItem as unknown as {
94
+ Designer: typeof MenuItemDesigner;
95
+ };
96
+
97
+ MenuItem.Designer = MenuItemDesigner;
@@ -0,0 +1,82 @@
1
+ import React from 'react';
2
+ import { MenuItem } from './Menu.Item';
3
+ import {
4
+ DndContext,
5
+ SchemaComponent,
6
+ SchemaInitializer,
7
+ SortableItem,
8
+ useDesignable,
9
+ useDesigner,
10
+ } from '@nocobase/client';
11
+ import { css, cx } from '@emotion/css';
12
+ import { MenuDesigner } from './Menu.Designer';
13
+ import { useFieldSchema } from '@formily/react';
14
+ import { List } from 'antd-mobile';
15
+ import { useTranslation } from '../../../../locale';
16
+ import { menuItemSchema } from './schema';
17
+ import { PageSchema } from '../../common';
18
+
19
+ const InternalMenu: React.FC = (props) => {
20
+ const Designer = useDesigner();
21
+ const fieldSchema = useFieldSchema();
22
+ const { insertBeforeEnd, designable } = useDesignable();
23
+
24
+ const { t } = useTranslation();
25
+
26
+ const onAddMenuItem = (values: any) => {
27
+ const properties = {
28
+ page: PageSchema,
29
+ };
30
+
31
+ return insertBeforeEnd({
32
+ type: 'void',
33
+ title: values.name,
34
+ 'x-component': 'MMenu.Item',
35
+ 'x-component-props': values,
36
+ 'x-designer': 'MMenu.Item.Designer',
37
+ properties,
38
+ });
39
+ };
40
+
41
+ return (
42
+ <SortableItem
43
+ className={cx(
44
+ 'nb-mobile-menu',
45
+ css`
46
+ background: #ffffff;
47
+ width: 100%;
48
+ margin-bottom: var(--nb-spacing);
49
+ `,
50
+ )}
51
+ >
52
+ <List>
53
+ {designable && (
54
+ <List.Item>
55
+ <Designer />
56
+ </List.Item>
57
+ )}
58
+ <DndContext>
59
+ <SchemaComponent onlyRenderProperties schema={fieldSchema}></SchemaComponent>
60
+ </DndContext>
61
+ {designable ? (
62
+ <List.Item>
63
+ <SchemaInitializer.ActionModal
64
+ buttonText={t('Add menu item')}
65
+ title={t('Add menu item')}
66
+ schema={menuItemSchema}
67
+ onSubmit={onAddMenuItem}
68
+ />
69
+ </List.Item>
70
+ ) : null}
71
+ </List>
72
+ </SortableItem>
73
+ );
74
+ };
75
+
76
+ export const MMenu = InternalMenu as unknown as typeof InternalMenu & {
77
+ Item: typeof MenuItem;
78
+ Designer: typeof MenuDesigner;
79
+ };
80
+
81
+ MMenu.Item = MenuItem;
82
+ MMenu.Designer = MenuDesigner;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { MenuOutlined } from '@ant-design/icons';
3
+ import { SchemaInitializer } from '@nocobase/client';
4
+
5
+ export const MMenuBlockInitializer = (props) => {
6
+ const { insert } = props;
7
+ return (
8
+ <SchemaInitializer.Item
9
+ icon={<MenuOutlined />}
10
+ onClick={async () => {
11
+ insert({
12
+ type: 'void',
13
+ 'x-component': 'MMenu',
14
+ 'x-designer': 'MMenu.Designer',
15
+ 'x-component-props': {},
16
+ });
17
+ }}
18
+ />
19
+ );
20
+ };
@@ -0,0 +1,2 @@
1
+ export * from './MenuBlockInitializer';
2
+ export * from './Menu';
@@ -0,0 +1,17 @@
1
+ export const menuItemSchema = {
2
+ properties: {
3
+ name: {
4
+ type: 'string',
5
+ title: `{{t('Menu name')}}`,
6
+ required: true,
7
+ 'x-component': 'Input',
8
+ 'x-decorator': 'FormItem',
9
+ },
10
+ icon: {
11
+ 'x-decorator': 'FormItem',
12
+ 'x-component': 'IconPicker',
13
+ title: `{{t('Icon')}}`,
14
+ 'x-component-props': {},
15
+ },
16
+ },
17
+ };